[RFC] saving and loading of global shortcuts
Andreas Hartmetz
ahartmetz at gmail.com
Wed Jun 27 20:26:11 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
KAction.
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.
Properly saving and loading global shortcuts, therefore, is pretty much
mandatory.
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 (they are quite rare) 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.
Of course shortcuts could be saved to disk at every change and loaded as soon
as an action is created and has a name to refer to, at some cost in
performance - and IMO it wouldn'd be any less ugly.
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
end.
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 with a tricky hack or two, which I
have no intention to write.
Cheers,
Andreas
More information about the kde-core-devel
mailing list