Skip to content

Commit 8bc91d0

Browse files
committed
break screen: add types
1 parent feaa1ee commit 8bc91d0

File tree

1 file changed

+78
-39
lines changed

1 file changed

+78
-39
lines changed

safeeyes/ui/break_screen.py

Lines changed: 78 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@
2020
import logging
2121
import os
2222
import time
23+
import typing
2324

2425
import gi
2526
from safeeyes import utility
26-
from safeeyes.model import TrayAction
27+
from safeeyes.model import Break, Config, TrayAction
2728
from safeeyes.translations import translate as _
2829
import Xlib
2930
from Xlib.display import Display
@@ -44,7 +45,15 @@ class BreakScreen:
4445
This class creates and manages the fullscreen windows for every monitor.
4546
"""
4647

47-
def __init__(self, application, context, on_skipped, on_postponed):
48+
windows: list["BreakScreenWindow"]
49+
50+
def __init__(
51+
self,
52+
application: Gtk.Application,
53+
context,
54+
on_skipped: typing.Callable[[], None],
55+
on_postponed: typing.Callable[[], None],
56+
):
4857
self.application = application
4958
self.context = context
5059
self.x11_display = None
@@ -64,7 +73,7 @@ def __init__(self, application, context, on_skipped, on_postponed):
6473
if not self.context["is_wayland"]:
6574
self.x11_display = Display()
6675

67-
def initialize(self, config):
76+
def initialize(self, config: Config) -> None:
6877
"""Initialize the internal properties from configuration."""
6978
logging.info("Initialize the break screen")
7079
self.enable_postpone = config.get("allow_postpone", False)
@@ -84,36 +93,38 @@ def initialize(self, config):
8493
self.shortcut_disable_time = config.get("shortcut_disable_time", 2)
8594
self.strict_break = config.get("strict_break", False)
8695

87-
def skip_break(self):
96+
def skip_break(self) -> None:
8897
"""Skip the break from the break screen."""
8998
logging.info("User skipped the break")
9099
# Must call on_skipped before close to lock screen before closing the break
91100
# screen
92101
self.on_skipped()
93102
self.close()
94103

95-
def postpone_break(self):
104+
def postpone_break(self) -> None:
96105
"""Postpone the break from the break screen."""
97106
logging.info("User postponed the break")
98107
self.on_postponed()
99108
self.close()
100109

101-
def on_skip_clicked(self, button):
110+
def on_skip_clicked(self, button) -> None:
102111
"""Skip button press event handler."""
103112
self.skip_break()
104113

105-
def on_postpone_clicked(self, button):
114+
def on_postpone_clicked(self, button) -> None:
106115
"""Postpone button press event handler."""
107116
self.postpone_break()
108117

109-
def show_count_down(self, countdown, seconds):
118+
def show_count_down(self, countdown: int, seconds: int) -> None:
110119
"""Show/update the count down on all screens."""
111120
self.enable_shortcut = self.shortcut_disable_time <= seconds
112121
mins, secs = divmod(countdown, 60)
113122
timeformat = "{:02d}:{:02d}".format(mins, secs)
114123
GLib.idle_add(lambda: self.__update_count_down(timeformat))
115124

116-
def show_message(self, break_obj, widget, tray_actions=[]):
125+
def show_message(
126+
self, break_obj: Break, widget: str, tray_actions: list[TrayAction] = []
127+
) -> None:
117128
"""Show the break screen with the given message on all displays."""
118129
message = break_obj.name
119130
image_path = break_obj.image
@@ -122,7 +133,7 @@ def show_message(self, break_obj, widget, tray_actions=[]):
122133
lambda: self.__show_break_screen(message, image_path, widget, tray_actions)
123134
)
124135

125-
def close(self):
136+
def close(self) -> None:
126137
"""Hide the break screen from active window and destroy all other
127138
windows.
128139
"""
@@ -133,14 +144,24 @@ def close(self):
133144
# Destroy other windows if exists
134145
GLib.idle_add(lambda: self.__destroy_all_screens())
135146

136-
def __show_break_screen(self, message, image_path, widget, tray_actions):
147+
def __show_break_screen(
148+
self,
149+
message: str,
150+
image_path: typing.Optional[str],
151+
widget: str,
152+
tray_actions: list[TrayAction],
153+
) -> None:
137154
"""Show an empty break screen on all screens."""
138155
# Lock the keyboard
139156
if not self.context["is_wayland"]:
140157
utility.start_thread(self.__lock_keyboard_x11)
141158

142159
display = Gdk.Display.get_default()
143-
monitors = display.get_monitors()
160+
161+
if display is None:
162+
raise Exception("display not found")
163+
164+
monitors = typing.cast(typing.Sequence[Gdk.Monitor], display.get_monitors())
144165
logging.info("Show break screens in %d display(s)", len(monitors))
145166

146167
skip_button_disabled = self.context.get("skip_button_disabled", False)
@@ -196,17 +217,22 @@ def __show_break_screen(self, message, image_path, widget, tray_actions):
196217

197218
if self.context["is_wayland"]:
198219
# this may or may not be granted by the window system
199-
window.get_surface().inhibit_system_shortcuts(None)
220+
surface = window.get_surface()
221+
if surface is not None:
222+
typing.cast(Gdk.Toplevel, surface).inhibit_system_shortcuts(None)
200223

201224
i = i + 1
202225

203-
def __update_count_down(self, count):
226+
def __update_count_down(self, count: str) -> None:
204227
"""Update the countdown on all break screens."""
205228
for window in self.windows:
206229
window.set_count_down(count)
207230

208-
def __window_set_keep_above_x11(self, window):
231+
def __window_set_keep_above_x11(self, window: "BreakScreenWindow") -> None:
209232
"""Use EWMH hints to keep window above and on all desktops."""
233+
if self.x11_display is None:
234+
return
235+
210236
NET_WM_STATE = self.x11_display.intern_atom("_NET_WM_STATE")
211237
NET_WM_STATE_ABOVE = self.x11_display.intern_atom("_NET_WM_STATE_ABOVE")
212238
NET_WM_STATE_STICKY = self.x11_display.intern_atom("_NET_WM_STATE_STICKY")
@@ -216,7 +242,12 @@ def __window_set_keep_above_x11(self, window):
216242
# See https://specifications.freedesktop.org/wm-spec/1.3/ar01s05.html#id-1.6.8
217243
root_window = self.x11_display.screen().root
218244

219-
xid = GdkX11.X11Surface.get_xid(window.get_surface())
245+
surface = window.get_surface()
246+
247+
if surface is None or not isinstance(surface, GdkX11.X11Surface):
248+
return
249+
250+
xid = GdkX11.X11Surface.get_xid(surface)
220251

221252
root_window.send_event(
222253
Xlib.protocol.event.ClientMessage(
@@ -240,11 +271,14 @@ def __window_set_keep_above_x11(self, window):
240271

241272
self.x11_display.sync()
242273

243-
def __lock_keyboard_x11(self):
274+
def __lock_keyboard_x11(self) -> None:
244275
"""Lock the keyboard to prevent the user from using keyboard shortcuts.
245276
246277
(X11 only)
247278
"""
279+
if self.x11_display is None:
280+
return
281+
248282
logging.info("Lock the keyboard")
249283
self.lock_keyboard = True
250284

@@ -275,7 +309,9 @@ def __lock_keyboard_x11(self):
275309
# Reduce the CPU usage by sleeping for a second
276310
time.sleep(1)
277311

278-
def on_key_pressed_wayland(self, event_controller_key, keyval, keycode, state):
312+
def on_key_pressed_wayland(
313+
self, event_controller_key, keyval, keycode, state
314+
) -> bool:
279315
if self.enable_shortcut:
280316
if keyval == Gdk.KEY_space and self.show_postpone_button:
281317
self.postpone_break()
@@ -286,14 +322,17 @@ def on_key_pressed_wayland(self, event_controller_key, keyval, keycode, state):
286322

287323
return False
288324

289-
def __release_keyboard_x11(self):
325+
def __release_keyboard_x11(self) -> None:
290326
"""Release the locked keyboard."""
327+
if self.x11_display is None:
328+
return
329+
291330
logging.info("Unlock the keyboard")
292331
self.lock_keyboard = False
293332
self.x11_display.ungrab_keyboard(X.CurrentTime)
294333
self.x11_display.flush()
295334

296-
def __destroy_all_screens(self):
335+
def __destroy_all_screens(self) -> None:
297336
"""Close all the break screens."""
298337
for win in self.windows:
299338
win.destroy()
@@ -309,25 +348,25 @@ class BreakScreenWindow(Gtk.Window):
309348

310349
__gtype_name__ = "BreakScreenWindow"
311350

312-
lbl_message = Gtk.Template.Child()
313-
lbl_count = Gtk.Template.Child()
314-
lbl_widget = Gtk.Template.Child()
315-
img_break = Gtk.Template.Child()
316-
box_buttons = Gtk.Template.Child()
317-
toolbar = Gtk.Template.Child()
351+
lbl_message: Gtk.Label = Gtk.Template.Child()
352+
lbl_count: Gtk.Label = Gtk.Template.Child()
353+
lbl_widget: Gtk.Label = Gtk.Template.Child()
354+
img_break: Gtk.Image = Gtk.Template.Child()
355+
box_buttons: Gtk.Box = Gtk.Template.Child()
356+
toolbar: Gtk.Box = Gtk.Template.Child()
318357

319358
def __init__(
320359
self,
321-
application,
322-
message,
323-
image_path,
324-
widget,
325-
tray_actions,
326-
on_close,
327-
show_postpone,
328-
on_postpone,
329-
show_skip,
330-
on_skip,
360+
application: Gtk.Application,
361+
message: str,
362+
image_path: typing.Optional[str],
363+
widget: str,
364+
tray_actions: list[TrayAction],
365+
on_close: typing.Callable[[], None],
366+
show_postpone: bool,
367+
on_postpone: typing.Callable[[Gtk.Button], None],
368+
show_skip: bool,
369+
on_skip: typing.Callable[[Gtk.Button], None],
331370
):
332371
super().__init__(application=application)
333372

@@ -372,10 +411,10 @@ def __init__(
372411
self.lbl_message.set_label(message)
373412
self.lbl_widget.set_markup(widget)
374413

375-
def set_count_down(self, count):
414+
def set_count_down(self, count: str) -> None:
376415
self.lbl_count.set_text(count)
377416

378-
def __tray_action(self, button, tray_action: TrayAction):
417+
def __tray_action(self, button, tray_action: TrayAction) -> None:
379418
"""Tray action handler.
380419
381420
Hides all toolbar buttons for this action and call the action
@@ -386,7 +425,7 @@ def __tray_action(self, button, tray_action: TrayAction):
386425
tray_action.action()
387426

388427
@Gtk.Template.Callback()
389-
def on_window_delete(self, *args):
428+
def on_window_delete(self, *args) -> None:
390429
"""Window close event handler."""
391430
logging.info("Closing the break screen")
392431
self.on_close()

0 commit comments

Comments
 (0)