Skip to content

Sunday, 1 March 2026

I was asked a good question: What are these things? What are the differences? I will try to explain what they are in this post, in bit less technical manner.

I will keep some of the parts bit short here, since I am not 100% knowledgeable about everything, and I rather people read documentation about it instead of relying my blogpost. :) But here's the basics of it.

My lizard fursona making an smug face.

It's infodump time.

QtWidgets

QtWidgets is the "older" way of writing Qt applications. It's mostly C++ and sometimes quite difficult to work with. It's not very flexible.

More information in here:

QStyle

QStyle is the class for making UI elements that follow the style given for the application. Instead of hardcoding all the styles, we use QStyle methods for writing things. This is what I was talking about in my previous post.

More information in here:

Breeze

Breeze is our current style/theme. It's what defines how things should look like. Sometimes when we say "Breeze" in QtWidgets context, it means the QStyle of it, since we do not have other name for it.

Repository: https://invent.kde.org/plasma/breeze/

QtQuick

QtQuick is the modern way of writing Qt applications. In QtQuick, we use QML which is a declarative language for writing the UI components and such. Then we usually have C++ code running the backend for the application, such as handling data.

More information in here:

qqc2-desktop-style

qqc2-desktop-style is the Breeze style for QtQuick applications. It tells QtQuick applications what certain elements should look like.

Repository: https://invent.kde.org/frameworks/qqc2-desktop-style/

Kirigami

Kirigami is a set of shared components and items we can utilize in our QtQuick applications. Instead of rewriting similar items every time for new apps, we use Kirigami for many things. We call them Kirigami applications since we rely on it quite a lot.

Kirigami and qqc2-desktop-style

These two are a bit intermixed. For example, Kirigami provides convenient size units we have agreed on together, such as Kirigami.Units.smallSpacing.

We then use these units in the qqc2-desktop-style, but in other applications as well: Both for basic components that QtQuick provides us which are then styled by qqc2-desktop-style, but also for any custom components one may need to write for an application, if Kirigami does not provide such.

My lizard fursona making an sad face.

I wish the two weren't so tightly coupled but there's probably a reason for that, that has been decided before my time. (Or it just happened as things tend to go.)

Diagram of the current stack

This is how the current stack looks like.

Diagram of current situation

Problem: Keeping styles in sync

As you can see from the diagram, the styles must be kept in sync by hand. We have to go over each change and somehow sync them.

My lizard fursona making an scream face.

Not all things have to be kept in sync. This whole thing is rather.. Primitive. Some parts come from QStyle, some parts are handcrafted, some metrics and spacings can get out of sync when changed.. But for purposes of "regular person reading this" they need to be carefully modified by developers to make sure everything looks consistent.

Even bigger problem is that these two (QtWidgets and QtQuick) can behave very differently, causing a lot of inconsistent look and behavior!

But this is why Union was made.

Union

Union is our own "style engine" on top of these two. Instead of having to keep two completely different stacks in sync, we feed Union one single source of truth in form of CSS files, and it then chews the data out to both QtQuick and QtWidgets apps, making sure the both look as close to each other as possible!

Diagram of what it looks like with Union

I think it's entirely possible to create other outputs for it too, such as GTK style. Our ideal goal with Union is to have it feed style information even across toolkits eventually, but first we just aim for these two! :)

My lizard fursona making an smile face.

And yes the CSS style files are completely customizable by users! But note that the CSS is not 1-to-1 something one would use to write for web platforms!

Repository: https://invent.kde.org/plasma/union/

Note about Plasma styles

Plasma styles are their own thing, which are made entirely out of SVG files.

I do not know if Union will have an output for that as well, or do we just use the qqc2-desktop-style directly in our Plasma stack (panels, widgets) so we can deprecate the SVG stack. Nothing has been decided in this front yet as far as I know.


Yeah that's a lot of stuff. Over +20 years of KDE we have accumulated so many different ways of doing things, so of course things will get out of sync.

Union will be a big step in resolving the inconsistencies and allowing users easily to customize their desktop with CSS files, instead of having to edit two or three different styles for different engines and then having to compile them all and load them over the defaults.

I hope this post helps open up this a bit. Please see the previous post as well, if you're interested in this work: https://akselmo.dev/posts/breeze-and-union-preparing/

