aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--harness/include/foreign_intf.h5
-rw-r--r--harness/include/plugin.h7
-rw-r--r--harness/src/plugin.c7
-rw-r--r--harness/src/wl.c113
-rw-r--r--package.yaml1
-rw-r--r--src/Wetterhorn/Core.hs39
-rw-r--r--src/Wetterhorn/Core/ForeignInterface.hs28
-rw-r--r--src/Wetterhorn/FFI.hs10
-rw-r--r--src/harness_adapter.c13
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"