Skip to content

Instantly share code, notes, and snippets.

@chuckwagoncomputing
Last active March 12, 2026 03:50
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
from collections import deque
from PyQt6.QtWidgets import QApplication, QSystemTrayIcon, QMenu
from PyQt6.QtGui import QIcon, QAction
from PyQt6.QtCore import QTimer
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)
# Status → icon mapping (you can use absolute paths or theme icons)
icons = {
"idle": QIcon.fromTheme("folder"),
"syncing": QIcon.fromTheme("folder-sync"),
"scanning": QIcon.fromTheme("view-refresh"),
"error": QIcon.fromTheme("dialog-error"),
}
# --- Qt application ---
app = QApplication(sys.argv)
# Tray icon
tray = QSystemTrayIcon()
tray.setIcon(icons["idle"])
tray.setToolTip("Starting...")
tray.show()
# Menu
menu = QMenu()
label_action = QAction(sys.argv[1])
label_action.setDisabled(True)
menu.addAction(label_action)
menu.addSeparator()
quit_action = QAction("Quit")
quit_action.triggered.connect(app.quit)
menu.addAction(quit_action)
tray.setContextMenu(menu)
tray.setToolTip(sys.argv[1])
# --- FIFO Reader ---
def fifo_reader():
# Open FIFO read/write so it never sees EOF
fd = os.open(FIFO_PATH, os.O_RDWR)
with os.fdopen(fd) as fifo:
while True:
line = fifo.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
# Update tray icon and tooltip
tray.setIcon(icons.get(status, icons["idle"]))
tray.setToolTip(sys.argv[1] + "\n" + status)
# Run FIFO reader in a separate thread
threading.Thread(target=fifo_reader, daemon=True).start()
print(f"Tray running with FIFO: {FIFO_PATH}")
sys.exit(app.exec())
#!/usr/bin/env bash
trap cleanup SIGINT
pytray $1 &
PTPID=$!
PTIN="/tmp/pytray-${PTPID}.fifo"
cleanup() {
kill $PTPID
rm $PTIN
exit
}
sleep 1s
while true; do
unison $1 2>&1 |
while IFS= read -r line; do
if [ "$2" == "-d" ]; then
echo "$line"
fi
case "$line" in
*"----"*)
;&
*"Looking for changes"*)
echo "scanning" >$PTIN
;;
*"Copying"*)
;&
*"Updating"*)
;&
*"Deleting"*)
;&
*"Reconciling changes"*)
;&
*"Propagating updates"*)
echo "syncing" >$PTIN
;;
*"Nothing to do"*)
;&
*"Synchronization complete"*)
echo "idle" >$PTIN
;;
*"failed"*|*"error"*)
echo "error" >$PTIN
;;
esac
done
done
[Unit]
Description=Run unison with profile %i
[Service]
Type=simple
Environment="PATH=%h/bin:%h/.local/bin:/usr/local/bin:/usr/bin"
ExecStart=%h/.local/bin/re-unison %i
[Install]
WantedBy=default.target
[Unit]
Description=Run unison server on port %i
[Service]
Type=simple
ExecStart=/usr/bin/unison -socket %i
[Install]
WantedBy=default.target
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment