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

Side by Side Diff: ash/wm/dock/docked_window_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 (some tests disabled on Windows) 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) 2013 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/docked_window_layout_manager.h"
6
7 #include "ash/launcher/launcher.h"
8 #include "ash/screen_ash.h"
9 #include "ash/shelf/shelf_layout_manager.h"
10 #include "ash/shelf/shelf_types.h"
11 #include "ash/shelf/shelf_widget.h"
12 #include "ash/shell.h"
13 #include "ash/shell_window_ids.h"
14 #include "ash/wm/coordinate_conversion.h"
15 #include "ash/wm/window_util.h"
16 #include "base/auto_reset.h"
17 #include "ui/aura/client/activation_client.h"
18 #include "ui/aura/client/aura_constants.h"
19 #include "ui/aura/focus_manager.h"
20 #include "ui/aura/root_window.h"
21 #include "ui/aura/window.h"
22 #include "ui/gfx/rect.h"
23
24 namespace ash {
25 namespace internal {
26
27 namespace {
28
29 DockedWindowLayoutManager* GetDockLayoutManager(aura::Window* window,
30 const gfx::Point& location) {
31 gfx::Rect near_location(location, gfx::Size());
32 aura::Window* dock = Shell::GetContainer(
33 wm::GetRootWindowMatching(near_location),
34 kShellWindowId_DockContainer);
35 return static_cast<internal::DockedWindowLayoutManager*>(
36 dock->layout_manager());
37 }
38
39 } // namespace
40
41 ////////////////////////////////////////////////////////////////////////////////
42 // DockLayoutManager public implementation:
43 DockedWindowLayoutManager::DockedWindowLayoutManager(
44 aura::Window* dock_container)
45 : dock_container_(dock_container),
46 in_layout_(false),
47 dragged_window_(NULL),
48 launcher_(NULL),
49 shelf_layout_manager_(NULL),
50 shelf_hidden_(false),
51 alignment_(DOCK_ALIGNMENT_NONE) {
52 DCHECK(dock_container);
53 aura::client::GetActivationClient(Shell::GetPrimaryRootWindow())->
54 AddObserver(this);
55 Shell::GetInstance()->AddShellObserver(this);
56 }
57
58 DockedWindowLayoutManager::~DockedWindowLayoutManager() {
59 Shutdown();
60 }
61
62 void DockedWindowLayoutManager::Shutdown() {
63 launcher_ = NULL;
64 if (shelf_layout_manager_)
65 shelf_layout_manager_->RemoveObserver(this);
66 aura::client::GetActivationClient(Shell::GetPrimaryRootWindow())->
67 RemoveObserver(this);
68 Shell::GetInstance()->RemoveShellObserver(this);
69 }
sky 2013/06/12 21:50:17 Remove observer on all child windows.
varkha 2013/06/13 05:02:11 Done.
70
71 void DockedWindowLayoutManager::StartDragging(aura::Window* window) {
72 if (window->parent() != dock_container_)
73 return;
74 DCHECK(!dragged_window_);
75 dragged_window_ = window;
76 Relayout();
77 }
78
79 void DockedWindowLayoutManager::FinishDragging() {
80 dragged_window_ = NULL;
81 Relayout();
82 }
83
84 // static
85 bool DockedWindowLayoutManager::ShouldWindowDock(aura::Window* window,
86 const gfx::Point& location) {
87 DockedWindowLayoutManager* layout_manager = GetDockLayoutManager(window,
88 location);
89 const gfx::Rect& bounds(window->GetBoundsInScreen());
90 gfx::Rect dock_bounds = layout_manager->dock_container_->GetBoundsInScreen();
91 // Possible sides of the screen that a window can be touching.
92 enum DockedEdge {
93 DOCKED_EDGE_NONE,
94 DOCKED_EDGE_LEFT,
95 DOCKED_EDGE_RIGHT,
96 } dock_edge = DOCKED_EDGE_NONE;
97 if (bounds.x() == dock_bounds.x() &&
98 layout_manager->alignment_ != DOCK_ALIGNMENT_RIGHT) {
99 dock_edge = DOCKED_EDGE_LEFT;
100 } else if (bounds.right() == dock_bounds.right() &&
101 layout_manager->alignment_ != DOCK_ALIGNMENT_LEFT) {
102 dock_edge = DOCKED_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 == DOCKED_EDGE_LEFT) ||
111 (shelf_alignment == SHELF_ALIGNMENT_RIGHT &&
112 dock_edge == DOCKED_EDGE_RIGHT)) {
113 dock_edge = DOCKED_EDGE_NONE;
114 }
115 }
116 return dock_edge != DOCKED_EDGE_NONE;
117 }
118
119 void DockedWindowLayoutManager::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 ////////////////////////////////////////////////////////////////////////////////
132 // DockLayoutManager, aura::LayoutManager implementation:
133 void DockedWindowLayoutManager::OnWindowResized() {
134 Relayout();
135 }
136
137 void DockedWindowLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
138 child->AddObserver(this);
139 Relayout();
140 }
141
142 void DockedWindowLayoutManager::OnWillRemoveWindowFromLayout(
143 aura::Window* child) {
144 }
145
146 void DockedWindowLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {
147 child->RemoveObserver(this);
148 Relayout();
149 }
150
151 void DockedWindowLayoutManager::OnChildWindowVisibilityChanged(
152 aura::Window* child, bool visible) {
153 Relayout();
154 }
155
156 void DockedWindowLayoutManager::SetChildBounds(
157 aura::Window* child, const gfx::Rect& requested_bounds) {
sky 2013/06/12 21:50:17 nit: when you wrap, one param per line.
varkha 2013/06/13 05:02:11 Done (here and above).
158 // Whenever one of our windows is moved or resized we need to enforce layout.
159 SetChildBoundsDirect(child, requested_bounds);
160 Relayout();
161 }
162
163 ////////////////////////////////////////////////////////////////////////////////
164 // DockLayoutManager, ash::ShellObserver implementation:
165
166 void DockedWindowLayoutManager::OnShelfAlignmentChanged(
167 aura::RootWindow* root_window) {
168 if (dock_container_->GetRootWindow() != root_window)
169 return;
170
171 if (!launcher_ || !launcher_->shelf_widget())
172 return;
173
174 if (alignment_ == DOCK_ALIGNMENT_NONE)
175 return;
176
177 DCHECK(!dock_container_->children().empty());
sky 2013/06/12 21:50:17 How come this is a DCHECK? How do you know there i
varkha 2013/06/13 05:02:11 My logic was that since the only assignments of an
178 aura::Window* window = dock_container_->children()[0];
179 gfx::Rect dock_bounds = dock_container_->bounds();
sky 2013/06/12 21:50:17 const gfx::Rect&
varkha 2013/06/13 05:02:11 Done.
180 gfx::Rect bounds = window->bounds();
181
182 // Do not allow launcher and dock on the same side. Switch side that
183 // the dock is attached to and move all dock windows to that new side.
184 // We actually only need to move the first window and the rest will follow
185 // in Relayout
186 ShelfAlignment shelf_alignment =
187 launcher_->shelf_widget()->GetAlignment();
188 if (alignment_ == DOCK_ALIGNMENT_LEFT &&
189 shelf_alignment == SHELF_ALIGNMENT_LEFT) {
190 bounds.set_x(dock_bounds.right() - bounds.width());
191 SetChildBoundsDirect(window, bounds);
192 } else if (alignment_ == DOCK_ALIGNMENT_RIGHT &&
193 shelf_alignment == SHELF_ALIGNMENT_RIGHT) {
194 bounds.set_x(0);
195 SetChildBoundsDirect(window, bounds);
196 }
197 Relayout();
198 }
199
200 /////////////////////////////////////////////////////////////////////////////
201 // DockLayoutManager, WindowObserver implementation:
202
203 void DockedWindowLayoutManager::OnWindowPropertyChanged(aura::Window* window,
204 const void* key,
205 intptr_t old) {
206 if (key != aura::client::kShowStateKey)
207 return;
208 // The window property will still be set, but no actual change will occur
209 // until WillChangeVisibilityState is called when the shelf is visible again
210 if (shelf_hidden_)
211 return;
212 ui::WindowShowState new_state =
213 window->GetProperty(aura::client::kShowStateKey);
214 if (new_state == ui::SHOW_STATE_MINIMIZED)
215 MinimizeWindow(window);
216 else
217 RestoreWindow(window);
218 }
219
220 void DockedWindowLayoutManager::OnWindowVisibilityChanged(
221 aura::Window* window, bool visible) {
sky 2013/06/12 21:50:17 nit: one param per line.
varkha 2013/06/13 05:02:11 Done.
222 if (visible)
223 window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
224 }
225
226 ////////////////////////////////////////////////////////////////////////////////
227 // DockLayoutManager, aura::client::ActivationChangeObserver implementation:
228
229 void DockedWindowLayoutManager::OnWindowActivated(aura::Window* gained_active,
230 aura::Window* lost_active) {
sky 2013/06/12 21:50:17 nit: indentation is off.
varkha 2013/06/13 05:02:11 Done.
231 // Ignore if the window that is not managed by this was activated.
232 if (gained_active && gained_active->parent() == dock_container_)
sky 2013/06/12 21:50:17 Seems like this should be an ancestor check. That
varkha 2013/06/13 05:02:11 Done.
233 UpdateStacking(gained_active);
234 }
235
236 ////////////////////////////////////////////////////////////////////////////////
237 // DockLayoutManager, ShelfLayoutManagerObserver implementation:
238
239 void DockedWindowLayoutManager::WillChangeVisibilityState(
240 ShelfVisibilityState new_state) {
241 // On entering / leaving full screen mode the shelf visibility state is
242 // changed to / from SHELF_HIDDEN. In this state, docked windows should hide
243 // to allow the full-screen application to use the full screen.
244
245 // TODO(varkha): ShelfLayoutManager::UpdateVisibilityState sets state to
246 // SHELF_AUTO_HIDE when in immersive mode. We need to distinguish this from
247 // when shelf enters auto-hide state based on mouse hover when auto-hide
248 // setting is enabled and hide all windows (immersive mode should hide dock).
249 shelf_hidden_ = new_state == ash::SHELF_HIDDEN;
250 for (size_t i = 0; i < dock_container_->children().size(); ++i) {
sky 2013/06/12 21:50:17 Might this end up doing n Relayouts (n=number of c
varkha 2013/06/13 05:02:11 More like 3xN because of upstream and downstream v
251 aura::Window* window = dock_container_->children()[i];
252 if (shelf_hidden_) {
253 if (window->IsVisible())
254 MinimizeWindow(window);
255 } else {
256 if (window->GetProperty(aura::client::kShowStateKey) !=
257 ui::SHOW_STATE_MINIMIZED) {
258 RestoreWindow(window);
259 }
260 }
261 }
262 }
263
264 ////////////////////////////////////////////////////////////////////////////////
265 // DockLayoutManager private implementation:
266
267 void DockedWindowLayoutManager::MinimizeWindow(aura::Window* window) {
268 window->Hide();
269 if (wm::IsActiveWindow(window))
270 wm::DeactivateWindow(window);
271 Relayout();
272 }
273
274 void DockedWindowLayoutManager::RestoreWindow(aura::Window* window) {
275 window->Show();
276 Relayout();
277 }
278
279 void DockedWindowLayoutManager::Relayout() {
280 if (in_layout_)
281 return;
282 base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true);
283
284 if (dock_container_->children().empty()) {
285 alignment_ = DOCK_ALIGNMENT_NONE;
286 return;
287 }
288
289 gfx::Rect dock_bounds = dock_container_->bounds();
290 aura::Window* active_window = NULL;
291 std::vector<aura::Window*> visible_windows;
292 alignment_ = DOCK_ALIGNMENT_ANY;
293 for (size_t i = 0; i < dock_container_->children().size(); ++i) {
294 aura::Window* window(dock_container_->children()[i]);
295
296 if (!window->IsVisible() ||
297 window->GetProperty(aura::client::kShowStateKey) ==
298 ui::SHOW_STATE_MINIMIZED) {
299 continue;
300 }
301
302 // If the shelf is currently hidden (full-screen mode), hide window until
303 // full-screen mode is exited.
304 if (shelf_hidden_) {
305 // The call to Hide does not set the minimize property, so the window will
306 // be restored when the shelf becomes visible again.
307 window->Hide();
308 continue;
309 }
310
311 gfx::Rect bounds = window->GetTargetBounds();
312 if (window != dragged_window_ && alignment_ == DOCK_ALIGNMENT_ANY) {
313 if (bounds.x() == 0)
314 alignment_ = DOCK_ALIGNMENT_LEFT;
315 else if (bounds.right() == dock_bounds.right())
316 alignment_ = DOCK_ALIGNMENT_RIGHT;
317 }
318
319 if (window->HasFocus() ||
320 window->Contains(
321 aura::client::GetFocusClient(window)->GetFocusedWindow())) {
322 DCHECK(!active_window);
323 active_window = window;
324 }
325
326 // all docked windows remain stuck to the screen edge
327 if (window != dragged_window_) {
328 switch (alignment_) {
329 case DOCK_ALIGNMENT_LEFT:
330 bounds.set_x(0);
331 break;
332 case DOCK_ALIGNMENT_RIGHT:
333 case DOCK_ALIGNMENT_ANY:
334 bounds.set_x(dock_bounds.right() - bounds.width());
335 break;
336 case DOCK_ALIGNMENT_NONE:
337 NOTREACHED() << "Relayout called when dock alignment is 'NONE'";
338 break;
339 }
340 }
341 SetChildBoundsDirect(window, bounds);
342 }
343
344 UpdateStacking(active_window);
345 }
346
347 void DockedWindowLayoutManager::UpdateStacking(aura::Window* active_window) {
348 // TODO(varkha): Implement restacking to ensure that all docked windows are at
349 // least partially visible and selectable.
350 }
351
352 ////////////////////////////////////////////////////////////////////////////////
353 // keyboard::KeyboardControllerObserver implementation:
354
355 void DockedWindowLayoutManager::OnKeyboardBoundsChanging(
356 const gfx::Rect& keyboard_bounds) {
357 // This bounds change will have caused a change to the Shelf which does not
358 // propagate automatically to this class, so manually recalculate bounds.
359 OnWindowResized();
360 }
361
362 } // namespace internal
363 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698