@@ -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<ElementBox> {
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<usize>,
is_active: bool,
+ is_fullscreen: bool,
invalidation: Option<WindowInvalidation>,
}
@@ -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
}
@@ -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<Box<dyn FnMut(Event) -> bool>>,
activate_callback: Option<Box<dyn FnMut(bool)>>,
resize_callback: Option<Box<dyn FnMut()>>,
+ fullscreen_callback: Option<Box<dyn FnMut(bool)>>,
should_close_callback: Option<Box<dyn FnMut() -> bool>>,
close_callback: Option<Box<dyn FnOnce()>>,
input_handler: Option<Box<dyn InputHandler>>,
@@ -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<dyn FnMut(bool)>) {
+ self.0.as_ref().borrow_mut().fullscreen_callback = Some(callback);
+ }
+
fn on_should_close(&mut self, callback: Box<dyn FnMut() -> 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
@@ -37,6 +37,7 @@ pub struct Window {
event_handlers: Vec<Box<dyn FnMut(super::Event) -> bool>>,
resize_handlers: Vec<Box<dyn FnMut()>>,
close_handlers: Vec<Box<dyn FnOnce()>>,
+ fullscreen_handlers: Vec<Box<dyn FnMut(bool)>>,
pub(crate) active_status_change_handlers: Vec<Box<dyn FnMut(bool)>>,
pub(crate) should_close_handler: Option<Box<dyn FnMut() -> bool>>,
pub(crate) title: Option<String>,
@@ -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<dyn FnMut(bool)>) {
+ self.fullscreen_handlers.push(callback)
+ }
+
fn on_resize(&mut self, callback: Box<dyn FnMut()>) {
self.resize_handlers.push(callback);
}