About deprecation of QFontMetrics::width()

With any new version of the Qt toolkit comes some clean-up of its APIs to keep it clean, consistent, and future-proof. Part of this clean-up is to rename API functions to make it more clear what they actually do.

Starting with Qt 5.11, the QFontMetrics::width() function was deprecated. You could still compile code that uses this function, but since it is marked obsolete, you were encouraged to port away from it.

So what is unclear or not consistent about it? The function name and signature suggest that you can retrieve the width of a text string (or single character) taking into account the metrics of a specific font. Such metrics are needed to create widget layouts that automatically adapt to user specified fonts or different system display DPIs.

Reading the API description, the result is actually not the width. The graphics shown at https://doc.qt.io/qt-5/qfontmetrics-obsolete.html#width illustrates that there is a difference between the horizontal advance, i.e. the number of pixels from one character to the next character, and the bounding rectangle width, which is needed to encompass all pixels including so called bearings that can overlap the next or the previous character.

Since it was not clear from the confusingly named function QFontMetrics::width() that it actually returned the horizontal advance, instead of the bounding width, this method is now obsolete. You must port to either QFontMetrics::horizontalAdvance() or QFontMetrics::boundingRect().width().

Please make sure you are aware of the difference, and do not port blindly. I am pretty sure that in most cases QFontMetrics::boundingRect() is what you want, unless you are writing custom text shaping/layouting code. Using the wrong function can cause clipped text or text that suddenly wraps to the next line despite calculating the width that it needs.


Teaching Comparing Strings in Python the Hard Way

Wait, is that actually related to KDE?

If you read between the lines…

Some long-time subscribers may remember that I am teaching math to 10-18 year old students. The COVID-19 situation nearly made me quit and look for an alternative to earn my rent, but my love for the kids and teaching them was stronger. After a few months of shortage, we found ways to responsibly resume the meetings, either online or with safety measures.

When schools were closed, some parents wondered what they could do to drag their offsprings away from computers; playing computer games seemed to be the new all-time favorite hobby. Of course, resistance was expected. Why not turn this interest into something useful? I didn’t expect that kids as young as eight are interested to learn how to create games. But why not? I learned from electronic magazines and books how computers, MS BASIC, and Z80 assembly worked when I was ten, and I am sure I would have been interested with eight, if my classmate had broken his leg two years earlier… But that’s not the story I want to tell.

An Evil Plan and Lessons Learned

Today I was again supporting a just-turned-thirteen year old in his journey to learn Python. Earlier, we had already mastered coordinate geometry to move colorful images with PyQt on key presses, so variables, arithmetics, and conditionals in Python are well understood. We also used lists of strings to write simple “guess the correct answer” games. To automatically label the answers with A, B, C, etc. I showed him ord and chr functions, so he was aware that letters are internally stored as numbers.

But for me learning to code is not only about writing games. What I call “theory” is writing programs that solve seemingly uninteresting tasks. Showing him the specification and a partial implementation of a “orderNumbers” function, today’s exercise was to solve the same task for two strings.

def orderNumbers(n1, n2):
    ''' Decide about the ordering of two numbers
        -1, when n1 comes before n2,
        0, when n1 is the same as n2,
        1, when n1 comes after/behind n2
    if n1 < n2:
        return -1
    elif n1 == n2:
        return 0
    # ...

def orderStrings(s1, s2):
    # ...

Intuitively, he started by typing “if s1 < s2:”, then he paused, and said: “No, this won’t work!”, and erased the faulty line. His understanding of strings is that they are a sequence of letters, each of them represented by a number, so his conclusion was that a single comparison cannot determine the ordering of complete words or names.

I could have simply said “It works, Python is that easy!”, but I didn’t. My evil plan was to make him implement that function the hard way. And I got rewarded, because he had to solve every single challenge this task offers.

  • we cannot use a simple “for c in s” loop, because we have to iterate both strings at the same time
  • we have to abort the loop/return early if the decision is final
  • he also found that “Andreas” incorrectly comes after “AXEL”, which forced us to understand the ASCII table to handle case conversion (I didn’t expect he finds this issue, but I am glad he did)
  • he had to fix the error that made the program abort when comparing “Andrea” with “Andreas” due to missing boundary checks
  • and finally, he needed to fix a wrong result when comparing two identical strings

Here is his final function (reformatted and variables renamed for brevity, his version was a bit messy).

    def orderStrings(s1, s2):
        ''' Decide about the ordering of two strings, ignoring case
            -1, when s1 comes before s2,
            0, when s1 is the same as s2,
            1, when s1 comes after/behind s2
        pos = 0
        while True:
            if pos >= len(s1) or pos >= len(s2):
                if len(s1) < len(s2):
                    return -1
                elif len(s1) > len(s2):
                    return 1
                    return 0

            c1 = ord(s1[pos])
            c2 = ord(s2[pos])
            if c1 > 90:
                c1 -= 32
            if c2 > 90:
                c2 -= 32

            if c1 < c2:
                return -1
            elif c1 > c2:
                return 1
                pos += 1

