Skip to content

feat: GlobalShortcut portal#3587

Draft
RottenFishbone wants to merge 9 commits intoniri-wm:mainfrom
RottenFishbone:global-shortcut
Draft

feat: GlobalShortcut portal#3587
RottenFishbone wants to merge 9 commits intoniri-wm:mainfrom
RottenFishbone:global-shortcut

Conversation

@RottenFishbone
Copy link

@RottenFishbone RottenFishbone commented Mar 10, 2026

This implements GlobalShortcuts via xdg-desktop-portal-gnome (as per discussion on #1165 and limited discussion #2775)

Two dbus interfaces are implemented org.gnome.Settings.GlobalShortcutsProvider and org.gnome.Shell. The former is requested by the gnome portal to validate shortcut requests and return the results to gnome portal (which it uses to call GrabAccelerators).
The latter is the interface to grab, ungrab and emit (de)activation signals for shortcuts.

I haven't added any wiki info on the global-shortcut config yet, if the current setup I have looks good to everyone then I'll add the wiki page to document it.

The limited number of programs I have found that implement GlobalShortcuts seem like they're all just doing their own thing, which makes config require some flexibility.
For example,

  • Electron/Chromium seem to make their shortcut id a string of numbers followed by the preferred-trigger, leaving the preferred-trigger entry empty.
  • OBS (flatpack version) uses fairly sensible shortcut id describing the action and fill the preferred-trigger.
  • Ghostty puts the preferred-trigger in the shortcut-id as well.

Niri has the final say on what a binding is so the mismatch between preferred-trigger and what is returned to the application is moot. (e.g. an application can request Ctrl+Shift+M and get Mod+Y returned to it, it only truly needs the action id returned alongside it)

Shortcuts can optionally disable inhibiting the keypresses.
A single binding can match multiple shortcuts if the match argument is set up as such. (e.g. app-id { match "(ghostty)|(discord)"; }

Currently it doesn't support mouse bindings but provided this PR is on the right track I believe I can add them fairly trivially.

Let me know thoughts and opinions and I'll try to get this shaped up.

Add global_shortcuts module to config
Implement Display for Key related structs.
Enables runtime comparison/(de)serialization of Key and incoming dbus
requests
Added tests for Display, idempotence must be maintained or communication
between dbus will result in failed shortcut registration/activation
Emulate gnome's settings provider using config file as source of truth,
rather than popups/menus
Enable conditional inhibiting of a global shortcut using `inhibit`
property, defaults to true
Creates `Shell` interface, serves as the interface between niri and the
GlobalShortcuts portal interface

Stores state of Key -> Action (u32) bindings, emits (De)activation
signals on relevant keypresses and intercepts where applicable
Rewrote some leftover badly structured code
Rename `inhibit` to `intercept` for better insight into its purpose
@Sempyos Sempyos added area:input Keyboard, mouse, touchpad, tablet, gestures, pointer area:config Config parsing, default config, new settings area:ipc niri msg, niri IPC, D-Bus, scripting pr kind:feature New features and functionality labels Mar 11, 2026
Refactor  `gen_action` and replace with the obvious iterator it should
have been.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:config Config parsing, default config, new settings area:input Keyboard, mouse, touchpad, tablet, gestures, pointer area:ipc niri msg, niri IPC, D-Bus, scripting pr kind:feature New features and functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants