the library that powers awm - forked from penrose

1 unstable release

Uses new Rust 2021

0.1.0 Jun 24, 2022

MIT license

11K SLoC

forked from (penrose)[https://github.com/sminez/penrose]


Penrose: a library for building your very own tiling window manager

Penrose is inspired by similar projects such as dwm, xmonad and qtile which allow you to configure your window manager in code and compile it for your system. It is most similar to xmonad in that it is more of a library for building a window manager (with low level details taken care of for you) rather than a minimal window manager that you edit and patch directly (such as dwm). Penrose strives to be as simple as possible in its implementation in order to make the guts of the window manager easier to understand. Given the nature of what this involves, this is not always possible but effort has been made to make the source readable and with relatively little magic.

Using Penrose

Penrose itself is not a binary application that you can build, install and run. You need to write your own main.rs as a rust binary crate that uses Penrose to set up, configure and run your very own window manager exactly how you want it. In short, you will need to write some code and you will need to know rust to some degree.

For learning rust itself, there are some fantastic official guides available on rust-lang.org and if you are sticking to using the out of the box functionality provided by the penrose crate, working through the book before diving into Penrose should be more than enough to get you started.

On GitHub you can find up to date examples of how to set up and configure penrose as your window manager, ranging from bare bones minimal to custom extensions and hooks.

Getting started

At it's simplest you will need to create a new binary crate to build your window manager and add penrose as a project dependency:

$ cargo new --bin my_penrose_config

As a bare minimum, you will need to the following in your main.rs:

  • keybindings (typically set up using the gen_keybindings macro)
  • A XConn instance to handle communication with the X server
  • A Config instance which contains the rest of your top level configuration for Penrose. Things like workspace names, layout functions and settings for gaps and borders.

With that, you will be able to create a WindowManager and start running Penrose after building and installing your binary. (It is also suggested that you set up a logging handler so that debugging any issues with your config is easier. simplelog is a good choice if you are unsure where to start with this.)


 extern crate penrose;

 use penrose::{
     Backward, Config, Forward, Less, More, WindowManager

 fn main() -> penrose::Result<()> {
     let key_bindings = gen_keybindings! {
         "M-j" => run_internal!(cycle_client, Forward);
         "M-k" => run_internal!(cycle_client, Backward);
         "M-S-j" => run_internal!(drag_client, Forward);
         "M-S-k" => run_internal!(drag_client, Backward);
         "M-S-q" => run_internal!(kill_client);
         "M-Tab" => run_internal!(toggle_workspace);
         "M-grave" => run_internal!(cycle_layout, Forward);
         "M-S-grave" => run_internal!(cycle_layout, Backward);
         "M-A-Up" => run_internal!(update_max_main, More);
         "M-A-Down" => run_internal!(update_max_main, Less);
         "M-A-Right" => run_internal!(update_main_ratio, More);
         "M-A-Left" => run_internal!(update_main_ratio, Less);
         "M-semicolon" => run_external!("dmenu_run");
         "M-Return" => run_external!("alacritty");
         "M-A-Escape" => run_internal!(exit);

         map: { "1", "2", "3", "4", "5", "6", "7", "8", "9" } to index_selectors(9) => {
             "M-{}" => focus_workspace (REF);
             "M-S-{}" => client_to_workspace (REF);

     let mut wm = new_xcb_backed_window_manager(
     wm.grab_keys_and_run(key_bindings, map!{})

Digging into the API

To add more functionality and flexability, you can start to add things like Hooks, a status bar and custom actions for running as part of key bindings. You will want to read the documentation of the core module which contains all of the core functionality of Penrose as a window manager. After that, the draw module contains utilities for rendering things like status bars and widgets, the contrib module has examples of simple hooks, extensions and key binding actions and the xcb module contains the referencing trait implementations for interacting with the X server via the XCB api.

NOTE: in order to use the xcb implementation of penrose, you will need to install the C libraries that are dependencies (namely xcb, Cairo and Pango).


~99K SLoC