Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Window icon on osx #427

Merged
merged 1 commit into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/conf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Icon>,

/// Platform specific settings. Hints to OS for context creation, driver-specific
Expand Down
34 changes: 33 additions & 1 deletion src/native/apple/frameworks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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" {
Expand Down
51 changes: 50 additions & 1 deletion src/native/macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//!
use {
crate::{
conf::AppleGfxApi,
conf::{AppleGfxApi, Icon},
event::{EventHandler, MouseButton},
native::{
apple::{apple_util::*, frameworks::*},
Expand Down Expand Up @@ -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<F>(conf: crate::conf::Conf, f: F)
where
F: 'static + FnOnce() -> Box<dyn EventHandler>,
Expand Down Expand Up @@ -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
Expand Down
Loading