Plasma 6 method to refresh kglobalaccel shortcuts?

I have a script that changes some default Plasma shortcuts for me, related to the task switcher dialog (moving the Alt+Grave and Alt+Tilde or Alt+Shift+Grave from the “Main” tab to the “Alternative” tab so moving through windows of the same app uses a different visual).

The script works, in the sense that it places the correct updated lines in kglobalshortcutsrc using kwriteconfig${KDE_SESSION_VERSION}. You can log out and log back in, and the shortcuts the script modified will be in place and active, as they should be.

In Plasma 5, I found a simple way to restart the kgobalaccel5 process to refresh its understanding of the currently active shortcuts, to avoid needing to log out. (I don’t know that this is the best/safest way, I just know that it works.)

killall kglobalaccel5 && sleep 2 && kstart5 kglobalaccel5

But with Plasma 6 I found that there is no existing process similar to this or kglobalaccel or kglobalaccel6, since it has apparently been merged into KWin itself, so there’s nothing separate expected to be running. There is a plasma-kglobalaccel user service, but restarting that service doesn’t update the active shortcuts.

The KWin reconfigure DBus command activates the updated task switcher settings that I change in the kwinrc file, but that command has no effect on the active shortcuts after updating the kglobalshortcutsrc file.

Is there some sort of equivalent DBus command to get Plasma or KWin to recognize that the shortcuts in kglobalshortcutsrc have been changed from a script? I tried to dig around in the DBus viewer but couldn’t find anything that seemed to do the job.

Any good reference links or insights on this would be appreciated.

The kglobalacceld API is run under KWin. I believe the DBus API call qdbus org.kde.KWin /KWin org.kde.KWin.reconfigure should reload all the configuration including shortcut keys.

That being said, if you update the shortcut keys using the DBus API calls
org.kde.kglobalaccel /kglobalaccel org.kde.KGlobalAccel.setShortcut -instead of editing some configuration file - then it should become effective immediately.

1 Like

I have been attempting to figure out how to use the DBus calls like setShortcut with no success. GPT-4 is usually good at digesting documentation and explaining how to use something that’s new to me, but the API documentation I found is so cryptic and abstract that it hasn’t been able to give me a working example. I’ll never grasp why API documentation never includes actual usage examples.

I’m sure once I see some examples I’ll figure out what I was misunderstanding about the usage syntax, but until I see those examples it is far more confusing than it was figuring out how to use kwriteconfig5 to change shortcuts in the RC file.

I am planning on putting together a full explanation (for humans like me that are bad at reading API documentation) showing how to use these DBus calls to set shortcuts, in a GitHub gist and/or a post on Reddit. So if anyone is feeling generous enough to explain how to use setShortcut or link to a good set of known working examples, please do so.

Just last night I figured out how to use org.kde.keyboard to connect to a signal and obtain the currently active keyboard layout index and layout list array, so I must not be entirely brain dead. But setShortcut still eludes my understanding.

You must have a write-up ahead of you :slightly_smiling_face: And, automating Plasma configuration is a popular topic.

Configuration files

Both the Plasma shell and KDE applications are configured mainly via their GUIs, although their configurations are stored in human-readable configuration files, which can also be edited manually to change the settings, and backed up and restored to transfer the settings. KDE applications use the KConfig framework to access their configuration files, and all configuration files are stored at paths relative to the same predetermined directories and share the same syntax: Each line can have a key-value pair. Lines are organized under groups that start with the group’s name in square brackets and ends when the next group begins or when the end of the configuration file is reached. Both keys and values may contain white spaces but all white spaces immediately before and after an equals sign, and at the end of a line are ignored. The KConfig framework provides a central configuration system, and consists of two parts: KConfigCore allows applications to access their configuration files, and KConfigGui allows applications to be hooked to the configuration system so that they are automatically initialized from their configuration files, and settings changed via their GUIs are automatically propagated to their configuration files.

KDE follows the XDG Base Directory Specification while storing its files. Therefore, system-wide and user-specific configuration files are stored at paths that are relative to the directories included in $XDG_CONFIG_DIRS and $XDG_CONFIG_HOME respectively, which roughly correspond to the paths below:

$XDG_CONFIG_DIRS:
  
    ~/.config/kdedefaults
    /etc/xdg
    /usr/share/kde-settings/kde-profile/default/xdg
  
$XDG_CONFIG_HOME:
  
    ~/.config

KDE applications may be built with the KParts framework, which is a library that implements a plugin framework that allows GUI components, which are also called kparts or KDE parts, to be reused. Applications built with the KParts framework, such as okular, are implemented as a kpart embedded in a frontend, and have one configuration file for the kpart (e.g. ~/.config/okularpartrc), which applies to all instances of the kpart embedded in different applications, and one configuration file for the application itself (e.g. ~/.config/okularrc). For example, text editor or terminal emulator features can be readily implemented by embedding katepart or konsolepart in an application. KParts are analogous to Bonobo components in GNOME and ActiveX controls in Microsoft’s Component Object Model.


Additionally, KDE applications may be built with the KXMLGUI framework, which consists of several libraries that allow GUI components such as menus, toolbars, icons, tooltips, etc., to be described in an XML file, which is parsed by the setupGUI() function of the KXmlGuiWindow class to construct the GUI. This allows a GUI to be redesigned by modifying the XML file rather than the source code. An XML file describing user modifications to the default GUI of an application is (arguably) considered a data file rather than a configuration file, and therefore is stored at a path that is relative to the $XDG_DATA_HOME/kxmlgui5 directory, with the .rc suffix in its file name (e.g. ~/.local/share/kxmlgui5/okular/{part.rc,shell.rc}), which roughly corresponds to:

