24 January, 2021

Discovering I never thought I could contribute with Open Source, or even imagined I could change my workspace, in my mind doing it was beyond my programming skills.


23 January, 2021

The year 2020 was difficult in many ways, but it also was important for me: I joined KDE e.V. as a consultant in the role of Project Coordinator.

One of the main focuses of mine was supporting the KDE Goals initiative, which resulted in creating a formalized process.

As you might know (or read in the process), the KDE Goals are to be replaced roughly every two years.

This timebox was selected to balance keeping the Goals fresh, and letting the Goal Champions have enough time to work on the topics with the community.

Often, the goals have dedicated Sprints, where community members from all over the world meet up to work together – this not only greatly accelerates the work, but also lets the community create a stronger bond (and is a perfect opportunity to take group photos that the Promo team can use later 🙂 ).

As you might guess, the previous year was hardly an ideal one for those kind of events, and even though Virtual Sprints did happen, they can only be a substitute for the in-person ones.

So as the new year started, discussion about a potential extension of the current Goals period began. An extension would mean that instead of starting the process of selecting new Goals this year, we would do that in 2022 instead.

This has two main benefits:

  1. The current goals will get more time to finish the work that is already ongoing and was somewhat hindered by the pandemic. And if we’re lucky enough, perhaps by this time next year we could even think about having a in-person event.
  2. The new Goal Champions will start their reign in a (hopefully) more predictable world, with all of us having a better understanding if the vaccines will let us travel and meet again. This will help the Champions set the scope of the Goals.

Of course there are some considerations to be made. As mentioned before, the process assumes replacing Goals with new ones, so that they reflect the current focus of the community. Extending the Goals forever would resolve in a discrepancy between what the community wants, and what the KDE e.V. is promoting and helping with. However, I hope you agree with me that the current Goals (Wayland, Consistency, and KDE is All About the Apps) are still very much relevant.

The other thing is, Championing can be a demanding task, so our current Champions might feel exhausted with an extra year in focus. The good news is, after talking with Méven, Niccolo and Jonathan I can confirm that they are ready to extend their roles for an additional year. Additionally, I have confirmed with the KDE e.V. Board that they are OK with this extension as well.

So this brings me to the part, where I can officially announce, that the KDE Goals get an extra year! I hope this will give you more time to engage with the work being done as part of this initiative, and also more time to plan out your Goal proposals for 2022 🙂

PS. Speaking of engaging in ongoing work, there is a Wayland Virtual Sprint currently active!

Well folks, you finally have a chance to test out Plasma 5.21, in beta form! Please do install it and find all the bugs we missed. Bug reports have already started pouring in, and we’ll fix them as fast as we can in the next month. 🙂

But check out what else we did this week:

New Features

Kate now has a searchable HUD-style command palette that lets you trigger menu items with super speed! It’s activated using the Ctrl+Alt+I shortcut, and we’re investigating adding it to other KDE apps as well in the form of a re-usable framework component. (Waqar Ahmed, Kate 21.04):

Bugfixes & Performance Improvements

Spectacle is once again able to take rectangular region screenshots on triple-screen setups (Franz Baumgärtner, Spectacle 20.12.2)

Okular’s Open dialog once again defaults to “All files” in its file type filter when run on non-Plasma desktops (Albert Astals Cid, Okular 20.12.2)

Dolphin now correctly reports the number of files present on other disks not using standard Linux filesystems, such as NTFS (Ilia Kats, Dolphin 20.12.2)

The “Add Network Folder” action is once again visible in Dolphin for people using Frameworks 5.78 or later–albeit it now lives in the toolbar, rather than in the view (Norbert Preining, Dolphin 20.12.2)

When you turn off Konsole’s “Remember window size” feature, that now works again (me: Nate Graham, Konsole 20.12.2)

The System Settings Fonts page no longer shows blank previews for the anti-aliasing styles when using the proprietary Nvidia driver (Yaroslav Sidlovsky, Plasma 5.21)

Discover now handles the situation where you’re installing an add-on that requires you to select a specific file from among a set of options, just like the standalone “get new [thing]” dialog (Dan Leinir Turthra Jensen, Plasma 5.21)

Plasma’s support for the Pulse Connect Secure VPN type now works (David Redondo, Plasma 5.21)

Discover is now a bit faster to launch and uses less memory (still a lot, but less than before at least) (Aleix Pol Gonzalez, Plasma 5.21)

It’s now possible to unset global shortcuts set for activating Plasma applets (David Redondo, Plasma 5.21)

While the “Get new Plasma Widgets” window is open, attempting to open it again now re-focuses the existing one rather than opening a second one (Willyanto, Plasma 5.21)

Fixed an uncommon crash in System Settings’ Shortcuts page (David Redondo, Plasma 5.21)

