Revert "Restore native title bar with theme-aware styling"

This reverts commit 07d7679889.
This commit is contained in:
lm 2025-10-19 18:36:27 +02:00
parent 07d7679889
commit 183b769000
3 changed files with 54 additions and 64 deletions

View File

@ -5,6 +5,7 @@ from __future__ import annotations
import ctypes
import platform
import tkinter as tk
from ctypes import wintypes
from importlib import resources
from .gui import ColorPickerMixin, ExclusionMixin, ThemeMixin, UIBuilderMixin
@ -76,9 +77,6 @@ class ICRAApp(
self.bring_to_front()
def _setup_window(self) -> None:
system = platform.system()
self.use_native_titlebar = system == "Windows"
screen_width = self.root.winfo_screenwidth()
screen_height = self.root.winfo_screenheight()
default_width = int(screen_width * 0.8)
@ -86,15 +84,8 @@ class ICRAApp(
default_x = (screen_width - default_width) // 2
default_y = (screen_height - default_height) // 4
self._window_geometry = f"{default_width}x{default_height}+{default_x}+{default_y}"
if self.use_native_titlebar:
self._is_maximized = False
self.root.geometry(self._window_geometry)
self.root.after(0, lambda: self.root.state("zoomed"))
else:
self.root.overrideredirect(True)
self._is_maximized = True
self.root.geometry(f"{screen_width}x{screen_height}+0+0")
self._is_maximized = True
self.root.geometry(f"{screen_width}x{screen_height}+0+0")
self.root.configure(bg="#f2f2f7")
self._window_icon_ref = None
self._apply_window_icon()
@ -151,55 +142,72 @@ class ICRAApp(
self._window_icon_ref = None
def _init_window_chrome(self) -> None:
"""Configure window chrome based on platform."""
"""Configure a borderless window while retaining a taskbar entry."""
try:
if self.use_native_titlebar:
if platform.system() == "Windows":
self.root.after(0, self._ensure_taskbar_entry)
initial_mode = getattr(self, "theme", "light")
self.root.after(0, lambda: self._apply_os_titlebar_theme(initial_mode))
self.root.bind(
"<Map>",
lambda _e: self._apply_os_titlebar_theme(getattr(self, "theme", "light")),
add="+",
)
self.root.bind("<Map>", lambda _e: self._ensure_taskbar_entry(), add="+")
else:
self.root.bind("<Map>", self._restore_borderless)
self.root.after(0, self._restore_borderless)
system = platform.system()
if system == "Windows":
self.root.after(0, self._apply_windows_borderless_style)
self.root.after(0, self._ensure_taskbar_entry)
self.root.bind("<Map>", lambda _e: self._apply_windows_borderless_style(), add="+")
self.root.bind("<Map>", lambda _e: self._ensure_taskbar_entry(), add="+")
else:
self.root.overrideredirect(True)
except Exception:
self.root.overrideredirect(True)
def _restore_borderless(self, _event=None) -> None:
try:
self.root.overrideredirect(True)
except Exception:
pass
def _apply_os_titlebar_theme(self, mode: str | None = None) -> None:
def _apply_windows_borderless_style(self) -> None:
try:
if platform.system() != "Windows":
return
hwnd = self.root.winfo_id()
if not hwnd:
self.root.after(50, lambda: self._apply_os_titlebar_theme(mode))
self.root.after(50, self._apply_windows_borderless_style)
return
user32 = ctypes.windll.user32 # type: ignore[attr-defined]
GWL_STYLE = -16
WS_CAPTION = 0x00C00000
WS_THICKFRAME = 0x00040000
WS_BORDER = 0x00800000
SWP_NOSIZE = 0x0001
SWP_NOMOVE = 0x0002
SWP_NOZORDER = 0x0004
SWP_FRAMECHANGED = 0x0020
set_window_long = getattr(user32, "SetWindowLongPtrW", user32.SetWindowLongW)
get_window_long = getattr(user32, "GetWindowLongPtrW", user32.GetWindowLongW)
ptr_type = ctypes.c_longlong if ctypes.sizeof(ctypes.c_void_p) == 8 else ctypes.c_long
get_window_long.restype = ptr_type # type: ignore[attr-defined]
get_window_long.argtypes = [wintypes.HWND, ctypes.c_int] # type: ignore[attr-defined]
set_window_long.restype = ptr_type # type: ignore[attr-defined]
set_window_long.argtypes = [wintypes.HWND, ctypes.c_int, ptr_type] # type: ignore[attr-defined]
style = get_window_long(hwnd, GWL_STYLE)
new_style = style & ~(WS_CAPTION | WS_THICKFRAME | WS_BORDER)
if new_style != style:
set_window_long(hwnd, GWL_STYLE, ptr_type(new_style))
user32.SetWindowPos(
hwnd,
0,
0,
0,
0,
0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED,
)
try:
dwmapi = ctypes.windll.dwmapi # type: ignore[attr-defined]
DWMWA_USE_IMMERSIVE_DARK_MODE = 20
value = ctypes.c_int(1)
dwmapi.DwmSetWindowAttribute(
hwnd,
ctypes.c_uint(DWMWA_USE_IMMERSIVE_DARK_MODE),
ctypes.byref(value),
ctypes.sizeof(value),
)
except Exception:
return
attribute = ctypes.c_uint(20) # DWMWA_USE_IMMERSIVE_DARK_MODE
value = ctypes.c_int(1 if (mode or self.theme) == "dark" else 0)
dwmapi.DwmSetWindowAttribute(
hwnd,
attribute,
ctypes.byref(value),
ctypes.sizeof(value),
)
pass
except Exception:
pass

View File

@ -71,10 +71,6 @@ class ThemeMixin:
if callable(canvas_refresher):
canvas_refresher()
os_theme_hook = getattr(self, "_apply_os_titlebar_theme", None)
if callable(os_theme_hook):
os_theme_hook(self.theme)
def detect_system_theme(self) -> str:
"""Best-effort detection of the OS theme preference."""
try:

View File

@ -12,9 +12,7 @@ class UIBuilderMixin:
"""Constructs the Tkinter UI and common widgets."""
def setup_ui(self) -> None:
self._custom_titlebar = not getattr(self, "use_native_titlebar", False)
if self._custom_titlebar:
self._create_titlebar()
self._create_titlebar()
toolbar = ttk.Frame(self.root)
toolbar.pack(fill=tk.X, padx=12, pady=(4, 2))
@ -467,8 +465,6 @@ class UIBuilderMixin:
pass
def _start_window_drag(self, event) -> None:
if not getattr(self, "_custom_titlebar", True):
return
if getattr(self, "_is_maximized", False):
cursor_x, cursor_y = event.x_root, event.y_root
self._toggle_maximize_window(force_state=False)
@ -480,8 +476,6 @@ class UIBuilderMixin:
self._drag_offset = (event.x_root - self.root.winfo_rootx(), event.y_root - self.root.winfo_rooty())
def _perform_window_drag(self, event) -> None:
if not getattr(self, "_custom_titlebar", True):
return
offset = getattr(self, "_drag_offset", None)
if offset is None:
return
@ -531,8 +525,6 @@ class UIBuilderMixin:
return None
def _maximize_window(self) -> None:
if not getattr(self, "_custom_titlebar", True):
return
self._remember_window_geometry()
work_area = self._monitor_work_area()
if work_area is None:
@ -551,8 +543,6 @@ class UIBuilderMixin:
self._update_maximize_button()
def _restore_window(self) -> None:
if not getattr(self, "_custom_titlebar", True):
return
geometry = getattr(self, "_window_geometry", None)
if not geometry:
screen_width = self.root.winfo_screenwidth()
@ -567,8 +557,6 @@ class UIBuilderMixin:
self._update_maximize_button()
def _toggle_maximize_window(self, force_state: bool | None = None) -> None:
if not getattr(self, "_custom_titlebar", True):
return
desired = force_state if force_state is not None else not getattr(self, "_is_maximized", False)
if desired:
self._maximize_window()
@ -576,8 +564,6 @@ class UIBuilderMixin:
self._restore_window()
def _minimize_window(self) -> None:
if not getattr(self, "_custom_titlebar", True):
return
try:
self._remember_window_geometry()
self.root.iconify()