Skip to content

Tuesday, 16 September 2025

This post is long winded and unfocused. If you prefer to not experience my rambling, this is your warning. If you do, enjoy!

Pre-Akademy Akademy-ing

Hello! I was at Akademy 2025! Along with Devin and Derek, this trip was actually part of a larger grad trip, the ending of which happened to conveniently line up with Akademy. The last time I attended Akademy was back in 2022, so I was excited to be back!

Flying out of Hong Kong airport to Berlin onboard Turkish Airlines

The last part of the grad trip was in Hong Kong, so naturally that’s where the journey to Akademy begins! We flew out using Turkish Airlines (a first for me), stopping over in Istanbul. I will say, the economy seats do come with a nice amenities kit:

In any case, after a brief (and really expensive! the food was not cheap!) layover in Istanbul, we arrive in Berlin! It was night by the time we got into the hotel, so we got some snacks and then headed to bed.

The first full day was all about getting setup, doing a bit of exploring, then heading out to the evenings main event: the welcome event!

The Pixel 3a was my Plasma Mobile device of choice for this Akademy (I found it in a Hard Off store in Japan during the trip!), and since Derek was getting a SIM for his phone, I decided to also get one for the Pixel. This lead to a pretty entertaining sequence of pulling out a Plasma Mobile device when the employee offered to install the SIM for me.

It all worked out, though! I mean, I ended up doing most of the work actually navigating the OS (they looked somewhat concerned when I rebooted the phone to get the SIM card recognized and the tty sped by), and they had to take a moment to look up the APN settings (probably an uncommon occurrence for them), but the SIM installed and I was connected to the Vodefone network without any drama.

The Brandenburg Gate
A classic Quebec moment, a Quebec government office near the Brandenburg gate. It’s not a Canadian embassy!
Ah, the Europeans sure do love their institutions. I do, too!

Of course, before heading back to the hotel room, we had to indulge ourselves with some local Berlin cuisine, which means currywurst. (for those not aware, it’s sausage and fries with ketchup, mayo and curry powder).

The currywurst was actually really good, we got more the next day too.

Back in the hotel room now, and you would think maybe we’d take a nap or otherwise rest. But nope, my hotel room instead became a place to lock in. After all, there were things that needed to be done! I for one spent the time flashing a fresh copy of postmarketOS on to my Anbernic RG35xx.

Akademy Welcome Event

Finally, it is time to go to the welcome event! Being in the Plasma Mobile sphere, naturally I sat with various Plasma Mobile and adjacent people. Overall a fun night, lot’s of excitement in the air with people meeting each other (some for the first time, some after years), and of course excitement for the week of Akademy to come. Also naturally, the table was full of drinks, food, and Plasma Mobile devices.

Akademy Day 1

Talks, talks, and more talks! That is the name of the game for the first two days of Akademy. Taking place in university lecture halls, they cover a wide variety of KDE related topics and are really interesting to listen to. There are also a lunch break, plus some coffee breaks sprinkled in.

During the day, there are usually two talks running in parallel in the two rooms, so you need to pick one. These are the talks I attended on Day 1:

  • Keynote: Open by Design: How Governments Can Lead the Shift to Digital Sovereignty (Alexander Rosenthal)
  • Plasma: Lessons Learned and Our Path Forward in 2026 and Beyond (David Edmundson)
  • KDE Linux: Banana Growth Cycle (Harald Sitter)
  • The Role of New Languages in the Future of the Qt Ecosystem (Dr Cristián Maureira-Fredes)
  • Report of the Board, Report of the Working Groups
  • KDE Goals – One Year Recap
  • Lightning talks: What’s New with Qt Learning? (Emilia Valkonen-Damjanovic), Gently Retiring KWallet (Marco Martin), Emergency and Weather Alerts (Volker Krause), Boosting your code and simplifying your life with clazy (Alexander Lohnau)

If any (or all) of those titles seem interesting to you, you can check out the Akademy program website for full descriptions. At some point the talks will also be edited and posted online as well.

In the little bits of time I managed to get during the day, I did get some work done as well! A handful of improvements to KRetro (my Libretro frontend for Plasma) and some hacking on Plasma Mobile.

After the talks finished for the day, people headed home or out to eat dinner in various groups. I went with one such group and had some really tasty vegan thai curry!

mmm delicious

Akademy Day 2

Wake up! It’s a new day, more talks! You don’t want to miss it! (I might have slept in a bit)

Day 2 is structured much the same as day 1, with the exception of the group photo! Always a fun time seeing everyone gathered together in one space.

The talks I attended on day 2 were:

  • Handling Negative Feedback (Akseli Lahtinen)
  • Developing on Flatpak (Aleix Pol Gonzalez)
  • Getting Hired to Work on FOSS – The Do-s, Don’t-s and Pitfalls for Everyone Involved (Till Adam)
  • Next-Gen Documentation Infrastructure for KDE (Nicolas Fella)
  • Fedora KDE Plasma Desktop Edition is Real, Now What? (Neal Gompa)
  • Lightning talks: Say what now? – Communication Theory for Software Developers (Nicolas Fella), The Art of a Good Commit Message (David Edmundson), Plasma Mobile Power Management: Reliable Sleep and Wake Ups (Bhushan Shah), Funding and Growing – Kdenlive Experiences and Perspectives (Jean-Baptiste Mardelle)

