[RFC] saving and loading of global shortcuts

Andreas Hartmetz ahartmetz at gmail.com
Sat Aug 18 18:41:24 BST 2007

Hello list,

There is a design issue with KGlobalAccel which has no obvious "perfect" 
solution so I am asking for your input. A quick outline of the global 
shortcuts infrastructure in my local working branch:

[Basic functionality]
- You call KAction::setGlobalShortcut() to set a shortcut for an action. 
KAction then calls KGlobalAccel which is, among other things, the interface 
to KdedGlobalAccel (communication via DBus). KdedGlobalAccel is a KDED module 
as you might have guessed.
- KdedGlobalAccel then grabs the shortcut key in a platform-specific way and 
makes an entry of the mapping key<->action where actions are identified by 
their main component name and their own name.
- When a key grab triggers, KdedGlobalAccel calls (via DBus) KGlobalAccel 
which tells the action to trigger.

[Conflict resolution]
KdedGlobalAccel has a list of all global shortcuts. If you try to assign a key 
twice, it will tell the appropriate KdedGlobalAccel/KGlobalAccel that the 
corresponding shortcut was changed to an empty one, which goes back to the 
When manually assigning shortcuts, the config widget asks 
KGlobalAccel/KdedGlobalAccel for conflicts and presents options to the user 
to fix them.
To prevent all clashes as good as possible, KdedGlobalAccel remembers key<-> 
action mappings even after the corresponding application shuts down.

[The issues]
The problem, now, is about KGlobalAccel::readSettings() and writeSettings(). 
They tell KdedGlobalAccel to save/load the mapping of the calling 
applications's shortcuts to/from a global config file. If an application A 
which had some shortcuts changed by the user or automatically, to avoid 
clashes, loads without callling readSettings(), it might snatch some 
shortcuts that were reassigned and "belong" to application B. Same thing if 
the changes (to resolve conflicts) were never saved to disk. They will be 
gone after a restart of KDED.

Ossi came up with an ugly but pragmatic solution [my attempts were all a bit 
lacking in the reliability department] which I fleshed out a bit:
Force applications and KParts (<-research needed...) to tell KGlobalAccel when 
they are done assigning their global shortcuts by calling doneSetup(), 
commit() or whatever, and at that point:
- change shortcuts to their saved values, if any
- save any changes that were made automatically to avoid conflicts
- Actually enable the shortcuts (the "force applications..." part)
Any further changes to shortcuts would then be saved to disk immediately or 
with some seconds latency to keep the in-memory and the on-disk state of 
KdedGlobal shortcuts in sync at all times.
What's so ugly about this is, of course, an incompatible API change and the 
general ugliness of KAction::setGlobalShortcut() not being enough to actually 
get a working global shortcut. What's good is that it works reliably.

ATM about all applications seem to set their global shortcuts in one single 
function where it's rather trivial to put a single doneSetup() call at the 

I am asking for any better ideas or other people who are also convinced that 
this is ugly but necessary.

If you wonder how this was done in KDE 3, the answer is "not". There was no 
working conflict resolution for global shortcuts. On the plus side, it had 
working global *multikey* shortcuts (like Ctrl+A,B) which have a code 
size/usefulness ratio that makes them unattractive, especially because some 
code involved in this [KShortcutMenu or KActionMenu or whatever] was dropped 
between KDE 3 and 4. 
Additional code size would be ~1000 lines of code which I have no intention 
to write.


More information about the kde-core-devel mailing list