From fd8d5819b8be55ead5333478c69d31cf34a2a41b Mon Sep 17 00:00:00 2001 From: SteveLauC Date: Thu, 4 Sep 2025 11:24:47 +0800 Subject: [PATCH] refactor: ensure Coco won't take focus on macOS (#891) * refactor: ensure Coco won't take focus Or the Window Management extension won't work * bring back set_focus() on Win/Linux; doc code --- docs/content.en/docs/release-notes/_index.md | 1 + src-tauri/Cargo.lock | 28 +++++++++++++++----- src-tauri/Cargo.toml | 1 + src-tauri/src/lib.rs | 10 +++++++ src-tauri/src/setup/mac.rs | 21 ++++++++------- 5 files changed, 45 insertions(+), 16 deletions(-) diff --git a/docs/content.en/docs/release-notes/_index.md b/docs/content.en/docs/release-notes/_index.md index 69802190..265f9b6d 100644 --- a/docs/content.en/docs/release-notes/_index.md +++ b/docs/content.en/docs/release-notes/_index.md @@ -50,6 +50,7 @@ Information about release notes of Coco App is provided here. - refactor: index iOS apps and macOS apps that store icon in Assets.car #872 - refactor: accept both '-' and '\_' as locale str separator #876 - refactor: relax the file search conditions on macOS #883 +- refactor: ensure Coco won't take focus #891 ## 0.7.1 (2025-07-27) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 54530bb6..f960c90c 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -868,6 +868,7 @@ dependencies = [ "meval", "notify 5.2.0", "num2words", + "objc2-app-kit 0.3.1", "once_cell", "ordered-float", "pizza-common", @@ -930,7 +931,7 @@ dependencies = [ "block", "cocoa-foundation", "core-foundation 0.10.0", - "core-graphics", + "core-graphics 0.24.0", "foreign-types 0.5.0", "libc", "objc", @@ -1075,6 +1076,19 @@ dependencies = [ "libc", ] +[[package]] +name = "core-graphics" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" +dependencies = [ + "bitflags 2.9.0", + "core-foundation 0.10.0", + "core-graphics-types", + "foreign-types 0.5.0", + "libc", +] + [[package]] name = "core-graphics-types" version = "0.2.0" @@ -1479,7 +1493,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67fd9ae1736d6ebb2e472740fbee86fb2178b8d56feb98a6751411d4c95b7e72" dependencies = [ "cocoa", - "core-graphics", + "core-graphics 0.24.0", "dunce", "gdk", "gdkx11", @@ -1568,7 +1582,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cf6f550bbbdd5fe66f39d429cb2604bcdacbf00dca0f5bbe2e9306a0009b7c6" dependencies = [ "core-foundation 0.10.0", - "core-graphics", + "core-graphics 0.24.0", "foreign-types-shared 0.3.1", "libc", "log", @@ -5742,7 +5756,7 @@ checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08" dependencies = [ "bytemuck", "cfg_aliases", - "core-graphics", + "core-graphics 0.24.0", "foreign-types 0.5.0", "js-sys", "log", @@ -5989,7 +6003,7 @@ checksum = "1e59c1f38e657351a2e822eadf40d6a2ad4627b9c25557bc1180ec1b3295ef82" dependencies = [ "bitflags 2.9.0", "core-foundation 0.10.0", - "core-graphics", + "core-graphics 0.24.0", "crossbeam-channel", "dispatch", "dlopen2", @@ -6183,13 +6197,13 @@ dependencies = [ [[package]] name = "tauri-nspanel" version = "2.0.1" -source = "git+https://github.com/ahkohd/tauri-nspanel?branch=v2#d4b9df797959f8fa4701e8a20ff69d9605bb66e9" +source = "git+https://github.com/ahkohd/tauri-nspanel?branch=v2#18ffb9a201fbf6fedfaa382fd4b92315ea30ab1a" dependencies = [ "bitflags 2.9.0", "block", "cocoa", "core-foundation 0.10.0", - "core-graphics", + "core-graphics 0.25.0", "objc", "objc-foundation", "objc_id", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index edaecb34..61c31663 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -112,6 +112,7 @@ tauri-plugin-prevent-default = "1" [target."cfg(target_os = \"macos\")".dependencies] tauri-nspanel = { git = "https://github.com/ahkohd/tauri-nspanel", branch = "v2" } +objc2-app-kit = { version = "0.3.1", features = ["NSWindow"] } [target."cfg(target_os = \"linux\")".dependencies] diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 1bfb8d10..f5d2cc57 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -264,6 +264,16 @@ async fn show_coco(app_handle: AppHandle) { let _ = window.show(); let _ = window.unminimize(); + + // The Window Management (WM) extension (macOS-only) controls the + // frontmost window. Setting focus on macOS makes Coco the frontmost + // window, which means the WM extension would control Coco instead of other + // windows, which is not what we want. + // + // On Linux/Windows, however, setting focus is a necessity to ensure that + // users open Coco's window, then they can start typing, without needing + // to click on the window. + #[cfg(not(target_os = "macos"))] let _ = window.set_focus(); let _ = app_handle.emit("show-coco", ()); diff --git a/src-tauri/src/setup/mac.rs b/src-tauri/src/setup/mac.rs index 2a0293d8..0ce000ea 100644 --- a/src-tauri/src/setup/mac.rs +++ b/src-tauri/src/setup/mac.rs @@ -1,13 +1,10 @@ //! credits to: https://github.com/ayangweb/ayangweb-EcoPaste/blob/169323dbe6365ffe4abb64d867439ed2ea84c6d1/src-tauri/src/core/setup/mac.rs +use crate::common::MAIN_WINDOW_LABEL; +use objc2_app_kit::NSNonactivatingPanelMask; use tauri::{AppHandle, Emitter, EventTarget, WebviewWindow}; use tauri_nspanel::{WebviewWindowExt, cocoa::appkit::NSWindowCollectionBehavior, panel_delegate}; -use crate::common::MAIN_WINDOW_LABEL; - -#[allow(non_upper_case_globals)] -const NSWindowStyleMaskNonActivatingPanel: i32 = 1 << 7; - const WINDOW_FOCUS_EVENT: &str = "tauri://focus"; const WINDOW_BLUR_EVENT: &str = "tauri://blur"; const WINDOW_MOVED_EVENT: &str = "tauri://move"; @@ -22,11 +19,17 @@ pub fn platform( // Convert ns_window to ns_panel let panel = main_window.to_panel().unwrap(); - // Make the window above the dock - panel.set_level(20); - // Do not steal focus from other windows - panel.set_style_mask(NSWindowStyleMaskNonActivatingPanel); + // + // Cast is safe + panel.set_style_mask(NSNonactivatingPanelMask.0 as i32); + // Set its level to NSFloatingWindowLevel to ensure it appears in front of + // all normal-level windows + // + // NOTE: some Chinese input methods use a level between NSDockWindowLevel (20) + // and NSMainMenuWindowLevel (24), setting our level above NSDockWindowLevel + // would block their window + panel.set_floating_panel(true); // Open the window in the active workspace and full screen panel.set_collection_behaviour(