And would you look at that, the talks are done! Blink and you’ll miss ’em. Honestly it felt like they went by so fast, it’s lots of fun getting to see all the KDE community members you see online in person, and getting to hear all the cool things they are involved in.

The rest of Akademy week?

After the saturday and sunday full of talks, the rest of Akademy week is dedicated to various activities, notably BoFs (birds-of-a-feather). They are essentially meetings of different interests (usually of specific topics, for example there is a BoF for Plasma Keyboard). These represent a pretty important part of Akademy, all these developers and community members from around the world are in one place, and so you get the unique opportunity to have in person meetings, discussions and planning. Besides BoFs, there are also various workshops and trainings held as well. Plus, there is the day trip in the middle of the week!

Unfortunately I could not attend the rest of Akademy due to timing with other obligations, and so it was time to finally head back home and bring the trip to a close.

Goodbye, Akademy!

The 3 days of Akademy were a lot of fun! It was great to meet fellow KDE community members and hear about all they had to say in the talks. I look forward to hopefully attending Akademy again next year!

Monday, 15 September 2025

Qt Multimedia is getting its own category at the Qt Forums!

As accessibility continues to gain traction across major operating systems, high contrast mode has become a key feature for improving visual clarity and usability. With the release of Qt 6.10, applications built with Qt now readily get support for high contrast modeacross multiple platforms, ensuring more inclusive and visually adaptive UIs. In this post, I explore how Qt 6.10 supports high contrast mode, what it means across different systems, and what Qt now provides for built-in styles.

Check out this quick video on a high contrast mode example to get you started:

Enhancing Accessibility with Better Contrast

In recent years, major platforms such as Windows 11, macOS, and the Gnome desktop have introduced settings for a high contrast mode that enhances the contrast between foreground and background user interface elements. Adjusting these contrast settings typically updates the system color scheme and, in some cases, adds more pronounced outlines or other modifications to native UI controls. On macOS, iOS, and Gnome, users can enable increased contrast through a toggle in the accessibility section of the system settings, which reinforces outlines for most native controls. Windows 11 takes a more advanced approach with its Contrast themes feature, resulting in significant changes to the appearance of native applications when activated.

New with the High Contrast Mode in Qt 6.10 

KWin Gamepad Plugin: Weeks 3-4

Picking up from weeks 1+2 ( research + prototypes with libevdev/uinput ), these two past weeks were about moving from “research-only mode” to turning ideas into programming logic that lives inside KWin to: detect gaming controllers and their input events, keeps Plasma awake on controller activity, handles hot-plug and pre-existing connections on startup, and lays down the first mappings from controller input to keyboard/mouse actions without stepping on other apps utilizing the controllers.

From the start my mentors and I have had a general idea of the features we wanted to add but weren't too sure how to implement them. After some thinking and experimenting they advised me to start off with a KWin::Plugin. This would allow us to start introducing the gaming controller functionalities to KWin while avoiding having to edit the core or guts of KWin. It would also be a great entry point for current and future game controller input objectives, allowing us to start small with a 1st party KWin plugin, build on it, and possibly integrate it into core functionality.

When it comes to creating KWin plugins I had a few options:

  • Scripts: Written in QML/JavaScript and used for automating window management, tiling, shortcuts, etc.
  • Effects: Implement visual effects on windows, the desktop, or transitions.
  • Core/Native: These are built into KWin itself and extend KWin’s internal functionality.

Since the plugin needs low-level device access, such as monitoring /dev/input/event*, listening to udev hotplugs, opening fds, and reacting to evdev events the best choice was to go with Core / Native plugin. As opposed to Effect and Script plugins which aren’t designed to open devices or do long-running I/O, most simply just live inside the rendering/scripting layers.

I started off by searching for an example of how to build a KWin plugin so I could start learning how to build my own. Thankfully my mentor @zamundaaa provided me with some great examples:

  • Example / Tutorial plugin located in src/plugin/examples/plugin
  • Screenshots plugin located in src/plugins

Between both of these examples and mentoring I was able to piece together the scaffolding ( essential parts ) of a KWin plugin and was able to put together the first version of this plugin, gamepad plugin, located in: kwin/src/plugins/gamepad. At this point the plugin is structured as follows:

main.cpp // Entry point & Defines GamepadManagerFactory Class
metadata.json // Declares the plugin to KWin, define information about plugin
CMakeLists.txt // C++ Build/Installation/Logging wiring
gamepadManager.{cpp/h} // Plugin Logic: Defines GamepadManager Class
gamepad.{cpp/h} // Game Controller Object: Wrapper Class for Physical Controller

Implementation notes

GamepadManagerFactory

GamepadManagerFactory Class serves simply as the entry point for the plugin. It's a factory class, or a class used to create other classes / object types. Like the examples, it inherits from PluginFactory and declares it as its interface as well as pointing to the metadata.json file for this plugin. It initializes the plugin through its create() function which returns a GamepadManager.

