Fix startup settings window flash

Signed-off-by: Loren Eteval <loren.eteval@proton.me>
This commit is contained in:
Loren Eteval
2026-10-06 22:59:31 +08:00
parent d4bbdfc7cc
commit 30a202c833
3 changed files with 67 additions and 2 deletions
+2 -1
View File
@@ -777,7 +777,8 @@ class SettingsPage(Mixins.QTranslatable, QMainWindow):
self.addAction(self.findAction)
self.generalSection = _SettingsSection(_('General'))
self.tunSection = _SettingsSection('TUN', translatable=False)
# Visibility is set before layout adoption; keep the section a child.
self.tunSection = _SettingsSection('TUN', translatable=False, parent=self)
self.connectionSection = _SettingsSection(_('Connection and Interface'))
self.applicationSection = _SettingsSection(_('Application'))
self.pluginSettingsTitleLabel = AppQLabel(_('Plugin Settings'))
+1 -1
View File
@@ -114,7 +114,7 @@ worker. Choose tests by the changed contract rather than by filename alone.
| [test_main_window_geometry.py](test_main_window_geometry.py) | First-show lifecycle, restored/default/legacy geometry, main/routing window reuse, session-only navigation state, protection of never-shown windows' saved geometry. |
| [test_dialog_geometry.py](test_dialog_geometry.py) | Dialog show/open/exec preparation, sizing/centering, failure cleanup, specialized message-box geometry and transient destruction. |
| [test_layout_matrix.py](test_layout_matrix.py) | Navigation and message-box layouts in fresh processes at scale factors 1, 1.25, 1.5, and 2, under both themes. |
| [test_ui_behavior.py](test_ui_behavior.py) | Translation and editor mappings, settings organization/search/platform gates, stable server/routing moves, real QR rendering/decoding, incremental log filtering/tail behavior, connected-routing change notices, message boxes and connection-error copy/log navigation, shared Home/tray state. |
| [test_ui_behavior.py](test_ui_behavior.py) | Translation and editor mappings, settings construction visibility/organization/search/platform gates, stable server/routing moves, real QR rendering/decoding, incremental log filtering/tail behavior, connected-routing change notices, message boxes and connection-error copy/log navigation, shared Home/tray state. |
| [test_qt_interactions.py](test_qt_interactions.py) | Real keyboard/mouse/focus and proxy mapping, scoped shortcuts, sorting/selection, stable subscription deletion confirmations, debounced Home search, Tests-menu selection color, shared settings, batched profile mutation and cancellation. |
| [test_qr_export_scalability.py](test_qr_export_scalability.py) | Production capture cap, immediate single export, incremental yielding, failure/cancel/close paths, immutable snapshots, window-owned state destruction. |
| [test_stylesheet_states.py](test_stylesheet_states.py) | Targeted rendering/alpha/geometry assertions for table/list insets, popup corners, clear buttons, focus/disabled states, and stylesheet composition. |
+64
View File
@@ -449,6 +449,70 @@ class SettingsPageOrganizationTest(unittest.TestCase):
return page, callbacks
def testConstructionDoesNotShowTopLevelSettingsWidgets(self):
"""Never expose a section as a separate window before layout adoption."""
class ShowObserver(QtCore.QObject):
def __init__(self, parent):
super().__init__(parent)
self.shownWindows = []
def eventFilter(self, watched, event):
if (
event.type() == QtCore.QEvent.Type.Show
and isinstance(watched, QWidget)
and watched.isWindow()
):
self.shownWindows.append(type(watched).__name__)
return False
cases = (
('Windows', ''),
('Darwin', ''),
('Linux', ''),
('Linux', 'io.github.LorenEteval.Furious'),
)
app = application()
for platform, flatpakID in cases:
with self.subTest(platform=platform, flatpakID=flatpakID):
observer = ShowObserver(app)
page = None
app.installEventFilter(observer)
with mock.patch('sys.excepthook') as callbackExceptionHook:
try:
page, _callbacks = self.buildPage(
platform=platform, flatpakID=flatpakID
)
self.assertEqual(observer.shownWindows, [])
self.assertFalse(page.isVisible())
self.assertFalse(page.tunSection.isWindow())
self.assertEqual(page.tunSection.isHidden(), bool(flatpakID))
self.assertEqual(
page.tunSection in page._searchSections, not flatpakID
)
page.show()
processQtEvents()
self.assertTrue(page.isVisible())
self.assertEqual(page.tunSection.isVisible(), not flatpakID)
finally:
app.removeEventFilter(observer)
if page is not None:
page.close()
page.deleteLater()
observer.deleteLater()
processQtEvents()
callbackExceptionHook.assert_not_called()
def testSearchMatchesDescriptionsAndSectionsWithoutApplyingSettings(self):
with isolatedSettings():
AppSettings.set('Language', 'EN')