1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
|
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/wm/container_finder.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/public/cpp/window_properties.h"
#include "ash/root_window_controller.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/wm/always_on_top_controller.h"
#include "ash/wm/window_positioning_utils.h"
#include "ash/wm/window_state.h"
#include "ash/wm/window_util.h"
#include "components/app_restore/window_properties.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/window.h"
#include "ui/base/ui_base_types.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/wm/core/window_util.h"
namespace ash {
namespace {
aura::Window* FindContainerRoot(aura::Window* root_window,
const gfx::Rect& bounds_in_screen) {
if (bounds_in_screen == gfx::Rect()) {
return Shell::GetRootWindowForNewWindows();
}
auto display =
display::Screen::GetScreen()->GetDisplayNearestWindow(root_window);
auto overlap = display.bounds();
overlap.Intersect(bounds_in_screen);
// If the window is nearly invisible on the current display, use matching
// display.
if (!display.bounds().Contains(bounds_in_screen) &&
overlap.width() < kMinimumOnScreenArea &&
overlap.height() < kMinimumOnScreenArea) {
return window_util::GetRootWindowMatching(bounds_in_screen);
}
return root_window;
}
bool HasTransientParentWindow(const aura::Window* window) {
const aura::Window* transient_parent = ::wm::GetTransientParent(window);
return transient_parent &&
transient_parent->GetType() != aura::client::WINDOW_TYPE_UNKNOWN;
}
aura::Window* GetSystemModalContainer(aura::Window* root,
aura::Window* window) {
DCHECK_EQ(ui::MODAL_TYPE_SYSTEM,
window->GetProperty(aura::client::kModalKey));
// If |window| is already in a system modal container in |root|, re-use it.
for (auto modal_container_id : kSystemModalContainerIds) {
aura::Window* modal_container = root->GetChildById(modal_container_id);
if (window->parent() == modal_container) {
return modal_container;
}
}
aura::Window* transient_parent = ::wm::GetTransientParent(window);
// If screen lock is not active and user session is active,
// all modal windows are placed into the normal modal container.
// In case of missing transient parent (it could happen for alerts from
// background pages) assume that the window belongs to user session.
if (!Shell::Get()->session_controller()->IsUserSessionBlocked() ||
!transient_parent) {
return root->GetChildById(kShellWindowId_SystemModalContainer);
}
// Otherwise those that originate from LockScreen container and above are
// placed in the screen lock modal container.
int window_container_id = transient_parent->parent()->GetId();
if (window_container_id < kShellWindowId_LockScreenContainer) {
return root->GetChildById(kShellWindowId_SystemModalContainer);
}
return root->GetChildById(kShellWindowId_LockSystemModalContainer);
}
aura::Window* GetContainerFromAlwaysOnTopController(aura::Window* root,
aura::Window* window) {
return RootWindowController::ForWindow(root)
->always_on_top_controller()
->GetContainer(window);
}
} // namespace
aura::Window* GetContainerForWindow(aura::Window* window) {
aura::Window* parent = window->parent();
// The first parent with an explicit shell window ID is the container.
while (parent && parent->GetId() == kShellWindowId_Invalid) {
parent = parent->parent();
}
return parent;
}
aura::Window* GetDefaultParentForWindow(aura::Window* window,
aura::Window* root_window,
const gfx::Rect& bounds_in_screen) {
aura::Window* target_root = nullptr;
aura::Window* transient_parent = ::wm::GetTransientParent(window);
if (transient_parent) {
// Transient window should use the same root as its transient parent.
target_root = transient_parent->GetRootWindow();
} else {
target_root = FindContainerRoot(root_window, bounds_in_screen);
}
// For window restore, the window may be created before the associated window
// restore data can be retrieved. In this case, we will place it in a hidden
// container and will move it to a desk container when the window restore data
// can be retrieved. An example would be ARC windows, which can be created
// before their associated tasks are, which are required to retrieve window
// restore data.
if (window->GetProperty(app_restore::kParentToHiddenContainerKey)) {
return target_root->GetChildById(kShellWindowId_UnparentedContainer);
}
// Use kShellWindowId_DragImageAndTooltipContainer to host security surfaces
// so that they are on top of other normal widgets (top-level windows, menus,
// bubbles etc). See http://crbug.com/1317904.
if (window->GetProperty(aura::client::kZOrderingKey) ==
ui::ZOrderLevel::kSecuritySurface) {
return target_root->GetChildById(
kShellWindowId_DragImageAndTooltipContainer);
}
switch (window->GetType()) {
case aura::client::WINDOW_TYPE_NORMAL:
case aura::client::WINDOW_TYPE_POPUP:
if (window->GetProperty(aura::client::kModalKey) ==
ui::MODAL_TYPE_SYSTEM) {
return GetSystemModalContainer(target_root, window);
}
if (HasTransientParentWindow(window)) {
return GetContainerForWindow(transient_parent);
}
return GetContainerFromAlwaysOnTopController(target_root, window);
case aura::client::WINDOW_TYPE_CONTROL:
return target_root->GetChildById(kShellWindowId_UnparentedContainer);
case aura::client::WINDOW_TYPE_MENU:
return target_root->GetChildById(kShellWindowId_MenuContainer);
case aura::client::WINDOW_TYPE_TOOLTIP:
return target_root->GetChildById(
kShellWindowId_DragImageAndTooltipContainer);
default:
NOTREACHED() << "Window " << window->GetId() << " has unhandled type "
<< window->GetType();
break;
}
return nullptr;
}
aura::Window::Windows GetContainersForAllRootWindows(
int container_id,
aura::Window* priority_root) {
aura::Window::Windows containers;
for (aura::Window* root : Shell::GetAllRootWindows()) {
aura::Window* container = root->GetChildById(container_id);
if (!container) {
continue;
}
if (priority_root && priority_root->Contains(container)) {
containers.insert(containers.begin(), container);
} else {
containers.push_back(container);
}
}
return containers;
}
aura::Window* GetPowerMenuContainerParent(aura::Window* root_window) {
return root_window->GetChildById(
kShellWindowId_LockScreenRelatedContainersContainer);
}
} // namespace ash
|