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