diff --git a/atom/browser/api/atom_api_tray.cc b/atom/browser/api/atom_api_tray.cc index 34fe81b92b22..c84e8a1d66b6 100644 --- a/atom/browser/api/atom_api_tray.cc +++ b/atom/browser/api/atom_api_tray.cc @@ -9,6 +9,7 @@ #include "atom/browser/api/atom_api_menu.h" #include "atom/browser/browser.h" #include "atom/browser/ui/tray_icon.h" +#include "atom/common/api/atom_api_native_image.h" #include "atom/common/native_mate_converters/gfx_converter.h" #include "atom/common/native_mate_converters/image_converter.h" #include "atom/common/native_mate_converters/string16_converter.h" @@ -22,9 +23,9 @@ namespace atom { namespace api { -Tray::Tray(v8::Isolate* isolate, const gfx::Image& image) +Tray::Tray(v8::Isolate* isolate, mate::Handle image) : tray_icon_(TrayIcon::Create()) { - tray_icon_->SetImage(image); + SetImage(isolate, image); tray_icon_->AddObserver(this); } @@ -32,7 +33,8 @@ Tray::~Tray() { } // static -mate::WrappableBase* Tray::New(v8::Isolate* isolate, const gfx::Image& image) { +mate::WrappableBase* Tray::New(v8::Isolate* isolate, + mate::Handle image) { if (!Browser::Get()->is_ready()) { isolate->ThrowException(v8::Exception::Error(mate::StringToV8( isolate, "Cannot create Tray before app is ready"))); @@ -94,29 +96,38 @@ void Tray::OnDragEnded() { Emit("drag-end"); } -void Tray::SetImage(mate::Arguments* args, const gfx::Image& image) { - tray_icon_->SetImage(image); +void Tray::SetImage(v8::Isolate* isolate, mate::Handle image) { +#if defined(OS_WIN) + tray_icon_->SetImage(image->GetHICON(GetSystemMetrics(SM_CXSMICON))); +#else + tray_icon_->SetImage(image->image()); +#endif } -void Tray::SetPressedImage(mate::Arguments* args, const gfx::Image& image) { - tray_icon_->SetPressedImage(image); +void Tray::SetPressedImage(v8::Isolate* isolate, + mate::Handle image) { +#if defined(OS_WIN) + tray_icon_->SetPressedImage(image->GetHICON(GetSystemMetrics(SM_CXSMICON))); +#else + tray_icon_->SetPressedImage(image->image()); +#endif } -void Tray::SetToolTip(mate::Arguments* args, const std::string& tool_tip) { +void Tray::SetToolTip(const std::string& tool_tip) { tray_icon_->SetToolTip(tool_tip); } -void Tray::SetTitle(mate::Arguments* args, const std::string& title) { +void Tray::SetTitle(const std::string& title) { tray_icon_->SetTitle(title); } -void Tray::SetHighlightMode(mate::Arguments* args, bool highlight) { +void Tray::SetHighlightMode(bool highlight) { tray_icon_->SetHighlightMode(highlight); } void Tray::DisplayBalloon(mate::Arguments* args, const mate::Dictionary& options) { - gfx::Image icon; + mate::Handle icon; options.Get("icon", &icon); base::string16 title, content; if (!options.Get("title", &title) || @@ -125,7 +136,14 @@ void Tray::DisplayBalloon(mate::Arguments* args, return; } - tray_icon_->DisplayBalloon(icon, title, content); +#if defined(OS_WIN) + tray_icon_->DisplayBalloon( + icon.IsEmpty() ? NULL : icon->GetHICON(GetSystemMetrics(SM_CXSMICON)), + title, content); +#else + tray_icon_->DisplayBalloon( + icon.IsEmpty() ? gfx::Image() : icon->image(), title, content); +#endif } void Tray::PopUpContextMenu(mate::Arguments* args) { @@ -136,7 +154,8 @@ void Tray::PopUpContextMenu(mate::Arguments* args) { tray_icon_->PopUpContextMenu(pos, menu.IsEmpty() ? nullptr : menu->model()); } -void Tray::SetContextMenu(mate::Arguments* args, Menu* menu) { +void Tray::SetContextMenu(v8::Isolate* isolate, mate::Handle menu) { + menu_.Reset(isolate, menu.ToV8()); tray_icon_->SetContextMenu(menu->model()); } @@ -162,7 +181,7 @@ void Tray::BuildPrototype(v8::Isolate* isolate, .SetMethod("setHighlightMode", &Tray::SetHighlightMode) .SetMethod("displayBalloon", &Tray::DisplayBalloon) .SetMethod("popUpContextMenu", &Tray::PopUpContextMenu) - .SetMethod("_setContextMenu", &Tray::SetContextMenu); + .SetMethod("setContextMenu", &Tray::SetContextMenu); } } // namespace api diff --git a/atom/browser/api/atom_api_tray.h b/atom/browser/api/atom_api_tray.h index 84e68220dba8..3c3d02e9ca40 100644 --- a/atom/browser/api/atom_api_tray.h +++ b/atom/browser/api/atom_api_tray.h @@ -11,6 +11,7 @@ #include "atom/browser/api/trackable_object.h" #include "atom/browser/ui/tray_icon_observer.h" #include "base/memory/scoped_ptr.h" +#include "native_mate/handle.h" namespace gfx { class Image; @@ -28,18 +29,19 @@ class TrayIcon; namespace api { class Menu; +class NativeImage; class Tray : public mate::TrackableObject, public TrayIconObserver { public: static mate::WrappableBase* New( - v8::Isolate* isolate, const gfx::Image& image); + v8::Isolate* isolate, mate::Handle image); static void BuildPrototype(v8::Isolate* isolate, v8::Local prototype); protected: - Tray(v8::Isolate* isolate, const gfx::Image& image); + Tray(v8::Isolate* isolate, mate::Handle image); ~Tray() override; // TrayIconObserver: @@ -55,18 +57,19 @@ class Tray : public mate::TrackableObject, void OnDragExited() override; void OnDragEnded() override; - void SetImage(mate::Arguments* args, const gfx::Image& image); - void SetPressedImage(mate::Arguments* args, const gfx::Image& image); - void SetToolTip(mate::Arguments* args, const std::string& tool_tip); - void SetTitle(mate::Arguments* args, const std::string& title); - void SetHighlightMode(mate::Arguments* args, bool highlight); + void SetImage(v8::Isolate* isolate, mate::Handle image); + void SetPressedImage(v8::Isolate* isolate, mate::Handle image); + void SetToolTip(const std::string& tool_tip); + void SetTitle(const std::string& title); + void SetHighlightMode(bool highlight); void DisplayBalloon(mate::Arguments* args, const mate::Dictionary& options); void PopUpContextMenu(mate::Arguments* args); - void SetContextMenu(mate::Arguments* args, Menu* menu); + void SetContextMenu(v8::Isolate* isolate, mate::Handle menu); private: v8::Local ModifiersToObject(v8::Isolate* isolate, int modifiers); + v8::Global menu_; scoped_ptr tray_icon_; DISALLOW_COPY_AND_ASSIGN(Tray); diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 399b4d36d2ec..dc9f0f6a152e 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -21,8 +21,11 @@ #include "native_mate/dictionary.h" #include "ui/gfx/geometry/rect.h" -#if defined(OS_WIN) +#if defined(TOOLKIT_VIEWS) #include "atom/browser/native_window_views.h" +#endif + +#if defined(OS_WIN) #include "atom/browser/ui/win/taskbar_host.h" #endif @@ -99,6 +102,13 @@ Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) { window_->InitFromOptions(options); window_->AddObserver(this); AttachAsUserData(window_.get()); + +#if defined(TOOLKIT_VIEWS) + // Sets the window icon. + mate::Handle icon; + if (options.Get(options::kIcon, &icon)) + SetIcon(icon); +#endif } Window::~Window() { @@ -617,6 +627,18 @@ void Window::ShowDefinitionForSelection() { } #endif +#if defined(TOOLKIT_VIEWS) +void Window::SetIcon(mate::Handle icon) { +#if defined(OS_WIN) + static_cast(window_.get())->SetIcon( + icon->GetHICON(GetSystemMetrics(SM_CXSMICON)), icon->GetHICON(256)); +#elif defined(USE_X11) + static_cast(window_.get())->SetIcon( + icon->image().AsImageSkia()); +#endif +} +#endif + void Window::SetAspectRatio(double aspect_ratio, mate::Arguments* args) { gfx::Size extra_size; args->GetNext(&extra_size); @@ -738,6 +760,9 @@ void Window::BuildPrototype(v8::Isolate* isolate, #if defined(OS_MACOSX) .SetMethod("showDefinitionForSelection", &Window::ShowDefinitionForSelection) +#endif +#if defined(TOOLKIT_VIEWS) + .SetMethod("setIcon", &Window::SetIcon) #endif .SetProperty("id", &Window::ID) .SetProperty("webContents", &Window::WebContents); diff --git a/atom/browser/api/atom_api_window.h b/atom/browser/api/atom_api_window.h index a00e063d99f8..7746dd8d7681 100644 --- a/atom/browser/api/atom_api_window.h +++ b/atom/browser/api/atom_api_window.h @@ -14,6 +14,7 @@ #include "atom/browser/api/trackable_object.h" #include "atom/browser/native_window.h" #include "atom/browser/native_window_observer.h" +#include "atom/common/api/atom_api_native_image.h" #include "native_mate/handle.h" class GURL; @@ -172,6 +173,10 @@ class Window : public mate::TrackableObject, void ShowDefinitionForSelection(); #endif +#if defined(TOOLKIT_VIEWS) + void SetIcon(mate::Handle icon); +#endif + void SetVisibleOnAllWorkspaces(bool visible); bool IsVisibleOnAllWorkspaces(); diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index 0d5c26c560d1..23a434a81b45 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -12,7 +12,6 @@ #include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/window_list.h" #include "atom/common/api/api_messages.h" -#include "atom/common/native_mate_converters/image_converter.h" #include "atom/common/native_mate_converters/file_path_converter.h" #include "atom/common/options_switches.h" #include "base/files/file_util.h" @@ -65,9 +64,6 @@ NativeWindow::NativeWindow( // mode. ui::GpuSwitchingManager::SetTransparent(transparent_); - // Read icon before window is created. - options.Get(options::kIcon, &icon_); - WindowList::AddWindow(this); } diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index 7317a7ba6f76..6a96c013e79e 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -251,7 +251,6 @@ class NativeWindow : public base::SupportsUserData, bool transparent() const { return transparent_; } SkRegion* draggable_region() const { return draggable_region_.get(); } bool enable_larger_than_screen() const { return enable_larger_than_screen_; } - gfx::ImageSkia icon() const { return icon_; } void set_has_dialog_attached(bool has_dialog_attached) { has_dialog_attached_ = has_dialog_attached; @@ -307,9 +306,6 @@ class NativeWindow : public base::SupportsUserData, // Whether window can be resized larger than screen. bool enable_larger_than_screen_; - // Window icon. - gfx::ImageSkia icon_; - // The windows has been closed. bool is_closed_; diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index a04a5a0eb25e..82c1158bdcf1 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -11,6 +11,7 @@ #include "atom/browser/ui/views/menu_layout.h" #include "atom/common/color_util.h" #include "atom/common/draggable_region.h" +#include "atom/common/native_mate_converters/image_converter.h" #include "atom/common/options_switches.h" #include "base/strings/utf_string_conversions.h" #include "brightray/browser/inspectable_web_contents.h" @@ -40,6 +41,7 @@ #include "chrome/browser/ui/libgtk2ui/unity_service.h" #include "ui/base/x/x11_util.h" #include "ui/gfx/x/x11_types.h" +#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h" #include "ui/views/window/native_frame_view.h" #elif defined(OS_WIN) #include "atom/browser/ui/views/win_frame_view.h" @@ -273,7 +275,6 @@ NativeWindowViews::NativeWindowViews( use_content_size_) size = ContentSizeToWindowSize(size); - window_->UpdateWindowIcon(); window_->CenterWindow(size); Layout(); } @@ -778,6 +779,23 @@ gfx::AcceleratedWidget NativeWindowViews::GetAcceleratedWidget() { return GetNativeWindow()->GetHost()->GetAcceleratedWidget(); } +#if defined(OS_WIN) +void NativeWindowViews::SetIcon(HICON small_icon, HICON app_icon) { + HWND hwnd = GetAcceleratedWidget(); + SendMessage(hwnd, WM_SETICON, ICON_SMALL, + reinterpret_cast(small_icon)); + SendMessage(hwnd, WM_SETICON, ICON_BIG, + reinterpret_cast(app_icon)); +} +#elif defined(USE_X11) +void NativeWindowViews::SetIcon(const gfx::ImageSkia& icon) { + views::DesktopWindowTreeHostX11* tree_host = + views::DesktopWindowTreeHostX11::GetHostForXID(GetAcceleratedWidget()); + static_cast(tree_host)->SetWindowIcons( + icon, icon); +} +#endif + void NativeWindowViews::OnWidgetActivationChanged( views::Widget* widget, bool active) { if (widget != window_.get()) @@ -842,14 +860,6 @@ bool NativeWindowViews::ShouldHandleSystemCommands() const { return true; } -gfx::ImageSkia NativeWindowViews::GetWindowAppIcon() { - return icon(); -} - -gfx::ImageSkia NativeWindowViews::GetWindowIcon() { - return GetWindowAppIcon(); -} - views::Widget* NativeWindowViews::GetWidget() { return window_.get(); } diff --git a/atom/browser/native_window_views.h b/atom/browser/native_window_views.h index bcf3ca8bd16f..8a5d8ae0e082 100644 --- a/atom/browser/native_window_views.h +++ b/atom/browser/native_window_views.h @@ -104,6 +104,12 @@ class NativeWindowViews : public NativeWindow, gfx::AcceleratedWidget GetAcceleratedWidget() override; +#if defined(OS_WIN) + void SetIcon(HICON small_icon, HICON app_icon); +#elif defined(USE_X11) + void SetIcon(const gfx::ImageSkia& icon); +#endif + views::Widget* widget() const { return window_.get(); } #if defined(OS_WIN) @@ -125,8 +131,6 @@ class NativeWindowViews : public NativeWindow, bool CanMinimize() const override; base::string16 GetWindowTitle() const override; bool ShouldHandleSystemCommands() const override; - gfx::ImageSkia GetWindowAppIcon() override; - gfx::ImageSkia GetWindowIcon() override; views::Widget* GetWidget() override; const views::Widget* GetWidget() const override; views::View* GetContentsView() override; @@ -145,7 +149,6 @@ class NativeWindowViews : public NativeWindow, // MessageHandlerDelegate: bool PreHandleMSG( UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) override; - void HandleSizeEvent(WPARAM w_param, LPARAM l_param); #endif @@ -202,7 +205,6 @@ class NativeWindowViews : public NativeWindow, // If true we have enabled a11y bool enabled_a11y_support_; - #endif // Handles unhandled keyboard messages coming back from the renderer process. diff --git a/atom/browser/ui/tray_icon.cc b/atom/browser/ui/tray_icon.cc index 60923c2ad0a6..dcdb90ac159c 100644 --- a/atom/browser/ui/tray_icon.cc +++ b/atom/browser/ui/tray_icon.cc @@ -12,7 +12,7 @@ TrayIcon::TrayIcon() { TrayIcon::~TrayIcon() { } -void TrayIcon::SetPressedImage(const gfx::Image& image) { +void TrayIcon::SetPressedImage(ImageType image) { } void TrayIcon::SetTitle(const std::string& title) { @@ -21,7 +21,7 @@ void TrayIcon::SetTitle(const std::string& title) { void TrayIcon::SetHighlightMode(bool highlight) { } -void TrayIcon::DisplayBalloon(const gfx::Image& icon, +void TrayIcon::DisplayBalloon(ImageType icon, const base::string16& title, const base::string16& contents) { } diff --git a/atom/browser/ui/tray_icon.h b/atom/browser/ui/tray_icon.h index c80ff08d6a52..dd018821cd3a 100644 --- a/atom/browser/ui/tray_icon.h +++ b/atom/browser/ui/tray_icon.h @@ -19,13 +19,19 @@ class TrayIcon { public: static TrayIcon* Create(); +#if defined(OS_WIN) + using ImageType = HICON; +#else + using ImageType = const gfx::Image&; +#endif + virtual ~TrayIcon(); // Sets the image associated with this status icon. - virtual void SetImage(const gfx::Image& image) = 0; + virtual void SetImage(ImageType image) = 0; // Sets the image associated with this status icon when pressed. - virtual void SetPressedImage(const gfx::Image& image); + virtual void SetPressedImage(ImageType image); // Sets the hover text for this status icon. This is also used as the label // for the menu item which is created as a replacement for the status icon @@ -43,7 +49,7 @@ class TrayIcon { // Displays a notification balloon with the specified contents. // Depending on the platform it might not appear by the icon tray. - virtual void DisplayBalloon(const gfx::Image& icon, + virtual void DisplayBalloon(ImageType icon, const base::string16& title, const base::string16& contents); diff --git a/atom/browser/ui/win/notify_icon.cc b/atom/browser/ui/win/notify_icon.cc index 464dc144ba3e..1cc616216c6e 100644 --- a/atom/browser/ui/win/notify_icon.cc +++ b/atom/browser/ui/win/notify_icon.cc @@ -9,7 +9,6 @@ #include "base/strings/utf_string_conversions.h" #include "base/win/windows_version.h" #include "third_party/skia/include/core/SkBitmap.h" -#include "ui/gfx/icon_util.h" #include "ui/gfx/image/image.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/rect.h" @@ -91,19 +90,20 @@ void NotifyIcon::ResetIcon() { LOG(WARNING) << "Unable to re-create status tray icon."; } -void NotifyIcon::SetImage(const gfx::Image& image) { +void NotifyIcon::SetImage(HICON image) { + icon_ = base::win::ScopedHICON(CopyIcon(image)); + // Create the icon. NOTIFYICONDATA icon_data; InitIconData(&icon_data); icon_data.uFlags |= NIF_ICON; - icon_ = IconUtil::CreateHICONFromSkBitmap(image.AsBitmap()); - icon_data.hIcon = icon_.get(); + icon_data.hIcon = image; BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data); if (!result) LOG(WARNING) << "Error setting status tray icon image"; } -void NotifyIcon::SetPressedImage(const gfx::Image& image) { +void NotifyIcon::SetPressedImage(HICON image) { // Ignore pressed images, since the standard on Windows is to not highlight // pressed status icons. } @@ -119,7 +119,7 @@ void NotifyIcon::SetToolTip(const std::string& tool_tip) { LOG(WARNING) << "Unable to set tooltip for status tray icon"; } -void NotifyIcon::DisplayBalloon(const gfx::Image& icon, +void NotifyIcon::DisplayBalloon(HICON icon, const base::string16& title, const base::string16& contents) { NOTIFYICONDATA icon_data; @@ -129,13 +129,8 @@ void NotifyIcon::DisplayBalloon(const gfx::Image& icon, wcsncpy_s(icon_data.szInfoTitle, title.c_str(), _TRUNCATE); wcsncpy_s(icon_data.szInfo, contents.c_str(), _TRUNCATE); icon_data.uTimeout = 0; - - base::win::Version win_version = base::win::GetVersion(); - if (!icon.IsEmpty() && win_version != base::win::VERSION_PRE_XP) { - balloon_icon_ = IconUtil::CreateHICONFromSkBitmap(icon.AsBitmap()); - icon_data.hBalloonIcon = balloon_icon_.get(); - icon_data.dwInfoFlags = NIIF_USER | NIIF_LARGE_ICON; - } + icon_data.hBalloonIcon = icon; + icon_data.dwInfoFlags = NIIF_USER | NIIF_LARGE_ICON; BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data); if (!result) diff --git a/atom/browser/ui/win/notify_icon.h b/atom/browser/ui/win/notify_icon.h index 53ed49b937c1..95e9945a17f8 100644 --- a/atom/browser/ui/win/notify_icon.h +++ b/atom/browser/ui/win/notify_icon.h @@ -45,10 +45,10 @@ class NotifyIcon : public TrayIcon { UINT message_id() const { return message_id_; } // Overridden from TrayIcon: - void SetImage(const gfx::Image& image) override; - void SetPressedImage(const gfx::Image& image) override; + void SetImage(HICON image) override; + void SetPressedImage(HICON image) override; void SetToolTip(const std::string& tool_tip) override; - void DisplayBalloon(const gfx::Image& icon, + void DisplayBalloon(HICON icon, const base::string16& title, const base::string16& contents) override; void PopUpContextMenu(const gfx::Point& pos, @@ -73,9 +73,6 @@ class NotifyIcon : public TrayIcon { // The currently-displayed icon for the window. base::win::ScopedHICON icon_; - // The currently-displayed icon for the notification balloon. - base::win::ScopedHICON balloon_icon_; - // The context menu. ui::SimpleMenuModel* menu_model_; diff --git a/atom/common/api/atom_api_native_image.cc b/atom/common/api/atom_api_native_image.cc index 97cc674a3115..d5a75e3f440b 100644 --- a/atom/common/api/atom_api_native_image.cc +++ b/atom/common/api/atom_api_native_image.cc @@ -142,7 +142,7 @@ bool IsTemplateFilename(const base::FilePath& path) { #endif #if defined(OS_WIN) -bool ReadImageSkiaFromICO(gfx::ImageSkia* image, const base::FilePath& path) { +base::win::ScopedHICON ReadICOFromPath(int size, const base::FilePath& path) { // If file is in asar archive, we extract it to a temp file so LoadImage can // load it. base::FilePath asar_path, relative_path; @@ -155,16 +155,15 @@ bool ReadImageSkiaFromICO(gfx::ImageSkia* image, const base::FilePath& path) { } // Load the icon from file. - base::win::ScopedHICON icon(static_cast( - LoadImage(NULL, image_path.value().c_str(), IMAGE_ICON, 0, 0, - LR_DEFAULTSIZE | LR_LOADFROMFILE))); - if (!icon.get()) - return false; + return base::win::ScopedHICON(static_cast( + LoadImage(NULL, image_path.value().c_str(), IMAGE_ICON, size, size, + LR_LOADFROMFILE))); +} +void ReadImageSkiaFromICO(gfx::ImageSkia* image, HICON icon) { // Convert the icon from the Windows specific HICON to gfx::ImageSkia. - scoped_ptr bitmap(IconUtil:: CreateSkBitmapFromHICON(icon.get())); + scoped_ptr bitmap(IconUtil::CreateSkBitmapFromHICON(icon)); image->AddRepresentation(gfx::ImageSkiaRep(*bitmap, 1.0f)); - return true; } #endif @@ -175,8 +174,40 @@ NativeImage::NativeImage(v8::Isolate* isolate, const gfx::Image& image) Init(isolate); } +#if defined(OS_WIN) +NativeImage::NativeImage(v8::Isolate* isolate, const base::FilePath& hicon_path) + : hicon_path_(hicon_path) { + // Use the 256x256 icon as fallback icon. + gfx::ImageSkia image_skia; + ReadImageSkiaFromICO(&image_skia, GetHICON(256)); + image_ = gfx::Image(image_skia); + Init(isolate); +} +#endif + NativeImage::~NativeImage() {} +#if defined(OS_WIN) +HICON NativeImage::GetHICON(int size) { + auto iter = hicons_.find(size); + if (iter != hicons_.end()) + return iter->second.get(); + + // First try loading the icon with specified size. + if (!hicon_path_.empty()) { + hicons_[size] = std::move(ReadICOFromPath(size, hicon_path_)); + return hicons_[size].get(); + } + + // Then convert the image to ICO. + if (image_.IsEmpty()) + return NULL; + hicons_[size] = std::move( + IconUtil::CreateHICONFromSkBitmap(image_.AsBitmap())); + return hicons_[size].get(); +} +#endif + v8::Local NativeImage::ToPNG(v8::Isolate* isolate) { scoped_refptr png = image_.As1xPNGBytes(); return node::Buffer::Copy(isolate, @@ -263,16 +294,15 @@ mate::Handle NativeImage::CreateFromJPEG( // static mate::Handle NativeImage::CreateFromPath( v8::Isolate* isolate, const base::FilePath& path) { - gfx::ImageSkia image_skia; base::FilePath image_path = NormalizePath(path); - - if (image_path.MatchesExtension(FILE_PATH_LITERAL(".ico"))) { #if defined(OS_WIN) - ReadImageSkiaFromICO(&image_skia, image_path); -#endif - } else { - PopulateImageSkiaRepsFromPath(&image_skia, image_path); + if (image_path.MatchesExtension(FILE_PATH_LITERAL(".ico"))) { + return mate::CreateHandle(isolate, + new NativeImage(isolate, image_path)); } +#endif + gfx::ImageSkia image_skia; + PopulateImageSkiaRepsFromPath(&image_skia, image_path); gfx::Image image(image_skia); mate::Handle handle = Create(isolate, image); #if defined(OS_MACOSX) @@ -328,6 +358,35 @@ void NativeImage::BuildPrototype( } // namespace atom +namespace mate { + +v8::Local Converter>::ToV8( + v8::Isolate* isolate, + const mate::Handle& val) { + return val.ToV8(); +} + +bool Converter>::FromV8( + v8::Isolate* isolate, v8::Local val, + mate::Handle* out) { + // Try converting from file path. + base::FilePath path; + if (ConvertFromV8(isolate, val, &path)) { + *out = atom::api::NativeImage::CreateFromPath(isolate, path); + // Should throw when failed to initialize from path. + return !(*out)->image().IsEmpty(); + } + + WrappableBase* wrapper = static_cast(internal::FromV8Impl( + isolate, val)); + if (!wrapper) + return false; + + *out = CreateHandle(isolate, static_cast(wrapper)); + return true; +} + +} // namespace mate namespace { diff --git a/atom/common/api/atom_api_native_image.h b/atom/common/api/atom_api_native_image.h index 79844604706c..de4db4c0f382 100644 --- a/atom/common/api/atom_api_native_image.h +++ b/atom/common/api/atom_api_native_image.h @@ -5,12 +5,18 @@ #ifndef ATOM_COMMON_API_ATOM_API_NATIVE_IMAGE_H_ #define ATOM_COMMON_API_ATOM_API_NATIVE_IMAGE_H_ +#include #include #include "native_mate/handle.h" #include "native_mate/wrappable.h" #include "ui/gfx/image/image.h" +#if defined(OS_WIN) +#include "base/files/file_path.h" +#include "base/win/scoped_gdi_object.h" +#endif + class GURL; namespace base { @@ -48,10 +54,17 @@ class NativeImage : public mate::Wrappable { static void BuildPrototype(v8::Isolate* isolate, v8::Local prototype); +#if defined(OS_WIN) + HICON GetHICON(int size); +#endif + const gfx::Image& image() const { return image_; } protected: NativeImage(v8::Isolate* isolate, const gfx::Image& image); +#if defined(OS_WIN) + NativeImage(v8::Isolate* isolate, const base::FilePath& hicon_path); +#endif ~NativeImage() override; private: @@ -69,6 +82,11 @@ class NativeImage : public mate::Wrappable { // Determine if the image is a template image. bool IsTemplateImage(); +#if defined(OS_WIN) + base::FilePath hicon_path_; + std::map hicons_; +#endif + gfx::Image image_; DISALLOW_COPY_AND_ASSIGN(NativeImage); @@ -78,4 +96,19 @@ class NativeImage : public mate::Wrappable { } // namespace atom +namespace mate { + +// A custom converter that allows converting path to NativeImage. +template<> +struct Converter> { + static v8::Local ToV8( + v8::Isolate* isolate, + const mate::Handle& val); + static bool FromV8(v8::Isolate* isolate, v8::Local val, + mate::Handle* out); +}; + +} // namespace mate + + #endif // ATOM_COMMON_API_ATOM_API_NATIVE_IMAGE_H_ diff --git a/atom/common/native_mate_converters/image_converter.cc b/atom/common/native_mate_converters/image_converter.cc index 550bb7b904a7..cfb1938a138f 100644 --- a/atom/common/native_mate_converters/image_converter.cc +++ b/atom/common/native_mate_converters/image_converter.cc @@ -28,16 +28,8 @@ bool Converter::FromV8(v8::Isolate* isolate, return true; Handle native_image; - if (!ConvertFromV8(isolate, val, &native_image)) { - // Try converting from file path. - base::FilePath path; - if (!Converter::FromV8(isolate, val, &path)) - return false; - - native_image = atom::api::NativeImage::CreateFromPath(isolate, path); - if (native_image->image().IsEmpty()) - return false; - } + if (!ConvertFromV8(isolate, val, &native_image)) + return false; *out = native_image->image(); return true; diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 93785878d146..aa21e5fd59ad 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -65,8 +65,9 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. `false`. * `kiosk` Boolean - The kiosk mode. Default is `false`. * `title` String - Default window title. Default is `"Electron"`. - * `icon` [NativeImage](native-image.md) - The window icon, when omitted on - Windows the executable's icon would be used as window icon. + * `icon` [NativeImage](native-image.md) - The window icon. On Windows it is + recommended to use `ICO` icons to get best visual effects, you can also + leave it undefined so the executable's icon will be used. * `show` Boolean - Whether window should be shown when created. Default is `true`. * `frame` Boolean - Specify `false` to create a @@ -885,6 +886,12 @@ The `flags` is an array that can include following `String`s: Shows pop-up dictionary that searches the selected word on the page. +### `win.setIcon(icon)` _Windows_ _Linux_ + +* `icon` [NativeImage](native-image.md) + +Changes window icon. + ### `win.setAutoHideMenuBar(hide)` * `hide` Boolean diff --git a/docs/api/native-image.md b/docs/api/native-image.md index b8479ac3b386..9790daaca49e 100644 --- a/docs/api/native-image.md +++ b/docs/api/native-image.md @@ -25,7 +25,12 @@ const appIcon = new Tray(image); Currently `PNG` and `JPEG` image formats are supported. `PNG` is recommended because of its support for transparency and lossless compression. -On Windows, you can also load an `ICO` icon from a file path. +On Windows, you can also load `ICO` icons from file paths, to get best visual +effects it is recommended to include at least followings sizes in the icon: + +* 16x16 +* 32x32 +* 256x256 ## High Resolution Image diff --git a/docs/api/tray.md b/docs/api/tray.md index 3fa6f606e90a..4c4891ef8960 100644 --- a/docs/api/tray.md +++ b/docs/api/tray.md @@ -29,6 +29,7 @@ __Platform limitations:__ * When app indicator is used on Linux, the `click` event is ignored. * On Linux in order for changes made to individual `MenuItem`s to take effect, you have to call `setContextMenu` again. For example: +* On Windows it is recommended to use `ICO` icons to get best visual effects. ```javascript contextMenu.items[2].checked = false; diff --git a/lib/browser/api/tray.js b/lib/browser/api/tray.js index 2afdb3643146..bc0a9d26f655 100644 --- a/lib/browser/api/tray.js +++ b/lib/browser/api/tray.js @@ -3,11 +3,4 @@ const {Tray} = process.atomBinding('tray') Object.setPrototypeOf(Tray.prototype, EventEmitter.prototype) -Tray.prototype.setContextMenu = function (menu) { - this._setContextMenu(menu) - - // Keep a strong reference of menu. - this.menu = menu -} - module.exports = Tray diff --git a/vendor/native_mate b/vendor/native_mate index ea07d4c6c89d..4ad6ecd19617 160000 --- a/vendor/native_mate +++ b/vendor/native_mate @@ -1 +1 @@ -Subproject commit ea07d4c6c89d8d460e76b2d2ab9b0ebc51f9a432 +Subproject commit 4ad6ecd19617ac33c09e93ccb6d8e652ac1ac126