From 92ec44c78bb272a3487c116e7de5de769c501760 Mon Sep 17 00:00:00 2001 From: Marco Fabbri Date: Tue, 9 Dec 2014 00:22:56 +0100 Subject: [PATCH 1/2] [OSX] Add iconsAreTemplates property to Tray API objects Add boolean property (defaults to `true`) `iconsAreTemplates` to `Tray` objects to allow for proper display of icons in Mac OS X (Yosemite) Dark Menus. When `iconsAreTemplates` is set to true, both `icon` and `altIcon` are treated as "templates" and the system automatically ensures proper styling according to the various states of the status item (e.g. dark menu, light menu, etc.). Template images should consist only of black and clear colours and can use the alpha channel in the image to adjust the opacity of black content. See [Dark Menus in AppKit Release Notes for OS X v10.10](https://developer.apple.com/library/mac/releasenotes/AppKit/RN-AppKit/#10_10DarkMenus) and [`NSImage setTemplate:`](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSImage_Class/index.html#//apple_ref/occ/instm/NSImage/setTemplate:). On Linux and Windows setting the property has no effect. FIX rogerwang/node-webkit#2476 --- src/api/tray/tray.cc | 8 ++++++++ src/api/tray/tray.h | 3 +++ src/api/tray/tray.js | 13 +++++++++++++ src/api/tray/tray_aura.cc | 3 +++ src/api/tray/tray_gtk.cc | 3 +++ src/api/tray/tray_mac.mm | 12 ++++++++++++ 6 files changed, 42 insertions(+) diff --git a/src/api/tray/tray.cc b/src/api/tray/tray.cc index 2371b10cc6..5d8bdbeb7d 100644 --- a/src/api/tray/tray.cc +++ b/src/api/tray/tray.cc @@ -37,6 +37,10 @@ Tray::Tray(int id, if (option.GetString("title", &title)) SetTitle(title); + bool areTemplates; + if (option.GetBoolean("iconsAreTemplates", &areTemplates)) + SetIconsAreTemplates(areTemplates); + std::string icon; if (option.GetString("icon", &icon) && !icon.empty()) SetIcon(icon); @@ -74,6 +78,10 @@ void Tray::Call(const std::string& method, std::string alticon; arguments.GetString(0, &alticon); SetAltIcon(alticon); + } else if (method == "SetIconsAreTemplates") { + bool areTemplates; + arguments.GetBoolean(0, &areTemplates); + SetIconsAreTemplates(areTemplates); } else if (method == "SetTooltip") { std::string tooltip; arguments.GetString(0, &tooltip); diff --git a/src/api/tray/tray.h b/src/api/tray/tray.h index 8f54eccb99..6795e59e5d 100644 --- a/src/api/tray/tray.h +++ b/src/api/tray/tray.h @@ -69,10 +69,13 @@ class Tray : public Base { void Remove(); // Alternate icons only work with Macs void SetAltIcon(const std::string& alticon_path); + // Template icons only work with Macs + void SetIconsAreTemplates(bool areTemplates); #if defined(OS_MACOSX) __block NSStatusItem* status_item_; MacTrayObserver* status_observer_; + bool iconsAreTemplates; #elif 0 GtkStatusIcon* status_item_; diff --git a/src/api/tray/tray.js b/src/api/tray/tray.js index 4f55cbfd94..512dfb961e 100644 --- a/src/api/tray/tray.js +++ b/src/api/tray/tray.js @@ -42,6 +42,11 @@ function Tray(option) { option.alticon = nw.getAbsolutePath(option.alticon); } + if (option.hasOwnProperty('iconsAreTemplates')) + option.iconsAreTemplates = Boolean(option.iconsAreTemplates); + else + option.iconsAreTemplates = true; + if (option.hasOwnProperty('tooltip')) option.tooltip = String(option.tooltip); @@ -103,6 +108,14 @@ Tray.prototype.__defineSetter__('alticon', function(val) { this.handleSetter('alticon', 'SetAlticon', String, real_path); }); +Tray.prototype.__defineGetter__('iconsAreTemplates', function() { + return this.handleGetter('iconsAreTemplates'); +}); + +Tray.prototype.__defineSetter__('iconsAreTemplates', function(val) { + this.handleSetter('iconsAreTemplates', 'SetIconsAreTemplates', Boolean, val); +}); + Tray.prototype.__defineGetter__('tooltip', function() { return this.handleGetter('tooltip'); }); diff --git a/src/api/tray/tray_aura.cc b/src/api/tray/tray_aura.cc index 4c0c677da1..404530c8a2 100644 --- a/src/api/tray/tray_aura.cc +++ b/src/api/tray/tray_aura.cc @@ -107,4 +107,7 @@ void Tray::Remove() { void Tray::SetAltIcon(const std::string& alticon_path) { } +void Tray::SetIconsAreTemplates(bool areTemplates) { +} + } // namespace nwapi diff --git a/src/api/tray/tray_gtk.cc b/src/api/tray/tray_gtk.cc index 33a9078e6d..12b5990ef2 100644 --- a/src/api/tray/tray_gtk.cc +++ b/src/api/tray/tray_gtk.cc @@ -83,4 +83,7 @@ void Tray::OnPopupMenu(GtkWidget* widget, guint button, guint time) { void Tray::SetAltIcon(const std::string& alticon_path) { } +void Tray::SetIconsAreTemplates(bool areTemplates) { +} + } // namespace nwapi diff --git a/src/api/tray/tray_mac.mm b/src/api/tray/tray_mac.mm index c983063883..26dc56910a 100644 --- a/src/api/tray/tray_mac.mm +++ b/src/api/tray/tray_mac.mm @@ -72,6 +72,7 @@ - (void)onClick:(id)sender { if (!icon.empty()) { NSImage* image = [[NSImage alloc] initWithContentsOfFile:[NSString stringWithUTF8String:icon.c_str()]]; + [image setTemplate:iconsAreTemplates]; [status_item_ setImage:image]; [image release]; } else { @@ -83,6 +84,7 @@ - (void)onClick:(id)sender { if (!alticon.empty()) { NSImage* image = [[NSImage alloc] initWithContentsOfFile:[NSString stringWithUTF8String:alticon.c_str()]]; + [image setTemplate:iconsAreTemplates]; [status_item_ setAlternateImage:image]; [image release]; } else { @@ -90,6 +92,16 @@ - (void)onClick:(id)sender { } } +void Tray::SetIconsAreTemplates(bool areTemplates) { + iconsAreTemplates = areTemplates; + if ([status_item_ image] != nil) { + [[status_item_ image] setTemplate:areTemplates]; + } + if ([status_item_ alternateImage] != nil) { + [[status_item_ alternateImage] setTemplate:areTemplates]; + } +} + void Tray::SetTooltip(const std::string& tooltip) { [status_item_ setToolTip:[NSString stringWithUTF8String:tooltip.c_str()]]; } From 0b3fda020606bfd5d6390db086fa558c9571c9da Mon Sep 17 00:00:00 2001 From: Marco Fabbri Date: Tue, 9 Dec 2014 16:17:38 +0100 Subject: [PATCH 2/2] [OSX] Add iconIsTemplate property to MenuItem API objects Add boolean property (defaults to `true`) `iconsIsTemplate` to `MenuItem` objects to allow for proper display of icons in Mac OS X (Yosemite) Dark Menus. When `iconsIsTemplate` is set to true, the `icon` is treated as a "template" and the system automatically ensures proper styling according to the various states of the menu item (e.g. dark menu, light menu, etc.). Template images should consist only of black and clear colours and can use the alpha channel in the image to adjust the opacity of black content. See [Dark Menus in AppKit Release Notes for OS X v10.10](https://developer.apple.com/library/mac/releasenotes/AppKit/RN-AppKit/#10_10DarkMenus) and [`NSImage setTemplate:`](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSImage_Class/index.html#//apple_ref/occ/instm/NSImage/setTemplate:). On Linux and Windows setting the property has no effect. FIX rogerwang/node-webkit#2773 --- src/api/menuitem/menuitem.cc | 4 ++++ src/api/menuitem/menuitem.h | 4 ++++ src/api/menuitem/menuitem.js | 13 +++++++++++++ src/api/menuitem/menuitem_gtk.cc | 3 +++ src/api/menuitem/menuitem_mac.mm | 11 +++++++++++ src/api/menuitem/menuitem_views.cc | 3 +++ 6 files changed, 38 insertions(+) diff --git a/src/api/menuitem/menuitem.cc b/src/api/menuitem/menuitem.cc index 2765e4ac0c..d6b6d1ae92 100644 --- a/src/api/menuitem/menuitem.cc +++ b/src/api/menuitem/menuitem.cc @@ -50,6 +50,10 @@ void MenuItem::Call(const std::string& method, std::string icon; arguments.GetString(0, &icon); SetIcon(icon); + } else if (method == "SetIconIsTemplate") { + bool isTemplate; + arguments.GetBoolean(0, &isTemplate); + SetIconIsTemplate(isTemplate); } else if (method == "SetTooltip") { std::string tooltip; arguments.GetString(0, &tooltip); diff --git a/src/api/menuitem/menuitem.h b/src/api/menuitem/menuitem.h index b1a5bc7e8e..6060b8a5db 100644 --- a/src/api/menuitem/menuitem.h +++ b/src/api/menuitem/menuitem.h @@ -82,11 +82,15 @@ class MenuItem : public Base { void SetChecked(bool checked); void SetSubmenu(Menu* sub_menu); + // Template icon works only on Mac OS X + void SetIconIsTemplate(bool isTemplate); + #if defined(OS_MACOSX) std::string type_; NSMenuItem* menu_item_; MenuItemDelegate* delegate_; + bool iconIsTemplate; #elif defined(OS_WIN) || defined(OS_LINUX) friend class MenuDelegate; diff --git a/src/api/menuitem/menuitem.js b/src/api/menuitem/menuitem.js index bacff28344..f0f1bd4e72 100644 --- a/src/api/menuitem/menuitem.js +++ b/src/api/menuitem/menuitem.js @@ -46,6 +46,11 @@ function MenuItem(option) { option.icon = nw.getAbsolutePath(option.icon); } + if (option.hasOwnProperty('iconIsTemplate')) + option.iconIsTemplate = Boolean(option.iconIsTemplate); + else + option.iconIsTemplate = true; + if (option.hasOwnProperty('tooltip')) option.tooltip = String(option.tooltip); @@ -116,6 +121,14 @@ MenuItem.prototype.__defineSetter__('icon', function(val) { this.handleSetter('icon', 'SetIcon', String, real_path); }); +MenuItem.prototype.__defineGetter__('iconIsTemplate', function() { + return this.handleGetter('iconIsTemplate'); +}); + +MenuItem.prototype.__defineSetter__('iconIsTemplate', function(val) { + this.handleSetter('iconIsTemplate', 'SetIconIsTemplate', Boolean, val); +}); + MenuItem.prototype.__defineGetter__('tooltip', function() { return this.handleGetter('tooltip'); }); diff --git a/src/api/menuitem/menuitem_gtk.cc b/src/api/menuitem/menuitem_gtk.cc index b9b4f39e7f..91955e2924 100644 --- a/src/api/menuitem/menuitem_gtk.cc +++ b/src/api/menuitem/menuitem_gtk.cc @@ -124,6 +124,9 @@ void MenuItem::SetIcon(const std::string& icon) { } } +void MenuItem::SetIconIsTemplate(bool isTemplate) { +} + void MenuItem::SetTooltip(const std::string& tooltip) { gtk_widget_set_tooltip_text(menu_item_, tooltip.c_str()); } diff --git a/src/api/menuitem/menuitem_mac.mm b/src/api/menuitem/menuitem_mac.mm index 36c8f6c55c..5d3e2960fc 100644 --- a/src/api/menuitem/menuitem_mac.mm +++ b/src/api/menuitem/menuitem_mac.mm @@ -71,6 +71,10 @@ if (option.GetBoolean("enabled", &enabled)) SetEnabled(enabled); + bool isTemplate; + if (option.GetBoolean("iconIsTemplate", &isTemplate)) + SetIconIsTemplate(isTemplate); + std::string icon; if (option.GetString("icon", &icon) && !icon.empty()) SetIcon(icon); @@ -131,6 +135,7 @@ if (!icon.empty()) { NSImage* image = [[NSImage alloc] initWithContentsOfFile:[NSString stringWithUTF8String:icon.c_str()]]; + [image setTemplate:iconIsTemplate]; [menu_item_ setImage:image]; [image release]; } else { @@ -138,6 +143,12 @@ } } +void MenuItem::SetIconIsTemplate(bool isTemplate) { + iconIsTemplate = isTemplate; + if ([menu_item_ image] != nil) + [[menu_item_ image] setTemplate:isTemplate]; +} + void MenuItem::SetTooltip(const std::string& tooltip) { [menu_item_ setToolTip:[NSString stringWithUTF8String:tooltip.c_str()]]; } diff --git a/src/api/menuitem/menuitem_views.cc b/src/api/menuitem/menuitem_views.cc index 20dcc4b6ee..238a7c46fc 100644 --- a/src/api/menuitem/menuitem_views.cc +++ b/src/api/menuitem/menuitem_views.cc @@ -134,6 +134,9 @@ void MenuItem::SetIcon(const std::string& icon) { package->GetImage(base::FilePath::FromUTF8Unsafe(icon), &icon_); } +void MenuItem::SetIconIsTemplate(bool isTemplate) { +} + void MenuItem::SetTooltip(const std::string& tooltip) { tooltip_ = base::UTF8ToUTF16(tooltip); if (menu_)