Refactor plugin logs

This commit is contained in:
Gobinath 2021-06-14 20:17:15 -04:00
parent 7d9ef930d0
commit cfb45c609a
9 changed files with 245 additions and 262 deletions

View File

@ -43,7 +43,7 @@ class Player:
@staticmethod
def __play(resource: str) -> None:
logging.info('Audible Alert: playing audio %s', resource)
logging.debug('Audible Alert: playing audio %s', resource)
# Open the sound file
path = utility.get_resource_path(resource)
if path is not None:

View File

@ -1,7 +1,7 @@
# Safe Eyes is a utility to remind you to take break frequently
# to protect your eyes from eye strain.
# Copyright (C) 2021 Gobinath
# Copyright (C) 2017 Gobinath
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -28,8 +28,9 @@ from safeeyes.context import Context
from safeeyes.spi.breaks import Break
from safeeyes.spi.plugin import TrayAction
from safeeyes.thread import main, worker
from safeeyes.util.locale import _
gi.require_version('Gtk', '3.0')
gi.require_version("Gtk", "3.0")
from gi.repository import Gdk
from gi.repository import Gtk
@ -46,12 +47,12 @@ class BreakScreen:
self.__context: Context = context
self.__count_labels: List[Gtk.Label] = []
self.__display: Display = Display()
self.__allow_skipping: bool = config.get('allow_skipping', True)
self.__allow_postponing: bool = config.get('allow_postponing', False)
self.__postpone_duration: int = config.get('postpone_duration', 5) * 60
self.__keycode_shortcut_skip: int = config.get('skip_keyboard_shortcut', 9)
self.__keycode_shortcut_postpone: int = config.get('postpone_keyboard_shortcut', 65)
self.__shortcut_disable_time: int = config.get('keyboard_disabled_period', 2)
self.__allow_skipping: bool = config.get("allow_skipping", True)
self.__allow_postponing: bool = config.get("allow_postponing", False)
self.__postpone_duration: int = config.get("postpone_duration", 5) * 60
self.__keycode_shortcut_skip: int = config.get("skip_keyboard_shortcut", 9)
self.__keycode_shortcut_postpone: int = config.get("postpone_keyboard_shortcut", 65)
self.__shortcut_disable_time: int = config.get("keyboard_disabled_period", 2)
self.__enable_shortcut: bool = False
self.__keyboard_locked: bool = False
self.__windows: List[Gtk.Window] = []
@ -66,7 +67,7 @@ class BreakScreen:
"""
Skip the break from the break screen
"""
logging.info("User skipped the break")
logging.debug("Break Screen: user skipped the break")
# Must call on_skip before close to lock screen before closing the break screen
self.__context.break_api.skip()
self.close()
@ -75,7 +76,7 @@ class BreakScreen:
"""
Postpone the break from the break screen
"""
logging.info("User postponed the break")
logging.debug("Break Screen: user postponed the break")
self.__context.break_api.postpone(self.__postpone_duration)
self.close()
@ -83,7 +84,6 @@ class BreakScreen:
"""
Window close event handler.
"""
logging.info("Closing the break screen")
self.close()
def on_skip_clicked(self, button):
@ -104,7 +104,7 @@ class BreakScreen:
"""
self.__enable_shortcut = 0 <= self.__shortcut_disable_time <= seconds
minutes, secs = divmod(countdown, 60)
time_format = '{:02d}:{:02d}'.format(minutes, secs)
time_format = "{:02d}:{:02d}".format(minutes, secs)
self.__update_count_down(time_format)
def show_message(self, break_obj):
@ -123,7 +123,7 @@ class BreakScreen:
"""
Hide the break screen from active window and destroy all other windows
"""
logging.info("Close the break screen(s)")
logging.debug("Break Screen: close the break screen(s)")
self.__release_keyboard()
# Destroy other windows if exists
@ -148,7 +148,7 @@ class BreakScreen:
screen = Gtk.Window().get_screen()
no_of_monitors = screen.get_n_monitors()
logging.info("Show break screens in %d display(s)", no_of_monitors)
logging.debug("Break Screen: show break screens in %d display(s)", no_of_monitors)
for monitor in range(no_of_monitors):
monitor_gemoetry = screen.get_monitor_geometry(monitor)
@ -184,17 +184,17 @@ class BreakScreen:
# Add the buttons
if self.__allow_postponing:
# Add postpone button
btn_postpone = Gtk.Button(_('Postpone'))
btn_postpone.get_style_context().add_class('btn_postpone')
btn_postpone.connect('clicked', self.on_postpone_clicked)
btn_postpone = Gtk.Button(_("Postpone"))
btn_postpone.get_style_context().add_class("btn_postpone")
btn_postpone.connect("clicked", self.on_postpone_clicked)
btn_postpone.set_visible(True)
box_buttons.pack_start(btn_postpone, True, True, 0)
if self.__allow_skipping:
# Add the skip button
btn_skip = Gtk.Button(_('Skip'))
btn_skip.get_style_context().add_class('btn_skip')
btn_skip.connect('clicked', self.on_skip_clicked)
btn_skip = Gtk.Button(_("Skip"))
btn_skip.get_style_context().add_class("btn_skip")
btn_skip.connect("clicked", self.on_skip_clicked)
btn_skip.set_visible(True)
box_buttons.pack_start(btn_skip, True, True, 0)
@ -209,7 +209,7 @@ class BreakScreen:
# Set visual to apply css theme. It should be called before show method.
window.set_visual(window.get_screen().get_rgba_visual())
if self.__context.env.name == 'kde':
if self.__context.env.name == "kde":
# Fix flickering screen in KDE by setting opacity to 1
window.set_opacity(0.9)
@ -223,7 +223,7 @@ class BreakScreen:
# In other desktop environments, move the window after present
window.move(x, y)
window.resize(monitor_gemoetry.width, monitor_gemoetry.height)
logging.info("Moved break screen to Display[%d, %d]", x, y)
logging.debug("Break Screen: Moved break screen to Display[%d, %d]", x, y)
@main
def __update_count_down(self, count):
@ -238,7 +238,7 @@ class BreakScreen:
"""
Lock the keyboard to prevent the user from using keyboard shortcuts
"""
logging.info("Lock the keyboard")
logging.debug("Break Screen: lock the keyboard")
self.__keyboard_locked = True
# # Grab the keyboard
@ -266,7 +266,7 @@ class BreakScreen:
"""
Release the locked keyboard.
"""
logging.info("Break Screen: unlock the keyboard")
logging.debug("Break Screen: unlock the keyboard")
self.__keyboard_locked = False
# self.__display.ungrab_keyboard(X.CurrentTime)
# self.__display.flush()
@ -282,7 +282,7 @@ class BreakScreen:
del self.__count_labels[:]
def __get_widgets(self, break_obj: Break) -> str:
widget_html = ''
widget_html = ""
for widget in self.__context.plugin_api.get_widgets(break_obj):
if widget is not None and not widget.is_empty():
widget_html += widget.format()
@ -298,7 +298,7 @@ def init(context: Context, config: dict) -> None:
"""
This function is called to initialize the plugin.
"""
logging.info('Break Screen: initialize the plugin')
logging.info("Break Screen: initialize the plugin")
global safe_eyes_context, break_config
safe_eyes_context = context
break_config = config

View File

@ -54,7 +54,7 @@ class SystemState:
return self.__is_wayland_full_screen() if self.__context.env.is_wayland() else self.__is_xorg_full_screen()
def __is_wayland_full_screen(self) -> bool:
logging.info('Do Not Disturb: searching for full-screen application in wayland')
logging.debug('Do Not Disturb: searching for full-screen application in wayland')
cmdlist = ['wlrctl', 'toplevel', 'find', 'state:fullscreen']
try:
process = subprocess.Popen(cmdlist, stdout=subprocess.PIPE)
@ -75,7 +75,7 @@ class SystemState:
Check for full-screen applications.
This method must be executed by the main thread. If not, it will cause random failure.
"""
logging.info('Do Not Disturb: searching for full-screen application in xorg')
logging.debug('Do Not Disturb: searching for full-screen application in xorg')
screen = Gdk.Screen.get_default()
active_window = screen.get_active_window()
@ -117,7 +117,7 @@ class SystemState:
"""
on_battery = False
power_sources = os.listdir('/sys/class/power_supply')
logging.info('Do Not Disturb: looking for battery status in available power sources: %s' % str(power_sources))
logging.debug('Do Not Disturb: looking for battery status in available power sources: %s' % str(power_sources))
for power_source in power_sources:
if 'BAT' in power_source:
# Found battery
@ -140,7 +140,7 @@ system_state: SystemState
def init(ctx: Context, plugin_config: dict):
logging.debug('Do Not Disturb: initialize the plugin')
logging.info('Do Not Disturb: initialize the plugin')
global system_state
system_state = SystemState(ctx, plugin_config)

View File

@ -145,7 +145,7 @@ def init(ctx: Context, plugin_config: dict) -> None:
"""
Initialize the plugin.
"""
logging.debug('Health Stats: initialize the plugin')
logging.info('Health Stats: initialize the plugin')
global stats
stats = HealthStats(ctx, plugin_config)

View File

@ -66,7 +66,7 @@ def init(ctx: Context, plugin_config: dict) -> None:
"""
Initialize the screensaver plugin.
"""
logging.info('Initialize Media Control plugin')
logging.info('Media Control: initialize the plugin')
global tray_icon_path
tray_icon_path = os.path.join(plugin_config['path'], "resource/pause.png")

View File

@ -22,15 +22,16 @@ import gi
from safeeyes.context import Context
from safeeyes.spi.breaks import BreakType, Break
from safeeyes.util.locale import _
gi.require_version('Notify', '0.7')
gi.require_version("Notify", "0.7")
from gi.repository import Notify
"""
Safe Eyes Notification plugin
"""
APPINDICATOR_ID = 'safeeyes'
APPINDICATOR_ID = "safeeyes"
notification = None
context = None
warning_time = 10
@ -44,9 +45,9 @@ def init(ctx: Context, plugin_config: dict) -> None:
"""
global context
global warning_time
logging.debug('Initialize Notification plugin')
logging.info("Notification: initialize the plugin")
context = ctx
warning_time = ctx.config.get('pre_break_warning_time')
warning_time = ctx.config.get("pre_break_warning_time")
def on_pre_break(break_obj: Break) -> None:
@ -55,18 +56,18 @@ def on_pre_break(break_obj: Break) -> None:
"""
# Construct the message based on the type of the next break
global notification
logging.info('Show the notification')
message = '\n'
logging.debug("Notification: show the notification")
message = "\n"
if break_obj.type == BreakType.SHORT:
message += (_('Ready for a short break in %s seconds') % warning_time)
message += (_("Ready for a short break in %s seconds") % warning_time)
else:
message += (_('Ready for a long break in %s seconds') % warning_time)
message += (_("Ready for a long break in %s seconds") % warning_time)
notification = Notify.Notification.new('Safe Eyes', message, icon='safeeyes_enabled')
notification = Notify.Notification.new("Safe Eyes", message, icon="safeeyes_enabled")
try:
notification.show()
except BaseException:
logging.error('Failed to show the notification')
logging.error("Notification: failed to show the notification")
def on_start_break(break_obj: Break) -> None:
@ -74,7 +75,7 @@ def on_start_break(break_obj: Break) -> None:
Close the notification.
"""
global notification
logging.info('Close pre-break notification')
logging.debug("Notification: close the pre-break notification")
if notification:
try:
notification.close()
@ -88,5 +89,5 @@ def on_exit() -> None:
"""
Uninitialize the registered notificaion.
"""
logging.debug('Stop Notification plugin')
logging.info("Notification: stop the plugin")
Notify.uninit()

