diff options
| author | Josh Rahm <joshuarahm@gmail.com> | 2026-01-05 01:11:45 -0700 |
|---|---|---|
| committer | Josh Rahm <joshuarahm@gmail.com> | 2026-01-05 01:11:45 -0700 |
| commit | 34e0354bb2d07ce0ad8a6e83e226370cfb9904da (patch) | |
| tree | a8b9638c6d74cc2454ca2d7354a8ecea7dbd4cba | |
| parent | 9daffd37236469e8089e3c12207c449b4db09e92 (diff) | |
| download | montis-34e0354bb2d07ce0ad8a6e83e226370cfb9904da.tar.gz montis-34e0354bb2d07ce0ad8a6e83e226370cfb9904da.tar.bz2 montis-34e0354bb2d07ce0ad8a6e83e226370cfb9904da.zip | |
[feat] right-click drag to resize windows.
| -rw-r--r-- | plug/src/Config.hs | 7 | ||||
| -rw-r--r-- | plug/src/Montis/Base/Foreign/Runtime.hs | 10 | ||||
| -rw-r--r-- | plug/src/Montis/Standard/Drag.hs | 82 | ||||
| -rw-r--r-- | rt/include/util.h | 5 | ||||
| -rw-r--r-- | rt/src/util.c | 35 |
5 files changed, 123 insertions, 16 deletions
diff --git a/plug/src/Config.hs b/plug/src/Config.hs index fd337eb..c76898e 100644 --- a/plug/src/Config.hs +++ b/plug/src/Config.hs @@ -4,9 +4,10 @@ import Control.Monad.IO.Class (liftIO) import Data.Bits (shiftL, (.&.)) import Data.Word (Word32) import Montis.Core -import Montis.Standard.Drag (DragConfig (DragConfig)) -import Montis.Standard.Mouse (MouseConfig (MouseConfig)) +import Montis.Base.Foreign.Runtime +import Montis.Standard.Drag (DragConfig (DragConfig), unwrapSelf) import Montis.Standard.Keys (KeysConfig (KeysConfig), subkeys) +import Montis.Standard.Mouse (MouseConfig (MouseConfig)) foreign export ccall "plugin_cold_start" coldStart :: MontisColdStart @@ -29,6 +30,8 @@ keys ev subkeys $ \ev -> case keyEvent_codepoint ev of 'k' -> do liftIO (putStrLn "k was pressed after j!") + self <- getSelfPtr + liftIO $ foreign_warpCursor (unwrapSelf self) 0 0 return True _ -> return False _ -> return False diff --git a/plug/src/Montis/Base/Foreign/Runtime.hs b/plug/src/Montis/Base/Foreign/Runtime.hs index 65ae53f..427545a 100644 --- a/plug/src/Montis/Base/Foreign/Runtime.hs +++ b/plug/src/Montis/Base/Foreign/Runtime.hs @@ -23,5 +23,15 @@ foreign import ccall "montis_plugin_get_toplevel_position" foreign import ccall "montis_plugin_set_toplevel_position" foreign_setToplevelPosition :: Ptr ForeignMontisToplevel -> CDouble -> CDouble -> IO () +foreign import ccall "montis_plugin_get_toplevel_geometry" + foreign_getToplevelGeometry :: + Ptr ForeignMontisToplevel -> Ptr CDouble -> Ptr CDouble -> Ptr CDouble -> Ptr CDouble -> IO () + +foreign import ccall "montis_plugin_set_toplevel_geometry" + foreign_setToplevelGeometry :: Ptr ForeignMontisToplevel -> CDouble -> CDouble -> CDouble -> CDouble -> IO () + foreign import ccall "montis_plugin_focus_toplevel" foreign_focusToplevel :: Ptr ForeignMontisToplevel -> IO () + +foreign import ccall "montis_plugin_warp_cursor" + foreign_warpCursor :: Ptr Void -> CDouble -> CDouble -> IO () diff --git a/plug/src/Montis/Standard/Drag.hs b/plug/src/Montis/Standard/Drag.hs index 192ade8..720398d 100644 --- a/plug/src/Montis/Standard/Drag.hs +++ b/plug/src/Montis/Standard/Drag.hs @@ -46,7 +46,23 @@ data DragState = DragState } deriving (Typeable) -newtype Dragging = Dragging (Maybe DragState) +data ResizeState = ResizeState + { resizeToplevel :: Ptr ForeignMontisToplevel, + resizeStartX :: Double, + resizeStartY :: Double, + resizeStartW :: Double, + resizeStartH :: Double, + resizeStartCursorX :: Double, + resizeStartCursorY :: Double + } + deriving (Typeable) + +data DragAction + = DragMove DragState + | DragResize ResizeState + deriving (Typeable) + +newtype Dragging = Dragging (Maybe DragAction) deriving (Typeable) instance StateExtension Dragging where @@ -57,24 +73,45 @@ instance StateExtension Dragging where leftButton :: Word32 leftButton = 272 -- BTN_LEFT +rightButton :: Word32 +rightButton = 273 -- BTN_RIGHT + onButton :: Word32 -> ButtonEvent -> Montis () onButton modMask ev - | buttonEvent_button ev /= leftButton = return () + | buttonEvent_button ev /= leftButton && buttonEvent_button ev /= rightButton = return () | buttonEvent_state ev == ButtonPressed = do if buttonEvent_modifiers ev .&. modMask == 0 then return () else do self <- getSelfPtr CursorPosition (x, y) <- xStateGet - newDrag <- liftIO $ do + (newDrag, warpState) <- liftIO $ do tl <- foreign_toplevelAt (unwrapSelf self) (realToFrac x) (realToFrac y) if tl == nullPtr - then return (Dragging Nothing) + then return (Dragging Nothing, Nothing) else do - (tx, ty) <- getToplevelPosition tl - return $ - Dragging - (Just (DragState tl (x - tx) (y - ty))) + (tx, ty, tw, th) <- getToplevelGeometry tl + if buttonEvent_button ev == rightButton + then do + let warpX = tx + tw + warpY = ty + th + foreign_warpCursor (unwrapSelf self) (realToFrac warpX) (realToFrac warpY) + return + ( Dragging + ( Just + ( DragResize + (ResizeState tl tx ty tw th warpX warpY) + ) + ), + Just (CursorPosition (warpX, warpY)) + ) + else + return + ( Dragging + (Just (DragMove (DragState tl (x - tx) (y - ty)))), + Nothing + ) + mapM_ xStatePut warpState xStatePut newDrag | buttonEvent_state ev == ButtonReleased = xStatePut (Dragging Nothing) @@ -87,20 +124,37 @@ onMotion ev = do Dragging mdrag <- xStateGet case mdrag of Nothing -> return () - Just (DragState tl dx dy) -> do + Just (DragMove (DragState tl dx dy)) -> do liftIO $ foreign_setToplevelPosition tl (realToFrac (x - dx)) (realToFrac (y - dy)) + Just (DragResize rs) -> do + let newW = max 1 (resizeStartW rs + (x - resizeStartCursorX rs)) + newH = max 1 (resizeStartH rs + (y - resizeStartCursorY rs)) + liftIO $ + foreign_setToplevelGeometry + (resizeToplevel rs) + (realToFrac (resizeStartX rs)) + (realToFrac (resizeStartY rs)) + (realToFrac newW) + (realToFrac newH) unwrapSelf :: SelfPtr -> Ptr Void unwrapSelf (SelfPtr p) = p -getToplevelPosition :: Ptr ForeignMontisToplevel -> IO (Double, Double) -getToplevelPosition tl = - alloca $ \xPtr -> alloca $ \yPtr -> do - foreign_getToplevelPosition tl xPtr yPtr +getToplevelGeometry :: Ptr ForeignMontisToplevel -> IO (Double, Double, Double, Double) +getToplevelGeometry tl = + alloca $ \xPtr -> alloca $ \yPtr -> alloca $ \wPtr -> alloca $ \hPtr -> do + foreign_getToplevelGeometry tl xPtr yPtr wPtr hPtr x <- peek xPtr y <- peek yPtr - return (realToFrac (x :: CDouble), realToFrac (y :: CDouble)) + w <- peek wPtr + h <- peek hPtr + return + ( realToFrac (x :: CDouble), + realToFrac (y :: CDouble), + realToFrac (w :: CDouble), + realToFrac (h :: CDouble) + ) diff --git a/rt/include/util.h b/rt/include/util.h index a9c290d..2ed2f70 100644 --- a/rt/include/util.h +++ b/rt/include/util.h @@ -9,6 +9,11 @@ void *montis_plugin_toplevel_at(void *ctx, double lx, double ly); void montis_plugin_get_toplevel_position(void *toplevel, double *x, double *y); void montis_plugin_set_toplevel_position(void *toplevel, double x, double y); +void montis_plugin_get_toplevel_geometry(void *toplevel, double *x, double *y, + double *w, double *h); +void montis_plugin_set_toplevel_geometry(void *toplevel, double x, double y, + double w, double h); void montis_plugin_focus_toplevel(void *toplevel); +void montis_plugin_warp_cursor(void *ctx, double lx, double ly); #endif /* MONTIS_UTIL_H */ diff --git a/rt/src/util.c b/rt/src/util.c index 66a2b20..e09cff9 100644 --- a/rt/src/util.c +++ b/rt/src/util.c @@ -63,6 +63,41 @@ void montis_plugin_set_toplevel_position(void *toplevel, double x, double y) wlr_scene_node_set_position(&tl->scene_tree->node, (int)x, (int)y); } +void montis_plugin_get_toplevel_geometry(void *toplevel, double *x, double *y, + double *w, double *h) +{ + if (!toplevel || !x || !y || !w || !h) { + return; + } + struct montis_toplevel *tl = toplevel; + struct wlr_box geo_box; + wlr_xdg_surface_get_geometry(tl->xdg_toplevel->base, &geo_box); + *x = tl->scene_tree->node.x; + *y = tl->scene_tree->node.y; + *w = geo_box.width; + *h = geo_box.height; +} + +void montis_plugin_set_toplevel_geometry(void *toplevel, double x, double y, + double w, double h) +{ + if (!toplevel) { + return; + } + struct montis_toplevel *tl = toplevel; + wlr_scene_node_set_position(&tl->scene_tree->node, (int)x, (int)y); + wlr_xdg_toplevel_set_size(tl->xdg_toplevel, (int)w, (int)h); +} + +void montis_plugin_warp_cursor(void *ctx, double lx, double ly) +{ + if (!ctx) { + return; + } + struct montis_server *server = server_from_ctx(ctx); + wlr_cursor_warp(server->cursor, NULL, lx, ly); +} + void montis_plugin_focus_toplevel(void *toplevel) { if (!toplevel) { |