GamepadManager

GamepadManager class serves as the central coordinator (the “brain” or “hub”) of the entire project. While creating this I took a lot of inspiration from src/backend/drm/drm_backend.{cpp/h}, which itself is responsible for handling drm/gpu devices. GamepadManager covers many responsibilities. It owns and manages all gamepad devices, handles discovery (startup enumeration, hot-plug), lifecycle (adding/removing), and communication (signals when pads are added/removed, or when their state changes). Overall its responsible for keeping track of the current set of controllers and their status.

Detect hot-plug and pre-existing device detection:

For this part many of the DRM backend pattern were used. The first thing the manager class does on initialization is create two QMetaObject::Connections that monitor the current KWin session for devicePaused and deviceResumed signals. This helps track devices when Plasma goes in and out of sleep/suspend which causes devices to be Paused and Resumed. It then enumerates over all event devices located in /dev/input/event* to handle any pre-existing connections to game controllers. If it discovers an event device it adds the gamepad ( start tracking it and its input ).

// On init:
// Enumerate current input nodes to filter and add ONLY event nodes
QDir dir(QStringLiteral("/dev/input"));
const auto files = dir.entryList({QStringLiteral("event*")}, QDir::Files | QDir::Readable | QDir::System);
for (const QString &file : files) {
 const QString path = dir.absoluteFilePath(file);
 if (!isTracked(path)) {
 addGamepad(path);
 }
}

Finally using udev it monitors the subsystems and filter for only "input" subsystem events. It uses QSocketNotifier to produce signal notifications from udev events and creates a connections between that notifier and a memeber function, handleUdevEvent, that handles events coming from the udev monitor when an input device is detecetd. Some checks are performed to verify if the device is a gaming controller, such as expected input events and input event types. This include input events like BTN_JOYSTICK and BTN_GAMEPAD, which are commonly defined in gaming controllers. As well as checking for joystick or D-pad capabilities. If the checks pass the game controller is "added", or in other words, the device is wrapped in a Gamepad class, kept track of and its presence monitored.

// setup udevMonitor
if (m_udevMonitor) {
 m_udevMonitor->filterSubsystemDevType("input");
 const int fd = m_udevMonitor->fd();
 if (fd != -1) {
 m_socketNotifier = std::make_unique<QSocketNotifier>(fd, QSocketNotifier::Read);
 connect(m_socketNotifier.get(), &QSocketNotifier::activated, this, &GamepadManager::handleUdevEvent);
 m_udevMonitor->enable();
 }
}

Gamepad

Gamepad is a wrapper class. It's purpose is to be tied to a physical controller. One Gamepad object per physical game controller. This enables quick access/reference to the device and allows for the physical controller to be treated like an object. This class is also responsible for device input handling, Plasma Idle refresh, and button to keyboard/mouse mappings. In the future things might get split up into seperate files but as it is, it handles a lot. As with the GamepadManager, this class takes a lot of inspiration from DRM backend patterns.

Detect Input Events:

Once a gaming controller device is detected it gets wrapped in a Gamepad class object. Which in turn wraps the controller in a libevdev object pointer. This is the part that gives access to the controller through the libevdev API, making it easier to work with it and monitor its input events. Like GamepadManager the first thing this class does is use QSocketNotifier to produce notifications from the controllers fd, i.e monitor for input. It then creates a connections between that notifier and a member function, handleEvdevEvent, which handles all incoming input events from that device.

libevdev *evdev = createEvDevice();
if (evdev) {
 m_evdev.reset(evdev);

 m_notifier = std::make_unique<QSocketNotifier>(m_fd, QSocketNotifier::Read, this);
 connect(m_notifier.get(), &QSocketNotifier::activated, this, &Gamepad::handleEvdevEvent);

 qCDebug(KWIN_GAMEPAD) << "Connected to Gamepad ( new libevdev* ): " << libevdev_get_name(m_evdev.get()) << "at" << m_path;
}

Plasma Idle Refresh On Controller Activity

With the ability to monitor for all input events from the device, the plugin then uses that information to know when to reset Plasma idle timer. For this Gamepad imports/includes input.h file and makes a call to input()->simulateUserActivity() when an input event is detected from the controller. This causes Plasma idle timer to be reset and prevents the system from going into sleep/suspend mode while using only gaming controller.

// reset idle time
input()->simulateUserActivity();

Controller -> Keyboard & Mouse Mapping

Gamepad uses API function from libevdev to check for input events, identify the specific input event and map that to a keyboard or mouse input event. Using libevdev_next_event() it checks for the input event coming from that game controller. It then identifies the specific input event through its input event type, code, and value. To simulate a mouse and keyboard the core/inputdevice.h file is imported and used to declare GenericInputDevice which inherits from InputDevice. That GenericInputDevice effectively behaves like a virtual keyboard and mouse inside KWin’s input stack.

