diff options
-rw-r--r-- | harness/include/foreign_intf.h | 5 | ||||
-rw-r--r-- | harness/include/plugin.h | 7 | ||||
-rw-r--r-- | harness/src/plugin.c | 7 | ||||
-rw-r--r-- | harness/src/wl.c | 113 | ||||
-rw-r--r-- | package.yaml | 1 | ||||
-rw-r--r-- | src/Wetterhorn/Core.hs | 39 | ||||
-rw-r--r-- | src/Wetterhorn/Core/ForeignInterface.hs | 28 | ||||
-rw-r--r-- | src/Wetterhorn/FFI.hs | 10 | ||||
-rw-r--r-- | src/harness_adapter.c | 13 |
9 files changed, 102 insertions, 121 deletions
diff --git a/harness/include/foreign_intf.h b/harness/include/foreign_intf.h index e0d178c..6558fab 100644 --- a/harness/include/foreign_intf.h +++ b/harness/include/foreign_intf.h @@ -19,10 +19,13 @@ typedef struct FOREIGN_INTERFACE { EXPORT(void (*request_hot_reload)(ctx_t ctx)); /* Requests the harness hot reload the current plugin. */ - EXPORT(void (*do_log)(ctx_t ctx, const char* str)); + EXPORT(void (*do_log)(ctx_t ctx, const char *str)); /* Requestes that the whole system exit. Exits with the given return code. */ EXPORT(void (*request_exit)(ctx_t ctx, int rc)); + + /* Returns the seat associated with the server. */ + EXPORT(void *(*get_seat)(ctx_t ctx)); } foreign_interface_t; #undef EXPORT diff --git a/harness/include/plugin.h b/harness/include/plugin.h index d47abb2..46e833a 100644 --- a/harness/include/plugin.h +++ b/harness/include/plugin.h @@ -6,6 +6,7 @@ #include <pthread.h> #include <stdint.h> #include <stdlib.h> +#include <wlr/types/wlr_input_device.h> #include <wlr/types/wlr_keyboard.h> #include <foreign_intf.h> @@ -18,8 +19,11 @@ #define EXPORT_INCLUDE(a) +// clang-format off EXPORT_INCLUDE(<foreign_intf.h>) EXPORT_INCLUDE(<wlr/types/wlr_keyboard.h>) +EXPORT_INCLUDE(<wlr/types/wlr_input_device.h>) +// clang-format on #define MAX_QUEUED_ACTIONS 8 @@ -93,7 +97,7 @@ typedef struct PLUGIN { * reliably torn down. It is up to the plugin to ensure this won't interfere * with hot-reloading. */ - EXPORT(void (*plugin_metaload)(int argc, char** argv)); + EXPORT(void (*plugin_metaload)(int argc, char **argv)); /** Intializes the plugin with the given argc/argv. This is the first thing * called on the plugin and is called immediately after the library is loaded. @@ -135,6 +139,7 @@ typedef struct PLUGIN { * Handles a keybinding. */ EXPORT(opqst_t (*plugin_handle_keybinding)( + struct wlr_input_device *input_device, struct wlr_event_keyboard_key *event, uint32_t modifiers, uint32_t keysym, uint32_t codepoint, int *out_handled, opqst_t state)); diff --git a/harness/src/plugin.c b/harness/src/plugin.c index 8226db7..38dd0bf 100644 --- a/harness/src/plugin.c +++ b/harness/src/plugin.c @@ -1,5 +1,6 @@ #include "plugin.h" #include "foreign_intf.h" +#include "wl.h" #include <sys/stat.h> #include <unistd.h> @@ -106,6 +107,11 @@ void do_request_exit(void *plugv, int ec) } } +static void* plugin_get_seat(void* ctx) { + struct tinywl_server* server = wl_container_of(ctx, server, plugin); + return server->seat; +} + static int load_plugin_from_file_(int argc, char **argv, const char *filename, plugin_t *plugin) { @@ -133,6 +139,7 @@ static int load_plugin_from_file_(int argc, char **argv, const char *filename, plugin->foreign_intf.request_hot_reload = do_request_hot_reload; plugin->foreign_intf.do_log = do_request_log; plugin->foreign_intf.request_exit = do_request_exit; + plugin->foreign_intf.get_seat = plugin_get_seat; plugin->plugin_load(plugin->argc, plugin->argv, &plugin->foreign_intf); end: diff --git a/harness/src/wl.c b/harness/src/wl.c index cdc3447..bed98b4 100644 --- a/harness/src/wl.c +++ b/harness/src/wl.c @@ -1,29 +1,10 @@ #define _POSIX_C_SOURCE 200112L -#include "plugin.h" -#include <getopt.h> -#include <stdbool.h> + +#include "wl.h" + #include <stdio.h> #include <stdlib.h> #include <time.h> -#include <unistd.h> -#include <wayland-server-core.h> -#include <wlr/backend.h> -#include <wlr/render/wlr_renderer.h> -#include <wlr/types/wlr_compositor.h> -#include <wlr/types/wlr_cursor.h> -#include <wlr/types/wlr_data_device.h> -#include <wlr/types/wlr_input_device.h> -#include <wlr/types/wlr_keyboard.h> -#include <wlr/types/wlr_matrix.h> -#include <wlr/types/wlr_output.h> -#include <wlr/types/wlr_output_layout.h> -#include <wlr/types/wlr_pointer.h> -#include <wlr/types/wlr_seat.h> -#include <wlr/types/wlr_xcursor_manager.h> -#include <wlr/types/wlr_xdg_shell.h> -#include <wlr/util/log.h> -#include <wlr/xwayland.h> -#include <xkbcommon/xkbcommon.h> // This macro is responsible for calling a handler on a plugin. This macro will // acquire the plugin's lock, call the member with the arguments and update the @@ -43,77 +24,6 @@ plugin_run_requested_actions(pl__); \ } while (0) -/* For brevity's sake, struct members are annotated where they are used. */ -enum tinywl_cursor_mode { - TINYWL_CURSOR_PASSTHROUGH, - TINYWL_CURSOR_MOVE, - TINYWL_CURSOR_RESIZE, -}; - -struct tinywl_server { - struct wl_display *wl_display; - struct wlr_backend *backend; - struct wlr_renderer *renderer; - - struct wlr_xdg_shell *xdg_shell; - struct wl_listener new_xdg_surface; - struct wl_list views; - - struct wlr_cursor *cursor; - struct wlr_xcursor_manager *cursor_mgr; - struct wl_listener cursor_motion; - struct wl_listener cursor_motion_absolute; - struct wl_listener cursor_button; - struct wl_listener cursor_axis; - struct wl_listener cursor_frame; - - struct wlr_seat *seat; - struct wl_listener new_input; - struct wl_listener request_cursor; - struct wl_listener request_set_selection; - struct wl_list keyboards; - enum tinywl_cursor_mode cursor_mode; - struct tinywl_view *grabbed_view; - double grab_x, grab_y; - struct wlr_box grab_geobox; - uint32_t resize_edges; - - struct wlr_output_layout *output_layout; - struct wl_list outputs; - struct wl_listener new_output; - - plugin_t plugin; -}; - -struct tinywl_output { - struct wl_list link; - struct tinywl_server *server; - struct wlr_output *wlr_output; - struct wl_listener frame; -}; - -struct tinywl_view { - struct wl_list link; - struct tinywl_server *server; - struct wlr_xdg_surface *xdg_surface; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener destroy; - struct wl_listener request_move; - struct wl_listener request_resize; - bool mapped; - int x, y; -}; - -struct tinywl_keyboard { - struct wl_list link; - struct tinywl_server *server; - struct wlr_input_device *device; - - struct wl_listener modifiers; - struct wl_listener key; -}; - static void focus_view(struct tinywl_view *view, struct wlr_surface *surface) { /* Note: this function only deals with keyboard focus. */ @@ -194,16 +104,17 @@ static void keyboard_handle_key(struct wl_listener *listener, void *data) if (nsyms > 0) { codepoint = xkb_state_key_get_utf32(keyboard->device->keyboard->xkb_state, keycode); - plugin_call_update_state(server->plugin, plugin_handle_keybinding, event, - modifiers, syms[0], codepoint, &handled); + plugin_call_update_state(server->plugin, plugin_handle_keybinding, + keyboard->device, event, modifiers, syms[0], + codepoint, &handled); } - if (!handled) { - /* Otherwise, we pass it along to the client. */ - wlr_seat_set_keyboard(seat, keyboard->device); - wlr_seat_keyboard_notify_key(seat, event->time_msec, event->keycode, - event->state); - } + // if (!handled) { + // /* Otherwise, we pass it along to the client. */ + // wlr_seat_set_keyboard(seat, keyboard->device); + // wlr_seat_keyboard_notify_key(seat, event->time_msec, event->keycode, + // event->state); + // } } static void server_new_keyboard(struct tinywl_server *server, diff --git a/package.yaml b/package.yaml index 7a1bbc2..ebc64c1 100644 --- a/package.yaml +++ b/package.yaml @@ -47,6 +47,7 @@ ghc-options: - -XTupleSections - -XViewPatterns - -XGeneralizedNewtypeDeriving +- -XRankNTypes - -fPIC executables: diff --git a/src/Wetterhorn/Core.hs b/src/Wetterhorn/Core.hs index 2f885f9..4a48f28 100644 --- a/src/Wetterhorn/Core.hs +++ b/src/Wetterhorn/Core.hs @@ -34,6 +34,8 @@ import Numeric (showHex) import Text.Printf import Wetterhorn.Core.ForeignInterface (ForeignInterface) import qualified Wetterhorn.Core.ForeignInterface as ForeignInterface +import Wetterhorn.WlRoots (WlrInputDevice, wlrSeatKeyboardNotifyKey, wlrSeatSetKeyboard) +import Data.Char (chr, ord) data WContext = WContext { ctxForeignInterface :: ForeignInterface, @@ -79,9 +81,10 @@ data KeyEvent = KeyEvent state :: KeyState, modifiers :: Word32, keysym :: Word32, - codepoint :: Char + codepoint :: Char, + device :: Ptr WlrInputDevice } - deriving (Show, Read, Ord, Eq) + deriving (Show, Ord, Eq) data WConfig = WConfig { keybindingHandler :: KeyEvent -> W Bool, @@ -91,19 +94,41 @@ data WConfig = WConfig defaultBindings :: Map (KeyState, Word32, Word32) (W ()) defaultBindings = Map.fromList - [ ((KeyPressed, 0x8, 0x72), requestHotReload), - ((KeyPressed, 0x8, 0x6c), requestLog "This is a log statement!\n"), - ((KeyPressed, 0x8, 0x71), requestExit 0) + [ ((KeyPressed, 0x8, sym 'r'), requestHotReload), + ((KeyPressed, 0x8, sym 'l'), requestLog "This is a log statement!\n"), + ((KeyPressed, 0x8, sym 't'), wio $ ForeignInterface.doShellExec "alacritty"), + ((KeyPressed, 0x9, sym 'T'), wio $ ForeignInterface.doShellExec "gnome-terminal"), + ((KeyPressed, 0x8, sym 'c'), wio $ ForeignInterface.doShellExec "pavucontrol"), + ((KeyPressed, 0x8, sym 'q'), requestExit 0) ] + where + sym = fromIntegral . ord + defaultConfig :: WConfig defaultConfig = WConfig { keybindingHandler = \keyEvent -> do i <- incrementState + seatPtr <- (wio . ForeignInterface.getSeat . ctxForeignInterface) =<< getWContext + wio $ printf "%d - Got %s\n" i (show keyEvent) - maybe (return False) (fmap (const True)) $ - Map.lookup + maybe + ( wio $ do + wlrSeatSetKeyboard seatPtr (device keyEvent) + wlrSeatKeyboardNotifyKey + seatPtr + (timeMs keyEvent) + (keycode keyEvent) + ( case state keyEvent of + KeyReleased -> 0 + _ -> 1 + ) + + return True + ) + (fmap (const True)) + $ Map.lookup (state keyEvent, modifiers keyEvent, keysym keyEvent) defaultBindings, surfaceHandler = \state ptr -> wio (printf "Surface %s is %s\n" (showHex (ptrToIntPtr ptr) "") (show state)) diff --git a/src/Wetterhorn/Core/ForeignInterface.hs b/src/Wetterhorn/Core/ForeignInterface.hs index 14720bb..5dc1454 100644 --- a/src/Wetterhorn/Core/ForeignInterface.hs +++ b/src/Wetterhorn/Core/ForeignInterface.hs @@ -4,21 +4,25 @@ module Wetterhorn.Core.ForeignInterface ForeignDemarshal (..), runForeignDemarshal, demarshal, + doShellExec ) where import Control.Monad.State (MonadState (get, put), MonadTrans (lift), StateT, evalStateT) +import qualified Data.ByteString as BS +import qualified Data.ByteString.Char8 as BC import Data.Void (Void) -import Foreign (Ptr, Storable (peek, sizeOf), castPtr, plusPtr) -import Foreign.C (CInt (..)) +import Foreign (Ptr, Storable (peek, sizeOf), Word8, castPtr, plusPtr) +import Foreign.C (CChar, CInt (..)) import Foreign.C.String import GHC.Exts (FunPtr) +import Wetterhorn.WlRoots newtype ForeignDemarshal a = ForeignDemarshal (StateT (Ptr ()) IO a) deriving (Functor, Monad, Applicative, MonadState (Ptr ())) -runForeignDemarshal :: Ptr () -> ForeignDemarshal a -> IO a -runForeignDemarshal p (ForeignDemarshal dm) = evalStateT dm p +runForeignDemarshal :: Ptr b -> ForeignDemarshal a -> IO a +runForeignDemarshal p (ForeignDemarshal dm) = evalStateT dm (castPtr p) demarshal :: (Storable a) => ForeignDemarshal a demarshal = do @@ -29,6 +33,8 @@ demarshal = do type CtxT = Ptr Void +type ForeignCallGetPtr = CtxT -> IO (Ptr ()) + type ForeignCall = CtxT -> IO () type ForeignCallStr = CtxT -> CString -> IO () @@ -43,12 +49,20 @@ foreign import ccall "dynamic" toForeignCallStr :: FunPtr ForeignCallStr -> Fore foreign import ccall "dynamic" toForeignCallInt :: FunPtr ForeignCallInt -> ForeignCallInt +foreign import ccall "dynamic" toForeignCallGetPtr :: FunPtr ForeignCallGetPtr -> ForeignCallGetPtr + +foreign import ccall "shell_exec" shellExec :: Ptr CChar -> IO () + data ForeignInterface = ForeignInterface { requestHotReload :: IO (), requestLog :: String -> IO (), - requestExit :: Int -> IO () + requestExit :: Int -> IO (), + getSeat :: IO (Ptr WlrSeat) } +doShellExec :: String -> IO () +doShellExec str = withCString str shellExec + getForeignInterface :: IO ForeignInterface getForeignInterface = do ptr <- foreignInterfacePtr @@ -57,11 +71,13 @@ getForeignInterface = do requestHotReloadFn <- demarshal doLogFn <- demarshal doRequestExit <- demarshal + getSeatFn <- demarshal return $ ForeignInterface { requestHotReload = toForeignCall requestHotReloadFn ctx, requestLog = \str -> withCString str $ \cs -> toForeignCallStr doLogFn ctx cs, - requestExit = toForeignCallInt doRequestExit ctx . fromIntegral + requestExit = toForeignCallInt doRequestExit ctx . fromIntegral, + getSeat = castPtr <$> toForeignCallGetPtr getSeatFn ctx } diff --git a/src/Wetterhorn/FFI.hs b/src/Wetterhorn/FFI.hs index 58c1aff..4be7189 100644 --- a/src/Wetterhorn/FFI.hs +++ b/src/Wetterhorn/FFI.hs @@ -20,6 +20,7 @@ import Foreign.C (CChar, CInt (..)) import System.Posix.Types (CIno) import Wetterhorn.Core import Wetterhorn.Core.ForeignInterface +import Wetterhorn.WlRoots (WlrEventKeyboardKey, WlrInputDevice) runForeign :: (WConfig -> W ()) -> Wetterhorn -> IO Wetterhorn runForeign fn stblptr = do @@ -85,7 +86,8 @@ pluginMarshalState stblptr outlen = do foreign export ccall "plugin_handle_keybinding" pluginHandleKeybinding :: - Ptr () -> + Ptr WlrInputDevice -> + Ptr WlrEventKeyboardKey -> Word32 -> Word32 -> Word32 -> @@ -94,14 +96,15 @@ foreign export ccall "plugin_handle_keybinding" IO Wetterhorn pluginHandleKeybinding :: - Ptr () -> + Ptr WlrInputDevice -> + Ptr WlrEventKeyboardKey -> Word32 -> Word32 -> Word32 -> Ptr CInt -> Wetterhorn -> IO Wetterhorn -pluginHandleKeybinding eventPtr mods sym cp = +pluginHandleKeybinding inputDevicePtr eventPtr mods sym cp = runForeignWithReturn $ \config -> do event <- wio $ runForeignDemarshal eventPtr $ do @@ -117,6 +120,7 @@ pluginHandleKeybinding eventPtr mods sym cp = mods sym (toEnum $ fromIntegral cp) + inputDevicePtr (\b -> if b then 1 else 0) <$> keybindingHandler config event foreign export ccall "plugin_handle_surface_map" diff --git a/src/harness_adapter.c b/src/harness_adapter.c index 8663b6a..3834a2c 100644 --- a/src/harness_adapter.c +++ b/src/harness_adapter.c @@ -5,6 +5,8 @@ #include "HsFFI.h" #include "plugin_interface.h" +#include <stdio.h> +#include <stdlib.h> #include <unistd.h> const char *plugin_name = "Wetterhorn"; @@ -20,7 +22,7 @@ extern void performMajorGC(); void plugin_metaload(int argc, char** argv) { - hs_init(&argc, &argv); + // hs_init(&argc, &argv); } void plugin_load(int argc, char **argv, foreign_interface_t* fintf) { @@ -34,7 +36,7 @@ void plugin_teardown(opqst_t st) { // // Used primarily in the case where the RTS is kept alive when performing a // hot-reload. - performMajorGC(); + // performMajorGC(); hs_exit(); // There's a race condition between when this shared library is unloaded and @@ -43,6 +45,13 @@ void plugin_teardown(opqst_t st) { sleep(1); } +void shell_exec(const char* cmd) { + if (fork() == 0) { + execl("/bin/sh", "/bin/sh", "-c", cmd, NULL); + exit(1); + } +} + static const char msg[] = "Wetterhorn Plugin v 0.01\n\n" "Welcome, and thank you for your interest.\n\n" |