aboutsummaryrefslogtreecommitdiffstats
path: root/deckit
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-11-09 20:35:26 +0100
committerDanilo M. <danix@danix.xyz>2026-11-09 20:35:26 +0100
commitedaad8e9f6e918c783fd8fb9237fa33032194ed5 (patch)
tree6c28c38cde47bd640531f6140d0d5dabc7c95813 /deckit
parent6b323fc06ec255153e86eafa4dffa67ad8c21f8c (diff)
downloaddeck-it-edaad8e9f6e918c783fd8fb9237fa33032194ed5.tar.gz
deck-it-edaad8e9f6e918c783fd8fb9237fa33032194ed5.zip
feat: launcher icons come from the configured icon theme
Diffstat (limited to 'deckit')
-rw-r--r--deckit/server.py20
1 files changed, 20 insertions, 0 deletions
diff --git a/deckit/server.py b/deckit/server.py
index 638322f..01e7ec1 100644
--- a/deckit/server.py
+++ b/deckit/server.py
@@ -9,6 +9,7 @@ import hmac
import json
import mimetypes
import os
+import re
import secrets
import socketserver
import subprocess
@@ -24,8 +25,11 @@ ROOT = Path(__file__).resolve().parent.parent
STATIC = ROOT / "static"
RUNDIR = Path(os.environ.get("XDG_RUNTIME_DIR", f"/run/user/{os.getuid()}")) / "deck-it"
SOCKET = RUNDIR / "http.sock"
+ICON = re.compile(r"[A-Za-z0-9._-]{1,64}")
+ICON_BASES = (Path.home() / ".local/share/icons", Path("/usr/share/icons"), Path.home() / ".icons")
CFG = config.load_config()
+ICON_THEME = CFG.get("icons", {}).get("theme", "candy-icons")
MONITOR = CFG.get("display", {}).get("name", "TAB")
PORT = CFG.get("ports", {}).get("command_center", 8765)
VNC_PORT = CFG.get("ports", {}).get("display", 5900)
@@ -47,6 +51,18 @@ def _run(cmd, timeout=2):
return ""
+def icon_path(name: str, theme: str = ICON_THEME, bases=ICON_BASES):
+ """An app icon from the installed icon theme, so launchers follow the theme."""
+ if not ICON.fullmatch(name):
+ return None
+ for base in bases:
+ for sub in ("apps/scalable", "apps/64", "apps/48", "apps/32"):
+ path = Path(base) / theme / sub / f"{name}.svg"
+ if path.is_file():
+ return path
+ return None
+
+
def art():
"""The current track's cover art, if the player exposes a local file."""
url = _run(["playerctl", "metadata", "mpris:artUrl"])
@@ -114,6 +130,10 @@ class Handler(BaseHTTPRequestHandler):
return
if path == "/theme.css":
return self._send(200, theme.load().encode(), "text/css")
+ if path.startswith("/icons/"):
+ name = path[len("/icons/"):].removesuffix(".svg")
+ icon = icon_path(name)
+ return self._send(200, icon.read_bytes(), "image/svg+xml", cache=True) if icon else self._send(404)
if path.startswith("/api/"):
if not self._authed():
return self._send(401)