aboutsummaryrefslogtreecommitdiff
path: root/harness/src
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2024-02-11 22:55:00 -0700
committerJosh Rahm <joshuarahm@gmail.com>2024-02-11 22:55:00 -0700
commite008ac8d837ad11557c7625f3c311f230986d7f5 (patch)
treeeb199548bd6fa8cad186a301194e930cc8636bc5 /harness/src
parent2d530e35ee67126c83afb89ed7a3066b65782f57 (diff)
downloadwetterhorn-e008ac8d837ad11557c7625f3c311f230986d7f5.tar.gz
wetterhorn-e008ac8d837ad11557c7625f3c311f230986d7f5.tar.bz2
wetterhorn-e008ac8d837ad11557c7625f3c311f230986d7f5.zip
Added event handlers for map/unmap/destroy surfaces, added Alt+F5 for hot reload.
It turns out I could actually remove the metaload handler from the plugin interface. As things turn out, when fully unloading the shared object and reloading it, the Haskell runtime no longer complained. This makes things much simpler, which is great. I do wonder if I'm going to run into issues because of this, but I'll cross that bridge when it's burning.
Diffstat (limited to 'harness/src')
-rw-r--r--harness/src/main.c3
-rw-r--r--harness/src/plugin.c12
-rw-r--r--harness/src/wl.c41
3 files changed, 43 insertions, 13 deletions
diff --git a/harness/src/main.c b/harness/src/main.c
index 336cafe..995d11e 100644
--- a/harness/src/main.c
+++ b/harness/src/main.c
@@ -65,11 +65,10 @@ int main_(int argc, char **argv) {
}
plugin_t plugin;
- if (read_plugin_from_file(argv[1], &plugin)) {
+ if (load_plugin_from_file(argv[1], &plugin)) {
fprintf(stderr, "Exiting due to other failures.\n");
return 1;
}
- plugin.plugin_metaload(argc, argv);
plugin.plugin_load(argc, argv);
plugin.state = plugin.plugin_cold_start();
diff --git a/harness/src/plugin.c b/harness/src/plugin.c
index d71608a..6344f4a 100644
--- a/harness/src/plugin.c
+++ b/harness/src/plugin.c
@@ -37,7 +37,7 @@ static void shx(uint8_t *state, uint32_t sz) {
}
}
-int read_plugin_from_file(const char *filename, plugin_t *plugin) {
+int load_plugin_from_file(const char *filename, plugin_t *plugin) {
dlhandle_t lib = dlopen(filename, RTLD_LAZY);
if (!lib) {
@@ -49,7 +49,7 @@ int read_plugin_from_file(const char *filename, plugin_t *plugin) {
return load_plugin_from_dl(lib, plugin);
}
-int plugin_hot_reload(int argc, char **argv, dlhandle_t library,
+int plugin_hot_reload(int argc, char **argv, const char* filepath,
plugin_t *plugin) {
int ec = 0;
uint32_t sz = 0;
@@ -67,12 +67,10 @@ int plugin_hot_reload(int argc, char **argv, dlhandle_t library,
printf("State Marshalled:\n");
shx(marshalled_state, sz);
- if (library != plugin->library_handle) {
- printf("Unloading old library handle.\n");
- dlclose(plugin->library_handle);
- }
+ printf("Unloading old library handle.\n");
+ dlclose(plugin->library_handle);
- if ((ec = load_plugin_from_dl(library, plugin))) {
+ if ((ec = load_plugin_from_file(filepath, plugin))) {
goto fail;
}
diff --git a/harness/src/wl.c b/harness/src/wl.c
index aac2bf8..5fa1395 100644
--- a/harness/src/wl.c
+++ b/harness/src/wl.c
@@ -24,6 +24,23 @@
#include <wlr/util/log.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
+// state.
+//
+// This only works on function which have the format:
+//
+// opqst_t function(args ..., opqst_t state);
+//
+// Note that the state parameter is omitted from this macro.
+#define plugin_call_update_state(plugin, member, ...) \
+ do { \
+ plugin_t *pl__ = &(plugin); \
+ pthread_mutex_lock(&pl__->lock); \
+ pl__->state = pl__->member(__VA_ARGS__, pl__->state); \
+ pthread_mutex_unlock(&pl__->lock); \
+ } while (0)
+
/* For brevity's sake, struct members are annotated where they are used. */
enum tinywl_cursor_mode {
TINYWL_CURSOR_PASSTHROUGH,
@@ -63,6 +80,9 @@ struct tinywl_server {
struct wl_list outputs;
struct wl_listener new_output;
+ int plugin_argc;
+ char **plugin_argv;
+ const char *plugin_fpath;
plugin_t plugin;
};
@@ -152,8 +172,7 @@ static void keyboard_handle_modifiers(struct wl_listener *listener,
}
static bool handle_keybinding(struct tinywl_server *server, xkb_keysym_t sym) {
- server->plugin.state =
- server->plugin.plugin_handle_keybinding(sym, server->plugin.state);
+ 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
@@ -161,10 +180,15 @@ static bool handle_keybinding(struct tinywl_server *server, xkb_keysym_t sym) {
*
* 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(server->plugin_argc, server->plugin_argv,
+ server->plugin_fpath, &server->plugin);
+ break;
case XKB_KEY_F1:
/* Cycle to the next view */
if (wl_list_length(&server->views) < 2) {
@@ -699,6 +723,8 @@ static void server_new_output(struct wl_listener *listener, void *data) {
static void xdg_surface_map(struct wl_listener *listener, void *data) {
/* Called when the surface is mapped, or ready to display on-screen. */
struct tinywl_view *view = wl_container_of(listener, view, map);
+ plugin_call_update_state(view->server->plugin, plugin_handle_surface_map,
+ data);
view->mapped = true;
focus_view(view, view->xdg_surface->surface);
}
@@ -706,12 +732,16 @@ static void xdg_surface_map(struct wl_listener *listener, void *data) {
static void xdg_surface_unmap(struct wl_listener *listener, void *data) {
/* Called when the surface is unmapped, and should no longer be shown. */
struct tinywl_view *view = wl_container_of(listener, view, unmap);
+ plugin_call_update_state(view->server->plugin, plugin_handle_surface_unmap,
+ data);
view->mapped = false;
}
static void xdg_surface_destroy(struct wl_listener *listener, void *data) {
/* Called when the surface is destroyed and should never be shown again. */
struct tinywl_view *view = wl_container_of(listener, view, destroy);
+ plugin_call_update_state(view->server->plugin, plugin_handle_surface_destroy,
+ data);
wl_list_remove(&view->link);
free(view);
}
@@ -842,14 +872,17 @@ int main(int argc, char *argv[]) {
struct tinywl_server server;
- if (read_plugin_from_file(plugin, &server.plugin)) {
+ if (load_plugin_from_file(plugin, &server.plugin)) {
fprintf(stderr, "Failed to read plugin from file.\n");
return 1;
}
- server.plugin.plugin_metaload(argc, argv);
+ // server.plugin.plugin_metaload(argc, argv);
server.plugin.plugin_load(argc, argv);
server.plugin.state = server.plugin.plugin_cold_start();
+ server.plugin_fpath = plugin;
+ server.plugin_argv = argv;
+ server.plugin_argc = argc;
/* The Wayland display is managed by libwayland. It handles accepting
* clients from the Unix socket, manging Wayland globals, and so on. */