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
5#include "ash/wm/stacking_controller.h"
6
7#include "ash/root_window_controller.h"
8#include "ash/session_state_delegate.h"
9#include "ash/shell.h"
10#include "ash/shell_window_ids.h"
11#include "ash/wm/always_on_top_controller.h"
12#include "ash/wm/coordinate_conversion.h"
13#include "ash/wm/window_state.h"
14#include "ui/aura/client/aura_constants.h"
15#include "ui/aura/root_window.h"
16#include "ui/aura/window.h"
17#include "ui/base/ui_base_types.h"
18
19namespace ash {
20namespace {
21
22// Find a root window that matches the |bounds|. If the virtual screen
23// coordinates is enabled and the bounds is specified, the root window
24// that matches the window's bound will be used. Otherwise, it'll
25// return the active root window.
26aura::Window* FindContainerRoot(const gfx::Rect& bounds) {
27  if (bounds.x() == 0 && bounds.y() == 0 && bounds.IsEmpty())
28    return Shell::GetTargetRootWindow();
29  return wm::GetRootWindowMatching(bounds);
30}
31
32aura::Window* GetContainerById(aura::Window* root, int id) {
33  return Shell::GetContainer(root, id);
34}
35
36bool IsSystemModal(aura::Window* window) {
37  return window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_SYSTEM;
38}
39
40bool HasTransientParentWindow(aura::Window* window) {
41  return window->transient_parent() &&
42      window->transient_parent()->type() != aura::client::WINDOW_TYPE_UNKNOWN;
43}
44
45internal::AlwaysOnTopController*
46GetAlwaysOnTopController(aura::Window* root_window) {
47  return internal::GetRootWindowController(root_window)->
48      always_on_top_controller();
49}
50
51}  // namespace
52
53////////////////////////////////////////////////////////////////////////////////
54// StackingController, public:
55
56StackingController::StackingController() {
57}
58
59StackingController::~StackingController() {
60}
61
62////////////////////////////////////////////////////////////////////////////////
63// StackingController, aura::client::WindowTreeClient implementation:
64
65aura::Window* StackingController::GetDefaultParent(aura::Window* context,
66                                                   aura::Window* window,
67                                                   const gfx::Rect& bounds) {
68  aura::Window* target_root = NULL;
69  if (window->transient_parent()) {
70    // Transient window should use the same root as its transient parent.
71    target_root = window->transient_parent()->GetRootWindow();
72  } else {
73    target_root = FindContainerRoot(bounds);
74  }
75
76  switch (window->type()) {
77    case aura::client::WINDOW_TYPE_NORMAL:
78    case aura::client::WINDOW_TYPE_POPUP:
79      if (IsSystemModal(window))
80        return GetSystemModalContainer(target_root, window);
81      else if (HasTransientParentWindow(window))
82        return internal::RootWindowController::GetContainerForWindow(
83            window->transient_parent());
84      return GetAlwaysOnTopController(target_root)->GetContainer(window);
85    case aura::client::WINDOW_TYPE_CONTROL:
86      return GetContainerById(
87          target_root, internal::kShellWindowId_UnparentedControlContainer);
88    case aura::client::WINDOW_TYPE_PANEL:
89      if (wm::GetWindowState(window)->panel_attached())
90        return GetContainerById(target_root,
91                                internal::kShellWindowId_PanelContainer);
92      else
93        return GetAlwaysOnTopController(target_root)->GetContainer(window);
94    case aura::client::WINDOW_TYPE_MENU:
95      return GetContainerById(
96          target_root, internal::kShellWindowId_MenuContainer);
97    case aura::client::WINDOW_TYPE_TOOLTIP:
98      return GetContainerById(
99          target_root, internal::kShellWindowId_DragImageAndTooltipContainer);
100    default:
101      NOTREACHED() << "Window " << window->id()
102                   << " has unhandled type " << window->type();
103      break;
104  }
105  return NULL;
106}
107
108////////////////////////////////////////////////////////////////////////////////
109// StackingController, private:
110
111aura::Window* StackingController::GetSystemModalContainer(
112    aura::Window* root,
113    aura::Window* window) const {
114  DCHECK(IsSystemModal(window));
115
116  // If screen lock is not active and user session is active,
117  // all modal windows are placed into the normal modal container.
118  // In case of missing transient parent (it could happen for alerts from
119  // background pages) assume that the window belongs to user session.
120  SessionStateDelegate* session_state_delegate =
121      Shell::GetInstance()->session_state_delegate();
122  if (!session_state_delegate->IsUserSessionBlocked() ||
123      !window->transient_parent()) {
124    return GetContainerById(root,
125                            internal::kShellWindowId_SystemModalContainer);
126  }
127
128  // Otherwise those that originate from LockScreen container and above are
129  // placed in the screen lock modal container.
130  int window_container_id = window->transient_parent()->parent()->id();
131  aura::Window* container = NULL;
132  if (window_container_id < internal::kShellWindowId_LockScreenContainer) {
133    container = GetContainerById(
134        root, internal::kShellWindowId_SystemModalContainer);
135  } else {
136    container = GetContainerById(
137        root, internal::kShellWindowId_LockSystemModalContainer);
138  }
139
140  return container;
141}
142
143}  // namespace ash
144