My month in KWin/Wayland

June has been a busy month in KWin, with me working on fixing remaining Wayland functionality and upcoming legend Vlad Zagorodniy working on polishing and cleaning up all the effects.

In this blog I’ll talk about the more interesting bits of kwin work that I did during June.

Fractional Scaling

A requested feature is to allow fractional scaling for QHD monitors which are roughly 1.5 times the resolution of standard monitors, but not the full 4k.

The wayland scale system is based around integers, but because the scaling is based around a normalised co-ordinate system, the compositor can show a display at a scale of 1.5 whilst clients are rendering for a 2x display with no changes in the client.

Patchset consists of XdgOutput support in both kwin and Qt so that windows that position themselves (such as xwayland clients, or plasmashell) can know the correct logical size of the screen and then relevant changes in kwin/kscreen to implement the extra fractional part.

Unfortunately as this requires a change in Qt to function properly. this won’t be available in our UI until Plasma depends on the Qt version that contains this support, probably around March 2019. Stupid desktop Linux.

Cursor Scaling

On the topic of scaling, I merged support for making sure that the cursor is the physical size the user selected regardless of the resolution of the monitor it happens to be on or the scale of the client that supplied it. Particularly useful for a multi-monitor setup where blindly using a pixel size doesn’t cut it.

XdgWmBase

The protocol for clients to register toplevels and popups to the window manager has gone through multiple stages, wl_shell, XDGShellV5, XdgShellV6 now settling on the finally stable protocol, Xdg WM Base. Having this finally stable is a hugely signifiant point in the road to wayland.

Previously we were lagging behind other desktops in shell protocol support, but KWin 5.14 will have support for XDG WM Base ahead of the toolkit support coming in Qt 5.12 / next GTK.

GTK decorations

GTK gained server side decoration support in 3.22, however, the implementation needed some work. It correctly removed it’s own decorations under KWin but failed to inform KWin, which didn’t want to add a “second” titlebar, leaving it in an even worse state than before.

I submitted a patch for GTK rectifiying all the issues and that was all merged pretty swiftly.

It's a window looking normal, I don't know why I added a screenshot. Just imagine it looking worse before then feel excited about this.

Misc

KWin also gained support to show different mouse cursors for resizing the left edge of a window or the right edge of a window. Useful for telling which window will be resized in the case of touching windows.

Plasma Startup

Startup is one of the rougher aspects of the Plasma experience and therefore something we’ve put some time into fixing

Why is startup slow?

The primary reason for Plasma startup being slow is simply that it does a lot of things, including:

  • Session restore
  • Config migration
  • Setting keyboard layouts
  • Most esoterically, making sure your colour scheme gets synced to the xrdb database, so that loading xfig or dia or any other pre-Qt/GTK1 application still has the correct colours in your Plasma session

Too many to list. This means it’s easily a whole second or more before we even start loading plasmashell, one of the more time consuming parts of startup.
This slow load gets exaggerated by us not removing the splash screen till everything is actually properly loaded.

However, it’s still an area we can improve.

About startup

Startup consists of mulitple components invoked at 3 different levels.

  • Kcminit
    Config modules (kcms) typically update a system when the user applies the settings, however as we need to restore settings there is an optional hook called on startup for various modules.
  • KDE Daemons (kded)
    Evolving from the more static nature above may services require running in the background waiting for external events. Some modules are loaded on demand, others are loaded explicitly during startup.
  • Autostarted applications
    Meaning launcing core applications such as plasmashell/krunner as well as other applications a user might have selected; such as nextcloud or kgpg
  • User shell scripts
    For anything else

These effectively all have their loading invoked at 3 different levels; as defined in the relevant kcminit/kded/autostart .desktop files. Note these may be shipped as core plasma, but can also include completely 3rd party items.

  • Before plasmashell and other core autostart services
  • Before user applications are restored / autoloaded
  • After everything is restored and

A slightly more detailed version can be seen here.

Profiling

The most important part of any speed work is correctly analysing it.
systemd-bootchart is nearly perfect for this job, but it’s filled with a lot of system noise.

I’ve made a fork of systemd-bootchart that only tracks processes owned by that user on github.
To use put the following line into:
/etc/X11/Xsession.d/00-bootchart

/usr/lib/systemd/systemd-bootchart -o /tmp -r &

To profile wayland sessions, mod the SDDM config wayland SessionCommand option.

After 20 seconds an SVG will be placed in /tmp.

An example

Below shows the boot process of my personal machine. The important part to track is when ksplashqml gets destroyed, that signifies that boot is complete. In my case this happens after 4.5 seconds.



