Countdown timers for the Linux desktop. Name them, run as many as you like, and when one finishes it rings until you answer it.
Built with GTK 3 through PyGObject. No pip packages, no build step.
./install.shThat links timer into ~/.local/bin and adds a Timer entry to the
application menu. Nothing is written outside your home directory.
To run it without installing:
python3 -m timerappRequires python3-gi and gir1.2-gtk-3.0, which Linux Mint and Ubuntu already
have. If they are missing: sudo apt install python3-gi gir1.2-gtk-3.0.
Type a name and a duration, press Start. Or use the preset buttons.
From a terminal — a second timer command is handed to the window that is
already open rather than starting a new app:
timer # open the window
timer 5m Tea # start a 5 minute timer called Tea
timer Tea 5m # the same, either order works
timer 1h30 # 1 hour 30 minutes
timer -p Pomodoro # start a saved preset (a unique prefix will do)
timer --list # show what is running
timer --help| You type | You get |
|---|---|
90s |
90 seconds |
5m |
5 minutes |
2h |
2 hours |
90 |
90 minutes — a bare number means minutes |
1h30 |
1 hour 30 minutes |
1h30m15s |
1 hour 30 minutes 15 seconds |
7:30 |
7 minutes 30 seconds |
1:02:03 |
1 hour 2 minutes 3 seconds |
The window shows what it read (= 1h 30m) as you type, so nothing is a
surprise.
An alarm sound repeats, a desktop notification appears, and a window opens with three answers:
- Snooze 5m — run for another five minutes
- Restart — run the whole duration again
- Dismiss — stop
The sound keeps going until the timer is answered. Several finished timers each get their own window, and the sound stops once the last one is answered.
- Pause and resume any running timer, or restart it, from its row.
- Rename a timer by clicking its name.
- Presets are saved to disk and editable from the gear button.
- Tray icon shows the nearest countdown. Closing the window hides to the tray and the timers keep running; quit from the tray menu.
- Start at login is in the window menu.
- Timers survive a restart. A timer whose time passed while the app was closed rings as soon as it opens, and says so.
| Path | What |
|---|---|
~/.local/share/timerapp/state.json |
running timers |
~/.local/share/timerapp/presets.json |
saved presets |
~/.config/autostart/timerapp.desktop |
start at login, when enabled |
A state file that has been corrupted is renamed aside rather than deleted, and the app starts with an empty list.
Logic and widgets are kept apart, so most of the app is testable without a display.
| Module | Job |
|---|---|
duration.py |
read and write durations |
model.py |
Timer and TimerStore — the state machine |
storage.py |
JSON on disk, written atomically |
cli.py |
argument handling |
session.py |
owns the timers, the tick, the saved state, the alarm sound |
alarm.py |
plays the sound, sends the notification |
ui/window.py |
the main window |
ui/row.py |
one timer in the list |
ui/alert.py |
the window a finished timer opens |
ui/presets.py |
preset buttons and their editor |
ui/tray.py |
the tray icon |
A running timer stores the wall-clock time it will finish, rather than counting ticks. That is why it stays correct across suspend, a busy UI, and a restart. One 200 ms tick drives every timer.
Only one instance runs at a time. Gtk.Application handles that, and forwards
any later command line to the instance already running.
python3 -m unittest discover -s tests -t .75 tests. The GTK ones drive the real widgets and skip when there is no display; the rest need nothing but Python.
rm ~/.local/bin/timer
rm ~/.local/share/applications/timerapp.desktop
rm -rf ~/.local/share/timerapp # optional: saved timers and presets
rm -f ~/.config/autostart/timerapp.desktopMIT — see LICENSE.