fix: delay emitting NotifyIcon events on Windows (#26668)

* wip?

* attempt to use weakptr

* apply posttask change to other balloon events

* chore: add clarifying comment on weakptr

* refactor: move weakptr include to implementation

(it's not needed in the header file)

* refactor: use default initializer for weak factory

* refactor: move weakptr usage outside of loop

* fix: convert mouse events as well

* refactor: use member function for balloon events

* fix: check if wicon is truthy in callback

* refactor: bind mouse events with member function

* refactor: inline lparams

* refactor: inline getkeyboardmodifiers()

* chore: correct GetKeyboardModifiers typo
This commit is contained in:
Erick Zhao 2020-11-29 23:49:30 -08:00 committed by GitHub
parent 14c8e000cb
commit 36af8022ca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 33 additions and 9 deletions

View file

@ -71,6 +71,8 @@ class NotifyIcon : public TrayIcon {
void SetContextMenu(ElectronMenuModel* menu_model) override; void SetContextMenu(ElectronMenuModel* menu_model) override;
gfx::Rect GetBounds() override; gfx::Rect GetBounds() override;
base::WeakPtr<NotifyIcon> GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
private: private:
void InitIconData(NOTIFYICONDATA* icon_data); void InitIconData(NOTIFYICONDATA* icon_data);
@ -101,6 +103,8 @@ class NotifyIcon : public TrayIcon {
// Context menu associated with this icon (if any). // Context menu associated with this icon (if any).
std::unique_ptr<views::MenuRunner> menu_runner_; std::unique_ptr<views::MenuRunner> menu_runner_;
base::WeakPtrFactory<NotifyIcon> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(NotifyIcon); DISALLOW_COPY_AND_ASSIGN(NotifyIcon);
}; };

View file

@ -9,10 +9,12 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/weak_ptr.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/win/win_util.h" #include "base/win/win_util.h"
#include "base/win/windows_types.h" #include "base/win/windows_types.h"
#include "base/win/wrapped_window_proc.h" #include "base/win/wrapped_window_proc.h"
#include "content/public/browser/browser_task_traits.h"
#include "shell/browser/ui/win/notify_icon.h" #include "shell/browser/ui/win/notify_icon.h"
#include "ui/events/event_constants.h" #include "ui/events/event_constants.h"
#include "ui/events/win/system_event_state_lookup.h" #include "ui/events/win/system_event_state_lookup.h"
@ -34,7 +36,7 @@ bool IsWinPressed() {
((::GetKeyState(VK_RWIN) & 0x8000) == 0x8000); ((::GetKeyState(VK_RWIN) & 0x8000) == 0x8000);
} }
int GetKeyboardModifers() { int GetKeyboardModifiers() {
int modifiers = ui::EF_NONE; int modifiers = ui::EF_NONE;
if (ui::win::IsShiftPressed()) if (ui::win::IsShiftPressed())
modifiers |= ui::EF_SHIFT_DOWN; modifiers |= ui::EF_SHIFT_DOWN;
@ -160,17 +162,29 @@ LRESULT CALLBACK NotifyIconHost::WndProc(HWND hwnd,
if (!win_icon) if (!win_icon)
return TRUE; return TRUE;
// We use a WeakPtr factory for NotifyIcons here so
// that the callback is aware if the NotifyIcon gets
// garbage-collected. This occurs when the tray gets
// GC'd, and the BALLOON events below will not emit.
base::WeakPtr<NotifyIcon> win_icon_weak = win_icon->GetWeakPtr();
switch (lparam) { switch (lparam) {
case NIN_BALLOONSHOW: case NIN_BALLOONSHOW:
win_icon->NotifyBalloonShow(); content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(&NotifyIcon::NotifyBalloonShow, win_icon_weak));
return TRUE; return TRUE;
case NIN_BALLOONUSERCLICK: case NIN_BALLOONUSERCLICK:
win_icon->NotifyBalloonClicked(); content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(&NotifyIcon::NotifyBalloonClicked, win_icon_weak));
return TRUE; return TRUE;
case NIN_BALLOONTIMEOUT: case NIN_BALLOONTIMEOUT:
win_icon->NotifyBalloonClosed(); content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(&NotifyIcon::NotifyBalloonClosed, win_icon_weak));
return TRUE; return TRUE;
case WM_LBUTTONDOWN: case WM_LBUTTONDOWN:
@ -180,14 +194,20 @@ LRESULT CALLBACK NotifyIconHost::WndProc(HWND hwnd,
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.
win_icon->HandleClickEvent( content::GetUIThreadTaskRunner({})->PostTask(
GetKeyboardModifers(), FROM_HERE,
(lparam == WM_LBUTTONDOWN || lparam == WM_LBUTTONDBLCLK), base::BindOnce(
(lparam == WM_LBUTTONDBLCLK || lparam == WM_RBUTTONDBLCLK)); &NotifyIcon::HandleClickEvent, win_icon_weak,
GetKeyboardModifiers(),
(lparam == WM_LBUTTONDOWN || lparam == WM_LBUTTONDBLCLK),
(lparam == WM_LBUTTONDBLCLK || lparam == WM_RBUTTONDBLCLK)));
return TRUE; return TRUE;
case WM_MOUSEMOVE: case WM_MOUSEMOVE:
win_icon->HandleMouseMoveEvent(GetKeyboardModifers()); content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&NotifyIcon::HandleMouseMoveEvent,
win_icon_weak, GetKeyboardModifiers()));
return TRUE; return TRUE;
} }
} }