1 use std::collections::VecDeque;
2 use std::fmt;
3 
4 use cocoa::appkit::NSScreen;
5 use cocoa::base::{id, nil};
6 use cocoa::foundation::{NSString, NSUInteger};
7 use core_graphics::display::{CGDirectDisplayID, CGDisplay, CGDisplayBounds};
8 
9 use {PhysicalPosition, PhysicalSize};
10 use super::EventsLoop;
11 use super::window::{IdRef, Window2};
12 
13 #[derive(Clone, PartialEq)]
14 pub struct MonitorId(CGDirectDisplayID);
15 
get_available_monitors() -> VecDeque<MonitorId>16 fn get_available_monitors() -> VecDeque<MonitorId> {
17     if let Ok(displays) = CGDisplay::active_displays() {
18         let mut monitors = VecDeque::with_capacity(displays.len());
19         for d in displays {
20             monitors.push_back(MonitorId(d));
21         }
22         monitors
23     } else {
24         VecDeque::with_capacity(0)
25     }
26 }
27 
get_primary_monitor() -> MonitorId28 pub fn get_primary_monitor() -> MonitorId {
29     let id = MonitorId(CGDisplay::main().id);
30     id
31 }
32 
33 impl EventsLoop {
34     #[inline]
get_available_monitors(&self) -> VecDeque<MonitorId>35     pub fn get_available_monitors(&self) -> VecDeque<MonitorId> {
36         get_available_monitors()
37     }
38 
39     #[inline]
get_primary_monitor(&self) -> MonitorId40     pub fn get_primary_monitor(&self) -> MonitorId {
41         get_primary_monitor()
42     }
43 
make_monitor_from_display(id: CGDirectDisplayID) -> MonitorId44     pub fn make_monitor_from_display(id: CGDirectDisplayID) -> MonitorId {
45         let id = MonitorId(id);
46         id
47     }
48 }
49 
50 impl Window2 {
51     #[inline]
get_available_monitors(&self) -> VecDeque<MonitorId>52     pub fn get_available_monitors(&self) -> VecDeque<MonitorId> {
53         get_available_monitors()
54     }
55 
56     #[inline]
get_primary_monitor(&self) -> MonitorId57     pub fn get_primary_monitor(&self) -> MonitorId {
58         get_primary_monitor()
59     }
60 }
61 
62 impl fmt::Debug for MonitorId {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result63     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
64         #[derive(Debug)]
65         struct MonitorId {
66             name: Option<String>,
67             native_identifier: u32,
68             dimensions: PhysicalSize,
69             position: PhysicalPosition,
70             hidpi_factor: f64,
71         }
72 
73         let monitor_id_proxy = MonitorId {
74             name: self.get_name(),
75             native_identifier: self.get_native_identifier(),
76             dimensions: self.get_dimensions(),
77             position: self.get_position(),
78             hidpi_factor: self.get_hidpi_factor(),
79         };
80 
81         monitor_id_proxy.fmt(f)
82     }
83 }
84 
85 impl MonitorId {
get_name(&self) -> Option<String>86     pub fn get_name(&self) -> Option<String> {
87         let MonitorId(display_id) = *self;
88         let screen_num = CGDisplay::new(display_id).model_number();
89         Some(format!("Monitor #{}", screen_num))
90     }
91 
92     #[inline]
get_native_identifier(&self) -> u3293     pub fn get_native_identifier(&self) -> u32 {
94         self.0
95     }
96 
get_dimensions(&self) -> PhysicalSize97     pub fn get_dimensions(&self) -> PhysicalSize {
98         let MonitorId(display_id) = *self;
99         let display = CGDisplay::new(display_id);
100         let height = display.pixels_high();
101         let width = display.pixels_wide();
102         PhysicalSize::from_logical(
103             (width as f64, height as f64),
104             self.get_hidpi_factor(),
105         )
106     }
107 
108     #[inline]
get_position(&self) -> PhysicalPosition109     pub fn get_position(&self) -> PhysicalPosition {
110         let bounds = unsafe { CGDisplayBounds(self.get_native_identifier()) };
111         PhysicalPosition::from_logical(
112             (bounds.origin.x as f64, bounds.origin.y as f64),
113             self.get_hidpi_factor(),
114         )
115     }
116 
get_hidpi_factor(&self) -> f64117     pub fn get_hidpi_factor(&self) -> f64 {
118         let screen = match self.get_nsscreen() {
119             Some(screen) => screen,
120             None => return 1.0, // default to 1.0 when we can't find the screen
121         };
122         unsafe { NSScreen::backingScaleFactor(screen) as f64 }
123     }
124 
get_nsscreen(&self) -> Option<id>125     pub(crate) fn get_nsscreen(&self) -> Option<id> {
126         unsafe {
127             let native_id = self.get_native_identifier();
128             let screens = NSScreen::screens(nil);
129             let count: NSUInteger = msg_send![screens, count];
130             let key = IdRef::new(NSString::alloc(nil).init_str("NSScreenNumber"));
131             let mut matching_screen: Option<id> = None;
132             for i in 0..count {
133                 let screen = msg_send![screens, objectAtIndex: i as NSUInteger];
134                 let device_description = NSScreen::deviceDescription(screen);
135                 let value: id = msg_send![device_description, objectForKey:*key];
136                 if value != nil {
137                     let screen_number: NSUInteger = msg_send![value, unsignedIntegerValue];
138                     if screen_number as u32 == native_id {
139                         matching_screen = Some(screen);
140                         break;
141                     }
142                 }
143             }
144             matching_screen
145         }
146     }
147 }
148