Skip to content

Wayland: always rebind global shortcuts on startup - #3678

Merged
hluk merged 1 commit into
hluk:masterfrom
Memoraike:fix/wayland-globalshortcuts-rebind-on-restart
Aug 15, 2026
Merged

hluk merged 1 commit into
hluk:masterfrom
Memoraike:fix/wayland-globalshortcuts-rebind-on-restart

Conversation

@Memoraike

Copy link
Copy Markdown
Contributor

Problem

On Wayland (KDE Plasma), global shortcuts stop working after a plain restart of CopyQ — no reboot, no logout, same KWin/portal session:

copyq exit
copyq --start-server show

No error is shown, and the entry in System Settings → Shortcuts → Applications still looks perfectly normal — the shortcuts are simply dead.

With COPYQ_LOG_LEVEL=DEBUG the log stops right after listing:

DEBUG: [copyq.globalshortcut] Portal global shortcut session: "..."
DEBUG: [copyq.globalshortcut] Previously registered shortcuts: QList(...)

There is no Binding portal global shortcuts: line after it. xdg-desktop-portal-kde confirms it from the other side — CreateSession and ListShortcuts are called, but BindShortcuts never is.

Wiping the registration with
qdbus6 org.kde.kglobalaccel /component/com_github_hluk_copyq org.kde.kglobalaccel.Component.cleanUp
and restarting makes everything work again, because ListShortcuts then comes back empty.

Cause

bindPortalGlobalShortcuts() treated a non-empty ListShortcuts() result as "nothing to do":

if (shortcuts.isEmpty() || shortcuts == m_boundShortcuts)
    return;

But ListShortcuts is a read-only query and does not establish anything. The portal interface documentation says so directly:

If BindShortcuts was called for session all active shortcuts for session are returned.
Otherwise returns the shortcuts that were successfully bound in a previous session by this application.

When the previous CopyQ process exits, its portal session — and the live grab with it — is closed, while the persisted "approved" record in kglobalaccel remains. So on the next start ListShortcuts keeps happily reporting the shortcuts as registered even though nothing is actually grabbing keys, and CopyQ skipped BindShortcuts on that basis.

The one-bind-per-session limit is per session, not per application lifetime, and a new session is created on every start:

Bind the shortcuts. [â€Ķ] An application can only attempt bind shortcuts of a session once.

Fix

Call BindShortcuts unconditionally on every session start, regardless of what ListShortcuts returns. The ListShortcuts result is still used — for the existing OBSOLETE|| override workaround and for the debug log — it just no longer decides whether to bind.

The set comparison is kept for repeat bind requests within one session, so re-applying an unchanged configuration still does not produce a spurious "restart needed" notification.

Rebinding an unchanged, already-approved set is silent: xdg-desktop-portal-kde skips the confirmation dialog in that case since MR !368 "Improve the global shortcuts workflow".

Testing

Tested on KDE Plasma Wayland, xdg-desktop-portal 1.22.1 / xdg-desktop-portal-kde 6.7.4, using an isolated app id so an existing CopyQ registration was not touched. Both a pre-fix and a post-fix build were run through the same scenario.

Restarting with an unchanged shortcut set:

before after
BindShortcuts reaches the portal no yes
kglobalaccel Component.isActive() false true
shortcut actually fires no yes
  • First registration — consent dialog shown, shortcuts work.
  • copyq exit + restart, same set — no dialog, BindShortcuts called silently, shortcuts keep working. This is the case that was broken.
  • Changed set + restart — rebound correctly, including the OBSOLETE|| entry for the removed trigger, and the new trigger works.
  • Re-applying an unchanged set in a running instance — still silent, no "restart needed" notification.

Shortcut activation was driven through org.kde.kglobalaccel.Component.invokeShortcut and verified by the Portal global shortcut activated: log line.

Not tested on other portal backends. Idempotent rebinding of an approved set is the specified behaviour, but I have only verified it live against xdg-desktop-portal-kde — I have no GNOME or wlroots/Hyprland setup to check. Should a backend re-prompt on every start, that is still better than the current situation, where shortcuts are listed as registered but completely inactive. This is noted in a comment next to the change.

The X11 path is untouched.

ListShortcuts() only reports previously-approved shortcuts; it does not
re-establish the compositor-side key grab. Its documentation is explicit
about this: it "returns the shortcuts that were successfully bound in a
previous session by this application".

When CopyQ exits, its portal session is closed and the live grab goes with
it, but the persisted "approved" record in kglobalaccel remains. On the
next start CopyQ saw a non-empty ListShortcuts() result matching the wanted
shortcuts and skipped BindShortcuts() entirely, leaving the shortcuts
listed as registered in System Settings but non-functional until the
kglobalaccel component was purged manually.

BindShortcuts() may be called once per session, and a new session is
created on each start. Rebinding an unchanged, already approved set is
silent in xdg-desktop-portal-kde since merge request !368 ("Improve the
global shortcuts workflow"), so call it unconditionally on every session
start instead of only when ListShortcuts() returns an empty list.

The set comparison is kept for repeated bind requests within a single
session, so an unchanged set still does not trigger a spurious
"restart needed" notification.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WnE5yttm5XHCE2VHfr1DnG
@Memoraike
Memoraike requested a review from hluk as a code owner August 11, 2026 06:39
Copilot AI lite review requested due to automatic review settings August 11, 2026 06:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request fixes a Wayland (portal-based) global-shortcut regression where shortcuts can appear “registered” after a CopyQ restart but remain inactive because the portal key grab is not re-established for the new session.

Changes:

  • Always call BindShortcuts on portal session startup (when there are enabled shortcuts), even if ListShortcuts() reports the same set from a previous session.
  • Preserve the existing “bind only once per session” behavior by short-circuiting repeat binds within the same session when the set is unchanged.
  • Add detailed in-code rationale documenting portal semantics and backend behavior expectations.

ðŸ’Ą Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@codecov

codecov Bot commented Aug 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.60%. Comparing base (809038f) to head (74c8fcf).
⚠ïļ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
qxt/qxtglobalshortcut_x11.cpp 0.00% 3 Missing ⚠ïļ

❌ Your patch check has failed because the patch coverage (0.00%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3678      +/-   ##
==========================================
+ Coverage   74.58%   74.60%   +0.02%     
==========================================
  Files         256      256              
  Lines       37968    37970       +2     
  Branches     5122     5119       -3     
==========================================
+ Hits        28318    28328      +10     
+ Misses       9650     9642       -8     

☔ View full report in Codecov by Harness.
ðŸ“Ē Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄ïļ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • ðŸ“Ķ JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@hluk

hluk commented Aug 15, 2026

Copy link
Copy Markdown
Owner

Thanks! I was having the same issue (#3680). Let me merge this now, I need to fix the CI afterwards.

@hluk
hluk merged commit beff00f into hluk:master Aug 15, 2026
9 of 13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants