Wednesday, March 11, 2026

Upgrading Quickbar from SFOS 3 to SFOS 5 #7

 It's been a while since the last post. Life can be hectic for many reasons; but there is _always_ time for SailfishOS development \o/ !

 So to come back on topic; we left the last post in the situation where basically we realized the sandboxing is rendering the current, i.e. at the time of writing, version of libcontentaction incompatible with it. This may sound as harsh news, but it is a consequence of moving towards a more user-controlled environment. Think about it, the control is moved from the system to the hands of the user. Isnt SFOS awesome? 

"Okay Tone, that is all great, but wtf are we supposed to do now? How the hell shall quickbar w0rk3z it's 4w3z0m3z  sk1lz0rz?"

Well, I tell you what. There is a few things to consider here. On SFOS, we have the opportunity to "publish" (if you pass me the term) an applicaton via two ways: one is the "classic" Jolla Harbour , the next one is the familiar OpenRepos . OpenRepos is the "far west", you could say, as it is a free hosted service (kindly provided by basil, you rock btw!), without prejudices and / or opinions on the content. Freely downloadable software, it's a ground of passion from people who like to develop for SFOS (amongs others).

So placing Quickbar on OpenRepos is not a challenge, per-se. And it has been done; which in turn has brought in many downloads (kudos!). This has been a "fallback" for up to SFOS3, when limitations from either bugs, or otherwise difficult integration "challenges" were hindering a quality result. However, this also "externalizes" the app from the "usual" user flow - i.e. download from _within_ the ecosystem, ie. from Jolla Harbor. This has been always a strategic decision (if you pass me the wording) for Quickbar; to be "easy" and feel "natural" to use for the user.

This means that accomodating the Harbour requirements (I prefer this word over "limitations" btw) will require compromises. But don't panic! Luckily the freedesktop foundation has a solution for us. Quoting:

interfaces should require that application is DBusActivatable, including the requirement that the application's desktop file is named using the D-Bus "reverse DNS" convention
What does this mean? It basically suggest that _all_ applications should implement the openApp-specific endpoints. There you go. A simple, UNIX-style solution. #melikes.

Let's see what the sailors think about this interface

Sailfish OS 4.5.0 and later support using org.freedesktop.Application D-Bus interface for opening files and activating windows. However, Sailfish’s implementation extends the specification in two important ways: Firstly, in addition to DBusActivatable=true key in Desktop Entry section, a prefixed custom X-DBusActivatable=true key is also supported. They behave identically. Secondly, Lipstick also supports using D-Bus bus name derived from X-Sailjail section instead of deriving it from the file name of the Desktop Entry file.
Ideally, libcontentaction would have support for this

So there it is, the sailors adhere to the standard. This is awesome for Quickbar. One aspect is, the implementation is not _required_. What this means, is that for those applications which do _not_ support the openApp endpoints, for Quickbar installed from Harbour, we wont be able to execute them. Unless, of course, there's a workaround :-). But we will see how to and more about this later. This btw is totally in line with the freedesktop initiative:

For instance, listing an interface here does not necessarily mean that this application implements that D-Bus interface or even that such a D-Bus interface exists.

Focussing on the change in question, at the moment, seems simple: Quickbar relies fully on libcontentaction to handle application dispatching (=launching). As libcontentaction however is lacking the support for the openApp (a PR is in the works), this is clearly not enough. So we need to add the handling for these DesktopFile entries into the application dispatcher logic.

