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

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: Dock with zero width (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/coordinate_conversion.h"
16 #include "ash/wm/property_util.h"
17 #include "ash/wm/window_animations.h"
18 #include "ash/wm/window_properties.h"
19 #include "ash/wm/window_util.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(),
44 kShellWindowId_DockContainer);
45 return static_cast<internal::DockLayoutManager*>(dock->layout_manager());
46 }
47
48 } // namespace
49
50 ////////////////////////////////////////////////////////////////////////////////
51 // DockLayoutManager public implementation:
52 DockLayoutManager::DockLayoutManager(aura::Window* dock_container)
53 : dock_container_(dock_container),
54 in_layout_(false),
55 dragged_window_(NULL),
56 launcher_(NULL),
57 shelf_layout_manager_(NULL),
58 shelf_hidden_(false),
59 alignment_(DOCK_ALIGNMENT_NONE) {
60 DCHECK(dock_container);
61 aura::client::GetActivationClient(Shell::GetPrimaryRootWindow())->
62 AddObserver(this);
63 Shell::GetInstance()->AddShellObserver(this);
64 }
65
66 DockLayoutManager::~DockLayoutManager() {
67 if (shelf_layout_manager_)
sky 2013/06/11 00:03:13 If you're going to have a Shutdown() method, shoul
varkha 2013/06/11 02:34:24 Done.
68 shelf_layout_manager_->RemoveObserver(this);
69 Shutdown();
70 aura::client::GetActivationClient(Shell::GetPrimaryRootWindow())->
71 RemoveObserver(this);
72 Shell::GetInstance()->RemoveShellObserver(this);
73 }
74
75 void DockLayoutManager::Shutdown() {
76 launcher_ = NULL;
77 }
78
79 void DockLayoutManager::StartDragging(aura::Window* window) {
80 DCHECK(!dragged_window_);
81 dragged_window_ = window;
82 Relayout();
83 }
84
85 void DockLayoutManager::FinishDragging() {
86 dragged_window_ = NULL;
87 Relayout();
88 }
89
90 DockEdge DockLayoutManager::FindDockEdge(aura::Window* window) {
sky 2013/06/11 00:03:13 Static sections should be prefixed with // static
varkha 2013/06/11 02:34:24 Done.
91 DockLayoutManager* layout_manager = GetDockLayoutManager(window);
92 const gfx::Rect& bounds(window->bounds());
93 gfx::Rect dock_bounds = layout_manager->dock_container_->bounds();
sky 2013/06/11 00:03:13 The coordinates are not necessarily the same here.
varkha 2013/06/11 02:34:24 Done. (I had this already fixed in the second CL.
94 DockEdge dock_edge = DOCK_EDGE_NONE;
95 if (bounds.x() == dock_bounds.x() &&
96 layout_manager->alignment_ != DOCK_ALIGNMENT_RIGHT) {
97 dock_edge = DOCK_EDGE_LEFT;
98 } else
99 if (bounds.right() == dock_bounds.right() &&
100 layout_manager->alignment_ != DOCK_ALIGNMENT_LEFT) {
101 dock_edge = DOCK_EDGE_RIGHT;
102 }
103
104 // do not allow dock on the same side as launcher shelf
105 if (layout_manager->launcher_ && layout_manager->launcher_->shelf_widget()) {
106 ShelfAlignment shelf_alignment =
107 layout_manager->launcher_->shelf_widget()->GetAlignment();
108 if ((shelf_alignment == SHELF_ALIGNMENT_LEFT &&
109 dock_edge == DOCK_EDGE_LEFT) ||
110 (shelf_alignment == SHELF_ALIGNMENT_RIGHT &&
111 dock_edge == DOCK_EDGE_RIGHT)) {
112 dock_edge = DOCK_EDGE_NONE;
113 }
114 }
115 return dock_edge;
116 }
117
118 void DockLayoutManager::SetLauncher(ash::Launcher* launcher) {
sky 2013/06/11 00:03:13 ordering should match header.
varkha 2013/06/11 02:34:24 Done. (I had this already fixed in the second CL.
119 DCHECK(!launcher_);
120 DCHECK(!shelf_layout_manager_);
121 launcher_ = launcher;
122 if (launcher_->shelf_widget()) {
123 shelf_layout_manager_ = ash::internal::ShelfLayoutManager::ForLauncher(
124 launcher_->shelf_widget()->GetNativeWindow());
125 WillChangeVisibilityState(shelf_layout_manager_->visibility_state());
126 shelf_layout_manager_->AddObserver(this);
127 }
128 }
129
130 void DockLayoutManager::ToggleMinimize(aura::Window* window) {
131 DCHECK(window->parent() == dock_container_);
132 if (window->GetProperty(aura::client::kShowStateKey) ==
sky 2013/06/11 00:03:13 Why is there here (and apparently in PanelLayoutMa
varkha 2013/06/11 02:34:24 I don't think this is doing anything useful at the
133 ui::SHOW_STATE_MINIMIZED) {
134 window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
sky 2013/06/11 00:03:13 What if the window was maximized?
varkha 2013/06/11 02:34:24 Removed.
135 } else {
136 window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
137 }
138 }
139
140 ////////////////////////////////////////////////////////////////////////////////
141 // DockLayoutManager, aura::LayoutManager implementation:
142 void DockLayoutManager::OnWindowResized() {
143 Relayout();
144 }
145
146 void DockLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
147 if (!IsWindowDocked(child))
148 return;
149
150 child->AddObserver(this);
151 Relayout();
152 }
153
154 void DockLayoutManager::OnWillRemoveWindowFromLayout(aura::Window* child) {
155 }
156
157 void DockLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {
158 if (!child->HasObserver(this))
159 return;
sky 2013/06/11 00:03:13 nit: spacing
varkha 2013/06/11 02:34:24 Done.
160
161 child->RemoveObserver(this);
162 SetDockEdge(child, DOCK_EDGE_NONE);
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);
sky 2013/06/11 00:03:13 Does this need to undock?
varkha 2013/06/11 02:34:24 I don't think so. The behavior we are trying to ge
sky 2013/06/11 16:15:26 Fair enough. It would be clearer if you had a comm
varkha 2013/06/12 04:52:13 Added comment. This gets called for resizes and mo
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 != aura::client::kShowStateKey)
215 return;
216 // The window property will still be set, but no actual change will occur
217 // until WillChangeVisibilityState is called when the shelf is visible again
218 if (shelf_hidden_)
219 return;
220 ui::WindowShowState new_state =
221 window->GetProperty(aura::client::kShowStateKey);
222 if (new_state == ui::SHOW_STATE_MINIMIZED)
223 MinimizeWindow(window);
224 else
225 RestoreWindow(window);
226 }
227
228 void DockLayoutManager::OnWindowVisibilityChanged(aura::Window* window,
229 bool visible) {
230 if (visible)
231 window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
232 }
233
234 ////////////////////////////////////////////////////////////////////////////////
235 // DockLayoutManager, aura::client::ActivationChangeObserver implementation:
236
237 void DockLayoutManager::OnWindowActivated(aura::Window* gained_active,
238 aura::Window* lost_active) {
239 // Ignore if the window that is not managed by this was activated.
240 if (gained_active && gained_active->parent() == dock_container_)
241 UpdateStacking(gained_active);
242 }
243
244 ////////////////////////////////////////////////////////////////////////////////
245 // DockLayoutManager, ShelfLayoutManagerObserver implementation:
246
247 void DockLayoutManager::WillChangeVisibilityState(
248 ShelfVisibilityState new_state) {
249 // On entering / leaving full screen mode the shelf visibility state is
250 // changed to / from SHELF_HIDDEN. In this state, docked windows should hide
251 // to allow the full-screen application to use the full screen.
252
253 // TODO(varkha): ShelfLayoutManager::UpdateVisibilityState sets state to
254 // SHELF_AUTO_HIDE when in immersive mode. We need to distinguish this from
255 // when shelf enters auto-hide state based on mouse hover when auto-hide
256 // setting is enabled and hide all windows (immersive mode should hide dock).
257 shelf_hidden_ = new_state == ash::SHELF_HIDDEN;
258 for (size_t i = 0; i < dock_container_->children().size(); ++i) {
259 aura::Window* window = dock_container_->children()[i];
260 if (shelf_hidden_) {
261 if (window->IsVisible())
262 MinimizeWindow(window);
263 } else {
264 if (window->GetProperty(aura::client::kShowStateKey) !=
265 ui::SHOW_STATE_MINIMIZED) {
266 RestoreWindow(window);
267 }
268 }
269 }
270 }
271
272 ////////////////////////////////////////////////////////////////////////////////
273 // DockLayoutManager private implementation:
274
275 void DockLayoutManager::MinimizeWindow(aura::Window* window) {
276 window->Hide();
277 if (wm::IsActiveWindow(window))
278 wm::DeactivateWindow(window);
279 Relayout();
280 }
281
282 void DockLayoutManager::RestoreWindow(aura::Window* window) {
283 window->Show();
284 Relayout();
285 }
286
287 void DockLayoutManager::Relayout() {
288 if (in_layout_)
289 return;
290 base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true);
291
292 if (dock_container_->children().empty()) {
293 alignment_ = DOCK_ALIGNMENT_NONE;
294 return;
295 }
296
297 gfx::Rect dock_bounds = dock_container_->bounds();
298 aura::Window* active_window = NULL;
299 std::vector<aura::Window*> visible_windows;
300 alignment_ = GetDockEdge(dock_container_->children()[0]) == DOCK_EDGE_LEFT ?
sky 2013/06/11 00:03:13 How come you need to cache the edge per window? Is
varkha 2013/06/11 02:34:24 We had this discussion so it is not unexpected. I
sky 2013/06/11 16:15:26 More properties typically means more things to get
varkha 2013/06/12 04:52:13 That actually forced me to simplify code quite a b
301 DOCK_ALIGNMENT_LEFT : DOCK_ALIGNMENT_RIGHT;
302 for (size_t i = 0; i < dock_container_->children().size(); ++i) {
303 aura::Window* window(dock_container_->children()[i]);
304
305 if (!window->IsVisible() ||
306 window->GetProperty(aura::client::kShowStateKey) ==
307 ui::SHOW_STATE_MINIMIZED) {
308 continue;
309 }
310
311 // If the shelf is currently hidden (full-screen mode), hide window until
312 // full-screen mode is exited.
313 if (shelf_hidden_) {
314 // The call to Hide does not set the minimize property, so the window will
315 // be restored when the shelf becomes visible again.
316 window->Hide();
317 continue;
318 }
319
320 if (window->HasFocus() ||
321 window->Contains(
322 aura::client::GetFocusClient(window)->GetFocusedWindow())) {
323 DCHECK(!active_window);
324 active_window = window;
325 }
326
327 gfx::Rect bounds = window->GetTargetBounds();
328 switch (alignment_) {
329 case DOCK_ALIGNMENT_LEFT:
330 if (window != dragged_window_ ||
331 abs(bounds.x() - dock_bounds.x()) < kMagnetismWidth) {
332 bounds.set_x(0);
333 }
334 break;
335 case DOCK_ALIGNMENT_RIGHT:
336 if (window != dragged_window_ ||
337 abs(dock_bounds.right() - bounds.right()) < kMagnetismWidth) {
338 bounds.set_x(dock_bounds.right() - bounds.width());
339 }
340 break;
341 case DOCK_ALIGNMENT_NONE:
342 NOTREACHED() << "Relayout called when dock alignment is 'NONE'";
343 break;
344 }
345 SetChildBoundsDirect(window, bounds);
346 }
347
348 UpdateStacking(active_window);
349 }
350
351 void DockLayoutManager::UpdateStacking(aura::Window* active_window) {
352 // TODO(varkha): Implement restacking to ensure that all docked windows are at
353 // least partially visible and selectable.
354 }
355
356 ////////////////////////////////////////////////////////////////////////////////
357 // keyboard::KeyboardControllerObserver implementation:
358
359 void DockLayoutManager::OnKeyboardBoundsChanging(
360 const gfx::Rect& keyboard_bounds) {
361 // This bounds change will have caused a change to the Shelf which does not
362 // propagate automatically to this class, so manually recalculate bounds.
363 OnWindowResized();
364 }
365
366 } // namespace internal
367 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698