Just some of the many fixes

There have been and continue to be lots of tiny changes around the code. Mostly using the awesome tool hotspot here are just a few of the more significant and interesting ones.

A mysterious gap of nothingness

This stupid bug was caused by ksmserver blocking whilst it completed launching phase 1 of kded daemons before it continued onto loading the next section.
Problem is plasmashell and other GUI apps loaded in phase0 first task is to register with the X session manager, ksmserver. End result is we lockup in X code till
ksmserver is done. Solved by a logic rewrite.

Multiple starts of the same daemon

This is the result of the following code in a bunch of processes all started at once.

if (! serviceExistsOnDBus) {
startExecutable(…)
}

Whilst the daemon did handle this case correctly and the false starts aborted, it’s still a lot of time spend linking a process we don’t want.
Solution in this case was to port to DBus activation which is designed for this exact case.

Shortcuts writing on load

When profiling kglobalaccel5 we found it spent a lot of time writing entries on boot, which is a clear sign of something being wrong. The cause was quite complex. Powerdevil would report that the user visible name of the executable (kded) was “Powerdevil”. KScreen would load and report that the username of the executable (also kded) was “kded” this would cause the shortcut daemon to think locales had changed and forcibly reload and save everything.

Summary

Startup is an area that is being improved and we have tonnes of ideas left of things to do, but because it’s dealing with unpredictable 3rd parties it’s an area which requires 90% reading and 10% coding.

If you do have an excessively long boot time, please do try creating a boot chart as above, it will really help start to narrow down where we have problem. I hope to see some detailed reports on bugzilla soon.

Cross-process Runners

KRunner, the framework, is the backend behind the ‘krunner’ UI, as well as being used for search operations within the Plasma shell. Backends (or ‘runners’) are written as plugins, which can come from a range of sources and loaded by both the plasmashell and krunner process.

This works fine for simple tasks like calculators, dictionaries and listing applications. However, if we want to search through data that’s available in an already running application, this approach isn’t ideal.

What’s changing

In addition to the current plugin structure, runners can have their results fetched from another process via DBus.

To work, apps supply a .desktop file with the DBus service name of a search provider. The apps then implements a couple of DBus methods to return a list of matches for a given search query, and another method called when a match is invoked. Depending on the situation, you might want to make this DBus-activatable, or just silently do nothing if the service is not running.

Example of a query being performed:


Results are presented identically.

Benefits:

Reduce code re-implementations

The original motivation for writing this was plasma-browser-integration writing a runner. Kai ended up writing both a DBus API on the client, and a runner to read from it. A common standard cuts that in half for any future apps wanting runners.

Memory saving

Instead of data being in 3 places: the app with the data, plasma shell and krunner, data is only stored in one place and then fetched by the two UIs.

Robustness

Plasma shell is a very core process. We want that to stay alive even if the included plugins fail. One of our more problematic runners was moved out of process to solve this in Plasma/5.11

Portability

By not being linked inside the same binary, we solve a lot of portability issues.

* I can make runners in python (example) or potentially any other language with no extra dependencies

* We’ll be able to handle the ineviatible Qt6 changeover in a few years without runners having to all be ported at the same time.

This was a big problem for KTp, which had the main USP of having tight Plasma integration. We caused a big problem for ourselves resulting in a rushed port.

* It’s a step towards next gen where more apps and services are sandboxed.

Conclusion

Hopefully this will improve Plasma and make it easier to write runners.

I hope to see runner support to kde-connect and search active konversation tabs. Personally, I’m already using the python support for custom code to talk to my home-automation server which had a python lib.

If this has inspired you to write a runner and documentation is unclear, ping me (d_ed) on #plasma.

Plasma accessibility updates

Marco Martin recently posted about some of the improvements in krunner, today I want to show some of the effort into navigating the Plasma panels.

This video shows a user navigating the plasma panel using voice and keyboard. A shortcut focusses the panel, and then one can use tab and cursor keys as normal. In future we will improve our key-focus visual indicators, and allow for richer interaction.

What makes Plasma different to existing apps

Plasma in general has been a sore point with regards to accessibility as it doesn’t follow some of the exact same concepts as a traditional toolkit. Some of these convention breakages are by design, in krunner you wouldn’t want to have to tab to a list of results in order to navigate results with the cursor keys. Unfortunately these changes, if done non-optimally, really conflict with core concepts of focus and screen reader parsing. On top of that, we have the issues of an emerging toolkit, which needs that extra push to get right.

Why is this work useful?

Blind people aside, the work here has multiple other advantages.

