Checkpoint
This commit is contained in:
@@ -533,7 +533,7 @@
|
||||
// TODO: Move this to a dock open action
|
||||
"cmd-shift-c": "collab_panel::ToggleFocus",
|
||||
"cmd-alt-i": "zed::DebugElements",
|
||||
"ctrl-:": "editor::ToggleInlayHints",
|
||||
"ctrl-:": "editor::ToggleInlayHints"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -199,11 +199,20 @@ impl<T: Clone + Debug + Mul<S, Output = T>, S: Clone> MulAssign<S> for Size<T> {
|
||||
|
||||
impl<T: Eq + Debug + Clone> Eq for Size<T> {}
|
||||
|
||||
impl From<Size<Option<Pixels>>> for Size<Option<f32>> {
|
||||
fn from(size: Size<Option<Pixels>>) -> Self {
|
||||
// impl From<Size<Option<Pixels>>> for Size<Option<f32>> {
|
||||
// fn from(size: Size<Option<Pixels>>) -> Self {
|
||||
// Size {
|
||||
// width: size.width.map(|p| p.0 as f32),
|
||||
// height: size.height.map(|p| p.0 as f32),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
impl From<Size<Pixels>> for Size<GlobalPixels> {
|
||||
fn from(size: Size<Pixels>) -> Self {
|
||||
Size {
|
||||
width: size.width.map(|p| p.0 as f32),
|
||||
height: size.height.map(|p| p.0 as f32),
|
||||
width: GlobalPixels(size.width.0),
|
||||
height: GlobalPixels(size.height.0),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -257,6 +266,18 @@ impl<T: Clone + Debug + Sub<Output = T>> Bounds<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + Debug + PartialOrd + Add<T, Output = T> + Sub<Output = T>> Bounds<T> {
|
||||
pub fn intersects(&self, other: &Bounds<T>) -> bool {
|
||||
let my_lower_right = self.lower_right();
|
||||
let their_lower_right = other.lower_right();
|
||||
|
||||
self.origin.x < their_lower_right.x
|
||||
&& my_lower_right.x > other.origin.x
|
||||
&& self.origin.y < their_lower_right.y
|
||||
&& my_lower_right.y > other.origin.y
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + Debug + PartialOrd + Add<T, Output = T> + Sub<Output = T>> Bounds<T> {
|
||||
pub fn intersect(&self, other: &Self) -> Self {
|
||||
let upper_left = self.origin.max(&other.origin);
|
||||
@@ -698,6 +719,28 @@ impl From<DevicePixels> for ScaledPixels {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default, Add, AddAssign, Sub, SubAssign, Div, PartialEq, PartialOrd)]
|
||||
#[repr(transparent)]
|
||||
pub struct GlobalPixels(pub(crate) f32);
|
||||
|
||||
impl Debug for GlobalPixels {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{} px (global coordinate space)", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GlobalPixels> for f64 {
|
||||
fn from(global_pixels: GlobalPixels) -> Self {
|
||||
global_pixels.0 as f64
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for GlobalPixels {
|
||||
fn from(global_pixels: f64) -> Self {
|
||||
GlobalPixels(global_pixels as f32)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default, Add, Sub, Mul, Div)]
|
||||
pub struct Rems(f32);
|
||||
|
||||
@@ -964,3 +1007,42 @@ impl<T: IsZero + Debug + Clone> IsZero for Corners<T> {
|
||||
&& self.bottom_left.is_zero()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_bounds_intersects() {
|
||||
let bounds1 = Bounds {
|
||||
origin: Point { x: 0.0, y: 0.0 },
|
||||
size: Size {
|
||||
width: 5.0,
|
||||
height: 5.0,
|
||||
},
|
||||
};
|
||||
let bounds2 = Bounds {
|
||||
origin: Point { x: 4.0, y: 4.0 },
|
||||
size: Size {
|
||||
width: 5.0,
|
||||
height: 5.0,
|
||||
},
|
||||
};
|
||||
let bounds3 = Bounds {
|
||||
origin: Point { x: 10.0, y: 10.0 },
|
||||
size: Size {
|
||||
width: 5.0,
|
||||
height: 5.0,
|
||||
},
|
||||
};
|
||||
|
||||
// Test Case 1: Intersecting bounds
|
||||
assert_eq!(bounds1.intersects(&bounds2), true);
|
||||
|
||||
// Test Case 2: Non-Intersecting bounds
|
||||
assert_eq!(bounds1.intersects(&bounds3), false);
|
||||
|
||||
// Test Case 3: Bounds intersecting with themselves
|
||||
assert_eq!(bounds1.intersects(&bounds1), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ pub use elements::*;
|
||||
pub use executor::*;
|
||||
pub use geometry::*;
|
||||
pub use gpui3_macros::*;
|
||||
pub use image_cache::*;
|
||||
pub use platform::*;
|
||||
pub use refineable::*;
|
||||
pub use scene::*;
|
||||
|
||||
@@ -5,10 +5,10 @@ mod mac;
|
||||
#[cfg(any(test, feature = "test"))]
|
||||
mod test;
|
||||
|
||||
use crate::image_cache::RenderImageParams;
|
||||
use crate::{
|
||||
AnyWindowHandle, Bounds, DevicePixels, Executor, Font, FontId, FontMetrics, GlyphId, Pixels,
|
||||
Point, RenderGlyphParams, RenderSvgParams, Result, Scene, ShapedLine, SharedString, Size,
|
||||
AnyWindowHandle, Bounds, DevicePixels, Executor, Font, FontId, FontMetrics, GlobalPixels,
|
||||
GlyphId, Pixels, Point, RenderGlyphParams, RenderImageParams, RenderSvgParams, Result, Scene,
|
||||
ShapedLine, SharedString, Size,
|
||||
};
|
||||
use anyhow::anyhow;
|
||||
use async_task::Runnable;
|
||||
@@ -16,7 +16,6 @@ use futures::channel::oneshot;
|
||||
use seahash::SeaHasher;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::borrow::Cow;
|
||||
use std::ffi::c_void;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::{
|
||||
any::Any,
|
||||
@@ -27,7 +26,6 @@ use std::{
|
||||
str::FromStr,
|
||||
sync::Arc,
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub use events::*;
|
||||
pub use keystroke::*;
|
||||
@@ -54,8 +52,8 @@ pub trait Platform: 'static {
|
||||
fn hide_other_apps(&self);
|
||||
fn unhide_other_apps(&self);
|
||||
|
||||
fn screens(&self) -> Vec<Rc<dyn PlatformScreen>>;
|
||||
fn screen_by_id(&self, id: ScreenId) -> Option<Rc<dyn PlatformScreen>>;
|
||||
fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>>;
|
||||
fn display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>>;
|
||||
fn main_window(&self) -> Option<AnyWindowHandle>;
|
||||
fn open_window(
|
||||
&self,
|
||||
@@ -97,23 +95,23 @@ pub trait Platform: 'static {
|
||||
fn delete_credentials(&self, url: &str) -> Result<()>;
|
||||
}
|
||||
|
||||
pub trait PlatformScreen: Debug {
|
||||
fn id(&self) -> Option<ScreenId>;
|
||||
fn handle(&self) -> PlatformScreenHandle;
|
||||
pub trait PlatformDisplay: Debug {
|
||||
fn id(&self) -> DisplayId;
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
fn bounds(&self) -> Bounds<Pixels>;
|
||||
fn content_bounds(&self) -> Bounds<Pixels>;
|
||||
fn bounds(&self) -> Bounds<GlobalPixels>;
|
||||
fn link(&self) -> Box<dyn PlatformDisplayLink>;
|
||||
}
|
||||
|
||||
pub struct PlatformScreenHandle(pub *mut c_void);
|
||||
#[derive(PartialEq, Eq, Hash, Copy, Clone)]
|
||||
pub struct DisplayId(pub(crate) u32);
|
||||
|
||||
impl Debug for PlatformScreenHandle {
|
||||
impl Debug for DisplayId {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "PlatformScreenHandle({:p})", self.0)
|
||||
write!(f, "DisplayId({})", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for PlatformScreenHandle {}
|
||||
unsafe impl Send for DisplayId {}
|
||||
|
||||
pub trait PlatformWindow {
|
||||
fn bounds(&self) -> WindowBounds;
|
||||
@@ -121,7 +119,7 @@ pub trait PlatformWindow {
|
||||
fn scale_factor(&self) -> f32;
|
||||
fn titlebar_height(&self) -> Pixels;
|
||||
fn appearance(&self) -> WindowAppearance;
|
||||
fn screen(&self) -> Rc<dyn PlatformScreen>;
|
||||
fn display(&self) -> Rc<dyn PlatformDisplay>;
|
||||
fn mouse_position(&self) -> Point<Pixels>;
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
fn set_input_handler(&mut self, input_handler: Box<dyn PlatformInputHandler>);
|
||||
@@ -158,6 +156,12 @@ pub trait PlatformDispatcher: Send + Sync {
|
||||
fn dispatch_on_main_thread(&self, task: Runnable);
|
||||
}
|
||||
|
||||
pub trait PlatformDisplayLink {
|
||||
fn set_output_callback(&mut self, callback: Box<dyn FnMut(&VideoTimestamp, &VideoTimestamp)>);
|
||||
fn start(&mut self);
|
||||
fn stop(&mut self);
|
||||
}
|
||||
|
||||
pub trait PlatformTextSystem: Send + Sync {
|
||||
fn add_fonts(&self, fonts: &[Arc<Vec<u8>>]) -> Result<()>;
|
||||
fn all_font_families(&self) -> Vec<String>;
|
||||
@@ -266,9 +270,6 @@ pub trait PlatformInputHandler {
|
||||
fn bounds_for_range(&self, range_utf16: Range<usize>) -> Option<Bounds<f32>>;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub struct ScreenId(pub(crate) Uuid);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WindowOptions {
|
||||
pub bounds: WindowBounds,
|
||||
@@ -278,7 +279,7 @@ pub struct WindowOptions {
|
||||
pub show: bool,
|
||||
pub kind: WindowKind,
|
||||
pub is_movable: bool,
|
||||
pub screen: Option<PlatformScreenHandle>,
|
||||
pub display_id: Option<DisplayId>,
|
||||
}
|
||||
|
||||
impl Default for WindowOptions {
|
||||
@@ -295,7 +296,7 @@ impl Default for WindowOptions {
|
||||
show: true,
|
||||
kind: WindowKind::Normal,
|
||||
is_movable: true,
|
||||
screen: None,
|
||||
display_id: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -332,7 +333,7 @@ pub enum WindowBounds {
|
||||
Fullscreen,
|
||||
#[default]
|
||||
Maximized,
|
||||
Fixed(Bounds<Pixels>),
|
||||
Fixed(Bounds<GlobalPixels>),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
///! Macos screen have a y axis that goings up from the bottom of the screen and
|
||||
///! an origin at the bottom left of the main display.
|
||||
mod dispatcher;
|
||||
mod display;
|
||||
mod display_link;
|
||||
mod events;
|
||||
mod metal_atlas;
|
||||
mod metal_renderer;
|
||||
mod open_type;
|
||||
mod platform;
|
||||
mod screen;
|
||||
mod text_system;
|
||||
mod window;
|
||||
mod window_appearence;
|
||||
|
||||
use crate::{px, size, Pixels, Size};
|
||||
use crate::{px, size, GlobalPixels, Pixels, Size};
|
||||
use anyhow::anyhow;
|
||||
use cocoa::{
|
||||
base::{id, nil},
|
||||
@@ -31,9 +32,10 @@ use std::{
|
||||
};
|
||||
|
||||
pub use dispatcher::*;
|
||||
pub use display::*;
|
||||
pub use display_link::*;
|
||||
pub use metal_atlas::*;
|
||||
pub use platform::*;
|
||||
pub use screen::*;
|
||||
pub use text_system::*;
|
||||
pub use window::*;
|
||||
|
||||
@@ -119,23 +121,33 @@ pub trait NSRectExt {
|
||||
fn intersects(&self, other: Self) -> bool;
|
||||
}
|
||||
|
||||
impl NSRectExt for NSRect {
|
||||
fn size(&self) -> Size<Pixels> {
|
||||
size(px(self.size.width as f32), px(self.size.height as f32))
|
||||
}
|
||||
|
||||
fn intersects(&self, other: Self) -> bool {
|
||||
self.size.width > 0.
|
||||
&& self.size.height > 0.
|
||||
&& other.size.width > 0.
|
||||
&& other.size.height > 0.
|
||||
&& self.origin.x <= other.origin.x + other.size.width
|
||||
&& self.origin.x + self.size.width >= other.origin.x
|
||||
&& self.origin.y <= other.origin.y + other.size.height
|
||||
&& self.origin.y + self.size.height >= other.origin.y
|
||||
impl From<NSRect> for Size<Pixels> {
|
||||
fn from(rect: NSRect) -> Self {
|
||||
let NSSize { width, height } = rect.size;
|
||||
size(width.into(), height.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NSRect> for Size<GlobalPixels> {
|
||||
fn from(rect: NSRect) -> Self {
|
||||
let NSSize { width, height } = rect.size;
|
||||
size(width.into(), height.into())
|
||||
}
|
||||
}
|
||||
|
||||
// impl NSRectExt for NSRect {
|
||||
// fn intersects(&self, other: Self) -> bool {
|
||||
// self.size.width > 0.
|
||||
// && self.size.height > 0.
|
||||
// && other.size.width > 0.
|
||||
// && other.size.height > 0.
|
||||
// && self.origin.x <= other.origin.x + other.size.width
|
||||
// && self.origin.x + self.size.width >= other.origin.x
|
||||
// && self.origin.y <= other.origin.y + other.size.height
|
||||
// && self.origin.y + self.size.height >= other.origin.y
|
||||
// }
|
||||
// }
|
||||
|
||||
// todo!
|
||||
#[allow(unused)]
|
||||
unsafe fn ns_url_to_path(url: id) -> crate::Result<PathBuf> {
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
use crate::{point, size, Bounds, DisplayId, GlobalPixels, MacDisplayLink, PlatformDisplay};
|
||||
|
||||
use core_graphics::{
|
||||
display::{CGDirectDisplayID, CGGetActiveDisplayList},
|
||||
geometry::{CGPoint, CGRect, CGSize},
|
||||
};
|
||||
use std::any::Any;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MacDisplay(pub(crate) CGDirectDisplayID);
|
||||
|
||||
unsafe impl Send for MacDisplay {}
|
||||
|
||||
impl MacDisplay {
|
||||
/// Get the screen with the given UUID.
|
||||
pub fn find_by_id(id: DisplayId) -> Option<Self> {
|
||||
Self::all().find(|screen| screen.id() == id)
|
||||
}
|
||||
|
||||
/// Get the primary screen - the one with the menu bar, and whose bottom left
|
||||
/// corner is at the origin of the AppKit coordinate system.
|
||||
pub fn primary() -> Self {
|
||||
Self::all().next().unwrap()
|
||||
}
|
||||
|
||||
pub fn all() -> impl Iterator<Item = Self> {
|
||||
unsafe {
|
||||
let mut display_count: u32 = 0;
|
||||
let result = CGGetActiveDisplayList(0, std::ptr::null_mut(), &mut display_count);
|
||||
|
||||
if result == 0 {
|
||||
let mut displays = Vec::with_capacity(display_count as usize);
|
||||
CGGetActiveDisplayList(display_count, displays.as_mut_ptr(), &mut display_count);
|
||||
displays.set_len(display_count as usize);
|
||||
|
||||
displays.into_iter().map(|display| MacDisplay(display))
|
||||
} else {
|
||||
panic!("Failed to get active display list");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert the given rectangle from CoreGraphics' native coordinate space to GPUI's coordinate space.
|
||||
///
|
||||
/// CoreGraphics' coordinate space has its origin at the bottom left of the primary screen,
|
||||
/// with the Y axis pointing upwards.
|
||||
///
|
||||
/// Conversely, in GPUI's coordinate system, the origin is placed at the top left of the primary
|
||||
/// screen, with the Y axis pointing downwards.
|
||||
pub(crate) fn display_bounds_from_native(rect: CGRect) -> Bounds<GlobalPixels> {
|
||||
let primary_screen_height = MacDisplay::primary().bounds().size.height;
|
||||
Bounds {
|
||||
origin: point(
|
||||
GlobalPixels(rect.origin.x as f32),
|
||||
primary_screen_height
|
||||
- GlobalPixels(rect.origin.y as f32)
|
||||
- GlobalPixels(rect.size.height as f32),
|
||||
),
|
||||
size: size(
|
||||
GlobalPixels(rect.size.width as f32),
|
||||
GlobalPixels(rect.size.height as f32),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert the given rectangle from GPUI's coordinate system to CoreGraphics' native coordinate space.
|
||||
///
|
||||
/// CoreGraphics' coordinate space has its origin at the bottom left of the primary screen,
|
||||
/// with the Y axis pointing upwards.
|
||||
///
|
||||
/// Conversely, in GPUI's coordinate system, the origin is placed at the top left of the primary
|
||||
/// screen, with the Y axis pointing downwards.
|
||||
pub(crate) fn display_bounds_to_native(bounds: Bounds<GlobalPixels>) -> CGRect {
|
||||
let primary_screen_height = MacDisplay::primary().bounds().size.height;
|
||||
|
||||
CGRect::new(
|
||||
&CGPoint::new(
|
||||
bounds.origin.x.into(),
|
||||
(primary_screen_height - bounds.origin.y - bounds.size.height).into(),
|
||||
),
|
||||
&CGSize::new(bounds.size.width.into(), bounds.size.height.into()),
|
||||
)
|
||||
}
|
||||
|
||||
impl PlatformDisplay for MacDisplay {
|
||||
fn id(&self) -> DisplayId {
|
||||
DisplayId(self.0)
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn bounds(&self) -> Bounds<GlobalPixels> {
|
||||
unsafe {
|
||||
use core_graphics::display::*;
|
||||
|
||||
let display_id = self.0;
|
||||
// The `CGDisplayBounds` function gets the display bounds
|
||||
// for this display. The bounds are returned as a CGRect
|
||||
// and specify the display's location and size in
|
||||
// pixel units, in the global coordinate space.
|
||||
// // The global coordinate space is a coordinate system used by macOS. In this
|
||||
// coordinate space, the origin {0, 0} represents the top-left corner of the primary
|
||||
// display, and the positive X and Y axes extend from the origin to the right and downward,
|
||||
// respectively, towards the bottom-right corner of the primary display. For any display
|
||||
// connected to the system, the global coordinate space identifies the position and size
|
||||
// of the display with respect to the primary display.
|
||||
|
||||
// The coordinates in this coordinate space are typically in the form of a CGRect,
|
||||
// which represents the rectangle bounding the display in terms of pixels. The CGRect
|
||||
// holds the origin for the rect's bottom-left corner and a CGSize, which
|
||||
// represent width and height.
|
||||
|
||||
// With respect to the above `bounds` function in `PlatformDisplay` trait implementation,
|
||||
// this coordinate space is used to fetch a display ID's CGRect and position of origin, and size.
|
||||
let native_bounds = CGDisplayBounds(display_id);
|
||||
display_bounds_from_native(native_bounds)
|
||||
}
|
||||
}
|
||||
|
||||
fn link(&self) -> Box<dyn crate::PlatformDisplayLink> {
|
||||
Box::new(unsafe { MacDisplayLink::new(self.0) })
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
use crate::PlatformDisplayLink;
|
||||
use std::ffi::c_void;
|
||||
|
||||
pub use sys::CVTimeStamp as VideoTimestamp;
|
||||
|
||||
pub struct MacDisplayLink {
|
||||
sys_link: sys::DisplayLink,
|
||||
output_callback: Option<Box<dyn FnMut(&VideoTimestamp, &VideoTimestamp)>>,
|
||||
}
|
||||
|
||||
impl MacDisplayLink {
|
||||
pub unsafe fn new(display_id: u32) -> Self {
|
||||
Self {
|
||||
sys_link: sys::DisplayLink::on_display(display_id).unwrap(),
|
||||
output_callback: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PlatformDisplayLink for MacDisplayLink {
|
||||
fn set_output_callback(&mut self, callback: Box<dyn FnMut(&VideoTimestamp, &VideoTimestamp)>) {
|
||||
unsafe {
|
||||
self.sys_link.set_output_callback(
|
||||
trampoline,
|
||||
self.output_callback.as_mut().unwrap()
|
||||
as *mut dyn FnMut(&VideoTimestamp, &VideoTimestamp)
|
||||
as *mut c_void,
|
||||
);
|
||||
}
|
||||
self.output_callback = Some(callback);
|
||||
}
|
||||
|
||||
fn start(&mut self) {
|
||||
unsafe { self.sys_link.start() }
|
||||
}
|
||||
|
||||
fn stop(&mut self) {
|
||||
unsafe { self.sys_link.stop() }
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn trampoline(
|
||||
_display_link_out: *mut sys::CVDisplayLink,
|
||||
current_time: *const sys::CVTimeStamp,
|
||||
output_time: *const sys::CVTimeStamp,
|
||||
_flags_in: i64,
|
||||
_flags_out: *mut i64,
|
||||
context: *mut c_void,
|
||||
) -> i32 {
|
||||
let output_callback = &mut (*(context as *mut MacDisplayLink)).output_callback;
|
||||
if let Some(callback) = output_callback {
|
||||
if let Some((current_time, output_time)) = current_time.as_ref().zip(output_time.as_ref()) {
|
||||
// convert sys::CVTimeStamp to VideoTimestamp
|
||||
callback(¤t_time, &output_time);
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
mod sys {
|
||||
//! Derived from display-link crate under the fololwing license:
|
||||
//! https://github.com/BrainiumLLC/display-link/blob/master/LICENSE-MIT
|
||||
//! Apple docs: [CVDisplayLink](https://developer.apple.com/documentation/corevideo/cvdisplaylinkoutputcallback?language=objc)
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub use cocoa::quartzcore::CVTimeStamp;
|
||||
use foreign_types::{foreign_type, ForeignType};
|
||||
use std::{
|
||||
ffi::c_void,
|
||||
fmt::{Debug, Formatter, Result},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CVDisplayLink {}
|
||||
|
||||
foreign_type! {
|
||||
type CType = CVDisplayLink;
|
||||
fn drop = CVDisplayLinkRelease;
|
||||
fn clone = CVDisplayLinkRetain;
|
||||
pub struct DisplayLink;
|
||||
pub struct DisplayLinkRef;
|
||||
}
|
||||
|
||||
impl Debug for DisplayLink {
|
||||
fn fmt(&self, formatter: &mut Formatter) -> Result {
|
||||
formatter
|
||||
.debug_tuple("DisplayLink")
|
||||
.field(&self.as_ptr())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub type CVDisplayLinkOutputCallback = unsafe extern "C" fn(
|
||||
display_link_out: *mut CVDisplayLink,
|
||||
// A pointer to the current timestamp. This represents the timestamp when the callback is called.
|
||||
current_time: *const CVTimeStamp,
|
||||
// A pointer to the output timestamp. This represents the timestamp for when the frame will be displayed.
|
||||
output_time: *const CVTimeStamp,
|
||||
// Unused
|
||||
flags_in: i64,
|
||||
// Unused
|
||||
flags_out: *mut i64,
|
||||
// A pointer to app-defined data.
|
||||
display_link_context: *mut c_void,
|
||||
) -> i32;
|
||||
|
||||
#[link(name = "CoreFoundation", kind = "framework")]
|
||||
#[link(name = "CoreVideo", kind = "framework")]
|
||||
#[allow(improper_ctypes)]
|
||||
extern "C" {
|
||||
pub fn CVDisplayLinkCreateWithActiveCGDisplays(
|
||||
display_link_out: *mut *mut CVDisplayLink,
|
||||
) -> i32;
|
||||
pub fn CVDisplayLinkCreateWithCGDisplay(
|
||||
display_id: u32,
|
||||
display_link_out: *mut *mut CVDisplayLink,
|
||||
) -> i32;
|
||||
pub fn CVDisplayLinkSetOutputCallback(
|
||||
display_link: &mut DisplayLinkRef,
|
||||
callback: CVDisplayLinkOutputCallback,
|
||||
user_info: *mut c_void,
|
||||
) -> i32;
|
||||
pub fn CVDisplayLinkSetCurrentCGDisplay(
|
||||
display_link: &mut DisplayLinkRef,
|
||||
display_id: u32,
|
||||
) -> i32;
|
||||
pub fn CVDisplayLinkStart(display_link: &mut DisplayLinkRef) -> i32;
|
||||
pub fn CVDisplayLinkStop(display_link: &mut DisplayLinkRef) -> i32;
|
||||
pub fn CVDisplayLinkRelease(display_link: *mut CVDisplayLink);
|
||||
pub fn CVDisplayLinkRetain(display_link: *mut CVDisplayLink) -> *mut CVDisplayLink;
|
||||
}
|
||||
|
||||
impl DisplayLink {
|
||||
/// Apple docs: [CVDisplayLinkCreateWithActiveCGDisplays](https://developer.apple.com/documentation/corevideo/1456863-cvdisplaylinkcreatewithactivecgd?language=objc)
|
||||
pub unsafe fn new() -> Option<Self> {
|
||||
let mut display_link: *mut CVDisplayLink = 0 as _;
|
||||
let code = CVDisplayLinkCreateWithActiveCGDisplays(&mut display_link);
|
||||
if code == 0 {
|
||||
Some(DisplayLink::from_ptr(display_link))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Apple docs: [CVDisplayLinkCreateWithCGDisplay](https://developer.apple.com/documentation/corevideo/1456981-cvdisplaylinkcreatewithcgdisplay?language=objc)
|
||||
pub unsafe fn on_display(display_id: u32) -> Option<Self> {
|
||||
let mut display_link: *mut CVDisplayLink = 0 as _;
|
||||
let code = CVDisplayLinkCreateWithCGDisplay(display_id, &mut display_link);
|
||||
if code == 0 {
|
||||
Some(DisplayLink::from_ptr(display_link))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DisplayLinkRef {
|
||||
/// Apple docs: [CVDisplayLinkSetOutputCallback](https://developer.apple.com/documentation/corevideo/1457096-cvdisplaylinksetoutputcallback?language=objc)
|
||||
pub unsafe fn set_output_callback(
|
||||
&mut self,
|
||||
callback: CVDisplayLinkOutputCallback,
|
||||
user_info: *mut c_void,
|
||||
) {
|
||||
assert_eq!(CVDisplayLinkSetOutputCallback(self, callback, user_info), 0);
|
||||
}
|
||||
|
||||
/// Apple docs: [CVDisplayLinkSetCurrentCGDisplay](https://developer.apple.com/documentation/corevideo/1456768-cvdisplaylinksetcurrentcgdisplay?language=objc)
|
||||
pub unsafe fn set_current_display(&mut self, display_id: u32) {
|
||||
assert_eq!(CVDisplayLinkSetCurrentCGDisplay(self, display_id), 0);
|
||||
}
|
||||
|
||||
/// Apple docs: [CVDisplayLinkStart](https://developer.apple.com/documentation/corevideo/1457193-cvdisplaylinkstart?language=objc)
|
||||
pub unsafe fn start(&mut self) {
|
||||
assert_eq!(CVDisplayLinkStart(self), 0);
|
||||
}
|
||||
|
||||
/// Apple docs: [CVDisplayLinkStop](https://developer.apple.com/documentation/corevideo/1457281-cvdisplaylinkstop?language=objc)
|
||||
pub unsafe fn stop(&mut self) {
|
||||
assert_eq!(CVDisplayLinkStop(self), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
use super::BoolExt;
|
||||
use crate::{
|
||||
AnyWindowHandle, ClipboardItem, CursorStyle, Event, Executor, MacDispatcher, MacScreen,
|
||||
MacTextSystem, MacWindow, PathPromptOptions, Platform, PlatformScreen, PlatformTextSystem,
|
||||
PlatformWindow, Result, ScreenId, SemanticVersion, WindowOptions,
|
||||
AnyWindowHandle, ClipboardItem, CursorStyle, DisplayId, Event, Executor, MacDispatcher,
|
||||
MacDisplay, MacTextSystem, MacWindow, PathPromptOptions, Platform, PlatformDisplay,
|
||||
PlatformTextSystem, PlatformWindow, Result, SemanticVersion, WindowOptions,
|
||||
};
|
||||
use anyhow::anyhow;
|
||||
use block::ConcreteBlock;
|
||||
@@ -455,21 +455,21 @@ impl Platform for MacPlatform {
|
||||
}
|
||||
}
|
||||
|
||||
fn screens(&self) -> Vec<Rc<dyn PlatformScreen>> {
|
||||
MacScreen::all()
|
||||
fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
|
||||
MacDisplay::all()
|
||||
.into_iter()
|
||||
.map(|screen| Rc::new(screen) as Rc<_>)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn screen_by_id(&self, id: ScreenId) -> Option<Rc<dyn PlatformScreen>> {
|
||||
MacScreen::find_by_id(id).map(|screen| Rc::new(screen) as Rc<_>)
|
||||
}
|
||||
|
||||
// fn add_status_item(&self, _handle: AnyWindowHandle) -> Box<dyn platform::Window> {
|
||||
// Box::new(StatusItem::add(self.fonts()))
|
||||
// }
|
||||
|
||||
fn display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
|
||||
MacDisplay::find_by_id(id).map(|screen| Rc::new(screen) as Rc<_>)
|
||||
}
|
||||
|
||||
fn main_window(&self) -> Option<AnyWindowHandle> {
|
||||
MacWindow::main_window()
|
||||
}
|
||||
@@ -736,6 +736,32 @@ impl Platform for MacPlatform {
|
||||
}
|
||||
}
|
||||
|
||||
// fn on_menu_command(&self, callback: Box<dyn FnMut(&dyn Action)>) {
|
||||
// self.0.lock().menu_command = Some(callback);
|
||||
// }
|
||||
|
||||
// fn on_will_open_menu(&self, callback: Box<dyn FnMut()>) {
|
||||
// self.0.lock().will_open_menu = Some(callback);
|
||||
// }
|
||||
|
||||
// fn on_validate_menu_command(&self, callback: Box<dyn FnMut(&dyn Action) -> bool>) {
|
||||
// self.0.lock().validate_menu_command = Some(callback);
|
||||
// }
|
||||
|
||||
// fn set_menus(&self, menus: Vec<Menu>, keystroke_matcher: &KeymapMatcher) {
|
||||
// unsafe {
|
||||
// let app: id = msg_send![APP_CLASS, sharedApplication];
|
||||
// let mut state = self.0.lock();
|
||||
// let actions = &mut state.menu_actions;
|
||||
// app.setMainMenu_(self.create_menu_bar(
|
||||
// menus,
|
||||
// app.delegate(),
|
||||
// actions,
|
||||
// keystroke_matcher,
|
||||
// ));
|
||||
// }
|
||||
// }
|
||||
|
||||
fn read_from_clipboard(&self) -> Option<ClipboardItem> {
|
||||
let state = self.0.lock();
|
||||
unsafe {
|
||||
@@ -773,32 +799,6 @@ impl Platform for MacPlatform {
|
||||
}
|
||||
}
|
||||
|
||||
// fn on_menu_command(&self, callback: Box<dyn FnMut(&dyn Action)>) {
|
||||
// self.0.lock().menu_command = Some(callback);
|
||||
// }
|
||||
|
||||
// fn on_will_open_menu(&self, callback: Box<dyn FnMut()>) {
|
||||
// self.0.lock().will_open_menu = Some(callback);
|
||||
// }
|
||||
|
||||
// fn on_validate_menu_command(&self, callback: Box<dyn FnMut(&dyn Action) -> bool>) {
|
||||
// self.0.lock().validate_menu_command = Some(callback);
|
||||
// }
|
||||
|
||||
// fn set_menus(&self, menus: Vec<Menu>, keystroke_matcher: &KeymapMatcher) {
|
||||
// unsafe {
|
||||
// let app: id = msg_send![APP_CLASS, sharedApplication];
|
||||
// let mut state = self.0.lock();
|
||||
// let actions = &mut state.menu_actions;
|
||||
// app.setMainMenu_(self.create_menu_bar(
|
||||
// menus,
|
||||
// app.delegate(),
|
||||
// actions,
|
||||
// keystroke_matcher,
|
||||
// ));
|
||||
// }
|
||||
// }
|
||||
|
||||
fn write_credentials(&self, url: &str, username: &str, password: &[u8]) -> Result<()> {
|
||||
let url = CFString::from(url);
|
||||
let username = CFString::from(username);
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
use super::ns_string;
|
||||
use crate::{point, px, size, Bounds, Pixels, PlatformScreen, PlatformScreenHandle, ScreenId};
|
||||
use cocoa::{
|
||||
appkit::NSScreen,
|
||||
base::{id, nil},
|
||||
foundation::{NSArray, NSDictionary, NSPoint, NSRect, NSSize},
|
||||
};
|
||||
use core_foundation::{
|
||||
number::{kCFNumberIntType, CFNumberGetValue, CFNumberRef},
|
||||
uuid::{CFUUIDGetUUIDBytes, CFUUIDRef},
|
||||
};
|
||||
use core_graphics::display::CGDirectDisplayID;
|
||||
use objc::runtime::Object;
|
||||
use std::{any::Any, ffi::c_void};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[link(name = "ApplicationServices", kind = "framework")]
|
||||
extern "C" {
|
||||
pub fn CGDisplayCreateUUIDFromDisplayID(display: CGDirectDisplayID) -> CFUUIDRef;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MacScreen {
|
||||
pub(crate) native_screen: id,
|
||||
}
|
||||
|
||||
unsafe impl Send for MacScreen {}
|
||||
|
||||
impl MacScreen {
|
||||
pub(crate) fn from_handle(handle: PlatformScreenHandle) -> Self {
|
||||
Self {
|
||||
native_screen: handle.0 as *mut Object,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the screen with the given UUID.
|
||||
pub fn find_by_id(id: ScreenId) -> Option<Self> {
|
||||
Self::all().find(|screen| screen.id() == Some(id))
|
||||
}
|
||||
|
||||
/// Get the primary screen - the one with the menu bar, and whose bottom left
|
||||
/// corner is at the origin of the AppKit coordinate system.
|
||||
fn primary() -> Self {
|
||||
Self::all().next().unwrap()
|
||||
}
|
||||
|
||||
pub fn all() -> impl Iterator<Item = Self> {
|
||||
unsafe {
|
||||
let native_screens = NSScreen::screens(nil);
|
||||
(0..NSArray::count(native_screens)).map(move |ix| MacScreen {
|
||||
native_screen: native_screens.objectAtIndex(ix),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert the given rectangle in screen coordinates from GPUI's
|
||||
/// coordinate system to the AppKit coordinate system.
|
||||
///
|
||||
/// In GPUI's coordinates, the origin is at the top left of the primary screen, with
|
||||
/// the Y axis pointing downward. In the AppKit coordindate system, the origin is at the
|
||||
/// bottom left of the primary screen, with the Y axis pointing upward.
|
||||
pub(crate) fn screen_bounds_to_native(bounds: Bounds<Pixels>) -> NSRect {
|
||||
let primary_screen_height =
|
||||
px(unsafe { Self::primary().native_screen.frame().size.height } as f32);
|
||||
|
||||
NSRect::new(
|
||||
NSPoint::new(
|
||||
bounds.origin.x.into(),
|
||||
(primary_screen_height - bounds.origin.y - bounds.size.height).into(),
|
||||
),
|
||||
NSSize::new(bounds.size.width.into(), bounds.size.height.into()),
|
||||
)
|
||||
}
|
||||
|
||||
/// Convert the given rectangle in screen coordinates from the AppKit
|
||||
/// coordinate system to GPUI's coordinate system.
|
||||
///
|
||||
/// In GPUI's coordinates, the origin is at the top left of the primary screen, with
|
||||
/// the Y axis pointing downward. In the AppKit coordindate system, the origin is at the
|
||||
/// bottom left of the primary screen, with the Y axis pointing upward.
|
||||
pub(crate) fn screen_bounds_from_native(rect: NSRect) -> Bounds<Pixels> {
|
||||
let primary_screen_height = unsafe { Self::primary().native_screen.frame().size.height };
|
||||
Bounds {
|
||||
origin: point(
|
||||
px(rect.origin.x as f32),
|
||||
px((primary_screen_height - rect.origin.y - rect.size.height) as f32),
|
||||
),
|
||||
size: size(px(rect.size.width as f32), px(rect.size.height as f32)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PlatformScreen for MacScreen {
|
||||
fn id(&self) -> Option<ScreenId> {
|
||||
unsafe {
|
||||
// This approach is similar to that which winit takes
|
||||
// https://github.com/rust-windowing/winit/blob/402cbd55f932e95dbfb4e8b5e8551c49e56ff9ac/src/platform_impl/macos/monitor.rs#L99
|
||||
let device_description = self.native_screen.deviceDescription();
|
||||
|
||||
let key = ns_string("NSScreenNumber");
|
||||
let device_id_obj = device_description.objectForKey_(key);
|
||||
if device_id_obj.is_null() {
|
||||
// Under some circumstances, especially display re-arrangements or display locking, we seem to get a null pointer
|
||||
// to the device id. See: https://linear.app/zed-industries/issue/Z-257/lock-screen-crash-with-multiple-monitors
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut device_id: u32 = 0;
|
||||
CFNumberGetValue(
|
||||
device_id_obj as CFNumberRef,
|
||||
kCFNumberIntType,
|
||||
(&mut device_id) as *mut _ as *mut c_void,
|
||||
);
|
||||
let cfuuid = CGDisplayCreateUUIDFromDisplayID(device_id as CGDirectDisplayID);
|
||||
if cfuuid.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let bytes = CFUUIDGetUUIDBytes(cfuuid);
|
||||
Some(ScreenId(Uuid::from_bytes([
|
||||
bytes.byte0,
|
||||
bytes.byte1,
|
||||
bytes.byte2,
|
||||
bytes.byte3,
|
||||
bytes.byte4,
|
||||
bytes.byte5,
|
||||
bytes.byte6,
|
||||
bytes.byte7,
|
||||
bytes.byte8,
|
||||
bytes.byte9,
|
||||
bytes.byte10,
|
||||
bytes.byte11,
|
||||
bytes.byte12,
|
||||
bytes.byte13,
|
||||
bytes.byte14,
|
||||
bytes.byte15,
|
||||
])))
|
||||
}
|
||||
}
|
||||
|
||||
fn handle(&self) -> PlatformScreenHandle {
|
||||
PlatformScreenHandle(self.native_screen as *mut c_void)
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn bounds(&self) -> Bounds<Pixels> {
|
||||
unsafe { Self::screen_bounds_from_native(self.native_screen.frame()) }
|
||||
}
|
||||
|
||||
fn content_bounds(&self) -> Bounds<Pixels> {
|
||||
unsafe { Self::screen_bounds_from_native(self.native_screen.visibleFrame()) }
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
use super::{ns_string, MetalRenderer, NSRange};
|
||||
use super::{display_bounds_from_native, ns_string, MacDisplay, MetalRenderer, NSRange};
|
||||
use crate::{
|
||||
point, px, size, AnyWindowHandle, Bounds, Event, Executor, KeyDownEvent, Keystroke, MacScreen,
|
||||
Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMovedEvent, MouseUpEvent,
|
||||
NSRectExt, Pixels, PlatformAtlas, PlatformInputHandler, PlatformScreen, PlatformWindow, Point,
|
||||
Scene, Size, Timer, WindowAppearance, WindowBounds, WindowKind, WindowOptions,
|
||||
WindowPromptLevel,
|
||||
display_bounds_to_native, point, px, size, AnyWindowHandle, Bounds, Event, Executor,
|
||||
GlobalPixels, KeyDownEvent, Keystroke, Modifiers, ModifiersChangedEvent, MouseButton,
|
||||
MouseDownEvent, MouseMovedEvent, MouseUpEvent, Pixels, PlatformAtlas, PlatformDisplay,
|
||||
PlatformInputHandler, PlatformWindow, Point, Scene, Size, Timer, WindowAppearance,
|
||||
WindowBounds, WindowKind, WindowOptions, WindowPromptLevel,
|
||||
};
|
||||
use block::ConcreteBlock;
|
||||
use cocoa::{
|
||||
@@ -14,7 +14,9 @@ use cocoa::{
|
||||
NSWindowStyleMask, NSWindowTitleVisibility,
|
||||
},
|
||||
base::{id, nil},
|
||||
foundation::{NSAutoreleasePool, NSInteger, NSPoint, NSRect, NSSize, NSString, NSUInteger},
|
||||
foundation::{
|
||||
NSAutoreleasePool, NSDictionary, NSInteger, NSPoint, NSRect, NSSize, NSString, NSUInteger,
|
||||
},
|
||||
};
|
||||
use core_graphics::display::CGRect;
|
||||
use ctor::ctor;
|
||||
@@ -365,7 +367,7 @@ impl MacWindowState {
|
||||
}
|
||||
|
||||
let frame = self.frame();
|
||||
let screen_size = self.native_window.screen().visibleFrame().size();
|
||||
let screen_size = self.native_window.screen().visibleFrame().into();
|
||||
if frame.size == screen_size {
|
||||
WindowBounds::Maximized
|
||||
} else {
|
||||
@@ -374,10 +376,10 @@ impl MacWindowState {
|
||||
}
|
||||
}
|
||||
|
||||
fn frame(&self) -> Bounds<Pixels> {
|
||||
fn frame(&self) -> Bounds<GlobalPixels> {
|
||||
unsafe {
|
||||
let frame = NSWindow::frame(self.native_window);
|
||||
MacScreen::screen_bounds_from_native(frame)
|
||||
display_bounds_from_native(mem::transmute::<NSRect, CGRect>(frame))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,15 +443,33 @@ impl MacWindow {
|
||||
msg_send![PANEL_CLASS, alloc]
|
||||
}
|
||||
};
|
||||
|
||||
let display = options
|
||||
.display_id
|
||||
.and_then(|display_id| MacDisplay::all().find(|display| display.id() == display_id))
|
||||
.unwrap_or_else(|| MacDisplay::primary());
|
||||
|
||||
let mut target_screen = nil;
|
||||
let screens = NSScreen::screens(nil);
|
||||
let count: u64 = cocoa::foundation::NSArray::count(screens);
|
||||
for i in 0..count {
|
||||
let screen = cocoa::foundation::NSArray::objectAtIndex(screens, i);
|
||||
let device_description = NSScreen::deviceDescription(screen);
|
||||
let screen_number_key: id = NSString::alloc(nil).init_str("NSScreenNumber");
|
||||
let screen_number =
|
||||
NSDictionary::objectForKey_(device_description, screen_number_key);
|
||||
if (*(screen_number as *const u32)) == display.id().0 {
|
||||
target_screen = screen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let native_window = native_window.initWithContentRect_styleMask_backing_defer_screen_(
|
||||
NSRect::new(NSPoint::new(0., 0.), NSSize::new(1024., 768.)),
|
||||
style_mask,
|
||||
NSBackingStoreBuffered,
|
||||
NO,
|
||||
options
|
||||
.screen
|
||||
.map(|screen| MacScreen::from_handle(screen).native_screen)
|
||||
.unwrap_or(nil),
|
||||
target_screen,
|
||||
);
|
||||
assert!(!native_window.is_null());
|
||||
|
||||
@@ -462,13 +482,13 @@ impl MacWindow {
|
||||
native_window.setFrame_display_(screen.visibleFrame(), YES);
|
||||
}
|
||||
WindowBounds::Fixed(bounds) => {
|
||||
let bounds = MacScreen::screen_bounds_to_native(bounds);
|
||||
let screen_bounds = screen.visibleFrame();
|
||||
if bounds.intersects(screen_bounds) {
|
||||
native_window.setFrame_display_(bounds, YES);
|
||||
let display_bounds = display.bounds();
|
||||
let frame = if bounds.intersects(&display_bounds) {
|
||||
display_bounds_to_native(bounds)
|
||||
} else {
|
||||
native_window.setFrame_display_(screen_bounds, YES);
|
||||
}
|
||||
display_bounds_to_native(display_bounds)
|
||||
};
|
||||
native_window.setFrame_display_(mem::transmute::<CGRect, NSRect>(frame), YES);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -649,11 +669,18 @@ impl PlatformWindow for MacWindow {
|
||||
}
|
||||
}
|
||||
|
||||
fn screen(&self) -> Rc<dyn PlatformScreen> {
|
||||
fn display(&self) -> Rc<dyn PlatformDisplay> {
|
||||
unsafe {
|
||||
Rc::new(MacScreen {
|
||||
native_screen: self.0.as_ref().lock().native_window.screen(),
|
||||
})
|
||||
let screen = self.0.lock().native_window.screen();
|
||||
let device_description: id = msg_send![screen, deviceDescription];
|
||||
let screen_number: id = NSDictionary::valueForKey_(
|
||||
device_description,
|
||||
NSString::alloc(nil).init_str("NSScreenNumber"),
|
||||
);
|
||||
|
||||
let screen_number: u32 = msg_send![screen_number, unsignedIntValue];
|
||||
|
||||
Rc::new(MacDisplay(screen_number))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::Platform;
|
||||
use crate::{Executor, ScreenId};
|
||||
use crate::{DisplayId, Executor};
|
||||
|
||||
pub struct TestPlatform;
|
||||
|
||||
@@ -47,11 +47,11 @@ impl Platform for TestPlatform {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn screens(&self) -> Vec<std::rc::Rc<dyn crate::PlatformScreen>> {
|
||||
fn displays(&self) -> Vec<std::rc::Rc<dyn crate::PlatformDisplay>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn screen_by_id(&self, _id: ScreenId) -> Option<std::rc::Rc<dyn crate::PlatformScreen>> {
|
||||
fn display(&self, _id: DisplayId) -> Option<std::rc::Rc<dyn crate::PlatformDisplay>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ fn main() {
|
||||
WindowOptions {
|
||||
bounds: WindowBounds::Fixed(Bounds {
|
||||
origin: Default::default(),
|
||||
size: size(px(800.), px(600.)),
|
||||
size: size(px(800.), px(600.)).into(),
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user