When specific libevdev input event are identified, such as EV_KEY + BTN_SOUTH ( A button press ) OR EV_KEY + BTN_EAST ( B button press ), it call InputDevice::sendKey() to simulate keyboard key press and inject the desired keys into KWin input pipeline. In this case Enter for A ( BTN_SOUTH ) and Escape for B ( BTN_EAST ). To emulate mouse/pointer the plugin makes calls to InputDevice::sendPointerButton() for left and right mouse buttons, and InputDevice::sendPointerMotionDelta() for pointer movement.

architecture_diagram_0
architecture_diagram_1
architecture_diagram_2
architecture_diagram_3

Here is a list of all the buttons to keyboard/mouse mappings:

Face Buttons
------------
BTN_SOUTH → Enter (Qt::Key_Return)
BTN_EAST → Escape (Qt::Key_Escape)
BTN_NORTH
BTN_WEST

Bumpers
-------
BTN_TL → Alt (Qt::Key_Alt)
BTN_TR → Tab (Qt::Key_Tab)

Trigger Buttons
---------------
ABS_Z → Mouse Left Click
ABS_RZ → Mouse Right Click

D-Pad
-----
BTN_DPAD_LEFT → Arrow Left (Qt::Key_Left)
BTN_DPAD_RIGHT → Arrow Right (Qt::Key_Right)
BTN_DPAD_UP → Arrow Up (Qt::Key_Up)
BTN_DPAD_DOWN → Arrow Down (Qt::Key_Down)

Analog Sticks
-------------
ABS_RX / ABS_RY → Pointer Motion

Center Buttons
--------------
BTN_SELECT → Show On-Screen Keyboard ( WIP )
BTN_START → Meta/Super (Qt::Key_Meta)

Prevent Stepping On Other Apps

It's essential that the plugin doesn't emulate keyboard and mouse for the gaming controller when another app is reading from it. Most likely in such cases the device is being used for something else and not being used to navigate the desktop. To achieve this the GamepadManager class creates an instance of inotify object, and adds a watch device to the fd of each game controller that’s added as a Gamepad. Whenever inotify produces a notification a function, GamepadManager::handleFdAccess, is called which increments a counter in Gamepad, Gamepad::m_usageCount by +1 if the event value is IN_OPEN or Gamepad::m_usageCount by -1 if the event value is IN_CLOSE_WRITE | IN_CLOSE_NOWRITE. The plugin will only attempt to emualte keyboard/mouse if m_usageCount is 0. This prevents emulation of keyboard and mouse when other apps have the game controller opened / in use.

// Process all inotify events in the buffer
for (char *ptr = buffer; ptr < buffer + length;) {
 struct inotify_event *event = reinterpret_cast<struct inotify_event *>(ptr);

 auto it = m_watchesToGamepads.find(event->wd);
 if (it != m_watchesToGamepads.end()) {
 Gamepad *pad = it.value();
 if (event->mask & IN_OPEN) {
 pad->countUsage(+1);
 } else if (event->mask & (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)) {
 pad->countUsage(-1);
 }
 qCDebug(KWIN_GAMEPAD) << "Device" << pad->path() << "in use by:" << pad->usageCount() << " other apps";
 }
 ptr += sizeof(struct inotify_event) + event->len;
}

Opt-In

Many of the native plugins that ship with KWin are enabled by default but for our gaming controller plugin we will disable it by default and make it an opt-in option. This will allow users to start experimenting and benefiting from the plugin without risking the possibility of breaking current game controller input on their system.

{
 "KPlugin": {
 "Category": "Input",
 "Description": "Enable KWin game controller input detection",
 "EnabledByDefault": false, <---------- Not enabled by default. 
 "License": "GPL",
 "Name": "gamepad"
 },
 "X-KDE-ServiceTypes": ["KWin/Plugin"]
}

Testing

  • Controller awareness at startup and hot-plugging: tested in development session, KWin logs show the plugin picking up controllers in both scenarios, works as expected.
  • Preventing sleep/suspend: tested in development session. Set suspend timer to 1min, repeatedly press A and B back and forth, and at 5min no suspend was initiated, works as expected.
  • USB and Bluetooth connectivity support: tested in development session, KWin logs show plugin picking up on the controllers in both scenarios, works as expected.
  • Mapping from controller to keyboard and mouse: tested in development session, all buttons are map to expected keyboard and mouse, works as expected.
  • Backoff On Grab: tested in development session. Verified mapping work, started Steam app, verify mapping no longer enabled.

Testing device: 8Bitdo Gaming Controller (USB/2.4h/Bluetooth)

What’s next from here

  • Integration into KWin Proper: Start pushing changes upstream for others to test.
  • Map to Virtual Keyboard: Allow users to navigate over and get input from a virtual keyboard. Might open the way for logging in using only game controller.
  • Test Cases: As per best practices when developing for KWin.
  • KCM integration: A GUI option for users to toggle plugin ON/OFF. Ground work for more robust, user defined, button remapping.
  • Use Config for Mapping: Using a config file to keep track of and read from all the button to keyboard/mouse button mapping.

Reference documentation:

Checkout the source code here: KWin Gamepad Plugin: https://invent.kde.org/yorisoft/kwin/-/tree/work/yorisoft/gamepad-plugin/src/plugins/gamepad

