Randa Meetings 2016 Part III: Translation System Troubles

[[Sic, 2016. This post about the results of studying the situation with the translation systems in software by KDE during the Randa event in 2016 had been a draft all the time due to being complicated matter and partly only lamenting about broken things instead of reporting world improvements. Still the lamenting might provide information unknown to some, so time to simply dump the still valid bits (quite some bits happily have been fixed since and are omitted, same for those notes I could no longer make sense off), even without a proper story thread. So if you ever wondered about the magic happening behind the scenes to get translations to appear in software based on Qt & KF, sit down and read on.]]

IMHO new technology should adapt by default to our cultures. Not our cultures to technology, especially if the technology is enforced on us by law or other pressures. Surely technology should instead allow to enhance cultures, extending options at best. But never limiting or disabling.

One motivation to create technology like Free/Libre Software is the idea that every human should be able to take part in the (world) society. A challenge here is to enrich life for people, not to just make it more complex. Also should it not force them into giving up parts of culture for the access to new technology. Code is becoming the new law maker: if your existing cultural artifacts are not mapped in the ontology of the computer systems, it does not exist by their definition. One has to be happy already then if there is at least any “Other” option to file away with.

Sure, e.g. for producers targeting more than their local home culture it would be so nice-because-simple if everyone would use the same language and other cultural artifacts (think measurement units). But who is to decide what should be the norm and how should they know what is best?

When it comes to software, the so called “Internationalization” technologies are here to help us in the humanity being. Adding variability to the user interface to allow adaption to the respective user’s culture (so called “Localization”).
Just, for some little irony, there is also more than one “culture” with Internationalization technologies. And getting those into synchronized cooperation is another challenge, sadly one which is currently not completely mastered when it comes to the software by the KDE community.

Multiple translation systems in one application


On Linux (and surely other *nixoid systems) traditionally gettext is used. Whose translation lookup code is either part of glibc or in a separate LibIntl. For a running executable the localization to choose is controlled by the environment variables “LANGUAGE” (GNU gettext specific), “LC_*” and “LANG” (see GNU gettext utilities documentation). Strings to be translated are grouped in so-called domains. There is one file per domain and per language, a so called “catalog”. A catalog appears in two variants, in the “Portable Object” (PO) format intended for direct editing by humans and in the “Machine Object” (MO) format intended for processing by software. For each domain optionally a separate directory can be set below which all the language catalogs belonging to that domain can be found.
On the call to the gettext API like dgettext("domain", msgid) when “LANG” is set to the id “locale” (and the other vars are not set), the translation will be taken from the file in the sub-path locale/LC_MESSAGES/domain.mo (or some less specific variant of the id “locale” until there is such a file) in the given directory for the domain.
So a library using gettext for translations has to install the catalog files in a certain directory at deploy time and, unless using the default, at execution start have that one registered for their domain (using bindtextdomain(...)). For locating and using the catalogs at run-time, an executable linking to such a library has nothing else to do to assist the library with that. And the same for the setup of translations in the code of the program itself with gettext.

Qt’s QTranslator

Qt uses another approach: one registers a set of handlers of type QTranslator which are queried one after the other if they can resolve the string to be translated. This is done by the central equivalent to the gettext API, QCoreApplication::translate(const char *context, const char *sourceText, const char *disambiguation, int n), which also if no handler could resolve the string simply returns the same string as passed in. That method is invoked indirectly from the tr(...) calls, which are class methods added to QObject subclasses via the Q_OBJECT macro, using the class name as the context.
With the Qt way, usually the caller of the translation invocation has to know which locale should be used and make sure the proper catalog handlers are registered, before doing that invocation. The Qt libraries themselves do not do those registration, it is the duty of the application linking to the Qt libraries to do that.

The Qt translation approach is not only used by all the Qt modules, but also many tier 1 modules of the KDE Frameworks. Because the KDE Frameworks module KI18n, which provides a convenience & utilitiy wrapper around gettext, is not available to them, being a tier 1 module itself.

Automagic setup of QTranslator-based translations

