1 #![cfg(target_os = "macos")]
2 
3 use std::os::raw::c_void;
4 
5 use crate::{
6     dpi::LogicalSize,
7     event_loop::EventLoopWindowTarget,
8     monitor::MonitorHandle,
9     window::{Window, WindowBuilder},
10 };
11 
12 /// Corresponds to `NSRequestUserAttentionType`.
13 #[derive(Debug, Clone, Copy, PartialEq)]
14 pub enum RequestUserAttentionType {
15     /// Corresponds to `NSCriticalRequest`.
16     ///
17     /// Dock icon will bounce until the application is focused.
18     Critical,
19 
20     /// Corresponds to `NSInformationalRequest`.
21     ///
22     /// Dock icon will bounce once.
23     Informational,
24 }
25 
26 impl Default for RequestUserAttentionType {
default() -> Self27     fn default() -> Self {
28         RequestUserAttentionType::Critical
29     }
30 }
31 
32 /// Additional methods on `Window` that are specific to MacOS.
33 pub trait WindowExtMacOS {
34     /// Returns a pointer to the cocoa `NSWindow` that is used by this window.
35     ///
36     /// The pointer will become invalid when the `Window` is destroyed.
ns_window(&self) -> *mut c_void37     fn ns_window(&self) -> *mut c_void;
38 
39     /// Returns a pointer to the cocoa `NSView` that is used by this window.
40     ///
41     /// The pointer will become invalid when the `Window` is destroyed.
ns_view(&self) -> *mut c_void42     fn ns_view(&self) -> *mut c_void;
43 
44     /// Request user attention, causing the application's dock icon to bounce.
45     /// Note that this has no effect if the application is already focused.
request_user_attention(&self, request_type: RequestUserAttentionType)46     fn request_user_attention(&self, request_type: RequestUserAttentionType);
47 
48     /// Returns whether or not the window is in simple fullscreen mode.
simple_fullscreen(&self) -> bool49     fn simple_fullscreen(&self) -> bool;
50 
51     /// Toggles a fullscreen mode that doesn't require a new macOS space.
52     /// Returns a boolean indicating whether the transition was successful (this
53     /// won't work if the window was already in the native fullscreen).
54     ///
55     /// This is how fullscreen used to work on macOS in versions before Lion.
56     /// And allows the user to have a fullscreen window without using another
57     /// space or taking control over the entire monitor.
set_simple_fullscreen(&self, fullscreen: bool) -> bool58     fn set_simple_fullscreen(&self, fullscreen: bool) -> bool;
59 
60     /// Returns whether or not the window has shadow.
has_shadow(&self) -> bool61     fn has_shadow(&self) -> bool;
62 
63     /// Sets whether or not the window has shadow.
set_has_shadow(&self, has_shadow: bool)64     fn set_has_shadow(&self, has_shadow: bool);
65 }
66 
67 impl WindowExtMacOS for Window {
68     #[inline]
ns_window(&self) -> *mut c_void69     fn ns_window(&self) -> *mut c_void {
70         self.window.ns_window()
71     }
72 
73     #[inline]
ns_view(&self) -> *mut c_void74     fn ns_view(&self) -> *mut c_void {
75         self.window.ns_view()
76     }
77 
78     #[inline]
request_user_attention(&self, request_type: RequestUserAttentionType)79     fn request_user_attention(&self, request_type: RequestUserAttentionType) {
80         self.window.request_user_attention(request_type)
81     }
82 
83     #[inline]
simple_fullscreen(&self) -> bool84     fn simple_fullscreen(&self) -> bool {
85         self.window.simple_fullscreen()
86     }
87 
88     #[inline]
set_simple_fullscreen(&self, fullscreen: bool) -> bool89     fn set_simple_fullscreen(&self, fullscreen: bool) -> bool {
90         self.window.set_simple_fullscreen(fullscreen)
91     }
92 
93     #[inline]
has_shadow(&self) -> bool94     fn has_shadow(&self) -> bool {
95         self.window.has_shadow()
96     }
97 
98     #[inline]
set_has_shadow(&self, has_shadow: bool)99     fn set_has_shadow(&self, has_shadow: bool) {
100         self.window.set_has_shadow(has_shadow)
101     }
102 }
103 
104 /// Corresponds to `NSApplicationActivationPolicy`.
105 #[derive(Debug, Clone, Copy, PartialEq)]
106 pub enum ActivationPolicy {
107     /// Corresponds to `NSApplicationActivationPolicyRegular`.
108     Regular,
109     /// Corresponds to `NSApplicationActivationPolicyAccessory`.
110     Accessory,
111     /// Corresponds to `NSApplicationActivationPolicyProhibited`.
112     Prohibited,
113 }
114 
115 impl Default for ActivationPolicy {
default() -> Self116     fn default() -> Self {
117         ActivationPolicy::Regular
118     }
119 }
120 
121 /// Additional methods on `WindowBuilder` that are specific to MacOS.
122 ///
123 /// **Note:** Properties dealing with the titlebar will be overwritten by the `with_decorations` method
124 /// on the base `WindowBuilder`:
125 ///
126 ///  - `with_titlebar_transparent`
127 ///  - `with_title_hidden`
128 ///  - `with_titlebar_hidden`
129 ///  - `with_titlebar_buttons_hidden`
130 ///  - `with_fullsize_content_view`
131 pub trait WindowBuilderExtMacOS {
132     /// Sets the activation policy for the window being built.
with_activation_policy(self, activation_policy: ActivationPolicy) -> WindowBuilder133     fn with_activation_policy(self, activation_policy: ActivationPolicy) -> WindowBuilder;
134     /// Enables click-and-drag behavior for the entire window, not just the titlebar.
with_movable_by_window_background(self, movable_by_window_background: bool) -> WindowBuilder135     fn with_movable_by_window_background(self, movable_by_window_background: bool)
136         -> WindowBuilder;
137     /// Makes the titlebar transparent and allows the content to appear behind it.
with_titlebar_transparent(self, titlebar_transparent: bool) -> WindowBuilder138     fn with_titlebar_transparent(self, titlebar_transparent: bool) -> WindowBuilder;
139     /// Hides the window title.
with_title_hidden(self, title_hidden: bool) -> WindowBuilder140     fn with_title_hidden(self, title_hidden: bool) -> WindowBuilder;
141     /// Hides the window titlebar.
with_titlebar_hidden(self, titlebar_hidden: bool) -> WindowBuilder142     fn with_titlebar_hidden(self, titlebar_hidden: bool) -> WindowBuilder;
143     /// Hides the window titlebar buttons.
with_titlebar_buttons_hidden(self, titlebar_buttons_hidden: bool) -> WindowBuilder144     fn with_titlebar_buttons_hidden(self, titlebar_buttons_hidden: bool) -> WindowBuilder;
145     /// Makes the window content appear behind the titlebar.
with_fullsize_content_view(self, fullsize_content_view: bool) -> WindowBuilder146     fn with_fullsize_content_view(self, fullsize_content_view: bool) -> WindowBuilder;
147     /// Build window with `resizeIncrements` property. Values must not be 0.
with_resize_increments(self, increments: LogicalSize<f64>) -> WindowBuilder148     fn with_resize_increments(self, increments: LogicalSize<f64>) -> WindowBuilder;
with_disallow_hidpi(self, disallow_hidpi: bool) -> WindowBuilder149     fn with_disallow_hidpi(self, disallow_hidpi: bool) -> WindowBuilder;
with_has_shadow(self, has_shadow: bool) -> WindowBuilder150     fn with_has_shadow(self, has_shadow: bool) -> WindowBuilder;
151 }
152 
153 impl WindowBuilderExtMacOS for WindowBuilder {
154     #[inline]
with_activation_policy(mut self, activation_policy: ActivationPolicy) -> WindowBuilder155     fn with_activation_policy(mut self, activation_policy: ActivationPolicy) -> WindowBuilder {
156         self.platform_specific.activation_policy = activation_policy;
157         self
158     }
159 
160     #[inline]
with_movable_by_window_background( mut self, movable_by_window_background: bool, ) -> WindowBuilder161     fn with_movable_by_window_background(
162         mut self,
163         movable_by_window_background: bool,
164     ) -> WindowBuilder {
165         self.platform_specific.movable_by_window_background = movable_by_window_background;
166         self
167     }
168 
169     #[inline]
with_titlebar_transparent(mut self, titlebar_transparent: bool) -> WindowBuilder170     fn with_titlebar_transparent(mut self, titlebar_transparent: bool) -> WindowBuilder {
171         self.platform_specific.titlebar_transparent = titlebar_transparent;
172         self
173     }
174 
175     #[inline]
with_titlebar_hidden(mut self, titlebar_hidden: bool) -> WindowBuilder176     fn with_titlebar_hidden(mut self, titlebar_hidden: bool) -> WindowBuilder {
177         self.platform_specific.titlebar_hidden = titlebar_hidden;
178         self
179     }
180 
181     #[inline]
with_titlebar_buttons_hidden(mut self, titlebar_buttons_hidden: bool) -> WindowBuilder182     fn with_titlebar_buttons_hidden(mut self, titlebar_buttons_hidden: bool) -> WindowBuilder {
183         self.platform_specific.titlebar_buttons_hidden = titlebar_buttons_hidden;
184         self
185     }
186 
187     #[inline]
with_title_hidden(mut self, title_hidden: bool) -> WindowBuilder188     fn with_title_hidden(mut self, title_hidden: bool) -> WindowBuilder {
189         self.platform_specific.title_hidden = title_hidden;
190         self
191     }
192 
193     #[inline]
with_fullsize_content_view(mut self, fullsize_content_view: bool) -> WindowBuilder194     fn with_fullsize_content_view(mut self, fullsize_content_view: bool) -> WindowBuilder {
195         self.platform_specific.fullsize_content_view = fullsize_content_view;
196         self
197     }
198 
199     #[inline]
with_resize_increments(mut self, increments: LogicalSize<f64>) -> WindowBuilder200     fn with_resize_increments(mut self, increments: LogicalSize<f64>) -> WindowBuilder {
201         self.platform_specific.resize_increments = Some(increments.into());
202         self
203     }
204 
205     #[inline]
with_disallow_hidpi(mut self, disallow_hidpi: bool) -> WindowBuilder206     fn with_disallow_hidpi(mut self, disallow_hidpi: bool) -> WindowBuilder {
207         self.platform_specific.disallow_hidpi = disallow_hidpi;
208         self
209     }
210 
211     #[inline]
with_has_shadow(mut self, has_shadow: bool) -> WindowBuilder212     fn with_has_shadow(mut self, has_shadow: bool) -> WindowBuilder {
213         self.platform_specific.has_shadow = has_shadow;
214         self
215     }
216 }
217 
218 /// Additional methods on `MonitorHandle` that are specific to MacOS.
219 pub trait MonitorHandleExtMacOS {
220     /// Returns the identifier of the monitor for Cocoa.
native_id(&self) -> u32221     fn native_id(&self) -> u32;
222     /// Returns a pointer to the NSScreen representing this monitor.
ns_screen(&self) -> Option<*mut c_void>223     fn ns_screen(&self) -> Option<*mut c_void>;
224 }
225 
226 impl MonitorHandleExtMacOS for MonitorHandle {
227     #[inline]
native_id(&self) -> u32228     fn native_id(&self) -> u32 {
229         self.inner.native_identifier()
230     }
231 
ns_screen(&self) -> Option<*mut c_void>232     fn ns_screen(&self) -> Option<*mut c_void> {
233         self.inner.ns_screen().map(|s| s as *mut c_void)
234     }
235 }
236 
237 /// Additional methods on `EventLoopWindowTarget` that are specific to macOS.
238 pub trait EventLoopWindowTargetExtMacOS {
239     /// Hide the entire application. In most applications this is typically triggered with Command-H.
hide_application(&self)240     fn hide_application(&self);
241     /// Hide the other applications. In most applications this is typically triggered with Command+Option-H.
hide_other_applications(&self)242     fn hide_other_applications(&self);
243 }
244 
245 impl<T> EventLoopWindowTargetExtMacOS for EventLoopWindowTarget<T> {
hide_application(&self)246     fn hide_application(&self) {
247         let cls = objc::runtime::Class::get("NSApplication").unwrap();
248         let app: cocoa::base::id = unsafe { msg_send![cls, sharedApplication] };
249         unsafe { msg_send![app, hide: 0] }
250     }
251 
hide_other_applications(&self)252     fn hide_other_applications(&self) {
253         let cls = objc::runtime::Class::get("NSApplication").unwrap();
254         let app: cocoa::base::id = unsafe { msg_send![cls, sharedApplication] };
255         unsafe { msg_send![app, hideOtherApplications: 0] }
256     }
257 }
258