Skip to content

A tiling window manager for Windows 11, built with Rust.

License

Notifications You must be signed in to change notification settings

policastro/mondrian

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

80 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Mondrian

Mondrian is a tiling window manager built with Rust for Windows 11.

🌟 Key Features

  • Automatic/manual window placement with different tiling layouts;
  • Keybindings;
  • Multi-monitor support;
  • Mouse movements support (moving/resizing windows);
  • Compatible with Virtual Desktops;
  • System tray application;
  • Multiple animations;
  • Highly customizable.

Getting Started

Usage

To start Mondrian, just download the mondrian.exe executable from the latest release and run it.

The application takes the following arguments (all of them are optional):

./mondrian.exe --log <LOG_TYPE> --loglevel <LOGLEVEL>

Where:

  • <LOG_TYPE> can be 0 (no log file is created), 1 (error log files is created) or 2 (all log files are created). By default, it is set to 1.
  • <LOG_LEVEL> can be 0 (off), 1 (error), 2 (warn), 3 (info), 4 (debug) or 5 (trace). By default, it is set to 3.

All the log files will be stored in the application directory under the logs subfolder. When a log file reaches 10MB, it will be archived in a .gz file (up to three previous versions).

Moving windows

You can swap two windows in the same monitor just by dragging one of them into the other. While dragging, you can:

  • hold ALT, to swap the windows and to invert the direction of the tiles;

When the window is dragged to another monitor, by default it will be inserted. In this case, you can:

  • hold SHIFT while dragging the window to swap the windows;
  • hold ALT while dragging the window to insert the windows and to invert the direction of the tiles.

By changing the insert_in_monitor configuration option to false, the window will be swapped in the other monitor by default. In this case, you can:

  • hold SHIFT while dragging the window to insert the windows;
  • hold ALT while dragging the window to insert the window and to invert the direction of the tiles.

If you drag a window while holding CTRL, you can place the window freely based on the cursor position relative to an other window. In particular:

  • if the cursor is at the top of an other window (i.e. <=20% of its height), the moving window will be placed above it;
  • if the cursor is at the bottom of an other window (i.e. >=80% of its height), the moving window will be placed below it;
  • if the cursor is to the left of an other window (i.e. <=50% of its width), the moving window will be placed to the left of it;
  • if the cursor is to the right of an other window (i.e. >50% of its width), the moving window will be placed to the right of it.

Holding CTRL has the same effect when dragging the window to another monitor (by default).

You can set the free_move_in_monitor configuration option to true if you want to place the window freely in another monitor without holding CTRL (in this case, holding CTRL will position the window automatically).

Below a table that shows the keybindings for moving/swapping windows in different monitors, depending on the values of the insert_in_monitor and free_move_in_monitor configuration options:

insert_in_monitor free_move_in_monitor No key CTRL SHIFT ALT
false false/true swaps inserts freely inserts auto inserts auto + inverts tiles
true false inserts auto inserts freely swaps inserts auto + inverts tiles
true true inserts freely inserts auto swaps inserts auto + inverts tiles

If more than one modifier is held, the precedence order is as follows: ALT > CTRL > SHIFT.

Resizing windows

Windows can be resized as usual just by dragging their borders.

Configuration

Warning

The application is still evolving and changes between versions may introduce breaking changes. Be sure to check the release notes before updating.

Mondrian can be configured by editing the mondrian.toml file located in the ~/.config/mondrian directory. If the configuration file does not exist, it will be created automatically when the application starts. The configuration generated by the application can be found here.

Configuration options

