2424import os
2525import typing
2626
27+ import gi
28+
29+ gi .require_version ("Gio" , "2.0" )
30+ from gi .repository import Gio
31+
2732from safeeyes import utility
2833from safeeyes .model import TrayAction
2934
3035context = None
3136is_long_break : bool = False
3237user_locked_screen = False
33- lock_screen_command = None
38+ lock_screen_command : typing . Union [ list [ str ], typing . Callable [[], None ], None ] = None
3439min_seconds = 0
3540seconds_passed = 0
3641tray_icon_path = None
3742icon_lock_later_path = None
3843
3944
40- def __lock_screen_command () -> typing .Optional [list [str ]]:
45+ def __lock_screen_command () -> typing .Union [list [str ], typing . Callable [[], None ], None ]:
4146 """Function tries to detect the screensaver command based on the current
4247 envinroment.
4348
49+ Returns either a command to execute or function to call.
50+
4451 Possible results:
45- Gnome, Unity, Budgie: ['gnome-screensaver-command', '--lock']
52+ Modern GNOME: DBus: org.gnome.ScreenSaver.Lock
53+ Old Gnome, Unity, Budgie: ['gnome-screensaver-command', '--lock']
4654 Cinnamon: ['cinnamon-screensaver-command', '--lock']
4755 Pantheon, LXDE: ['light-locker-command', '--lock']
4856 Mate: ['mate-screensaver-command', '--lock']
49- KDE: ['qdbus', 'org.freedesktop.ScreenSaver',
50- '/ScreenSaver', 'Lock']
57+ KDE: DBus: org.freedesktop.ScreenSaver.Lock
5158 XFCE: ['xflock4']
5259 Otherwise: None
5360 """
@@ -64,6 +71,7 @@ def __lock_screen_command() -> typing.Optional[list[str]]:
6471 elif desktop_session == "cinnamon" and utility .command_exist (
6572 "cinnamon-screensaver-command"
6673 ):
74+ # This calls org.cinnamon.ScreenSaver.Lock internally
6775 return ["cinnamon-screensaver-command" , "--lock" ]
6876 elif (
6977 desktop_session == "pantheon" or desktop_session .startswith ("lubuntu" )
@@ -72,14 +80,23 @@ def __lock_screen_command() -> typing.Optional[list[str]]:
7280 elif desktop_session == "mate" and utility .command_exist (
7381 "mate-screensaver-command"
7482 ):
83+ # This calls org.mate.ScreenSaver.Lock internally
84+ # However, it warns not to rely on that
7585 return ["mate-screensaver-command" , "--lock" ]
7686 elif (
7787 desktop_session == "kde"
7888 or "plasma" in desktop_session
7989 or desktop_session .startswith ("kubuntu" )
8090 or os .environ .get ("KDE_FULL_SESSION" ) == "true"
8191 ):
82- 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+ )
83100 elif (
84101 desktop_session in ["gnome" , "unity" , "budgie-desktop" ]
85102 or desktop_session .startswith ("ubuntu" )
@@ -88,13 +105,11 @@ def __lock_screen_command() -> typing.Optional[list[str]]:
88105 if utility .command_exist ("gnome-screensaver-command" ):
89106 return ["gnome-screensaver-command" , "--lock" ]
90107 # From Gnome 3.8 no gnome-screensaver-command
91- return [
92- "dbus-send" ,
93- "--type=method_call" ,
94- "--dest=org.gnome.ScreenSaver" ,
95- "/org/gnome/ScreenSaver" ,
96- "org.gnome.ScreenSaver.Lock" ,
97- ]
108+ return lambda : __lock_screen_dbus (
109+ destination = "org.gnome.ScreenSaver" ,
110+ path = "/org/gnome/ScreenSaver" ,
111+ method = "Lock" ,
112+ )
98113 elif gd_session := os .environ .get ("GNOME_DESKTOP_SESSION_ID" ):
99114 if "deprecated" not in gd_session and utility .command_exist (
100115 "gnome-screensaver-command"
@@ -104,13 +119,35 @@ def __lock_screen_command() -> typing.Optional[list[str]]:
104119 return None
105120
106121
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+
107136def __lock_screen_later ():
108137 global user_locked_screen
109138 user_locked_screen = True
110139
111140
112141def __lock_screen_now () -> None :
113- 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 ()
114151
115152
116153def init (ctx , safeeyes_config , plugin_config ):
@@ -142,8 +179,8 @@ def on_start_break(break_obj):
142179 global user_locked_screen
143180 user_locked_screen = False
144181 seconds_passed = 0
145- if lock_screen_command :
146- is_long_break = break_obj .is_long_break ()
182+
183+ is_long_break = break_obj .is_long_break ()
147184
148185
149186def on_countdown (countdown , seconds ):
0 commit comments