2121from datetime import datetime
2222from functools import partial
2323from pprint import pformat
24- from threading import Event , Thread
24+ from threading import Thread
2525from typing import Any , Callable
2626import inspect
2727import multiprocessing
28- import time
2928
3029from pyqttoast import Toast , ToastButtonAlignment , ToastIcon , ToastPosition , ToastPreset
31- from PySide6 .QtCore import QMargins , QObject , QSize , Qt , QThread , QTimer , Signal
30+ from PySide6 .QtCore import QMargins , QObject , QSize , Qt , QThread , Signal
3231from PySide6 .QtGui import QAction , QColor , QFont , QIcon , QPixmap
3332from PySide6 .QtWidgets import (
3433 QApplication ,
4645 QVBoxLayout ,
4746 QWidget ,
4847)
49- import requests
5048
5149from openadapt .app import FPATH , quick_record , stop_record
5250from openadapt .app .dashboard .run import cleanup as cleanup_dashboard
@@ -112,109 +110,6 @@ def run(self) -> None:
112110 self .data .emit (data )
113111
114112
115- class DashboardMonitor (QObject ):
116- """Monitor dashboard initialization."""
117-
118- ready = Signal ()
119-
120- def __init__ (self , app : QApplication = None , port : int = 5173 ) -> None :
121- """Initializes the DashboardMonitor.
122-
123- Args:
124- app (QApplication, optional): The QApplication instance. Defaults to None.
125- port (int, optional): The port number for the dashboard. Defaults to 5173.
126-
127- Attributes:
128- stop_flag (Event): An event flag to signal stopping the monitor.
129- port (int): The port number for the dashboard.
130- _is_ready (bool): A flag indicating if the monitor is ready.
131- monitor_thread (QThread or None): The thread for monitoring.
132- """
133- super ().__init__ ()
134- self .stop_flag = Event ()
135- self .port = port
136- self ._is_ready = False
137-
138- if app is not None :
139- self .monitor_thread = QThread ()
140- self .moveToThread (self .monitor_thread )
141- self .monitor_thread .started .connect (self .monitor_startup )
142- self .monitor_thread .finished .connect (self .on_thread_finished )
143- else :
144- self .monitor_thread = None
145-
146- print ("DEBUG(DashboardMonitor): Signal ready created" )
147-
148- # Connect to our own ready signal to update state
149- self .ready .connect (self ._update_ready_state )
150-
151- def _update_ready_state (self ) -> None :
152- """Update internal ready state when signal is emitted."""
153- self ._is_ready = True
154- print ("DEBUG(DashboardMonitor): Ready state updated" )
155-
156- def on_thread_finished (self ) -> None :
157- """Handle thread finished signal."""
158- logger .info ("Dashboard monitor thread finished" )
159-
160- def monitor_startup (self ) -> None :
161- """Monitor dashboard startup process."""
162- logger .info ("Starting dashboard monitoring" )
163- start_time = time .time ()
164- try :
165- while not self .stop_flag .is_set ():
166- try :
167- elapsed_time = time .time () - start_time
168- print (
169- "DEBUG(DashboardMonitor): Checking dashboard. Elapsed:"
170- f" { elapsed_time :.2f} s"
171- )
172-
173- response = requests .get (f"http://localhost:{ self .port } " , timeout = 1 )
174- if response .status_code == 200 :
175- logger .info ("Dashboard is ready!" )
176-
177- # Emit signal in main thread
178- QTimer .singleShot (0 , self .on_dashboard_ready )
179- break
180- except requests .RequestException as e :
181- logger .debug (f"Connection attempt failed: { e } " )
182- time .sleep (0.5 )
183-
184- if time .time () - start_time > 30 :
185- logger .warning ("Monitoring timeout" )
186- break
187- finally :
188- self .monitor_thread .quit ()
189-
190- def on_dashboard_ready (self ) -> None :
191- """Handle dashboard being ready."""
192- try :
193- self .ready .emit ()
194- logger .info ("Emitting ready signal" )
195- except Exception as e :
196- logger .error (f"Error emitting signal: { e } " )
197-
198- def check_ready_state (self ) -> None :
199- """Check if dashboard is ready and re-emit if necessary."""
200- if self ._is_ready :
201- QTimer .singleShot (0 , self .on_dashboard_ready )
202-
203- def stop (self ) -> None :
204- """Stop monitoring and cleanup thread."""
205- logger .info ("Stopping dashboard monitor" )
206- self .stop_flag .set ()
207-
208- if self .monitor_thread and self .monitor_thread .isRunning ():
209- try :
210- self .monitor_thread .quit ()
211- if not self .monitor_thread .wait (1000 ):
212- logger .warning ("Dashboard monitor thread did not stop cleanly" )
213- self .monitor_thread .terminate ()
214- except Exception as e :
215- logger .error (f"Error stopping dashboard monitor thread: { e } " )
216-
217-
218113class SystemTrayIcon :
219114 """System tray icon for OpenAdapt."""
220115
@@ -225,13 +120,11 @@ class SystemTrayIcon:
225120 # storing actions is required to prevent garbage collection
226121 recording_actions = {"visualize" : [], "replay" : []}
227122
228- def __init__ (self , app : QApplication = None ) -> None :
123+ def __init__ (self ) -> None :
229124 """Initialize the system tray icon."""
230- if app is None :
125+ self .app = QApplication .instance ()
126+ if not self .app :
231127 self .app = QApplication ([])
232- else :
233- self .app = app
234-
235128 if sys .platform == "darwin" :
236129 # hide Dock icon while allowing focus on dialogs
237130 # (must come after QApplication())
@@ -613,36 +506,13 @@ def populate_menu(self, menu: QMenu, action: Callable, action_type: str) -> None
613506
614507 def launch_dashboard (self ) -> None :
615508 """Launch the web dashboard."""
616- try :
617- if self .dashboard_thread :
618- if is_running_from_executable ():
619- return
620- cleanup_dashboard ()
621- self .dashboard_thread .join ()
622-
623- # Start dashboard
624- self .dashboard_thread = run_dashboard ()
625- self .dashboard_thread .start ()
626- logger .info ("Dashboard thread started" )
627-
628- # Initialize dashboard monitor
629- self .dashboard_monitor = DashboardMonitor (app = self .app )
630-
631- # Connect ready signal BEFORE starting monitoring
632- self .dashboard_monitor .ready .connect (
633- self .on_dashboard_ready , Qt .ConnectionType .QueuedConnection
634- )
635-
636- # Start monitoring
637- self .dashboard_monitor .monitor_startup ()
638- logger .info ("Dashboard monitor started" )
639-
640- except Exception as e :
641- logger .error (f"Launch dashboard error: { e } " )
642-
643- def on_dashboard_ready (self ) -> None :
644- """Handle dashboard being ready."""
645- logger .info ("Dashboard is ready - performing final setup" )
509+ if self .dashboard_thread :
510+ if is_running_from_executable ():
511+ return
512+ cleanup_dashboard ()
513+ self .dashboard_thread .join ()
514+ self .dashboard_thread = run_dashboard ()
515+ self .dashboard_thread .start ()
646516
647517 def run (self ) -> None :
648518 """Run the system tray icon."""
0 commit comments