Desktop: show platform specific window buttons (#3078)

Implement app window button functionality and set platform
This commit is contained in:
Timon 2025-08-25 14:15:31 +00:00 committed by GitHub
parent 508606cdba
commit c5991c6f61
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 91 additions and 28 deletions

View File

@ -2,7 +2,7 @@ use crate::CustomEvent;
use crate::cef::WindowSize;
use crate::consts::{APP_NAME, CEF_MESSAGE_LOOP_MAX_ITERATIONS};
use crate::render::GraphicsState;
use graphite_desktop_wrapper::messages::{DesktopFrontendMessage, DesktopWrapperMessage};
use graphite_desktop_wrapper::messages::{DesktopFrontendMessage, DesktopWrapperMessage, Platform};
use graphite_desktop_wrapper::{DesktopWrapper, NodeGraphExecutionResult, WgpuContext, serialize_frontend_messages};
use rfd::AsyncFileDialog;
@ -152,6 +152,15 @@ impl WinitApp {
graphics_state.set_overlays_scene(scene);
}
}
DesktopFrontendMessage::UpdateWindowState { maximized, minimized } => {
if let Some(window) = &self.window {
window.set_maximized(maximized);
window.set_minimized(minimized);
}
}
DesktopFrontendMessage::CloseWindow => {
let _ = self.event_loop_proxy.send_event(CustomEvent::CloseWindow);
}
}
}
@ -223,9 +232,17 @@ impl ApplicationHandler<CustomEvent> for WinitApp {
tracing::info!("Winit window created and ready");
self.desktop_wrapper.init(self.wgpu_context.clone());
#[cfg(target_os = "windows")]
let platform = Platform::Windows;
#[cfg(target_os = "macos")]
let platform = Platform::Mac;
#[cfg(target_os = "linux")]
let platform = Platform::Linux;
self.dispatch_desktop_wrapper_message(DesktopWrapperMessage::UpdatePlatform(platform));
}
fn user_event(&mut self, _: &ActiveEventLoop, event: CustomEvent) {
fn user_event(&mut self, event_loop: &ActiveEventLoop, event: CustomEvent) {
match event {
CustomEvent::WebCommunicationInitialized => {
self.web_communication_initialized = true;
@ -268,6 +285,12 @@ impl ApplicationHandler<CustomEvent> for WinitApp {
self.cef_schedule = Some(instant);
}
}
CustomEvent::CloseWindow => {
// TODO: Implement graceful shutdown
tracing::info!("Exiting main event loop");
event_loop.exit();
}
}
}
@ -276,14 +299,12 @@ impl ApplicationHandler<CustomEvent> for WinitApp {
match event {
WindowEvent::CloseRequested => {
tracing::info!("The close button was pressed; stopping");
event_loop.exit();
let _ = self.event_loop_proxy.send_event(CustomEvent::CloseWindow);
}
WindowEvent::Resized(PhysicalSize { width, height }) => {
let _ = self.window_size_sender.send(WindowSize::new(width as usize, height as usize));
self.cef_context.notify_of_resize();
}
WindowEvent::RedrawRequested => {
let Some(ref mut graphics_state) = self.graphics_state else { return };
// Only rerender once we have a new ui texture to display

View File

@ -24,6 +24,7 @@ pub(crate) enum CustomEvent {
WebCommunicationInitialized,
DesktopWrapperMessage(DesktopWrapperMessage),
NodeGraphExecutionResult(NodeGraphExecutionResult),
CloseWindow,
}
fn main() {

View File

@ -1,6 +1,9 @@
use graphene_std::Color;
use graphene_std::raster::Image;
use graphite_editor::messages::prelude::{DocumentMessage, PortfolioMessage};
use graphite_editor::messages::app_window::app_window_message_handler::AppWindowPlatform;
use graphite_editor::messages::prelude::{AppWindowMessage, DocumentMessage, PortfolioMessage};
use crate::messages::Platform;
use super::DesktopWrapperMessageDispatcher;
use super::messages::{DesktopFrontendMessage, DesktopWrapperMessage, EditorMessage, OpenFileDialogContext, SaveFileDialogContext};
@ -106,5 +109,14 @@ pub(super) fn handle_desktop_wrapper_message(dispatcher: &mut DesktopWrapperMess
dispatcher.queue_editor_message(message.into());
}
DesktopWrapperMessage::PollNodeGraphEvaluation => dispatcher.poll_node_graph_evaluation(),
DesktopWrapperMessage::UpdatePlatform(platform) => {
let platform = match platform {
Platform::Windows => AppWindowPlatform::Windows,
Platform::Mac => AppWindowPlatform::Mac,
Platform::Linux => AppWindowPlatform::Linux,
};
let message = AppWindowMessage::AppWindowUpdatePlatform { platform };
dispatcher.queue_editor_message(message.into());
}
}
}

View File

@ -64,6 +64,15 @@ pub(super) fn intercept_frontend_message(dispatcher: &mut DesktopWrapperMessageD
FrontendMessage::TriggerVisitLink { url } => {
dispatcher.respond(DesktopFrontendMessage::OpenUrl(url));
}
FrontendMessage::UpdateWindowState { maximized, minimized } => {
dispatcher.respond(DesktopFrontendMessage::UpdateWindowState { maximized, minimized });
// Forward this to update the ui
return Some(message);
}
FrontendMessage::CloseWindow => {
dispatcher.respond(DesktopFrontendMessage::CloseWindow);
}
m => return Some(m),
}
None

View File

@ -30,6 +30,11 @@ pub enum DesktopFrontendMessage {
height: f32,
},
UpdateOverlays(vello::Scene),
UpdateWindowState {
maximized: bool,
minimized: bool,
},
CloseWindow,
}
pub struct FileFilter {
@ -47,6 +52,7 @@ pub enum DesktopWrapperMessage {
ImportSvg { path: PathBuf, content: Vec<u8> },
ImportImage { path: PathBuf, content: Vec<u8> },
PollNodeGraphEvaluation,
UpdatePlatform(Platform),
}
pub enum OpenFileDialogContext {
@ -58,3 +64,9 @@ pub enum SaveFileDialogContext {
Document { document_id: DocumentId, content: Vec<u8> },
File { content: Vec<u8> },
}
pub enum Platform {
Windows,
Mac,
Linux,
}

View File

@ -1,9 +1,12 @@
use crate::messages::prelude::*;
use super::app_window_message_handler::AppWindowPlatform;
#[impl_message(Message, AppWindow)]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum AppWindowMessage {
AppWindowMinimize,
AppWindowMaximize,
AppWindowUpdatePlatform { platform: AppWindowPlatform },
AppWindowClose,
}

View File

@ -6,34 +6,34 @@ use graphite_proc_macros::{ExtractField, message_handler_data};
pub struct AppWindowMessageHandler {
platform: AppWindowPlatform,
maximized: bool,
viewport_hole_punch_active: bool,
minimized: bool,
}
#[message_handler_data]
impl MessageHandler<AppWindowMessage, ()> for AppWindowMessageHandler {
fn process_message(&mut self, message: AppWindowMessage, responses: &mut std::collections::VecDeque<Message>, _: ()) {
match message {
AppWindowMessage::AppWindowMinimize => {
self.platform = if self.platform == AppWindowPlatform::Mac {
AppWindowPlatform::Windows
} else {
AppWindowPlatform::Mac
};
responses.add(FrontendMessage::UpdatePlatform { platform: self.platform });
}
AppWindowMessage::AppWindowMaximize => {
self.maximized = !self.maximized;
responses.add(FrontendMessage::UpdateMaximized { maximized: self.maximized });
self.viewport_hole_punch_active = !self.viewport_hole_punch_active;
responses.add(FrontendMessage::UpdateViewportHolePunch {
active: self.viewport_hole_punch_active,
responses.add(FrontendMessage::UpdateWindowState {
maximized: self.maximized,
minimized: self.minimized,
});
}
AppWindowMessage::AppWindowClose => {
self.platform = AppWindowPlatform::Web;
AppWindowMessage::AppWindowMinimize => {
self.minimized = !self.minimized;
responses.add(FrontendMessage::UpdateWindowState {
maximized: self.maximized,
minimized: self.minimized,
});
}
AppWindowMessage::AppWindowUpdatePlatform { platform } => {
self.platform = platform;
responses.add(FrontendMessage::UpdatePlatform { platform: self.platform });
}
AppWindowMessage::AppWindowClose => {
responses.add(FrontendMessage::CloseWindow);
}
}
}

View File

@ -329,9 +329,11 @@ pub enum FrontendMessage {
UpdatePlatform {
platform: AppWindowPlatform,
},
UpdateMaximized {
UpdateWindowState {
maximized: bool,
minimized: bool,
},
CloseWindow,
UpdateViewportHolePunch {
active: bool,
},

View File

@ -356,10 +356,13 @@ export class UpdatePlatform extends JsMessage {
readonly platform!: AppWindowPlatform;
}
export class UpdateMaximized extends JsMessage {
export class UpdateWindowState extends JsMessage {
readonly maximized!: boolean;
readonly minimized!: boolean;
}
export class CloseWindow extends JsMessage {}
export class UpdateViewportHolePunch extends JsMessage {
readonly active!: boolean;
}
@ -1741,7 +1744,7 @@ export const messageMakers: Record<string, MessageMaker> = {
UpdateLayersPanelControlBarLeftLayout,
UpdateLayersPanelControlBarRightLayout,
UpdateLayerWidths,
UpdateMaximized,
UpdateWindowState,
UpdateMenuBarLayout,
UpdateMouseCursor,
UpdateNodeGraphControlBarLayout,

View File

@ -3,7 +3,7 @@
import { writable } from "svelte/store";
import { type Editor } from "@graphite/editor";
import { type AppWindowPlatform, UpdatePlatform, UpdateMaximized, UpdateViewportHolePunch } from "@graphite/messages";
import { type AppWindowPlatform, UpdatePlatform, UpdateViewportHolePunch, UpdateWindowState } from "@graphite/messages";
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export function createAppWindowState(editor: Editor) {
@ -20,9 +20,9 @@ export function createAppWindowState(editor: Editor) {
return state;
});
});
editor.subscriptions.subscribeJsMessage(UpdateMaximized, (maximized) => {
editor.subscriptions.subscribeJsMessage(UpdateWindowState, (updateWindowState) => {
update((state) => {
state.maximized = maximized.maximized;
state.maximized = updateWindowState.maximized;
return state;
});
});