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