Option Description Values Default
layout.tiling_strategy Tiling strategy "golden_ratio", "horizontal", "vertical", "twostep", "squared" "golden_ratio"
layout.animations_enabled Enables/disables the animations true, false true
layout.animations_duration Duration of the animations in ms 100 - 10000 300
layout.animations_framerate Framerate of the animations 10 - 240 60
layout.animation_type Animation type "linear"/any of the easings functions from https://easings.net/ (in snake_case) "linear"
layout.tiles_padding Padding between tiles 0 - 100 12
layout.border_padding Padding between border and tiles 0 - 100 18
layout.focalized_padding Padding between border and focalized window 0 - 120 8
layout.insert_in_monitor If true, moving the window to a new monitor inserts it rather than swapping true, false true
layout.free_move_in_monitor If true, free moving the window to a new monitor is enabled by default true, false false
layout.golden_ratio.ratio The ratio of the first split 10 - 90 50
layout.golden_ratio.clockwise Places the windows clockwise or counterclockwise true, false true
layout.golden_ratio.vertical If true, the layout will be vertical true, false false
layout.twostep.first_step First insertion direction "right", "left", "up", "down" "right"
layout.twostep.second_step Second insertion direction "right", "left", "up", "down" "down"
layout.twostep.ratio Ratio of the first split 10 - 90 50
layout.horizontal.grow_right If true, the layout will grow on the right side true, false true
layout.vertical.grow_down If true, the layout will grow on the bottom side true, false true
modules.keybindings.enabled Enables/disables the keybindings module true, false false
modules.keybindings.bindings Custom keybindings check the relative section for more info. -
modules.overlays.enabled Enables/disables the overlays module true, false true
modules.overlays.update_while_resizing Updates the overlays while resizing true, false true
modules.overlays.active.enabled Enables/disables the overlay for the active window true, false true
modules.overlays.active.thickness Thickness of the border 0 - 100 4
modules.overlays.active.padding Padding between the overlay and the window 0 - 30 0
modules.overlays.active.color Color of the overlay [r, g, b] or as hex string ("#rrggbb") [254, 74, 73] (or "#FE4A49")
modules.overlays.inactive.enabled Enables/disables the overlays for the inactive windows true,false true
modules.overlays.inactive.thickness Thickness of the border 0 - 100 4
modules.overlays.inactive.padding Padding between the overlay and the window 0 - 30 0
modules.overlays.inactive.color Color of the overlay [r, g, b] or as hex string ("#rrggbb") [254, 215, 102] (or "#FED766")
advanced.detect_maximized_windows Prevents maximized windows from being managed true, false true
core.rules Custom rules to exclude windows from being managed check the relative section for more info. -
core.move_cursor_on_focus Moves the mouse cursor to the center of the focused window true, false false
core.auto_reload_configs Reloads the configuration on changes true, false false

All the options are optional and if not specified, the default values will be used.

The only exception is for the modules.overlays.active.* and modules.overlays.inactive.* options. When at least one of them is specified, the other options will have the following default values:

  • modules.overlays.*.enabled = false;
  • modules.overlays.*.thickness = 0;
  • modules.overlays.*.padding = 0;
  • modules.overlays.*.color = [0, 0, 0].

Custom keybindings with modules.keybindings.bindings

You can specify custom keybindings with the modules.keybindings.bindings option. Each binding has the following format:

bindings = [
    { modifiers = "MODIFIERS", key = "KEY", action = "ACTION" } # "modifiers" can be also spelled as "modifier" or "mod"
]

The available modifiers are ALT, CTRL, SHIFT, WIN or any combination of them joined by + (e.g. ALT+SHIFT). This parameter is required, except when the key is a function key, in which case it can be omitted.

