diff options
Diffstat (limited to 'rt/include')
| -rw-r--r-- | rt/include/foreign_intf.h | 33 | ||||
| -rw-r--r-- | rt/include/plugin.h | 190 | ||||
| -rw-r--r-- | rt/include/plugin_types.h | 9 | ||||
| -rw-r--r-- | rt/include/wl.h | 116 |
4 files changed, 348 insertions, 0 deletions
diff --git a/rt/include/foreign_intf.h b/rt/include/foreign_intf.h new file mode 100644 index 0000000..6558fab --- /dev/null +++ b/rt/include/foreign_intf.h @@ -0,0 +1,33 @@ +/* Contains a structure, which contains functions to back-call into + * the harness code. */ + +#ifndef __FOREIGN_INTERFACE +#define __FOREIGN_INTERFACE + +#define EXPORT(a) a + +typedef void *ctx_t; + +typedef struct FOREIGN_INTERFACE { + /* DO NOT ADD ANY UNEXPORTED VARIABLES HERE */ + + /* The context, which needs to be passed to each function. This context is + * opaque to the plugin and should not be changed. */ + EXPORT(ctx_t ctx); + + /* Requests the harness hot reload the current plugin. */ + 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)); + + /* 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 + +#endif /* __FOREIGN_INTERFACE */ diff --git a/rt/include/plugin.h b/rt/include/plugin.h new file mode 100644 index 0000000..4d69d76 --- /dev/null +++ b/rt/include/plugin.h @@ -0,0 +1,190 @@ +#ifndef _PLUGIN_H_ +#define _PLUGIN_H_ + +#include <dlfcn.h> +#include <linux/limits.h> +#include <pthread.h> +#include <stdint.h> +#include <stdlib.h> +#include <wlr/types/wlr_input_device.h> +#include <wlr/types/wlr_keyboard.h> +#include <wlr/types/wlr_pointer.h> + +#include "plugin_types.h" +#include <foreign_intf.h> + +/* + * Marker macro to define what functions should be exported. This generates the + * interface which the plugin needs to implement. + */ +#define EXPORT(a) a + +#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>) +EXPORT_INCLUDE(<wlr/types/wlr_pointer.h>) +// clang-format on + +#define MAX_QUEUED_ACTIONS 8 + +typedef void *dlhandle_t; + +/* Opaque state for a plugin. Not to be touched by the harness (not that it + * really can be.) */ + +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); + union { + void *ptr_arg; + int int_arg; + char *str_arg; + }; +} requested_action_t; + +/* + * Structure for the plugin. + */ +typedef struct PLUGIN { + /* The argc this plugin is loaded with. Typically the argc from main(). */ + int argc; + + /* The argv this plugin is loaded with. Typically the argv from main(). */ + char **argv; + + /* Filename the plugin is loaded from. */ + char filename[PATH_MAX]; + + /* Interface to the harness that this plugin can use. */ + foreign_interface_t foreign_intf; + + /* Opaque state of this plugin. The state is usually some kind of pointer to + * the plugin state, but all the harness knows is the opaque state is a + * pointer-sized piece of data. + * + * This opaque state is used in a linear pattern where the handlers take the + * opaque state, maybe operate on it, and return a new opaque state, which is + * then passed to the next handler, etc. It is on the plugin to properly + * manager the memory for this state and to destroy it upon teardown. + * + * It's guaranteed that this state is used linearly, meaning the harness gives + * up all ownership to it once passed into a handler. */ + opqst_t state; + + /* This plugin's lock. This avoids potential issues with multiple threads + * trying to change the opaque state at once which can lead to undesireable + * outcomes. */ + pthread_mutex_t lock; + + /** Set to not-zero if this plugin is initialized, otherwise set to zero. */ + int initialized; + + /* The handle to the shared library. */ + dlhandle_t library_handle; + + /* Pointer to the plugin name. This is in the shared library and a + * null-terminated string. If the library does not have a plugin name, this + * will be NULL. */ + const char *plugin_name; + + /** + * Initializes the plugin on the first time, and only the first time, it is + * loaded. This is used to do things like setup a runtime that cannot be + * 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)); + + /** 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)); + + /* Start the plugin with the marshalled state from the previous plugin. + * + * This should return the opaque state from the mashalled_state. + * + * This function should not fail if the state cannot be demarshalled, rather a + * default state should be returned. This is because changing the plugin and + * hot-reloading can produce incompatibilities between the old state and the + * new state, and this should not cause a failure. + */ + EXPORT(opqst_t (*plugin_hot_start)(uint8_t *mashalled_state, uint32_t n)); + + /* + * Starts the plugin without a marshalled state. Happens during the first boot + * when there is not state. + */ + EXPORT(opqst_t (*plugin_cold_start)()); + + /* + * Marshals the state to a bytestring. The returned pointer should be malloc'd + * on the heap. The harness takes ownership of the malloc'd pointer. + * + * This is usually called in preparation for a teardown followed by a + * hot-start. + */ + EXPORT(uint8_t *(*plugin_marshal_state)(opqst_t st, uint32_t *szout)); + + /* + * Teardown the plugin in preperation for the library's imminent unloading. + */ + EXPORT(void (*plugin_teardown)(opqst_t)); + + /* + * Handles a keybinding. + */ + EXPORT(opqst_t (*plugin_handle_keybinding)( + struct wlr_keyboard *keyboard, struct wlr_keyboard_key_event *event, + uint32_t modifiers, uint32_t keysym, uint32_t codepoint, int *out_handled, + opqst_t state)); + + EXPORT(opqst_t (*plugin_handle_button)(struct wlr_pointer_button_event *event, + uint32_t modifiers, opqst_t state)); + + /* + * Handles a surface being mapped, unmapped or destroyed. + */ + EXPORT(opqst_t (*plugin_handle_surface)(void *surface, surface_event_t event, + opqst_t)); + + /* List of requested actions by the plugin. Right now there is a maximum of 8 + * allowed at one time. That should be plenty. The actions should be flushed + * after each call to a handler anyway. */ + size_t n_requested_actions; + requested_action_t requested_actions[MAX_QUEUED_ACTIONS]; +} plugin_t; + +#undef EXPORT +#undef EXPORT_INCLUDE + +/* Reloads the plugin. This tears down the existing plugin, marshals the state + * for it and reloads it. + * + * This function will call dlclose on the plugin's library handle. + */ +int plugin_hot_reload(int argc, char **argv, const char *filepath, + plugin_t *plugin); + +/* + * Like hot-reload, but uses the same parameters the plugin was originally + * loaded with. + */ +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); + +/* Reads a plugin from a filename. */ +int load_plugin_from_file(int argc, char **argv, const char *filename, + plugin_t *plugin); + +void plugin_run_requested_actions(plugin_t *plugin); + +#endif /* _PLUGIN_H_ */ diff --git a/rt/include/plugin_types.h b/rt/include/plugin_types.h new file mode 100644 index 0000000..df1eab5 --- /dev/null +++ b/rt/include/plugin_types.h @@ -0,0 +1,9 @@ +#pragma once + +typedef void *opqst_t; + +typedef enum { + SURFACE_MAP = 0, + SURFACE_UNMAP, + SURFACE_DELETE, +} surface_event_t; diff --git a/rt/include/wl.h b/rt/include/wl.h new file mode 100644 index 0000000..dc7fe9f --- /dev/null +++ b/rt/include/wl.h @@ -0,0 +1,116 @@ +#pragma once + +#include <assert.h> +#include <getopt.h> +#include <stdbool.h> +#include <unistd.h> +#include <wayland-server-core.h> +#include <wlr/backend.h> +#include <wlr/backend/session.h> +#include <wlr/render/allocator.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_output.h> +#include <wlr/types/wlr_output_layout.h> +#include <wlr/types/wlr_pointer.h> +#include <wlr/types/wlr_scene.h> +#include <wlr/types/wlr_seat.h> +#include <wlr/types/wlr_subcompositor.h> +#include <wlr/types/wlr_xcursor_manager.h> +#include <wlr/types/wlr_xdg_shell.h> +#include <wlr/util/log.h> +#include <xkbcommon/xkbcommon.h> + +#include <plugin.h> + +/* For brevity's sake, struct members are annotated where they are used. */ +enum montis_cursor_mode { + TINYWL_CURSOR_PASSTHROUGH, + TINYWL_CURSOR_MOVE, + TINYWL_CURSOR_RESIZE, +}; + +struct montis_server { + struct wl_display *wl_display; + struct wlr_backend *backend; + struct wlr_renderer *renderer; + struct wlr_allocator *allocator; + struct wlr_scene *scene; + struct wlr_scene_output_layout *scene_layout; + + struct wlr_xdg_shell *xdg_shell; + struct wl_listener new_xdg_toplevel; + struct wl_listener new_xdg_popup; + struct wl_list toplevels; + + 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 montis_cursor_mode cursor_mode; + struct montis_toplevel *grabbed_toplevel; + 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; + + struct wlr_session *session; + plugin_t plugin; +}; + +struct montis_output { + struct wl_list link; + struct montis_server *server; + struct wlr_output *wlr_output; + struct wl_listener frame; + struct wl_listener request_state; + struct wl_listener destroy; +}; + +struct montis_toplevel { + struct wl_list link; + struct montis_server *server; + struct wlr_xdg_toplevel *xdg_toplevel; + struct wlr_scene_tree *scene_tree; + struct wl_listener map; + struct wl_listener unmap; + struct wl_listener destroy; + struct wl_listener commit; + struct wl_listener request_move; + struct wl_listener request_resize; + struct wl_listener request_maximize; + struct wl_listener request_fullscreen; +}; + +struct montis_keyboard { + struct wl_list link; + struct montis_server *server; + struct wlr_keyboard *wlr_keyboard; + + struct wl_listener modifiers; + struct wl_listener key; + struct wl_listener destroy; +}; + +struct montis_popup { + struct wlr_xdg_popup *xdg_popup; + struct wl_listener commit; + struct wl_listener destroy; +}; + |