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

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 (small fix for shelf auto-hide) 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_DockedContainer);
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_(DOCKED_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 launcher_ = NULL;
60 for (size_t i = 0; i < dock_container_->children().size(); ++i)
61 dock_container_->children()[i]->RemoveObserver(this);
62 if (shelf_layout_manager_)
63 shelf_layout_manager_->RemoveObserver(this);
64 aura::client::GetActivationClient(Shell::GetPrimaryRootWindow())->
65 RemoveObserver(this);
66 Shell::GetInstance()->RemoveShellObserver(this);
67 }
68
69 void DockedWindowLayoutManager::StartDragging(aura::Window* window) {
70 if (window->parent() != dock_container_)
71 return;
72 DCHECK(!dragged_window_);
73 dragged_window_ = window;
74 Relayout();
75 }
76
77 void DockedWindowLayoutManager::FinishDragging() {
78 dragged_window_ = NULL;
79 Relayout();
80 }
81
82 // static
83 bool DockedWindowLayoutManager::ShouldWindowDock(aura::Window* window,
84 const gfx::Point& location) {
85 DockedWindowLayoutManager* layout_manager = GetDockLayoutManager(window,
86 location);
87 const gfx::Rect& bounds(window->GetBoundsInScreen());
88 gfx::Rect dock_bounds = layout_manager->dock_container_->GetBoundsInScreen();
89 // Possible sides of the screen that a window can be touching.
90 enum DockedEdge {
91 DOCKED_EDGE_NONE,
92 DOCKED_EDGE_LEFT,
93 DOCKED_EDGE_RIGHT,
94 } dock_edge = DOCKED_EDGE_NONE;
95 if (bounds.x() == dock_bounds.x() &&
96 layout_manager->alignment_ != DOCKED_ALIGNMENT_RIGHT) {
97 dock_edge = DOCKED_EDGE_LEFT;
98 } else if (bounds.right() == dock_bounds.right() &&
99 layout_manager->alignment_ != DOCKED_ALIGNMENT_LEFT) {
100 dock_edge = DOCKED_EDGE_RIGHT;
101 }
102
103 // do not allow dock on the same side as launcher shelf
104 if (layout_manager->launcher_ && layout_manager->launcher_->shelf_widget()) {
105 ShelfAlignment shelf_alignment =
106 layout_manager->launcher_->shelf_widget()->GetAlignment();
107 if ((shelf_alignment == SHELF_ALIGNMENT_LEFT &&
108 dock_edge == DOCKED_EDGE_LEFT) ||
109 (shelf_alignment == SHELF_ALIGNMENT_RIGHT &&
110 dock_edge == DOCKED_EDGE_RIGHT)) {
111 dock_edge = DOCKED_EDGE_NONE;
112 }
113 }
114 return dock_edge != DOCKED_EDGE_NONE;
115 }
116
117 void DockedWindowLayoutManager::SetLauncher(ash::Launcher* launcher) {
118 DCHECK(!launcher_);
119 DCHECK(!shelf_layout_manager_);
120 launcher_ = launcher;
121 if (launcher_->shelf_widget()) {
122 shelf_layout_manager_ = ash::internal::ShelfLayoutManager::ForLauncher(
123 launcher_->shelf_widget()->GetNativeWindow());
124 WillChangeVisibilityState(shelf_layout_manager_->visibility_state());
125 shelf_layout_manager_->AddObserver(this);
126 }
127 }
128
129 ////////////////////////////////////////////////////////////////////////////////
130 // DockLayoutManager, aura::LayoutManager implementation:
131 void DockedWindowLayoutManager::OnWindowResized() {
132 Relayout();
133 }
134
135 void DockedWindowLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
136 child->AddObserver(this);
137 Relayout();
138 }
139
140 void DockedWindowLayoutManager::OnWillRemoveWindowFromLayout(
141 aura::Window* child) {
142 }
143
144 void DockedWindowLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {
145 child->RemoveObserver(this);
146 Relayout();
147 }
148
149 void DockedWindowLayoutManager::OnChildWindowVisibilityChanged(
150 aura::Window* child,
151 bool visible) {
152 if (visible)
153 child->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
154 Relayout();
155 }
156
157 void DockedWindowLayoutManager::SetChildBounds(
158 aura::Window* child,
159 const gfx::Rect& requested_bounds) {
160 // Whenever one of our windows is moved or resized we need to enforce layout.
161 SetChildBoundsDirect(child, requested_bounds);
162 Relayout();
163 }
164
165 ////////////////////////////////////////////////////////////////////////////////
166 // DockLayoutManager, ash::ShellObserver implementation:
167
168 void DockedWindowLayoutManager::OnShelfAlignmentChanged(
169 aura::RootWindow* root_window) {
170 if (dock_container_->GetRootWindow() != root_window)
171 return;
172
173 if (!launcher_ || !launcher_->shelf_widget())
174 return;
175
176 if (alignment_ == DOCKED_ALIGNMENT_NONE)
177 return;
178
179 // It should not be possible to have empty children() while alignment is set
180 // to anything other than DOCKED_ALIGNMENT_NONE - see Relayout.
181 DCHECK(!dock_container_->children().empty());
182 if (dock_container_->children().empty())
183 return;
stevenjb 2013/06/13 17:54:41 Since we handle the error condition, we should use
varkha 2013/06/13 20:19:14 Done.
184 aura::Window* window = dock_container_->children()[0];
185 const gfx::Rect& dock_bounds = dock_container_->bounds();
186 gfx::Rect bounds = window->bounds();
187
188 // Do not allow launcher and dock on the same side. Switch side that
189 // the dock is attached to and move all dock windows to that new side.
190 // We actually only need to move the first window and the rest will follow
191 // in Relayout
192 ShelfAlignment shelf_alignment =
193 launcher_->shelf_widget()->GetAlignment();
194 if (alignment_ == DOCKED_ALIGNMENT_LEFT &&
195 shelf_alignment == SHELF_ALIGNMENT_LEFT) {
196 bounds.set_x(dock_bounds.right() - bounds.width());
197 SetChildBoundsDirect(window, bounds);
198 } else if (alignment_ == DOCKED_ALIGNMENT_RIGHT &&
199 shelf_alignment == SHELF_ALIGNMENT_RIGHT) {
200 bounds.set_x(0);
201 SetChildBoundsDirect(window, bounds);
202 }
203 Relayout();
204 }
205
206 /////////////////////////////////////////////////////////////////////////////
207 // DockLayoutManager, WindowObserver implementation:
208
209 void DockedWindowLayoutManager::OnWindowPropertyChanged(aura::Window* window,
210 const void* key,
211 intptr_t old) {
212 if (key != aura::client::kShowStateKey)
213 return;
214 // The window property will still be set, but no actual change will occur
215 // until WillChangeVisibilityState is called when the shelf is visible again
216 if (shelf_hidden_)
217 return;
218 if (wm::IsWindowMinimized(window))
219 MinimizeWindow(window);
220 else
221 RestoreWindow(window);
222 }
223
224 ////////////////////////////////////////////////////////////////////////////////
225 // DockLayoutManager, aura::client::ActivationChangeObserver implementation:
226
227 void DockedWindowLayoutManager::OnWindowActivated(aura::Window* gained_active,
228 aura::Window* lost_active) {
229 // Ignore if the window that is not managed by this was activated.
230 aura::Window* ancestor = NULL;
231 for (aura::Window* parent = gained_active;
232 parent; parent = parent->parent()) {
233 if (parent->parent() == dock_container_) {
234 ancestor = parent;
235 break;
236 }
237 }
238 if (ancestor)
239 UpdateStacking(ancestor);
240 }
241
242 ////////////////////////////////////////////////////////////////////////////////
243 // DockLayoutManager, ShelfLayoutManagerObserver implementation:
244
245 void DockedWindowLayoutManager::WillChangeVisibilityState(
246 ShelfVisibilityState new_state) {
247 // On entering / leaving full screen mode the shelf visibility state is
248 // changed to / from SHELF_HIDDEN. In this state, docked windows should hide
249 // to allow the full-screen application to use the full screen.
250
251 // TODO(varkha): ShelfLayoutManager::UpdateVisibilityState sets state to
252 // SHELF_AUTO_HIDE when in immersive mode. We need to distinguish this from
253 // when shelf enters auto-hide state based on mouse hover when auto-hide
254 // setting is enabled and hide all windows (immersive mode should hide docked
255 // windows).
256 shelf_hidden_ =
257 new_state == ash::SHELF_HIDDEN;
sky 2013/06/13 15:36:45 nit: no need to wrap here.
varkha 2013/06/13 20:19:14 Done.
258 {
259 // prevent Relayout from getting called multiple times during this
260 base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true);
261 for (size_t i = 0; i < dock_container_->children().size(); ++i) {
262 aura::Window* window = dock_container_->children()[i];
263 if (shelf_hidden_) {
264 if (window->IsVisible())
265 MinimizeWindow(window);
266 } else {
267 if (!wm::IsWindowMinimized(window))
268 RestoreWindow(window);
269 }
270 }
271 }
272 Relayout();
273 }
274
275 ////////////////////////////////////////////////////////////////////////////////
276 // DockLayoutManager private implementation:
277
278 void DockedWindowLayoutManager::MinimizeWindow(aura::Window* window) {
279 window->Hide();
280 if (wm::IsActiveWindow(window))
281 wm::DeactivateWindow(window);
282 }
283
284 void DockedWindowLayoutManager::RestoreWindow(aura::Window* window) {
285 window->Show();
286 }
287
288 void DockedWindowLayoutManager::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_ = DOCKED_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_ = DOCKED_ALIGNMENT_ANY;
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() || wm::IsWindowMinimized(window)) {
306 continue;
307 }
stevenjb 2013/06/13 17:54:41 nit: don't need {}
varkha 2013/06/13 20:19:14 Done.
308
309 // If the shelf is currently hidden (full-screen mode), hide window until
310 // full-screen mode is exited.
311 if (shelf_hidden_) {
312 // The call to Hide does not set the minimize property, so the window will
313 // be restored when the shelf becomes visible again.
314 window->Hide();
315 continue;
316 }
317
318 gfx::Rect bounds = window->GetTargetBounds();
319 if (window != dragged_window_ && alignment_ == DOCKED_ALIGNMENT_ANY) {
320 if (bounds.x() == 0)
321 alignment_ = DOCKED_ALIGNMENT_LEFT;
322 else if (bounds.right() == dock_bounds.right())
323 alignment_ = DOCKED_ALIGNMENT_RIGHT;
324 }
325
326 if (window->HasFocus() ||
327 window->Contains(
328 aura::client::GetFocusClient(window)->GetFocusedWindow())) {
329 DCHECK(!active_window);
330 active_window = window;
331 }
332
333 // all docked windows remain stuck to the screen edge
334 if (window != dragged_window_) {
335 switch (alignment_) {
336 case DOCKED_ALIGNMENT_LEFT:
337 bounds.set_x(0);
338 break;
339 case DOCKED_ALIGNMENT_RIGHT:
340 case DOCKED_ALIGNMENT_ANY:
341 bounds.set_x(dock_bounds.right() - bounds.width());
342 break;
343 case DOCKED_ALIGNMENT_NONE:
344 NOTREACHED() << "Relayout called when dock alignment is 'NONE'";
345 break;
346 }
347 }
348 SetChildBoundsDirect(window, bounds);
349 }
350
351 UpdateStacking(active_window);
352 }
353
354 void DockedWindowLayoutManager::UpdateStacking(aura::Window* active_window) {
355 // TODO(varkha): Implement restacking to ensure that all docked windows are at
356 // least partially visible and selectable.
357 }
358
359 ////////////////////////////////////////////////////////////////////////////////
360 // keyboard::KeyboardControllerObserver implementation:
361
362 void DockedWindowLayoutManager::OnKeyboardBoundsChanging(
363 const gfx::Rect& keyboard_bounds) {
364 // This bounds change will have caused a change to the Shelf which does not
365 // propagate automatically to this class, so manually recalculate bounds.
366 OnWindowResized();
367 }
368
369 } // namespace internal
370 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698