root_view.cc 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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 "atom/browser/ui/views/root_view.h"
  5. #include "atom/browser/native_window.h"
  6. #include "atom/browser/ui/views/menu_bar.h"
  7. #include "content/public/browser/native_web_keyboard_event.h"
  8. namespace atom {
  9. namespace {
  10. // The menu bar height in pixels.
  11. #if defined(OS_WIN)
  12. const int kMenuBarHeight = 20;
  13. #else
  14. const int kMenuBarHeight = 25;
  15. #endif
  16. bool IsAltKey(const content::NativeWebKeyboardEvent& event) {
  17. return event.windows_key_code == ui::VKEY_MENU;
  18. }
  19. bool IsAltModifier(const content::NativeWebKeyboardEvent& event) {
  20. typedef content::NativeWebKeyboardEvent::Modifiers Modifiers;
  21. int modifiers = event.GetModifiers();
  22. modifiers &= ~Modifiers::kNumLockOn;
  23. modifiers &= ~Modifiers::kCapsLockOn;
  24. return (modifiers == Modifiers::kAltKey) ||
  25. (modifiers == (Modifiers::kAltKey | Modifiers::kIsLeft)) ||
  26. (modifiers == (Modifiers::kAltKey | Modifiers::kIsRight));
  27. }
  28. } // namespace
  29. RootView::RootView(NativeWindow* window) : window_(window) {
  30. set_owned_by_client();
  31. }
  32. RootView::~RootView() {}
  33. void RootView::SetMenu(AtomMenuModel* menu_model) {
  34. if (menu_model == nullptr) {
  35. // Remove accelerators
  36. accelerator_table_.clear();
  37. GetFocusManager()->UnregisterAccelerators(this);
  38. // and menu bar.
  39. SetMenuBarVisibility(false);
  40. menu_bar_.reset();
  41. return;
  42. }
  43. RegisterAccelerators(menu_model);
  44. // Do not show menu bar in frameless window.
  45. if (!window_->has_frame())
  46. return;
  47. if (!menu_bar_) {
  48. menu_bar_.reset(new MenuBar(this));
  49. menu_bar_->set_owned_by_client();
  50. if (!menu_bar_autohide_)
  51. SetMenuBarVisibility(true);
  52. }
  53. menu_bar_->SetMenu(menu_model);
  54. Layout();
  55. }
  56. bool RootView::HasMenu() const {
  57. return !!menu_bar_;
  58. }
  59. int RootView::GetMenuBarHeight() const {
  60. return kMenuBarHeight;
  61. }
  62. void RootView::SetAutoHideMenuBar(bool auto_hide) {
  63. menu_bar_autohide_ = auto_hide;
  64. }
  65. bool RootView::IsMenuBarAutoHide() const {
  66. return menu_bar_autohide_;
  67. }
  68. void RootView::SetMenuBarVisibility(bool visible) {
  69. if (!window_->content_view() || !menu_bar_ || menu_bar_visible_ == visible)
  70. return;
  71. // Always show the accelerator when the auto-hide menu bar shows.
  72. if (menu_bar_autohide_)
  73. menu_bar_->SetAcceleratorVisibility(visible);
  74. menu_bar_visible_ = visible;
  75. if (visible) {
  76. DCHECK_EQ(child_count(), 1);
  77. AddChildView(menu_bar_.get());
  78. } else {
  79. DCHECK_EQ(child_count(), 2);
  80. RemoveChildView(menu_bar_.get());
  81. }
  82. Layout();
  83. }
  84. bool RootView::IsMenuBarVisible() const {
  85. return menu_bar_visible_;
  86. }
  87. void RootView::HandleKeyEvent(const content::NativeWebKeyboardEvent& event) {
  88. if (!menu_bar_)
  89. return;
  90. // Show accelerator when "Alt" is pressed.
  91. if (menu_bar_visible_ && IsAltKey(event))
  92. menu_bar_->SetAcceleratorVisibility(event.GetType() ==
  93. blink::WebInputEvent::kRawKeyDown);
  94. // Show the submenu when "Alt+Key" is pressed.
  95. if (event.GetType() == blink::WebInputEvent::kRawKeyDown &&
  96. !IsAltKey(event) && IsAltModifier(event)) {
  97. if (!menu_bar_visible_ &&
  98. (menu_bar_->HasAccelerator(event.windows_key_code)))
  99. SetMenuBarVisibility(true);
  100. menu_bar_->ActivateAccelerator(event.windows_key_code);
  101. return;
  102. }
  103. if (!menu_bar_autohide_)
  104. return;
  105. // Toggle the menu bar only when a single Alt is released.
  106. if (event.GetType() == blink::WebInputEvent::kRawKeyDown && IsAltKey(event)) {
  107. // When a single Alt is pressed:
  108. menu_bar_alt_pressed_ = true;
  109. } else if (event.GetType() == blink::WebInputEvent::kKeyUp &&
  110. IsAltKey(event) && menu_bar_alt_pressed_) {
  111. // When a single Alt is released right after a Alt is pressed:
  112. menu_bar_alt_pressed_ = false;
  113. SetMenuBarVisibility(!menu_bar_visible_);
  114. } else {
  115. // When any other keys except single Alt have been pressed/released:
  116. menu_bar_alt_pressed_ = false;
  117. }
  118. }
  119. void RootView::ResetAltState() {
  120. menu_bar_alt_pressed_ = false;
  121. }
  122. void RootView::Layout() {
  123. if (!window_->content_view()) // Not ready yet.
  124. return;
  125. const auto menu_bar_bounds =
  126. menu_bar_visible_ ? gfx::Rect(0, 0, size().width(), kMenuBarHeight)
  127. : gfx::Rect();
  128. if (menu_bar_)
  129. menu_bar_->SetBoundsRect(menu_bar_bounds);
  130. window_->content_view()->SetBoundsRect(
  131. gfx::Rect(0, menu_bar_bounds.height(), size().width(),
  132. size().height() - menu_bar_bounds.height()));
  133. }
  134. gfx::Size RootView::GetMinimumSize() const {
  135. return window_->GetMinimumSize();
  136. }
  137. gfx::Size RootView::GetMaximumSize() const {
  138. return window_->GetMaximumSize();
  139. }
  140. bool RootView::AcceleratorPressed(const ui::Accelerator& accelerator) {
  141. return accelerator_util::TriggerAcceleratorTableCommand(&accelerator_table_,
  142. accelerator);
  143. }
  144. void RootView::RegisterAccelerators(AtomMenuModel* menu_model) {
  145. // Clear previous accelerators.
  146. views::FocusManager* focus_manager = GetFocusManager();
  147. accelerator_table_.clear();
  148. focus_manager->UnregisterAccelerators(this);
  149. // Register accelerators with focus manager.
  150. accelerator_util::GenerateAcceleratorTable(&accelerator_table_, menu_model);
  151. for (const auto& iter : accelerator_table_) {
  152. focus_manager->RegisterAccelerator(
  153. iter.first, ui::AcceleratorManager::kNormalPriority, this);
  154. }
  155. }
  156. } // namespace atom