commit
eedb2c53c7
|
@ -18,13 +18,15 @@
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
gi.require_version('Gtk', '3.0')
|
gi.require_version('Gtk', '3.0')
|
||||||
from gi.repository import Gtk, Gdk, GdkX11
|
from gi.repository import Gtk
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
AboutDialog reads the about_dialog.glade and build the user interface using that file.
|
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.
|
It shows the application name with version, a small description, license and the GitHub url.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class AboutDialog:
|
class AboutDialog:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -42,21 +44,18 @@ class AboutDialog:
|
||||||
# Set the version at the runtime
|
# Set the version at the runtime
|
||||||
builder.get_object("lbl_app_name").set_label("Safe Eyes " + version)
|
builder.get_object("lbl_app_name").set_label("Safe Eyes " + version)
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Show the About dialog.
|
Show the About dialog.
|
||||||
"""
|
"""
|
||||||
def show(self):
|
def show(self):
|
||||||
self.window.show_all()
|
self.window.show_all()
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Window close event handler.
|
Window close event handler.
|
||||||
"""
|
"""
|
||||||
def on_window_delete(self, *args):
|
def on_window_delete(self, *args):
|
||||||
self.window.destroy()
|
self.window.destroy()
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Close button click event handler.
|
Close button click event handler.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -16,16 +16,17 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import gi, signal, sys, threading, logging
|
import gi, threading, logging
|
||||||
from Xlib import Xatom, Xutil
|
|
||||||
from Xlib.display import Display, X
|
from Xlib.display import Display, X
|
||||||
gi.require_version('Gtk', '3.0')
|
gi.require_version('Gtk', '3.0')
|
||||||
from gi.repository import Gtk, Gdk, GLib, GdkX11
|
from gi.repository import Gtk, Gdk, GLib
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
The fullscreen window which prevents users from using the computer.
|
The fullscreen window which prevents users from using the computer.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class BreakScreen:
|
class BreakScreen:
|
||||||
|
|
||||||
def __init__(self, context, on_skip, on_postpone, glade_file, style_sheet_path):
|
def __init__(self, context, on_skip, on_postpone, glade_file, style_sheet_path):
|
||||||
|
@ -46,7 +47,6 @@ class BreakScreen:
|
||||||
css_provider.load_from_path(style_sheet_path)
|
css_provider.load_from_path(style_sheet_path)
|
||||||
Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(), css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
|
Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(), css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
|
||||||
|
|
||||||
|
|
||||||
def initialize(self, config, language):
|
def initialize(self, config, language):
|
||||||
"""
|
"""
|
||||||
Initialize the internal properties from configuration
|
Initialize the internal properties from configuration
|
||||||
|
@ -60,7 +60,6 @@ class BreakScreen:
|
||||||
self.keycode_shortcut_postpone = config.get('shortcut_postpone', 65)
|
self.keycode_shortcut_postpone = config.get('shortcut_postpone', 65)
|
||||||
self.shortcut_disable_time = config.get('shortcut_disable_time', 2)
|
self.shortcut_disable_time = config.get('shortcut_disable_time', 2)
|
||||||
|
|
||||||
|
|
||||||
def skip_break(self):
|
def skip_break(self):
|
||||||
"""
|
"""
|
||||||
Skip the break from the break screen
|
Skip the break from the break screen
|
||||||
|
@ -69,7 +68,7 @@ class BreakScreen:
|
||||||
# Must call on_skip before close to lock screen before closing the break screen
|
# Must call on_skip before close to lock screen before closing the break screen
|
||||||
self.on_skip()
|
self.on_skip()
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
def postpone_break(self):
|
def postpone_break(self):
|
||||||
"""
|
"""
|
||||||
Postpone the break from the break screen
|
Postpone the break from the break screen
|
||||||
|
@ -86,14 +85,12 @@ class BreakScreen:
|
||||||
self.__release_keyboard()
|
self.__release_keyboard()
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
|
|
||||||
def on_skip_clicked(self, button):
|
def on_skip_clicked(self, button):
|
||||||
"""
|
"""
|
||||||
Skip button press event handler.
|
Skip button press event handler.
|
||||||
"""
|
"""
|
||||||
self.skip_break()
|
self.skip_break()
|
||||||
|
|
||||||
|
|
||||||
def on_postpone_clicked(self, button):
|
def on_postpone_clicked(self, button):
|
||||||
"""
|
"""
|
||||||
Postpone button press event handler.
|
Postpone button press event handler.
|
||||||
|
@ -109,7 +106,6 @@ class BreakScreen:
|
||||||
timeformat = '{:02d}:{:02d}'.format(mins, secs)
|
timeformat = '{:02d}:{:02d}'.format(mins, secs)
|
||||||
GLib.idle_add(lambda: self.__update_count_down(timeformat))
|
GLib.idle_add(lambda: self.__update_count_down(timeformat))
|
||||||
|
|
||||||
|
|
||||||
def show_message(self, message, image_path, plugins_data):
|
def show_message(self, message, image_path, plugins_data):
|
||||||
"""
|
"""
|
||||||
Show the break screen with the given message on all displays.
|
Show the break screen with the given message on all displays.
|
||||||
|
@ -117,7 +113,6 @@ class BreakScreen:
|
||||||
self.enable_shortcut = not self.strict_break and self.shortcut_disable_time <= 0
|
self.enable_shortcut = not self.strict_break and self.shortcut_disable_time <= 0
|
||||||
GLib.idle_add(lambda: self.__show_break_screen(message, image_path, plugins_data))
|
GLib.idle_add(lambda: self.__show_break_screen(message, image_path, plugins_data))
|
||||||
|
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""
|
"""
|
||||||
Hide the break screen from active window and destroy all other windows
|
Hide the break screen from active window and destroy all other windows
|
||||||
|
@ -128,7 +123,6 @@ class BreakScreen:
|
||||||
# Destroy other windows if exists
|
# Destroy other windows if exists
|
||||||
GLib.idle_add(lambda: self.__destroy_all_screens())
|
GLib.idle_add(lambda: self.__destroy_all_screens())
|
||||||
|
|
||||||
|
|
||||||
def __show_break_screen(self, message, image_path, plugins_data):
|
def __show_break_screen(self, message, image_path, plugins_data):
|
||||||
"""
|
"""
|
||||||
Show an empty break screen on all screens.
|
Show an empty break screen on all screens.
|
||||||
|
@ -175,14 +169,12 @@ class BreakScreen:
|
||||||
btn_skip.set_visible(True)
|
btn_skip.set_visible(True)
|
||||||
box_buttons.pack_start(btn_skip, True, True, 0)
|
box_buttons.pack_start(btn_skip, True, True, 0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Set values
|
# Set values
|
||||||
if image_path:
|
if image_path:
|
||||||
img_break.set_from_file(image_path)
|
img_break.set_from_file(image_path)
|
||||||
lbl_message.set_label(message)
|
lbl_message.set_label(message)
|
||||||
lbl_left.set_markup(plugins_data['left']);
|
lbl_left.set_markup(plugins_data['left'])
|
||||||
lbl_right.set_markup(plugins_data['right']);
|
lbl_right.set_markup(plugins_data['right'])
|
||||||
|
|
||||||
self.windows.append(window)
|
self.windows.append(window)
|
||||||
self.count_labels.append(lbl_count)
|
self.count_labels.append(lbl_count)
|
||||||
|
@ -199,7 +191,6 @@ class BreakScreen:
|
||||||
window.present()
|
window.present()
|
||||||
window.fullscreen()
|
window.fullscreen()
|
||||||
|
|
||||||
|
|
||||||
def __update_count_down(self, count):
|
def __update_count_down(self, count):
|
||||||
"""
|
"""
|
||||||
Update the countdown on all break screens.
|
Update the countdown on all break screens.
|
||||||
|
@ -207,7 +198,6 @@ class BreakScreen:
|
||||||
for label in self.count_labels:
|
for label in self.count_labels:
|
||||||
label.set_text(count)
|
label.set_text(count)
|
||||||
|
|
||||||
|
|
||||||
def __lock_keyboard(self):
|
def __lock_keyboard(self):
|
||||||
"""
|
"""
|
||||||
Lock the keyboard to prevent the user from using keyboard shortcuts
|
Lock the keyboard to prevent the user from using keyboard shortcuts
|
||||||
|
@ -217,11 +207,11 @@ class BreakScreen:
|
||||||
display = Display()
|
display = Display()
|
||||||
root = display.screen().root
|
root = display.screen().root
|
||||||
# Grap the keyboard
|
# Grap the keyboard
|
||||||
root.grab_keyboard(owner_events = False, pointer_mode = X.GrabModeAsync, keyboard_mode = X.GrabModeAsync, time = X.CurrentTime)
|
root.grab_keyboard(owner_events=False, pointer_mode=X.GrabModeAsync, keyboard_mode=X.GrabModeAsync, time=X.CurrentTime)
|
||||||
# Consume keyboard events
|
# Consume keyboard events
|
||||||
while self.lock_keyboard:
|
while self.lock_keyboard:
|
||||||
event = display.next_event()
|
event = display.next_event()
|
||||||
display.allow_events(mode = X.AsyncBoth, time = X.CurrentTime)
|
display.allow_events(mode=X.AsyncBoth, time=X.CurrentTime)
|
||||||
if self.enable_shortcut and event.type == X.KeyPress:
|
if self.enable_shortcut and event.type == X.KeyPress:
|
||||||
if event.detail == self.keycode_shortcut_skip:
|
if event.detail == self.keycode_shortcut_skip:
|
||||||
self.skip_break()
|
self.skip_break()
|
||||||
|
@ -235,14 +225,12 @@ class BreakScreen:
|
||||||
display.ungrab_keyboard(X.CurrentTime)
|
display.ungrab_keyboard(X.CurrentTime)
|
||||||
display.flush()
|
display.flush()
|
||||||
|
|
||||||
|
|
||||||
def __release_keyboard(self):
|
def __release_keyboard(self):
|
||||||
"""
|
"""
|
||||||
Release the locked keyboard.
|
Release the locked keyboard.
|
||||||
"""
|
"""
|
||||||
self.lock_keyboard = False
|
self.lock_keyboard = False
|
||||||
|
|
||||||
|
|
||||||
def __destroy_all_screens(self):
|
def __destroy_all_screens(self):
|
||||||
"""
|
"""
|
||||||
Close all the break screens.
|
Close all the break screens.
|
||||||
|
|
|
@ -24,12 +24,12 @@ from safeeyes import Utility
|
||||||
|
|
||||||
APPINDICATOR_ID = 'safeeyes'
|
APPINDICATOR_ID = 'safeeyes'
|
||||||
|
|
||||||
|
|
||||||
class Notification:
|
class Notification:
|
||||||
"""
|
"""
|
||||||
This class is responsible for the notification to the user before the break.
|
This class is responsible for the notification to the user before the break.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, context, language):
|
def __init__(self, context, language):
|
||||||
"""
|
"""
|
||||||
Initialize the notification.
|
Initialize the notification.
|
||||||
|
@ -39,13 +39,11 @@ class Notification:
|
||||||
self.context = context
|
self.context = context
|
||||||
self.language = language
|
self.language = language
|
||||||
|
|
||||||
|
|
||||||
def initialize(self, language):
|
def initialize(self, language):
|
||||||
"""
|
"""
|
||||||
Initialize the notification object.
|
Initialize the notification object.
|
||||||
"""
|
"""
|
||||||
self.language = language
|
self.language = language
|
||||||
|
|
||||||
|
|
||||||
def show(self, warning_time):
|
def show(self, warning_time):
|
||||||
"""
|
"""
|
||||||
|
@ -59,14 +57,13 @@ class Notification:
|
||||||
message += self.language['messages']['ready_for_a_short_break'].format(warning_time)
|
message += self.language['messages']['ready_for_a_short_break'].format(warning_time)
|
||||||
else:
|
else:
|
||||||
message += self.language['messages']['ready_for_a_long_break'].format(warning_time)
|
message += self.language['messages']['ready_for_a_long_break'].format(warning_time)
|
||||||
|
|
||||||
self.notification = Notify.Notification.new('Safe Eyes', message, icon='safeeyes_enabled')
|
self.notification = Notify.Notification.new('Safe Eyes', message, icon='safeeyes_enabled')
|
||||||
try:
|
try:
|
||||||
self.notification.show()
|
self.notification.show()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.exception('Error in showing notification', e)
|
logging.exception('Error in showing notification', e)
|
||||||
|
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""
|
"""
|
||||||
Close the notification if it is not closed by the system already.
|
Close the notification if it is not closed by the system already.
|
||||||
|
@ -78,10 +75,9 @@ class Notification:
|
||||||
# Some Linux systems automatically close the notification.
|
# Some Linux systems automatically close the notification.
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def quite(self):
|
def quite(self):
|
||||||
"""
|
"""
|
||||||
Uninitialize the notification. Call this method when closing the application.
|
Uninitialize the notification. Call this method when closing the application.
|
||||||
"""
|
"""
|
||||||
logging.info('Uninitialize Safe Eyes notification')
|
logging.info('Uninitialize Safe Eyes notification')
|
||||||
Utility.execute_main_thread(Notify.uninit)
|
Utility.execute_main_thread(Notify.uninit)
|
||||||
|
|
|
@ -23,12 +23,12 @@ from safeeyes import Utility
|
||||||
plugins_directory = os.path.join(Utility.config_directory, 'plugins')
|
plugins_directory = os.path.join(Utility.config_directory, 'plugins')
|
||||||
sys.path.append(os.path.abspath(plugins_directory))
|
sys.path.append(os.path.abspath(plugins_directory))
|
||||||
|
|
||||||
|
|
||||||
class Plugins:
|
class Plugins:
|
||||||
"""
|
"""
|
||||||
This class manages imports the plugins and calls the methods defined in those plugins.
|
This class manages imports the plugins and calls the methods defined in those plugins.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
"""
|
"""
|
||||||
Load the plugins.
|
Load the plugins.
|
||||||
|
@ -47,18 +47,17 @@ class Plugins:
|
||||||
else:
|
else:
|
||||||
logging.warning('Plugin file ' + str(plugin['name']) + '.py not found')
|
logging.warning('Plugin file ' + str(plugin['name']) + '.py not found')
|
||||||
else:
|
else:
|
||||||
logging.warning('Ignoring the plugin ' + str(plugin['name']) + ' due to invalid location value: ' + plugin['location'])
|
logging.warning('Ignoring the plugin ' + str(plugin['name']) + ' due to invalid location value: ' + plugin['location'])
|
||||||
|
|
||||||
if self.__plugins:
|
if self.__plugins:
|
||||||
self.__thread_pool = ThreadPool(min([4, len(self.__plugins)]))
|
self.__thread_pool = ThreadPool(min([4, len(self.__plugins)]))
|
||||||
|
|
||||||
|
|
||||||
def start(self, context):
|
def start(self, context):
|
||||||
"""
|
"""
|
||||||
Call the start function of all the plugins in separate thread.
|
Call the start function of all the plugins in separate thread.
|
||||||
"""
|
"""
|
||||||
if self.__plugins:
|
if self.__plugins:
|
||||||
context = copy.deepcopy(context) # If plugins change the context, it should not affect Safe Eyes
|
context = copy.deepcopy(context) # If plugins change the context, it should not affect Safe Eyes
|
||||||
for plugin in self.__plugins:
|
for plugin in self.__plugins:
|
||||||
try:
|
try:
|
||||||
self.__thread_pool.apply_async(plugin['module'].start, (context,))
|
self.__thread_pool.apply_async(plugin['module'].start, (context,))
|
||||||
|
@ -70,14 +69,13 @@ class Plugins:
|
||||||
Call the pre_notification function of all the plugins in separate thread.
|
Call the pre_notification function of all the plugins in separate thread.
|
||||||
"""
|
"""
|
||||||
if self.__plugins:
|
if self.__plugins:
|
||||||
context = copy.deepcopy(context) # If plugins change the context, it should not affect Safe Eyes
|
context = copy.deepcopy(context) # If plugins change the context, it should not affect Safe Eyes
|
||||||
for plugin in self.__plugins:
|
for plugin in self.__plugins:
|
||||||
try:
|
try:
|
||||||
self.__thread_pool.apply_async(plugin['module'].pre_notification, (context,))
|
self.__thread_pool.apply_async(plugin['module'].pre_notification, (context,))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def pre_break(self, context):
|
def pre_break(self, context):
|
||||||
"""
|
"""
|
||||||
Call the pre_break function of all the plugins and provide maximum 1 second to return the result.
|
Call the pre_break function of all the plugins and provide maximum 1 second to return the result.
|
||||||
|
@ -87,14 +85,14 @@ class Plugins:
|
||||||
"""
|
"""
|
||||||
output = {'left': ' \n', 'right': ' \n'}
|
output = {'left': ' \n', 'right': ' \n'}
|
||||||
if self.__plugins:
|
if self.__plugins:
|
||||||
context = copy.deepcopy(context) # If plugins change the context, it should not affect Safe Eyes
|
context = copy.deepcopy(context) # If plugins change the context, it should not affect Safe Eyes
|
||||||
multiple_results = [self.__thread_pool.apply_async(plugin['module'].pre_break, (context,)) for plugin in self.__plugins]
|
multiple_results = [self.__thread_pool.apply_async(plugin['module'].pre_break, (context,)) for plugin in self.__plugins]
|
||||||
for i in range(len(multiple_results)):
|
for i in range(len(multiple_results)):
|
||||||
try:
|
try:
|
||||||
result = multiple_results[i].get(timeout=1)
|
result = multiple_results[i].get(timeout=1)
|
||||||
if result:
|
if result:
|
||||||
# Limit the line length to 50 characters
|
# Limit the line length to 50 characters
|
||||||
large_lines = list(filter(lambda x: len(x) > 50, Utility.html_to_text(result).splitlines()))
|
large_lines = list(filter(lambda x: len(x) > 50, Utility.html_to_text(result).splitlines()))
|
||||||
if large_lines:
|
if large_lines:
|
||||||
logging.warning('Ignoring lengthy result from the plugin ' + self.__plugins[i]['name'])
|
logging.warning('Ignoring lengthy result from the plugin ' + self.__plugins[i]['name'])
|
||||||
continue
|
continue
|
||||||
|
@ -105,13 +103,12 @@ class Plugins:
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
def post_break(self, context):
|
def post_break(self, context):
|
||||||
"""
|
"""
|
||||||
Call the post_break function of all the plugins in separate thread.
|
Call the post_break function of all the plugins in separate thread.
|
||||||
"""
|
"""
|
||||||
if self.__plugins:
|
if self.__plugins:
|
||||||
context = copy.deepcopy(context) # If plugins change the context, it should not affect Safe Eyes
|
context = copy.deepcopy(context) # If plugins change the context, it should not affect Safe Eyes
|
||||||
for plugin in self.__plugins:
|
for plugin in self.__plugins:
|
||||||
try:
|
try:
|
||||||
self.__thread_pool.apply_async(plugin['module'].post_break, (context,))
|
self.__thread_pool.apply_async(plugin['module'].post_break, (context,))
|
||||||
|
@ -123,7 +120,7 @@ class Plugins:
|
||||||
Call the exit function of all the plugins in separate thread.
|
Call the exit function of all the plugins in separate thread.
|
||||||
"""
|
"""
|
||||||
if self.__plugins:
|
if self.__plugins:
|
||||||
context = copy.deepcopy(context) # If plugins change the context, it should not affect Safe Eyes
|
context = copy.deepcopy(context) # If plugins change the context, it should not affect Safe Eyes
|
||||||
|
|
||||||
# Give maximum 1 sec for all plugins before terminating the thread pool
|
# Give maximum 1 sec for all plugins before terminating the thread pool
|
||||||
multiple_results = [self.__thread_pool.apply_async(plugin['module'].exit, (context,)) for plugin in self.__plugins]
|
multiple_results = [self.__thread_pool.apply_async(plugin['module'].exit, (context,)) for plugin in self.__plugins]
|
||||||
|
@ -135,12 +132,11 @@ class Plugins:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.__thread_pool.terminate() # Shutdown the pool
|
self.__thread_pool.terminate() # Shutdown the pool
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def __has_method(self, module, method_name, no_of_args=1):
|
||||||
def __has_method(self, module, method_name, no_of_args = 1):
|
|
||||||
"""
|
"""
|
||||||
Check whether the given function is defined in the module or not.
|
Check whether the given function is defined in the module or not.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -17,13 +17,15 @@
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
import time, datetime, threading, sys, subprocess, logging
|
import time, datetime, threading, logging
|
||||||
from safeeyes import Utility
|
from safeeyes import Utility
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Core of Safe Eyes which runs the scheduler and notifies the breaks.
|
Core of Safe Eyes which runs the scheduler and notifies the breaks.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class SafeEyesCore:
|
class SafeEyesCore:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -48,14 +50,13 @@ class SafeEyesCore:
|
||||||
self.context['skipped'] = False
|
self.context['skipped'] = False
|
||||||
self.context['postponed'] = False
|
self.context['postponed'] = False
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Initialize the internal properties from configuration
|
Initialize the internal properties from configuration
|
||||||
"""
|
"""
|
||||||
def initialize(self, config, language):
|
def initialize(self, config, language):
|
||||||
logging.info("Initialize the core")
|
logging.info("Initialize the core")
|
||||||
self.short_break_exercises = [] #language['exercises']['short_break_exercises']
|
self.short_break_exercises = [] # language['exercises']['short_break_exercises']
|
||||||
self.long_break_exercises = [] #language['exercises']['long_break_exercises']
|
self.long_break_exercises = [] # language['exercises']['long_break_exercises']
|
||||||
|
|
||||||
self.no_of_short_breaks_per_long_break = config['no_of_short_breaks_per_long_break']
|
self.no_of_short_breaks_per_long_break = config['no_of_short_breaks_per_long_break']
|
||||||
self.pre_break_warning_time = config['pre_break_warning_time']
|
self.pre_break_warning_time = config['pre_break_warning_time']
|
||||||
|
@ -111,7 +112,6 @@ class SafeEyesCore:
|
||||||
|
|
||||||
self.long_break_exercises.append([name, break_time, audible_alert, image])
|
self.long_break_exercises.append([name, break_time, audible_alert, image])
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Start Safe Eyes is it is not running already.
|
Start Safe Eyes is it is not running already.
|
||||||
"""
|
"""
|
||||||
|
@ -125,7 +125,6 @@ class SafeEyesCore:
|
||||||
if self.context['idle_pause_enabled']:
|
if self.context['idle_pause_enabled']:
|
||||||
Utility.start_thread(self.__start_idle_monitor)
|
Utility.start_thread(self.__start_idle_monitor)
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Stop Safe Eyes if it is running.
|
Stop Safe Eyes if it is running.
|
||||||
"""
|
"""
|
||||||
|
@ -150,7 +149,6 @@ class SafeEyesCore:
|
||||||
self.idle_condition.notify_all()
|
self.idle_condition.notify_all()
|
||||||
self.idle_condition.release()
|
self.idle_condition.release()
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Pause Safe Eyes if it is running.
|
Pause Safe Eyes if it is running.
|
||||||
"""
|
"""
|
||||||
|
@ -162,7 +160,6 @@ class SafeEyesCore:
|
||||||
self.notification_condition.notify_all()
|
self.notification_condition.notify_all()
|
||||||
self.notification_condition.release()
|
self.notification_condition.release()
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Resume Safe Eyes if it is not running.
|
Resume Safe Eyes if it is not running.
|
||||||
"""
|
"""
|
||||||
|
@ -172,7 +169,6 @@ class SafeEyesCore:
|
||||||
self.running = True
|
self.running = True
|
||||||
Utility.start_thread(self.__scheduler_job)
|
Utility.start_thread(self.__scheduler_job)
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
User skipped the break using Skip button
|
User skipped the break using Skip button
|
||||||
"""
|
"""
|
||||||
|
@ -185,7 +181,6 @@ class SafeEyesCore:
|
||||||
def postpone_break(self):
|
def postpone_break(self):
|
||||||
self.context['postponed'] = True
|
self.context['postponed'] = True
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Scheduler task to execute during every interval
|
Scheduler task to execute during every interval
|
||||||
"""
|
"""
|
||||||
|
@ -193,7 +188,7 @@ class SafeEyesCore:
|
||||||
if not self.__is_running():
|
if not self.__is_running():
|
||||||
return
|
return
|
||||||
|
|
||||||
time_to_wait = self.break_interval # In minutes
|
time_to_wait = self.break_interval # In minutes
|
||||||
|
|
||||||
if self.context['postponed']:
|
if self.context['postponed']:
|
||||||
# Reduce the break count by 1 to show the same break again
|
# Reduce the break count by 1 to show the same break again
|
||||||
|
@ -222,7 +217,7 @@ class SafeEyesCore:
|
||||||
# Wait for the pre break warning period
|
# Wait for the pre break warning period
|
||||||
logging.info("Pre-break waiting for {} minutes".format(time_to_wait))
|
logging.info("Pre-break waiting for {} minutes".format(time_to_wait))
|
||||||
self.notification_condition.acquire()
|
self.notification_condition.acquire()
|
||||||
self.notification_condition.wait(time_to_wait * 60) # Convert to seconds
|
self.notification_condition.wait(time_to_wait * 60) # Convert to seconds
|
||||||
self.notification_condition.release()
|
self.notification_condition.release()
|
||||||
|
|
||||||
logging.info("Pre-break waiting is over")
|
logging.info("Pre-break waiting is over")
|
||||||
|
@ -235,7 +230,6 @@ class SafeEyesCore:
|
||||||
self.is_before_break = False
|
self.is_before_break = False
|
||||||
Utility.execute_main_thread(self.__check_active_window)
|
Utility.execute_main_thread(self.__check_active_window)
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Show the notification and start the break after the notification.
|
Show the notification and start the break after the notification.
|
||||||
"""
|
"""
|
||||||
|
@ -252,13 +246,12 @@ class SafeEyesCore:
|
||||||
self.is_before_break = True
|
self.is_before_break = True
|
||||||
Utility.execute_main_thread(self.__check_active_window)
|
Utility.execute_main_thread(self.__check_active_window)
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Check the active window for full-screen and user defined exceptions.
|
Check the active window for full-screen and user defined exceptions.
|
||||||
"""
|
"""
|
||||||
def __check_active_window(self):
|
def __check_active_window(self):
|
||||||
# Check the active window again. (User might changed the window)
|
# Check the active window again. (User might changed the window)
|
||||||
if self.__is_running() and Utility.is_active_window_skipped(self.skip_break_window_classes, self.take_break_window_classes, self.is_before_break):
|
if self.__is_running() and Utility.is_active_window_skipped(self.skip_break_window_classes, self.take_break_window_classes, self.is_before_break):
|
||||||
# If full screen app found, do not show break screen
|
# If full screen app found, do not show break screen
|
||||||
logging.info("Found a skip_break or full-screen window. Skip the break")
|
logging.info("Found a skip_break or full-screen window. Skip the break")
|
||||||
if self.__is_running():
|
if self.__is_running():
|
||||||
|
@ -272,8 +265,6 @@ class SafeEyesCore:
|
||||||
else:
|
else:
|
||||||
Utility.start_thread(self.__show_notification)
|
Utility.start_thread(self.__show_notification)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Start the break screen.
|
Start the break screen.
|
||||||
"""
|
"""
|
||||||
|
@ -311,7 +302,7 @@ class SafeEyesCore:
|
||||||
count_down = total_break_time - seconds
|
count_down = total_break_time - seconds
|
||||||
self.context['count_down'] = count_down
|
self.context['count_down'] = count_down
|
||||||
self.on_countdown(count_down, seconds)
|
self.on_countdown(count_down, seconds)
|
||||||
time.sleep(1) # Sleep for 1 second
|
time.sleep(1) # Sleep for 1 second
|
||||||
seconds -= 1
|
seconds -= 1
|
||||||
|
|
||||||
# Loop terminated because of timeout (not skipped) -> Close the break alert
|
# Loop terminated because of timeout (not skipped) -> Close the break alert
|
||||||
|
@ -327,22 +318,18 @@ class SafeEyesCore:
|
||||||
# Schedule the break again
|
# Schedule the break again
|
||||||
Utility.start_thread(self.__scheduler_job)
|
Utility.start_thread(self.__scheduler_job)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Tells whether Safe Eyes is running or not.
|
Tells whether Safe Eyes is running or not.
|
||||||
"""
|
"""
|
||||||
def __is_running(self):
|
def __is_running(self):
|
||||||
return self.active and self.running
|
return self.active and self.running
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Check if the current break is long break or short current
|
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
|
return self.break_count == self.no_of_short_breaks_per_long_break - 1
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Continuously check the system idle time and pause/resume Safe Eyes based on it.
|
Continuously check the system idle time and pause/resume Safe Eyes based on it.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -18,9 +18,10 @@
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
gi.require_version('Gtk', '3.0')
|
gi.require_version('Gtk', '3.0')
|
||||||
from gi.repository import Gtk, Gdk, GdkX11, GObject
|
from gi.repository import Gtk, GObject
|
||||||
from safeeyes import Utility
|
from safeeyes import Utility
|
||||||
|
|
||||||
|
|
||||||
class SettingsDialog:
|
class SettingsDialog:
|
||||||
"""
|
"""
|
||||||
Create and initialize SettingsDialog instance.
|
Create and initialize SettingsDialog instance.
|
||||||
|
@ -117,7 +118,7 @@ class SettingsDialog:
|
||||||
language_list_store.append([language['ui_controls']['system_language']])
|
language_list_store.append([language['ui_controls']['system_language']])
|
||||||
language_list_store.append(['-'])
|
language_list_store.append(['-'])
|
||||||
self.languages.append('system')
|
self.languages.append('system')
|
||||||
self.languages.append('system') # Dummy record for row separator
|
self.languages.append('system') # Dummy record for row separator
|
||||||
if 'system' == lang_code:
|
if 'system' == lang_code:
|
||||||
self.cmb_language.set_active(0)
|
self.cmb_language.set_active(0)
|
||||||
|
|
||||||
|
@ -129,19 +130,17 @@ class SettingsDialog:
|
||||||
language_index += 1
|
language_index += 1
|
||||||
|
|
||||||
self.cmb_language.set_model(language_list_store)
|
self.cmb_language.set_model(language_list_store)
|
||||||
self.cmb_language.set_row_separator_func(lambda m,i: m.get_value(i, 0) == '-')
|
self.cmb_language.set_row_separator_func(lambda m, i: m.get_value(i, 0) == '-')
|
||||||
cell = Gtk.CellRendererText()
|
cell = Gtk.CellRendererText()
|
||||||
self.cmb_language.pack_start(cell, True)
|
self.cmb_language.pack_start(cell, True)
|
||||||
self.cmb_language.add_attribute(cell, 'text', 0)
|
self.cmb_language.add_attribute(cell, 'text', 0)
|
||||||
|
|
||||||
|
|
||||||
def show(self):
|
def show(self):
|
||||||
"""
|
"""
|
||||||
Show the SettingsDialog.
|
Show the SettingsDialog.
|
||||||
"""
|
"""
|
||||||
self.window.show_all()
|
self.window.show_all()
|
||||||
|
|
||||||
|
|
||||||
def on_switch_screen_lock_activate(self, switch, state):
|
def on_switch_screen_lock_activate(self, switch, state):
|
||||||
"""
|
"""
|
||||||
Event handler to the state change of the screen_lock switch.
|
Event handler to the state change of the screen_lock switch.
|
||||||
|
@ -149,13 +148,12 @@ class SettingsDialog:
|
||||||
"""
|
"""
|
||||||
self.spin_time_to_screen_lock.set_sensitive(self.switch_screen_lock.get_active())
|
self.spin_time_to_screen_lock.set_sensitive(self.switch_screen_lock.get_active())
|
||||||
|
|
||||||
|
|
||||||
def on_switch_strict_break_activate(self, switch, state):
|
def on_switch_strict_break_activate(self, switch, state):
|
||||||
"""
|
"""
|
||||||
Event handler to the state change of the postpone switch.
|
Event handler to the state change of the postpone switch.
|
||||||
Enable or disable the self.spin_postpone_duration based on the state of the postpone switch.
|
Enable or disable the self.spin_postpone_duration based on the state of the postpone switch.
|
||||||
"""
|
"""
|
||||||
strict_break_enable = state #self.switch_strict_break.get_active()
|
strict_break_enable = state # self.switch_strict_break.get_active()
|
||||||
self.switch_postpone.set_sensitive(not strict_break_enable)
|
self.switch_postpone.set_sensitive(not strict_break_enable)
|
||||||
if strict_break_enable:
|
if strict_break_enable:
|
||||||
self.switch_postpone.set_active(False)
|
self.switch_postpone.set_active(False)
|
||||||
|
@ -176,14 +174,13 @@ class SettingsDialog:
|
||||||
self.__show_message_dialog(self.language['messages']['audible_alert_disabled'], self.language['messages']['software_required'].format('pyaudio'))
|
self.__show_message_dialog(self.language['messages']['audible_alert_disabled'], self.language['messages']['software_required'].format('pyaudio'))
|
||||||
switch.emit_stop_by_name('state-set')
|
switch.emit_stop_by_name('state-set')
|
||||||
self.switch_audible_alert.set_active(False)
|
self.switch_audible_alert.set_active(False)
|
||||||
|
|
||||||
def on_window_delete(self, *args):
|
def on_window_delete(self, *args):
|
||||||
"""
|
"""
|
||||||
Event handler for Settings dialog close action.
|
Event handler for Settings dialog close action.
|
||||||
"""
|
"""
|
||||||
self.window.destroy()
|
self.window.destroy()
|
||||||
|
|
||||||
|
|
||||||
def on_save_clicked(self, button):
|
def on_save_clicked(self, button):
|
||||||
"""
|
"""
|
||||||
Event handler for Save button click.
|
Event handler for Save button click.
|
||||||
|
@ -210,9 +207,8 @@ class SettingsDialog:
|
||||||
else:
|
else:
|
||||||
self.config['audible_alert'] = self.switch_audible_alert.get_active()
|
self.config['audible_alert'] = self.switch_audible_alert.get_active()
|
||||||
|
|
||||||
self.on_save_settings(self.config) # Call the provided save method
|
self.on_save_settings(self.config) # Call the provided save method
|
||||||
self.window.destroy() # Close the settings window
|
self.window.destroy() # Close the settings window
|
||||||
|
|
||||||
|
|
||||||
def on_cancel_clicked(self, button):
|
def on_cancel_clicked(self, button):
|
||||||
"""
|
"""
|
||||||
|
@ -227,4 +223,4 @@ class SettingsDialog:
|
||||||
dialog = Gtk.MessageDialog(self.window, 0, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK, primary_text)
|
dialog = Gtk.MessageDialog(self.window, 0, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK, primary_text)
|
||||||
dialog.format_secondary_text(secondary_text)
|
dialog.format_secondary_text(secondary_text)
|
||||||
dialog.run()
|
dialog.run()
|
||||||
dialog.destroy()
|
dialog.destroy()
|
||||||
|
|
|
@ -231,7 +231,6 @@ class TrayIcon:
|
||||||
Utility.start_thread(self.__schedule_resume, time_minutes=time_to_wait)
|
Utility.start_thread(self.__schedule_resume, time_minutes=time_to_wait)
|
||||||
self.item_info.set_label(self.language['messages']['disabled_until_x'].format(Utility.format_time(self.wakeup_time)))
|
self.item_info.set_label(self.language['messages']['disabled_until_x'].format(Utility.format_time(self.wakeup_time)))
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This method is called by the core to prevent user from disabling Safe Eyes after the notification.
|
This method is called by the core to prevent user from disabling Safe Eyes after the notification.
|
||||||
"""
|
"""
|
||||||
|
@ -254,7 +253,7 @@ class TrayIcon:
|
||||||
|
|
||||||
def __schedule_resume(self, time_minutes):
|
def __schedule_resume(self, time_minutes):
|
||||||
self.idle_condition.acquire()
|
self.idle_condition.acquire()
|
||||||
self.idle_condition.wait(time_minutes * 60) # Convert to seconds
|
self.idle_condition.wait(time_minutes * 60) # Convert to seconds
|
||||||
self.idle_condition.release()
|
self.idle_condition.release()
|
||||||
|
|
||||||
with self.lock:
|
with self.lock:
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
gi.require_version('Gdk', '3.0')
|
gi.require_version('Gdk', '3.0')
|
||||||
from gi.repository import Gtk, Gdk, GLib
|
from gi.repository import Gdk, GLib
|
||||||
from html.parser import HTMLParser
|
from html.parser import HTMLParser
|
||||||
from distutils.version import LooseVersion
|
from distutils.version import LooseVersion
|
||||||
from logging.handlers import RotatingFileHandler
|
from logging.handlers import RotatingFileHandler
|
||||||
|
@ -65,10 +65,11 @@ def play_notification():
|
||||||
|
|
||||||
# Create a sound stream
|
# Create a sound stream
|
||||||
wrapper = pyaudio.PyAudio()
|
wrapper = pyaudio.PyAudio()
|
||||||
stream = wrapper.open(format=wrapper.get_format_from_width(sound.getsampwidth()),
|
stream = wrapper.open(format=wrapper.get_format_from_width(
|
||||||
channels=sound.getnchannels(),
|
sound.getsampwidth()),
|
||||||
rate=sound.getframerate(),
|
channels=sound.getnchannels(),
|
||||||
output=True)
|
rate=sound.getframerate(),
|
||||||
|
output=True)
|
||||||
|
|
||||||
# Write file data into the sound stream
|
# Write file data into the sound stream
|
||||||
data = sound.readframes(CHUNK)
|
data = sound.readframes(CHUNK)
|
||||||
|
@ -110,7 +111,7 @@ def system_idle_time():
|
||||||
Return the idle time if xprintidle is available, otherwise return 0.
|
Return the idle time if xprintidle is available, otherwise return 0.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return int(subprocess.check_output(['xprintidle']).decode('utf-8')) / 60000 # Convert to minutes
|
return int(subprocess.check_output(['xprintidle']).decode('utf-8')) / 60000 # Convert to minutes
|
||||||
except:
|
except:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
@ -144,7 +145,7 @@ def is_active_window_skipped(skip_break_window_classes, take_break_window_classe
|
||||||
active_window = screen.get_active_window()
|
active_window = screen.get_active_window()
|
||||||
if active_window:
|
if active_window:
|
||||||
active_xid = str(active_window.get_xid())
|
active_xid = str(active_window.get_xid())
|
||||||
cmdlist = ['xprop', '-root', '-notype','-id',active_xid, 'WM_CLASS', '_NET_WM_STATE']
|
cmdlist = ['xprop', '-root', '-notype', '-id', active_xid, 'WM_CLASS', '_NET_WM_STATE']
|
||||||
|
|
||||||
try:
|
try:
|
||||||
stdout = subprocess.check_output(cmdlist).decode('utf-8')
|
stdout = subprocess.check_output(cmdlist).decode('utf-8')
|
||||||
|
@ -206,6 +207,7 @@ def mkdir(path):
|
||||||
logging.error('Error while creating ' + str(path))
|
logging.error('Error while creating ' + str(path))
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
def parse_language_code(lang_code):
|
def parse_language_code(lang_code):
|
||||||
"""
|
"""
|
||||||
Convert the user defined language code to a valid one.
|
Convert the user defined language code to a valid one.
|
||||||
|
@ -273,7 +275,7 @@ def desktop_environment():
|
||||||
current_desktop = os.environ.get('XDG_CURRENT_DESKTOP')
|
current_desktop = os.environ.get('XDG_CURRENT_DESKTOP')
|
||||||
if desktop_session is not None:
|
if desktop_session is not None:
|
||||||
desktop_session = desktop_session.lower()
|
desktop_session = desktop_session.lower()
|
||||||
if desktop_session in ['gnome','unity', 'budgie-desktop', 'cinnamon', 'mate', 'xfce4', 'lxde', 'pantheon', 'fluxbox', 'blackbox', 'openbox', 'icewm', 'jwm', 'afterstep','trinity', 'kde']:
|
if desktop_session in ['gnome', 'unity', 'budgie-desktop', 'cinnamon', 'mate', 'xfce4', 'lxde', 'pantheon', 'fluxbox', 'blackbox', 'openbox', 'icewm', 'jwm', 'afterstep', 'trinity', 'kde']:
|
||||||
return desktop_session
|
return desktop_session
|
||||||
elif (desktop_session.startswith('xubuntu') or (current_desktop is not None and 'xfce' in current_desktop)):
|
elif (desktop_session.startswith('xubuntu') or (current_desktop is not None and 'xfce' in current_desktop)):
|
||||||
return 'xfce'
|
return 'xfce'
|
||||||
|
@ -314,14 +316,14 @@ def lock_screen_command():
|
||||||
return ['mate-screensaver-command', '--lock']
|
return ['mate-screensaver-command', '--lock']
|
||||||
elif desktop_session == 'kde' or 'plasma' in desktop_session or desktop_session.startswith('kubuntu') or os.environ.get('KDE_FULL_SESSION') == 'true':
|
elif desktop_session == 'kde' or 'plasma' in desktop_session or desktop_session.startswith('kubuntu') or os.environ.get('KDE_FULL_SESSION') == 'true':
|
||||||
return ['qdbus', 'org.freedesktop.ScreenSaver', '/ScreenSaver', 'Lock']
|
return ['qdbus', 'org.freedesktop.ScreenSaver', '/ScreenSaver', 'Lock']
|
||||||
elif desktop_session in ['gnome','unity', 'budgie-desktop'] or desktop_session.startswith('ubuntu'):
|
elif desktop_session in ['gnome', 'unity', 'budgie-desktop'] or desktop_session.startswith('ubuntu'):
|
||||||
if command_exist('gnome-screensaver-command'):
|
if command_exist('gnome-screensaver-command'):
|
||||||
return ['gnome-screensaver-command', '--lock']
|
return ['gnome-screensaver-command', '--lock']
|
||||||
else:
|
else:
|
||||||
# From Gnome 3.8 no gnome-screensaver-command
|
# 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']
|
||||||
elif os.environ.get('GNOME_DESKTOP_SESSION_ID'):
|
elif os.environ.get('GNOME_DESKTOP_SESSION_ID'):
|
||||||
if not 'deprecated' in os.environ.get('GNOME_DESKTOP_SESSION_ID') and command_exist('gnome-screensaver-command'):
|
if 'deprecated' not in os.environ.get('GNOME_DESKTOP_SESSION_ID') and command_exist('gnome-screensaver-command'):
|
||||||
# Gnome 2
|
# Gnome 2
|
||||||
return ['gnome-screensaver-command', '--lock']
|
return ['gnome-screensaver-command', '--lock']
|
||||||
return None
|
return None
|
||||||
|
@ -417,7 +419,7 @@ def intialize_logging():
|
||||||
log_formatter = logging.Formatter('%(asctime)s [%(levelname)s]:[%(threadName)s] %(message)s')
|
log_formatter = logging.Formatter('%(asctime)s [%(levelname)s]:[%(threadName)s] %(message)s')
|
||||||
|
|
||||||
# Apped the logs and overwrite once reached 5MB
|
# Apped the logs and overwrite once reached 5MB
|
||||||
handler = RotatingFileHandler(log_file_path, mode='a', maxBytes=5*1024*1024, backupCount=2, encoding=None, delay=0)
|
handler = RotatingFileHandler(log_file_path, mode='a', maxBytes=5 * 1024 * 1024, backupCount=2, encoding=None, delay=0)
|
||||||
handler.setFormatter(log_formatter)
|
handler.setFormatter(log_formatter)
|
||||||
handler.setLevel(logging.INFO)
|
handler.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
@ -484,7 +486,7 @@ class __HTMLTextExtractor(HTMLParser):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.reset()
|
self.reset()
|
||||||
self.strict = False
|
self.strict = False
|
||||||
self.convert_charrefs= True
|
self.convert_charrefs = True
|
||||||
self.fed = []
|
self.fed = []
|
||||||
|
|
||||||
def handle_data(self, d):
|
def handle_data(self, d):
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import os, gi, json, dbus, logging, operator, psutil, sys
|
import os, gi, json, dbus, logging, psutil, sys
|
||||||
from threading import Timer
|
from threading import Timer
|
||||||
from dbus.mainloop.glib import DBusGMainLoop
|
from dbus.mainloop.glib import DBusGMainLoop
|
||||||
gi.require_version('Gtk', '3.0')
|
gi.require_version('Gtk', '3.0')
|
||||||
|
@ -41,6 +41,7 @@ about_dialog_glade = os.path.join(Utility.bin_directory, "glade/about_dialog.gla
|
||||||
is_active = True
|
is_active = True
|
||||||
SAFE_EYES_VERSION = "1.2.1"
|
SAFE_EYES_VERSION = "1.2.1"
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Listen to tray icon Settings action and send the signal to Settings dialog.
|
Listen to tray icon Settings action and send the signal to Settings dialog.
|
||||||
"""
|
"""
|
||||||
|
@ -52,6 +53,7 @@ def show_settings():
|
||||||
settings_dialog = SettingsDialog(config, language, Utility.read_lang_files(), able_to_lock_screen, save_settings, settings_dialog_glade)
|
settings_dialog = SettingsDialog(config, language, Utility.read_lang_files(), able_to_lock_screen, save_settings, settings_dialog_glade)
|
||||||
settings_dialog.show()
|
settings_dialog.show()
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Listen to tray icon About action and send the signal to About dialog.
|
Listen to tray icon About action and send the signal to About dialog.
|
||||||
"""
|
"""
|
||||||
|
@ -60,6 +62,7 @@ def show_about():
|
||||||
about_dialog = AboutDialog(about_dialog_glade, SAFE_EYES_VERSION, language)
|
about_dialog = AboutDialog(about_dialog_glade, SAFE_EYES_VERSION, language)
|
||||||
about_dialog.show()
|
about_dialog.show()
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Receive the signal from core and pass it to the Notification.
|
Receive the signal from core and pass it to the Notification.
|
||||||
"""
|
"""
|
||||||
|
@ -69,6 +72,7 @@ def show_notification():
|
||||||
plugins.pre_notification(context)
|
plugins.pre_notification(context)
|
||||||
notification.show(config['pre_break_warning_time'])
|
notification.show(config['pre_break_warning_time'])
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Receive the break signal from core and pass it to the break screen.
|
Receive the break signal from core and pass it to the break screen.
|
||||||
"""
|
"""
|
||||||
|
@ -80,6 +84,7 @@ def show_alert(message, image_name):
|
||||||
if config['strict_break'] and is_active:
|
if config['strict_break'] and is_active:
|
||||||
Utility.execute_main_thread(tray_icon.unlock_menu)
|
Utility.execute_main_thread(tray_icon.unlock_menu)
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Receive the stop break signal from core and pass it to the break screen.
|
Receive the stop break signal from core and pass it to the break screen.
|
||||||
"""
|
"""
|
||||||
|
@ -101,9 +106,10 @@ def on_quit():
|
||||||
logging.info("Quit Safe Eyes")
|
logging.info("Quit Safe Eyes")
|
||||||
plugins.exit(context)
|
plugins.exit(context)
|
||||||
core.stop()
|
core.stop()
|
||||||
notification.quite();
|
notification.quite()
|
||||||
Gtk.main_quit()
|
Gtk.main_quit()
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
If the system goes to sleep, Safe Eyes stop the core if it is already active.
|
If the system goes to sleep, Safe Eyes stop the core if it is already active.
|
||||||
If it was active, Safe Eyes will become active after wake up.
|
If it was active, Safe Eyes will become active after wake up.
|
||||||
|
@ -120,6 +126,7 @@ def handle_suspend_callback(sleeping):
|
||||||
core.start()
|
core.start()
|
||||||
logging.info("Resumed Safe Eyes after system wakeup")
|
logging.info("Resumed Safe Eyes after system wakeup")
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Setup system suspend listener.
|
Setup system suspend listener.
|
||||||
"""
|
"""
|
||||||
|
@ -128,6 +135,7 @@ def handle_system_suspend():
|
||||||
bus = dbus.SystemBus()
|
bus = dbus.SystemBus()
|
||||||
bus.add_signal_receiver(handle_suspend_callback, 'PrepareForSleep', 'org.freedesktop.login1.Manager', 'org.freedesktop.login1')
|
bus.add_signal_receiver(handle_suspend_callback, 'PrepareForSleep', 'org.freedesktop.login1.Manager', 'org.freedesktop.login1')
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Listen to break screen Skip action and send the signal to core.
|
Listen to break screen Skip action and send the signal to core.
|
||||||
"""
|
"""
|
||||||
|
@ -139,6 +147,7 @@ def on_skipped():
|
||||||
core.skip_break()
|
core.skip_break()
|
||||||
plugins.post_break(context)
|
plugins.post_break(context)
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Listen to break screen Postpone action and send the signal to core.
|
Listen to break screen Postpone action and send the signal to core.
|
||||||
"""
|
"""
|
||||||
|
@ -149,6 +158,7 @@ def on_postponed():
|
||||||
Utility.lock_desktop(system_lock_command)
|
Utility.lock_desktop(system_lock_command)
|
||||||
core.postpone_break()
|
core.postpone_break()
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Listen to Settings dialog Save action and write to the config file.
|
Listen to Settings dialog Save action and write to the config file.
|
||||||
"""
|
"""
|
||||||
|
@ -180,6 +190,7 @@ def save_settings(config):
|
||||||
# 1 sec delay is required to give enough time for core to be stopped
|
# 1 sec delay is required to give enough time for core to be stopped
|
||||||
Timer(1.0, core.start).start()
|
Timer(1.0, core.start).start()
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Listen to tray icon enable action and send the signal to core.
|
Listen to tray icon enable action and send the signal to core.
|
||||||
"""
|
"""
|
||||||
|
@ -188,6 +199,7 @@ def enable_safeeyes():
|
||||||
is_active = True
|
is_active = True
|
||||||
core.start()
|
core.start()
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Listen to tray icon disable action and send the signal to core.
|
Listen to tray icon disable action and send the signal to core.
|
||||||
"""
|
"""
|
||||||
|
@ -203,7 +215,8 @@ def running():
|
||||||
"""
|
"""
|
||||||
process_count = 0
|
process_count = 0
|
||||||
for proc in psutil.process_iter():
|
for proc in psutil.process_iter():
|
||||||
if not proc.cmdline: continue
|
if not proc.cmdline:
|
||||||
|
continue
|
||||||
try:
|
try:
|
||||||
# Check if safeeyes is in process arguments
|
# Check if safeeyes is in process arguments
|
||||||
if callable(proc.cmdline):
|
if callable(proc.cmdline):
|
||||||
|
@ -257,7 +270,6 @@ def main():
|
||||||
else:
|
else:
|
||||||
system_lock_command = Utility.lock_screen_command()
|
system_lock_command = Utility.lock_screen_command()
|
||||||
|
|
||||||
|
|
||||||
# Initialize the Safe Eyes Context
|
# Initialize the Safe Eyes Context
|
||||||
context['version'] = SAFE_EYES_VERSION
|
context['version'] = SAFE_EYES_VERSION
|
||||||
context['desktop'] = Utility.desktop_environment()
|
context['desktop'] = Utility.desktop_environment()
|
||||||
|
@ -279,5 +291,6 @@ def main():
|
||||||
logging.info('Another instance of safeeyes is already running')
|
logging.info('Another instance of safeeyes is already running')
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
12
setup.py
12
setup.py
|
@ -3,13 +3,13 @@ import setuptools
|
||||||
|
|
||||||
|
|
||||||
requires = [
|
requires = [
|
||||||
'python-xlib',
|
'python-xlib',
|
||||||
'psutil',
|
'psutil',
|
||||||
'babel']
|
'babel']
|
||||||
|
|
||||||
extras = {
|
extras = {
|
||||||
'audible_alert': ['pyaudio']
|
'audible_alert': ['pyaudio']
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
here = os.path.abspath(os.path.dirname(__file__))
|
here = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
@ -17,12 +17,14 @@ here = os.path.abspath(os.path.dirname(__file__))
|
||||||
with open(os.path.join(here, 'README.md')) as f:
|
with open(os.path.join(here, 'README.md')) as f:
|
||||||
long_description = '\n' + f.read()
|
long_description = '\n' + f.read()
|
||||||
|
|
||||||
|
|
||||||
def _data_files(path):
|
def _data_files(path):
|
||||||
for root, dirs, files in os.walk(path):
|
for root, dirs, files in os.walk(path):
|
||||||
if not files:
|
if not files:
|
||||||
continue
|
continue
|
||||||
yield (os.path.join('/usr', root), [os.path.join(root, f) for f in files])
|
yield (os.path.join('/usr', root), [os.path.join(root, f) for f in files])
|
||||||
|
|
||||||
|
|
||||||
setuptools.setup(
|
setuptools.setup(
|
||||||
name="safeeyes",
|
name="safeeyes",
|
||||||
version="1.2.1",
|
version="1.2.1",
|
||||||
|
|
Loading…
Reference in New Issue