I was at Akademy 2025 last-last week where I did some preliminary research on optimizing the VM viewer’s display rendering on Karton. After some more work this past week, it’s somewhat here! I’m still finishing up the merge request, but exciting news to come!

This has been something I’ve been planning on for quite a while now and will significantly improve the experience using Karton :)

a comparison with an old video I had.

Old Rendering Pipeline

My original approach for rendering listened to display-primary-create and invalidate-display-primary SPICE signals. Everytime it received a callback, it would create a new QImage and render that to the QQuickItem (the viewer window). As you can imagine, this was very inefficient as it is basically generating new images for every single frame being rendered. It suffered a lot from screen-tearing any time there were sudden changes to the screen.

You can read more about my experiences in my SPICE client blog.

We can do better!

Rendering via OpenGL can offload a lot of these tasks to the GPU and can significantly improve performance. I had known about GL properties in SPICE for a while now, but I kept putting it off since I really didn’t want to deal with any more graphics stuff after my last attempt.

Fast forward to last-last week, I was attending my first ever KDE Akademy in Berlin and all of a sudden gained some motivation.

It was really exciting hearing talks about all the kool things happening in KDE.

gl-draw

My first order of business was getting the gl-draw signal to properly receive gl-scanouts from my SPICE connection. After setting up the callback, I found out that I had to reconfigure my VMs to properly support it.

This was easy enough as I’ve made the Karton VM installation classes a few months ago done through the libvirt domain XML format. VMs need enabling of GL and 3D acceleration through the graphics element in the XML. The socket connection to SPICE also had to be switched from TCP to UNIX, which was set to /tmp/spice-vm{uuid}.sock. As a result, previous VMs configured in Karton will no longer work as the previous rendering pipeline has been removed.

<graphics type="spice" socket="/tmp/spice-vm{uuid}.sock">
    <listen type="socket" socket="/tmp/spice-vm{uuid}.sock"/>
    <gl enable="yes"/>
</graphics>
<video>
    <model type="virtio" heads="1" primary="yes">
        <acceleration accel3d="yes"/>
    </model>
    <address type="pci" domain="0x0000" bus="0x00" slot="0x01" function="0x0"/>
</video>

An example libvirt domain XML snippet generated by Karton

Once properly configured, I was able to get SpiceGlScanout objects from my callback linked to the gl-draw signal. Now, I needed to render these scanouts onto my QQuickItem canvas.

EGL stuff

Having no background in graphics, I pretty much had no idea what I was doing by this point.

The SpiceGlScanout is a struct that looks like this:

struct SpiceGlScanout {
    gint fd;
    guint32 width;
    guint32 height;
    guint32 stride;
    guint32 format;
    gboolean y0top;
};

The width, height, stride, etc…, are all parameters that can be used to set your final rendered frame, but the important field is the fd (file descriptor) which is a “a drm DMABUF file that can be imported with eglCreateImageKHR”. I didn’t know what that was; but at least I learned I should be using the EGL library to do the processing.

I had found some forum articles (Qt forum, Arm developer forum) related to rendering OpenGL textures which used the EGL library and were quite helpful. I also looked at the SPICE GTK widget source code which gave me some ideas on the GL parameters to work with.

From these references, I saw that they pretty much followed the same pattern. Very simply put:

-> create egl image from a bunch of attributes/settings
-> generate texture from the fd 
-> bind texture to a texture type 
-> "glEGLImageTargetTexture2DOES" use this function?? still don't know what this does lol
-> destroy egl image

I originally tried setting the GL context properties manually, but there were some issues with getting it to detect my display and apparently thread syncronization. Then, I found out that Qt had a QOpenGLFunctions library which had all of the EGL functions and context properties wrapped and made my life a whole bunch easier.

OpenGL texture -> Qt

After a ton of trial and error, it looked like my EGL images were properly being created. Now I needed to render these GL textures to the QQuickItem.

How you do so is, within the inherited updatePaintNode() function, you return a QSGNode which has the information for updating that frame. Looking through the Qt documentation, QNativeTexture is a struct that allows you to store a texture ID to an OpenGL image. With that, you can create a wrapper QRhi class from the QNativeTexture with some of the generic context of your display.

Finally, you can use the createTextureFromRhiTexture() function under QQuickWindow which allows you to create a QSGTexture from that RHI for a QSGNode that can be returned by updatePaintNode(). And, we’re done! Yay!

To sum it up, here’s the framebuffer pipeline:

gl-draw signal->receive gl-scanout->import GL texture->GL texture ID->QNativeTexture->QRhi->QSGTexture->QSGNode->QQuickItem

so much smoother! yes, I was very excited.

Socials

Website: https://kenoi.dev/

Mastodon: https://mastodon.social/@kenoi

GitLab: https://invent.kde.org/kenoi

GitHub: https://github.com/kenoi1

Matrix: @kenoi:matrix.org

Discord: kenyoy

Sunday, 14 September 2025

I’m happy to announce the 0.8.2 release of Subtitle Composer.

