Desktop: Hide menu bar in fullscreen mode on Mac (#3464)

hide menu bar in fullscreen mode on mac
This commit is contained in:
Timon 2025-12-12 13:09:31 +00:00 committed by GitHub
parent 6d852f11af
commit 7532bd7260
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 94 additions and 36 deletions

View File

@ -28,6 +28,9 @@ pub(crate) struct App {
wgpu_context: WgpuContext, wgpu_context: WgpuContext,
window: Option<Window>, window: Option<Window>,
window_scale: f64, window_scale: f64,
window_size: PhysicalSize<u32>,
window_maximized: bool,
window_fullscreen: bool,
app_event_receiver: Receiver<AppEvent>, app_event_receiver: Receiver<AppEvent>,
app_event_scheduler: AppEventScheduler, app_event_scheduler: AppEventScheduler,
desktop_wrapper: DesktopWrapper, desktop_wrapper: DesktopWrapper,
@ -81,6 +84,9 @@ impl App {
wgpu_context, wgpu_context,
window: None, window: None,
window_scale: 1., window_scale: 1.,
window_size: PhysicalSize { width: 0, height: 0 },
window_maximized: false,
window_fullscreen: false,
app_event_receiver, app_event_receiver,
app_event_scheduler, app_event_scheduler,
desktop_wrapper: DesktopWrapper::new(), desktop_wrapper: DesktopWrapper::new(),
@ -97,6 +103,56 @@ impl App {
} }
} }
fn resize(&mut self) {
let Some(window) = &self.window else {
tracing::error!("Resize failed due to missing window");
return;
};
let maximized = window.is_maximized();
if maximized != self.window_maximized {
self.window_maximized = maximized;
self.app_event_scheduler.schedule(AppEvent::DesktopWrapperMessage(DesktopWrapperMessage::UpdateMaximized { maximized }));
}
let fullscreen = window.is_fullscreen();
if fullscreen != self.window_fullscreen {
self.window_fullscreen = fullscreen;
self.app_event_scheduler
.schedule(AppEvent::DesktopWrapperMessage(DesktopWrapperMessage::UpdateFullscreen { fullscreen }));
}
let size = window.surface_size();
let scale = window.scale_factor();
let is_new_size = size != self.window_size;
let is_new_scale = scale != self.window_scale;
if !is_new_size && !is_new_scale {
return;
}
if is_new_size {
let _ = self.cef_view_info_sender.send(cef::ViewInfoUpdate::Size {
width: size.width,
height: size.height,
});
}
if is_new_scale {
let _ = self.cef_view_info_sender.send(cef::ViewInfoUpdate::Scale(scale));
}
self.cef_context.notify_view_info_changed();
if let Some(render_state) = &mut self.render_state {
render_state.resize(size.width, size.height);
}
window.request_redraw();
self.window_size = size;
self.window_scale = scale;
}
fn handle_desktop_frontend_message(&mut self, message: DesktopFrontendMessage, responses: &mut Vec<DesktopWrapperMessage>) { fn handle_desktop_frontend_message(&mut self, message: DesktopFrontendMessage, responses: &mut Vec<DesktopWrapperMessage>) {
match message { match message {
DesktopFrontendMessage::ToWeb(messages) => { DesktopFrontendMessage::ToWeb(messages) => {
@ -393,22 +449,13 @@ impl App {
impl ApplicationHandler for App { impl ApplicationHandler for App {
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
let window = Window::new(event_loop, self.app_event_scheduler.clone()); let window = Window::new(event_loop, self.app_event_scheduler.clone());
self.window_scale = window.scale_factor();
let _ = self.cef_view_info_sender.send(cef::ViewInfoUpdate::Scale(self.window_scale));
// Ensures the CEF texture does not remain at 1x1 pixels until the window is resized by the user
// Affects only some Mac devices (issue found on 2023 M2 Mac Mini).
let PhysicalSize { width, height } = window.surface_size();
let _ = self.cef_view_info_sender.send(cef::ViewInfoUpdate::Size { width, height });
self.cef_context.notify_view_info_changed();
self.window = Some(window); self.window = Some(window);
let render_state = RenderState::new(self.window.as_ref().unwrap(), self.wgpu_context.clone()); let render_state = RenderState::new(self.window.as_ref().unwrap(), self.wgpu_context.clone());
self.render_state = Some(render_state); self.render_state = Some(render_state);
self.resize();
self.desktop_wrapper.init(self.wgpu_context.clone()); self.desktop_wrapper.init(self.wgpu_context.clone());
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
@ -433,32 +480,15 @@ impl ApplicationHandler for App {
WindowEvent::CloseRequested => { WindowEvent::CloseRequested => {
self.app_event_scheduler.schedule(AppEvent::CloseWindow); self.app_event_scheduler.schedule(AppEvent::CloseWindow);
} }
WindowEvent::SurfaceResized(PhysicalSize { width, height }) => { WindowEvent::SurfaceResized(_) | WindowEvent::ScaleFactorChanged { .. } => {
let _ = self.cef_view_info_sender.send(cef::ViewInfoUpdate::Size { width, height }); self.resize();
self.cef_context.notify_view_info_changed();
if let Some(render_state) = &mut self.render_state {
render_state.resize(width, height);
}
if let Some(window) = &self.window {
let maximized = window.is_maximized();
self.app_event_scheduler.schedule(AppEvent::DesktopWrapperMessage(DesktopWrapperMessage::UpdateMaximized { maximized }));
window.request_redraw();
}
}
WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
self.window_scale = scale_factor;
let _ = self.cef_view_info_sender.send(cef::ViewInfoUpdate::Scale(self.window_scale));
self.cef_context.notify_view_info_changed();
} }
WindowEvent::RedrawRequested => { WindowEvent::RedrawRequested => {
#[cfg(target_os = "macos")]
self.resize();
let Some(render_state) = &mut self.render_state else { return }; let Some(render_state) = &mut self.render_state else { return };
if let Some(window) = &self.window { if let Some(window) = &self.window {
let size = window.surface_size();
render_state.resize(size.width, size.height);
match render_state.render(window) { match render_state.render(window) {
Ok(_) => {} Ok(_) => {}
Err(RenderError::OutdatedUITextureError) => { Err(RenderError::OutdatedUITextureError) => {

View File

@ -99,6 +99,10 @@ impl Window {
self.winit_window.is_maximized() self.winit_window.is_maximized()
} }
pub(crate) fn is_fullscreen(&self) -> bool {
self.winit_window.fullscreen().is_some()
}
pub(crate) fn start_drag(&self) { pub(crate) fn start_drag(&self) {
let _ = self.winit_window.drag_window(); let _ = self.winit_window.drag_window();
} }

View File

@ -121,6 +121,10 @@ pub(super) fn handle_desktop_wrapper_message(dispatcher: &mut DesktopWrapperMess
let message = FrontendMessage::UpdateMaximized { maximized }; let message = FrontendMessage::UpdateMaximized { maximized };
dispatcher.queue_editor_message(message); dispatcher.queue_editor_message(message);
} }
DesktopWrapperMessage::UpdateFullscreen { fullscreen } => {
let message = FrontendMessage::UpdateFullscreen { fullscreen };
dispatcher.queue_editor_message(message);
}
DesktopWrapperMessage::LoadDocument { DesktopWrapperMessage::LoadDocument {
id, id,
document, document,

View File

@ -103,6 +103,9 @@ pub enum DesktopWrapperMessage {
UpdateMaximized { UpdateMaximized {
maximized: bool, maximized: bool,
}, },
UpdateFullscreen {
fullscreen: bool,
},
LoadDocument { LoadDocument {
id: DocumentId, id: DocumentId,
document: Document, document: Document,

View File

@ -326,6 +326,9 @@ pub enum FrontendMessage {
UpdateMaximized { UpdateMaximized {
maximized: bool, maximized: bool,
}, },
UpdateFullscreen {
fullscreen: bool,
},
UpdateViewportHolePunch { UpdateViewportHolePunch {
active: bool, active: bool,
}, },

View File

@ -18,7 +18,9 @@
</script> </script>
<LayoutCol class="main-window" classes={{ "viewport-hole-punch": $appWindow.viewportHolePunch }}> <LayoutCol class="main-window" classes={{ "viewport-hole-punch": $appWindow.viewportHolePunch }}>
<TitleBar /> {#if !($appWindow.platform == "Mac" && $appWindow.fullscreen)}
<TitleBar />
{/if}
<Workspace /> <Workspace />
<StatusBar /> <StatusBar />
{#if $dialog.visible} {#if $dialog.visible}

View File

@ -302,6 +302,10 @@ export class UpdateMaximized extends JsMessage {
readonly maximized!: boolean; readonly maximized!: boolean;
} }
export class UpdateFullscreen extends JsMessage {
readonly fullscreen!: boolean;
}
export class CloseWindow extends JsMessage {} export class CloseWindow extends JsMessage {}
export class UpdateViewportHolePunch extends JsMessage { export class UpdateViewportHolePunch extends JsMessage {
@ -1742,7 +1746,6 @@ export const messageMakers: Record<string, MessageMaker> = {
UpdateLayersPanelControlBarRightLayout, UpdateLayersPanelControlBarRightLayout,
UpdateLayersPanelState, UpdateLayersPanelState,
UpdateLayerWidths, UpdateLayerWidths,
UpdateMaximized,
UpdateMenuBarLayout, UpdateMenuBarLayout,
UpdateMouseCursor, UpdateMouseCursor,
UpdateNodeGraphControlBarLayout, UpdateNodeGraphControlBarLayout,
@ -1754,6 +1757,8 @@ export const messageMakers: Record<string, MessageMaker> = {
UpdateNodeThumbnail, UpdateNodeThumbnail,
UpdateOpenDocumentsList, UpdateOpenDocumentsList,
UpdatePlatform, UpdatePlatform,
UpdateMaximized,
UpdateFullscreen,
UpdatePropertiesPanelLayout, UpdatePropertiesPanelLayout,
UpdatePropertiesPanelState, UpdatePropertiesPanelState,
UpdateStatusBarHintsLayout, UpdateStatusBarHintsLayout,

View File

@ -1,12 +1,13 @@
import { writable } from "svelte/store"; import { writable } from "svelte/store";
import { type Editor } from "@graphite/editor"; import { type Editor } from "@graphite/editor";
import { type AppWindowPlatform, UpdatePlatform, UpdateViewportHolePunch, UpdateMaximized as UpdateMaximized } from "@graphite/messages"; import { type AppWindowPlatform, UpdatePlatform, UpdateViewportHolePunch, UpdateMaximized, UpdateFullscreen } from "@graphite/messages";
export function createAppWindowState(editor: Editor) { export function createAppWindowState(editor: Editor) {
const { subscribe, update } = writable({ const { subscribe, update } = writable({
platform: "Web" as AppWindowPlatform, platform: "Web" as AppWindowPlatform,
maximized: false, maximized: false,
fullscreen: false,
viewportHolePunch: false, viewportHolePunch: false,
}); });
@ -23,6 +24,12 @@ export function createAppWindowState(editor: Editor) {
return state; return state;
}); });
}); });
editor.subscriptions.subscribeJsMessage(UpdateFullscreen, (updateFullscreen) => {
update((state) => {
state.fullscreen = updateFullscreen.fullscreen;
return state;
});
});
editor.subscriptions.subscribeJsMessage(UpdateViewportHolePunch, (viewportHolePunch) => { editor.subscriptions.subscribeJsMessage(UpdateViewportHolePunch, (viewportHolePunch) => {
update((state) => { update((state) => {
state.viewportHolePunch = viewportHolePunch.active; state.viewportHolePunch = viewportHolePunch.active;