123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ash/wm/ash_focus_rules.h"
- #include "ash/public/cpp/shell_window_ids.h"
- #include "ash/session/session_controller_impl.h"
- #include "ash/shell.h"
- #include "ash/shell_delegate.h"
- #include "ash/wm/container_finder.h"
- #include "ash/wm/desks/desks_util.h"
- #include "ash/wm/mru_window_tracker.h"
- #include "ash/wm/overview/overview_controller.h"
- #include "ash/wm/window_restore/window_restore_controller.h"
- #include "ash/wm/window_state.h"
- #include "base/containers/adapters.h"
- #include "base/containers/contains.h"
- #include "components/app_restore/full_restore_utils.h"
- #include "ui/aura/client/aura_constants.h"
- #include "ui/aura/window.h"
- #include "ui/events/event.h"
- #include "ui/wm/core/window_util.h"
- namespace ash {
- namespace {
- bool BelongsToContainerWithEqualOrGreaterId(const aura::Window* window,
- int container_id) {
- for (; window; window = window->parent()) {
- if (window->GetId() >= container_id)
- return true;
- }
- return false;
- }
- bool BelongsToContainerWithId(const aura::Window* window, int container_id) {
- for (; window; window = window->parent()) {
- if (window->GetId() == container_id)
- return true;
- }
- return false;
- }
- bool IsInactiveDeskContainerId(int id) {
- return desks_util::IsDeskContainerId(id) &&
- id != desks_util::GetActiveDeskContainerId();
- }
- } // namespace
- ////////////////////////////////////////////////////////////////////////////////
- // AshFocusRules, public:
- AshFocusRules::AshFocusRules()
- : activatable_container_ids_(GetActivatableShellWindowIds()) {}
- AshFocusRules::~AshFocusRules() = default;
- ////////////////////////////////////////////////////////////////////////////////
- // AshFocusRules, ::wm::FocusRules:
- bool AshFocusRules::IsToplevelWindow(const aura::Window* window) const {
- DCHECK(window);
- // The window must be in a valid hierarchy.
- if (!window->GetRootWindow() || !window->parent())
- return false;
- // The window must exist within a container that supports activation.
- // The window cannot be blocked by a modal transient.
- return base::Contains(activatable_container_ids_, window->parent()->GetId());
- }
- bool AshFocusRules::SupportsChildActivation(const aura::Window* window) const {
- return base::Contains(activatable_container_ids_, window->GetId());
- }
- bool AshFocusRules::IsWindowConsideredVisibleForActivation(
- const aura::Window* window) const {
- DCHECK(window);
- // If the |window| doesn't belong to the current active user and also doesn't
- // show for the current active user, then it should not be activated.
- if (!Shell::Get()->shell_delegate()->CanShowWindowForUser(window))
- return false;
- if (window->IsVisible())
- return true;
- // Minimized windows are hidden in their minimized state, but they can always
- // be activated.
- if (WindowState::Get(window)->IsMinimized())
- return true;
- if (!window->TargetVisibility())
- return false;
- const aura::Window* const parent = window->parent();
- return desks_util::IsDeskContainer(parent) ||
- parent->GetId() == kShellWindowId_LockScreenContainer;
- }
- bool AshFocusRules::CanActivateWindow(const aura::Window* window) const {
- // Clearing activation is always permissible.
- if (!window)
- return true;
- if (!WindowRestoreController::CanActivateRestoredWindow(window))
- return false;
- // Special case during Full Restore that prevents the app list from being
- // activated during tablet mode if the topmost window of any root window is a
- // Full Restore'd window. See http://crbug/1202923.
- if (!WindowRestoreController::CanActivateAppList(window))
- return false;
- if (!BaseFocusRules::CanActivateWindow(window))
- return false;
- // Special case to allow the login shelf to be activatable when the OOBE
- // modal is visible. See http://crbug/871184
- // TODO: remove this special case once login shelf is moved into a child
- // widget of the lock screen (https://crbug.com/767235).
- if (Shell::Get()->session_controller()->IsUserSessionBlocked() &&
- BelongsToContainerWithId(window, kShellWindowId_ShelfContainer)) {
- return true;
- }
- int modal_container_id = Shell::GetOpenSystemModalWindowContainerId();
- if (modal_container_id >= 0)
- return BelongsToContainerWithEqualOrGreaterId(window, modal_container_id);
- return true;
- }
- bool AshFocusRules::CanFocusWindow(const aura::Window* window,
- const ui::Event* event) const {
- if (!window)
- return true;
- if (event && (event->IsMouseEvent() || event->IsGestureEvent()) &&
- !window->GetProperty(aura::client::kActivateOnPointerKey)) {
- return false;
- }
- return BaseFocusRules::CanFocusWindow(window, event);
- }
- aura::Window* AshFocusRules::GetNextActivatableWindow(
- aura::Window* ignore) const {
- DCHECK(ignore);
- // If the window that just lost focus |ignore| has a transient parent, then
- // start from the container of that parent, otherwise start from the container
- // of the most-recently-used window. If the list of MRU windows is empty, then
- // start from the container of |ignore|.
- aura::Window* starting_window = nullptr;
- aura::Window* transient_parent = ::wm::GetTransientParent(ignore);
- OverviewController* overview_controller = Shell::Get()->overview_controller();
- // It's possible for this to be called either on shutdown or when a session is
- // not yet active, so we need to check for the existence of the overview
- // controller.
- if (overview_controller && overview_controller->InOverviewSession() &&
- overview_controller->overview_session()->IsTemplatesUiLosingActivation(
- ignore)) {
- starting_window =
- overview_controller->overview_session()->GetOverviewFocusWindow();
- } else if (transient_parent) {
- starting_window = transient_parent;
- } else {
- MruWindowTracker* mru = Shell::Get()->mru_window_tracker();
- aura::Window::Windows windows = mru->BuildMruWindowList(kActiveDesk);
- starting_window = windows.empty() ? ignore : windows[0];
- }
- DCHECK(starting_window);
- // Look for windows to focus in |starting_window|'s container. If none are
- // found, we look in all the containers in front of |starting_window|'s
- // container, then all behind.
- int starting_container_index = 0;
- aura::Window* root = starting_window->GetRootWindow();
- if (!root)
- root = Shell::GetRootWindowForNewWindows();
- const int container_count = activatable_container_ids_.size();
- for (int i = 0; i < container_count; i++) {
- aura::Window* container =
- Shell::GetContainer(root, activatable_container_ids_[i]);
- if (container && container->Contains(starting_window)) {
- starting_container_index = i;
- break;
- }
- }
- aura::Window* window = nullptr;
- for (int i = starting_container_index; !window && i < container_count; i++)
- window = GetTopmostWindowToActivateForContainerIndex(i, ignore);
- if (!window && starting_container_index > 0) {
- for (int i = starting_container_index - 1; !window && i >= 0; i--)
- window = GetTopmostWindowToActivateForContainerIndex(i, ignore);
- }
- return window;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // AshFocusRules, private:
- aura::Window* AshFocusRules::GetTopmostWindowToActivateForContainerIndex(
- int index,
- aura::Window* ignore) const {
- const int container_id = activatable_container_ids_[index];
- // Inactive desk containers should be ignored, since windows in them should
- // never be returned as a next activatable window.
- if (IsInactiveDeskContainerId(container_id))
- return nullptr;
- aura::Window* window = nullptr;
- aura::Window* root = ignore ? ignore->GetRootWindow() : nullptr;
- aura::Window::Windows containers =
- GetContainersForAllRootWindows(container_id, root);
- for (aura::Window* container : containers) {
- window = GetTopmostWindowToActivateInContainer(container, ignore);
- if (window)
- return window;
- }
- return window;
- }
- aura::Window* AshFocusRules::GetTopmostWindowToActivateInContainer(
- aura::Window* container,
- aura::Window* ignore) const {
- for (aura::Window* child : base::Reversed(container->children())) {
- WindowState* window_state = WindowState::Get(child);
- if (child != ignore && window_state->CanActivate() &&
- !window_state->IsMinimized())
- return child;
- }
- return nullptr;
- }
- } // namespace ash
|