1#!/usr/local/bin/python3.8 2 3from gi.repository import Gio, GLib, CScreensaver 4import os 5 6from dbusdepot.baseClient import BaseClient 7from dbusdepot.loginInterface import LoginInterface 8 9class LogindClient(LoginInterface, BaseClient): 10 """ 11 A client for communicating with logind. At startup we check 12 for its availability, falling back to ConsoleKit if it's not 13 available. 14 """ 15 LOGIND_SERVICE = "org.freedesktop.login1" 16 LOGIND_PATH = "/org/freedesktop/login1" 17 18 def __init__(self): 19 """ 20 We first try to connect to the logind manager. 21 """ 22 super(LogindClient, self).__init__(Gio.BusType.SYSTEM, 23 CScreensaver.LogindManagerProxy, 24 self.LOGIND_SERVICE, 25 self.LOGIND_PATH) 26 27 self.pid = os.getpid() 28 29 self.session_id = None 30 self.session_proxy = None 31 32 def on_client_setup_complete(self): 33 """ 34 If our manager connection succeeds, we ask it for the current session id and 35 then attempt to connect to its session interface. 36 37 Note: there are issues with retrieving this session id depending on how the 38 screensaver instances was started, when running under systemd. If started from 39 a terminal (which is running in a different scope than the current session,) we 40 need to retrieve the session id via its environment variable. 41 42 If the screensaver is started as part of the session (due to autostart conditions,) 43 there is no issue here. 44 """ 45 try: 46 self.session_id = self.proxy.call_get_session_by_pid_sync(self.pid) 47 except GLib.Error: 48 print("Not running under the session scope, trying XDG_SESSION_ID") 49 id_suffix = os.getenv("XDG_SESSION_ID", "") 50 if id_suffix != "": 51 self.session_id = "/org/freedesktop/login1/session/%s" % (id_suffix,) 52 print("found session: %s" % (id_suffix,)) 53 else: 54 print("Could not construct a valid ID for Logind session. Is XDG_SESSION_ID set?") 55 self.session_proxy = None 56 self.on_failure() 57 return 58 59 try: 60 self.session_proxy = CScreensaver.LogindSessionProxy.new_for_bus(Gio.BusType.SYSTEM, 61 Gio.DBusProxyFlags.NONE, 62 self.LOGIND_SERVICE, 63 self.session_id, 64 None, 65 self.on_session_ready, 66 None) 67 except GLib.Error: 68 self.session_proxy = None 69 self.on_failure() 70 71 def on_session_ready(self, object, result, data=None): 72 """ 73 Once we're connected to the session interface, we can respond to signals sent from 74 it - used primarily when returning from suspend, hibernation or the login screen. 75 """ 76 self.session_proxy = CScreensaver.LogindSessionProxy.new_for_bus_finish(result) 77 78 self.session_proxy.connect("unlock", lambda proxy: self.emit("unlock")) 79 self.session_proxy.connect("lock", lambda proxy: self.emit("lock")) 80 self.session_proxy.connect("notify::active", self.on_active_changed) 81 82 self.emit("startup-status", True) 83 84 def on_active_changed(self, proxy, pspec, data=None): 85 if self.session_proxy.get_property("active"): 86 self.emit("active") 87 88 def on_failure(self, *args): 89 self.emit("startup-status", False) 90