Skip to content

Commit 6833bd5

Browse files
authored
Merge pull request slgobinath#749 from deltragon/thread-fixes
threading fixes
2 parents 785db28 + 3a626cb commit 6833bd5

File tree

4 files changed

+37
-46
lines changed

4 files changed

+37
-46
lines changed

safeeyes/context.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import typing
2222

2323
from safeeyes import utility
24-
from safeeyes.model import State
24+
from safeeyes.model import BreakType, State
2525

2626
if typing.TYPE_CHECKING:
2727
from safeeyes.safeeyes import SafeEyes
@@ -60,8 +60,8 @@ def status(self) -> str:
6060
def quit(self) -> None:
6161
utility.execute_main_thread(self._application.quit)
6262

63-
def take_break(self, break_type=None) -> None:
64-
self._application.take_break(break_type)
63+
def take_break(self, break_type: typing.Optional[BreakType] = None) -> None:
64+
utility.execute_main_thread(self._application.take_break, break_type)
6565

6666
def has_breaks(self, break_type=None) -> bool:
6767
return self._application.safe_eyes_core.has_breaks(break_type)

safeeyes/plugins/trayicon/plugin.py

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
from safeeyes import utility
2727
from safeeyes.context import Context
2828
from safeeyes.translations import translate as _
29-
import threading
3029
import typing
3130

3231
"""
@@ -440,6 +439,8 @@ class TrayIcon:
440439
_animation_timeout_id: typing.Optional[int] = None
441440
_animation_icon_enabled: bool = False
442441

442+
_resume_timeout_id: typing.Optional[int] = None
443+
443444
def __init__(self, context: Context, plugin_config):
444445
self.context = context
445446
self.on_show_settings = context.api.show_settings
@@ -454,8 +455,6 @@ def __init__(self, context: Context, plugin_config):
454455
self.date_time = None
455456
self.active = True
456457
self.wakeup_time = None
457-
self.idle_condition = threading.Condition()
458-
self.lock = threading.Lock()
459458
self.allow_disabling = plugin_config["allow_disabling"]
460459
self.menu_locked = False
461460

@@ -663,12 +662,9 @@ def quit_safe_eyes(self):
663662
664663
This action terminates the application.
665664
"""
666-
with self.lock:
667-
self.active = True
668-
# Notify all schedulers
669-
self.idle_condition.acquire()
670-
self.idle_condition.notify_all()
671-
self.idle_condition.release()
665+
self.active = True
666+
self.__clear_resume_timer()
667+
672668
self.quit()
673669

674670
def show_settings(self) -> None:
@@ -720,13 +716,9 @@ def on_enable_clicked(self):
720716
This action enables the application if it is currently disabled.
721717
"""
722718
if not self.active:
723-
with self.lock:
724-
self.enable_ui()
725-
self.enable_safeeyes()
726-
# Notify all schedulers
727-
self.idle_condition.acquire()
728-
self.idle_condition.notify_all()
729-
self.idle_condition.release()
719+
self.enable_ui()
720+
self.enable_safeeyes()
721+
self.__clear_resume_timer()
730722

731723
def on_disable_clicked(self, time_to_wait):
732724
"""Handle the menu actions of all the sub menus of 'Disable Safe Eyes'.
@@ -746,7 +738,9 @@ def on_disable_clicked(self, time_to_wait):
746738
)
747739
info = _("Disabled until %s") % utility.format_time(self.wakeup_time)
748740
self.disable_safeeyes(info)
749-
utility.start_thread(self.__schedule_resume, time_minutes=time_to_wait)
741+
self._resume_timeout_id = GLib.timeout_add_seconds(
742+
time_to_wait * 60, self.__resume
743+
)
750744
self.update_menu()
751745

752746
def lock_menu(self):
@@ -783,17 +777,19 @@ def enable_ui(self):
783777
self.sni_service.set_icon("io.github.slgobinath.SafeEyes-enabled")
784778
self.update_menu()
785779

786-
def __schedule_resume(self, time_minutes):
787-
"""Schedule a local timer to enable Safe Eyes after the given
788-
timeout.
789-
"""
790-
self.idle_condition.acquire()
791-
self.idle_condition.wait(time_minutes * 60) # Convert to seconds
792-
self.idle_condition.release()
780+
def __resume(self):
781+
"""Reenable Safe Eyes after the given timeout."""
782+
if not self.active:
783+
self.on_enable_clicked()
784+
785+
self._resume_timeout_id = None
786+
787+
return GLib.SOURCE_REMOVE
793788

