Never forget your users or extending the User Actions Menu by KWin Scripts

KWin’s userbase is quite diverse. We have users being in the range from the absolute Computer beginner to the Kernel hacker. Such a diverese user base can be quite challenging for the development. On the one hand you need to keep the UI as simple as possible so that even not so experienced users can use the computer without problems. On the other hand you should not dumb down the application to not upset your very vocal Kernel hackers. There is always the tempation to have the user interface too complex given that one as a developer is an advanced user and does not really see the needs of a normal user.

In the case of KWin we are in the lucky (or unlucky) situation that our target user group should not even know that an application called “KWin” exists. The only user visible place where the name “KWin” is written is the crash dialog – and I do hope that a normal user never sees that one ­čśë Of course that means that we never get bug reports or feature suggestions from “normal” users. This means we have to look at each suggested feature and each extension with the thought about our primary user group. In our mission statement we clearly define that KWin should go out of the way and the user should not notice that there is a window manager. This is something to keep always in ones mind.

But nevertheless we have and want to have advanced features. In the mission statement it’s written down that KWin provides a steep learning curve for advanced features. Think for example about things like window specific rules which are not really easy to define whithout understanding of window management.

From time to time it happens that features for advanced users are in direct conflict with our goals and what our primary user group needs. An example for that is the menu to change the window’s opacity in the window decoration menu. To be honest: it’s a quite geeky feature and soooo 200* (look what we can do: translucent windows!). It’s almost an embarrassing feature as it changes the complete window to being translucent instead of adjusting just the background. Not only is this feature quite geeky, it also clutters an already cluttered menu even more.

Based on that the menu got removed after some discussion a few releases ago, but we acknowledged the need of the experienced users and added shortcuts and mouse action support to the window decoration for changing the opacity. So we removed one way at a user visible place and replaced it with several ways to alter the opacity.

Nevertheless over the time I have seen a few complaints about the removal of the feature and it made me think what we can do about it. Of course we don’t want to bring it back, but we also don’t want to anger our advanced users. Since 4.9 we have the wonderful possibility to have scripts and so I decided to extend the scripting support to allow adding entries to it from scripts.

This means since todays git master you can execute the following script to get your Window Opacity menu back:

registerUserActionsMenu(function (client) {
  var opacity = Math.round(client.opacity*100);
  return {
    text: "Window Opacity",
    items: [{
      text: "100 %",
      checkable: true,
      checked: opacity == 100,
      triggered: function () {
 	        client.opacity = 1.0;
      }
    }, {
      text: "75 %",
      checkable: true,
      checked: opacity == 75,
      triggered: function () {
	         client.opacity = 0.75;
      }
    }, {
      text: "50 %",
      checkable: true,
      checked: opacity == 50,
      triggered: function () {
	        client.opacity = 0.5;
      }
    }, {
      text: "25 %",
      checkable: true,
      checked: opacity == 25,
      triggered: function () {
	         client.opacity = 0.25;
      }
    }, {
      text: "10 %",
      checkable: true,
      checked: opacity == 10,
      triggered: function () {
	         client.opacity = 0.1;
      }
    }
    ]
  };
})

I intend to make this script part of 4.10, but before I can do so we need i18n support inside the scripts or the titles of the menus cannot be translated.

Enabling Others to do Awesome

Recently Aaron wrote a blog series for the introduction of Spark, I want to cite a central saying of one post:

I want the things which I help make to become opportunities for others in their turn to participate with their own voice, their own movement and their own passion.

If I reflect my own motivation for my work on KWin and especially the areas of work I decided to work on in the 4.9 cycle I see quite some parallels to the paragraph cited above. But personally I would phrase it slightly different:

I want to help others to do awesome.

This describes perfectly what I am currently working on. I no longer want to write fancy effects – in fact I stopped adding effects quite some time ago. I don’t want to extend KWin to be the window manager which incorporates all other window manager concepts no matter how useful they are – we stopped doing that as well.

But still I want that our users get the window manager they want. Whether it is fancy effects or a tiling window manager or new concepts for virtual desktops, KWin should be the base for it.

