OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ash/common/wm/window_positioning_utils.h" | 5 #include "ash/common/wm/window_positioning_utils.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
| 9 #include "ash/common/wm/system_modal_container_layout_manager.h" |
9 #include "ash/common/wm/window_state.h" | 10 #include "ash/common/wm/window_state.h" |
10 #include "ash/common/wm/wm_event.h" | 11 #include "ash/common/wm/wm_event.h" |
11 #include "ash/common/wm/wm_screen_util.h" | 12 #include "ash/common/wm/wm_screen_util.h" |
| 13 #include "ash/common/wm_lookup.h" |
| 14 #include "ash/common/wm_root_window_controller.h" |
| 15 #include "ash/common/wm_shell.h" |
12 #include "ash/common/wm_window.h" | 16 #include "ash/common/wm_window.h" |
| 17 #include "ash/common/wm_window_tracker.h" |
| 18 #include "ui/display/display.h" |
13 #include "ui/gfx/geometry/rect.h" | 19 #include "ui/gfx/geometry/rect.h" |
14 #include "ui/gfx/geometry/size.h" | 20 #include "ui/gfx/geometry/size.h" |
15 | 21 |
16 namespace ash { | 22 namespace ash { |
17 namespace wm { | 23 namespace wm { |
18 | 24 |
19 namespace { | 25 namespace { |
20 | 26 |
21 // Returns the default width of a snapped window. | 27 // Returns the default width of a snapped window. |
22 int GetDefaultSnappedWindowWidth(WmWindow* window) { | 28 int GetDefaultSnappedWindowWidth(WmWindow* window) { |
23 const float kSnappedWidthWorkspaceRatio = 0.5f; | 29 const float kSnappedWidthWorkspaceRatio = 0.5f; |
24 | 30 |
25 int work_area_width = GetDisplayWorkAreaBoundsInParent(window).width(); | 31 int work_area_width = GetDisplayWorkAreaBoundsInParent(window).width(); |
26 int min_width = window->GetMinimumSize().width(); | 32 int min_width = window->GetMinimumSize().width(); |
27 int ideal_width = | 33 int ideal_width = |
28 static_cast<int>(work_area_width * kSnappedWidthWorkspaceRatio); | 34 static_cast<int>(work_area_width * kSnappedWidthWorkspaceRatio); |
29 return std::min(work_area_width, std::max(ideal_width, min_width)); | 35 return std::min(work_area_width, std::max(ideal_width, min_width)); |
30 } | 36 } |
31 | 37 |
| 38 // Return true if the window or one of its ancestor returns true from |
| 39 // IsLockedToRoot(). |
| 40 bool IsWindowOrAncestorLockedToRoot(const WmWindow* window) { |
| 41 return window && (window->IsLockedToRoot() || |
| 42 IsWindowOrAncestorLockedToRoot(window->GetParent())); |
| 43 } |
| 44 |
| 45 // Move all transient children to |dst_root|, including the ones in |
| 46 // the child windows and transient children of the transient children. |
| 47 void MoveAllTransientChildrenToNewRoot(const display::Display& display, |
| 48 WmWindow* window) { |
| 49 WmWindow* dst_root = WmLookup::Get() |
| 50 ->GetRootWindowControllerWithDisplayId(display.id()) |
| 51 ->GetWindow(); |
| 52 for (WmWindow* transient_child : window->GetTransientChildren()) { |
| 53 const int container_id = transient_child->GetParent()->GetShellWindowId(); |
| 54 DCHECK_GE(container_id, 0); |
| 55 WmWindow* container = dst_root->GetChildByShellWindowId(container_id); |
| 56 const gfx::Rect transient_child_bounds_in_screen = |
| 57 transient_child->GetBoundsInScreen(); |
| 58 container->AddChild(transient_child); |
| 59 transient_child->SetBoundsInScreen(transient_child_bounds_in_screen, |
| 60 display); |
| 61 |
| 62 // Transient children may have transient children. |
| 63 MoveAllTransientChildrenToNewRoot(display, transient_child); |
| 64 } |
| 65 // Move transient children of the child windows if any. |
| 66 for (WmWindow* child : window->GetChildren()) |
| 67 MoveAllTransientChildrenToNewRoot(display, child); |
| 68 } |
| 69 |
32 } // namespace | 70 } // namespace |
33 | 71 |
34 void AdjustBoundsSmallerThan(const gfx::Size& max_size, gfx::Rect* bounds) { | 72 void AdjustBoundsSmallerThan(const gfx::Size& max_size, gfx::Rect* bounds) { |
35 bounds->set_width(std::min(bounds->width(), max_size.width())); | 73 bounds->set_width(std::min(bounds->width(), max_size.width())); |
36 bounds->set_height(std::min(bounds->height(), max_size.height())); | 74 bounds->set_height(std::min(bounds->height(), max_size.height())); |
37 } | 75 } |
38 | 76 |
39 void AdjustBoundsToEnsureWindowVisibility(const gfx::Rect& visible_area, | 77 void AdjustBoundsToEnsureWindowVisibility(const gfx::Rect& visible_area, |
40 int min_width, | 78 int min_width, |
41 int min_height, | 79 int min_height, |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
80 int width = GetDefaultSnappedWindowWidth(window); | 118 int width = GetDefaultSnappedWindowWidth(window); |
81 return gfx::Rect(work_area_in_parent.right() - width, work_area_in_parent.y(), | 119 return gfx::Rect(work_area_in_parent.right() - width, work_area_in_parent.y(), |
82 width, work_area_in_parent.height()); | 120 width, work_area_in_parent.height()); |
83 } | 121 } |
84 | 122 |
85 void CenterWindow(WmWindow* window) { | 123 void CenterWindow(WmWindow* window) { |
86 WMEvent event(WM_EVENT_CENTER); | 124 WMEvent event(WM_EVENT_CENTER); |
87 window->GetWindowState()->OnWMEvent(&event); | 125 window->GetWindowState()->OnWMEvent(&event); |
88 } | 126 } |
89 | 127 |
| 128 void SetBoundsInScreen(WmWindow* window, |
| 129 const gfx::Rect& bounds_in_screen, |
| 130 const display::Display& display) { |
| 131 DCHECK_NE(display::Display::kInvalidDisplayID, display.id()); |
| 132 // Don't move a window to other root window if: |
| 133 // a) the window is a transient window. It moves when its |
| 134 // transient parent moves. |
| 135 // b) if the window or its ancestor has IsLockedToRoot(). It's intentionally |
| 136 // kept in the same root window even if the bounds is outside of the |
| 137 // display. |
| 138 if (!window->GetTransientParent() && |
| 139 !IsWindowOrAncestorLockedToRoot(window)) { |
| 140 WmRootWindowController* dst_root_window_controller = |
| 141 WmLookup::Get()->GetRootWindowControllerWithDisplayId(display.id()); |
| 142 DCHECK(dst_root_window_controller); |
| 143 WmWindow* dst_root = dst_root_window_controller->GetWindow(); |
| 144 DCHECK(dst_root); |
| 145 WmWindow* dst_container = nullptr; |
| 146 if (dst_root != window->GetRootWindow()) { |
| 147 int container_id = window->GetParent()->GetShellWindowId(); |
| 148 // All containers that uses screen coordinates must have valid window ids. |
| 149 DCHECK_GE(container_id, 0); |
| 150 // Don't move modal background. |
| 151 if (!SystemModalContainerLayoutManager::IsModalBackground(window)) |
| 152 dst_container = dst_root->GetChildByShellWindowId(container_id); |
| 153 } |
| 154 |
| 155 if (dst_container && window->GetParent() != dst_container) { |
| 156 WmWindow* focused = WmShell::Get()->GetFocusedWindow(); |
| 157 WmWindow* active = WmShell::Get()->GetActiveWindow(); |
| 158 |
| 159 WmWindowTracker tracker; |
| 160 if (focused) |
| 161 tracker.Add(focused); |
| 162 if (active && focused != active) |
| 163 tracker.Add(active); |
| 164 |
| 165 gfx::Point origin = bounds_in_screen.origin(); |
| 166 const gfx::Point display_origin = display.bounds().origin(); |
| 167 origin.Offset(-display_origin.x(), -display_origin.y()); |
| 168 gfx::Rect new_bounds = gfx::Rect(origin, bounds_in_screen.size()); |
| 169 |
| 170 // Set new bounds now so that the container's layout manager can adjust |
| 171 // the bounds if necessary. |
| 172 window->SetBounds(new_bounds); |
| 173 |
| 174 dst_container->AddChild(window); |
| 175 |
| 176 MoveAllTransientChildrenToNewRoot(display, window); |
| 177 |
| 178 // Restore focused/active window. |
| 179 if (tracker.Contains(focused)) { |
| 180 focused->SetFocused(); |
| 181 WmShell::Get()->set_root_window_for_new_windows( |
| 182 focused->GetRootWindow()); |
| 183 } else if (tracker.Contains(active)) { |
| 184 active->Activate(); |
| 185 } |
| 186 // TODO(oshima): We should not have to update the bounds again |
| 187 // below in theory, but we currently do need as there is a code |
| 188 // that assumes that the bounds will never be overridden by the |
| 189 // layout mananger. We should have more explicit control how |
| 190 // constraints are applied by the layout manager. |
| 191 } |
| 192 } |
| 193 gfx::Point origin(bounds_in_screen.origin()); |
| 194 const gfx::Point display_origin = |
| 195 window->GetDisplayNearestWindow().bounds().origin(); |
| 196 origin.Offset(-display_origin.x(), -display_origin.y()); |
| 197 window->SetBounds(gfx::Rect(origin, bounds_in_screen.size())); |
| 198 } |
| 199 |
90 } // namespace wm | 200 } // namespace wm |
91 } // namespace ash | 201 } // namespace ash |
OLD | NEW |