diff --git a/docs/superpowers/plans/2026-05-08-browserlay-mvp.md b/docs/superpowers/plans/2026-05-08-browserlay-mvp.md index 79909bf..cb7cacd 100644 --- a/docs/superpowers/plans/2026-05-08-browserlay-mvp.md +++ b/docs/superpowers/plans/2026-05-08-browserlay-mvp.md @@ -1883,8 +1883,9 @@ pub fn get_hotkey_status(app: AppHandle) -> Result Ok(guard.clone()) } -/// Set window opacity. Tauri 2's JS WebviewWindow does NOT expose setOpacity -/// (only the Rust side does), so the JS layer routes through this command. +/// Set window opacity. Tauri 2.11 does NOT expose set_opacity on either side +/// (open issue tauri-apps/tauri#3279), so we drop down to Win32 directly via +/// SetLayeredWindowAttributes. See `apply_window_opacity` for details. #[tauri::command] pub fn set_window_opacity( app: AppHandle, @@ -1894,10 +1895,12 @@ pub fn set_window_opacity( let Some(window) = app.get_webview_window(&label) else { return Err(format!("window not found: {label}")); }; - window.set_opacity(opacity).map_err(|e| e.to_string()) + apply_window_opacity(&window, opacity) } ``` +> **Window opacity implementation note:** Tauri 2.11.x's `WebviewWindow` doesn't expose `set_opacity` on either the JS or Rust side (long-running open issue tauri-apps/tauri#3279). To get true OS-level window translucency we drop down to the Win32 API directly. Pin `windows = "0.61"` in `Cargo.toml` to match Tauri's transitive `windows` version (otherwise `WebviewWindow::hwnd()` returns an HWND from a different `windows` major and you get a diamond-dependency type mismatch). The `apply_window_opacity` helper sets `WS_EX_LAYERED` if not already present, then calls `SetLayeredWindowAttributes(hwnd, 0, alpha, LWA_ALPHA)`. + > **Note on the design:** Tauri 2 doesn't expose a getter for `ignore_cursor_events` / `opacity` on `WebviewWindow`. Rather than rely on getters, we keep a tiny Rust-side cache (`AppState.click_through`) that the JS side keeps in sync via `sync_click_through_cache`. The global shortcut handler reads this cache, computes the inverse, calls `apply_state`. The JS-driven toggle path uses `toggle_click_through(current)` and skips the cache. - [ ] **Step 3: Commit**