When waking up a sleeping laptop that has a touchscreen, KWin no longer pretends that a finger is being held down on the touchscreen until you really do touch it at least once yourself (Xaver Hugl, Plasma 5.21)

In the Plasma Wayland session, windows no longer try to snap to OSDs and notifications (Vlad Zahorodnii, Plasma 5.21)

The System Tray’s back button now reverses itself correctly when using an RTL language (Jan Blackquill, Plasma 5.21)

Filenames in the Breeze-themed GTK folder dialog are now readable, especially when using a dark color scheme (Jan Blackquill, Plasma 5.21)

Undoing the deletion of a file or folder can no longer unexpectedly overwrite an existing item that has the same name as the undeleted item (David Faure, Frameworks 5.79)

System Settings no longer crashes when you navigate to the Screen Locking page’s “Appearance” sub-page and then navigate away (Nicolas Fella, Frameworks 5.79)

Okular and potentially other KDE apps too can once again open files accessed from a web browser (i.e. using their “Open” dialogs (Albert Astals Cid, Frameworks 5.79)

When you open a file accessed from a web browser in a KDE app and then show the Open dialog again, it no longer tries to show you the file’s parent website (Albert Astals Cid, Frameworks 5.79)

System Tray applets that feature expanding lists of actions no longer sometimes have some of the actions clipped out of the view when using non-default fonts or font sizes (me: Nate Graham, Frameworks 5.79)

User Interface Improvements

Dolphin’s “Copy file path” action has had its shortcut changed to Ctrl+Alt+C so as not to conflict with the “Copy” action in the embedded terminal panel, whose shortcut is Ctrl+Shift+C (Someone going by the pseudonym “The Imp”, Dolphin 20.12.2)

Gwenview’s titlebar now shows the path to the currently-viewed location while in Browse mode (Antonio Prcela, Gwenview 21.04)

When using the systemwide Double-Click mode, you can now rename files on the desktop by clicking on the label of an already-selected item, just like in Dolphin (me: Nate Graham, Plasma 5.21)

Plasma no longer ever sends a pointless notification when you create a link to a file somewhere else (Nicolas Fella, Plasma 5.21)

Rotated widgets are no longer jaggy and aliased (David Edmundson, Plasma 5.21):

The Edit Mode toolbar now includes a link to the System Settings Global Themes page (someone going by the pseudonym “Wael CH”, Plasma 5.21):

System Settings’ Desktop Effects and Background Services pages now support the “Highlight changed settings” feature (Cyril Rossi, Plasma 5.21)

The icons used for screen rotation in System Settings’ Display & Monitor page are now clearer (someone going by the pseudonym “Wael CH”, Plasma 5.21):

Breeze theme monochrome icons now stay monochrome when using scale factors greater than 200% (Kai Uwe Broulik, Frameworks 5.79)

How You Can Help

Have a look at to discover ways to be part of a project that really matters. Each contributor makes a huge difference in KDE; you are not a number or a cog in a machine! You don’t have to already be a programmer, either. I wasn’t when I got started. Try it, you’ll like it! We don’t bite!

Finally, consider making a tax-deductible donation to the KDE e.V. foundation.


21 January, 2021

My talk “Partially-Formed Objects For Fun And Profit” from Meeting C++ 2020 is now online here:

From the abstract:

Lately, partially-formed states have gained some traction as the natural state of moved-from objects. Alexander Stepanov, in his landmark book Elements of Programming (EoP), defines them as a state in which the only valid operations are assignment and destruction. This state was, and continues to be, essential to high-performance code, and to the C++ guarantee of “don’t pay for what you don’t use”.

We will also show how developers that feel uneasy about the partially-formed state can avoid them at little to no cost, neither in code readability, nor performance, and use these examples to propose a new (or old) paradigm for API design: safe and unsafe functions (in the Sean Parent sense).

A longer version of the talk, in which I also cover the Bonus Slides, for which I didn’t have time in the Meeting C++ version, is available from the MUC++ YouTube channel:


20 January, 2021

Featured image of post Efficient custom shapes in QtQuick with Rust

One of the advantages of QWidgets when building a Qt application is the ability to build in a simple way custom widgets with the QPainter API. This gives the Qt developer almost total freedom to implement complex geometries for their widgets.

On the other hands, QML contains by default only rectangles. These rectangles can change the radius to create circles and rounded rectangles, but more complex shapes are more complicated.

The current state of custom geometry in QtQuick

Fortunally, the Qt API provides multiple ways to implement custom shapes, that depending on the needs might be enough.

There is the Canvas API using the same API as the canvas API on the web but in QML. It’s easy to use but very slow and I wouldn’t recommend it.

Instead of the Canvas API, from the QML side, there is the QtQuick Shapes module. This module allows creating more complex shapes directly from the QML with a straightforward declarative API. In many cases, this is good enough for the application developer but this module doesn’t offer a public C++ API.

If you need more controls, using C++ will be required to implement custom QQuickItem. Unfortunately drawing on the GPU using QQuickItem is more complex than the QPainter API. You can’t just use commands like drawRect, but will need to convert all your shapes in triangles first. This involves a lot of maths like it can be seen in the example from the official documentation or from the KDAB tutorial (Efficient custom shapes in Qt Quick).

A QPainer way is also available with QQuickPaintedItem, but it is slow because it renders your shape in a textured rectangle in the Scene Graph.

The Rusty way

What if we could transform arbitrary shapes into triangles? We would get a high level API but still get great performance. This process is called tessellation and there are a few libraries that implement it. For example in C++, we have Skia and CGAL. Unfortunatelly, both aren’t easy to use, so I decided to look at the Rust library ecosystem and in particular at Lyon, which was designed with performance and compliance to the SVG standard in mind since the goal is to use it in Servo in the future.

Lyon doesn’t have any C++ bindings but I got inspired by the recent blog post from Jonah and I need to say the experience of writing bindings was a breeze.

The first step was creating wrapper structs around the Lyon primitives. LyonPoint, LyonGeometry and LyonBuilder will later be directly usable from the C++ side.

mod ffi {
    pub struct LyonPoint {
        x: f32,
        y: f32,

    pub struct LyonVector {
        x: f32,
        y: f32,

    pub struct LyonGeometry {
        vertices: Vec<LyonPoint>,
        indices: Vec<u16>,

    extern "Rust" {
        type LyonBuilder;
        fn new_builder() -> Box<LyonBuilder>;
        fn move_to(self: &mut LyonBuilder, point: &LyonPoint);
        fn line_to(self: &mut LyonBuilder, point: &LyonPoint);
        fn relative_move_to(self: &mut LyonBuilder, to: LyonVector);
        fn close(self: &mut LyonBuilder);
        fn quadratic_bezier_to(self: &mut LyonBuilder, ctrl: &LyonPoint, to: &LyonPoint);
        fn cubic_bezier_to(self: &mut LyonBuilder, ctrl1: &LyonPoint, ctrl2: &LyonPoint, to: &LyonPoint);
        fn build_fill(builder: Box<LyonBuilder>) -> LyonGeometry;
        fn build_stroke(builder: Box<LyonBuilder>) -> LyonGeometry;

We then need to define the methods we declared above. These are all trivial to implement since they are just wrapping the Lyon API.

use ffi:{LyonPoint, LyonVector, LyonGeometry};

// Create a wrapper arround Lyon svg path. This struct is opaque from
// the C++ side so we won't be able to access the internal object, but
// we still can call the methods on it.
pub struct LyonBuilder {
    builder: WithSvg<Builder>,

// Implement wrapping methods
impl LyonBuilder {
    fn close(&mut self) {

    fn move_to(&mut self, to: &LyonPoint) {
        self.builder.move_to(point(to.x, to.y));

    fn line_to(&mut self, to: &LyonPoint) {
        self.builder.line_to(point(to.x, to.y));

    fn quadratic_bezier_to(&mut self, ctrl: &LyonPoint, to: &LyonPoint) {
        self.builder.quadratic_bezier_to(point(ctrl.x, ctrl.y), point(to.x, to.y));


// Lyon Builder constructor
pub fn new_builder() -> Box<LyonBuilder> {
    return Box::new(LyonBuilder{
        builder: Path::builder().with_svg()

The next step was to add the build_fill that will transform the SVG path instructions into a set of vertices and indices. These vertices and indices will be directly available from the C++ side. This is extremely handy since this can be directly fed into the QSGGeometry painting method.

pub fn build_fill(builder: Box<LyonBuilder>) -> LyonGeometry {
    let mut buffers: VertexBuffers<Point, u16> = VertexBuffers::new();
        let mut vertex_builder = simple_builder(&mut buffers);

        // Create the tessellator.
        let mut tessellator = FillTessellator::new();

        let path =;

        // Compute the tessellation.
        let result = tessellator.tessellate_path(
            &mut vertex_builder

    LyonGeometry {
        // convert_points transform lyon::point to our LyonPoint wrapper
        vertices: convert_points(buffers.vertices), 
        indices: buffers.indices,

And we are almost done with the Rust side, we still need to create the cargo and corrosion configuration, but I won’t go into details in this post. You can look at how it was done in this pet project.

Using the generated bindings

To make it easy to store and manipulate the path, I create a simple abstraction to the various SVG path instructions.

#include <QList>
#include <variant>
#include <>

/// Move to the point without drawing a line.
struct MoveTo
    /// The destination.
    LyonPoint to;

/// Drawe a line to a specific point.
struct LineTo
    /// The destination.
    LyonPoint to;

/// Draw a cubic bezier curve to the point.
struct CubicBezierTo
    /// First control point.
    LyonPoint ctrl1;
    /// Second control point.
    LyonPoint ctrl2;
    /// The destination.
    LyonPoint to;

/// Close a path.
struct Close

/// SVG conform path commands
using PathSection = std::variant<MoveTo, LineTo, CubicBezierTo, Close>;

template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

/// The SVG path data. It contains a list of instruction (move to, line to, ...).
using PathData = QList<PathSection>;

Now let finally use Lyon to generate the geometry primitives. This will need to be called every time the list of commands is updated. It’s using the command abstraction, I build previously, but this could directly call the LyonBuilder methods.

const auto commands << MoveTo { LyonPoint{0.0, 0.0} }
                    << LineTo { LyonPoint{0.0, 40.0} }
                    << LineTo { LyonPoint{40.0, 40.0} }
                    << CubicBezierTo{ LyonPoint{70.0, 40.0}, LyonPoint{70.0, 0.0}, LyonPoint{ 50.0, 20.0} }
                    << LineTo { LyonPoint{40.0, 0.0} }
                    << Close {};

auto lyonBuilder = new_builder();
for (const auto &command: commands) {
    std::visit(overloaded {
        [&lyonBuilder](MoveTo moveTo) { lyonBuilder->move_to(; },
        [&lyonBuilder](LineTo lineTo) { lyonBuilder->line_to(; },
        [&lyonBuilder](CubicBezierTo cubicBezierTo) { lyonBuilder->cubic_bezier_to(cubicBezierTo.ctrl1, cubicBezierTo.ctrl2,; },
        [&lyonBuilder](Close) { lyonBuilder->close(); },
    }, command);
auto m_geometry = build_fill(std::move(lyonBuilder));

And finally here is our updatePaintNode method. It’s using the GL_TRIANGLES drawing mode and the vertices and indices are copied directly from the geometry Lyon gave us.

QSGNode *PathItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
    QSGGeometryNode *node = nullptr;
    QSGGeometry *geometry = nullptr;

    if (!oldNode) {
        node = new QSGGeometryNode;
        geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(),
                                   m_geometry.vertices.size(), m_geometry.indices.size());

        QSGFlatColorMaterial *material = new QSGFlatColorMaterial;
        material->setColor(QColor(255, 0, 0));
    } else {
        node = static_cast<QSGGeometryNode *>(oldNode);
        geometry = node->geometry();
        geometry->allocate(m_geometry.vertices.size(), m_geometry.indices.size());

    QSGGeometry::Point2D *points = geometry->vertexDataAsPoint2D();
    std::size_t i = 0;
    for (const auto &vertice: m_geometry.vertices) {
        points[i].set(vertice.x, vertice.y);

    quint16* indices = geometry->indexDataAsUShort();
    i = 0;
    for (const auto indice: m_geometry.indices) {
        indices[i] = indice;

    return node;

It is only using Lyon SVG path rendering, but Lyon provides a lot more APIs. For example, there is an abstraction that allows to draw circle, ellipse, rounded rectangle and other basic geometric forms.

There is also the possibility to add custom attributes for texture coordinate or color coordinate. Depending on your need more part of the API could be wrapped and I might create a small library wrapping most of the API.

Custom shape in action

I used this technique in a new toy I’m building. I’m not sure where it is going, but I currently have this:

As was previously discussed, since the 6.0.0 release of Qt, Qt 3D no longer ships as a pre-compiled module. If you need to use it on your projects, try out the new features, or just see your existing application is ready for the next chapter of Qt’s life, you need to compile Qt 3D from source.

In order to do this, you can do it the traditional way ([cq]make ...; make; make install) or use the Conan-based system that is being pioneered with the latest version of the MaintenanceTool.

Using Conan

The latest version of the MaintenanceTool (from the unified installers) will optionally install several things:

  • Conan, a package manager which can build C++ libraries and handle the dependencies
  • CMake, the meta-build system, which is required for Qt 6
  • Ninja, the lighting fast replacement for make and nmake

Additionally, you will need to select Qt 3D in the Additional libraries section so that the source code is available.

As mentioned above, these are optional. You need to find them and enable them in the MaintenanceTool’s UI.


Conan, being a package manager, is designed to handle all dependencies to make it easy to build libraries and applications. However, the way this is setup in the current packages installed by the MaintenanceTool is not complete.

Additional things you need for Conan

In particular, you need two other things:

  • You need to select the Qt Shader Tools module in the MaintenanceTool, if you intend to use the new RHI-based backend for Qt 3D. Without it, Qt 3D will build fine but only the original (and more feature rich) backend will be available.
  • Since Qt 3D is a Qt module, it has many of the similar requirements you need when building Qt itself. At the very least, you need a perl interpreter, so that the module header files can be generated. A full list of requirements for the various platforms is available here.

Once you have all the required bits, it’s time to open a console and run Conan. The process is platform-specific, as each platform has it’s own Conan profile. A complete example is available on the Qt wiki, but this is how it works on my mac where the Qt SDK is installed in /Users/Shared/Qt:

conan install qt3d/6.0.0@qt/final --build=missing -s build_type=Release -g cmake_paths -g=cmake -g deploy --profile=/Users/Shared/Qt/Tools/Conan/profiles/qt-6.0.0-macx-clang

and wait…it takes a while to build Qt 3D.

  • conan, cmake and ninja need to be in your path. In particular, make sure the Qt provided version of Conan is found first, because…
  • the MaintenanceTool installs a custom version of Conan and write config files in the $HOME/.conan folder. This means, at least on multi-user systems, Conan will only properly work for the user who installed the Qt SDK, and that version is found before any platform-provided version.


Using QMake or CMake

Using the MaintenanceTool and Conan makes it easy to get the source and the required dependencies for building Qt 3D. As we saw in the aforementioned, there are still some rough edges. So, in particular, if you are familiar with building Qt modules already, you can just use the “old way”, i.e., download the source and use QMake, or now, CMake.

The packages for the released versions of Qt 3D (and other Additional modules) are available here.


Once extracted, you can do a shadow build of Qt 3D pretty easily (this has the same build requirements as above though, QtShaderTools module and perl interpreter).

tar zxf qt3d-everywhere-src-6.0.0.tar.xz
cd qt3d-everywhere-src-6.0.0
mkdir build
cd build
/Users/Shared/Qt/6.0.0/clang_64/bin/qmake ..
make install

And, again, wait 🙂.


The process is similar if you want to use CMake instead. In the build folder, do:

/Users/Shared/Qt/6.0.0/clang_64/bin/qt-cmake -G Ninja ..
ninja install

Once done, your applications should be able to find the Qt 3D modules.

You can optionally build the documentation using the docs target (but this will not be installed; you will need to register it with Creator and/or QtAssistant for it to appear).


Qt 3D will likely preserve the dual QMake/CMake build system for a while still.


As you see, building Qt 3D involves a bit more work than it did before. Fortunately, it needs to be done only once for each release. Going forward, we will be able to release Qt 3D on a different cycle from the rest of Qt and, as a result, introduce features and bug fixes more frequently. Please do not hesitate to get in touch with us or the Qt build system team if you have questions regarding this new setup.


KDAB provides a number of services around Qt 3D, including mentoring your team and embedding Qt 3D code into your application, among others. You can find out more about these services here.


About KDAB

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

Subscribe to KDAB TV for similar informative short video content.

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

The post Getting your 3D ready for Qt 6 appeared first on KDAB.

SimpleMail is a small Qt library for sending mails, this release makes sure it compiles fine with Qt6, and has some small issues fixed.

I thought this would give me a bit of work but was mostly changing CMakeLists.txt and including one header.

This week I’ll start working for KDAB 🙂 and my first task will be porting one app to Qt6, so I decided to do a little of homework and port my own stuff first as you might have noticed (Cutelyst and ASql).


19 January, 2021

Cutelyst a Qt Web Framework and ASql an asyncronous SQL library for Qt got new releases.

The Cutelyst version 2.14.0 was made in December but was a silent one, I had some issues in production but weren’t related to Cutelyst, the .1 release included some contributions by Adriaan de Groot, I also did some changes for Qt 5.15 and Qt6 but for Qt6 a new major version is needed.

Besides a bunch of fixes, a major regression on the plaintext benchmarks got fixed, unfourtunately not in time for round 20, but thanks to ASql you will Cutelyst got a better scoring on SQL related benchmarks

ASql also got a bunch of bug fixes, but most importantly it’s now Qt6 ready.

And speaking of Qt6 Cutelyst port is also completed now, after I port most of my own apps I’ll do a v3 release which is compatible with both Qt5 and 6.

Have fun!

Today, the Krita team has released Krita 4.4.2. With over 300 changes, this is mainly a bugfix release, though some key new features, too!

New Features

Mesh Gradients

Sharaf Zaman’s Google Summer of Code project has landed in this release! Compatible with Inkscape, Krita now provides the second independent implementation of SVG Mesh Gradients. Mesh gradients are used on vector objects and can deliver really natural looking results:

Mesh Gradients

Mesh Gradients

Mesh Transform

Image showing how useful mesh transforms can be

Mesh transforms will greatly speed up your concept by allowing complex transformations, such as the half-rounded grate on this window!

But the gradients are not the only mesh related feature! This release also sees the first iteration of the mesh-transform. Like the gradient mesh, the mesh transform consists of bezier patches that can be individually shaped to create precise transforms, especially useful for rounded objects. Not shown in the above screenshot: you can optionally show the handles of each bezier curve making up the mesh for even more precision and control!

We’re still tweaking this one, but currently the shortcuts are the following:

  1. Mesh node:
    – click+drag — move node
  2. Border node:
    – click+drag — move node
    – shift+click+drag — move whole row/column
    – ctrl+alt+click+drag — split/slide row/column
    – ctrl+alt+click+drag-away — remove split
  3. Control point:
    – click+drag — change control point symmetrically
    – shift+click+drag — change control point non-symmetrically;
    this action will create angular texture
  4. Node or Control:
    – ctrl+click — select multiple nodes
  5. Patch area:
    – click+drag — free patch deform
    – shift+click+drag — move whole mesh
  6. Empty area outside mesh:
    – click+drag — rotate mesh or selection
    – ctrl+click+drag — scale mesh or selection
    – shift+click+drag — move mesh or selection

Gradient Fill Layer and new Gradient Editor

Showing the gradient fill layer and the new gradient editor.

The gradient fill layer and the new gradient editor in action.

Deif Lou added a new gradient fill layer type, this one will make it easy to quickly create a variety of gradients non-destructively. With it, he also made an important usability fix: Gradients in Krita could be either segment type, or stop type, with different features each, and different editors each. That could get quite annoying if you were working on a gradient, but you realized you had the wrong type! This is now fixed, as both gradient types can now be edited by the same editor, which also converts between the two.

Improved Halftone Filter

Deif Lou also created a new halftone filter. The old filter was slow and could not be used as a filter mask, and could only show dots.

Our splash screen as filtered by the half tone filter

The new halftone filter can do per-channel filtering, useful for vintag effects and maybe even printing!

The new filter can handle being applied as filter layer, per-channel filtering, and the pattern itself can be generated with any of the fill layer options, giving endless combinations.

Updated macOS integration plugins

Amyspark improved the quicklook plugin by adding thumbnailing support (needs macOS 10.15 or higher) and added metadata support for Spotlight.

A Paste Shape Style Action

A small feature that allows you to only paste the style of the copied vector shape onto other selected vector shapes. This feature can be found under the edit menu, or assigned a shortcut in the shortcut settings.

A Toolbar Button for Wraparound Mode

Originally, we had a shortcut, W, that enabled Krita’s Wraparound mode, one of the features Adobe copied this year for the next release of Photoshop.

But too many people pressed the shortcut by accident and were then confused and thought Krita had gone crazy… So we removed the shortcut, but now nobody could find it anymore. That’s why in this release, we have added a button to the toolbar that activates wraparound:

Please don’t press it by accident!

New brushes

There are also six new brushes by Ramon Miranda, meant to show off the new RGBA brush tip feature:

HiDPI Support

This image shows the difference between the old popup palette and the new one on 4k display with 200% UI scaling. Note that it also shows a new button and custom UI text.
Agata Cacko improved HiDPI rendering (BUG:411118) of

  • Pixelart previews
  • Reference images
  • Comic manager pages
  • Image thumbnails in the last documents docker
  • Recent documents thumbnails
  • The Popup palette
  • Clipboard content in the new image dialog
  • The Color selectors
  • Gamut masks
  • Brush preset icon in the Brush preset editor
  • Layer thumbnails and icons
  • Resource choosers
  • Bundle icons

Bug Fixes

File Handling

  • Files with names starting with a number are now autosaved correctly
  • Make it possible to load EXR files with non-ascii characters in the path
  • Disable making the background black for a semi-transparent EXR file (BUG:427720)


  • The PressureIn sensor now works correctly in combination with the Hue color expression (BUG:426234)
  • The speed smoothing algorithm no longer creates blobby lines (BUG:363364, 375360)
  • The colorsmudge brush now blends when there is a selection active (BUG:423851)
  • The brush outline no longer snaps when switching between two images with a different zoom level (BUG:427094)


Most animation work is going in the master branch, which will become Krita 5.0.

  • Onion skins are hidden when playing an animation (BUG:426246)
  • Warn the user when they are trying to run the ffmpeg download archive, instead of unpacking it
  • Fix converting an animated transparency mask to a paint layer (BUG:419223)


  • The default shortcuts for changing the mode in the selection tools have been removed: they are replaced by ctrl/shift/alt modifiers. The actions still exist, so you can configure single-key shortcuts in Krita’s shorcut settings dialog.
  • The magnetic selection tool now has buttons to confirm or discard a selection
  • An issue where moving a selection would jump was fixed (BUG:426949)
  • A Fit to Height zoom shortcut was added, patch by Jonathan Colman (BUG:410929)
  • The screentone generator’s defaults were improved
  • File layers that are dragged and dropped now have a proper name (patch by Jonathan Colman) (BUG:427235)
  • The popup palette now has a clear color history button (patch by Emilio Del Castillo)
  • The report bug dialog now provides the system information and usage logs in an easy to copy/paste manner
  • Blacklisted resources that contain a \ in the filename were ignored (BUG:421575)
  • Displays are shown by name in the color management settings page (BUG:412943)
  • Fix showing custom icons for user-defined templates (patch by Evan Thompson) (BUG:395894)
  • The fill layer dialog and seexpr widgets were polished
  • The x/y position spin boxes in the move tool options were fixed (BUG:420329, 423452)
  • Add default letter spacing for the text shape (patch by Lucid Sunlight)
  • Add support for user-installed color schemes (patch by Daniel)
  • All dialogs and message boxes are now correctly parented to the main window (patch by Daniel)
  • Make it possible to export groups as merged layers (patch by Dmitrij Antsevich)
  • Fix kerning handling in the text editor (patch by Lucid Sunlight)
  • Add support for color opacity in the text editor (patch by Lucid Sunlight) (BUG:342303)
  • Fix cropping the transform mask when moving the masked layer
  • Improve switching between SVG source and rich text editor (patch by Lucid Sunlight) (BUG:424213)
  • Fix issues with the brush outline getting stuck when the brush size is smaller than 0 (BUG:427751)
  • Improve the Python plugin importer so action files get imported correctly. (Patch by Rebecca Breu) (BUG:429262)
  • Fix tearing of patterns when scrolling in the resource chooser.
  • The rectangle and ellipse tool now have default shortcuts: Shift+R and Shift+J, respectively
  • Allow the Select Similar Color selection tool to pick from a set of layers, make work correctly with image bounds and handle transparent layers correctly. (BUG:428441)
  • Fix the isometric grid so it is drawn correctly
  • The outline selection tool was renamed to freehand selection tool (BUG:425894)


  • The bundled g’mic plugin is updated to 2.9.2 which contains a correct Boost-Fade filter (BUG:412617)
  • The gradient map filter was improved and made faster (patch by Deif Lou)

Stability and Performance

  • Fix a lot of memory leaks
  • Improve performance by removing a bottleneck when transforming internal colors to and from QColor
  • Fix a race condition in the Comics Manager plugin (BUG:426701)
  • Fix the fill layers updating too many times
  • Fix random crashes when changing screentone fill layer parameters (BUG:428014)
  • Fix a crash in the Square Gradient strategy (patch by Deif Lou)
  • Fix a crash when converting SVG source to rich text or back (patch by Lucid Sunlight)
  • Fix an assert when trying to liquify transform an empty layer (BUG:428685)
  • Fix an assert when creating a new layer from the visible layers while the active layer is hidden (BUG:428683)
  • Make the Select Similar selection tool multithreaded.


  • On macOS, the Delete key (which is actually backspace) now deletes a selection. (BUG:425370)


  • It’s now possible to open files from external sources, like a file manager, google drive or a download manager on Android
  • Add mimetype and pathpatter for .kra files
  • Make Krita a SingleTask application: this means that opening a file of a type supported by Krita will work properly even if Krita is already running.
  • Fix possible corruption when saving .kra or .ora files
  • Fix a crash on closing Krita (BUG:426092)
  • Fix “also save as KRA” (BUG:424612)
  • Handle mouse buttons state and touch events properly
  • Make resaving with different mime type work on Android (BUG:429056)
  • Make the theme background black for chromeos: this used to be pink, which looked ugly when resizing a window.
  • Fix flickering tiles when OpenGL is enabled (BUG:424347)



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


(If, for some reason, Firefox thinks it needs to load this as text: to download, right-click on the link.)


Note: the gmic-qt is not available on OSX.


This time, the Android releases are made from the release tarball, so there are translations. We consider Krita on ChromeOS and Android still beta. There are many things that don’t work and other things that are impossible without a real keyboard.

Source code


For all downloads:

Support Krita

Krita is a free and open source project. Please consider supporting the project with donations or by buying training videos! With your support, we can keep the core team working on Krita full-time.

The post Krita 4.4.2 Released appeared first on Krita.


18 January, 2021

One of the forgotten tools

Environment Modules is one of those open source projects that I wish more people would know and use. I always wonder why tools like asdf don’t provide support for it instead of rolling their own implementation. So lets increase awareness.

The Environment Modules package provides for the dynamic modification of a user’s environment via modulefiles.

Environment Modules Homepage

So what does it do? Here is a small example:

~ $ type ansible
bash: type: ansible: not found

~ $ module avail -l ansible/
- Package/Alias -----------------------.- Versions --------.- Last mod. -------
ansible/2.8.15                          2.8                 2020/10/28 18:43:05
ansible/2.9.13                          2.9                 2020/10/28 18:43:15
ansible/2.10.1                          2.10:default        2020/10/28 18:42:56

~ $ module load ansible/2.9.13

~ $ ansible --version
ansible 2.9.13
  config file = None
  configured module search path = ['/home/mjansen/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/mjansen/local/opt/ansible/2.9.13/lib64/python3.8/site-packages/ansible
  executable location = /home/mjansen/local/opt/ansible/2.9.13/bin/ansible
  python version = 3.8.6 (default, Nov 09 2020, 12:09:06) [GCC]

~ $ type ansible
ansible is hashed (/home/mjansen/local/opt/ansible/2.9.13/bin/ansible)

~ $ module unload ansible

~ $ type ansible
bash: type: ansible: not found

So in short environment modules allow you to alter your shell session dynamically by

  • Altering the content of environment variables
  • Setting/Removing aliases
  • Create functions in the users environment
  • There is more in the modulefile man page.

Modulefiles are actually tcl scripts. It is a slightly weird (imo) looking scripting language. Tcl and environment modules are available forever. They are from the 1990s.

The ansible script above looks like this:

proc ModulesHelp { } {
        global version
        puts stderr "\tActivates ansible v$version [ARA]"

set     home         $::env(HOME)
set     version      2.9.13
set     root         $home/local/opt/ansible/$version
set     ansible_callback_plugins [exec $root/bin/python3 -m ara.setup.callback_plugins]

module-whatis   "Ansible V$version"

conflict ansible

append-path PATH $root/bin
setenv ANSIBLE_CALLBACK_PLUGINS $ansible_callback_plugins

So why should you care. As a hypothetical developer you probably need to install different versions of libraries and tools to check your programs against or with. Like different Qt Versions or compiler. Most developer I know then proceed to use shell scripts they source to deal with that. This does not allow easy unloading and switching. Utilizing environment modules gives you a much more pleasant experience. My list currently looks like this:

- Package/Alias -----------------------.- Versions --------.- Last mod. -------
ansible/2.8.15                          2.8                 2020/10/28 18:43:05
ansible/2.9.13                          2.9                 2020/10/28 18:43:15
ansible/2.10.1                          2.10:default        2020/10/28 18:42:56
catt                                                        2019/08/26 14:58:23
editor/vim                                                  2020/10/26 19:39:10
elixir_escripts                                             2020/11/11 05:29:32
elm/0.19.1-3                            0.19:0.19.1:default 2020/03/31 22:24:21
go/1.13.6                                                   2020/01/21 16:06:16
gopath                                                      2020/01/21 16:16:09
groovy/2.4.7                                                2019/08/26 14:58:23
groovy/2.5.7                                                2019/08/26 14:58:23
home_install                                                2020/02/23 16:20:05
hugo/0.76.5                                                 2020/10/28 18:46:11
hugo/0.80.0                                                 2021/01/09 21:07:52
java/jdk1.8.0_172                                           2019/08/26 14:58:23
jupyter                                                     2019/08/26 14:58:23
maven/3.3.9                                                 2019/08/26 14:58:23
minishift                                                   2020/03/29 16:29:17
novisual                                                    2019/08/26 14:58:23
reclass/1.4.1                                               2020/01/27 14:27:20
reclass/git                                                 2020/12/20 19:51:34
usr_local                                                   2020/01/29 13:36:42
vit                                                         2020/01/15 17:01:25
zeppelin/0.9.0-preview2                                     2020/10/29 16:42:13

Environment modules also has the concept of sessions which allows you to save and load different configurations. Either in a central location (eg. ~/.module) or to a file specified on the command line.

~ $ module save homepage

~ $ module savelist
Named collection list:
 1) homepage  

~ $ module saveshow homepage

module use --append /home/mjansen/local/etc/modules
module load editor
module load gopath
module load go
module load hugo


Modulefiles can even specify conflicts, so you don’t load two different versions of a library or program. They can also specify requirements, so you don’t forget to load a python version before loading ansible.

If you want to try environment modules one word of warning. In opensuse after installing environment modules it is not active. I guess the same applies to other distros. Shell initialization files for additional packages are a sore spot in most distros. You have to activate it manually in your shell initialization file (eg. bashrc).

# ACTIVATE ENVIRONMENT MODULES                                           # {{{2
case "$0" in
          -sh|sh|*/sh)  modules_shell=sh ;;
       -ksh|ksh|*/ksh)  modules_shell=ksh ;;
       -zsh|zsh|*/zsh)  modules_shell=zsh ;;
    -bash|bash|*/bash)  modules_shell=bash ;;

source /usr/share/Modules/init/$modules_shell
test -r /usr/share/Modules/init/{$modules_shell}_completion && source /usr/share/Modules/init/{$modules_shell}_completion