| 
									
										
										
										
											2014-10-31 11:17:05 -07:00
										 |  |  | // Copyright (c) 2014 GitHub, Inc.
 | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  | // Use of this source code is governed by the MIT license that can be
 | 
					
						
							|  |  |  | // found in the LICENSE file.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-19 13:46:59 -07:00
										 |  |  | #include "shell/browser/ui/views/menu_delegate.h"
 | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-16 18:12:00 -04:00
										 |  |  | #include <memory>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-12 06:30:43 +05:30
										 |  |  | #include "content/public/browser/browser_task_traits.h"
 | 
					
						
							| 
									
										
										
										
											2016-01-05 11:57:58 +08:00
										 |  |  | #include "content/public/browser/browser_thread.h"
 | 
					
						
							| 
									
										
										
										
											2019-06-19 13:46:59 -07:00
										 |  |  | #include "shell/browser/ui/views/menu_bar.h"
 | 
					
						
							|  |  |  | #include "shell/browser/ui/views/menu_model_adapter.h"
 | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  | #include "ui/views/controls/button/menu_button.h"
 | 
					
						
							| 
									
										
										
										
											2014-07-28 10:11:47 +00:00
										 |  |  | #include "ui/views/controls/menu/menu_item_view.h"
 | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  | #include "ui/views/controls/menu/menu_runner.h"
 | 
					
						
							|  |  |  | #include "ui/views/widget/widget.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-19 14:23:04 -07:00
										 |  |  | namespace electron { | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 19:16:21 +01:00
										 |  |  | MenuDelegate::MenuDelegate(MenuBar* menu_bar) : menu_bar_(menu_bar) {} | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-16 18:12:00 -04:00
										 |  |  | MenuDelegate::~MenuDelegate() = default; | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-04 12:19:40 -08:00
										 |  |  | void MenuDelegate::RunMenu(ElectronMenuModel* model, | 
					
						
							| 
									
										
										
										
											2019-04-20 13:20:37 -04:00
										 |  |  |                            views::Button* button, | 
					
						
							| 
									
										
										
										
											2018-10-29 19:08:47 +01:00
										 |  |  |                            ui::MenuSourceType source_type) { | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  |   gfx::Point screen_loc; | 
					
						
							|  |  |  |   views::View::ConvertPointToScreen(button, &screen_loc); | 
					
						
							|  |  |  |   // Subtract 1 from the height to make the popup flush with the button border.
 | 
					
						
							|  |  |  |   gfx::Rect bounds(screen_loc.x(), screen_loc.y(), button->width(), | 
					
						
							|  |  |  |                    button->height() - 1); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:08:47 +01:00
										 |  |  |   if (source_type == ui::MENU_SOURCE_KEYBOARD) { | 
					
						
							|  |  |  |     hold_first_switch_ = true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-25 09:46:14 +02:00
										 |  |  |   id_ = button->GetID(); | 
					
						
							| 
									
										
										
										
											2019-09-16 18:12:00 -04:00
										 |  |  |   adapter_ = std::make_unique<MenuModelAdapter>(model); | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-28 13:40:12 -08:00
										 |  |  |   auto item = std::make_unique<views::MenuItemView>(this); | 
					
						
							|  |  |  |   static_cast<MenuModelAdapter*>(adapter_.get())->BuildMenu(item.get()); | 
					
						
							| 
									
										
										
										
											2016-01-05 11:57:58 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-16 18:12:00 -04:00
										 |  |  |   menu_runner_ = std::make_unique<views::MenuRunner>( | 
					
						
							| 
									
										
										
										
											2023-11-28 13:40:12 -08:00
										 |  |  |       std::move(item), | 
					
						
							|  |  |  |       views::MenuRunner::CONTEXT_MENU | views::MenuRunner::HAS_MNEMONICS); | 
					
						
							| 
									
										
										
										
											2019-04-30 20:18:22 -04:00
										 |  |  |   menu_runner_->RunMenuAt( | 
					
						
							|  |  |  |       button->GetWidget()->GetTopLevelWidget(), | 
					
						
							|  |  |  |       static_cast<views::MenuButton*>(button)->button_controller(), bounds, | 
					
						
							|  |  |  |       views::MenuAnchorPosition::kTopRight, source_type); | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MenuDelegate::ExecuteCommand(int id) { | 
					
						
							| 
									
										
										
										
											2018-10-29 19:08:47 +01:00
										 |  |  |   for (Observer& obs : observers_) | 
					
						
							|  |  |  |     obs.OnBeforeExecuteCommand(); | 
					
						
							| 
									
										
										
										
											2016-01-05 11:57:58 +08:00
										 |  |  |   adapter_->ExecuteCommand(id); | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MenuDelegate::ExecuteCommand(int id, int mouse_event_flags) { | 
					
						
							| 
									
										
										
										
											2018-10-29 19:08:47 +01:00
										 |  |  |   for (Observer& obs : observers_) | 
					
						
							|  |  |  |     obs.OnBeforeExecuteCommand(); | 
					
						
							| 
									
										
										
										
											2016-01-05 11:57:58 +08:00
										 |  |  |   adapter_->ExecuteCommand(id, mouse_event_flags); | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool MenuDelegate::IsTriggerableEvent(views::MenuItemView* source, | 
					
						
							|  |  |  |                                       const ui::Event& e) { | 
					
						
							| 
									
										
										
										
											2016-01-05 11:57:58 +08:00
										 |  |  |   return adapter_->IsTriggerableEvent(source, e); | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-01 20:10:14 +08:00
										 |  |  | bool MenuDelegate::GetAccelerator(int id, ui::Accelerator* accelerator) const { | 
					
						
							| 
									
										
										
										
											2016-01-05 11:57:58 +08:00
										 |  |  |   return adapter_->GetAccelerator(id, accelerator); | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-16 12:18:45 -04:00
										 |  |  | std::u16string MenuDelegate::GetLabel(int id) const { | 
					
						
							| 
									
										
										
										
											2016-01-05 11:57:58 +08:00
										 |  |  |   return adapter_->GetLabel(id); | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-26 09:02:16 -07:00
										 |  |  | const gfx::FontList* MenuDelegate::GetLabelFontList(int id) const { | 
					
						
							|  |  |  |   return adapter_->GetLabelFontList(id); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-10 23:23:35 +01:00
										 |  |  | std::optional<SkColor> MenuDelegate::GetLabelColor(int id) const { | 
					
						
							| 
									
										
										
										
											2021-07-26 09:02:16 -07:00
										 |  |  |   return adapter_->GetLabelColor(id); | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool MenuDelegate::IsCommandEnabled(int id) const { | 
					
						
							| 
									
										
										
										
											2016-01-05 11:57:58 +08:00
										 |  |  |   return adapter_->IsCommandEnabled(id); | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-16 16:01:33 +08:00
										 |  |  | bool MenuDelegate::IsCommandVisible(int id) const { | 
					
						
							| 
									
										
										
										
											2016-01-05 11:57:58 +08:00
										 |  |  |   return adapter_->IsCommandVisible(id); | 
					
						
							| 
									
										
										
										
											2014-11-16 16:01:33 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  | bool MenuDelegate::IsItemChecked(int id) const { | 
					
						
							| 
									
										
										
										
											2016-01-05 11:57:58 +08:00
										 |  |  |   return adapter_->IsItemChecked(id); | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MenuDelegate::WillShowMenu(views::MenuItemView* menu) { | 
					
						
							| 
									
										
										
										
											2016-01-05 11:57:58 +08:00
										 |  |  |   adapter_->WillShowMenu(menu); | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MenuDelegate::WillHideMenu(views::MenuItemView* menu) { | 
					
						
							| 
									
										
										
										
											2016-01-05 11:57:58 +08:00
										 |  |  |   adapter_->WillHideMenu(menu); | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 00:06:43 +03:00
										 |  |  | void MenuDelegate::OnMenuClosed(views::MenuItemView* menu) { | 
					
						
							| 
									
										
										
										
											2018-10-29 19:08:47 +01:00
										 |  |  |   for (Observer& obs : observers_) | 
					
						
							|  |  |  |     obs.OnMenuClosed(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-28 18:59:06 +09:00
										 |  |  |   // Only switch to new menu when current menu is closed.
 | 
					
						
							|  |  |  |   if (button_to_open_) | 
					
						
							|  |  |  |     button_to_open_->Activate(nullptr); | 
					
						
							| 
									
										
										
										
											2017-07-03 12:47:02 -07:00
										 |  |  |   delete this; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  | views::MenuItemView* MenuDelegate::GetSiblingMenu( | 
					
						
							|  |  |  |     views::MenuItemView* menu, | 
					
						
							|  |  |  |     const gfx::Point& screen_point, | 
					
						
							| 
									
										
										
										
											2014-07-28 10:11:47 +00:00
										 |  |  |     views::MenuAnchorPosition* anchor, | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  |     bool* has_mnemonics, | 
					
						
							| 
									
										
										
										
											2016-01-05 11:57:58 +08:00
										 |  |  |     views::MenuButton**) { | 
					
						
							| 
									
										
										
										
											2018-10-29 19:08:47 +01:00
										 |  |  |   if (hold_first_switch_) { | 
					
						
							|  |  |  |     hold_first_switch_ = false; | 
					
						
							|  |  |  |     return nullptr; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-28 18:59:06 +09:00
										 |  |  |   // TODO(zcbenz): We should follow Chromium's logics on implementing the
 | 
					
						
							|  |  |  |   // sibling menu switches, this code is almost a hack.
 | 
					
						
							| 
									
										
										
										
											2016-01-05 11:57:58 +08:00
										 |  |  |   views::MenuButton* button; | 
					
						
							| 
									
										
										
										
											2020-02-04 12:19:40 -08:00
										 |  |  |   ElectronMenuModel* model; | 
					
						
							| 
									
										
										
										
											2016-01-05 11:57:58 +08:00
										 |  |  |   if (menu_bar_->GetMenuButtonFromScreenPoint(screen_point, &model, &button) && | 
					
						
							| 
									
										
										
										
											2022-07-25 09:46:14 +02:00
										 |  |  |       button->GetID() != id_) { | 
					
						
							| 
									
										
										
										
											2017-08-28 18:59:06 +09:00
										 |  |  |     bool switch_in_progress = !!button_to_open_; | 
					
						
							|  |  |  |     // Always update target to open.
 | 
					
						
							|  |  |  |     button_to_open_ = button; | 
					
						
							| 
									
										
										
										
											2020-10-13 10:25:21 -07:00
										 |  |  |     // Switching menu asynchronously to avoid crash.
 | 
					
						
							| 
									
										
										
										
											2017-08-28 18:59:06 +09:00
										 |  |  |     if (!switch_in_progress) { | 
					
						
							| 
									
										
										
										
											2022-05-17 12:48:40 -04:00
										 |  |  |       content::GetUIThreadTaskRunner({})->PostTask( | 
					
						
							|  |  |  |           FROM_HERE, base::BindOnce(&views::MenuRunner::Cancel, | 
					
						
							| 
									
										
										
										
											2019-09-18 15:58:00 -04:00
										 |  |  |                                     base::Unretained(menu_runner_.get()))); | 
					
						
							| 
									
										
										
										
											2017-08-28 18:59:06 +09:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-01-05 11:57:58 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-05 11:57:58 +08:00
										 |  |  |   return nullptr; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-07-17 14:23:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-19 14:23:04 -07:00
										 |  |  | }  // namespace electron
 |