794-
with self.lock:
795-
if not self.active:
796-
utility.execute_main_thread(self.on_enable_clicked)
789+
def __clear_resume_timer(self):
790+
if self._resume_timeout_id is not None:
791+
GLib.source_remove(self._resume_timeout_id)
792+
self._resume_timeout_id = None
797793

798794
def start_animation(self) -> None:
799795
if self._animation_timeout_id is not None:

safeeyes/safeeyes.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
from safeeyes.ui.about_dialog import AboutDialog
3131
from safeeyes.ui.break_screen import BreakScreen
3232
from safeeyes.ui.required_plugin_dialog import RequiredPluginDialog
33-
from safeeyes.model import State, RequiredPluginException
33+
from safeeyes.model import BreakType, State, RequiredPluginException
3434
from safeeyes.translations import translate as _
3535
from safeeyes.plugin_manager import PluginManager
3636
from safeeyes.core import SafeEyesCore
@@ -536,9 +536,9 @@ def stop_break(self):
536536
self.plugins_manager.stop_break()
537537
return True
538538

539-
def take_break(self, break_type=None):
539+
def take_break(self, break_type: typing.Optional[BreakType] = None) -> None:
540540
"""Take a break now."""
541-
utility.execute_main_thread(self.safe_eyes_core.take_break, break_type)
541+
self.safe_eyes_core.take_break(break_type)
542542

543543
def status(self):
544544
"""Return the status of Safe Eyes."""

safeeyes/ui/break_screen.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333

3434
gi.require_version("Gtk", "4.0")
3535
from gi.repository import Gdk
36-
from gi.repository import GLib
3736
from gi.repository import Gtk
3837
from gi.repository import GdkX11
3938

@@ -121,7 +120,7 @@ def show_count_down(self, countdown: int, seconds: int) -> None:
121120
self.enable_shortcut = self.shortcut_disable_time <= seconds
122121
mins, secs = divmod(countdown, 60)
123122
timeformat = "{:02d}:{:02d}".format(mins, secs)
124-
GLib.idle_add(lambda: self.__update_count_down(timeformat))
123+
self.__update_count_down(timeformat)
125124

126125
def show_message(
127126
self, break_obj: Break, widget: str, tray_actions: list[TrayAction] = []
@@ -130,9 +129,7 @@ def show_message(
130129
message = break_obj.name
131130
image_path = break_obj.image
132131
self.enable_shortcut = self.shortcut_disable_time <= 0
133-
GLib.idle_add(
134-
lambda: self.__show_break_screen(message, image_path, widget, tray_actions)
135-
)
132+
self.__show_break_screen(message, image_path, widget, tray_actions)
136133

137134
def close(self) -> None:
138135
"""Hide the break screen from active window and destroy all other
@@ -143,7 +140,7 @@ def close(self) -> None:
143140
self.__release_keyboard_x11()
144141

145142
# Destroy other windows if exists
146-
GLib.idle_add(lambda: self.__destroy_all_screens())
143+
self.__destroy_all_screens()
147144

148145
def __show_break_screen(
149146
self,
@@ -298,18 +295,21 @@ def __lock_keyboard_x11(self) -> None:
298295
event.detail == self.keycode_shortcut_skip
299296
and self.show_skip_button
300297
):
301-
self.skip_break()
298+
utility.execute_main_thread(lambda: self.skip_break())
302299
break
303300
elif (
304301
event.detail == self.keycode_shortcut_postpone
305302
and self.show_postpone_button
306303
):
307-
self.postpone_break()
304+
utility.execute_main_thread(lambda: self.postpone_break())
308305
break
309306
else:
310307
# Reduce the CPU usage by sleeping for a second
311308
time.sleep(1)
312309

310+
self.x11_display.ungrab_keyboard(X.CurrentTime)
311+
self.x11_display.flush()
312+
313313
def on_key_pressed_wayland(
314314
self, event_controller_key, keyval, keycode, state
315315
) -> bool:
@@ -325,13 +325,8 @@ def on_key_pressed_wayland(
325325

326326
def __release_keyboard_x11(self) -> None:
327327
"""Release the locked keyboard."""
328-
if self.x11_display is None:
329-
return
330-
331328
logging.info("Unlock the keyboard")
332329
self.lock_keyboard = False
333-
self.x11_display.ungrab_keyboard(X.CurrentTime)
334-
self.x11_display.flush()
335330

336331
def __destroy_all_screens(self) -> None:
337332
"""Close all the break screens."""

0 commit comments

Comments
 (0)