Skip to content

Instantly share code, notes, and snippets.

@chuckwagoncomputing
Last active March 10, 2026 10:54
Show Gist options
  • Select an option

  • Save chuckwagoncomputing/1cae9b032aebad3f7e41baa2f5bbc17e to your computer and use it in GitHub Desktop.

Select an option

Save chuckwagoncomputing/1cae9b032aebad3f7e41baa2f5bbc17e to your computer and use it in GitHub Desktop.
Unison system tray icon wrapper [slop]
#!/usr/bin/env python3
import os
import sys
import threading
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib
gi.require_version('AyatanaAppIndicator3', '0.1')
from gi.repository import AyatanaAppIndicator3 as AppIndicator
APP_ID = "pytray"
# Include PID in FIFO name for uniqueness
PID = os.getpid()
FIFO_PATH = f"/tmp/{APP_ID}-{PID}.fifo"
if not os.path.exists(FIFO_PATH):
os.mkfifo(FIFO_PATH)
icons = {
"idle": "folder",
"syncing": "folder-sync",
"scanning": "view-refresh",
"error": "dialog-error",
}
indicator = AppIndicator.Indicator.new(
"unison-tray",
icons["idle"],
AppIndicator.IndicatorCategory.APPLICATION_STATUS
)
indicator.set_status(AppIndicator.IndicatorStatus.ACTIVE)
menu = Gtk.Menu()
quit_item = Gtk.MenuItem(label="Quit")
quit_item.connect("activate", lambda _: Gtk.main_quit())
menu.append(quit_item)
menu.show_all()
indicator.set_menu(menu)
def update(status, message):
icon = icons.get(status, icons["idle"])
indicator.set_icon(icon)
indicator.set_title(message)
# Persistent FIFO reader
def fifo_reader():
# Open FIFO for reading and writing to avoid EOF immediately
fifo_fd = os.open(FIFO_PATH, os.O_RDWR)
fifo_file = os.fdopen(fifo_fd)
while True:
line = fifo_file.readline()
if not line:
continue
line = line.strip()
if not line:
continue
parts = line.split(" ", 1)
status = parts[0]
message = parts[1] if len(parts) > 1 else status
GLib.idle_add(update, status, message)
threading.Thread(target=fifo_reader, daemon=True).start()
print(f"Tray running with FIFO: {FIFO_PATH}")
Gtk.main()
#!/usr/bin/env bash
trap cleanup SIGINT
pytray &
PTPID=$!
PTIN="/tmp/pytray-${PTPID}.fifo"
cleanup() {
kill $PTPID
rm $PTIN
exit
}
sleep 1s
while true; do
unison $1 -repeat watch -prefer newer -retry 100 2>&1 |
while IFS= read -r line; do
echo "$line"
case "$line" in
*"Looking for changes"*)
echo "scanning" >$PTIN
;;
*"Copying"*)
;&
*"Updating"*)
;&
*"Deleting"*)
;&
*"Reconciling changes"*)
;&
*"Propagating updates"*)
echo "syncing" >$PTIN
;;
*"failed"*|*"error"*)
echo "error" >$PTIN
;;
*"Nothing to do"*)
echo "idle" >$PTIN
;;
esac
done
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment