In ~/.kde/share/config/kdeglobals, the value for the default web browser starts with an exclamation mark. What is the purpose of the exclamation mark?


Let's just ask the source code. If you're not interested in the details, just skip to the end to see the result:

There is a KCM for setting the default applications. Let's look up its name:

$ kcmshell4 --list | ack -i default
componentchooser           - Choose the default components for various services

NOTE: The following 5 steps are Gentoo specific, but could be applied to any other distribution or could be replaced by browsing through KDE's source repositories manually!

Let's search the filesystem for files belonging to the componentchooser:

$ find /usr -name "*componentchooser*"

Now we'll query the package manager (in our case Gentoo's Portage) and ask for the package which contains any of these files:

$ find /usr -name "*componentchooser*" | xargs qfile
kde-base/kdelibs (/usr/share/apps/kcm_componentchooser)
kde-base/kcontrol (/usr/share/apps/kcm_componentchooser)
kde-base/kcontrol (/usr/share/kde4/services/componentchooser.desktop)
kde-base/kcontrol (/usr/share/doc/HTML/en/kcontrol/componentchooser)
kde-base/kcontrol (/usr/lib64/kde4/kcm_componentchooser.so)
kde-base/kde-l10n (/usr/share/locale/de/LC_MESSAGES/kcmcomponentchooser.mo)
kde-base/kde-l10n (/usr/share/doc/HTML/de/kcontrol/componentchooser)

As we're looking for the source code which actually writes the value for the default-browser, we should look into the .so file which contains actual code, while the other files just provide documentation (/usr/share/doc/[…]), meta-information ([…].desktop) and translation strings (/usr/share/locale/[…]).

This means, we'll have to take a look at the package providing the shared-object (.so) file, which is kde-base/kcontrol on Gentoo.

First, we make sure, the source tarball is present on our filesystem, by asking Portage to download it for this package (--nodeps ensures, only the sources for this package are downloaded, but not for any dependencies):

$ emerge --fetchonly --nodeps kde-base/kcontrol
>>> Fetching (1 of 1) kde-base/kcontrol-4.11.4
 * kde-runtime-4.11.4.tar.xz SHA256 SHA512 WHIRLPOOL size ;-) ...    [ ok ]

In this case, the file was already present and just its checksums were verified.

Now we're going to unpack this file into a temporary location for examining it further:

$ cd /tmp
$ tar xf /usr/portage/distfiles/kde-runtime-4.11.4.tar.xz

The result is the directory kde-runtime-4.11.4 which we're going to change into now:

$ cd kde-runtime-4.11.4

This directory contains now a lot of components belonging to the kde-runtime package of KDE SC. We're interested in the kcontrol component:

$ cd kcontrol

Now we need to identify the file which contains the source code to write the default browser to kdeglobalsrc. There are different ways to do this:

  1. Browse through the directory structure and try to find the file by its name.
  2. Look for a file whose name contains something like componentchooser and examine its source code
  3. Scan the source code and find directly the file which writes the value BrowserApplication.

The shortest path to our goal is option '3', so that's what we're going to do:

$ ack BrowserApplication
50:    QString exec = config.readPathEntry( QLatin1String("BrowserApplication"), QString("") );
92:    config.writePathEntry( QLatin1String("BrowserApplication"), exec); // KConfig::Normal|KConfig::Global

So obviously in line '92' of the file componentchooser/componentchooserbrowser.cpp, that's were this value is being written, so let's have a closer look at it:

 80 void CfgBrowser::save(KConfig *)
 81 {
 82     KConfigGroup config(KSharedConfig::openConfig("kdeglobals"), QLatin1String("General") );
 83     QString exec;
 84     if (radioExec->isChecked())
 85     {
 86         exec = lineExec->text();
 87         if (m_browserService && (exec == m_browserExec))
 88             exec = m_browserService->storageId(); // Use service
 89         else if (!exec.isEmpty())
 90             exec = '!' + exec; // Literal command
 91     }
 92     config.writePathEntry( QLatin1String("BrowserApplication"), exec); // KConfig::Normal|KConfig::Global
 93     config.sync();
 95     KGlobalSettings::self()->emitChange(KGlobalSettings::SettingsChanged);
 97     emit changed(false);
 98 }

In line '92', the key BrowserApplication is written and it's value is in the variable exec. The exclamation mark is added to the command string in line '90', but there is no elaborate comment in the code at this line which would explain, why this is done, so let's have a look instead at the code logic which leads to adding an ! in front of the BrowserApplication value:

  • Line '86' sets exec to the string which is provided by the input field
  • Line '87' checks, whether the member variable m_browserService is true and whether the content of the variable exec is the same as the member variable m_browserExec.
    • m_browserService is set (0 or 1) by the method CfgBrowser::selectBrowser when the default browser is selected by browsing the application tree instead of entering the executable name directly as string. In case the browser is selected by browsing the application tree, the content of the input field is the name of the applications *.desktop file.
    • m_browserExec is the name of the *.desktop file when selecting the browser via the application tree.
    • In case both statements evaluate to TRUE, exec is set to the result of storageId (the name of the *.desktop entry).
    • Otherwise, the name of the executable file is set, but it is prepended by an !.

To make it short:

The exclamation mark for the BrowserApplication entry in kdeglobalsrc is used to distinguish between an actual binary name to be executed for launching the browser or the name of a browser's *.desktop file.

  • Awesome, super-detailed thorough answer. Thanks Elias. – Vince Dec 14 '13 at 5:25

It is most likely a recall to last command executed with the same name. A bit of search led me to this script which rose a suspicion that the exclamation mark is something of a bash sorcery.

This discussion about exclamation mark sounds relevant.

It most likely means that bash expects a full command name that starts with sensible-browser.

  • I'm pretty sure that the exclamation mark is only used as a history expansion character at the command line. It's specifically a feature of the shell and the KDE configuration files don't really involve the shell. If you look closely at the script you linked, it's basically just doing a couple of search and replace tasks on the config file using sed. Also search for "HISTORY EXPANSION" in man bash. – Vince Dec 13 '13 at 6:40
  • Isn't the same thing that I say in my answer: "It is most likely a recall to last command executed with the same name." – mkc Dec 13 '13 at 19:33
  • 1
    It's not used in any way as history expansion or something similar, as KDE applications are not bound to any specific shell. They are supposed to work on any platform (even Windows), so relying on some kind of bash-specific history expansion doesn't make any sense at this point. See my answer to this question instead why there's an exclamation mark. – Elias Probst Dec 13 '13 at 21:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.