Thanks for your interest in improving GlazeWM 💛
There are fundamentally three ways to contribute:
-
Opening issues: If you believe you've found a bug or have a feature request, open an issue to discuss it.
-
Helping triage issues: Add supporting details and suggestions to existing issues.
-
Submitting PRs: Submit a PR that fixes a bug or implements a feature.
The #glazewm-dev channel ⚡ is also available for any concerns not covered in this guide, please join us!
For PRs, a good place to start are the issues marked as good first issue
or help wanted
. PR's don't have a requirement to have a corresponding issue, but if there is one already, please drop a comment in the issue and we can assign it to you.
First fork, then clone the repo:
git clone git@github.com:your-username/glazewm.git
If not already installed, install Rust, then run:
# `cargo build` will build all binaries and libraries.
# `cargo run` will run the default binary, which is configured to be the wm.
cargo build && cargo run
After making your changes, push to your fork and submit a pull request against the main
branch. Please try to address only a single feature or fix in the PR so that it's easy to review.
If using VSCode, it's recommended to use the Rust Analyzer extension. Get automatic linting by adding this to your VSCode's settings.json
:
{
"rust-analyzer.check.command": "clippy"
}
Knowledge of the entire codebase should never be required to make changes. The following should hopefully help with understanding a particular part of the codebase.
GlazeWM is organized into several Rust crates:
wm
(bin): Main application, which implements the core window management logic.- Gets installed to
C:\Program Files\glzr.io\glazewm.exe
.
- Gets installed to
wm-cli
(bin/lib): CLI for interacting with the main application.- Gets installed to
C:\Program Files\glzr.io\cli\glazewm.exe
. This is added to$PATH
by default.
- Gets installed to
wm-common
(lib): Shared types, utilities, and constants used across other crates.wm-ipc-client
(lib): WebSocket client library for IPC with the main application.wm-platform
(lib): Wrappers over Windows APIs - other crates don't interact directly with the Windows APIs.wm-watcher
(bin): Watchdog process that ensures proper cleanup when the main application exits.- Gets installed to
C:\Program Files\glzr.io\glazewm-watcher.exe
.
- Gets installed to
GlazeWM uses a command-event architecture. The state of the WM (stored in WmState
) is modified via commands and events.
- Commands are run as a result of keybindings, IPC calls, the CLI (which calls IPC internally), or by being called from another command. Most commands are just for internal use and might not have a public-facing API.
- Events arise from the Windows platform (e.g. a window being created, destroyed, focused, etc.). Each of these events have a handler that then modifies the WM state.
Commands and events are processed in a loop in start_wm
.
Windows in GlazeWM are organized within a tree hierarchy with the following "container" types:
- Root
- Monitors (physical displays)
- Workspaces (virtual groups of windows)
- Split containers (for tiling layouts)
- Windows (application windows)
Here's an example container tree:
Root
|
+----------------+----------------+
| |
Monitor 1 Monitor 2
| |
+--------+--------+ |
| | |
Workspace 1 Workspace 2 Workspace 3
[horizontal] [vertical] [horizontal]
| | |
| | |
+----+----+ Tiling Window +-----+-----+
| | (Spotify) | |
Tiling Window | Tiling Window Floating Window
(Terminal) | (Discord) (Slack)
|
|
Split Container
[vertical]
|
+----+----+
| |
Tiling Window Tiling Window
(Chrome) (VS Code)
Windows can be either tiling (nested within split containers) or non-tiling (floating, minimized, maximized, or fullscreen). Non-tiling windows are always direct children of a workspace. Split containers can only have windows as children, and must have at least one child window.