diff options
| author | Josh Rahm <joshuarahm@gmail.com> | 2026-01-06 15:09:52 -0700 |
|---|---|---|
| committer | Josh Rahm <joshuarahm@gmail.com> | 2026-01-06 15:09:52 -0700 |
| commit | 68dd63f6b3de774863051b66e609a0ca4f4ac2a1 (patch) | |
| tree | a908ebced56be6fc14307b1a1dc304c47905f8e2 | |
| parent | 12f8ef6dbf8618aaa304d239fbfd3c1b7b4494d3 (diff) | |
| download | montis-68dd63f6b3de774863051b66e609a0ca4f4ac2a1.tar.gz montis-68dd63f6b3de774863051b66e609a0ca4f4ac2a1.tar.bz2 montis-68dd63f6b3de774863051b66e609a0ca4f4ac2a1.zip | |
[rebrand] to arken = runtime, montis = plugin
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | CMakeLists.txt | 20 | ||||
| -rw-r--r-- | README.md | 133 | ||||
| -rw-r--r-- | arken/CMakeLists.txt (renamed from rt/CMakeLists.txt) | 12 | ||||
| -rw-r--r-- | arken/include/plugin.h (renamed from rt/include/plugin.h) | 0 | ||||
| -rw-r--r-- | arken/include/plugin_types.h (renamed from rt/include/plugin_types.h) | 0 | ||||
| -rw-r--r-- | arken/include/util.h (renamed from rt/include/util.h) | 0 | ||||
| -rw-r--r-- | arken/include/wl.h (renamed from rt/include/wl.h) | 0 | ||||
| -rw-r--r-- | arken/src/plugin.c (renamed from rt/src/plugin.c) | 0 | ||||
| -rw-r--r-- | arken/src/util.c (renamed from rt/src/util.c) | 0 | ||||
| -rw-r--r-- | arken/src/wl.c (renamed from rt/src/wl.c) | 0 | ||||
| -rw-r--r-- | arken/tools/genbuild.pl (renamed from rt/tools/genbuild.pl) | 0 | ||||
| -rw-r--r-- | arken/tools/genintf.pl (renamed from rt/tools/genintf.pl) | 0 | ||||
| -rw-r--r-- | montis/README.md (renamed from plug/README.md) | 0 | ||||
| -rw-r--r-- | montis/package.yaml (renamed from plug/package.yaml) | 2 | ||||
| -rw-r--r-- | montis/src/Config.hs (renamed from plug/src/Config.hs) | 0 | ||||
| -rw-r--r-- | montis/src/Link.hs (renamed from plug/src/Link.hs) | 0 | ||||
| -rw-r--r-- | montis/src/Montis/Base/Foreign/Runtime.hs (renamed from plug/src/Montis/Base/Foreign/Runtime.hs) | 0 | ||||
| -rw-r--r-- | montis/src/Montis/Base/Foreign/WlRoots.hs (renamed from plug/src/Montis/Base/Foreign/WlRoots.hs) | 0 | ||||
| -rw-r--r-- | montis/src/Montis/Base/Foreign/WlRoots/Types.hs (renamed from plug/src/Montis/Base/Foreign/WlRoots/Types.hs) | 0 | ||||
| -rw-r--r-- | montis/src/Montis/Core.hs (renamed from plug/src/Montis/Core.hs) | 0 | ||||
| -rw-r--r-- | montis/src/Montis/Core/Events.hs (renamed from plug/src/Montis/Core/Events.hs) | 0 | ||||
| -rw-r--r-- | montis/src/Montis/Core/Extensions.hs (renamed from plug/src/Montis/Core/Extensions.hs) | 0 | ||||
| -rw-r--r-- | montis/src/Montis/Core/Internal/Foreign/Export.hs (renamed from plug/src/Montis/Core/Internal/Foreign/Export.hs) | 0 | ||||
| -rw-r--r-- | montis/src/Montis/Core/Monad.hs (renamed from plug/src/Montis/Core/Monad.hs) | 0 | ||||
| -rw-r--r-- | montis/src/Montis/Core/Plugin/Interface.hs (renamed from plug/src/Montis/Core/Plugin/Interface.hs) | 0 | ||||
| -rw-r--r-- | montis/src/Montis/Core/Runtime.hs (renamed from plug/src/Montis/Core/Runtime.hs) | 0 | ||||
| -rw-r--r-- | montis/src/Montis/Core/Start.hs (renamed from plug/src/Montis/Core/Start.hs) | 0 | ||||
| -rw-r--r-- | montis/src/Montis/Core/State.hs (renamed from plug/src/Montis/Core/State.hs) | 0 | ||||
| -rw-r--r-- | montis/src/Montis/Core/State/Marshal.hs (renamed from plug/src/Montis/Core/State/Marshal.hs) | 0 | ||||
| -rw-r--r-- | montis/src/Montis/Foreign/Marshal.hs (renamed from plug/src/Montis/Foreign/Marshal.hs) | 0 | ||||
| -rw-r--r-- | montis/src/Montis/Standard/Drag.hs (renamed from plug/src/Montis/Standard/Drag.hs) | 0 | ||||
| -rw-r--r-- | montis/src/Montis/Standard/Keys.hs (renamed from plug/src/Montis/Standard/Keys.hs) | 0 | ||||
| -rw-r--r-- | montis/src/Montis/Standard/Mouse.hs (renamed from plug/src/Montis/Standard/Mouse.hs) | 0 | ||||
| -rw-r--r-- | montis/src/harness_adapter.c (renamed from plug/src/harness_adapter.c) | 0 | ||||
| -rw-r--r-- | montis/stack.yaml (renamed from plug/stack.yaml) | 0 | ||||
| -rw-r--r-- | montis/test/Spec.hs (renamed from plug/test/Spec.hs) | 0 |
37 files changed, 107 insertions, 62 deletions
@@ -1,4 +1,4 @@ -plug/.stack-work +montis/.stack-work *~ harness/build wtr.so diff --git a/CMakeLists.txt b/CMakeLists.txt index 18348ae..95296b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,32 +3,32 @@ project(montis LANGUAGES C) add_custom_target(wlroots_build ALL DEPENDS "${WLROOTS_LIB_LINK}") -add_subdirectory(rt) -add_dependencies(montis wlroots_build) +add_subdirectory(arken) +add_dependencies(arken wlroots_build) add_custom_target( plug_build ALL - COMMAND sh -c "if [ -d \"$1\" ] && [ ! -L \"$1\" ]; then rm -rf \"$2\"; mv \"$1\" \"$2\"; fi" sh "${CMAKE_SOURCE_DIR}/plug/.stack-work" "${CMAKE_BINARY_DIR}/stack-work" + 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}/plug/.stack-work" - COMMAND "${CMAKE_COMMAND}" -E chdir "${CMAKE_SOURCE_DIR}/plug" stack build + 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}/plug/a.out" - DEPENDS montis + COMMAND "${CMAKE_COMMAND}" -E rm -f "${CMAKE_SOURCE_DIR}/montis/a.out" + DEPENDS arken COMMENT "Building Haskell plugin 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:montis>\" -s foot -p \"$PLUGIN_SO\"" - DEPENDS montis plug_build + 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 USES_TERMINAL VERBATIM ) -install(TARGETS montis RUNTIME DESTINATION bin) +install(TARGETS arken RUNTIME DESTINATION bin) install(CODE [[ execute_process( @@ -1,44 +1,89 @@ -# Wetterhorn - -Wetterhorn is a wlroots-based Wayland compositor inspired by XMonad. It has a -unique harness-plugin architecture to support hot-reloading of some code. The -goal is to have as much code as feasible hot-reloadable. - -This is accomplished by Wetterhorn's architecture. It has 2 parts: - - - A harness, written in C, that provides the core of interacting with Wayland. - It is based off tinywl, dwl, weston and others. The window management and - event handling duties are stubbed out though, relying on a plugin to manage - those. - - - A plugin, written in Haskell, which provides the "configuration" for - handling events and window management. This plugin could theoretically be - replaced by any other program implementing the stubs. - - The aim is for the plugin to contain as much logic as possible as it is - likely to be written in a safe language. - -This architecture provides some benefits. - - 1. It provides speed where it counts by having the compositor bits being - written in a language like C. - - 2. It provides safety and expressiveness where it counts by having the logic - and handlers written in a higher level language, like Haskell. - - 3. Right now the harness and Haskell plugin are coupled together, but in the - future the boundary between the plugin and harness can be generalized to - allow different plugins to be used if one particularly does not like the - haskell implementation. - - 4. It enables hot-reloading. This is a huge benefit, and the main impetus for - this architecture. With X11, the Window Manager was a separate binary that - could be reloaded without killing the whole session. This is not the case - for Wayland because the Window Manager and Compositor are the same binary. - This is great for performance, but really bad for window managers like DWM - and XMonad which rely on the hot-swappability as these WMs source code _is_ - their configuration. - - Now, when a changes is made to the plugin, it can be hot-reloaded by the - harness, theoretically providing the best of both worlds in terms of - performance and configuration expressiveness. + +``` +Ladies and Gentlemen, this is + +• ▌ ▄ ·. ▐ ▄ ▄▄▄▄▄▪ .▄▄ · +·██ ▐███▪▪ •█▌▐█•██ ██ ▐█ ▀. +▐█ ▌▐▌▐█· ▄█▀▄ ▐█▐▐▌ ▐█.▪▐█·▄▀▀▀█▄ +██ ██▌▐█▌▐█▌.▐▌██▐█▌ ▐█▌·▐█▌▐█▄▪▐█ +▀▀ █▪▀▀▀ ▀█▄▀▪▀▀ █▪ ▀▀▀ ▀▀▀ ▀▀▀▀ +``` + +Montis is a pluggable Wayland compositor, designed to make *hot-pluggable window +management* a thing of the present ... again! + + +## What Is It + +Montis is intentionally split into two components, each with a very different role. + +### Arken -- The Runtime + +**Arken** 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 is deliberately lean: a harness, not an engine + +Arken exists to keep the window system alive while everything interesting +changes around it. + +### Montis -- The Window Manager + +Montis is the window management logic, written in Haskell. + +* It compiles to a shared object (.so) +* It is loaded into Arken 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 +runtime and wlroots itself. + +### Why This is Powerful + +Montis takes direct inspiration from XMonad. + +XMonad is often described as a window manager “configured in Haskell”, but +that’s misleading. In reality: + +* XMonad is a library +* Your “configuration” is just a cleverly hidden main +* You can rip the abstraction layer off entirely if you want +* The configuration language is arbitrarily powerful + +That power is fundamentally impossible to replicate with window managers that +invent their own configuration formats. + +However, XMonad has one major downside: + + Because the configuration is the window manager, changing it requires a full + recompile—and a restart. + +On X11, that’s fine. The window manager is a separate process from the windowing +system. + +On Wayland, that model collapses. The compositor is the window system. +Restarting it kills every GUI application. + +### Montis's Mandate + +Montis exists to answer a simple question: + + Can we get XMonad-style window management configuration on Wayland without + restarting the compositor? + +The constraints are strict: + +* Like XMonad, the configuration is the window manager +* Changes must not require restarting the window system +* No IPC-heavy control planes +* No bespoke configuration languages + +The solution is a pluggable architecture: + +* A persistent runtime (Arken) that owns wlroots and the Wayland lifecycle +* A hot-reloadable window manager (Montis) that owns behavior diff --git a/rt/CMakeLists.txt b/arken/CMakeLists.txt index 742d2f0..2bfd1d7 100644 --- a/rt/CMakeLists.txt +++ b/arken/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.10) project ( - montis + arken VERSION 0.1 LANGUAGES C) @@ -95,7 +95,7 @@ file (GLOB_RECURSE SOURCES src/*.c) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -add_executable (montis ${SOURCES} ${PLUGIN_LOAD} ${PLUGIN_INTF} ${WLROOTS_LIB_LINK} +add_executable (arken ${SOURCES} ${PLUGIN_LOAD} ${PLUGIN_INTF} ${WLROOTS_LIB_LINK} xdg-shell-protocol.c) find_package(PkgConfig REQUIRED) @@ -116,7 +116,7 @@ pkg_check_modules(WLREQ REQUIRED IMPORTED_TARGET glesv2 ) -target_link_libraries(montis PRIVATE PkgConfig::WLREQ dl pthread ${WLROOTS_LIB_LINK}) +target_link_libraries(arken PRIVATE PkgConfig::WLREQ dl pthread ${WLROOTS_LIB_LINK}) pkg_check_modules(WLOPT IMPORTED_TARGET cairo @@ -141,9 +141,9 @@ pkg_check_modules(WLOPT IMPORTED_TARGET ) if(WLOPT_FOUND) - target_link_libraries(montis PRIVATE PkgConfig::WLOPT) + target_link_libraries(arken PRIVATE PkgConfig::WLOPT) endif() -target_link_directories(montis PUBLIC +target_link_directories(arken PUBLIC "${WLROOTS_BUILD_DIR}") -target_link_options(montis PRIVATE -rdynamic) +target_link_options(arken PRIVATE -rdynamic) diff --git a/rt/include/plugin.h b/arken/include/plugin.h index 3098602..3098602 100644 --- a/rt/include/plugin.h +++ b/arken/include/plugin.h diff --git a/rt/include/plugin_types.h b/arken/include/plugin_types.h index df1eab5..df1eab5 100644 --- a/rt/include/plugin_types.h +++ b/arken/include/plugin_types.h diff --git a/rt/include/util.h b/arken/include/util.h index 2ed2f70..2ed2f70 100644 --- a/rt/include/util.h +++ b/arken/include/util.h diff --git a/rt/include/wl.h b/arken/include/wl.h index f10ee7d..f10ee7d 100644 --- a/rt/include/wl.h +++ b/arken/include/wl.h diff --git a/rt/src/plugin.c b/arken/src/plugin.c index 3edf486..3edf486 100644 --- a/rt/src/plugin.c +++ b/arken/src/plugin.c diff --git a/rt/src/util.c b/arken/src/util.c index e09cff9..e09cff9 100644 --- a/rt/src/util.c +++ b/arken/src/util.c diff --git a/rt/src/wl.c b/arken/src/wl.c index 8963e39..8963e39 100644 --- a/rt/src/wl.c +++ b/arken/src/wl.c diff --git a/rt/tools/genbuild.pl b/arken/tools/genbuild.pl index 1acabc0..1acabc0 100644 --- a/rt/tools/genbuild.pl +++ b/arken/tools/genbuild.pl diff --git a/rt/tools/genintf.pl b/arken/tools/genintf.pl index 794f966..794f966 100644 --- a/rt/tools/genintf.pl +++ b/arken/tools/genintf.pl diff --git a/plug/README.md b/montis/README.md index 5592f08..5592f08 100644 --- a/plug/README.md +++ b/montis/README.md diff --git a/plug/package.yaml b/montis/package.yaml index bd42ced..c381197 100644 --- a/plug/package.yaml +++ b/montis/package.yaml @@ -70,7 +70,7 @@ executables: - -O2 - -shared - -I../build/ - - -I../rt/include/ + - -I../arken/include/ - -I../build/wlroots/include - -I../build/wlroots-src/include - -DWLR_USE_UNSTABLE diff --git a/plug/src/Config.hs b/montis/src/Config.hs index 8ec06dd..8ec06dd 100644 --- a/plug/src/Config.hs +++ b/montis/src/Config.hs diff --git a/plug/src/Link.hs b/montis/src/Link.hs index 4ac3f5c..4ac3f5c 100644 --- a/plug/src/Link.hs +++ b/montis/src/Link.hs diff --git a/plug/src/Montis/Base/Foreign/Runtime.hs b/montis/src/Montis/Base/Foreign/Runtime.hs index 427545a..427545a 100644 --- a/plug/src/Montis/Base/Foreign/Runtime.hs +++ b/montis/src/Montis/Base/Foreign/Runtime.hs diff --git a/plug/src/Montis/Base/Foreign/WlRoots.hs b/montis/src/Montis/Base/Foreign/WlRoots.hs index 272567f..272567f 100644 --- a/plug/src/Montis/Base/Foreign/WlRoots.hs +++ b/montis/src/Montis/Base/Foreign/WlRoots.hs diff --git a/plug/src/Montis/Base/Foreign/WlRoots/Types.hs b/montis/src/Montis/Base/Foreign/WlRoots/Types.hs index c109653..c109653 100644 --- a/plug/src/Montis/Base/Foreign/WlRoots/Types.hs +++ b/montis/src/Montis/Base/Foreign/WlRoots/Types.hs diff --git a/plug/src/Montis/Core.hs b/montis/src/Montis/Core.hs index 5399f1e..5399f1e 100644 --- a/plug/src/Montis/Core.hs +++ b/montis/src/Montis/Core.hs diff --git a/plug/src/Montis/Core/Events.hs b/montis/src/Montis/Core/Events.hs index 91b8618..91b8618 100644 --- a/plug/src/Montis/Core/Events.hs +++ b/montis/src/Montis/Core/Events.hs diff --git a/plug/src/Montis/Core/Extensions.hs b/montis/src/Montis/Core/Extensions.hs index 0e8384f..0e8384f 100644 --- a/plug/src/Montis/Core/Extensions.hs +++ b/montis/src/Montis/Core/Extensions.hs diff --git a/plug/src/Montis/Core/Internal/Foreign/Export.hs b/montis/src/Montis/Core/Internal/Foreign/Export.hs index faa1964..faa1964 100644 --- a/plug/src/Montis/Core/Internal/Foreign/Export.hs +++ b/montis/src/Montis/Core/Internal/Foreign/Export.hs diff --git a/plug/src/Montis/Core/Monad.hs b/montis/src/Montis/Core/Monad.hs index b7d1633..b7d1633 100644 --- a/plug/src/Montis/Core/Monad.hs +++ b/montis/src/Montis/Core/Monad.hs diff --git a/plug/src/Montis/Core/Plugin/Interface.hs b/montis/src/Montis/Core/Plugin/Interface.hs index 73c0371..73c0371 100644 --- a/plug/src/Montis/Core/Plugin/Interface.hs +++ b/montis/src/Montis/Core/Plugin/Interface.hs diff --git a/plug/src/Montis/Core/Runtime.hs b/montis/src/Montis/Core/Runtime.hs index 0d4c905..0d4c905 100644 --- a/plug/src/Montis/Core/Runtime.hs +++ b/montis/src/Montis/Core/Runtime.hs diff --git a/plug/src/Montis/Core/Start.hs b/montis/src/Montis/Core/Start.hs index 54ec8c5..54ec8c5 100644 --- a/plug/src/Montis/Core/Start.hs +++ b/montis/src/Montis/Core/Start.hs diff --git a/plug/src/Montis/Core/State.hs b/montis/src/Montis/Core/State.hs index ce8f903..ce8f903 100644 --- a/plug/src/Montis/Core/State.hs +++ b/montis/src/Montis/Core/State.hs diff --git a/plug/src/Montis/Core/State/Marshal.hs b/montis/src/Montis/Core/State/Marshal.hs index 04a2a57..04a2a57 100644 --- a/plug/src/Montis/Core/State/Marshal.hs +++ b/montis/src/Montis/Core/State/Marshal.hs diff --git a/plug/src/Montis/Foreign/Marshal.hs b/montis/src/Montis/Foreign/Marshal.hs index 157d928..157d928 100644 --- a/plug/src/Montis/Foreign/Marshal.hs +++ b/montis/src/Montis/Foreign/Marshal.hs diff --git a/plug/src/Montis/Standard/Drag.hs b/montis/src/Montis/Standard/Drag.hs index a6ee878..a6ee878 100644 --- a/plug/src/Montis/Standard/Drag.hs +++ b/montis/src/Montis/Standard/Drag.hs diff --git a/plug/src/Montis/Standard/Keys.hs b/montis/src/Montis/Standard/Keys.hs index 0b670eb..0b670eb 100644 --- a/plug/src/Montis/Standard/Keys.hs +++ b/montis/src/Montis/Standard/Keys.hs diff --git a/plug/src/Montis/Standard/Mouse.hs b/montis/src/Montis/Standard/Mouse.hs index 933a2f4..933a2f4 100644 --- a/plug/src/Montis/Standard/Mouse.hs +++ b/montis/src/Montis/Standard/Mouse.hs diff --git a/plug/src/harness_adapter.c b/montis/src/harness_adapter.c index db5e7ce..db5e7ce 100644 --- a/plug/src/harness_adapter.c +++ b/montis/src/harness_adapter.c diff --git a/plug/stack.yaml b/montis/stack.yaml index 0faf47c..0faf47c 100644 --- a/plug/stack.yaml +++ b/montis/stack.yaml diff --git a/plug/test/Spec.hs b/montis/test/Spec.hs index cd4753f..cd4753f 100644 --- a/plug/test/Spec.hs +++ b/montis/test/Spec.hs |