Merge pull request #2369 from atom/better-modifiers
Fix a few things of Tray
This commit is contained in:
commit
d5893d8c9f
9 changed files with 129 additions and 34 deletions
|
@ -14,6 +14,7 @@
|
|||
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||
#include "native_mate/constructor.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "ui/events/event_constants.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
@ -41,11 +42,24 @@ mate::Wrappable* Tray::New(v8::Isolate* isolate, const gfx::Image& image) {
|
|||
}
|
||||
|
||||
void Tray::OnClicked(const gfx::Rect& bounds, int modifiers) {
|
||||
Emit("clicked", bounds, modifiers);
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
EmitCustomEvent("clicked",
|
||||
ModifiersToObject(isolate(), modifiers), bounds);
|
||||
}
|
||||
|
||||
void Tray::OnDoubleClicked(const gfx::Rect& bounds, int modifiers) {
|
||||
Emit("double-clicked", bounds, modifiers);
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
EmitCustomEvent("double-clicked",
|
||||
ModifiersToObject(isolate(), modifiers), bounds);
|
||||
}
|
||||
|
||||
void Tray::OnRightClicked(const gfx::Rect& bounds, int modifiers) {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
EmitCustomEvent("right-clicked",
|
||||
ModifiersToObject(isolate(), modifiers), bounds);
|
||||
}
|
||||
|
||||
void Tray::OnBalloonShow() {
|
||||
|
@ -60,10 +74,6 @@ void Tray::OnBalloonClosed() {
|
|||
Emit("balloon-closed");
|
||||
}
|
||||
|
||||
void Tray::OnRightClicked(const gfx::Rect& bounds, int modifiers) {
|
||||
Emit("right-clicked", bounds, modifiers);
|
||||
}
|
||||
|
||||
void Tray::OnDropFiles(const std::vector<std::string>& files) {
|
||||
Emit("drop-files", files);
|
||||
}
|
||||
|
@ -120,6 +130,16 @@ void Tray::SetContextMenu(mate::Arguments* args, Menu* menu) {
|
|||
tray_icon_->SetContextMenu(menu->model());
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> Tray::ModifiersToObject(v8::Isolate* isolate,
|
||||
int modifiers) {
|
||||
mate::Dictionary obj(isolate, v8::Object::New(isolate));
|
||||
obj.Set("shiftKey", static_cast<bool>(modifiers & ui::EF_SHIFT_DOWN));
|
||||
obj.Set("ctrlKey", static_cast<bool>(modifiers & ui::EF_CONTROL_DOWN));
|
||||
obj.Set("altKey", static_cast<bool>(modifiers & ui::EF_ALT_DOWN));
|
||||
obj.Set("metaKey", static_cast<bool>(modifiers & ui::EF_COMMAND_DOWN));
|
||||
return obj.GetHandle();
|
||||
}
|
||||
|
||||
// static
|
||||
void Tray::BuildPrototype(v8::Isolate* isolate,
|
||||
v8::Local<v8::ObjectTemplate> prototype) {
|
||||
|
|
|
@ -44,10 +44,10 @@ class Tray : public mate::EventEmitter,
|
|||
// TrayIconObserver:
|
||||
void OnClicked(const gfx::Rect& bounds, int modifiers) override;
|
||||
void OnDoubleClicked(const gfx::Rect& bounds, int modifiers) override;
|
||||
void OnRightClicked(const gfx::Rect& bounds, int modifiers) override;
|
||||
void OnBalloonShow() override;
|
||||
void OnBalloonClicked() override;
|
||||
void OnBalloonClosed() override;
|
||||
void OnRightClicked(const gfx::Rect& bounds, int modifiers) override;
|
||||
void OnDropFiles(const std::vector<std::string>& files) override;
|
||||
|
||||
// mate::Wrappable:
|
||||
|
@ -64,6 +64,8 @@ class Tray : public mate::EventEmitter,
|
|||
void SetContextMenu(mate::Arguments* args, Menu* menu);
|
||||
|
||||
private:
|
||||
v8::Local<v8::Object> ModifiersToObject(v8::Isolate* isolate, int modifiers);
|
||||
|
||||
scoped_ptr<TrayIcon> tray_icon_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Tray);
|
||||
|
|
|
@ -37,9 +37,8 @@ v8::Local<v8::Object> CreateEventObject(v8::Isolate* isolate) {
|
|||
EventEmitter::EventEmitter() {
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> EventEmitter::CreateJSEvent(v8::Isolate* isolate,
|
||||
content::WebContents* sender,
|
||||
IPC::Message* message) {
|
||||
v8::Local<v8::Object> EventEmitter::CreateJSEvent(
|
||||
v8::Isolate* isolate, content::WebContents* sender, IPC::Message* message) {
|
||||
v8::Local<v8::Object> event;
|
||||
bool use_native_event = sender && message;
|
||||
|
||||
|
@ -54,4 +53,12 @@ v8::Local<v8::Object> EventEmitter::CreateJSEvent(v8::Isolate* isolate,
|
|||
return event;
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> EventEmitter::CreateCustomEvent(
|
||||
v8::Isolate* isolate, v8::Local<v8::Object> custom_event) {
|
||||
v8::Local<v8::Object> event = CreateEventObject(isolate);
|
||||
event->SetPrototype(custom_event->CreationContext(), custom_event);
|
||||
mate::Dictionary(isolate, event).Set("sender", GetWrapper(isolate));
|
||||
return event;
|
||||
}
|
||||
|
||||
} // namespace mate
|
||||
|
|
|
@ -25,6 +25,14 @@ class EventEmitter : public Wrappable {
|
|||
public:
|
||||
typedef std::vector<v8::Local<v8::Value>> ValueArray;
|
||||
|
||||
// this.emit(name, event, args...);
|
||||
template<typename... Args>
|
||||
bool EmitCustomEvent(const base::StringPiece& name,
|
||||
v8::Local<v8::Object> event,
|
||||
const Args&... args) {
|
||||
return EmitWithEvent(name, CreateCustomEvent(isolate(), event), args...);
|
||||
}
|
||||
|
||||
// this.emit(name, new Event(), args...);
|
||||
template<typename... Args>
|
||||
bool Emit(const base::StringPiece& name, const Args&... args) {
|
||||
|
@ -37,21 +45,31 @@ class EventEmitter : public Wrappable {
|
|||
content::WebContents* sender,
|
||||
IPC::Message* message,
|
||||
const Args&... args) {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
v8::Local<v8::Object> event = CreateJSEvent(isolate(), sender, message);
|
||||
EmitEvent(isolate(), GetWrapper(isolate()), name, event, args...);
|
||||
return event->Get(
|
||||
StringToV8(isolate(), "defaultPrevented"))->BooleanValue();
|
||||
return EmitWithEvent(name, event, args...);
|
||||
}
|
||||
|
||||
protected:
|
||||
EventEmitter();
|
||||
|
||||
private:
|
||||
// this.emit(name, event, args...);
|
||||
template<typename... Args>
|
||||
bool EmitWithEvent(const base::StringPiece& name,
|
||||
v8::Local<v8::Object> event,
|
||||
const Args&... args) {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
EmitEvent(isolate(), GetWrapper(isolate()), name, event, args...);
|
||||
return event->Get(
|
||||
StringToV8(isolate(), "defaultPrevented"))->BooleanValue();
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> CreateJSEvent(v8::Isolate* isolate,
|
||||
content::WebContents* sender,
|
||||
IPC::Message* message);
|
||||
v8::Local<v8::Object> CreateCustomEvent(
|
||||
v8::Isolate* isolate, v8::Local<v8::Object> event);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(EventEmitter);
|
||||
};
|
||||
|
|
|
@ -63,23 +63,32 @@ NotifyIcon::~NotifyIcon() {
|
|||
}
|
||||
|
||||
void NotifyIcon::HandleClickEvent(const gfx::Point& cursor_pos,
|
||||
bool left_mouse_click) {
|
||||
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);
|
||||
if (has_tray_app_id_hash_)
|
||||
memcpy(reinterpret_cast<void*>(&icon_id.guidItem),
|
||||
&tray_app_id_hash_,
|
||||
sizeof(GUID));
|
||||
|
||||
RECT rect = { 0 };
|
||||
Shell_NotifyIconGetRect(&icon_id, &rect);
|
||||
|
||||
// Pass to the observer if appropriate.
|
||||
if (left_mouse_click) {
|
||||
NotifyClicked(gfx::Rect(rect));
|
||||
if (double_button_click) // double left click
|
||||
NotifyDoubleClicked(gfx::Rect(rect), modifiers);
|
||||
else // single left click
|
||||
NotifyClicked(gfx::Rect(rect), modifiers);
|
||||
return;
|
||||
}
|
||||
|
||||
NotifyRightClicked(gfx::Rect(rect));
|
||||
} else if (!double_button_click) { // single right click
|
||||
NotifyRightClicked(gfx::Rect(rect), modifiers);
|
||||
PopContextMenu(cursor_pos);
|
||||
}
|
||||
}
|
||||
|
||||
void NotifyIcon::ResetIcon() {
|
||||
|
|
|
@ -33,7 +33,10 @@ class NotifyIcon : public TrayIcon {
|
|||
// Handles a click event from the user - if |left_button_click| is true and
|
||||
// there is a registered observer, passes the click event to the observer,
|
||||
// otherwise displays the context menu if there is one.
|
||||
void HandleClickEvent(const gfx::Point& cursor_pos, bool left_button_click);
|
||||
void HandleClickEvent(const gfx::Point& cursor_pos,
|
||||
int modifiers,
|
||||
bool left_button_click,
|
||||
bool double_button_click);
|
||||
|
||||
// Re-creates the status tray icon now after the taskbar has been created.
|
||||
void ResetIcon();
|
||||
|
|
|
@ -5,13 +5,16 @@
|
|||
#include "atom/browser/ui/win/notify_icon_host.h"
|
||||
|
||||
#include <commctrl.h>
|
||||
#include <winuser.h>
|
||||
|
||||
#include "atom/browser/ui/win/notify_icon.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "base/threading/non_thread_safe.h"
|
||||
#include "base/threading/thread.h"
|
||||
#include "base/win/win_util.h"
|
||||
#include "base/win/wrapped_window_proc.h"
|
||||
#include "ui/events/event_constants.h"
|
||||
#include "ui/gfx/screen.h"
|
||||
#include "ui/gfx/win/hwnd_util.h"
|
||||
|
||||
|
@ -26,6 +29,24 @@ const UINT kBaseIconId = 2;
|
|||
|
||||
const wchar_t kNotifyIconHostWindowClass[] = L"Electron_NotifyIconHostWindow";
|
||||
|
||||
bool IsWinPressed() {
|
||||
return ((::GetKeyState(VK_LWIN) & 0x8000) == 0x8000) ||
|
||||
((::GetKeyState(VK_RWIN) & 0x8000) == 0x8000);
|
||||
}
|
||||
|
||||
int GetKeyboardModifers() {
|
||||
int modifiers = ui::EF_NONE;
|
||||
if (base::win::IsShiftPressed())
|
||||
modifiers |= ui::EF_SHIFT_DOWN;
|
||||
if (base::win::IsCtrlPressed())
|
||||
modifiers |= ui::EF_CONTROL_DOWN;
|
||||
if (base::win::IsAltPressed())
|
||||
modifiers |= ui::EF_ALT_DOWN;
|
||||
if (IsWinPressed())
|
||||
modifiers |= ui::EF_COMMAND_DOWN;
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NotifyIconHost::NotifyIconHost()
|
||||
|
@ -146,12 +167,18 @@ LRESULT CALLBACK NotifyIconHost::WndProc(HWND hwnd,
|
|||
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_RBUTTONDOWN:
|
||||
case WM_LBUTTONDBLCLK:
|
||||
case WM_RBUTTONDBLCLK:
|
||||
case WM_CONTEXTMENU:
|
||||
// Walk our icons, find which one was clicked on, and invoke its
|
||||
// HandleClickEvent() method.
|
||||
gfx::Point cursor_pos(
|
||||
gfx::Screen::GetNativeScreen()->GetCursorScreenPoint());
|
||||
win_icon->HandleClickEvent(cursor_pos, lparam == WM_LBUTTONDOWN);
|
||||
win_icon->HandleClickEvent(
|
||||
cursor_pos,
|
||||
GetKeyboardModifers(),
|
||||
(lparam == WM_LBUTTONDOWN || lparam == WM_LBUTTONDBLCLK),
|
||||
(lparam == WM_LBUTTONDBLCLK || lparam == WM_RBUTTONDBLCLK));
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -183,6 +183,7 @@ void NativeImage::SetTemplateImage(bool setAsTemplate) {
|
|||
}
|
||||
|
||||
bool NativeImage::IsTemplateImage() {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -47,13 +47,16 @@ Creates a new tray icon associated with the `image`.
|
|||
|
||||
### Event: 'clicked'
|
||||
|
||||
* `event`
|
||||
* `event` Event
|
||||
* `altKey` Boolean
|
||||
* `shiftKey` Boolean
|
||||
* `ctrlKey` Boolean
|
||||
* `metaKey` Boolean
|
||||
* `bounds` Object - the bounds of tray icon
|
||||
* `x` Integer
|
||||
* `y` Integer
|
||||
* `width` Integer
|
||||
* `height` Integer
|
||||
* [`modifiers`][modifiers] Integer - bitsum of keyboard modifiers and mouse keys
|
||||
|
||||
Emitted when the tray icon is clicked.
|
||||
|
||||
|
@ -61,32 +64,37 @@ __Note:__ The `bounds` payload is only implemented on OS X and Windows 7 or newe
|
|||
|
||||
### Event: 'right-clicked'
|
||||
|
||||
* `event`
|
||||
* `event` Event
|
||||
* `altKey` Boolean
|
||||
* `shiftKey` Boolean
|
||||
* `ctrlKey` Boolean
|
||||
* `metaKey` Boolean
|
||||
* `bounds` Object - the bounds of tray icon
|
||||
* `x` Integer
|
||||
* `y` Integer
|
||||
* `width` Integer
|
||||
* `height` Integer
|
||||
* [`modifiers`][modifiers] Integer - bitsum of keyboard modifiers and mouse keys
|
||||
|
||||
Emitted when the tray icon is right clicked.
|
||||
|
||||
__Note:__ This is only implemented on OS X and Windows. On Windows, this event
|
||||
will be emitted if the tray icon has context menu.
|
||||
__Note:__ This is only implemented on OS X and Windows.
|
||||
|
||||
### Event: 'double-clicked'
|
||||
|
||||
* `event`
|
||||
* `event` Event
|
||||
* `altKey` Boolean
|
||||
* `shiftKey` Boolean
|
||||
* `ctrlKey` Boolean
|
||||
* `metaKey` Boolean
|
||||
* `bounds` Object - the bounds of tray icon
|
||||
* `x` Integer
|
||||
* `y` Integer
|
||||
* `width` Integer
|
||||
* `height` Integer
|
||||
* [`modifiers`][modifiers] Integer - bitsum of keyboard modifiers and mouse keys
|
||||
|
||||
Emitted when the tray icon is double clicked.
|
||||
|
||||
__Note:__ This is only implemented on OS X.
|
||||
__Note:__ This is only implemented on OS X and Windows.
|
||||
|
||||
### Event: 'balloon-show'
|
||||
|
||||
|
@ -171,9 +179,10 @@ __Note:__ This is only implemented on Windows.
|
|||
* `x` Integer
|
||||
* `y` Integer
|
||||
|
||||
__Note:__ This is only implemented on OS X and Windows.
|
||||
The `position` is only available on Windows, and it is (0, 0) by default.
|
||||
|
||||
__Note:__ This is only implemented on OS X and Windows.
|
||||
|
||||
### Tray.setContextMenu(menu)
|
||||
|
||||
* `menu` Menu
|
||||
|
@ -181,4 +190,3 @@ The `position` is only available on Windows, and it is (0, 0) by default.
|
|||
Sets the context menu for this icon.
|
||||
|
||||
[event-emitter]: http://nodejs.org/api/events.html#events_class_events_eventemitter
|
||||
[modifiers]: https://code.google.com/p/chromium/codesearch#chromium/src/ui/events/event_constants.h&l=77
|
||||
|
|
Loading…
Reference in a new issue