From 42addd3172c1d95a11b710d6ec3d9ed961e272eb Mon Sep 17 00:00:00 2001 From: Test User Date: Sat, 28 Feb 2026 16:27:51 +0000 Subject: [PATCH 1/4] fix: read port from aw-server-rust config instead of hardcoding 5600 Reads the port from aw-server-rust's config.toml (or config-testing.toml) so that users running on a non-default port get the correct dashboard URL when clicking "Open Dashboard" in the tray icon. Falls back to the defaults (5600/5666) if the config file doesn't exist or can't be parsed. Fixes #79 --- aw_qt/config.py | 28 +++++++++++++++++++++++++++- aw_qt/main.py | 2 +- aw_qt/trayicon.py | 9 ++++++--- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/aw_qt/config.py b/aw_qt/config.py index 864ebe2..5681950 100644 --- a/aw_qt/config.py +++ b/aw_qt/config.py @@ -1,7 +1,12 @@ -from typing import List, Any +import logging +import os +from typing import Any, List +import tomlkit +from aw_core import dirs from aw_core.config import load_config_toml +logger = logging.getLogger(__name__) default_config = """ [aw-qt] @@ -12,6 +17,26 @@ """.strip() +def _read_server_port(testing: bool) -> int: + """Read the port from aw-server-rust's config file, falling back to defaults.""" + default_port = 5666 if testing else 5600 + config_dir = dirs.get_config_dir("aw-server-rust") + config_file = "config-testing.toml" if testing else "config.toml" + config_path = os.path.join(config_dir, config_file) + + if not os.path.isfile(config_path): + return default_port + + try: + with open(config_path) as f: + config = tomlkit.parse(f.read()) + port = config.get("port", default_port) + return int(port) + except Exception as e: + logger.warning("Failed to read aw-server-rust config: %s", e) + return default_port + + class AwQtSettings: def __init__(self, testing: bool): """ @@ -22,3 +47,4 @@ def __init__(self, testing: bool): config_section: Any = config["aw-qt" if not testing else "aw-qt-testing"] self.autostart_modules: List[str] = config_section["autostart_modules"] + self.port: int = _read_server_port(testing) diff --git a/aw_qt/main.py b/aw_qt/main.py index c5b72f7..a90cb04 100644 --- a/aw_qt/main.py +++ b/aw_qt/main.py @@ -114,7 +114,7 @@ def main( from . import trayicon # pylint: disable=import-outside-toplevel # run the trayicon, wait for signal to quit - error_code = trayicon.run(manager, testing=testing) + error_code = trayicon.run(manager, testing=testing, port=config.port) elif interactive_cli: # just an experiment, don't really see the use right now _interactive_cli(manager) diff --git a/aw_qt/trayicon.py b/aw_qt/trayicon.py index da42281..75c4120 100644 --- a/aw_qt/trayicon.py +++ b/aw_qt/trayicon.py @@ -82,6 +82,7 @@ def __init__( icon: QIcon, parent: Optional[QWidget] = None, testing: bool = False, + port: Optional[int] = None, ) -> None: QSystemTrayIcon.__init__(self, icon, parent) self._parent = parent # QSystemTrayIcon also tries to save parent info but it screws up the type info @@ -91,7 +92,9 @@ def __init__( self.testing = testing self._restart_timestamps: Dict[str, List[float]] = {} - self.root_url = f"http://localhost:{5666 if self.testing else 5600}" + if port is None: + port = 5666 if testing else 5600 + self.root_url = f"http://localhost:{port}" self.activated.connect(self.on_activated) self._build_rootmenu() @@ -263,7 +266,7 @@ def exit(manager: Manager) -> None: QApplication.quit() -def run(manager: Manager, testing: bool = False) -> Any: +def run(manager: Manager, testing: bool = False, port: Optional[int] = None) -> Any: logger.info("Creating trayicon...") # print(QIcon.themeSearchPaths()) @@ -330,7 +333,7 @@ def run(manager: Manager, testing: bool = False) -> Any: else: icon = QIcon("icons:logo.png") - trayIcon = TrayIcon(manager, icon, widget, testing=testing) + trayIcon = TrayIcon(manager, icon, widget, testing=testing, port=port) trayIcon.show() # Re-apply tooltip after show() to ensure it registers with the From 136dcfbe129a8d84bbccc8532ee822308cd839bf Mon Sep 17 00:00:00 2001 From: Bob Date: Mon, 2 Mar 2026 16:23:29 +0000 Subject: [PATCH 2/4] fix: also read port from aw-server (Python) config Extends port detection to support both aw-server and aw-server-rust: - aw-server-rust: ~/.config/activitywatch/aw-server-rust/config.toml - aw-server: ~/.config/activitywatch/aw-server/aw-server.toml ([server]/[server-testing] sections) Tries aw-server-rust first, falls back to aw-server, then to hardcoded defaults. --- aw_qt/config.py | 48 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/aw_qt/config.py b/aw_qt/config.py index 5681950..f1e1e5e 100644 --- a/aw_qt/config.py +++ b/aw_qt/config.py @@ -17,24 +17,58 @@ """.strip() -def _read_server_port(testing: bool) -> int: - """Read the port from aw-server-rust's config file, falling back to defaults.""" - default_port = 5666 if testing else 5600 +def _read_server_rust_port(testing: bool) -> int | None: + """Read port from aw-server-rust config, returns None if not found/set.""" config_dir = dirs.get_config_dir("aw-server-rust") config_file = "config-testing.toml" if testing else "config.toml" config_path = os.path.join(config_dir, config_file) if not os.path.isfile(config_path): - return default_port + return None try: with open(config_path) as f: config = tomlkit.parse(f.read()) - port = config.get("port", default_port) - return int(port) + if "port" in config: + return int(config["port"]) except Exception as e: logger.warning("Failed to read aw-server-rust config: %s", e) - return default_port + return None + + +def _read_aw_server_port(testing: bool) -> int | None: + """Read port from aw-server (Python) config, returns None if not found/set.""" + config_dir = dirs.get_config_dir("aw-server") + config_path = os.path.join(config_dir, "aw-server.toml") + section = "server-testing" if testing else "server" + + if not os.path.isfile(config_path): + return None + + try: + with open(config_path) as f: + config = tomlkit.parse(f.read()) + section_data = config.get(section, {}) + if "port" in section_data: + return int(section_data["port"]) + except Exception as e: + logger.warning("Failed to read aw-server config: %s", e) + return None + + +def _read_server_port(testing: bool) -> int: + """Read port from server config (aw-server-rust or aw-server), falling back to defaults.""" + default_port = 5666 if testing else 5600 + + port = _read_server_rust_port(testing) + if port is not None: + return port + + port = _read_aw_server_port(testing) + if port is not None: + return port + + return default_port class AwQtSettings: From e6edd2952b3ef5eb3a9d5888f14c7586bd21e095 Mon Sep 17 00:00:00 2001 From: Bob Date: Mon, 2 Mar 2026 16:27:07 +0000 Subject: [PATCH 3/4] fix: use Optional[int] for Python 3.9 compatibility --- aw_qt/config.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aw_qt/config.py b/aw_qt/config.py index f1e1e5e..f14e022 100644 --- a/aw_qt/config.py +++ b/aw_qt/config.py @@ -1,6 +1,6 @@ import logging import os -from typing import Any, List +from typing import Any, List, Optional import tomlkit from aw_core import dirs @@ -17,7 +17,7 @@ """.strip() -def _read_server_rust_port(testing: bool) -> int | None: +def _read_server_rust_port(testing: bool) -> Optional[int]: """Read port from aw-server-rust config, returns None if not found/set.""" config_dir = dirs.get_config_dir("aw-server-rust") config_file = "config-testing.toml" if testing else "config.toml" @@ -36,7 +36,7 @@ def _read_server_rust_port(testing: bool) -> int | None: return None -def _read_aw_server_port(testing: bool) -> int | None: +def _read_aw_server_port(testing: bool) -> Optional[int]: """Read port from aw-server (Python) config, returns None if not found/set.""" config_dir = dirs.get_config_dir("aw-server") config_path = os.path.join(config_dir, "aw-server.toml") From a0cbfda190c84c01ede7606e2ddb1ee5145373d7 Mon Sep 17 00:00:00 2001 From: Bob Date: Mon, 2 Mar 2026 16:30:28 +0000 Subject: [PATCH 4/4] fix: use str() to satisfy mypy for tomlkit Item types --- aw_qt/config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aw_qt/config.py b/aw_qt/config.py index f14e022..cb5ccbb 100644 --- a/aw_qt/config.py +++ b/aw_qt/config.py @@ -30,7 +30,7 @@ def _read_server_rust_port(testing: bool) -> Optional[int]: with open(config_path) as f: config = tomlkit.parse(f.read()) if "port" in config: - return int(config["port"]) + return int(str(config["port"])) except Exception as e: logger.warning("Failed to read aw-server-rust config: %s", e) return None @@ -50,7 +50,7 @@ def _read_aw_server_port(testing: bool) -> Optional[int]: config = tomlkit.parse(f.read()) section_data = config.get(section, {}) if "port" in section_data: - return int(section_data["port"]) + return int(str(section_data["port"])) except Exception as e: logger.warning("Failed to read aw-server config: %s", e) return None