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