Merge pull request #2369 from atom/better-modifiers

Fix a few things of Tray
This commit is contained in:
Cheng Zhao 2015-07-29 15:22:27 +08:00
commit d5893d8c9f
9 changed files with 129 additions and 34 deletions

View file

@ -14,6 +14,7 @@
#include "atom/common/native_mate_converters/string16_converter.h" #include "atom/common/native_mate_converters/string16_converter.h"
#include "native_mate/constructor.h" #include "native_mate/constructor.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "ui/events/event_constants.h"
#include "ui/gfx/image/image.h" #include "ui/gfx/image/image.h"
#include "atom/common/node_includes.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) { 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) { 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() { void Tray::OnBalloonShow() {
@ -60,10 +74,6 @@ void Tray::OnBalloonClosed() {
Emit("balloon-closed"); 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) { void Tray::OnDropFiles(const std::vector<std::string>& files) {
Emit("drop-files", files); Emit("drop-files", files);
} }
@ -120,6 +130,16 @@ void Tray::SetContextMenu(mate::Arguments* args, Menu* menu) {
tray_icon_->SetContextMenu(menu->model()); 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 // static
void Tray::BuildPrototype(v8::Isolate* isolate, void Tray::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) { v8::Local<v8::ObjectTemplate> prototype) {

View file

@ -44,10 +44,10 @@ class Tray : public mate::EventEmitter,
// TrayIconObserver: // TrayIconObserver:
void OnClicked(const gfx::Rect& bounds, int modifiers) override; void OnClicked(const gfx::Rect& bounds, int modifiers) override;
void OnDoubleClicked(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 OnBalloonShow() override;
void OnBalloonClicked() override; void OnBalloonClicked() override;
void OnBalloonClosed() override; void OnBalloonClosed() override;
void OnRightClicked(const gfx::Rect& bounds, int modifiers) override;
void OnDropFiles(const std::vector<std::string>& files) override; void OnDropFiles(const std::vector<std::string>& files) override;
// mate::Wrappable: // mate::Wrappable:
@ -64,6 +64,8 @@ class Tray : public mate::EventEmitter,
void SetContextMenu(mate::Arguments* args, Menu* menu); void SetContextMenu(mate::Arguments* args, Menu* menu);
private: private:
v8::Local<v8::Object> ModifiersToObject(v8::Isolate* isolate, int modifiers);
scoped_ptr<TrayIcon> tray_icon_; scoped_ptr<TrayIcon> tray_icon_;
DISALLOW_COPY_AND_ASSIGN(Tray); DISALLOW_COPY_AND_ASSIGN(Tray);

View file

@ -37,9 +37,8 @@ v8::Local<v8::Object> CreateEventObject(v8::Isolate* isolate) {
EventEmitter::EventEmitter() { EventEmitter::EventEmitter() {
} }
v8::Local<v8::Object> EventEmitter::CreateJSEvent(v8::Isolate* isolate, v8::Local<v8::Object> EventEmitter::CreateJSEvent(
content::WebContents* sender, v8::Isolate* isolate, content::WebContents* sender, IPC::Message* message) {
IPC::Message* message) {
v8::Local<v8::Object> event; v8::Local<v8::Object> event;
bool use_native_event = sender && message; bool use_native_event = sender && message;
@ -54,4 +53,12 @@ v8::Local<v8::Object> EventEmitter::CreateJSEvent(v8::Isolate* isolate,
return event; 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 } // namespace mate

View file

@ -25,6 +25,14 @@ class EventEmitter : public Wrappable {
public: public:
typedef std::vector<v8::Local<v8::Value>> ValueArray; 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...); // this.emit(name, new Event(), args...);
template<typename... Args> template<typename... Args>
bool Emit(const base::StringPiece& name, const Args&... args) { bool Emit(const base::StringPiece& name, const Args&... args) {
@ -37,21 +45,31 @@ class EventEmitter : public Wrappable {
content::WebContents* sender, content::WebContents* sender,
IPC::Message* message, IPC::Message* message,
const Args&... args) { const Args&... args) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
v8::Local<v8::Object> event = CreateJSEvent(isolate(), sender, message); v8::Local<v8::Object> event = CreateJSEvent(isolate(), sender, message);
EmitEvent(isolate(), GetWrapper(isolate()), name, event, args...); return EmitWithEvent(name, event, args...);
return event->Get(
StringToV8(isolate(), "defaultPrevented"))->BooleanValue();
} }
protected: protected:
EventEmitter(); EventEmitter();
private: 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, v8::Local<v8::Object> CreateJSEvent(v8::Isolate* isolate,
content::WebContents* sender, content::WebContents* sender,
IPC::Message* message); IPC::Message* message);
v8::Local<v8::Object> CreateCustomEvent(
v8::Isolate* isolate, v8::Local<v8::Object> event);
DISALLOW_COPY_AND_ASSIGN(EventEmitter); DISALLOW_COPY_AND_ASSIGN(EventEmitter);
}; };

View file

@ -63,23 +63,32 @@ NotifyIcon::~NotifyIcon() {
} }
void NotifyIcon::HandleClickEvent(const gfx::Point& cursor_pos, 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; NOTIFYICONIDENTIFIER icon_id;
memset(&icon_id, 0, sizeof(NOTIFYICONIDENTIFIER)); memset(&icon_id, 0, sizeof(NOTIFYICONIDENTIFIER));
icon_id.uID = icon_id_; icon_id.uID = icon_id_;
icon_id.hWnd = window_; icon_id.hWnd = window_;
icon_id.cbSize = sizeof(NOTIFYICONIDENTIFIER); 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 }; RECT rect = { 0 };
Shell_NotifyIconGetRect(&icon_id, &rect); Shell_NotifyIconGetRect(&icon_id, &rect);
// Pass to the observer if appropriate.
if (left_mouse_click) { 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; return;
} } else if (!double_button_click) { // single right click
NotifyRightClicked(gfx::Rect(rect), modifiers);
NotifyRightClicked(gfx::Rect(rect));
PopContextMenu(cursor_pos); PopContextMenu(cursor_pos);
}
} }
void NotifyIcon::ResetIcon() { void NotifyIcon::ResetIcon() {

View file

@ -33,7 +33,10 @@ class NotifyIcon : public TrayIcon {
// Handles a click event from the user - if |left_button_click| is true and // 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, // there is a registered observer, passes the click event to the observer,
// otherwise displays the context menu if there is one. // 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. // Re-creates the status tray icon now after the taskbar has been created.
void ResetIcon(); void ResetIcon();

View file

@ -5,13 +5,16 @@
#include "atom/browser/ui/win/notify_icon_host.h" #include "atom/browser/ui/win/notify_icon_host.h"
#include <commctrl.h> #include <commctrl.h>
#include <winuser.h>
#include "atom/browser/ui/win/notify_icon.h" #include "atom/browser/ui/win/notify_icon.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/threading/non_thread_safe.h" #include "base/threading/non_thread_safe.h"
#include "base/threading/thread.h" #include "base/threading/thread.h"
#include "base/win/win_util.h"
#include "base/win/wrapped_window_proc.h" #include "base/win/wrapped_window_proc.h"
#include "ui/events/event_constants.h"
#include "ui/gfx/screen.h" #include "ui/gfx/screen.h"
#include "ui/gfx/win/hwnd_util.h" #include "ui/gfx/win/hwnd_util.h"
@ -26,6 +29,24 @@ const UINT kBaseIconId = 2;
const wchar_t kNotifyIconHostWindowClass[] = L"Electron_NotifyIconHostWindow"; 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 } // namespace
NotifyIconHost::NotifyIconHost() NotifyIconHost::NotifyIconHost()
@ -146,12 +167,18 @@ LRESULT CALLBACK NotifyIconHost::WndProc(HWND hwnd,
case WM_LBUTTONDOWN: case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN: case WM_RBUTTONDOWN:
case WM_LBUTTONDBLCLK:
case WM_RBUTTONDBLCLK:
case WM_CONTEXTMENU: case WM_CONTEXTMENU:
// Walk our icons, find which one was clicked on, and invoke its // Walk our icons, find which one was clicked on, and invoke its
// HandleClickEvent() method. // HandleClickEvent() method.
gfx::Point cursor_pos( gfx::Point cursor_pos(
gfx::Screen::GetNativeScreen()->GetCursorScreenPoint()); 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; return TRUE;
} }
} }

