commit
eedb2c53c7
|
@ -18,13 +18,15 @@
|
|||
|
||||
import gi
|
||||
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.
|
||||
It shows the application name with version, a small description, license and the GitHub url.
|
||||
"""
|
||||
|
||||
|
||||
class AboutDialog:
|
||||
|
||||
"""
|
||||
|
@ -42,21 +44,18 @@ class AboutDialog:
|
|||
# Set the version at the runtime
|
||||
builder.get_object("lbl_app_name").set_label("Safe Eyes " + version)
|
||||
|
||||
|
||||
"""
|
||||
Show the About dialog.
|
||||
"""
|
||||
def show(self):
|
||||
self.window.show_all()
|
||||
|
||||
|
||||
"""
|
||||
Window close event handler.
|
||||
"""
|
||||
def on_window_delete(self, *args):
|
||||
self.window.destroy()
|
||||
|
||||
|
||||
"""
|
||||
Close button click event handler.
|
||||
"""
|
||||
|
|
|
@ -16,16 +16,17 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import gi, signal, sys, threading, logging
|
||||
from Xlib import Xatom, Xutil
|
||||
import gi, threading, logging
|
||||
from Xlib.display import Display, X
|
||||
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.
|
||||
"""
|
||||
|
||||
|
||||
class BreakScreen:
|
||||
|
||||
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)
|
||||
Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(), css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
|
||||
|
||||
|
||||
def initialize(self, config, language):
|
||||
"""
|
||||
Initialize the internal properties from configuration
|
||||
|
@ -60,7 +60,6 @@ class BreakScreen:
|
|||
self.keycode_shortcut_postpone = config.get('shortcut_postpone', 65)
|
||||
self.shortcut_disable_time = config.get('shortcut_disable_time', 2)
|
||||
|
||||
|
||||
def skip_break(self):
|
||||
"""
|
||||
Skip the break from the break screen
|
||||
|
@ -86,14 +85,12 @@ class BreakScreen:
|
|||
self.__release_keyboard()
|
||||
self.close()
|
||||
|
||||
|
||||
def on_skip_clicked(self, button):
|
||||
"""
|
||||
Skip button press event handler.
|
||||
"""
|
||||
self.skip_break()
|
||||
|
||||
|
||||
def on_postpone_clicked(self, button):
|
||||
"""
|
||||
Postpone button press event handler.
|
||||
|
@ -109,7 +106,6 @@ class BreakScreen:
|
|||
timeformat = '{:02d}:{:02d}'.format(mins, secs)
|
||||
GLib.idle_add(lambda: self.__update_count_down(timeformat))
|
||||
|
||||
|
||||
def show_message(self, message, image_path, plugins_data):
|
||||
"""
|
||||
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
|
||||
GLib.idle_add(lambda: self.__show_break_screen(message, image_path, plugins_data))
|
||||
|
||||
|
||||
def close(self):
|
||||
"""
|
||||
Hide the break screen from active window and destroy all other windows
|
||||
|
@ -128,7 +123,6 @@ class BreakScreen:
|
|||
# Destroy other windows if exists
|
||||
GLib.idle_add(lambda: self.__destroy_all_screens())
|
||||
|
||||
|
||||
def __show_break_screen(self, message, image_path, plugins_data):
|
||||
"""
|
||||
Show an empty break screen on all screens.
|
||||
|
@ -175,14 +169,12 @@ class BreakScreen:
|
|||
btn_skip.set_visible(True)
|
||||
box_buttons.pack_start(btn_skip, True, True, 0)
|
||||
|
||||
|
||||
|
||||
# Set values
|
||||
if image_path:
|
||||
img_break.set_from_file(image_path)
|
||||
lbl_message.set_label(message)
|
||||
lbl_left.set_markup(plugins_data['left']);
|
||||
lbl_right.set_markup(plugins_data['right']);
|
||||
lbl_left.set_markup(plugins_data['left'])
|
||||
lbl_right.set_markup(plugins_data['right'])
|
||||
|
||||
self.windows.append(window)
|
||||
self.count_labels.append(lbl_count)
|
||||
|
@ -199,7 +191,6 @@ class BreakScreen:
|
|||
window.present()
|
||||
window.fullscreen()
|
||||
|
||||
|
||||
def __update_count_down(self, count):
|
||||
"""
|
||||
Update the countdown on all break screens.
|
||||
|
@ -207,7 +198,6 @@ class BreakScreen:
|
|||
for label in self.count_labels:
|
||||
label.set_text(count)
|
||||
|
||||
|
||||
def __lock_keyboard(self):
|
||||
"""
|
||||
Lock the keyboard to prevent the user from using keyboard shortcuts
|
||||
|
@ -235,14 +225,12 @@ class BreakScreen:
|
|||
display.ungrab_keyboard(X.CurrentTime)
|
||||
display.flush()
|
||||
|
||||
|
||||
def __release_keyboard(self):
|
||||
"""
|
||||
Release the locked keyboard.
|
||||
"""
|
||||
self.lock_keyboard = False
|
||||
|
||||
|
||||
def __destroy_all_screens(self):
|
||||
"""
|
||||
Close all the break screens.
|
||||
|
|
|
@ -24,12 +24,12 @@ from safeeyes import Utility
|
|||
|
||||
APPINDICATOR_ID = 'safeeyes'
|
||||
|
||||
|
||||
class Notification:
|
||||
"""
|
||||
This class is responsible for the notification to the user before the break.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, context, language):
|
||||
"""
|
||||
Initialize the notification.
|
||||
|
@ -39,14 +39,12 @@ class Notification:
|
|||
self.context = context
|
||||
self.language = language
|
||||
|
||||
|
||||
def initialize(self, language):
|
||||
"""
|
||||
Initialize the notification object.
|
||||
"""
|
||||
self.language = language
|
||||
|
||||
|
||||
def show(self, warning_time):
|
||||
"""
|
||||
Show the notification
|
||||
|
@ -66,7 +64,6 @@ class Notification:
|
|||
except Exception as e:
|
||||
logging.exception('Error in showing notification', e)
|
||||
|
||||
|
||||
def close(self):
|
||||
"""
|
||||
Close the notification if it is not closed by the system already.
|
||||
|
@ -78,7 +75,6 @@ class Notification:
|
|||
# Some Linux systems automatically close the notification.
|
||||
pass
|
||||
|
||||
|
||||
def quite(self):
|
||||
"""
|
||||
Uninitialize the notification. Call this method when closing the application.
|
||||
|
|
|
@ -23,12 +23,12 @@ from safeeyes import Utility
|
|||
plugins_directory = os.path.join(Utility.config_directory, 'plugins')
|
||||
sys.path.append(os.path.abspath(plugins_directory))
|
||||
|
||||
|
||||
class Plugins:
|
||||
"""
|
||||
This class manages imports the plugins and calls the methods defined in those plugins.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, config):
|
||||
"""
|
||||
Load the plugins.
|
||||
|
@ -52,7 +52,6 @@ class Plugins:
|
|||
if self.__plugins:
|
||||
self.__thread_pool = ThreadPool(min([4, len(self.__plugins)]))
|
||||
|
||||
|
||||
def start(self, context):
|
||||
"""
|
||||
Call the start function of all the plugins in separate thread.
|
||||
|
@ -77,7 +76,6 @@ class Plugins:
|
|||
except Exception as e:
|
||||
pass
|
||||
|
||||
|
||||
def pre_break(self, context):
|
||||
"""
|
||||
Call the pre_break function of all the plugins and provide maximum 1 second to return the result.
|
||||
|
@ -105,7 +103,6 @@ class Plugins:
|
|||
|
||||
return output
|
||||
|
||||
|
||||
def post_break(self, context):
|
||||
"""
|
||||
Call the post_break function of all the plugins in separate thread.
|
||||
|
@ -139,7 +136,6 @@ class Plugins:
|
|||
except Exception as e:
|
||||
pass
|
||||
|
||||
|
||||
def __has_method(self, module, method_name, no_of_args=1):
|
||||
"""
|
||||
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/>.
|
||||
|
||||
|
||||
import time, datetime, threading, sys, subprocess, logging
|
||||
import time, datetime, threading, logging
|
||||
from safeeyes import Utility
|
||||
|
||||
|
||||
"""
|
||||
Core of Safe Eyes which runs the scheduler and notifies the breaks.
|
||||
"""
|
||||
|
||||
|
||||
class SafeEyesCore:
|
||||
|
||||
"""
|
||||
|
@ -48,7 +50,6 @@ class SafeEyesCore:
|
|||
self.context['skipped'] = False
|
||||
self.context['postponed'] = False
|
||||
|
||||
|
||||
"""
|
||||
Initialize the internal properties from configuration
|
||||
"""
|
||||
|
@ -111,7 +112,6 @@ class SafeEyesCore:
|
|||
|
||||
self.long_break_exercises.append([name, break_time, audible_alert, image])
|
||||
|
||||
|
||||
"""
|
||||
Start Safe Eyes is it is not running already.
|
||||
"""
|
||||
|
@ -125,7 +125,6 @@ class SafeEyesCore:
|
|||
if self.context['idle_pause_enabled']:
|
||||
Utility.start_thread(self.__start_idle_monitor)
|
||||
|
||||
|
||||
"""
|
||||
Stop Safe Eyes if it is running.
|
||||
"""
|
||||
|
@ -150,7 +149,6 @@ class SafeEyesCore:
|
|||
self.idle_condition.notify_all()
|
||||
self.idle_condition.release()
|
||||
|
||||
|
||||
"""
|
||||
Pause Safe Eyes if it is running.
|
||||
"""
|
||||
|
@ -162,7 +160,6 @@ class SafeEyesCore:
|
|||
self.notification_condition.notify_all()
|
||||
self.notification_condition.release()
|
||||
|
||||
|
||||
"""
|
||||
Resume Safe Eyes if it is not running.
|
||||
"""
|
||||
|
@ -172,7 +169,6 @@ class SafeEyesCore:
|
|||
self.running = True
|
||||
Utility.start_thread(self.__scheduler_job)
|
||||
|
||||
|
||||
"""
|
||||
User skipped the break using Skip button
|
||||
"""
|
||||
|
@ -185,7 +181,6 @@ class SafeEyesCore:
|
|||
def postpone_break(self):
|
||||
self.context['postponed'] = True
|
||||
|
||||
|
||||
"""
|
||||
Scheduler task to execute during every interval
|
||||
"""
|
||||
|
@ -235,7 +230,6 @@ class SafeEyesCore:
|
|||
self.is_before_break = False
|
||||
Utility.execute_main_thread(self.__check_active_window)
|
||||
|
||||
|
||||
"""
|
||||
Show the notification and start the break after the notification.
|
||||
"""
|
||||
|
@ -252,7 +246,6 @@ class SafeEyesCore:
|
|||
self.is_before_break = True
|
||||
Utility.execute_main_thread(self.__check_active_window)
|
||||
|
||||
|
||||
"""
|
||||
Check the active window for full-screen and user defined exceptions.
|
||||
"""
|
||||
|
@ -272,8 +265,6 @@ class SafeEyesCore:
|
|||
else:
|
||||
Utility.start_thread(self.__show_notification)
|
||||
|
||||
|
||||
|
||||
"""
|
||||
Start the break screen.
|
||||
"""
|
||||
|
@ -327,22 +318,18 @@ class SafeEyesCore:
|
|||
# Schedule the break again
|
||||
Utility.start_thread(self.__scheduler_job)
|
||||
|
||||
|
||||
|
||||
"""
|
||||
Tells whether Safe Eyes is running or not.
|
||||
"""
|
||||
def __is_running(self):
|
||||
return self.active and self.running
|
||||
|
||||
|
||||
"""
|
||||
Check if the current break is long break or short current
|
||||
"""
|
||||
def __is_long_break(self):
|
||||
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.
|
||||
"""
|
||||
|
|
|
@ -18,9 +18,10 @@
|
|||
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk, Gdk, GdkX11, GObject
|
||||
from gi.repository import Gtk, GObject
|
||||
from safeeyes import Utility
|
||||
|
||||
|
||||
class SettingsDialog:
|
||||
"""
|
||||
Create and initialize SettingsDialog instance.
|
||||
|
@ -134,14 +135,12 @@ class SettingsDialog:
|
|||
self.cmb_language.pack_start(cell, True)
|
||||
self.cmb_language.add_attribute(cell, 'text', 0)
|
||||
|
||||
|
||||
def show(self):
|
||||
"""
|
||||
Show the SettingsDialog.
|
||||
"""
|
||||
self.window.show_all()
|
||||
|
||||
|
||||
def on_switch_screen_lock_activate(self, switch, state):
|
||||
"""
|
||||
Event handler to the state change of the screen_lock switch.
|
||||
|
@ -149,7 +148,6 @@ class SettingsDialog:
|
|||
"""
|
||||
self.spin_time_to_screen_lock.set_sensitive(self.switch_screen_lock.get_active())
|
||||
|
||||
|
||||
def on_switch_strict_break_activate(self, switch, state):
|
||||
"""
|
||||
Event handler to the state change of the postpone switch.
|
||||
|
@ -183,7 +181,6 @@ class SettingsDialog:
|
|||
"""
|
||||
self.window.destroy()
|
||||
|
||||
|
||||
def on_save_clicked(self, button):
|
||||
"""
|
||||
Event handler for Save button click.
|
||||
|
@ -213,7 +210,6 @@ class SettingsDialog:
|
|||
self.on_save_settings(self.config) # Call the provided save method
|
||||
self.window.destroy() # Close the settings window
|
||||
|
||||
|
||||
def on_cancel_clicked(self, button):
|
||||
"""
|
||||
Event handler for Cancel button click.
|
||||
|
|
|
@ -231,7 +231,6 @@ class TrayIcon:
|
|||
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)))
|
||||
|
||||
|
||||
"""
|
||||
This method is called by the core to prevent user from disabling Safe Eyes after the notification.
|
||||
"""
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
import gi
|
||||
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 distutils.version import LooseVersion
|
||||
from logging.handlers import RotatingFileHandler
|
||||
|
@ -65,7 +65,8 @@ def play_notification():
|
|||
|
||||
# Create a sound stream
|
||||
wrapper = pyaudio.PyAudio()
|
||||
stream = wrapper.open(format=wrapper.get_format_from_width(sound.getsampwidth()),
|
||||
stream = wrapper.open(format=wrapper.get_format_from_width(
|
||||
sound.getsampwidth()),
|
||||
channels=sound.getnchannels(),
|
||||
rate=sound.getframerate(),
|
||||
output=True)
|
||||
|
@ -206,6 +207,7 @@ def mkdir(path):
|
|||
logging.error('Error while creating ' + str(path))
|
||||
raise
|
||||
|
||||
|
||||
def parse_language_code(lang_code):
|
||||
"""
|
||||
Convert the user defined language code to a valid one.
|
||||
|
@ -321,7 +323,7 @@ def lock_screen_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']
|
||||
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
|
||||
return ['gnome-screensaver-command', '--lock']
|
||||
return None
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os, gi, json, dbus, logging, operator, psutil, sys
|
||||
import os, gi, json, dbus, logging, psutil, sys
|
||||
from threading import Timer
|
||||
from dbus.mainloop.glib import DBusGMainLoop
|
||||
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
|
||||
SAFE_EYES_VERSION = "1.2.1"
|
||||
|
||||
|
||||
"""
|
||||
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.show()
|
||||
|
||||
|
||||
"""
|
||||
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.show()
|
||||
|
||||
|
||||
"""
|
||||
Receive the signal from core and pass it to the Notification.
|
||||
"""
|
||||
|
@ -69,6 +72,7 @@ def show_notification():
|
|||
plugins.pre_notification(context)
|
||||
notification.show(config['pre_break_warning_time'])
|
||||
|
||||
|
||||
"""
|
||||
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:
|
||||
Utility.execute_main_thread(tray_icon.unlock_menu)
|
||||
|
||||
|
||||
"""
|
||||
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")
|
||||
plugins.exit(context)
|
||||
core.stop()
|
||||
notification.quite();
|
||||
notification.quite()
|
||||
Gtk.main_quit()
|
||||
|
||||
|
||||
"""
|
||||
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.
|
||||
|
@ -120,6 +126,7 @@ def handle_suspend_callback(sleeping):
|
|||
core.start()
|
||||
logging.info("Resumed Safe Eyes after system wakeup")
|
||||
|
||||
|
||||
"""
|
||||
Setup system suspend listener.
|
||||
"""
|
||||
|
@ -128,6 +135,7 @@ def handle_system_suspend():
|
|||
bus = dbus.SystemBus()
|
||||
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.
|
||||
"""
|
||||
|
@ -139,6 +147,7 @@ def on_skipped():
|
|||
core.skip_break()
|
||||
plugins.post_break(context)
|
||||
|
||||
|
||||
"""
|
||||
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)
|
||||
core.postpone_break()
|
||||
|
||||
|
||||
"""
|
||||
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
|
||||
Timer(1.0, core.start).start()
|
||||
|
||||
|
||||
"""
|
||||
Listen to tray icon enable action and send the signal to core.
|
||||
"""
|
||||
|
@ -188,6 +199,7 @@ def enable_safeeyes():
|
|||
is_active = True
|
||||
core.start()
|
||||
|
||||
|
||||
"""
|
||||
Listen to tray icon disable action and send the signal to core.
|
||||
"""
|
||||
|
@ -203,7 +215,8 @@ def running():
|
|||
"""
|
||||
process_count = 0
|
||||
for proc in psutil.process_iter():
|
||||
if not proc.cmdline: continue
|
||||
if not proc.cmdline:
|
||||
continue
|
||||
try:
|
||||
# Check if safeeyes is in process arguments
|
||||
if callable(proc.cmdline):
|
||||
|
@ -257,7 +270,6 @@ def main():
|
|||
else:
|
||||
system_lock_command = Utility.lock_screen_command()
|
||||
|
||||
|
||||
# Initialize the Safe Eyes Context
|
||||
context['version'] = SAFE_EYES_VERSION
|
||||
context['desktop'] = Utility.desktop_environment()
|
||||
|
@ -279,5 +291,6 @@ def main():
|
|||
logging.info('Another instance of safeeyes is already running')
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
2
setup.py
2
setup.py
|
@ -17,12 +17,14 @@ here = os.path.abspath(os.path.dirname(__file__))
|
|||
with open(os.path.join(here, 'README.md')) as f:
|
||||
long_description = '\n' + f.read()
|
||||
|
||||
|
||||
def _data_files(path):
|
||||
for root, dirs, files in os.walk(path):
|
||||
if not files:
|
||||
continue
|
||||
yield (os.path.join('/usr', root), [os.path.join(root, f) for f in files])
|
||||
|
||||
|
||||
setuptools.setup(
|
||||
name="safeeyes",
|
||||
version="1.2.1",
|
||||
|
|
Loading…
Reference in New Issue