fix(window): show the window buttons in full screen on macOS (#2015)

Native full screen moves a window's buttons into the bar revealed with the menu bar, and a project tab shown in its group's full-screen Space has none, so the title bar's slot for them stayed empty. The title bar now draws them there while the window fills the screen: close closes that project's tab, the green button leaves full screen, and minimize is disabled.
Цей коміт міститься в:
l0ng-ai authored and GitHub committed 2026-11-07 23:08:25 +08:00
1 джерело 257fb0f50f
коміт 429b8f0efe
16 files changed
+205 -7

No files matched your search

+1
Переглянути файл
@@ -431,6 +431,7 @@ pub fn builder() -> tauri_specta::Builder<tauri::Wry> {
window::window_toggle_fullscreen,
window::window_flash_taskbar,
window::window_set_titlebar_height,
window::window_is_fullscreen,
window_drag::window_start_drag,
window::window_take_launch,
window::window_close_context,
+14
Переглянути файл
@@ -193,6 +193,20 @@ pub fn window_open_projects(
.collect())
}
/// Whether this window fills the screen: in native full screen, or (macOS) shown in its window
/// group's full-screen Space.
#[tauri::command]
#[specta::specta]
pub fn window_is_fullscreen(window: WebviewWindow) -> bool {
#[cfg(target_os = "macos")]
{
use tauri::Manager;
crate::window_groups::in_fullscreen(window.app_handle(), &window)
}
#[cfg(not(target_os = "macos"))]
window.is_fullscreen().unwrap_or(false)
}
#[derive(Serialize, Deserialize, Type)]
#[serde(rename_all = "camelCase")]
pub struct CloseContext {
+1
Переглянути файл
@@ -135,6 +135,7 @@ pub fn set_fullscreen_auxiliary(window: &WebviewWindow, host: Option<&WebviewWin
if let Some(frame) = frame {
native.setFrame_display(frame, true);
}
target.state::<crate::state::AppState>().sink.emit(ide_core::IdeEvent::WindowFullscreenChanged);
})
}
+12 -6
Переглянути файл
@@ -12,11 +12,12 @@ use objc2::{
runtime::ProtocolObject,
};
use objc2_app_kit::{
NSToolbar, NSWindow, NSWindowDidExitFullScreenNotification, NSWindowStyleMask, NSWindowToolbarStyle,
NSWindowWillEnterFullScreenNotification,
NSToolbar, NSWindow, NSWindowDidEnterFullScreenNotification, NSWindowDidExitFullScreenNotification,
NSWindowStyleMask, NSWindowToolbarStyle, NSWindowWillEnterFullScreenNotification,
};
use objc2_foundation::{NSNotificationCenter, NSObjectProtocol};
use std::{cell::Cell, cell::RefCell, collections::HashMap, rc::Rc};
use tauri::Manager;
/// Unified compact (38pt) and unified (52pt) toolbars; pick the one closer to the web bar.
const COMPACT_MAX_HEIGHT: f64 = 45.0;
@@ -55,7 +56,7 @@ impl Drop for Observer {
struct Tracked {
state: Rc<Fullscreen>,
_observers: [Observer; 2],
_observers: [Observer; 3],
}
thread_local! {
@@ -71,7 +72,7 @@ fn apply(window: &NSWindow, state: &Fullscreen) {
}
}
fn track(window: &NSWindow) -> Tracked {
fn track(window: &NSWindow, app: &tauri::AppHandle) -> Tracked {
let state = Rc::new(Fullscreen::default());
if window.styleMask().contains(NSWindowStyleMask::FullScreen) {
state.will_enter();
@@ -79,11 +80,14 @@ fn track(window: &NSWindow) -> Tracked {
let observe = |name, change: fn(&Fullscreen)| {
let weak = Weak::new(window);
let state = state.clone();
let app = app.clone();
let block = block2::RcBlock::new(move |_| {
change(&state);
if let Some(window) = weak.load() {
apply(&window, &state);
}
// The web title bar shows the window buttons itself in full screen.
app.state::<crate::state::AppState>().sink.emit(ide_core::IdeEvent::WindowFullscreenChanged);
});
let observer = unsafe {
NSNotificationCenter::defaultCenter().addObserverForName_object_queue_usingBlock(
@@ -98,6 +102,7 @@ fn track(window: &NSWindow) -> Tracked {
let observers = unsafe {
[
observe(NSWindowWillEnterFullScreenNotification, Fullscreen::will_enter),
observe(NSWindowDidEnterFullScreenNotification, Fullscreen::will_enter),
observe(NSWindowDidExitFullScreenNotification, Fullscreen::did_exit),
]
};
@@ -106,12 +111,13 @@ fn track(window: &NSWindow) -> Tracked {
pub fn set_height(window: &tauri::WebviewWindow, height: f64) -> tauri::Result<()> {
let label = window.label().to_owned();
let app = window.app_handle().clone();
// with_webview runs on the AppKit thread.
window.with_webview(move |webview| unsafe {
let Some(mtm) = MainThreadMarker::new() else { return };
let native = &*webview.ns_window().cast::<NSWindow>();
let state =
WINDOWS.with_borrow_mut(|windows| windows.entry(label).or_insert_with(|| track(native)).state.clone());
let state = WINDOWS
.with_borrow_mut(|windows| windows.entry(label).or_insert_with(|| track(native, &app)).state.clone());
if native.toolbar().is_none() {
let toolbar = NSToolbar::new(mtm);
native.setToolbar(Some(&toolbar));