Skip to content

Friday, 25 November 2022

Let’s go for my web review for the week 2022-47.

Open letter for the right to install any software on any device - FSFE

Tags: tech, vendor-lockin, foss

Definitely something to sign, let’s get back some freedom on the device we got in our pocket.

Digital environmental impact evaluation accross organizations

Tags: tech, ecology

I often find tools regarding environmental impacts on the client side. This group seems to focus more on the server side, definitely something to look into.

The Fediverse Could Be Awesome (if we don’t screw it up)

Tags: tech, fediverse, social-media

This sudden rise of the Fediverse is indeed a chance. Let’s hope it’s not wasted. Good list of things to pay attention to in this article.

Tags: tech, blog, rss

Woa, that’s definitely welcome. A strong list of blogs to use in your feed aggregator. Time to explore.

Tree views in CSS

Tags: tech, web, frontend, css

Nice CSS trick to make collapsable trees without too much fuss.

An Interactive Guide to Flexbox in CSS

Tags: tech, frontend, browser, css

Nice guide, the interactive parts definitely help. Good way to improve CSS use.

Internals of sets and dicts | Fluent Python, the lizard book

Tags: tech, python, performance, optimization

Interesting deep dive on how sets and dicts are implemented in CPython. There are a couple of interesting tricks in there.

Always use [closed, open) intervals. A programmer’s perspective

Tags: tech,, programming,, mathematics

Good reasons to use [closed, open) intervals. If you didn’t know where it was coming from, here it is.

D2 Tour | D2 Documentation

Tags: tech, diagrams

That looks like a nice declarative language to make diagrams. Missing sequence diagrams but otherwise seems fairly useful and readable.

Ignore RuboCop changes in Git Blame

Tags: tech, git

Now this is a very interesting trick for git. This way large reformatting commits are less of a concern when exploring commit history.

Inhumanity of Root Cause Analysis – Verica

Tags: tech, complexity, project-management, failure, postmortem

A bit heavy handed in the way it tries to paint Root Cause Analysis as evil. Still it has good points about its shortcomings. In particular I appreciate the emphasis on complexity which indeed points to have contributing factors and unexpected outcomes. Definitely things to keep in mind for any postmortem efforts.

The Ancient Japanese Technique That Produces Lumber Without Cutting Trees

Tags: history, japan, ecology

Very interesting technique. Clearly some more work but prevents deforesting like mad for lumber. It’s amazing to see those… clearly a bit like giant bonsais.

Bye for now!

Be like Konqi and get all KDE's awesome apps, all the versions of Plasma, and fantastic frameworks to build your own software at unbelievable prices!

Blue Friday is here!

Thursday, 24 November 2022

Since the last post about AudioTube, a lot has happened! So in this blog post, you can find a summary of the important changes.

Notable new features


AudioTube now has a library, in which you can see your favourite, most often and recently played songs. library with rounded covers

Filtering through previous searches

This allows searching through locally known songs and previous search terms, without even sending a request to youtube. search dialogue which displays songs from your history


While playing a song, you can now see the lyrics of the song in a separate tab. lyrics shown in the player

User Interface improvements

Finally, AudioTube displays album covers everywhere. Devin Lin has redesigned and improved the actual audio player. Mathis Brüchert has done several design improvements across the board, like rounded album covers, improved spacing.

The support for wider screens has also been improved, and the queue list will now only expand up too 900 virtual pixels. player


Fetching thumbnails is now much faster, since in most cases the thumbnail ID can be reliably predicted, without querying yt-dlp. In the few remaining cases, querying yt-dlp is still the fallback


If you want to try AudioTube, you can get the latest stable version from flathub. If you want the latest improvements, which are usually already reasonably stable, you can grab a nightly build from the KDE Nightly flatpak repository.

Code improvements

While developing the library feature, a small new library was developed. I called it FutureSQL, after the QFuture type it uses for most parts of its API. FutureSQL provides an asynchronous API for QtSql, by running the database queries on a separate thread. It also provides convinient template functions for passing parameters to SQL queries.

Possibly the most interesting feature is automatically deserialize the resulting data from an SQL query into a struct. This works thanks to C++ templates.

In the simplest cases, nothing but

struct Song {
	using ColumnTypes = std::tuple<QString, QString, QString, QString>;

