@@ -60,15 +60,10 @@ namespace Ui {
6060QT_END_NAMESPACE
6161
6262enum class RefreshAnchor {
63- // Re-select the same profiles by id; select nothing if they are gone.
6463 KeepPlace,
65- // As above, but if all of them were deleted select whatever took their row.
6664 Removal,
6765};
6866
69- // What the app launches in place of itself once on_menu_exit_triggered() has torn
70- // it down. Doubles as get_elevated_permissions()'s reason: on Windows that exits
71- // and relaunches elevated with the matching flag.
7267enum class ExitReason {
7368 None,
7469 RunUpdater,
@@ -85,9 +80,6 @@ class MainWindow : public QMainWindow {
8580
8681 ~MainWindow () override ;
8782
88- // Runtime Stats panel helpers, read on the UI thread. GetCorePid returns 0
89- // when the core process isn't running; GetRunningConfigName is empty when no
90- // profile is active.
9183 qint64 GetCorePid ();
9284 QString GetRunningConfigName ();
9385
@@ -130,11 +122,8 @@ class MainWindow : public QMainWindow {
130122
131123 void UpdateDataView (bool force = false );
132124
133- // Pushes the auto-selector snapshot into the data view, toggles the Tools
134- // entry, and refreshes the dialog if it is open.
135125 void refresh_auto_selector_view ();
136126
137- // Non-owning: cleared by the dialog's finished() handler.
138127 class DialogAutoSelector *m_autoSelectorDialog = nullptr ;
139128
140129 void setDownloadReport (const DownloadProgressReport& report, bool show);
@@ -213,27 +202,21 @@ private slots:
213202
214203private:
215204 Ui::MainWindow *ui;
216- // Monotonic, and invalid while the window is active or was never activated; see trayClickEvent().
217205 QElapsedTimer sinceWindowDeactivated;
218206 ProfilesTableModel *profilesTableModel = nullptr ;
219- // What the view is attached to: rows from the view or its selection model are
220- // proxy rows, not profilesTableModel rows.
207+
221208 ProfilesFilterProxyModel *profilesFilterModel = nullptr ;
222209 QSystemTrayIcon *tray;
223210 QMenu *trayMenu = nullptr ; // tray context menu
224- // Tray "Select Server"/"Select Routing" open this small Qt-drawn popup instead of a
225- // submenu, because a tray submenu isn't painted by Qt on Linux (SNI/DBusMenu) or macOS
226- // (native NSMenu) and so can't reliably expand a dynamic list. Recreated on each open.
227211 QPointer<TrayProfileSelector> traySelector;
228212 void openTraySelector (bool routing);
229213 QShortcut *shortcut_esc = new QShortcut(QKeySequence::Cancel, this );
230214 //
231- // Shared by the test sweeps and the batch profile scans (remove-invalid).
232215 QThreadPool *parallelCoreCallPool = new QThreadPool(this );
233216 std::unique_ptr<TestRunner> testRunner;
234217 //
235218 Configs_sys::CoreProcess *core_process = nullptr ;
236- QMutex coreProcessMutex; // serializes core_process init (DS_cores) vs IPC newConnection (UI)
219+ QMutex coreProcessMutex;
237220 QLocalServer *core_server = nullptr ;
238221 bool rpc_started = false ;
239222 qint64 vpn_pid = 0 ;
@@ -244,14 +227,8 @@ private slots:
244227 int icon_status = -1 ;
245228 std::shared_ptr<Configs::Profile> running;
246229 int last_running_profile_id = -1 ;
247- // True from the moment a profile start is kicked off until it succeeds or
248- // fails; drives the start/stop button's transient "Connecting" state.
249230 bool m_profileConnecting = false ;
250- // True while a profile stop is in progress; drives the "Disconnecting" state.
251231 bool m_profileDisconnecting = false ;
252- // Single-flight guard for the Xray geo-asset (geoip.dat/geosite.dat) download
253- // prompt: a batch test can surface the missing-asset error for many profiles at
254- // once, and we only want one prompt/download. Touched on the UI thread only.
255232 bool m_xrayGeoAssetBusy = false ;
256233 QString traffic_update_cache;
257234 qint64 last_test_time = 0 ;
@@ -272,7 +249,6 @@ private slots:
272249 SpeedWidget *speedChartWidget;
273250 //
274251 // for data view
275- // Repaint throttle, in ms since epoch. Atomic: worker threads drive it too.
276252 std::atomic<qint64> lastUpdatedMs = QDateTime::currentMSecsSinceEpoch();
277253 DataViewHtmlGenerator dataViewHtmlGenerator_;
278254
@@ -287,7 +263,6 @@ private slots:
287263
288264 QTimer *m_filterRefreshDebounce = nullptr ;
289265
290- // Only meaningful between a saveProfileFocusState() and its restore.
291266 bool m_profilesTableHadFocus = false ;
292267 int m_profilesScrollValue = 0 ;
293268
@@ -301,10 +276,10 @@ private slots:
301276 QWaitCondition logWaiter;
302277 Qv2ray::ui::SyntaxHighlighter *logHighlighter = nullptr ;
303278
304- // Immutable snapshot of the log filter fields. The log thread copies these
305- // under logMutex (Qt containers are copy-on-write, so it's O(1)) and then
306- // filters without holding the lock, so producers calling append_log() are
307- // never blocked on the regex/keyword work.
279+ QMutex logPendingMutex;
280+ QString logPendingText;
281+ bool logFlushScheduled = false ;
282+
308283 struct LogFilter {
309284 bool enableInclude = false ;
310285 bool enableExclude = false ;
@@ -318,12 +293,13 @@ private slots:
318293
319294 void log_process_loop ();
320295
296+ // UI thread only.
297+ void flush_log_batch ();
298+
321299 bool should_print_log (const QString &log, const LogFilter &filter);
322300
323301 void updateLogFilterFields ();
324302
325- // (Re)installs the log syntax highlighter, deleting any previous one so
326- // highlighters don't stack up (and keep re-highlighting) on theme changes.
327303 void setLogHighlighter (bool darkMode);
328304
329305 void applyProfileFilters ();
@@ -353,12 +329,8 @@ private slots:
353329
354330 void handle_import_route (const QString &url);
355331
356- // throne://remoteRoute?data=<...> : add one or more remote routing profiles. The data is
357- // (base64 of) a JSON array of {url, auto_update[, name]} objects.
358332 void handle_add_remote_routes (const QString &url);
359333
360- // Routes user-supplied text: throne:// links go to the deeplink handler, the
361- // rest to the subscription/profile importer.
362334 void import_or_handle_deeplink (const QString &text);
363335
364336 void refresh_proxy_list_column_size ();
@@ -369,9 +341,6 @@ private slots:
369341
370342 void parseQrImage (const QPixmap *image);
371343
372- // Imports local files picked from the file dialog or dropped on the window.
373- // What each file is gets decided from its bytes, never from its name: config
374- // files arrive as .json, .conf, .txt or with no extension at all.
375344 void importFromFiles (const QStringList &paths);
376345
377346 void trayClickEvent ();
@@ -388,10 +357,6 @@ private slots:
388357
389358 void resizeEvent (QResizeEvent *event) override ;
390359
391- // Tell the connection lister whether its tab is actually on screen (stats tab
392- // selected, window neither minimized nor hidden to tray) so it can drop to a
393- // relaxed poll cadence when nobody is looking. Recomputed on tab/visibility
394- // changes.
395360 void syncConnectionViewState ();
396361
397362 void dragEnterEvent (QDragEnterEvent *event);
@@ -400,16 +365,10 @@ private slots:
400365
401366 void applyLogBrowserFont ();
402367
403- // Re-derives the top bar's sizing from the current font and translation, and
404- // raises the window's minimum to whatever the layout actually needs. Called
405- // at startup and on every font change.
406368 void applyTopBarMetrics ();
407369
408- // The window minimum the .ui was designed with; applyTopBarMetrics() only ever
409- // grows past this, so a smaller font returns to the designed floor.
410370 QSize designMinimumSize;
411371
412- // Debounced refresh_proxy_list trigger for font/theme/resize events.
413372 QTimer *m_proxyListRefreshDebounce = nullptr ;
414373 void scheduleProxyListRefresh ();
415374
@@ -420,15 +379,7 @@ private slots:
420379 void HotkeyEvent (const QString &key);
421380
422381 void RegisterHiddenMenuShortcuts (bool unregister = false );
423- // Register a QShortcut for every action in `menu` (recursing into submenus),
424- // appending them to hiddenMenuShortcuts. Needed because the menubar is hidden,
425- // so actions reachable only through popup menus get no shortcut on their own.
426- // `claimed` holds the key sequences already handled (either by Qt automatically
427- // or by an earlier call); shortcuts already in it are skipped to avoid the
428- // ambiguous-shortcut conflict that breaks actions shared with other menus.
429382 void registerMenuShortcuts (QMenu *menu, QSet<QKeySequence> &claimed);
430- // Collect the shortcut key sequences of every action in `menu` (recursing into
431- // submenus) into `out`, without registering anything.
432383 void collectMenuShortcuts (QMenu *menu, QSet<QKeySequence> &out);
433384
434385 void setActionsData ();
@@ -443,29 +394,14 @@ private slots:
443394
444395 bool verify_core_pid (QLocalSocket *socket);
445396
446- // Measures the members of an auto selector that have no test result yet
447- // (plus `stale`, whose stored result is known to be out of date) and
448- // rewrites its ranked pool. Blocks — call from a worker thread.
449397 void rank_auto_selector (const std::shared_ptr<Configs::Profile>& ent, const QList<int >& stale = {});
450398
451- // Every running member of the auto selector died: re-rank and restart on
452- // the next batch of good ones.
453399 void on_auto_selector_exhausted (int profileID);
454400
455- // A subscription refresh rewrote the servers of `gid`. Drops ids that no
456- // longer exist from every selector tracking that group, and rebuilds the
457- // running one only if the refresh touched a member it actually built.
458- // `disturbed` holds the profiles the refresh deleted or replaced in place.
459401 void on_subscription_group_changed (int gid, const QList<int >& disturbed);
460402
461- // Guards the re-entrant profile_start used to rank before building.
462403 bool auto_selector_ranked = false ;
463404
464- // If `error` reports missing Xray geo assets (geoip.dat / geosite.dat), prompt
465- // once (guarded by m_xrayGeoAssetBusy) and download the missing .dat files in
466- // the background. Shared by profile start and the test paths. `contextName` is
467- // the profile/config name shown in the prompt. Returns true when the error was
468- // a geo-asset error (and thus handled), false otherwise.
469405 bool handleXrayGeoAssetError (const QString& error, const QString& contextName);
470406
471407 void url_test_current ();
@@ -478,8 +414,6 @@ private slots:
478414
479415 void setupConnectionSortMenu ();
480416
481- // The window's own component, not an outside caller: it drives the data
482- // view, the profile table and the geo-asset prompt while a sweep runs.
483417 friend class TestRunner ;
484418
485419protected:
0 commit comments