[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
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.
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
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 of code which I have no intention
to write.
Cheers,
Andreas
More information about the kde-core-devel
mailing list