At the heart of all these efforts we have the scripting bindings. While we already had bindings since 4.6 they never really got used – this will change ­čÖé But JavaScript bindings is just one part of the game, the other part is declarative, that is QML, bindings.

In 4.8 we already experimented with QML for the window switcher layouts to test whether QML fits our needs and I am very happy so far with it. But 4.8 does not yet include the possibility to really write own layouts. While it is possible to do so, there is no way to configure a custom one or even distribute this.

For 4.9 the installation of the window switcher has been adjusted to use the Plasma Package structure which makes it possible to install window switcher through the plasmapkg tool. But this is only part of it: plasmapkg has been extended to support any kind of scriptable KWin content, be it window switchers, KWin scripts or KWin effects written in JavaScript (decoration to be added soon).

For this KWin scripts follow also the Plasma Package structure which is quite awesome as it finally allows to dynamically enable/disable scripts through our KCM:

This dialog wants to tell me: “I want Get Hot New Stuff integration” to directly download new scripts from the Internet. And sure it does need that and this will be added for the 4.9 release.

The screenshot shows two scripts I’m currently working on – both will be shipped with KWin in 4.9. Videowall is a script which scales fullscreen video players over all attached screens to generate a video wall. This is the first script which actually replaces functionality from KWin core. KWin had the functionality to disable multiscreen support for fullscreen windows and that really cluttered both code and UI. And it just did not make any sense. There are just no valid usecases to have in general fullscreen windows┬áspan all screens, except for video walls. And that’s what we have here: a small KWin script to make an obsoleted functionality sane. We improved KWin for everyone by removing an difficult and confusing control module without taking away the functionality for expert users.

But even more interesting than the video wall is the other script. This is not a JavaScript based KWin script, but a declarative QML script. It will replace the existing C++ based implementation of the┬ádesktop change OSD without any functionality loss. Which means less code and much more readable code ­čÖé

And what’s really awesome: JavaScript and QML have the same bindings, the API is exactly the same. So going from QML to JavaScript and vice versa is extremely simple. But that’s not all with QML based KWin scripts you can include live window thumbnails. So this is a technology to allow you to do awesome new switchers like Present Windows or Desktop Grid.

As you notice I’m currently dogfooding the bindings to myself. This helps me to see what is needed, what can be improved and to ensure that the bindings will work for any given usecase we can imagine. My wish is to see for example the complete window tiling support in KWin to be rewritten as a KWin script. This should be possible and would proof that you can use scripting to get a completely different window management.

So if you want to make awesome things with your window manager, now is the time to get started. Don’t hesitate to contact me and demand further bindings if anything is missing.

Disclaimer: QML support has not yet been merged into master.

KWin Effects written in JavaScript

Today I cannot make such a nice announcement as Aaron yesterday, but I can at least try announce something I personally consider as awesome.

This weekend I tried to make it possible to write KWin effects in JavaScript. After about two hours of work the effect loader was adjusted to load a Qt script instead of the library written in C++. This is a quite important step for the future of effects in KWin. It finally makes it possible to share effects via Get Hot New Stuff, so that our users can download new effects directly from the control module.

For packaging effects we use the well established Plasma Package structure, so that our script developers only need to know this one common way. The API itself will share as much as possible with the KWin scripting API – of course with adjustments for effects. For animating the API is based on the AnimationEffect introduced in 4.8.

From a performance point of view using JavaScript does not change anything. Our effect system has two phases: one to react on changes in the window manager (e.g. a window got activated) and one to perform the rendering. The scripting API only interacts with the window manager, so all the rendering is still good old C++ code – a similar approach to QML.

Now I guess you want to know what you can do with it. So here I present for example a Fade like effect written in JavaScript (for comparison: C++ version is > 200 SLOC):

var duration = 250;
effects.windowAdded.connect(function(w) {
    effect.animate(w, Effect.Opacity, duration, 1.0);
});
effects.windowClosed.connect(function(w) {
    effect.animate(w, Effect.Opacity, duration, 0.0, 1.0);
});