View File

@ -31,16 +31,16 @@ from safeeyes.env import system
from safeeyes.spi.breaks import Break
from safeeyes.spi.plugin import TrayAction
gi.require_version('Gtk', '3.0')
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class Screensaver:
def __init__(self, ctx: Context, config: dict):
self.min_seconds: int = config['min_seconds']
self.__tray_icon_path: str = os.path.join(config['path'], "resource/lock.png")
self.__command: List[str] = config['command'].split() if config[
'command'] else Screensaver.__lock_screen_command(ctx.env.name)
self.min_seconds: int = config["min_seconds"]
self.__tray_icon_path: str = os.path.join(config["path"], "resource/lock.png")
self.__command: List[str] = config["command"].split() if config[
"command"] else Screensaver.__lock_screen_command(ctx.env.name)
self.__lock_required = False
def reset(self) -> None:
@ -61,31 +61,31 @@ class Screensaver:
"""
Function tries to detect the screensaver command based on the current environment
Possible results:
Gnome, Unity, Budgie: ['gnome-screensaver-command', '--lock']
Cinnamon: ['cinnamon-screensaver-command', '--lock']
Pantheon, LXDE: ['light-locker-command', '--lock']
Mate: ['mate-screensaver-command', '--lock']
KDE: ['qdbus', 'org.freedesktop.ScreenSaver', '/ScreenSaver', 'Lock']
XFCE: ['xflock4']
Gnome, Unity, Budgie: ["gnome-screensaver-command", "--lock"]
Cinnamon: ["cinnamon-screensaver-command", "--lock"]
Pantheon, LXDE: ["light-locker-command", "--lock"]
Mate: ["mate-screensaver-command", "--lock"]
KDE: ["qdbus", "org.freedesktop.ScreenSaver", "/ScreenSaver", "Lock"]
XFCE: ["xflock4"]
Otherwise: None
"""
if desktop is not None:
if desktop == 'xfce' and utility.command_exist('xflock4'):
return ['xflock4']
elif desktop == 'cinnamon' and utility.command_exist('cinnamon-screensaver-command'):
return ['cinnamon-screensaver-command', '--lock']
elif (desktop == 'pantheon' or desktop == 'lxde') and utility.command_exist('light-locker-command'):
return ['light-locker-command', '--lock']
elif desktop == 'mate' and utility.command_exist('mate-screensaver-command'):
return ['mate-screensaver-command', '--lock']
elif desktop == 'kde':
return ['qdbus', 'org.freedesktop.ScreenSaver', '/ScreenSaver', 'Lock']
elif desktop in ['gnome', 'unity', 'budgie-desktop']:
if utility.command_exist('gnome-screensaver-command'):
return ['gnome-screensaver-command', '--lock']
if desktop == "xfce" and utility.command_exist("xflock4"):
return ["xflock4"]
elif desktop == "cinnamon" and utility.command_exist("cinnamon-screensaver-command"):
return ["cinnamon-screensaver-command", "--lock"]
elif (desktop == "pantheon" or desktop == "lxde") and utility.command_exist("light-locker-command"):
return ["light-locker-command", "--lock"]
elif desktop == "mate" and utility.command_exist("mate-screensaver-command"):
return ["mate-screensaver-command", "--lock"]
elif desktop == "kde":
return ["qdbus", "org.freedesktop.ScreenSaver", "/ScreenSaver", "Lock"]
elif desktop in ["gnome", "unity", "budgie-desktop"]:
if utility.command_exist("gnome-screensaver-command"):
return ["gnome-screensaver-command", "--lock"]
# From Gnome 3.8 no gnome-screensaver-command
return ['dbus-send', '--type=method_call', '--dest=org.gnome.ScreenSaver', '/org/gnome/ScreenSaver',
'org.gnome.ScreenSaver.Lock']
return ["dbus-send", "--type=method_call", "--dest=org.gnome.ScreenSaver", "/org/gnome/ScreenSaver",
"org.gnome.ScreenSaver.Lock"]
return None
@ -97,11 +97,11 @@ def init(ctx: Context, plugin_config: dict) -> None:
"""
Initialize the screensaver plugin.
"""
logging.debug('Initialize Screensaver plugin')
logging.info("Screensaver: initialize the plugin")
global screensaver
global tray_icon_path
screensaver = Screensaver(ctx, plugin_config)
tray_icon_path = os.path.join(plugin_config['path'], "resource/lock.png")
tray_icon_path = os.path.join(plugin_config["path"], "resource/lock.png")
def on_start_break(break_obj: Break) -> None:

