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