The classical application from the KDE spheres is traditionally developed with gettext and KI18n in mind, and thus not used to care for that registration of Qt translation handlers. To allow them staying that innocent, all libraries done by KDE using the Qt translation approach will trigger the creation and registration of the handler with their catalog themselves during loading of the library, picking a catalog matching current QLocale::system(). They are using the hook Q_COREAPP_STARTUP_FUNCTION, which evaluates to code for the definition of a global static instance of a custom structure whose constructor, invoked then after library load due to being global static instance, registers that function as startup function for the QCoreApplication (or subclass) instance or, if such instance already exists, directly calls the function. To spare the libraries’ authors writing the respective automatic loading code, KDE’s Extra CMake Modules provides the module ECMPoQmTools to have that code generated and added to the library build, by the CMake macro ecm_create_qm_loader(...).

One issue: currently the documentation of ECMPoQmTools misses to hint that generation of the handler is ensured to be done only in the main thread. In case the library is loaded in another thread, the generation code is triggered (and thus delayed) in the main thread via a timer event. This can result in race condition if other code run after loading the library in the other thread already relies on the translation handler present.

KI18n: doing automagic setup for Qt libraries translations even

The thoughtful reader may now wonder, given that KDE Frameworks modules using the Qt translation system are doing that by help of automatic loading of catalogs, whether something similar is valid for the Qt libraries itself when it comes to programs from KDE. The answer is: it depends 🙂
If the program links to the KDE Frameworks module KI18n, directly or indirectly and thus loads it, that library has code using Q_COREAPP_STARTUP_FUNCTION as well to automatically trigger the creation and deploy of the handler of the translations for the Qt libraries (see src/main.cpp). For which Qt libraries that is, see below. Otherwise, as explained before, the program has to do it explicitly.

So this is why the developers of the typical application done in the KDE community do not have to write explicit code to initiate any loading of translation catalogs.

Does it blend?

Just, the above also means that still there are two separate translation systems with different principles and rules in the same application process (if not more from 3rd-party libraries, which though usually use gettext). And that brings a set of issues, like potentially resulting in inconsistently localized UI due to different libraries having different set of localizations available or following different environment variables or internal flags to decide which localization to use (also for things like number formatting). And add to that having different teams with different guidelines doing the translations for the different libraries and programs from different organizations.

KI18n: too helpful with the Qt libraries translations sometimes

The automatic generation and deployment of the handler for the translations of Qt libraries when the KI18n library is linked to and thus loaded (as described above) is not really expected in Qt-only, not-KF-using programs. Yet, when such programs are loading plugins linking directly or indirectly KI18n, these programs will be confronted of getting the KI18n-generated handler deployed on top (and thus overriding any previously installed handler from the program itself). At best this means only duplicated handlers, but it can also mean changing the locale, as the KI18n code picks the catalog locale to use from what is QLocale::system() at the time of being run.

And such plugin can simply be the Qt platform integration plugin, which in the case of the Plasma platform integration has KI18n in the set of linked and thus loaded libraries. This issue is currently reported indirectly via Bug 215837 – Nativ KDE QFileDialog changes translation

When it comes to the Qt platform integration plugin, the use of Q_COREAPP_STARTUP_FUNCTION when being invoked via such a plugin also shows some issue in the design of the Qt startup phase, resulting in the registered function being 2x called, in this case resulting in duplicated creation of translation handlers (reported as QTBUG-54479)

Qt5: no longer one single catalog for all Qt modules

Seems in Qt4 times there was one single catalog per language for all that made up the Qt framework. In Qt5 this no longer is true though, for each language now a separate catalog file is used per Qt module. There is some backward compatibility though which has hidden this for most eyes so far, so called meta catalogs (see Linguist docs). The meta catalog qt_ does not have translations itself, but links to the catalogs qtbase_, qtscript_, qtquick1_, qtmultimedia_ and qtxmlpatterns_ (see yourself and open /usr/share/qt5/translations/qt_ll.qm, with ll your language code, e.g. de, in your favorite hex editor).

So applications which use further Qt modules, directly or indirectly, need to make sure themselves to get the respective catalogs loaded and used. Which gets complicated for those used indirectly (via plugins or indirectly linked as implementation detail of another non-Qt lib). There seems no way to know what catalogs are loaded already.

This might be important for programs from KDE using QtQuick Controls, given there exist qtquickcontrols2_*.qm files with some strings. Yet to be investigated if those catalogs are loaded via some QML mechanism perhaps, or if some handling is needed?