We need better keyboard navigation, regardless. You often hear people say they prefer console apps; it’s not because they’re inherently better, but because being “handicapped” forces them to have good keyboard handling. We should be matching or beating that.

Also, approaching a large code base from a completely different angle has helped to tidy up some complex code that has built up over the years. Kickoff key handling is now not only better but the code is 2/3 the size.



SDDM v0.15.0

SDDM is a Qt based Display Manager used by multiple desktops, but most importantly (certainly for the PlanetKDE crowd), KDE.

After a year of seemingly little activity, I’ve released SDDM v0.15.0
It is mostly a bugfix release with important changes, but nothing to get particularly excited about.

For full release notes please see: https://github.com/sddm/sddm/wiki/0.15.0-Release-Announcement

Now this is out, I shall be merge a huge queue of pending larger changes – hopefully we shall see 0.16 in only a few months.

KWin Wayland Independent Monitor Scaling

We want:

  • Legacy apps at the same physical as modern apps that support high DPI
  • Apps and window decoration to work across multiple screens at different DPI
  • Consistent mouse speed and input across monitors of different DPI
  • What we want to see:
    What we want to see

    What we need to render
    What we need to render

    How it works:

    In order to have a normalised co-ordinate system between monitors and to support apps that can’t scale themselves the system is defined as follows:

    * KWin pretends all monitors are ~96dpi and handles all communication and input co-ordinates as such. Final output is then scaled up if applicable

    * Clients which support high DPI, when relevant, will provide a buffer (the picture of their contents) which is twice the resolution of their window size.

    This covers all the different scenarios:

    If we have a 1x window on a 2x screen, the compositor will draw the window twice the size.

    If we have a 2x window on a 1x screen, the window contents will be drawn implicitly downsized.

    If we have a 2x window on a 2x screen, the window will be drawn twice the size, but because it’s at twice the resolution, we end up painting the contents at the native resolution.

    Clients without scaling now work as intended, I can use ardour or xfig on my high DPI screen and can read and interact with it normally (albeit obviously at standard resolution)

    The mouse even moves at a consistent speed across monitors and even if you had two touch screens at different DPI showing the same content, both will work perfectly.

    The changes to kwin were therefore really small, and mostly was not about implementing features but more about removing an assumed coupling between a texture size and the rendered size.

    FAQ

    When?

    The code to do all of this is in Plasma 5.10 as a hidden feature whilst we get more testing with everything except a UI to configure it. This is ready to land for 5.11 An extra problem is that Qt < 5.9 has a bug if the screen scale changes dynamically.

    What’s left?

    Using this technique means everything is at the right size, but some adjustments are needed to make sure everything appears at native DPI not normal DPI. This is something being fixed over time.

    What about fractional scaling?

    The wayland protocol specifies a scaling in integers. We can’t really go against the protocol. However, there’s absolutely nothing against kwin scaling to a different amount to the protocol. It’s something we can expand on later.

    Dave’s QML Binding Loop Backtrace Printer

    Binding loops suck, and they can be hard to fix. I wrote a tool that prints a backtrace of the bindings being updated when a loop occurs. See link at bottom.

    About:

    QML bindings are a very fast and easy way to write a declarative UI. However it’s quite easy to accidentally write an infinite loop.
    This can happen if we bind propertyA to affect propertyB and also bind propertyB to affect propertyA, they would constantly update each other.

    Consider the following example:

    1 import QtQuick 2.0
    2 
    3 Rectangle {
    4     width: childrenRect.width
    5     Text {
    6        text: parent.width > 10 ? "Hello World" : "Hi"
    7     }
    8 }

    The Rectangle width changes on startup, that changes the text’s size, which in turn changes the Rectangle’s width. If this was undetected the application would loop forever and eventually crash.
    QML prints a warning, and ceases processing, but it’s an indication that something is wrong with the logic of your code, and it needs fixing.

    However, whilst the loop here is obvious to spot, it can be considerably more complicated when looping through tens of bindings over many many components.

    Creating a Tool

    The problem with this warning is that on its own is rather unhelpful – trying to find the loop then becomes a manual task of tracing all possible combinations through every bindings that could lead to a short circuit. GDB on its own doesn’t help as the C++ backtrace tells us absolutely nothing we can use.

    I’ve created a small script that, using gdb, unwinds the backtrace detecting where the properties changed and then showing the QML code which is responsible.

    Simply download here into $PATH and run with

    “binding-loop-tracker.py myAppName”

    In the case of the loop above we will see output like:

    =====Binding loop detected - printing backtrace =====
    #0 - file:///home/david/temp/binding_loop.qml:4:12
    #1 - file:///home/david/temp/binding_loop.qml:6:15
    #2 - file:///home/david/temp/binding_loop.qml:4:12
    

    Which shows which line of QML was being updated when we hit the loop.

    It still requires some manual work to follow the trace through, but it’s a useful aid and has already helped me in two real world cases that I couldn’t resolve manually.

    Building stable branches with kdesrc-build

    When coming up to a release it’s important to track the stable branch of a project so that we’re actually running what we’re going to release and can put our focus on fixing any remaining tiny bugs.

    If you build all of Plasma with kdesrc-build you can easily switching to building the stable release with the following command:

    kdesrc-build –Branch Plasma/5.7 kf5-workspace-modules

    To change back, simply emit the –Branch parameter.

    My Randa Plans

    The Randa meeting starts this week, and I’ll be working with the KDE multi-platform group, being led by Aleix Pol, and will be spending my time working on both flatpak (formerly xdg-app) and Snappy.

    During this past week I have been brought into some technical discussions about deployment on both platforms; so I intend to spend my time working closely with other interested developers solving problems that affect either platform as there is a lot of overlap. Tackling these independently doesn’t make sense.

    These two emerging technologies both have a lot of potential to revolutionise Linux packaging and distribution with either being a huge boost over the current state.
    Both are going to become relevant in the Linux world over the next few years, and the important thing is making sure our software works best for our users whatever the platform.

    So far over this week I’ve spent some time fixing KDE flatpak applications, in particular fixing multiple problems we’ve encountered with Dolphin; namely being able to load plugins and making kio slaves work.

    In the meantime I’ve been testing out packaging some Snappy apps, packaging and running a few applications.

    Over the week I’ll write some more in depth blog posts, exploring the state of each, where we have problems deploying our apps, and hopefully some concrete solutions 🙂

    Be sure to sponsor the sprint to help pay for developers from around the world to come together to work on important projects and be sure to follow PlanetKDE for blog posts about software developments from the people here.

    PlasmaShell Sans GL

    Since Plasma 5, the main shell is powered by QtQuick, which till now brings a requirement on a working OpenGL setup. This causes problems for Plasma in situations where we can’t run OpenGL; either extremely cheap hardware, xrdc or when a user upgrades and breaks their nvidia setup (a seemingly common occurence).

    Qt 5.6 brings a new module which opens some interesting possibilities; the QtQuick 2D renderer, which avoids that.
    This has existed for a while, but it has only recently been open sourced as GPL3.

    QtQuick Internals

    QtQuick is powered by a scenegraph.

    Each graphical item updates a tree containing nodes containing either transformations or content. That content being either a rectangle, a picture or a custom openGL shader from the application. The important part is that it stores a tree of items in an way optimised for rendering, but also acts somewhat as an layer between any QtQuick component and the underlying OpenGL renderer.

    Using the QtQuick 2D renderer

    The QtQuick 2D renderer still uses the same scenegraph, so all custom QQuickItem’s which use the standard QtQuick SceneGraph nodes still work, but instead of calling OpenGL functions, calls are mapped to a raster backend instead.

    The Result

    My personal desktop, running Plasma using the QtQuick 2D renderer. The screenshot shows some of the parts working, but also highlights some of the bugs

    Performance is surprisingly fast, not faster than the OpenGL backend, but plasmashell still remains perfectly usable on my desktop.

    Most of the basic scene graph nodes have a 2d renderer implementation, however any node that does custom openGL, such as QtGraphicalEffects or certain parts of Plasma, will simply fail.

    What’s broken

    There are plenty of known limitations with using the 2D renderer, some cosmetic, some more fundametnal.
    Qt provides their own list.

    In terms of Plasma, the list of broken items are:

    • We have our own GL check in the shell that needs adapting
    • Icons were broken. We implemented our own shader whilst animating between states rather than uploading a new pixmap per frame. I fixed this by simply turning that off.
    • Our load monitor plasmoids are pure GL. I’ve made a patch that makes it not crash. Making it actually work would mean having two implementations…which isn’t a route I really want to go down.
    • Widget explorer is broken, again we have our own shader for some effects
    • We are missing a lot of minor graphical effects. Fewer shadows and alike, but that’s a hit I think we will just have to accept

    Summary

    In general it seems that with a relatively small amount of work this might be a valid option for users without working openGL.

    It will always be a second class citizen, but it should be do-able to support without hindering progress for the vast majority of users.

    What’s interesting is to see how easy it is to support a different scene graph backend, as it is a clear indication of what we will encounter when it comes to Vulcan in a few years time.