Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export const ConnectionWatcher = () => {

const hover = useHover(context, {
handleClose: safePolygon(),
enabled: connected,
});

const dismiss = useDismiss(context, {
Expand Down
69 changes: 68 additions & 1 deletion src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ x25519-dalek = { version = "2", features = [
] }

[target.'cfg(target_os = "macos")'.dependencies]
cocoa = "0.26"
block2 = "0.6"
objc2 = "0.6"
objc2-foundation = "0.3"
Expand Down
64 changes: 37 additions & 27 deletions src-tauri/src/tray.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,38 +144,48 @@ pub async fn setup_tray(app: &AppHandle) -> Result<(), Error> {

TrayIconBuilder::with_id(TRAY_ICON_ID)
.menu(&tray_menu)
.show_menu_on_left_click(cfg!(target_os = "macos"))
.show_menu_on_left_click(false)
.on_tray_icon_event(|icon, event| {
store_tray_click_position(icon.app_handle(), &event);
if let TrayIconEvent::Click {
button: MouseButton::Left,
button_state: MouseButtonState::Up,
..
} = event
{
let app = icon.app_handle();
let any_visible = [NEW_UI_WINDOW_ID, OLD_UI_WINDOW_ID].iter().any(|id| {
app.get_webview_window(id)
.and_then(|w| w.is_visible().ok())
.unwrap_or(false)
});
if any_visible {
hide_visible_windows(app);
} else {
#[cfg(not(target_os = "linux"))]
{
let has_locations = tauri::async_runtime::block_on(
crate::window_manager::has_non_service_locations(),
);
if has_locations {
show_new_ui_window_near_tray(app);
} else {
let _ = WindowManager::open_full_view(app);
match event {
#[cfg(target_os = "macos")]
TrayIconEvent::Click {
button: MouseButton::Right,
button_state: MouseButtonState::Up,
..
} => {
let _ = icon.show_menu();
}
TrayIconEvent::Click {
button: MouseButton::Left,
button_state: MouseButtonState::Up,
..
} => {
let app = icon.app_handle();
let any_visible = [NEW_UI_WINDOW_ID, OLD_UI_WINDOW_ID].iter().any(|id| {
app.get_webview_window(id)
.and_then(|w| w.is_visible().ok())
.unwrap_or(false)
});
if any_visible {
hide_visible_windows(app);
} else {
#[cfg(not(target_os = "linux"))]
{
let has_locations = tauri::async_runtime::block_on(
crate::window_manager::has_non_service_locations(),
);
if has_locations {
show_new_ui_window_near_tray(app);
} else {
let _ = WindowManager::open_full_view(app);
}
}
#[cfg(target_os = "linux")]
show_new_ui_window_near_tray(app);
}
#[cfg(target_os = "linux")]
show_new_ui_window_near_tray(app);
}
_ => {}
}
})
.on_menu_event(handle_tray_menu_event)
Expand Down
35 changes: 35 additions & 0 deletions src-tauri/src/window_manager/macos.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,43 @@
use tauri::{AppHandle, LogicalPosition, Manager, Monitor, PhysicalSize, Position, WebviewWindow};

#[cfg(target_os = "macos")]
use tauri::Runtime;

use crate::appstate::AppState;
use crate::window_manager::{WindowManager, NEW_UI_WINDOW_ID, OLD_UI_WINDOW_ID};

#[cfg(target_os = "macos")]
use cocoa::{
appkit::{NSView, NSWindow, NSWindowStyleMask},
base::id,
};

#[cfg(target_os = "macos")]
pub fn enable_rounded_corners<R: Runtime>(window: WebviewWindow<R>) -> Result<(), String> {
window
.with_webview(move |webview| {
unsafe {
let ns_window = webview.ns_window() as id;

let mut style_mask = ns_window.styleMask();

// Add necessary styles for rounded corners
style_mask |= NSWindowStyleMask::NSFullSizeContentViewWindowMask;
style_mask |= NSWindowStyleMask::NSTitledWindowMask;
style_mask |= NSWindowStyleMask::NSClosableWindowMask;
style_mask |= NSWindowStyleMask::NSMiniaturizableWindowMask;
style_mask |= NSWindowStyleMask::NSResizableWindowMask;

ns_window.setStyleMask_(style_mask);
ns_window.setTitlebarAppearsTransparent_(cocoa::base::YES);

let content_view = ns_window.contentView();
content_view.setWantsLayer(cocoa::base::YES);
}
})
.map_err(|e| e.to_string())
}

/// Try to get monitor at the given position, with a fall back to primary monitor, and then to the
/// first one on the list of available monitors.
fn get_monitor_for_position(app: &AppHandle, x: f64, y: f64) -> Option<Monitor> {
Expand Down
11 changes: 9 additions & 2 deletions src-tauri/src/window_manager/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,22 @@ pub struct WindowManager;

impl WindowManager {
pub fn build_tray_window(app: &AppHandle) -> tauri::Result<WebviewWindow> {
WebviewWindowBuilder::new(app, NEW_UI_WINDOW_ID, new_ui_url())
let window = WebviewWindowBuilder::new(app, NEW_UI_WINDOW_ID, new_ui_url())
.title("Defguard")
.inner_size(NEW_UI_WIDTH, NEW_UI_HEIGHT)
.resizable(false)
.decorations(false)
.visible(false)
.always_on_top(true)
.skip_taskbar(true)
.build()
.build()?;

#[cfg(target_os = "macos")]
if let Err(err) = macos::enable_rounded_corners(window.clone()) {
tracing::warn!("Failed to enable rounded corners on tray window: {err}");
}

Ok(window)
}

pub fn build_full_window(app: &AppHandle) -> tauri::Result<WebviewWindow> {
Expand Down
Loading