From 65b64ad8d13c4ef5d4d26549c59c617099481932 Mon Sep 17 00:00:00 2001 From: Birh Burh Date: Sat, 16 Mar 2024 00:27:57 +0100 Subject: [PATCH] Window icon on osx --- src/conf.rs | 2 +- src/native/apple/frameworks.rs | 34 ++++++++++++++++++++++- src/native/macos.rs | 51 +++++++++++++++++++++++++++++++++- 3 files changed, 84 insertions(+), 3 deletions(-) diff --git a/src/conf.rs b/src/conf.rs index 92a23833..2700c921 100644 --- a/src/conf.rs +++ b/src/conf.rs @@ -153,9 +153,9 @@ pub struct Conf { /// Miniquad allows to change the window icon programmatically. /// The icon will be used as /// - taskbar and titlebar icons on Windows. + /// - dock and titlebar icon on MacOs. /// - TODO: favicon on HTML5 /// - TODO: taskbar and titlebar(highly dependent on the WM) icons on Linux - /// - TODO: dock and titlebar icon on MacOs pub icon: Option, /// Platform specific settings. Hints to OS for context creation, driver-specific diff --git a/src/native/apple/frameworks.rs b/src/native/apple/frameworks.rs index fd81e94e..3a30880d 100644 --- a/src/native/apple/frameworks.rs +++ b/src/native/apple/frameworks.rs @@ -158,6 +158,8 @@ pub const kCGEventLeftMouseUp: u32 = 2; pub const kCGMouseEventClickState: u32 = 1; //pub const kCGEventSourceStateHIDSystemState: u32 = 1; +type DataReleaseCallback = unsafe extern "C" fn(info: *mut &[u8], data: *const c_void, size: usize); + #[link(name = "CoreGraphics", kind = "framework")] extern "C" { pub fn CGEventSourceCreate(state_id: u32) -> ObjcId; @@ -190,7 +192,37 @@ extern "C" { pub fn CGColorCreateGenericRGB(red: f64, green: f64, blue: f64, alpha: f64) -> ObjcId; pub fn CGAssociateMouseAndMouseCursorPosition(connected: bool); pub fn CGWarpMouseCursorPosition(newCursorPosition: NSPoint); -} + + pub fn CGImageCreate( + width: usize, + height: usize, + bpc: usize, + bpp: usize, + bpr: usize, + colorspace: *const ObjcId, + bitmap_info: u32, + provider: *const ObjcId, + decode: *const c_void, + interpolate: bool, + intent: u32, + ) -> *const ObjcId; + pub fn CGImageRelease(image: *const ObjcId); + + pub fn CGDataProviderCreateWithData( + info: *mut &[u8], + data: *const u8, + size: usize, + callback: DataReleaseCallback, + ) -> *const ObjcId; + pub fn CGDataProviderRelease(provider: *const ObjcId); + + pub fn CGColorSpaceCreateDeviceRGB() -> *const ObjcId; + pub fn CGColorSpaceRelease(space: *const ObjcId); +} + +pub const kCGBitmapByteOrderDefault: u32 = (0 << 12); +pub const kCGImageAlphaLast: u32 = 3; +pub const kCGRenderingIntentDefault: u32 = 0; #[link(name = "Metal", kind = "framework")] extern "C" { diff --git a/src/native/macos.rs b/src/native/macos.rs index 96ada124..e240176c 100644 --- a/src/native/macos.rs +++ b/src/native/macos.rs @@ -4,7 +4,7 @@ //! use { crate::{ - conf::AppleGfxApi, + conf::{AppleGfxApi, Icon}, event::{EventHandler, MouseButton}, native::{ apple::{apple_util::*, frameworks::*}, @@ -864,6 +864,51 @@ impl crate::native::Clipboard for MacosClipboard { fn set(&mut self, _data: &str) {} } +unsafe extern "C" fn release_data(info: *mut &[u8], _: *const c_void, _: usize) { + Box::from_raw(info); +} + +unsafe fn set_icon(ns_app: ObjcId, icon: &Icon) { + let width = 64 as usize; + let height = 64 as usize; + let colors = &icon.big[..]; + let rgb = CGColorSpaceCreateDeviceRGB(); + let bits_per_component: usize = 8; // number of bits in UInt8 + let bits_per_pixel = 4 * bits_per_component; // ARGB uses 4 components + let bytes_per_row = width * 4; // bitsPerRow / 8 + + let data = colors.as_ptr(); + let size = colors.len(); + let boxed = Box::new(colors); + let info = Box::into_raw(boxed); + let provider = CGDataProviderCreateWithData(info, data, size, release_data); + let image = CGImageCreate( + width, + height, + bits_per_component, + bits_per_pixel, + bytes_per_row, + rgb, + kCGBitmapByteOrderDefault | kCGImageAlphaLast, + provider, + std::ptr::null(), + false, + kCGRenderingIntentDefault, + ); + + let size = NSSize { + width: width as f64, + height: height as f64, + }; + let ns_image: ObjcId = msg_send![class!(NSImage), alloc]; + let () = msg_send![ns_image, initWithCGImage: image size: size]; + + let () = msg_send![ns_app, setApplicationIconImage: ns_image]; + CGDataProviderRelease(provider); + CGColorSpaceRelease(rgb); + CGImageRelease(image); +} + pub unsafe fn run(conf: crate::conf::Conf, f: F) where F: 'static + FnOnce() -> Box, @@ -903,6 +948,10 @@ where ]; let () = msg_send![ns_app, activateIgnoringOtherApps: YES]; + if let Some(icon) = &conf.icon { + set_icon(ns_app, icon); + } + let window_masks = NSWindowStyleMask::NSTitledWindowMask as u64 | NSWindowStyleMask::NSClosableWindowMask as u64 | NSWindowStyleMask::NSMiniaturizableWindowMask as u64