This release contains bugfixes and few improvements including:

  • Fixed issues and crashes with newer Qt6 versions
  • Fixed Waveform and VideoPlayer paint issues
  • Fixed PGS subtitle mime type
  • Improved Wayland compatibility
  • Improved GoogleCloudEngine translations
  • Added configurable whitespace detection to VobSub import
  • Replaced deprecated FFmpeg channel code
  • Require FFmpeg >= 5.1.5

As usual all binaries are available from download page.

Source tarball can be downloaded from download.kde.org.

— Mladen

It was the turn of the millenium when I got my first computer fresh at university. Windows seemed uninteresting, it was impossible to work out how it worked or write programs for it. SuSE Linux 6.2 was much more interesting to try and opened a world of understanding how computers worked and wanting to code on them. These were the days of the .com boom and I went to big expos in London where they showered you with freebies and IBM competed with SuSE and Red Hat for the biggest stall. IBM said that Linux had made it on the server and now was going to take over the desktop so I realised that working with KDE would be a good idea. And as a novice coder it was very perfect for learning Qt and how open development worked and I loved the free software ideals. Going to the pre-Akademy conference (it was called Kastle then) in Nove Hrady was a great intro to the community in person and in some ways I learnt more about software development in a week there then my years at uni.

So clearly this was a good way to make a career. I dossed around for a year until the Quaker geek collective heard tale of an African Spaceman who was funding a new Linux distro called SSDS (Shuttleworth’s Super Secret Debian Startup) so I got into Debian packaging and made a point that KDE should be involved. Before long they came knocking and I went to the first Ubuntu conference in Australia. I spent about ten amazing years brining KDE to Ubuntu or bringing Ubuntu to KDE for what was already called Kubuntu (not my name choice), a successful community project I’m really proud of. At one point Nokia wanted to use it alongside Plasma Active to sell on a tablet thing along with phones, this could well have taken over the world but y’know, iPhone happened and Kubuntu never found a commercial use after that although it still gets used in big places like Google or the City of Munich or Weta digital (watch those Hobbit DVD extras). I loved being invited out to Nigeria or India to give talks and spread the world of open software. Looking back there’s probably a million business cases that would have been possible but I’m not the best at being a future visionary. Eventually Canonical decided to stop funding it which is fair enough.

But then Blue Systems came along, another nice guy with deep pockets wanting to help and we carried on. When Canonical decided to kill off lots of community projects we came up with the idea of moving directly into KDE to make KDE neon. It has always been crazy how open source communities like KDE are reliant on separate companies to take their software out to the world so we wanted to change that, and I like to think we succeeded. Using CI systems we could create a much more manageable setup. Still the system was never as resiliant as it should have been and several times KDE neon ended up shipping a duff update which will have been very painful for users. We had three people working full time on it at the start but before long it was just me and a volunteer and the quality suffered as a result.

Last winter I drove to the Blue Systems schoße for a routine conference and was organising people to give talks when the guy who pays us started off by saying he was dying and the company would be shutting down. Which was very sad but it makes sense to end it on a high. After years of having no business modal and not knowing what the aims of the company were, which caused several people to genuinely go mad, we finally had a business model of sorts with Valve paying us to make Plasma up to the standards needed to ship it as Desktop Scope on the Valve Steam Deck games console. Nate had been given advanced notice of the company shutting down and had already started another company, Tech Paladin, to take on the business. Shouldn’t this be run as a cooperative we wondered? No that was too complex he said. The next day I ended up at a funeral for some German accountants and when I came back there had been some more discussion and we watched a video about Igalia who make the other operating system for Valve. They are a cooperative socialist paradise and Nate said he’d look into doing that instead of the setup where he had full control and all the profit. It was clear there was to be no other discussion on the matter of our future.

A few weeks later we had an online meeting where I proposed a useful agenda but was ignored, instead Nate gave his updated plan for a business which was to give Dave a slice of the profit and otherwise he’d keep all the profit and all the control. So I gave my proposal I’d been working on for a company with equal ownership, equal profit, a management structure and workers rights. A couple weeks later we had anther video call but Nate called me first and told me I’d be excluded from it. No explanation was given beyond I had “made some comments and would not be happy”. If someone is telling you what your emotions that is when controlling behaviour starts to become abusive. And thus ended my 25 years with KDE.

And what of my colleagues? Surely they wouldn’t want a setup where they have no control over their professional life and all their profit goes to one person? Well dunno, they’ve stopped speaking to me. Nothing. Silence. Nil. Not so much as a “cheereo”, nor “sorry we chose the option were you got excluded” and certainly no explanation. From people who I have worked with for some twenty years in some cases that hurts. I don’t know why they stopped talking to me, I can only speculate and I don’t want to do that.

We never had workers rights at Blue Systems, we were all on self employment contracts. This will continue at Tech Paladin. It is illegal but unenforceable when done on an international setup. But employment rights are not a luxury you can chose to do without if you enjoy your job and want some more flexibility in your work day. They are fundamental and life altering rights that change people’s lives as I discovered when my adopted children were taken away from me. Nobody should be doing business with or taking money from Tech Paladin else be party to illegal workers rights abuses.

