Add keyboard shortcuts to skip and postpone

This commit is contained in:
Gobinath 2017-07-02 16:27:07 -04:00
parent 0f08c14cf4
commit 4509aa1d18
25 changed files with 160 additions and 80 deletions

View File

@ -28,18 +28,18 @@ from gi.repository import Gtk, Gdk, GLib, GdkX11
"""
class BreakScreen:
"""
Read the break_screen.glade and build the user interface.
"""
def __init__(self, context, on_skip, on_postpone, glade_file, style_sheet_path):
"""
Read the break_screen.glade and build the user interface.
"""
self.context = context
self.on_skip = on_skip
self.on_postpone = on_postpone
self.is_pretified = False
self.key_lock_condition = threading.Condition()
self.windows = []
self.count_labels = []
self.glade_file = glade_file
self.enable_shortcut = False
# Initialize the theme
css_provider = Gtk.CssProvider()
@ -47,63 +47,81 @@ class BreakScreen:
Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(), css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
"""
Initialize the internal properties from configuration
"""
def initialize(self, config, language):
"""
Initialize the internal properties from configuration
"""
logging.info("Initialize the break screen")
self.skip_button_text = language['ui_controls']['skip']
self.postpone_button_text = language['ui_controls']['postpone']
self.strict_break = config.get('strict_break', False)
self.enable_postpone = config.get('allow_postpone', False)
self.keycode_shortcut_skip = config.get('shortcut_skip', 9)
self.keycode_shortcut_postpone = config.get('shortcut_postpone', 65)
self.shortcut_disable_time = config.get('shortcut_disable_time', 2)
"""
Window close event handler.
"""
def on_window_delete(self, *args):
logging.info("Closing the break screen")
self.lock_keyboard = False
self.close()
"""
Skip button press event handler.
"""
def on_skip_clicked(self, button):
def skip_break(self):
"""
Skip the break from the break screen
"""
logging.info("User skipped the break")
# Must call on_skip before close to lock screen before closing the break screen
self.on_skip()
self.close()
"""
Postpone button press event handler.
"""
def on_postpone_clicked(self, button):
def postpone_break(self):
"""
Postpone the break from the break screen
"""
logging.info("User postponed the break")
self.on_postpone()
self.close()
def on_window_delete(self, *args):
"""
Window close event handler.
"""
logging.info("Closing the break screen")
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.
"""
self.postpone_break()
def show_count_down(self, count_down, seconds):
"""
Show/update the count down on all screens.
"""
def show_count_down(self, count):
GLib.idle_add(lambda: self.__update_count_down(count))
"""
self.enable_shortcut = not self.strict_break and self.shortcut_disable_time <= count_down
mins, secs = divmod(seconds, 60)
timeformat = '{:02d}:{:02d}'.format(mins, secs)
GLib.idle_add(lambda: self.__update_count_down(timeformat))
"""
Show the break screen with the given message on all displays.
"""
def show_message(self, message, image_path, plugins_data):
"""
Show the break screen with the given message on all displays.
"""
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))
"""
Hide the break screen from active window and destroy all other windows
"""
def close(self):
"""
Hide the break screen from active window and destroy all other windows
"""
logging.info("Close the break screen(s)")
self.__release_keyboard()
@ -111,10 +129,10 @@ class BreakScreen:
GLib.idle_add(lambda: self.__destroy_all_screens())
"""
Show an empty break screen on all screens.
"""
def __show_break_screen(self, message, image_path, plugins_data):
"""
Show an empty break screen on all screens.
"""
# Lock the keyboard
thread = threading.Thread(target=self.__lock_keyboard)
thread.start()
@ -182,18 +200,18 @@ class BreakScreen:
window.fullscreen()
"""
Update the countdown on all break screens.
"""
def __update_count_down(self, count):
"""
Update the countdown on all break screens.
"""
for label in self.count_labels:
label.set_text(count)
"""
Lock the keyboard to prevent the user from using keyboard shortcuts
"""
def __lock_keyboard(self):
"""
Lock the keyboard to prevent the user from using keyboard shortcuts
"""
logging.info("Lock the keyboard")
self.lock_keyboard = True
display = Display()
@ -201,10 +219,16 @@ class BreakScreen:
# Grap the keyboard
root.grab_keyboard(owner_events = False, pointer_mode = X.GrabModeAsync, keyboard_mode = X.GrabModeAsync, time = X.CurrentTime)
# Consume keyboard events
self.key_lock_condition.acquire()
while self.lock_keyboard:
self.key_lock_condition.wait()
self.key_lock_condition.release()
event = display.next_event()
display.allow_events(mode = X.AsyncBoth, time = X.CurrentTime)
if self.enable_shortcut and event.type == X.KeyPress:
if event.detail == self.keycode_shortcut_skip:
self.skip_break()
break
elif self.enable_postpone and event.detail == self.keycode_shortcut_postpone:
self.postpone_break()
break
# Ungrap the keyboard
logging.info("Unlock the keyboard")
@ -212,20 +236,17 @@ class BreakScreen:
display.flush()
"""
Release the locked keyboard.
"""
def __release_keyboard(self):
self.key_lock_condition.acquire()
"""
Release the locked keyboard.
"""
self.lock_keyboard = False
self.key_lock_condition.notify()
self.key_lock_condition.release()
"""
Close all the break screens.
"""
def __destroy_all_screens(self):
"""
Close all the break screens.
"""
for win in self.windows:
win.destroy()
del self.windows[:]

View File

@ -308,10 +308,9 @@ class SafeEyesCore:
# Use self.active instead of self.__is_running to avoid idle pause interrupting the break
while seconds and self.active and not self.context['skipped'] and not self.context['postponed']:
self.context['count_down'] = total_break_time - seconds
mins, secs = divmod(seconds, 60)
timeformat = '{:02d}:{:02d}'.format(mins, secs)
self.on_countdown(timeformat)
count_down = total_break_time - seconds
self.context['count_down'] = count_down
self.on_countdown(count_down, seconds)
time.sleep(1) # Sleep for 1 second
seconds -= 1

View File

@ -46,6 +46,7 @@ class SettingsDialog:
self.spin_time_to_prepare = builder.get_object('spin_time_to_prepare')
self.spin_idle_time_to_pause = builder.get_object('spin_idle_time_to_pause')
self.spin_postpone_duration = builder.get_object('spin_postpone_duration')
self.spin_disable_keyboard_shortcut = builder.get_object('spin_disable_keyboard_shortcut')
self.switch_show_time_in_tray = builder.get_object('switch_show_time_in_tray')
self.switch_strict_break = builder.get_object('switch_strict_break')
self.switch_postpone = builder.get_object('switch_postpone')
@ -63,6 +64,7 @@ class SettingsDialog:
builder.get_object('lbl_idle_time_to_pause').set_label(language['ui_controls']['idle_time'])
builder.get_object('lbl_postpone_duration').set_label(language['ui_controls']['postpone_duration'])
builder.get_object('lbl_allow_postpone').set_label(language['ui_controls']['allow_postpone'])
builder.get_object('lbl_disable_keyboard_shortcut').set_label(language['ui_controls']['disable_keyboard_shortcut'])
builder.get_object('lbl_show_time_in_tray').set_label(language['ui_controls']['show_time_in_tray'])
builder.get_object('lbl_strict_break').set_label(language['ui_controls']['strict_break'])
builder.get_object('lbl_audible_alert').set_label(language['ui_controls']['audible_alert'])
@ -80,6 +82,7 @@ class SettingsDialog:
self.spin_time_to_prepare.set_value(config['pre_break_warning_time'])
self.spin_idle_time_to_pause.set_value(config['idle_time'] and xprintidle_available)
self.spin_postpone_duration.set_value(config['postpone_duration'])
self.spin_disable_keyboard_shortcut.set_value(config['shortcut_disable_time'])
self.switch_show_time_in_tray.set_active(config['show_time_in_tray'])
self.switch_strict_break.set_active(config['strict_break'])
self.switch_audible_alert.set_active(config['audible_alert'] and Utility.pyaudio is None)
@ -192,6 +195,7 @@ class SettingsDialog:
self.config['pre_break_warning_time'] = self.spin_time_to_prepare.get_value_as_int()
self.config['idle_time'] = self.spin_idle_time_to_pause.get_value_as_int()
self.config['postpone_duration'] = self.spin_postpone_duration.get_value_as_int()
self.config['shortcut_disable_time'] = self.spin_disable_keyboard_shortcut.get_value_as_int()
self.config['show_time_in_tray'] = self.switch_show_time_in_tray.get_active()
self.config['strict_break'] = self.switch_strict_break.get_active()
self.config['language'] = self.languages[self.cmb_language.get_active()]

View File

@ -33,6 +33,7 @@
"cancel": "Canceŀla",
"close": "Tanca",
"disable": "Desactiva Safe Eyes",
"disable_keyboard_shortcut": "Shortcut disabled period to prevent unintentional skip (in seconds)",
"enable": "Activa Safe Eyes",
"enable_screen_lock": "Bloca la pantalla després de cada pausa llarga",
"for_x_hour": "Durant {} hora",

View File

@ -33,6 +33,7 @@
"cancel": "Zrušit",
"close": "Close",
"disable": "Pozastavit Safe Eyes",
"disable_keyboard_shortcut": "Shortcut disabled period to prevent unintentional skip (in seconds)",
"enable": "Zapnout Safe Eyes",
"enable_screen_lock": "Po každé dlouhé přestávce uzamknout obrazovku",
"for_x_hour": "Na {} hodinu",

View File

@ -33,6 +33,7 @@
"cancel": "Abbrechen",
"close": "Schließen",
"disable": "Safe Eyes deaktivieren",
"disable_keyboard_shortcut": "Shortcut disabled period to prevent unintentional skip (in seconds)",
"enable": "Safe Eyes aktivieren",
"enable_screen_lock": "Sperrt den Bildschirm nach einer langen Pause",
"for_x_hour": "Für {} Stunde",

View File

@ -33,6 +33,7 @@
"cancel": "Cancel",
"close": "Close",
"disable": "Disable Safe Eyes",
"disable_keyboard_shortcut": "Shortcut disabled period to prevent unintentional skip (in seconds)",
"enable": "Enable Safe Eyes",
"enable_screen_lock": "Lock the screen after every long break",
"for_x_hour": "For {} Hour",

View File

@ -33,6 +33,7 @@
"cancel": "Cancelar",
"close": "Close",
"disable": "Desactivar Safe Eyes",
"disable_keyboard_shortcut": "Shortcut disabled period to prevent unintentional skip (in seconds)",
"enable": "Activar Safe Eyes",
"enable_screen_lock": "Bloquear la pantalla despues de cada pausa larga",
"for_x_hour": "Durante {} hora",

View File

@ -33,6 +33,7 @@
"cancel": "لغو",
"close": "بستن",
"disable": "غیر فعال کردن Safe Eyes",
"disable_keyboard_shortcut": "Shortcut disabled period to prevent unintentional skip (in seconds)",
"enable": "فعال کردن Safe Eyes",
"enable_screen_lock": "قفل کردن صفحه بعد از هر استراحت طولانی",
"for_x_hour": "برای {} ساعت",

View File

@ -33,6 +33,7 @@
"cancel": "Annuler",
"close": "Fermer",
"disable": "Désactiver Safe Eyes",
"disable_keyboard_shortcut": "Shortcut disabled period to prevent unintentional skip (in seconds)",
"enable": "Activer Safe Eyes",
"enable_screen_lock": "Verrouiller l'écran après chaque pause longue",
"for_x_hour": "Pendant {} heure",

View File

@ -33,6 +33,7 @@
"cancel": "უარყოფა",
"close": "Close",
"disable": "Safe Eyes გამორთვა",
"disable_keyboard_shortcut": "Shortcut disabled period to prevent unintentional skip (in seconds)",
"enable": "Safe Eyes ჩართვა",
"enable_screen_lock": "Lock the screen after every long break",
"for_x_hour": "{} საათით",

View File

@ -33,6 +33,7 @@
"cancel": "रखना नहीं",
"close": "Close",
"disable": "सेफ आईज बंद",
"disable_keyboard_shortcut": "Shortcut disabled period to prevent unintentional skip (in seconds)",
"enable": "सेफ आईज शुरू",
"enable_screen_lock": "Lock the screen after every long break",
"for_x_hour": "{} घंटे के लिए",

View File

@ -33,6 +33,7 @@
"cancel": "Mégse",
"close": "Close",
"disable": "Disable Safe Eyes",
"disable_keyboard_shortcut": "Shortcut disabled period to prevent unintentional skip (in seconds)",
"enable": "Safe Eyes Bekapcsolása",
"enable_screen_lock": "Lock the screen after every long break",
"for_x_hour": "For {} Hour",

View File

@ -33,6 +33,7 @@
"cancel": "Batal",
"close": "Close",
"disable": "Matikan Safe Eyes",
"disable_keyboard_shortcut": "Shortcut disabled period to prevent unintentional skip (in seconds)",
"enable": "Hidupkan Safe Eyes",
"enable_screen_lock": "Lock the screen after every long break",
"for_x_hour": "Selama {} Jam",

View File

@ -33,6 +33,7 @@
"cancel": "Откажи",
"close": "Затвори",
"disable": "Оневозможете го Safe Eyes",
"disable_keyboard_shortcut": "Shortcut disabled period to prevent unintentional skip (in seconds)",
"enable": "Овозможете го Safe Eyes",
"enable_screen_lock": "Заклучување на екранот по секоја долга пауза",
"for_x_hour": "За {} час",

View File

@ -33,6 +33,7 @@
"cancel": "Anuluj",
"close": "Zamknij",
"disable": "Zatrzymaj Safe Eyes",
"disable_keyboard_shortcut": "Shortcut disabled period to prevent unintentional skip (in seconds)",
"enable": "Uruchom Safe Eyes",
"enable_screen_lock": "Zablokuj ekran po każdej długiej przerwie",
"for_x_hour": "Na {} godzinę",

View File

@ -33,6 +33,7 @@
"cancel": "Cancelar",
"close": "Fechar",
"disable": "Desativar Safe Eyes",
"disable_keyboard_shortcut": "Shortcut disabled period to prevent unintentional skip (in seconds)",
"enable": "Habilitar Safe Eyes",
"enable_screen_lock": "Bloqueie a tela após cada pausa longa",
"for_x_hour": "Por {} Hora",

View File

@ -33,6 +33,7 @@
"cancel": "Отменить",
"close": "Close",
"disable": "Отключить Safe Eyes",
"disable_keyboard_shortcut": "Shortcut disabled period to prevent unintentional skip (in seconds)",
"enable": "Активировать Safe Eyes",
"enable_screen_lock": "Включить блокировку экрана",
"for_x_hour": "На {} час",

View File

@ -33,6 +33,7 @@
"cancel": "Zrušiť",
"close": "Close",
"disable": "Zakázať Safe Eyes",
"disable_keyboard_shortcut": "Shortcut disabled period to prevent unintentional skip (in seconds)",
"enable": "Povoliť Safe Eyes",
"enable_screen_lock": "Zablokovať obrazovku po každej dlhej prestávke",
"for_x_hour": "Počas {} hodiny",

View File

@ -33,6 +33,7 @@
"cancel": "ரத்து",
"close": "மூடு",
"disable": "Safe Eyes ஐ நிறுத்துக",
"disable_keyboard_shortcut": "Shortcut disabled period to prevent unintentional skip (in seconds)",
"enable": "Safe Eyes ஐ செயல்படுத்துக",
"enable_screen_lock": "நீண்ட கால இடைவேளைகளின் பின்னர் திரையை பூட்டுக",
"for_x_hour": "{} மணித்தியாலத்திற்கு",

View File

@ -33,6 +33,7 @@
"cancel": "İptal",
"close": "Kapat",
"disable": "Safe Eyes'ı devre dışı bırak",
"disable_keyboard_shortcut": "Shortcut disabled period to prevent unintentional skip (in seconds)",
"enable": "Safe Eyes'ı etkinleştir",
"enable_screen_lock": "Her uzun mola sonunda ekranı kilitle",
"for_x_hour": "{} Saat",

View File

@ -33,6 +33,7 @@
"cancel": "Відмінити",
"close": "Закрити",
"disable": "Відключити Safe Eyes",
"disable_keyboard_shortcut": "Shortcut disabled period to prevent unintentional skip (in seconds)",
"enable": "Включити Safe Eyes",
"enable_screen_lock": "Блокувати екран після довгих перерв",
"for_x_hour": "На {} годину",

View File

@ -38,6 +38,7 @@
"cancel": "Huỷ",
"close": "Đóng",
"disable": "Tắt Safe Eyes",
"disable_keyboard_shortcut": "Shortcut disabled period to prevent unintentional skip (in seconds)",
"enable": "Bật Safe Eyes",
"enable_screen_lock": "Khoá màn hình ở mỗi thời điểm nghỉ ngơi dài",
"for_x_hour": "Trong {} giờ",

View File

@ -1,6 +1,6 @@
{
"meta": {
"config_version": "5.0.1"
"config_version": "5.0.2"
},
"allow_postpone": false,
"break_interval": 15,
@ -10,7 +10,11 @@
"pre_break_warning_time": 10,
"short_break_duration": 15,
"idle_time": 5,
"persist_state": true,
"postpone_duration": 5,
"shortcut_disable_time": 2,
"shortcut_skip": 9,
"shortcut_postpone": 65,
"show_time_in_tray": false,
"strict_break": false,
"audible_alert": false,

View File

@ -52,6 +52,12 @@
<property name="step_increment">1</property>
<property name="page_increment">5</property>
</object>
<object class="GtkAdjustment" id="adjust_disable_keyboard_shortcut_duration">
<property name="lower">1</property>
<property name="upper">15</property>
<property name="step_increment">1</property>
<property name="page_increment">5</property>
</object>
<object class="GtkAdjustment" id="adjust_short_break_duration">
<property name="lower">1</property>
<property name="upper">60</property>
@ -189,7 +195,7 @@
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">9</property>
<property name="top_attach">10</property>
</packing>
</child>
<child>
@ -202,7 +208,7 @@
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">6</property>
<property name="top_attach">7</property>
</packing>
</child>
<child>
@ -215,7 +221,7 @@
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">7</property>
<property name="top_attach">8</property>
</packing>
</child>
<child>
@ -346,7 +352,7 @@
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">9</property>
<property name="top_attach">10</property>
</packing>
</child>
<child>
@ -358,7 +364,7 @@
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">6</property>
<property name="top_attach">7</property>
</packing>
</child>
<child>
@ -370,7 +376,7 @@
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">7</property>
<property name="top_attach">8</property>
</packing>
</child>
<child>
@ -382,7 +388,7 @@
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">10</property>
<property name="top_attach">11</property>
</packing>
</child>
<child>
@ -395,7 +401,7 @@
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">10</property>
<property name="top_attach">11</property>
</packing>
</child>
<child>
@ -405,7 +411,7 @@
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">13</property>
<property name="top_attach">14</property>
</packing>
</child>
<child>
@ -418,7 +424,7 @@
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">13</property>
<property name="top_attach">14</property>
</packing>
</child>
<child>
@ -431,7 +437,7 @@
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">11</property>
<property name="top_attach">12</property>
</packing>
</child>
<child>
@ -442,7 +448,7 @@
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">11</property>
<property name="top_attach">12</property>
</packing>
</child>
<child>
@ -455,7 +461,7 @@
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">12</property>
<property name="top_attach">13</property>
</packing>
</child>
<child>
@ -474,7 +480,7 @@
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">12</property>
<property name="top_attach">13</property>
</packing>
</child>
<child>
@ -487,7 +493,7 @@
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">8</property>
<property name="top_attach">9</property>
</packing>
</child>
<child>
@ -498,14 +504,40 @@
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">8</property>
<property name="top_attach">9</property>
</packing>
</child>
<child>
<placeholder/>
<object class="GtkLabel" id="lbl_disable_keyboard_shortcut">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="label" translatable="yes">Disable keyboard shortcut</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">6</property>
</packing>
</child>
<child>
<placeholder/>
<object class="GtkSpinButton" id="spin_disable_keyboard_shortcut">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="halign">end</property>
<property name="valign">center</property>
<property name="text" translatable="yes">1</property>
<property name="input_purpose">number</property>
<property name="adjustment">adjust_disable_keyboard_shortcut_duration</property>
<property name="climb_rate">1</property>
<property name="numeric">True</property>
<property name="update_policy">if-valid</property>
<property name="value">1</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">6</property>
</packing>
</child>
</object>
<packing>