Restore custom title bar without native chrome

This commit is contained in:
lm 2025-10-19 18:38:13 +02:00
parent 183b769000
commit 8ed1acc32d
2 changed files with 20 additions and 61 deletions

View File

@ -5,7 +5,6 @@ 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
@ -87,6 +86,7 @@ class ICRAApp(
self._is_maximized = True
self.root.geometry(f"{screen_width}x{screen_height}+0+0")
self.root.configure(bg="#f2f2f7")
self.root.overrideredirect(True)
self._window_icon_ref = None
self._apply_window_icon()
self._init_window_chrome()
@ -144,70 +144,19 @@ class ICRAApp(
def _init_window_chrome(self) -> None:
"""Configure a borderless window while retaining a taskbar entry."""
try:
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)
self.root.bind("<Map>", self._restore_borderless)
self.root.after(0, self._restore_borderless)
self.root.after(0, self._ensure_taskbar_entry)
except Exception:
self.root.overrideredirect(True)
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, 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),
)
self.root.overrideredirect(True)
except Exception:
pass
def _restore_borderless(self, _event=None) -> None:
try:
self.root.overrideredirect(True)
self._ensure_taskbar_entry()
except Exception:
pass

View File

@ -566,7 +566,17 @@ class UIBuilderMixin:
def _minimize_window(self) -> None:
try:
self._remember_window_geometry()
if hasattr(self.root, "overrideredirect"):
try:
self.root.overrideredirect(False)
except Exception:
pass
self.root.iconify()
restorer = getattr(self, "_restore_borderless", None)
if callable(restorer):
self.root.after(120, restorer)
elif hasattr(self.root, "overrideredirect"):
self.root.after(120, lambda: self.root.overrideredirect(True)) # type: ignore[arg-type]
except Exception:
pass