Juggling with catalogs on release time

The catalogs with the string translations for KDE software are maintained and developed by the translators in a database separate from the actual sources, a subversion system, partially for historic reasons.
When doing a release of KDE software, the scripts used to generate the source tarballs then do both a checkout of the sources to package as well as iterating over the translation database to download and add the matching catalogs.
KDE Frameworks extends this scheme by adding the snapshot of the translations in a commit to the source repository, using a tagged git commit off the main branch.

Issues seen:

  • which catalogs to fetch exactly based on fragile system, not exactly defined
  • which version of the database the fetched catalogs are from is not noted, tarball reproducibility from VCS not easily possible (solved for KF)
  • script accidentally added catalog files used internally by KDE translation system for in-source translations (fixed meanwhile)
  • script accidentally added by-product of translation statistic (fixed meanwhile)

Lifting some of the mystery around QT_MOC_COMPAT

((Dumping here the info collected as reminder to self, but also everyone who might wonder and search the internet. If you know a proper place to put it, please copy it there.))

When working on adding macros to control warnings by & visibility to the compiler for deprecated API in the KDE Frameworks modules, a certain C++ preprocessor macro has been found in some places in the code: QT_MOC_COMPAT. This macro is found as annotation to signals or slots which are otherwise tagged as deprecated.

Yet, searching in the Qt documentation (both website & local docs) has not yield any hits. More, grepping the headers of Qt libraries itself does not yield any hits, besides a blank definition of the macro in qglobal.h:

/* moc compats (signals/slots) */
#  define QT_MOC_COMPAT
#  undef QT_MOC_COMPAT
#  define QT_MOC_COMPAT

So, what has it been there for?

Looking at the code generated by moc, one can see that QT_MOC_COMPAT gets reflected in some flags being set on the metadata about the signals and slots methods. See by the example of KActionCollection (as found in the build directory src/KF5XmlGui_autogen/include/moc_kactioncollection.cpp, note the MethodCompatibility comments):

