MCPcopy Index your code
hub / github.com/adelmonte/niri_window_buttons

github.com/adelmonte/niri_window_buttons @v0.4.3

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.4.3 ↗ · + Follow
265 symbols 568 edges 12 files 0 documented · 0% updated 31d agov0.4.3 · 2026-06-07★ 52
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

niri_window_buttons License: GPL v3

A Waybar module for displaying and managing traditional window buttons in the Niri compositor.

screenshot

Features

  • Window buttons with application icons and optional title text
  • Fully configurable click actions (left, right, middle, double-click, scroll wheel)
  • Separate actions for focused vs unfocused windows
  • Context menu with custom scripts support
  • Multi-select windows with modifier keys
  • Per-application click behavior and styling via regex title matching, optionally scoped per workspace
  • Advanced window filtering (by app, title, workspace)
  • Drag and drop window reordering, including multi-select group drag, with hover-to-focus for external drags
  • Dynamic button sizing with taskbar width limits and scroll overflow
  • Optional proportional button sizing that mirrors each window's width in the niri layout
  • Multi-monitor support
  • Audio indicator with click-to-mute for windows playing audio
  • Notification integration with urgency hints
  • Custom CSS classes via pattern matching
  • Shows active window in Niri overview

Installation

From AUR (Arch Linux)

yay -S niri_window_buttons      # stable release
yay -S niri_window_buttons-git  # latest git version

The compiled module will be at /usr/lib/waybar/libniri_window_buttons.so.

Manual Installation

cargo build --release

The compiled module will be at target/release/libniri_window_buttons.so.

Configuration

Example

{
  "modules-left": ["cffi/niri_window_buttons"],
  "cffi/niri_window_buttons": {
    "module_path": "/path/to/libniri_window_buttons.so",

    // Display
    "only_current_workspace": true,
    "show_window_titles": true,
    "truncate_titles": true,
    "allow_title_linebreaks": false,
    "button_alignment": "left",
    "show_tooltip": true,
    "tooltip_delay": 200,

    // Sizing
    "icon_size": 18,
    "icon_spacing": 6,
    "min_button_width": 10,
    "max_button_width": 190,
    "max_taskbar_width": 1210,
    "scroll_arrow_left": "",
    "scroll_arrow_right": "",

    // Per-output overrides
    "max_taskbar_width_per_output": {
      "DP-1": 1400,
      "eDP-1": 800
    },
    "dimensions_per_output": {
      "eDP-1": {
        "min_button_width": 10,
        "max_button_width": 150,
        "max_taskbar_width": 600
      }
    },

    // Drag reorder
    "drag_style": "browser",
    "left_click_focus_on_press": true,
    "drag_hover_focus": true,
    "drag_hover_focus_delay": 500,

    // Click actions
    "click_actions": {
      "left_click_unfocused": "focus-window",
      "left_click_focused": "maximize-column",
      "double_click": "maximize-window-to-edges",
      "right_click_unfocused": "menu",
      "right_click_focused": "menu",
      "middle_click_unfocused": "close-window",
      "middle_click_focused": "close-window",
      "scroll_up": "move-column-left",
      "scroll_down": "move-column-right"
    },

    // Context menu
    "context_menu": [
      {"label": "  Maximize Column", "action": "maximize-column"},
      {"label": "  Maximize to Edges", "action": "maximize-window-to-edges"},
      {"label": "  Center Column", "action": "center-window"},
      {"label": "󰉩  Toggle Floating", "action": "toggle-window-floating"},
      {"label": "  Move WS Up", "action": "move-window-to-workspace-up"},
      {"label": "  Move WS Down", "action": "move-window-to-workspace-down"},
      {"label": "  Run Script", "command": "notify-send '{app_id}'"},
      {"label": "  Close Window", "action": "close-window"}
    ],

    // Multi-select
    "multi_select_modifier": "shift",
    "multi_select_menu": [
      {"label": "  Move All Up", "action": "move-to-workspace-up"},
      {"label": "  Move All Down", "action": "move-to-workspace-down"},
      {"label": "  Maximize All", "action": "maximize-columns"},
      {"label": "  Close All", "action": "close-windows"}
    ],

    // Filtering
    "ignore_rules": [
      {"app_id": "xpad"},
      {"app_id": "launcher"},
      {"title_contains": "Picture-in-Picture"},
      {"app_id": "firefox", "title_regex": "^Extension:"}
    ],

    // Notifications
    "notifications": {
      "enabled": true,
      "use_desktop_entry": true,
      "use_fuzzy_matching": true,
      "map_app_ids": {
        "org.mozilla.firefox": "firefox"
      }
    },

    // Audio indicator
    "audio_indicator": {
      "enabled": true,
      "playing_icon": "󰕾",
      "muted_icon": "󰖁",
      "clickable": true
    },

    // Per-app CSS classes and click overrides
    "apps": {
      "signal": [
        {"match": "\\([0-9]+\\)$", "class": "unread"}
      ],
      "firefox": [
        {"match": ".*YouTube.*", "class": "youtube"},
        {"match": ".*", "click_actions": {
          "middle_click_unfocused": "none",
          "middle_click_focused": "none"
        }}
      ]
    }
  }
}

