aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt16
-rw-r--r--Makefile6
-rw-r--r--README.md22
-rw-r--r--ark/CMakeLists.txt1
-rw-r--r--ark/README.md24
-rw-r--r--ark/include/soul.h111
-rw-r--r--ark/include/soul_interface.h23
-rw-r--r--ark/include/wl.h150
-rw-r--r--ark/include/world.h112
-rw-r--r--ark/include/world_exports.h (renamed from ark/include/soul_exports.h)60
-rw-r--r--ark/include/world_interface.h23
-rw-r--r--ark/include/world_types.h (renamed from ark/include/soul_types.h)0
-rw-r--r--ark/src/soul.c198
-rw-r--r--ark/src/wl.c238
-rw-r--r--ark/src/world.c199
-rw-r--r--ark/src/world_load.c (renamed from ark/src/soul_load.c)22
-rw-r--r--cross/README.md8
-rw-r--r--cross/include/util.h20
-rw-r--r--cross/src/runtime_requests.c44
-rw-r--r--cross/src/util.c16
-rw-r--r--montis/README.md12
-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/State.hs4
-rw-r--r--montis/src/Montis/Core/World/Interface.hs (renamed from montis/src/Montis/Core/Soul/Interface.hs)4
-rw-r--r--montis/src/harness_adapter.c16
28 files changed, 781 insertions, 626 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b4921ce..5046a00 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,18 +1,18 @@
cmake_minimum_required(VERSION 3.16)
project(montis LANGUAGES C)
-option(MONTIS_BUILD_BUNDLED_SOUL "Build the bundled Haskell soul (montis.so)" ON)
+option(MONTIS_BUILD_BUNDLED_WORLD "Build the bundled Haskell world (montis.so)" ON)
if(DEFINED MONTIS_BUILD_BUNDLED_PLUGIN)
- set(MONTIS_BUILD_BUNDLED_SOUL "${MONTIS_BUILD_BUNDLED_PLUGIN}")
+ set(MONTIS_BUILD_BUNDLED_WORLD "${MONTIS_BUILD_BUNDLED_PLUGIN}")
endif()
add_subdirectory(ark)
add_subdirectory(cross)
-if(MONTIS_BUILD_BUNDLED_SOUL)
+if(MONTIS_BUILD_BUNDLED_WORLD)
add_custom_target(
- soul_build ALL
+ world_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"
@@ -20,14 +20,14 @@ if(MONTIS_BUILD_BUNDLED_SOUL)
# 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 ark cross
- COMMENT "Building bundled Haskell soul with Stack"
+ COMMENT "Building bundled Haskell world with Stack"
VERBATIM
)
add_custom_target(
run
- 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
+ COMMAND sh -c "WORLD_SO=$(find '${CMAKE_BINARY_DIR}/stack-work' -name montis.so -type f | head -n 1); if [ -z \"$WORLD_SO\" ]; then echo 'montis.so not found in ${CMAKE_BINARY_DIR}/stack-work' 1>&2; exit 1; fi; \"$<TARGET_FILE:ark>\" -s foot -p \"$WORLD_SO\""
+ DEPENDS ark world_build
USES_TERMINAL
VERBATIM
)
@@ -36,7 +36,7 @@ endif()
install(TARGETS ark RUNTIME DESTINATION bin)
-if(MONTIS_BUILD_BUNDLED_SOUL)
+if(MONTIS_BUILD_BUNDLED_WORLD)
install(CODE [[
execute_process(
COMMAND sh -c "find '${CMAKE_BINARY_DIR}/stack-work' -name montis.so -type f | head -n 1"
diff --git a/Makefile b/Makefile
index d814302..aa4f004 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-.PHONY: all configure build ark cross soul run install clean distclean
+.PHONY: all configure build ark cross world run install clean distclean
BUILD_DIR ?= build
BUILD_TYPE ?= Debug
@@ -18,8 +18,8 @@ ark: configure
cross: configure
cmake --build $(BUILD_DIR) --target cross
-soul: configure
- cmake --build $(BUILD_DIR) --target soul_build
+world: configure
+ cmake --build $(BUILD_DIR) --target world_build
run: configure
cmake --build $(BUILD_DIR) --target run
diff --git a/README.md b/README.md
index 1240f49..9ba174f 100644
--- a/README.md
+++ b/README.md
@@ -47,7 +47,7 @@ runtime and wlroots itself.
**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
+`montis.so` world so these FFI bindings hot-reload along with the Haskell code
instead of living inside the long-running compositor process.
Code lives in `cross/src` and headers in `cross/include` (notably
@@ -109,23 +109,23 @@ 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 soul): Haskell toolchain via Stack: `stack` (+ GHC)
+- Optional (only for the bundled world): Haskell toolchain via Stack: `stack` (+ GHC)
### Build
This repo uses CMake to build:
- `ark` (the compositor runtime)
- `cross` (`libcross.a`)
-- the bundled Haskell soul (`montis.so`) via Stack
+- the bundled Haskell world (`montis.so`) via Stack
```sh
make build
```
-To build only the runtime + bridge library (no bundled soul):
+To build only the runtime + bridge library (no bundled world):
```sh
-make BUILD_DIR=build BUILD_TYPE=Debug CMAKE_ARGS=-DMONTIS_BUILD_BUNDLED_SOUL=OFF build
+make BUILD_DIR=build BUILD_TYPE=Debug CMAKE_ARGS=-DMONTIS_BUILD_BUNDLED_WORLD=OFF build
```
To run via the CMake helper target:
@@ -137,18 +137,18 @@ make run
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 Soul
+### Using Your Own World
-If you disable the bundled soul (`-DMONTIS_BUILD_BUNDLED_SOUL=OFF`), you can
-build and supply your own soul `.so` at runtime.
+If you disable the bundled world (`-DMONTIS_BUILD_BUNDLED_WORLD=OFF`), you can
+build and supply your own world `.so` at runtime.
-- Soul ABI: `ark/include/soul.h` (soul header: `ark/include/soul_interface.h`)
+- World ABI: `ark/include/world.h` (world header: `ark/include/world_interface.h`)
- Optional bridge helpers: `cross/include` + `build/cross/libcross.a`
Runtime invocation looks like:
```sh
-./build/ark/ark -p /path/to/your_soul.so
+./build/ark/ark -p /path/to/your_world.so
```
## Installing
@@ -159,4 +159,4 @@ make install PREFIX=~/.local
This installs:
- `ark` to `~/.local/bin`
-- if `-DMONTIS_BUILD_BUNDLED_SOUL=ON`, the latest built soul `.so` to `~/.local/lib`
+- if `-DMONTIS_BUILD_BUNDLED_WORLD=ON`, the latest built world `.so` to `~/.local/lib`
diff --git a/ark/CMakeLists.txt b/ark/CMakeLists.txt
index 35e47a9..4e2c259 100644
--- a/ark/CMakeLists.txt
+++ b/ark/CMakeLists.txt
@@ -127,6 +127,7 @@ pkg_check_modules(WLOPT IMPORTED_TARGET
if(WLOPT_FOUND)
target_link_libraries(ark PRIVATE PkgConfig::WLOPT)
+ target_compile_definitions(ark PRIVATE ARK_HAVE_CAIRO)
endif()
target_link_directories(ark PUBLIC
diff --git a/ark/README.md b/ark/README.md
index d773e0d..a8be7e1 100644
--- a/ark/README.md
+++ b/ark/README.md
@@ -1,35 +1,35 @@
Ark (Runtime)
=============
-Ark is a long-running Wayland compositor runtime with a hot-reloadable soul
+Ark is a long-running Wayland compositor runtime with a hot-reloadable world
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.
+- Loads a world shared object (`.so`) at runtime and routes input/surface events to it.
+- Supports hot-reloading the world without restarting the compositor.
-Soul interface
+World interface
--------------
-The runtime defines a C ABI that souls must implement (load/start/teardown,
+The runtime defines a C ABI that worlds must implement (load/start/teardown,
event handlers, and optional state marshal/unmarshal for hot reload). The ABI is
defined in:
-- `ark/include/soul.h`
+- `ark/include/world.h`
-Souls should include:
+Worlds should include:
-- `ark/include/soul_interface.h`
+- `ark/include/world_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.
+- `ark/src/wl.c`: compositor setup + event loop + world callbacks.
+- `ark/src/world.c`: dynamic loading, lifecycle, and hot-reload logic.
+- `ark/include/world.h`: C ABI the world must implement.
Building
--------
@@ -44,7 +44,7 @@ cmake --build ../build --target ark
Running
-------
-Use the top-level `run` target (builds the bundled soul and launches Ark):
+Use the top-level `run` target (builds the bundled world and launches Ark):
```sh
cmake --build ../build --target run
diff --git a/ark/include/soul.h b/ark/include/soul.h
deleted file mode 100644
index fa3415b..0000000
--- a/ark/include/soul.h
+++ /dev/null
@@ -1,111 +0,0 @@
-#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/ark/include/soul_interface.h b/ark/include/soul_interface.h
deleted file mode 100644
index 6e45573..0000000
--- a/ark/include/soul_interface.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#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/ark/include/wl.h b/ark/include/wl.h
index e5cf4f3..725025c 100644
--- a/ark/include/wl.h
+++ b/ark/include/wl.h
@@ -21,105 +21,109 @@
#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/types/wlr_xdg_decoration_v1.h>
+#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/log.h>
#include <xkbcommon/xkbcommon.h>
-#include <soul.h>
+#include <world.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,
+ 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_xdg_decoration_manager_v1 *xdg_decoration_manager;
- struct wl_listener new_xdg_decoration;
-
- 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 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_xdg_decoration_manager_v1 *xdg_decoration_manager;
+ struct wl_listener new_xdg_decoration;
+
+ 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_buffer *background_buffer;
+ char *background_path;
struct wlr_session *session;
- soul_t soul;
+ world_t world;
};
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 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 wlr_scene_buffer *background;
};
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 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_list link;
+ struct montis_server *server;
+ struct wlr_keyboard *wlr_keyboard;
- struct wl_listener modifiers;
- struct wl_listener key;
- struct wl_listener destroy;
+ 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;
+ struct wlr_xdg_popup *xdg_popup;
+ struct wl_listener commit;
+ struct wl_listener destroy;
};
struct montis_xdg_decoration {
- struct wlr_xdg_toplevel_decoration_v1 *decoration;
- struct wl_listener request_mode;
- struct wl_listener destroy;
+ struct wlr_xdg_toplevel_decoration_v1 *decoration;
+ struct wl_listener request_mode;
+ struct wl_listener destroy;
};
diff --git a/ark/include/world.h b/ark/include/world.h
new file mode 100644
index 0000000..307608e
--- /dev/null
+++ b/ark/include/world.h
@@ -0,0 +1,112 @@
+#ifndef _WORLD_H_
+#define _WORLD_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 "world_exports.h"
+#include "world_types.h"
+
+#define MAX_QUEUED_ACTIONS 8
+
+typedef void *dlhandle_t;
+
+/* Opaque state for a world. Not to be touched by the harness (not that it
+ * really can be.) */
+
+struct WORLD;
+/* This structure represents an action requested by the world for the harness.
+ */
+typedef struct {
+ int (*action)(struct WORLD *requester, void *arg);
+ void (*arg_dtor)(void *arg);
+ union {
+ void *ptr_arg;
+ int int_arg;
+ char *str_arg;
+ };
+} requested_action_t;
+
+/*
+ * Structure for the world.
+ */
+typedef struct WORLD {
+ /* The argc this world is loaded with. Typically the argc from main(). */
+ int argc;
+
+ /* The argv this world is loaded with. Typically the argv from main(). */
+ char **argv;
+
+ /* Filename the world is loaded from. */
+ char filename[PATH_MAX];
+
+ /* Opaque state of this world. The state is usually some kind of pointer to
+ * the world 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 world 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 world'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 world is initialized, otherwise set to zero. */
+ int initialized;
+
+ /* The handle to the shared library. */
+ dlhandle_t library_handle;
+
+ /* Pointer to the world name. This is in the shared library and a
+ * null-terminated string. If the library does not have a world name, this
+ * will be NULL. */
+ const char *world_name;
+
+ /* World function table populated by the runtime loader. */
+#define WORLD_FN_PTR(ret, name, args) ret(*name) args;
+ ARKWORLD_EXPORTS(WORLD_FN_PTR)
+#undef WORLD_FN_PTR
+
+ /* List of requested actions by the world. 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];
+} world_t;
+
+/* Reloads the world. This tears down the existing world, marshals the state
+ * for it and reloads it.
+ *
+ * This function will call dlclose on the world's library handle.
+ */
+int world_hot_reload(int argc, char **argv, const char *filepath,
+ world_t *world);
+
+/*
+ * Like hot-reload, but uses the same parameters the world was originally
+ * loaded with.
+ */
+int world_hot_reload_same_state(world_t *world);
+
+/* Starts a world in a cold state. Called after load_world_from_file. */
+void world_cold_start(world_t *world);
+
+/* Reads a world from a filename. */
+int load_world_from_file(int argc, char **argv, const char *filename,
+ world_t *world);
+
+void world_run_requested_actions(world_t *world);
+
+#endif /* _WORLD_H_ */
diff --git a/ark/include/soul_exports.h b/ark/include/world_exports.h
index 8e22b15..c0ee74e 100644
--- a/ark/include/soul_exports.h
+++ b/ark/include/world_exports.h
@@ -1,42 +1,42 @@
#pragma once
/*
- * Single source of truth for the soul ABI.
+ * Single source of truth for the world ABI.
*
* Consumers must define an X-macro like:
* #define X(ret, name, args) ...
* and then invoke:
- * ARKSOUL_EXPORTS(X)
+ * ARKWORLD_EXPORTS(X)
*
* Note: this file intentionally does not include headers. Include whatever you
- * need (e.g. <stdint.h>, soul_types.h, wlroots headers) before expanding.
+ * need (e.g. <stdint.h>, world_types.h, wlroots headers) before expanding.
*/
-#define ARKSOUL_EXPORTS(X) \
+#define ARKWORLD_EXPORTS(X) \
/* \
- * `arksoul_export_metaload` \
+ * `arkworld_export_metaload` \
* \
- * Called at most once per process *per `soul_name`*. This is the place \
+ * Called at most once per process *per `world_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 soul entrypoint. \
+ * - Must be safe to call before any other world entrypoint. \
*/ \
- X(void, arksoul_export_metaload, (int argc, char **argv)) \
+ X(void, arkworld_export_metaload, (int argc, char **argv)) \
/* \
- * `arksoul_export_load` \
+ * `arkworld_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, arksoul_export_load, (int argc, char **argv)) \
+ X(void, arkworld_export_load, (int argc, char **argv)) \
/* \
- * `arksoul_export_rebirth` \
+ * `arkworld_export_rebirth` \
* \
- * Called after a hot reload with the previous soul's preserved state. \
+ * Called after a hot reload with the previous world'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, arksoul_export_rebirth, \
+ X(opqst_t, arkworld_export_rebirth, \
(void *self, uint8_t *marshalled_state, uint32_t n)) \
/* \
- * `arksoul_export_ensoul` \
+ * `arkworld_export_enworld` \
* \
* Called on first boot when no previous state exists. Must construct and \
* return an initial opaque state. \
*/ \
- X(opqst_t, arksoul_export_ensoul, (void *self)) \
+ X(opqst_t, arkworld_export_enworld, (void *self)) \
/* \
- * `arksoul_export_preserve` \
+ * `arkworld_export_preserve` \
* \
- * Called before unloading the current soul during hot reload. Must \
+ * Called before unloading the current world 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 \
- * `arksoul_export_rebirth`. \
+ * `arkworld_export_rebirth`. \
*/ \
- X(uint8_t *, arksoul_export_preserve, (opqst_t st, uint32_t *szout)) \
+ X(uint8_t *, arkworld_export_preserve, (opqst_t st, uint32_t * szout)) \
/* \
- * `arksoul_export_release` \
+ * `arkworld_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 `arksoul_export_load`). \
+ * created in `arkworld_export_load`). \
*/ \
- X(void, arksoul_export_release, (opqst_t st)) \
+ X(void, arkworld_export_release, (opqst_t st)) \
/* \
- * `arksoul_export_handle_keybinding` \
+ * `arkworld_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, arksoul_export_handle_keybinding, \
+ X(opqst_t, arkworld_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)) \
/* \
- * `arksoul_export_handle_button` \
+ * `arkworld_export_handle_button` \
* \
* Called for pointer button events (mouse/trackpad clicks). Returns the \
* updated opaque state. \
*/ \
- X(opqst_t, arksoul_export_handle_button, \
+ X(opqst_t, arkworld_export_handle_button, \
(struct wlr_pointer_button_event * event, uint32_t modifiers, \
opqst_t state)) \
/* \
- * `arksoul_export_handle_motion` \
+ * `arkworld_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, arksoul_export_handle_motion, \
+ X(opqst_t, arkworld_export_handle_motion, \
(void *event, uint32_t modifiers, uint32_t is_absolute, double lx, \
double ly, opqst_t state)) \
/* \
- * `arksoul_export_handle_surface` \
+ * `arkworld_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. \
*/ \
- X(opqst_t, arksoul_export_handle_surface, \
+ X(opqst_t, arkworld_export_handle_surface, \
(void *surface, surface_event_t event, opqst_t state))
diff --git a/ark/include/world_interface.h b/ark/include/world_interface.h
new file mode 100644
index 0000000..9e703fa
--- /dev/null
+++ b/ark/include/world_interface.h
@@ -0,0 +1,23 @@
+#ifndef _WORLD_INTF
+#define _WORLD_INTF
+
+#include <stdint.h>
+
+#include "world_exports.h"
+#include "world_types.h"
+
+#include <wlr/types/wlr_input_device.h>
+#include <wlr/types/wlr_keyboard.h>
+#include <wlr/types/wlr_pointer.h>
+
+/*
+ * World ABI: worlds must export these symbols.
+ *
+ * This header is intended to be included by world implementations.
+ */
+
+#define DECLARE_WORLD_EXPORT(ret, name, args) ret name args;
+ARKWORLD_EXPORTS(DECLARE_WORLD_EXPORT)
+#undef DECLARE_WORLD_EXPORT
+
+#endif /* _WORLD_INTF */
diff --git a/ark/include/soul_types.h b/ark/include/world_types.h
index df1eab5..df1eab5 100644
--- a/ark/include/soul_types.h
+++ b/ark/include/world_types.h
diff --git a/ark/src/soul.c b/ark/src/soul.c
deleted file mode 100644
index 4268cd5..0000000
--- a/ark/src/soul.c
+++ /dev/null
@@ -1,198 +0,0 @@
-#include "soul.h"
-
-#include <ctype.h>
-#include <dlfcn.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-/* Utility function for showing the marshalled states as hex code */
-static void shx(uint8_t *state, uint32_t sz)
-{
- uint32_t i = 0;
- while (i < sz) {
- for (int j = 0; j < 16; ++j) {
- if (i < sz) {
- printf("%02x ", (unsigned int)state[i]);
- }
- else {
- printf(" ");
- }
- ++i;
- }
-
- i -= 16;
-
- printf(" ");
-
- for (int j = 0; j < 16; ++j) {
- if (i < sz) {
- if (isprint(state[i]) && !isspace(state[i])) {
- printf("%c", state[i]);
- }
- else {
- printf(".");
- }
- }
- else {
- printf(" ");
- }
- ++i;
- }
- printf("\n");
- }
-}
-
-int load_soul_from_dl_(dlhandle_t dl, soul_t *soul);
-
-static void lock(soul_t *soul) { pthread_mutex_lock(&soul->lock); };
-
-static void unlock(soul_t *soul) { pthread_mutex_unlock(&soul->lock); };
-
-static int load_soul_from_file_(int argc, char **argv, const char *filename,
- soul_t *soul)
-{
- dlhandle_t lib = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
- int ec = 0;
-
- if (!lib) {
- fprintf(stderr, "Failed to open library: %s: %s\n", filename, dlerror());
- ec = 1;
- goto end;
- }
-
- printf("Loading file.\n");
- ec = load_soul_from_dl_(lib, soul);
-
- if (ec) {
- goto end;
- }
-
- strncpy(soul->filename, filename, sizeof(soul->filename));
- soul->argc = argc;
- soul->argv = argv;
-
- soul->arksoul_export_load(soul->argc, soul->argv);
-end:
- return ec;
-}
-
-static void maybe_run_metaload(int argc, char **argv, soul_t *soul)
-{
- static char *loaded_souls[12];
- int i;
- for (i = 0; i < 12 && loaded_souls[i]; ++i) {
- if (strcmp(loaded_souls[i], soul->soul_name) == 0) {
- return; // Soul is already loaded
- }
- }
- loaded_souls[i] = strdup(soul->soul_name);
-
- printf("First time loading %s, running metaload.\n", soul->soul_name);
- if (soul->arksoul_export_metaload) {
- soul->arksoul_export_metaload(argc, argv);
- }
-}
-
-int load_soul_from_file(int argc, char **argv, const char *filename,
- soul_t *soul)
-{
- memset(soul, 0, sizeof(*soul));
-
- pthread_mutexattr_t attr;
- if (pthread_mutexattr_init(&attr)) {
- perror("pthread_mutexattr_init");
- return 1;
- }
-
- if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) {
- perror("pthread_mutexattr_settype");
- return 1;
- }
-
- if (pthread_mutex_init(&soul->lock, &attr)) {
- pthread_mutexattr_destroy(&attr);
- perror("pthread_mutexattr_init");
- return 1;
- }
- pthread_mutexattr_destroy(&attr);
- int rc = load_soul_from_file_(argc, argv, filename, soul);
-
- if (rc == 0) {
- maybe_run_metaload(argc, argv, soul);
- }
-
- return rc;
-}
-
-int soul_hot_reload_same_state(soul_t *soul)
-{
- char filename_cpy[PATH_MAX];
- strncpy(filename_cpy, soul->filename, sizeof(filename_cpy));
- return soul_hot_reload(soul->argc, soul->argv, filename_cpy, soul);
-}
-
-int soul_hot_reload(int argc, char **argv, const char *filepath, soul_t *soul)
-{
- int ec = 0;
- uint32_t sz = 0;
- uint8_t *marshalled_state = NULL;
-
- printf("Hot Reloading %s\n", soul->soul_name);
- lock(soul);
-
- printf("Marshalling state ...\n");
- marshalled_state = soul->arksoul_export_preserve(soul->state, &sz);
-
- printf("Calling teardown ...\n");
- soul->arksoul_export_release(soul->state);
-
- printf("State Marshalled:\n");
- shx(marshalled_state, sz);
-
- printf("Unloading old library handle.\n");
- if (dlclose(soul->library_handle)) {
- printf("Could not close library handle: %s\n", dlerror());
- }
-
- if ((ec = load_soul_from_file_(argc, argv, filepath, soul))) {
- goto fail;
- }
-
- printf("Hot starting soul ...\n");
- soul->state = soul->arksoul_export_rebirth(soul, marshalled_state, sz);
-
-fail:
- free(marshalled_state);
- unlock(soul);
- return ec;
-}
-
-void soul_run_requested_actions(soul_t *soul)
-{
- lock(soul);
- requested_action_t requested_actions[MAX_QUEUED_ACTIONS];
- size_t n_requested_actions = soul->n_requested_actions;
- memcpy(&requested_actions, soul->requested_actions,
- sizeof(requested_actions));
- soul->n_requested_actions = 0;
- unlock(soul);
-
- size_t i;
- for (i = 0; i < n_requested_actions; ++i) {
- requested_actions[i].action(soul, requested_actions[i].str_arg);
- if (requested_actions[i].arg_dtor) {
- requested_actions[i].arg_dtor(requested_actions[i].ptr_arg);
- }
- }
-}
-
-void soul_cold_start(soul_t *soul)
-{
- lock(soul);
- soul->state = soul->arksoul_export_ensoul(soul);
- unlock(soul);
-}
diff --git a/ark/src/wl.c b/ark/src/wl.c
index b9ce952..fc0ddc7 100644
--- a/ark/src/wl.c
+++ b/ark/src/wl.c
@@ -9,8 +9,15 @@
#include "xdg-decoration-unstable-v1-client-protocol.h"
-// This macro is responsible for calling a handler on a soul. This macro will
-// acquire the soul's lock, call the member with the arguments and update the
+#include <wlr/interfaces/wlr_buffer.h>
+
+#ifdef ARK_HAVE_CAIRO
+#include <cairo.h>
+#include <drm_fourcc.h>
+#endif
+
+// This macro is responsible for calling a handler on a world. This macro will
+// acquire the world's lock, call the member with the arguments and update the
// state.
//
// This only works on function which have the format:
@@ -18,15 +25,133 @@
// opqst_t function(args ..., opqst_t state);
//
// Note that the state parameter is omitted from this macro.
-#define soul_call_update_state(soul, member, ...) \
+#define world_call_update_state(world, member, ...) \
do { \
- soul_t *sl__ = &(soul); \
+ world_t *sl__ = &(world); \
pthread_mutex_lock(&sl__->lock); \
sl__->state = sl__->member(__VA_ARGS__, sl__->state); \
pthread_mutex_unlock(&sl__->lock); \
- soul_run_requested_actions(sl__); \
+ world_run_requested_actions(sl__); \
} while (0)
+#ifdef ARK_HAVE_CAIRO
+struct montis_image_buffer {
+ struct wlr_buffer base;
+ cairo_surface_t *surface;
+ uint32_t drm_format;
+};
+
+static void image_buffer_destroy(struct wlr_buffer *wlr_buffer)
+{
+ struct montis_image_buffer *buffer =
+ wl_container_of(wlr_buffer, buffer, base);
+ cairo_surface_destroy(buffer->surface);
+ free(buffer);
+}
+
+static bool image_buffer_begin_data_ptr_access(struct wlr_buffer *wlr_buffer,
+ uint32_t flags, void **data,
+ uint32_t *format, size_t *stride)
+{
+ if (flags & WLR_BUFFER_DATA_PTR_ACCESS_WRITE) {
+ return false;
+ }
+ struct montis_image_buffer *buffer =
+ wl_container_of(wlr_buffer, buffer, base);
+ cairo_surface_flush(buffer->surface);
+ *data = cairo_image_surface_get_data(buffer->surface);
+ *stride = cairo_image_surface_get_stride(buffer->surface);
+ *format = buffer->drm_format;
+ return true;
+}
+
+static void image_buffer_end_data_ptr_access(struct wlr_buffer *wlr_buffer) {}
+
+static const struct wlr_buffer_impl image_buffer_impl = {
+ .destroy = image_buffer_destroy,
+ .begin_data_ptr_access = image_buffer_begin_data_ptr_access,
+ .end_data_ptr_access = image_buffer_end_data_ptr_access,
+};
+
+static struct wlr_buffer *load_background_buffer(const char *path)
+{
+ cairo_surface_t *surface = cairo_image_surface_create_from_png(path);
+ if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
+ cairo_surface_destroy(surface);
+ wlr_log(WLR_ERROR, "failed to load background image: %s", path);
+ return NULL;
+ }
+
+ cairo_format_t format = cairo_image_surface_get_format(surface);
+ uint32_t drm_format = DRM_FORMAT_ARGB8888;
+ if (format == CAIRO_FORMAT_RGB24) {
+ drm_format = DRM_FORMAT_XRGB8888;
+ }
+ else if (format != CAIRO_FORMAT_ARGB32) {
+ cairo_surface_destroy(surface);
+ wlr_log(WLR_ERROR, "unsupported background image format: %d", format);
+ return NULL;
+ }
+
+ int width = cairo_image_surface_get_width(surface);
+ int height = cairo_image_surface_get_height(surface);
+
+ struct montis_image_buffer *buffer = calloc(1, sizeof(*buffer));
+ if (!buffer) {
+ cairo_surface_destroy(surface);
+ return NULL;
+ }
+
+ wlr_buffer_init(&buffer->base, &image_buffer_impl, width, height);
+ buffer->surface = surface;
+ buffer->drm_format = drm_format;
+ return &buffer->base;
+}
+#else
+static struct wlr_buffer *load_background_buffer(const char *path)
+{
+ (void)path;
+ wlr_log(WLR_ERROR, "backgrounds require cairo support");
+ return NULL;
+}
+#endif
+
+static bool background_accepts_input(struct wlr_scene_buffer *buffer,
+ double *sx, double *sy)
+{
+ (void)buffer;
+ (void)sx;
+ (void)sy;
+ return false;
+}
+
+static void output_update_background(struct montis_output *output)
+{
+ struct montis_server *server = output->server;
+ if (!server->background_buffer) {
+ return;
+ }
+
+ if (!output->background) {
+ output->background = wlr_scene_buffer_create(&server->scene->tree,
+ server->background_buffer);
+ if (!output->background) {
+ wlr_log(WLR_ERROR, "failed to create background node");
+ return;
+ }
+ output->background->point_accepts_input = background_accepts_input;
+ wlr_scene_node_lower_to_bottom(&output->background->node);
+ }
+ else {
+ wlr_scene_buffer_set_buffer(output->background, server->background_buffer);
+ }
+
+ struct wlr_box box;
+ wlr_output_layout_get_box(server->output_layout, output->wlr_output, &box);
+ wlr_scene_node_set_position(&output->background->node, box.x, box.y);
+ wlr_scene_buffer_set_dest_size(output->background, box.width, box.height);
+}
+
static void focus_toplevel(struct montis_toplevel *toplevel,
struct wlr_surface *surface)
{
@@ -113,9 +238,9 @@ static void keyboard_handle_key(struct wl_listener *listener, void *data)
if (nsyms > 0 && syms[0] >= XKB_KEY_XF86Switch_VT_1 &&
syms[0] <= XKB_KEY_XF86Switch_VT_12) {
/* Escape-hatch to change sessions. These should always be available key
- * bindings regardless of what the soul dictates. This allows an escape
- * hatch to edit the soul in a different vterm and then use the escape
- * hatch below to hot-restart the soul if things get borked. */
+ * bindings regardless of what the world dictates. This allows an escape
+ * hatch to edit the world in a different vterm and then use the escape
+ * hatch below to hot-restart the world if things get borked. */
if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
wlr_session_change_vt(server->session,
syms[0] - XKB_KEY_XF86Switch_VT_1 + 1);
@@ -124,26 +249,26 @@ static void keyboard_handle_key(struct wl_listener *listener, void *data)
else if (modifiers ==
(WLR_MODIFIER_SHIFT | WLR_MODIFIER_CTRL | WLR_MODIFIER_ALT) &&
nsyms > 0 && syms[0] == XKB_KEY_Escape) {
- /* Escape-hatch to hot-reload the soul in case the soul got borked and
+ /* Escape-hatch to hot-reload the world in case the world got borked and
* stops accepting keybindings. Ctrl+Shift+Alt+Escape will always reload the
- * soul. */
+ * world. */
if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
- if ((ec = soul_hot_reload_same_state(&server->soul)) != 0) {
- fprintf(stderr, "Failed to hot reload soul");
+ if ((ec = world_hot_reload_same_state(&server->world)) != 0) {
+ fprintf(stderr, "Failed to hot reload world");
exit(1);
}
}
}
else {
- /* Pass the information along to the soul for the soul to handle. The
- * soul will return via 'handled' whether or not the key event was handled
+ /* Pass the information along to the world for the world to handle. The
+ * world will return via 'handled' whether or not the key event was handled
* or not. */
if (nsyms > 0) {
codepoint =
xkb_state_key_get_utf32(keyboard->wlr_keyboard->xkb_state, keycode);
- soul_call_update_state(server->soul, arksoul_export_handle_keybinding,
- keyboard->wlr_keyboard, event, modifiers, syms[0],
- codepoint, &handled);
+ world_call_update_state(server->world, arkworld_export_handle_keybinding,
+ keyboard->wlr_keyboard, event, modifiers, syms[0],
+ codepoint, &handled);
}
}
}
@@ -440,9 +565,8 @@ static void server_cursor_motion(struct wl_listener *listener, void *data)
wlr_cursor_move(server->cursor, &event->pointer->base, event->delta_x,
event->delta_y);
process_cursor_motion(server, event->time_msec);
- soul_call_update_state(server->soul, arksoul_export_handle_motion, event,
- modifiers,
- 0, server->cursor->x, server->cursor->y);
+ world_call_update_state(server->world, arkworld_export_handle_motion, event,
+ modifiers, 0, server->cursor->x, server->cursor->y);
}
static void server_cursor_motion_absolute(struct wl_listener *listener,
@@ -465,9 +589,8 @@ static void server_cursor_motion_absolute(struct wl_listener *listener,
wlr_cursor_warp_absolute(server->cursor, &event->pointer->base, event->x,
event->y);
process_cursor_motion(server, event->time_msec);
- soul_call_update_state(server->soul, arksoul_export_handle_motion, event,
- modifiers,
- 1, server->cursor->x, server->cursor->y);
+ world_call_update_state(server->world, arkworld_export_handle_motion, event,
+ modifiers, 1, server->cursor->x, server->cursor->y);
}
static void server_cursor_button(struct wl_listener *listener, void *data)
@@ -481,8 +604,8 @@ static void server_cursor_button(struct wl_listener *listener, void *data)
struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat);
uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard);
- soul_call_update_state(server->soul, arksoul_export_handle_button, event,
- modifiers);
+ world_call_update_state(server->world, arkworld_export_handle_button, event,
+ modifiers);
/* Notify the client with pointer focus that a button press has occurred */
// wlr_seat_pointer_notify_button(server->seat, event->time_msec,
@@ -553,12 +676,18 @@ static void output_request_state(struct wl_listener *listener, void *data)
wl_container_of(listener, output, request_state);
const struct wlr_output_event_request_state *event = data;
wlr_output_commit_state(output->wlr_output, event->state);
+ output_update_background(output);
}
static void output_destroy(struct wl_listener *listener, void *data)
{
struct montis_output *output = wl_container_of(listener, output, destroy);
+ if (output->background) {
+ wlr_scene_node_destroy(&output->background->node);
+ output->background = NULL;
+ }
+
wl_list_remove(&output->frame.link);
wl_list_remove(&output->request_state.link);
wl_list_remove(&output->destroy.link);
@@ -630,6 +759,8 @@ static void server_new_output(struct wl_listener *listener, void *data)
wlr_scene_output_create(server->scene, wlr_output);
wlr_scene_output_layout_add_output(server->scene_layout, l_output,
scene_output);
+
+ output_update_background(output);
}
static void xdg_toplevel_map(struct wl_listener *listener, void *data)
@@ -640,9 +771,9 @@ static void xdg_toplevel_map(struct wl_listener *listener, void *data)
wl_list_insert(&toplevel->server->toplevels, &toplevel->link);
fprintf(stderr, "Surface map ...\n");
- soul_call_update_state(toplevel->server->soul, arksoul_export_handle_surface,
- toplevel,
- SURFACE_MAP);
+ world_call_update_state(toplevel->server->world,
+ arkworld_export_handle_surface, toplevel,
+ SURFACE_MAP);
fprintf(stderr, "/ Surface map ...\n");
focus_toplevel(toplevel, toplevel->xdg_toplevel->base->surface);
@@ -659,9 +790,9 @@ static void xdg_toplevel_unmap(struct wl_listener *listener, void *data)
}
fprintf(stderr, "Surface unmap ...\n");
- soul_call_update_state(toplevel->server->soul, arksoul_export_handle_surface,
- toplevel,
- SURFACE_UNMAP);
+ world_call_update_state(toplevel->server->world,
+ arkworld_export_handle_surface, toplevel,
+ SURFACE_UNMAP);
fprintf(stderr, "/ Surface map ...\n");
wl_list_remove(&toplevel->link);
@@ -682,9 +813,9 @@ static void xdg_toplevel_destroy(struct wl_listener *listener, void *data)
wl_list_remove(&toplevel->request_fullscreen.link);
fprintf(stderr, "Surface destroy ...\n");
- soul_call_update_state(toplevel->server->soul, arksoul_export_handle_surface,
- toplevel,
- SURFACE_DELETE);
+ world_call_update_state(toplevel->server->world,
+ arkworld_export_handle_surface, toplevel,
+ SURFACE_DELETE);
fprintf(stderr, "/ Surface destroy ...\n");
free(toplevel);
@@ -843,8 +974,7 @@ static void xdg_decoration_request_mode(struct wl_listener *listener,
static void xdg_decoration_destroy(struct wl_listener *listener, void *data)
{
- struct montis_xdg_decoration *dec =
- wl_container_of(listener, dec, destroy);
+ struct montis_xdg_decoration *dec = wl_container_of(listener, dec, destroy);
wl_list_remove(&dec->request_mode.link);
wl_list_remove(&dec->destroy.link);
free(dec);
@@ -927,35 +1057,42 @@ int main(int argc, char *argv[])
{
wlr_log_init(WLR_DEBUG, NULL);
char *startup_cmd = NULL;
- char *soul_path = NULL;
+ char *world_path = NULL;
+ char *background_path = NULL;
int c;
- while ((c = getopt(argc, argv, "s:p:h")) != -1) {
+ while ((c = getopt(argc, argv, "s:p:b:h")) != -1) {
switch (c) {
case 's':
startup_cmd = optarg;
break;
case 'p':
- soul_path = optarg;
+ world_path = optarg;
+ break;
+ case 'b':
+ background_path = optarg;
break;
default:
- printf("Usage: %s -p [soul] [-s startup command]\n", argv[0]);
+ printf("Usage: %s -p [world] [-s startup command] [-b background.png]\n",
+ argv[0]);
return 0;
}
}
- if (optind < argc || !soul_path) {
- printf("Usage: %s -p [soul] [-s startup command]\n", argv[0]);
+ if (optind < argc || !world_path) {
+ printf("Usage: %s -p [world] [-s startup command] [-b background.png]\n",
+ argv[0]);
return 0;
}
struct montis_server server = {0};
+ server.background_path = background_path;
- if (load_soul_from_file(argc, argv, soul_path, &server.soul)) {
- fprintf(stderr, "Failed to read soul from file.\n");
+ if (load_world_from_file(argc, argv, world_path, &server.world)) {
+ fprintf(stderr, "Failed to read world from file.\n");
return 1;
}
- soul_cold_start(&server.soul);
+ world_cold_start(&server.world);
/* The Wayland display is managed by libwayland. It handles accepting
* clients from the Unix socket, manging Wayland globals, and so on. */
@@ -1024,6 +1161,13 @@ int main(int argc, char *argv[])
server.scene_layout =
wlr_scene_attach_output_layout(server.scene, server.output_layout);
+ if (server.background_path) {
+ server.background_buffer = load_background_buffer(server.background_path);
+ if (!server.background_buffer) {
+ wlr_log(WLR_ERROR, "background image disabled");
+ }
+ }
+
/* Set up xdg-shell version 3. The xdg-shell is a Wayland protocol which is
* used for application windows. For more detail on shells, refer to
* https://drewdevault.com/2018/07/29/Wayland-shells.html.
@@ -1133,6 +1277,10 @@ int main(int argc, char *argv[])
* server. */
wl_display_destroy_clients(server.wl_display);
wlr_scene_node_destroy(&server.scene->tree.node);
+ if (server.background_buffer) {
+ wlr_buffer_drop(server.background_buffer);
+ server.background_buffer = NULL;
+ }
wlr_xcursor_manager_destroy(server.cursor_mgr);
wlr_output_layout_destroy(server.output_layout);
wl_display_destroy(server.wl_display);
diff --git a/ark/src/world.c b/ark/src/world.c
new file mode 100644
index 0000000..e7641ed
--- /dev/null
+++ b/ark/src/world.c
@@ -0,0 +1,199 @@
+#include "world.h"
+
+#include <ctype.h>
+#include <dlfcn.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+/* Utility function for showing the marshalled states as hex code */
+static void shx(uint8_t *state, uint32_t sz)
+{
+ uint32_t i = 0;
+ while (i < sz) {
+ for (int j = 0; j < 16; ++j) {
+ if (i < sz) {
+ printf("%02x ", (unsigned int)state[i]);
+ }
+ else {
+ printf(" ");
+ }
+ ++i;
+ }
+
+ i -= 16;
+
+ printf(" ");
+
+ for (int j = 0; j < 16; ++j) {
+ if (i < sz) {
+ if (isprint(state[i]) && !isspace(state[i])) {
+ printf("%c", state[i]);
+ }
+ else {
+ printf(".");
+ }
+ }
+ else {
+ printf(" ");
+ }
+ ++i;
+ }
+ printf("\n");
+ }
+}
+
+int load_world_from_dl_(dlhandle_t dl, world_t *world);
+
+static void lock(world_t *world) { pthread_mutex_lock(&world->lock); };
+
+static void unlock(world_t *world) { pthread_mutex_unlock(&world->lock); };
+
+static int load_world_from_file_(int argc, char **argv, const char *filename,
+ world_t *world)
+{
+ dlhandle_t lib = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
+ int ec = 0;
+
+ if (!lib) {
+ fprintf(stderr, "Failed to open library: %s: %s\n", filename, dlerror());
+ ec = 1;
+ goto end;
+ }
+
+ printf("Loading file.\n");
+ ec = load_world_from_dl_(lib, world);
+
+ if (ec) {
+ goto end;
+ }
+
+ strncpy(world->filename, filename, sizeof(world->filename));
+ world->argc = argc;
+ world->argv = argv;
+
+ world->arkworld_export_load(world->argc, world->argv);
+end:
+ return ec;
+}
+
+static void maybe_run_metaload(int argc, char **argv, world_t *world)
+{
+ static char *loaded_worlds[12];
+ int i;
+ for (i = 0; i < 12 && loaded_worlds[i]; ++i) {
+ if (strcmp(loaded_worlds[i], world->world_name) == 0) {
+ return; // World is already loaded
+ }
+ }
+ loaded_worlds[i] = strdup(world->world_name);
+
+ printf("First time loading %s, running metaload.\n", world->world_name);
+ if (world->arkworld_export_metaload) {
+ world->arkworld_export_metaload(argc, argv);
+ }
+}
+
+int load_world_from_file(int argc, char **argv, const char *filename,
+ world_t *world)
+{
+ memset(world, 0, sizeof(*world));
+
+ pthread_mutexattr_t attr;
+ if (pthread_mutexattr_init(&attr)) {
+ perror("pthread_mutexattr_init");
+ return 1;
+ }
+
+ if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) {
+ perror("pthread_mutexattr_settype");
+ return 1;
+ }
+
+ if (pthread_mutex_init(&world->lock, &attr)) {
+ pthread_mutexattr_destroy(&attr);
+ perror("pthread_mutexattr_init");
+ return 1;
+ }
+ pthread_mutexattr_destroy(&attr);
+ int rc = load_world_from_file_(argc, argv, filename, world);
+
+ if (rc == 0) {
+ maybe_run_metaload(argc, argv, world);
+ }
+
+ return rc;
+}
+
+int world_hot_reload_same_state(world_t *world)
+{
+ char filename_cpy[PATH_MAX];
+ strncpy(filename_cpy, world->filename, sizeof(filename_cpy));
+ return world_hot_reload(world->argc, world->argv, filename_cpy, world);
+}
+
+int world_hot_reload(int argc, char **argv, const char *filepath,
+ world_t *world)
+{
+ int ec = 0;
+ uint32_t sz = 0;
+ uint8_t *marshalled_state = NULL;
+
+ printf("Hot Reloading %s\n", world->world_name);
+ lock(world);
+
+ printf("Marshalling state ...\n");
+ marshalled_state = world->arkworld_export_preserve(world->state, &sz);
+
+ printf("Calling teardown ...\n");
+ world->arkworld_export_release(world->state);
+
+ printf("State Marshalled:\n");
+ shx(marshalled_state, sz);
+
+ printf("Unloading old library handle.\n");
+ if (dlclose(world->library_handle)) {
+ printf("Could not close library handle: %s\n", dlerror());
+ }
+
+ if ((ec = load_world_from_file_(argc, argv, filepath, world))) {
+ goto fail;
+ }
+
+ printf("Hot starting world ...\n");
+ world->state = world->arkworld_export_rebirth(world, marshalled_state, sz);
+
+fail:
+ free(marshalled_state);
+ unlock(world);
+ return ec;
+}
+
+void world_run_requested_actions(world_t *world)
+{
+ lock(world);
+ requested_action_t requested_actions[MAX_QUEUED_ACTIONS];
+ size_t n_requested_actions = world->n_requested_actions;
+ memcpy(&requested_actions, world->requested_actions,
+ sizeof(requested_actions));
+ world->n_requested_actions = 0;
+ unlock(world);
+
+ size_t i;
+ for (i = 0; i < n_requested_actions; ++i) {
+ requested_actions[i].action(world, requested_actions[i].str_arg);
+ if (requested_actions[i].arg_dtor) {
+ requested_actions[i].arg_dtor(requested_actions[i].ptr_arg);
+ }
+ }
+}
+
+void world_cold_start(world_t *world)
+{
+ lock(world);
+ world->state = world->arkworld_export_enworld(world);
+ unlock(world);
+}
diff --git a/ark/src/soul_load.c b/ark/src/world_load.c
index fcf04a9..098c4b0 100644
--- a/ark/src/soul_load.c
+++ b/ark/src/world_load.c
@@ -1,37 +1,37 @@
-#include "soul.h"
+#include "world.h"
#include <dlfcn.h>
#include <stdio.h>
-#include "soul_exports.h"
+#include "world_exports.h"
-int load_soul_from_dl_(dlhandle_t dl, soul_t *soul)
+int load_world_from_dl_(dlhandle_t dl, world_t *world)
{
void *ptr;
int ret = 0;
- const char **name = dlsym(dl, "soul_name");
+ const char **name = dlsym(dl, "world_name");
if (name) {
- soul->soul_name = *name;
+ world->world_name = *name;
}
else {
- soul->soul_name = NULL;
+ world->world_name = NULL;
}
- soul->state = NULL;
- soul->library_handle = dl;
+ world->state = NULL;
+ world->library_handle = dl;
#define LOAD_SYM(ret_type, sym, args) \
do { \
ptr = dlsym(dl, #sym); \
if (!ptr) { \
- fprintf(stderr, "Soul missing %s\n", #sym); \
+ fprintf(stderr, "World missing %s\n", #sym); \
ret |= 1; \
} \
- soul->sym = (ret_type(*) args)ptr; \
+ world->sym = (ret_type(*) args)ptr; \
} while (0);
- ARKSOUL_EXPORTS(LOAD_SYM);
+ ARKWORLD_EXPORTS(LOAD_SYM);
#undef LOAD_SYM
diff --git a/cross/README.md b/cross/README.md
index cea84bb..b435e7c 100644
--- a/cross/README.md
+++ b/cross/README.md
@@ -2,21 +2,21 @@ Cross (Native Bridge Library)
=============================
Cross is a static C library (`libcross.a`) that provides native helper
-functions for a dynamically loaded soul to interact with the runtime and
+functions for a dynamically loaded world to interact with the runtime and
wlroots.
Why a static library?
---------------------
-These helpers are linked into the soul (`.so`) so they hot-reload along with
-the soul, instead of being stuck inside the long-running runtime process.
+These helpers are linked into the world (`.so`) so they hot-reload along with
+the world, instead of being stuck inside the long-running runtime process.
API surface
-----------
Public headers live in `cross/include`.
-- `cross/include/util.h`: soul-facing functions used via FFI, including:
+- `cross/include/util.h`: world-facing functions used via FFI, including:
- runtime requests (log/exit/hot-reload)
- seat access
- toplevel queries and basic positioning/geometry helpers
diff --git a/cross/include/util.h b/cross/include/util.h
index 3707ae1..bf89c2d 100644
--- a/cross/include/util.h
+++ b/cross/include/util.h
@@ -2,23 +2,23 @@
#define MONTIS_UTIL_H
/*
- * Runtime helpers exposed to souls. These operate on compositor state and are
- * intended for direct FFI use from a soul implementation.
+ * Runtime helpers exposed to worlds. These operate on compositor state and are
+ * intended for direct FFI use from a world implementation.
*/
void montis_do_request_hot_reload(void *plugv);
void montis_do_request_log(void *plugv, const char *str);
void montis_do_request_exit(void *plugv, int ec);
-void *arksoul_get_seat(void *ctx);
-void *arksoul_toplevel_at(void *ctx, double lx, double ly);
-void arksoul_get_toplevel_position(void *toplevel, double *x, double *y);
-void arksoul_set_toplevel_position(void *toplevel, double x, double y);
-void arksoul_get_toplevel_geometry(void *toplevel, double *x, double *y,
+void *arkworld_get_seat(void *ctx);
+void *arkworld_toplevel_at(void *ctx, double lx, double ly);
+void arkworld_get_toplevel_position(void *toplevel, double *x, double *y);
+void arkworld_set_toplevel_position(void *toplevel, double x, double y);
+void arkworld_get_toplevel_geometry(void *toplevel, double *x, double *y,
double *w, double *h);
-void arksoul_set_toplevel_geometry(void *toplevel, double x, double y,
+void arkworld_set_toplevel_geometry(void *toplevel, double x, double y,
double w, double h);
-void arksoul_focus_toplevel(void *toplevel);
-void arksoul_warp_cursor(void *ctx, double lx, double ly);
+void arkworld_focus_toplevel(void *toplevel);
+void arkworld_warp_cursor(void *ctx, double lx, double ly);
#endif /* MONTIS_UTIL_H */
diff --git a/cross/src/runtime_requests.c b/cross/src/runtime_requests.c
index adb2b2f..cf0955c 100644
--- a/cross/src/runtime_requests.c
+++ b/cross/src/runtime_requests.c
@@ -5,26 +5,26 @@
#include <stdlib.h>
#include <string.h>
-static int soul_hot_reload_same_state_action_(soul_t *soul, void *ignore)
+static int world_hot_reload_same_state_action_(world_t *world, void *ignore)
{
(void)ignore;
- return soul_hot_reload_same_state(soul);
+ return world_hot_reload_same_state(world);
}
void montis_do_request_hot_reload(void *plugv)
{
- soul_t *soul = plugv;
+ world_t *world = plugv;
- size_t n = soul->n_requested_actions++;
+ size_t n = world->n_requested_actions++;
if (n < MAX_QUEUED_ACTIONS) {
- soul->requested_actions[n].action = soul_hot_reload_same_state_action_;
- soul->requested_actions[n].arg_dtor = NULL;
+ world->requested_actions[n].action = world_hot_reload_same_state_action_;
+ world->requested_actions[n].arg_dtor = NULL;
}
}
-static int soul_do_log(soul_t *soul, void *chrs)
+static int world_do_log(world_t *world, void *chrs)
{
- (void)soul;
+ (void)world;
char *str = chrs;
puts(str);
return 0;
@@ -32,17 +32,17 @@ static int soul_do_log(soul_t *soul, void *chrs)
void montis_do_request_log(void *plugv, const char *str)
{
- soul_t *soul = plugv;
+ world_t *world = plugv;
- size_t n = soul->n_requested_actions++;
+ size_t n = world->n_requested_actions++;
if (n < MAX_QUEUED_ACTIONS) {
- soul->requested_actions[n].action = soul_do_log;
- soul->requested_actions[n].str_arg = strdup(str);
- soul->requested_actions[n].arg_dtor = free;
+ world->requested_actions[n].action = world_do_log;
+ world->requested_actions[n].str_arg = strdup(str);
+ world->requested_actions[n].arg_dtor = free;
}
}
-static int arksoul_do_exit(void *plugv, int ec)
+static int arkworld_do_exit(void *plugv, int ec)
{
(void)plugv;
exit(ec);
@@ -51,19 +51,19 @@ static int arksoul_do_exit(void *plugv, int ec)
void montis_do_request_exit(void *plugv, int ec)
{
- soul_t *soul = plugv;
+ world_t *world = plugv;
- size_t n = soul->n_requested_actions++;
+ size_t n = world->n_requested_actions++;
if (n < MAX_QUEUED_ACTIONS) {
- soul->requested_actions[n].action =
- (int (*)(soul_t *, void *))arksoul_do_exit;
- soul->requested_actions[n].int_arg = ec;
- soul->requested_actions[n].arg_dtor = NULL;
+ world->requested_actions[n].action =
+ (int (*)(world_t *, void *))arkworld_do_exit;
+ world->requested_actions[n].int_arg = ec;
+ world->requested_actions[n].arg_dtor = NULL;
}
}
-void *arksoul_get_seat(void *ctx)
+void *arkworld_get_seat(void *ctx)
{
- struct montis_server *server = wl_container_of(ctx, server, soul);
+ struct montis_server *server = wl_container_of(ctx, server, world);
return server->seat;
}
diff --git a/cross/src/util.c b/cross/src/util.c
index 0c02dfe..6497d89 100644
--- a/cross/src/util.c
+++ b/cross/src/util.c
@@ -6,7 +6,7 @@
static struct montis_server *server_from_ctx(void *ctx)
{
- struct montis_server *server = wl_container_of(ctx, server, soul);
+ struct montis_server *server = wl_container_of(ctx, server, world);
return server;
}
@@ -35,7 +35,7 @@ static struct montis_toplevel *toplevel_at(struct montis_server *server,
return tree ? tree->node.data : NULL;
}
-void *arksoul_toplevel_at(void *ctx, double lx, double ly)
+void *arkworld_toplevel_at(void *ctx, double lx, double ly)
{
if (!ctx) {
return NULL;
@@ -44,7 +44,7 @@ void *arksoul_toplevel_at(void *ctx, double lx, double ly)
return toplevel_at(server, lx, ly);
}
-void arksoul_get_toplevel_position(void *toplevel, double *x, double *y)
+void arkworld_get_toplevel_position(void *toplevel, double *x, double *y)
{
if (!toplevel || !x || !y) {
return;
@@ -54,7 +54,7 @@ void arksoul_get_toplevel_position(void *toplevel, double *x, double *y)
*y = tl->scene_tree->node.y;
}
-void arksoul_set_toplevel_position(void *toplevel, double x, double y)
+void arkworld_set_toplevel_position(void *toplevel, double x, double y)
{
if (!toplevel) {
return;
@@ -63,7 +63,7 @@ void arksoul_set_toplevel_position(void *toplevel, double x, double y)
wlr_scene_node_set_position(&tl->scene_tree->node, (int)x, (int)y);
}
-void arksoul_get_toplevel_geometry(void *toplevel, double *x, double *y,
+void arkworld_get_toplevel_geometry(void *toplevel, double *x, double *y,
double *w, double *h)
{
if (!toplevel || !x || !y || !w || !h) {
@@ -78,7 +78,7 @@ void arksoul_get_toplevel_geometry(void *toplevel, double *x, double *y,
*h = geo_box.height;
}
-void arksoul_set_toplevel_geometry(void *toplevel, double x, double y,
+void arkworld_set_toplevel_geometry(void *toplevel, double x, double y,
double w, double h)
{
if (!toplevel) {
@@ -89,7 +89,7 @@ void arksoul_set_toplevel_geometry(void *toplevel, double x, double y,
wlr_xdg_toplevel_set_size(tl->xdg_toplevel, (int)w, (int)h);
}
-void arksoul_warp_cursor(void *ctx, double lx, double ly)
+void arkworld_warp_cursor(void *ctx, double lx, double ly)
{
if (!ctx) {
return;
@@ -98,7 +98,7 @@ void arksoul_warp_cursor(void *ctx, double lx, double ly)
wlr_cursor_warp(server->cursor, NULL, lx, ly);
}
-void arksoul_focus_toplevel(void *toplevel)
+void arkworld_focus_toplevel(void *toplevel)
{
if (!toplevel) {
return;
diff --git a/montis/README.md b/montis/README.md
index cfe264e..f3974c2 100644
--- a/montis/README.md
+++ b/montis/README.md
@@ -1,30 +1,30 @@
-Montis (Haskell Window Manager Soul)
+Montis (Haskell Window Manager World)
====================================
Montis is the hot-reloadable window manager logic for the Ark runtime.
It builds to a shared object (`montis.so`) that Ark loads at runtime. You can
-edit/rebuild the soul and hot-reload it without restarting the compositor.
+edit/rebuild the world and hot-reload it without restarting the compositor.
Native interface
----------------
Montis talks to the runtime through:
-- the soul ABI defined by Ark (`ark/include/soul.h`), implemented in Haskell via
+- the world ABI defined by Ark (`ark/include/world.h`), implemented in Haskell via
`montis/src/Montis/Core/Internal/Foreign/Export.hs` and a small C shim
`montis/src/harness_adapter.c`.
-- the Cross bridge library (`libcross.a`), which provides soul-facing helper
+- the Cross bridge library (`libcross.a`), which provides world-facing helper
functions used via FFI (see `montis/src/Montis/Base/Foreign/Runtime.hs`).
Building
--------
-The soul is built by Stack, typically driven by the top-level CMake build:
+The world is built by Stack, typically driven by the top-level CMake build:
```sh
cmake -S .. -B ../build
-cmake --build ../build --target soul_build
+cmake --build ../build --target world_build
```
Or directly:
diff --git a/montis/src/Link.hs b/montis/src/Link.hs
index 9c0a07f..295d153 100644
--- a/montis/src/Link.hs
+++ b/montis/src/Link.hs
@@ -1,14 +1,14 @@
-- | Module that provides the start hooks using the config required to link the
--- soul's shared library.
+-- world's shared library.
module Link () where
import Config (config)
import Montis.Core
-foreign export ccall "arksoul_export_ensoul"
+foreign export ccall "arkworld_export_enworld"
coldStart :: MontisColdStart
-foreign export ccall "arksoul_export_rebirth"
+foreign export ccall "arkworld_export_rebirth"
hotStart :: MontisHotStart
coldStart :: MontisColdStart
diff --git a/montis/src/Montis/Base/Foreign/Runtime.hs b/montis/src/Montis/Base/Foreign/Runtime.hs
index 46507b5..5690b51 100644
--- a/montis/src/Montis/Base/Foreign/Runtime.hs
+++ b/montis/src/Montis/Base/Foreign/Runtime.hs
@@ -12,26 +12,26 @@ foreign import ccall "montis_do_request_log" foreign_doRequestLog :: Ptr Void ->
foreign import ccall "montis_do_request_exit" foreign_doRequestExit :: Ptr Void -> CInt -> IO ()
-foreign import ccall "arksoul_get_seat" foreign_getSeat :: Ptr Void -> IO (Ptr Void)
+foreign import ccall "arkworld_get_seat" foreign_getSeat :: Ptr Void -> IO (Ptr Void)
-foreign import ccall "arksoul_toplevel_at"
+foreign import ccall "arkworld_toplevel_at"
foreign_toplevelAt :: Ptr Void -> CDouble -> CDouble -> IO (Ptr ForeignMontisToplevel)
-foreign import ccall "arksoul_get_toplevel_position"
+foreign import ccall "arkworld_get_toplevel_position"
foreign_getToplevelPosition :: Ptr ForeignMontisToplevel -> Ptr CDouble -> Ptr CDouble -> IO ()
-foreign import ccall "arksoul_set_toplevel_position"
+foreign import ccall "arkworld_set_toplevel_position"
foreign_setToplevelPosition :: Ptr ForeignMontisToplevel -> CDouble -> CDouble -> IO ()
-foreign import ccall "arksoul_get_toplevel_geometry"
+foreign import ccall "arkworld_get_toplevel_geometry"
foreign_getToplevelGeometry ::
Ptr ForeignMontisToplevel -> Ptr CDouble -> Ptr CDouble -> Ptr CDouble -> Ptr CDouble -> IO ()
-foreign import ccall "arksoul_set_toplevel_geometry"
+foreign import ccall "arkworld_set_toplevel_geometry"
foreign_setToplevelGeometry :: Ptr ForeignMontisToplevel -> CDouble -> CDouble -> CDouble -> CDouble -> IO ()
-foreign import ccall "arksoul_focus_toplevel"
+foreign import ccall "arkworld_focus_toplevel"
foreign_focusToplevel :: Ptr ForeignMontisToplevel -> IO ()
-foreign import ccall "arksoul_warp_cursor"
+foreign import ccall "arkworld_warp_cursor"
foreign_warpCursor :: Ptr Void -> CDouble -> CDouble -> IO ()
diff --git a/montis/src/Montis/Core/Internal/Foreign/Export.hs b/montis/src/Montis/Core/Internal/Foreign/Export.hs
index 635955a..d3d5662 100644
--- a/montis/src/Montis/Core/Internal/Foreign/Export.hs
+++ b/montis/src/Montis/Core/Internal/Foreign/Export.hs
@@ -1,5 +1,5 @@
-- | This module has no public functions, but provides the surface interface
--- between the Montis runtime and the soul.
+-- between the Montis runtime and the world.
module Montis.Core.Internal.Foreign.Export () where
import Control.Monad (forM_)
@@ -64,11 +64,11 @@ runForeignWithReturn fn outptr stableptr = do
-- State marshal/export
-- | Marshals the opaque state to a C-style byte array and size pointer.
-foreign export ccall "arksoul_export_preserve"
- soulMarshalState :: OpqStT -> Ptr Word32 -> IO (Ptr Word8)
+foreign export ccall "arkworld_export_preserve"
+ worldMarshalState :: OpqStT -> Ptr Word32 -> IO (Ptr Word8)
-soulMarshalState :: OpqStT -> Ptr Word32 -> IO (Ptr Word8)
-soulMarshalState opqStT outlen = do
+worldMarshalState :: OpqStT -> Ptr Word32 -> IO (Ptr Word8)
+worldMarshalState opqStT outlen = do
(_, st) <- deRefStablePtr opqStT
let bs = CH.pack (marshalState st)
ret <- mallocBytes (BS.length bs)
@@ -80,11 +80,11 @@ soulMarshalState opqStT outlen = do
-- ----------------------------------------------------------------------
-- Input handlers
-foreign export ccall "arksoul_export_handle_button"
- soulHandleButton :: Ptr WlrPointerButtonEvent -> Word32 -> OpqStT -> IO OpqStT
+foreign export ccall "arkworld_export_handle_button"
+ worldHandleButton :: Ptr WlrPointerButtonEvent -> Word32 -> OpqStT -> IO OpqStT
-soulHandleButton :: Ptr WlrPointerButtonEvent -> Word32 -> OpqStT -> IO OpqStT
-soulHandleButton eventPtr modifiers =
+worldHandleButton :: Ptr WlrPointerButtonEvent -> Word32 -> OpqStT -> IO OpqStT
+worldHandleButton eventPtr modifiers =
runForeign $ do
s <- gets currentHooks
event <- liftIO $
@@ -107,8 +107,8 @@ soulHandleButton eventPtr modifiers =
-- ----------------------------------------------------------------------
-- Keybinding handler
-foreign export ccall "arksoul_export_handle_keybinding"
- soulHandleKeybinding ::
+foreign export ccall "arkworld_export_handle_keybinding"
+ worldHandleKeybinding ::
Ptr ForeignWlrInputDevice ->
Ptr WlrEventKeyboardKey ->
Word32 ->
@@ -118,7 +118,7 @@ foreign export ccall "arksoul_export_handle_keybinding"
OpqStT ->
IO OpqStT
-soulHandleKeybinding ::
+worldHandleKeybinding ::
Ptr ForeignWlrInputDevice ->
Ptr WlrEventKeyboardKey ->
Word32 ->
@@ -127,7 +127,7 @@ soulHandleKeybinding ::
Ptr CInt ->
OpqStT ->
IO OpqStT
-soulHandleKeybinding inputDevicePtr eventPtr mods sym cp =
+worldHandleKeybinding inputDevicePtr eventPtr mods sym cp =
runForeignWithReturn $ do
s <- gets currentHooks
event <- liftIO $
@@ -153,11 +153,11 @@ soulHandleKeybinding inputDevicePtr eventPtr mods sym cp =
-- ----------------------------------------------------------------------
-- Motion handler
-foreign export ccall "arksoul_export_handle_motion"
- soulHandleMotion :: Ptr Void -> Word32 -> Word32 -> CDouble -> CDouble -> OpqStT -> IO OpqStT
+foreign export ccall "arkworld_export_handle_motion"
+ worldHandleMotion :: Ptr Void -> Word32 -> Word32 -> CDouble -> CDouble -> OpqStT -> IO OpqStT
-soulHandleMotion :: Ptr Void -> Word32 -> Word32 -> CDouble -> CDouble -> OpqStT -> IO OpqStT
-soulHandleMotion eventPtr modifiers isAbsolute lx ly =
+worldHandleMotion :: Ptr Void -> Word32 -> Word32 -> CDouble -> CDouble -> OpqStT -> IO OpqStT
+worldHandleMotion eventPtr modifiers isAbsolute lx ly =
runForeign $ do
s <- gets currentHooks
event <- liftIO $
@@ -201,26 +201,26 @@ soulHandleMotion eventPtr modifiers isAbsolute lx ly =
-- | Function exported to the harness to handle the mapping/unmapping/deletion
-- of an XDG surface.
-foreign export ccall "arksoul_export_handle_surface"
- soulHandleSurface ::
+foreign export ccall "arkworld_export_handle_surface"
+ worldHandleSurface ::
Ptr ForeignWlrXdgSurface -> CInt -> OpqStT -> IO OpqStT
-soulHandleSurface ::
+worldHandleSurface ::
Ptr ForeignWlrXdgSurface -> CInt -> OpqStT -> IO OpqStT
-soulHandleSurface p t =
+worldHandleSurface p t =
runForeign $ do
s <- gets currentHooks
surfaceHook s (SurfaceEvent (toEnum $ fromIntegral t) (toSurface p))
-- | Function exported to the harness to handle the mapping/unmapping/deletion
-- of an XWayland surface.
-foreign export ccall "arksoul_export_handle_xwayland_surface"
- soulHandleXWaylandSurface ::
+foreign export ccall "arkworld_export_handle_xwayland_surface"
+ worldHandleXWaylandSurface ::
Ptr ForeignWlrXWaylandSurface -> CInt -> OpqStT -> IO OpqStT
-soulHandleXWaylandSurface ::
+worldHandleXWaylandSurface ::
Ptr ForeignWlrXWaylandSurface -> CInt -> OpqStT -> IO OpqStT
-soulHandleXWaylandSurface p t =
+worldHandleXWaylandSurface p t =
runForeign $ do
s <- gets currentHooks
surfaceHook s (SurfaceEvent (toEnum $ fromIntegral t) (toSurface p))
diff --git a/montis/src/Montis/Core/Monad.hs b/montis/src/Montis/Core/Monad.hs
index 0eee819..72b2321 100644
--- a/montis/src/Montis/Core/Monad.hs
+++ b/montis/src/Montis/Core/Monad.hs
@@ -23,7 +23,7 @@ type MontisContext = Context Montis
-- | A State type for the Montis monad.
type MontisState = State Montis
--- | The Opaque State Type passed between the soul and the runtime. The
+-- | The Opaque State Type passed between the world and the runtime. The
-- OpqStT *is* the opq_st_t from the runtime code.
type OpqStT = StablePtr (MontisContext, MontisState)
@@ -34,7 +34,7 @@ newtype Montis a where
deriving (Functor, Applicative, Monad, MonadState MontisState, MonadIO)
-- | Reader access is scoped to the config portion of the full context; this
--- keeps soul code from mutating the context while still allowing read-only
+-- keeps world code from mutating the context while still allowing read-only
-- access to configuration.
instance MonadReader MontisConfig Montis where
ask :: Montis MontisConfig
@@ -47,7 +47,7 @@ instance MonadReader MontisConfig Montis where
local cfn (Montis fn) =
Montis $ local (\ctx -> ctx {ctxConfig = cfn (ctxConfig ctx)}) fn
--- | Access the soul self pointer stored in the context.
+-- | Access the world self pointer stored in the context.
getSelfPtr :: Montis SelfPtr
getSelfPtr = Montis $ asks ctxSelfPtr
diff --git a/montis/src/Montis/Core/State.hs b/montis/src/Montis/Core/State.hs
index 6a2d5d0..3df06b2 100644
--- a/montis/src/Montis/Core/State.hs
+++ b/montis/src/Montis/Core/State.hs
@@ -10,11 +10,11 @@ import Montis.Core.Events
import Montis.Core.Extensions
import Text.Read (readMaybe)
--- | An opaque type used for the soul's self-reference.
+-- | An opaque type used for the world's self-reference.
newtype SelfPtr where
SelfPtr :: Ptr Void -> SelfPtr
--- | This is the context the soul operates under. The context contains data
+-- | This is the context the world operates under. The context contains data
-- which must be provided by the runtime or the configuration. This data may not
-- be cold-created.
--
diff --git a/montis/src/Montis/Core/Soul/Interface.hs b/montis/src/Montis/Core/World/Interface.hs
index 3271ab7..39d4e4c 100644
--- a/montis/src/Montis/Core/Soul/Interface.hs
+++ b/montis/src/Montis/Core/World/Interface.hs
@@ -1,5 +1,5 @@
--- | Provides the soul interface through foreign exports.
-module Montis.Core.Soul.Interface where
+-- | Provides the world interface through foreign exports.
+module Montis.Core.World.Interface where
import Data.ByteString (ByteString)
import Data.Data (Typeable)
diff --git a/montis/src/harness_adapter.c b/montis/src/harness_adapter.c
index fb5646c..b6c1979 100644
--- a/montis/src/harness_adapter.c
+++ b/montis/src/harness_adapter.c
@@ -4,25 +4,25 @@
// Currently these functions exclusively enable/disable the Haskell runtime.
#include "HsFFI.h"
-#include "soul_interface.h"
+#include "world_interface.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
-const char *soul_name = "Montis";
+const char *world_name = "Montis";
extern void performMajorGC();
-void arksoul_export_metaload(int argc, char** argv)
+void arkworld_export_metaload(int argc, char** argv)
{
// hs_init(&argc, &argv);
}
-void arksoul_export_load(int argc, char **argv) {
+void arkworld_export_load(int argc, char **argv) {
hs_init(&argc, &argv);
}
-void arksoul_export_release(opqst_t st) {
+void arkworld_export_release(opqst_t st) {
hs_exit();
}
@@ -34,10 +34,10 @@ void shell_exec(const char* cmd) {
}
static const char msg[] =
- "Montis Soul v 0.01\n\n"
+ "Montis World v 0.01\n\n"
"Welcome, and thank you for your interest.\n\n"
- "This is merely a soul for the Montis Compositor and not meant to be\n"
- "executed as a standalone binary. This soul requires a harness to run\n"
+ "This is merely a world for the Montis Compositor and not meant to be\n"
+ "executed as a standalone binary. This world requires a harness to run\n"
"To use this file, please use './wtr_harness [full-path-to-wtr.so]'\n"
"That will allow you to see how this compositor works in all its glory!\n";
static const int msg_sz = sizeof(msg);