Fork me on GitHub

SpeedRunner: Above All Windows

on Python,

Introduction

For some reason or another, I needed a stopwatch to time myself when working on my projects. I also wanted one which does not run in the browser, and is easily to use.

There are awesome timing apps on Windows built for speedrunning (gaming). Without close Mac equivalents, I thought I’d make one for myself to use.

SpeedRunner is Stopwatch and Timer for Mac OS X. It helps to track time conveniently by having a window always-on-top, but stays in it’s own small corner.

I hadn’t found other apps that “hijacks” the screen area. Though, priority interrupts could be a thing, for instance, if monitoring catches a fire, or critical systems require attention. Some things could just be that important.

Stopwatch and Timer

A basic addition for a stopwatch is to include splits/ lap times. Whereas, for timers, a sound alert is essential.

No buttons for the Timer (right) …yet

Tk GUIs on Python are useful for quickly prototyping stuff. Unfortunately, coding view layers tend to be messy work, so it’s best not to spend too much time on UIs.

Borderless, fixed window

I needed to find a way to make window overlays. I knew that this was possible to some extent, e.g. if you use Alfred, it shows a windowless search that looks like a Spotlight replacement.

I found that Tk has a -topmost attribute that keeps windows always-on-top. There is another option overrideredirect that removes the usual toolbar with close, minimise and fullscreen keys.

 1class FloatingWindow(tk.Toplevel):
 2    """
 3    Sticky, always-on-top window for the main UI
 4    """
 5    def __init__(self, *args, **kwargs):
 6        tk.Toplevel.__init__(self, *args, **kwargs)
 7        # ...
 8        self.window_config()
 9        
10    def window_config(self):
11        self.overrideredirect(1)
12        self.lift()
13        self.wm_attributes('-topmost', 1)

Shortcut Keys

One drawback is that the window is now unable to receive keypress events (clicks on elements still work as usual, like on the big red button).

The way around it is to place the borderless window as a child of a regular 0x0 window (which doesn’t get drawn on the screen). Keypress events get passed to the regular window when the app is focused, which you can further pass to FloatingWindow.

 1class HiddenWindow(tk.Tk):
 2    """
 3    This hidden window is required to bind keyboard keys
 4    """
 5    def __init__(self, *args, **kwargs):
 6        tk.Tk.__init__(self, *args, **kwargs)
 7        self.fw = FloatingWindow(self)
 8        self.hide()
 9        self.hotkeys = {
10            '<space>': self.fw.dispatch_event('trigger')
11            # ...
12        }
13        self.bind_keys()
14        
15    def bind_keys(self):
16        for key in self.hotkeys:
17            self.bind_all(key, self.hotkeys[key])
18            
19    def hide(self):
20        """
21        Setting height and width to 0 makes the window invisible
22        but lets keypresses register.
23        """
24        self.geometry('%dx%d%+d%+d' % (0, 0, 0, 0))

After some use, I gave it some shortcut keys:

GLOBAL
Space -> start/ stop
r     -> reset (only works when stopped)
m     -> switch modes (only works when stopped)

STOPWATCH
n     -> next split
b     -> previous split

TIMER
up    -> add 1 minute
down  -> remove 1 minute

WINDOW
+/-   -> make window larger/ smaller
h     -> hide/ show button (currently only stopwatch)

Sense of Urgency

All the elements are coloured red to be as alerting as possible. This little timer is just so in-your-face that it must motivate you to do things faster!

I used the Seven-segment display font since it’s ubiquitous in all digital timers. It also gives a nice 24 (the TV series) feel to it, as if you are on a timer to save to the world.

Source

Get it here on Github: nicluo/speed-runner

For a lack of a better name, I just called this SpeedRunner. Ironic, because I don’t do any speedrunning. I just need it to time my toast, tea and breaks.

Inspired by the real speedrunner