Saturday, 28 February 2026

We have worked on some spring cleaning for Breeze, which helps us to prepare for Union and the changes it brings. This post is a bit more technical.

Help us test things!

Edit: I made another post that should help explain some of the terminology and such: https://akselmo.dev/posts/what-are-breeze-widgets-quick-union/

If you are running Plasma git master branch, you may have noticed that Breeze has gotten various (small) changes to it.

Note that these changes are NOT in 6.6 branch, just in master branch. Current target is Plasma 6.7 but that may change (6.8) if we still have some issues with it! And to clarify, I do not know when Union releases to wider public yet. These changes will be most likely before Union.

This all is happening for two reasons:

  1. Bring Breeze on-par with the current QtQuick styling, which is our current vision for Breeze
  2. Find out any discrepancies and fix them, to make moving to Union theming more seamless

In more technical terms, this means we have made QStyle::PE_PanelItemViewItem (docs) more round. This primitive is used in a lot of places.

For example, see the background of the places panel element here:

Places panel item background being more rounded

It looks much more like the items in our System Settings for example, since they're rounded too.

However this has not been easy: Due to how QStyle works, we have to add margins to the primitive itself, otherwise it will be touching the edges of the view, making it look bad.

These changes have made us notice bunch of visual oddities since we have +20 years of cruft across our stack, working on top of Breeze style without taking QStyle into account. People use completely custom solutions instead of relying on QStyle, though the QStyle API is not easy to work with so I do understand why it can be annoying.

Why does using QStyle API matters in regards to Union?

This is all fine and good if we just decide to use Breeze always and forever. But we're not! With Union style engine, people are going to do all kinds of cool things. First of course we just are trying to make 1-to-1 Breeze "copy" with Union, since it's a good target to compare that everything works.

But when people are going to make their cool new themes with Union, our QtWidgets stack will not always follow that, due to all the custom things they're doing! So we need to minimize custom styling within QtWidgets apps and frameworks, and make sure they use QStyle APIs, so that Union can tell them properly what to do.

A more practical example:

  1. KoolApp directly paints a rectangle with QPainter as a selection background.
    • It's a regular rectangle, 90 degree angles.
  2. Union style engine is released to the public and everyone starts making their own themes
  3. Someone makes a theme that makes all selection backgrounds a rounded rectangle
  4. They then open KoolApp and notice nothing changes! Since KoolApp draws its on its own.
  5. Everyone is unhappy. :(

However, when KoolApp is updated to use drawPrimitive like this:

// Remove the old background
//painter->setRenderHint(QPainter::Antialiasing);
//painter->setPen(Qt::NoPen);
//painter->setBrush(color);
//painter->drawRect(rect);

// Use style API instead
...
style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, &painter, this);
...

// Then for text, add some spacing at start and end so it does not hug the edges of the primitive
const int margin = style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing);

// NOTE: you can use QStyle::SE_ItemViewItemText to get the subelement of the text
// NOTE: If you use HTML to draw rich text, you will have to do adjustments manually!
//       Because nothing can be ever easy. :(
...

Now the background uses what the QStyle gives it, which in turn is whatever Union has declared for it.

I understand there are cases where someone might want to draw their custom thing, but if at all possible, please use QStyle API instead! It will make theming much easier on the long run.

Why change now? Why not wait for Union?

It's better to start catching this all now. It can be more tough to find the bugs with Union styling later on, because it changes much more than just one style: It changes the whole styling engine.

When we tinker with Breeze theme to find out these discrepancies, it's easier to spot if the problem is in Breeze theme itself or the application/framework drawing the items. With Union, we can also have a bug in Union too, so it adds one more layer to the bughunt.

So when Breeze looks fine with apps, we can be sure that any changes Union brings, it can be either a bug in Union or the style Union is using, instead of having to also hunt down the bug from application/framework.

Think of it as a gradual rollout of changes. :)

A call for testing

The current Breeze style changes we have now in git master branch are already out there if you're using KDE Linux for example.

What we need is YOU to test out our stack. Test out other peoples Qt apps too.

So please check this VDG issue and join there: https://invent.kde.org/teams/vdg/issues/-/issues/118

Read the tasks section, look over what others have shared, share information, etc. Report everything in that issue!

Any help is appreciated, from spotting small errors to fixing them.

I doubt our QtWidgets and QtQuick styles can be 1-to-1 without Union, so do not worry too much about that. At the moment goal is just to make sure the Breeze QStyle is properly utilized. Perfect is the enemy of good and all that.

I hope this does not cause too much annoyance for our git master branch users, but if you're using master branch, we hope you're helping us test too. :)

Let's make the movement from separate QtWidgets/QtQuick style engines to one unified Union style engine as seamless as possible. And this will help other QtWidgets styles too, such as Fusion, Kvantum, Klassy, etc..!

Happy testing!

For Weeks 4 and 5, I tackled a pretty big issue in Lokalize: "ghost actions." Back in Week 2, I had asked the KDE translators' mailing list for feedback on their workflow. Based on their responses and digging through the ui files, i found several editing and file management tools that were declared in the XML but had no actual C++ backend. My goal was to finally wire these up.

To keep the review process manageable, i split the work into two Merge Requests.

My first MR implemented Cut, Copy, Paste, and an Alternate Translation File picker. The tricky part here was figuring out context. Lokalize's editor isn't just a single text box a user might be focused on the main translation area, the search bar, or another input field entirely. I needed to route the edit action to whichever widget the user was actively using.

I really didn't want to write a massive, fragile chain of qobject_cast checks for every possible widget type in the codebase. Instead, I ended up using Qt's meta-object system. I wrote a helper function using QMetaObject::invokeMethod():

void EditorTab::triggerFocusedEditAction(const char *methodName)
{
    QWidget *focusWidget = QApplication::focusWidget();
    if (focusWidget && QMetaObject::invokeMethod(focusWidget, methodName, Qt::DirectConnection))
        return;

    QMetaObject::invokeMethod(m_view->viewport(), methodName, Qt::DirectConnection);
}

This dynamically asks the currently focused widget at runtime if it supports the requested action. If it doesn't, it just falls back to the main translation viewport. It's a much cleaner approach that keeps the logic completely decoupled from specific widget types.

Image

My second MR added batch actions: Save All, Revert All, and Close All. For "Close All", I built a safe shutdown sequence that loops through all open files and prompts the user for unsaved changes.

Image

It feels great to have both of these MRs merged:)

Friday, 27 February 2026

If you are building an XMPP client or bot today, plain text is no longer acceptable. Users expect modern, multi-device, end-to-end encryption.
Continuing my Season of KDE work on the Mankala game engine, I've completed a comprehensive implementation and benchmarking of five different parallel programming models for alpha-beta search. This post explores the performance characteristics, trade-offs, and surprising results from parallelizing g…
Imagine you’re sending a private message to a friend.

Wednesday, 25 February 2026

Today we're releasing Krita 5.2.16. The previous version of 5.2 had issues with saving heif, heic and avif files, and while we are busy preparing 5.3, we decided this was worth it to make another release over.

Download

Windows

If you're using the portable zip files, just open the zip file in Explorer and drag the folder somewhere convenient, then double-click on the Krita icon in the folder. This will not impact an installed version of Krita, though it will share your settings and custom resources with your regular installed version of Krita. For reporting crashes, also get the debug symbols folder.

ⓘ Note

We are no longer making 32-bit Windows builds.

Linux

Note: starting with recent releases, the minimum supported distro versions may change.

⚠️ Warning

Starting with recent AppImage runtime updates, some AppImageLauncher versions may be incompatible. See AppImage runtime docs for troubleshooting.

MacOS

Note: minimum supported MacOS may change between releases.

Android

Krita on Android is still beta; tablets only.

Source code

md5sum

For all downloads, visit https://download.kde.org/stable/krita/5.2.16/ and click on "Details" to get the hashes.

Key

The Linux AppImage and the source tarballs are signed. You can retrieve the public key here. The signatures are here (filenames ending in .sig).

Tuesday, 24 February 2026

I interviewed Robert back in 2017 because he was going to deliver the opening keynote at Akademy that year. He
An exploration of things that could be.

Monday, 23 February 2026

While working on the Mankala Next Gen project for Season of KDE, I needed to create two distinct logos: one for the game itself and another for the mankalaengine backend. What started as a straightforward design task in Inkscape quickly became a lesson in SVG optimization when my initial exports bal…