// ...
static const uint qt_meta_data_KActionCollection[] = {

 // content:
       8,       // revision
       0,       // classname
       0,    0, // classinfo
      12,   14, // methods
       2,  108, // properties
       0,    0, // enums/sets
       0,    0, // constructors
       0,       // flags
       5,       // signalCount

 // signals: name, argc, parameters, tag, flags
       1,    1,   74,    2, 0x06 /* Public */,
       5,    1,   77,    2, 0x16 /* Public | MethodCompatibility */,
       6,    1,   80,    2, 0x16 /* Public | MethodCompatibility */,
       7,    1,   83,    2, 0x06 /* Public */,
       8,    1,   86,    2, 0x06 /* Public */,

 // slots: name, argc, parameters, tag, flags
       9,    0,   89,    2, 0x09 /* Protected */,
      10,    0,   90,    2, 0x19 /* Protected | MethodCompatibility */,
// ...

Those flags reflect enums defined in qmetaobject_p.h:

enum MethodFlags  {
    // ...
    MethodCompatibility = 0x10,
    MethodCloned = 0x20,
    MethodScriptable = 0x40,
    MethodRevisioned = 0x80

So, what makes use of this flag?

At first it seems nothing does. Looking some more, one can though discover that the flag is being brought back into the game via some bitshifting and being mapped onto another of set of flags (qmetaobject.h & qmetaobject.cpp):

class Q_CORE_EXPORT QMetaMethod
    // ...
    enum Attributes { Compatibility = 0x1, Cloned = 0x2, Scriptable = 0x4 };
    int attributes() const;
    // ...

int QMetaMethod::attributes() const
    if (!mobj)
        return false;
    return ((mobj->d.data[handle + 4])>>4);

The very flag QMetaMethod::Compatibility is then checked for in debug builds of Qt during QObject::connect(...) calls, which invokes in such builds the following code to generate runtime warnings in the log:

#ifndef QT_NO_DEBUG
static inline void check_and_warn_compat(const QMetaObject *sender, const QMetaMethod &signal,
                                         const QMetaObject *receiver, const QMetaMethod &method)
    if (signal.attributes() & QMetaMethod::Compatibility) {
        if (!(method.attributes() & QMetaMethod::Compatibility))
            qWarning("QObject::connect: Connecting from COMPAT signal (%s::%s)",
                     sender->className(), signal.methodSignature().constData());
    } else if ((method.attributes() & QMetaMethod::Compatibility) &&
               method.methodType() == QMetaMethod::Signal) {
        qWarning("QObject::connect: Connecting from %s::%s to COMPAT slot (%s::%s)",
                 sender->className(), signal.methodSignature().constData(),
                 receiver->className(), method.methodSignature().constData());

Chance is that QT_MOC_COMPAT is a left-over from string-based signal/slot connection times. Where now using the method-function-pointer-based signal/slot connects catches connections with deprecated signals or slots at build time, as opposed to the runtime-only approach of the earlier, which also comes at runtime costs and thus is only available in debug builds of Qt.

Perhaps some Qt contributor reading this can shed more light on this and about its future, presence & past 🙂

More control over warnings for and visibility of deprecated library API via generated export macro header

Or: More preparation for the autumn of version 5 of KDE Frameworks

Consumer and producer interest in legacy in a library API

During the development life-time of a library in a API-compatible major version, quite some part of its API can be found to be insufficient and thus be deprecated in favour of API additions that serve the purpose better. And the producers of the library want to make the consumers of the library aware about those changes, both to make the investment into the improved API pay out for the consumers as well as prepare them for the future removal of the old API. As a deprecation note in the API documentation or release notes might be missed for existing consumer software, the compiler is pulled into the game using deprecation attributes on the API symbols, so developers looking at the build log have a chance to automatically be pointed to use of deprecated API in their software.
Next, once the chance for dropping the legacy parts of an API arrives on a change to a new major version, again having the compiler support pointing out that part is easier then grepping over the codebase for potentially pattern-less informal notes in code comments or the documentation.

At the same time consumers of a library might be well aware about API deprecations. But they might want to support a range of released versions of the library, using a single code base without variants for the different library versions. They might have more important issues to solve than deprecated API and want to get rid of any deprecation warnings at all. Or they want to ensure that no new uses of deprecated API is added.
Others consumers again might want to use custom builds of the library with all the implementation for deprecated API dropped, at least until a certain version, to save size when bundling the library product.

KDE Frameworks: … TODO

KDE Frameworks, the continuation of the “kdelibs” bundle of libraries, but with emphasis on modularization, is now at API-compatible major version 5. Yet one can find legacy API already deprecated in version 3 times, but done so only as comment in the API dox, without support by the compiler. And while lots of API is also properly marked as deprecated to the compiler, the consumer has no KDE Frameworks specific option to control the warnings and visibility. While some “*_NO_DEPRECATED” macros are used, they are not consistently used and usually only for deprecations done at version 5.0.

As you surely are aware, currently the foundations of the next generation of Qt, version 6, are sketched, and with the end of 2020 there even exists a rough date planned for its initial release. Given the API breakage then happening the same can also be expected for the libraries part of KDE Frameworks. And which would be a good time to also get rid of any legacy cruft.

New: ECMGenerateExportHeader, enabling more control about deprecated API

A proposed new addition to KDE’s Extra CMake Modules (ECM) should allow to improve the situation with KDE Frameworks, but also other libraries: ECMGenerateExportHeader (review request).

It would generate an extended export macro definition header which also includes macros to control which parts of the deprecated are warned about, are visible to the compiler for library consumers or included in the build of the library at all. The macros would be inspired by similar macros introduced with Qt 5.13, so the mind model can be transferred.
(Inspired, but not a plain copy, as e.g. the name “QT_DISABLE_DEPRECATED_BEFORE” is a bit misleading, as the macro is specified to work as “before and including”, so the proposed inspired name uses “*_DISABLE_DEPRECATED_BEFORE_AND_AT”.)

More elaborated example usage would be like this (note the difference between FOO_BUILD_DEPRECATED_SINCE and OO_ENABLE_DEPRECATED_SINCE, see documentation for explanation):



set(EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 CACHE STRING "Control what part of deprecated API is excluded from build [default=0].")


Installed header foo.hpp:

#include <foo_export.h>

enum Bars {

  * @deprecated Since 5.0
void doFoo();

  * @deprecated Since 5.12
FOO_EXPORT void doBar();

class Foo {
    * @deprecated Since 5.12
  virtual void doFoo();

Source file foo.cpp:

#include "foo.hpp"

void doFoo()
    // [...]

void doBar()
    // [...]

void Foo::doFoo()
    // [...]

Other, better approaches?

The author is not aware of other approaches currently, but would be happy to learn about, to compare, improve, or even discard in favour of another the proposed approach.

Please also have a look at the documentation for the proposed CMake macro ECMGenerateExportHeader (review request) and tell your thoughts.

For this macro being applied, see a patch for KCoreAddons and a patch for KService.

Please test improved Plasma Theme switching for Plasma 5.16

Help testing the Plasma Theme switching now

You like Plasma Themes? You design Plasma Themes even yourself? You want to see switching Plasma Themes working correctly, especially for Plasma panels?

Please get one of the Live images with latest code from the Plasma developers hands (or if you build manually yourself from master branches, last night’s code should be fine) and give the switching of Plasma Themes a good test, so we can be sure things will work as expected on arrival of Plasma 5.16:

If you find glitches, please report them here in the comments, or better on the #plasma IRC channel.

Plasma Themes, to make it more your Plasma

One of the things which makes Plasma so attractive is the officially supported option to customize also the style, and that beyond colors and wallpaper, to allow users to personalize the look to their likes. And designers have picked up on that and did a good set of custom designs (store.kde.org lists at the time of writing 470 themes).

And while in the last Plasma versions some regressions in the Theme support had sneaked in, because most people & developers are happily using the default Breeze theme, with Plasma 5.16 some theming fixes are to arrive.

Plasma Theme looking good on first contact with Plasma 5.16

The most annoying pain point has been that on selecting and applying a new Plasma Theme, the theme data was not correctly picked up especially by Plasma panels. Only after a restart of Plasma could the theme be fully experienced. Which made quick testing of themes e.g. from store.kde.org a sad story, given most themes looked a bit broken. And without knowing more one would think it is the theme’s fault.

But some evenings & nights have been spent to hunt down the reasons, and it seems they all have been found and corrected. So when one clicks the “Apply” button, the Plasma Theme instantly styles your Plasma desktop as it should, especially the panels.

And dressing up your desktop to match your day or week or mood or your shirt with one of those partially excellent themes is only a matter of some mouse clicks. No more restart needed 🙂

Coming to your system with Plasma 5.16 and KDE Frameworks 5.59 (both to be released in June).

Make your Plasma Theme take advantage of Plasma 5.16

Theme designers, please study the recently added page on techbase.kde.org about Porting Themes to latest Plasma 5. It lists the changes known so far and what to do for them. Please extend the list if something is yet missing.
And tell your theme designer friends about this page, so they can improve their themes as well.

Some theming fixes to arrive with Plasma 5.16

One of the things which makes Plasma so attractive is the officially supported option to customize also the style, and that beyond colors and wallpaper, to allow users to personalize the look to their likes. And designers have picked up on that and did a good set of custom designs (store.kde.org lists at the time of writing 454 themes).

Intended changes and unintended changes

In the 11 years since Plasma was released first (January 11, 2008) there has been some evolution of the theming options. Sadly also sometimes regressions in the support of older options were introduced, mainly in the early phase of Plasma 5 when code was ported to QtQuick 2 and the new default theme Breeze did not expose the regression or even triggered some changes for its special needs or for simplifications it allowed.

Given Breeze as default was pleasing to most, and possibly some alternative theme designers were lost during the longer phase from a pleasing KDE4 to an again pleasing Plasma 5, and new theme designers made their themes directly matching latest Plasma 5 Theme support, the piled-up regressions were not a real issue for those contributing.

Well, not a real issue unless on started to restore an old theme like “Fluffy Bunny”. And was wondering why it looks broken. And then wondering the same while playing with all the other old themes still available on store.kde.org.

So much partially good artwork being broken made my heart bleed, and in the absence of own designer abilities it was time to document the regressions as well as fix some code where possible to restore previous variability.

Teaching Porting to Plasma 5

So, theme designers, please find a new page on techbase.kde.org about Porting Themes to latest Plasma 5. It lists the changes known so far and what to do for them. Please extend the list if something is yet missing. One might test the fixes in the code against one’s themes with latest development versions of Plasma using Live images.

Fresh old Air & Oxygen

And even the Oxygen & Air themes, the default Plasma themes during KDE4 times, while being maintained as official themes part of current Plasma releases, had suffered some small regressions (e.g. analog clocks hands rotation point or progressbar height). No more, with Plasma 5.16 the visual experience of Oxygen & Air should be closer to the original.

Luxury on the borders results in bad looks

Sadly there is one thing which is not so easy to fix: Plasma code now assumes for any frames (like with borders of panels & pop-up dialogs) that the actual border visuals are negligible and the margin from the outside to the content is the same, with border on the side enabled or not. With luxurious decorated borders (like Fluffy Bunny or Spoons Original) this sadly results in bad looking bigger margins on sides where the border is disabled (see details). Which is sad especially given that High DPI display actually would allow more fanciness, even more when in the future Flat design gets replaced by whatever new trend. My passive dreams & hopes are on for Plasma 6 😉

Separating Plasma 5 compatible themes on store.kde.org

And while there now is a list of things to do to make old themes work again, many themes on store.kde.org no longer are maintained. There is talk about separating those, e.g. at time of Plasma 5.16 release, so there would be a clean list of working and maintained themes for latest Plasma 5.

The Second Return of the Fluffy Bunny

The old among us might remember KDE4 and something one could call the “Pink Phase”, when people explored how “interesting” they could make their digital workplace by applying certain colors and themes… don’t most of us sometimes need a fluffy and color-intensive world to escape to… if only to learn to value reality again, when things get too fluffy 🙂

The most outstanding work useful for that had been done once by Florian Schepper who created the Plasma theme “Fluffy Bunny”, which won hearts over on first sight. Sadly though the theme bundle got lost, was recovered, only to then by the times getting lost again from the stores. Time to repeat that, at least the recovering 🙂

And so last week the internet and local backups had been scanned to restore the theme again, to quick first success:

Well, besides the regression Plasma5 has over the old Plasma 😉 With only thin & non-tiled border themes trendy and used the last years, sadly current Plasma has some issues, also does it assume that borders of panels are rectangular when creating the default BlurBehind mask. Some first patches (1, 2, 3) are already under review.

Get the initial restored version from your Plasma desktop via System settings/Workspace Theme/Plasma Theme/Get new Plasma Themes…/Search “Fluffy Bunny” or via the Web interface from store.kde.org and enjoy a bit of fluffy Plasma 😉

Next up: restoring the “Plasma Bunny” theme from the once drafted “Fluffy” linux distribution… less flurry, but more pink!
Update: First version of new named “Unicorn” is now up in the store for your entertainment.

All new Okteta features of version 0.26 in a picture

Okteta, a simple editor for the raw data of files, has been released in version 0.26.0. The 0.26 series mainly brings a clean-up of the public API of the provided shared libraries. The UI & features of the Okteta program have been kept stable, next to one added new feature: there is now a context menu in the byte array viewer/editor available.

Since the port to Qt5 & KF5 Okteta has not seen work on new features. Instead some rework of the internal architecture has been started, and is still on-going.

Though this release there is a small feature added again, and thus the chance to pick up on the good tradition of the series of all-new-features-in-a-picture, like done for 0.9, 0.7, 0.4, 0.3, and 0.2. See in one quick glance what is new since 0.9 (sic):

How to break your code porting from Q_PRIVATE_SLOT to context & function object based connection

TL;DR Beware of connections to function objects accessing class members which could be triggered during execution of subclass destructor methods.

Oh, those name-based signal/slot connections feel outdated!

So you are a happy embracer of Qt’s new QObject signal/slot connection way of coding based on function-pointer or functor objects, like myself. This compile-time check of signals and slots feels just so much better. And thus you also port any existing code to it. Including some which uses the pimpl approach for some public classes, borrowing Qt’s macros Q_PRIVATE_SLOT, Q_D & Co.:

class MyWidgetPrivate;

class MyWidget : public QWidget
    explicit MyWidget(QWidget *parent);
    // [...]
    // setting a QWidget-subclass to be used as custom form in this widget
    void setForm(Form *form);
    const QScopedPointer d_ptr;
    Q_PRIVATE_SLOT(d_func(), void handleFormDeleted())

// implementation side:

class MyWidgetPrivate
// [...]
    void handleFormDeleted() { /*...*/ }

MyWidget::MyWidget(QWidget *parent)
    : QWidget(parent)
    , d_ptr(new MyWidgetPrivate)
    // [...]

void MyWidget::setForm(Form *form)
    // [...]
    connect(form, SIGNAL(destroyed()), this, SLOT(handleFormDeleted()));

Got some time, let’s modernize the code

The old code calls to be changed into using a connection from the destroyed signal to a lambda expression calling handleFormDeleted() directly on the private object, with MyWidget instance as context object, thus removing the need for that Q_PRIVATE_SLOT:

class MyWidgetPrivate;

class MyWidget : public QWidget
    explicit MyWidget(QWidget *parent);
    // [...]
    // setting a QWidget-subclass to be used as custom form in this widget
    void setForm(Form *form);
    const QScopedPointer d_ptr;

// implementation side:

class MyWidgetPrivate
// [...]
    void handleFormDeleted() { /*...*/ }

MyWidget::MyWidget(QWidget *parent)
    : QWidget(parent)
    , d_ptr(new MyWidgetPrivate)
    // [...]

void MyWidget::setForm(Form *form)
    // [...]
    connect(form, &QObject::destroyed,
            this, [this] { Q_D(MyWidget); d->handleFormDeleted(); });

Looks fine & compiles. Code feels more future-proof with the compiler now warning if some signal or slots got changed/removed.

Ooops, crashing now?

Just… nooos, it sometimes crashes now, in the destructor of MyWidget. How that on this innocent looking change?

Reading once more closely the documentation of QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection) we notice the remark:

The connection will automatically disconnect if the sender or the context is destroyed. However, you should take care that any objects used within the function object are still alive when the signal is emitted.

Which subtly hints to the problem we now have: if the form instance is set as child widget of the MyWidget instance, it will be deleted when ~QWidget() is run as part of the MyWidget destructor. And then emit the destroyed signal. At that point in time this as seen by the function object no longer is a proper MyWidget instance. And things go *boom*.

The old string-based connection as well as the member-function-pointer-based one handle that case for us, by some QObject magic using virtual methods which catch that the receiver no longer is a MyWidget and somehow then just drop the slot call (got lost in the code details, but it is something like this).
While with the new function-object-based connection that one will only become automatically inactive by being destroyed if the ~QObject destructor of either sender or receiver is reached. So having a longer lifetime, which can come a bit unexpected to some.

Fixing the modern times, unsure how

Lesson learned: do not blindly port code to the context & function object based connection. Instead beware of the additional traps which there are given that the function object is an independent complex object and not just a member function pointer. I will have to revisit quite some code where I might have missed this trap with the subclass destructor methods :/
As I seemed not the only one hit by this, I filed QTBUG-71432: “API dox of context & function object using QObject::connect should hint about destructor issues” so other people like me might be saved from this from the start.

Curious to learn about best practices for private slots and non-string-based connections. Thus happy to hear about proposals/hints in the comments.

(Update: text now using C++ standard lingo term “function object” instead of “functor”)

Happy 20th anniversary, KDevelop

It’s exactly 20 years ago to the day, that on an equinox as well the first announcement of a KDevelop snapshot, the 0.1 Alpha, was made:

List: kde-announce
Subject: ANNOUNCE: kdevelop-0.1.tar.gz
From: konold () alpha ! tat ! physik ! uni-tuebingen ! de
Date: 1998-09-22 15:50:19

Dear KDE Enthusiast,

the KDE Team is pleased to announce the availability of:


It can be found at

and at our U.S mirror site

it will probably appear firstly at

Here follows the LSM:

Title: KDevelop
Version: 0.1 Alpha
Entered-date: 22 Sep 1998
Description: an IDE for X/Qt/KDE
Keywords: IDE, KDE, X11, Qt, development
Author: Sandy Meier, Stefan Heidrich, Stefan Bartel
Maintained-by: Sandy Meier
Primary-site: http​://www.cs.uni-potsdam.de/~smeier/kdevelop/kdevelop-0.1.tar.gz
Home-page: http​://www.cs.uni-potsdam.de/~smeier/kdevelop/index.html
Original-site: http​://www.cs.uni-potsdam.de/~smeier/kdevelop/kdevelop-0.1.tar.gz
Platform: Linux, needs Qt 1.4 and the kde libs
Copying-policy: GNU Public License

20 years of getting feature by feature, sometimes first of its kind, being partially rewritten, getting ported from Qt1 to Qt2 to Qt3 to Qt4 to now Qt5, being made run on non-Linux platforms, seeing hand-overs of maintainers.
At its 20th anniversary KDevelop, now to be called an extensible cross-platform IDE for C, C++, Python, PHP and other languages, continues to provide developers a very reliable and powerful environment to get their code work done. While being inviting to enhance their tool, KDevelop, itself, being a FLOSS software and with no company agenda attached.

I have been a happy user of KDevelop all the years, and currently am giving back to it by doing some development and feature additions.
Be a happy user as well, and then one giving back.
Looking forward to more 20 years, and then some.

KDevelop, ensuring development equity, by day and night. 🙂

From code to related bug report or review in just a hover & click

When working on existing code bases, now and then one reads code that raises some questions and the desire for more context, to understand the purpose or the intention of that code. Context like the commit message, the author, the commit date, or some review discussion of the commit or some bug report or feature request the commit was done for.

In the Beginning There Were Raw Commit Ids…

KDevelop, the extensible cross-platform IDE for C, C++, Python, PHP and other languages, has supported showing line-by-line commit data annotations since many years, starting by showing the commit id and in the tooltip info like author, date and message.
See here a screenshot from the KDevelop 4.1 Dot article (2010):

Annotations border in KDevelop 4.1

Then There Were Year and Author…

Not everyone was capable to deal with raw commit ids, also is it just a reference to the actual metadata, so since some versions of KDevelop the annotation border was changed to show the author name and the commit year instead.
See here a screenshot how it looks by the example of upcoming KDevelop 5.3:

Annotations border in KDevelop 5.3

Soon We Might Get the Message and More

While year and author are already interesting info about a commit, if one is looking at a bunch of lines coming from different commits, it can be unpleasant having always to do some explicit action to get further data, like the commit message, by moving the mouse to trigger the tooltip. And with the recent trend in screen sizes, there often is some vertical space left asking to get its Return-On-Investment 😉 .
More, if in the raw commit message displayed in the tooltip some review discussion or bug report is mentioned, one has to remember the review id or bug id and manually navigate to e.g. the respective web page. Again unpleasant if having to do this multiple times.

End of last year two patches have been started with the goal to improve those things:

The first patch would extend KTextEditor by a new class AbstractAnnotationItemDelegate (modelled after QAbstractItemDelegate), which then gives KDevelop and other potential API users full independent flexibility to decide on which data about annotations to render and how, as developers and users prefer by the time.
The second patch would change KDevelop to make use of that delegate option and change what is rendered for a start: for groups of consecutive lines from the same commit the first would show the commit message summary line, with the age of the commit, a second line would show the author. And it would make use of the KDevelop::ActiveToolTip class (as also used e.g. for code type information tooltips), which allows the user to interact with the content of the tooltip, like copying text or clicking links in the commit message, which would be shown enriched with links where feasible.
The latter though currently misses some support from the KDevelop git plugin, which only delivers the message summary line in the data model (due to making use of git blame --porcelain, possibly needs rewrite using libgit2 instead of parsing git output). So tooltips for now still only show the summary line as before at least with git (did not test the other VCS plugins yet).
See here a screenshot how it looks with the patches applied to master branches of KTextEditor & KDevelop (and some example complete commit message text for demoing what is possible):

Annotations border in a future KDevelop?

Please Help to See If It Is Good

Work on those patches has been picked up again the last week, and they have now reached Merge Candidate state and are ready for final review, targeting KTextEditor of KF 5.52 (to be merged right after tagging 5.51) and KDevelop 5.4.

If you are interested in this feature, please consider to help now by testing those patches and/or reviewing their code (see links to patches above), so the feature will be good once it arrives at users like yourself 🙂