mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-01-11 20:00:29 +01:00
Window title working again
This commit is contained in:
@@ -2216,6 +2216,13 @@
|
||||
"shell:allow-open"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:allow-spawn -> Enables the spawn command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:allow-spawn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:allow-stdin-write -> Enables the stdin_write command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -2244,6 +2251,13 @@
|
||||
"shell:deny-open"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:deny-spawn -> Denies the spawn command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:deny-spawn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:deny-stdin-write -> Denies the stdin_write command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -2498,6 +2512,69 @@
|
||||
"clipboard-manager:deny-write-text"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "deep-link:default -> Allows reading the opened deep link via the get_current command",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"deep-link:default"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "deep-link:allow-get-current -> Enables the get_current command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"deep-link:allow-get-current"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "deep-link:allow-is-registered -> Enables the is_registered command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"deep-link:allow-is-registered"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "deep-link:allow-register -> Enables the register command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"deep-link:allow-register"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "deep-link:allow-unregister -> Enables the unregister command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"deep-link:allow-unregister"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "deep-link:deny-get-current -> Denies the get_current command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"deep-link:deny-get-current"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "deep-link:deny-is-registered -> Denies the is_registered command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"deep-link:deny-is-registered"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "deep-link:deny-register -> Denies the register command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"deep-link:deny-register"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "deep-link:deny-unregister -> Denies the unregister command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"deep-link:deny-unregister"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
@@ -5323,6 +5400,13 @@
|
||||
"shell:allow-open"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:allow-spawn -> Enables the spawn command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:allow-spawn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:allow-stdin-write -> Enables the stdin_write command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -5351,6 +5435,13 @@
|
||||
"shell:deny-open"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:deny-spawn -> Denies the spawn command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:deny-spawn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:deny-stdin-write -> Denies the stdin_write command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -5533,6 +5624,13 @@
|
||||
"updater:allow-check"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "updater:allow-download -> Enables the download command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"updater:allow-download"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "updater:allow-download-and-install -> Enables the download_and_install command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -5540,6 +5638,13 @@
|
||||
"updater:allow-download-and-install"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "updater:allow-install -> Enables the install command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"updater:allow-install"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "updater:deny-check -> Denies the check command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -5547,6 +5652,13 @@
|
||||
"updater:deny-check"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "updater:deny-download -> Denies the download command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"updater:deny-download"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "updater:deny-download-and-install -> Denies the download_and_install command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -5554,6 +5666,13 @@
|
||||
"updater:deny-download-and-install"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "updater:deny-install -> Denies the install command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"updater:deny-install"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "webview:default -> Default permissions for the plugin.",
|
||||
"type": "string",
|
||||
@@ -5897,6 +6016,13 @@
|
||||
"window:allow-minimize"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "window:allow-monitor-from-point -> Enables the monitor_from_point command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"window:allow-monitor-from-point"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "window:allow-outer-position -> Enables the outer_position command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -6331,6 +6457,13 @@
|
||||
"window:deny-minimize"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "window:deny-monitor-from-point -> Denies the monitor_from_point command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"window:deny-monitor-from-point"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "window:deny-outer-position -> Denies the outer_position command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
||||
@@ -69,7 +69,10 @@ mod plugin;
|
||||
mod render;
|
||||
mod updates;
|
||||
mod window_menu;
|
||||
mod tauri_plugin_traffic_light;
|
||||
#[cfg(target_os = "macos")]
|
||||
mod tauri_plugin_mac_window;
|
||||
#[cfg(target_os = "windows")]
|
||||
mod tauri_plugin_windows_window;
|
||||
|
||||
async fn migrate_db(app_handle: &AppHandle, db: &Mutex<Pool<Sqlite>>) -> Result<(), String> {
|
||||
let pool = &*db.lock().await;
|
||||
@@ -1533,41 +1536,49 @@ async fn cmd_check_for_updates(
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
tauri::Builder::default()
|
||||
let mut builder = tauri::Builder::default()
|
||||
.plugin(tauri_plugin_clipboard_manager::init())
|
||||
.plugin(tauri_plugin_window_state::Builder::default().with_denylist(&["settings"]).build())
|
||||
.plugin(tauri_plugin_window_state::Builder::default().build())
|
||||
.plugin(tauri_plugin_shell::init())
|
||||
.plugin(tauri_plugin_updater::Builder::new().build())
|
||||
.plugin(tauri_plugin_dialog::init())
|
||||
.plugin(tauri_plugin_os::init())
|
||||
.plugin(tauri_plugin_fs::init())
|
||||
.plugin(tauri_plugin_traffic_light::init())
|
||||
.plugin(
|
||||
tauri_plugin_log::Builder::default()
|
||||
.targets([
|
||||
Target::new(TargetKind::Stdout),
|
||||
Target::new(TargetKind::LogDir { file_name: None }),
|
||||
Target::new(TargetKind::Webview),
|
||||
])
|
||||
.level_for("cookie_store", log::LevelFilter::Info)
|
||||
.level_for("h2", log::LevelFilter::Info)
|
||||
.level_for("hyper", log::LevelFilter::Info)
|
||||
.level_for("hyper_rustls", log::LevelFilter::Info)
|
||||
.level_for("reqwest", log::LevelFilter::Info)
|
||||
.level_for("sqlx", log::LevelFilter::Warn)
|
||||
.level_for("tao", log::LevelFilter::Info)
|
||||
.level_for("tokio_util", log::LevelFilter::Info)
|
||||
.level_for("tonic", log::LevelFilter::Info)
|
||||
.level_for("tower", log::LevelFilter::Info)
|
||||
.level_for("tracing", log::LevelFilter::Info)
|
||||
.with_colors(ColoredLevelConfig::default())
|
||||
.level(if is_dev() {
|
||||
log::LevelFilter::Trace
|
||||
} else {
|
||||
log::LevelFilter::Info
|
||||
})
|
||||
.build(),
|
||||
)
|
||||
.plugin(tauri_plugin_fs::init());
|
||||
|
||||
#[cfg(target_os = "windows")] {
|
||||
builder = builder.plugin(tauri_plugin_windows_window::init());
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")] {
|
||||
builder = builder.plugin(tauri_plugin_mac_window::init());
|
||||
}
|
||||
|
||||
builder.plugin(
|
||||
tauri_plugin_log::Builder::default()
|
||||
.targets([
|
||||
Target::new(TargetKind::Stdout),
|
||||
Target::new(TargetKind::LogDir { file_name: None }),
|
||||
Target::new(TargetKind::Webview),
|
||||
])
|
||||
.level_for("cookie_store", log::LevelFilter::Info)
|
||||
.level_for("h2", log::LevelFilter::Info)
|
||||
.level_for("hyper", log::LevelFilter::Info)
|
||||
.level_for("hyper_rustls", log::LevelFilter::Info)
|
||||
.level_for("reqwest", log::LevelFilter::Info)
|
||||
.level_for("sqlx", log::LevelFilter::Warn)
|
||||
.level_for("tao", log::LevelFilter::Info)
|
||||
.level_for("tokio_util", log::LevelFilter::Info)
|
||||
.level_for("tonic", log::LevelFilter::Info)
|
||||
.level_for("tower", log::LevelFilter::Info)
|
||||
.level_for("tracing", log::LevelFilter::Info)
|
||||
.with_colors(ColoredLevelConfig::default())
|
||||
.level(if is_dev() {
|
||||
log::LevelFilter::Trace
|
||||
} else {
|
||||
log::LevelFilter::Info
|
||||
})
|
||||
.build(),
|
||||
)
|
||||
.setup(|app| {
|
||||
let app_data_dir = app.path().app_data_dir().unwrap();
|
||||
let app_config_dir = app.path().app_config_dir().unwrap();
|
||||
@@ -1744,10 +1755,9 @@ fn is_dev() -> bool {
|
||||
|
||||
fn create_nested_window(window: &WebviewWindow, label: &str, url: &str, title: &str) -> WebviewWindow {
|
||||
info!("Create new nested window label={label}");
|
||||
let pos = window.outer_position().unwrap();
|
||||
let mut win_builder = tauri::WebviewWindowBuilder::new(
|
||||
window,
|
||||
label,
|
||||
format!("nested_{}_{}", window.label(), label),
|
||||
WebviewUrl::App(url.into()),
|
||||
)
|
||||
.resizable(true)
|
||||
@@ -1756,14 +1766,7 @@ fn create_nested_window(window: &WebviewWindow, label: &str, url: &str, title: &
|
||||
.title(title)
|
||||
.parent(&window)
|
||||
.unwrap()
|
||||
.position(
|
||||
(pos.x + 20) as f64,
|
||||
(pos.y + 20) as f64,
|
||||
)
|
||||
.inner_size(
|
||||
500.0f64,
|
||||
300.0f64,
|
||||
);
|
||||
.inner_size(700.0f64, 600.0f64);
|
||||
|
||||
// Add macOS-only things
|
||||
#[cfg(target_os = "macos")]
|
||||
@@ -1827,7 +1830,7 @@ fn create_window(handle: &AppHandle, url: &str) -> WebviewWindow {
|
||||
handle.set_menu(menu).expect("Failed to set app menu");
|
||||
|
||||
let window_num = handle.webview_windows().len();
|
||||
let label = format!("wnd_{}", window_num);
|
||||
let label = format!("main_{}", window_num);
|
||||
info!("Create new window label={label}");
|
||||
let mut win_builder = tauri::WebviewWindowBuilder::new(
|
||||
handle,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use hex_color::HexColor;
|
||||
use objc::{msg_send, sel, sel_impl};
|
||||
use rand::{distributions::Alphanumeric, Rng};
|
||||
use tauri::{Manager, plugin::{Builder, TauriPlugin}, Runtime, Window};
|
||||
@@ -6,23 +7,108 @@ const WINDOW_CONTROL_PAD_X: f64 = 13.0;
|
||||
const WINDOW_CONTROL_PAD_Y: f64 = 18.0;
|
||||
|
||||
struct UnsafeWindowHandle(*mut std::ffi::c_void);
|
||||
|
||||
unsafe impl Send for UnsafeWindowHandle {}
|
||||
|
||||
unsafe impl Sync for UnsafeWindowHandle {}
|
||||
|
||||
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
Builder::new("traffic_light_positioner")
|
||||
Builder::new("mac_window")
|
||||
.on_window_ready(|window| {
|
||||
#[cfg(target_os = "macos")]
|
||||
setup_traffic_light_positioner(window);
|
||||
#[cfg(target_os = "macos")] {
|
||||
setup_traffic_light_positioner(&window);
|
||||
let h = window.app_handle();
|
||||
|
||||
let window_for_theme = window.clone();
|
||||
h.listen("yaak_bg_changed", move |ev| {
|
||||
let payload = serde_json::from_str::<&str>(ev.payload())
|
||||
.unwrap()
|
||||
.trim();
|
||||
let color = HexColor::parse_rgb(payload).unwrap();
|
||||
update_window_theme(window_for_theme.clone(), color);
|
||||
});
|
||||
|
||||
let window_for_title = window.clone();
|
||||
h.listen("yaak_title_changed", move |ev| {
|
||||
let payload = serde_json::from_str::<&str>(ev.payload())
|
||||
.unwrap()
|
||||
.trim();
|
||||
update_window_title(window_for_title.clone(), payload.to_string());
|
||||
});
|
||||
}
|
||||
return;
|
||||
})
|
||||
.build()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn position_traffic_lights(ns_window_handle: UnsafeWindowHandle, x: f64, y: f64) {
|
||||
fn update_window_title<R: Runtime>(window: Window<R>, title: String) {
|
||||
use cocoa::{
|
||||
appkit::NSWindow,
|
||||
base::nil,
|
||||
foundation::NSString,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let window_handle = UnsafeWindowHandle(window.ns_window().unwrap());
|
||||
|
||||
let window2 = window.clone();
|
||||
let label = window.label().to_string();
|
||||
let _ = window.run_on_main_thread(move || {
|
||||
let win_title = NSString::alloc(nil).init_str(&title);
|
||||
let handle = window_handle;
|
||||
NSWindow::setTitle_(handle.0 as cocoa::base::id, win_title);
|
||||
position_traffic_lights(
|
||||
UnsafeWindowHandle(window2.ns_window().expect("Failed to create window handle")),
|
||||
WINDOW_CONTROL_PAD_X,
|
||||
WINDOW_CONTROL_PAD_Y,
|
||||
label,
|
||||
);
|
||||
});
|
||||
}}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn update_window_theme<R: Runtime>(window: Window<R>, color: HexColor) {
|
||||
use cocoa::appkit::{
|
||||
NSAppearance, NSAppearanceNameVibrantDark, NSAppearanceNameVibrantLight, NSWindow,
|
||||
};
|
||||
|
||||
let brightness = (color.r as u64 + color.g as u64 + color.b as u64) / 3;
|
||||
let label = window.label().to_string();
|
||||
|
||||
unsafe {
|
||||
let window_handle = UnsafeWindowHandle(window.ns_window().unwrap());
|
||||
|
||||
let window2 = window.clone();
|
||||
let _ = window.run_on_main_thread(move || {
|
||||
let handle = window_handle;
|
||||
|
||||
let selected_appearance = if brightness >= 128 {
|
||||
NSAppearance(NSAppearanceNameVibrantLight)
|
||||
} else {
|
||||
NSAppearance(NSAppearanceNameVibrantDark)
|
||||
};
|
||||
|
||||
NSWindow::setAppearance(handle.0 as cocoa::base::id, selected_appearance);
|
||||
position_traffic_lights(
|
||||
UnsafeWindowHandle(window2.ns_window().expect("Failed to create window handle")),
|
||||
WINDOW_CONTROL_PAD_X,
|
||||
WINDOW_CONTROL_PAD_Y,
|
||||
label,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn position_traffic_lights(ns_window_handle: UnsafeWindowHandle, x: f64, y: f64, label: String) {
|
||||
if label.starts_with("nested_") {
|
||||
return;
|
||||
}
|
||||
|
||||
use cocoa::appkit::{NSView, NSWindow, NSWindowButton};
|
||||
use cocoa::foundation::NSRect;
|
||||
|
||||
let ns_window = ns_window_handle.0 as cocoa::base::id;
|
||||
unsafe {
|
||||
let close = ns_window.standardWindowButton_(NSWindowButton::NSWindowCloseButton);
|
||||
@@ -59,7 +145,7 @@ struct WindowState<R: Runtime> {
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn setup_traffic_light_positioner<R: Runtime>(window: Window<R>) {
|
||||
pub fn setup_traffic_light_positioner<R: Runtime>(window: &Window<R>) {
|
||||
use cocoa::delegate;
|
||||
use cocoa::appkit::NSWindow;
|
||||
use cocoa::base::{BOOL, id};
|
||||
@@ -67,11 +153,11 @@ pub fn setup_traffic_light_positioner<R: Runtime>(window: Window<R>) {
|
||||
use objc::runtime::{Object, Sel};
|
||||
use std::ffi::c_void;
|
||||
|
||||
// Do the initial positioning
|
||||
position_traffic_lights(
|
||||
UnsafeWindowHandle(window.ns_window().expect("Failed to create window handle")),
|
||||
WINDOW_CONTROL_PAD_X,
|
||||
WINDOW_CONTROL_PAD_Y,
|
||||
window.label().to_string(),
|
||||
);
|
||||
|
||||
// Ensure they stay in place while resizing the window.
|
||||
@@ -86,6 +172,7 @@ pub fn setup_traffic_light_positioner<R: Runtime>(window: Window<R>) {
|
||||
func(ptr);
|
||||
}
|
||||
|
||||
|
||||
unsafe {
|
||||
let ns_win = window
|
||||
.ns_window()
|
||||
@@ -115,11 +202,11 @@ pub fn setup_traffic_light_positioner<R: Runtime>(window: Window<R>) {
|
||||
.expect("NS window should exist on state to handle resize")
|
||||
as id;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
position_traffic_lights(
|
||||
UnsafeWindowHandle(id as *mut std::ffi::c_void),
|
||||
UnsafeWindowHandle(id as *mut c_void),
|
||||
WINDOW_CONTROL_PAD_X,
|
||||
WINDOW_CONTROL_PAD_Y,
|
||||
state.window.label().to_string(),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -248,9 +335,10 @@ pub fn setup_traffic_light_positioner<R: Runtime>(window: Window<R>) {
|
||||
|
||||
let id = state.window.ns_window().expect("Failed to emit event") as id;
|
||||
position_traffic_lights(
|
||||
UnsafeWindowHandle(id as *mut std::ffi::c_void),
|
||||
UnsafeWindowHandle(id as *mut c_void),
|
||||
WINDOW_CONTROL_PAD_X,
|
||||
WINDOW_CONTROL_PAD_Y,
|
||||
state.window.label().to_string(),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -309,10 +397,10 @@ pub fn setup_traffic_light_positioner<R: Runtime>(window: Window<R>) {
|
||||
}
|
||||
}
|
||||
|
||||
// Are we deallocing this properly ? (I miss safe Rust :( )
|
||||
// Are we de-allocing this properly ? (I miss safe Rust :( )
|
||||
let window_label = window.label().to_string();
|
||||
|
||||
let app_state = WindowState { window };
|
||||
let app_state = WindowState { window: window.clone() };
|
||||
let app_box = Box::into_raw(Box::new(app_state)) as *mut c_void;
|
||||
let random_str: String = rand::thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
89
src-tauri/src/tauri_plugin_windows_window.rs
Normal file
89
src-tauri/src/tauri_plugin_windows_window.rs
Normal file
@@ -0,0 +1,89 @@
|
||||
use hex_color::HexColor;
|
||||
use tauri::{ Runtime, Window};
|
||||
|
||||
use std::mem::transmute;
|
||||
use std::{ptr, ffi::c_void, mem::size_of};
|
||||
use tauri::plugin::{Builder, TauriPlugin};
|
||||
|
||||
use windows::Win32::UI::Controls::{WTA_NONCLIENT, WTNCA_NODRAWICON, WTNCA_NOSYSMENU, WTNCA_NOMIRRORHELP};
|
||||
|
||||
use windows::Win32::UI::Controls::SetWindowThemeAttribute;
|
||||
use windows::Win32::UI::Controls::WTNCA_NODRAWCAPTION;
|
||||
use windows::Win32::Graphics::Dwm::DWMWA_CAPTION_COLOR;
|
||||
use windows::Win32::Foundation::COLORREF;
|
||||
use windows::Win32::Foundation::BOOL;
|
||||
use windows::Win32::Graphics::Dwm::DwmSetWindowAttribute;
|
||||
use windows::Win32::Foundation::HWND;
|
||||
use windows::Win32::Graphics::Dwm::{DWMWA_USE_IMMERSIVE_DARK_MODE};
|
||||
|
||||
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
Builder::new("windows_window")
|
||||
.on_window_ready(|window| {
|
||||
#[cfg(target_os = "windows")]
|
||||
setup_win_window(window);
|
||||
return;
|
||||
})
|
||||
.build()
|
||||
}
|
||||
|
||||
fn hex_color_to_colorref(color: HexColor) -> COLORREF {
|
||||
// TODO: Remove this unsafe, This operation doesn't need to be unsafe!
|
||||
unsafe {
|
||||
COLORREF(transmute::<[u8; 4], u32>([color.r, color.g, color.b, 0]))
|
||||
}
|
||||
}
|
||||
|
||||
struct WinThemeAttribute {
|
||||
flag: u32,
|
||||
mask: u32
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn update_bg_color(hwnd: &HWND, bg_color: HexColor) {
|
||||
|
||||
let use_dark_mode = BOOL::from(true);
|
||||
|
||||
let final_color = hex_color_to_colorref(bg_color);
|
||||
|
||||
unsafe {
|
||||
DwmSetWindowAttribute(
|
||||
HWND(hwnd.0),
|
||||
DWMWA_USE_IMMERSIVE_DARK_MODE,
|
||||
ptr::addr_of!(use_dark_mode) as *const c_void,
|
||||
size_of::<BOOL>().try_into().unwrap()
|
||||
).unwrap();
|
||||
|
||||
DwmSetWindowAttribute(
|
||||
HWND(hwnd.0),
|
||||
DWMWA_CAPTION_COLOR,
|
||||
ptr::addr_of!(final_color) as *const c_void,
|
||||
size_of::<COLORREF>().try_into().unwrap()
|
||||
).unwrap();
|
||||
|
||||
let flags = WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON;
|
||||
let mask = WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON | WTNCA_NOSYSMENU | WTNCA_NOMIRRORHELP;
|
||||
let options = WinThemeAttribute { flag: flags, mask };
|
||||
|
||||
SetWindowThemeAttribute(
|
||||
HWND(hwnd.0),
|
||||
WTA_NONCLIENT,
|
||||
ptr::addr_of!(options) as *const c_void,
|
||||
size_of::<WinThemeAttribute>().try_into().unwrap()
|
||||
).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn setup_win_window<R: Runtime>(window: Window<R>) {
|
||||
let win_handle = window.hwnd().unwrap();
|
||||
let win_clone = win_handle.clone();
|
||||
|
||||
window.listen_global("yaak_bg_changed", move |ev| {
|
||||
let payload = serde_json::from_str::<&str>(ev.payload().unwrap())
|
||||
.unwrap()
|
||||
.trim();
|
||||
|
||||
let color = HexColor::parse_rgb(payload).unwrap();
|
||||
update_bg_color(&HWND(win_clone.0), color);
|
||||
});
|
||||
}
|
||||
@@ -32,7 +32,7 @@ export const SettingsDialog = ({ fullscreen }: Props) => {
|
||||
{fullscreen && (
|
||||
<div
|
||||
data-tauri-drag-region
|
||||
className="h-[38px] bg-background-highlight-secondary flex items-center justify-center border-b border-background-highlight"
|
||||
className="h-[27px] bg-background-highlight-secondary flex items-center justify-center border-b border-background-highlight"
|
||||
>
|
||||
Settings
|
||||
</div>
|
||||
|
||||
@@ -14,7 +14,6 @@ import { Icon } from './core/Icon';
|
||||
import { IconButton } from './core/IconButton';
|
||||
import { useDialog } from './DialogContext';
|
||||
import { KeyboardShortcutsDialog } from './KeyboardShortcutsDialog';
|
||||
import { SettingsDialog } from './Settings/SettingsDialog';
|
||||
|
||||
export function SettingsDropdown() {
|
||||
const importData = useImportData();
|
||||
@@ -26,13 +25,12 @@ export function SettingsDropdown() {
|
||||
const routes = useAppRoutes();
|
||||
const workspaceId = useActiveWorkspaceId();
|
||||
|
||||
const showSettings = () => {
|
||||
dialog.show({
|
||||
id: 'settings',
|
||||
size: 'dynamic',
|
||||
noScroll: true,
|
||||
noPadding: true,
|
||||
render: () => <SettingsDialog />,
|
||||
const showSettings = async () => {
|
||||
if (!workspaceId) return;
|
||||
await invoke('cmd_new_nested_window', {
|
||||
url: routes.paths.workspaceSettings({ workspaceId }),
|
||||
label: 'settings',
|
||||
title: 'Yaak Settings',
|
||||
});
|
||||
};
|
||||
|
||||
@@ -63,20 +61,6 @@ export function SettingsDropdown() {
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'foo',
|
||||
label: 'Foo',
|
||||
hotKeyAction: 'hotkeys.showHelp',
|
||||
leftSlot: <Icon icon="keyboard" />,
|
||||
onSelect: async () => {
|
||||
if (!workspaceId) return;
|
||||
await invoke('cmd_new_nested_window', {
|
||||
url: routes.paths.workspaceSettings({ workspaceId }),
|
||||
label: 'settings',
|
||||
title: 'Yaak Settings',
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'import-data',
|
||||
label: 'Import Data',
|
||||
|
||||
@@ -40,7 +40,7 @@ export const WorkspaceHeader = memo(function WorkspaceHeader({ className }: Prop
|
||||
<div className="pointer-events-none">
|
||||
<RecentRequestsDropdown />
|
||||
</div>
|
||||
<div className="flex-1 flex gap-1 items-center h-full justify-end pointer-events-none">
|
||||
<div className="flex-1 flex gap-1 items-center h-full justify-end pointer-events-none pr-0.5">
|
||||
<ImportCurlButton />
|
||||
<SettingsDropdown />
|
||||
{(osInfo?.osType === 'linux' || osInfo?.osType === 'windows') && (
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useActiveEnvironment } from './useActiveEnvironment';
|
||||
import { useActiveRequest } from './useActiveRequest';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
import { useOsInfo } from './useOsInfo';
|
||||
import { emit } from '@tauri-apps/api/event';
|
||||
|
||||
export function useSyncWindowTitle() {
|
||||
const activeRequest = useActiveRequest();
|
||||
@@ -26,13 +27,12 @@ export function useSyncWindowTitle() {
|
||||
newTitle += ` – ${fallbackRequestName(activeRequest)}`;
|
||||
}
|
||||
|
||||
// TODO: This resets the stoplight position so we can't use it on macOS yet. Perhaps
|
||||
// we can
|
||||
// TODO: This resets the stoplight position so we can't use it on macOS yet. So we send
|
||||
// a custom command instead
|
||||
if (osInfo?.osType !== 'macos') {
|
||||
console.log('DO IT', osInfo?.osType);
|
||||
getCurrent().setTitle(newTitle).catch(console.error);
|
||||
} else {
|
||||
// emit('yaak_title_changed', newTitle).catch(console.error);
|
||||
emit('yaak_title_changed', newTitle).catch(console.error);
|
||||
}
|
||||
}, [activeEnvironment, activeRequest, activeWorkspace, osInfo?.osType]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user