371 lines
12 KiB
Rust
371 lines
12 KiB
Rust
use std::os::raw::c_void;
|
|
|
|
use objc2::rc::Id;
|
|
|
|
use crate::{
|
|
event_loop::{EventLoopBuilder, EventLoopWindowTarget},
|
|
monitor::MonitorHandle,
|
|
window::{Window, WindowBuilder},
|
|
};
|
|
|
|
/// Additional methods on [`Window`] that are specific to MacOS.
|
|
pub trait WindowExtMacOS {
|
|
/// Returns a pointer to the cocoa `NSWindow` that is used by this window.
|
|
///
|
|
/// The pointer will become invalid when the [`Window`] is destroyed.
|
|
fn ns_window(&self) -> *mut c_void;
|
|
|
|
/// Returns a pointer to the cocoa `NSView` that is used by this window.
|
|
///
|
|
/// The pointer will become invalid when the [`Window`] is destroyed.
|
|
fn ns_view(&self) -> *mut c_void;
|
|
|
|
/// Returns whether or not the window is in simple fullscreen mode.
|
|
fn simple_fullscreen(&self) -> bool;
|
|
|
|
/// Toggles a fullscreen mode that doesn't require a new macOS space.
|
|
/// Returns a boolean indicating whether the transition was successful (this
|
|
/// won't work if the window was already in the native fullscreen).
|
|
///
|
|
/// This is how fullscreen used to work on macOS in versions before Lion.
|
|
/// And allows the user to have a fullscreen window without using another
|
|
/// space or taking control over the entire monitor.
|
|
fn set_simple_fullscreen(&self, fullscreen: bool) -> bool;
|
|
|
|
/// Returns whether or not the window has shadow.
|
|
fn has_shadow(&self) -> bool;
|
|
|
|
/// Sets whether or not the window has shadow.
|
|
fn set_has_shadow(&self, has_shadow: bool);
|
|
|
|
/// Get the window's edit state.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```ignore
|
|
/// WindowEvent::CloseRequested => {
|
|
/// if window.is_document_edited() {
|
|
/// // Show the user a save pop-up or similar
|
|
/// } else {
|
|
/// // Close the window
|
|
/// drop(window);
|
|
/// }
|
|
/// }
|
|
/// ```
|
|
fn is_document_edited(&self) -> bool;
|
|
|
|
/// Put the window in a state which indicates a file save is required.
|
|
fn set_document_edited(&self, edited: bool);
|
|
|
|
/// Set option as alt behavior as described in [`OptionAsAlt`].
|
|
///
|
|
/// This will ignore diacritical marks and accent characters from
|
|
/// being processed as received characters. Instead, the input
|
|
/// device's raw character will be placed in event queues with the
|
|
/// Alt modifier set.
|
|
fn set_option_as_alt(&self, option_as_alt: OptionAsAlt);
|
|
|
|
/// Getter for the [`WindowExtMacOS::set_option_as_alt`].
|
|
fn option_as_alt(&self) -> OptionAsAlt;
|
|
}
|
|
|
|
impl WindowExtMacOS for Window {
|
|
#[inline]
|
|
fn ns_window(&self) -> *mut c_void {
|
|
self.window.ns_window()
|
|
}
|
|
|
|
#[inline]
|
|
fn ns_view(&self) -> *mut c_void {
|
|
self.window.ns_view()
|
|
}
|
|
|
|
#[inline]
|
|
fn simple_fullscreen(&self) -> bool {
|
|
self.window.simple_fullscreen()
|
|
}
|
|
|
|
#[inline]
|
|
fn set_simple_fullscreen(&self, fullscreen: bool) -> bool {
|
|
self.window.set_simple_fullscreen(fullscreen)
|
|
}
|
|
|
|
#[inline]
|
|
fn has_shadow(&self) -> bool {
|
|
self.window.has_shadow()
|
|
}
|
|
|
|
#[inline]
|
|
fn set_has_shadow(&self, has_shadow: bool) {
|
|
self.window.set_has_shadow(has_shadow)
|
|
}
|
|
|
|
#[inline]
|
|
fn is_document_edited(&self) -> bool {
|
|
self.window.is_document_edited()
|
|
}
|
|
|
|
#[inline]
|
|
fn set_document_edited(&self, edited: bool) {
|
|
self.window.set_document_edited(edited)
|
|
}
|
|
|
|
#[inline]
|
|
fn set_option_as_alt(&self, option_as_alt: OptionAsAlt) {
|
|
self.window.set_option_as_alt(option_as_alt)
|
|
}
|
|
|
|
#[inline]
|
|
fn option_as_alt(&self) -> OptionAsAlt {
|
|
self.window.option_as_alt()
|
|
}
|
|
}
|
|
|
|
/// Corresponds to `NSApplicationActivationPolicy`.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
pub enum ActivationPolicy {
|
|
/// Corresponds to `NSApplicationActivationPolicyRegular`.
|
|
Regular,
|
|
/// Corresponds to `NSApplicationActivationPolicyAccessory`.
|
|
Accessory,
|
|
/// Corresponds to `NSApplicationActivationPolicyProhibited`.
|
|
Prohibited,
|
|
}
|
|
|
|
impl Default for ActivationPolicy {
|
|
fn default() -> Self {
|
|
ActivationPolicy::Regular
|
|
}
|
|
}
|
|
|
|
/// Additional methods on [`WindowBuilder`] that are specific to MacOS.
|
|
///
|
|
/// **Note:** Properties dealing with the titlebar will be overwritten by the [`WindowBuilder::with_decorations`] method:
|
|
/// - `with_titlebar_transparent`
|
|
/// - `with_title_hidden`
|
|
/// - `with_titlebar_hidden`
|
|
/// - `with_titlebar_buttons_hidden`
|
|
/// - `with_fullsize_content_view`
|
|
pub trait WindowBuilderExtMacOS {
|
|
/// Enables click-and-drag behavior for the entire window, not just the titlebar.
|
|
fn with_movable_by_window_background(self, movable_by_window_background: bool)
|
|
-> WindowBuilder;
|
|
/// Makes the titlebar transparent and allows the content to appear behind it.
|
|
fn with_titlebar_transparent(self, titlebar_transparent: bool) -> WindowBuilder;
|
|
/// Hides the window title.
|
|
fn with_title_hidden(self, title_hidden: bool) -> WindowBuilder;
|
|
/// Hides the window titlebar.
|
|
fn with_titlebar_hidden(self, titlebar_hidden: bool) -> WindowBuilder;
|
|
/// Hides the window titlebar buttons.
|
|
fn with_titlebar_buttons_hidden(self, titlebar_buttons_hidden: bool) -> WindowBuilder;
|
|
/// Makes the window content appear behind the titlebar.
|
|
fn with_fullsize_content_view(self, fullsize_content_view: bool) -> WindowBuilder;
|
|
fn with_disallow_hidpi(self, disallow_hidpi: bool) -> WindowBuilder;
|
|
fn with_has_shadow(self, has_shadow: bool) -> WindowBuilder;
|
|
/// Window accepts click-through mouse events.
|
|
fn with_accepts_first_mouse(self, accepts_first_mouse: bool) -> WindowBuilder;
|
|
|
|
/// Set whether the `OptionAsAlt` key is interpreted as the `Alt` modifier.
|
|
///
|
|
/// See [`WindowExtMacOS::set_option_as_alt`] for details on what this means if set.
|
|
fn with_option_as_alt(self, option_as_alt: OptionAsAlt) -> WindowBuilder;
|
|
}
|
|
|
|
impl WindowBuilderExtMacOS for WindowBuilder {
|
|
#[inline]
|
|
fn with_movable_by_window_background(
|
|
mut self,
|
|
movable_by_window_background: bool,
|
|
) -> WindowBuilder {
|
|
self.platform_specific.movable_by_window_background = movable_by_window_background;
|
|
self
|
|
}
|
|
|
|
#[inline]
|
|
fn with_titlebar_transparent(mut self, titlebar_transparent: bool) -> WindowBuilder {
|
|
self.platform_specific.titlebar_transparent = titlebar_transparent;
|
|
self
|
|
}
|
|
|
|
#[inline]
|
|
fn with_titlebar_hidden(mut self, titlebar_hidden: bool) -> WindowBuilder {
|
|
self.platform_specific.titlebar_hidden = titlebar_hidden;
|
|
self
|
|
}
|
|
|
|
#[inline]
|
|
fn with_titlebar_buttons_hidden(mut self, titlebar_buttons_hidden: bool) -> WindowBuilder {
|
|
self.platform_specific.titlebar_buttons_hidden = titlebar_buttons_hidden;
|
|
self
|
|
}
|
|
|
|
#[inline]
|
|
fn with_title_hidden(mut self, title_hidden: bool) -> WindowBuilder {
|
|
self.platform_specific.title_hidden = title_hidden;
|
|
self
|
|
}
|
|
|
|
#[inline]
|
|
fn with_fullsize_content_view(mut self, fullsize_content_view: bool) -> WindowBuilder {
|
|
self.platform_specific.fullsize_content_view = fullsize_content_view;
|
|
self
|
|
}
|
|
|
|
#[inline]
|
|
fn with_disallow_hidpi(mut self, disallow_hidpi: bool) -> WindowBuilder {
|
|
self.platform_specific.disallow_hidpi = disallow_hidpi;
|
|
self
|
|
}
|
|
|
|
#[inline]
|
|
fn with_has_shadow(mut self, has_shadow: bool) -> WindowBuilder {
|
|
self.platform_specific.has_shadow = has_shadow;
|
|
self
|
|
}
|
|
|
|
#[inline]
|
|
fn with_accepts_first_mouse(mut self, accepts_first_mouse: bool) -> WindowBuilder {
|
|
self.platform_specific.accepts_first_mouse = accepts_first_mouse;
|
|
self
|
|
}
|
|
|
|
#[inline]
|
|
fn with_option_as_alt(mut self, option_as_alt: OptionAsAlt) -> WindowBuilder {
|
|
self.platform_specific.option_as_alt = option_as_alt;
|
|
self
|
|
}
|
|
}
|
|
|
|
pub trait EventLoopBuilderExtMacOS {
|
|
/// Sets the activation policy for the application.
|
|
///
|
|
/// It is set to [`ActivationPolicy::Regular`] by default.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// Set the activation policy to "accessory".
|
|
///
|
|
/// ```
|
|
/// use winit::event_loop::EventLoopBuilder;
|
|
/// #[cfg(target_os = "macos")]
|
|
/// use winit::platform::macos::{EventLoopBuilderExtMacOS, ActivationPolicy};
|
|
///
|
|
/// let mut builder = EventLoopBuilder::new();
|
|
/// #[cfg(target_os = "macos")]
|
|
/// builder.with_activation_policy(ActivationPolicy::Accessory);
|
|
/// # if false { // We can't test this part
|
|
/// let event_loop = builder.build();
|
|
/// # }
|
|
/// ```
|
|
fn with_activation_policy(&mut self, activation_policy: ActivationPolicy) -> &mut Self;
|
|
|
|
/// Used to control whether a default menubar menu is created.
|
|
///
|
|
/// Menu creation is enabled by default.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// Disable creating a default menubar.
|
|
///
|
|
/// ```
|
|
/// use winit::event_loop::EventLoopBuilder;
|
|
/// #[cfg(target_os = "macos")]
|
|
/// use winit::platform::macos::EventLoopBuilderExtMacOS;
|
|
///
|
|
/// let mut builder = EventLoopBuilder::new();
|
|
/// #[cfg(target_os = "macos")]
|
|
/// builder.with_default_menu(false);
|
|
/// # if false { // We can't test this part
|
|
/// let event_loop = builder.build();
|
|
/// # }
|
|
/// ```
|
|
fn with_default_menu(&mut self, enable: bool) -> &mut Self;
|
|
|
|
/// Used to prevent the application from automatically activating when launched if
|
|
/// another application is already active.
|
|
///
|
|
/// The default behavior is to ignore other applications and activate when launched.
|
|
fn with_activate_ignoring_other_apps(&mut self, ignore: bool) -> &mut Self;
|
|
}
|
|
|
|
impl<T> EventLoopBuilderExtMacOS for EventLoopBuilder<T> {
|
|
#[inline]
|
|
fn with_activation_policy(&mut self, activation_policy: ActivationPolicy) -> &mut Self {
|
|
self.platform_specific.activation_policy = activation_policy;
|
|
self
|
|
}
|
|
|
|
#[inline]
|
|
fn with_default_menu(&mut self, enable: bool) -> &mut Self {
|
|
self.platform_specific.default_menu = enable;
|
|
self
|
|
}
|
|
|
|
#[inline]
|
|
fn with_activate_ignoring_other_apps(&mut self, ignore: bool) -> &mut Self {
|
|
self.platform_specific.activate_ignoring_other_apps = ignore;
|
|
self
|
|
}
|
|
}
|
|
|
|
/// Additional methods on [`MonitorHandle`] that are specific to MacOS.
|
|
pub trait MonitorHandleExtMacOS {
|
|
/// Returns the identifier of the monitor for Cocoa.
|
|
fn native_id(&self) -> u32;
|
|
/// Returns a pointer to the NSScreen representing this monitor.
|
|
fn ns_screen(&self) -> Option<*mut c_void>;
|
|
}
|
|
|
|
impl MonitorHandleExtMacOS for MonitorHandle {
|
|
#[inline]
|
|
fn native_id(&self) -> u32 {
|
|
self.inner.native_identifier()
|
|
}
|
|
|
|
fn ns_screen(&self) -> Option<*mut c_void> {
|
|
self.inner.ns_screen().map(|s| Id::as_ptr(&s) as _)
|
|
}
|
|
}
|
|
|
|
/// Additional methods on [`EventLoopWindowTarget`] that are specific to macOS.
|
|
pub trait EventLoopWindowTargetExtMacOS {
|
|
/// Hide the entire application. In most applications this is typically triggered with Command-H.
|
|
fn hide_application(&self);
|
|
/// Hide the other applications. In most applications this is typically triggered with Command+Option-H.
|
|
fn hide_other_applications(&self);
|
|
}
|
|
|
|
impl<T> EventLoopWindowTargetExtMacOS for EventLoopWindowTarget<T> {
|
|
fn hide_application(&self) {
|
|
self.p.hide_application()
|
|
}
|
|
|
|
fn hide_other_applications(&self) {
|
|
self.p.hide_other_applications()
|
|
}
|
|
}
|
|
|
|
/// Option as alt behavior.
|
|
///
|
|
/// The default is `None`.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
pub enum OptionAsAlt {
|
|
/// The left `Option` key is treated as `Alt`.
|
|
OnlyLeft,
|
|
|
|
/// The right `Option` key is treated as `Alt`.
|
|
OnlyRight,
|
|
|
|
/// Both `Option` keys are treated as `Alt`.
|
|
Both,
|
|
|
|
/// No special handling is applied for `Option` key.
|
|
None,
|
|
}
|
|
|
|
impl Default for OptionAsAlt {
|
|
fn default() -> Self {
|
|
OptionAsAlt::None
|
|
}
|
|
}
|