{"id":17525654,"url":"https://github.com/yazeed1s/zwm","last_synced_at":"2026-01-18T01:11:05.186Z","repository":{"id":214116670,"uuid":"735721573","full_name":"yazeed1s/zwm","owner":"yazeed1s","description":"X11 tiling window manager","archived":false,"fork":false,"pushed_at":"2026-01-15T00:20:29.000Z","size":1828,"stargazers_count":89,"open_issues_count":5,"forks_count":6,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-01-15T07:10:04.503Z","etag":null,"topics":["c","linux","window-manager","x11","x11-wm","xcb"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yazeed1s.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-12-26T00:31:24.000Z","updated_at":"2026-01-15T00:19:15.000Z","dependencies_parsed_at":"2026-01-15T02:07:49.662Z","dependency_job_id":null,"html_url":"https://github.com/yazeed1s/zwm","commit_stats":null,"previous_names":["yazeed1s/zwm"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/yazeed1s/zwm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yazeed1s%2Fzwm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yazeed1s%2Fzwm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yazeed1s%2Fzwm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yazeed1s%2Fzwm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yazeed1s","download_url":"https://codeload.github.com/yazeed1s/zwm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yazeed1s%2Fzwm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28525694,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-18T00:39:45.795Z","status":"ssl_error","status_checked_at":"2026-01-18T00:39:39.467Z","response_time":85,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","linux","window-manager","x11","x11-wm","xcb"],"created_at":"2024-10-20T15:00:33.048Z","updated_at":"2026-01-18T01:11:05.168Z","avatar_url":"https://github.com/yazeed1s.png","language":"C","funding_links":[],"categories":["C"],"sub_categories":[],"readme":"### zwm\n\n## Table of Contents\n\n- [About ZWM](#about-zwm)\n- [Motivation](#motivation)\n- [Goals](#goals)\n- [Features](#features)\n- [The underlying data structure](#the-underlying-data-structure)\n- [Screenshots](#screenshots)\n- [Installation](#installation)\n- [Configuration](#configuration)\n- [Default Keybindings](#default-keybindings)\n- [ewmh specific settings for polybar](#ewmh-specific-settings-for-polybar)\n- [Contributing](#contributing)\n\n## About ZWM\n\nzwm is a minimalistic and opinionated tiling window manager for X11. It uses XCB instead of Xlib to communicate with the X server. The underlying data structure for managing windows is a customized BSP tree.\n\n## Motivation\n\nThe motivation behind zwm stems from a desire to create a window manager that is both lightweight and highly efficient, yet tailored to how I like to work. Sure, there are other great tiling window managers that perform well and offer robust features, but zwm was developed primarily as a learning exercise in creating a window manager from scratch.\n\n## Goals\n\n- Minimalism\n- Efficiency\n- Performance\n\n## Features\n\n- Compliance with a subset of [ewmh](https://specifications.freedesktop.org/wm-spec/wm-spec-1.3.html) and [icccm](https://www.x.org/releases/X11R7.6/doc/xorg-docs/specs/ICCCM/icccm.html)\n- Multiple Layouts (default, master, stack, grid).\n- Multiple virtual desktops.\n- Multi-monitor support.\n- Independent workspaces for each monitor by default.\n- Low memory footprint, runs within ~2MB of memory\n- Resize, flip, and swap windows or partitions.\n- Layouts apply to individual desktops.\n- Keyboard-Driven, fully controlled via keyboard shortcuts.\n- Mouse for convenience: move/resize for floating/tiled windows and partitions.\n- Drag-and-drop windows between partitions.\n- Customizable settings.\n- Customizable window rules.\n- Can be integrated with any status bar.\n- Can handle multiple bars per monitor/display, in different locations (top, bottom, left, right).\n- Config reload on the fly.\n\n## The underlying data structure:\n\nZWM uses **binary space partitioning tree** ([BSP-tree](https://en.wikipedia.org/wiki/Binary_space_partitioning)) to store and manage windows. This allows for more flexible layouts.\n\n- Each desktop has its own pointer to a bsp-tree.\n- The tree is a partition of a monitor's rectangle into smaller rectangular regions.\n- Each leaf node holds exactly one window.\n- Each node in a bsp-tree either has zero or two children.\n- Each internal node is responsible for splitting a rectangle in half.\n\n#### The following should illustrate how bsp-tree is used to achieve window management:\n\n```\n    Window and Partition Structure in a BSP-tree:\n\n    The layout of windows in BSPWM follows a binary tree structure:\n\n         I         ROOT (root is an INTERNAL NODE, unless it is a leaf by definition)\n       /   \\\n      I     I      INTERNAL NODES (screen sections/partitions)\n     / \\   / \\\n    E   E E   E    EXTERNAL NODES (windows/leaves)\n\n    - Internal Nodes (I) represent screen sections where windows can be displayed.\n    - External Nodes (E) represent the actual windows within those sections.\n    - Windows (E nodes) share the width, height, and coordinates (x, y) of their   parent sections (I nodes).\n\n    Example Structure:\n\n         I\n       /   \\\n      I     I\n     / \\   / \\\n    E   E E   I\n             / \\\n            E   E\n\n    Partition Behavior:\n    - Internal nodes (I) can contain other partitions or be contained within other partitions.\n    - External nodes (E) are the leaves (actual windows).\n\n    Example of tree:\n    - 1, 2, 3 are leaves/windows (EXTERNAL_NODE).\n    - a, b are internal nodes (INTERNAL_NODE), or screen sections/partitions.\n\n            1                               a                          a\n                                           / \\                        / \\\n                            ---\u003e          1   2         ---\u003e         1   b\n                                                                        / \\\n                                                                       2   3\n    Visualization of Screen Layout:\n\n    +-----------------------+  +-----------------------+  +-----------------------+\n    |                       |  |           |           |  |           |           |\n    |                       |  |           |           |  |           |     2     |\n    |                       |  |           |           |  |           |           |\n    |           1           |  |     1     |     2     |  |     1     |-----------|\n    |                       |  |           |           |  |           |           |\n    |                       |  |           |           |  |           |     3     |\n    |                       |  |           |           |  |           |           |\n    +-----------------------+  +-----------------------+  +-----------------------+\n\n    Another Example:\n    - Numbers are the are leaves/windows (EXTERNAL_NODE).\n    - Letters are internal nodes (INTERNAL_NODE), or screen sections/partitions.\n\n             a                             a                          a\n            / \\                           / \\                        / \\\n           1   b            ---\u003e         c   b         ---\u003e         c   b\n              / \\                       / \\ / \\                    / \\ / \\\n             2   3                     1  4 2  3                  1  d 2  3\n                                                             \t    / \\\n                                                                   4   5\n\n     +-----------------------+  +-----------------------+  +-----------------------+\n     |           |           |  |           |           |  |           |           |\n     |           |     2     |  |     1     |     2     |  |     1     |     2     |\n     |           |           |  |           |           |  |           |           |\n     |     1     |-----------|  |-----------|-----------|  |-----------|-----------|\n     |           |           |  |           |           |  |     |     |           |\n     |           |     3     |  |     4     |     3     |  |  4  |  5  |     3     |\n     |           |           |  |           |           |  |     |     |           |\n     +-----------------------+  +-----------------------+  +-----------------------+\n\n```\n\n## Screenshots:\n\n\u003cp align=\"left\"\u003e\n  \u003cimg src=\"https://github.com/Yazeed1s/zwm/blob/main/docs/img/img1.png\" width=\"1000\"\u003e\n\u003c/p\u003e\n\u003cp align=\"left\"\u003e\n  \u003cimg src=\"https://github.com/Yazeed1s/zwm/blob/main/docs/img/img2.png\" width=\"1000\"\u003e\n\u003c/p\u003e\n\u003cp align=\"left\"\u003e\n  \u003cimg src=\"https://github.com/Yazeed1s/zwm/blob/main/docs/img/img3.png\" width=\"1000\"\u003e\n\u003c/p\u003e\n\n## Installation\n\n#### Arch Linux (AUR)\n\n```bash\nyay -S zwm\n```\n\n#### Void Linux (XBPS)\n\n```bash\nxbps-install -S zwm\n```\n\n#### Build from source\n\n##### Dependencies\n\n- gcc\n- libxcb\n- xcb-util\n- xcb-util-keysyms\n- xcb-util-wm (ewmh,icccm)\n- lxcb-randr\n- lxcb-xinerama\n- lxcb-cursor\n\n```bash\ngit clone https://github.com/Yazeed1s/zwm.git\ncd zwm \u0026\u0026 sudo make install\n```\n\n## Configuration\n\n##### A config file will be generated when you first start `zwm`. The file can be found in the following location:\n\n- ~/.config/zwm/zwm.conf\n\n###### As of now, the following configs are offered:\n\n### 1- Config variables\n\n```ini\nborder_width = 2\nactive_border_color = 0x4a4a48\nnormal_border_color = 0x30302f\nwindow_gap = 10\nvirtual_desktops = 7\nfocus_follow_pointer = true\nfocus_follow_spawn = false\nrestore_last_focus = false\n```\n\n##### Available Variables:\n\n- **border_width**: Defines the width of the window borders in pixels.\n- **active_border_color**: Specifies the color of the border for the active (focused) window.\n- **normal_border_color**: Specifies the color of the border for inactive (unfocused) windows.\n- **window_gap**: Sets the gap between windows in pixels.\n- **virtual_desktops**: sets the number of virtual desktops.\n- **focus_follow_pointer**: If false, the window is focused on click; if true, the window is focused when the cursor enters it.\n- **focus_follow_spawn**: If false, new windows require manual focus (e.g., via click); if true, newly spawned windows will automatically receive focus.\n- **restore_last_focus**: If true, ZWM will restore the previously focused window when switching to a desktop, only if that desktop’s layout is not set to stack.\n\n### 2- Commands to run on startup\n\n##### Use the `exec` directive to specify programs that should be started when ZWM is launched.\n\n- For a single command:\n\n```ini\nexec = \"polybar\"\n```\n\n- To specify additional arguments as a list:\n\n```ini\nexec = [\"polybar\", \"-c\", \".config/polybar/config.ini\"]\n```\n\n### 3- Custom window rules\n\n##### Custom window rules allow you to define specific behaviors for windows based on their window class.\n\n##### Syntax:\n\n```ini\nrule = wm_class(\"window class name\"), state(tiled|floated), desktop(1..N)\n```\n\n##### Explanation:\n\n- **wm_class**: The window class name used to identify the window.\n    - Use the **`xprop`** tool to find the wm_class of a window.\n- **state**: Specifies whether the window should be tiled or floated.\n- **tiled**: The window will be tiled... clearly.\n- **floated**: The window will be floated... clearly.\n- **desktop**: The virtual desktop number where the window should be placed.\n    - Use **-1** if you do not want to set it to a specific desktop.\n\n```ini\n; Example:\nrule = wm_class(\"firefox\"), state(tiled), desktop(-1)\n; This rule sets \"firefox\" window to be tiled and does not change its virtual desktop.\n```\n\n### 4- Key bindings\n\n- The format for defining key bindings is: `bind = modifier + key -\u003e action`\n- If two modifiers are used, combine them with a pipe `(|)`. For example, alt + shift is written as `alt|shift`.\n- Note: Some functions require additional arguments to specify details of the action.\n- These arguments are provided using a colon syntax, where the function and its argument are separated by a colon.\n- Example: `func(switch_desktop:1)` means \"switch to desktop 1\".\n- Example: `func(resize:grow)` means \"grow the size of the window\".\n- Example: `func(layout:master)` means \"toggle master layout\".\n\n#### Available modifiers:\n\n- **super (meta)**, **alt**, **shift**, **ctrl**\n\n#### Available Actions:\n\n- run(...): Executes a specified process.\n    - Example: `bind = super + return -\u003e run(\"alacritty\")`\n    - To run a process with arguments, use a list:\n      Example: `bind = super + p -\u003e run([\"rofi\", \"-show\", \"drun\"])`\n\n- func(...): Calls a predefined function. The following functions are available:\n    - **kill**: Kills the focused window.\n    - **switch_desktop**: Switches to a specified virtual desktop.\n    - **fullscreen**: Toggles fullscreen mode for the focused window.\n    - **swap**: Swaps the focused window with its sibling.\n    - **transfer_node**: Moves the focused window to another virtual desktop.\n    - **layout**: Toggles the specified layout (master, default, stack).\n    - **traverse**: (In stack layout only) Moves focus to the window above or below.\n    - **flip**: Changes the window's orientation; if the window is primarily vertical, it becomes horizontal, and vice versa.\n    - **cycle_window**: Moves focus to the window in the specified direction (up, down, left, right).\n    - **cycle_desktop**: Cycles through the virtual desktops (left, right).\n    - **resize**: Adjusts the size of the focused window (grow, shrink).\n    - **reload_config**: Reloads the configuration file without restarting ZWM.\n    - **shift_window**: Shift the floating window's position to the specified direction by 10px (up, down, left, right).\n    - **gap_handler**: Increase or decrease window gaps (GROW, SHRINK).\n    - **change_state**: Set window state (FLOATING, TILED).\n    - **grow_floating_window**: Grow floating window (horizontally or vertically).\n    - **shrink_floating_window**: Shrink floating window (horizontally or vertically).\n    - **cycle_monitors**: Cycle between monitors (left or right, relative to the linked-list order not the physical positioning).\n    - **start_keyboard_drag**: Enter keyboard-driven drag mode to move tiled windows between partitions.\n\n- Default keys\n\n```ini\nbind = super + return -\u003e run(\"alacritty\")\nbind = super + space -\u003e run(\"dmenu_run\")\nbind = super + p -\u003e run([\"rofi\",\"-show\", \"drun\"])\nbind = super + w -\u003e func(kill)\nbind = super + 1 -\u003e func(switch_desktop:1)\nbind = super + 2 -\u003e func(switch_desktop:2)\nbind = super + 3 -\u003e func(switch_desktop:3)\nbind = super + 4 -\u003e func(switch_desktop:4)\nbind = super + 5 -\u003e func(switch_desktop:5)\nbind = super + 6 -\u003e func(switch_desktop:6)\nbind = super + 7 -\u003e func(switch_desktop:7)\nbind = super + l -\u003e func(resize:grow)\nbind = super + h -\u003e func(resize:shrink)\nbind = super + i -\u003e func(gap_handler:grow)\nbind = super + d -\u003e func(gap_handler:shrink)\nbind = super + f -\u003e func(fullscreen)\nbind = super + s -\u003e func(swap)\nbind = super + up -\u003e func(cycle_window:up)\nbind = super + right -\u003e func(cycle_window:right)\nbind = super + left -\u003e func(cycle_window:left)\nbind = super + down -\u003e func(cycle_window:down)\nbind = super|shift + up -\u003e func(shift_window:up)\nbind = super|shift + right -\u003e func(shift_window:right)\nbind = super|shift + left -\u003e func(shift_window:left)\nbind = super|shift + down -\u003e func(shift_window:down)\nbind = super|alt + f -\u003e func(change_state:float)\nbind = super|alt + t -\u003e func(change_state:tile)\nbind = super|shift + t -\u003e func(shrink_floating_window:horizontal)\nbind = super|shift + g -\u003e func(shrink_floating_window:vertical)\nbind = super|shift + y -\u003e func(grow_floating_window:horizontal)\nbind = super|shift + h -\u003e func(grow_floating_window:vertical)\nbind = super|alt + left -\u003e func(cycle_desktop:left)\nbind = super|alt + right -\u003e func(cycle_desktop:right)\nbind = super|ctrl + right -\u003e func(cycle_monitors:next)\nbind = super|ctrl + left -\u003e func(cycle_monitors:prev)\nbind = super|shift + 1 -\u003e func(transfer_node:1)\nbind = super|shift + 2 -\u003e func(transfer_node:2)\nbind = super|shift + 3 -\u003e func(transfer_node:3)\nbind = super|shift + 4 -\u003e func(transfer_node:4)\nbind = super|shift + 5 -\u003e func(transfer_node:5)\nbind = super|shift + 6 -\u003e func(transfer_node:6)\nbind = super|shift + 7 -\u003e func(transfer_node:7)\nbind = super|shift + m -\u003e func(layout:master)\nbind = super|shift + s -\u003e func(layout:stack)\nbind = super|shift + d -\u003e func(layout:default)\nbind = super|shift + k -\u003e func(traverse:up)\nbind = super|shift + j -\u003e func(traverse:down)\nbind = super|shift + f -\u003e func(flip)\nbind = super + m -\u003e func(start_keyboard_drag)\nbind = super|shift + r -\u003e func(reload_config)\n```\n\nMore options will be added in the future as development progresses.\n\n## Default Keybindings\n \n| Key                      | Description                                               |\n| ------------------------ | --------------------------------------------------------- |\n| `super + w`              | kill/close window                                         |\n| `super + return`         | launch a terminal (alacritty)                             |\n| `super + space`          | launch dmenu                                              |\n| `super + p `             | launch rofi                                               |\n| `super + [1..N]`         | switch to desktop                                         |\n| `super + l`              | resize window (grow/expand)                               |\n| `super + h`              | resize window (shrink)                                    |\n| `super + f`              | toggle fullscreen                                         |\n| `super + shift + [1..N]` | transfer window to a diff desktop                         |\n| `super + shift + m`      | toggle master layout                                      |\n| `super + shift + s`      | toggle stack layout                                       |\n| `super + shift + d`      | toggle default layout                                     |\n| `super + shift + j/k`    | traverse the stack                                        |\n| `super + shift + f`      | flip the window/partition                                 |\n| `super + shift + r`      | hot-reload                                                |\n| `super + shift + y`      | grow floating windows horizontally                        |\n| `super + shift + h`      | grow floating windows vertically                          |\n| `super + shift + t`      | shrink floating windows horizontally                      |\n| `super + shift + g`      | shrink floating windows vertically                        |\n| `super + button1`        | move window (drag tiled / move floating)                  |\n| `super + button3`        | resize window (drag resize)                               |\n| `super + ctrl + →`       | focus/change monitor right                                |\n| `super + ctrl + ←`       | focus/change monitor left                                 |\n| `super + s`              | swap window's orientation                                 |\n| `super + ←`              | focus window on the left                                  |\n| `super + ↑`              | focus window above                                        |\n| `super + →`              | focus window on the right                                 |\n| `super + ↓`              | focus window below                                        |\n| `super + alt + →`        | cycle desktop right                                       |\n| `super + alt + ←`        | cycle desktop left                                        |\n| `super + shift + ←`      | shift floating window to the left by 10px                 |\n| `super + shift + ↑`      | shift floating window up by 10px                          |\n| `super + shift + →`      | shift floating window to the right by 10px                |\n| `super + shift + ↓`      | shift floating window down by 10px                        |\n| `super + i`              | increase window gaps by 5px                               |\n| `super + d`              | decrease window gaps by 5px                               |\n| `super + alt + t`        | tile window                                               |\n| `super + alt + f`        | float window                                              |\n| `super + m`              | start keyboard-driven window drag                         |\n \n## Mouse and Keyboard Control\n \nZWM is designed to be fully keyboard-driven but also offers robust mouse support for convenience.\n \n**Feature Statistics:**\n- **Keyboard only operations**: 25\n- **Keyboard OR mouse operations**: 2 (Move/Drag, Resize)\n \n### Drag and resize features\n \nDetailed below are the operations that can be performed via both mouse and keyboard.\n \n#### 1. Move/drag window\n- **Mouse**: `super + button1` (Left Click) while dragging the window.\n  - Works on **Tiled Windows**: Drags the window to a new partition (swaps or moves).\n  - Works on **Floating Windows**: Moves the window freely.\n- **Keyboard**:\n  - **Tiled**: `super + m` initiates keyboard drag mode. Use arrow keys to move the window.\n  - **Floating**: `super + shift + [arrow keys]` shifts the window to the arrow direction by 10px.\n \n#### 2. Resize window\n- **Mouse**: `super + button3` (Right Click) while dragging near edges/corners.\n  - Works on **Tiled Windows** (Default Layout only): Resizes the shared edge between windows.\n  - Works on **Floating Windows**: Resizes the window dimensions.\n- **Keyboard**:\n  - **Tiled**: `super + l` (Grow) / `super + h` (Shrink).\n  - **Floating**: `super + shift + y/h` (Grow Horiz/Vert) and `super + shift + t/g` (Shrink Horiz/Vert).\n\n## ewmh specific settings for polybar\n\n### To display the window name (CLASS_NAME):\n\n```ini\n[module/xwindow]\ntype \t\t\t= internal/xwindow\nformat \t\t= \u003clabel\u003e\n; Available tokens:\n;   %title%\n;   %instance% (first part of the WM_CLASS atom, new in version 3.7.0)\n;   %class%    (second part of the WM_CLASS atom, new in version 3.7.0)\n; Default: %title%\nlabel \t\t    = %title%\nlabel-maxlen \t= 50\nlabel-empty \t= \"[null]\"\n```\n\n### To display workspaces:\n\n```ini\n[module/ewmh]\ntype = internal/xworkspaces\nlabel-active \t\t\t        = %index%\nlabel-active-background \t= ${colors.bg}\nlabel-active-underline\t\t= ${colors.blue}\nlabel-active-padding\t\t  = 1\nlabel-occupied \t\t\t      = %index%\nlabel-occupied-padding \t\t= 1\nlabel-urgent \t\t\t        = %index%!\nlabel-urgent-background \t= ${colors.red}\nlabel-urgent-padding \t\t  = 1\nlabel-empty \t\t\t        = %index%\nlabel-empty-foreground \t\t= ${colors.gray}\nlabel-empty-padding \t\t  = 1\nlabel-separator \t\t      = \" \"\n```\n\nFor further customization please refer to polybar's wiki.\n\n## Contributing\n\nIf you would like to add a feature or to fix a bug please feel free to submit a PR.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyazeed1s%2Fzwm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyazeed1s%2Fzwm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyazeed1s%2Fzwm/lists"}