Then I started to get sad, being cut off from my life for the last 25 years was too much for me. All things come to an end and I’ve seen plenty people had to leave KDE because the money ran out or maybe they had a disagreement with someone in the project, but never a profiteering control struggle like this. I struggled to get out of bed on some days. I’ve given my life to KDE, I’ve seen it gone from a sure fire project to take over the world to being one open desktop project in a world of many to seeing the revival in recent years where we can honestly say we make some of the best software out there. I like to think I’ve been part of keeping it alive, progressing, relevant and at the forefront of commercial, government and community usage. It’s been an amazing ride full of opportunities and adventures the likes of which I’m sure my peers from my university course have never had.

But in the end I lost my friends, my colleagues, my job, my career and my family. What’s a spod who just tried to do the right thing for society to do? Dunno. For now, if you want me, you can find me surfing the endless wave whenever the sun sets over my digital nomad coliving paddleshack at the end of the world.

Sunset surfs at the digital nomad coliving paddleshack at the end of the world

I was able to attend the talks at Akademy this year in Berlin! The last time I attended Akademy in person was in 2022, so it was really nice being able to come back and meet everyone again.

I was unfortunately not able to attend BoFs (development meetings) due to having to leave early. I did attend some meetings a few months earlier however, you can read more in my Plasma sprint recap post.

Talks 🔗

Akademy runs with two concurrent tracks of talks, and so sometimes there were two talks at the same that I both wanted to attend, I had a hard time deciding! Here are some of the ones I attended:

KDE Linux: Banana Growth Cycle 🔗

Harald released KDE Linux Alpha was to the public during the talk! I hadn’t followed the project super closely, but it was awesome getting up to speed learning about the state of the project and the inner workings of how the distribution works.

The Role of New Languages in the Future of the Qt Ecosystem 🔗

I was introduced to Qt Bridges, which is an effort to go beyond Qt bindings for other languages and tightly integrate with them (ex. Rust, Python). Once this is more mature, it will likely be an easy recommendation for others to start learning Qt with, who don’t want to use C++!

KDE Goals - One Year Recap 🔗

It was interesting to see all the work that had been done on the KDE Goals so far!

I am actually involved with one of them this time around (“We care about your input”) through my work on plasma-keyboard. Blog post likely coming in a few months, once that work is further along!

Next-Gen Documentation Infrastructure for KDE 🔗

KDE’s reference API documentation has been a bit of sore spot for me, since it didn’t support QML very well. As a result, I usually go manually go through header files instead in the source code to figure out how to use libraries.

The talk went over Nicolas’s work on doing the mammoth task of porting all of KDE’s API documentation to QDoc from Doxygen, which properly supports QML. The new api.kde.org went live, and boy is it such an improvement! It’s much easier for me to point new developers to the Kirigami documentation now.

Fedora KDE Plasma Desktop Edition is Real, Now What? 🔗

I personally use Fedora on my workstation and laptops, and so it was cool to get some history about how Plasma on Fedora was revived in the past, and plans for the future. Neal also expressed some interest in a Plasma Bigscreen spin (similar to the one for Plasma Mobile), which could be pretty interesting once it becomes more mature!

Plasma Mobile Power Management: Reliable Sleep and Wake Ups 🔗

Bhushan gave an update on his work power management work across the Plasma stack! He obtained an NLNet grant recently for the project, detailed on his blog.

Discussions 🔗

I was really happy to meet and discuss with quite a few people during the event.

I met Bart, Luca, Casey and Pablo from the postmarketOS project! As it is the main platform I test and develop Plasma Mobile with, it was really nice to finally meet some of their developers (I had met Bart and Luca at Akademy 2022)! I also was able to finally meet Florian, who has been collaborating with me in contributing to Plasma Mobile in the past few years!

I met Dorota, who has been working on Wayland input related things for the past few years, and is in the process of pushing through updates to text-input-v3, and Jakob who has been working on the KDE side pushing through the input related KDE goals! We discussed some input related topics, which was insightful as I worked on the client side through plasma-keyboard (and my limited Wayland knowledge).

I also discussed some Kirigami page navigation related topics with Marco. I’m doing a bit of investigation into how we can improve the way we navigate between pages in applications, and perhaps restricting the page left/right gesture into the side (similar to iOS).

I’m back from Akademy 2025 in Berlin, and what an experience it was.

At this point, I’ve gotten a reputation as a “big picture guy”, so that’s what I’ll focus on here, rather than the details of my experiences in specific events. Lots of other folks are starting to write blog posts you can find on https://planet.kde.org about their Akademy experiences that I’m sure will be full of juicy details!


But basically, to me this year’s Akademy felt like it had a theme: “KDE is on the cusp of something big.”

Here’s one example: at the very cool C-base hackerspace, I was talking with someone who mused that 15 years ago, Akademy was full of KDE hackers talking about the government one day using our software… and then fast-forward 15 years and our two keynote speakers are from the German government talking about using KDE’s software!

