21
21
from datetime import datetime
22
22
from functools import partial
23
23
from pprint import pformat
24
- from threading import Event , Thread
24
+ from threading import Thread
25
25
from typing import Any , Callable
26
26
import inspect
27
27
import multiprocessing
28
- import time
29
28
30
29
from 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
32
31
from PySide6 .QtGui import QAction , QColor , QFont , QIcon , QPixmap
33
32
from PySide6 .QtWidgets import (
34
33
QApplication ,
46
45
QVBoxLayout ,
47
46
QWidget ,
48
47
)
49
- import requests
50
48
51
49
from openadapt .app import FPATH , quick_record , stop_record
52
50
from openadapt .app .dashboard .run import cleanup as cleanup_dashboard
@@ -112,109 +110,6 @@ def run(self) -> None:
112
110
self .data .emit (data )
113
111
114
112
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
-
218
113
class SystemTrayIcon :
219
114
"""System tray icon for OpenAdapt."""
220
115
@@ -225,13 +120,11 @@ class SystemTrayIcon:
225
120
# storing actions is required to prevent garbage collection
226
121
recording_actions = {"visualize" : [], "replay" : []}
227
122
228
- def __init__ (self , app : QApplication = None ) -> None :
123
+ def __init__ (self ) -> None :
229
124
"""Initialize the system tray icon."""
230
- if app is None :
125
+ self .app = QApplication .instance ()
126
+ if not self .app :
231
127
self .app = QApplication ([])
232
- else :
233
- self .app = app
234
-
235
128
if sys .platform == "darwin" :
236
129
# hide Dock icon while allowing focus on dialogs
237
130
# (must come after QApplication())
@@ -613,36 +506,13 @@ def populate_menu(self, menu: QMenu, action: Callable, action_type: str) -> None
613
506
614
507
def launch_dashboard (self ) -> None :
615
508
"""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 ()
646
516
647
517
def run (self ) -> None :
648
518
"""Run the system tray icon."""
0 commit comments