This is an old revision of the document!
Xfce Session Management Thoughts
This is a vague not-even-draft document describing how session management will work in Xfce 4.8 (or 4.10 if I don't have enough time). I'm sure it will undergo a lot of changes before the implementation is finished, so don't assume anything in this document will remain the same.
To give credit where it's due, a decent amount of this is based on GNOME's next-gen session management.
Currently, session data is stored in an ini-type key-value file in
- A single file means less disk access/stats/opens/closes.
- It's easy to clear the session if all else fails; just delete the file (or wipe the entire dir).
- Very poor integration with XDG autostart.
- File is annoying to edit when removing or adding a single app from/to the session (either manually or programmatically).
- Apps can't easily add themselves to the session at install-time for critical system services (example: annoying fiasco for 4.6.0 with getting xfce4-session-helper into the session automatically so SmRestartImmediately will work; this still doesn't work right).
There are probably more good and bad points with this.
Store session data in .desktop files, one file per app in the session. These .desktop files could be stored in the XDG autostart dir, or in a dedicated directory, and would have extension keys for storing session-management-specific data.
Pros for using XDG autostart's dir:
- Single place (er, “single” places) to look for “stuff that starts when I log in.”
- Easy integration with the autostart editor.
- Third-party autostart editing tools would be able to see our stuff too.
Cons for using XDG autostart's dir:
- This is somewhat abusing the XDG autostart spec. We'd end up either setting
NoDisplay=trueto keep anyone else from seeing it, or (more likely) using
OnlyShowIn=XFCE;to achieve the same result. But still, it's a little nasty.
- Third-party tools might wipe out our session-management-specific keys upon editing them, if they're not written in a sane way. This is a minor consideration, I think.
- It's more difficult to clear the session, both manually and programmatically. Instead of just deleting a file or directory, you have to check each file to see if it's a plain-vanilla XDG autostart file, or if it's part of a saved session. This also raises the question of what a “session removal” really is: is it just removing apps restored by the session manager, or does it also mean clearing out all XDG autostart files, even those created by the user or auto-created by some random app?
- Using the XDG autostart dir makes having more than one saved session difficult (well, not too difficult: you just have an extra key in the file with the session name; but of course this makes the previous point more complicated, and makes the point about third-party tools fail completely, since they'll likely show all apps from all sessions). However, I've often thought having multiple sessions is a rarely-used feature that just bloats xfce4-session, complicates the code, and is confusing to end-users so I'd consider removing it.
I'm currently leaning toward storing these in the XDG autostart directory.
Desktop File Keys
To segregate stuff, I'd probably use an extra group in the file, something like:
… and then keys wouldn't have to have ugly
X-XfceSM- prefixes (the XDG desktop entry spec allows custom keys to avoid using a prefix if they are placed in a custom group that starts with
X-ProductName). So we'd do something like this:
Name=Xfce Desktop Manager
RestartCommand=xfdesktop –sm-client-id abcdefg-0123456789
I'll note that I'm not including all the things here that xfce4-session currently saves in its session file. I might change my mind about this later, but:
Hostname: currently the ability to restart a client on another host doesn't work in xfce4-session, as far as I can tell. I'm not sure how this would work (securely) in practice anyway. At any rate, we ship xfce4-session with TCP support disabled by default, so clients wouldn't be connecting from other hosts anyway. If support for this is added in the future, it's easy to add this key at runtime the next time the session is saved. Current .desktop files that don't have the key will default it to localhost.
CloneCommand: since this property isn't used to initially start the application, it doesn't need to be known at session start time. The client will set the property after connecting to the session manager if it cares to. In practice, this property is never really used anyway, even though the XSMP spec requires it.
DiscardCommand: similar to CloneCommand, this property isn't required to initially start the application, and the client will set it on startup if it cares to. : but what happens if the client fails to start, or fails to connect to the session manager, and we later want to remove the app from the session somehow? We'll need the DiscardCommand then, won't we?
Program: isn't needed to start the app, and the app should set it after connecting to the SM. : this key might be useful for some kind of matching at some point, so maybe we might want to save it.
UserId: how would an app get restarted under a different user account anyway? Would we possibly want to hook into PolicyKit and some sort of su/sudo mechanism to allow starting as a different user? I'm not sure about this; probably not.
There are a number of improvements that this approach will bring:
- The aforementioned issue with apps being unable to automatically add themselves to the session at install time goes away. All they need to do is drop a .desktop file with the custom keys into the system autostart directory.
- Each app is stored in its own file, so adding and removing single apps from the session at once is trivial.
Value of the Name Key
Name key in the desktop file would provide a user-readable name for the application. This is useful in a session editor (which ends up being the autostart editor). For autostart/session files installed by the application, this is already taken care of for us, and the names are even probably localized for us.
But for apps started by the user that get saved in the session, how do we figure out a useful value to put in the
- Use the value of the SmProgram XSMP property if present.
- Dig around in the system and user .desktop file directories (
$XDG_DATA_DIRS/applications) and try to find an application with a matching
Execkey (or at least one with the same argv), and use the (probably localized)
Namekey from there.
- When the session is saved, find the WM_CLIENT_LEADER window and take its _NET_WM_NAME property. This is also beneficial to allow the user to uniquely identify each entry if several copies of the same app are saved to the session. Usually this value will be localized as well.
The third option seems ideal, though for many apps it might be odd (for example, currently my web browser's title bar says “dev:session-management [Xfce wiki] - Mozilla Firefox”, which is a little unfriendly). The second option is better for usability than the first option (apps could put strings in the SmProgram field that aren't intended to be user-visible), but might be slow given the number of files on the filesystem that might need to be inspected. Also I believe the SmProgram field is optional.
It's possible that SmProgram won't be set, and no matching .desktop file can be found. The _NET_WM_NAME method will be the only option in that case. I'm thinking the _NET_WM_NAME option might be our first choice, anyway, so the other options wouldn't need to be implemented at all (I'd be very surprised to see an app not name its client leader window).
Integration With XDG Autostart
We get some nice autostart integration “for free” with this. If we use the XDG autostart dir to store the session .desktop files, effectively all session-managed apps are just a superset of autostarted apps. The code in xfce4-session can be simplified because it only deals with one data source.
There are a few important details that need to be handled in a special manner.
Apps may be added to the XDG autostart directory manually by the user (using the autostart editor or by creating files), or by applications themselves, or by some other unknown means that doesn't know about the XfceSM-specific keys. While these apps will still start properly, it's possible that they also have support for XSMP. In that case, they will connect to the session manager, and, if the user saves the session later, there is the potential for saving a new copy of the .desktop file. If this happens, the next time the user logs in, two instances of the application will be started.
So, how do we “match” .desktop files with clients when the connect to the SM?
- If the client is already in the session, obviously we can match the ClientId key with the client ID they use to register.
- If the client sets the SmProcessId property after connecting to the SM, we can match it with the PID we observed being created when we launched the app.
- If the application supports startup notification, we can generate a DESKTOP_STARTUP_ID to put in the app's environment before starting it. When the app completes its startup, we'll know how to match the app with its WM_CLIENT_LEADER window. After it connects to the SM, we can check for the SM_CLIENT_ID property on this window.
None of this is perfect. Apps that are already in the session aren't an issue. Not all apps set the SmProcessId property. Not all apps support startup notification. But we can hope that the set of apps that:
- Use XSMP,
- Don't set the SmProcessId property, and
- Don't support startup notification
… is a very small set (or, if we're lucky, an empty set). And if that set is small, we stand a chance of bugging the developers of those apps to fix their behavior.
Intentional Multiple Copies
Sometimes we actually do want multiple copies of an app in the session. Say we have a text editor that opens documents in different processes, or something like that. If you have 5 documents open, and you save your session, you're going to want all 5 documents opened in 5 copies of the app when your session gets restored.
One of the main issues with this is .desktop file naming. The naive method would be to create the desktop-file-id by taking and munging the
Exec key in some way, or by taking the
Name key, lowercasing it, and substituting dashes for spaces. If there are multiple copies of the app, this breaks. I suppose we can just append a sequential identifier to the end of each desktop-file-id, but that sounds wrong to me for some reason.
Is there any situation where the user would want one copy of the app in autostart (but not session managed), and another copy of the app session managed? I don't think so… I'm not even sure how that would work in practice (unless the app has some sort of –dont-connect-to-the-sm startup switch, which would strike me as very odd).
GNOME's new session management flow drops the concept of integer priority values and simplifies it down to a series of five startup phases. Four of the phases include various usually-required core desktop applications, while the last phase includes pretty much anything else.
While this approach does have its merits, I'd like to stick with the numerical priority values for now. If needed, we can define phases by convention (e.g., prio < 10 means init phase, prio < 20 means WM phase, etc.).
Random unrelated note: the panel should have a lower priority value so it starts in the group prior to xfdesktop. This way it'll set its struts before xfdesktop starts, which means xfdesktop won't have to redraw itself after _NET_WORKAREA changes.
This also has the benefit of not making fundamental protocol changes. So far I haven't suggested anything that's “incompatible” with XSMP as we know it, but doing the phase thing would change how things work quite a bit and would only work properly for Xfce apps.
Client Interaction on Startup
Ok, since that I just said I haven't talked about making any fundamental changes, I'll suggest one now.
As mentioned, GNOME's new SM flow defines five startup phases. The fifth startup phase, the Application phase, is somewhat special. For the first four phases, the standard SM practice of waiting for each app to connect to the SM before moving on is still in effect. However, for the Application phase, the SM doesn't really care if the app connects to it at all. Effectively, immediately after the SM has fork()ed and exec()ed the last app in the Application phase, startup is complete from the SM's perspective.
This is good because the Application phase can contain any app, some of which may misbehave, which might cause the SM to halt for a while to wait until the app times out. In theory, the apps in the first four phases are all core desktop apps, so we (usually) have some control over them and can expect them to behave properly (and when they don't, we know who to beat up on until it's fixed).
So, in line with my unofficial conventions above of defining the phases in terms of priority levels, we might just have two phases:
We could define a priority level (let's say 50 for the sake of example) such that numbers lower are sorted into the Desktop phase, and numbers higher are sorted into the Application phase. We'll still do parallel startup, and it'll still follow the priority numbers for the parallel startup groups for apps with priority values that put them in the Desktop phase (so we can set the WM's priority to 25 and the panel's priority to 30 and be sure that the WM has fully started before the panel starts).
However, once we get into the Application phase, the actual priority value is effectively ignored. We'll sort the apps in priority order and start them in that order (but still in parallel), but we won't wait at all for any apps to connect to the session manager before moving on to the next numerical priority group (and, similar to GNOME's method, we won't really care if the app even connects to the SM at all).
As a side effect, all standard XDG autostart apps get assigned to a default priority value that's somewhere in the Application phase range, and will get started just like any other session-managed app (except that we start it using the
Exec key in the .desktop file rather than the
: if an app in the Application phase (that was previously saved in the session and is not a standard plain-vanilla XDG autostart file) fails to connect to the session manager, do we remove it from the session? On first glance, I'm not sure, but I'd lean toward yes, we remove it.