Skip to content

Support logout from SystemdProvider#372

Open
basil wants to merge 2 commits intolxqt:masterfrom
basil:uwsm
Open

Support logout from SystemdProvider#372
basil wants to merge 2 commits intolxqt:masterfrom
basil:uwsm

Conversation

@basil
Copy link
Copy Markdown

@basil basil commented Jan 5, 2026

Background

lxqtpower provides a provider mechanism. Providers are initialized in

mProviders.append(new CustomProvider(this));
if (useLxqtSessionProvider)
mProviders.append(new LXQtProvider(this));
mProviders.append(new SystemdProvider(this));
mProviders.append(new UPowerProvider(this));
mProviders.append(new ConsoleKitProvider(this));
mProviders.append(new LxSessionProvider(this));
according to these rules:

  • If useLxqtSessionProvider is true, then LXQtProvider is initialized. This communicates with lxqt-session via DBus.
  • SystemdProvider is unconditionally initialized with lower precedence.

When power actions are performed, the providers are tried in order:

bool Power::canAction(Power::Action action) const
{
for(const PowerProvider* provider : std::as_const(mProviders))
{
if (provider->canAction(action))
return true;
}
return false;
}
bool Power::doAction(Power::Action action)
{
for(PowerProvider* provider : std::as_const(mProviders))
{
if (provider->canAction(action) &&
provider->doAction(action)
)
{
return true;
}
}
return false;
}
So first LXQtProvider is tried (if useLxqtSessionProvider is true), and then SystemdProvider is tried. Thus we have established that lxqtpower does not depend on lxqt-session.

Problem

When SystemdProvider is in use (i.e., when lxqt-session is not running), lxqt-leave shows a grayed-out logout button, but the shutdown and reboot buttons are not grayed out.

Evaluation

SystemdProvider::canAction and SystemdProvider::doAction include case statements for case Power::PowerShutdown and case Power::PowerReboot, but not for case Power::PowerLogout:

bool SystemdProvider::canAction(Power::Action action) const
{
QString command;
switch (action)
{
case Power::PowerReboot:
command = QL1SV("CanReboot");
break;
case Power::PowerShutdown:
command = QL1SV("CanPowerOff");
break;
case Power::PowerSuspend:
command = QL1SV("CanSuspend");
break;
case Power::PowerHibernate:
command = QL1SV("CanHibernate");
break;
default:
return false;
}
return dbusCallSystemd(QL1SV(SYSTEMD_SERVICE),
QL1SV(SYSTEMD_PATH),
QL1SV(SYSTEMD_INTERFACE),
QDBusConnection::systemBus(),
command,
false,
// canAction should be always silent because it can freeze
// g_main_context_iteration Qt event loop in QMessageBox
// on panel startup if there is no DBUS running.
PowerProvider::DontCheckDBUS
);
}
bool SystemdProvider::doAction(Power::Action action)
{
QString command;
switch (action)
{
case Power::PowerReboot:
command = QL1SV("Reboot");
break;
case Power::PowerShutdown:
command = QL1SV("PowerOff");
break;
case Power::PowerSuspend:
command = QL1SV("Suspend");
break;
case Power::PowerHibernate:
command = QL1SV("Hibernate");
break;
default:
return false;
}
return dbusCallSystemd(QL1SV(SYSTEMD_SERVICE),
QL1SV(SYSTEMD_PATH),
QL1SV(SYSTEMD_INTERFACE),
QDBusConnection::systemBus(),
command,
true
);
}

Solution

As discussed in lxqt/lxqt-wayland-session#105 (comment), add the missing case, calling systemd's TerminateSession via DBus. This is the equivalent of loginctl terminate-session (man page) which is documented as follows:

Terminates a session. This kills all processes of the session and deallocates all resources attached to the session.

Implementation details

XDG_SESSION_ID is set by systemd-logind for a user session. If it's missing, we are not running inside a logind-managed session and consider the functionality unavailable. systemd does not offer a CanLogout or CanTerminateSession method analogous to CanReboot, CanPowerOff, etc. So we therefore check if we have an XDG_SESSION_ID and that the DBus service, object, and interface are present on the system bus, then consider the functionality available.

