Merge pull request #6159 from electron/tray-get-bounds

This commit is contained in:
Cheng Zhao 2016-06-21 16:38:03 +09:00
commit 00f5fa440d
9 changed files with 87 additions and 60 deletions

View file

@ -159,6 +159,10 @@ void Tray::SetContextMenu(v8::Isolate* isolate, mate::Handle<Menu> menu) {
tray_icon_->SetContextMenu(menu->model()); tray_icon_->SetContextMenu(menu->model());
} }
gfx::Rect Tray::GetBounds() {
return tray_icon_->GetBounds();
}
v8::Local<v8::Object> Tray::ModifiersToObject(v8::Isolate* isolate, v8::Local<v8::Object> Tray::ModifiersToObject(v8::Isolate* isolate,
int modifiers) { int modifiers) {
mate::Dictionary obj(isolate, v8::Object::New(isolate)); mate::Dictionary obj(isolate, v8::Object::New(isolate));
@ -181,7 +185,8 @@ void Tray::BuildPrototype(v8::Isolate* isolate,
.SetMethod("setHighlightMode", &Tray::SetHighlightMode) .SetMethod("setHighlightMode", &Tray::SetHighlightMode)
.SetMethod("displayBalloon", &Tray::DisplayBalloon) .SetMethod("displayBalloon", &Tray::DisplayBalloon)
.SetMethod("popUpContextMenu", &Tray::PopUpContextMenu) .SetMethod("popUpContextMenu", &Tray::PopUpContextMenu)
.SetMethod("setContextMenu", &Tray::SetContextMenu); .SetMethod("setContextMenu", &Tray::SetContextMenu)
.SetMethod("getBounds", &Tray::GetBounds);
} }
} // namespace api } // namespace api

View file

@ -65,6 +65,7 @@ class Tray : public mate::TrackableObject<Tray>,
void DisplayBalloon(mate::Arguments* args, const mate::Dictionary& options); void DisplayBalloon(mate::Arguments* args, const mate::Dictionary& options);
void PopUpContextMenu(mate::Arguments* args); void PopUpContextMenu(mate::Arguments* args);
void SetContextMenu(v8::Isolate* isolate, mate::Handle<Menu> menu); void SetContextMenu(v8::Isolate* isolate, mate::Handle<Menu> menu);
gfx::Rect GetBounds();
private: private:
v8::Local<v8::Object> ModifiersToObject(v8::Isolate* isolate, int modifiers); v8::Local<v8::Object> ModifiersToObject(v8::Isolate* isolate, int modifiers);

View file

@ -30,6 +30,10 @@ void TrayIcon::PopUpContextMenu(const gfx::Point& pos,
ui::SimpleMenuModel* menu_model) { ui::SimpleMenuModel* menu_model) {
} }
gfx::Rect TrayIcon::GetBounds() {
return gfx::Rect();
}
void TrayIcon::NotifyClicked(const gfx::Rect& bounds, int modifiers) { void TrayIcon::NotifyClicked(const gfx::Rect& bounds, int modifiers) {
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnClicked(bounds, modifiers)); FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnClicked(bounds, modifiers));
} }

View file

