**_
The Inspiration
_**
Have you ever watched a movie and thought, "I want that technology in real life"?
That happened to me with "In Time" (2011) - the dystopian sci-fi film where people have glowing green countdown timers embedded in their arms. When the timer hits zero, they die. Time literally becomes currency - you pay for coffee with minutes, earn years at work, and can transfer time between people.
It's a dark concept, but the visual of a constantly-visible countdown created something powerful: visceral time awareness.
So I built it for my Linux desktop.
### What is InTime Widget?
InTime Widget is a Hyprland overlay that displays countdown timers inspired by the film. Unlike your system clock that you glance at and ignore, InTime creates constant awareness of time passing.
Features
- 4 Display Modes: Clock, countdown, midnight countdown, horror-style deadline
- Dynamic Colors: Real-time color sampling from your screen
- Sci-Fi Effects: 15-layer particle glow inspired by the movie
- Wayland Native: Built with GTK4 and Layer Shell
- IPC Control: Remote control via Unix sockets
- Multi-Monitor: Display on one or all monitors
The Technical Stack
Building a Wayland overlay widget required some interesting technical choices:
GTK4 + Layer Shell
Wayland's security model doesn't allow arbitrary windows to float on top (unlike X11). The solution? Layer Shell - a Wayland protocol that lets you create overlay surfaces legitimately.
import gi
gi.require_version('Gtk', '4.0')
gi.require_version('Gtk4LayerShell', '1.0')
from gi.repository import Gtk, Gtk4LayerShell as LayerShell
class InTimeWidget(Gtk.Window):
def __init__(self):
super().__init__()
# Initialize layer shell
LayerShell.init_for_window(self)
LayerShell.set_layer(self, LayerShell.Layer.OVERLAY)
LayerShell.set_keyboard_mode(self, LayerShell.KeyboardMode.NONE)
# Set anchors for positioning
LayerShell.set_anchor(self, LayerShell.Edge.TOP, True)
LayerShell.set_anchor(self, LayerShell.Edge.BOTTOM, True)
This gives us:
- ✅ Always-on-top behavior
- ✅ Click-through transparency
- ✅ Proper Wayland integration
- ✅ Multi-monitor support
Cairo Rendering
For the visual effects (glow, particles, text rendering), I used Cairo - a 2D graphics library that integrates beautifully with GTK.
The challenge? Achieving true transparency (not just window opacity).
def on_draw(self, widget, cr):
# Clear with full transparency
cr.set_operator(cairo.Operator.SOURCE)
cr.set_source_rgba(0, 0, 0, 0)
cr.paint()
# Now draw content
cr.set_operator(cairo.Operator.OVER)
# ... drawing code
Using cairo.Operator.SOURCE clears the canvas to actual transparency, then switching to cairo.Operator.OVER for drawing creates proper alpha compositing.
Dynamic Color Sampling
One of the coolest features is adaptive colors - the widget samples your screen and adjusts its color to match.
On Wayland, this requires the grim screenshot tool:
def sample_screen_color(self):
# Take screenshot
subprocess.run(['grim', '/tmp/screen.png'],
capture_output=True)
# Load and analyze
img = Image.open('/tmp/screen.png')
pixels = list(img.getdata())
# Extract dominant color using custom algorithm
color = self.process_colors(pixels)
return color
I implemented a hybrid color processor that:
- Calculates average RGB
- Finds dominant color by frequency
- Blends the two for better aesthetics
- Throttles updates to avoid performance issues
Multi-Monitor Architecture
Hyprland supports multiple monitors, so the widget needed to as well.
The approach: one GTK application, multiple windows:
class InTimeApplication(Gtk.Application):
def do_activate(self):
# Detect monitors
monitors = self.get_monitors()
# Create widget per monitor
for monitor in monitors:
widget = InTimeWidget(monitor_index=monitor.index)
self.add_window(widget)
Each window runs independently but can sync via IPC.
IPC Control System
For remote control (start/stop, change modes), I built a Unix socket server:
class IPCServer(threading.Thread):
def __init__(self, widget, socket_path='/tmp/intime_widget.sock'):
super().__init__(daemon=True)
self.widget = widget
self.socket_path = socket_path
def run(self):
with socket.socket(socket.AF_UNIX) as sock:
sock.bind(self.socket_path)
sock.listen(1)
while True:
conn, _ = sock.accept()
data = conn.recv(1024).decode()
self.handle_command(data)
Commands like reload_config, forbidden_alarm, and toggle_screen_sampling work via simple netcat:
echo "reload_config" | nc -U /tmp/intime_widget.sock
The Visual Effects
The "lightbulb" mode deserved special attention. It creates a 15-layer particle glow effect:
def draw_lightbulb(self, cr, text, x, y, r, g, b):
# Draw 15 layers of decreasing opacity
for i in range(15, 0, -1):
size_offset = i * 3
opacity = 0.4 - (i * 0.02)
cr.set_source_rgba(r, g, b, opacity)
# ... draw enlarged text with blur
The effect builds from large, faint outer layers to sharp inner text - creating a sci-fi glow reminiscent of the movie's bio-clocks.
Performance Optimization
Desktop widgets need to be lightweight. Nobody wants a clock eating 10% CPU.
Optimizations:
- Variable frame rates: 1fps for clock mode, 3fps for deadline, 20fps for lightbulb
- Lazy updates: Only redraw when something changes
- Low layer counts: 15 layers sounds like a lot, but it's tuned for efficiency
- Throttled color sampling: Max once per 0.5 seconds
Result: <1% CPU idle, ~30-50MB RAM
The "Forbidden Alarm"
My favorite feature: an urgent visual alarm that takes over your screen.
Inspired by the movie scene where the protagonist's time runs out, this creates:
- 12-layer glow effect
- Pulsing waves
- Screen shake (via positioning offsets)
- Red color shift
Perfect for "oh crap, deadline is NOW" moments.
Challenges & Lessons
Challenge 1: Wayland Transparency
X11 made overlay windows trivial. Wayland's security model required learning Layer Shell protocol. Worth it for proper integration.
Challenge 2: Color Sampling Performance
Initial implementation took screenshots every frame - CPU usage spiked. Solution: throttling and caching.
Challenge 3: Multi-Monitor Sync
Keeping multiple widget instances in sync required careful IPC design. Used broadcasting to all instances.
Challenge 4: Font Rendering
Getting crisp, bold text at large sizes required Pango (GTK's text layout engine):
layout = PangoCairo.create_layout(cr)
font = Pango.FontDescription("Monospace Bold 78")
layout.set_font_description(font)
layout.set_text(time_str, -1)
PangoCairo.show_layout(cr, layout)
What I Learned
- Wayland is different - Security model requires proper protocol support
- GTK4 is powerful - Once you learn it, complex UIs become simple
- Visual polish matters - The glow effects took 20% of dev time but create 80% of the appeal
- Performance first - Easy to build pretty effects; hard to make them efficient
- Community loves themes - Open source projects need good aesthetics
Try It Yourself
The widget is fully open source (MIT license) and ready to use:
GitHub: https://github.com/mathis0/InTime
Quick Start:
git clone https://github.com/mathis0/InTime.git
cd InTime
./scripts/install.sh
intime-widget start --mode countdown --duration 25m --style lightbulb
What's Next?
Future ideas:
- More color themes (Nord, Dracula, Catppuccin presets)
- Integration with task managers
- Sound effects for alarms
- Customizable alarm triggers
- Better multi-monitor configuration
Conclusion
Building InTime Widget taught me that time awareness changes behavior. With a countdown always visible, I find myself:
- More focused during work sessions
- Less likely to waste time
- More aware of how I spend each hour
It's "Memento Mori" for the desktop age - a constant reminder that time is the ultimate currency.
If you've ever wanted that visceral time-awareness from "In Time" on your Linux desktop, give it a try!
Questions? Feedback? Drop a comment or open an issue on GitHub!
If you found this interesting, follow me on GitHub for more open source projects!

Top comments (0)