From ab760493cfc4f75bc6a3bbf2c578efa643017afd Mon Sep 17 00:00:00 2001 From: ForLoveOfCats Date: Tue, 9 Aug 2022 15:34:57 -0400 Subject: [PATCH] Route whether or not a window is fullscreen down into GPUI This still needs to be able to invalidate things to be useful but it's a good first cut at just making the information available to platform-agnostic code Co-authored-by: Mikayla --- crates/gpui/src/app.rs | 91 +++++++++++++++++++++++++- crates/gpui/src/platform.rs | 1 + crates/gpui/src/platform/mac/window.rs | 32 +++++++++ crates/gpui/src/platform/test.rs | 6 ++ 4 files changed, 128 insertions(+), 2 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 8285fda2132af5d318c2716c91e0658579158543..532f59f008f051752f38b96b47d7c060e3da878f 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -1248,6 +1248,13 @@ impl MutableAppContext { .map_or(false, |window| window.is_active) } + pub fn window_is_fullscreen(&self, window_id: usize) -> bool { + self.cx + .windows + .get(&window_id) + .map_or(false, |window| window.is_fullscreen) + } + pub fn render_view(&mut self, params: RenderParams) -> Result { let window_id = params.window_id; let view_id = params.view_id; @@ -1934,6 +1941,7 @@ impl MutableAppContext { focused_view_id: Some(root_view.id()), is_active: false, invalidation: None, + is_fullscreen: false, }, ); root_view.update(this, |view, cx| view.on_focus(cx)); @@ -2010,6 +2018,13 @@ impl MutableAppContext { })); } + { + let mut app = self.upgrade(); + window.on_fullscreen(Box::new(move |is_fullscreen| { + app.update(|cx| cx.window_was_fullscreen_changed(window_id, is_fullscreen)) + })); + } + { let mut app = self.upgrade(); window.on_close(Box::new(move || { @@ -2151,7 +2166,9 @@ impl MutableAppContext { subscription_id, callback, } => self.handle_subscription_effect(entity_id, subscription_id, callback), + Effect::Event { entity_id, payload } => self.emit_event(entity_id, payload), + Effect::GlobalSubscription { type_id, subscription_id, @@ -2161,21 +2178,27 @@ impl MutableAppContext { subscription_id, callback, ), + Effect::GlobalEvent { payload } => self.emit_global_event(payload), + Effect::Observation { entity_id, subscription_id, callback, } => self.handle_observation_effect(entity_id, subscription_id, callback), + Effect::ModelNotification { model_id } => { self.handle_model_notification_effect(model_id) } + Effect::ViewNotification { window_id, view_id } => { self.handle_view_notification_effect(window_id, view_id) } + Effect::GlobalNotification { type_id } => { self.handle_global_notification_effect(type_id) } + Effect::Deferred { callback, after_window_update, @@ -2186,15 +2209,19 @@ impl MutableAppContext { callback(self) } } + Effect::ModelRelease { model_id, model } => { self.handle_entity_release_effect(model_id, model.as_any()) } + Effect::ViewRelease { view_id, view } => { self.handle_entity_release_effect(view_id, view.as_any()) } + Effect::Focus { window_id, view_id } => { self.handle_focus_effect(window_id, view_id); } + Effect::FocusObservation { view_id, subscription_id, @@ -2202,6 +2229,7 @@ impl MutableAppContext { } => { self.handle_focus_observation_effect(view_id, subscription_id, callback) } + Effect::ResizeWindow { window_id } => { if let Some(window) = self.cx.windows.get_mut(&window_id) { window @@ -2209,6 +2237,7 @@ impl MutableAppContext { .get_or_insert(WindowInvalidation::default()); } } + Effect::WindowActivationObservation { window_id, subscription_id, @@ -2218,10 +2247,17 @@ impl MutableAppContext { subscription_id, callback, ), + Effect::ActivateWindow { window_id, is_active, } => self.handle_window_activation_effect(window_id, is_active), + + Effect::FullscreenWindow { + window_id, + is_fullscreen, + } => self.handle_fullscreen_effect(window_id, is_fullscreen), + Effect::RefreshWindows => { refreshing = true; } @@ -2294,6 +2330,13 @@ impl MutableAppContext { .push_back(Effect::ResizeWindow { window_id }); } + fn window_was_fullscreen_changed(&mut self, window_id: usize, is_fullscreen: bool) { + self.pending_effects.push_back(Effect::FullscreenWindow { + window_id, + is_fullscreen, + }); + } + fn window_changed_active_status(&mut self, window_id: usize, is_active: bool) { self.pending_effects.push_back(Effect::ActivateWindow { window_id, @@ -2608,13 +2651,36 @@ impl MutableAppContext { } } + fn handle_fullscreen_effect(&mut self, window_id: usize, is_fullscreen: bool) { + //Short circuit evaluation if we're already g2g + if self + .cx + .windows + .get(&window_id) + .map(|w| w.is_fullscreen == is_fullscreen) + .unwrap_or(false) + { + return; + } + + self.update(|this| { + let window = this.cx.windows.get_mut(&window_id)?; + window.is_fullscreen = is_fullscreen; + + // self.emit_event(entity_id, payload); + + Some(()) + }); + } + fn handle_window_activation_effect(&mut self, window_id: usize, active: bool) { + //Short circuit evaluation if we're already g2g if self .cx .windows .get(&window_id) - .map(|w| w.is_active) - .map_or(false, |cur_active| cur_active == active) + .map(|w| w.is_active == active) + .unwrap_or(false) { return; } @@ -2622,6 +2688,8 @@ impl MutableAppContext { self.update(|this| { let window = this.cx.windows.get_mut(&window_id)?; window.is_active = active; + + //Handle focus let view_id = window.focused_view_id?; if let Some(mut view) = this.cx.views.remove(&(window_id, view_id)) { if active { @@ -2632,6 +2700,7 @@ impl MutableAppContext { this.cx.views.insert((window_id, view_id), view); } + //Deliver events let callbacks = this .window_activation_observations .lock() @@ -2640,6 +2709,7 @@ impl MutableAppContext { for (id, callback) in callbacks { if let Some(mut callback) = callback { let alive = callback(active, this); + //Put entry back if alive { match this .window_activation_observations @@ -3072,6 +3142,7 @@ struct Window { root_view: AnyViewHandle, focused_view_id: Option, is_active: bool, + is_fullscreen: bool, invalidation: Option, } @@ -3138,6 +3209,10 @@ pub enum Effect { ResizeWindow { window_id: usize, }, + FullscreenWindow { + window_id: usize, + is_fullscreen: bool, + }, ActivateWindow { window_id: usize, is_active: bool, @@ -3256,6 +3331,14 @@ impl Debug for Effect { .field("window_id", window_id) .field("is_active", is_active) .finish(), + Effect::FullscreenWindow { + window_id, + is_fullscreen, + } => f + .debug_struct("Effect::FullscreenWindow") + .field("window_id", window_id) + .field("is_fullscreen", is_fullscreen) + .finish(), Effect::RefreshWindows => f.debug_struct("Effect::FullViewRefresh").finish(), Effect::WindowShouldCloseSubscription { window_id, .. } => f .debug_struct("Effect::WindowShouldCloseSubscription") @@ -4032,6 +4115,10 @@ impl<'a, V: View> RenderContext<'a, V> { WeakViewHandle::new(self.window_id, self.view_id) } + pub fn window_id(&self) -> usize { + self.window_id + } + pub fn view_id(&self) -> usize { self.view_id } diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 833912587c0f99e99583f0b2c1e67d91b2c5a5f4..df7727ee89ee47a463bbdb5dbe37732707553a21 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -112,6 +112,7 @@ pub trait Window: WindowContext { fn on_event(&mut self, callback: Box bool>); fn on_active_status_change(&mut self, callback: Box); fn on_resize(&mut self, callback: Box); + fn on_fullscreen(&mut self, callback: Box); fn on_should_close(&mut self, callback: Box bool>); fn on_close(&mut self, callback: Box); fn set_input_handler(&mut self, input_handler: Box); diff --git a/crates/gpui/src/platform/mac/window.rs b/crates/gpui/src/platform/mac/window.rs index 908efd451cf1fa79765e1ccd2c7f98730e8b044f..2168b07ffed6f4b546c0fca13ea57f48aa01109f 100644 --- a/crates/gpui/src/platform/mac/window.rs +++ b/crates/gpui/src/platform/mac/window.rs @@ -128,6 +128,14 @@ unsafe fn build_classes() { sel!(windowDidResize:), window_did_resize as extern "C" fn(&Object, Sel, id), ); + decl.add_method( + sel!(windowDidEnterFullScreen:), + window_did_enter_fullscreen as extern "C" fn(&Object, Sel, id), + ); + decl.add_method( + sel!(windowDidExitFullScreen:), + window_did_exit_fullscreen as extern "C" fn(&Object, Sel, id), + ); decl.add_method( sel!(windowDidBecomeKey:), window_did_change_key_status as extern "C" fn(&Object, Sel, id), @@ -276,6 +284,7 @@ struct WindowState { event_callback: Option bool>>, activate_callback: Option>, resize_callback: Option>, + fullscreen_callback: Option>, should_close_callback: Option bool>>, close_callback: Option>, input_handler: Option>, @@ -368,6 +377,7 @@ impl Window { should_close_callback: None, close_callback: None, activate_callback: None, + fullscreen_callback: None, input_handler: None, pending_key_down: None, performed_key_equivalent: false, @@ -467,6 +477,10 @@ impl platform::Window for Window { self.0.as_ref().borrow_mut().resize_callback = Some(callback); } + fn on_fullscreen(&mut self, callback: Box) { + self.0.as_ref().borrow_mut().fullscreen_callback = Some(callback); + } + fn on_should_close(&mut self, callback: Box bool>) { self.0.as_ref().borrow_mut().should_close_callback = Some(callback); } @@ -908,6 +922,24 @@ extern "C" fn window_did_resize(this: &Object, _: Sel, _: id) { window_state.as_ref().borrow().move_traffic_light(); } +extern "C" fn window_did_enter_fullscreen(this: &Object, _: Sel, _: id) { + window_fullscreen_changed(this, true); +} + +extern "C" fn window_did_exit_fullscreen(this: &Object, _: Sel, _: id) { + window_fullscreen_changed(this, false); +} + +fn window_fullscreen_changed(this: &Object, is_fullscreen: bool) { + let window_state = unsafe { get_window_state(this) }; + let mut window_state_borrow = window_state.as_ref().borrow_mut(); + if let Some(mut callback) = window_state_borrow.fullscreen_callback.take() { + drop(window_state_borrow); + callback(is_fullscreen); + window_state.borrow_mut().fullscreen_callback = Some(callback); + } +} + extern "C" fn window_did_change_key_status(this: &Object, selector: Sel, _: id) { let is_active = if selector == sel!(windowDidBecomeKey:) { true diff --git a/crates/gpui/src/platform/test.rs b/crates/gpui/src/platform/test.rs index 8ea55b5e0d3d71c077c201909c2622eb3bb310bb..3eb9b1e88efa354799b30af66eda18343b27d871 100644 --- a/crates/gpui/src/platform/test.rs +++ b/crates/gpui/src/platform/test.rs @@ -37,6 +37,7 @@ pub struct Window { event_handlers: Vec bool>>, resize_handlers: Vec>, close_handlers: Vec>, + fullscreen_handlers: Vec>, pub(crate) active_status_change_handlers: Vec>, pub(crate) should_close_handler: Option bool>>, pub(crate) title: Option, @@ -199,6 +200,7 @@ impl Window { close_handlers: Default::default(), should_close_handler: Default::default(), active_status_change_handlers: Default::default(), + fullscreen_handlers: Default::default(), scale_factor: 1.0, current_scene: None, title: None, @@ -253,6 +255,10 @@ impl super::Window for Window { self.active_status_change_handlers.push(callback); } + fn on_fullscreen(&mut self, callback: Box) { + self.fullscreen_handlers.push(callback) + } + fn on_resize(&mut self, callback: Box) { self.resize_handlers.push(callback); }