From 5a8061ac7bce1c0b2742c01d50cc0ad7fc1a7bc9 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 26 Oct 2022 12:04:45 +0200 Subject: [PATCH 1/4] Add the ability to open a window on a given screen This is done by supplying the screen in the `WindowOptions` struct. Note that it's optional, and we will let the operating system choose which screen to show the window on when `screen` is not provided, as we did before this change. --- crates/gpui/src/platform.rs | 11 ++++-- crates/gpui/src/platform/mac.rs | 1 + crates/gpui/src/platform/mac/platform.rs | 20 +++++------ crates/gpui/src/platform/mac/screen.rs | 44 ++++++++++++++++++++++++ crates/gpui/src/platform/mac/window.rs | 10 ++++-- crates/gpui/src/platform/test.rs | 4 +-- 6 files changed, 73 insertions(+), 17 deletions(-) create mode 100644 crates/gpui/src/platform/mac/screen.rs diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 9fc2c16497fa4f14db8ecc2a671fe119b68b5527..d2aee035ff0ffc40d259982b2e9b8c5d302e668b 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -25,7 +25,7 @@ use postage::oneshot; use serde::Deserialize; use std::{ any::Any, - fmt::{self, Display}, + fmt::{self, Debug, Display}, ops::Range, path::{Path, PathBuf}, rc::Rc, @@ -44,7 +44,7 @@ pub trait Platform: Send + Sync { fn unhide_other_apps(&self); fn quit(&self); - fn screen_size(&self) -> Vector2F; + fn screens(&self) -> Vec>; fn open_window( &self, @@ -115,6 +115,11 @@ pub trait InputHandler { fn rect_for_range(&self, range_utf16: Range) -> Option; } +pub trait Screen: Debug { + fn as_any(&self) -> &dyn Any; + fn size(&self) -> Vector2F; +} + pub trait Window { fn as_any_mut(&mut self) -> &mut dyn Any; fn on_event(&mut self, callback: Box bool>); @@ -149,6 +154,7 @@ pub struct WindowOptions<'a> { pub center: bool, pub kind: WindowKind, pub is_movable: bool, + pub screen: Option>, } #[derive(Debug)] @@ -292,6 +298,7 @@ impl<'a> Default for WindowOptions<'a> { center: false, kind: WindowKind::Normal, is_movable: true, + screen: None, } } } diff --git a/crates/gpui/src/platform/mac.rs b/crates/gpui/src/platform/mac.rs index 90b378e4a644dacb22f6550ea4783db98caa7237..7eb080083e9d4e2ed2f74597b95ebc7217f120af 100644 --- a/crates/gpui/src/platform/mac.rs +++ b/crates/gpui/src/platform/mac.rs @@ -7,6 +7,7 @@ mod geometry; mod image_cache; mod platform; mod renderer; +mod screen; mod sprite_cache; mod status_item; mod window; diff --git a/crates/gpui/src/platform/mac/platform.rs b/crates/gpui/src/platform/mac/platform.rs index a27220cf2eac85e775227d8887bc5b7e18255279..f703d863be4113d62a0b68f60c6d09aae0b53f3d 100644 --- a/crates/gpui/src/platform/mac/platform.rs +++ b/crates/gpui/src/platform/mac/platform.rs @@ -1,10 +1,9 @@ use super::{ - event::key_to_native, status_item::StatusItem, BoolExt as _, Dispatcher, FontSystem, Window, + event::key_to_native, screen::Screen, status_item::StatusItem, BoolExt as _, Dispatcher, + FontSystem, Window, }; use crate::{ - executor, - geometry::vector::{vec2f, Vector2F}, - keymap, + executor, keymap, platform::{self, CursorStyle}, Action, AppVersion, ClipboardItem, Event, Menu, MenuItem, }; @@ -14,7 +13,7 @@ use cocoa::{ appkit::{ NSApplication, NSApplicationActivationPolicy::NSApplicationActivationPolicyRegular, NSEventModifierFlags, NSMenu, NSMenuItem, NSModalResponse, NSOpenPanel, NSPasteboard, - NSPasteboardTypeString, NSSavePanel, NSScreen, NSWindow, + NSPasteboardTypeString, NSSavePanel, NSWindow, }, base::{id, nil, selector, YES}, foundation::{ @@ -488,12 +487,11 @@ impl platform::Platform for MacPlatform { } } - fn screen_size(&self) -> Vector2F { - unsafe { - let screen = NSScreen::mainScreen(nil); - let frame = NSScreen::frame(screen); - vec2f(frame.size.width as f32, frame.size.height as f32) - } + fn screens(&self) -> Vec> { + Screen::all() + .into_iter() + .map(|screen| Rc::new(screen) as Rc<_>) + .collect() } fn open_window( diff --git a/crates/gpui/src/platform/mac/screen.rs b/crates/gpui/src/platform/mac/screen.rs new file mode 100644 index 0000000000000000000000000000000000000000..fdc7fbb50581a1d13f465e23ed1d7c50187fb590 --- /dev/null +++ b/crates/gpui/src/platform/mac/screen.rs @@ -0,0 +1,44 @@ +use std::any::Any; + +use crate::{ + geometry::vector::{vec2f, Vector2F}, + platform, +}; +use cocoa::{ + appkit::NSScreen, + base::{id, nil}, + foundation::NSArray, +}; + +#[derive(Debug)] +pub struct Screen { + pub(crate) native_screen: id, +} + +impl Screen { + pub fn all() -> Vec { + let mut screens = Vec::new(); + unsafe { + let native_screens = NSScreen::screens(nil); + for ix in 0..native_screens.count() { + screens.push(Screen { + native_screen: native_screens.objectAtIndex(ix), + }); + } + } + screens + } +} + +impl platform::Screen for Screen { + fn as_any(&self) -> &dyn Any { + self + } + + fn size(&self) -> Vector2F { + unsafe { + let frame = self.native_screen.frame(); + vec2f(frame.size.width as f32, frame.size.height as f32) + } + } +} diff --git a/crates/gpui/src/platform/mac/window.rs b/crates/gpui/src/platform/mac/window.rs index 688c0eabcfed27a2cd344bd510ead37cc979713d..2a416ce9f513b83ac08beea0339131412e3d2c95 100644 --- a/crates/gpui/src/platform/mac/window.rs +++ b/crates/gpui/src/platform/mac/window.rs @@ -8,7 +8,7 @@ use crate::{ mac::platform::NSViewLayerContentsRedrawDuringViewResize, platform::{ self, - mac::{geometry::RectFExt, renderer::Renderer}, + mac::{geometry::RectFExt, renderer::Renderer, screen::Screen}, Event, WindowBounds, }, InputHandler, KeyDownEvent, ModifiersChangedEvent, MouseButton, MouseButtonEvent, @@ -377,11 +377,17 @@ impl Window { msg_send![PANEL_CLASS, alloc] } }; - let native_window = native_window.initWithContentRect_styleMask_backing_defer_( + let native_window = native_window.initWithContentRect_styleMask_backing_defer_screen_( RectF::new(Default::default(), vec2f(1024., 768.)).to_ns_rect(), style_mask, NSBackingStoreBuffered, NO, + options + .screen + .and_then(|screen| { + Some(screen.as_any().downcast_ref::()?.native_screen) + }) + .unwrap_or(nil), ); assert!(!native_window.is_null()); diff --git a/crates/gpui/src/platform/test.rs b/crates/gpui/src/platform/test.rs index 2a44616cdd89d4739e49fa88ef506cd055039f42..1bd92eb6e37f4bc8aee1a347f57ce673c7f4814d 100644 --- a/crates/gpui/src/platform/test.rs +++ b/crates/gpui/src/platform/test.rs @@ -131,8 +131,8 @@ impl super::Platform for Platform { fn quit(&self) {} - fn screen_size(&self) -> Vector2F { - vec2f(1024., 768.) + fn screens(&self) -> Vec> { + Default::default() } fn open_window( From 5984be3d84ecf2dc6e3bfcbae3197fb88a9a01c5 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 26 Oct 2022 12:05:56 +0200 Subject: [PATCH 2/4] Display call notifications on all screens --- .../src/incoming_call_notification.rs | 39 ++++++------ .../src/project_shared_notification.rs | 62 +++++++++++-------- crates/zed/src/zed.rs | 1 + 3 files changed, 58 insertions(+), 44 deletions(-) diff --git a/crates/collab_ui/src/incoming_call_notification.rs b/crates/collab_ui/src/incoming_call_notification.rs index ff359b9d9e087219cfabb95fd0c719b67183aa44..32b97274b355011cfeb2b2281209c55256f8c87d 100644 --- a/crates/collab_ui/src/incoming_call_notification.rs +++ b/crates/collab_ui/src/incoming_call_notification.rs @@ -18,34 +18,37 @@ pub fn init(cx: &mut MutableAppContext) { let mut incoming_call = ActiveCall::global(cx).read(cx).incoming(); cx.spawn(|mut cx| async move { - let mut notification_window = None; + let mut notification_windows = Vec::new(); while let Some(incoming_call) = incoming_call.next().await { - if let Some(window_id) = notification_window.take() { + for window_id in notification_windows.drain(..) { cx.remove_window(window_id); } if let Some(incoming_call) = incoming_call { const PADDING: f32 = 16.; - let screen_size = cx.platform().screen_size(); - let window_size = cx.read(|cx| { let theme = &cx.global::().theme.incoming_call_notification; vec2f(theme.window_width, theme.window_height) }); - let (window_id, _) = cx.add_window( - WindowOptions { - bounds: WindowBounds::Fixed(RectF::new( - vec2f(screen_size.x() - window_size.x() - PADDING, PADDING), - window_size, - )), - titlebar: None, - center: false, - kind: WindowKind::PopUp, - is_movable: false, - }, - |_| IncomingCallNotification::new(incoming_call), - ); - notification_window = Some(window_id); + + for screen in cx.platform().screens() { + let screen_size = screen.size(); + let (window_id, _) = cx.add_window( + WindowOptions { + bounds: WindowBounds::Fixed(RectF::new( + vec2f(screen_size.x() - window_size.x() - PADDING, PADDING), + window_size, + )), + titlebar: None, + center: false, + kind: WindowKind::PopUp, + is_movable: false, + screen: Some(screen), + }, + |_| IncomingCallNotification::new(incoming_call.clone()), + ); + notification_windows.push(window_id); + } } } }) diff --git a/crates/collab_ui/src/project_shared_notification.rs b/crates/collab_ui/src/project_shared_notification.rs index e5ded819afeb0062ea2ce76b07fdf419cea45bb8..e814ae2720096c6467db41e9510ee2e8aadcedfc 100644 --- a/crates/collab_ui/src/project_shared_notification.rs +++ b/crates/collab_ui/src/project_shared_notification.rs @@ -27,39 +27,49 @@ pub fn init(cx: &mut MutableAppContext) { worktree_root_names, } => { const PADDING: f32 = 16.; - let screen_size = cx.platform().screen_size(); - let theme = &cx.global::().theme.project_shared_notification; let window_size = vec2f(theme.window_width, theme.window_height); - let (window_id, _) = cx.add_window( - WindowOptions { - bounds: WindowBounds::Fixed(RectF::new( - vec2f(screen_size.x() - window_size.x() - PADDING, PADDING), - window_size, - )), - titlebar: None, - center: false, - kind: WindowKind::PopUp, - is_movable: false, - }, - |_| { - ProjectSharedNotification::new( - owner.clone(), - *project_id, - worktree_root_names.clone(), - ) - }, - ); - notification_windows.insert(*project_id, window_id); + + for screen in cx.platform().screens() { + let screen_size = screen.size(); + let (window_id, _) = cx.add_window( + WindowOptions { + bounds: WindowBounds::Fixed(RectF::new( + vec2f(screen_size.x() - window_size.x() - PADDING, PADDING), + window_size, + )), + titlebar: None, + center: false, + kind: WindowKind::PopUp, + is_movable: false, + screen: Some(screen), + }, + |_| { + ProjectSharedNotification::new( + owner.clone(), + *project_id, + worktree_root_names.clone(), + ) + }, + ); + notification_windows + .entry(*project_id) + .or_insert(Vec::new()) + .push(window_id); + } } room::Event::RemoteProjectUnshared { project_id } => { - if let Some(window_id) = notification_windows.remove(&project_id) { - cx.remove_window(window_id); + if let Some(window_ids) = notification_windows.remove(&project_id) { + for window_id in window_ids { + cx.remove_window(window_id); + } } } room::Event::Left => { - for (_, window_id) in notification_windows.drain() { - cx.remove_window(window_id); + for (_, window_ids) in notification_windows.drain() { + for window_id in window_ids { + cx.remove_window(window_id); + } } } _ => {} diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index ef504026d5027c11e5319812f18db112d66a7533..d343e213d9e5a81919db0877d1eae6ecd1ade9c3 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -344,6 +344,7 @@ pub fn build_window_options() -> WindowOptions<'static> { center: false, kind: WindowKind::Normal, is_movable: true, + screen: None, } } From f611b443c04958b7d060d9c4af4bfd45f07d627d Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 26 Oct 2022 14:27:53 +0200 Subject: [PATCH 3/4] Convert window frame rect to screen coordinates --- crates/gpui/src/platform/mac/window.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/gpui/src/platform/mac/window.rs b/crates/gpui/src/platform/mac/window.rs index 2a416ce9f513b83ac08beea0339131412e3d2c95..55340a172716f82d70f6dba6bc99b6553c535850 100644 --- a/crates/gpui/src/platform/mac/window.rs +++ b/crates/gpui/src/platform/mac/window.rs @@ -406,8 +406,12 @@ impl Window { - top_left_bounds.height(), ), top_left_bounds.size(), + ) + .to_ns_rect(); + native_window.setFrame_display_( + native_window.convertRectToScreen_(bottom_left_bounds), + YES, ); - native_window.setFrame_display_(bottom_left_bounds.to_ns_rect(), YES); } } From 1e8536191484d7f352fb2049815322971b3c8f39 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 26 Oct 2022 14:30:48 +0200 Subject: [PATCH 4/4] Log instead of panicking when we can't retrieve a drawable --- crates/gpui/src/platform/mac/renderer.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/gpui/src/platform/mac/renderer.rs b/crates/gpui/src/platform/mac/renderer.rs index 6a70ff41f0a975cefa0fa2b3f9e28cda3dad61f3..24c44bb69833a2454cc7b18701bbf5d789ed30fd 100644 --- a/crates/gpui/src/platform/mac/renderer.rs +++ b/crates/gpui/src/platform/mac/renderer.rs @@ -189,7 +189,15 @@ impl Renderer { pub fn render(&mut self, scene: &Scene) { let layer = self.layer.clone(); let drawable_size = layer.drawable_size(); - let drawable = layer.next_drawable().unwrap(); + let drawable = if let Some(drawable) = layer.next_drawable() { + drawable + } else { + log::error!( + "failed to retrieve next drawable, drawable size: {:?}", + drawable_size + ); + return; + }; let command_queue = self.command_queue.clone(); let command_buffer = command_queue.new_command_buffer();