Rebrand to Galaxy, major improvements to Bedrock support, still needs some TLC though

This commit is contained in:
Ryan Ward
2026-05-07 11:29:34 -05:00
parent f4e2475c60
commit a41cbd8cc7
2433 changed files with 14208 additions and 9409 deletions
+110
View File
@@ -0,0 +1,110 @@
pub mod state;
mod system;
use std::rc::Rc;
use pathfinder_geometry::rect::RectF;
pub use state::{State, StateEvent, WindowManager};
pub use system::{CreateWindowingSystemError, System};
use crate::{
actions::StandardAction, platform::WindowContext, AppContext, AppContextRefMut, CursorInfo,
Event, Scene,
};
/// Result of dispatching an event through the UI framework.
#[derive(Debug, Clone, Copy, Default)]
pub struct EventDispatchResult {
/// Whether the event was handled by the UI framework.
pub handled: bool,
/// Whether the soft keyboard should be shown (mobile WASM only).
pub soft_keyboard_requested: bool,
}
pub(crate) type EventCallback = Box<dyn Fn(Event, &mut AppContext) -> EventDispatchResult>;
pub(crate) type ResizeCallback = Box<dyn Fn(&dyn WindowContext, &mut AppContext)>;
pub(crate) type StandardActionCallback = Box<dyn Fn(StandardAction, &mut AppContext)>;
pub(crate) type ActiveCursorPositionCallback = Box<dyn Fn(&mut AppContext) -> Option<CursorInfo>>;
pub(crate) type MoveCallback = Box<dyn Fn(RectF, &mut AppContext)>;
pub(crate) type FrameCallback = Box<dyn Fn(&mut AppContext)>;
pub(crate) type BuildSceneCallback = Box<dyn Fn(&dyn WindowContext, &mut AppContext) -> Rc<Scene>>;
/// A collection of callbacks that are used to update UI framework state in
/// response to platform-level events.
pub struct WindowCallbacks {
/// Dispatches a [`StandardAction`].
pub standard_action_callback: StandardActionCallback,
/// Dispatches an [`Event`].
pub event_callback: EventCallback,
/// Notifies the UI framework that the window was resized.
pub resize_callback: ResizeCallback,
/// Requests that the UI framework construct a scene to render.
pub build_scene_callback: BuildSceneCallback,
/// Notifies the UI framework that a frame was rendered.
pub frame_callback: FrameCallback,
/// Notifies the UI framework that a frame failed to draw.
pub draw_frame_error_callback: FrameCallback,
/// Notifies the UI framework that the window moved.
pub move_callback: MoveCallback,
/// Returns the current location of the text editing cursor, if an
/// editable text field is focused.
pub active_cursor_position_callback: ActiveCursorPositionCallback,
}
/// A helper structure to simplify and standardize the act of making calls from
/// platform code into platform-independent UI framework code.
pub struct WindowCallbackDispatcher<'a> {
callbacks: &'a WindowCallbacks,
ctx: AppContextRefMut<'a>,
}
impl<'a> WindowCallbackDispatcher<'a> {
pub(crate) fn new(callbacks: &'a WindowCallbacks, ctx: AppContextRefMut<'a>) -> Self {
Self { callbacks, ctx }
}
pub fn dispatch_event(&mut self, event: Event) -> EventDispatchResult {
(self.callbacks.event_callback)(event, &mut self.ctx)
}
pub fn window_resized(&mut self, window: &dyn WindowContext) {
(self.callbacks.resize_callback)(window, &mut self.ctx)
}
pub fn frame_drawn(&mut self) {
(self.callbacks.frame_callback)(&mut self.ctx)
}
#[cfg_attr(target_os = "macos", allow(dead_code))]
pub fn frame_failed_to_draw(&mut self) {
(self.callbacks.draw_frame_error_callback)(&mut self.ctx)
}
pub fn get_active_cursor_position(&mut self) -> Option<CursorInfo> {
(self.callbacks.active_cursor_position_callback)(&mut self.ctx)
}
pub fn window_moved(&mut self, bounds: RectF) {
(self.callbacks.move_callback)(bounds, &mut self.ctx)
}
pub fn build_scene(&mut self, window: &dyn WindowContext) -> Rc<Scene> {
(self.callbacks.build_scene_callback)(window, &mut self.ctx)
}
}
// Functions in WindowCallbackDispatcher that relate to application menus.
//
// This is marked as `allow(dead_code)` on Linux and wasm, as they do not
// support application menus, so these never get called.
// TODO(CORE-2691): implement native Windows OS app menus
#[cfg_attr(
any(target_os = "linux", target_os = "windows", target_family = "wasm"),
allow(dead_code)
)]
impl WindowCallbackDispatcher<'_> {
pub fn dispatch_standard_action(&mut self, action: StandardAction) {
(self.callbacks.standard_action_callback)(action, &mut self.ctx)
}
}
+325
View File
@@ -0,0 +1,325 @@
use pathfinder_geometry::rect::RectF;
use std::{
collections::VecDeque,
fmt::{Display, Formatter},
};
use crate::{
geometry,
platform::{self, FullscreenState, TerminationMode, WindowFocusBehavior},
scene::{CornerRadius, Radius},
windowing, DisplayId, DisplayIdx, Entity, ModelContext, OptionalPlatformWindow,
SingletonEntity, WindowId,
};
use super::WindowCallbacks;
/// Description of the current stage in the lifecycle of the app.
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub enum ApplicationStage {
#[default]
/// The application is starting. We move from `Starting` to `Active` when we process the
/// lifecycle event when we open the first window.
Starting,
/// The app is currently the active application.
Active,
/// Some other application is currently active.
Inactive,
/// The application is in the process of terminating.
Terminating,
}
impl Display for ApplicationStage {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ApplicationStage::Starting => write!(f, "Starting"),
ApplicationStage::Active => write!(f, "Active"),
ApplicationStage::Inactive => write!(f, "Inactive"),
ApplicationStage::Terminating => write!(f, "Terminating"),
}
}
}
#[derive(Clone, Debug, Default)]
pub struct State {
/// The current stage of the app.
pub stage: ApplicationStage,
/// The [`WindowId`] of the currently active (frontmost) window. If Warp goes out of focus,
/// this will go back to None.
pub active_window: Option<WindowId>,
/// A stack of [`WindowId`]s which had been active before.
active_window_stack: VecDeque<WindowId>,
/// Whether the active window is fullscreen.
pub is_active_window_fullscreen: Option<bool>,
}
/// Struct that enumerates windowing-related state within the application.
pub struct WindowManager {
state: State,
platform: Box<dyn platform::WindowManager>,
}
impl WindowManager {
/// Constructs a new [`State`] in an inactive state.
/// NOTE the `State` begins with no windows and an inactive state--it is updated by platform
/// code when the application first becomes active.
pub(crate) fn new(window_manager: Box<dyn platform::WindowManager>) -> Self {
Self {
state: Default::default(),
platform: window_manager,
}
}
#[cfg(any(test, feature = "test-util", feature = "integration_tests"))]
pub fn overwrite_for_test(&mut self, stage: ApplicationStage, active_window: Option<WindowId>) {
self.state.stage = stage;
self.state.active_window = active_window;
self.state.active_window_stack = active_window.into_iter().collect();
self.state.is_active_window_fullscreen = Some(false);
}
pub fn platform_window(&self, window_id: WindowId) -> OptionalPlatformWindow {
self.platform.platform_window(window_id)
}
pub fn app_is_active(&self) -> bool {
self.platform.app_is_active()
}
pub fn hide_window(&self, window_id: WindowId) {
self.platform.hide_window(window_id)
}
pub fn set_window_bounds(&self, window_id: WindowId, bound: RectF) {
self.platform.set_window_bounds(window_id, bound)
}
pub fn cancel_synthetic_drag(&self, window_id: WindowId) {
self.platform.cancel_synthetic_drag(window_id)
}
#[cfg(target_os = "macos")]
pub fn show_window_and_focus_app_without_ordering_front(&self, window_id: WindowId) {
self.platform
.show_window_and_focus_app(window_id, WindowFocusBehavior::RetainZIndex)
}
pub fn show_window_and_focus_app(&self, window_id: WindowId) {
self.platform
.show_window_and_focus_app(window_id, WindowFocusBehavior::default())
}
pub fn activate_app(&self) -> Option<WindowId> {
self.platform.activate_app(self.frontmost_window_id())
}
pub fn hide_app(&self) {
self.platform.hide_app()
}
pub fn set_all_windows_background_blur_radius(&self, blur_radius_pixels: u8) {
self.platform
.set_all_windows_background_blur_radius(blur_radius_pixels)
}
pub fn set_all_windows_background_blur_texture(&self, use_blur_texture: bool) {
self.platform
.set_all_windows_background_blur_texture(use_blur_texture)
}
pub fn set_window_title(&self, window_id: WindowId, title: &str) {
self.platform.set_window_title(window_id, title)
}
pub fn key_window_is_modal_panel(&self) -> bool {
self.platform.key_window_is_modal_panel()
}
pub fn close_window(&self, window_id: WindowId, termination_mode: TerminationMode) {
self.platform
.close_window_async(window_id, termination_mode)
}
pub fn active_cursor_position_updated(&self) {
self.platform.active_cursor_position_updated();
}
pub fn active_window(&self) -> Option<WindowId> {
self.platform.active_window_id()
}
// Get the rect of the current active screen. We need the bound instead of just
// the size of the screen because Mac has a global coordination system containing
// all user's screens. So the active screen may not have a origin of (0, 0).
pub fn active_display_bounds(&self) -> geometry::rect::RectF {
self.platform.active_display_bounds()
}
pub fn active_display_id(&self) -> DisplayId {
self.platform.active_display_id()
}
pub fn bounds_for_display_idx(&self, idx: DisplayIdx) -> Option<RectF> {
self.platform.bounds_for_display_idx(idx)
}
pub fn display_count(&self) -> usize {
self.platform.display_count()
}
pub fn is_tiling_window_manager(&self) -> bool {
self.platform.is_tiling_window_manager()
}
pub fn os_window_manager_name(&self) -> Option<String> {
self.platform.os_window_manager_name()
}
pub fn did_window_change_focus(window_id: WindowId, current: &State, previous: &State) -> bool {
let current_window_is_active = current.active_window == Some(window_id);
let previous_window_was_active = previous.active_window == Some(window_id);
current_window_is_active != previous_window_was_active
}
/// The window itself usually has rounded corners, except when running in a tiling window
/// manager or when on Windows. We don't need to specify a custom window corner radius on
/// Windows because we use OS APIs to round the corners of the window.
pub fn window_corner_radius(&self) -> CornerRadius {
let radius = if self.is_tiling_window_manager() || cfg!(windows) {
0.
} else {
8.
};
CornerRadius::with_all(Radius::Pixels(radius))
}
pub(crate) fn open_window(
&mut self,
window_id: WindowId,
window_options: platform::WindowOptions,
callbacks: WindowCallbacks,
) -> anyhow::Result<()> {
self.platform
.open_window(window_id, window_options, callbacks)
}
pub(crate) fn remove_window(&mut self, window_id: WindowId, ctx: &mut ModelContext<Self>) {
self.update(
|state| {
state.active_window_stack.retain(|id| *id != window_id);
},
ctx,
);
self.platform.remove_window(window_id)
}
pub(crate) fn close_window_async(
&self,
window_id: WindowId,
termination_mode: TerminationMode,
) {
self.platform
.close_window_async(window_id, termination_mode)
}
/// Sets the current active window to `window_id`.
pub(crate) fn set_active_window(
&mut self,
window_id: Option<WindowId>,
ctx: &mut ModelContext<Self>,
) {
self.update(
|state| {
state.active_window = window_id;
if let Some(window_id) = window_id {
state.active_window_stack.retain(|id| *id != window_id);
state.active_window_stack.push_back(window_id);
state.stage = ApplicationStage::Active;
} else {
state.stage = ApplicationStage::Inactive;
}
},
ctx,
);
}
pub fn toggle_fullscreen(&mut self, window_id: WindowId, ctx: &mut ModelContext<Self>) {
if let Some(window) = self.platform_window(window_id) {
window.toggle_fullscreen();
}
if self.state.active_window == Some(window_id) {
self.update_is_active_window_fullscreen(ctx);
}
}
/// Updates saved state corresponding to whether the active window is fullscreen.
pub(crate) fn update_is_active_window_fullscreen(&mut self, ctx: &mut ModelContext<Self>) {
let is_active_window_fullscreen = self.state.active_window.map(|id| {
self.platform_window(id)
.map(|window| window.fullscreen_state() == FullscreenState::Fullscreen)
.unwrap_or(false)
});
self.update(
|state| state.is_active_window_fullscreen = is_active_window_fullscreen,
ctx,
);
}
/// Sets the current stage of the application to `stage`.
pub(crate) fn set_stage(&mut self, stage: ApplicationStage, ctx: &mut ModelContext<Self>) {
self.update(|state| state.stage = stage, ctx);
}
/// Returns the current [`ApplicationStage`] of the application.
pub fn stage(&self) -> ApplicationStage {
self.state.stage
}
pub fn frontmost_window_id(&self) -> Option<WindowId> {
self.state.active_window_stack.back().cloned()
}
/// Returns boolean representing whether the active window is fullscreen. Returns `false` if
/// no window is currently active.
pub fn is_active_window_fullscreen(&self) -> bool {
self.state.is_active_window_fullscreen.unwrap_or(false)
}
pub fn ordered_window_ids(&self) -> Vec<WindowId> {
self.platform.ordered_window_ids()
}
pub fn state(&self) -> &State {
&self.state
}
pub fn windowing_system(&self) -> Option<windowing::System> {
self.platform.windowing_system()
}
/// Helper function used to ensure that updates to [`State`] end up triggering the proper event
/// updates.
fn update(&mut self, update_fn: impl FnOnce(&mut State), ctx: &mut ModelContext<Self>) {
let previous = self.state.clone();
update_fn(&mut self.state);
ctx.emit(StateEvent::ValueChanged {
previous,
current: self.state.clone(),
});
ctx.notify();
}
}
/// The set of events that are emitted by the [`crate::windowing::State`] model.
pub enum StateEvent {
/// The state changed from `previous` to `current`.
ValueChanged { current: State, previous: State },
}
impl Entity for WindowManager {
type Event = StateEvent;
}
/// Mark [`State`] as global application state.
impl SingletonEntity for WindowManager {}
@@ -0,0 +1,72 @@
//! Module containing the definition of the current windowing [`System`] the application is
//! rendering to.
use std::fmt::{Display, Formatter};
use raw_window_handle::RawDisplayHandle;
/// The windowing system that is being used.
#[derive(Copy, Clone, Debug)]
pub enum System {
X11 { is_x_wayland: bool },
Wayland,
AppKit,
Windows,
}
impl System {
/// Whether this window server protocol allows windows to programmatically "activate" or
/// show/focus themselves.
pub fn allows_programmatic_window_activation(&self) -> bool {
match self {
Self::AppKit | Self::X11 { .. } | Self::Windows => true,
Self::Wayland => false,
}
}
}
impl Display for System {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
System::X11 { is_x_wayland } => {
if *is_x_wayland {
write!(f, "Xwayland")
} else {
write!(f, "X11")
}
}
System::Wayland => write!(f, "Wayland"),
System::AppKit => write!(f, "AppKit"),
System::Windows => write!(f, "Windows"),
}
}
}
impl TryFrom<RawDisplayHandle> for System {
type Error = CreateWindowingSystemError;
fn try_from(raw_display_handle: RawDisplayHandle) -> Result<Self, Self::Error> {
let display = match raw_display_handle {
RawDisplayHandle::AppKit(_) => System::AppKit,
RawDisplayHandle::Wayland(_) => System::Wayland,
RawDisplayHandle::Xlib(_) | RawDisplayHandle::Xcb(_) => System::X11 {
is_x_wayland: std::env::var("WAYLAND_DISPLAY")
.ok()
.filter(|val| !val.is_empty())
.is_some(),
},
RawDisplayHandle::Windows(_) => System::Windows,
_ => {
return Err(Self::Error::UnrecognizedDisplayHandle);
}
};
Ok(display)
}
}
#[derive(thiserror::Error, Debug)]
pub enum CreateWindowingSystemError {
#[error("Unrecognized DisplayHandle")]
UnrecognizedDisplayHandle,
}