Skip to content

Instantly share code, notes, and snippets.

@entrity
Last active September 23, 2017 07:13
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save entrity/685894af0642fc31a906 to your computer and use it in GitHub Desktop.
Save entrity/685894af0642fc31a906 to your computer and use it in GitHub Desktop.
Python timer app with a GUI for time input and display of time remaining. When timer expires, it jiggles the icon in the unity launcher until the GUI window receives a focus-in event.
[Desktop Entry]
Name=My Timer
Exec=/home/markham/scripts/timer.py
Icon=/usr/share/icons/cute.jpg
Type=Application
Terminal=false
StartupNotify=true
Categories=GTK;GNOME;Utility;
#!/usr/bin/python
DESKTOP_FILE_NAME = 'my-timer.desktop' # you need to create this file
INITIAL_TEXT = '0:0:1'
from gi.repository import Unity, GObject, Gtk
import re, StringIO
class TimerWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="My Timer")
self.connect("delete-event", Gtk.main_quit)
box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
self.add(box)
self.entry = Gtk.Entry()
self.entry.set_text(INITIAL_TEXT)
self.entry.connect("activate", self.activate_entry)
# self.focus_btn = Gtk.Button()
# self.focus_btn.set_label(u"\u2766")
box.add(self.entry)
# box.add(self.focus_btn)
self.show_all()
self.finished = False
def reset(self, a, b):
self.disconnect(self.focus_in_handler)
self.finished = False
print 'reset'
def activate_entry(self, entry):
self.start_time = GObject.get_current_time()
text = entry.get_text()
print text
arr = re.split('\D+', text)
n = len(arr)
hr = int(arr[-3]) if n >= 3 else 0
mn = int(arr[-2] or 0) if n >= 2 else int(arr[0])
sc = int(arr[-1]) if n >= 2 else 0
self.total_seconds = sc + 60*mn + 360*hr
print 'Timer for', self.total_seconds, 'seconds'
launcher.set_property('progress_visible', True)
self.set_focus(None)
self.update_progress()
GObject.timeout_add_seconds(1, self.update_progress)
def update_progress(self):
delta = GObject.get_current_time() - self.start_time
progress = delta / self.total_seconds
if progress >= 1:
if not self.finished:
self.finished = True
launcher.set_property('progress_visible', False)
self.entry.set_text("TIME'S UP!")
GObject.timeout_add(200, self.jiggle_unity)
message = Gtk.MessageDialog(None, Gtk.DialogFlags.MODAL, Gtk.MessageType.INFO, Gtk.ButtonsType.OK, "TIME'S UP!")
message.set_keep_above(True)
btn = message.get_child().get_children()[1].get_children()[0]
btn.connect('activate', lambda x: message.close())
btn.connect('clicked', lambda x: message.close())
message.run() # Blocks. Should return -4; Before calling this, I could add self.set_focus(message), but I don't want to accidentally hit Enter at the wrong moment and miss seeing the modal dialog
self.focus_in_handler = self.connect("focus-in-event", self.reset)
message.close()
self.set_focus(self.entry)
return False
else:
launcher.set_property('progress', progress)
if not self.entry.has_focus():
remaining = self.total_seconds - delta
mn = remaining / 60
hr = mn / 60
stamp = StringIO.StringIO()
stamp.write('%d:%02d:%02d' % (hr, mn%60, remaining%60))
self.entry.set_text(stamp.getvalue())
return True
def jiggle_unity(self):
if self.finished:
urgent = launcher.get_property('urgent')
launcher.set_property('urgent', not urgent)
return True
else:
return False
launcher = Unity.LauncherEntry.get_for_desktop_id(DESKTOP_FILE_NAME)
win = TimerWindow()
Gtk.main()
@khurshid-alam
Copy link

khurshid-alam commented Sep 23, 2017

It would be nice if you can integrate with messaging menu integration as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment