 of hands. Who have you ever launched an application? Well, I don't actually see the results, but that doesn't really matter because I think all of you have raised their hands. And you are probably thinking about a different kind of launching. Now, imagine your application developer and one day you wake up and decide, I really want to write a chat application today. Then you get hacking and at some point you get to the feature where your user can send files to each other. And when you have one of those files in your timeline and you click on it, you want that file to be opened. And now you have to implement that. That's easy, right? Let's imagine for a moment for the sake of simplicity that the file we want to open is an image file. Image files should, of course, be opened in VenView. What else would you use for that? So what you would do on a terminal is just type in VenView, press enter, and then VenView opens. Success. You can replicate that just by doing Q process and then passing VenView as the executable name. And then when you do that and call process.start, then you have a VenView instance open. But wait, we didn't just want to open VenView. We wanted to open VenView with a particular file which you have in the form of a URL to somewhere on your disk. You can achieve that just by adding URL as an argument. So you augment your call to Q process by passing this URL as argument, then so called start, and then VenView starts with that image. There's one minorish problem with that, which is when you close your chat application, then suddenly VenView closes too, which is kind of unexpected from a user point of view because as far as they are concerned, VenView and your chat app are different applications. The reason this happens is because you start at VenView from your application, then VenView sort of becomes a child process of that application and when the application process ends, it takes all of the child processes with it. That's easy enough to fix. You just need to replace process.start with process.start detached. That thing doesn't happen anymore. So now you would think your code is working fine. What else could there be to be fixed or improved? And that sort of code is something that comes up quite often in KDE and other code bases. But during this talk, I want to show you all of the minor and subtle and not so subtle ways in which this code is actually not ideal and needs to be fixed. First of all, what we're doing right now assumes that there is an executable called VenView somewhere in your path. And that assumption is, for example, broken if VenView is shipped as a Flatpak application because in that case, there is no executable called VenView in your path. Instead, what you call is the Flatpak executable with some magic command line arguments that tell you, please run VenView. So we need to sort of shift our mental model of thinking how we launch applications away from specific executables or commands towards launching desktop files. If you're a Linux, if you've been a Linux user for a while, you probably have some idea what a desktop file is. But just as a pre-freecap, it's a text file consisting of key value pairs that sort of describe application metadata. And if those desktop files are placed on a particular location on your disk, then that application will show up in the start menu. The metadata is stuff like the application name, a description, an icon, that sort of thing. And most importantly here, there is a line called exec, which describes exactly how that application is launched. For simple cases like a traditional distro shipped VenView that exec line is rather simple, it's just VenView and then in present view. What that means, I will get to in a bit. For the Flatpak case, it's a bit more complicated because you have this very elaborate commands, but basically it does the same thing. It opens VenView, and it also has this present view placeholder. And a desktop file has a particular name, so for VenView that would be, for example, org.kde.venview.desktop. And so we would say org.kde.venview is this application's desktop file name or desktop entry name. So what does this person view mean? As I've mentioned, we want to not just open VenView, but we actually want to open a file with it. And this open a file with it part is where these placeholders come in. Because if something is launching that desktop file with another file, then this placeholder gets replaced by a reference to what we want to open. So for example, if we have a percent lowercasef as a placeholder, then we want to pass a single file path. With percent uppercasef, we can pass multiple file paths. With a lowercase person view, we pass a URL. And with an uppercase person view, we can pass multiple URLs. The difference between file and URL here is that with file, we have a path like home, Nico documents my image. And with URLs, we have the file colon slash slash slash home user, blah, blah, blah. So we have a proper URL instead of just a path. Now, how do we deal with all of that in KDE code? And for this, we have a framework like Adrian used to say in one of his Academy talks, there's a framework for that, which is called KService here. A KService object is something that parses and encapsulates a particular desktop file. And we can get a handle to a KService for when you by calling KService service by desktop name, and then the desktop name for when you, which is or KDE that when you, once we have that service, we can ask it stuff like, what is your name? What is your description? And here, most importantly, what's your exact line? Once we've got that exact line, we need to replace those placeholders like replace person you with file path person replace person replace person you with your L replace person F file path. And then we get the command we want to launch that we then can feed into Q process. There's a slide gotcha in there because we can just split the command at every space because we need to take into account stuff like quoting, because sometimes you want to pass a string that contains spaces as one argument, you do that by quoting and to sort of process that quoting, we can use K shell split arcs, which gives us the arguments and executable properly split it so we can pass that directly into Q process. That's already a huge improvement of what we had earlier, but it's still not enough. What if the user doesn't like then view? I know the thought of it is absurd, but can imagine some people might want to use this new cocoa image to you that we're developing in plasma mobile. So the bigger question is how do we find out what the user's preferred image viewer is or preferred application for for any type in general. Fortunately, there's an xdg specification for that, which is called association between mind times and applications. And what this defines is config files that describe which applications can open which files and which application is to be preferred for any given file type. Which config file is that? Well, all of those. Obviously, you don't want to read all of those config files yourselves, because those can amount to quite a lot if you take into account all of the xdg config in data tiers. So nobody wants to do that by hand. Fortunately, again, there's a framework for that. It's again case service in form of the K application trader class. K application trader does all of this logic of parsing those config files and figuring out which file should be open with which application and you can ask for that. So if you want to know what is the preferred application for open PNG files, then you call K application trader preferred service with image slash PNG. And that gives you a case service pointer to the application that you should use. If you want to know all of the applications that can open in this particular file type, then you can use query by mime type, which gives you a list of all of the applications that can open PNG files sorted by their preference. You can optionally also pass a filter function to do some more elaborate filtering. So for example, when you're inside then view, and you want to open the want to offer the user to open the file in another application, you don't want to offer them opening then view again, because that would be kind of silly. So you can do basically arbitrary filtering there. Then another topic that isn't working properly with our current setup is window activation. So imagine you have a link in your chat application that somebody sent you and you click on that link. Then you of course want that link to be opened in your default browser. But most of the time what happens is you don't get a new browser window for every time you click on a link. Instead, what happens is you get any a new tab with your link in the existing browser window. That's just sort of the behavior everyone expects nowadays. And an important part of this is when your browser window is somewhere deep and hidden behind other windows, you want that browser window to be brought to the front so you actually see what's going on. On Wayland, there's a problem with that because windows like the browser can't just say, hey, I want to be on the top now, because that just doesn't happen. There's no applications just can't do that on Wayland. So there needs to be a special way to address that. On X11, they sort of can't say that except they can't really because like every X11 window manager has a thing called focus stealing protection, which aims to make sure that no application can just jump in your focus and steal all of your attention and all of your input. So both on Wayland and on X11, we need some kind of solution for that. On Wayland, that is exigee activation. That's the protocol that Aleish talked earlier today in his Wayland talk, and it works roughly like that. Some client in our case, the chat application goes to the compositor like Quinn, for example, and asks the compositor, hey, I want to launch something, please give me a token. Then the compositor checks, is this application even allowed to do that? And to do that, to check that it checks stuff like, is the chat window the currently focused window? Because you can't pass focus to something else if you don't have focus yourself. When Quinn will see, okay, the chat application is focused, everything looks legit, here's a token. Then the chat application takes this token, gives it to the browser application in some way. And then the browser application takes the token, gives to Quinn and says, hey, I would like to be raised on top, here's a token that proves I'm allowed to do that. And then Quinn will happily do that. That works nowadays. There's a very similar mechanism on X11 too. But it's something that you actively need to take into account when launching in your application. Something else you need to take into account is C groups. C groups are amazing for many things. At Academy 2020, David and Benjamin had a talk about why C groups make everything amazing. I can only recommend watching that. The important thing here is when we launch an application, then applications should be launched into the appropriate C groups, otherwise stuff like displaying them and plasma system monitor is broken and suddenly your application is shown as a jail application of another application. So it's really important for different reasons that applications are launching the proper C group. And that involves talking to the C group controller at launch, which in our case is usually system D. So depending on some technicalities that can either mean launching something, then telling system D, hey, I just launched this thing, please put it into this C group. Or it can even go as far as say, hey, system D, please launch this thing in this C group for me. So again, something you probably didn't think of when it came to launching applications, but it's actually really important to get right. There's also the problem of Q or rather the problem of apps not understanding Q. I'm sure all of you are aware what Q is. It allows KDE applications to support a wide range of network protocols. The problem is when other applications don't understand them. So imagine you're in Dolphin on an SFTP share and you click on an image. Then what happens is when you get opened with an SFTP URL, when you understand SFTP because it's using Q and it can just open it fine. Now swap out when view for GNOME's image viewer, which doesn't understand Q, obviously. And suddenly you have a problem because you will pass the SFTP URL and will think, I don't know that protocol, I don't know how to open that, go away, which is of course not what the user expects. There's a solution for that for, there's been a solution for that for quite a while, which is called QXAC. It's a rather brute force approach to the problem. Whenever you're launching something from a KDE application, to a non-Q application, QXAC will just download the file for you, face it in a temporary location and pass a path to the temporary location to the other application. That kind of works for simple cases like small images, but it comes with some problems, for example, with larger files. For example, if you have a huge video file, you would download all of that file upfront and then pass it to the application instead of just giving the URL to the application and then the application can start streaming the file instead of downloading it all at once. There's a better solution that avoids these problems in a few years, which is called QFuse, which basically works by bridging Q to a sort of virtual file system that every application can understand because for them it just looks like a regular file. So that's also a lot of those problems, but it's again something that you explicitly need to do in the case of opening a non-Q application from a Q application. There's also Flatpacks, and Flatpacks have a rather limited view of the outside world, and most of the interaction that Flatpak applications do with the outside is done using portals. For example, most of what I've shown you today, like reading config files to figure out what application should be launched, doesn't work when your application is inside a Flatpak because you can't even read those config files to figure out what application you should use. So for the use case of opening a file or opening a URL, there are special portals, like the OpenURI or OpenFile portal, which you should use when running inside a Flatpak application to open stuff properly. It's also something you need to take into account when writing the application. So I've talked a lot about difficulties and challenges and things you need to do and probably don't want to do when writing your applications, but I promised you there is a solution for that. And when it comes to launching an application, this solution is KIO Application Launcher Job. So whenever you want to launch a particular application, say GrainView, you obtain a key service to that, either through explicitly acquiring it by name or by using KApplicationTrader or some other mechanism, then you can pass that to QApplicationLauncher Job. Optionally, you can pass some URLs with that that you want to open, like opening images in GrainView or open text files in Kate. Then you call start on the job and it does all of those things that I've just mentioned now and you don't have to worry about any of them. What you can also do is you can omit passing an application at all, just pass some URLs and then it will internally ask the user which application should I use to open this file, which comes in handy when you don't have any information about what application should actually be used. For opening URLs, there's a different tool called Open URL Job, but you can just pass any URL. Internally, it will determine what kind of URL is that, is it an HTTP URL, then open it in the browser, is it a local file, then you can open that, is it a remote file that we're opening in a non-KIO application, then it will do all of the KIO view stuff and once it has determined that, it will just fall back to or build on KIO application launcher job and also do all of those nice things and it also takes care of using the appropriate portal stuff when you're running inside a flatback. Then as a bit more low-level building block, there's a class called KIO command launcher job, which is handy when you don't want that abstraction of a desktop file in an exec line and instead you want to have very tight control over the arguments you pass. For example, Kate can do some argument dependent things differently and sometimes you need to take that and have some more control about things, but still benefit from some of the stuff like proper window activation and C-group stuff and that is where command launcher job comes in handy. It's from an API point of view a bit similar to Q-Process in the sense that you pass it a command like an executable and some arguments, but internally it does some of the stuff I mentioned like C-group integration, window activation, so whenever you're sort of calling a GUI application by command, then you should be using that. And then there's the case of wanting to write emails, like not in composing email and send it immediately, but open an email client to a specific address with a particular draft text and that's something you can do using the email client launcher job. You could achieve the same thing with using an open URL job and a mail to URL, but that's not super fun to use because you need to construct all of the mail to URL and get all of the arguments right. And with email client launcher job, you have dedicated API for all of those things. So you create an email client launcher job, you do things like set to on some address, you can set a subject, you can set attachments, and then it will do the thing. It also has the nice benefit that it papers over some quirks and different email applications. For example, Thunderbird doesn't allow you for security reasons to add attachments via a mail to URL, but there is a Thunderbird specific way to achieve this thing. And so as an application developer, you would have to special case Thunderbird to work around that and pay email client launcher job for you so that you as an application developer don't have to worry about that. So in summary, what have we learned today? We learned that launching applications is surprisingly hard and there's things that you need to do or expected to do or should do that you probably didn't know about and probably don't want to know about too much. But I've also shown you how you can use API from KDE frameworks like application launcher job, open URL job, command launcher job to make it all nice and easy and you don't have to worry about any of the details. So what's in the future? We still have some places in KDE code somewhere that don't do this correctly, like they use your overall Q process to call GUI application or they're using a tool invocation or they're doing something else entirely that doesn't respect any of what I just said and we need to fix those and use the proper API that I've just shown you. Also, most of what I've talked about today is quite Linux or BSD specific and doesn't really apply to Android or Windows or Mac OS, but we have some of the same problems there as well. And it could make a lot of sense to turn this currently very Linux specific things into a proper cross-platform abstraction because we have quite a few use cases where we have with data and application one, we need to launch application two with that data and currently we don't have a cross-platform way of doing that and having one could be really handy. So that's something that has come up in the past discussing stuff like KF6, but we haven't really done anything of that and doing it would be really worthwhile in my opinion. And with that, I thank you for your attention. I will be happy to answer any questions. Any questions to Nico? None in the room that I see. Let's see if online. No, no questions. So that was a perfect talk. Now everything is clear. Thank you very much, Nicolas.