Oxide documentation
Oxide is a tiling window manager for X11. It is written in Rust and uses X11rb. This project idea is inspired by DWM, leftWM and i3WM.

Oxide screenshot
Contents
Introducing Oxide
Introduction
Terminology
Target group
The target group contains power users with advanced Linux knowledge.
Product functions
Config file
Oxide can be configured via its config file. This includes keybindings, appearance and more. Before editing, the global config file located under
/etc/oxide/config.yml
should be copied into the users home directory under
~/.config/oxide/config.yml
For a more detailed description of the config see configuration of Oxide.
Logging
Oxide log messages are written to
/var/log/syslog
Files
Per-user config file:
~/.config/oxide/config.yml
Global config file:
/etc/oxide/config.yml
Oxide desktop file:
/usr/share/xsessions/oxide.desktop
Bugs
Please open an issue on https://github.com/DHBW-FN/OxideWM/issues .
Project procedure
Customer specification (Lastenheft)
Product goal
Getting to know how window managers and Xorg work. Development of a working window manager.
Target group
Target group contains power users with advanced Linux knowledge.
Product functions
Fundamental
Basic
Desired
Documentation
Keeping track of tickets with timestamps.
Technical specification (Pflichtenheft)
Product functions
1. Fundamental
1.1 starting and quitting apps
The Oxide window manager should give the user the ability to start and quit applications through its interface.
1.2 tiling functionality
The software itself must support dynamic tiling, allowing the user to arrange applications in a grid-like arrangement optimizing screen space utilization. Along with this it shouis supposed to support both floating and static applications, giving the user flexibility in his window management.
1.3 moving windows
Therefore applications are expected to be moved around the screen by the user to different tiled positions or to float as a separate window.
1.4 controllable via keyboard
The user must be able to control all aspects of the applications by using keyboard shortcuts.
1.5 controllable via IPC
The user must be able to control all aspects of the applications by using the IPC interface.
1.6 focusing windows
The software must support focusing on different windows, allowing the user to switch between applications.
1.7 key-forwarding
When a window is stated to be focused the keybord inputs must be directed to the focused application.
2. Basic
2.1 multiple workspaces
The software must support at least ten workspaces, allowing the user to create, quit and switch between different virtual desktops.
2.1.1 move window to workspace
The software must support moving a window to another workspace. When this functionality is executed, the windowmanager must: - remove the window from the old workspace - add the window to the new workspace
2.1.2 switching between workspaces
When this functionality of the window manager is executed, the window manager must: - display all windows that were opened or moved to this screen (if fullscreen is not active).
2.1.3 closing workspaces
When this functionality of the window manager is executed, the window manager must: - close all windows that are currently in this workspace - switch to another open one, so that the user is never on “no” workspace When the last workspace is closed, a new workspace must be created. The windowmanager must then switch to the newly created workspace.
2.2 config
The window manager must provide an interface for configuring various settings and options. This configuration must be human readable or must provide another interface so that an linux averse person can change the settings. There must be default values for the configuration elements, so that when a users configuration is incorrect, the windowmanager still starts. Furthermore, the configuration must be applied to the windowmanager, every time it is started.
2.2.1 keybindings
For every command, that the window manager provides, the user must be able to configure a keybinding specified as below. A keybinding must contain exactly one none modifier key such as 1, 2, A, B, … It can contain any combination of the following modifiers: Alt, Meta, Command, Shift. To enhance the configurability, the user must be able to assign multiple commands to a single keybinding.
2.2.2 autostart
Autostarting of applications must be supported, allowing the user to specify which applications should start automatically.
2.3 utilities
The window manager should integrate a taskbar providing astreamlined way to switch between open applications and workspaces. For this it is necessary to support popular utilities like Drun or Rofi.
3. Desired
3.1 multiple screens
The windowmanager must empower the user to use multiple screens connected to his computer.
3.1.1 multiple screens workspaces
To take full advantage of the multiple screens, the windowmanager must allow workspaces on every stream.
3.1.1 multiple screens moving windows
The windowmanager must provide a way, to move windows between workspaces across screens.
3.2 screen locking
Also power management features should be included, such as screen locking after a specified timeout to help conserve energy and improve security.
3.3 statusbar
The windowmanager should provide a statusbar of some sort, to keep track of which workspaces exist, and on which workspace the user currently operates.
4. Documentation
Keeping track of tickets with timestamps.
5. Data relevant for the user
The application will be running locally so it needs to be downloaded and installed by the user before using it for the first time. Files needed for configuration will be stored locally.
6. Product performance - requirements
Claim is having no delay between key inputs and the following action. If possible, visible tasks should be performed in under a 24th of a second. This is not possible for opening application windows.
7. Quality requirements
Randomly crashing must not happen. If configurations are invalid they should be overwritten by default values. The config file should be formatted as JSON.
8. User Interface
Controlling the window manager will only be possible by using the keyboard. A mouse can be used to focus on individal frames and interact with application interfaces like webbrowsers.
9. Non-functional requirements
An installer with package manager cargo is required.
10. Project enviroment
10.1. Software
The product is supposed to be used on Unix based operating systems with an X11 instance running. Furthermore there is no other running window manager accepted.
10.2. Hardware
Required hardware is at least one monitor as well as a keyboard working with the operating system. There are no hardware limitations.
10.3 Organizational framework
Since the code is licensed with GPL v3 there are no conflicts with GPL licensed libraries.
10.4 Product interface
The behavior of the window manager can be customized by changing the config files. Program actions will be stored in log files located under TODO .
11. Special requirements
11.1 Software
buildin crate log for logging
Zbus for IPC
Serde for parsing
11.2 Development interfaces
X11 API
D-Bus
Project handbook
General project schedule
Researching technologies
All research results and discussions will be stored in the concepts
folder. All documents will be written in markdown - there are no other
formal restrictions.
Ticketing
Every task will be documented with a Git issue. The current status will be kept updated for the following states:
TODO
in progress
open for review
done
Branching
Every issue will get its own branch. A feature branch will be named after the following guideline:
feature/ISSUE<ISSUENUMBER>-<Featurename>
A bugfix branch will be named after the following guideline:
bug/ISSUE<ISSUENUMBER>-<Featurename>
The feature branches can freely be branched for testing purposes. These sub-branches can be merged back into to top-branch without any pull requests.
Crossbranching between feature branches is prohibited.
Every merge into the main
branch has to be accepted and reviewed
through a pull request. There should not be any rebase onto main
.
Working methods on the feature branches are open to developer.
Testing
All test logs are to be stored in the subdirectory test_logs
. Those
will not be published on GitHub. Upcoming issues should be documented
with Git issues with the following format:
Titel: error-code
error description
\```
stackstrace
\```
Unittest
Logs from unittests are to be stored in test_logs/unittests
. At the
end of the project all logs should be pushed to GitHub with one commit.
Unittests can be documented with their source code. The output has to be
logged and saved.
Manual tests
Manual tests are stored in test_logs/manual
. At the end the logs
should be commited like the unittest logs. These logs are formatted like
the following:
# Testname_Testdate
## Content
... What was tested? ...
## Test results
... Which errors occured, which functions worked? ...
Logging
Logging should work with the following levels:
info
trace
warn
Scrum
Sprint duration: 1 week Sprint-Meeting: weekly while the lecture
Work package plan
Title |
Duration [weeks] |
---|---|
Planning |
3 |
Project setup |
2 |
Concepts |
3 |
Fundamental features |
6 |
Basic features |
5 |
Testing |
6 |
Desired features |
3 |
Feature freeze / bug fixing |
2 |
Presentation planning |
2 |
Hint
If the work package plan is not shown big enough to read, please click on it.

work package plan
Technologies
Critical technologies
Rust as implementation language
This document outlines why rust has been chosen as the language of implementation for this project. But it needs to be mentioned that this choice was not purely made out of technical reasoning, because we think rust is fun and we enjoy to learn this language.
Technical arguments for Rust
Rust is a good choice for a system level language as it allows direct memory acces but also object orientation and offers a memory safe environment. Further this is achieved without a resource intensive garbage collection and high speeds in the realm of C are possible. Even though rust is still “relatively” new, it already has a stable ecosystem and a lot of libraries supporting it.
A first search for rust libraries allowing connections to the X-Server shows multiple results. The same is true for dbus- and IPC-libraries.
Therefore Rust seems to be a good choice for our project.
Inter Process Communication (IPC)
During a first discussion it was decided that Oxide should be controllable via an IPC mechanism. This functionality will be inspired by i3-msg.
Description
An IPC mechanism for the window manager is required. This is neccessary for:
Taskbar
External libraries
Command line utility
Feature list
The following list includes currently proposed features
everything that is achievable via the keyboard (kill, move, launch…)
current state of the window manager including e.g. layout or windows
IPC integration solution
Since there are two types of events that have to be handled, there needs to be some separation between them.
One type are xevents
, received from the X11
instance, and the
other one is custom events created by the user, received over zbus
.
For this reason, each type of event will get its own loop on its own thread, which will await them and push them into a list shared between them. The events in this list will be taken care of by the window manager, who will execute the correct action based on event type and content.

IPC queue
Technical solution
The following sections describe the argument for the different IPC-mechanisms and libraries.
Requirements
As for the aforementioned use cases it will not be required to send large amounts of data. Only short messages will be exchanged between the clients. Also it is not expected that the IPC performance will have a significant impact on the usability of the system. Therefore some IPC options such as shared memory and semaphores will not be regarded as these options are not as easy to use and do not offer any significant advantages.
Possible IPC mechanisms
There are multiple different ways of implementing IPC on posix systems.
FIFO
work like normal pipes, but are a permanent file on the system
fasted regarded option
good library support
Unix Sockets
work like TCP sockets
very fast IPC mechanism
easy to use and inbuilt library support
D-Bus
high level IPC mechanism
based on unix sockets
widely used in projects such as Gnome and KDE
offers message queuing, tow way communication and is supposed to offer a easy to use interface
comparetively slow compared to FIFO or UNIX sockets
Key Takeaways
TCP Sockets are only about 16% slower compared to FIFO
IPC performance is in most cases not the bottleneck
Sockets allow for two way communication
Sockets are more widely supported
IPC interface should be abstracted, so that the IPC mechanism can be changed in a later stage
D-Bus should offer a high level, simple to use IPC mechanism
Conclusion
After a technical discussion with the team the conclusion came to that D-Bus is most suitable. The performance is deemed non critical in our use case and the ease of use will be benefitial for the project. None the less, the IPC interface should be created in an abstract manner allowing for a possible replacement of the underlying IPC mechanism.
Implementation
Available libraries
There seem to be two main projects striving to provide D-Bus support for rust.
official D-Bus rust implementation by the freedesktop.org foundation
pure rust implementation
extensive documentation
examples
wrapper library for libdbus -> libdbus dependency - examples
Conclusion
Zbus seems to have some advantages over D-Bus-rs, mainly: - official freedesktop.org library - pure rust -> no libdbus dependency - Extensive documentation - Due to being an official library, maintenance is most likely certain
Therefore we came to the conclusion to use zbus as our IPC library.
Conclusion
As IPC-mechanism dbus was chosen as most suitable. The rust library zbus has been chosen as implementation.
Reactiveness
The window manager should at all stages be reactive and only use a minimal amount of resources. In order to assure this polling of threads should never be implemented.
Event Sources
Events for the window manager can be created by multiple sources.
X-Events
Generated by the X-Server and regarding userinput, clients requests and more.IPC-Events
Generated via the IPC-mechanism by the user or programs running on the system.
In order to be able to handle these two event sources two possible solutions are available:
Polling of both event-sources
This layout allows for a very simple single threaded implementation of the window manager but requires a frequent polling loop in order to allow for a reactive behavior.
Therefore this layout is not suitable for our requirements as this would be very inefficient.
Multithreaded queues

IPC-queue
This layout requires three different queues. 1. X-Event queue -> waits until an x-event is received 2. IPC-Event queue -> waits until an IPC-event is reveived 3. mainloop -> waits for an event forwarded to the mainevent-queue by the above mentioned threads
If implemented in the above shown way, no polling is required. This therefore allows to sleep the threads until an event is received and the kernel wakes up the thread. It therefore will be very reactive and use only minimal resources.
=> Therefore we will implement this layout.
Technical solution
Waiting for event
The following documents functions of the chosen libraries that support waiting for an event:
X-Event The
x11rb
library supports waiting on an event: wait_for_event methodIPC-Event Zbus is asynchronous in nature. The handling functions are registered to the server and executed when an event is received. Zbus Example
mainloop as shared queue the channel implementation of the rust standard library was chosen. This allows to wait for an event: recv method
XCB
This document covers some basics of XCB. This contains strengths and weaknesses and other aspects worth mentioning when trying to decide between it and Xlib.
All information was pulled from the XCB tutorial.
What is XCB
It is a alternative to the X-server interface Xlib. Both offer the ability to communicate with a systems x-server, which is a crucially important aspect of a window manager.
XCB eliminates the need for programs to implement the X protocol layer by offering low-level access to X-servers. Since the protocol is standardized, it is possible to talk to any X-server with XCB.
What does XCB provide over Xlib
Toolkit implementation
Direct protocol programming (see section Why not to use XCB)
Leightweight emulation of commonly used portions of the Xlib API
XCB does not lock itself while waiting for a response it send to a x-server instance like Xlib. This avoids needless stalling while a request is processed. Instead, XCB binds a cookie to a request which can then be used to ask for a pointer to the corresponding reply. This not only enables reading of the reply only when it is required, but also is ~5 times faster then locking while waiting for a reply.
Latency comparison
Request:
W
Reply:
R
No action:
-
Amount of send requests:
N
Xlib
Due to how Xlib works, a request-reply cycle works like this:
W-----RW-----RW-----RW-----R
The total time is N * (T_write + T_round_trip + T_read)
.
XCB
XCBs request-reply cycle looks like this:
WWWW--RRRR
The total time is
N * T_write + max(0, T_round_trip - (N-1) * T_write) + N * T_read
.
Conclusion
XCB offers considerably faster event handling. The tutorial linked at the top of this document also proiveds the source code and results of a benchmarking which leads to the same results.
Why to not use Xlib
Xlib is quite big: Xlib is bigger then XCB and can therefore not be used with minimalistic systems. However, the target groups of this project are (semi-)well equiped computers, which makes this not as much of an advantage.
Latency: Xlib manages events synchronously, with the principle of first in, first out (fifo). This can cause delays when dealing with a bigger amount of events within a short notice.
Multithreading: XCB appears to support this feature. Xlib can to some degree work with multiple threads too but its API was not designed for this purpose which makes it difficult to work with as well as error-prone.
Why not to use XCB
Direct protocol access: This can be good or not depending on the system an application will run on. Xlib performs chaching, layering and other optimizations by itself. XCB does not provide this feature.
Summary
XCB seems to be a lighter version of Xlib that also solves issues like multithreading while losing some optimizations such as caching in the process. However, XCB offers a considerably quicker request-reply method, which also allows reading of replies when necessary and does not force an aplication to do so when the response becomes available.
Window manager configuration
At the beginning of the project, it was decided to have an external config file which can be personalised freely. For this to happen a suitable file format had to be chosen.
File format
Typical file formats used for config files are JSON
, YAML
or
XML
. Due to poor readability, XML
has been ruled out from the
start. Unfortunately does JSON
not support any comments inside the
file, which was decided to be an important feature. Therefore it was
decided to use YAML
as the proper file format for Oxide config
files.
Technical implementation
The following sections describe the argument for the chosen parsing library.
Parsing the config file
The config file needs to be parsed before we can accesses the stored data. This should be as easy and effortless as possible. The preferred solution for this is to have a parser that outputs a single struct which contains all config values.
Library
The serde crate is the obvious choice for serialization and deserialization in the rust eco-system. It is widely supported and has subcrates such as serde_yaml for specific file formats.
Additionally features such as giving fiels default values when not part of the config are possible.
#[serde(default='default_value')]
Using this it is possible to use default values for not present or wrongly assigned variables.
Conclusion
After evaluating all aspects the team came to the conclusion to use YAML as file format and the serde_yaml crate as parser.
Programming paradigms
Client-Server model
event driven, functional, imperative, procedural, structured programming
Programming languages
Rust
bash/shell
Make
Development Environment
Posix
Xorg
Xephyr
CLion / Vim / Visual Studio Code
Hardware
Personal Computer
D-Bus interprocess communication (IPC)
D-Bus interface description
OxideWM has a D-Bus interface for IPC communication. This is primarily used in the Oxide-IPC
library.
This interface mainly gives access to the current state of Oxide. This state includes the loaded config, current windows, layouts, workspaces…
It also allows to execute oxide commands.
Interface
org.oxide.interface
D-Bus Method Calls
Returns the current OxideState as a JSON object:
get_state() -> String
Executes the given command:
sent_event(WmActionEvent) -> void
D-Bus Signal
Returns the current oxide state when change occurs to the subscribers:
state_change -> String
Testing Oxide
Running tests
Automated and integration tests can be run using the main makefile:
make test
Where to find test results
Automated test logs are exluded from version control to avoid cluttering. Manual test results and findings can be found in:
test/results
Unittests
Unittests are not used in this project due to the significant amount of human input required to complete them. Instead, integration and automated tests are used to test and validate features.
Integration tests
Since the project requires some very restrictive setup, like a connection to the X11 server, which can only be granted once at a time, intergration tests are very limited as well, due to them running in parallel. They are currently used to validate that the projects config parser works correctly, which includes checking for wrong datatypes or missing fields in the config file. Additionally, the creation- and switching-process of workspaces is tested.
Automated tests
In this project, an automated tests is defined as a test that is performed on the full build, but does not require any human input. This is useful for testing much of the basic functionality that the project should support after each new update while removing the significantly higher test duration a human reviewer would require.
Unfortunately it is not possible to test everything using this method, and issues found by this kind of tests have to be manually traced back to their origin as well, as the only information the testing framework has access to is a JSON-dump of the entire windowmanager.
Automated tests for this project work by using Xephyr
in combination
with oxide-msg
as well as a custom testing framwork tailored to make
writing new tests as simple as possible. The files relevant for
automated testing are located here:
test/resources
Manual tests
Manual tests are used to cover all other areas ignored by the previous testing methods.
dmenu
In addition, this type of test is used to narrow down issues after they are discovered by automated tests.
Diagrams
Components and behavior diagrams
The individual components and their behavior in certain situations are shown below.
Hint
If the diagrams are not shown big enough to read, please click on them.
Components

components
Change request

behaviour while incoming change request
New application

behaviour when new application is demanded
New application user perspective

behaviour when new application is demanded from the user perspective
Switch workspace user perspective

behaviour when a new workspace is selected from the user perspective
Switch workspace user perspective

behaviour what happens during a config change from the user perspective
HMI behavior
The individual components and their behavior in certain situations are shown below.
Hint
If the diagrams are not shown big enough to read, please click on them.
Horizontal layout

horizontal layout
Vertical layout

vertical layout
Tiled layout

tiled layout
Workspaces in statusbar

workspace 3 is active
Flowcharts
The following flowcharts show the technical structure and sequence of the product.
Hint
If the diagrams are not shown big enough to read, please click on them.
Main event loop

main event loop
Instantiation

instantiation
Eventhandling

eventhandling
Communication window manager and statusbar

window manager and statusbar communicating
Register keybinds

register keybinds
Getting associated keybind when key pressed

associated keybind for pressed key
Class diagrams
All shown class diagrams are automatically generated.
extensions
All shown class diagrams are automatically generated.
oxide-bar
Hint
If the diagrams are not shown big enough to read, please click on them.
config

config.png
main

main.png
xcb visualtype

xcb_visualtype.png
oxide-ipc
Hint
If the diagrams are not shown big enough to read, please click on them.
ipc

ipc.png
lib

lib.png
oxide-msg
Hint
If the diagrams are not shown big enough to read, please click on them.
main

main.png
windowmanager
All shown class diagrams are automatically generated.
config
Hint
If the diagrams are not shown big enough to read, please click on them.
commands

commands.png
config

mod.png
eventhandler
Hint
If the diagrams are not shown big enough to read, please click on them.
events

events.png
eventhandler

mod.png
screeninfo
Hint
If the diagrams are not shown big enough to read, please click on them.
error

error.png
screeninfo

mod.png
setup
Hint
If the diagrams are not shown big enough to read, please click on them.
connection

connection.png
windowmanager
Hint
If the diagrams are not shown big enough to read, please click on them.
windowmanager

mod.png
workspace
Hint
If the diagrams are not shown big enough to read, please click on them.
workspace

mod.png
parse error

parse_error.png
workspace layout

workspace_layout.png
Hint
If the diagrams are not shown big enough to read, please click on them.
auxiliary

auxiliary.png
ipc

ipc.png
keybindings

keybindings.png
main

main.png
windowstate

windowstate.png
Using Oxide
Installation
Prerequisits
Rust needs to be installed. After it has been installed, restart the terminal session, so that any new environment variables are loaded.
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Build tools need to be install:
sudo apt install git make build-essential libglib2.0-dev libcairo2-dev libpango1.0-dev kitty xterm
Installation
Clone the Oxide git repository:
git clone https://github.com/DHBW-FN/OxideWM.git
Install Oxide via make:
cd OxideWM
make install
Configuration
Description
Define the behavior of Oxide. The config file provides the possibility to customize e. g. keybindings, layout, style. If the home config file is not existing, default values will be used but commands like exec and exec_always will not be working. The config file is written in YAML.
Files
During launch, Oxide searches for a config file in the following locations:
Home config file:
~/.config/Oxide/config.yml
System config file:
/etc/Oxide/config.yml
Keybindings
Keys
A keybinding has to consist of at least one or more MODIFIERS and exactly one normal key such as ‘t’ for example.
Modifier
Commands
Commands consist of a command and optional arguments.
Commands (COMMAND)
Arguments (ARGS)
Command arguments are necessary for the movement, the layout or to control workspaces.
Movement (MOVEMENT)
Layout (LAYOUT)
Workspace arguments (WORKSPACE_ARGS)
Iterations
The iteration commands provide the possibility to change between workspaces when given an iteration number as shown in the example down below.
Default keybindings
Here is a short overview of the default keybindings.
Borders
Execute
Examples
Keybindings
cmds:
- keys: ["M", "t"]
commands:
- command: Exec
args: "dmenu"
In this example pressing the meta key and ‘t’, a new dmenu window is opened.
Iterations
iter_cmds:
- iter: [1, 2, 3, 4, 5, 6, 7, 8, 9]
command:
keys: ["M", "C", "$VAR"]
commands:
- command: GoToWorkspace
args: "$VAR"
In this example using the ALT and CONTROL key paired with a number from one to nine, the user can go to the desired workspace.
$VAR
is a reference for the entered iterator.
Bugs
Please open an issue https://github.com/DHBW-FN/OxideWM/issues .
Configuration of statusbar
Description
Define the behavior of the statusbar for Oxide. The config file provides the possibility to customize the text and background color of the Oxide statusbar. The config file is written in YAML.
Files
During launch, Oxide bar searches for a statusbar config file in the following two locations.
Home config file:
~/.config/Oxide/bar_config.yml
System config file:
/etc/Oxide/bar_config.yml
Color
In order to configure the colors, they have to be entered in hexadecimal. If the colors are not defined, default values will be used.
Examples
color_bg: "0x008000" # green
color_txt: "0xFFFF00" # black
Bugs
Please open an issue https://github.com/DHBW-FN/OxideWM/issues .
Configuration of Oxide msg
Synopsis
oxide-msg [-h] | [-v] | [-c command] [-a argument]
Description
The oxide-msg is an IPC command tool allowing querying and messaging to Oxide via the commandline.
Options
WM commands (WM_COMMAND)
Movement (MOVEMENT)
Layout (LAYOUT)
Workspace arguments (WORKSPACE_ARGS)
Examples
cargo run -p oxide-msg -- -c "exec" -a "kitty"
cargo run -p oxide-msg -- --command "kill"
Bugs
Please open an issue https://github.com/DHBW-FN/OxideWM/issues .