Skip to content

Wednesday, 30 July 2025

The future is now!!

It’s been almost two years since my last update on this project, what changed? And if you aren’t familiar with what I’ve been working on, here’s a quick recap.

The hardware

Here is a graphics tablet I bought a few years ago now, the XP-Pen Artist 22R Pro:

Yeah this picture is years old by now, but it still looks the same…

It has a fatal flaw that a lot of non-Wacom tablets share though, it doesn’t work that well on Linux! To be more specific, it “works” but has a few problems:

  • You can’t rebind the pad buttons easily, because it starts in a “compatibility mode” that can only send pre-defined keyboard buttons.
  • Using the second stylus button prevents further stylus input. (Before I fixed that, I would train myself not to press that button 🙈)
  • The two dials do not function, and if they did they aren’t rebindable anyway.

That is not great, especially since it’s not the cheapest graphics tablet on the market. So it really sucks that artists can’t take advantage of all of it’s features on the best operating system. You can achieve some parity with Windows if you use XP-Pen’s proprietary user-space driver (which works on Wayland BTW.) This solution isn’t satisfying though - I want this thing to work out of the box, using open-source software ❤️

Linux

I have completed the patch for the kernel to add support for this specific tablet. After sitting it on it for a while (due to being busy with other things.) I’m happy to announce it’s merged and should be generally available in the upcoming Linux 6.17 release 🎉

Thank you to the original author Aren Villanueva who wrote the original DIGImend kernel driver. I took his work, rebased it on top of the existing uclogic driver and changed how the many keys and dials were handled among other changes. Some of this work was covered in previous entries in this series, if you’re interested.

What this means is regardless of your desktop environment, this tablet is properly initialized and all of the flaws listed in the hardware section will be fixed.

libwacom

I added a descriptor to libwacom for this tablet, which means it shows the correct configuration options under KDE Plasma and GNOME. For example, it will show that the pen has two buttons and not three (which is the fallback):

libinput

I added support for tablet dials in libinput. In layman terms, this means desktop environments like GNOME and KDE are now aware of this feature on your tablet. This has huge implications outside of this specific tablet, for example certain HUION devices also benefit from this. More information on how KDE Plasma uses this is explained in a later section.

Wayland

Thanks to work by Peter Hutterer, the Tablet protocol in Wayland now has support for tablet dials. What this means is that applications can now read tablet dial input and do whatever they want with it, like making it zoom in and out of a canvas.

KDE Plasma

Thanks to work by Nicolas Fella, KWin (the compositor in KDE Plasma) is now dial-aware and can send them to Wayland-enabled applications beginning in Plasma 6.4. Because of the aformentioned lack of application support however, I added a feature in KDE Plasma 6.5 to rebind dials to custom user actions:

Don’t mind the buggy-looking dialog, that is caused by a development version of Kirigami I was using.

The XP-PEN software allows you to do this too, so having a built-in solution in KDE Plasma would be great! I did just that, and added support for rebinding dials which will show up in the upcoming KDE Plasma 6.5 release. Making them user configurable is meant as a “bridge”, as I’m not aware of any applications supporting dials yet.

With this final piece - from top-to-bottom - the entire Linux graphics tablet stack can now take advantage of relative dials like any other hardware feature 🎉

Conclusion

I want to make it clear (especially if you don’t know me) that this isn’t some hack, or a rushed driver. This is thanks to years of effort, and from multiple parties and ecosystems. I also literally use this driver and KDE Plasma for my hobbies every day, I know it works first-hand.

I also hope this series showcases that the graphics tablet infrastructure in Linux is not stagnant, but actively being worked on by super-talented people every day. In a theoretical future distribution release that has Linux 6.17 and KDE Plasma 6.5, this tablet will work out-of-the-box. (And for other hardware, it’s only a matter of time!) We can make the Linux desktop not just usable for artists, but we can executing it better than anything else out there. No more crappy driver software, tablets will work out of the box on an operating system that actually respects you ❤️

