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 /// Additional methods on `Window` that are specific to MacOS.
13 pub trait WindowExtMacOS {
14     /// Returns a pointer to the cocoa `NSWindow` that is used by this window.
15     ///
16     /// The pointer will become invalid when the `Window` is destroyed.
ns_window(&self) -> *mut c_void17     fn ns_window(&self) -> *mut c_void;
18 
19     /// Returns a pointer to the cocoa `NSView` that is used by this window.
20     ///
21     /// The pointer will become invalid when the `Window` is destroyed.
ns_view(&self) -> *mut c_void22     fn ns_view(&self) -> *mut c_void;
23 
24     /// Returns whether or not the window is in simple fullscreen mode.
simple_fullscreen(&self) -> bool25     fn simple_fullscreen(&self) -> bool;
26 
27     /// Toggles a fullscreen mode that doesn't require a new macOS space.
28     /// Returns a boolean indicating whether the transition was successful (this
29     /// won't work if the window was already in the native fullscreen).
30     ///
31     /// This is how fullscreen used to work on macOS in versions before Lion.
32     /// And allows the user to have a fullscreen window without using another
33     /// space or taking control over the entire monitor.
set_simple_fullscreen(&self, fullscreen: bool) -> bool34     fn set_simple_fullscreen(&self, fullscreen: bool) -> bool;
35 
36     /// Returns whether or not the window has shadow.
has_shadow(&self) -> bool37     fn has_shadow(&self) -> bool;
38 
39     /// Sets whether or not the window has shadow.
set_has_shadow(&self, has_shadow: bool)40     fn set_has_shadow(&self, has_shadow: bool);
41 }
42 
43 impl WindowExtMacOS for Window {
44     #[inline]
ns_window(&self) -> *mut c_void45     fn ns_window(&self) -> *mut c_void {
46         self.window.ns_window()
47     }
48 
49     #[inline]
ns_view(&self) -> *mut c_void50     fn ns_view(&self) -> *mut c_void {
51         self.window.ns_view()
52     }
53 
54     #[inline]
simple_fullscreen(&self) -> bool55     fn simple_fullscreen(&self) -> bool {
56         self.window.simple_fullscreen()
57     }
58 
59     #[inline]
set_simple_fullscreen(&self, fullscreen: bool) -> bool60     fn set_simple_fullscreen(&self, fullscreen: bool) -> bool {
61         self.window.set_simple_fullscreen(fullscreen)
62     }
63 
64     #[inline]
has_shadow(&self) -> bool65     fn has_shadow(&self) -> bool {
66         self.window.has_shadow()
67     }
68 
69     #[inline]
set_has_shadow(&self, has_shadow: bool)70     fn set_has_shadow(&self, has_shadow: bool) {
71         self.window.set_has_shadow(has_shadow)
72     }
73 }
74 
75 /// Corresponds to `NSApplicationActivationPolicy`.
76 #[derive(Debug, Clone, Copy, PartialEq)]
77 pub enum ActivationPolicy {
78     /// Corresponds to `NSApplicationActivationPolicyRegular`.
79     Regular,
80     /// Corresponds to `NSApplicationActivationPolicyAccessory`.
81     Accessory,
82     /// Corresponds to `NSApplicationActivationPolicyProhibited`.
83     Prohibited,
84 }
85 
86 impl Default for ActivationPolicy {
default() -> Self87     fn default() -> Self {
88         ActivationPolicy::Regular
89     }
90 }
91 
92 /// Additional methods on `WindowBuilder` that are specific to MacOS.
93 ///
94 /// **Note:** Properties dealing with the titlebar will be overwritten by the `with_decorations` method
95 /// on the base `WindowBuilder`:
96 ///
97 ///  - `with_titlebar_transparent`
98 ///  - `with_title_hidden`
99 ///  - `with_titlebar_hidden`
100 ///  - `with_titlebar_buttons_hidden`
101 ///  - `with_fullsize_content_view`
102 pub trait WindowBuilderExtMacOS {
103     /// Sets the activation policy for the window being built.
with_activation_policy(self, activation_policy: ActivationPolicy) -> WindowBuilder104     fn with_activation_policy(self, activation_policy: ActivationPolicy) -> WindowBuilder;
105     /// Enables click-and-drag behavior for the entire window, not just the titlebar.
with_movable_by_window_background(self, movable_by_window_background: bool) -> WindowBuilder106     fn with_movable_by_window_background(self, movable_by_window_background: bool)
107         -> WindowBuilder;
108     /// Makes the titlebar transparent and allows the content to appear behind it.
with_titlebar_transparent(self, titlebar_transparent: bool) -> WindowBuilder109     fn with_titlebar_transparent(self, titlebar_transparent: bool) -> WindowBuilder;
110     /// Hides the window title.
with_title_hidden(self, title_hidden: bool) -> WindowBuilder111     fn with_title_hidden(self, title_hidden: bool) -> WindowBuilder;
112     /// Hides the window titlebar.
with_titlebar_hidden(self, titlebar_hidden: bool) -> WindowBuilder113     fn with_titlebar_hidden(self, titlebar_hidden: bool) -> WindowBuilder;
114     /// Hides the window titlebar buttons.
with_titlebar_buttons_hidden(self, titlebar_buttons_hidden: bool) -> WindowBuilder115     fn with_titlebar_buttons_hidden(self, titlebar_buttons_hidden: bool) -> WindowBuilder;
116     /// Makes the window content appear behind the titlebar.
with_fullsize_content_view(self, fullsize_content_view: bool) -> WindowBuilder117     fn with_fullsize_content_view(self, fullsize_content_view: bool) -> WindowBuilder;
118     /// Build window with `resizeIncrements` property. Values must not be 0.
with_resize_increments(self, increments: LogicalSize<f64>) -> WindowBuilder119     fn with_resize_increments(self, increments: LogicalSize<f64>) -> WindowBuilder;
with_disallow_hidpi(self, disallow_hidpi: bool) -> WindowBuilder120     fn with_disallow_hidpi(self, disallow_hidpi: bool) -> WindowBuilder;
with_has_shadow(self, has_shadow: bool) -> WindowBuilder121     fn with_has_shadow(self, has_shadow: bool) -> WindowBuilder;
122 }
123 
124 impl WindowBuilderExtMacOS for WindowBuilder {
125     #[inline]
with_activation_policy(mut self, activation_policy: ActivationPolicy) -> WindowBuilder126     fn with_activation_policy(mut self, activation_policy: ActivationPolicy) -> WindowBuilder {
127         self.platform_specific.activation_policy = activation_policy;
128         self
129     }
130 
131     #[inline]
with_movable_by_window_background( mut self, movable_by_window_background: bool, ) -> WindowBuilder132     fn with_movable_by_window_background(
133         mut self,
134         movable_by_window_background: bool,
135     ) -> WindowBuilder {
136         self.platform_specific.movable_by_window_background = movable_by_window_background;
137         self
138     }
139 
140     #[inline]
with_titlebar_transparent(mut self, titlebar_transparent: bool) -> WindowBuilder141     fn with_titlebar_transparent(mut self, titlebar_transparent: bool) -> WindowBuilder {
142         self.platform_specific.titlebar_transparent = titlebar_transparent;
143         self
144     }
145 
146     #[inline]
with_titlebar_hidden(mut self, titlebar_hidden: bool) -> WindowBuilder147     fn with_titlebar_hidden(mut self, titlebar_hidden: bool) -> WindowBuilder {
148         self.platform_specific.titlebar_hidden = titlebar_hidden;
149         self
150     }
151 
152     #[inline]
with_titlebar_buttons_hidden(mut self, titlebar_buttons_hidden: bool) -> WindowBuilder153     fn with_titlebar_buttons_hidden(mut self, titlebar_buttons_hidden: bool) -> WindowBuilder {
154         self.platform_specific.titlebar_buttons_hidden = titlebar_buttons_hidden;
155         self
156     }
157 
158     #[inline]
with_title_hidden(mut self, title_hidden: bool) -> WindowBuilder159     fn with_title_hidden(mut self, title_hidden: bool) -> WindowBuilder {
160         self.platform_specific.title_hidden = title_hidden;
161         self
162     }
163 
164     #[inline]
with_fullsize_content_view(mut self, fullsize_content_view: bool) -> WindowBuilder165     fn with_fullsize_content_view(mut self, fullsize_content_view: bool) -> WindowBuilder {
166         self.platform_specific.fullsize_content_view = fullsize_content_view;
167         self
168     }
169 
170     #[inline]
with_resize_increments(mut self, increments: LogicalSize<f64>) -> WindowBuilder171     fn with_resize_increments(mut self, increments: LogicalSize<f64>) -> WindowBuilder {
172         self.platform_specific.resize_increments = Some(increments.into());
173         self
174     }
175 
176     #[inline]
with_disallow_hidpi(mut self, disallow_hidpi: bool) -> WindowBuilder177     fn with_disallow_hidpi(mut self, disallow_hidpi: bool) -> WindowBuilder {
178         self.platform_specific.disallow_hidpi = disallow_hidpi;
179         self
180     }
181 
182     #[inline]
with_has_shadow(mut self, has_shadow: bool) -> WindowBuilder183     fn with_has_shadow(mut self, has_shadow: bool) -> WindowBuilder {
184         self.platform_specific.has_shadow = has_shadow;
185         self
186     }
187 }
188 
189 /// Additional methods on `MonitorHandle` that are specific to MacOS.
190 pub trait MonitorHandleExtMacOS {
191     /// Returns the identifier of the monitor for Cocoa.
native_id(&self) -> u32192     fn native_id(&self) -> u32;
193     /// Returns a pointer to the NSScreen representing this monitor.
ns_screen(&self) -> Option<*mut c_void>194     fn ns_screen(&self) -> Option<*mut c_void>;
195 }
196 
197 impl MonitorHandleExtMacOS for MonitorHandle {
198     #[inline]
native_id(&self) -> u32199     fn native_id(&self) -> u32 {
200         self.inner.native_identifier()
201     }
202 
ns_screen(&self) -> Option<*mut c_void>203     fn ns_screen(&self) -> Option<*mut c_void> {
204         self.inner.ns_screen().map(|s| s as *mut c_void)
205     }
206 }
207 
208 /// Additional methods on `EventLoopWindowTarget` that are specific to macOS.
209 pub trait EventLoopWindowTargetExtMacOS {
210     /// Hide the entire application. In most applications this is typically triggered with Command-H.
hide_application(&self)211     fn hide_application(&self);
212     /// Hide the other applications. In most applications this is typically triggered with Command+Option-H.
hide_other_applications(&self)213     fn hide_other_applications(&self);
214 }
215 
216 impl<T> EventLoopWindowTargetExtMacOS for EventLoopWindowTarget<T> {
hide_application(&self)217     fn hide_application(&self) {
218         let cls = objc::runtime::Class::get("NSApplication").unwrap();
219         let app: cocoa::base::id = unsafe { msg_send![cls, sharedApplication] };
220         unsafe { msg_send![app, hide: 0] }
221     }
222 
hide_other_applications(&self)223     fn hide_other_applications(&self) {
224         let cls = objc::runtime::Class::get("NSApplication").unwrap();
225         let app: cocoa::base::id = unsafe { msg_send![cls, sharedApplication] };
226         unsafe { msg_send![app, hideOtherApplications: 0] }
227     }
228 }
229