Add support for Xfce
Opened this issue · 3 comments
fohrloop commented
Different methods on xfce:
org.Xfce.Session.Manager.Inhibit
- Introduced in xfce-session/#22 (in particular, the commit 895a580d). Merged into xfce-session in commit aa586e05 (April 13th, 2023). It is not part of the xfce-4.18 branch, but it is part of the xfce-session-4.19.0 tag.
- Since Xfce releases every odd number (..., 4.14, 4.16, 4.18, 4.20, ...) as binary releases (changelog here), the org.Xfce.Session.Manager.Inhibit will only be part of the 4.19 "development" (source) release, and then finally in the Xfce 4.20, which is probably out in late 2024 or early 2025 (ref). See also: Schedule for and Status of the Xfce 4.20 Development Cycle.
- D-Bus path:
/org/xfce/SessionManager
- D-Bus interface:
org.xfce.Session.Manager
- Method:
Inhibit
, with parameters app_id (str), toplevel_xid (int), reason (str), flags (int) and return value inhibit_cookie (int)
org.freedesktop.PowerManagement.Inhibit
- Obsolete spec, but still used: https://wakepy.readthedocs.io/stable/methods-reference.html#org-freedesktop-powermanagement
- There's a bug in XFCE.
org.freedesktop.PowerManagement.Inhibit
inhibits also screensaver: https://gitlab.xfce.org/xfce/xfce4-power-manager/-/issues/65 - This is present on Xfce 4.18 session bus. Tested and this prevents idle; it implements keep.presenting mode.
- D-Bus name
org.freedesktop.PowerManagement
(on Session bus) - D-Bus path:
/org/freedesktop/PowerManagement/Inhibit
- D-Bus interface:
org.freedesktop.PowerManagement.Inhibit
- Method:
Inhibit
, with parameters application_name (str) and reason (str) and return value inhibit_cookie (int). Note that since this does not have input parameter "flags", you may not control what this inhibits, and there are two kinds of behaviors found in the wild (keep.running (=the correct one?) and keep.presenting).
org.freedesktop.login1.Manager.Inhibit
- This is present on Xfce 4.18 system bus
- D-Bus name:
org.freedesktop.login1
- D-Bus path:
/org/freedesktop/login1
- D-Bus interface:
org.freedesktop.login1.Manager
- Method:
Inhibit
, with parameters what (str) who (str) why (str) mode (str) and return value file_descriptor (File Descriptor).
org.xfce.PowerManager
- Mentioned on xfce4-power-manager roadmap for Xfce 4.10
- Likely to just be a proxy or alias for org.freedesktop.PowerManagement.Inhibit
- This is present on Xfce 4.18 session bus. Tested and this prevents idle; it implements keep.presenting mode.
- D-Bus name:
org.xfce.PowerManager
- D-Bus path:
/org/freedesktop/PowerManagement/Inhibit
- D-Bus interface:
org.freedesktop.PowerManagement.Inhibit
- Method:
Inhibit
, with parameters application_name (str) and reason (str) and return value inhibit_cookie (int).
Notes
- See discussion in: https://gitlab.xfce.org/xfce/xfce4-session/-/issues/71
fohrloop commented
I've done some testing and here are results.
org.Xfce.Session.Manager.Inhibit
- Does not exists yet in Xfce 4.18. Should probably be the chosen method on Xfce 4.20 and above (in the future).
org.freedesktop.PowerManagement.Inhibit
- Has only one possible "mode": keep.presenting, which prevents the idle action and keeps also the screen awake. This cannot be modified in any way, so implementing keep.presenting mode is not possible. In my understanding, the spec says that this should only prevent suspending (allow automatic screenlock+screen saver), so using this method would mean that wakepy would rely on a bug existing on Xfce. See also xfce4-power-manager/#65 and org.freedesktop.PowerManagement docs. This bug has been fixed in KDE 5.12.90.
org.xfce.PowerManager
- Seems to be just a proxy / alias for org.freedesktop.PowerManagement.Inhibit
org.freedesktop.login1.Manager.Inhibit
- Should be able to prevent suspend/sleep or the idle action. Checking if this is possible without root.
Test 1
- Trying to inhibit "sleep" with org.freedesktop.login1.Manager.Inhibit. (no sudo used)
- Result: This does not work.
Test 1 details
from jeepney import DBusAddress, new_method_call
from jeepney.io.blocking import open_dbus_connection
from jeepney.wrappers import unwrap_msg
addr = DBusAddress(
object_path='/org/freedesktop/login1',
bus_name='org.freedesktop.login1',
interface='org.freedesktop.login1.Manager',
)
msg = new_method_call(
addr,
method='Inhibit',
signature='ssss',
body=('sleep', 'wakepy', 'wakelock active', 'block'),
)
connection = open_dbus_connection(bus="SYSTEM", enable_fds=True)
reply = connection.send_and_get_reply(msg, timeout=2)
resp = unwrap_msg(reply)
fd = resp[0]
Running this with -i
flag to keep the file descriptor object open.
(venv) fohrloop@fedora:~/code/wakepy$ python -i foo.py
>>> fd
<FileDescriptor (5)>
But this did not prevent automatic suspend
Test 2
- Trying to inhibit "sleep" with org.freedesktop.login1.Manager.Inhibit with sudo.
- This time the suspend was prevented. After logging back in (from screensaver/screenlock), I was greeted with this:
Code
Some pieces of code for possible use in the future
org.freedesktop.login1
class FreedesktopLogin1Inhibit(Method):
"""Method using org.freedesktop.login1.Manager.Inhibit D-Bus API
References:
[1]: https://www.freedesktop.org/software/systemd/man/latest/org.freedesktop.login1.html
[2]: https://systemd.io/INHIBITOR_LOCKS/
"""
name = "org.freedesktop.login1"
mode_name = ModeName.KEEP_RUNNING
login1_manager = DBusAddress(
bus=BusType.SYSTEM,
service="org.freedesktop.login1",
path="/org/freedesktop/login1",
interface="org.freedesktop.login1.Manager",
)
# Note: There is no "UnInhibit" method. The method returns a file
# descriptor. The lock is released the moment this file descriptor and all
# its duplicates are closed.
method_inhibit = DBusMethod(
name="Inhibit",
signature="ssss",
params=("what", "who", "why", "mode"),
output_signature="h",
output_params=("fd",),
).of(login1_manager)
supported_platforms = (PlatformType.UNIX_LIKE_FOSS,)
def enter_mode(self) -> None:
# The method arguments are:
# what (str):
# Colon-separated list of lock types: shutdown, sleep, idle,
# handle-power-key, handle-suspend-key, handle-hibernate-key
# and handle-lid-switch. The ones interesting for wakepy are "sleep"
# and "idle".
# who (str)
# The name of the application requesting the lock.
# why (str):
# The reason for requesting the lock.
# mode (str):
# The lock mode. Either "block" or "delay".
call = DBusMethodCall(
method=self.method_inhibit,
args=dict(
what="sleep",
who="wakepy",
why="wakelock active",
mode="block",
),
)
retval = self.process_dbus_call(call)
if retval is None:
raise RuntimeError(
"Could not get file handle from org.freedesktop.login1"
)
self.inhibit_cookie = retval[0]
lower-level alternative:
from jeepney import DBusAddress, new_method_call
from jeepney.io.blocking import open_dbus_connection
from jeepney.wrappers import unwrap_msg
addr = DBusAddress(
object_path='/org/freedesktop/login1',
bus_name='org.freedesktop.login1',
interface='org.freedesktop.login1.Manager',
)
msg = new_method_call(
addr,
method='Inhibit',
signature='ssss',
body=('sleep', 'wakepy', 'wakelock active', 'block'),
)
connection = open_dbus_connection(bus="SYSTEM", enable_fds=True)
reply = connection.send_and_get_reply(msg, timeout=2)
resp = unwrap_msg(reply)
fd = resp[0]
org.xfce.PowerManager
class XfcePowerManagerInhibit(FreedesktopInhibitorWithCookieMethod):
name = "org.xfce.PowerManager"
mode_name = ModeName.KEEP_RUNNING
service_dbus_address = DBusAddress(
bus=BusType.SESSION,
service="org.xfce.PowerManager",
path="/org/freedesktop/PowerManagement/Inhibit",
interface="org.freedesktop.PowerManagement.Inhibit",
)
fohrloop commented
As none of the above methods are suitable for just the keep.running method (without sudo), I'm not sure what to do. I asked on the xfce forums some advice. Perhaps there's still some other way to prevent automatic suspending on Xcfe < 4.19.