ash_focus_rules.cc 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/wm/ash_focus_rules.h"
  5. #include "ash/public/cpp/shell_window_ids.h"
  6. #include "ash/session/session_controller_impl.h"
  7. #include "ash/shell.h"
  8. #include "ash/shell_delegate.h"
  9. #include "ash/wm/container_finder.h"
  10. #include "ash/wm/desks/desks_util.h"
  11. #include "ash/wm/mru_window_tracker.h"
  12. #include "ash/wm/overview/overview_controller.h"
  13. #include "ash/wm/window_restore/window_restore_controller.h"
  14. #include "ash/wm/window_state.h"
  15. #include "base/containers/adapters.h"
  16. #include "base/containers/contains.h"
  17. #include "components/app_restore/full_restore_utils.h"
  18. #include "ui/aura/client/aura_constants.h"
  19. #include "ui/aura/window.h"
  20. #include "ui/events/event.h"
  21. #include "ui/wm/core/window_util.h"
  22. namespace ash {
  23. namespace {
  24. bool BelongsToContainerWithEqualOrGreaterId(const aura::Window* window,
  25. int container_id) {
  26. for (; window; window = window->parent()) {
  27. if (window->GetId() >= container_id)
  28. return true;
  29. }
  30. return false;
  31. }
  32. bool BelongsToContainerWithId(const aura::Window* window, int container_id) {
  33. for (; window; window = window->parent()) {
  34. if (window->GetId() == container_id)
  35. return true;
  36. }
  37. return false;
  38. }
  39. bool IsInactiveDeskContainerId(int id) {
  40. return desks_util::IsDeskContainerId(id) &&
  41. id != desks_util::GetActiveDeskContainerId();
  42. }
  43. } // namespace
  44. ////////////////////////////////////////////////////////////////////////////////
  45. // AshFocusRules, public:
  46. AshFocusRules::AshFocusRules()
  47. : activatable_container_ids_(GetActivatableShellWindowIds()) {}
  48. AshFocusRules::~AshFocusRules() = default;
  49. ////////////////////////////////////////////////////////////////////////////////
  50. // AshFocusRules, ::wm::FocusRules:
  51. bool AshFocusRules::IsToplevelWindow(const aura::Window* window) const {
  52. DCHECK(window);
  53. // The window must be in a valid hierarchy.
  54. if (!window->GetRootWindow() || !window->parent())
  55. return false;
  56. // The window must exist within a container that supports activation.
  57. // The window cannot be blocked by a modal transient.
  58. return base::Contains(activatable_container_ids_, window->parent()->GetId());
  59. }
  60. bool AshFocusRules::SupportsChildActivation(const aura::Window* window) const {
  61. return base::Contains(activatable_container_ids_, window->GetId());
  62. }
  63. bool AshFocusRules::IsWindowConsideredVisibleForActivation(
  64. const aura::Window* window) const {
  65. DCHECK(window);
  66. // If the |window| doesn't belong to the current active user and also doesn't
  67. // show for the current active user, then it should not be activated.
  68. if (!Shell::Get()->shell_delegate()->CanShowWindowForUser(window))
  69. return false;
  70. if (window->IsVisible())
  71. return true;
  72. // Minimized windows are hidden in their minimized state, but they can always
  73. // be activated.
  74. if (WindowState::Get(window)->IsMinimized())
  75. return true;
  76. if (!window->TargetVisibility())
  77. return false;
  78. const aura::Window* const parent = window->parent();
  79. return desks_util::IsDeskContainer(parent) ||
  80. parent->GetId() == kShellWindowId_LockScreenContainer;
  81. }
  82. bool AshFocusRules::CanActivateWindow(const aura::Window* window) const {
  83. // Clearing activation is always permissible.
  84. if (!window)
  85. return true;
  86. if (!WindowRestoreController::CanActivateRestoredWindow(window))
  87. return false;
  88. // Special case during Full Restore that prevents the app list from being
  89. // activated during tablet mode if the topmost window of any root window is a
  90. // Full Restore'd window. See http://crbug/1202923.
  91. if (!WindowRestoreController::CanActivateAppList(window))
  92. return false;
  93. if (!BaseFocusRules::CanActivateWindow(window))
  94. return false;
  95. // Special case to allow the login shelf to be activatable when the OOBE
  96. // modal is visible. See http://crbug/871184
  97. // TODO: remove this special case once login shelf is moved into a child
  98. // widget of the lock screen (https://crbug.com/767235).
  99. if (Shell::Get()->session_controller()->IsUserSessionBlocked() &&
  100. BelongsToContainerWithId(window, kShellWindowId_ShelfContainer)) {
  101. return true;
  102. }
  103. int modal_container_id = Shell::GetOpenSystemModalWindowContainerId();
  104. if (modal_container_id >= 0)
  105. return BelongsToContainerWithEqualOrGreaterId(window, modal_container_id);
  106. return true;
  107. }
  108. bool AshFocusRules::CanFocusWindow(const aura::Window* window,
  109. const ui::Event* event) const {
  110. if (!window)
  111. return true;
  112. if (event && (event->IsMouseEvent() || event->IsGestureEvent()) &&
  113. !window->GetProperty(aura::client::kActivateOnPointerKey)) {
  114. return false;
  115. }
  116. return BaseFocusRules::CanFocusWindow(window, event);
  117. }
  118. aura::Window* AshFocusRules::GetNextActivatableWindow(
  119. aura::Window* ignore) const {
  120. DCHECK(ignore);
  121. // If the window that just lost focus |ignore| has a transient parent, then
  122. // start from the container of that parent, otherwise start from the container
  123. // of the most-recently-used window. If the list of MRU windows is empty, then
  124. // start from the container of |ignore|.
  125. aura::Window* starting_window = nullptr;
  126. aura::Window* transient_parent = ::wm::GetTransientParent(ignore);
  127. OverviewController* overview_controller = Shell::Get()->overview_controller();
  128. // It's possible for this to be called either on shutdown or when a session is
  129. // not yet active, so we need to check for the existence of the overview
  130. // controller.
  131. if (overview_controller && overview_controller->InOverviewSession() &&
  132. overview_controller->overview_session()->IsTemplatesUiLosingActivation(
  133. ignore)) {
  134. starting_window =
  135. overview_controller->overview_session()->GetOverviewFocusWindow();
  136. } else if (transient_parent) {
  137. starting_window = transient_parent;
  138. } else {
  139. MruWindowTracker* mru = Shell::Get()->mru_window_tracker();
  140. aura::Window::Windows windows = mru->BuildMruWindowList(kActiveDesk);
  141. starting_window = windows.empty() ? ignore : windows[0];
  142. }
  143. DCHECK(starting_window);
  144. // Look for windows to focus in |starting_window|'s container. If none are
  145. // found, we look in all the containers in front of |starting_window|'s
  146. // container, then all behind.
  147. int starting_container_index = 0;
  148. aura::Window* root = starting_window->GetRootWindow();
  149. if (!root)
  150. root = Shell::GetRootWindowForNewWindows();
  151. const int container_count = activatable_container_ids_.size();
  152. for (int i = 0; i < container_count; i++) {
  153. aura::Window* container =
  154. Shell::GetContainer(root, activatable_container_ids_[i]);
  155. if (container && container->Contains(starting_window)) {
  156. starting_container_index = i;
  157. break;
  158. }
  159. }
  160. aura::Window* window = nullptr;
  161. for (int i = starting_container_index; !window && i < container_count; i++)
  162. window = GetTopmostWindowToActivateForContainerIndex(i, ignore);
  163. if (!window && starting_container_index > 0) {
  164. for (int i = starting_container_index - 1; !window && i >= 0; i--)
  165. window = GetTopmostWindowToActivateForContainerIndex(i, ignore);
  166. }
  167. return window;
  168. }
  169. ////////////////////////////////////////////////////////////////////////////////
  170. // AshFocusRules, private:
  171. aura::Window* AshFocusRules::GetTopmostWindowToActivateForContainerIndex(
  172. int index,
  173. aura::Window* ignore) const {
  174. const int container_id = activatable_container_ids_[index];
  175. // Inactive desk containers should be ignored, since windows in them should
  176. // never be returned as a next activatable window.
  177. if (IsInactiveDeskContainerId(container_id))
  178. return nullptr;
  179. aura::Window* window = nullptr;
  180. aura::Window* root = ignore ? ignore->GetRootWindow() : nullptr;
  181. aura::Window::Windows containers =
  182. GetContainersForAllRootWindows(container_id, root);
  183. for (aura::Window* container : containers) {
  184. window = GetTopmostWindowToActivateInContainer(container, ignore);
  185. if (window)
  186. return window;
  187. }
  188. return window;
  189. }
  190. aura::Window* AshFocusRules::GetTopmostWindowToActivateInContainer(
  191. aura::Window* container,
  192. aura::Window* ignore) const {
  193. for (aura::Window* child : base::Reversed(container->children())) {
  194. WindowState* window_state = WindowState::Get(child);
  195. if (child != ignore && window_state->CanActivate() &&
  196. !window_state->IsMinimized())
  197. return child;
  198. }
  199. return nullptr;
  200. }
  201. } // namespace ash