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

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

Powered by Google App Engine
This is Rietveld 408576698