Of course his case checks are not really correct; I will have to introduce him to Unicode and Python’s built-in ways to handle case-ignoring comparisons sometimes later.

Lessons learned:

  • using an index variable to iterate through sequences
  • using arithmetic on the ASCII codes to transform letters
  • missing boundary checks can “crash” your program
  • making sure you handle every case of inputs possible

Exercise solved, well done!

Celebrating 10 Years with KDE

Of course I am using KDE software much longer. My first Linux distribution, SuSE 6.2 (the precursor to openSUSE), came with KDE 1.1.1 and was already released 19 years ago. But this post is not celebrating the years I am using KDE software.

Exactly ten years ago, dear Albert committed my first contribution to KDE. A simple patch for a problem that looked obvious to fix, but waiting for someone to actually do the work. Not really understanding the consequences, it marks the start of my journey within the amazing KDE community.

Bug Triaging and Quality

In the following ten years, I contributed to or resolved thousands of bugs in kdelibs, systemsettings, and various other KDE software. Much of the passion to triage and tackle bugs do I owe Darío Andrés, the original author of our bug triaging guide. I have not heard from him later, but hope he does well.

Long before we had a continuous build service, I used to build nearly all KDE software with a self-written script, monitoring its output for build errors and newly introduced compiler warnings. Someone surely remembers my constant mails about failing builds and other issues I felt responsible for as part of the quality assurance in the KDE team.

Theming and Decorations

Besides tackling wierd crashes, I was also active in UI polishing, freeing our code from hard-coded spacings, colors, font or icon sizes, using my own Qt widget style Skulpture and a specially crafted color scheme as a testbed. Not that dark themes and HiDPI displays were common ten years ago; I just always liked the full control of the user over his software. After all, UI stands for User Interface.

The Skulpture style came with its own simple KWin window decoration. For those not satisfied with its look, I ported and improved the Dekorator theming engine, and even created a version of Emerald (the Compiz/Beryl decorator) for KDE4, called Smaragd, which has recently been ported to Plasma 5. Once installed, it gives Plasma 5 users access to over thousand window decoration themes.

Applications Porting and Releasing

Apropos porting: Hopefully my porting status page was useful for contributors to decide where to help, and for users to decide when to switch. Besides tracking porting progress, I helped porting small utilities, such as KCalc, KCharSelect, KCron, KMag, and KRuler, but also bigger applications, such as KmPlot, KolourPaint, and KTurtle. You might notice a slight bias towards math and graphics applications 🙂

The longer you are part of a community, the more responsibilites you are going to accept. Being the maintainer of a few KF5 frameworks is not exactly exciting. But a year ago, I got the opportunity to help Albert with KDE Applications releases, learning about the release process, including tagging, packaging tarballs, and posting announcements. Creating a release is a nice way to see all the fruits of the work of many contributors coming together.

So what am I going to do in the next ten years? If you had asked me that question ten years ago, I could not have given you an answer, and I am glad I cannot give you answer today. What is so special about the KDE community is that it constantly gives you new problems to tackle, and I hope I will be able to report in ten years which of them we mastered.

KF5 Applications Porting

