From 5a8061ac7bce1c0b2742c01d50cc0ad7fc1a7bc9 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 26 Oct 2022 12:04:45 +0200 Subject: [PATCH] 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 9fc2c16497..d2aee035ff 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 90b378e4a6..7eb080083e 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 a27220cf2e..f703d863be 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 0000000000..fdc7fbb505 --- /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 688c0eabcf..2a416ce9f5 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 2a44616cdd..1bd92eb6e3 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(