Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(540)

Side by Side Diff: ash/wm/dock/dock_layout_manager.cc

Issue 13896026: Stick windows to sides of workspaces (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Docking with dock width=0 (more comments) Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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/dock/dock_layout_manager.h"
6
7 #include "ash/launcher/launcher.h"
8 #include "ash/root_window_controller.h"
9 #include "ash/screen_ash.h"
10 #include "ash/shelf/shelf_layout_manager.h"
11 #include "ash/shelf/shelf_types.h"
12 #include "ash/shelf/shelf_widget.h"
13 #include "ash/shell.h"
14 #include "ash/shell_window_ids.h"
15 #include "ash/wm/property_util.h"
16 #include "ash/wm/window_animations.h"
17 #include "ash/wm/window_properties.h"
18 #include "ash/wm/window_util.h"
19 #include "ash/wm/workspace_controller.h"
20 #include "base/auto_reset.h"
21 #include "base/bind.h"
22 #include "base/bind_helpers.h"
23 #include "ui/aura/client/activation_client.h"
24 #include "ui/aura/client/aura_constants.h"
25 #include "ui/aura/focus_manager.h"
26 #include "ui/aura/root_window.h"
27 #include "ui/aura/window.h"
28 #include "ui/compositor/scoped_layer_animation_settings.h"
29 #include "ui/gfx/rect.h"
30
31 namespace ash {
32 namespace internal {
33
34 namespace {
35
36 const int kMagnetismWidth = 32;
37
38 // Duration for window animations.
39 const int kWindowSlideDurationMilliseconds = 50;
40
41 DockLayoutManager* GetDockLayoutManager(aura::Window* window) {
42 aura::Window* dock = Shell::GetContainer(
43 window->GetRootWindow(), kShellWindowId_DockContainer);
44 return static_cast<internal::DockLayoutManager*>(dock->layout_manager());
45 }
46
47 } // namespace
48
49 ////////////////////////////////////////////////////////////////////////////////
50 // DockLayoutManager public implementation:
51 DockLayoutManager::DockLayoutManager(aura::Window* dock_container)
52 : dock_container_(dock_container),
53 in_layout_(false),
54 dragged_window_(NULL),
55 launcher_(NULL),
56 shelf_layout_manager_(NULL),
57 shelf_hidden_(false),
58 alignment_(DOCK_ALIGNMENT_NONE) {
59 DCHECK(dock_container);
60 aura::client::GetActivationClient(Shell::GetPrimaryRootWindow())->
61 AddObserver(this);
62 Shell::GetInstance()->AddShellObserver(this);
63 }
64
65 DockLayoutManager::~DockLayoutManager() {
66 if (shelf_layout_manager_)
67 shelf_layout_manager_->RemoveObserver(this);
68 Shutdown();
69 aura::client::GetActivationClient(Shell::GetPrimaryRootWindow())->
70 RemoveObserver(this);
71 Shell::GetInstance()->RemoveShellObserver(this);
72 }
73
74 void DockLayoutManager::Shutdown() {
75 launcher_ = NULL;
76 }
77
78 void DockLayoutManager::StartDragging(aura::Window* window) {
79 DCHECK(!dragged_window_);
80 dragged_window_ = window;
81 Relayout();
82 }
83
84 void DockLayoutManager::FinishDragging() {
85 if (dragged_window_) {
86 DockEdge dock_edge = FindDockEdge(dragged_window_);
87 if (dock_edge == DOCK_EDGE_NONE)
88 // this will reparent the window back to workspace
89 SetDockEdge(dragged_window_, dock_edge);
90 }
91 dragged_window_ = NULL;
92 Relayout();
93 }
94
95 DockEdge DockLayoutManager::FindDockEdge(aura::Window* window) {
96 DockLayoutManager* layout_manager = GetDockLayoutManager(window);
97 const gfx::Rect& bounds(window->bounds());
98 DockEdge dock_edge = DOCK_EDGE_NONE;
99 gfx::Rect dock_bounds = layout_manager->dock_container_->bounds();
100 if (bounds.x() == dock_bounds.x() &&
101 layout_manager->alignment_ != DOCK_ALIGNMENT_RIGHT) {
102 dock_edge = DOCK_EDGE_LEFT;
103 }
104 if (bounds.right() == dock_bounds.right() &&
105 layout_manager->alignment_ != DOCK_ALIGNMENT_LEFT) {
106 dock_edge = DOCK_EDGE_RIGHT;
107 }
108
109 // do not allow dock on the same side as launcher shelf
110 if (layout_manager->launcher_ && layout_manager->launcher_->shelf_widget()) {
111 ShelfAlignment shelf_alignment =
112 layout_manager->launcher_->shelf_widget()->GetAlignment();
113 if ((shelf_alignment == SHELF_ALIGNMENT_LEFT &&
114 dock_edge == DOCK_EDGE_LEFT) ||
115 (shelf_alignment == SHELF_ALIGNMENT_RIGHT &&
116 dock_edge == DOCK_EDGE_RIGHT)) {
flackr 2013/06/04 19:58:10 this should be aligned with "shelf_alignment" abov
varkha 2013/06/07 19:01:28 Done.
117 dock_edge = DOCK_EDGE_NONE;
118 }
119 }
120 return dock_edge;
121 }
122
123 void DockLayoutManager::SetLauncher(ash::Launcher* launcher) {
124 DCHECK(!launcher_);
125 DCHECK(!shelf_layout_manager_);
126 launcher_ = launcher;
127 if (launcher_->shelf_widget()) {
128 shelf_layout_manager_ = ash::internal::ShelfLayoutManager::ForLauncher(
129 launcher_->shelf_widget()->GetNativeWindow());
130 WillChangeVisibilityState(shelf_layout_manager_->visibility_state());
131 shelf_layout_manager_->AddObserver(this);
132 }
133 }
134
135 void DockLayoutManager::ToggleMinimize(aura::Window* window) {
136 DCHECK(window->parent() == dock_container_);
137 if (window->GetProperty(aura::client::kShowStateKey) ==
138 ui::SHOW_STATE_MINIMIZED) {
139 window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
140 } else {
141 window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
142 }
143 }
144
145 ////////////////////////////////////////////////////////////////////////////////
146 // DockLayoutManager, aura::LayoutManager implementation:
147 void DockLayoutManager::OnWindowResized() {
148 Relayout();
149 }
150
151 void DockLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
152 DCHECK(GetDockEdge(child) != DOCK_EDGE_NONE);
153 child->AddObserver(this);
154 Relayout();
155 }
156
157 void DockLayoutManager::OnWillRemoveWindowFromLayout(aura::Window* child) {
158 }
159
160 void DockLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {
161 SetDockEdge(child, DOCK_EDGE_NONE);
162 child->RemoveObserver(this);
163
164 if (dragged_window_ == child)
165 dragged_window_ = NULL;
166
167 Relayout();
168 }
169
170 void DockLayoutManager::OnChildWindowVisibilityChanged(aura::Window* child,
171 bool visible) {
172 Relayout();
173 }
174
175 void DockLayoutManager::SetChildBounds(aura::Window* child,
176 const gfx::Rect& requested_bounds) {
177 SetChildBoundsDirect(child, requested_bounds);
178 Relayout();
179 }
180
181 ////////////////////////////////////////////////////////////////////////////////
182 // DockLayoutManager, ash::ShellObserver implementation:
183
184 void DockLayoutManager::OnShelfAlignmentChanged(
185 aura::RootWindow* root_window) {
186 if (dock_container_->GetRootWindow() != root_window)
187 return;
188
189 if (!launcher_ || !launcher_->shelf_widget())
190 return;
191
192 // We do not allow launcher and dock on the same side. Switch side that
193 // the dock is attached to and move all dock windows to that new side
194 ShelfAlignment shelf_alignment =
195 launcher_->shelf_widget()->GetAlignment();
196 if (alignment_ == DOCK_ALIGNMENT_LEFT &&
197 shelf_alignment == SHELF_ALIGNMENT_LEFT) {
198 for (size_t i = 0; i < dock_container_->children().size(); ++i)
199 SetDockEdge(dock_container_->children()[i], DOCK_EDGE_RIGHT);
200 } else if (alignment_ == DOCK_ALIGNMENT_RIGHT &&
201 shelf_alignment == SHELF_ALIGNMENT_RIGHT) {
202 for (size_t i = 0; i < dock_container_->children().size(); ++i)
203 SetDockEdge(dock_container_->children()[i], DOCK_EDGE_LEFT);
204 }
205 Relayout();
206 }
207
208 /////////////////////////////////////////////////////////////////////////////
209 // DockLayoutManager, WindowObserver implementation:
210
211 void DockLayoutManager::OnWindowPropertyChanged(aura::Window* window,
212 const void* key,
213 intptr_t old) {
214 if (key == ash::internal::kDockEdge &&
215 GetDockEdge(window) != static_cast<DockEdge>(old)) {
216 DockEdge edge = GetDockEdge(window);
217 if (edge == DOCK_EDGE_NONE && window->GetRootWindow()) {
218 // Reparenting will cause Relayout and possible dock resize.
219 window->SetDefaultParentByRootWindow(window->GetRootWindow(),
220 window->GetBoundsInScreen());
221 // A maximized workspace may be active so we may need to switch
222 // to a parent workspace of the window being dragged out.
223 internal::WorkspaceController* workspace_controller =
224 GetRootWindowController(
225 window->GetRootWindow())->workspace_controller();
226 workspace_controller->SetActiveWorkspaceByWindow(window);
227 }
228 }
229
flackr 2013/06/04 19:58:10 nit: move else if up to brace } else if (...) {
varkha 2013/06/07 19:01:28 Done.
230 else if (key == aura::client::kShowStateKey) {
stevenjb 2013/06/04 16:23:54 nit: else on line 228, after }
varkha 2013/06/07 19:01:28 Done.
231 // The window property will still be set, but no actual change will occur
232 // until WillChangeVisibilityState is called when the shelf is visible again
233 if (shelf_hidden_)
234 return;
235 ui::WindowShowState new_state =
236 window->GetProperty(aura::client::kShowStateKey);
237 if (new_state == ui::SHOW_STATE_MINIMIZED)
238 MinimizeWindow(window);
239 else
240 RestoreWindow(window);
241 }
242 }
243
244 void DockLayoutManager::OnWindowVisibilityChanged(aura::Window* window,
245 bool visible) {
246 if (visible)
247 window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
248 }
249
250 ////////////////////////////////////////////////////////////////////////////////
251 // DockLayoutManager, aura::client::ActivationChangeObserver implementation:
252
253 void DockLayoutManager::OnWindowActivated(aura::Window* gained_active,
254 aura::Window* lost_active) {
255 // Ignore if the window that is not managed by this was activated.
256 if (gained_active && gained_active->parent() == dock_container_)
257 UpdateStacking(gained_active);
258 }
259
260 ////////////////////////////////////////////////////////////////////////////////
261 // DockLayoutManager, ShelfLayoutManagerObserver implementation:
262
263 void DockLayoutManager::WillChangeVisibilityState(
264 ShelfVisibilityState new_state) {
265 // On entering / leaving full screen mode the shelf visibility state is
266 // changed to / from SHELF_HIDDEN. In this state, docked windows should hide
267 // to allow the full-screen application to use the full screen.
268
269 // TODO(varkha): ShelfLayoutManager::UpdateVisibilityState sets state to
270 // SHELF_AUTO_HIDE when in immersive mode. We need to distinguish this from
271 // when shelf enters auto-hide state based on mouse hover when auto-hide
272 // setting is enabled and hide all windows (immersive mode should hide dock).
273 shelf_hidden_ = new_state == ash::SHELF_HIDDEN;
274 for (size_t i = 0; i < dock_container_->children().size(); ++i) {
275 aura::Window* window = dock_container_->children()[i];
276 if (shelf_hidden_) {
277 if (window->IsVisible())
278 MinimizeWindow(window);
279 } else {
280 if (window->GetProperty(aura::client::kShowStateKey) !=
281 ui::SHOW_STATE_MINIMIZED) {
282 RestoreWindow(window);
283 }
284 }
285 }
286 }
287
288 ////////////////////////////////////////////////////////////////////////////////
289 // DockLayoutManager private implementation:
290
291 void DockLayoutManager::MinimizeWindow(aura::Window* window) {
292 window->Hide();
293 if (wm::IsActiveWindow(window))
294 wm::DeactivateWindow(window);
295 Relayout();
296 }
297
298 void DockLayoutManager::RestoreWindow(aura::Window* window) {
299 window->Show();
300 Relayout();
301 }
302
303 void DockLayoutManager::Relayout() {
304 if (in_layout_)
305 return;
306 base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true);
307
308 if (dock_container_->children().empty()) {
309 alignment_ = DOCK_ALIGNMENT_NONE;
310 return;
311 }
312
313 gfx::Rect dock_bounds = dock_container_->bounds();
314 aura::Window* active_window = NULL;
315 std::vector<aura::Window*> visible_windows;
316 alignment_ = GetDockEdge(dock_container_->children()[0]) == DOCK_EDGE_LEFT ?
317 DOCK_ALIGNMENT_LEFT : DOCK_ALIGNMENT_RIGHT;
318 for (size_t i = 0; i < dock_container_->children().size(); ++i) {
319 aura::Window* window(dock_container_->children()[i]);
320
321 if (!window->IsVisible() ||
322 window->GetProperty(aura::client::kShowStateKey) ==
323 ui::SHOW_STATE_MINIMIZED) {
324 continue;
325 }
326
327 // If the shelf is currently hidden (full-screen mode), hide window until
328 // full-screen mode is exited.
329 if (shelf_hidden_) {
330 // The call to Hide does not set the minimize property, so the window will
331 // be restored when the shelf becomes visible again.
332 window->Hide();
333 continue;
334 }
335
336 if (window->HasFocus() ||
337 window->Contains(
338 aura::client::GetFocusClient(window)->GetFocusedWindow())) {
339 DCHECK(!active_window);
340 active_window = window;
341 }
342
343 gfx::Rect bounds = window->GetTargetBounds();
344 switch (alignment_) {
345 case DOCK_ALIGNMENT_LEFT:
346 if (window != dragged_window_ ||
347 bounds.x() - dock_bounds.x() < kMagnetismWidth) {
348 bounds.set_x(0);
349 }
350 break;
351 case DOCK_ALIGNMENT_RIGHT:
352 if (window != dragged_window_ ||
353 dock_bounds.right() - bounds.right() < kMagnetismWidth) {
354 bounds.set_x(dock_bounds.right() - bounds.width());
355 }
356 break;
357 case DOCK_ALIGNMENT_NONE:
flackr 2013/06/04 19:58:10 Assert that this never happens. If there are any w
varkha 2013/06/07 19:01:28 Done.
358 break;
359 }
360 SetChildBoundsDirect(window, bounds);
361 }
362
363 UpdateStacking(active_window);
364 }
365
366 void DockLayoutManager::UpdateStacking(aura::Window* active_window) {
367 // TODO(varkha): Implement restacking to ensure that all docked windows are at
368 // least partially visible and selectable.
369 }
370
371 ////////////////////////////////////////////////////////////////////////////////
372 // keyboard::KeyboardControllerObserver implementation:
373
374 void DockLayoutManager::OnKeyboardBoundsChanging(
375 const gfx::Rect& keyboard_bounds) {
376 // This bounds change will have caused a change to the Shelf which does not
377 // propagate automatically to this class, so manually recalculate bounds.
378 OnWindowResized();
379 }
380
381 } // namespace internal
382 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698