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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Cheng Zhao
				Cheng Zhao