$XDG_DATA_HOME/kxmlgui5
  
    ~/.local/share/kxmlgui5

So, all user-specific settings for the Plasma shell and KDE applications can be rougly backed up and restored by copying the associated configuration files foundunder ~/.config and ~/.local/share/kxmlgui5.

Shortcuts

One of the most important configuration categories for humans since think-and-type interface of a keyboards can be much more efficient than look-and-click interface of pointy devices.

If automation isn’t required, shortcuts are set either via the System Settings application, or by manually editing the configuration files.

Since Plasma uses human-readable configuration files, the kwriteconfig6 utility is the intended utility to make setting shortcuts (as well as other plasma configurations) scriptable, I think. However, the setShortcut method available via D-Bus is an alternative way to do it, although maybe not the best way on Plasma.

These are the methods exposed by the KGlobalAccel interface on D-Bus:

$ busctl --user introspect org.kde.kglobalaccel /kglobalaccel org.kde.KGlobalAccel
NAME                           TYPE      SIGNATURE RESULT/VALUE  FLAGS
.action                        method    i         as            -
.actionList                    method    (ai)      as            -
.activateGlobalShortcutContext method    ss        -             -
.allActionsForComponent        method    as        aas           -
.allComponents                 method    -         ao            -
.allMainComponents             method    -         aas           -
.blockGlobalShortcuts          method    b         -             -
.defaultShortcut               method    as        ai            -
.defaultShortcutKeys           method    as        a(ai)         -
.doRegister                    method    as        -             -
.getComponent                  method    s         o             -
.getGlobalShortcutsByKey       method    i         a(ssssssaiai) -
.globalShortcutAvailable       method    (ai)s     b             -
.globalShortcutsByKey          method    (ai)(i)   a(ssssssaiai) -
.isGlobalShortcutAvailable     method    is        b             -
.setForeignShortcut            method    asai      -             -
.setForeignShortcutKeys        method    asa(ai)   -             -
.setInactive                   method    as        -             -
.setShortcut                   method    asaiu     ai            -
.setShortcutKeys               method    asa(ai)u  a(ai)         -
.shortcut                      method    as        ai            -
.shortcutKeys                  method    as        a(ai)         -
.unRegister                    method    as        -             -
.unregister                    method    ss        b             -
.yourShortcutGotChanged        signal    asai      -             -
.yourShortcutsChanged          signal    asa(ai)   -             -

So, the setShortcut method accepts asaiu (arrays of strings, array of integers, and unsigned integer), and returns ai (array of integers):

  • The array of strings, as the first argument, collectively describe the action.
  • The array of integers, as the second argument, are the shortcuts that are to be bound to the action, where a single shortcut can be used if alternative shortcuts aren’t desired. Each shortcut is an integer obtained by adding the values corresponding to key names in tables keys and modifiers, e.g. Pressing the Super key (i.e. Qt::MetaModifier = 0x10000000 = 268435456) and ‘m’ key (i.e. Qt::Key_M = 0x4d = 77) results in the keycode 268435533.
  • loadFlag, as the last argument, can take either the value of 0, which autoloads the saved global shortcut, or the value of 4, which prevents autoloading, so that the outcome of setShortcut call will persist.
  • And the array of integers, as the return value, is the updated set of assigned shortcuts for the action.

An example command:
$ gdbus call --session --dest org.kde.kglobalaccel --object-path /kglobalaccel --method org.kde.KGlobalAccel.setShortcut "['kwin', 'Window Move Center', 'KWin', 'Move Window to the Center']" "[268435533]" 4
  
([268435533],)

The set of strings that describe an action that already has an assigned shortcut can be found out by running the `action` method specified by the same interface, and passing the keycode of the already assigned shortcut as the only argument:
$ gdbus call --session --dest org.kde.kglobalaccel --object-path /kglobalaccel --method org.kde.KGlobalAccel.action '268435533'
  
(['kwin', 'Window Move Center', 'KWin', 'Move Window to the Center'],)

The equivalent qdbus command is:

$ qdbus org.kde.kglobalaccel /kglobalaccel org.kde.KGlobalAccel.action '268435533'

kwin
Window Move Center
KWin
Move Window to the Center

There are multiple CLI utilities that implement the D-Bus protocol:

  • As far as I can tell, the qdbus utility cannot accept array of integers as arguments: Cannot call method 'setShortcut' because type 'QDBusRawType::ai' is unknown to this tool.
  • The syntax of the dbus-send utility requires explicit notation for the D-Bus type system rather than the dense notation of gdbus, e.g. array:string:"kwin","Window Move Center","KWin","Move Window to the Center".
3 Likes

@frovo104

Indeed a will have quite an extensive write-up to complete when I actually get these commands working.

This post alone is going to be far more helpful than anything else I’ve been able to find on the web. Especially those context notes about types.

One piece that still seems to be missing is how to convert key names into that array of int that these methods want for some reason, which is not very human-friendly. Or to convert the int back into key names. I’ll keep looking into that.

I will let you know how it goes. Thanks for taking the time to post that comment.