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/window_util.h"
6
7#include <vector>
8
9#include "ash/ash_constants.h"
10#include "ash/screen_util.h"
11#include "ash/shell.h"
12#include "ash/wm/window_properties.h"
13#include "ash/wm/window_state.h"
14#include "ash/wm/wm_event.h"
15#include "ui/aura/client/aura_constants.h"
16#include "ui/aura/window.h"
17#include "ui/aura/window_delegate.h"
18#include "ui/aura/window_event_dispatcher.h"
19#include "ui/gfx/display.h"
20#include "ui/gfx/rect.h"
21#include "ui/gfx/screen.h"
22#include "ui/gfx/size.h"
23#include "ui/views/view.h"
24#include "ui/views/widget/widget.h"
25#include "ui/wm/core/window_util.h"
26#include "ui/wm/public/activation_client.h"
27
28namespace ash {
29namespace wm {
30
31namespace {
32
33// Returns the default width of a snapped window.
34int GetDefaultSnappedWindowWidth(aura::Window* window) {
35  const float kSnappedWidthWorkspaceRatio = 0.5f;
36
37  int work_area_width =
38      ScreenUtil::GetDisplayWorkAreaBoundsInParent(window).width();
39  int min_width = window->delegate() ?
40      window->delegate()->GetMinimumSize().width() : 0;
41  int ideal_width =
42      static_cast<int>(work_area_width * kSnappedWidthWorkspaceRatio);
43  return std::min(work_area_width, std::max(ideal_width, min_width));
44}
45
46}  // namespace
47
48// TODO(beng): replace many of these functions with the corewm versions.
49void ActivateWindow(aura::Window* window) {
50  ::wm::ActivateWindow(window);
51}
52
53void DeactivateWindow(aura::Window* window) {
54  ::wm::DeactivateWindow(window);
55}
56
57bool IsActiveWindow(aura::Window* window) {
58  return ::wm::IsActiveWindow(window);
59}
60
61aura::Window* GetActiveWindow() {
62  return aura::client::GetActivationClient(Shell::GetPrimaryRootWindow())->
63      GetActiveWindow();
64}
65
66aura::Window* GetActivatableWindow(aura::Window* window) {
67  return ::wm::GetActivatableWindow(window);
68}
69
70bool CanActivateWindow(aura::Window* window) {
71  return ::wm::CanActivateWindow(window);
72}
73
74bool IsWindowMinimized(aura::Window* window) {
75  return ash::wm::GetWindowState(window)->IsMinimized();
76}
77
78void CenterWindow(aura::Window* window) {
79  wm::WMEvent event(wm::WM_EVENT_CENTER);
80  wm::GetWindowState(window)->OnWMEvent(&event);
81}
82
83gfx::Rect GetDefaultLeftSnappedWindowBoundsInParent(aura::Window* window) {
84  gfx::Rect work_area_in_parent(ScreenUtil::GetDisplayWorkAreaBoundsInParent(
85      window));
86  return gfx::Rect(work_area_in_parent.x(),
87                   work_area_in_parent.y(),
88                   GetDefaultSnappedWindowWidth(window),
89                   work_area_in_parent.height());
90}
91
92gfx::Rect GetDefaultRightSnappedWindowBoundsInParent(aura::Window* window) {
93  gfx::Rect work_area_in_parent(ScreenUtil::GetDisplayWorkAreaBoundsInParent(
94      window));
95  int width = GetDefaultSnappedWindowWidth(window);
96  return gfx::Rect(work_area_in_parent.right() - width,
97                   work_area_in_parent.y(),
98                   width,
99                   work_area_in_parent.height());
100}
101
102void AdjustBoundsSmallerThan(const gfx::Size& max_size, gfx::Rect* bounds) {
103  bounds->set_width(std::min(bounds->width(), max_size.width()));
104  bounds->set_height(std::min(bounds->height(), max_size.height()));
105}
106
107void AdjustBoundsToEnsureMinimumWindowVisibility(const gfx::Rect& visible_area,
108                                                 gfx::Rect* bounds) {
109  AdjustBoundsToEnsureWindowVisibility(
110      visible_area, kMinimumOnScreenArea, kMinimumOnScreenArea, bounds);
111}
112
113void AdjustBoundsToEnsureWindowVisibility(const gfx::Rect& visible_area,
114                                          int min_width,
115                                          int min_height,
116                                          gfx::Rect* bounds) {
117  AdjustBoundsSmallerThan(visible_area.size(), bounds);
118
119  min_width = std::min(min_width, visible_area.width());
120  min_height = std::min(min_height, visible_area.height());
121
122  if (bounds->right() < visible_area.x() + min_width) {
123    bounds->set_x(visible_area.x() + min_width - bounds->width());
124  } else if (bounds->x() > visible_area.right() - min_width) {
125    bounds->set_x(visible_area.right() - min_width);
126  }
127  if (bounds->bottom() < visible_area.y() + min_height) {
128    bounds->set_y(visible_area.y() + min_height - bounds->height());
129  } else if (bounds->y() > visible_area.bottom() - min_height) {
130    bounds->set_y(visible_area.bottom() - min_height);
131  }
132  if (bounds->y() < visible_area.y())
133    bounds->set_y(visible_area.y());
134}
135
136bool MoveWindowToEventRoot(aura::Window* window, const ui::Event& event) {
137  views::View* target = static_cast<views::View*>(event.target());
138  if (!target)
139    return false;
140  aura::Window* target_root =
141      target->GetWidget()->GetNativeView()->GetRootWindow();
142  if (!target_root || target_root == window->GetRootWindow())
143    return false;
144  aura::Window* window_container =
145      ash::Shell::GetContainer(target_root, window->parent()->id());
146  // Move the window to the target launcher.
147  window_container->AddChild(window);
148  return true;
149}
150
151void ReparentChildWithTransientChildren(aura::Window* child,
152                                        aura::Window* old_parent,
153                                        aura::Window* new_parent) {
154  if (child->parent() == old_parent)
155    new_parent->AddChild(child);
156  ReparentTransientChildrenOfChild(child, old_parent, new_parent);
157}
158
159void ReparentTransientChildrenOfChild(aura::Window* child,
160                                      aura::Window* old_parent,
161                                      aura::Window* new_parent) {
162  for (size_t i = 0;
163       i < ::wm::GetTransientChildren(child).size();
164       ++i) {
165    ReparentChildWithTransientChildren(
166        ::wm::GetTransientChildren(child)[i],
167        old_parent,
168        new_parent);
169  }
170}
171
172}  // namespace wm
173}  // namespace ash
174