Skip to content

Commit 1ded330

Browse files
authored
Merge pull request slgobinath#726 from deltragon/lock-screen-now
screensaver: add tray action to lock screen now
2 parents 32830e6 + 5bc3e16 commit 1ded330

File tree

7 files changed

+146
-38
lines changed

7 files changed

+146
-38
lines changed

safeeyes/glade/break_screen.glade

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@
2525
<property name="decorated">0</property>
2626
<property name="deletable">0</property>
2727
<child>
28-
<placeholder/>
29-
</child>
30-
<property name="child">
3128
<object class="GtkGrid" id="grid1">
3229
<property name="row_homogeneous">1</property>
3330
<property name="column_homogeneous">1</property>
@@ -151,7 +148,6 @@
151148
<child>
152149
<object class="GtkBox" id="toolbar">
153150
<property name="css-classes">toolbar</property>
154-
<property name="can_focus">0</property>
155151
<property name="halign">end</property>
156152
<property name="valign">start</property>
157153
<style>
@@ -174,7 +170,7 @@
174170
</object>
175171
</child>
176172
</object>
177-
</property>
173+
</child>
178174
<style>
179175
<class name="window_main"/>
180176
</style>

safeeyes/model.py

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -474,21 +474,32 @@ def __ne__(self, config):
474474
class TrayAction:
475475
"""Data object wrapping name, icon and action."""
476476

477-
def __init__(self, name, icon, action, system_icon):
477+
__toolbar_buttons: list[Gtk.Button]
478+
479+
def __init__(
480+
self,
481+
name: str,
482+
icon: str,
483+
action: typing.Callable,
484+
system_icon: bool,
485+
single_use: bool,
486+
) -> None:
478487
self.name = name
479488
self.__icon = icon
480489
self.action = action
481490
self.system_icon = system_icon
482491
self.__toolbar_buttons = []
492+
self.single_use = single_use
483493

484-
def get_icon(self):
485-
if self.system_icon:
486-
image = Gtk.Image.new_from_icon_name(self.__icon)
487-
return image
488-
else:
494+
def get_icon(self) -> Gtk.Image:
495+
if not self.system_icon:
489496
image = utility.load_and_scale_image(self.__icon, 16, 16)
490-
image.show()
491-
return image
497+
if image is not None:
498+
image.show()
499+
return image
500+
501+
image = Gtk.Image.new_from_icon_name(self.__icon)
502+
return image
492503

493504
def add_toolbar_button(self, button):
494505
self.__toolbar_buttons.append(button)
@@ -499,12 +510,20 @@ def reset(self):
499510
self.__toolbar_buttons.clear()
500511

501512
@classmethod
502-
def build(cls, name, icon_path, icon_id, action):
503-
image = utility.load_and_scale_image(icon_path, 12, 12)
504-
if image is None:
505-
return TrayAction(name, icon_id, action, True)
506-
else:
507-
return TrayAction(name, icon_path, action, False)
513+
def build(
514+
cls,
515+
name: str,
516+
icon_path: typing.Optional[str],
517+
icon_id: str,
518+
action: typing.Callable,
519+
single_use: bool = True,
520+
) -> "TrayAction":
521+
if icon_path is not None:
522+
image = utility.load_and_scale_image(icon_path, 12, 12)
523+
if image is not None:
524+
return TrayAction(name, icon_path, action, False, single_use)
525+
526+
return TrayAction(name, icon_id, action, True, single_use)
508527

509528

510529
@dataclass

