56 lines
4.1 KiB
Markdown
56 lines
4.1 KiB
Markdown
# 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)
|