Display Options

Option Description Default
show_all_outputs Show windows from all monitors false
only_current_workspace Show only current workspace windows false
show_window_titles Display window titles next to icons true
truncate_titles Truncate long titles with ellipsis true
allow_title_linebreaks Allow line breaks in window titles (expands button height) false
drag_style Drag reorder style: "browser" (grabbed button follows cursor) or "classic" (GTK drag-and-drop) "browser"
drag_hover_focus Focus window when external drag hovers over button true
drag_hover_focus_delay Delay in milliseconds before hover triggers focus 500
show_tooltip Show window title tooltip on hover true
tooltip_delay Delay in milliseconds before tooltip appears 300
button_alignment Align buttons within the taskbar: "left", "center", or "right" "left"
left_click_focus_on_press Focus unfocused windows on mouse-down instead of mouse-up. When false, dragging an unfocused window reorders it without stealing focus false

Size Controls

Option Description Default
min_button_width Minimum button width in pixels 150
max_button_width Maximum button width in pixels 235
max_taskbar_width Total taskbar width limit in pixels 1200
icon_size Icon dimensions in pixels 24
icon_spacing Space between icon and title in pixels 6
proportional_button_width Size each button to match its window's on-screen width false
proportional_icon_size Shrink icons along with proportional buttons (only applies when proportional_button_width is enabled) true

Proportional Button Width

With proportional_button_width enabled, each button is sized to reflect how wide its window currently is on screen, mirroring the niri layout. A full-width window gets a button near max_button_width; a window taking half the screen gets roughly half that width, and so on (clamped between min_button_width and max_button_width). Buttons update live as you split, resize, or maximize columns.

By default the app icons shrink along with the buttons. Set proportional_icon_size to false to keep icons at a fixed icon_size while the button widths still scale.

{
  "proportional_button_width": true,
  "proportional_icon_size": true
}

Per-Output Dimension Configuration

For more granular control, configure all button dimensions per output:

{
  "min_button_width": 150,
  "max_button_width": 235,
  "max_taskbar_width": 1200,
  "dimensions_per_output": {
    "eDP-1": {
      "min_button_width": 100,
      "max_button_width": 150,
      "max_taskbar_width": 800
    },
    "DP-1": {
      "min_button_width": 200,
      "max_button_width": 300,
      "max_taskbar_width": 1600
    }
  }
}

The top-level dimension settings are used as defaults. For each output, you can override any combination of min_button_width, max_button_width, and max_taskbar_width. Output names can be found using niri msg outputs.

Scroll Overflow Behavior

When window buttons exceed max_taskbar_width, the taskbar becomes scrollable. Arrow buttons appear at the edges for navigation.

Scrolling methods:

Method Behavior
Click arrow buttons Scrolls taskbar by one page
Mouse wheel on buttons Scrolls taskbar (when scroll_up/scroll_down are "none")

When scroll_up/scroll_down are set to a window action (e.g., "move-column-left"), that action executes instead of scrolling the taskbar. Set them to "none" to enable mouse wheel taskbar scrolling.

Arrow customization:

{
  "scroll_arrow_left": "←",
  "scroll_arrow_right": "→"
}

Defaults are "◀" and "▶". You can use any unicode characters, emoji, or Nerd Font icons. The arrows can also be styled via CSS using the .scroll-arrow-left and .scroll-arrow-right classes.

Click Actions

Configure what happens when you click buttons. All click types can be assigned any action, including the context menu. Right-click and middle-click support separate actions for focused vs unfocused windows:

"click_actions": {
  "left_click_unfocused": "focus-window",
  "left_click_focused": "maximize-column",
  "double_click": "maximize-window-to-edges",
  "right_click_unfocused": "menu",
  "right_click_focused": "menu",
  "middle_click_unfocused": "focus-window",
  "middle_click_focused": "close-window",
  "scroll_up": "move-column-left",
  "scroll_down": "move-column-right"
}

