Code refactored and audible alert is added
This commit is contained in:
parent
f81a5fe264
commit
d1f9042ac7
|
@ -20,19 +20,42 @@ import gi
|
|||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk, Gdk, GdkX11
|
||||
|
||||
|
||||
"""
|
||||
AboutDialog reads the about_dialog.glade and build the user interface using that file.
|
||||
It shows the application name with version, a small description, license and the GitHub url.
|
||||
"""
|
||||
class AboutDialog:
|
||||
|
||||
"""
|
||||
Read the about_dialog.glade and build the user interface.
|
||||
"""
|
||||
def __init__(self, glade_file, version):
|
||||
builder = Gtk.Builder()
|
||||
builder.add_from_file(glade_file)
|
||||
builder.connect_signals(self)
|
||||
self.window = builder.get_object("window_about")
|
||||
|
||||
# Set the version at the runtime
|
||||
builder.get_object("lbl_app_name").set_label("Safe Eyes " + version)
|
||||
|
||||
|
||||
"""
|
||||
Show the About dialog.
|
||||
"""
|
||||
def show(self):
|
||||
self.window.show_all()
|
||||
|
||||
|
||||
"""
|
||||
Window close event handler.
|
||||
"""
|
||||
def on_window_delete(self, *args):
|
||||
self.window.destroy()
|
||||
|
||||
|
||||
"""
|
||||
Close button click event handler.
|
||||
"""
|
||||
def on_close_clicked(self, button):
|
||||
self.window.destroy()
|
||||
|
|
|
@ -23,13 +23,18 @@ import threading
|
|||
import logging
|
||||
from Xlib import Xatom, Xutil
|
||||
from Xlib.display import Display, X
|
||||
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk, Gdk, GLib, GdkX11
|
||||
|
||||
class BreakScreen:
|
||||
"""Full screen break window"""
|
||||
|
||||
"""
|
||||
The fullscreen window which prevents users from using the computer.
|
||||
"""
|
||||
class BreakScreen:
|
||||
|
||||
"""
|
||||
Read the break_screen.glade and build the user interface.
|
||||
"""
|
||||
def __init__(self, on_skip, glade_file, style_sheet_path):
|
||||
self.on_skip = on_skip
|
||||
self.is_pretified = False
|
||||
|
@ -52,52 +57,58 @@ class BreakScreen:
|
|||
self.skip_button_text = language['ui_controls']['skip']
|
||||
self.strict_break = config['strict_break']
|
||||
|
||||
|
||||
"""
|
||||
Window close event handler.
|
||||
"""
|
||||
def on_window_delete(self, *args):
|
||||
logging.info("Closing the break screen")
|
||||
self.lock_keyboard = False
|
||||
self.close()
|
||||
|
||||
|
||||
"""
|
||||
Skip button press event handler.
|
||||
"""
|
||||
def on_skip_clicked(self, button):
|
||||
logging.info("User skipped the break")
|
||||
self.on_skip()
|
||||
self.close()
|
||||
|
||||
|
||||
"""
|
||||
Show/update the count down on all screens.
|
||||
"""
|
||||
def show_count_down(self, count):
|
||||
GLib.idle_add(lambda: self.__show_count_down(count))
|
||||
GLib.idle_add(lambda: self.__update_count_down(count))
|
||||
|
||||
def __show_count_down(self, count):
|
||||
for label in self.count_labels:
|
||||
label.set_text(count)
|
||||
|
||||
"""
|
||||
Show the break screen with the given message on all displays.
|
||||
"""
|
||||
def show_message(self, message):
|
||||
GLib.idle_add(lambda: self.__show_message(message))
|
||||
|
||||
"""
|
||||
Lock the keyboard to prevent the user from using keyboard shortcuts
|
||||
"""
|
||||
def block_keyboard(self):
|
||||
logging.info("Lock the keyboard")
|
||||
self.lock_keyboard = True
|
||||
display = Display()
|
||||
root = display.screen().root
|
||||
# Grap the keyboard
|
||||
root.grab_keyboard(owner_events = False, pointer_mode = X.GrabModeAsync, keyboard_mode = X.GrabModeAsync, time = X.CurrentTime)
|
||||
# Consume keyboard events
|
||||
self.key_lock_condition.acquire()
|
||||
while self.lock_keyboard:
|
||||
self.key_lock_condition.wait()
|
||||
self.key_lock_condition.release()
|
||||
|
||||
# Ungrap the keyboard
|
||||
logging.info("Unlock the keyboard")
|
||||
display.ungrab_keyboard(X.CurrentTime)
|
||||
display.flush()
|
||||
GLib.idle_add(lambda: self.__show_break_screen(message))
|
||||
|
||||
|
||||
"""
|
||||
Show an empty break screen on each non-active screens.
|
||||
Hide the break screen from active window and destroy all other windows
|
||||
"""
|
||||
def show_break_screen(self, message):
|
||||
def close(self):
|
||||
logging.info("Close the break screen(s)")
|
||||
self.__release_keyboard()
|
||||
|
||||
# Destroy other windows if exists
|
||||
GLib.idle_add(lambda: self.__destroy_all_screens())
|
||||
|
||||
|
||||
"""
|
||||
Show an empty break screen on all screens.
|
||||
"""
|
||||
def __show_break_screen(self, message):
|
||||
# Lock the keyboard
|
||||
thread = threading.Thread(target=self.__lock_keyboard)
|
||||
thread.start()
|
||||
|
||||
logging.info("Show break screens in all displays")
|
||||
screen = Gtk.Window().get_screen()
|
||||
no_of_monitors = screen.get_n_monitors()
|
||||
|
@ -131,33 +142,52 @@ class BreakScreen:
|
|||
window.set_keep_above(True)
|
||||
window.present()
|
||||
window.fullscreen()
|
||||
|
||||
|
||||
def release_keyboard(self):
|
||||
|
||||
"""
|
||||
Update the countdown on all break screens.
|
||||
"""
|
||||
def __update_count_down(self, count):
|
||||
for label in self.count_labels:
|
||||
label.set_text(count)
|
||||
|
||||
|
||||
"""
|
||||
Lock the keyboard to prevent the user from using keyboard shortcuts
|
||||
"""
|
||||
def __lock_keyboard(self):
|
||||
logging.info("Lock the keyboard")
|
||||
self.lock_keyboard = True
|
||||
display = Display()
|
||||
root = display.screen().root
|
||||
# Grap the keyboard
|
||||
root.grab_keyboard(owner_events = False, pointer_mode = X.GrabModeAsync, keyboard_mode = X.GrabModeAsync, time = X.CurrentTime)
|
||||
# Consume keyboard events
|
||||
self.key_lock_condition.acquire()
|
||||
while self.lock_keyboard:
|
||||
self.key_lock_condition.wait()
|
||||
self.key_lock_condition.release()
|
||||
|
||||
# Ungrap the keyboard
|
||||
logging.info("Unlock the keyboard")
|
||||
display.ungrab_keyboard(X.CurrentTime)
|
||||
display.flush()
|
||||
|
||||
|
||||
"""
|
||||
Release the locked keyboard.
|
||||
"""
|
||||
def __release_keyboard(self):
|
||||
self.key_lock_condition.acquire()
|
||||
self.lock_keyboard = False
|
||||
self.key_lock_condition.notify()
|
||||
self.key_lock_condition.release()
|
||||
|
||||
def __show_message(self, message):
|
||||
# Lock the keyboard
|
||||
thread = threading.Thread(target=self.block_keyboard)
|
||||
thread.start()
|
||||
|
||||
self.show_break_screen(message)
|
||||
|
||||
|
||||
"""
|
||||
Hide the break screen from active window and destroy all other windows
|
||||
Close all the break screens.
|
||||
"""
|
||||
def close(self):
|
||||
logging.info("Close the break screen(s)")
|
||||
self.release_keyboard()
|
||||
|
||||
# Destroy other windows if exists
|
||||
GLib.idle_add(lambda: self.__close())
|
||||
|
||||
def __close(self):
|
||||
def __destroy_all_screens(self):
|
||||
for win in self.windows:
|
||||
win.destroy()
|
||||
del self.windows[:]
|
||||
|
|
|
@ -24,27 +24,48 @@ gi.require_version('Notify', '0.7')
|
|||
from gi.repository import Gtk, Gdk, GLib, GdkX11
|
||||
from gi.repository import AppIndicator3 as appindicator
|
||||
from gi.repository import Notify
|
||||
|
||||
|
||||
APPINDICATOR_ID = 'safeeyes'
|
||||
|
||||
"""
|
||||
This class is responsible for the notification to the user before the break.
|
||||
"""
|
||||
class Notification:
|
||||
|
||||
"""
|
||||
Initialize the notification.
|
||||
"""
|
||||
def __init__(self, language):
|
||||
logging.info("Initialize the notification")
|
||||
Notify.init(APPINDICATOR_ID)
|
||||
self.language = language
|
||||
|
||||
|
||||
"""
|
||||
Show the notification"
|
||||
"""
|
||||
def show(self, warning_time):
|
||||
logging.info("Show pre-break notification")
|
||||
self.notification = Notify.Notification.new("Safe Eyes", "\n" + self.language['messages']['ready_for_a_break'].format(warning_time), icon="safeeyes_enabled")
|
||||
self.notification.show()
|
||||
|
||||
|
||||
"""
|
||||
Close the notification if it is not closed by the system already.
|
||||
"""
|
||||
def close(self):
|
||||
logging.info("Close pre-break notification")
|
||||
try:
|
||||
self.notification.close()
|
||||
except:
|
||||
logging.warning("Notification is already closed")
|
||||
# Some Linux systems automatically close the notification.
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
Uninitialize the notification. Call this method when closing the application.
|
||||
"""
|
||||
def quite(self):
|
||||
logging.info("Uninitialize Safe Eyes notification")
|
||||
GLib.idle_add(lambda: Notify.uninit())
|
|
@ -21,8 +21,15 @@ gi.require_version('Gdk', '3.0')
|
|||
from gi.repository import Gdk, Gio, GLib, GdkX11
|
||||
import time, datetime, threading, sys, subprocess, logging
|
||||
|
||||
|
||||
"""
|
||||
Core of Safe Eyes which runs the scheduler and notifies the breaks.
|
||||
"""
|
||||
class SafeEyesCore:
|
||||
|
||||
"""
|
||||
Initialize the internal variables of the core.
|
||||
"""
|
||||
def __init__(self, show_notification, start_break, end_break, on_countdown, update_next_break_info):
|
||||
# Initialize the variables
|
||||
self.break_count = 0
|
||||
|
@ -38,6 +45,7 @@ class SafeEyesCore:
|
|||
self.notification_condition = threading.Condition()
|
||||
self.break_condition = threading.Condition()
|
||||
|
||||
|
||||
"""
|
||||
Initialize the internal properties from configuration
|
||||
"""
|
||||
|
@ -51,10 +59,50 @@ class SafeEyesCore:
|
|||
self.short_break_duration = config['short_break_duration']
|
||||
self.break_interval = config['break_interval']
|
||||
|
||||
|
||||
"""
|
||||
Start Safe Eyes is it is not running already.
|
||||
"""
|
||||
def start(self):
|
||||
if not self.active:
|
||||
logging.info("Scheduling next break")
|
||||
self.active = True
|
||||
self.__schedule_next_break()
|
||||
|
||||
|
||||
"""
|
||||
Stop Safe Eyes if it is running.
|
||||
"""
|
||||
def stop(self):
|
||||
if self.active:
|
||||
logging.info("Stop the core")
|
||||
# Reset the state properties in case of restart
|
||||
# self.break_count = 0
|
||||
# self.long_break_message_index = -1
|
||||
# self.short_break_message_index = -1
|
||||
|
||||
self.notification_condition.acquire()
|
||||
self.active = False
|
||||
self.notification_condition.notify()
|
||||
self.notification_condition.release()
|
||||
|
||||
# If waiting after notification, notify the thread to wake up and die
|
||||
self.notification_condition.acquire()
|
||||
self.notification_condition.notify()
|
||||
self.notification_condition.release()
|
||||
|
||||
|
||||
"""
|
||||
User skipped the break using Skip button
|
||||
"""
|
||||
def skip_break(self):
|
||||
self.skipped = True
|
||||
|
||||
|
||||
"""
|
||||
Scheduler task to execute during every interval
|
||||
"""
|
||||
def scheduler_job(self):
|
||||
def __scheduler_job(self):
|
||||
if not self.active:
|
||||
return
|
||||
|
||||
|
@ -75,30 +123,29 @@ class SafeEyesCore:
|
|||
|
||||
logging.info("Ready to show the break")
|
||||
|
||||
GLib.idle_add(lambda: self.process_job())
|
||||
GLib.idle_add(lambda: self.__process_job())
|
||||
|
||||
"""
|
||||
Used to process the job in default thread because is_full_screen_app_found must be run by default thread
|
||||
Used to process the job in default thread because __is_full_screen_app_found must be run by default thread
|
||||
"""
|
||||
def process_job(self):
|
||||
if self.is_full_screen_app_found():
|
||||
def __process_job(self):
|
||||
if self.__is_full_screen_app_found():
|
||||
# If full screen app found, do not show break screen
|
||||
logging.info("Found a full-screen application. Skip the break")
|
||||
if self.active:
|
||||
# Schedule the break again
|
||||
thread = threading.Thread(target=self.scheduler_job)
|
||||
thread.start()
|
||||
self.__schedule_next_break()
|
||||
return
|
||||
|
||||
self.break_count = ((self.break_count + 1) % self.no_of_short_breaks_per_long_break)
|
||||
|
||||
thread = threading.Thread(target=self.notify_and_start_break)
|
||||
thread = threading.Thread(target=self.__notify_and_start_break)
|
||||
thread.start()
|
||||
|
||||
"""
|
||||
Show notification and start the break after given number of seconds
|
||||
"""
|
||||
def notify_and_start_break(self):
|
||||
def __notify_and_start_break(self):
|
||||
# Show a notification
|
||||
self.show_notification()
|
||||
|
||||
|
@ -111,7 +158,7 @@ class SafeEyesCore:
|
|||
# User can disable SafeEyes during notification
|
||||
if self.active:
|
||||
message = ""
|
||||
if self.is_long_break():
|
||||
if self.__is_long_break():
|
||||
logging.info("Count is {}; get a long beak message".format(self.break_count))
|
||||
self.long_break_message_index = (self.long_break_message_index + 1) % len(self.long_break_exercises)
|
||||
message = self.long_break_exercises[self.long_break_message_index]
|
||||
|
@ -125,7 +172,7 @@ class SafeEyesCore:
|
|||
|
||||
# Start the countdown
|
||||
seconds = 0
|
||||
if self.is_long_break():
|
||||
if self.__is_long_break():
|
||||
seconds = self.long_break_duration
|
||||
else:
|
||||
seconds = self.short_break_duration
|
||||
|
@ -145,58 +192,30 @@ class SafeEyesCore:
|
|||
# Resume
|
||||
if self.active:
|
||||
# Schedule the break again
|
||||
thread = threading.Thread(target=self.scheduler_job)
|
||||
thread.start()
|
||||
self.__schedule_next_break()
|
||||
|
||||
self.skipped = False
|
||||
|
||||
|
||||
"""
|
||||
Check if the current break is long break or short current
|
||||
"""
|
||||
def is_long_break(self):
|
||||
def __is_long_break(self):
|
||||
return self.break_count == self.no_of_short_breaks_per_long_break - 1
|
||||
|
||||
"""
|
||||
User skipped the break using Skip button
|
||||
"""
|
||||
def skip_break(self):
|
||||
self.skipped = True
|
||||
|
||||
"""
|
||||
Stop Safe Eyes
|
||||
Start a new thread to schedule the next break.
|
||||
"""
|
||||
def stop(self):
|
||||
if self.active:
|
||||
logging.info("Stop the core")
|
||||
# Reset the state properties in case of restart
|
||||
# self.break_count = 0
|
||||
# self.long_break_message_index = -1
|
||||
# self.short_break_message_index = -1
|
||||
def __schedule_next_break(self):
|
||||
thread = threading.Thread(target=self.__scheduler_job)
|
||||
thread.start()
|
||||
|
||||
self.notification_condition.acquire()
|
||||
self.active = False
|
||||
self.notification_condition.notify()
|
||||
self.notification_condition.release()
|
||||
|
||||
# If waiting after notification, notify the thread to wake up and die
|
||||
self.notification_condition.acquire()
|
||||
self.notification_condition.notify()
|
||||
self.notification_condition.release()
|
||||
|
||||
"""
|
||||
Start Safe Eyes
|
||||
"""
|
||||
def start(self):
|
||||
if not self.active:
|
||||
logging.info("Scheduling next break")
|
||||
self.active = True
|
||||
thread = threading.Thread(target=self.scheduler_job)
|
||||
thread.start()
|
||||
|
||||
"""
|
||||
Check for full-screen applications
|
||||
"""
|
||||
def is_full_screen_app_found(self):
|
||||
def __is_full_screen_app_found(self):
|
||||
logging.info("Searching for full-screen application")
|
||||
screen = Gdk.Screen.get_default()
|
||||
active_xid = str(screen.get_active_window().get_xid())
|
||||
|
@ -210,4 +229,3 @@ class SafeEyesCore:
|
|||
else:
|
||||
if stdout:
|
||||
return 'FULLSCREEN' in stdout
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ class SettingsDialog:
|
|||
self.spin_short_between_long = builder.get_object('spin_short_between_long')
|
||||
self.spin_time_to_prepare = builder.get_object('spin_time_to_prepare')
|
||||
self.switch_strict_break = builder.get_object('switch_strict_break')
|
||||
self.switch_audible_alert = builder.get_object('switch_audible_alert')
|
||||
self.cmb_language = builder.get_object('cmb_language')
|
||||
|
||||
builder.get_object('lbl_short_break').set_label(language['ui_controls']['short_break_duration'])
|
||||
|
@ -48,6 +49,7 @@ class SettingsDialog:
|
|||
builder.get_object('lbl_short_per_long').set_label(language['ui_controls']['no_of_short_breaks_between_two_long_breaks'])
|
||||
builder.get_object('lbl_time_to_prepare').set_label(language['ui_controls']['time_to_prepare_for_break'])
|
||||
builder.get_object('lbl_strict_break').set_label(language['ui_controls']['strict_break'])
|
||||
builder.get_object('lbl_audible_alert').set_label(language['ui_controls']['audible_alert'])
|
||||
builder.get_object('lbl_language').set_label(language['ui_controls']['language'])
|
||||
builder.get_object('btn_cancel').set_label(language['ui_controls']['cancel'])
|
||||
builder.get_object('btn_save').set_label(language['ui_controls']['save'])
|
||||
|
@ -58,6 +60,7 @@ class SettingsDialog:
|
|||
self.spin_short_between_long.set_value(config['no_of_short_breaks_per_long_break'])
|
||||
self.spin_time_to_prepare.set_value(config['pre_break_warning_time'])
|
||||
self.switch_strict_break.set_active(config['strict_break'])
|
||||
self.switch_audible_alert.set_active(config['audible_alert'])
|
||||
|
||||
# Initialize the language combobox
|
||||
language_list_store = Gtk.ListStore(GObject.TYPE_STRING)
|
||||
|
@ -90,6 +93,7 @@ class SettingsDialog:
|
|||
self.config['no_of_short_breaks_per_long_break'] = self.spin_short_between_long.get_value_as_int()
|
||||
self.config['pre_break_warning_time'] = self.spin_time_to_prepare.get_value_as_int()
|
||||
self.config['strict_break'] = self.switch_strict_break.get_active()
|
||||
self.config['audible_alert'] = self.switch_audible_alert.get_active()
|
||||
self.config['language'] = self.languages[self.cmb_language.get_active()]
|
||||
|
||||
self.on_save_settings(self.config) # Call the provided save method
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
# Safe Eyes is a utility to remind you to take break frequently
|
||||
# to protect your eyes from eye strain.
|
||||
|
||||
# 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
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import subprocess
|
||||
|
||||
"""
|
||||
Play the alert.mp3
|
||||
"""
|
||||
def play_notification():
|
||||
try:
|
||||
subprocess.Popen(['mpg123', '-q', 'resource/alert.mp3'])
|
||||
except:
|
||||
pass
|
|
@ -33,6 +33,7 @@
|
|||
"no_of_short_breaks_between_two_long_breaks": "Number of short breaks between two long breaks",
|
||||
"time_to_prepare_for_break": "Time to prepare for break (in seconds)",
|
||||
"strict_break": "Strict break (Hide skip button)",
|
||||
"audible_alert": "Audible alert at the end of break",
|
||||
"language": "Language",
|
||||
"enable": "Enable Safe Eyes",
|
||||
"settings": "Settings",
|
||||
|
|
|
@ -8,5 +8,6 @@
|
|||
"pre_break_warning_time": 10,
|
||||
"short_break_duration": 15,
|
||||
"strict_break": false,
|
||||
"audible_alert": true,
|
||||
"language": "en"
|
||||
}
|
||||
|
|
|
@ -161,6 +161,32 @@
|
|||
<property name="top_attach">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="lbl_audible_alert">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="label" translatable="yes">Audible alert at the end of break</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">6</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="lbl_language">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="label" translatable="yes">Language</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">7</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="spin_short_break_duration">
|
||||
<property name="visible">True</property>
|
||||
|
@ -265,15 +291,12 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="lbl_language">
|
||||
<object class="GtkSwitch" id="switch_audible_alert">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="label" translatable="yes">Language</property>
|
||||
<property name="can_focus">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">6</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
@ -284,7 +307,7 @@
|
|||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">6</property>
|
||||
<property name="top_attach">7</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
|
|
Binary file not shown.
|
@ -18,24 +18,15 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import gi
|
||||
import json
|
||||
import shutil
|
||||
import errno
|
||||
import dbus
|
||||
import logging
|
||||
import operator
|
||||
import os, gi, json, shutil, errno, dbus, logging, operator, Utility
|
||||
from threading import Timer
|
||||
from dbus.mainloop.glib import DBusGMainLoop
|
||||
|
||||
from BreakScreen import BreakScreen
|
||||
from TrayIcon import TrayIcon
|
||||
from SettingsDialog import SettingsDialog
|
||||
from AboutDialog import AboutDialog
|
||||
from SafeEyesCore import SafeEyesCore
|
||||
from Notification import Notification
|
||||
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
|
@ -91,6 +82,8 @@ def show_alert(message):
|
|||
def close_alert():
|
||||
logging.info("Close the break screen")
|
||||
break_screen.close()
|
||||
if config['audible_alert']:
|
||||
Utility.play_notification()
|
||||
|
||||
"""
|
||||
Receive the count from core and pass it to the break screen.
|
||||
|
|
Loading…
Reference in New Issue