mirror of
https://github.com/infinilabs/coco-app.git
synced 2025-12-16 19:47:43 +01:00
fix: ensure app is always on top and visible on all workspaces (#127)
This commit is contained in:
52
src-tauri/Cargo.lock
generated
52
src-tauri/Cargo.lock
generated
@@ -625,11 +625,11 @@ dependencies = [
|
||||
"serde_json",
|
||||
"tauri",
|
||||
"tauri-build",
|
||||
"tauri-nspanel",
|
||||
"tauri-plugin-autostart",
|
||||
"tauri-plugin-deep-link",
|
||||
"tauri-plugin-global-shortcut",
|
||||
"tauri-plugin-http",
|
||||
"tauri-plugin-oauth",
|
||||
"tauri-plugin-shell",
|
||||
"tauri-plugin-single-instance",
|
||||
"tauri-plugin-store",
|
||||
@@ -2652,6 +2652,17 @@ dependencies = [
|
||||
"malloc_buf",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc-foundation"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
|
||||
dependencies = [
|
||||
"block",
|
||||
"objc",
|
||||
"objc_id",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc-sys"
|
||||
version = "0.3.5"
|
||||
@@ -2870,6 +2881,15 @@ dependencies = [
|
||||
"objc2-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc_id"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
|
||||
dependencies = [
|
||||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.5"
|
||||
@@ -4463,6 +4483,22 @@ dependencies = [
|
||||
"tauri-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-nspanel"
|
||||
version = "2.0.1"
|
||||
source = "git+https://github.com/ahkohd/tauri-nspanel?branch=v2#9b5deee48ccadc8e3f3b44c7e05ca1908a534034"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"block",
|
||||
"cocoa",
|
||||
"core-foundation 0.10.0",
|
||||
"core-graphics",
|
||||
"objc",
|
||||
"objc-foundation",
|
||||
"objc_id",
|
||||
"tauri",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin"
|
||||
version = "2.0.1"
|
||||
@@ -4572,20 +4608,6 @@ dependencies = [
|
||||
"urlpattern",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-oauth"
|
||||
version = "2.0.0"
|
||||
source = "git+https://github.com/FabianLars/tauri-plugin-oauth?branch=v2#daf24f3b3f34fd471f561750a7cc00dc9930850b"
|
||||
dependencies = [
|
||||
"httparse",
|
||||
"log",
|
||||
"serde",
|
||||
"tauri",
|
||||
"tauri-plugin",
|
||||
"thiserror 1.0.64",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-shell"
|
||||
version = "2.0.1"
|
||||
|
||||
@@ -27,8 +27,7 @@ tauri-plugin-http = "2"
|
||||
|
||||
tauri-plugin-websocket = "2"
|
||||
tauri-plugin-theme = "2.1.2"
|
||||
|
||||
tauri-plugin-oauth = { git = "https://github.com/FabianLars/tauri-plugin-oauth", branch = "v2" }
|
||||
tauri-nspanel = { git = "https://github.com/ahkohd/tauri-nspanel", branch = "v2" }
|
||||
tauri-plugin-deep-link = "2.0.0"
|
||||
tauri-plugin-single-instance = "2.0.0"
|
||||
tauri-plugin-store = "2.2.0"
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
|
||||
<key>NSPrefPaneIconLabel</key>
|
||||
<string>coco-ai</string>
|
||||
|
||||
<key>LSUIElement</key>
|
||||
<true/>
|
||||
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "default",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main", "chat", "settings"],
|
||||
"windows": [
|
||||
"main",
|
||||
"chat",
|
||||
"settings"
|
||||
],
|
||||
"permissions": [
|
||||
"core:default",
|
||||
"core:event:allow-emit",
|
||||
@@ -45,8 +49,7 @@
|
||||
"global-shortcut:allow-unregister",
|
||||
"global-shortcut:allow-unregister-all",
|
||||
"theme:default",
|
||||
"oauth:allow-start",
|
||||
"deep-link:allow-get-current",
|
||||
"deep-link:allow-get-current",
|
||||
"deep-link:default",
|
||||
"deep-link:allow-register",
|
||||
{
|
||||
@@ -57,9 +60,6 @@
|
||||
},
|
||||
{
|
||||
"url": "https://coco.infini.cloud"
|
||||
},
|
||||
{
|
||||
"url": "http://infini.tpddns.cn:27200"
|
||||
}
|
||||
],
|
||||
"deny": []
|
||||
|
||||
@@ -8,3 +8,6 @@ pub mod search;
|
||||
pub mod document;
|
||||
pub mod traits;
|
||||
pub mod register;
|
||||
|
||||
pub static MAIN_WINDOW_LABEL: &str = "main";
|
||||
pub static SETTINGS_WINDOW_LABEL: &str = "settings";
|
||||
@@ -6,8 +6,11 @@ mod util;
|
||||
mod local;
|
||||
mod search;
|
||||
|
||||
mod setup;
|
||||
|
||||
use crate::common::register::SearchSourceRegistry;
|
||||
use crate::common::traits::SearchSource;
|
||||
use crate::common::{MAIN_WINDOW_LABEL, SETTINGS_WINDOW_LABEL};
|
||||
use crate::server::search::CocoSearchSource;
|
||||
use crate::server::servers::{load_or_insert_default_server, load_servers_token};
|
||||
use autostart::{change_autostart, enable_autostart};
|
||||
@@ -19,15 +22,13 @@ use tauri::{AppHandle, Emitter, Listener, Manager, Runtime, WebviewWindow};
|
||||
use tauri_plugin_autostart::MacosLauncher;
|
||||
use tauri_plugin_deep_link::DeepLinkExt;
|
||||
use tokio::runtime::Runtime as RT;
|
||||
// Add this import
|
||||
// Add this import
|
||||
|
||||
/// Tauri store name
|
||||
pub(crate) const COCO_TAURI_STORE: &str = "coco_tauri_store";
|
||||
|
||||
#[tauri::command]
|
||||
fn change_window_height(handle: AppHandle, height: u32) {
|
||||
let window: WebviewWindow = handle.get_webview_window("main").unwrap();
|
||||
let window: WebviewWindow = handle.get_webview_window(MAIN_WINDOW_LABEL).unwrap();
|
||||
|
||||
let mut size = window.outer_size().unwrap();
|
||||
size.height = height;
|
||||
@@ -73,8 +74,7 @@ pub fn run() {
|
||||
let mut ctx = tauri::generate_context!();
|
||||
|
||||
tauri::Builder::default()
|
||||
// .plugin(tauri_nspanel::init())
|
||||
.plugin(tauri_plugin_oauth::init())
|
||||
.plugin(tauri_nspanel::init())
|
||||
.plugin(tauri_plugin_http::init())
|
||||
.plugin(tauri_plugin_shell::init())
|
||||
.plugin(tauri_plugin_autostart::init(
|
||||
@@ -153,6 +153,9 @@ pub fn run() {
|
||||
dbg!(event.urls());
|
||||
});
|
||||
|
||||
let main_window = app.get_webview_window(MAIN_WINDOW_LABEL).unwrap();
|
||||
let settings_window = app.get_webview_window(SETTINGS_WINDOW_LABEL).unwrap();
|
||||
setup::default(app, main_window.clone(), settings_window.clone());
|
||||
|
||||
Ok(())
|
||||
})
|
||||
@@ -226,7 +229,9 @@ pub async fn init<R: Runtime>(app_handle: &AppHandle<R>) {
|
||||
|
||||
#[tauri::command]
|
||||
fn hide_coco(app: tauri::AppHandle) {
|
||||
if let Some(window) = app.get_window("main") {
|
||||
dbg!("Hide Coco menu clicked!");
|
||||
|
||||
if let Some(window) = app.get_window(MAIN_WINDOW_LABEL) {
|
||||
match window.is_visible() {
|
||||
Ok(true) => {
|
||||
if let Err(err) = window.hide() {
|
||||
@@ -250,8 +255,10 @@ fn hide_coco(app: tauri::AppHandle) {
|
||||
fn handle_open_coco(app: &AppHandle) {
|
||||
// println!("Open Coco menu clicked!");
|
||||
|
||||
if let Some(window) = app.get_window("main") {
|
||||
if let Some(window) = app.get_window(MAIN_WINDOW_LABEL) {
|
||||
window.show().unwrap();
|
||||
window.set_visible_on_all_workspaces(true).unwrap();
|
||||
window.set_always_on_top(true).unwrap();
|
||||
window.set_focus().unwrap();
|
||||
} else {
|
||||
eprintln!("Failed to get main window.");
|
||||
@@ -261,7 +268,7 @@ fn handle_open_coco(app: &AppHandle) {
|
||||
fn handle_hide_coco(app: &AppHandle) {
|
||||
// println!("Hide Coco menu clicked!");
|
||||
|
||||
if let Some(window) = app.get_window("main") {
|
||||
if let Some(window) = app.get_window(MAIN_WINDOW_LABEL) {
|
||||
if let Err(err) = window.hide() {
|
||||
eprintln!("Failed to hide the window: {}", err);
|
||||
} else {
|
||||
|
||||
3
src-tauri/src/setup/linux.rs
Normal file
3
src-tauri/src/setup/linux.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
use tauri::{App, WebviewWindow};
|
||||
|
||||
pub fn platform(_app: &mut App, _main_window: WebviewWindow, _settings_window: WebviewWindow) {}
|
||||
58
src-tauri/src/setup/mac.rs
Normal file
58
src-tauri/src/setup/mac.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
//credits to: https://github.com/ayangweb/ayangweb-EcoPaste/blob/169323dbe6365ffe4abb64d867439ed2ea84c6d1/src-tauri/src/core/setup/mac.rs
|
||||
use tauri::{ActivationPolicy, App, Emitter, Manager, WebviewWindow};
|
||||
use tauri_nspanel::{
|
||||
cocoa::appkit::{NSMainMenuWindowLevel, NSWindowCollectionBehavior},
|
||||
panel_delegate, WebviewWindowExt,
|
||||
};
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
const NSWindowStyleMaskNonActivatingPanel: i32 = 1 << 7;
|
||||
#[allow(non_upper_case_globals)]
|
||||
const NSResizableWindowMask: i32 = 1 << 3;
|
||||
const MACOS_PANEL_FOCUS: &str = "macos-panel-focus";
|
||||
|
||||
pub fn platform(app: &mut App, main_window: WebviewWindow, _settings_window: WebviewWindow) {
|
||||
let app_handle = app.app_handle().clone();
|
||||
|
||||
app.set_activation_policy(ActivationPolicy::Accessory);
|
||||
|
||||
// Convert ns_window to ns_panel
|
||||
let panel = main_window.to_panel().unwrap();
|
||||
|
||||
// Make the window above the dock
|
||||
panel.set_level(NSMainMenuWindowLevel + 1);
|
||||
|
||||
// Do not steal focus from other windows and support resizing
|
||||
panel.set_style_mask(NSWindowStyleMaskNonActivatingPanel | NSResizableWindowMask);
|
||||
|
||||
// Share the window across all desktop spaces and full screen
|
||||
panel.set_collection_behaviour(
|
||||
NSWindowCollectionBehavior::NSWindowCollectionBehaviorCanJoinAllSpaces
|
||||
| NSWindowCollectionBehavior::NSWindowCollectionBehaviorStationary
|
||||
| NSWindowCollectionBehavior::NSWindowCollectionBehaviorFullScreenAuxiliary,
|
||||
);
|
||||
|
||||
// Define the panel's delegate to listen to panel window events
|
||||
let delegate = panel_delegate!(EcoPanelDelegate {
|
||||
window_did_become_key,
|
||||
window_did_resign_key
|
||||
});
|
||||
|
||||
// Set event listeners for the delegate
|
||||
delegate.set_listener(Box::new(move |delegate_name: String| {
|
||||
match delegate_name.as_str() {
|
||||
// Called when the window gains keyboard focus
|
||||
"window_did_become_key" => {
|
||||
app_handle.emit(MACOS_PANEL_FOCUS, true).unwrap();
|
||||
}
|
||||
// Called when the window loses keyboard focus
|
||||
"window_did_resign_key" => {
|
||||
app_handle.emit(MACOS_PANEL_FOCUS, false).unwrap();
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}));
|
||||
|
||||
// Set the delegate object for the window to handle window events
|
||||
panel.set_delegate(delegate);
|
||||
}
|
||||
25
src-tauri/src/setup/mod.rs
Normal file
25
src-tauri/src/setup/mod.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
use tauri::{App, WebviewWindow};
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
mod mac;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
mod win;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
mod linux;
|
||||
mod linux;
|
||||
mod windows;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub use mac::*;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use win::*;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub use linux::*;
|
||||
|
||||
pub fn default(app: &mut App, main_window: WebviewWindow, settings_window: WebviewWindow) {
|
||||
platform(app, main_window.clone(), settings_window.clone());
|
||||
}
|
||||
3
src-tauri/src/setup/windows.rs
Normal file
3
src-tauri/src/setup/windows.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
use tauri::{App, WebviewWindow};
|
||||
|
||||
pub fn platform(_app: &mut App, _main_window: WebviewWindow, _settings_window: WebviewWindow) {}
|
||||
@@ -108,6 +108,8 @@ fn _register_shortcut<R: Runtime>(app: &AppHandle<R>, shortcut: Shortcut) {
|
||||
main_window.hide().unwrap();
|
||||
} else {
|
||||
main_window.show().unwrap();
|
||||
main_window.set_visible_on_all_workspaces(true).unwrap();
|
||||
main_window.set_always_on_top(true).unwrap();
|
||||
main_window.set_focus().unwrap();
|
||||
}
|
||||
}
|
||||
@@ -117,19 +119,24 @@ fn _register_shortcut<R: Runtime>(app: &AppHandle<R>, shortcut: Shortcut) {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
use crate::common::MAIN_WINDOW_LABEL;
|
||||
|
||||
/// Helper function to register a shortcut, used to set up the shortcut up App's first start.
|
||||
fn _register_shortcut_upon_start(app: &App, shortcut: Shortcut) {
|
||||
let window = app.get_webview_window("main").unwrap();
|
||||
let window = app.get_webview_window(MAIN_WINDOW_LABEL).unwrap();
|
||||
app.handle()
|
||||
.plugin(
|
||||
tauri_plugin_global_shortcut::Builder::new()
|
||||
.with_handler(move |_app, scut, event| {
|
||||
.with_handler(move |app, scut, event| {
|
||||
if scut == &shortcut {
|
||||
if let ShortcutState::Pressed = event.state() {
|
||||
if window.is_visible().unwrap() {
|
||||
window.hide().unwrap();
|
||||
} else {
|
||||
dbg!("showing window");
|
||||
window.show().unwrap();
|
||||
window.set_visible_on_all_workspaces(true).unwrap();
|
||||
window.set_always_on_top(true).unwrap();
|
||||
window.set_focus().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"macOSPrivateApi": true,
|
||||
"windows": [
|
||||
{
|
||||
"label": "main",
|
||||
"title": "Coco AI",
|
||||
"url": "/ui",
|
||||
"height": 590,
|
||||
@@ -22,6 +23,8 @@
|
||||
"maximizable": false,
|
||||
"skipTaskbar": true,
|
||||
"resizable": false,
|
||||
"alwaysOnTop": false,
|
||||
"acceptFirstMouse": true,
|
||||
"shadow": true,
|
||||
"transparent": true,
|
||||
"fullscreen": false,
|
||||
@@ -30,6 +33,24 @@
|
||||
"effects": [],
|
||||
"radius": 12
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "settings",
|
||||
"url": "/ui/settings",
|
||||
"width": 1000,
|
||||
"height": 700,
|
||||
"center": true,
|
||||
"transparent": true,
|
||||
"maximizable": false,
|
||||
"skipTaskbar": false,
|
||||
"dragDropEnabled": true,
|
||||
"visible": false,
|
||||
"windowEffects": {
|
||||
"effects": [
|
||||
"sidebar"
|
||||
],
|
||||
"state": "active"
|
||||
}
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
@@ -75,11 +96,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"resources": ["assets", "icons"]
|
||||
"resources": [
|
||||
"assets",
|
||||
"icons"
|
||||
]
|
||||
},
|
||||
"plugins": {
|
||||
"features": {
|
||||
"protocol": ["all"]
|
||||
"protocol": [
|
||||
"all"
|
||||
]
|
||||
},
|
||||
"window": {},
|
||||
"websocket": {},
|
||||
@@ -88,11 +114,20 @@
|
||||
"deep-link": {
|
||||
"schema": "coco",
|
||||
"mobile": [
|
||||
{ "host": "app.infini.cloud", "pathPrefix": ["/open"] },
|
||||
{ "host": "localhost:9000" }
|
||||
{
|
||||
"host": "app.infini.cloud",
|
||||
"pathPrefix": [
|
||||
"/open"
|
||||
]
|
||||
},
|
||||
{
|
||||
"host": "localhost:9000"
|
||||
}
|
||||
],
|
||||
"desktop": {
|
||||
"schemes": ["coco"]
|
||||
"schemes": [
|
||||
"coco"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user