From de80974a1d5bb3beb877aae19d22638206386b2a Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 2 Nov 2023 16:11:52 +0100 Subject: [PATCH 1/3] Add `ViewContext::observe_fullscreen` Co-Authored-By: Conrad Irwin --- crates/gpui2/src/window.rs | 44 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index 0202b7521e..667ef6c486 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -6,8 +6,9 @@ use crate::{ Model, ModelContext, Modifiers, MonochromeSprite, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformWindow, Point, PolychromeSprite, PromptLevel, Quad, Render, RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels, - SceneBuilder, Shadow, SharedString, Size, Style, Subscription, TaffyLayoutEngine, Task, - Underline, UnderlineStyle, View, VisualContext, WeakView, WindowOptions, SUBPIXEL_VARIANTS, + SceneBuilder, Shadow, SharedString, Size, Style, SubscriberSet, Subscription, + TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, VisualContext, WeakView, + WindowOptions, SUBPIXEL_VARIANTS, }; use anyhow::{anyhow, Result}; use collections::HashMap; @@ -64,6 +65,7 @@ type AnyKeyListener = Box< + 'static, >; type AnyFocusListener = Box; +type AnyFullScreenListener = Box bool + 'static>; slotmap::new_key_type! { pub struct FocusId; } @@ -180,10 +182,12 @@ pub struct Window { focus_stack: Vec, focus_parents_by_child: HashMap, pub(crate) focus_listeners: Vec, + fullscreen_listeners: SubscriberSet<(), AnyFullScreenListener>, pub(crate) focus_handles: Arc>>, default_prevented: bool, mouse_position: Point, scale_factor: f32, + fullscreen: bool, pub(crate) scene_builder: SceneBuilder, pub(crate) dirty: bool, pub(crate) last_blur: Option>, @@ -202,6 +206,7 @@ impl Window { let mouse_position = platform_window.mouse_position(); let content_size = platform_window.content_size(); let scale_factor = platform_window.scale_factor(); + platform_window.on_resize(Box::new({ let mut cx = cx.to_async(); move |content_size, scale_factor| { @@ -216,6 +221,21 @@ impl Window { .log_err(); } })); + platform_window.on_fullscreen(Box::new({ + let mut cx = cx.to_async(); + move |fullscreen| { + handle + .update(&mut cx, |_, cx| { + cx.window.fullscreen = fullscreen; + cx.window + .fullscreen_listeners + .clone() + .retain(&(), |callback| callback(fullscreen, cx)); + cx.window.dirty = true; + }) + .log_err(); + } + })); platform_window.on_input({ let mut cx = cx.to_async(); @@ -250,10 +270,12 @@ impl Window { focus_stack: Vec::new(), focus_parents_by_child: HashMap::default(), focus_listeners: Vec::new(), + fullscreen_listeners: SubscriberSet::new(), focus_handles: Arc::new(RwLock::new(SlotMap::with_key())), default_prevented: true, mouse_position, scale_factor, + fullscreen: false, scene_builder: SceneBuilder::new(), dirty: true, last_blur: None, @@ -1710,6 +1732,24 @@ impl<'a, V: 'static> ViewContext<'a, V> { }); } + pub fn observe_fullscreen( + &mut self, + mut callback: impl FnMut(&mut V, bool, &mut ViewContext) + 'static, + ) -> Subscription { + let view = self.view.downgrade(); + self.window.fullscreen_listeners.insert( + (), + Box::new(move |fullscreen, cx| { + view.update(cx, |view, cx| callback(view, fullscreen, cx)) + .is_ok() + }), + ) + } + + // fn observe_window_activation(&mut self) -> Subscription {} + + // fn observe_window_bounds(&mut self) -> Subscription {} + pub fn on_focus_changed( &mut self, listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext) + 'static, From 3a824e468f8852204265f74a649b8fa652bdf4c5 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 2 Nov 2023 16:31:27 +0100 Subject: [PATCH 2/3] Subsume `observe_fullscreen` into `observe_window_bounds` Co-Authored-By: Conrad Irwin --- crates/gpui2/src/window.rs | 68 +++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index 667ef6c486..8d3afc9ae0 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -8,7 +8,7 @@ use crate::{ PromptLevel, Quad, Render, RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, Style, SubscriberSet, Subscription, TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, VisualContext, WeakView, - WindowOptions, SUBPIXEL_VARIANTS, + WindowBounds, WindowOptions, SUBPIXEL_VARIANTS, }; use anyhow::{anyhow, Result}; use collections::HashMap; @@ -54,6 +54,7 @@ pub enum DispatchPhase { Capture, } +type AnyObserver = Box bool + 'static>; type AnyListener = Box; type AnyKeyListener = Box< dyn Fn( @@ -65,7 +66,6 @@ type AnyKeyListener = Box< + 'static, >; type AnyFocusListener = Box; -type AnyFullScreenListener = Box bool + 'static>; slotmap::new_key_type! { pub struct FocusId; } @@ -182,12 +182,12 @@ pub struct Window { focus_stack: Vec, focus_parents_by_child: HashMap, pub(crate) focus_listeners: Vec, - fullscreen_listeners: SubscriberSet<(), AnyFullScreenListener>, pub(crate) focus_handles: Arc>>, default_prevented: bool, mouse_position: Point, scale_factor: f32, - fullscreen: bool, + bounds: WindowBounds, + bounds_observers: SubscriberSet<(), AnyObserver>, pub(crate) scene_builder: SceneBuilder, pub(crate) dirty: bool, pub(crate) last_blur: Option>, @@ -206,33 +206,21 @@ impl Window { let mouse_position = platform_window.mouse_position(); let content_size = platform_window.content_size(); let scale_factor = platform_window.scale_factor(); + let bounds = platform_window.bounds(); platform_window.on_resize(Box::new({ let mut cx = cx.to_async(); - move |content_size, scale_factor| { + move |_, _| { handle - .update(&mut cx, |_, cx| { - cx.window.scale_factor = scale_factor; - cx.window.scene_builder = SceneBuilder::new(); - cx.window.content_size = content_size; - cx.window.display_id = cx.window.platform_window.display().id(); - cx.window.dirty = true; - }) + .update(&mut cx, |_, cx| cx.window_bounds_changed()) .log_err(); } })); - platform_window.on_fullscreen(Box::new({ + platform_window.on_moved(Box::new({ let mut cx = cx.to_async(); - move |fullscreen| { + move || { handle - .update(&mut cx, |_, cx| { - cx.window.fullscreen = fullscreen; - cx.window - .fullscreen_listeners - .clone() - .retain(&(), |callback| callback(fullscreen, cx)); - cx.window.dirty = true; - }) + .update(&mut cx, |_, cx| cx.window_bounds_changed()) .log_err(); } })); @@ -270,12 +258,12 @@ impl Window { focus_stack: Vec::new(), focus_parents_by_child: HashMap::default(), focus_listeners: Vec::new(), - fullscreen_listeners: SubscriberSet::new(), focus_handles: Arc::new(RwLock::new(SlotMap::with_key())), default_prevented: true, mouse_position, scale_factor, - fullscreen: false, + bounds, + bounds_observers: SubscriberSet::new(), scene_builder: SceneBuilder::new(), dirty: true, last_blur: None, @@ -540,6 +528,23 @@ impl<'a> WindowContext<'a> { bounds } + fn window_bounds_changed(&mut self) { + self.window.scale_factor = self.window.platform_window.scale_factor(); + self.window.content_size = self.window.platform_window.content_size(); + self.window.bounds = self.window.platform_window.bounds(); + self.window.display_id = self.window.platform_window.display().id(); + self.window.dirty = true; + + self.window + .bounds_observers + .clone() + .retain(&(), |callback| callback(self)); + } + + pub fn window_bounds(&self) -> WindowBounds { + self.window.bounds + } + /// The scale factor of the display associated with the window. For example, it could /// return 2.0 for a "retina" display, indicating that each logical pixel should actually /// be rendered as two pixels on screen. @@ -1732,23 +1737,18 @@ impl<'a, V: 'static> ViewContext<'a, V> { }); } - pub fn observe_fullscreen( + pub fn observe_window_bounds( &mut self, - mut callback: impl FnMut(&mut V, bool, &mut ViewContext) + 'static, + mut callback: impl FnMut(&mut V, &mut ViewContext) + 'static, ) -> Subscription { let view = self.view.downgrade(); - self.window.fullscreen_listeners.insert( + self.window.bounds_observers.insert( (), - Box::new(move |fullscreen, cx| { - view.update(cx, |view, cx| callback(view, fullscreen, cx)) - .is_ok() - }), + Box::new(move |cx| view.update(cx, |view, cx| callback(view, cx)).is_ok()), ) } - // fn observe_window_activation(&mut self) -> Subscription {} - - // fn observe_window_bounds(&mut self) -> Subscription {} + fn observe_window_activation(&mut self) -> Subscription {} pub fn on_focus_changed( &mut self, From ec4f0d7bca73cc55c71882ab73ab96ebe6517a9c Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 2 Nov 2023 16:37:22 +0100 Subject: [PATCH 3/3] Implement `ViewContext::observe_window_activation` Co-Authored-By: Conrad Irwin --- crates/gpui2/src/window.rs | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index 8d3afc9ae0..f1335b3cff 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -188,6 +188,8 @@ pub struct Window { scale_factor: f32, bounds: WindowBounds, bounds_observers: SubscriberSet<(), AnyObserver>, + active: bool, + activation_observers: SubscriberSet<(), AnyObserver>, pub(crate) scene_builder: SceneBuilder, pub(crate) dirty: bool, pub(crate) last_blur: Option>, @@ -224,6 +226,20 @@ impl Window { .log_err(); } })); + platform_window.on_active_status_change(Box::new({ + let mut cx = cx.to_async(); + move |active| { + handle + .update(&mut cx, |_, cx| { + cx.window.active = active; + cx.window + .activation_observers + .clone() + .retain(&(), |callback| callback(cx)); + }) + .log_err(); + } + })); platform_window.on_input({ let mut cx = cx.to_async(); @@ -264,6 +280,8 @@ impl Window { scale_factor, bounds, bounds_observers: SubscriberSet::new(), + active: false, + activation_observers: SubscriberSet::new(), scene_builder: SceneBuilder::new(), dirty: true, last_blur: None, @@ -1748,7 +1766,16 @@ impl<'a, V: 'static> ViewContext<'a, V> { ) } - fn observe_window_activation(&mut self) -> Subscription {} + pub fn observe_window_activation( + &mut self, + mut callback: impl FnMut(&mut V, &mut ViewContext) + 'static, + ) -> Subscription { + let view = self.view.downgrade(); + self.window.activation_observers.insert( + (), + Box::new(move |cx| view.update(cx, |view, cx| callback(view, cx)).is_ok()), + ) + } pub fn on_focus_changed( &mut self,