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

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 (rebase) 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 if (dock_container_->children().empty()) {
182 LOG(ERROR) << "No children and alignment set to " << alignment_;
183 return;
184 }
185 aura::Window* window = dock_container_->children()[0];
186 const gfx::Rect& dock_bounds = dock_container_->bounds();
187 gfx::Rect bounds = window->bounds();
188
189 // Do not allow launcher and dock on the same side. Switch side that
190 // the dock is attached to and move all dock windows to that new side.
191 // We actually only need to move the first window and the rest will follow
192 // in Relayout
193 ShelfAlignment shelf_alignment =
194 launcher_->shelf_widget()->GetAlignment();
195 if (alignment_ == DOCKED_ALIGNMENT_LEFT &&
196 shelf_alignment == SHELF_ALIGNMENT_LEFT) {
197 bounds.set_x(dock_bounds.right() - bounds.width());
198 SetChildBoundsDirect(window, bounds);
199 } else if (alignment_ == DOCKED_ALIGNMENT_RIGHT &&
200 shelf_alignment == SHELF_ALIGNMENT_RIGHT) {
201 bounds.set_x(0);
202 SetChildBoundsDirect(window, bounds);
203 }
204 Relayout();
205 }
206
207 /////////////////////////////////////////////////////////////////////////////
208 // DockLayoutManager, WindowObserver implementation:
209
210 void DockedWindowLayoutManager::OnWindowPropertyChanged(aura::Window* window,
211 const void* key,
212 intptr_t old) {
213 if (key != aura::client::kShowStateKey)
214 return;
215 // The window property will still be set, but no actual change will occur
216 // until WillChangeVisibilityState is called when the shelf is visible again
217 if (shelf_hidden_)
218 return;
219 if (wm::IsWindowMinimized(window))
220 MinimizeWindow(window);
221 else
222 RestoreWindow(window);
223 }
224
225 ////////////////////////////////////////////////////////////////////////////////
226 // DockLayoutManager, aura::client::ActivationChangeObserver implementation:
227
228 void DockedWindowLayoutManager::OnWindowActivated(aura::Window* gained_active,
229 aura::Window* lost_active) {
230 // Ignore if the window that is not managed by this was activated.
231 aura::Window* ancestor = NULL;
232 for (aura::Window* parent = gained_active;
233 parent; parent = parent->parent()) {
234 if (parent->parent() == dock_container_) {
235 ancestor = parent;
236 break;
237 }
238 }
239 if (ancestor)
240 UpdateStacking(ancestor);
241 }
242
243 ////////////////////////////////////////////////////////////////////////////////
244 // DockLayoutManager, ShelfLayoutManagerObserver implementation:
245
246 void DockedWindowLayoutManager::WillChangeVisibilityState(
247 ShelfVisibilityState new_state) {
248 // On entering / leaving full screen mode the shelf visibility state is
249 // changed to / from SHELF_HIDDEN. In this state, docked windows should hide
250 // to allow the full-screen application to use the full screen.
251
252 // TODO(varkha): ShelfLayoutManager::UpdateVisibilityState sets state to
253 // SHELF_AUTO_HIDE when in immersive mode. We need to distinguish this from
254 // when shelf enters auto-hide state based on mouse hover when auto-hide
255 // setting is enabled and hide all windows (immersive mode should hide docked
256 // windows).
257 shelf_hidden_ = new_state == ash::SHELF_HIDDEN;
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
308 // If the shelf is currently hidden (full-screen mode), hide window until
309 // full-screen mode is exited.
310 if (shelf_hidden_) {
311 // The call to Hide does not set the minimize property, so the window will
312 // be restored when the shelf becomes visible again.
313 window->Hide();
314 continue;
315 }
316
317 gfx::Rect bounds = window->GetTargetBounds();
318 if (window != dragged_window_ && alignment_ == DOCKED_ALIGNMENT_ANY) {
319 if (bounds.x() == 0)
320 alignment_ = DOCKED_ALIGNMENT_LEFT;
321 else if (bounds.right() == dock_bounds.right())
322 alignment_ = DOCKED_ALIGNMENT_RIGHT;
323 }
324
325 if (window->HasFocus() ||
326 window->Contains(
327 aura::client::GetFocusClient(window)->GetFocusedWindow())) {
328 DCHECK(!active_window);
329 active_window = window;
330 }
331
332 // all docked windows remain stuck to the screen edge
333 if (window != dragged_window_) {
334 switch (alignment_) {
335 case DOCKED_ALIGNMENT_LEFT:
336 bounds.set_x(0);
337 break;
338 case DOCKED_ALIGNMENT_RIGHT:
339 case DOCKED_ALIGNMENT_ANY:
340 bounds.set_x(dock_bounds.right() - bounds.width());
341 break;
342 case DOCKED_ALIGNMENT_NONE:
343 NOTREACHED() << "Relayout called when dock alignment is 'NONE'";
344 break;
345 }
346 }
347 SetChildBoundsDirect(window, bounds);
348 }
349
350 UpdateStacking(active_window);
351 }
352
353 void DockedWindowLayoutManager::UpdateStacking(aura::Window* active_window) {
354 // TODO(varkha): Implement restacking to ensure that all docked windows are at
355 // least partially visible and selectable.
356 }
357
358 ////////////////////////////////////////////////////////////////////////////////
359 // keyboard::KeyboardControllerObserver implementation:
360
361 void DockedWindowLayoutManager::OnKeyboardBoundsChanging(
362 const gfx::Rect& keyboard_bounds) {
363 // This bounds change will have caused a change to the Shelf which does not
364 // propagate automatically to this class, so manually recalculate bounds.
365 OnWindowResized();
366 }
367
368 } // namespace internal
369 } // namespace ash
OLDNEW
« no previous file with comments | « ash/wm/dock/docked_window_layout_manager.h ('k') | ash/wm/dock/docked_window_layout_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698