Then we had a talk from the “End of 10” crowd about KDE’s campaign encouraging people to upgrade to Linux rather than buying new hardware capable of running Windows 11. And then as if to reflect on the success of this initiative, Patrick Fitzgerald gave a talk about how to do massive migrations from Windows to Linux, with examples provided of cases where literally thousands of machines were migrated to KDE software at a small fraction of the cost of moving to Windows 11.

Till Adam gave a talk about how commercial work changes relationships with respect to his experience in KDAB, a software consultancy founded by KDE contributors. I found this talk highly relevant given that David Edmundson and I just started a KDE-focused company this year ourselves. Alexandra Betouni also gave a talk about rising to the top of a company. Hmm, lots of companies!

We heard about how Mercedes is rolling out a vehicle powered by KDE technology under the hood.

In the “hallway track”, I had a fascinating discussion about how KDE’s efforts to improve accessibility have the potential to be an industry-wide force multiplier.

And then I gave a talk myself about the big picture of all of these trends — that as the world falls apart around us, everything being on fire includes tremendous opportunities for change that KDE is well-positioned to benefit from.


Basically, at age 29, KDE is all grown up now. Our software solves real problems for real people, at scale. It works for governments and big businesses. It saves or earns money for a lot of people. Our competitors are beginning to falter and look weak. But through it all, KDE remains healthy and strong, and grows in stature.

So I found Akademy 2025 to be an unexpectedly serious conference, full of heavy topics and sharing of priceless wisdom from hard-earned experience. There was of course also a lot of fun hacking and group gatherings and renewing of social bonds, but throughout everything was that underpinning that KDE isn’t just a fun little online community anymore, but rather a player with a growing significance on the world stage.

Pretty cool stuff, I think! Personally, I get energized by working on things that matter, and boy did Akademy 2025 leave me with the impression that KDE matters.

From the 3rd to the 5th of September, the Kdenlive team was reunited in Berlin for a sprint and to attend Akademy, KDE's annual conference. This was an occasion for us to meet in person since our team is spread across continents, and to join our forces to make Kdenlive better. And I must say this was one of the most productive sprints in Kdenlive's history!

We were kindly hosted by c-base for our Sprint so a big thanks to the team for welcoming us there!

Let's get into the details of what we did:

We started by reviewing and updating our roadmap, so it is easier to understand what we are working on, what we plan and when. Another important step towards improving our workflows is that we created issues for each of these goals where the details will be discussed, so everyone can follow and possibly help us on the road to success.

Dopesheet

Very exciting, I received a grant from the NGI Zero Commons Fund through NLnet to work on a dopesheet feature in Kdenlive. This will bring a much improved keyframing interface with powerful features. We discussed what core features we want in it and some drafts on how that would work. This feature won't be ready for the December release, but I will post updates on the progress of this task in the coming months.

We then reviewed specific parts of the UI that we would like to improve. All these ideas will be discussed in specific issues so that we can refine the implementation.

This task started two years ago but we never took time to finalize it. We progressed a lot on this and you can expect it to land in the December release. Among the changes, we decided to rename the Project Bin to Media, Render to Export, and reorganize the menus to make things more logical. We will make another blog to present these changes in detail once this is done.

Timeline toolbar

We want to cleanup the UI, make the timeline timecode display cleaner and get rid of the large Master button currently taking a lot of space.

Monitor UI

We plan to move the audio vu-meter to a collapsible vertical widget on the right side of the monitor to free some space in the toolbar, make the zone duration always visible and move the insert/overwrite actions currently in the timeline toolbar there.

Audio monitor

When selecting an audio clip, the Clip Monitor currently displays a huge audio waveform that is not that useful. We reviewed the UI to also display an overview at the top, making it easier to zoom and see where you are in the clip.

Monitor with audio before the Sprint
Monitor with audio a few days after the Sprint

Layout and docks

We have several open issues regarding docking. One of the frequent request we have is to save the layout per project file, since sometimes you want very specific layouts for a project. We discussed how to make it happen and are also evaluating switching the library managing the widgets docking to KDDockWidgets that would bring us some very nice improvements like being able to detach the timeline or group several undocked widgets together

Titler

Our current titler does the job for simple tasks but many users would like to be able to use some animation presets to make their titles more dynamic. We discussed the possible options to make this a reality. Among the ideas, we could use Lottie animations, since our video backend MLT already has support to play them through the Glaxnimate module. Another option would be to implement a Qml producer for MLT, allowing to play Qml files directly as a video. Any help on that topic is welcome.

Website

We have some planned changes to make our website look better and discussed some of the options.

And all the rest

We discussed tons of other things and even managed to shoot some interviews of our team members. Less relevant maybe for users but we also reviewed some of the administrative and trademark issues, and CI/CD issues

Akademy 2025

Akademy was also an occasion to have interesting exchanges, notably with Glaxnimate's maintainer, Plasma developers and more. We are now back home with tons of ideas and TODO's, and the next release of Kdenlive, to be launched in December, will shine with some of the improvements we prepared during this week in Berlin !

If you would like to help our small team, you are always welcome to contribute by giving some feedback, talk about us, create a merge request or donate.