The code from lancia/fondamonta/mdebotaexesync.cpp handles eventual DBus registrations (yes I know its messy blabla #sowhat); so that is the appropriate place for our code to handle the FreeDesktop spec:

            //Supporteia FreeDesktop DBusActivatable
            if (service == "" && tempDE->contains("Desktop Entry","DBusActivatable")) {
                if (tempDE->contains("X-Sailjail", "OrganizationName") && tempDE->contains("X-Sailjail", "ApplicationName")){
                    service = tempDE->contains("X-Sailjail", "OrganizationName") + QString(".") + tempDE->contains("X-Sailjail", "ApplicationName");
                } else  //Do a FreeDesktop spec
                    service = ennomFile.mid(0, ennomFile.indexOf(".desktop") - 1);
                path = service.replace(".", "/");
                method = path + ".openApp";
            }

this should cover most of the cases, where:

  • An app is DBusActivatable (as per FreeDesktop spec) 
  • An app has overridden the service name in the X-Sailjal/OrganizationName|ApplicationName settings
  • An app did not override the service name thus we expect the desktop file name to be taken for it. In this case, it will need to be a proper DNS entry name 

 There! That's it! :)

Now, of course this doesnt cover the cases of applications that do not implement hte DBusActivatable. These will still remain "unlaunchable" from Quickbar (as the sandboxing prevents it). For these, we need a workaround. Enter debota-tools ; a repository with convenient tools. The only way to work around the sandbox limitation is to leverage this repo to provide a simple DBus service via an rpm package (to be installed via developer mode previous user configuration).

Friday, March 6, 2026

Upgrading Quickbar from SFOS 3 to SFOS 5 #6

So, today morning I posted the link to my previous blog entry, and today we got a reply from the sailors! Pekka Vuorela was very quick in helping out. It's great to see that, despite the workload they most likely have on a day-to-day basis, the Sailors are still ready to help out when community members reach out! Kudos!

It seems however that the SailJail will pose quite an interesting challenge. Not only does it hide other applications to be visible from a given sandboxed app, it also allows access merely to files. If you look into libcontentaction's Exec action code, you will notice that at some point it validates the presence of invoker exe file, a helper executable to (you guessed) help launch (or re-launch) programs. Given invoker is not available from the SailJail, this part is skipped. The alternative is a fallback to glib's desktop utilities, which apparently also fail. The question is, why? Well, let's find out! One way to go for this is to install a debug version of glib, perhaps alongside Quickbar, with more debug logs. But there's a fancier way to do it, with the help of a tool called strace. So after installing strace from devel-su, we can launch Quickbar, and then in a root-ified terminal, do:

strace -p `pgrep debota`  -e trace=!ppoll,recvmsg,sendmsg

which will attach the strace to the Quickbar process. When we then proceed to attempt to launch, say, terminal, we will get:

newfstatat(AT_FDCWD, "/usr/bin/invoker", 0x7fcb73cb10, 0) = -1 ENOENT (Datei oder Verzeichnis nicht gefunden)
newfstatat(AT_FDCWD, "/usr/bin/invoker", 0x7fcb73cb10, 0) = -1 ENOENT (Datei oder Verzeichnis nicht gefunden)
faccessat(AT_FDCWD, "/usr/bin/fingerterm", X_OK) = -1 ENOENT (Datei oder Verzeichnis nicht gefunden)

and as can be seen, in the last entry, /usr/bin/fingerterm is not available to the sandboxed environment either.  And dumping the items available in the /usr/bin folder from Quickbar confirms there's nothing but the executable itself there:

[D] AppDispatcher::startCachedApp:74 - Listing items in /usr/bin
[D] AppDispatcher::startCachedApp:76 -  /usr/bin  "/usr/bin/harbour-debota"
[D] AppDispatcher::startCachedApp:78 - Listing items in /usr/bin -> DONE

So this is expected, kindof. The operating system itself is in constant development, and so far it has been "easy" to get things to run on it, without unnecessary patches (which I am personally very proud of). It's to be expected that, once the security gets tighter, there will be less things that can be done. Pekka suggested to drop the SailJail, but that would exclude Quickbar from the harbour, which is not really ideal in my opinion. One is to wonder how apps in the sandbox can open other files; as the same mechanism (dropping SailJail) cannot be applied to all applications - it would just simply be counter-productive.  So, there must be some other way to launch apps. The main inter-process communication mechanism on SFOS is DBus. And in fact, lipstick, the main compositor on SFOS, has an endpoint to launch apps:

method void local.Lipstick.WindowModel.launchProcess(QString binaryName)

however, it requires privileged permissions for the client application in order to be used.
This can be seen as very "hostile", but in reality is very important. In fact, it keeps the control of what is to be done with the system to the user. A user can do whatever, as root; however, unless it's the user itself acting, nothing should really happen.

So we have seen today that SFOS is tightening the security. Which is a good thing, albeit it becomes an interesting conundrum for me :).
Well, not much that can be done about this at this point in time; so let's continue without SailJail for now!

Another "breaking" change I noticed; all android apps have relocated to the user's own applications folder (under $HOME/.local). This is not a problem per-se, as we can just consider the specific directory for it. However, as we know, SFOS has transitioned from the "user" username, to "defaultuser" at some point in time. So we need to make sure we consider both locations; by only looking at the relevant one. We can decide that based on the existence of the /home/user folder, simple kludge for now, we'll #fixitlater kthxbye (onte to self: dont be too angry about this when you fix it :-) ).

After adding this, Android apps re-appear! Nice!

However, it seems the naming search is not 100% accurate and leaves out most of the entries.  Also, not all app's launches are correctly detected (for example the Messaging app).