Next week, KDE developers will release the beta of KDE Applications 17.08. This release will again have more applications and nearly all games ported to Qt5/KF5. While Qt4 is already no longer supported for over a year, KDE has decided to support Qt4/kdelibs4-based applications a bit longer.

The 17.08 release, however, will be the last to include Qt4/kdelibs4-based applications. This means, 17.12 will only include applications that are based on Qt5/KF5. See this mailing list discussion.

We hope to find more contributors who help porting the remaining applications. Instructions are on community.kde.org. Ask for help in our developer forum, mailing list, or IRC channel. You do not need git commit rights; you can add a patch/diff via Phabricator.

Porting Status

There used to be an automatically updated porting status page. Sadly the machine that created it stopped working because of a hardware failure; its DIMM simply died.

This week, I had the chance to run its script over a checkout of nearly all KDE repositories from cgit.kde.org. Unfortunately, the repository layout is not nicely structured into directories, and includes many unmaintained and playground repositories, but maybe it is still useful.

See http://imagezero.maxiom.de/files/portingstatus.html.

For contributors helping to get it more green, there is also a shorter version that omits all-green repositories, see portingstatus-todo.html.

Smaragd for Plasma 5

Smaragd is a port of the Emerald window decoration engine to Plasma‘s window manager KWin. In other words, if you install Smaragd, you will be able to use Emerald themes for Compiz/Beryl in your Plasma desktop.

Smaragd was already released 6 years ago for KWin 4. Today, I have ported most of it to the new KDecoration2 API that KWin 5 uses. What is still missing is the configuration dialog, but you should be able to move the old kwinsmaragdrc file to ~/.config/ to keep your old settings.

Build instructions:

(Install Cairo, GLIB2, KDecoration2, and KF5 devel packages)
git clone git://anongit.kde.org/smaragd.git
cd smaragd
git checkout kdecoration2
mkdir build && cd build
make && sudo make install
(Logout and restart KWin)

To use Smaragd, you need to extract the *.emerald archive to ~/.emerald/theme/ (make sure the file ~/.emerald/theme/theme.ini exists after extracting). In the future, GHNS support will be added to ease installation.

Please report issues to bug.kde.org.

KF5 Porting Progress

The porting of KDE software from Qt4 to Qt5 is in full progress. The KDE core libraries were splitted to multiple manageable frameworks, ready to be used with any Qt5 application.

On top of these frameworks (collectively called KF5 or KDE Frameworks version 5), the KDE community also ported the desktop shell and released Plasma 5.

But KDE software does not stop at the desktop shell. We have many other applications, games, and utilities, that are released either independently, or collectively with the triannual KDE Applications release.

You can find an overview of the porting status of many KDE projects at http://developer.kde.org/~cfeck/portingstatus.html (updated as time permits).

If you want to join in and help, this is a good opportunity to get in contact with the KDE community.

February Bug of the Month

The KDE Gardening Team selected the February “Bug of the Month”. Before announcing it, let me write about other bugs that got resolved recently.

First, our January bug (Bug 271934, kded4 memory leak) has been investigated and resolved by Max A. Dednev. He identified excess reference counting in the underlying PolicyKit package, and proposed a patch upstream. While Max uses KDE software since the very early KDE 3 releases, and also works as a developer for Astra Linux, this was his first contribution to the open source communities. Thanks Max!

Let me mention three other bugs, all of them very high on the list of possible candidates for the election as the next Bug of the Month, out of the literally hundreds that are resolved each month:

  • Bug 245482 (Trash has reached maximum size) was resolved by David Faure. An update to the freedesktop.org Trash specification was required to fix it.
  • Bug 340202 (ksnapshot captures itself) was identified as a regression in the xorg-intel video drivers.
  • Bug 328014 (printer-manager password prompt stuck) was resolved by Wolfgang Bauer from the openSUSE KDE team.

But now to the bug for February. This time, a keyboard usability bug was selected.
It is Bug 309193: Keyboard shortcuts do not work with certain layout order

