From a5c5132eba6ebbc71c96727e0c82f91608c8cafe Mon Sep 17 00:00:00 2001 From: Dave Russell Date: Mon, 14 Oct 2024 19:09:38 +1100 Subject: [PATCH] Feat: Allow MacOS menubar icon height to be overridden Implemented via functional options, so as to be backwards-compatible for existing importers. Allow the height of the menubar icon on MacOS to be set, scaling the input image proportionally to avoid any kind of squish effect. The default size of 16x16 is fine, but it can be nice to use up a little more space with a 22-height icon. --- example/main.go | 2 +- systray.go | 21 +++++++++++++++++++++ systray.h | 2 +- systray_darwin.go | 8 ++++++-- systray_darwin.m | 7 +++++-- systray_linux.c | 2 +- systray_linux.go | 4 ++-- systray_nonwindows.go | 8 ++++++-- systray_windows.go | 6 +++--- 9 files changed, 46 insertions(+), 14 deletions(-) diff --git a/example/main.go b/example/main.go index b88ac018..246e32b2 100644 --- a/example/main.go +++ b/example/main.go @@ -33,7 +33,7 @@ func onReady() { // We can manipulate the systray in other goroutines go func() { - systray.SetTemplateIcon(icon.Data, icon.Data) + systray.SetTemplateIcon(icon.Data, icon.Data, systray.WithHeight(22)) systray.SetTitle("Awesome App") systray.SetTooltip("Pretty awesome棒棒嗒") mChange := systray.AddMenuItem("Change Me", "Change Me") diff --git a/systray.go b/systray.go index cd5ae283..b1022037 100644 --- a/systray.go +++ b/systray.go @@ -234,3 +234,24 @@ func systrayMenuItemSelected(id uint32) { default: } } + +type iconOptions struct { + height int + template bool +} + +// WithHeight resizes the provided icon image to the provided +// height, in pixels (macOS only). The default systray icon +// height is 16px. +func WithHeight(pixels int) func(*iconOptions) { + return func(opts *iconOptions) { + opts.height = pixels + } +} + +// WithTemplate is an alternate method to calling SetTemplateIcon. +func WithTemplate() func(*iconOptions) { + return func(opts *iconOptions) { + opts.template = true + } +} diff --git a/systray.h b/systray.h index 7141ec67..9603375c 100644 --- a/systray.h +++ b/systray.h @@ -6,7 +6,7 @@ extern void systray_menu_item_selected(int menu_id); void registerSystray(void); int nativeLoop(void); -void setIcon(const char* iconBytes, int length, bool template); +void setIcon(const char* iconBytes, int length, int iconHeight, bool template); void setMenuItemIcon(const char* iconBytes, int length, int menuId, bool template); void setTitle(char* title); void setTooltip(char* tooltip); diff --git a/systray_darwin.go b/systray_darwin.go index 252ca91e..30199198 100644 --- a/systray_darwin.go +++ b/systray_darwin.go @@ -16,9 +16,13 @@ import ( // to a regular icon on other platforms. // templateIconBytes and regularIconBytes should be the content of .ico for windows and // .ico/.jpg/.png for other platforms. -func SetTemplateIcon(templateIconBytes []byte, regularIconBytes []byte) { +func SetTemplateIcon(templateIconBytes []byte, regularIconBytes []byte, opts ...func(*iconOptions)) { + var io iconOptions + for _, opt := range opts { + opt(&io) + } cstr := (*C.char)(unsafe.Pointer(&templateIconBytes[0])) - C.setIcon(cstr, (C.int)(len(templateIconBytes)), true) + C.setIcon(cstr, (C.int)(len(templateIconBytes)), (C.int)(io.height), true) } // SetIcon sets the icon of a menu item. Only works on macOS and Windows. diff --git a/systray_darwin.m b/systray_darwin.m index ecf21ace..2eecc62a 100644 --- a/systray_darwin.m +++ b/systray_darwin.m @@ -250,10 +250,13 @@ void runInMainThread(SEL method, id object) { waitUntilDone: YES]; } -void setIcon(const char* iconBytes, int length, bool template) { +void setIcon(const char* iconBytes, int length, int iconHeight, bool template) { + if (iconHeight == 0) { + iconHeight = 16; + } NSData* buffer = [NSData dataWithBytes: iconBytes length:length]; NSImage *image = [[NSImage alloc] initWithData:buffer]; - [image setSize:NSMakeSize(16, 16)]; + [image setSize:NSMakeSize(image.size.width * iconHeight / image.size.height, iconHeight)]; image.template = template; runInMainThread(@selector(setIcon:), (id)image); } diff --git a/systray_linux.c b/systray_linux.c index 9e14ba01..d65bfa32 100644 --- a/systray_linux.c +++ b/systray_linux.c @@ -222,7 +222,7 @@ gboolean do_quit(gpointer data) { return FALSE; } -void setIcon(const char* iconBytes, int length, bool template) { +void setIcon(const char* iconBytes, int length, int iconHeight, bool template) { GBytes* bytes = g_bytes_new_static(iconBytes, length); g_idle_add(do_set_icon, bytes); } diff --git a/systray_linux.go b/systray_linux.go index 0b1b786f..fc4a98f2 100644 --- a/systray_linux.go +++ b/systray_linux.go @@ -4,8 +4,8 @@ package systray // to a regular icon on other platforms. // templateIconBytes and iconBytes should be the content of .ico for windows and // .ico/.jpg/.png for other platforms. -func SetTemplateIcon(templateIconBytes []byte, regularIconBytes []byte) { - SetIcon(regularIconBytes) +func SetTemplateIcon(templateIconBytes []byte, regularIconBytes []byte, opts ...func(*iconOptions)) { + SetIcon(regularIconBytes, opts...) } // SetRemovalAllowed sets whether a user can remove the systray icon or not. diff --git a/systray_nonwindows.go b/systray_nonwindows.go index 12eacdfa..b85c27be 100644 --- a/systray_nonwindows.go +++ b/systray_nonwindows.go @@ -25,9 +25,13 @@ func quit() { // SetIcon sets the systray icon. // iconBytes should be the content of .ico for windows and .ico/.jpg/.png // for other platforms. -func SetIcon(iconBytes []byte) { +func SetIcon(iconBytes []byte, opts ...func(*iconOptions)) { + var io iconOptions + for _, opt := range opts { + opt(&io) + } cstr := (*C.char)(unsafe.Pointer(&iconBytes[0])) - C.setIcon(cstr, (C.int)(len(iconBytes)), false) + C.setIcon(cstr, (C.int)(len(iconBytes)), (C.int)(io.height), (C.bool)(io.template)) } // SetTitle sets the systray title, only available on Mac and Linux. diff --git a/systray_windows.go b/systray_windows.go index 13b4411d..55cfbb3d 100644 --- a/systray_windows.go +++ b/systray_windows.go @@ -835,7 +835,7 @@ func iconBytesToFilePath(iconBytes []byte) (string, error) { // SetIcon sets the systray icon. // iconBytes should be the content of .ico for windows and .ico/.jpg/.png // for other platforms. -func SetIcon(iconBytes []byte) { +func SetIcon(iconBytes []byte, opts ...func(*iconOptions)) { iconFilePath, err := iconBytesToFilePath(iconBytes) if err != nil { log.Errorf("Unable to write icon data to temp file: %v", err) @@ -851,8 +851,8 @@ func SetIcon(iconBytes []byte) { // to a regular icon on other platforms. // templateIconBytes and iconBytes should be the content of .ico for windows and // .ico/.jpg/.png for other platforms. -func SetTemplateIcon(templateIconBytes []byte, regularIconBytes []byte) { - SetIcon(regularIconBytes) +func SetTemplateIcon(templateIconBytes []byte, regularIconBytes []byte, opts ...func(*iconOptions)) { + SetIcon(regularIconBytes, opts...) } // SetTitle sets the systray title, only available on Mac and Linux.