- Introduction
- Implementations
- mitsuko core library
- *app-data-paths*
- *app-writable-path*
- *is-swank-available*
- *mitsuko-module*
- *mitsuko-path*
- *qml-application-engine*
- *qml-search-path*
- *swank-path*
- *swank-port*
- *wayland-terminals*
- (find-in-app-data file)
- (find-in-path program)
- (l library &optional fatal)
- (run-command command &optional path)
- (run-terminal)
- (shutdown)
- (start)
- mitsuko library
- float implementation
- ion4 implementation
- mitsuko core library
- References
This is an attempt to create a framework to easily create and modify Wayland compositors using QML and Lisp, as well as including one or more fully usable reference implementations.
While there are interesting projects like ulubis trying to build sensible compositors for Wayland they generally are far from usable, and due to the attempt to (re-)build all the low level Wayland stuff require a lot of work to get there. While it my eventually prove to be a bad decision basing this on top of Qt`s Wayland compositor code allows quick prototyping and reuse of a lot of existing code.
Mitsuko just has a very small compiled core to bootstrap the runtime, and loads everything else based on the initial user configuration. As this is written completely in QML and Lisp adjustments can be made quickly without recompiling the core binary, and in many cases even to a running instance.
For building you’ll need ecl, EQL5 and ecl-qmake - either as system wide packages or installed discoverable by qmake. For openSuSE packages exist on obs: ecl, EQL5 and ecl-qmake. Additionally the Qt5 devel packages for the Qt Wayland compositor need to be installed.
With all dependencies installed create a build directory, and run qmake and make from there:
$ mkdir build
$ cd build
$ qmake-qt5
$ make -j16
mitsuko tries to use the QPA platforms wayland, xcb and eglfs, in this order. Any other platforms can be used by specifying the -platform
argument. In some cases one or more of the following variables need to be set:
- QT_XCB_GL_INTEGRATION=xcb_egl
- QT_WAYLAND_CLIENT_BUFFER_INTEGRATION=xcomposite-egl
- QML2_IMPORT_PATH=/path/to/qml/modules/top/dir:/path/to/other/dir
- MITSUKO_PATH=/path/to/lisp/topdir:/path/to/other/dir
- QT_LOGGING_RULES=qt.qpa.input=true to debug input devices
- QT_QPA_ENABLE_TERMINAL_KEYBOARD=1 to keep the terminal keyboard active - mostly useful in case of crashes
On startup mitsuko searches for mitsuko-init.lisp
in the common data directories. It’ll then check if mitsuko-pre-init
and mitsuko-init
are defined. It’ll call them if defined, and otherwise fall back to builtin functions - which generally should be sufficient.
The only configuration absolutely required is setting the compositor module to use, either through the MITSUKO_MODULE
environment variable, or through mitsuko-core:*mitsuko-module*
. Without a valid configuration or missing resource files mitsuko will try to write a very simple compositor into *app-writable-path*/mitsuko-vanilla-main.qml
and start it.
Some compositor implementations also will need the qml-xwayland plugin needs to be installed and discoverable. When installed to a subdirectory of usr/lib64 or /usr/lib it’ll be discovered without additional configuration.
The run
script at the top level of the source directory will run mitsuko from the build directory, after setting up the environment to allow loading resources from the build directory as well as the source directory for QML/LISP. As the core binary should not change much in most cases a system wide installation with a subset of libraries in a local directory added to the search path should be sufficient, though. See the configuration section for details.
mitsuko tries to load a configuration file from ~/.local/share/mitsuko/mitsuko-init.lisp
at the very beginning. This allows both overriding of early startup functions as well as customising later behaviour:
(in-package :mitsuko-core)
(setf *mitsuko-module* "float")
(setf *wayland-terminals* '("qterminal"))
The startup goes through five phases:
- swank discovery
- pre-init
- init
- Qt UI startup
- post-init
mitsuko tries to locate a slime directory in one of the default directories by searching for slime/swank.asd
. Both a git checkout or an unpacked release should be fine.
To use an existing copy somewhere else *swank-path*
can be set to an absolute path to the directory contaniing swank.asd
in the init file. mitsuko core sets *swank-available*
to t
if it assumes swank is available, and loads the library. The default module loader starts the swank server just before loading the compositor modules.
The pre-init step creates the QML application engine, checks for the MITSUKO_MODULE
environment variable, configures additional QML module search paths and sets up a startup timer to run post-init hooks.
By defining a function called mitsuko-pre-init
this can be replaced with a custom implementation - but usually doing so is not recommended.
The init step tries to locate and load compositor module files, both QML and LISP. If no compositor module is found it’ll write out the minimal compositor to a file, and load that.
By defining a function called mitsuko-init
this can be replaced by a custom implementation - but this should no longer be necessary.
This happens in the C++ part, and just brings everything into a usable state. If fatal errors were triggered earlier teardown will happen as part of the early startup.
Per default this just triggers a log message from a Qt timer into LISP code to signal that startup is complete. By defining a mitsuko-post-init
function custom code can be executed after this message.
A compositor implementation must contain:
- one LISP file, named <implementation>.lisp, which must implement a package called
mitsuko-compositor
. This package must export a function calledinit-module
, and may export a function calledpost-init-module
. - one QML file, named <implementation>.qml, implementing a WaylandCompositor
(defpackage :mitsuko-compositor
(:use :cl :eql :mitsuko-core)
(:export
#:init-module
#:post-init-module))
(in-package :mitsuko-compositor)
(defun init-module()
"Compositor module initialisation run before loading the QML implementation"
)
(defun post-init-module()
"Compositor module initialisation run after loading the QML implementation"
)
The following libraries are loaded before compositor initialisation
- asdf
- quick
- mitsuko-core
- mitsuko and the bundled qml-lisp
A list of directories to search for LISP and QML files. Initialised from QStandardPaths::standardLocations(QStandardPaths::DataLocation).
To completely ignore the default paths something like this can be added to the user configuration file:
(setq *app-data-paths*
(nconc (list "/home/user/git/mitsuko/lisp/core"
"/home/user/git/mitsuko/lisp/ion4")
*app-data-paths*))
A directory used for writing out generated files. Initialised from QStandardPaths::writableLocation(QStandardPaths::DataLocation).
Initialised as nil
, and set to t
when swank has been located and loaded. This does not indicate if the server was started.
The name of the mitsuko module to use. Defaults to nil
, and must be set by either the MITSUKO_MODULE
environment variable, or through user configuration.
Additional directories for mitsuko to search LISP and QML files in. Directories listed here are searched first, followed by MITSUKO_PATH
environment variable, and then *app-data-paths*
.
The QQmlApplicationEngine object used for displaying the QML part. This gets initialised in vanilla-pre-init
- so if you decide to override that by defining mitsuko-pre-init
in your configuration you’ll need to create the object yourself.
When bypassing the default module initialisation by defining mitsuko-pre-init-module
QML loading can be implemented as follows:
(in-package :mitsuko-core)
(defun mitsuko-pre-init()
(x:do-with *qml-application-engine*
(|load| (|fromLocalFile.QUrl| (find-in-app-data "minimal.qml")))
;; add other settings for the application engine here
))
A list of directories to add to the QML search path. This is mostly required to find 3rd party QML extensions, like the XWayland extension. Defaults to '("/usr/lib64/qml" "/usr/lib/qml")
.
The path to swank. Defaults to nil
, and should be set to the full path of swank.asd
if swank is not in *app-data-paths*
. If swank is in *app-data-paths*
it will be discovered and this variable correctly configured on startup.
The port to start the swank server on. Defaults to 4005
.
A list of wayland terminals to use. Defaults to '("terminator" "qterminal" "kitty" "terminology" "alacritty")
.
Try to locate file
in *app-data-paths*
. If MITSUKO_PATH
environment variable is set directories listed there are searched first.
Try to locate program
in PATH
. Returns the complete path if found, nil
otherwise.
Try to qload
a file after locating it with find-in-app-data
.
If the second optional argument fatal
is set to t
this will shut down mitsuko if the library can’t be loaded - from inside a compositor that’s typically not the error handling you should be going for, though.
Run an arbitrary command, if found in PATH
. With the second optional path parameter the command is executed from there instead.
Start a terminal application. The first terminal from *wayland-terminals*
found in PATH
is used.
Shut down mitsuko. This can be called from QML via Lisp.call("mitsuko-core:shutdown")
.
Start up mitsuko. You probably will never need to call that yourself.
The core library provides code which is not implementation specific, like a variant of EQL5s qml-lisp
.
This implements a simple floating window manager.
This aims to be a tiling window manager, implementing the main features I use in ion3 to make switching for me as painless as possible. Those features are:
- use pretty much static frame layouts, with multiple applications possible per frame
- open a terminal in current frame with F2
- query for and open a man page in current frame with F1
- run arbitrary commands with F3
- query for and start a SSH connection with F4 (mosh with ALT+F4)
- open an Emacs frame attaching to an Emacs daemon with ALT+F5
- switch between frames and workspaces by keyboard navigation only
- have an easy to toggle scratch pad
- have an optional statusbar at the bottom of the screen
- improve on the scripting to allow most of the behaviour to be changed at runtime.
Currently there are experiments to decide if logic should come from the C++ side via MitsukoGridWM extension, or be fully done with QML only.