Reasons for the nomination:

  • not being able to invoke keyboard shortcuts is a blocker for usability,
  • most (if not all) KDE developers use a single keyboard layout, so there is little chance that any of them runs into it,
  • it is still unclear whether the bug is in KDE software or underlying components, such as the Qt library, the xorg input layer, or in the keyboard layout definition files,
  • actually, it is very unclear which combination of components and configuration files triggers the bug,
  • the nomination was also dedicated to Max A. Dednev, in the hope that we can attract more developers from countries with non-latin keyboard layouts.

If you are able to fix it, you will receive a honorable mention in the next issue of my blog post “The Bug of the Month” on Planet KDE.

Not all developers that would be able to fix it are subscribed to this bug. If you know someone, feel free to point them here.

January Bug of the Month

The KDE Gardening Team selected the January “Bug of the Month”. Before announcing it, let me write more about this initiative.

When I blogged about the nomination of the first bug, I probably left the impression that each bug is to be resolved in a time frame of one month. The bugs that get selected are often unresolved for a long time, and solving them might overlap with the announcement of the next bugs, so some patience is needed. But I have good news!

The first bug (Bug 324975: Volume gets restored to 100% after each knotify event) has been resolved thanks to the work of Albert Astals Cid. Because of translation changes, the fix will be available in the next KDE Applications release in April.

Regarding the second bug (Bug 288410: KDE daemon kded4 crashes on wake up), we already have a patch to test. There are packages available for openSUSE and Kubuntu, and Fedora packages are being prepared. Please check the recents comments in the bug report and give feedback.

But now to the bug for January. This time, a memory leak was selected.
It is Bug 271934: KDE daemon kded4 grows on memory usage

Reasons for the nomination:

  • the bug is the most reported memory leak in our bug tracker,
  • some people reported growth rates beyond megabytes per minute,
  • having to restart just to keep a low memory usage is annoying,
  • there was growing interest recently (raising CC list size),
  • getting more developers to try Milian’s new heaptrack tool.

If you are able to fix it, you will receive a honorable mention in the next issue of my blog post “The Bug of the Month” on Planet KDE.

Not all developers that would be able to fix it are subscribed to this bug. If you know someone, feel free to point them here.

December Bug of the Month

The KDE Gardening Team selected the December “Bug of the Month”.

It is Bug 288410: KDE daemon kded4 crashes on wake up (related to power/battery change)

Reasons for the nomination:

  • the bug is one of the most reported crashes in our bug tracker,
  • a defunct kded4 process can cause several other issues,
  • it is annoying to restart the desktop just after a wake up,
  • getting a crash dialog when the laptop wakes up makes bad publicity,
  • it might be fixable, it looks like an access to a stale object pointer.

If you are able to fix it, you will receive a honorable mention in the next issue of my blog post “The Bug of the Month” on Planet KDE.

Not all developers that would be able to fix it are subscribed to this bug. If you know someone, feel free to point him here.

The Bug of the Month

The KDE Gardening Team had the idea to nominate one particular annoying bug as “The Bug of the Month”. While we have literally hundreds of bugs that would qualify, only one bug per month gets nominated.

To get the initiative going, I took the liberty to select the first “Bug of the Month”:
it is Bug 324975: Volume gets restored to 100% after each knotify event.

Reasons for the nomination:

  • the bug affects practically all users, because notifications are not only used by many KDE applications, but also by the KDE Workspaces itself,
  • the bug is severe, as it can damage hardware and ears in extreme cases,
  • the bug is annoying, which was also measured by the rapid growth of votes and comments,
  • the bug seems fixable, we just did not find someone who was able to do it.

If you are able to fix it, you will receive a honorable mention in the next issue of my blog post “The Bug of the Month” on Planet KDE.

We do not have a knotify maintainer. If the issue is in knotify, please suggest a patch with anything that fixes it and create a review request at https://git.reviewboard.kde.org/ and paste the link here. If the issue is in Phonon, its backends, in gstreamer, VLC, pulseaudio, or ALSA, please suggest a patch there.

Not all developers that would be able to fix it are subscribed to this bug. If you know someone, feel free to point him here.

If we receive multiple patches, we will have to decide which of them is best suited, and nominate one of them for the fix.