#![cfg(target_os = "macos")]
use std::os::raw::c_void;
use crate::{
dpi::LogicalSize,
event_loop::{EventLoop, EventLoopWindowTarget},
menu::CustomMenuItem,
monitor::MonitorHandle,
platform_impl::{get_aux_state_mut, Parent},
window::{Window, WindowBuilder},
};
#[cfg(feature = "tray")]
use crate::system_tray::{SystemTray, SystemTrayBuilder};
use cocoa::{
appkit::{
self, NSApplicationActivationPolicy, NSApplicationActivationPolicyAccessory,
NSApplicationActivationPolicyProhibited, NSApplicationActivationPolicyRegular,
},
base::id,
};
pub trait WindowExtMacOS {
fn ns_window(&self) -> *mut c_void;
fn ns_view(&self) -> *mut c_void;
fn simple_fullscreen(&self) -> bool;
fn set_simple_fullscreen(&self, fullscreen: bool) -> bool;
fn has_shadow(&self) -> bool;
fn set_has_shadow(&self, has_shadow: bool);
fn set_is_document_edited(&self, edited: bool);
fn is_document_edited(&self) -> bool;
fn set_allows_automatic_window_tabbing(&self, enabled: bool);
fn allows_automatic_window_tabbing(&self) -> bool;
fn set_tabbing_identifier(&self, identifier: &str);
fn tabbing_identifier(&self) -> String;
}
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 set_is_document_edited(&self, edited: bool) {
self.window.set_is_document_edited(edited)
}
#[inline]
fn is_document_edited(&self) -> bool {
self.window.is_document_edited()
}
#[inline]
fn set_allows_automatic_window_tabbing(&self, enabled: bool) {
self.window.set_allows_automatic_window_tabbing(enabled)
}
#[inline]
fn allows_automatic_window_tabbing(&self) -> bool {
self.window.allows_automatic_window_tabbing()
}
#[inline]
fn set_tabbing_identifier(&self, identifier: &str) {
self.window.set_tabbing_identifier(identifier)
}
#[inline]
fn tabbing_identifier(&self) -> String {
self.window.tabbing_identifier()
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ActivationPolicy {
Regular,
Accessory,
Prohibited,
}
impl Default for ActivationPolicy {
fn default() -> Self {
ActivationPolicy::Regular
}
}
impl From<ActivationPolicy> for NSApplicationActivationPolicy {
fn from(act_pol: ActivationPolicy) -> Self {
match act_pol {
ActivationPolicy::Regular => NSApplicationActivationPolicyRegular,
ActivationPolicy::Accessory => NSApplicationActivationPolicyAccessory,
ActivationPolicy::Prohibited => NSApplicationActivationPolicyProhibited,
}
}
}
pub trait CustomMenuItemExtMacOS {
fn set_native_image(&mut self, native_image: NativeImage);
}
impl CustomMenuItemExtMacOS for CustomMenuItem {
fn set_native_image(&mut self, native_image: NativeImage) {
self.0.set_native_image(native_image)
}
}
#[non_exhaustive]
pub enum NativeImage {
Add,
Advanced,
Bluetooth,
Bookmarks,
Caution,
ColorPanel,
ColumnView,
Computer,
EnterFullScreen,
Everyone,
ExitFullScreen,
FlowView,
Folder,
FolderBurnable,
FolderSmart,
FollowLinkFreestanding,
FontPanel,
GoLeft,
GoRight,
Home,
IChatTheater,
IconView,
Info,
InvalidDataFreestanding,
LeftFacingTriangle,
ListView,
LockLocked,
LockUnlocked,
MenuMixedState,
MenuOnState,
MobileMe,
MultipleDocuments,
Network,
Path,
PreferencesGeneral,
QuickLook,
RefreshFreestanding,
Refresh,
Remove,
RevealFreestanding,
RightFacingTriangle,
Share,
Slideshow,
SmartBadge,
StatusAvailable,
StatusNone,
StatusPartiallyAvailable,
StatusUnavailable,
StopProgressFreestanding,
StopProgress,
TrashEmpty,
TrashFull,
User,
UserAccounts,
UserGroup,
UserGuest,
}
impl NativeImage {
pub(crate) unsafe fn get_ns_image(self) -> id {
match self {
NativeImage::Add => appkit::NSImageNameAddTemplate,
NativeImage::StatusAvailable => appkit::NSImageNameStatusAvailable,
NativeImage::StatusUnavailable => appkit::NSImageNameStatusUnavailable,
NativeImage::StatusPartiallyAvailable => appkit::NSImageNameStatusPartiallyAvailable,
NativeImage::Advanced => appkit::NSImageNameAdvanced,
NativeImage::Bluetooth => appkit::NSImageNameBluetoothTemplate,
NativeImage::Bookmarks => appkit::NSImageNameBookmarksTemplate,
NativeImage::Caution => appkit::NSImageNameCaution,
NativeImage::ColorPanel => appkit::NSImageNameColorPanel,
NativeImage::ColumnView => appkit::NSImageNameColumnViewTemplate,
NativeImage::Computer => appkit::NSImageNameComputer,
NativeImage::EnterFullScreen => appkit::NSImageNameEnterFullScreenTemplate,
NativeImage::Everyone => appkit::NSImageNameEveryone,
NativeImage::ExitFullScreen => appkit::NSImageNameExitFullScreenTemplate,
NativeImage::FlowView => appkit::NSImageNameFlowViewTemplate,
NativeImage::Folder => appkit::NSImageNameFolder,
NativeImage::FolderBurnable => appkit::NSImageNameFolderBurnable,
NativeImage::FolderSmart => appkit::NSImageNameFolderSmart,
NativeImage::FollowLinkFreestanding => appkit::NSImageNameFollowLinkFreestandingTemplate,
NativeImage::FontPanel => appkit::NSImageNameFontPanel,
NativeImage::GoLeft => appkit::NSImageNameGoLeftTemplate,
NativeImage::GoRight => appkit::NSImageNameGoRightTemplate,
NativeImage::Home => appkit::NSImageNameHomeTemplate,
NativeImage::IChatTheater => appkit::NSImageNameIChatTheaterTemplate,
NativeImage::IconView => appkit::NSImageNameIconViewTemplate,
NativeImage::Info => appkit::NSImageNameInfo,
NativeImage::InvalidDataFreestanding => appkit::NSImageNameInvalidDataFreestandingTemplate,
NativeImage::LeftFacingTriangle => appkit::NSImageNameLeftFacingTriangleTemplate,
NativeImage::ListView => appkit::NSImageNameListViewTemplate,
NativeImage::LockLocked => appkit::NSImageNameLockLockedTemplate,
NativeImage::LockUnlocked => appkit::NSImageNameLockUnlockedTemplate,
NativeImage::MenuMixedState => appkit::NSImageNameMenuMixedStateTemplate,
NativeImage::MenuOnState => appkit::NSImageNameMenuOnStateTemplate,
NativeImage::MobileMe => appkit::NSImageNameMobileMe,
NativeImage::MultipleDocuments => appkit::NSImageNameMultipleDocuments,
NativeImage::Network => appkit::NSImageNameNetwork,
NativeImage::Path => appkit::NSImageNamePathTemplate,
NativeImage::PreferencesGeneral => appkit::NSImageNamePreferencesGeneral,
NativeImage::QuickLook => appkit::NSImageNameQuickLookTemplate,
NativeImage::RefreshFreestanding => appkit::NSImageNameRefreshFreestandingTemplate,
NativeImage::Refresh => appkit::NSImageNameRefreshTemplate,
NativeImage::Remove => appkit::NSImageNameRemoveTemplate,
NativeImage::RevealFreestanding => appkit::NSImageNameRevealFreestandingTemplate,
NativeImage::RightFacingTriangle => appkit::NSImageNameRightFacingTriangleTemplate,
NativeImage::Share => appkit::NSImageNameShareTemplate,
NativeImage::Slideshow => appkit::NSImageNameSlideshowTemplate,
NativeImage::SmartBadge => appkit::NSImageNameSmartBadgeTemplate,
NativeImage::StatusNone => appkit::NSImageNameStatusNone,
NativeImage::StopProgressFreestanding => appkit::NSImageNameStopProgressFreestandingTemplate,
NativeImage::StopProgress => appkit::NSImageNameStopProgressTemplate,
NativeImage::TrashEmpty => appkit::NSImageNameTrashEmpty,
NativeImage::TrashFull => appkit::NSImageNameTrashFull,
NativeImage::User => appkit::NSImageNameUser,
NativeImage::UserAccounts => appkit::NSImageNameUserAccounts,
NativeImage::UserGroup => appkit::NSImageNameUserGroup,
NativeImage::UserGuest => appkit::NSImageNameUserGuest,
}
}
}
pub trait WindowBuilderExtMacOS {
fn with_parent_window(self, parent: *mut c_void) -> WindowBuilder;
fn with_movable_by_window_background(self, movable_by_window_background: bool) -> WindowBuilder;
fn with_titlebar_transparent(self, titlebar_transparent: bool) -> WindowBuilder;
fn with_title_hidden(self, title_hidden: bool) -> WindowBuilder;
fn with_titlebar_hidden(self, titlebar_hidden: bool) -> WindowBuilder;
fn with_titlebar_buttons_hidden(self, titlebar_buttons_hidden: bool) -> WindowBuilder;
fn with_fullsize_content_view(self, fullsize_content_view: bool) -> WindowBuilder;
fn with_resize_increments(self, increments: LogicalSize<f64>) -> WindowBuilder;
fn with_disallow_hidpi(self, disallow_hidpi: bool) -> WindowBuilder;
fn with_has_shadow(self, has_shadow: bool) -> WindowBuilder;
fn with_automatic_window_tabbing(self, automatic_tabbing: bool) -> WindowBuilder;
fn with_tabbing_identifier(self, identifier: &str) -> WindowBuilder;
}
impl WindowBuilderExtMacOS for WindowBuilder {
#[inline]
fn with_parent_window(mut self, parent: *mut c_void) -> WindowBuilder {
self.platform_specific.parent = Parent::ChildOf(parent);
self
}
#[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_resize_increments(mut self, increments: LogicalSize<f64>) -> WindowBuilder {
self.platform_specific.resize_increments = Some(increments);
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_automatic_window_tabbing(mut self, automatic_tabbing: bool) -> WindowBuilder {
self.platform_specific.automatic_tabbing = automatic_tabbing;
self
}
#[inline]
fn with_tabbing_identifier(mut self, tabbing_identifier: &str) -> WindowBuilder {
self
.platform_specific
.tabbing_identifier
.replace(tabbing_identifier.into());
self
}
}
pub trait EventLoopExtMacOS {
fn set_activation_policy(&mut self, activation_policy: ActivationPolicy);
fn enable_default_menu_creation(&mut self, enable: bool);
fn set_activate_ignoring_other_apps(&mut self, ignore: bool);
}
impl<T> EventLoopExtMacOS for EventLoop<T> {
#[inline]
fn set_activation_policy(&mut self, activation_policy: ActivationPolicy) {
unsafe {
get_aux_state_mut(&**self.event_loop.delegate).activation_policy = activation_policy;
}
}
#[inline]
fn enable_default_menu_creation(&mut self, enable: bool) {
unsafe {
get_aux_state_mut(&**self.event_loop.delegate).create_default_menu = enable;
}
}
#[inline]
fn set_activate_ignoring_other_apps(&mut self, ignore: bool) {
unsafe {
get_aux_state_mut(&**self.event_loop.delegate).activate_ignoring_other_apps = ignore;
}
}
}
pub trait MonitorHandleExtMacOS {
fn native_id(&self) -> u32;
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| s as *mut c_void)
}
}
pub trait EventLoopWindowTargetExtMacOS {
fn hide_application(&self);
fn show_application(&self);
fn hide_other_applications(&self);
fn set_activation_policy_at_runtime(&self, activation_policy: ActivationPolicy);
}
impl<T> EventLoopWindowTargetExtMacOS for EventLoopWindowTarget<T> {
fn hide_application(&self) {
let cls = objc::runtime::Class::get("NSApplication").unwrap();
let app: cocoa::base::id = unsafe { msg_send![cls, sharedApplication] };
unsafe { msg_send![app, hide: 0] }
}
fn show_application(&self) {
let cls = objc::runtime::Class::get("NSApplication").unwrap();
let app: cocoa::base::id = unsafe { msg_send![cls, sharedApplication] };
unsafe { msg_send![app, unhide: 0] }
}
fn hide_other_applications(&self) {
let cls = objc::runtime::Class::get("NSApplication").unwrap();
let app: cocoa::base::id = unsafe { msg_send![cls, sharedApplication] };
unsafe { msg_send![app, hideOtherApplications: 0] }
}
fn set_activation_policy_at_runtime(&self, activation_policy: ActivationPolicy) {
let cls = objc::runtime::Class::get("NSApplication").unwrap();
let app: cocoa::base::id = unsafe { msg_send![cls, sharedApplication] };
let ns_activation_policy: NSApplicationActivationPolicy = activation_policy.into();
unsafe { msg_send![app, setActivationPolicy: ns_activation_policy] }
}
}
#[cfg(feature = "tray")]
pub trait SystemTrayBuilderExtMacOS {
fn with_icon_as_template(self, is_template: bool) -> Self;
fn with_menu_on_left_click(self, enable: bool) -> Self;
fn with_title(self, title: &str) -> Self;
}
#[cfg(feature = "tray")]
impl SystemTrayBuilderExtMacOS for SystemTrayBuilder {
fn with_icon_as_template(mut self, is_template: bool) -> Self {
self.platform_tray_builder.icon_is_template = is_template;
self
}
fn with_menu_on_left_click(mut self, enable: bool) -> Self {
self.platform_tray_builder.menu_on_left_click = enable;
self
}
fn with_title(mut self, title: &str) -> Self {
self.platform_tray_builder.title = Some(title.to_owned());
self
}
}
#[cfg(feature = "tray")]
pub trait SystemTrayExtMacOS {
fn set_icon_as_template(&mut self, is_template: bool);
fn enable_menu_on_left_click(&mut self, enable: bool);
fn set_title(&mut self, title: &str);
}
#[cfg(feature = "tray")]
impl SystemTrayExtMacOS for SystemTray {
fn set_icon_as_template(&mut self, is_template: bool) {
self.0.set_icon_as_template(is_template);
}
fn enable_menu_on_left_click(&mut self, enable: bool) {
self.0.set_show_menu_on_left_click(enable);
}
fn set_title(&mut self, title: &str) {
self.0.set_title(title)
}
}