diff --git a/atom/browser/api/atom_api_tray.cc b/atom/browser/api/atom_api_tray.cc index c84e8a1d66b6..85c0578a8e89 100644 --- a/atom/browser/api/atom_api_tray.cc +++ b/atom/browser/api/atom_api_tray.cc @@ -159,6 +159,10 @@ void Tray::SetContextMenu(v8::Isolate* isolate, mate::Handle menu) { tray_icon_->SetContextMenu(menu->model()); } +gfx::Rect Tray::GetBounds() { + return tray_icon_->GetBounds(); +} + v8::Local Tray::ModifiersToObject(v8::Isolate* isolate, int modifiers) { mate::Dictionary obj(isolate, v8::Object::New(isolate)); @@ -181,7 +185,8 @@ 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) + .SetMethod("getBounds", &Tray::GetBounds); } } // namespace api diff --git a/atom/browser/api/atom_api_tray.h b/atom/browser/api/atom_api_tray.h index a6c329567ca3..0bc28af818cf 100644 --- a/atom/browser/api/atom_api_tray.h +++ b/atom/browser/api/atom_api_tray.h @@ -65,6 +65,7 @@ class Tray : public mate::TrackableObject, void DisplayBalloon(mate::Arguments* args, const mate::Dictionary& options); void PopUpContextMenu(mate::Arguments* args); void SetContextMenu(v8::Isolate* isolate, mate::Handle menu); + gfx::Rect GetBounds(); private: v8::Local ModifiersToObject(v8::Isolate* isolate, int modifiers); diff --git a/atom/browser/ui/tray_icon.cc b/atom/browser/ui/tray_icon.cc index dcdb90ac159c..fda68b09cd11 100644 --- a/atom/browser/ui/tray_icon.cc +++ b/atom/browser/ui/tray_icon.cc @@ -30,6 +30,10 @@ void TrayIcon::PopUpContextMenu(const gfx::Point& pos, ui::SimpleMenuModel* menu_model) { } +gfx::Rect TrayIcon::GetBounds() { + return gfx::Rect(); +} + void TrayIcon::NotifyClicked(const gfx::Rect& bounds, int modifiers) { FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnClicked(bounds, modifiers)); } diff --git a/atom/browser/ui/tray_icon.h b/atom/browser/ui/tray_icon.h index 1916c11b23af..2763e50941b6 100644 --- a/atom/browser/ui/tray_icon.h +++ b/atom/browser/ui/tray_icon.h @@ -60,8 +60,12 @@ class TrayIcon { // Set the context menu for this icon. virtual void SetContextMenu(ui::SimpleMenuModel* menu_model) = 0; + // Returns the bounds of tray icon. + virtual gfx::Rect GetBounds(); + void AddObserver(TrayIconObserver* obs) { observers_.AddObserver(obs); } void RemoveObserver(TrayIconObserver* obs) { observers_.RemoveObserver(obs); } + void NotifyClicked(const gfx::Rect& = gfx::Rect(), int modifiers = 0); void NotifyDoubleClicked(const gfx::Rect& = gfx::Rect(), int modifiers = 0); void NotifyBalloonShow(); diff --git a/atom/browser/ui/tray_icon_cocoa.h b/atom/browser/ui/tray_icon_cocoa.h index 59e2241aa480..cb972d54a9af 100644 --- a/atom/browser/ui/tray_icon_cocoa.h +++ b/atom/browser/ui/tray_icon_cocoa.h @@ -32,6 +32,7 @@ class TrayIconCocoa : public TrayIcon, void PopUpContextMenu(const gfx::Point& pos, ui::SimpleMenuModel* menu_model) override; void SetContextMenu(ui::SimpleMenuModel* menu_model) override; + gfx::Rect GetBounds() override; protected: // AtomMenuModel::Observer: diff --git a/atom/browser/ui/tray_icon_cocoa.mm b/atom/browser/ui/tray_icon_cocoa.mm index 0dfd59132ae8..8b25aa3540ff 100644 --- a/atom/browser/ui/tray_icon_cocoa.mm +++ b/atom/browser/ui/tray_icon_cocoa.mm @@ -8,6 +8,7 @@ #include "base/strings/sys_string_conversions.h" #include "ui/events/cocoa/cocoa_event_utils.h" #include "ui/gfx/image/image.h" +#include "ui/gfx/mac/coordinate_conversion.h" #include "ui/gfx/screen.h" namespace { @@ -236,13 +237,13 @@ const CGFloat kVerticalTitleMargin = 2; // Single click event. if (event.clickCount == 1) trayIcon_->NotifyClicked( - [self getBoundsFromEvent:event], + gfx::ScreenRectFromNSRect(event.window.frame), ui::EventFlagsFromModifiers([event modifierFlags])); // Double click event. if (event.clickCount == 2) trayIcon_->NotifyDoubleClicked( - [self getBoundsFromEvent:event], + gfx::ScreenRectFromNSRect(event.window.frame), ui::EventFlagsFromModifiers([event modifierFlags])); [self setNeedsDisplay:YES]; @@ -273,7 +274,7 @@ const CGFloat kVerticalTitleMargin = 2; - (void)rightMouseUp:(NSEvent*)event { trayIcon_->NotifyRightClicked( - [self getBoundsFromEvent:event], + gfx::ScreenRectFromNSRect(event.window.frame), ui::EventFlagsFromModifiers([event modifierFlags])); } @@ -324,13 +325,6 @@ const CGFloat kVerticalTitleMargin = 2; return isHighlightEnable_ && (inMouseEventSequence_ || isMenuOpen); } -- (gfx::Rect)getBoundsFromEvent:(NSEvent*)event { - NSRect frame = event.window.frame; - gfx::Rect bounds(frame.origin.x, 0, NSWidth(frame), NSHeight(frame)); - NSScreen* screen = [[NSScreen screens] objectAtIndex:0]; - bounds.set_y(NSHeight([screen frame]) - NSMaxY(frame)); - return bounds; -} @end namespace atom { @@ -386,6 +380,15 @@ void TrayIconCocoa::SetContextMenu(ui::SimpleMenuModel* menu_model) { [status_item_view_ setMenuController:menu_.get()]; } +gfx::Rect TrayIconCocoa::GetBounds() { + auto bounds = gfx::ScreenRectFromNSRect([status_item_view_ window].frame); + // Calling [window frame] immediately after the view gets created will have + // negative |y| sometimes. + if (bounds.y() < 0) + bounds.set_y(0); + return bounds; +} + void TrayIconCocoa::MenuClosed() { [status_item_view_ setNeedsDisplay:YES]; } diff --git a/atom/browser/ui/win/notify_icon.cc b/atom/browser/ui/win/notify_icon.cc index 1cc616216c6e..0ccf46b83212 100644 --- a/atom/browser/ui/win/notify_icon.cc +++ b/atom/browser/ui/win/notify_icon.cc @@ -13,6 +13,7 @@ #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/screen.h" +#include "ui/gfx/win/dpi.h" #include "ui/views/controls/menu/menu_runner.h" namespace atom { @@ -48,26 +49,19 @@ NotifyIcon::~NotifyIcon() { void NotifyIcon::HandleClickEvent(int modifiers, bool left_mouse_click, bool double_button_click) { - NOTIFYICONIDENTIFIER icon_id; - memset(&icon_id, 0, sizeof(NOTIFYICONIDENTIFIER)); - icon_id.uID = icon_id_; - icon_id.hWnd = window_; - icon_id.cbSize = sizeof(NOTIFYICONIDENTIFIER); - - RECT rect = { 0 }; - Shell_NotifyIconGetRect(&icon_id, &rect); + gfx::Rect bounds = GetBounds(); if (left_mouse_click) { if (double_button_click) // double left click - NotifyDoubleClicked(gfx::Rect(rect), modifiers); + NotifyDoubleClicked(bounds, modifiers); else // single left click - NotifyClicked(gfx::Rect(rect), modifiers); + NotifyClicked(bounds, modifiers); return; } else if (!double_button_click) { // single right click if (menu_model_) PopUpContextMenu(gfx::Point(), menu_model_); else - NotifyRightClicked(gfx::Rect(rect), modifiers); + NotifyRightClicked(bounds, modifiers); } } @@ -163,6 +157,18 @@ void NotifyIcon::SetContextMenu(ui::SimpleMenuModel* menu_model) { menu_model_ = menu_model; } +gfx::Rect NotifyIcon::GetBounds() { + NOTIFYICONIDENTIFIER icon_id; + memset(&icon_id, 0, sizeof(NOTIFYICONIDENTIFIER)); + icon_id.uID = icon_id_; + icon_id.hWnd = window_; + icon_id.cbSize = sizeof(NOTIFYICONIDENTIFIER); + + RECT rect = { 0 }; + Shell_NotifyIconGetRect(&icon_id, &rect); + return gfx::win::ScreenToDIPRect(gfx::Rect(rect)); +} + void NotifyIcon::InitIconData(NOTIFYICONDATA* icon_data) { memset(icon_data, 0, sizeof(NOTIFYICONDATA)); icon_data->cbSize = sizeof(NOTIFYICONDATA); diff --git a/atom/browser/ui/win/notify_icon.h b/atom/browser/ui/win/notify_icon.h index 95e9945a17f8..1284ebadcf1c 100644 --- a/atom/browser/ui/win/notify_icon.h +++ b/atom/browser/ui/win/notify_icon.h @@ -54,6 +54,7 @@ class NotifyIcon : public TrayIcon { void PopUpContextMenu(const gfx::Point& pos, ui::SimpleMenuModel* menu_model) override; void SetContextMenu(ui::SimpleMenuModel* menu_model) override; + gfx::Rect GetBounds() override; private: void InitIconData(NOTIFYICONDATA* icon_data); diff --git a/docs/api/tray.md b/docs/api/tray.md index 902444e5336b..aed699b8ee43 100644 --- a/docs/api/tray.md +++ b/docs/api/tray.md @@ -3,20 +3,20 @@ > Add icons and context menus to the system's notification area. ```javascript -const {app, Menu, Tray} = require('electron'); +const {app, Menu, Tray} = require('electron') -let appIcon = null; +let tray = null app.on('ready', () => { - appIcon = new Tray('/path/to/my/icon'); + tray = new Tray('/path/to/my/icon') const contextMenu = Menu.buildFromTemplate([ {label: 'Item1', type: 'radio'}, {label: 'Item2', type: 'radio'}, {label: 'Item3', type: 'radio', checked: true}, {label: 'Item4', type: 'radio'} ]); - appIcon.setToolTip('This is my application.'); - appIcon.setContextMenu(contextMenu); -}); + tray.setToolTip('This is my application.') + tray.setContextMenu(contextMenu) +}) ``` __Platform limitations:__ @@ -49,21 +49,18 @@ rely on the `click` event and always attach a context menu to the tray icon. Creates a new tray icon associated with the `image`. -## Events +### Instance Events The `Tray` module emits the following events: -**Note:** Some events are only available on specific operating systems and are -labeled as such. - -### Event: 'click' +#### Event: 'click' * `event` Event * `altKey` Boolean * `shiftKey` Boolean * `ctrlKey` Boolean * `metaKey` Boolean -* `bounds` Object - the bounds of tray icon. +* `bounds` Object _macOS_ _Windows_ - the bounds of tray icon. * `x` Integer * `y` Integer * `width` Integer @@ -71,9 +68,7 @@ labeled as such. Emitted when the tray icon is clicked. -**Note:** The `bounds` payload is only implemented on macOS and Windows. - -### Event: 'right-click' _macOS_ _Windows_ +#### Event: 'right-click' _macOS_ _Windows_ * `event` Event * `altKey` Boolean @@ -88,7 +83,7 @@ Emitted when the tray icon is clicked. Emitted when the tray icon is right clicked. -### Event: 'double-click' _macOS_ _Windows_ +#### Event: 'double-click' _macOS_ _Windows_ * `event` Event * `altKey` Boolean @@ -103,85 +98,82 @@ Emitted when the tray icon is right clicked. Emitted when the tray icon is double clicked. -### Event: 'balloon-show' _Windows_ +#### Event: 'balloon-show' _Windows_ Emitted when the tray balloon shows. -### Event: 'balloon-click' _Windows_ +#### Event: 'balloon-click' _Windows_ Emitted when the tray balloon is clicked. -### Event: 'balloon-closed' _Windows_ +#### Event: 'balloon-closed' _Windows_ Emitted when the tray balloon is closed because of timeout or user manually closes it. -### Event: 'drop' _macOS_ +#### Event: 'drop' _macOS_ Emitted when any dragged items are dropped on the tray icon. -### Event: 'drop-files' _macOS_ +#### Event: 'drop-files' _macOS_ * `event` * `files` Array - the file path of dropped files. Emitted when dragged files are dropped in the tray icon. -### Event: 'drag-enter' _macOS_ +#### Event: 'drag-enter' _macOS_ Emitted when a drag operation enters the tray icon. -### Event: 'drag-leave' _macOS_ +#### Event: 'drag-leave' _macOS_ Emitted when a drag operation exits the tray icon. -### Event: 'drag-end' _macOS_ +#### Event: 'drag-end' _macOS_ Emitted when a drag operation ends on the tray or ends at another location. -## Methods +### Instance Methods -The `Tray` module has the following methods: +The `Tray` class has the following methods: -**Note:** Some methods are only available on specific operating systems and are -labeled as such. - -### `Tray.destroy()` +#### `tray.destroy()` Destroys the tray icon immediately. -### `Tray.setImage(image)` +#### `tray.setImage(image)` * `image` [NativeImage](native-image.md) Sets the `image` associated with this tray icon. -### `Tray.setPressedImage(image)` _macOS_ +#### `tray.setPressedImage(image)` _macOS_ * `image` [NativeImage](native-image.md) Sets the `image` associated with this tray icon when pressed on macOS. -### `Tray.setToolTip(toolTip)` +#### `tray.setToolTip(toolTip)` * `toolTip` String Sets the hover text for this tray icon. -### `Tray.setTitle(title)` _macOS_ +#### `tray.setTitle(title)` _macOS_ * `title` String Sets the title displayed aside of the tray icon in the status bar. -### `Tray.setHighlightMode(highlight)` _macOS_ +#### `tray.setHighlightMode(highlight)` _macOS_ * `highlight` Boolean Sets whether the tray icon's background becomes highlighted (in blue) when the tray icon is clicked. Defaults to true. -### `Tray.displayBalloon(options)` _Windows_ +#### `tray.displayBalloon(options)` _Windows_ * `options` Object * `icon` [NativeImage](native-image.md) @@ -190,7 +182,7 @@ when the tray icon is clicked. Defaults to true. Displays a tray balloon. -### `Tray.popUpContextMenu([menu, position])` _macOS_ _Windows_ +#### `tray.popUpContextMenu([menu, position])` _macOS_ _Windows_ * `menu` Menu (optional) * `position` Object (optional) - The pop up position. @@ -202,10 +194,20 @@ be shown instead of the tray icon's context menu. The `position` is only available on Windows, and it is (0, 0) by default. -### `Tray.setContextMenu(menu)` +#### `tray.setContextMenu(menu)` * `menu` Menu Sets the context menu for this icon. +#### `tray.getBounds()` _macOS_ _Windows_ + +Returns the `bounds` of this tray icon as `Object`. + +* `bounds` Object + * `x` Integer + * `y` Integer + * `width` Integer + * `height` Integer + [event-emitter]: http://nodejs.org/api/events.html#events_class_events_eventemitter