aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Rahm <rahm@google.com>2024-02-16 15:41:49 -0700
committerJosh Rahm <rahm@google.com>2024-02-21 12:18:46 -0700
commit22571fc455f50d1774e7abb9a77db3a51182a420 (patch)
treefbd99182c7ac48ff5dc91e9c29fae5c3da0d1dc3
parent860a75bd4dee36880c9372d1f78ced18d1246988 (diff)
downloadwetterhorn-22571fc455f50d1774e7abb9a77db3a51182a420.tar.gz
wetterhorn-22571fc455f50d1774e7abb9a77db3a51182a420.tar.bz2
wetterhorn-22571fc455f50d1774e7abb9a77db3a51182a420.zip
Do most of keyboard handling in the plugin now.
-rw-r--r--harness/include/plugin.h18
-rw-r--r--harness/src/wl.c59
-rw-r--r--harness/tools/genbuild.pl27
-rw-r--r--harness/tools/genintf.pl31
-rw-r--r--package.yaml1
-rw-r--r--src/Wetterhorn/Core.hs39
-rw-r--r--src/Wetterhorn/Core/ForeignInterface.hs3
-rw-r--r--src/Wetterhorn/FFI.hs42
8 files changed, 132 insertions, 88 deletions
diff --git a/harness/include/plugin.h b/harness/include/plugin.h
index bde8990..37e36ba 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_keyboard.h>
#include <foreign_intf.h>
@@ -18,6 +19,7 @@
#define EXPORT_INCLUDE(a)
EXPORT_INCLUDE(<foreign_intf.h>)
+EXPORT_INCLUDE(<wlr / types / wlr_keyboard.h>)
#define MAX_QUEUED_ACTIONS 8
@@ -31,12 +33,12 @@ struct PLUGIN;
/* This structure represents an action requested by the plugin for the harness.
*/
typedef struct {
- int (*action)(struct PLUGIN *requester, void* arg);
- void (*arg_dtor)(void* arg);
+ int (*action)(struct PLUGIN *requester, void *arg);
+ void (*arg_dtor)(void *arg);
union {
- void* ptr_arg;
+ void *ptr_arg;
int int_arg;
- char* str_arg;
+ char *str_arg;
};
} requested_action_t;
@@ -96,7 +98,7 @@ typedef struct PLUGIN {
/** 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.
*/
- EXPORT(void (*plugin_load)(int argc, char** argv, foreign_interface_t *intf));
+ EXPORT(void (*plugin_load)(int argc, char **argv, foreign_interface_t *intf));
/* Start the plugin with the marshalled state from the previous plugin.
*
@@ -132,7 +134,9 @@ typedef struct PLUGIN {
/*
* Handles a keybinding.
*/
- EXPORT(opqst_t (*plugin_handle_keybinding)(uint32_t keysym, opqst_t state));
+ EXPORT(opqst_t (*plugin_handle_keybinding)(
+ struct wlr_event_keyboard_key *event, uint32_t modifiers, uint32_t keysym,
+ int *out_handled, opqst_t state));
/*
* Handles a surface being mapped, unmapped or destroyed.
@@ -166,7 +170,7 @@ int plugin_hot_reload(int argc, char **argv, const char *filepath,
int plugin_hot_reload_same_state(plugin_t *plugin);
/* Starts a plugin in a cold state. Called after load_plugin_from_file. */
-void plugin_cold_start(plugin_t* plugin);
+void plugin_cold_start(plugin_t *plugin);
/* Reads a plugin from a filename. */
int load_plugin_from_file(int argc, char **argv, const char *filename,
diff --git a/harness/src/wl.c b/harness/src/wl.c
index d01797c..3f00e06 100644
--- a/harness/src/wl.c
+++ b/harness/src/wl.c
@@ -171,44 +171,6 @@ static void keyboard_handle_modifiers(struct wl_listener *listener, void *data)
&keyboard->device->keyboard->modifiers);
}
-static bool handle_keybinding(struct tinywl_server *server, xkb_keysym_t sym)
-{
- plugin_call_update_state(server->plugin, plugin_handle_keybinding, sym);
- /*
- * Here we handle compositor keybindings. This is when the compositor is
- * processing keys, rather than passing them on to the client for its own
- * processing.
- *
- * This function assumes Alt is held down.
- */
- dlhandle_t new_handle;
- switch (sym) {
- case XKB_KEY_Escape:
- wl_display_terminate(server->wl_display);
- break;
- case XKB_KEY_F5:
- plugin_hot_reload_same_state(&server->plugin);
- break;
- case XKB_KEY_F1:
- /* Cycle to the next view */
- if (wl_list_length(&server->views) < 2) {
- break;
- }
- struct tinywl_view *current_view =
- wl_container_of(server->views.next, current_view, link);
- struct tinywl_view *next_view =
- wl_container_of(current_view->link.next, next_view, link);
- focus_view(next_view, next_view->xdg_surface->surface);
- /* Move the previous view to the end of the list */
- wl_list_remove(&current_view->link);
- wl_list_insert(server->views.prev, &current_view->link);
- break;
- default:
- return false;
- }
- return true;
-}
-
static void keyboard_handle_key(struct wl_listener *listener, void *data)
{
/* This event is raised when a key is pressed or released. */
@@ -223,17 +185,13 @@ static void keyboard_handle_key(struct wl_listener *listener, void *data)
const xkb_keysym_t *syms;
int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state,
keycode, &syms);
-
- bool handled = false;
uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard);
- if ((modifiers & WLR_MODIFIER_ALT) &&
- event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
- /* If alt is held down and this button was _pressed_, we attempt to
- * process it as a compositor keybinding. */
- for (int i = 0; i < nsyms; i++) {
- handled = handle_keybinding(server, syms[i]);
- }
- }
+ /* Pass the information along to the plugin for the plugin to handle. The
+ * plugin will return via 'handled' whether or not the key event was handled
+ * or not. */
+ int handled = 0;
+ plugin_call_update_state(server->plugin, plugin_handle_keybinding, event,
+ modifiers, syms[0], &handled);
if (!handled) {
/* Otherwise, we pass it along to the client. */
@@ -1043,8 +1001,9 @@ int main(int argc, char *argv[])
setenv("DISPLAY", xwayland->display_name, 1);
}
else {
- fprintf(stderr,
- "======= failed to setup XWayland X server. Continuing without it.\n");
+ fprintf(
+ stderr,
+ "======= failed to setup XWayland X server. Continuing without it.\n");
}
/* Set the WAYLAND_DISPLAY environment variable to our socket and run the
diff --git a/harness/tools/genbuild.pl b/harness/tools/genbuild.pl
index 7020e81..1acabc0 100644
--- a/harness/tools/genbuild.pl
+++ b/harness/tools/genbuild.pl
@@ -24,15 +24,24 @@ print " plug->state = NULL;\n";
print " plug->library_handle = dl;\n";
print "\n";
while (<>) {
- if (/^\s*EXPORT\(\s*((?:\w|\s*\*\s*)+)\s*\(\*(\w+)\)\s*\((.*)\)\);/) {
- print "\n";
- print " ptr = dlsym(dl, \"$2\");\n";
- print " if (!ptr) {\n";
- print " fprintf(stderr, \"Plugin missing %s\\n\", \"$2\");\n";
- print " ret |= 1;\n";
- print " }\n";
- print " plug->$2 = ptr;\n";
- $comment="";
+ if (/^\s*EXPORT/) {
+ my $line = "$_";
+ while (not ($line =~ /;$/)) {
+ my $nextline = <STDIN>;
+ last unless defined $nextline;
+
+ $line="$line$nextline";
+ }
+ if ($line =~ /^\s*EXPORT\(\s*((?:\w|\s*\*\s*)+)\s*\(\*(\w+)\)\s*\((.*)\)\);/s) {
+ print "\n";
+ print " ptr = dlsym(dl, \"$2\");\n";
+ print " if (!ptr) {\n";
+ print " fprintf(stderr, \"Plugin missing %s\\n\", \"$2\");\n";
+ print " ret |= 1;\n";
+ print " }\n";
+ print " plug->$2 = ptr;\n";
+ $comment="";
+ }
}
}
print "\n return ret;\n";
diff --git a/harness/tools/genintf.pl b/harness/tools/genintf.pl
index 6f53951..d446d83 100644
--- a/harness/tools/genintf.pl
+++ b/harness/tools/genintf.pl
@@ -6,25 +6,38 @@ print "#ifndef _PLUG_INTF\n";
print "#define _PLUG_INTF\n";
print "\n#include <stdint.h>\n";
print "\ntypedef void* opqst_t;\n";
-while (<>) {
+
+while (<STDIN>) {
if (/^\s*\/\*/) {
$_ =~ s/^\s*//;
$comment="$_";
+ next;
}
if (/^\s*\*/) {
$_ =~ s/^\s*/ /;
$comment="$comment$_";
+ next;
}
- if (/^\s*EXPORT_INCLUDE\((.*)\)/) {
- print "#include $1\n";
- } elsif (/^\s*EXPORT\(\s*((?:\w|\s*\*\s*)+)\s*\(\*(\w+)\)\s*\((.*)\)\);/) {
- print "$comment";
- print "$1 $2($3);\n\n";
- $comment="";
- } elsif (/^\s*EXPORT\((.*)\)/) {
- print "$1\n";
+ if (/^\s*EXPORT/) {
+ my $line = "$_";
+ while (not ($line =~ /;$/)) {
+ my $nextline = <STDIN>;
+ last unless defined $nextline;
+
+ $line="$line$nextline";
+ }
+
+ if ($line =~ /^\s*EXPORT_INCLUDE\((.*)\)/s) {
+ print "#include $1\n";
+ } elsif ($line =~ /^\s*EXPORT\(\s*((?:\w|\s*\*\s*)+)\s*\(\*(\w+)\)\s*\((.*)\)\);/s) {
+ print "$comment";
+ print "$1 $2($3);\n\n";
+ $comment="";
+ } elsif ($line =~ /^\s*EXPORT\((.*)\);/s) {
+ print "$1\n";
+ }
}
}
print "#endif /* _PLUG_INTF */\n";
diff --git a/package.yaml b/package.yaml
index b559bd7..ba0b9d3 100644
--- a/package.yaml
+++ b/package.yaml
@@ -32,6 +32,7 @@ dependencies:
- base >= 4.7 && < 5
- mtl
- bytestring
+- containers
ghc-options:
- -Wall
diff --git a/src/Wetterhorn/Core.hs b/src/Wetterhorn/Core.hs
index 5a9d9e5..16978bb 100644
--- a/src/Wetterhorn/Core.hs
+++ b/src/Wetterhorn/Core.hs
@@ -16,6 +16,8 @@ module Wetterhorn.Core
defaultConfig,
requestHotReload,
ctxConfig,
+ KeyEvent (..),
+ KeyState (..),
)
where
@@ -24,7 +26,10 @@ import Control.Exception
import Control.Monad (when)
import Data.ByteString (ByteString)
import qualified Data.ByteString.Char8 as CH
-import Foreign (Ptr, StablePtr, Word32, newStablePtr, ptrToIntPtr, castForeignPtr)
+import Data.Map (Map)
+import qualified Data.Map as Map
+import Data.Maybe (fromMaybe)
+import Foreign (Ptr, StablePtr, Word32, castForeignPtr, newStablePtr, ptrToIntPtr)
import Numeric (showHex)
import Text.Printf
import Wetterhorn.Core.ForeignInterface (ForeignInterface)
@@ -66,20 +71,40 @@ data WState = WState
data SurfaceState = Map | Unmap | Destroy deriving (Eq, Ord, Show, Enum)
+data KeyState = KeyPressed | KeyReleased deriving (Show, Read, Eq, Enum, Ord)
+
+data KeyEvent = KeyEvent
+ { timeMs :: Word32,
+ keycode :: Word32,
+ state :: KeyState,
+ modifiers :: Word32,
+ keysym :: Word32
+ }
+ deriving (Show, Read, Ord, Eq)
+
data WConfig = WConfig
- { keybindingHandler :: Word32 -> W (),
+ { keybindingHandler :: KeyEvent -> W Bool,
surfaceHandler :: SurfaceState -> Ptr () -> W ()
}
+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)
+ ]
+
defaultConfig :: WConfig
defaultConfig =
WConfig
- { keybindingHandler = \sym -> do
+ { keybindingHandler = \keyEvent -> do
i <- incrementState
- wio (printf "[%d] Got key: %d\n" i sym)
- when (sym == 111) requestHotReload
- when (sym == 112) (requestLog "Hey daddy ths is a log statement.\n")
- when (sym == 0x71) (requestExit 0),
+ wio $ printf "%d - got %s\n" i (show keyEvent)
+ maybe (return False) (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 0b763b0..14720bb 100644
--- a/src/Wetterhorn/Core/ForeignInterface.hs
+++ b/src/Wetterhorn/Core/ForeignInterface.hs
@@ -1,6 +1,9 @@
module Wetterhorn.Core.ForeignInterface
( getForeignInterface,
ForeignInterface (..),
+ ForeignDemarshal (..),
+ runForeignDemarshal,
+ demarshal,
)
where
diff --git a/src/Wetterhorn/FFI.hs b/src/Wetterhorn/FFI.hs
index 3221903..969f86f 100644
--- a/src/Wetterhorn/FFI.hs
+++ b/src/Wetterhorn/FFI.hs
@@ -16,8 +16,10 @@ import Foreign
mallocBytes,
newStablePtr,
)
-import Foreign.C (CChar)
+import Foreign.C (CChar, CInt (..))
+import System.Posix.Types (CIno)
import Wetterhorn.Core
+import Wetterhorn.Core.ForeignInterface
runForeign :: (WConfig -> W ()) -> Wetterhorn -> IO Wetterhorn
runForeign fn stblptr = do
@@ -83,26 +85,54 @@ pluginMarshalState stblptr outlen = do
foreign export ccall "plugin_handle_keybinding"
pluginHandleKeybinding ::
- Word32 -> Wetterhorn -> IO Wetterhorn
-
-pluginHandleKeybinding :: Word32 -> Wetterhorn -> IO Wetterhorn
-pluginHandleKeybinding sym = runForeign (`keybindingHandler` sym)
+ Ptr () ->
+ Word32 ->
+ Word32 ->
+ Ptr CInt ->
+ Wetterhorn ->
+ IO Wetterhorn
+
+pluginHandleKeybinding ::
+ Ptr () ->
+ Word32 ->
+ Word32 ->
+ Ptr CInt ->
+ Wetterhorn ->
+ IO Wetterhorn
+pluginHandleKeybinding eventPtr mods sym =
+ runForeignWithReturn $ \config -> do
+ event <- wio $
+ runForeignDemarshal eventPtr $ do
+ tMs <- demarshal
+ kc <- demarshal
+ _ <- (demarshal :: ForeignDemarshal Word32)
+ keyState <- demarshal
+ return $
+ KeyEvent
+ tMs
+ kc
+ (if keyState == (0 :: Word8) then KeyReleased else KeyPressed)
+ mods
+ sym
+ (\b -> if b then 1 else 0) <$> keybindingHandler config event
foreign export ccall "plugin_handle_surface_map"
pluginHandleSurfaceMap ::
Ptr () -> Wetterhorn -> IO Wetterhorn
+
pluginHandleSurfaceMap :: Ptr () -> Wetterhorn -> IO Wetterhorn
pluginHandleSurfaceMap p = runForeign (\c -> surfaceHandler c Map p)
foreign export ccall "plugin_handle_surface_unmap"
pluginHandleSurfaceUnmap ::
Ptr () -> Wetterhorn -> IO Wetterhorn
+
pluginHandleSurfaceUnmap :: Ptr () -> Wetterhorn -> IO Wetterhorn
pluginHandleSurfaceUnmap p = runForeign (\c -> surfaceHandler c Unmap p)
-
foreign export ccall "plugin_handle_surface_destroy"
pluginHandleSurfaceDestroy ::
Ptr () -> Wetterhorn -> IO Wetterhorn
+
pluginHandleSurfaceDestroy :: Ptr () -> Wetterhorn -> IO Wetterhorn
pluginHandleSurfaceDestroy p = runForeign (\c -> surfaceHandler c Destroy p)