aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2026-01-07 00:26:32 -0700
committerJosh Rahm <joshuarahm@gmail.com>2026-01-07 00:26:32 -0700
commit4847aa0b4a6f945c24e1523e729652271bbc9680 (patch)
tree9ffac8b1934153cbde6f6814277f80c337d937b1
parent37e5037b68fb35276f0c426779f61aa278d5b21b (diff)
downloadmontis-4847aa0b4a6f945c24e1523e729652271bbc9680.tar.gz
montis-4847aa0b4a6f945c24e1523e729652271bbc9680.tar.bz2
montis-4847aa0b4a6f945c24e1523e729652271bbc9680.zip
[rebrand] Arken -> Ark, Plugin -> Soul, Erebor -> Cross
-rw-r--r--CMakeLists.txt29
-rw-r--r--README.md56
-rw-r--r--ark/CMakeLists.txt (renamed from arken/CMakeLists.txt)57
-rw-r--r--ark/README.md51
-rw-r--r--ark/include/soul.h111
-rw-r--r--ark/include/soul_exports.h (renamed from arken/include/plugin_exports.h)64
-rw-r--r--ark/include/soul_interface.h23
-rw-r--r--ark/include/soul_types.h (renamed from arken/include/plugin_types.h)0
-rw-r--r--ark/include/wl.h (renamed from arken/include/wl.h)4
-rw-r--r--ark/src/soul.c198
-rw-r--r--ark/src/soul_load.c (renamed from arken/src/plugin_load.c)22
-rw-r--r--ark/src/wl.c (renamed from arken/src/wl.c)85
-rw-r--r--arken/README.md51
-rw-r--r--arken/include/plugin.h112
-rw-r--r--arken/include/plugin_interface.h23
-rw-r--r--arken/src/plugin.c199
-rw-r--r--arken/tools/genbuild.pl48
-rw-r--r--arken/tools/genintf.pl42
-rw-r--r--cross/CMakeLists.txt27
-rw-r--r--cross/README.md32
-rw-r--r--cross/include/util.h24
-rw-r--r--cross/src/runtime_requests.c69
-rw-r--r--cross/src/util.c (renamed from erebor/src/util.c)20
-rw-r--r--erebor/CMakeLists.txt25
-rw-r--r--erebor/README.md32
-rw-r--r--erebor/include/util.h24
-rw-r--r--erebor/src/runtime_requests.c69
-rw-r--r--montis/README.md18
-rw-r--r--montis/package.yaml8
-rw-r--r--montis/src/Link.hs6
-rw-r--r--montis/src/Montis/Base/Foreign/Runtime.hs16
-rw-r--r--montis/src/Montis/Core/Internal/Foreign/Export.hs50
-rw-r--r--montis/src/Montis/Core/Monad.hs6
-rw-r--r--montis/src/Montis/Core/Soul/Interface.hs (renamed from montis/src/Montis/Core/Plugin/Interface.hs)4
-rw-r--r--montis/src/Montis/Core/State.hs4
-rw-r--r--montis/src/harness_adapter.c16
36 files changed, 771 insertions, 854 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e191a24..b4921ce 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,43 +1,42 @@
cmake_minimum_required(VERSION 3.16)
project(montis LANGUAGES C)
-option(MONTIS_BUILD_BUNDLED_PLUGIN "Build the bundled Haskell plugin (montis.so)" ON)
-
-add_custom_target(wlroots_build ALL DEPENDS "${WLROOTS_LIB_LINK}")
+option(MONTIS_BUILD_BUNDLED_SOUL "Build the bundled Haskell soul (montis.so)" ON)
+if(DEFINED MONTIS_BUILD_BUNDLED_PLUGIN)
+ set(MONTIS_BUILD_BUNDLED_SOUL "${MONTIS_BUILD_BUNDLED_PLUGIN}")
+endif()
-add_subdirectory(arken)
-add_dependencies(arken wlroots_build)
+add_subdirectory(ark)
-add_subdirectory(erebor)
-add_dependencies(erebor wlroots_build)
+add_subdirectory(cross)
-if(MONTIS_BUILD_BUNDLED_PLUGIN)
+if(MONTIS_BUILD_BUNDLED_SOUL)
add_custom_target(
- plug_build ALL
+ soul_build ALL
COMMAND sh -c "if [ -d \"$1\" ] && [ ! -L \"$1\" ]; then rm -rf \"$2\"; mv \"$1\" \"$2\"; fi" sh "${CMAKE_SOURCE_DIR}/montis/.stack-work" "${CMAKE_BINARY_DIR}/stack-work"
COMMAND "${CMAKE_COMMAND}" -E make_directory "${CMAKE_BINARY_DIR}/stack-work"
COMMAND "${CMAKE_COMMAND}" -E create_symlink "${CMAKE_BINARY_DIR}/stack-work" "${CMAKE_SOURCE_DIR}/montis/.stack-work"
COMMAND "${CMAKE_COMMAND}" -E chdir "${CMAKE_SOURCE_DIR}/montis" stack build
# Not sure why stack is generating an a.out file, but remove it.
COMMAND "${CMAKE_COMMAND}" -E rm -f "${CMAKE_SOURCE_DIR}/montis/a.out"
- DEPENDS arken erebor
- COMMENT "Building Haskell plugin with Stack"
+ DEPENDS ark cross
+ COMMENT "Building bundled Haskell soul with Stack"
VERBATIM
)
add_custom_target(
run
- COMMAND sh -c "PLUGIN_SO=$(find '${CMAKE_BINARY_DIR}/stack-work' -name montis.so -type f | head -n 1); if [ -z \"$PLUGIN_SO\" ]; then echo 'montis.so not found in ${CMAKE_BINARY_DIR}/stack-work' 1>&2; exit 1; fi; \"$<TARGET_FILE:arken>\" -s foot -p \"$PLUGIN_SO\""
- DEPENDS arken plug_build
+ COMMAND sh -c "SOUL_SO=$(find '${CMAKE_BINARY_DIR}/stack-work' -name montis.so -type f | head -n 1); if [ -z \"$SOUL_SO\" ]; then echo 'montis.so not found in ${CMAKE_BINARY_DIR}/stack-work' 1>&2; exit 1; fi; \"$<TARGET_FILE:ark>\" -s foot -p \"$SOUL_SO\""
+ DEPENDS ark soul_build
USES_TERMINAL
VERBATIM
)
endif()
-install(TARGETS arken RUNTIME DESTINATION bin)
+install(TARGETS ark RUNTIME DESTINATION bin)
-if(MONTIS_BUILD_BUNDLED_PLUGIN)
+if(MONTIS_BUILD_BUNDLED_SOUL)
install(CODE [[
execute_process(
COMMAND sh -c "find '${CMAKE_BINARY_DIR}/stack-work' -name montis.so -type f | head -n 1"
diff --git a/README.md b/README.md
index 2aaaefb..c174139 100644
--- a/README.md
+++ b/README.md
@@ -17,17 +17,17 @@ management* a thing of the present ... again!
Montis is intentionally split into two components, each with a very different role.
-### Arken -- The Runtime
+### Ark -- The Runtime
-**Arken** is the small, stable executable at the heart of the system. It very
+**Ark** is the small, stable executable at the heart of the system. It very
much *is* the compositor.
* It is the compositor runtime.
* It sets up wlroots, Wayland invariants, and lifecycle management.
-* It persists ocross reload.
+* It persists across reload.
* It is deliberately lean: a harness, not an engine
-Arken exists to keep the window system alive while everything interesting
+Ark exists to keep the window system alive while everything interesting
changes around it.
### Montis -- The Window Manager
@@ -35,23 +35,23 @@ changes around it.
Montis is the window management logic, written in Haskell.
* It compiles to a shared object (.so)
-* It is loaded into Arken at runtime
+* It is loaded into Ark at runtime
* It can be edited, recompiled, and hot-reloaded on the fly
* No compositor restart required
Montis is not a DSL and not a configuration file. It is the window manager.
-Written in a Turing-complete programming language with full access to the Arken
+Written in a Turing-complete programming language with full access to the Ark
runtime and wlroots itself.
-#### Erebor -- Native Bridge Library
+#### Cross -- Native Bridge Library
-**Erebor** (`liberebor.a`) is a static C library that contains the native
-functions Montis uses to interact with Arken/wlroots. It is linked into the
-`montis.so` plugin so these FFI bindings hot-reload along with the Haskell code
+**Cross** (`libcross.a`) is a static C library that contains the native
+functions Montis uses to interact with Ark/wlroots. It is linked into the
+`montis.so` soul so these FFI bindings hot-reload along with the Haskell code
instead of living inside the long-running compositor process.
-Code lives in `erebor/src` and headers in `erebor/include` (notably
-`erebor/include/util.h`).
+Code lives in `cross/src` and headers in `cross/include` (notably
+`cross/include/util.h`).
### Why This is Powerful
@@ -95,7 +95,7 @@ The constraints are strict:
The solution is a pluggable architecture:
-* A persistent runtime (Arken) that owns wlroots and the Wayland lifecycle
+* A persistent runtime (Ark) that owns wlroots and the Wayland lifecycle
* A hot-reloadable window manager (Montis) that owns behavior
## Building
@@ -109,24 +109,24 @@ The solution is a pluggable architecture:
- `meson` (wlroots is built via Meson) and a backend like `ninja`
- `wayland-scanner` and `wayland-protocols`
- `curl` (first build downloads wlroots)
-- Optional (only for the bundled plugin): Haskell toolchain via Stack: `stack` (+ GHC)
+- Optional (only for the bundled soul): Haskell toolchain via Stack: `stack` (+ GHC)
### Build
This repo uses CMake to build:
-- `arken` (the compositor runtime)
-- `erebor` (`liberebor.a`)
-- the Haskell plugin (`montis.so`) via Stack
+- `ark` (the compositor runtime)
+- `cross` (`libcross.a`)
+- the bundled Haskell soul (`montis.so`) via Stack
```sh
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build
```
-To build only the runtime + bridge library (no bundled plugin):
+To build only the runtime + bridge library (no bundled soul):
```sh
-cmake -S . -B build -DMONTIS_BUILD_BUNDLED_PLUGIN=OFF
+cmake -S . -B build -DMONTIS_BUILD_BUNDLED_SOUL=OFF
cmake --build build
```
@@ -136,21 +136,21 @@ To run via the CMake helper target:
cmake --build build --target run
```
-Note: the `run` target currently starts `arken` with `-s foot`, so you’ll want
+Note: the `run` target currently starts `ark` with `-s foot`, so you’ll want
`foot` installed (or adjust the target in `CMakeLists.txt`).
-### Using Your Own Plugin
+### Using Your Own Soul
-If you disable the bundled plugin (`-DMONTIS_BUILD_BUNDLED_PLUGIN=OFF`), you can
-build and supply your own plugin `.so` at runtime.
+If you disable the bundled soul (`-DMONTIS_BUILD_BUNDLED_SOUL=OFF`), you can
+build and supply your own soul `.so` at runtime.
-- Plugin ABI: `arken/include/plugin.h` (plugin header: `arken/include/plugin_interface.h`)
-- Optional bridge helpers: `erebor/include` + `build/erebor/liberebor.a`
+- Soul ABI: `ark/include/soul.h` (soul header: `ark/include/soul_interface.h`)
+- Optional bridge helpers: `cross/include` + `build/cross/libcross.a`
Runtime invocation looks like:
```sh
-./build/arken/arken -p /path/to/your_plugin.so
+./build/ark/ark -p /path/to/your_soul.so
```
## Installing
@@ -160,5 +160,5 @@ cmake --install build --prefix ~/.local
```
This installs:
-- `arken` to `~/.local/bin`
-- if `-DMONTIS_BUILD_BUNDLED_PLUGIN=ON`, the latest built plugin `.so` to `~/.local/lib`
+- `ark` to `~/.local/bin`
+- if `-DMONTIS_BUILD_BUNDLED_SOUL=ON`, the latest built soul `.so` to `~/.local/lib`
diff --git a/arken/CMakeLists.txt b/ark/CMakeLists.txt
index 9219879..35e47a9 100644
--- a/arken/CMakeLists.txt
+++ b/ark/CMakeLists.txt
@@ -1,31 +1,34 @@
cmake_minimum_required(VERSION 3.10)
project (
- arken
+ ark
VERSION 0.1
LANGUAGES C)
set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_BUILD_TYPE Debug)
-set(WLROOTS_VERSION "0.18")
-set(WLROOTS_URL "https://gitlab.freedesktop.org/wlroots/wlroots/-/archive/${WLROOTS_VERSION}/wlroots-${WLROOTS_VERSION}.tar.gz")
-set(WLROOTS_TARBALL "${CMAKE_BINARY_DIR}/wlroots-${WLROOTS_VERSION}.tar.gz")
-set(WLROOTS_SOURCE_DIR "${CMAKE_BINARY_DIR}/wlroots-src")
-set(WLROOTS_BUILD_DIR "${CMAKE_BINARY_DIR}/wlroots")
-set(WLROOTS_LIB_STATIC "${WLROOTS_BUILD_DIR}/libwlroots-${WLROOTS_VERSION}.a")
-set(WLROOTS_LIB_LINK "${WLROOTS_BUILD_DIR}/libwlroots.a")
-
-add_custom_command(
- OUTPUT "${WLROOTS_LIB_LINK}"
- COMMAND sh -c "if [ ! -d \"$1\" ]; then mkdir -p \"$1\" && curl -L \"$2\" | tar xzf - --strip-components=1 -C \"$1\"; fi" sh "${WLROOTS_SOURCE_DIR}" "${WLROOTS_URL}"
- COMMAND "${CMAKE_COMMAND}" -E make_directory "${WLROOTS_BUILD_DIR}"
- COMMAND meson setup --reconfigure -Ddefault_library=static "${WLROOTS_BUILD_DIR}" "${WLROOTS_SOURCE_DIR}"
- COMMAND meson compile -C "${WLROOTS_BUILD_DIR}"
- COMMAND "${CMAKE_COMMAND}" -E create_symlink "${WLROOTS_LIB_STATIC}" "${WLROOTS_LIB_LINK}"
- WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
- COMMENT "Building wlroots via Meson (static)"
- VERBATIM
-)
+if(NOT TARGET wlroots_build)
+ set(WLROOTS_VERSION "0.18")
+ set(WLROOTS_URL "https://gitlab.freedesktop.org/wlroots/wlroots/-/archive/${WLROOTS_VERSION}/wlroots-${WLROOTS_VERSION}.tar.gz")
+ set(WLROOTS_SOURCE_DIR "${CMAKE_BINARY_DIR}/wlroots-src")
+ set(WLROOTS_BUILD_DIR "${CMAKE_BINARY_DIR}/wlroots")
+ set(WLROOTS_LIB_STATIC "${WLROOTS_BUILD_DIR}/libwlroots-${WLROOTS_VERSION}.a")
+ set(WLROOTS_LIB_LINK "${WLROOTS_BUILD_DIR}/libwlroots.a")
+
+ add_custom_command(
+ OUTPUT "${WLROOTS_LIB_LINK}"
+ COMMAND sh -c "if [ ! -d \"$1\" ]; then mkdir -p \"$1\" && curl -L \"$2\" | tar xzf - --strip-components=1 -C \"$1\"; fi" sh "${WLROOTS_SOURCE_DIR}" "${WLROOTS_URL}"
+ COMMAND "${CMAKE_COMMAND}" -E make_directory "${WLROOTS_BUILD_DIR}"
+ COMMAND meson setup --reconfigure -Ddefault_library=static "${WLROOTS_BUILD_DIR}" "${WLROOTS_SOURCE_DIR}"
+ COMMAND meson compile -C "${WLROOTS_BUILD_DIR}"
+ COMMAND "${CMAKE_COMMAND}" -E create_symlink "${WLROOTS_LIB_STATIC}" "${WLROOTS_LIB_LINK}"
+ WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
+ COMMENT "Building wlroots via Meson (static)"
+ VERBATIM
+ )
+
+ add_custom_target(wlroots_build ALL DEPENDS "${WLROOTS_LIB_LINK}")
+endif()
include_directories(include/ /usr/include/pixman-1
${CMAKE_CURRENT_BINARY_DIR}/
@@ -77,9 +80,6 @@ file (GLOB_RECURSE SOURCES src/*.c)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
-add_executable (arken ${SOURCES} ${WLROOTS_LIB_LINK}
- xdg-shell-protocol.c)
-
find_package(PkgConfig REQUIRED)
pkg_check_modules(WLREQ REQUIRED IMPORTED_TARGET
@@ -98,7 +98,10 @@ pkg_check_modules(WLREQ REQUIRED IMPORTED_TARGET
glesv2
)
-target_link_libraries(arken PRIVATE PkgConfig::WLREQ dl pthread ${WLROOTS_LIB_LINK})
+add_executable (ark ${SOURCES} ${WLROOTS_LIB_LINK}
+ xdg-shell-protocol.c)
+
+target_link_libraries(ark PRIVATE PkgConfig::WLREQ dl pthread ${WLROOTS_LIB_LINK})
pkg_check_modules(WLOPT IMPORTED_TARGET
cairo
@@ -123,9 +126,9 @@ pkg_check_modules(WLOPT IMPORTED_TARGET
)
if(WLOPT_FOUND)
- target_link_libraries(arken PRIVATE PkgConfig::WLOPT)
+ target_link_libraries(ark PRIVATE PkgConfig::WLOPT)
endif()
-target_link_directories(arken PUBLIC
+target_link_directories(ark PUBLIC
"${WLROOTS_BUILD_DIR}")
-target_link_options(arken PRIVATE -rdynamic)
+target_link_options(ark PRIVATE -rdynamic)
diff --git a/ark/README.md b/ark/README.md
new file mode 100644
index 0000000..d773e0d
--- /dev/null
+++ b/ark/README.md
@@ -0,0 +1,51 @@
+Ark (Runtime)
+=============
+
+Ark is a long-running Wayland compositor runtime with a hot-reloadable soul
+interface.
+
+Responsibilities
+----------------
+
+- Owns the Wayland display lifecycle and wlroots setup.
+- Loads a soul shared object (`.so`) at runtime and routes input/surface events to it.
+- Supports hot-reloading the soul without restarting the compositor.
+
+Soul interface
+--------------
+
+The runtime defines a C ABI that souls must implement (load/start/teardown,
+event handlers, and optional state marshal/unmarshal for hot reload). The ABI is
+defined in:
+
+- `ark/include/soul.h`
+
+Souls should include:
+
+- `ark/include/soul_interface.h`
+
+Key files
+---------
+
+- `ark/src/wl.c`: compositor setup + event loop + soul callbacks.
+- `ark/src/soul.c`: dynamic loading, lifecycle, and hot-reload logic.
+- `ark/include/soul.h`: C ABI the soul must implement.
+
+Building
+--------
+
+Ark is built via the top-level CMake project:
+
+```sh
+cmake -S .. -B ../build
+cmake --build ../build --target ark
+```
+
+Running
+-------
+
+Use the top-level `run` target (builds the bundled soul and launches Ark):
+
+```sh
+cmake --build ../build --target run
+```
diff --git a/ark/include/soul.h b/ark/include/soul.h
new file mode 100644
index 0000000..fa3415b
--- /dev/null
+++ b/ark/include/soul.h
@@ -0,0 +1,111 @@
+#ifndef _SOUL_H_
+#define _SOUL_H_
+
+#include <dlfcn.h>
+#include <linux/limits.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <wlr/types/wlr_input_device.h>
+#include <wlr/types/wlr_keyboard.h>
+#include <wlr/types/wlr_pointer.h>
+
+#include "soul_types.h"
+#include "soul_exports.h"
+
+#define MAX_QUEUED_ACTIONS 8
+
+typedef void *dlhandle_t;
+
+/* Opaque state for a soul. Not to be touched by the harness (not that it
+ * really can be.) */
+
+struct SOUL;
+/* This structure represents an action requested by the soul for the harness.
+ */
+typedef struct {
+ int (*action)(struct SOUL *requester, void *arg);
+ void (*arg_dtor)(void *arg);
+ union {
+ void *ptr_arg;
+ int int_arg;
+ char *str_arg;
+ };
+} requested_action_t;
+
+/*
+ * Structure for the soul.
+ */
+typedef struct SOUL {
+ /* The argc this soul is loaded with. Typically the argc from main(). */
+ int argc;
+
+ /* The argv this soul is loaded with. Typically the argv from main(). */
+ char **argv;
+
+ /* Filename the soul is loaded from. */
+ char filename[PATH_MAX];
+
+ /* Opaque state of this soul. The state is usually some kind of pointer to
+ * the soul 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 soul 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 soul'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 soul is initialized, otherwise set to zero. */
+ int initialized;
+
+ /* The handle to the shared library. */
+ dlhandle_t library_handle;
+
+ /* Pointer to the soul name. This is in the shared library and a
+ * null-terminated string. If the library does not have a soul name, this
+ * will be NULL. */
+ const char *soul_name;
+
+ /* Soul function table populated by the runtime loader. */
+#define SOUL_FN_PTR(ret, name, args) ret (*name) args;
+ ARKSOUL_EXPORTS(SOUL_FN_PTR)
+#undef SOUL_FN_PTR
+
+ /* List of requested actions by the soul. 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];
+} soul_t;
+
+/* Reloads the soul. This tears down the existing soul, marshals the state
+ * for it and reloads it.
+ *
+ * This function will call dlclose on the soul's library handle.
+ */
+int soul_hot_reload(int argc, char **argv, const char *filepath, soul_t *soul);
+
+/*
+ * Like hot-reload, but uses the same parameters the soul was originally
+ * loaded with.
+ */
+int soul_hot_reload_same_state(soul_t *soul);
+
+/* Starts a soul in a cold state. Called after load_soul_from_file. */
+void soul_cold_start(soul_t *soul);
+
+/* Reads a soul from a filename. */
+int load_soul_from_file(int argc, char **argv, const char *filename,
+ soul_t *soul);
+
+void soul_run_requested_actions(soul_t *soul);
+
+#endif /* _SOUL_H_ */
diff --git a/arken/include/plugin_exports.h b/ark/include/soul_exports.h
index 4518d92..8e22b15 100644
--- a/arken/include/plugin_exports.h
+++ b/ark/include/soul_exports.h
@@ -1,42 +1,42 @@
#pragma once
/*
- * Single source of truth for the plugin ABI.
+ * Single source of truth for the soul ABI.
*
* Consumers must define an X-macro like:
* #define X(ret, name, args) ...
* and then invoke:
- * MONTIS_PLUGIN_EXPORTS(X)
+ * ARKSOUL_EXPORTS(X)
*
* Note: this file intentionally does not include headers. Include whatever you
- * need (e.g. <stdint.h>, plugin_types.h, wlroots headers) before expanding.
+ * need (e.g. <stdint.h>, soul_types.h, wlroots headers) before expanding.
*/
-#define MONTIS_PLUGIN_EXPORTS(X) \
+#define ARKSOUL_EXPORTS(X) \
/* \
- * `plugin_metaload` \
+ * `arksoul_export_metaload` \
* \
- * Called at most once per process *per `plugin_name`*. This is the place \
+ * Called at most once per process *per `soul_name`*. This is the place \
* for truly global initialization that should survive hot reloads (e.g. \
* one-time language runtime init, registering global hooks, etc.). \
* \
* Notes: \
* - May be a no-op. \
- * - Must be safe to call before any other plugin entrypoint. \
+ * - Must be safe to call before any other soul entrypoint. \
*/ \
- X(void, plugin_metaload, (int argc, char **argv)) \
+ X(void, arksoul_export_metaload, (int argc, char **argv)) \
/* \
- * `plugin_load` \
+ * `arksoul_export_load` \
* \
* Called every time the shared object is loaded (cold start and each hot \
* reload). Use this for per-load initialization that must be re-done after \
* `dlopen`. \
*/ \
- X(void, plugin_load, (int argc, char **argv)) \
+ X(void, arksoul_export_load, (int argc, char **argv)) \
/* \
- * `plugin_hot_start` \
+ * `arksoul_export_rebirth` \
* \
- * Called after a hot reload with the previous plugin's marshalled state. \
+ * Called after a hot reload with the previous soul's preserved state. \
* Must return the new live opaque state (`opqst_t`) to be used for future \
* handler calls. \
* \
@@ -45,56 +45,56 @@
* - `self` is an opaque pointer owned by the runtime; treat it as \
* read-only. \
*/ \
- X(opqst_t, plugin_hot_start, \
+ X(opqst_t, arksoul_export_rebirth, \
(void *self, uint8_t *marshalled_state, uint32_t n)) \
/* \
- * `plugin_cold_start` \
+ * `arksoul_export_ensoul` \
* \
* Called on first boot when no previous state exists. Must construct and \
* return an initial opaque state. \
*/ \
- X(opqst_t, plugin_cold_start, (void *self)) \
+ X(opqst_t, arksoul_export_ensoul, (void *self)) \
/* \
- * `plugin_marshal_state` \
+ * `arksoul_export_preserve` \
* \
- * Called before unloading the current plugin during hot reload. Must \
+ * Called before unloading the current soul during hot reload. Must \
* serialize the provided opaque state into a newly allocated byte buffer. \
* \
* Ownership: \
* - Return a heap-allocated buffer (e.g. `malloc`). \
* - The runtime takes ownership and will `free()` it after \
- * `plugin_hot_start`. \
+ * `arksoul_export_rebirth`. \
*/ \
- X(uint8_t *, plugin_marshal_state, (opqst_t st, uint32_t *szout)) \
+ X(uint8_t *, arksoul_export_preserve, (opqst_t st, uint32_t *szout)) \
/* \
- * `plugin_teardown` \
+ * `arksoul_export_release` \
* \
* Called immediately before the shared object is unloaded. Use this to \
* release resources owned by the opaque state (and any per-load resources \
- * created in `plugin_load`). \
+ * created in `arksoul_export_load`). \
*/ \
- X(void, plugin_teardown, (opqst_t st)) \
+ X(void, arksoul_export_release, (opqst_t st)) \
/* \
- * `plugin_handle_keybinding` \
+ * `arksoul_export_handle_keybinding` \
* \
* Called for keyboard events. Returns the updated opaque state. Set \
* `*out_handled` to non-zero if the event is consumed. \
*/ \
- X(opqst_t, plugin_handle_keybinding, \
+ X(opqst_t, arksoul_export_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)) \
/* \
- * `plugin_handle_button` \
+ * `arksoul_export_handle_button` \
* \
* Called for pointer button events (mouse/trackpad clicks). Returns the \
* updated opaque state. \
*/ \
- X(opqst_t, plugin_handle_button, \
+ X(opqst_t, arksoul_export_handle_button, \
(struct wlr_pointer_button_event * event, uint32_t modifiers, \
opqst_t state)) \
/* \
- * `plugin_handle_motion` \
+ * `arksoul_export_handle_motion` \
* \
* Called for pointer motion. Returns the updated opaque state. \
* \
@@ -103,15 +103,15 @@
* (type depends on `is_absolute`). \
* - `lx`/`ly` are layout coordinates in compositor space. \
*/ \
- X(opqst_t, plugin_handle_motion, \
+ X(opqst_t, arksoul_export_handle_motion, \
(void *event, uint32_t modifiers, uint32_t is_absolute, double lx, \
double ly, opqst_t state)) \
/* \
- * `plugin_handle_surface` \
+ * `arksoul_export_handle_surface` \
* \
* Called when a surface is mapped/unmapped/destroyed. `surface` is an \
- * opaque pointer to the runtime surface representation. Returns the updated \
- * opaque state. \
+ * opaque pointer to the runtime surface representation. Returns the updated \
+ * opaque state. \
*/ \
- X(opqst_t, plugin_handle_surface, \
+ X(opqst_t, arksoul_export_handle_surface, \
(void *surface, surface_event_t event, opqst_t state))
diff --git a/ark/include/soul_interface.h b/ark/include/soul_interface.h
new file mode 100644
index 0000000..6e45573
--- /dev/null
+++ b/ark/include/soul_interface.h
@@ -0,0 +1,23 @@
+#ifndef _SOUL_INTF
+#define _SOUL_INTF
+
+#include <stdint.h>
+
+#include "soul_types.h"
+#include "soul_exports.h"
+
+#include <wlr/types/wlr_input_device.h>
+#include <wlr/types/wlr_keyboard.h>
+#include <wlr/types/wlr_pointer.h>
+
+/*
+ * Soul ABI: souls must export these symbols.
+ *
+ * This header is intended to be included by soul implementations.
+ */
+
+#define DECLARE_SOUL_EXPORT(ret, name, args) ret name args;
+ARKSOUL_EXPORTS(DECLARE_SOUL_EXPORT)
+#undef DECLARE_SOUL_EXPORT
+
+#endif /* _SOUL_INTF */
diff --git a/arken/include/plugin_types.h b/ark/include/soul_types.h
index df1eab5..df1eab5 100644
--- a/arken/include/plugin_types.h
+++ b/ark/include/soul_types.h
diff --git a/arken/include/wl.h b/ark/include/wl.h
index f10ee7d..e5cf4f3 100644
--- a/arken/include/wl.h
+++ b/ark/include/wl.h
@@ -26,7 +26,7 @@
#include <wlr/util/log.h>
#include <xkbcommon/xkbcommon.h>
-#include <plugin.h>
+#include <soul.h>
/* For brevity's sake, struct members are annotated where they are used. */
enum montis_cursor_mode {