To Nicolas, Peter and Aren - you can redeem a beer or drink of choice at your earliest convenience 🍻


If this series has been fascinating for you, then I highly suggest making plans to watch my Akademy 2025 talk in Berlin or online about bridging the gap for artists using Linux and KDE Plasma. I’m going to be covering the amazing progress - especially in our KDE Plasma 6.x series - that’s relevant to artists big and small, and also discuss plans for the long road ahead. You also need to follow the KDE account on Mastodon and Bluesky if you haven’t already, where we post announcements and sometimes call-to-actions like our recent push to contribute data about graphics tablet hardware!

I also want to remind everyone that one of KDE’s current goals is about input, and as it’s Goal Champion I’ve been volunteering and organizing to fix issues like the ones seen above. If you are having trouble with your graphics tablet on the KDE Plasma Wayland session (and it’s our fault) then we want to know! Or if you’re super happy with KDE and nothing is wrong, we wouldn’t mind hearing about that was well 🐸

If you’re still addicted to me hearing me talk about improving stuff, here is a sneak peek of the hardware I’m testing in KDE Plasma next:

Sorry that the HUION tracks fingerprints like crazy

But that’s for another time!

Tuesday, 29 July 2025

Intro

Apart from setting up a new open source project, it is important to understand how the application works in order to make the changes you need. In this blog I will go over how I find code, understand the application, and my progress so far with the Selection Action Bar.

Searching code

One Stop Shop for Searching

Command Line

grep -rn "<string_to_search>"

QTCreator

ctrl + f
crtl + shift + f

Debug in C++ code

qDebug() << "[Debug] <string_to_display_for_debugger> << <additional_parameters>;

Krita's codebase is massive, so don't expect to understand everything in one day. What is important is knowing how to find code you need to make the improvements you want. Above are some tools I use when looking for code. I would use the command line or QTCreator search functionality to reverse search strings that are displayed in Krita. This helps me find buttons, dropdowns, and tools. When I want to understand the functionality of the application, I will add qDebug in the code. This allows me to perform an action when Krtia is running and display debug information about the functions I added qDebug to.

Progress

Through the use of the the useful tools above, I was able to make the base UI of the floating toolbar in Krita by identifying QPainter class that created the Assistant Tool. I wanted to use Assistant tool as a reference and recreate a similar UI look. For quick learning purposes and proof of concept, when an Assistant Tool widget is active, the floating toolbar is also generated on screen.

Below is a proof of concept for the Selection Action Bar. I used QPainter to 'draw' onto the KisCanvas2 class. This is like using a paintbrush (QPainter) and painting on a canvas (KisCanvas2). There will still need to be some more UI clean up, however I wanted to present my learnings so far.

Conclusion

Making changes in Krita can be challenging, but by using a few simple tools it can make hours turn into minutes for searching what you need. Again, "the hardest part is finding the resources to be successful". I hope this blog post helps whoever is in need of searching Krita or any C++ codebase.

Contact

To anyone reading this, please feel free to reach out to me. I’m always open to suggestions and thoughts on how to improve as a developer and as a person.
Email: ross.erosales@gmail.com
Matrix: @rossr:matrix.org

Monday, 28 July 2025

Dear friends, family, and community,

I’m reaching out during a challenging time in my life to ask for your support. This year has been particularly difficult as I’ve been out of work for most of it due to a broken arm and a serious MRSA infection that required extensive treatment and recovery time.

Current Situation

While I’ve been recovering, I’ve been actively working to maintain and improve my professional skills by contributing to open source software projects. These contributions help me stay current with industry trends and demonstrate my ongoing commitment to my field, but unfortunately, they don’t provide the income I need to cover my basic living expenses.

Despite my efforts, I’m still struggling to secure employment, and I’m falling behind on essential bills including:

  • Rent/mortgage payments
  • Utilities
  • Medical expenses
  • Basic living costs