The available keys are:

  • alphanumeric keys (A to Z, a to z, 0 to 9);
  • arrow keys (up, down, left, right);
  • SPACE key;
  • symbols `, ', ., ,, ;, [, ], -, =, /, \;
  • function keys (F1 to F24).

The keys and modifiers are case-insensitive.

The available actions are:

  • refresh-config: reloads the configuration and restarts the application;
  • open-config: opens the configuration file in the default editor;
  • retile: re-tiles the windows;
  • minimize: minimizes the focused window;
  • focus <left|right|up|down>: focuses the window in the specified direction;
  • move <left|right|up|down>: swaps the focused window with the window in the specified direction;
  • insert <left|right|up|down>: adds the focused window in the monitor in the specified direction;
  • moveinsert <left|right|up|down>: first tries the move and then the insert action if no window is found in the specified direction;
  • resize <left|right|up|down> <40-250>: resizes the focused window in the specified direction by the specified amount;
  • invert: inverts the orientation of the focused window and the neighboring windows;
  • release: removes the focused window from the tiling manager, or adds it back;
  • focalize: focalizes the focused window (i.e. hides the neighboring windows) or unfocalizes it (i.e. restores the neighboring windows);
  • amplify: swaps the focused window with the biggest one in the same monitor;
  • pause [keybindings|overlays]: if no parameter is specified, pauses/unpauses the application. Otherwise, pauses/unpauses the specified module;
  • quit: closes the application.

The syntax of the actions is as follows:

  • action <v1|v2> means "action v1" or "action v2" (i.e. required parameter);
  • action [v1|v2] means "action", "action v1" or "action v2" (i.e. optional parameter);

Some examples:

[modules.keybindings]
enabled = true
bindings = [
    { key = "F4", action = "quit" },                                  # F4 to "quit"
    { modifiers = "WIN+ALT",  key = "F4", action = "release" },       # WIN+ALT+F4 to "release"
    { modifiers = "CTRL+ALT", key = "left", action = "focus left" }   # CTRL+ALT+Left to "focus left"
]

Ignore windows with core.rules

You can ignore windows with the core.rules option. Each rule has the following format:

[core]
rules = [
    { title = "TITLE", exename = "EXENAME", classname = "CLASSNAME" }
]

You can specify at least one or more parameters, and the rule will be matched if all the parameters match the corresponding window property. Each parameter can be either a string or a regex (enclosed in slashes). Some example:

[core]
rules = [
    { title = "Title", exename = "app.exe", classname = "ApplicationWindow" },    # match any window with a title="Title" and exename="app.exe" and classname="ApplicationWindow"
    { title = "Title" },                                                          # match any window with a title="Title"
    { title = "/Title[0-9]/" }                                                    # match any window with a title that matches the regex "Title[0-9]"
]

FAQ

1. Why another tiling window manager?

It sounded like a fun project to build, and I used it to learn Rust and the Win32 API.

In the beginning, I just wanted to build a simple tiling window manager for Windows, which allowed me to:

  • automatically place windows in the correct positions, in multiple monitors;
  • use the mouse to move and resize windows.

Then, I started working on it and new features were added. In any case, the main idea is to have an application that "just works" out-of-box, without any special configuration.

2. Are there any alternatives?

Yes, there are others tiling window managers for Windows out there. In particular, I used komorebi and GlazeWM before building this project. Both of them are really good and with great features, and they are in active development. If you need a more mature and established TWM, I recommend trying them.

3. Are there any options to improve the performance?

There are different configurations options that can improve the performances. Here the most important ones:

  • layout.animations_enabled = false: disables the animations;
  • layout.animations_framerate: you can set this option to reduce the framerate of the animations;
  • modules.overlays.enabled = false: disables the overlays (both the "active" and "inactives" ones);
  • modules.overlays.update_while_resizing = false: the overlays will be updated only when the window resize operation is done;
  • modules.overlays.active.enabled = false: disables the "active" overlay;
  • modules.overlays.inactive.enabled = false: disables all the "inactives" overlays;
  • advanced.detect_maximized_windows = false: disables the detection of maximized windows. Disabling this option doesn't work very well when the overlays are enabled.

4. How can I ignore a window?

If you want to ignore it temporarily, you can bind the release action to a key. Otherwise, you can create a rule in the configuration file (see the core.rules section).

License

This project is licensed under the GPLv3 license. See the LICENSE.md for more information.

Acknowledgments

About

A tiling window manager for Windows 11, built with Rust.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages