Enhance title bar theming and refresh logic; ensure immediate updates for main and dialog windows

This commit is contained in:
2025-07-31 15:27:49 +02:00
parent a9965493e8
commit 2abc71347f
+114 -15
View File
@@ -2094,8 +2094,19 @@ class MainWindow(QtWidgets.QMainWindow):
if result == 0: # S_OK if result == 0: # S_OK
logger.debug(f"Applied Windows {'dark' if enable_dark else 'light'} title bar ({'newer' if use_newer_api else 'legacy'} API)") logger.debug(f"Applied Windows {'dark' if enable_dark else 'light'} title bar ({'newer' if use_newer_api else 'legacy'} API)")
# Force window to redraw # Force immediate window redraw using multiple methods
self.update() self.update()
self.repaint()
# Force a window refresh by briefly changing and restoring window flags
try:
original_flags = self.windowFlags()
self.setWindowFlags(original_flags | QtCore.Qt.WindowType.WindowStaysOnTopHint)
self.setWindowFlags(original_flags)
self.show()
except:
pass
return True return True
else: else:
logger.debug(f"Windows title bar API returned error code: {result}") logger.debug(f"Windows title bar API returned error code: {result}")
@@ -2115,6 +2126,17 @@ class MainWindow(QtWidgets.QMainWindow):
if result == 0: if result == 0:
logger.debug(f"Applied Windows {'dark' if enable_dark else 'light'} title bar (fallback API)") logger.debug(f"Applied Windows {'dark' if enable_dark else 'light'} title bar (fallback API)")
self.update() self.update()
self.repaint()
# Force window refresh
try:
original_flags = self.windowFlags()
self.setWindowFlags(original_flags | QtCore.Qt.WindowType.WindowStaysOnTopHint)
self.setWindowFlags(original_flags)
self.show()
except:
pass
return True return True
except Exception as fallback_e: except Exception as fallback_e:
logger.debug(f"Windows dark title bar fallback failed: {fallback_e}") logger.debug(f"Windows dark title bar fallback failed: {fallback_e}")
@@ -2171,17 +2193,36 @@ class MainWindow(QtWidgets.QMainWindow):
colors = self.get_theme_styles() colors = self.get_theme_styles()
is_dark = self.get_effective_dark_mode() is_dark = self.get_effective_dark_mode()
# Apply title bar theming with multiple attempts to ensure it takes effect # Apply title bar theming immediately
def apply_title_bar_theming(): self.apply_dark_title_bar(is_dark)
success = self.apply_dark_title_bar(is_dark)
if not success:
# Retry after a longer delay if first attempt failed
QtCore.QTimer.singleShot(100, lambda: self.apply_dark_title_bar(is_dark))
# Apply immediately and with delays to handle different timing scenarios # Also apply to any open dialogs immediately
apply_title_bar_theming() for dialog in QtWidgets.QApplication.allWidgets():
QtCore.QTimer.singleShot(50, apply_title_bar_theming) if isinstance(dialog, QtWidgets.QDialog) and dialog.isVisible():
QtCore.QTimer.singleShot(200, apply_title_bar_theming) try:
hwnd = int(dialog.winId())
if hwnd:
import ctypes
DWMWA_USE_IMMERSIVE_DARK_MODE = 20
DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19
# Try both API versions
for attribute in [DWMWA_USE_IMMERSIVE_DARK_MODE, DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1]:
try:
result = ctypes.windll.dwmapi.DwmSetWindowAttribute(
hwnd,
attribute,
ctypes.byref(ctypes.c_int(1 if is_dark else 0)),
ctypes.sizeof(ctypes.c_int)
)
if result == 0:
dialog.update()
dialog.repaint()
break
except:
continue
except:
pass
# Main window style # Main window style
main_style = f""" main_style = f"""
@@ -2234,13 +2275,17 @@ class MainWindow(QtWidgets.QMainWindow):
QComboBox::drop-down {{ QComboBox::drop-down {{
border: none; border: none;
width: 20px; width: 20px;
subcontrol-origin: padding;
subcontrol-position: center right;
}} }}
QComboBox::down-arrow {{ QComboBox::down-arrow {{
image: none; image: none;
border-left: 4px solid transparent; width: 0;
border-right: 4px solid transparent; height: 0;
border-top: 4px solid {colors['foreground']}; border-left: 5px solid transparent;
margin: 0px 4px 0px 4px; border-right: 5px solid transparent;
border-top: 6px solid {colors['foreground']};
margin: 0px;
}} }}
QListWidget {{ QListWidget {{
font-size: 9pt; font-size: 9pt;
@@ -2329,6 +2374,39 @@ class MainWindow(QtWidgets.QMainWindow):
is_dark = self.get_effective_dark_mode() is_dark = self.get_effective_dark_mode()
self.apply_dark_title_bar(is_dark) self.apply_dark_title_bar(is_dark)
# Also apply to any open dialogs immediately
for dialog in QtWidgets.QApplication.allWidgets():
if isinstance(dialog, QtWidgets.QDialog) and dialog.isVisible():
try:
hwnd = int(dialog.winId())
if hwnd:
import ctypes
DWMWA_USE_IMMERSIVE_DARK_MODE = 20
DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19
# Try both API versions
for attribute in [DWMWA_USE_IMMERSIVE_DARK_MODE, DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1]:
try:
result = ctypes.windll.dwmapi.DwmSetWindowAttribute(
hwnd,
attribute,
ctypes.byref(ctypes.c_int(1 if is_dark else 0)),
ctypes.sizeof(ctypes.c_int)
)
if result == 0:
dialog.update()
dialog.repaint()
break
except:
continue
except:
pass
# Force an immediate application repaint for instant visual feedback
QtWidgets.QApplication.processEvents()
self.update()
self.repaint()
# Save the theme preference immediately # Save the theme preference immediately
self._save_window_geometry() self._save_window_geometry()
@@ -2457,11 +2535,32 @@ class MainWindow(QtWidgets.QMainWindow):
self.theme_combo.setMinimumWidth(100) self.theme_combo.setMinimumWidth(100)
self.theme_combo.setMaximumWidth(120) self.theme_combo.setMaximumWidth(120)
self.theme_combo.setToolTip('Select theme: System (follows OS), Light, or Dark') self.theme_combo.setToolTip('Select theme: System (follows OS), Light, or Dark')
# Make the theme dropdown open upwards by setting a custom style
# This will be handled in the theme application
self.theme_combo.addItem('System', 'system') self.theme_combo.addItem('System', 'system')
self.theme_combo.addItem('Light', 'light') self.theme_combo.addItem('Light', 'light')
self.theme_combo.addItem('Dark', 'dark') self.theme_combo.addItem('Dark', 'dark')
self.theme_combo.setCurrentText('System') # Default to system self.theme_combo.setCurrentText('System') # Default to system
self.theme_combo.currentTextChanged.connect(self.on_theme_changed) self.theme_combo.currentTextChanged.connect(self.on_theme_changed)
# Make theme dropdown open upwards
def showPopupUpwards():
# Get the combo box position and size
combo_rect = self.theme_combo.geometry()
popup = self.theme_combo.view()
popup_height = popup.sizeHint().height()
# Calculate position above the combo box
global_pos = self.theme_combo.mapToGlobal(QtCore.QPoint(0, -popup_height))
# Show the popup at the calculated position
popup.setGeometry(global_pos.x(), global_pos.y(), combo_rect.width(), popup_height)
popup.show()
# Override the showPopup method to make it open upwards
self.theme_combo.showPopup = showPopupUpwards
# State label # State label
self.state_label = QtWidgets.QLabel('State: Paused') self.state_label = QtWidgets.QLabel('State: Paused')