Merge pull request #168 from Jalakas/master

flake8 suggested fixes
This commit is contained in:
Gobinath 2017-07-06 05:58:55 -04:00 committed by GitHub
commit eedb2c53c7
10 changed files with 83 additions and 105 deletions

View File

@ -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.
""" """

View File

@ -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.

View File

@ -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)

View File

@ -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.
""" """

View File

@ -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.
""" """

View File

@ -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()

View File

@ -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:

View File

@ -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):

View File

@ -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()

View File

@ -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",