From 54af048f04c3194530081c56e10c567a14195339 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Sun, 2 Aug 2015 11:11:29 +0800 Subject: [PATCH 1/6] win: Add BrowserWindow.setThumbarButtons API. --- atom/browser/api/atom_api_window.cc | 34 +++++ atom/browser/api/atom_api_window.h | 8 ++ .../atom_desktop_window_tree_host_win.cc | 44 +++++++ .../atom_desktop_window_tree_host_win.h | 41 ++++++ atom/browser/native_window.h | 8 ++ atom/browser/native_window_views.cc | 22 ++++ atom/browser/native_window_views.h | 9 ++ atom/browser/ui/win/thumbar_host.cc | 122 ++++++++++++++++++ atom/browser/ui/win/thumbar_host.h | 51 ++++++++ filenames.gypi | 4 + 10 files changed, 343 insertions(+) create mode 100644 atom/browser/atom_desktop_window_tree_host_win.cc create mode 100644 atom/browser/atom_desktop_window_tree_host_win.h create mode 100644 atom/browser/ui/win/thumbar_host.cc create mode 100644 atom/browser/ui/win/thumbar_host.h diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 5f7c2503fced..bcdc57c3c704 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -20,6 +20,30 @@ #include "atom/common/node_includes.h" +#if defined(OS_WIN) +#include "atom/browser/ui/win/thumbar_host.h" +#endif + +namespace mate { + +#if defined(OS_WIN) +template<> +struct Converter { + static bool FromV8(v8::Isolate* isolate, v8::Handle val, + atom::ThumbarHost::ThumbarButton* out) { + mate::Dictionary dict; + if (!ConvertFromV8(isolate, val, &dict)) + return false; + dict.Get("click", &(out->clicked_callback)); + dict.Get("tooltip", &(out->tooltip)); + dict.Get("flags", &out->flags); + return dict.Get("icon", &(out->icon)); + } +}; +#endif + +} // namespace mate + namespace atom { namespace api { @@ -413,6 +437,13 @@ void Window::SetOverlayIcon(const gfx::Image& overlay, window_->SetOverlayIcon(overlay, description); } +#if defined(OS_WIN) +void Window::SetThumbarButtons( + const std::vector& buttons) { + window_->SetThumbarButtons(buttons); +} +#endif + void Window::SetMenu(v8::Isolate* isolate, v8::Local value) { mate::Handle menu; if (value->IsObject() && @@ -538,6 +569,9 @@ void Window::BuildPrototype(v8::Isolate* isolate, .SetMethod("capturePage", &Window::CapturePage) .SetMethod("setProgressBar", &Window::SetProgressBar) .SetMethod("setOverlayIcon", &Window::SetOverlayIcon) +#if defined(OS_WIN) + .SetMethod("setThumbarButtons", &Window::SetThumbarButtons) +#endif .SetMethod("setMenu", &Window::SetMenu) .SetMethod("setAutoHideMenuBar", &Window::SetAutoHideMenuBar) .SetMethod("isMenuBarAutoHide", &Window::IsMenuBarAutoHide) diff --git a/atom/browser/api/atom_api_window.h b/atom/browser/api/atom_api_window.h index cc2b3a64b5e9..fdb10825a6ca 100644 --- a/atom/browser/api/atom_api_window.h +++ b/atom/browser/api/atom_api_window.h @@ -14,6 +14,10 @@ #include "atom/browser/native_window_observer.h" #include "native_mate/handle.h" +#if defined(OS_WIN) +#include "atom/browser/ui/win/thumbar_host.h" +#endif + class GURL; namespace gfx { @@ -129,6 +133,10 @@ class Window : public mate::TrackableObject, void SetProgressBar(double progress); void SetOverlayIcon(const gfx::Image& overlay, const std::string& description); +#if defined(OS_WIN) + void SetThumbarButtons( + const std::vector& buttons); +#endif void SetMenu(v8::Isolate* isolate, v8::Local menu); void SetAutoHideMenuBar(bool auto_hide); bool IsMenuBarAutoHide(); diff --git a/atom/browser/atom_desktop_window_tree_host_win.cc b/atom/browser/atom_desktop_window_tree_host_win.cc new file mode 100644 index 000000000000..9c5ebf0f42c2 --- /dev/null +++ b/atom/browser/atom_desktop_window_tree_host_win.cc @@ -0,0 +1,44 @@ +// Copyright (c) 2015 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/atom_desktop_window_tree_host_win.h" +#include "atom/browser/ui/win/thumbar_host.h" + +namespace atom { + +AtomDesktopWindowTreeHostWin::AtomDesktopWindowTreeHostWin( + views::internal::NativeWidgetDelegate* native_widget_delegate, + views::DesktopNativeWidgetAura* desktop_native_widget_aura) + : views::DesktopWindowTreeHostWin(native_widget_delegate, + desktop_native_widget_aura) { +} + +AtomDesktopWindowTreeHostWin::~AtomDesktopWindowTreeHostWin() { +} + +bool AtomDesktopWindowTreeHostWin::SetThumbarButtons( + HWND window, + const std::vector& buttons) { + if (!thumbar_host_.get()) { + thumbar_host_.reset(new ThumbarHost(window)); + } + return thumbar_host_->SetThumbarButtons(buttons); +} + +bool AtomDesktopWindowTreeHostWin::PreHandleMSG(UINT message, + WPARAM w_param, + LPARAM l_param, + LRESULT* result) { + switch (message) { + case WM_COMMAND: { + int id = LOWORD(w_param); + if (thumbar_host_ && thumbar_host_->HandleThumbarButtonEvent(id)) + return true; + } + } + + return false; +} + +} // namespace atom diff --git a/atom/browser/atom_desktop_window_tree_host_win.h b/atom/browser/atom_desktop_window_tree_host_win.h new file mode 100644 index 000000000000..0271d06e6af2 --- /dev/null +++ b/atom/browser/atom_desktop_window_tree_host_win.h @@ -0,0 +1,41 @@ +// Copyright (c) 2015 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_ATOM_DESKTOP_WINDOW_TREE_HOST_WIN_H_ +#define ATOM_BROWSER_ATOM_DESKTOP_WINDOW_TREE_HOST_WIN_H_ + +#include + +#include + +#include "atom/browser/ui/win/thumbar_host.h" +#include "base/memory/scoped_ptr.h" +#include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h" + +namespace atom { + +class AtomDesktopWindowTreeHostWin : public views::DesktopWindowTreeHostWin { + public: + AtomDesktopWindowTreeHostWin( + views::internal::NativeWidgetDelegate* native_widget_delegate, + views::DesktopNativeWidgetAura* desktop_native_widget_aura); + ~AtomDesktopWindowTreeHostWin(); + + bool SetThumbarButtons( + HWND window, + const std::vector& buttons); + + protected: + bool PreHandleMSG(UINT message, + WPARAM w_param, + LPARAM l_param, + LRESULT* result) override; + + private: + scoped_ptr thumbar_host_; +}; + +} // namespace atom + +#endif // ATOM_BROWSER_ATOM_DESKTOP_WINDOW_TREE_HOST_WIN_H_ diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index 8919d529df03..0ae22214f563 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -23,6 +23,10 @@ #include "ui/gfx/image/image.h" #include "ui/gfx/image/image_skia.h" +#if defined(OS_WIN) +#include "atom/browser/ui/win/thumbar_host.h" +#endif + class SkRegion; namespace base { @@ -144,6 +148,10 @@ class NativeWindow : public content::WebContentsObserver, const std::string& description) = 0; virtual void SetVisibleOnAllWorkspaces(bool visible) = 0; virtual bool IsVisibleOnAllWorkspaces() = 0; +#if defined(OS_WIN) + virtual bool SetThumbarButtons( + const std::vector& buttons) = 0; +#endif virtual bool IsClosed() const { return is_closed_; } diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index 5f3472a7ffdb..e0221fbde597 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -27,6 +27,7 @@ #include "ui/views/controls/webview/unhandled_keyboard_event_handler.h" #include "ui/views/controls/webview/webview.h" #include "ui/views/window/client_view.h" +#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" #include "ui/views/widget/native_widget_private.h" #include "ui/views/widget/widget.h" #include "ui/wm/core/shadow_types.h" @@ -44,6 +45,7 @@ #include "ui/gfx/x/x11_types.h" #include "ui/views/window/native_frame_view.h" #elif defined(OS_WIN) +#include "atom/browser/atom_desktop_window_tree_host_win.h" #include "atom/browser/ui/views/win_frame_view.h" #include "base/win/scoped_comptr.h" #include "base/win/windows_version.h" @@ -215,6 +217,14 @@ NativeWindowViews::NativeWindowViews( if (transparent()) params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; +#if defined(OS_WIN) + params.native_widget = + new views::DesktopNativeWidgetAura(window_.get()); + atom_desktop_window_tree_host_win_ = new AtomDesktopWindowTreeHostWin( + window_.get(), + static_cast(params.native_widget)); + params.desktop_window_tree_host = atom_desktop_window_tree_host_win_; +#endif #if defined(USE_X11) std::string name = Browser::Get()->GetName(); // Set WM_WINDOW_ROLE. @@ -707,6 +717,18 @@ bool NativeWindowViews::IsVisibleOnAllWorkspaces() { return false; } +#if defined(OS_WIN) +bool NativeWindowViews::SetThumbarButtons( + const std::vector& buttons) { + if (atom_desktop_window_tree_host_win_) { + return atom_desktop_window_tree_host_win_->SetThumbarButtons( + views::HWNDForNativeWindow(window_->GetNativeWindow()), + buttons); + } + return false; +} +#endif + gfx::AcceleratedWidget NativeWindowViews::GetAcceleratedWidget() { return GetNativeWindow()->GetHost()->GetAcceleratedWidget(); } diff --git a/atom/browser/native_window_views.h b/atom/browser/native_window_views.h index dcf1f603a4f4..94c0c04373f7 100644 --- a/atom/browser/native_window_views.h +++ b/atom/browser/native_window_views.h @@ -23,6 +23,9 @@ namespace atom { class GlobalMenuBarX11; class MenuBar; class WindowStateWatcher; +#if defined(OS_WIN) +class AtomDesktopWindowTreeHostWin; +#endif class NativeWindowViews : public NativeWindow, public views::WidgetDelegateView, @@ -79,6 +82,10 @@ class NativeWindowViews : public NativeWindow, bool IsMenuBarVisible() override; void SetVisibleOnAllWorkspaces(bool visible) override; bool IsVisibleOnAllWorkspaces() override; +#if defined(OS_WIN) + bool SetThumbarButtons( + const std::vector& buttons) override; +#endif gfx::AcceleratedWidget GetAcceleratedWidget(); @@ -154,6 +161,8 @@ class NativeWindowViews : public NativeWindow, // Handles window state events. scoped_ptr window_state_watcher_; #elif defined(OS_WIN) + // Weak ref. + AtomDesktopWindowTreeHostWin* atom_desktop_window_tree_host_win_; // Records window was whether restored from minimized state or maximized // state. bool is_minimized_; diff --git a/atom/browser/ui/win/thumbar_host.cc b/atom/browser/ui/win/thumbar_host.cc new file mode 100644 index 000000000000..22e9ba8c4169 --- /dev/null +++ b/atom/browser/ui/win/thumbar_host.cc @@ -0,0 +1,122 @@ +// Copyright (c) 2015 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/ui/win/thumbar_host.h" + +#include + +#include "base/win/scoped_comptr.h" +#include "base/win/win_util.h" +#include "base/win/wrapped_window_proc.h" +#include "base/strings/utf_string_conversions.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/gfx/icon_util.h" +#include "ui/gfx/win/hwnd_util.h" + +namespace atom { + +namespace { + +// The thumbnail toolbar has a maximum of seven buttons due to the limited room. +const int kMaxButtonsCount = 7; + +bool GetThumbarButtonFlags(const std::vector& flags, + THUMBBUTTONFLAGS* out) { + if (flags.empty()) { + *out = THBF_ENABLED; + return true; + } + THUMBBUTTONFLAGS result = static_cast(0); + for (const auto& flag : flags) { + if (flag == "enabled") { + result |= THBF_ENABLED; + } else if (flag == "disabled") { + result |= THBF_DISABLED; + } else if (flag == "dismissonclick") { + result |= THBF_DISMISSONCLICK; + } else if (flag == "nobackground") { + result |= THBF_NOBACKGROUND; + } else if (flag == "hidden") { + result |= THBF_HIDDEN; + } else if (flag == "noninteractive") { + result |= THBF_NONINTERACTIVE; + } else { + return false; + } + } + *out = result; + return true; +} + +} // namespace + +ThumbarHost::ThumbarHost(HWND window) : is_initialized_(false), + window_(window) { +} + +ThumbarHost::~ThumbarHost() { +} + +bool ThumbarHost::SetThumbarButtons( + const std::vector& buttons) { + THUMBBUTTON thumb_buttons[kMaxButtonsCount]; + thumbar_button_clicked_callback_map_.clear(); + + // Once a toolbar with a set of buttons is added to thumbnail, there is no way + // to remove it without re-creating the window. + // To achieve to re-set thumbar buttons, we initialize the buttons with + // HIDDEN state and only updated the caller's specified buttons. + // + // Initialize all thumb buttons with HIDDEN state. + for (int i = 0; i < kMaxButtonsCount; ++i) { + thumb_buttons[i].iId = i; + thumb_buttons[i].dwFlags = THBF_HIDDEN; + } + + // Update the callers' specified buttons. + for (size_t i = 0; i < buttons.size(); ++i) { + if (!GetThumbarButtonFlags(buttons[i].flags, &thumb_buttons[i].dwFlags)) + return false; + thumb_buttons[i].dwMask = THB_ICON | THB_FLAGS; + thumb_buttons[i].hIcon = IconUtil::CreateHICONFromSkBitmap( + buttons[i].icon.AsBitmap()); + if (!buttons[i].tooltip.empty()) { + thumb_buttons[i].dwMask |= THB_TOOLTIP; + wcscpy_s(thumb_buttons[i].szTip, + base::UTF8ToUTF16(buttons[i].tooltip).c_str()); + } + + thumbar_button_clicked_callback_map_[i] = + buttons[i].clicked_callback; + } + + base::win::ScopedComPtr taskbar; + if (FAILED(taskbar.CreateInstance(CLSID_TaskbarList, + nullptr, + CLSCTX_INPROC_SERVER)) || + FAILED(taskbar->HrInit())) { + return false; + } + if (!is_initialized_) { + is_initialized_ = true; + return taskbar->ThumbBarAddButtons( + window_, kMaxButtonsCount, thumb_buttons) == S_OK; + } + + return taskbar->ThumbBarUpdateButtons( + window_, kMaxButtonsCount, thumb_buttons) == S_OK; +} + +bool ThumbarHost::HandleThumbarButtonEvent(int button_id) { + if (thumbar_button_clicked_callback_map_.find(button_id) != + thumbar_button_clicked_callback_map_.end()) { + auto callback = thumbar_button_clicked_callback_map_[button_id]; + if (!callback.is_null()) + callback.Run(); + return true; + } + return false; +} + +} // namespace atom diff --git a/atom/browser/ui/win/thumbar_host.h b/atom/browser/ui/win/thumbar_host.h new file mode 100644 index 000000000000..2ab3b06a381d --- /dev/null +++ b/atom/browser/ui/win/thumbar_host.h @@ -0,0 +1,51 @@ +// Copyright (c) 2015 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_UI_WIN_THUMBAR_HOST_H_ +#define ATOM_BROWSER_UI_WIN_THUMBAR_HOST_H_ + +#include + +#include +#include +#include + +#include "base/callback.h" +#include "ui/gfx/image/image.h" + +namespace atom { + +class ThumbarHost { + public: + using ThumbarButtonClickedCallback = base::Callback; + + struct ThumbarButton { + std::string tooltip; + gfx::Image icon; + std::vector flags; + ThumbarButtonClickedCallback clicked_callback; + }; + + explicit ThumbarHost(HWND window); + ~ThumbarHost(); + + bool SetThumbarButtons( + const std::vector& buttons); + bool HandleThumbarButtonEvent(int button_id); + + private: + using ThumbarButtonClickedCallbackMap = std::map< + int, ThumbarButtonClickedCallback>; + ThumbarButtonClickedCallbackMap thumbar_button_clicked_callback_map_; + + bool is_initialized_; + + HWND window_; + + DISALLOW_COPY_AND_ASSIGN(ThumbarHost); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_UI_WIN_THUMBAR_HOST_H_ diff --git a/filenames.gypi b/filenames.gypi index 82f9ea95d078..3b3d3a4cc48f 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -119,6 +119,8 @@ 'atom/browser/atom_browser_main_parts.h', 'atom/browser/atom_browser_main_parts_linux.cc', 'atom/browser/atom_browser_main_parts_mac.mm', + "atom/browser/atom_desktop_window_tree_host_win.cc", + "atom/browser/atom_desktop_window_tree_host_win.h", 'atom/browser/atom_javascript_dialog_manager.cc', 'atom/browser/atom_javascript_dialog_manager.h', 'atom/browser/atom_quota_permission_context.cc', @@ -206,6 +208,8 @@ 'atom/browser/ui/win/notify_icon_host.h', 'atom/browser/ui/win/notify_icon.cc', 'atom/browser/ui/win/notify_icon.h', + 'atom/browser/ui/win/thumbar_host.cc', + 'atom/browser/ui/win/thumbar_host.h', 'atom/browser/ui/x/window_state_watcher.cc', 'atom/browser/ui/x/window_state_watcher.h', 'atom/browser/ui/x/x_window_utils.cc', From 97ab780305abda01e3aacc9898e0967d798b3649 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Sun, 2 Aug 2015 13:07:55 +0800 Subject: [PATCH 2/6] :memo: BrowserWindow.setThumbarButton API. --- docs/api/browser-window.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index add5cfff8ba9..73f9c97de58d 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -643,6 +643,35 @@ Sets a 16px overlay onto the current taskbar icon, usually used to convey some s __Note:__ This API is only available on Windows (Windows 7 and above) + +### BrowserWindow.setThumbarButtons(buttons) + +* `buttons` Array of `button` objects + * `button` Object + * `icon` [NativeImage](native-image.md) - The icon showing in thumbnail toolbar. + * `tooltip` String - (Option) - The text of the button's tooltip. + * `flags` Array of Strings - (Option) Control specific states and behaviors + of the button. By default, it uses `enabled`. + * `enabled` - The button is active and available to the user. + * `disabled` - The button is disabled. It is present, but has a visual state + that indicates that it will not respond to user action. + * `dismissonclick` - When the button is clicked, the taskbar button's flyout + closes immediately. + * `nobackground` - Do not draw a button border, use only the image. + * `hidden` - The button is not shown to the user. + * `noninteractive` - The button is enabled but not interactive; no pressed + button state is drawn. This value is intended for instances where the button + is used in a notification. + * `click` - Function + +Add a thumbnail toolbar with a specified set of buttons to the thumbnail image of +a window in a taskbar button layout. + +__Note:__ This API is only available on Windows (Windows 7 and above). +Once you setup the thumbnail toolbar, the toolbar cannot be removed due to the +platform's limitation. But you can call the API with an empty array to clean the +buttons. + ### BrowserWindow.showDefinitionForSelection() Shows pop-up dictionary that searches the selected word on the page. From ad01a1731afa7d4c6f37eb960621c6baee6051b2 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Sun, 2 Aug 2015 13:09:42 +0800 Subject: [PATCH 3/6] :memo: say more about thumbnail toolbar. --- .../desktop-environment-integration.md | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/docs/tutorial/desktop-environment-integration.md b/docs/tutorial/desktop-environment-integration.md index 0691b15f4091..80b4c456938b 100644 --- a/docs/tutorial/desktop-environment-integration.md +++ b/docs/tutorial/desktop-environment-integration.md @@ -134,6 +134,59 @@ The user tasks will still show even after your application closes, so the icon and program path specified for a task should exist until your application is uninstalled. +## Thumbnail Toolbars + +On Windows, you can add a thumbnail toolbar with specified buttons in a taskbar +layout of an application window. It provides users a way to access to a particualr +window's command without restoring or activating the window. + +From MSDN, it's illustrated: + +> This toolbar is simply the familiar standard toolbar common control. It has a +> maximum of seven buttons. Each button's ID, image, tooltip, and state are defined +> in a structure, which is then passed to the taskbar. The application can show, +> enable, disable, or hide buttons from the thumbnail toolbar as required by its +> current state. +> +> For example, Windows Media Player might offer standard media transport controls +> such as play, pause, mute, and stop. + +__Thumbnail toolbar of Windows Media Player:__ + +![player](https://i-msdn.sec.s-msft.com/dynimg/IC420540.png) + +You can use [BrowserWindow.setThumbarButtons][setthumbarbuttons] to set thumbnail +toolbar in your application: + +``` +var BrowserWindow = require('browser-window'); +var path = require('path'); +var win = new BrowserWindow({ + width: 800, + height: 600 +}); +win.setThumbarButtons([ + { + tooltip: "button1", + icon: path.join(__dirname, 'button1.png'), + click: function() { console.log("button2 clicked"); } + }, + { + tooltip: "button2", + icon: path.join(__dirname, 'button2.png'), + flags:['enabled', 'dismissonclick'], + click: function() { console.log("button2 clicked."); } + } +]); +``` + +To clean thumbnail toolbar buttons, just call `BrowserWindow.setThumbarButtons` +with an empty array: + +```javascript +win.setThumbarButtons([]); +``` + ## Unity launcher shortcuts (Linux) In Unity, you can add custom entries to its launcher via modifying `.desktop` @@ -199,3 +252,4 @@ window.setDocumentEdited(true); [setdocumentedited]: ../api/browser-window.md#browserwindowsetdocumenteditededited [app-registration]: http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx [unity-launcher]: https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher +[setthumbarbuttons]: ../api/browser-window.md#browserwindowsetthumbarbuttonsbuttons From dfd076a3e5e364dfa0e1b02ad9d77ecc293bdd55 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Wed, 5 Aug 2015 13:04:21 +0800 Subject: [PATCH 4/6] Move atom_desktop_window_tree_host_win to atom/browser/ui/win directory. --- atom/browser/native_window_views.cc | 2 +- .../{ => ui/win}/atom_desktop_window_tree_host_win.cc | 2 +- .../{ => ui/win}/atom_desktop_window_tree_host_win.h | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) rename atom/browser/{ => ui/win}/atom_desktop_window_tree_host_win.cc (95%) rename atom/browser/{ => ui/win}/atom_desktop_window_tree_host_win.h (83%) diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index e0221fbde597..018f294b8df1 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -45,8 +45,8 @@ #include "ui/gfx/x/x11_types.h" #include "ui/views/window/native_frame_view.h" #elif defined(OS_WIN) -#include "atom/browser/atom_desktop_window_tree_host_win.h" #include "atom/browser/ui/views/win_frame_view.h" +#include "atom/browser/ui/win/atom_desktop_window_tree_host_win.h" #include "base/win/scoped_comptr.h" #include "base/win/windows_version.h" #include "ui/base/win/shell.h" diff --git a/atom/browser/atom_desktop_window_tree_host_win.cc b/atom/browser/ui/win/atom_desktop_window_tree_host_win.cc similarity index 95% rename from atom/browser/atom_desktop_window_tree_host_win.cc rename to atom/browser/ui/win/atom_desktop_window_tree_host_win.cc index 9c5ebf0f42c2..55912612ebba 100644 --- a/atom/browser/atom_desktop_window_tree_host_win.cc +++ b/atom/browser/ui/win/atom_desktop_window_tree_host_win.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. -#include "atom/browser/atom_desktop_window_tree_host_win.h" +#include "atom/browser/ui/win/atom_desktop_window_tree_host_win.h" #include "atom/browser/ui/win/thumbar_host.h" namespace atom { diff --git a/atom/browser/atom_desktop_window_tree_host_win.h b/atom/browser/ui/win/atom_desktop_window_tree_host_win.h similarity index 83% rename from atom/browser/atom_desktop_window_tree_host_win.h rename to atom/browser/ui/win/atom_desktop_window_tree_host_win.h index 0271d06e6af2..7f2abf801ad3 100644 --- a/atom/browser/atom_desktop_window_tree_host_win.h +++ b/atom/browser/ui/win/atom_desktop_window_tree_host_win.h @@ -2,8 +2,8 @@ // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. -#ifndef ATOM_BROWSER_ATOM_DESKTOP_WINDOW_TREE_HOST_WIN_H_ -#define ATOM_BROWSER_ATOM_DESKTOP_WINDOW_TREE_HOST_WIN_H_ +#ifndef ATOM_BROWSER_UI_WIN_ATOM_DESKTOP_WINDOW_TREE_HOST_WIN_H_ +#define ATOM_BROWSER_UI_WIN_ATOM_DESKTOP_WINDOW_TREE_HOST_WIN_H_ #include @@ -38,4 +38,4 @@ class AtomDesktopWindowTreeHostWin : public views::DesktopWindowTreeHostWin { } // namespace atom -#endif // ATOM_BROWSER_ATOM_DESKTOP_WINDOW_TREE_HOST_WIN_H_ +#endif // ATOM_BROWSER_UI_WIN_ATOM_DESKTOP_WINDOW_TREE_HOST_WIN_H_ From 78eac4116c656b7bb7cb2c539984726068cb7a71 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Wed, 5 Aug 2015 13:47:59 +0800 Subject: [PATCH 5/6] Polish thumbar code. * Fix a memory leak in thumbar initialization. * Check the number of thumbar buttons, should be <= 7. * Correct to check thumbar button click event. --- atom/browser/native_window_views.cc | 2 +- .../win/atom_desktop_window_tree_host_win.cc | 8 +++- atom/browser/ui/win/thumbar_host.cc | 43 +++++++++++++------ atom/browser/ui/win/thumbar_host.h | 2 +- docs/api/browser-window.md | 43 ++++++++++--------- filenames.gypi | 4 +- 6 files changed, 64 insertions(+), 38 deletions(-) diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index 018f294b8df1..eda98dc4f853 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -27,7 +27,6 @@ #include "ui/views/controls/webview/unhandled_keyboard_event_handler.h" #include "ui/views/controls/webview/webview.h" #include "ui/views/window/client_view.h" -#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" #include "ui/views/widget/native_widget_private.h" #include "ui/views/widget/widget.h" #include "ui/wm/core/shadow_types.h" @@ -52,6 +51,7 @@ #include "ui/base/win/shell.h" #include "ui/gfx/icon_util.h" #include "ui/gfx/win/dpi.h" +#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" #include "ui/views/win/hwnd_util.h" #endif diff --git a/atom/browser/ui/win/atom_desktop_window_tree_host_win.cc b/atom/browser/ui/win/atom_desktop_window_tree_host_win.cc index 55912612ebba..5c5833f64c09 100644 --- a/atom/browser/ui/win/atom_desktop_window_tree_host_win.cc +++ b/atom/browser/ui/win/atom_desktop_window_tree_host_win.cc @@ -3,6 +3,9 @@ // found in the LICENSE file. #include "atom/browser/ui/win/atom_desktop_window_tree_host_win.h" + +#include + #include "atom/browser/ui/win/thumbar_host.h" namespace atom { @@ -32,8 +35,11 @@ bool AtomDesktopWindowTreeHostWin::PreHandleMSG(UINT message, LRESULT* result) { switch (message) { case WM_COMMAND: { + // Handle thumbar button click message. int id = LOWORD(w_param); - if (thumbar_host_ && thumbar_host_->HandleThumbarButtonEvent(id)) + int thbn_message = HIWORD(w_param); + if (thbn_message == THBN_CLICKED && thumbar_host_ && + thumbar_host_->HandleThumbarButtonEvent(id)) return true; } } diff --git a/atom/browser/ui/win/thumbar_host.cc b/atom/browser/ui/win/thumbar_host.cc index 22e9ba8c4169..2d82cd4c6cdb 100644 --- a/atom/browser/ui/win/thumbar_host.cc +++ b/atom/browser/ui/win/thumbar_host.cc @@ -18,9 +18,14 @@ namespace atom { namespace { +// From MSDN: https://msdn.microsoft.com/en-us/library/windows/desktop/ +// dd378460(v=vs.85).aspx#thumbbars // The thumbnail toolbar has a maximum of seven buttons due to the limited room. const int kMaxButtonsCount = 7; +// The base id of Thumbar button. +const int kButtonIdBase = 40001; + bool GetThumbarButtonFlags(const std::vector& flags, THUMBBUTTONFLAGS* out) { if (flags.empty()) { @@ -60,7 +65,18 @@ ThumbarHost::~ThumbarHost() { bool ThumbarHost::SetThumbarButtons( const std::vector& buttons) { - THUMBBUTTON thumb_buttons[kMaxButtonsCount]; + if (buttons.size() > kMaxButtonsCount) + return false; + + base::win::ScopedComPtr taskbar; + if (FAILED(taskbar.CreateInstance(CLSID_TaskbarList, + nullptr, + CLSCTX_INPROC_SERVER)) || + FAILED(taskbar->HrInit())) { + return false; + } + + THUMBBUTTON thumb_buttons[kMaxButtonsCount] = {}; thumbar_button_clicked_callback_map_.clear(); // Once a toolbar with a set of buttons is added to thumbnail, there is no way @@ -70,7 +86,8 @@ bool ThumbarHost::SetThumbarButtons( // // Initialize all thumb buttons with HIDDEN state. for (int i = 0; i < kMaxButtonsCount; ++i) { - thumb_buttons[i].iId = i; + thumb_buttons[i].iId = kButtonIdBase + i; + thumb_buttons[i].dwMask = THB_FLAGS; // dwFlags is valid. thumb_buttons[i].dwFlags = THBF_HIDDEN; } @@ -87,25 +104,25 @@ bool ThumbarHost::SetThumbarButtons( base::UTF8ToUTF16(buttons[i].tooltip).c_str()); } - thumbar_button_clicked_callback_map_[i] = + thumbar_button_clicked_callback_map_[thumb_buttons[i].iId] = buttons[i].clicked_callback; } - base::win::ScopedComPtr taskbar; - if (FAILED(taskbar.CreateInstance(CLSID_TaskbarList, - nullptr, - CLSCTX_INPROC_SERVER)) || - FAILED(taskbar->HrInit())) { - return false; - } + bool is_success = false; if (!is_initialized_) { is_initialized_ = true; - return taskbar->ThumbBarAddButtons( + is_success = taskbar->ThumbBarAddButtons( + window_, kMaxButtonsCount, thumb_buttons) == S_OK; + } else { + is_success = taskbar->ThumbBarUpdateButtons( window_, kMaxButtonsCount, thumb_buttons) == S_OK; } - return taskbar->ThumbBarUpdateButtons( - window_, kMaxButtonsCount, thumb_buttons) == S_OK; + // Release thumb_buttons' icons, the taskbar makes its own copy. + for (size_t i = 0; i < buttons.size(); ++i) { + ::DestroyIcon(thumb_buttons[i].hIcon); + } + return is_success; } bool ThumbarHost::HandleThumbarButtonEvent(int button_id) { diff --git a/atom/browser/ui/win/thumbar_host.h b/atom/browser/ui/win/thumbar_host.h index 2ab3b06a381d..40d0ae7400e8 100644 --- a/atom/browser/ui/win/thumbar_host.h +++ b/atom/browser/ui/win/thumbar_host.h @@ -18,7 +18,7 @@ namespace atom { class ThumbarHost { public: - using ThumbarButtonClickedCallback = base::Callback; + using ThumbarButtonClickedCallback = base::Closure; struct ThumbarButton { std::string tooltip; diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 73f9c97de58d..60b9b84735d0 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -648,29 +648,32 @@ __Note:__ This API is only available on Windows (Windows 7 and above) * `buttons` Array of `button` objects * `button` Object - * `icon` [NativeImage](native-image.md) - The icon showing in thumbnail toolbar. - * `tooltip` String - (Option) - The text of the button's tooltip. - * `flags` Array of Strings - (Option) Control specific states and behaviors - of the button. By default, it uses `enabled`. - * `enabled` - The button is active and available to the user. - * `disabled` - The button is disabled. It is present, but has a visual state - that indicates that it will not respond to user action. - * `dismissonclick` - When the button is clicked, the taskbar button's flyout - closes immediately. - * `nobackground` - Do not draw a button border, use only the image. - * `hidden` - The button is not shown to the user. - * `noninteractive` - The button is enabled but not interactive; no pressed - button state is drawn. This value is intended for instances where the button - is used in a notification. - * `click` - Function + * `icon` [NativeImage](native-image.md) - The icon showing in thumbnail + toolbar. + * `tooltip` String - (Option) - The text of the button's tooltip. + * `flags` Array of Strings - (Option) Control specific states and behaviors + of the button. By default, it uses `enabled`. + * `enabled` - The button is active and available to the user. + * `disabled` - The button is disabled. It is present, but has a visual + state that indicates that it will not respond to user action. + * `dismissonclick` - When the button is clicked, the taskbar button's + flyout closes immediately. + * `nobackground` - Do not draw a button border, use only the image. + * `hidden` - The button is not shown to the user. + * `noninteractive` - The button is enabled but not interactive; no + pressed button state is drawn. This value is intended for instances + where the button is used in a notification. + * `click` - Function -Add a thumbnail toolbar with a specified set of buttons to the thumbnail image of -a window in a taskbar button layout. +Add a thumbnail toolbar with a specified set of buttons to the thumbnail image +of a window in a taskbar button layout. Returns a `Boolean` object indicates +whether the thumbnail has been added successfully. __Note:__ This API is only available on Windows (Windows 7 and above). -Once you setup the thumbnail toolbar, the toolbar cannot be removed due to the -platform's limitation. But you can call the API with an empty array to clean the -buttons. +The number of buttons in thumbnail toolbar should be no greater than 7 due to +the limited room. Once you setup the thumbnail toolbar, the toolbar cannot be +removed due to the platform's limitation. But you can call the API with an empty +array to clean the buttons. ### BrowserWindow.showDefinitionForSelection() diff --git a/filenames.gypi b/filenames.gypi index 3b3d3a4cc48f..45aaac7c2778 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -119,8 +119,6 @@ 'atom/browser/atom_browser_main_parts.h', 'atom/browser/atom_browser_main_parts_linux.cc', 'atom/browser/atom_browser_main_parts_mac.mm', - "atom/browser/atom_desktop_window_tree_host_win.cc", - "atom/browser/atom_desktop_window_tree_host_win.h", 'atom/browser/atom_javascript_dialog_manager.cc', 'atom/browser/atom_javascript_dialog_manager.h', 'atom/browser/atom_quota_permission_context.cc', @@ -204,6 +202,8 @@ 'atom/browser/ui/views/submenu_button.h', 'atom/browser/ui/views/win_frame_view.cc', 'atom/browser/ui/views/win_frame_view.h', + "atom/browser/ui/win/atom_desktop_window_tree_host_win.cc", + "atom/browser/ui/win/atom_desktop_window_tree_host_win.h", 'atom/browser/ui/win/notify_icon_host.cc', 'atom/browser/ui/win/notify_icon_host.h', 'atom/browser/ui/win/notify_icon.cc', From 2f1cb8b52a195655f85be428a953c41c0644b039 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Wed, 5 Aug 2015 22:26:18 +0800 Subject: [PATCH 6/6] Expose NativeWindow.setThumbarButtons API to all platforms. --- atom/browser/api/atom_api_window.cc | 16 +++------------- atom/browser/api/atom_api_window.h | 9 ++------- atom/browser/native_window.cc | 5 +++++ atom/browser/native_window.h | 18 ++++++++++-------- atom/browser/native_window_views.cc | 6 +++--- atom/browser/native_window_views.h | 4 +--- .../win/atom_desktop_window_tree_host_win.cc | 3 ++- .../ui/win/atom_desktop_window_tree_host_win.h | 3 ++- atom/browser/ui/win/thumbar_host.cc | 6 ++++-- atom/browser/ui/win/thumbar_host.h | 17 +++-------------- 10 files changed, 35 insertions(+), 52 deletions(-) diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index bcdc57c3c704..0b2c8c9ece79 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -20,17 +20,12 @@ #include "atom/common/node_includes.h" -#if defined(OS_WIN) -#include "atom/browser/ui/win/thumbar_host.h" -#endif - namespace mate { -#if defined(OS_WIN) template<> -struct Converter { +struct Converter { static bool FromV8(v8::Isolate* isolate, v8::Handle val, - atom::ThumbarHost::ThumbarButton* out) { + atom::NativeWindow::ThumbarButton* out) { mate::Dictionary dict; if (!ConvertFromV8(isolate, val, &dict)) return false; @@ -40,7 +35,6 @@ struct Converter { return dict.Get("icon", &(out->icon)); } }; -#endif } // namespace mate @@ -437,12 +431,10 @@ void Window::SetOverlayIcon(const gfx::Image& overlay, window_->SetOverlayIcon(overlay, description); } -#if defined(OS_WIN) void Window::SetThumbarButtons( - const std::vector& buttons) { + const std::vector& buttons) { window_->SetThumbarButtons(buttons); } -#endif void Window::SetMenu(v8::Isolate* isolate, v8::Local value) { mate::Handle menu; @@ -569,9 +561,7 @@ void Window::BuildPrototype(v8::Isolate* isolate, .SetMethod("capturePage", &Window::CapturePage) .SetMethod("setProgressBar", &Window::SetProgressBar) .SetMethod("setOverlayIcon", &Window::SetOverlayIcon) -#if defined(OS_WIN) .SetMethod("setThumbarButtons", &Window::SetThumbarButtons) -#endif .SetMethod("setMenu", &Window::SetMenu) .SetMethod("setAutoHideMenuBar", &Window::SetAutoHideMenuBar) .SetMethod("isMenuBarAutoHide", &Window::IsMenuBarAutoHide) diff --git a/atom/browser/api/atom_api_window.h b/atom/browser/api/atom_api_window.h index fdb10825a6ca..7742c8a9fa9b 100644 --- a/atom/browser/api/atom_api_window.h +++ b/atom/browser/api/atom_api_window.h @@ -11,13 +11,10 @@ #include "base/memory/scoped_ptr.h" #include "ui/gfx/image/image.h" #include "atom/browser/api/trackable_object.h" +#include "atom/browser/native_window.h" #include "atom/browser/native_window_observer.h" #include "native_mate/handle.h" -#if defined(OS_WIN) -#include "atom/browser/ui/win/thumbar_host.h" -#endif - class GURL; namespace gfx { @@ -133,10 +130,8 @@ class Window : public mate::TrackableObject, void SetProgressBar(double progress); void SetOverlayIcon(const gfx::Image& overlay, const std::string& description); -#if defined(OS_WIN) void SetThumbarButtons( - const std::vector& buttons); -#endif + const std::vector& buttons); void SetMenu(v8::Isolate* isolate, v8::Local menu); void SetAutoHideMenuBar(bool auto_hide); bool IsMenuBarAutoHide(); diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index 96085846bca8..91770af316e3 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -277,6 +277,11 @@ bool NativeWindow::HasModalDialog() { return has_dialog_attached_; } +bool NativeWindow::SetThumbarButtons( + const std::vector& buttons) { + return false; +} + void NativeWindow::FocusOnWebView() { web_contents()->GetRenderViewHost()->Focus(); } diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index 0ae22214f563..d461215222d6 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -23,10 +23,6 @@ #include "ui/gfx/image/image.h" #include "ui/gfx/image/image_skia.h" -#if defined(OS_WIN) -#include "atom/browser/ui/win/thumbar_host.h" -#endif - class SkRegion; namespace base { @@ -63,7 +59,15 @@ struct DraggableRegion; class NativeWindow : public content::WebContentsObserver, public brightray::InspectableWebContentsViewDelegate { public: - typedef base::Callback CapturePageCallback; + using CapturePageCallback = base::Callback; + using ThumbarButtonClickedCallback = base::Closure; + + struct ThumbarButton { + std::string tooltip; + gfx::Image icon; + std::vector flags; + ThumbarButtonClickedCallback clicked_callback; + }; class DialogScope { public: @@ -148,10 +152,8 @@ class NativeWindow : public content::WebContentsObserver, const std::string& description) = 0; virtual void SetVisibleOnAllWorkspaces(bool visible) = 0; virtual bool IsVisibleOnAllWorkspaces() = 0; -#if defined(OS_WIN) virtual bool SetThumbarButtons( - const std::vector& buttons) = 0; -#endif + const std::vector& buttons); virtual bool IsClosed() const { return is_closed_; } diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index eda98dc4f853..acb7de33f4d6 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -717,17 +717,17 @@ bool NativeWindowViews::IsVisibleOnAllWorkspaces() { return false; } -#if defined(OS_WIN) bool NativeWindowViews::SetThumbarButtons( - const std::vector& buttons) { + const std::vector& buttons) { +#if defined(OS_WIN) if (atom_desktop_window_tree_host_win_) { return atom_desktop_window_tree_host_win_->SetThumbarButtons( views::HWNDForNativeWindow(window_->GetNativeWindow()), buttons); } +#endif return false; } -#endif gfx::AcceleratedWidget NativeWindowViews::GetAcceleratedWidget() { return GetNativeWindow()->GetHost()->GetAcceleratedWidget(); diff --git a/atom/browser/native_window_views.h b/atom/browser/native_window_views.h index 94c0c04373f7..792a72c75624 100644 --- a/atom/browser/native_window_views.h +++ b/atom/browser/native_window_views.h @@ -82,10 +82,8 @@ class NativeWindowViews : public NativeWindow, bool IsMenuBarVisible() override; void SetVisibleOnAllWorkspaces(bool visible) override; bool IsVisibleOnAllWorkspaces() override; -#if defined(OS_WIN) bool SetThumbarButtons( - const std::vector& buttons) override; -#endif + const std::vector& buttons) override; gfx::AcceleratedWidget GetAcceleratedWidget(); diff --git a/atom/browser/ui/win/atom_desktop_window_tree_host_win.cc b/atom/browser/ui/win/atom_desktop_window_tree_host_win.cc index 5c5833f64c09..157cb610fb3a 100644 --- a/atom/browser/ui/win/atom_desktop_window_tree_host_win.cc +++ b/atom/browser/ui/win/atom_desktop_window_tree_host_win.cc @@ -6,6 +6,7 @@ #include +#include "atom/browser/native_window.h" #include "atom/browser/ui/win/thumbar_host.h" namespace atom { @@ -22,7 +23,7 @@ AtomDesktopWindowTreeHostWin::~AtomDesktopWindowTreeHostWin() { bool AtomDesktopWindowTreeHostWin::SetThumbarButtons( HWND window, - const std::vector& buttons) { + const std::vector& buttons) { if (!thumbar_host_.get()) { thumbar_host_.reset(new ThumbarHost(window)); } diff --git a/atom/browser/ui/win/atom_desktop_window_tree_host_win.h b/atom/browser/ui/win/atom_desktop_window_tree_host_win.h index 7f2abf801ad3..fc09b6503b80 100644 --- a/atom/browser/ui/win/atom_desktop_window_tree_host_win.h +++ b/atom/browser/ui/win/atom_desktop_window_tree_host_win.h @@ -9,6 +9,7 @@ #include +#include "atom/browser/native_window.h" #include "atom/browser/ui/win/thumbar_host.h" #include "base/memory/scoped_ptr.h" #include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h" @@ -24,7 +25,7 @@ class AtomDesktopWindowTreeHostWin : public views::DesktopWindowTreeHostWin { bool SetThumbarButtons( HWND window, - const std::vector& buttons); + const std::vector& buttons); protected: bool PreHandleMSG(UINT message, diff --git a/atom/browser/ui/win/thumbar_host.cc b/atom/browser/ui/win/thumbar_host.cc index 2d82cd4c6cdb..af57ef4e5c64 100644 --- a/atom/browser/ui/win/thumbar_host.cc +++ b/atom/browser/ui/win/thumbar_host.cc @@ -6,6 +6,8 @@ #include +#include + #include "base/win/scoped_comptr.h" #include "base/win/win_util.h" #include "base/win/wrapped_window_proc.h" @@ -64,7 +66,7 @@ ThumbarHost::~ThumbarHost() { } bool ThumbarHost::SetThumbarButtons( - const std::vector& buttons) { + const std::vector& buttons) { if (buttons.size() > kMaxButtonsCount) return false; @@ -112,7 +114,7 @@ bool ThumbarHost::SetThumbarButtons( if (!is_initialized_) { is_initialized_ = true; is_success = taskbar->ThumbBarAddButtons( - window_, kMaxButtonsCount, thumb_buttons) == S_OK; + window_, buttons.size(), thumb_buttons) == S_OK; } else { is_success = taskbar->ThumbBarUpdateButtons( window_, kMaxButtonsCount, thumb_buttons) == S_OK; diff --git a/atom/browser/ui/win/thumbar_host.h b/atom/browser/ui/win/thumbar_host.h index 40d0ae7400e8..d14bbaeda305 100644 --- a/atom/browser/ui/win/thumbar_host.h +++ b/atom/browser/ui/win/thumbar_host.h @@ -8,35 +8,24 @@ #include #include -#include #include -#include "base/callback.h" -#include "ui/gfx/image/image.h" +#include "atom/browser/native_window.h" namespace atom { class ThumbarHost { public: - using ThumbarButtonClickedCallback = base::Closure; - - struct ThumbarButton { - std::string tooltip; - gfx::Image icon; - std::vector flags; - ThumbarButtonClickedCallback clicked_callback; - }; - explicit ThumbarHost(HWND window); ~ThumbarHost(); bool SetThumbarButtons( - const std::vector& buttons); + const std::vector& buttons); bool HandleThumbarButtonEvent(int button_id); private: using ThumbarButtonClickedCallbackMap = std::map< - int, ThumbarButtonClickedCallback>; + int, NativeWindow::ThumbarButtonClickedCallback>; ThumbarButtonClickedCallbackMap thumbar_button_clicked_callback_map_; bool is_initialized_;