root_view.cc 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. // Copyright (c) 2018 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "shell/browser/ui/views/root_view.h"
  5. #include <memory>
  6. #include "components/input/native_web_keyboard_event.h"
  7. #include "shell/browser/native_window.h"
  8. #include "shell/browser/ui/views/menu_bar.h"
  9. #include "ui/views/layout/box_layout.h"
  10. namespace electron {
  11. namespace {
  12. bool IsAltKey(const input::NativeWebKeyboardEvent& event) {
  13. return event.windows_key_code == ui::VKEY_MENU;
  14. }
  15. bool IsAltModifier(const input::NativeWebKeyboardEvent& event) {
  16. using Modifiers = input::NativeWebKeyboardEvent::Modifiers;
  17. int modifiers = event.GetModifiers();
  18. modifiers &= ~Modifiers::kNumLockOn;
  19. modifiers &= ~Modifiers::kCapsLockOn;
  20. return (modifiers == Modifiers::kAltKey) ||
  21. (modifiers == (Modifiers::kAltKey | Modifiers::kIsLeft)) ||
  22. (modifiers == (Modifiers::kAltKey | Modifiers::kIsRight));
  23. }
  24. } // namespace
  25. RootView::RootView(NativeWindow* window)
  26. : window_{raw_ref<NativeWindow>::from_ptr(window)},
  27. main_view_{raw_ref<views::View>::from_ptr(
  28. AddChildView(std::make_unique<views::View>()))} {
  29. set_owned_by_client();
  30. views::BoxLayout* layout =
  31. SetLayoutManager(std::make_unique<views::BoxLayout>(
  32. views::BoxLayout::Orientation::kVertical));
  33. main_view_->SetUseDefaultFillLayout(true);
  34. layout->SetFlexForView(&main_view_.get(), 1);
  35. }
  36. RootView::~RootView() = default;
  37. void RootView::SetMenu(ElectronMenuModel* menu_model) {
  38. if (menu_model == nullptr) {
  39. // Remove accelerators
  40. UnregisterAcceleratorsWithFocusManager();
  41. // and menu bar.
  42. SetMenuBarVisibility(false);
  43. menu_bar_.reset();
  44. return;
  45. }
  46. RegisterAcceleratorsWithFocusManager(menu_model);
  47. // Do not show menu bar in frameless window.
  48. if (!window_->has_frame())
  49. return;
  50. if (!menu_bar_) {
  51. menu_bar_ = std::make_unique<MenuBar>(&window_.get(), this);
  52. menu_bar_->set_owned_by_client();
  53. if (!menu_bar_autohide_)
  54. SetMenuBarVisibility(true);
  55. }
  56. menu_bar_->SetMenu(menu_model);
  57. InvalidateLayout();
  58. }
  59. bool RootView::HasMenu() const {
  60. return !!menu_bar_;
  61. }
  62. int RootView::GetMenuBarHeight() const {
  63. return menu_bar_ ? menu_bar_->GetPreferredSize().height() : 0;
  64. }
  65. void RootView::SetAutoHideMenuBar(bool auto_hide) {
  66. menu_bar_autohide_ = auto_hide;
  67. }
  68. void RootView::SetMenuBarVisibility(bool visible) {
  69. if (!window_->content_view() || !menu_bar_ || menu_bar_visible_ == visible)
  70. return;
  71. menu_bar_visible_ = visible;
  72. if (visible) {
  73. AddChildViewAt(menu_bar_.get(), 0);
  74. } else {
  75. RemoveChildView(menu_bar_.get());
  76. }
  77. InvalidateLayout();
  78. }
  79. void RootView::HandleKeyEvent(const input::NativeWebKeyboardEvent& event) {
  80. if (!menu_bar_)
  81. return;
  82. // Show accelerator when "Alt" is pressed.
  83. if (menu_bar_visible_ && IsAltKey(event))
  84. menu_bar_->SetAcceleratorVisibility(
  85. event.GetType() == blink::WebInputEvent::Type::kRawKeyDown);
  86. // Show the submenu when "Alt+Key" is pressed.
  87. if (event.GetType() == blink::WebInputEvent::Type::kRawKeyDown &&
  88. event.windows_key_code >= ui::VKEY_A &&
  89. event.windows_key_code <= ui::VKEY_Z && IsAltModifier(event) &&
  90. menu_bar_->HasAccelerator(event.windows_key_code)) {
  91. if (!menu_bar_visible_) {
  92. SetMenuBarVisibility(true);
  93. View* focused_view = GetFocusManager()->GetFocusedView();
  94. last_focused_view_tracker_.SetView(focused_view);
  95. menu_bar_->RequestFocus();
  96. }
  97. menu_bar_->ActivateAccelerator(event.windows_key_code);
  98. return;
  99. }
  100. // Toggle the menu bar only when a single Alt is released.
  101. if (event.GetType() == blink::WebInputEvent::Type::kRawKeyDown &&
  102. IsAltKey(event)) {
  103. // When a single Alt is pressed:
  104. menu_bar_alt_pressed_ = true;
  105. } else if (event.GetType() == blink::WebInputEvent::Type::kKeyUp &&
  106. IsAltKey(event) && menu_bar_alt_pressed_) {
  107. // When a single Alt is released right after a Alt is pressed:
  108. menu_bar_alt_pressed_ = false;
  109. if (menu_bar_autohide_)
  110. SetMenuBarVisibility(!menu_bar_visible_);
  111. View* focused_view = GetFocusManager()->GetFocusedView();
  112. last_focused_view_tracker_.SetView(focused_view);
  113. if (menu_bar_visible_) {
  114. menu_bar_->RequestFocus();
  115. // Show accelerators when menu bar is focused
  116. menu_bar_->SetAcceleratorVisibility(true);
  117. }
  118. } else {
  119. // When any other keys except single Alt have been pressed/released:
  120. menu_bar_alt_pressed_ = false;
  121. }
  122. }
  123. void RootView::RestoreFocus() {
  124. View* last_focused_view = last_focused_view_tracker_.view();
  125. if (last_focused_view) {
  126. GetFocusManager()->SetFocusedViewWithReason(
  127. last_focused_view,
  128. views::FocusManager::FocusChangeReason::kFocusRestore);
  129. }
  130. if (menu_bar_autohide_)
  131. SetMenuBarVisibility(false);
  132. }
  133. void RootView::ResetAltState() {
  134. menu_bar_alt_pressed_ = false;
  135. }
  136. gfx::Size RootView::GetMinimumSize() const {
  137. return window_->GetMinimumSize();
  138. }
  139. gfx::Size RootView::GetMaximumSize() const {
  140. return window_->GetMaximumSize();
  141. }
  142. bool RootView::AcceleratorPressed(const ui::Accelerator& accelerator) {
  143. return accelerator_util::TriggerAcceleratorTableCommand(&accelerator_table_,
  144. accelerator);
  145. }
  146. void RootView::RegisterAcceleratorsWithFocusManager(
  147. ElectronMenuModel* menu_model) {
  148. if (!menu_model)
  149. return;
  150. // Clear previous accelerators.
  151. UnregisterAcceleratorsWithFocusManager();
  152. views::FocusManager* focus_manager = GetFocusManager();
  153. // Register accelerators with focus manager.
  154. accelerator_util::GenerateAcceleratorTable(&accelerator_table_, menu_model);
  155. for (const auto& iter : accelerator_table_) {
  156. focus_manager->RegisterAccelerator(
  157. iter.first, ui::AcceleratorManager::kNormalPriority, this);
  158. }
  159. }
  160. void RootView::UnregisterAcceleratorsWithFocusManager() {
  161. views::FocusManager* focus_manager = GetFocusManager();
  162. accelerator_table_.clear();
  163. focus_manager->UnregisterAccelerators(this);
  164. }
  165. } // namespace electron