View File

@ -36,13 +36,13 @@ class SmartPause:
self.__context = context
self.__lock: threading.Lock = threading.Lock()
self.__condition: ThreadCondition = context.thread_api.new_condition()
self.__postpone_if_active = config['postpone_if_active']
self.__idle_time = config['idle_time']
self.__interpret_idle_as_break = config['interpret_idle_as_break']
self.__short_break_interval = context.config.get('short_break_interval') * 60 # Convert to seconds
self.__long_break_duration = context.config.get('long_break_duration')
self.__postpone_if_active = config["postpone_if_active"]
self.__idle_time = config["idle_time"]
self.__interpret_idle_as_break = config["interpret_idle_as_break"]
self.__short_break_interval = context.config.get("short_break_interval") * 60 # Convert to seconds
self.__long_break_duration = context.config.get("long_break_duration")
self.__waiting_time = min(2, self.__idle_time) # If idle time is 1 sec, wait only 1 sec
self.__is_wayland_and_gnome = context.env.name == 'gnome' and context.env.is_wayland()
self.__is_wayland_and_gnome = context.env.name == "gnome" and context.env.is_wayland()
self.__active: bool = False
self.__smart_pause_activated: bool = False
self.__next_break_time: datetime.datetime = None
@ -52,7 +52,7 @@ class SmartPause:
def start(self) -> None:
if not self.__is_active():
# If SmartPause is already started, do not start it again
logging.debug('Start Smart Pause plugin')
logging.debug("Start Smart Pause plugin")
self.__set_active(True)
self.__start_idle_monitor()
@ -61,7 +61,7 @@ class SmartPause:
# Safe Eyes is stopped due to system idle
self.__smart_pause_activated = False
return
logging.debug('Stop Smart Pause plugin')
logging.debug("Stop Smart Pause plugin")
self.__set_active(False)
self.__condition.release_all()
@ -80,8 +80,8 @@ class SmartPause:
return False
def clean(self) -> None:
session_config = self.__context.session.get_plugin('smartpause')
session_config.pop('idle_period', None)
session_config = self.__context.session.get_plugin("smartpause")
session_config.pop("idle_period", None)
def __system_idle_time(self) -> int:
if self.__is_wayland_and_gnome:
@ -119,22 +119,23 @@ class SmartPause:
if system_idle_time >= self.__idle_time and self.__context.state == State.WAITING:
self.__smart_pause_activated = True
self.__idle_start_time = datetime.datetime.now() - datetime.timedelta(seconds=system_idle_time)
logging.info('Pause Safe Eyes due to system idle')
logging.debug("Smart Pause: pause Safe Eyes due to system idle")
self.__context.core_api.stop()
elif system_idle_time < self.__idle_time and self.__context.state == State.STOPPED and self.__idle_start_time is not None:
logging.info('Resume Safe Eyes due to user activity')
logging.debug("Smart Pause: resume Safe Eyes due to user activity")
self.__smart_pause_activated = False
idle_period = (datetime.datetime.now() - self.__idle_start_time)
idle_seconds = idle_period.total_seconds()
session_config = self.__context.session.get_plugin('smartpause')
session_config['idle_period'] = idle_seconds
self.__context.session.set_plugin('smartpause', session_config)
session_config = self.__context.session.get_plugin("smartpause")
session_config["idle_period"] = idle_seconds
self.__context.session.set_plugin("smartpause", session_config)
if self.__interpret_idle_as_break and idle_seconds >= self.__next_break_duration:
# User is idle for break duration and wants to consider it as a break
logging.debug("Idle for %d seconds, long break %d", idle_seconds, self.__long_break_duration)
logging.debug("Smart Pause: idle for %d seconds and the long break duration is %d",
idle_seconds, self.__long_break_duration)
self.__context.core_api.start(
reset_breaks=(idle_seconds >= self.__long_break_duration))
elif idle_seconds < self.__short_break_interval:
@ -158,9 +159,9 @@ class SmartPause:
"""
try:
# Convert to seconds
return int(subprocess.check_output(['xprintidle']).decode('utf-8')) / 1000
return int(subprocess.check_output(["xprintidle"]).decode("utf-8")) / 1000
except BaseException as e:
logging.warning("Failed to get system idle time for xorg.")
logging.warning("Smart Pause: failed to get system idle time for xorg.")
logging.warning(str(e))
return 0
@ -168,20 +169,20 @@ class SmartPause:
def __gnome_wayland_idle_time():
"""
Determine system idle time in seconds, specifically for gnome with wayland.
If there's a failure, return 0.
If there"s a failure, return 0.
https://unix.stackexchange.com/a/492328/222290
"""
try:
output = subprocess.check_output([
'dbus-send',
'--print-reply',
'--dest=org.gnome.Mutter.IdleMonitor',
'/org/gnome/Mutter/IdleMonitor/Core',
'org.gnome.Mutter.IdleMonitor.GetIdletime'
"dbus-send",
"--print-reply",
"--dest=org.gnome.Mutter.IdleMonitor",
"/org/gnome/Mutter/IdleMonitor/Core",
"org.gnome.Mutter.IdleMonitor.GetIdletime"
])
return int(re.search(rb'\d+$', output).group(0)) / 1000
return int(re.search(rb"\d+$", output).group(0)) / 1000
except BaseException as e:
logging.warning("Failed to get system idle time for gnome/wayland.")
logging.warning("Smart Pause: failed to get system idle time for gnome/wayland.")
logging.warning(str(e))
return 0
@ -193,7 +194,7 @@ def init(context: Context, plugin_config: dict):
"""
Initialize the plugin.
"""
logging.info('Initialize Smart Pause plugin')
logging.info("Smart Pause: initialize the plugin")
global smart_pause
smart_pause = SmartPause(context, plugin_config)

View File

@ -24,9 +24,10 @@ import gi
from safeeyes.context import Context
from safeeyes.spi.breaks import BreakType
from safeeyes.thread import worker, main
from safeeyes.util.locale import _
gi.require_version('Gtk', '3.0')
gi.require_version('AppIndicator3', '0.1')
gi.require_version("Gtk", "3.0")
gi.require_version("AppIndicator3", "0.1")
from gi.repository import AppIndicator3 as appindicator
from gi.repository import Gtk
import logging
@ -38,7 +39,7 @@ import time
Safe Eyes tray icon plugin
"""
APPINDICATOR_ID = 'safeeyes_2'
APPINDICATOR_ID = "safeeyes_2"
class TrayIcon:
@ -52,199 +53,182 @@ class TrayIcon:
self.__date_time = None
self.__active = True
self.__wakeup_time = None
self.__idle_condition = threading.Condition()
self.lock = threading.Lock()
self.__allow_disabling = plugin_config['allow_disabling']
self.__idle_condition = ctx.thread_api.new_condition()
self.__lock = threading.Lock()
self.__allow_disabling = plugin_config["allow_disabling"]
self.__animate = False
# Construct the tray icon
self.indicator = appindicator.Indicator.new(
self.__indicator = appindicator.Indicator.new(
APPINDICATOR_ID, "safeeyes_enabled", appindicator.IndicatorCategory.APPLICATION_STATUS)
self.indicator.set_status(appindicator.IndicatorStatus.ACTIVE)
self.__indicator.set_status(appindicator.IndicatorStatus.ACTIVE)
# Construct the context menu
self.menu = Gtk.Menu()
self.__menu = Gtk.Menu()
self.__item_info = Gtk.ImageMenuItem()
self.__item_separator = Gtk.SeparatorMenuItem()
self.__item_enable = Gtk.MenuItem()
self.__item_disable = Gtk.MenuItem()
self.__sub_menu_item_until_restart = Gtk.MenuItem()
self.__item_settings = Gtk.MenuItem()
self.__item_about = Gtk.MenuItem()
self.__item_quit = Gtk.MenuItem()
self.__item_manual_break = Gtk.MenuItem()
self.__sub_menu_manual_next_break = Gtk.MenuItem()
self.__sub_menu_manual_next_short_break = Gtk.MenuItem()
self.__sub_menu_manual_next_long_break = Gtk.MenuItem()
self.__sub_menu_disable = Gtk.Menu()
self.__sub_menu_manual_break = Gtk.Menu()
# Next break info menu item
self.item_info = Gtk.ImageMenuItem()
img_timer = Gtk.Image()
img_timer.set_from_icon_name("safeeyes_timer", 16)
self.item_info.set_image(img_timer)
self.__item_info.set_image(img_timer)
self.item_separator = Gtk.SeparatorMenuItem()
self.item_enable = Gtk.MenuItem()
self.item_enable.connect('activate', self.on_enable_clicked)
self.item_disable = Gtk.MenuItem()
self.sub_menu_disable = Gtk.Menu()
self.sub_menu_disable_items = []
self.__sub_menu_disable_items = []
# Read disable options and build the sub menu
for disable_option in plugin_config['disable_options']:
time_in_minutes = disable_option['time']
for disable_option in plugin_config["disable_options"]:
time_in_minutes = disable_option["time"]
label = []
# Validate time value
if not isinstance(time_in_minutes, int) or time_in_minutes <= 0:
logging.error('Invalid time in disable option: ' + str(time_in_minutes))
logging.error("Invalid time in disable option: " + str(time_in_minutes))
continue
time_unit = disable_option['unit'].lower()
if time_unit == 'seconds' or time_unit == 'second':
time_unit = disable_option["unit"].lower()
if time_unit == "seconds" or time_unit == "second":
time_in_minutes = int(time_in_minutes / 60)
label = ['For %d Second', 'For %d Seconds']
elif time_unit == 'minutes' or time_unit == 'minute':
label = ["For %d Second", "For %d Seconds"]
elif time_unit == "minutes" or time_unit == "minute":
time_in_minutes = int(time_in_minutes * 1)
label = ['For %d Minute', 'For %d Minutes']
elif time_unit == 'hours' or time_unit == 'hour':
label = ["For %d Minute", "For %d Minutes"]
elif time_unit == "hours" or time_unit == "hour":
time_in_minutes = int(time_in_minutes * 60)
label = ['For %d Hour', 'For %d Hours']
label = ["For %d Hour", "For %d Hours"]
else:
# Invalid unit
logging.error('Invalid unit in disable option: ' + str(disable_option))
logging.error("Invalid unit in disable option: " + str(disable_option))
continue
# Create submenu
sub_menu_item = Gtk.MenuItem()
sub_menu_item.connect('activate', self.on_disable_clicked, time_in_minutes)
self.sub_menu_disable_items.append([sub_menu_item, label, disable_option['time']])
self.sub_menu_disable.append(sub_menu_item)
sub_menu_item.connect("activate", self.on_disable_clicked, time_in_minutes)
self.__sub_menu_disable_items.append([sub_menu_item, label, disable_option["time"]])
self.__sub_menu_disable.append(sub_menu_item)
# Disable until restart submenu
self.sub_menu_item_until_restart = Gtk.MenuItem()
self.sub_menu_item_until_restart.connect('activate', self.on_disable_clicked, -1)
self.sub_menu_disable.append(self.sub_menu_item_until_restart)
self.__sub_menu_disable.append(self.__sub_menu_item_until_restart)
self.__item_disable.set_submenu(self.__sub_menu_disable)
self.__sub_menu_manual_break.append(self.__sub_menu_manual_next_break)
self.__sub_menu_manual_break.append(self.__sub_menu_manual_next_short_break)
self.__sub_menu_manual_break.append(self.__sub_menu_manual_next_long_break)
self.__item_manual_break.set_submenu(self.__sub_menu_manual_break)
# Add the sub menu to the enable/disable menu
self.item_disable.set_submenu(self.sub_menu_disable)
self.__sub_menu_item_until_restart.connect("activate", self.on_disable_clicked, -1)
self.__sub_menu_manual_next_break.connect("activate", self.on_manual_break_clicked, None)
self.__sub_menu_manual_next_short_break.connect("activate", self.on_manual_break_clicked, BreakType.SHORT)
self.__sub_menu_manual_next_long_break.connect("activate", self.on_manual_break_clicked, BreakType.LONG)
self.__item_enable.connect("activate", self.on_enable_clicked)
self.__item_settings.connect("activate", self.show_settings)
self.__item_about.connect("activate", self.show_about)
self.__item_quit.connect("activate", self.quit_safe_eyes)
# Settings menu item
self.item_manual_break = Gtk.MenuItem()
self.sub_menu_manual_next_break = Gtk.MenuItem()
self.sub_menu_manual_next_break.connect('activate', self.on_manual_break_clicked, None)
self.sub_menu_manual_next_short_break = Gtk.MenuItem()
self.sub_menu_manual_next_short_break.connect('activate', self.on_manual_break_clicked, BreakType.SHORT)
self.sub_menu_manual_next_long_break = Gtk.MenuItem()
self.sub_menu_manual_next_long_break.connect('activate', self.on_manual_break_clicked, BreakType.LONG)
self.sub_menu_manual_break = Gtk.Menu()
self.sub_menu_manual_break.append(self.sub_menu_manual_next_break)
self.sub_menu_manual_break.append(self.sub_menu_manual_next_short_break)
self.sub_menu_manual_break.append(self.sub_menu_manual_next_long_break)
self.item_manual_break.set_submenu(self.sub_menu_manual_break)
# Settings menu item
self.item_settings = Gtk.MenuItem()
self.item_settings.connect('activate', self.show_settings)
# About menu item
self.item_about = Gtk.MenuItem()
self.item_about.connect('activate', self.show_about)
# Quit menu item
self.item_quit = Gtk.MenuItem()
self.item_quit.connect('activate', self.quit_safe_eyes)
self.set_labels()
self.__set_labels()
# At startup, no need for activate menu
self.item_enable.set_sensitive(False)
self.__item_enable.set_sensitive(False)
# Append all menu items and show the menu
self.menu.append(self.item_info)
self.menu.append(self.item_separator)
self.menu.append(self.item_enable)
self.menu.append(self.item_disable)
self.menu.append(self.item_manual_break)
self.menu.append(self.item_settings)
self.menu.append(self.item_about)
self.menu.append(self.item_quit)
self.menu.show_all()
self.__menu.append(self.__item_info)
self.__menu.append(self.__item_separator)
self.__menu.append(self.__item_enable)
self.__menu.append(self.__item_disable)
self.__menu.append(self.__item_manual_break)
self.__menu.append(self.__item_settings)
self.__menu.append(self.__item_about)
self.__menu.append(self.__item_quit)
self.__menu.show_all()
self.item_enable.set_visible(self.__allow_disabling)
self.item_disable.set_visible(self.__allow_disabling)
self.item_quit.set_visible(self.__allow_disabling)
self.item_quit.set_visible(self.__allow_disabling)
self.__set_visibility()
self.indicator.set_menu(self.menu)
self.__indicator.set_menu(self.__menu)
def initialize(self, plugin_config):
"""
Initialize the tray icon by setting the config.
"""
self.__config = plugin_config
self.set_labels()
self.__allow_disabling = plugin_config['allow_disabling']
self.item_enable.set_visible(self.__allow_disabling)
self.item_disable.set_visible(self.__allow_disabling)
self.item_quit.set_visible(self.__allow_disabling)
self.item_quit.set_visible(self.__allow_disabling)
self.__set_labels()
self.__allow_disabling = plugin_config["allow_disabling"]
self.__set_visibility()
def set_labels(self):
def __set_visibility(self) -> None:
self.__item_enable.set_visible(self.__allow_disabling)
self.__item_disable.set_visible(self.__allow_disabling)
self.__item_quit.set_visible(self.__allow_disabling)
self.__item_quit.set_visible(self.__allow_disabling)
def __set_labels(self):
"""
Update the text of menu items based on the selected language.
"""
for entry in self.sub_menu_disable_items:
# print(self.context['locale'].ngettext('For %d Hour', 'For %d Hours', 1) % 1)
for entry in self.__sub_menu_disable_items:
entry[0].set_label(self.__context.locale.ngettext(entry[1][0], entry[1][1], entry[2]) % entry[2])
self.sub_menu_item_until_restart.set_label(_('Until restart'))
self.item_enable.set_label(_('Enable Safe Eyes'))
self.item_disable.set_label(_('Disable Safe Eyes'))
self.__sub_menu_item_until_restart.set_label(_("Until restart"))
self.__item_enable.set_label(_("Enable Safe Eyes"))
self.__item_disable.set_label(_("Disable Safe Eyes"))
breaks_found = self.__context.break_api.has_breaks()
if breaks_found:
if self.__active:
if self.__date_time:
self.__set_next_break_info()
self.indicator.set_icon("safeeyes_enabled")
self.__indicator.set_icon("safeeyes_enabled")
else:
if self.__wakeup_time:
self.item_info.set_label(_('Disabled until %s') % utility.format_time(self.__wakeup_time))
self.__item_info.set_label(_("Disabled until %s") % utility.format_time(self.__wakeup_time))
else:
self.item_info.set_label(_('Disabled until restart'))
self.indicator.set_label('', '')
self.indicator.set_icon("safeeyes_disabled")
self.__item_info.set_label(_("Disabled until restart"))
self.__indicator.set_label("", "")
self.__indicator.set_icon("safeeyes_disabled")
else:
self.item_info.set_label(_('No Breaks Available'))
self.indicator.set_label('', '')
self.indicator.set_icon("safeeyes_disabled")
self.item_info.set_sensitive(breaks_found and self.__active)
self.item_enable.set_sensitive(breaks_found and not self.__active)
self.item_disable.set_sensitive(breaks_found and self.__active)
self.item_manual_break.set_sensitive(breaks_found and self.__active)
self.__item_info.set_label(_("No Breaks Available"))
self.__indicator.set_label("", "")
self.__indicator.set_icon("safeeyes_disabled")
self.__item_info.set_sensitive(breaks_found and self.__active)
self.__item_enable.set_sensitive(breaks_found and not self.__active)
self.__item_disable.set_sensitive(breaks_found and self.__active)
self.__item_manual_break.set_sensitive(breaks_found and self.__active)
self.item_manual_break.set_label(_('Take a break now'))
self.sub_menu_manual_next_break.set_label(_('Any break'))
self.sub_menu_manual_next_short_break.set_label(_('Short break'))
self.sub_menu_manual_next_long_break.set_label(_('Long break'))
self.item_settings.set_label(_('Settings'))
self.item_about.set_label(_('About'))
self.item_quit.set_label(_('Quit'))
self.__item_manual_break.set_label(_("Take a break now"))
self.__sub_menu_manual_next_break.set_label(_("Any break"))
self.__sub_menu_manual_next_short_break.set_label(_("Short break"))
self.__sub_menu_manual_next_long_break.set_label(_("Long break"))
self.__item_settings.set_label(_("Settings"))
self.__item_about.set_label(_("About"))
self.__item_quit.set_label(_("Quit"))
def show_icon(self):
"""
Show the tray icon.
"""
self.indicator.set_status(appindicator.IndicatorStatus.ACTIVE)
self.__indicator.set_status(appindicator.IndicatorStatus.ACTIVE)
def hide_icon(self):
"""
Hide the tray icon.
"""
self.indicator.set_status(appindicator.IndicatorStatus.PASSIVE)
self.__indicator.set_status(appindicator.IndicatorStatus.PASSIVE)
def quit_safe_eyes(self, *args):
"""
Handle Quit menu action.
This action terminates the application.
"""
with self.lock:
with self.__lock:
self.__active = True
# Notify all schedulers
self.__idle_condition.acquire()
self.__idle_condition.notify_all()
self.__idle_condition.release()
self.__idle_condition.release_all()
self.__context.core_api.quit()
def show_settings(self, *args):
@ -265,7 +249,7 @@ class TrayIcon:
"""
Update the next break time to be displayed in the menu and optionally in the tray icon.
"""
logging.info("Update next break information")
logging.debug("Tray Icon: update the next break information")
self.__date_time = dateTime
self.__set_next_break_info()
@ -274,14 +258,14 @@ class TrayIcon:
A private method to be called within this class to update the next break information using self.dateTime.
"""
formatted_time = utility.format_time(self.__date_time)
message = _('Next break at %s') % (formatted_time)
message = _("Next break at %s") % (formatted_time)
# Update the menu item label
self.__set_label(message)
# Update the tray icon label
if self.__config.get('show_time_in_tray', False):
self.indicator.set_label(formatted_time, '')
if self.__config.get("show_time_in_tray", False):
self.__indicator.set_label(formatted_time, "")
else:
self.indicator.set_label('', '')
self.__indicator.set_label("", "")
def on_manual_break_clicked(self, *args):
"""
@ -295,22 +279,20 @@ class TrayIcon:
def on_enable_clicked(self, *args):
"""
Handle 'Enable Safe Eyes' menu action.
Handle "Enable Safe Eyes" menu action.
This action enables the application if it is currently disabled.
"""
# active = self.item_enable.get_active()
if not self.__active:
with self.lock:
with self.__lock:
self.enable_ui()
self.__context.core_api.start()
# Notify all schedulers
self.__idle_condition.acquire()
self.__idle_condition.notify_all()
self.__idle_condition.release()
self.__idle_condition.release_all()
def on_disable_clicked(self, *args):
"""
Handle the menu actions of all the sub menus of 'Disable Safe Eyes'.
Handle the menu actions of all the sub menus of "Disable Safe Eyes".
This action disables the application if it is currently active.
"""
# active = self.item_enable.get_active()
@ -319,15 +301,16 @@ class TrayIcon:
time_to_wait = args[1]
if time_to_wait <= 0:
info = _('Disabled until restart')
info = _("Disabled until restart")
self.__context.core_api.stop(info)
self.__wakeup_time = None
self.item_info.set_label(info)
self.__item_info.set_label(info)
else:
self.__wakeup_time = datetime.datetime.now() + datetime.timedelta(minutes=time_to_wait)
info = _('Disabled until %s') % utility.format_time(self.__wakeup_time)
self.__context.core_api.stop(info)
self.item_info.set_label(info)
info = _("Disabled until %s") % utility.format_time(self.__wakeup_time)
self.__context.core_api.set_status(info)
self.__context.core_api.stop()
self.__item_info.set_label(info)
self.__schedule_resume(time_to_wait)
def lock_menu(self):
@ -335,53 +318,51 @@ class TrayIcon:
This method is called by the core to prevent user from disabling Safe Eyes after the notification.
"""
if self.__active:
self.menu.set_sensitive(False)
self.__menu.set_sensitive(False)
def unlock_menu(self):
"""
This method is called by the core to activate the menu after the the break.
"""
if self.__active:
self.menu.set_sensitive(True)
self.__menu.set_sensitive(True)
def disable_ui(self):
"""
Change the UI to disabled state.
"""
if self.__active:
logging.info('Disable Safe Eyes')
logging.debug("Tray Icon: disable Safe Eyes")
self.__active = False
self.indicator.set_icon("safeeyes_disabled")
self.item_info.set_label(_('Disabled until restart'))
self.indicator.set_label('', '')
self.item_info.set_sensitive(False)
self.item_enable.set_sensitive(True)
self.item_disable.set_sensitive(False)
self.item_manual_break.set_sensitive(False)
self.__indicator.set_icon("safeeyes_disabled")
self.__item_info.set_label(_("Disabled until restart"))
self.__indicator.set_label("", "")
self.__item_info.set_sensitive(False)
self.__item_enable.set_sensitive(True)
self.__item_disable.set_sensitive(False)
self.__item_manual_break.set_sensitive(False)
def enable_ui(self):
"""
Change the UI to enabled state.
"""
if not self.__active:
logging.info('Enable Safe Eyes')
logging.debug("Tray Icon: enable Safe Eyes")
self.__active = True
self.indicator.set_icon("safeeyes_enabled")
self.item_info.set_sensitive(True)
self.item_enable.set_sensitive(False)
self.item_disable.set_sensitive(True)
self.item_manual_break.set_sensitive(True)
self.__indicator.set_icon("safeeyes_enabled")
self.__item_info.set_sensitive(True)
self.__item_enable.set_sensitive(False)
self.__item_disable.set_sensitive(True)
self.__item_manual_break.set_sensitive(True)
@worker
def __schedule_resume(self, time_minutes):
"""
Schedule a local timer to enable Safe Eyes after the given timeout.
"""
self.__idle_condition.acquire()
self.__idle_condition.wait(time_minutes * 60) # Convert to seconds
self.__idle_condition.release()
self.__idle_condition.hold(time_minutes * 60)
with self.lock:
with self.__lock:
if not self.__active:
self.__activate_enable_menu()
@ -406,18 +387,18 @@ class TrayIcon:
@main
def __set_icon(self, icon_name: str) -> None:
self.indicator.set_icon(icon_name)
self.__indicator.set_icon(icon_name)
@main
def __activate_enable_menu(self) -> None:
self.item_enable.activate()
self.__item_enable.activate()
@main
def __set_label(self, message: str) -> None:
self.item_info.set_label(message)
self.__item_info.set_label(message)
context: Context = None
context: Context
tray_icon: TrayIcon = None
@ -427,7 +408,7 @@ def init(ctx: Context, plugin_config: dict):
"""
global context
global tray_icon
logging.debug('Initialize Tray Icon plugin')
logging.debug("Tray Icon: initialize the plugin")
context = ctx
if not tray_icon:
tray_icon = TrayIcon(context, plugin_config)
@ -454,7 +435,7 @@ def on_pre_break(break_obj):
"""
Disable the menu if strict_break is enabled
"""
if context.config.get('strict_break'):
if context.config.get("strict_break"):
tray_icon.lock_menu()
tray_icon.__animate = True
tray_icon.start_animation()