How You Can Help

Any financial assistance, no matter the amount, would make a meaningful difference in helping me stay afloat during this job search. Your support would allow me to:

  • Keep my housing stable
  • Maintain essential services
  • Focus fully on finding employment without the constant stress of unpaid bills
  • Continue contributing to the open source community

Moving Forward

I’m actively job searching and interviewing, and I’m confident that I’ll be back on my feet soon. Your temporary support during this difficult period would mean the world to me and help bridge the gap until I can secure stable employment.

If you’re able to contribute, GoFundMe . If you’re unable to donate, I completely understand, and sharing this request with others who might be able to help would be greatly appreciated.

Thank you for taking the time to read this and for considering helping me during this challenging time.

With gratitude, Scarlett

Intro

This week I focused on making the Selection Action Bar draggable directly on the canvas. This would let the user reposition the toolbar that is best for their workflow.

Obstacles to Implementation

Up to this point adding elements on Krita using Qt was straightforward however making these elements interact and respond to mouse click events needed some deeper diving. The goal of this part of the Selection Action Bar was to allow users to click and drag the tool to reposition it anywhere within the canvas. In order to implement this I asked myself some questions: Where does Qt handle click events? How can the UI elements dynamically update their position?

Event Filters and Mouse Events

Documentation Links https://doc.qt.io/qt-6/eventsandfilters.html
https://doc.qt.io/qt-5.15/events.html
https://doc.qt.io/qt-5/qobject.html#installEventFilter

My research led me to Qt’s event system. One of the key concepts I learned about was event filters. Event filters are able to intercept events that are sent to another object. In our case, we can intercept the click events that are sent to the canvas and process that event to update the positions of our floating toolbar.

Since canvas was passed in through the KisSelectionAssistantsDecoration class, we can install an event filter on the canvas object, specifically the canvasWidget to intercept the mouse events.

// install event filter on canvasWidget, so KisSelectionAssistantsDecoration class (aka 'this') can look at event first
canvasWidget->installEventFilter(this);

After learning about event filters, I needed to learn how to handle the mouse events. By distinguishing user inputs of MouseButtonPress, MouseMove, and MouseButtonRelease, I was able to update the position of the floating bar. To keep things simple, imagine a rectangle on a 2D grid. Between the top left point of the rectangle and a point we click inside the rectangle is called an offset. This offset is to make sure that when we click and drag from within the rectangle, we are updating the position of the rectangle. Get offset = mouse position (click) - rectangle position
Update rectangle position = mouse position (click + drag) - offset
Mouse button release = stop updating rectangle

Working concept

With this major change, the Selection Action Bar is starting to feel like a full feature. Currently, we are able to activate selection actions, move the toolbar to a desirable position on canvas, and toggle it on and off via Krita settings.

Conclusion

This week really pushed me to explore how to handle events and how to make elements move in Krita! As I continue building out the Selection Action Bar every week, I start to understand how complex a ‘simple’ change could be. Next week I plan to improve on the movement of the toolbar by restricting its dragging area within the canvas.

Contact

To anyone reading this, please feel free to reach out to me. I’m always open to suggestions and thoughts on how to improve as a developer and as a person. Email: ross.erosales@gmail.com Matrix: @rossr:matrix.org

Sunday, 27 July 2025

🎉 Clazy Now Integrates with Clang-Tidy!

I am excited to announce a major improvement to the Clazy project: Clazy now integrates seamlessly with Clang-Tidy!

🧩 One Toolchain, All the Checks

Clazy now provides a plugin (on Unix ClazyClangTidy.so) that allows all its checks to run inside clang-tidy, unifying your static analysis workflow. You no longer need to run two separate tools — just configure Clazy’s checks through clang-tidy itself.

This change needed quite a few refactorings to make the existing Clazy codebase more adaptable. In total, changes were spread out to 9 different pull requests to gradually implement the needed changes. Besides implementing the functionality, the testsuite was also adapted to ensure Clazy’s clang-tidy provides proper results.