For us KWin core developers the scripted effects will be an important step as well. For quite some time we have been unhappy with the fact that there are too many effects which become difficult to maintain – especially if we have to adjust the API. With effects written in JavaScript this becomes much simpler. As we do not have to keep the ABI (API compatibility is enough) stable we can move effects written in JavaScript out of the source tree and make them available for download.

At the moment the JavaScript API is just at the beginning. But I expect it to evolve over the course of the current release cycle. For me the scripts are rather important as it also provides us an easy way to have device specific adjustments.

As I wrote currently the scripts do not operate during the rendering. Because of that we don’t have bindings for WebGL. This would at the moment not make any sense. Nevertheless it might be that we allow to upload custom shaders, but I won’t pursue such a task in the 4.9 cycle.

Create Temporary Desktops For Applications

There are applications which are more or less a mess for a window manager. For example The GIMP opens quite a lot of windows and you want to have all of those windows visible. In general you don’t want to have any other window on the same desktop

The solution to that is to move GIMP on it’s own desktop. But how? We can use static window rules to get this working, but what if there are already windows on that desktop? The perfect solution to that would be to have a desktop which gets created when you open GIMP and gets removed again when GIMP closes.

This was so far not yet possible without manual interaction. But with todays additions to KWin scripting this became possible. Here I present a KWin script which does exactly that:

workspace.clientAdded.connect(function(client) {
  if (client.resourceClass == "gimp-2.6" && client.windowRole == "gimp-image-window") {
    // create a new workspace for the Gimp image window (kind of the main window)
    // switch to the new desktop and send the gimp window to it
    workspace.desktops = workspace.desktops+1;
    workspace.currentDesktop = workspace.desktops;
    client.desktop = workspace.currentDesktop;
  } else if (client.resourceClass == "gimp-2.6") {
    // send all other gimp windows to the current desktop
    client.desktop = workspace.currentDesktop;
  }
});

workspace.clientRemoved.connect(function(client) {
  if (client.resourceClass == "gimp-2.6" && client.windowRole == "gimp-image-window") {
    // when closing the gimp window let's remove the last desktop
    workspace.desktops = workspace.desktops-1;
  }
});

I should really start to publish the quite useful example scripts I write to test the scripting functionality on places like kde-apps ­čÖé The API for 4.9 is documented on Techbase

What’s new in KWin Scripting?

First of all a happy and successful 2012 to everyone. Let’s work together to make this year a great success for KDE!

One of the big topics in 2012 for my development efforts in KWin will be JavaScript bindings and QML. This is a technology which will allow our users to build their own custom window manager giving even greater power to our static window rules as before. It will also reduce our maintenance need when major parts of our UI can be transitioned to either QML or JavaScript.

The work on this area has already started and the first code set has been merged into master (aka 4.9). The old scripting API had manually crafted bindings for around 30 properties for windows. Now the API is generated and everything that is available for effects is also exported to JavaScript, which means more than 60 properties, more properties than before are writable and many more signals are available. Interestingly I could drop several hundreds lines of code by exporting more properties and the code becomes cleaner and better documented. These are changes I really like ­čÖé

The API documentation of KWin scripting is now auto-generated through Doxygen and already imported to techbase together with detailed Update Notes on what changed. If you run master and use KWin scripting be aware that you have to adjust the script. Exactly the same API will be available in QML and also the Effects API is very close – given that the property names are inspired by the Effects API.

One of my favorite changes is that our Plasma Desktop Console is now able to execute KWin Scripts:
Plasma Desktop Console executing a KWin script

To open just use KRunner and type the new keyword “wm console” or start the desktop console and switch using the toolbar button.

This is a very important change for me during development as I can easily test whether my scripts are correct and most important my implementation. But also for users it means that scripts can be tried at runtime and don’t require a KWin restart any more. So adjusting the runtime behavior becomes possible.

So what’s next? I am currently with the progress quite satisfied with the work done so far on scripting and will now concentrate on two other areas first: getting my unmerged kickoff-qml and screenlocker branch into master. Both require still a little bit of work. After that scripting and QML get my number one priority again.