Files

56 lines
4.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Windows Quake Mode: Focus and Sizing Fix — Tech Spec
Product spec: `specs/CODE-1787/PRODUCT.md`
## Context
Two independent bugs prevent quake mode from working correctly on Windows when triggered while a non-Warp application has foreground focus.
### Bug 1: focus not transferred
`WinitWindow::focus()` in `crates/warpui/src/windowing/winit/window.rs:1080` had two branches: if the window was already visible it called `focus_window()`, otherwise it called `set_visible(true)` and relied on visibility implying focus. On Windows, `set_visible(true)` does not steal foreground focus from another application — an explicit `SetForegroundWindow` (via winit's `focus_window()`) is required. The quake window was hidden via `set_visible(false)`, so re-showing it always took the `set_visible(true)` branch and never called `focus_window()`.
### Bug 2: incorrect window size
All Windows monitor queries in `crates/warpui/src/windowing/winit/window/windows_wm.rs` routed through `get_active_window_handle()`, which requires a focused + visible Warp window. When no Warp window has focus, this fails and `active_display_bounds()` falls back to a hardcoded `DEFAULT_WINDOW_SIZE` (1280×800). The quake window is then sized as a percentage of that default instead of the actual display dimensions.
### Relevant code
- `crates/warpui/src/windowing/winit/window.rs:1080-1092``WinitWindow::focus()`
- `crates/warpui/src/windowing/winit/window/windows_wm.rs` — all Windows monitor query methods
- `crates/warpui/src/windowing/winit/window.rs:222-227``WindowManager::show_window_and_focus_app` (calls `focus()`)
- `app/src/root_view.rs:1481-1507` — quake mode toggle, hidden→visible branch
## Proposed changes
### 1. Always call `focus_window()` in `WinitWindow::focus()`
Restructure `focus()` so `focus_window()` is called unconditionally after the window is made visible or un-minimized. The previous code only called it in the already-visible branch.
Before:
```
if visible → set_minimized(false); focus_window()
else → set_visible(true) // hoped this would also focus
```
After:
```
if visible → set_minimized(false)
else → set_visible(true)
focus_window() // always, regardless of prior visibility
```
This fixes Behavior 1 and 2.
### 2. Decouple monitor queries from active-window requirement
Split the Windows monitor methods into two categories:
**Global queries** (don't care which monitor): `get_primary_monitor_handle`, `get_available_monitors`, `get_available_monitor_count`. These only need *any* winit window handle to access platform APIs. Add `get_any_window_handle()` which returns the first available window regardless of focus, and call it directly from these methods.
**Active-monitor queries** (need to know which monitor the user is on): `get_active_monitor`, `get_current_monitor_id`, `get_active_monitor_logical_bounds`. When a Warp window has focus, use its `current_monitor()`. When no Warp window has focus, fall back to `get_foreground_monitor()`, which uses Win32 `GetForegroundWindow` + `MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST)` to find the monitor of the app that has keyboard focus. This is the window that triggered the global hotkey.
This fixes Behavior 3 and 4. The foreground-window approach is preferred over cursor position because the cursor may be on a different monitor than the window handling keypress events.
### 3. Add Win32 feature dependencies
Enable `Win32_Graphics_Gdi` (for `MonitorFromWindow`, `MONITOR_DEFAULTTONEAREST`) and `Win32_UI_WindowsAndMessaging` (for `GetForegroundWindow`) in `crates/warpui/Cargo.toml`.
## Testing and validation
- Manual: configure quake mode with 100% width, focus a non-Warp app, press the hotkey. Verify the quake window receives focus and spans the full display width. (Behavior 1, 3)
- Manual: with a Warp window focused, press the hotkey. Verify existing behavior is preserved. (Behavior 2)
- Manual (multi-monitor): focus an app on monitor B, press the hotkey. Verify the quake window appears on monitor B at the correct size. (Behavior 4)
- Manual: verify macOS quake mode is unaffected — changes are behind `#[cfg(windows)]` and winit-only code paths. (Behavior 6)