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

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 (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) 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/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 // What it takes to undock a window
37 const int kMagnetismWidth = 32;
38
39 // Duration for window animations.
40 const int kWindowSlideDurationMilliseconds = 50;
41
42 DockedWindowLayoutManager* GetDockLayoutManager(aura::Window* window,
43 const gfx::Point& location) {
44 gfx::Rect near_location(location, gfx::Size());
45 aura::Window* dock = Shell::GetContainer(
46 wm::GetRootWindowMatching(near_location),
47 kShellWindowId_DockContainer);
48 return static_cast<internal::DockedWindowLayoutManager*>(
49 dock->layout_manager());
50 }
51
52 } // namespace
53
54 ////////////////////////////////////////////////////////////////////////////////
55 // DockLayoutManager public implementation:
56 DockedWindowLayoutManager::DockedWindowLayoutManager(
57 aura::Window* dock_container)
58 : dock_container_(dock_container),
59 in_layout_(false),
60 dragged_window_(NULL),
61 launcher_(NULL),
62 shelf_layout_manager_(NULL),
63 shelf_hidden_(false),
64 alignment_(DOCK_ALIGNMENT_NONE) {
65 DCHECK(dock_container);
66 aura::client::GetActivationClient(Shell::GetPrimaryRootWindow())->
67 AddObserver(this);
68 Shell::GetInstance()->AddShellObserver(this);
69 }
70
71 DockedWindowLayoutManager::~DockedWindowLayoutManager() {
72 Shutdown();
73 }
74
75 void DockedWindowLayoutManager::Shutdown() {
76 launcher_ = NULL;
77 if (shelf_layout_manager_)
78 shelf_layout_manager_->RemoveObserver(this);
79 aura::client::GetActivationClient(Shell::GetPrimaryRootWindow())->
80 RemoveObserver(this);
81 Shell::GetInstance()->RemoveShellObserver(this);
82 }
83
84 void DockedWindowLayoutManager::StartDragging(aura::Window* window) {
85 DCHECK(!dragged_window_);
86 dragged_window_ = window;
87 Relayout();
88 }
89
90 void DockedWindowLayoutManager::FinishDragging() {
91 dragged_window_ = NULL;
92 Relayout();
93 }
94
95 // static
96 DockedEdge DockedWindowLayoutManager::FindDockEdge(aura::Window* window,
97 const gfx::Point& location) {
98 DockedWindowLayoutManager* layout_manager = GetDockLayoutManager(window,
99 location);
100 const gfx::Rect& bounds(window->GetBoundsInScreen());
101 gfx::Rect dock_bounds = layout_manager->dock_container_->GetBoundsInScreen();
102 DockedEdge dock_edge = DOCKED_EDGE_NONE;
103 if (bounds.x() == dock_bounds.x() &&
104 layout_manager->alignment_ != DOCK_ALIGNMENT_RIGHT) {
105 dock_edge = DOCKED_EDGE_LEFT;
106 } else
107 if (bounds.right() == dock_bounds.right() &&
108 layout_manager->alignment_ != DOCK_ALIGNMENT_LEFT) {
109 dock_edge = DOCKED_EDGE_RIGHT;
110 }
111
112 // do not allow dock on the same side as launcher shelf
113 if (layout_manager->launcher_ && layout_manager->launcher_->shelf_widget()) {
114 ShelfAlignment shelf_alignment =
115 layout_manager->launcher_->shelf_widget()->GetAlignment();
116 if ((shelf_alignment == SHELF_ALIGNMENT_LEFT &&
117 dock_edge == DOCKED_EDGE_LEFT) ||
118 (shelf_alignment == SHELF_ALIGNMENT_RIGHT &&
119 dock_edge == DOCKED_EDGE_RIGHT)) {
120 dock_edge = DOCKED_EDGE_NONE;
121 }
122 }
123 return dock_edge;
124 }
125
126 void DockedWindowLayoutManager::SetLauncher(ash::Launcher* launcher) {
127 DCHECK(!launcher_);
128 DCHECK(!shelf_layout_manager_);
129 launcher_ = launcher;
130 if (launcher_->shelf_widget()) {
131 shelf_layout_manager_ = ash::internal::ShelfLayoutManager::ForLauncher(
132 launcher_->shelf_widget()->GetNativeWindow());
133 WillChangeVisibilityState(shelf_layout_manager_->visibility_state());
134 shelf_layout_manager_->AddObserver(this);
135 }
136 }
137
138 ////////////////////////////////////////////////////////////////////////////////
139 // DockLayoutManager, aura::LayoutManager implementation:
140 void DockedWindowLayoutManager::OnWindowResized() {
141 Relayout();
142 }
143
144 void DockedWindowLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
145 if (!IsWindowDocked(child))
146 return;
147
148 child->AddObserver(this);
149 Relayout();
150 }
151
152 void DockedWindowLayoutManager::OnWillRemoveWindowFromLayout(
153 aura::Window* child) {
154 }
155
156 void DockedWindowLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {
157 if (!child->HasObserver(this))
158 return;
159
160 child->RemoveObserver(this);
161 SetDockEdge(child, DOCKED_EDGE_NONE);
162
163 if (dragged_window_ == child)
164 dragged_window_ = NULL;
165
166 Relayout();
167 }
168
169 void DockedWindowLayoutManager::OnChildWindowVisibilityChanged(
170 aura::Window* child, bool visible) {
171 Relayout();
172 }
173
174 void DockedWindowLayoutManager::SetChildBounds(
175 aura::Window* child, const gfx::Rect& requested_bounds) {
176 SetChildBoundsDirect(child, requested_bounds);
177 Relayout();
178 }
179
180 ////////////////////////////////////////////////////////////////////////////////
181 // DockLayoutManager, ash::ShellObserver implementation:
182
183 void DockedWindowLayoutManager::OnShelfAlignmentChanged(
184 aura::RootWindow* root_window) {
185 if (dock_container_->GetRootWindow() != root_window)
186 return;
187
188 if (!launcher_ || !launcher_->shelf_widget())
189 return;
190
191 // We do not allow launcher and dock on the same side. Switch side that
192 // the dock is attached to and move all dock windows to that new side
193 ShelfAlignment shelf_alignment =
194 launcher_->shelf_widget()->GetAlignment();
195 if (alignment_ == DOCK_ALIGNMENT_LEFT &&
196 shelf_alignment == SHELF_ALIGNMENT_LEFT) {
197 for (size_t i = 0; i < dock_container_->children().size(); ++i)
198 SetDockEdge(dock_container_->children()[i], DOCKED_EDGE_RIGHT);
199 } else if (alignment_ == DOCK_ALIGNMENT_RIGHT &&
200 shelf_alignment == SHELF_ALIGNMENT_RIGHT) {
201 for (size_t i = 0; i < dock_container_->children().size(); ++i)
202 SetDockEdge(dock_container_->children()[i], DOCKED_EDGE_LEFT);
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 ui::WindowShowState new_state =
220 window->GetProperty(aura::client::kShowStateKey);
221 if (new_state == ui::SHOW_STATE_MINIMIZED)
222 MinimizeWindow(window);
223 else
224 RestoreWindow(window);
225 }
226
227 void DockedWindowLayoutManager::OnWindowVisibilityChanged(
228 aura::Window* window, bool visible) {
229 if (visible)
230 window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
231 }
232
233 ////////////////////////////////////////////////////////////////////////////////
234 // DockLayoutManager, aura::client::ActivationChangeObserver implementation:
235
236 void DockedWindowLayoutManager::OnWindowActivated(aura::Window* gained_active,
237 aura::Window* lost_active) {
238 // Ignore if the window that is not managed by this was activated.
239 if (gained_active && gained_active->parent() == dock_container_)
240 UpdateStacking(gained_active);
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 dock).
256 shelf_hidden_ = new_state == ash::SHELF_HIDDEN;
257 for (size_t i = 0; i < dock_container_->children().size(); ++i) {
258 aura::Window* window = dock_container_->children()[i];
259 if (shelf_hidden_) {
260 if (window->IsVisible())
261 MinimizeWindow(window);
262 } else {
263 if (window->GetProperty(aura::client::kShowStateKey) !=
264 ui::SHOW_STATE_MINIMIZED) {
265 RestoreWindow(window);
266 }
267 }
268 }
269 }
270
271 ////////////////////////////////////////////////////////////////////////////////
272 // DockLayoutManager private implementation:
273
274 void DockedWindowLayoutManager::MinimizeWindow(aura::Window* window) {
275 window->Hide();
276 if (wm::IsActiveWindow(window))
277 wm::DeactivateWindow(window);
278 Relayout();
279 }
280
281 void DockedWindowLayoutManager::RestoreWindow(aura::Window* window) {
282 window->Show();
283 Relayout();
284 }
285
286 void DockedWindowLayoutManager::Relayout() {
287 if (in_layout_)
288 return;
289 base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true);
290
291 if (dock_container_->children().empty()) {
292 alignment_ = DOCK_ALIGNMENT_NONE;
293 return;
294 }
295
296 gfx::Rect dock_bounds = dock_container_->bounds();
297 aura::Window* active_window = NULL;
298 std::vector<aura::Window*> visible_windows;
299 alignment_ = GetDockEdge(dock_container_->children()[0]) == DOCKED_EDGE_LEFT ?
300 DOCK_ALIGNMENT_LEFT : DOCK_ALIGNMENT_RIGHT;
301 for (size_t i = 0; i < dock_container_->children().size(); ++i) {
302 aura::Window* window(dock_container_->children()[i]);
303
304 if (!window->IsVisible() ||
305 window->GetProperty(aura::client::kShowStateKey) ==
306 ui::SHOW_STATE_MINIMIZED) {
307 continue;
308 }
309
310 // If the shelf is currently hidden (full-screen mode), hide window until
311 // full-screen mode is exited.
312 if (shelf_hidden_) {
313 // The call to Hide does not set the minimize property, so the window will
314 // be restored when the shelf becomes visible again.
315 window->Hide();
316 continue;
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 gfx::Rect bounds = window->GetTargetBounds();
327 switch (alignment_) {
328 case DOCK_ALIGNMENT_LEFT:
329 if (window != dragged_window_ ||
330 abs(bounds.x() - dock_bounds.x()) < kMagnetismWidth) {
flackr 2013/06/11 17:59:31 Snapping windows during drags seems like something
varkha 2013/06/12 04:52:13 Done.
331 bounds.set_x(0);
332 }
333 break;
334 case DOCK_ALIGNMENT_RIGHT:
335 if (window != dragged_window_ ||
336 abs(dock_bounds.right() - bounds.right()) < kMagnetismWidth) {
337 bounds.set_x(dock_bounds.right() - bounds.width());
338 }
339 break;
340 case DOCK_ALIGNMENT_NONE:
341 NOTREACHED() << "Relayout called when dock alignment is 'NONE'";
342 break;
343 }
344 SetChildBoundsDirect(window, bounds);
345 }
346
347 UpdateStacking(active_window);
348 }
349
350 void DockedWindowLayoutManager::UpdateStacking(aura::Window* active_window) {
351 // TODO(varkha): Implement restacking to ensure that all docked windows are at
352 // least partially visible and selectable.
353 }
354
355 ////////////////////////////////////////////////////////////////////////////////
356 // keyboard::KeyboardControllerObserver implementation:
357
358 void DockedWindowLayoutManager::OnKeyboardBoundsChanging(
359 const gfx::Rect& keyboard_bounds) {
360 // This bounds change will have caused a change to the Shelf which does not
361 // propagate automatically to this class, so manually recalculate bounds.
362 OnWindowResized();
363 }
364
365 } // namespace internal
366 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698