For actually logging out the user, TerminateSession takes a string ID rather than an interactive boolean like the PowerOff and Reboot methods, so the dbusCallSystemd function is not suitable. Instead, we modify the dbusCall method to support arbitrary arguments (with a default value of no arguments). If binary compatibility is a concern, I can leave the existing function signature alone and create a new signature for invoking DBus methods with arguments.

Testing done

Tested in Fedora 43 under UWSM (without lxqt-session running). Before this PR, the logout button was grayed out. After this PR, it is not grayed out, and clicking it logs out the session.

@tsujan
Copy link
Copy Markdown
Member

tsujan commented Jan 5, 2026

Logging out of a session is the session's job. Shutting down a system is a system job.

I'm talking as an LXQt dev, not as an LXQt representative:

Until now, your suggestions were about cluttering LXQt's codes for this or that app to work without an lxqt-session. Well, that's the problem of this or that app. LXQt has a session and handles it gracefully.

@basil
Copy link
Copy Markdown
Author

basil commented Jan 5, 2026

Thanks @tsujan! As I mentioned in an email to you, I'm happy to discuss this with you further privately if desired.

@tsujan
Copy link
Copy Markdown
Member

tsujan commented Jan 5, 2026

I'm happy to discuss this with you further privately if desired.

This isn't a private matter ;)

@basil
Copy link
Copy Markdown
Author

basil commented Jan 5, 2026

Thanks @tsujan, this pull request isn't the right place to have a broader discussion about systemd support at a high level. You are welcome to respond to my points in lxqt/lxqt-session#623 if you wish to continue the conversation publicly on GitHub. I remain available to discuss the design in an audio or video chat, which may be recorded and made publicly available afterward (if desired).

Copy link
Copy Markdown
Contributor

@palinek palinek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR seems perfectly valid (and thoroughly explained 👍) and I agree with the logic (I'm just putting some nitpicking code-flow comments).

Ad changing the static function signature -> it is a private not-exposed symbol, so IMO we don't need to be too cautious here


bool SystemdProvider::canAction(Power::Action action) const
{
if (action == Power::PowerLogout)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to put this into the pre-existing switch.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in commit d91ff3e


bool SystemdProvider::doAction(Power::Action action)
{
if (action == Power::PowerLogout)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this also be put into the switch and even the unified dbusCall used for all cases afterwards?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this also be put into the switch

Done in commit d91ff3e

[Can] even the unified dbusCall used for all cases afterwards?

Possibly? From the docs:

CanPowerOff(), CanReboot(), CanHalt(), CanSuspend(), CanHibernate(), CanHybridSleep(), CanSuspendThenHibernate(), CanSleep(), CanRebootParameter(), CanRebootToFirmwareSetup(), CanRebootToBootLoaderMenu(), and CanRebootToBootLoaderEntry() test whether the system supports the respective operation and whether the calling user is allowed to execute it. Returns one of "na", "yes", "no", and "challenge".

The docs say nothing about the return value of the Reboot, PowerOff, Suspend, and Hibernate commands, so I'm not sure if it's safe to replace the calls to dbusCallSystemd (which has special handling for the string values "yes" and "challenge") with calls to dbusCall (which does not have such special handling). The existing behavior of the reboot, shutdown, suspend, or hibernate functionality could likely be cleaned up, but this code cleanup deserves to be implemented and tested as part of a separate PR rather than adding risk to this PR.

@tsujan tsujan requested a review from palinek January 5, 2026 18:18
bmwiedemann pushed a commit to bmwiedemann/openSUSE that referenced this pull request Feb 6, 2026
https://build.opensuse.org/request/show/1331460
by user sfalken + anag_factory
- Added 0001-Support-logout-in-SystemdProvider.patch, for better
  systemd compaitibility and functionality, please see
  lxqt/liblxqt#372
@stefonarch
Copy link
Copy Markdown
Member

@palinek is this good now?

@palinek
Copy link
Copy Markdown
Contributor

palinek commented Apr 1, 2026

Seems OK. But to be honor, I haven't tested/run anything of these changes.

@stefonarch
Copy link
Copy Markdown
Member

Seems OK. But to be honor, I haven't tested/run anything of these changes.

I've no interest in uwsm but I'll run it for some days on my setup and if I notice no issue I'll merge it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants