#![cfg(target_os = "macos")]
use std::os::raw::c_void;
use objc2_foundation::NSObject;
use crate::{
dpi::{LogicalSize, Position},
event_loop::{EventLoop, EventLoopWindowTarget},
monitor::MonitorHandle,
platform_impl::{get_aux_state_mut, set_badge_label, set_dock_visibility, Parent},
window::{Window, WindowBuilder},
};
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_traffic_light_inset<P: Into<Position>>(&self, position: P);
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;
fn set_fullsize_content_view(&self, fullsize: bool);
fn set_titlebar_transparent(&self, transparent: bool);
fn set_badge_label(&self, label: Option<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_traffic_light_inset<P: Into<Position>>(&self, position: P) {
self.window.set_traffic_light_inset(position)
}
#[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()
}
#[inline]
fn set_fullsize_content_view(&self, fullsize: bool) {
self.window.set_fullsize_content_view(fullsize);
}
#[inline]
fn set_titlebar_transparent(&self, transparent: bool) {
self.window.set_titlebar_transparent(transparent);
}
#[inline]
fn set_badge_label(&self, label: Option<String>) {
self.window.set_badge_label(label);
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub enum ActivationPolicy {
#[default]
Regular,
Accessory,
Prohibited,
}
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_traffic_light_inset<P: Into<Position>>(self, inset: P) -> 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_traffic_light_inset<P: Into<Position>>(mut self, inset: P) -> WindowBuilder {
self.platform_specific.traffic_light_inset = Some(inset.into());
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 set_dock_visibility(&mut self, visible: 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 set_dock_visibility(&mut self, visible: bool) {
unsafe {
get_aux_state_mut(&**self.event_loop.delegate).dock_visibility = visible;
}
}
#[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| objc2::rc::Retained::into_raw(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);
fn set_dock_visibility(&self, visible: bool);
fn set_badge_label(&self, label: Option<String>);
}
impl<T> EventLoopWindowTargetExtMacOS for EventLoopWindowTarget<T> {
fn hide_application(&self) {
let mtm = unsafe { objc2_foundation::MainThreadMarker::new_unchecked() };
objc2_app_kit::NSApplication::sharedApplication(mtm).hide(None)
}
fn show_application(&self) {
let mtm = unsafe { objc2_foundation::MainThreadMarker::new_unchecked() };
unsafe { objc2_app_kit::NSApplication::sharedApplication(mtm).unhide(None) }
}
fn hide_other_applications(&self) {
let mtm = unsafe { objc2_foundation::MainThreadMarker::new_unchecked() };
objc2_app_kit::NSApplication::sharedApplication(mtm).hideOtherApplications(None)
}
fn set_activation_policy_at_runtime(&self, activation_policy: ActivationPolicy) {
use objc2_app_kit::NSApplicationActivationPolicy;
let ns_activation_policy = match activation_policy {
ActivationPolicy::Regular => NSApplicationActivationPolicy::Regular,
ActivationPolicy::Accessory => NSApplicationActivationPolicy::Accessory,
ActivationPolicy::Prohibited => NSApplicationActivationPolicy::Prohibited,
};
let mtm = unsafe { objc2_foundation::MainThreadMarker::new_unchecked() };
objc2_app_kit::NSApplication::sharedApplication(mtm).setActivationPolicy(ns_activation_policy);
}
fn set_dock_visibility(&self, visible: bool) {
let Some(Ok(delegate)) = (unsafe {
let mtm = objc2_foundation::MainThreadMarker::new_unchecked();
objc2_app_kit::NSApplication::sharedApplication(mtm)
.delegate()
.map(|delegate| delegate.downcast::<NSObject>())
}) else {
return;
};
set_dock_visibility(&delegate, visible);
}
fn set_badge_label(&self, label: Option<String>) {
set_badge_label(label);
}
}