wrap win32 usage in conditionals

This commit is contained in:
2026-03-13 13:29:13 -04:00
parent 87bd2ae11c
commit 9f8dd48a2e
2 changed files with 81 additions and 70 deletions

View File

@@ -29,8 +29,12 @@ from src import mcp_client
from src import markdown_helper
from src import bg_shader
import re
import win32gui
import win32con
if sys.platform == "win32":
import win32gui
import win32con
else:
win32gui = None
win32con = None
from pydantic import BaseModel
from imgui_bundle import imgui, hello_imgui, immapp, imgui_node_editor as ed
@@ -368,58 +372,59 @@ class App:
self.ai_status = f"error: {e}"
imgui.end_menu()
# Draw right-aligned window controls directly in the menu bar
try:
import ctypes
ctypes.pythonapi.PyCapsule_GetPointer.restype = ctypes.c_void_p
ctypes.pythonapi.PyCapsule_GetPointer.argtypes = [ctypes.py_object, ctypes.c_char_p]
hwnd_capsule = imgui.get_main_viewport().platform_handle_raw
hwnd = ctypes.pythonapi.PyCapsule_GetPointer(hwnd_capsule, b"nb_handle")
except Exception:
hwnd = 0
if hwnd:
btn_w = 40
display_w = imgui.get_io().display_size.x
right_x = display_w - (btn_w * 3)
# Drag area check using an explicit invisible button spanning the empty space
curr_x = imgui.get_cursor_pos_x()
drag_w = right_x - curr_x
if drag_w > 0:
# Use a small positive height to satisfy IM_ASSERT(size_arg.y != 0.0f)
# The menu bar naturally constrains the hit box height anyway.
imgui.invisible_button("##drag_area", (drag_w, 20.0))
if imgui.is_item_active() and imgui.is_mouse_dragging(0):
# CRITICAL: We must reset ImGui's mouse_down state BEFORE passing control to Windows.
# Otherwise, the Windows modal drag loop swallows the WM_LBUTTONUP event,
# and ImGui thinks the mouse is permanently held down, causing "sticky" dragging.
imgui.get_io().mouse_down[0] = False
win32gui.ReleaseCapture()
win32gui.SendMessage(hwnd, win32con.WM_NCLBUTTONDOWN, win32con.HTCAPTION, 0)
imgui.push_style_color(imgui.Col_.button, vec4(0, 0, 0, 0))
# Draw right-aligned window controls directly in the menu bar (Win32 only)
if sys.platform == "win32":
try:
is_max = win32gui.GetWindowPlacement(hwnd)[1] == win32con.SW_SHOWMAXIMIZED
import ctypes
ctypes.pythonapi.PyCapsule_GetPointer.restype = ctypes.c_void_p
ctypes.pythonapi.PyCapsule_GetPointer.argtypes = [ctypes.py_object, ctypes.c_char_p]
hwnd_capsule = imgui.get_main_viewport().platform_handle_raw
hwnd = ctypes.pythonapi.PyCapsule_GetPointer(hwnd_capsule, b"nb_handle")
except Exception:
is_max = False
imgui.set_cursor_pos_x(right_x)
if imgui.button("_", (btn_w, 0)):
win32gui.ShowWindow(hwnd, win32con.SW_MINIMIZE)
hwnd = 0
if hwnd:
btn_w = 40
display_w = imgui.get_io().display_size.x
right_x = display_w - (btn_w * 3)
imgui.set_cursor_pos_x(right_x + btn_w)
if imgui.button("[=]" if is_max else "[]", (btn_w, 0)):
win32gui.ShowWindow(hwnd, win32con.SW_RESTORE if is_max else win32con.SW_MAXIMIZE)
imgui.set_cursor_pos_x(right_x + btn_w * 2)
imgui.push_style_color(imgui.Col_.button_hovered, vec4(200, 50, 50, 255))
if imgui.button("X", (btn_w, 0)):
win32gui.PostMessage(hwnd, win32con.WM_CLOSE, 0, 0)
imgui.pop_style_color()
imgui.pop_style_color()
# Drag area check using an explicit invisible button spanning the empty space
curr_x = imgui.get_cursor_pos_x()
drag_w = right_x - curr_x
if drag_w > 0:
# Use a small positive height to satisfy IM_ASSERT(size_arg.y != 0.0f)
# The menu bar naturally constrains the hit box height anyway.
imgui.invisible_button("##drag_area", (drag_w, 20.0))
if imgui.is_item_active() and imgui.is_mouse_dragging(0):
# CRITICAL: We must reset ImGui's mouse_down state BEFORE passing control to Windows.
# Otherwise, the Windows modal drag loop swallows the WM_LBUTTONUP event,
# and ImGui thinks the mouse is permanently held down, causing "sticky" dragging.
imgui.get_io().mouse_down[0] = False
win32gui.ReleaseCapture()
win32gui.SendMessage(hwnd, win32con.WM_NCLBUTTONDOWN, win32con.HTCAPTION, 0)
imgui.push_style_color(imgui.Col_.button, vec4(0, 0, 0, 0))
try:
is_max = win32gui.GetWindowPlacement(hwnd)[1] == win32con.SW_SHOWMAXIMIZED
except Exception:
is_max = False
imgui.set_cursor_pos_x(right_x)
if imgui.button("_", (btn_w, 0)):
win32gui.ShowWindow(hwnd, win32con.SW_MINIMIZE)
imgui.set_cursor_pos_x(right_x + btn_w)
if imgui.button("[=]" if is_max else "[]", (btn_w, 0)):
win32gui.ShowWindow(hwnd, win32con.SW_RESTORE if is_max else win32con.SW_MAXIMIZE)
imgui.set_cursor_pos_x(right_x + btn_w * 2)
imgui.push_style_color(imgui.Col_.button_hovered, vec4(200, 50, 50, 255))
if imgui.button("X", (btn_w, 0)):
win32gui.PostMessage(hwnd, win32con.WM_CLOSE, 0, 0)
imgui.pop_style_color()
imgui.pop_style_color()
def _render_custom_title_bar(self) -> None:
# Obsolete, removed since it renders behind the full screen dock space.
@@ -4002,7 +4007,13 @@ def hello():
theme.load_from_config(self.config)
self.runner_params = hello_imgui.RunnerParams()
self.runner_params.app_window_params.window_title = "manual slop"
self.runner_params.app_window_params.borderless = True
if sys.platform == "win32":
self.runner_params.app_window_params.borderless = True
self.runner_params.app_window_params.borderless_closable = False
self.runner_params.app_window_params.borderless_movable = False
self.runner_params.app_window_params.borderless_resizable = True
self.runner_params.app_window_params.window_geometry.size = (1680, 1200)
self.runner_params.imgui_window_params.enable_viewports = getattr(self, "ui_multi_viewport", False)
self.runner_params.imgui_window_params.remember_theme = True