Click actions can also run custom shell commands using object syntax:

"click_actions": {
  "left_click_focused": { "command": "notify-send 'Clicked {app_id}'" },
  "middle_click_focused": { "command": "my-script.sh {window_id}" }
}

Placeholders: {window_id}, {app_id}, {title}

Available actions:

Action Description
none Do nothing (for scroll_up/scroll_down: enables taskbar scrolling)
menu Show context menu
focus-window Focus the window
close-window Close the window
Column/Window Sizing
maximize-column Maximize column width
maximize-window-to-edges Maximize window to screen edges
expand-column-to-available-width Expand column to fill available space
reset-window-height Reset window to default height
switch-preset-column-width Cycle through preset column widths
switch-preset-window-height Cycle through preset window heights
Centering
center-column Center column on screen
center-window Center window on screen
center-visible-columns Center all visible columns
Display
toggle-title Toggle title label visibility for this button
Fullscreen/Floating
fullscreen-window Toggle fullscreen
toggle-windowed-fullscreen Toggle windowed fullscreen
toggle-window-floating Toggle floating mode
Column Stacking
consume-window-into-column Stack window into adjacent column
expel-window-from-column Unstack window from column
toggle-column-tabbed-display Toggle tabbed display mode
Movement
move-column-left Move column left
move-column-right Move column right
move-column-to-first Move column to first position
move-column-to-last Move column to last position
move-window-up Move window up in column
move-window-down Move window down in column
Workspace/Monitor Movement
move-window-to-workspace-up Move window to workspace above
move-window-to-workspace-down Move window to workspace below
move-window-up-or-to-workspace-up Move up, or to workspace above if at top
move-window-down-or-to-workspace-down Move down, or to workspace below if at bottom
move-window-to-monitor-left Move window to left monitor
move-window-to-monitor-right Move window to right monitor
move-column-left-or-to-monitor-left Move column left, or to left monitor
move-column-right-or-to-monitor-right Move column right, or to right monitor
Focus
focus-workspace-previous Focus previously active workspace

Context Menu

Customize which actions appear in the context menu and their order:

"context_menu": [
  {"label": "  Fullscreen", "action": "fullscreen-window"},
  {"label": "  Maximize Column", "action": "maximize-column"},
  {"label": "  Maximize to Edges", "action": "maximize-window-to-edges"},
  {"label": "󰉩  Toggle Floating", "action": "toggle-window-floating"},
  {"label": "󱆃  Custom Script", "command": "my-script.sh {window_ids}"},
  {"label": "  Toggle Title", "action": "toggle-title"},
  {"label": "  Close Window", "action": "close-window"}
]

Menu items can also run custom shell commands with placeholders: - {window_id} - Window ID - {app_id} - Application ID - {title} - Window title

Example: {"label": " Run Script", "command": "notify-send 'Window: {app_id}'"}

The menu can be triggered via any click action by setting it to "menu".

Multi-Select

Select multiple windows using a modifier key, then perform batch actions via right-click menu:

{
  "multi_select_modifier": "ctrl",
  "multi_select_menu": [
    {"label": "  Move All Up", "action": "move-to-workspace-up"},
    {"label": "  Move All Down", "action": "move-to-workspace-down"},
    {"label": "󰉩  Float All", "action": "toggle-floating"},
    {"label": "  Fullscreen All", "action": "fullscreen-windows"},
    {"label": "󱆃  Custom Script", "command": "my-script.sh {window_ids}"},
    {"label": "  Close All", "action": "close-windows"}
  ]
}

Modifier options: ctrl, shift, alt, super

**Requirements:

Core symbols most depended-on inside this repo

compositor
called by 57
src/global.rs
settings
called by 51
src/global.rs
focused_action
called by 27
src/compositor.rs
clear_selection
called by 10
src/widget.rs
send_action
called by 10
src/compositor.rs
focus_window
called by 8
src/compositor.rs
execute_click_action
called by 7
src/widget.rs
is_none
called by 7
src/settings.rs

Shape

Method 155
Function 63
Class 34
Enum 13

Languages

Rust100%

Modules by API surface

src/settings.rs77 symbols
src/compositor.rs63 symbols
src/widget.rs36 symbols
src/lib.rs21 symbols
src/notifications/pid_cache.rs14 symbols
src/notifications.rs13 symbols
src/global.rs12 symbols
src/audio.rs11 symbols
src/screen.rs7 symbols
src/icons.rs6 symbols
src/system.rs3 symbols
src/errors.rs2 symbols

For agents

$ claude mcp add niri_window_buttons \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page