From a9ff6713054ac00692844c6f264c35ca896a80a7 Mon Sep 17 00:00:00 2001 From: sekwah Date: Mon, 13 Nov 2023 19:45:54 +0000 Subject: [PATCH] fix(tauri): high dpi screen scaling --- app/tauri/build.rs | 2 +- app/tauri/src/commands.rs | 118 ++++++++++++++++++++++-------- app/tauri/src/global_shortcuts.rs | 25 ++++--- app/tauri/src/main.rs | 49 ++++++++++--- app/tauri/src/system_tray.rs | 26 ++++--- app/tauri/src/updater.rs | 68 ++++++++++++----- package.json | 3 +- yarn.lock | 8 +- 8 files changed, 208 insertions(+), 91 deletions(-) diff --git a/app/tauri/build.rs b/app/tauri/build.rs index 795b9b7c..d860e1e6 100644 --- a/app/tauri/build.rs +++ b/app/tauri/build.rs @@ -1,3 +1,3 @@ fn main() { - tauri_build::build() + tauri_build::build() } diff --git a/app/tauri/src/commands.rs b/app/tauri/src/commands.rs index 4344448e..fc5504e7 100644 --- a/app/tauri/src/commands.rs +++ b/app/tauri/src/commands.rs @@ -3,7 +3,7 @@ use std::sync::Mutex; // Learn more about Tauri commands at https://tauri.app/v1/guides/features/command -use tauri::{Builder, PhysicalSize, Runtime, Wry}; +use tauri::{Builder, LogicalSize, Runtime, Wry}; #[non_exhaustive] struct WindowSize; @@ -12,13 +12,20 @@ use crate::system_tray; use crate::updater; impl WindowSize { - // Not sure why, if its due to UI scaling or what though these values seem to size smaller than the same values on electron - pub const MIN: PhysicalSize = PhysicalSize { width : 420, height: 602}; - pub const COMPACT: PhysicalSize = PhysicalSize { width : 420, height: 80}; + pub const MIN: LogicalSize = LogicalSize { + width: 340, + height: 540, + }; + pub const COMPACT: LogicalSize = LogicalSize { + width: 340, + height: 60, + }; } -static ORIGINAL_SIZE: Mutex> = Mutex::new(WindowSize::MIN); +static ORIGINAL_SIZE: Mutex> = Mutex::new(WindowSize::MIN); + +static UNDECORATED_TITLE_SIZE: u32 = 40; static HAS_DECORATIONS: Mutex = Mutex::new(true); static IS_COMPACT: Mutex = Mutex::new(false); @@ -55,8 +62,16 @@ fn set_always_on_top(always_on_top: bool, window: tauri::Window) } #[tauri::command] -fn set_fullscreen_break(should_fullscreen: bool, always_on_top: bool, window: tauri::Window) { - println!("set_fullscreen_break! {} {}", should_fullscreen, always_on_top); +fn set_fullscreen_break( + should_fullscreen: bool, + always_on_top: bool, + window: tauri::Window, +) { + println!( + "set_fullscreen_break! {} {}", + should_fullscreen, always_on_top + ); + try_set_always_on_top(always_on_top, &window); if should_fullscreen { try_set_native_titlebar(true, &window); @@ -84,14 +99,15 @@ fn try_set_always_on_top(always_on_top: bool, window: &tauri::Window } } -fn try_set_min_size(size: Option>, window: &tauri::Window) { - match window.set_min_size(size) {//Some(size)) { +fn try_set_min_size(size: Option>, window: &tauri::Window) { + match window.set_min_size(size) { + //Some(size)) { Ok(_) => (), Err(e) => println!("There was a problem setting min size! {:?}", e), } } -fn try_set_size(size: PhysicalSize, window: &tauri::Window) { +fn try_set_size(size: LogicalSize, window: &tauri::Window) { match window.set_size(size) { Ok(_) => (), Err(e) => println!("There was a problem setting the window size! {:?}", e), @@ -103,27 +119,39 @@ fn try_set_resizeable(resizeable: bool, window: &tauri::Window) { println!("Window resizeable {:?}", resizeable); match window.set_resizable(resizeable) { Ok(_) => (), - Err(e) => println!("There was a problem making the window resizeable {:?}", e) + Err(e) => println!("There was a problem making the window resizeable {:?}", e), } } -// Atm resizeable seems to cause a problem where the size cannot be set smaller than a certain amount -// https://github.com/tauri-apps/tao/issues/561, just use resizeable until this is fixed. -fn set_window_fixed_size(size: PhysicalSize, window: &tauri::Window) { +fn set_window_fixed_size(size: LogicalSize, window: &tauri::Window) { let decorations = HAS_DECORATIONS.lock().unwrap(); - let new_height = size.height + (if *decorations { 0 } else { 34 }); - let new_size = PhysicalSize { width : size.width, height: new_height}; + + let new_height = size.height + + (if *decorations { + 0 + } else { + UNDECORATED_TITLE_SIZE + }); + + let new_size = LogicalSize { + width: size.width, + height: new_height, + }; + try_set_size(new_size, window); try_set_resizeable(false, window); } -fn set_window_resizeable(min_size: PhysicalSize, size: PhysicalSize, window: &tauri::Window) { +fn set_window_resizeable( + min_size: LogicalSize, + size: LogicalSize, + window: &tauri::Window, +) { try_set_resizeable(true, window); try_set_size(size, window); try_set_min_size(Some(min_size), window); } - #[tauri::command] fn set_compact_mode(compact_mode: bool, window: tauri::Window) { { @@ -134,11 +162,18 @@ fn set_compact_mode(compact_mode: bool, window: tauri::Window) { if compact_mode { { let mut size = ORIGINAL_SIZE.lock().unwrap(); - *size = window.outer_size().unwrap().clone(); + *size = window + .outer_size() + .unwrap() + .to_logical(window.scale_factor().unwrap()); } set_window_fixed_size(WindowSize::COMPACT, &window); } else { - set_window_resizeable(WindowSize::MIN, ORIGINAL_SIZE.lock().unwrap().clone(), &window); + set_window_resizeable( + WindowSize::MIN, + ORIGINAL_SIZE.lock().unwrap().clone(), + &window, + ); } } @@ -161,31 +196,52 @@ fn set_native_titlebar(use_native_titlebar: bool, window: tauri::Win try_set_native_titlebar(use_native_titlebar, &window); } -fn try_set_native_titlebar(use_native_titlebar: bool, window: &tauri::Window) { +pub fn try_set_native_titlebar(use_native_titlebar: bool, window: &tauri::Window) { match window.set_decorations(use_native_titlebar) { Ok(_) => (), - Err(e) => println!("There was a problem setting the window decorations! {:?}", e), + Err(e) => println!( + "There was a problem setting the window decorations! {:?}", + e + ), } println!("set_native_titlebar! {}", use_native_titlebar); -} + // Check DECORATIONS and IS_COMPACT + let decorated = HAS_DECORATIONS.lock().unwrap(); + let compact = IS_COMPACT.lock().unwrap(); + if !*decorated && *compact { + let size = LogicalSize { + width: WindowSize::COMPACT.width, + height: WindowSize::COMPACT.height + UNDECORATED_TITLE_SIZE, + }; + try_set_size(size, window); + } +} /** - * We could do this by passing the object into a custom function that adds the commands but I wanted - * to practice more with rust. Plus it makes the setup cleaner. +* We could do this by passing the object into a custom function that adds the commands but I wanted +* to practice more with rust. Plus it makes the setup cleaner. - * Switch to a function that takes and returns tauri::Builder or uses a reference if we need to - * switch it. - */ +* Switch to a function that takes and returns tauri::Builder or uses a reference if we need to +* switch it. +*/ pub trait PomatezCommands { fn register_pomatez_commands(self) -> tauri::Builder; } impl PomatezCommands for Builder { fn register_pomatez_commands(self) -> tauri::Builder { - self.invoke_handler(tauri::generate_handler![set_show, set_always_on_top, - set_fullscreen_break, set_compact_mode, set_ui_theme, set_native_titlebar, - system_tray::tray_icon_update, set_close, set_minimize, updater::check_for_updates, + self.invoke_handler(tauri::generate_handler![ + set_show, + set_always_on_top, + set_fullscreen_break, + set_compact_mode, + set_ui_theme, + set_native_titlebar, + system_tray::tray_icon_update, + set_close, + set_minimize, + updater::check_for_updates, updater::install_update ]) } diff --git a/app/tauri/src/global_shortcuts.rs b/app/tauri/src/global_shortcuts.rs index e4c0ac69..5b0feee0 100644 --- a/app/tauri/src/global_shortcuts.rs +++ b/app/tauri/src/global_shortcuts.rs @@ -1,11 +1,13 @@ use lazy_static::lazy_static; -use tauri::{Manager, AppHandle, App}; -use tauri_plugin_global_shortcut::{GlobalShortcutExt, Modifiers, Shortcut}; +use tauri::{App, AppHandle, Manager}; use tauri_plugin_global_shortcut::Code; +use tauri_plugin_global_shortcut::{GlobalShortcutExt, Modifiers, Shortcut}; lazy_static! { - static ref SHOW_SHORTCUT: Shortcut = Shortcut::new(Some(Modifiers::SHIFT | Modifiers::ALT), Code::KeyS); - static ref HIDE_SHORTCUT: Shortcut = Shortcut::new(Some(Modifiers::SHIFT | Modifiers::ALT), Code::KeyH); + static ref SHOW_SHORTCUT: Shortcut = + Shortcut::new(Some(Modifiers::SHIFT | Modifiers::ALT), Code::KeyS); + static ref HIDE_SHORTCUT: Shortcut = + Shortcut::new(Some(Modifiers::SHIFT | Modifiers::ALT), Code::KeyH); static ref REFRESH: Shortcut = Shortcut::new(None, Code::F5); } @@ -34,14 +36,12 @@ impl PomatezGlobalShortcutsSetup for App { } } } - key if HIDE_SHORTCUT.id() == key => { - match window.hide() { - Ok(_) => {} - Err(e) => { - println!("Failed to hide window: {:?}", e); - } + key if HIDE_SHORTCUT.id() == key => match window.hide() { + Ok(_) => {} + Err(e) => { + println!("Failed to hide window: {:?}", e); } - } + }, _ => println!("Shortcut pressed: {:?}", shortcut), } if shortcut.matches(Modifiers::ALT | Modifiers::SHIFT, Code::KeyH) { @@ -54,7 +54,8 @@ impl PomatezGlobalShortcutsSetup for App { } else { println!("Shortcut pressed: {:?}", shortcut); } - }).build() + }) + .build() }; let app_handle = self.handle(); diff --git a/app/tauri/src/main.rs b/app/tauri/src/main.rs index d8c81c24..14eb49d6 100644 --- a/app/tauri/src/main.rs +++ b/app/tauri/src/main.rs @@ -1,9 +1,8 @@ #![cfg_attr( -all(not(debug_assertions), target_os = "windows"), -windows_subsystem = "windows" + all(not(debug_assertions), target_os = "windows"), + windows_subsystem = "windows" )] -#[cfg(debug_assertions)] use tauri::{Manager}; use tauri::{RunEvent}; use tauri_plugin_autostart::MacosLauncher; @@ -11,21 +10,38 @@ use tauri_plugin_window; #[macro_use] mod commands; -mod system_tray; mod global_shortcuts; +mod system_tray; mod updater; +#[cfg(target_os = "macos")] +use crate::commands::try_set_native_titlebar; + use commands::PomatezCommands; +use global_shortcuts::{PomatezGlobalShortcutsRegister, PomatezGlobalShortcutsSetup}; use system_tray::PomatezTray; -use global_shortcuts::{PomatezGlobalShortcutsSetup, PomatezGlobalShortcutsRegister}; fn main() { - let app = tauri::Builder::default() - .plugin(tauri_plugin_autostart::init(MacosLauncher::LaunchAgent, None)) + let mut context = tauri::generate_context!(); + + let config = context.config_mut(); + + let mut app = tauri::Builder::default() + .plugin(tauri_plugin_autostart::init( + MacosLauncher::LaunchAgent, + None, + )) .plugin(tauri_plugin_window::init()) .plugin(tauri_plugin_shell::init()) - .plugin(tauri_plugin_notification::init()) - .plugin(tauri_plugin_updater::Builder::new().build()) + .plugin(tauri_plugin_notification::init()); + + + + if config.tauri.bundle.updater.active { + app = app.plugin(tauri_plugin_updater::Builder::new().build()); + } + + let app = app .register_pomatez_commands() .setup(|app| { #[cfg(desktop)] @@ -36,16 +52,25 @@ fn main() { Ok(()) }) - .build(tauri::generate_context!()) + .build(context) .expect("error while running tauri application"); + #[cfg(desktop)] app.run(|app_handle, e| match e { RunEvent::Ready => { - #[cfg(desktop)] app_handle.register_global_shortcuts(); + let window = app_handle.get_window("main").unwrap(); + + // There is a bug on mac where the size is not properly respected initially, though this seems to fix it. + #[cfg(target_os = "macos")] + { + try_set_native_titlebar(false, &window); + try_set_native_titlebar(true, &window); + } + #[cfg(debug_assertions)] - app_handle.get_window("main").unwrap().open_devtools(); + window.open_devtools(); println!("Pomatez is ready"); } diff --git a/app/tauri/src/system_tray.rs b/app/tauri/src/system_tray.rs index 026c13fa..bd86540f 100644 --- a/app/tauri/src/system_tray.rs +++ b/app/tauri/src/system_tray.rs @@ -1,14 +1,14 @@ use std::path::PathBuf; -use tauri::{App, Icon, Manager, Runtime}; +use tauri::path::BaseDirectory; use tauri::{ menu::{MenuBuilder, MenuItemBuilder}, tray::{ClickType, TrayIconBuilder}, }; -use tauri::path::BaseDirectory; +use tauri::{App, Icon, Manager, Runtime}; use base64; -use base64::Engine; use base64::engine::general_purpose; +use base64::Engine; #[tauri::command] pub fn tray_icon_update(data_url: String, window: tauri::Window) { @@ -33,7 +33,6 @@ pub fn tray_icon_update(data_url: String, window: tauri::Window) } } - /** * We could do this by passing the object into a custom function that adds the commands but I wanted * to practice more with rust. Plus it makes the setup cleaner. @@ -46,11 +45,10 @@ pub trait PomatezTray { } impl PomatezTray for App { - /* * The icon is updated after rendering on the frontend so that is handled in the commands file. * However the initial setup and behavior is handled here. - */ + */ fn set_pomatez_system_tray(&self) { println!("Setting system tray"); // Was defined in tauri.config.json to start in v1 @@ -58,10 +56,17 @@ impl PomatezTray for App { let show = MenuItemBuilder::with_id("show", "Show").build(self); let quit = MenuItemBuilder::with_id("quit", "Quit").build(self); - let menu = MenuBuilder::new(self).items(&[&show, &quit]).build().expect("failed to build menu"); + let menu = MenuBuilder::new(self) + .items(&[&show, &quit]) + .build() + .expect("failed to build menu"); - let icon_path = self.path().resolve::("icons/icon.png".into(), BaseDirectory::Resource) - .expect("failed to resolve icon path, this should not happen as it is an internal file"); + let icon_path = self + .path() + .resolve::("icons/icon.png".into(), BaseDirectory::Resource) + .expect( + "failed to resolve icon path, this should not happen as it is an internal file", + ); let _ = TrayIconBuilder::new() .menu(&menu) @@ -86,6 +91,7 @@ impl PomatezTray for App { } }) .icon(Icon::File(icon_path)) - .build(self).expect("failed to build tray icon"); + .build(self) + .expect("failed to build tray icon"); } } diff --git a/app/tauri/src/updater.rs b/app/tauri/src/updater.rs index cfc55c16..db94407e 100644 --- a/app/tauri/src/updater.rs +++ b/app/tauri/src/updater.rs @@ -1,5 +1,5 @@ +use serde::{Deserialize, Serialize}; use std::sync::Mutex; -use serde::{Serialize, Deserialize}; use tauri::{Manager, Runtime}; use tauri_plugin_updater::{Update, UpdaterExt}; use url::Url; @@ -21,21 +21,25 @@ struct Asset { #[derive(Serialize, Debug, Clone)] struct UpdateAvailable { version: String, - body: Option + body: Option, } #[tauri::command] pub fn check_for_updates(ignore_version: String, window: tauri::Window) { - let handle = window.app_handle().clone(); + if !handle.config().tauri.bundle.updater.active { + return; + } + println!("Current version: {}", handle.package_info().version); tauri::async_runtime::spawn(async move { println!("Searching for update file on github."); // Custom configure the updater. // If we use this endpoint even if the url changes e.g. org name change or project name change the updates should still follow. - let github_releases_endpoint = "https://api.github.com/repos/zidoro/pomatez/releases/latest"; + let github_releases_endpoint = + "https://api.github.com/repos/zidoro/pomatez/releases/latest"; let github_releases_endpoint = match Url::parse(github_releases_endpoint) { Ok(url) => url, Err(e) => { @@ -44,32 +48,45 @@ pub fn check_for_updates(ignore_version: String, window: tauri::Wind } }; let client = reqwest::Client::new(); - let req = client.get(github_releases_endpoint.clone()) + let req = client + .get(github_releases_endpoint.clone()) .header("Content-Type", "application/json") // If this is not set you will get a 403 forbidden error. .header("User-Agent", "pomatez"); let response = match req.send().await { Ok(response) => response, Err(e) => { - println!("Failed to send request: {:?}. Failed to check for updates", e); + println!( + "Failed to send request: {:?}. Failed to check for updates", + e + ); return; } }; if response.status() != reqwest::StatusCode::OK { - println!("Non OK status code: {:?}. Failed to check for updates", response.status()); + println!( + "Non OK status code: {:?}. Failed to check for updates", + response.status() + ); return; } let latest_release = match response.json::().await { Ok(latest_release) => latest_release, Err(e) => { - println!("Failed to parse response: {:?}. Failed to check for updates", e); + println!( + "Failed to parse response: {:?}. Failed to check for updates", + e + ); return; } }; // Find an asset named "tauri-release.json". - let tauri_release_asset = latest_release.assets.iter().find(|asset| asset.name == "tauri-updater.json"); + let tauri_release_asset = latest_release + .assets + .iter() + .find(|asset| asset.name == "tauri-updater.json"); // If we found the asset, set it as the updater endpoint. let tauri_release_asset = match tauri_release_asset { @@ -91,12 +108,17 @@ pub fn check_for_updates(ignore_version: String, window: tauri::Wind return; } }; - let updater_builder = match handle.updater_builder() - .endpoints(vec!(tauri_release_endpoint)) - .header("User-Agent", "pomatez") { + let updater_builder = match handle + .updater_builder() + .endpoints(vec![tauri_release_endpoint]) + .header("User-Agent", "pomatez") + { Ok(updater_builder) => updater_builder, Err(e) => { - println!("Failed to build updater builder: {:?}. Failed to check for updates", e); + println!( + "Failed to build updater builder: {:?}. Failed to check for updates", + e + ); return; } }; @@ -104,7 +126,10 @@ pub fn check_for_updates(ignore_version: String, window: tauri::Wind let updater = match updater_builder.build() { Ok(updater) => updater, Err(e) => { - println!("Failed to build updater: {:?}. Failed to check for updates", e); + println!( + "Failed to build updater: {:?}. Failed to check for updates", + e + ); return; } }; @@ -123,11 +148,14 @@ pub fn check_for_updates(ignore_version: String, window: tauri::Wind } UPDATE_INFO.lock().unwrap().replace(update.clone()); - match window.emit("UPDATE_AVAILABLE", Some(UpdateAvailable { - version: update.version, - body: update.body - })) { - Ok(_) => {}, + match window.emit( + "UPDATE_AVAILABLE", + Some(UpdateAvailable { + version: update.version, + body: update.body, + }), + ) { + Ok(_) => {} Err(e) => { println!("Failed to emit update available event: {:?}", e); } @@ -150,7 +178,7 @@ pub async fn install_update(_window: tauri::Window) { } }; - let install_response = update.download_and_install(|_,_| {}, || {}).await; + let install_response = update.download_and_install(|_, _| {}, || {}).await; if let Err(e) = install_response { println!("Failed to install update: {:?}", e); } else { diff --git a/package.json b/package.json index 6e74ccd2..3e6e8391 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,8 @@ "gen:tts": "lerna run gen:tts --stream", "format": "prettier --write .", "tauri": "tauri", - "tauri:dev": "tauri dev --config ./app/tauri/release.conf.json", + "tauri:dev": "tauri dev", + "tauri:dev-with-updater": "tauri dev --config ./app/tauri/release.conf.json", "tauri:updateversion": "node ./app/tauri/util/cargo-version-updater.js" }, "config": { diff --git a/yarn.lock b/yarn.lock index b4065434..8fd9a0aa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14930,10 +14930,10 @@ react-dom@^16.14.0: prop-types "^15.6.2" scheduler "^0.19.1" -react-error-overlay@^6.0.11: - version "6.0.11" - resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.11.tgz#92835de5841c5cf08ba00ddd2d677b6d17ff9adb" - integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg== +react-error-overlay@6.0.9, react-error-overlay@^6.0.11: + version "6.0.9" + resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a" + integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew== react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.6: version "16.13.1"