	QString videoId;
	QString title;
	QString album;
	QString artist

is required.

The library version of this code does not yet have a stable release, however you can already try the API if you build the library from the repository.

Ramon has just published a new video, digging deeper than ever into brush preset creation in Krita! Enjoy!


The post New Video! Making Brushes Part 4 appeared first on Krita.

Wednesday, 23 November 2022

KDE is getting a much more user-friendly fundraising platform, and it’s a big deal!

Currently our small-donor donation page is, which lets you make a single one-time donation. To make a recurring donation, you have to visit, which is less user-friendly, and it’s always struck me as odd to have these split up in two locations.

Well, KDE is getting a much better donation system powered by Donorbox, which I hope will turbocharge our fundraising! It’s very user-friendly and allows you to easily make recurring donations, which is important. We already set this up for the Kdenlive fundraiser, and it was a smash hit, raising 100% of the funds in the first month of the 3-month campaign. That fundraiser has since moved into stretch goals!

We’ve now done it again, rolling out a Donorbox-powered donation UI on, our tongue-in-cheek anti-black-friday fundraiser, which will become a general end-of-year campaign. This work was done by members of KDE’s promo team and fundraising working group, principally Lays Rodrigues, Carl Schwan, and Paul Brown. And so far the response has been huge! The fundraiser opened yesterday, and at the time of publication, it’s already collected 530€ from 28 generous donors! And after the new year, the current plan is to continue to use the Donorbox-powered UI for all small donations.

This really goes to show how important user-friendliness is. When you make it easy for people to give you money… they give you more money! Thank you so much, everyone.

Why is all this money stuff so important? Well, it’s how the KDE e.V. pays for hiring (such as for the Platform Software Engineer position I blogged about two days ago), development sprints, conferences, infrastructure, and similar activities that help KDE thrive and grow. If we’re gonna hugely expand technical employment–which is a major goal of mine–then we’re gonna need a lot more recurring donations to do it.

So what are you waiting for? Head over to and make a donation today. If it’s a recurring donation, we’ll love you forever! 🥰

Tuesday, 22 November 2022

Initial support for rpm-ostree was added in Discover as part of a Season of KDE 2021 project that was completed by Mariam Fahmy.

Unfortunately, we hit some hard to diagnose issues related to DBus interactions with rpm-ostree so the work was left in limbo for a while and kept disabled in Fedora Kinoite.

I recently picked it up again and implemented a workaround as I could not figure out the root cause of the original issue.

I am pleased to announce that we now have good support for rpm-ostree in Discover! 🎉

This will be available with the Plasma 5.27 release. It will be pushed to Fedora Kinoite 37 once the update is ready and will be available by default in Fedora Kinoite 38.

In the meantime, here are some screenshots of how this will look like!

First, here is the default view in Discover. Notice that we now have an Operating System category.

Default view in Discover

All versions of the system are listed there.

Operating System category

Selecting a deployment will get you more details. You can see that this version is pinned. This means that it will not be automatically cleaned-up by rpm-ostree. Support for pinning and un-pinning versions has not been implemented yet but the status is shown in the interface if you do it via the command line.

Entry detail

If you go into the Update section you will see the available updates.

Available updates

You can “mostly” follow the update progress. I say “mostly” here as we are not fully able to represent the entire progress in Discover yet (due to the DBus interface issues mentioned at the beginning) so the progress is not completely accurate as we do not show download progress.

Update in progress

Once the update is installed, you will be suggested to reboot. rpm-ostree updates are transactional, safe and atomic: they do not change your currently running system and are installed alongside it. Using a system with a pending update is thus perfectly safe. The new version will be used after a reboot.

Ready for reboot

If you look at the Operating System category before you reboot, you will see the new installed version waiting here. You do not need to reboot right away and can wait for a good time for you. If a new version is released, Discover will offer the new version as an update again and you will directly update from the current version to the latest one.

Operating System category before reboot

Once you have rebooted, you can see the new version as active and the previous version as fallback.

Operating System category after reboot

Now let’s see what happens when a new major version of Fedora Kinoite is released. If you have pending or available updates for the current version, then Discover will ask you to update your system first.

New major release with pending update

Same thing in the update view with pending updates.

New major release with pending update (update view)

If you are all up to date, then you can rebase to the next major version.

Rebase to next major version available

Same thing in the update view.

Rebase to next major version available (update view)


I will soon write an updated blog post about how I do KDE development on Fedora Kinoite but in the meantime you can follow the instructions from the Development on Fedora Silverblue and Fedora Kinoite post to build Discover from source.

Please report any issue you may find in the KDE bug tracker with the Discover product and the rpm-ostree Backend component.

I will also soon start a discussion with KDE’s Visual Design Group (VDG) to work on improving the user experience in Discover for this backend.

We just released CXX-Qt version 0.4!

CXX-Qt is a set of Rust crates for creating bidirectional Rust ⇄ C++ bindings with Qt. It can be used to integrate Rust into C++ applications using CMake or build Rust applications with Cargo. CXX-Qt provides tools for implementing QObject subclasses in Rust that can be used from C++, QML, and JavaScript.

For 0.4, most of the internals of CXX-Qt have been refactored into stages, which means it is easier to maintain. There are various small changes to the API, such as the capability of using attributes in more places rather than magic struct names. Relocatable Qt types have been marked as trivial to CXX (which means they don’t need to be wrapped in pointers).

Some of the larger developer-facing changes are listed below.

Refactor of API So That CXX-Qt is a Superset of CXX

You can now combine CXX definitions into the CXX-Qt bridge macro.

This allows you to define custom types with CXX extern blocks that can then be used for CXX-Qt purposes, such as properties, invokables, and signals.

For example, in the bridge below, a CXX extern “C++” block is used to define QString as a type. Then, this can be used as a property in the QObject definition.

mod my_object {
    unsafe extern "C++" {
        type QString = cxx_qt_lib::QString;

    pub struct MyObject {
        number: i32,
        string: QString,

Rewrite of the Build System

Custom CMake files have been removed from the build process; Corrosion is used instead, for CMake builds. This allows for a cleaner build that configures and builds Rust code at the correct times.

There is also support for Cargo-only builds for Rust developers who don’t use CMake.

Simplified Thread Queueing

Rust closures can now be used to queue tasks onto the Qt event loop from a Rust background thread. This allows you to capture items rather than use a channel with function pointers, as we did in the previous release.

Thanks to Yuya Nishihara for this contribution.

// In an invokable request a handle to the qt thread
let qt_thread = self.qt_thread();
// Spawn a Rust thread
std::thread::spawn(move || {
    let value = compute_value_on_rust_thread();
    // Use a closure to move the value and run the task on the Qt event loop
        .queue(move |mut qobject| {
            // Happens on the Qt event loop

For More Information

Find CXX-Qt on our GitHub page.

We also have a Rust book with a getting started guide.

Discussions and contributions are welcome, as the API continues evolving for 0.5. With 0.5, we hope to improve the ability to implement listmodels from Rust and introduce Qt container types.


About KDAB

If you like this article and want to read similar material, consider subscribing via our RSS feed.

Subscribe to KDAB TV for similar informative short video content.

KDAB provides market leading software consulting and development services and training in Qt, C++ and 3D/OpenGL. Contact us.

The post CXX-Qt 0.4 Released appeared first on KDAB.

Monday, 21 November 2022

Yes that’s right folks, it’s happening!!! KDE is growing up, joining the big leagues, and cooking on all burners!

The KDE e.V. recently dipped its toes into the waters of technical hiring by contracting with longtime KDE contributor Ingo Klöcker to maintain and improve KDE’s packaging infrastructure for non-FOSS platforms. Now we’re at it again with a new open position for a “Software Platform Engineer.”

This is an open-ended development position, with responsibilities for work on KDE frameworks, Plasma, Qt, middleware like Pipewire and Wayland protocols–basically, the same things that a lot of people are already doing. But… on a consistent work-work basis, for money, with your KDE friends as professional colleagues and supervisors!

If this interests you, check out the job ad and apply! We want lots of good candidates so we can feel bad about only hiring one person and then feel even more incentivized to open more positions for them too! And we have other open positions as well! So go apply for a career in KDE today!

Of course sustaining these high-pay technical positions won’t be cheap. The KDE e.V. can just barely afford it now, and needs a larger and growing budget to be able to sustainably keep up the pace of hiring. Please donate today! Every little bit helps. If you can swing it, make it an annual donation!

Rotate what now? Aks, what are you talking about?

I wanted to write down how I made the enemy characters in Artificial Rage rotate towards the player, since I couldn’t find a simple answer.

Most things I found was math. Now math is fun and good, but when you’re tired and want to get one thing just to work at 4 am, it’s not gonna help you.

Especially since I’ve never learned linear algebra at any school I’ve went to (or I just likely don’t remember), and double especially since all the math lingo is in English and I have no idea what any of it means!!!

Getting Gooder at math is on my eternal to-do list, but anyhow, for those like me who just need to get something done, here’s how I did it.

First off, I just wanted the character to rotate around it’s Y-axis: If you would stick a.. well stick in a grape and twirl the stick in your fingers, that’s the Y-axis of the grape. This means the following snippet does not take account the other axises. But I’m sure it could be used for it.

Code dump incoming:

// C99 code
void Actor_RotateTowards(Actor_Data* actor, Vector3 targetPosition)
    // Rotates the actor around Y axis
    Vector3 diff        = Vector3Subtract(actor->position, targetPosition);
    float y_angle       = -(atan2(diff.z, diff.x) + PI / 2.0);
    Vector3 newRotation = (Vector3) { 0, y_angle, 0 };

    // Use quaternion slerping for smoother rotation, so the actor always follows the shortest path
    Quaternion start = QuaternionFromEuler(actor->rotation.z, actor->rotation.y, actor->rotation.x);
    Quaternion end   = QuaternionFromEuler(newRotation.z, newRotation.y, newRotation.x);
    Quaternion slerp = QuaternionSlerp(start, end, actor->rotationSpeed * GetFrameTime());

    actor->model.transform = QuaternionToMatrix(slerp);
    actor->rotation        = newRotation;

I’ll quickly walk you through the code:

  1. First you need the position of the target, so the actor knows where to rotate towards.
  2. Get the difference between actors position and targets position
  3. Measure the counterclockwise angle for the X- and Z-axis of the difference of the actor and target position, then rub some PI on it. Divide this with two because my friend CapitalEx said so. Something about radians/euler angles. Math. Comment if you can explain this like you would for a 5 year old. hlep
  4. Your new rotation is now ready, just use the y_angle you got for the, well, Y-axis.
  5. Uhhhhh quaternions. Create Quaternion for start position that is the current rotation of the actor, end position that is the target rotation so the thing you just got. We use quaternions so the computer uses shortest rotation path possible.
  6. Slerrrrrrrp the rotation from start to end with your wanted speed. Don’t forget to apply frame deltatime or the higher the fps, the faster the spins.
  7. Give the new cool slerped quaternion you just got as a matrix to the model’s transform. Don’t forget to update the rotation to the new one.
  8. Done! Nice.

I wish I understood this better. I’ve tried to learn quaternions with this fun website: It works for a while, but then I forget it.

Anyhow, that’s the gist of it. Now the 3d models rotate around their Y-axis towards anything you would ever want. Nice!

Feel free to explain math in the comments to me. Again, math words in English are difficult for me, but if explained simple enough I think I would understand it. Also if you have videos you can recommend me about the topic, do share!

That’s all for this time, thanks for reading!

Sunday, 20 November 2022

QCoro 0.7.0 Release Announcement

The major new feature in this release is initial QML support, contributed by Jonah Brüchert. Jonah also contributed QObject::connect helper and a coroutine version of QQuickImageProvider. As always, this release includes some smaller enhancements and bugfixes, you can find a full list of them on the Github release page.

As always, big thank you to everyone who report issues and contributed to QCoro. Your help is much appreciated!

Initial QML Support

Jonah Brüchert has contributed initial support for QML. Unfortunately, we cannot extend the QML engine to support the async and await keywords from ES8, but we can make it possible to set a callback from QML that should be called when the coroutine finishes.

The problem with QCoro::Task is that it is a template class so it cannot be registered into the QML type system and used from inside QML. The solution that Jonach has come up with is to introduce QCoro::QmlTask class, which can wrap any awaitable (be it QCoro::Task or any generic awaitable type) and provides a then() method that can be called from QML and that takes a JavaScript function as its only argument. The function will be invoked by QCoro::QmlTask when the wrapped awaitable has finished.

The disadvantage of this approach is that in order to expose a class that uses QCoro::Task<T> as return types of its member functions into QML, we need to create a wrapper class that converts those return types to QCoro::QmlTask.

Luckily, we should be able to provide a smoother user experience when using QCoro in QML for Qt6 in a future QCoro release.

class QmlCoroTimer: public QObject {
    explicit QmlCoroTimer(QObject *parent = nullptr)
        : QObject(parent)

    Q_INVOCABLE QCoro::QmlTask start(int milliseconds) {
        // Implicitly wraps QCoro::Task<> into QCoro::QmlTask
        return waitFor(milliseconds);

    // A simple coroutine that co_awaits a timer timeout
    QCoro::Task<> waitFor(int milliseconds) {
        QTimer timer;
        co_await timer;

qmlRegisterType<QmlCoroTimer>("cz.dvratil.qcoro.example", 0, 1);
import cz.dvratil.qcoro.example 1.0

Item {

    QmlCoroTimer {
        id: timer

    Component.onCompleted: () {
        // Attaches a callback to be called when the QmlCoroTimer::waitFor()
        // coroutine finishes.
        timer.start(1000).then(() => {
            console.log("1 second elapsed!");

Read the documentation for QCoro::QmlTask for more details.

QCoro::connect Helper

The QCoro::connect() helper is similar to QObject::connect() - except you you pass in a QCoro::Task<T> instead of a sender and signal pointers. While using the .then() continuation can achieve similar results, the main difference is that QCoro::connect() takes a pointer to a context (receiver) QObject. If the receiver is destroyed before the connected QCoro::Task<T> finishes, the slot is not invoked.

void MyClass::buttonClicked() {
    QCoro::Task<QByteArray> task = sendNetworkRequest();
    // If this object is deleted before the `task` completes,
    // the slot is not invoked.
    QCoro::connect(std::move(task), this, &handleNetworkReply);

See the QCoro documentation for more details.

Full changelog

See changelog on Github