✅ How to Use

To load the plugin:

clang-tidy -load=ClazyClangTidy.so ...

🔒 If the plugin isn’t in a standard library path, either add it to your LD_LIBRARY_PATH or provide an absolute path to the plugin file.

Unfortunately, Clang-Tidy needs to have Clazy checks enabled explicitly and does not have a concept of “levels” to group checks. While wildcards like clazy-* would also work, it enables all manual-level checks. Those have more false positives and can hurt performance.

As a helper, you can export environment variables containing the check names to concatenate the desired combination:

export CLAZY_LEVEL0=clazy-overloaded-signal,clazy-connect-by-name,clazy-connect-non-signal,clazy-qstring-comparison-to-implicit-char,clazy-wrong-qevent-cast,clazy-lambda-in-connect,clazy-lambda-unique-connection,clazy-qdatetime-utc,clazy-qgetenv,clazy-qstring-insensitive-allocation,clazy-fully-qualified-moc-types,clazy-unused-non-trivial-variable,clazy-connect-not-normalized,clazy-mutable-container-key,clazy-qenums,clazy-qmap-with-pointer-key,clazy-qstring-ref,clazy-strict-iterators,clazy-writing-to-temporary,clazy-container-anti-pattern,clazy-qcolor-from-literal,clazy-qfileinfo-exists,clazy-qstring-arg,clazy-empty-qstringliteral,clazy-qt-macros,clazy-temporary-iterator,clazy-wrong-qglobalstatic,clazy-lowercase-qml-type-name,clazy-no-module-include,clazy-use-static-qregularexpression
export CLAZY_LEVEL1=clazy-auto-unexpected-qstringbuilder,clazy-connect-3arg-lambda,clazy-const-signal-or-slot,clazy-detaching-temporary,clazy-foreach,clazy-incorrect-emit,clazy-install-event-filter,clazy-non-pod-global-static,clazy-post-event,clazy-qdeleteall,clazy-qlatin1string-non-ascii,clazy-qproperty-without-notify,clazy-qstring-left,clazy-range-loop-detach,clazy-range-loop-reference,clazy-returning-data-from-temporary,clazy-rule-of-two-soft,clazy-child-event-qobject-cast,clazy-virtual-signal,clazy-overridden-signal,clazy-qhash-namespace,clazy-skipped-base-method,clazy-readlock-detaching
export CLAZY_LEVEL2=clazy-ctor-missing-parent-argument,clazy-base-class-event,clazy-copyable-polymorphic,clazy-function-args-by-ref,clazy-function-args-by-value,clazy-global-const-char-pointer,clazy-implicit-casts,clazy-missing-qobject-macro,clazy-missing-typeinfo,clazy-old-style-connect,clazy-qstring-allocations,clazy-returning-void-expression,clazy-rule-of-three,clazy-virtual-call-ctor,clazy-static-pmf

Checks in Clang-Tidy can be disabled when prefixing them with “-“, whereas Clazy uses “no-“ prefixes. An example clang-tidy command to use all level0 checks, with overloaded-signal being disabled and the qt-keywords manual check being enabled:

clang-tidy -load=ClazyClangTidy.so \
-checks="$CLAZY_LEVEL0,-overloaded-signal,qt-keywords" \
-p my_build_dir mydir/**.cpp

In case you want to speed up linting in the project, run-clang-tidy can be used for parallel execution.

🚧✨ Limitations & Tricks

Unlike using Clazy directly, clang-tidy has its own filter mechanism to only emit warnings from files that were provided as an input. This means if a warning is emitted from a header file and not the “.cpp” file you provide as an input, Clang-Tidy will suppress it. To see those warnings -header-filter=".*" can be added to the command.

💡💬 Getting it & Feedback

The Clang-Tidy plugin is currently not released, and some additional development on various checks is happening. For trying it out, one has to compile the project from source. It is just a simple CMake setup - promise ;) See the instructions for more details: https://invent.kde.org/sdk/clazy/#build-instructions

Any feedback and contributions are appreciated - let’s make Clazy better together 😎. Please report bugs or suggestions on https://bugs.kde.org/enter_bug.cgi?product=clazy or https://invent.kde.org/sdk/clazy/-/issues.

Thursday, 24 July 2025

Kdenlive 25.08 Release Candidate is ready for testing. While this release focuses mostly on bug fixing, the dev team still managed to sneak in some cool features during the summer heat. Some highlights include:

  • Optimized interface for lower resolution screens
  • Project files are now properly recognized and can easily be opened by clicking them on MacOS
  • Fix location of title templates on Windows
  • Fix downloadable keyboard schemes
  • Fix python 3.13 compatibility for Whisper
  • Added power management support to prevent sleep while playing / rendering
  • Support for start timecode
  • Added option to display the markers of all clips in the project in the guides list
  • Show thumbnails in the guides list
  • Redesigned mixer

Download the binaries from below and give it a spin. Please share your feedback in the comments if you encounter any bugs or have a suggestion to help us polish the final release.

Pre-release binaries can be downloaded here.

Intro

This week builds on the work from last week, where I started adding selection action buttons to the floating toolbar in Krita. The focus this time was on integrating more actions and improving the user interface by adding icons to those buttons.

Adding Buttons and Icons

After learning how Selection Tools are triggered through existing UI buttons, the next step was figuring out where those actions originate in the code and how to reuse them in new buttons. I also explored how to visually represent each button using Krita's icon system.

Here’s a simple example of how I added an icon to a button:

d->buttonCopyToNewLayer = new QPushButton();
d->buttonCopyToNewLayer->setIcon(KisIconUtils::loadIcon("duplicateitem"));
d->buttonCopyToNewLayer->setIconSize(QSize(25, 25));

This pattern forms the basis for a reusable template I can follow as I implement additional action buttons across the toolbar.

Finding Icons

Icons play a huge role in usability. Much like how we can recognize cartoon characters by their silhouettes, users often identify tools in a UI by their icons. Good icons make interfaces faster to use and easier to understand.

To find appropriate icons for my buttons, I’ve been referencing these sources:

Krita’s official icon library:
scripting.krita.org/icon-library

Krita source file:
$KRITASOURCE/krita/krita.action

If I couldn’t find an icon there, I searched the codebase for related keywords or looked at how similar tools were implemented with icons. When I exhaust these options, I can also reach out to @Animtim who helps create Krita's custom icons.

Conclusion

Buttons are most powerful when they’re not only functional but also accessible and visually intuitive. This week extends on the work from last week

Next on my list, while I continue adding selection buttons and icons, is to make the floating selection bar movable on the canvas!

Contact

To anyone reading this, please feel free to reach out to me. I’m always open to suggestions and thoughts on how to improve as a developer and as a person. Email: ross.erosales@gmail.com Matrix: @rossr:matrix.org

Wednesday, 23 July 2025

Hello everyone! Midterm evaluations are here, and I wanted to share an update on my GSoC project. Here’s what I’ve accomplished so far:

Progress So Far

Migration of Existing Fuzz Targets

The first step was migrating the existing build scripts and fuzz targets from the OSS-Fuzz repository into the respective KDE repositories. Maintaining them within the OSS-Fuzz repo added a bit of friction when making changes. Having them in KDE repos makes it easier to maintain and update them.

KArchive Fuzzer

Then I worked on KArchive fuzzer doing mainly two changes: First was to split the fuzzer into separate targets for each archive format (like zip, tar, 7z, etc.) to improve coverage. Second was to add libFuzzer dictionary files to guide the fuzzing process better. Here is an image showing the coverage after these changes:

KArchive Fuzzer

This coverage was tested using a local corpus and it is pretty solid for just fuzzing the “reading” part. The coverage will increase on OSS-Fuzz by time as the corpus keeps growing. Splitting the fuzzer into multiple targets allows the fuzzer to focus on specific archive formats, which keeps the corpus size smaller and more efficient.

KMime Fuzzer

After that, I focused on KMime. I created a fuzz target for it, which focused on the just the MIME parsing functionality. The parsing part of KMime is critical as it handles untrusted input, such as, from emails (in KMail).

KMime Fuzzer

For KMime, I also added a libFuzzer-style dictionary file to help guide the fuzzing process. This helps the fuzzer generate more meaningful inputs, which can improve coverage and help the fuzzer reach deeper code paths.

KDE Thumbnailers Fuzzer

After KMime, I moved on to KDE Thumbnailers. I created a fuzzer for the thumbnailers that are used in KDE applications to generate previews of files. This is important as it handles untrusted input from various file formats, such as images, documents, etc. KDE has a lot of thumbnailers, I started with the thumbnailers in KIO-Extras repository, which includes thumbnailers for various file formats like images, videos, documents, etc.

KDE Thumbnailers were tricky to fuzz because they aren’t standalone. They depend on KIO and KIOGui, which are pretty heavy and pull in a bunch of dependencies not required for thumbnailing. Building the full KIO stack inside OSS-Fuzz would have made the build process slow and complicated.

To avoid that, I wrote a custom build script that compiles just the thumbnailer source files and their direct dependencies. That keeps the fuzzers lightweight and focused only on the thumbnailing functionality.

KDE Thumbnailers Fuzzer

For these thumbnailers, I also created a dictionary file for each thumbnailer separately for the same reason as KMime.

KFileMetaData Fuzzer

At last, I worked on KFileMetaData. This library is used to extract metadata from files, such as images, videos, documents, etc. Same as KDE Thumbnailers, it handles untrusted input from various file formats, so fuzzing it is important to ensure it can handle malformed or unexpected data gracefully.

Initially, I made a single fuzzer that used Qt plugin system to load metadata extractors and ran the extractors based on content mimetype. However, this required using dynamic libraries which is not great for OSS-Fuzz integration. So I split the fuzzer into multiple targets, one for each extractor, and compiled them statically. This way, each fuzzer is focused on a specific extractor and doesn’t depend on dynamic linking.

KFileMetaData Fuzzer

The thumbnailers and kfilemetadata currently have the highest coverage among all the fuzzers I’ve created so far, which is great! The coverage will improve and reach closer to 100% for them as the corpus grows on OSS-Fuzz.

What’s Next

There are still many more libraries that could benefit from OSS-Fuzz integration. Here are some that I plan to work on next:

More Thumbnailers

KDE maintains a large number of thumbnailer plugins, and I intend to integrate as many of them as possible. The next ones on my list (provided by Albert Astals Cid) include:

Okular Generators & QMobipocket

QMobipocket is a library used by Okular for reading .mobi files. It parses Mobipocket documents and could benefit from fuzzing to identify edge cases and potential vulnerabilities.

Okular also includes several generators responsible for rendering various document formats. While most rely on third-party libraries, a few include custom code that has not yet been fuzzed. These components may be susceptible to bugs triggered by malformed files.

Fuzzing these generators is a bit tricky, since building the full Okular application and all its dependencies would slow down the build process and make its maintenance harder. To address this, I plan to build only the relevant generator source files and their minimal dependencies similar to the approach I used for KDE thumbnailers.

KContacts (VCard Parser)

KContacts is a KDE framework for handling contact data. It includes a VCard parser that reads .vcf files. Although the format is relatively simple, it supports multiple character encodings and codecs, making it an interesting candidate for fuzz testing.

That’s it for now. If you’re working on/know a KDE library that touches untrusted input and could benefit from fuzzing, please let me know! You can reach me on Matrix or Email.