safeeyes/plugin_manager.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,7 @@
2424
|- plugin.py
2525
|- icon.png (Optional)
2626
27-
The plugin.py can have following methods but all are optional:
28-
- description()
29-
If a custom description has to be displayed, use this function
27+
The plugin.py can have following lifecycle methods but all are optional:
3028
- init(context, safeeyes_config, plugin_config)
3129
Initialize the plugin. Will be called after loading and after every changes in
3230
configuration
@@ -50,6 +48,20 @@
5048
Executes once the plugin.py is loaded as a module
5149
- disable()
5250
Executes if the plugin is disabled at the runtime by the user
51+
52+
The plugin.py can additionally have the following methods:
53+
- get_widget_title(break_obj)
54+
Returns title of this plugin's widget on the break screen
55+
If this is used, it must also use get_widget_content to work correctly
56+
- get_widget_content(break_obj)
57+
Returns content of this plugin's widget on the break screen
58+
If this is used, it must also use get_widget_title to work correctly
59+
- get_tray_action(break_obj) -> TrayAction | list[TrayAction]
60+
Display button(s) on the break screen's tray that triggers an action
61+
62+
This method is unused:
63+
- description()
64+
If a custom description has to be displayed, use this function
5365
"""
5466

5567
import importlib
@@ -58,7 +70,7 @@
5870
import sys
5971

6072
from safeeyes import utility
61-
from safeeyes.model import PluginDependency, RequiredPluginException
73+
from safeeyes.model import Break, PluginDependency, RequiredPluginException, TrayAction
6274

6375
sys.path.append(os.path.abspath(utility.SYSTEM_PLUGINS_DIR))
6476
sys.path.append(os.path.abspath(utility.USER_PLUGINS_DIR))
@@ -207,15 +219,19 @@ def get_break_screen_widgets(self, break_obj):
207219
continue
208220
return widget.strip()
209221

210-
def get_break_screen_tray_actions(self, break_obj):
222+
def get_break_screen_tray_actions(self, break_obj: Break) -> list[TrayAction]:
211223
"""Return Tray Actions."""
212224
actions = []
213225
for plugin in self.__plugins.values():
214226
action = plugin.call_plugin_method_break_obj(
215227
"get_tray_action", 1, break_obj
216228
)
217-
if action:
229+
if isinstance(action, TrayAction):
218230
actions.append(action)
231+
elif isinstance(action, list):
232+
for a in action:
233+
if isinstance(a, TrayAction):
234+
actions.append(a)
219235

220236
return actions
221237

safeeyes/plugins/screensaver/plugin.py

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
min_seconds = 0
3434
seconds_passed = 0
3535
tray_icon_path = None
36+
icon_lock_later_path = None
3637

3738

3839
def __lock_screen_command():
@@ -102,21 +103,29 @@ def __lock_screen_command():
102103
return None
103104

104105

105-
def __lock_screen():
106+
def __lock_screen_later():
106107
global user_locked_screen
107108
user_locked_screen = True
108109

109110

111+
def __lock_screen_now() -> None:
112+
utility.execute_command(lock_screen_command)
113+
114+
110115
def init(ctx, safeeyes_config, plugin_config):
111116
"""Initialize the screensaver plugin."""
112117
global context
113118
global lock_screen_command
114119
global min_seconds
115120
global tray_icon_path
121+
global icon_lock_later_path
116122
logging.debug("Initialize Screensaver plugin")
117123
context = ctx
118124
min_seconds = plugin_config["min_seconds"]
119125
tray_icon_path = os.path.join(plugin_config["path"], "resource/lock.png")
126+
icon_lock_later_path = os.path.join(
127+
plugin_config["path"], "resource/rotation-lock-symbolic.svg"
128+
)
120129
if plugin_config["command"]:
121130
lock_screen_command = plugin_config["command"].split()
122131
else:
@@ -147,10 +156,22 @@ def on_stop_break():
147156
min_seconds.
148157
"""
149158
if user_locked_screen or (lock_screen and seconds_passed >= min_seconds):
150-
utility.execute_command(lock_screen_command)
151-
152-
153-
def get_tray_action(break_obj):
154-
return TrayAction.build(
155-
"Lock screen", tray_icon_path, "dialog-password", __lock_screen
156-
)
159+
__lock_screen_now()
160+
161+
162+
def get_tray_action(break_obj) -> list[TrayAction]:
163+
return [
164+
TrayAction.build(
165+
"Lock screen now",
166+
tray_icon_path,
167+
"system-lock-screen",
168+
__lock_screen_now,
169+
single_use=False,
170+
),
171+
TrayAction.build(
172+
"Lock screen after break",
173+
icon_lock_later_path,
174+
"dialog-password",
175+
__lock_screen_later,
176+
),
177+
]
Lines changed: 51 additions & 0 deletions
Loading

safeeyes/ui/break_screen.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import gi
2525
from safeeyes import utility
26+
from safeeyes.model import TrayAction
2627
from safeeyes.translations import translate as _
2728
import Xlib
2829
from Xlib.display import Display
@@ -139,13 +140,14 @@ def close(self):
139140
# Destroy other windows if exists
140141
GLib.idle_add(lambda: self.__destroy_all_screens())
141142

142-
def __tray_action(self, button, tray_action):
143+
def __tray_action(self, button, tray_action: TrayAction):
143144
"""Tray action handler.
144145
145-
Hides all toolbar buttons for this action and call the action
146-
provided by the plugin.
146+
Hides all toolbar buttons for this action, if it is single use,
147+
and call the action provided by the plugin.
147148
"""
148-
tray_action.reset()
149+
if tray_action.single_use:
150+
tray_action.reset()
149151
tray_action.action()
150152

151153
def __show_break_screen(self, message, image_path, widget, tray_actions):

safeeyes/utility.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import shutil
3232
import subprocess
3333
import threading
34+
import typing
3435
from logging.handlers import RotatingFileHandler
3536
from pathlib import Path
3637

@@ -732,7 +733,9 @@ def create_gtk_builder(glade_file):
732733
return builder
733734

734735

735-
def load_and_scale_image(path, width, height):
736+
def load_and_scale_image(
737+
path: str, width: int, height: int
738+
) -> typing.Optional[Gtk.Image]:
736739
if not os.path.isfile(path):
737740
return None
738741
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(

0 commit comments

Comments
 (0)