@ -60,8 +60,12 @@ class TrayIcon {
// Set the context menu for this icon. // Set the context menu for this icon.
virtual void SetContextMenu(ui::SimpleMenuModel* menu_model) = 0; 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 AddObserver(TrayIconObserver* obs) { observers_.AddObserver(obs); }
void RemoveObserver(TrayIconObserver* obs) { observers_.RemoveObserver(obs); } void RemoveObserver(TrayIconObserver* obs) { observers_.RemoveObserver(obs); }
void NotifyClicked(const gfx::Rect& = gfx::Rect(), int modifiers = 0); void NotifyClicked(const gfx::Rect& = gfx::Rect(), int modifiers = 0);
void NotifyDoubleClicked(const gfx::Rect& = gfx::Rect(), int modifiers = 0); void NotifyDoubleClicked(const gfx::Rect& = gfx::Rect(), int modifiers = 0);
void NotifyBalloonShow(); void NotifyBalloonShow();

View file

@ -32,6 +32,7 @@ class TrayIconCocoa : public TrayIcon,
void PopUpContextMenu(const gfx::Point& pos, void PopUpContextMenu(const gfx::Point& pos,
ui::SimpleMenuModel* menu_model) override; ui::SimpleMenuModel* menu_model) override;
void SetContextMenu(ui::SimpleMenuModel* menu_model) override; void SetContextMenu(ui::SimpleMenuModel* menu_model) override;
gfx::Rect GetBounds() override;
protected: protected:
// AtomMenuModel::Observer: // AtomMenuModel::Observer:

View file

@ -8,6 +8,7 @@
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "ui/events/cocoa/cocoa_event_utils.h" #include "ui/events/cocoa/cocoa_event_utils.h"
#include "ui/gfx/image/image.h" #include "ui/gfx/image/image.h"
#include "ui/gfx/mac/coordinate_conversion.h"
#include "ui/gfx/screen.h" #include "ui/gfx/screen.h"
namespace { namespace {
@ -236,13 +237,13 @@ const CGFloat kVerticalTitleMargin = 2;
// Single click event. // Single click event.
if (event.clickCount == 1) if (event.clickCount == 1)
trayIcon_->NotifyClicked( trayIcon_->NotifyClicked(
[self getBoundsFromEvent:event], gfx::ScreenRectFromNSRect(event.window.frame),
ui::EventFlagsFromModifiers([event modifierFlags])); ui::EventFlagsFromModifiers([event modifierFlags]));
// Double click event. // Double click event.
if (event.clickCount == 2) if (event.clickCount == 2)
trayIcon_->NotifyDoubleClicked( trayIcon_->NotifyDoubleClicked(
[self getBoundsFromEvent:event], gfx::ScreenRectFromNSRect(event.window.frame),
ui::EventFlagsFromModifiers([event modifierFlags])); ui::EventFlagsFromModifiers([event modifierFlags]));
[self setNeedsDisplay:YES]; [self setNeedsDisplay:YES];
@ -273,7 +274,7 @@ const CGFloat kVerticalTitleMargin = 2;
- (void)rightMouseUp:(NSEvent*)event { - (void)rightMouseUp:(NSEvent*)event {
trayIcon_->NotifyRightClicked( trayIcon_->NotifyRightClicked(
[self getBoundsFromEvent:event], gfx::ScreenRectFromNSRect(event.window.frame),
ui::EventFlagsFromModifiers([event modifierFlags])); ui::EventFlagsFromModifiers([event modifierFlags]));
} }
@ -324,13 +325,6 @@ const CGFloat kVerticalTitleMargin = 2;
return isHighlightEnable_ && (inMouseEventSequence_ || isMenuOpen); 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 @end
namespace atom { namespace atom {
@ -386,6 +380,15 @@ void TrayIconCocoa::SetContextMenu(ui::SimpleMenuModel* menu_model) {
[status_item_view_ setMenuController:menu_.get()]; [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() { void TrayIconCocoa::MenuClosed() {
[status_item_view_ setNeedsDisplay:YES]; [status_item_view_ setNeedsDisplay:YES];
} }

View file

@ -13,6 +13,7 @@
#include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect.h"
#include "ui/gfx/screen.h" #include "ui/gfx/screen.h"
#include "ui/gfx/win/dpi.h"
#include "ui/views/controls/menu/menu_runner.h" #include "ui/views/controls/menu/menu_runner.h"
namespace atom { namespace atom {
@ -48,26 +49,19 @@ NotifyIcon::~NotifyIcon() {
void NotifyIcon::HandleClickEvent(int modifiers, void NotifyIcon::HandleClickEvent(int modifiers,
bool left_mouse_click, bool left_mouse_click,
bool double_button_click) { bool double_button_click) {
NOTIFYICONIDENTIFIER icon_id; gfx::Rect bounds = GetBounds();
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);
if (left_mouse_click) { if (left_mouse_click) {
if (double_button_click) // double left click if (double_button_click) // double left click
NotifyDoubleClicked(gfx::Rect(rect), modifiers); NotifyDoubleClicked(bounds, modifiers);
else // single left click else // single left click
NotifyClicked(gfx::Rect(rect), modifiers); NotifyClicked(bounds, modifiers);
return; return;
} else if (!double_button_click) { // single right click } else if (!double_button_click) { // single right click
if (menu_model_) if (menu_model_)
PopUpContextMenu(gfx::Point(), menu_model_); PopUpContextMenu(gfx::Point(), menu_model_);
else else
NotifyRightClicked(gfx::Rect(rect), modifiers); NotifyRightClicked(bounds, modifiers);
} }
} }
@ -163,6 +157,18 @@ void NotifyIcon::SetContextMenu(ui::SimpleMenuModel* menu_model) {
menu_model_ = 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) { void NotifyIcon::InitIconData(NOTIFYICONDATA* icon_data) {
memset(icon_data, 0, sizeof(NOTIFYICONDATA)); memset(icon_data, 0, sizeof(NOTIFYICONDATA));
icon_data->cbSize = sizeof(NOTIFYICONDATA); icon_data->cbSize = sizeof(NOTIFYICONDATA);

View file

@ -54,6 +54,7 @@ class NotifyIcon : public TrayIcon {
void PopUpContextMenu(const gfx::Point& pos, void PopUpContextMenu(const gfx::Point& pos,
ui::SimpleMenuModel* menu_model) override; ui::SimpleMenuModel* menu_model) override;
void SetContextMenu(ui::SimpleMenuModel* menu_model) override; void SetContextMenu(ui::SimpleMenuModel* menu_model) override;
gfx::Rect GetBounds() override;
private: private:
void InitIconData(NOTIFYICONDATA* icon_data); void InitIconData(NOTIFYICONDATA* icon_data);

View file

@ -3,20 +3,20 @@
> Add icons and context menus to the system's notification area. > Add icons and context menus to the system's notification area.
```javascript ```javascript
const {app, Menu, Tray} = require('electron'); const {app, Menu, Tray} = require('electron')
let appIcon = null; let tray = null
app.on('ready', () => { app.on('ready', () => {
appIcon = new Tray('/path/to/my/icon'); tray = new Tray('/path/to/my/icon')
const contextMenu = Menu.buildFromTemplate([ const contextMenu = Menu.buildFromTemplate([
{label: 'Item1', type: 'radio'}, {label: 'Item1', type: 'radio'},
{label: 'Item2', type: 'radio'}, {label: 'Item2', type: 'radio'},
{label: 'Item3', type: 'radio', checked: true}, {label: 'Item3', type: 'radio', checked: true},
{label: 'Item4', type: 'radio'} {label: 'Item4', type: 'radio'}
]); ]);
appIcon.setToolTip('This is my application.'); tray.setToolTip('This is my application.')
appIcon.setContextMenu(contextMenu); tray.setContextMenu(contextMenu)
}); })
``` ```
__Platform limitations:__ __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`. Creates a new tray icon associated with the `image`.
## Events ### Instance Events
The `Tray` module emits the following events: The `Tray` module emits the following events:
**Note:** Some events are only available on specific operating systems and are #### Event: 'click'
labeled as such.
### Event: 'click'
* `event` Event * `event` Event
* `altKey` Boolean * `altKey` Boolean
* `shiftKey` Boolean * `shiftKey` Boolean
* `ctrlKey` Boolean * `ctrlKey` Boolean
* `metaKey` Boolean * `metaKey` Boolean
* `bounds` Object - the bounds of tray icon. * `bounds` Object _macOS_ _Windows_ - the bounds of tray icon.
* `x` Integer * `x` Integer
* `y` Integer * `y` Integer
* `width` Integer * `width` Integer
@ -71,9 +68,7 @@ labeled as such.
Emitted when the tray icon is clicked. 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 * `event` Event
* `altKey` Boolean * `altKey` Boolean
@ -88,7 +83,7 @@ Emitted when the tray icon is clicked.
Emitted when the tray icon is right clicked. Emitted when the tray icon is right clicked.
### Event: 'double-click' _macOS_ _Windows_ #### Event: 'double-click' _macOS_ _Windows_
* `event` Event * `event` Event
* `altKey` Boolean * `altKey` Boolean
@ -103,85 +98,82 @@ Emitted when the tray icon is right clicked.
Emitted when the tray icon is double clicked. Emitted when the tray icon is double clicked.
### Event: 'balloon-show' _Windows_ #### Event: 'balloon-show' _Windows_
Emitted when the tray balloon shows. Emitted when the tray balloon shows.
### Event: 'balloon-click' _Windows_ #### Event: 'balloon-click' _Windows_
Emitted when the tray balloon is clicked. 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 Emitted when the tray balloon is closed because of timeout or user manually
closes it. closes it.
### Event: 'drop' _macOS_ #### Event: 'drop' _macOS_
Emitted when any dragged items are dropped on the tray icon. Emitted when any dragged items are dropped on the tray icon.
### Event: 'drop-files' _macOS_ #### Event: 'drop-files' _macOS_
* `event` * `event`
* `files` Array - the file path of dropped files. * `files` Array - the file path of dropped files.
Emitted when dragged files are dropped in the tray icon. 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. 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. 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. 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 #### `tray.destroy()`
labeled as such.
### `Tray.destroy()`
Destroys the tray icon immediately. Destroys the tray icon immediately.
### `Tray.setImage(image)` #### `tray.setImage(image)`
* `image` [NativeImage](native-image.md) * `image` [NativeImage](native-image.md)
Sets the `image` associated with this tray icon. Sets the `image` associated with this tray icon.
### `Tray.setPressedImage(image)` _macOS_ #### `tray.setPressedImage(image)` _macOS_
* `image` [NativeImage](native-image.md) * `image` [NativeImage](native-image.md)
Sets the `image` associated with this tray icon when pressed on macOS. Sets the `image` associated with this tray icon when pressed on macOS.
### `Tray.setToolTip(toolTip)` #### `tray.setToolTip(toolTip)`
* `toolTip` String * `toolTip` String
Sets the hover text for this tray icon. Sets the hover text for this tray icon.
### `Tray.setTitle(title)` _macOS_ #### `tray.setTitle(title)` _macOS_
* `title` String * `title` String
Sets the title displayed aside of the tray icon in the status bar. Sets the title displayed aside of the tray icon in the status bar.
### `Tray.setHighlightMode(highlight)` _macOS_ #### `tray.setHighlightMode(highlight)` _macOS_
* `highlight` Boolean * `highlight` Boolean
Sets whether the tray icon's background becomes highlighted (in blue) Sets whether the tray icon's background becomes highlighted (in blue)
when the tray icon is clicked. Defaults to true. when the tray icon is clicked. Defaults to true.
### `Tray.displayBalloon(options)` _Windows_ #### `tray.displayBalloon(options)` _Windows_
* `options` Object * `options` Object
* `icon` [NativeImage](native-image.md) * `icon` [NativeImage](native-image.md)
@ -190,7 +182,7 @@ when the tray icon is clicked. Defaults to true.
Displays a tray balloon. Displays a tray balloon.
### `Tray.popUpContextMenu([menu, position])` _macOS_ _Windows_ #### `tray.popUpContextMenu([menu, position])` _macOS_ _Windows_
* `menu` Menu (optional) * `menu` Menu (optional)
* `position` Object (optional) - The pop up position. * `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. The `position` is only available on Windows, and it is (0, 0) by default.
### `Tray.setContextMenu(menu)` #### `tray.setContextMenu(menu)`
* `menu` Menu * `menu` Menu
Sets the context menu for this icon. 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 [event-emitter]: http://nodejs.org/api/events.html#events_class_events_eventemitter