View file

@ -183,6 +183,7 @@ void NativeImage::SetTemplateImage(bool setAsTemplate) {
} }
bool NativeImage::IsTemplateImage() { bool NativeImage::IsTemplateImage() {
return false;
} }
#endif #endif

View file

@ -47,13 +47,16 @@ Creates a new tray icon associated with the `image`.
### Event: 'clicked' ### Event: 'clicked'
* `event` * `event` Event
* `altKey` Boolean
* `shiftKey` Boolean
* `ctrlKey` Boolean
* `metaKey` Boolean
* `bounds` Object - the bounds of tray icon * `bounds` Object - the bounds of tray icon
* `x` Integer * `x` Integer
* `y` Integer * `y` Integer
* `width` Integer * `width` Integer
* `height` Integer * `height` Integer
* [`modifiers`][modifiers] Integer - bitsum of keyboard modifiers and mouse keys
Emitted when the tray icon is clicked. 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: 'right-clicked'
* `event` * `event` Event
* `altKey` Boolean
* `shiftKey` Boolean
* `ctrlKey` Boolean
* `metaKey` Boolean
* `bounds` Object - the bounds of tray icon * `bounds` Object - the bounds of tray icon
* `x` Integer * `x` Integer
* `y` Integer * `y` Integer
* `width` Integer * `width` Integer
* `height` Integer * `height` Integer
* [`modifiers`][modifiers] Integer - bitsum of keyboard modifiers and mouse keys
Emitted when the tray icon is right clicked. Emitted when the tray icon is right clicked.
__Note:__ This is only implemented on OS X and Windows. On Windows, this event __Note:__ This is only implemented on OS X and Windows.
will be emitted if the tray icon has context menu.
### Event: 'double-clicked' ### Event: 'double-clicked'
* `event` * `event` Event
* `altKey` Boolean
* `shiftKey` Boolean
* `ctrlKey` Boolean
* `metaKey` Boolean
* `bounds` Object - the bounds of tray icon * `bounds` Object - the bounds of tray icon
* `x` Integer * `x` Integer
* `y` Integer * `y` Integer
* `width` Integer * `width` Integer
* `height` Integer * `height` Integer
* [`modifiers`][modifiers] Integer - bitsum of keyboard modifiers and mouse keys
Emitted when the tray icon is double clicked. 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' ### Event: 'balloon-show'
@ -171,9 +179,10 @@ __Note:__ This is only implemented on Windows.
* `x` Integer * `x` Integer
* `y` 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. 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) ### Tray.setContextMenu(menu)
* `menu` 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. Sets the context menu for this icon.
[event-emitter]: http://nodejs.org/api/events.html#events_class_events_eventemitter [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