2222
2323import logging
2424import os
25+ import typing
26+
27+ import gi
28+
29+ gi .require_version ("Gio" , "2.0" )
30+ from gi .repository import Gio
2531
2632from safeeyes import utility
2733from safeeyes .model import TrayAction
2834
2935context = None
30- lock_screen = False
36+ is_long_break : bool = False
3137user_locked_screen = False
32- lock_screen_command = None
38+ lock_screen_command : typing . Union [ list [ str ], typing . Callable [[], None ], None ] = None
3339min_seconds = 0
3440seconds_passed = 0
3541tray_icon_path = None
3642icon_lock_later_path = None
3743
3844
39- def __lock_screen_command ():
45+ def __lock_screen_command () -> typing . Union [ list [ str ], typing . Callable [[], None ], None ] :
4046 """Function tries to detect the screensaver command based on the current
4147 envinroment.
4248
49+ Returns either a command to execute or function to call.
50+
4351 Possible results:
44- Gnome, Unity, Budgie: ['gnome-screensaver-command', '--lock']
52+ Modern GNOME: DBus: org.gnome.ScreenSaver.Lock
53+ Old Gnome, Unity, Budgie: ['gnome-screensaver-command', '--lock']
4554 Cinnamon: ['cinnamon-screensaver-command', '--lock']
4655 Pantheon, LXDE: ['light-locker-command', '--lock']
4756 Mate: ['mate-screensaver-command', '--lock']
48- KDE: ['qdbus', 'org.freedesktop.ScreenSaver',
49- '/ScreenSaver', 'Lock']
57+ KDE: DBus: org.freedesktop.ScreenSaver.Lock
5058 XFCE: ['xflock4']
5159 Otherwise: None
5260 """
@@ -63,6 +71,7 @@ def __lock_screen_command():
6371 elif desktop_session == "cinnamon" and utility .command_exist (
6472 "cinnamon-screensaver-command"
6573 ):
74+ # This calls org.cinnamon.ScreenSaver.Lock internally
6675 return ["cinnamon-screensaver-command" , "--lock" ]
6776 elif (
6877 desktop_session == "pantheon" or desktop_session .startswith ("lubuntu" )
@@ -71,14 +80,23 @@ def __lock_screen_command():
7180 elif desktop_session == "mate" and utility .command_exist (
7281 "mate-screensaver-command"
7382 ):
83+ # This calls org.mate.ScreenSaver.Lock internally
84+ # However, it warns not to rely on that
7485 return ["mate-screensaver-command" , "--lock" ]
7586 elif (
7687 desktop_session == "kde"
7788 or "plasma" in desktop_session
7889 or desktop_session .startswith ("kubuntu" )
7990 or os .environ .get ("KDE_FULL_SESSION" ) == "true"
8091 ):
81- return ["qdbus" , "org.freedesktop.ScreenSaver" , "/ScreenSaver" , "Lock" ]
92+ # Note that this is unfortunately a non-standard KDE extension.
93+ # See https://gitlab.gnome.org/GNOME/gnome-settings-daemon/-/issues/632
94+ # for details.
95+ return lambda : __lock_screen_dbus (
96+ destination = "org.freedesktop.ScreenSaver" ,
97+ path = "/ScreenSaver" ,
98+ method = "Lock" ,
99+ )
82100 elif (
83101 desktop_session in ["gnome" , "unity" , "budgie-desktop" ]
84102 or desktop_session .startswith ("ubuntu" )
@@ -87,29 +105,49 @@ def __lock_screen_command():
87105 if utility .command_exist ("gnome-screensaver-command" ):
88106 return ["gnome-screensaver-command" , "--lock" ]
89107 # From Gnome 3.8 no gnome-screensaver-command
90- return [
91- "dbus-send" ,
92- "--type=method_call" ,
93- "--dest=org.gnome.ScreenSaver" ,
94- "/org/gnome/ScreenSaver" ,
95- "org.gnome.ScreenSaver.Lock" ,
96- ]
97- elif os .environ .get ("GNOME_DESKTOP_SESSION_ID" ):
98- if "deprecated" not in os .environ .get (
99- "GNOME_DESKTOP_SESSION_ID"
100- ) and utility .command_exist ("gnome-screensaver-command" ):
108+ return lambda : __lock_screen_dbus (
109+ destination = "org.gnome.ScreenSaver" ,
110+ path = "/org/gnome/ScreenSaver" ,
111+ method = "Lock" ,
112+ )
113+ elif gd_session := os .environ .get ("GNOME_DESKTOP_SESSION_ID" ):
114+ if "deprecated" not in gd_session and utility .command_exist (
115+ "gnome-screensaver-command"
116+ ):
101117 # Gnome 2
102118 return ["gnome-screensaver-command" , "--lock" ]
103119 return None
104120
105121
122+ def __lock_screen_dbus (destination : str , path : str , method : str ) -> None :
123+ """This assumes that the interface is the same as the destination."""
124+ dbus_proxy = Gio .DBusProxy .new_for_bus_sync (
125+ bus_type = Gio .BusType .SESSION ,
126+ flags = Gio .DBusProxyFlags .DO_NOT_LOAD_PROPERTIES ,
127+ info = None ,
128+ name = destination ,
129+ object_path = path ,
130+ interface_name = destination ,
131+ )
132+
133+ dbus_proxy .call_sync (method , None , Gio .DBusCallFlags .NONE , - 1 )
134+
135+
106136def __lock_screen_later ():
107137 global user_locked_screen
108138 user_locked_screen = True
109139
110140
111141def __lock_screen_now () -> None :
112- utility .execute_command (lock_screen_command )
142+ global lock_screen_command
143+
144+ if lock_screen_command is None :
145+ return
146+
147+ if isinstance (lock_screen_command , list ):
148+ utility .execute_command (lock_screen_command )
149+ else :
150+ lock_screen_command ()
113151
114152
115153def init (ctx , safeeyes_config , plugin_config ):
@@ -134,15 +172,15 @@ def init(ctx, safeeyes_config, plugin_config):
134172
135173def on_start_break (break_obj ):
136174 """Determine the break type and only if it is a long break, enable the
137- lock_screen flag.
175+ is_long_break flag.
138176 """
139- global lock_screen
177+ global is_long_break
140178 global seconds_passed
141179 global user_locked_screen
142180 user_locked_screen = False
143181 seconds_passed = 0
144- if lock_screen_command :
145- lock_screen = break_obj .is_long_break ()
182+
183+ is_long_break = break_obj .is_long_break ()
146184
147185
148186def on_countdown (countdown , seconds ):
@@ -155,7 +193,7 @@ def on_stop_break():
155193 """Lock the screen after a long break if the user has not skipped within
156194 min_seconds.
157195 """
158- if user_locked_screen or (lock_screen and seconds_passed >= min_seconds ):
196+ if user_locked_screen or (is_long_break and seconds_passed >= min_seconds ):
159197 __lock_screen_now ()
160198
161199
0 commit comments