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

Unified 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: Docking with dock width=0 Created 7 years, 7 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 side-by-side diff with in-line comments
Download patch
Index: ash/wm/dock/dock_layout_manager.cc
diff --git a/ash/wm/dock/dock_layout_manager.cc b/ash/wm/dock/dock_layout_manager.cc
new file mode 100644
index 0000000000000000000000000000000000000000..2d082700bde597a0e4f63f9f92527d3611f6eaa3
--- /dev/null
+++ b/ash/wm/dock/dock_layout_manager.cc
@@ -0,0 +1,386 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/wm/dock/dock_layout_manager.h"
+
+#include "ash/launcher/launcher.h"
+#include "ash/root_window_controller.h"
+#include "ash/screen_ash.h"
+#include "ash/shelf/shelf_layout_manager.h"
+#include "ash/shelf/shelf_types.h"
+#include "ash/shelf/shelf_widget.h"
+#include "ash/shell.h"
+#include "ash/wm/property_util.h"
+#include "ash/wm/window_animations.h"
+#include "ash/wm/window_properties.h"
+#include "ash/wm/window_util.h"
+#include "ash/wm/workspace_controller.h"
+#include "base/auto_reset.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "ui/aura/client/activation_client.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/focus_manager.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/window.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/gfx/rect.h"
+
+namespace ash {
+namespace internal {
+
+namespace {
stevenjb 2013/06/03 18:19:03 nit: blank line
varkha 2013/06/03 21:03:17 Done.
+const int kMagnetismWidth = 32;
+
+// Duration for window animations.
+const int kWindowSlideDurationMilliseconds = 50;
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// DockLayoutManager public implementation:
+DockLayoutManager::DockLayoutManager(aura::Window* dock_container)
+ : dock_container_(dock_container),
+ in_layout_(false),
+ dragged_window_(NULL),
+ launcher_(NULL),
+ shelf_layout_manager_(NULL),
+ shelf_hidden_(false),
+ alignment_(DOCK_ALIGNMENT_NONE) {
+ DCHECK(dock_container);
+ aura::client::GetActivationClient(Shell::GetPrimaryRootWindow())->
+ AddObserver(this);
+ Shell::GetInstance()->AddShellObserver(this);
+}
+
+DockLayoutManager::~DockLayoutManager() {
+ if (shelf_layout_manager_)
+ shelf_layout_manager_->RemoveObserver(this);
+ Shutdown();
+ aura::client::GetActivationClient(Shell::GetPrimaryRootWindow())->
+ RemoveObserver(this);
+ Shell::GetInstance()->RemoveShellObserver(this);
+}
+
+void DockLayoutManager::Shutdown() {
+ launcher_ = NULL;
+}
+
+void DockLayoutManager::StartDragging(aura::Window* window) {
+ DCHECK(!dragged_window_);
+ dragged_window_ = window;
+ Relayout(DO_NOT_FORCE_MOVE);
+}
+
+void DockLayoutManager::FinishDragging() {
+ ForceMove force_move(DO_NOT_FORCE_MOVE);
+ if (dragged_window_) {
+ DockEdge dock_edge = FindDockEdge(dragged_window_->bounds());
+ if (dock_edge == DOCK_EDGE_NONE)
+ // this will reparent the window back to workspace
flackr 2013/06/03 22:03:43 Doesn't the reparenting happen immediately? I'm no
varkha 2013/06/04 03:13:50 Done.
+ SetDockEdge(dragged_window_, dock_edge);
+ else {
+ force_move = FORCE_MOVE;
flackr 2013/06/03 22:03:43 nit: both if and else should either have or not ha
varkha 2013/06/04 03:13:50 Done (no need for else anymore).
+ }
+ }
+ dragged_window_ = NULL;
+ Relayout(force_move);
+}
+
+DockEdge DockLayoutManager::FindDockEdge(const gfx::Rect& bounds) const {
+ DockEdge dock_edge = DOCK_EDGE_NONE;
+ gfx::Rect dock_bounds = dock_container_->bounds();
+ if (bounds.x() == dock_bounds.x() && alignment_ != DOCK_ALIGNMENT_RIGHT)
+ dock_edge = DOCK_EDGE_LEFT;
+ if (bounds.right() == dock_bounds.right() &&
+ alignment_ != DOCK_ALIGNMENT_LEFT)
+ dock_edge = DOCK_EDGE_RIGHT;
flackr 2013/06/03 22:03:43 nit: curlies for multi-line if condition.
varkha 2013/06/04 03:13:50 Done. Here and in a few more places. Thanks, I mis
+
+ // do not allow dock on the same side as launcher shelf
+ if (launcher_ && launcher_->shelf_widget()) {
+ ShelfAlignment shelf_alignment = launcher_->shelf_widget()->GetAlignment();
+ if ((shelf_alignment == SHELF_ALIGNMENT_LEFT &&
+ dock_edge == DOCK_EDGE_LEFT) ||
+ (shelf_alignment == SHELF_ALIGNMENT_RIGHT &&
+ dock_edge == DOCK_EDGE_RIGHT))
stevenjb 2013/06/03 18:19:03 nit: alignment
varkha 2013/06/03 21:03:17 Done.
+ dock_edge = DOCK_EDGE_NONE;
+ }
+ return dock_edge;
+}
+
+void DockLayoutManager::SetLauncher(ash::Launcher* launcher) {
+ DCHECK(!launcher_);
+ DCHECK(!shelf_layout_manager_);
+ launcher_ = launcher;
+ if (launcher_->shelf_widget()) {
+ shelf_layout_manager_ = ash::internal::ShelfLayoutManager::ForLauncher(
+ launcher_->shelf_widget()->GetNativeWindow());
+ WillChangeVisibilityState(shelf_layout_manager_->visibility_state());
+ shelf_layout_manager_->AddObserver(this);
+ }
+}
+
+void DockLayoutManager::ToggleMinimize(aura::Window* window) {
+ DCHECK(window->parent() == dock_container_);
+ if (window->GetProperty(aura::client::kShowStateKey) ==
+ ui::SHOW_STATE_MINIMIZED) {
+ window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
+ } else {
+ window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DockLayoutManager, aura::LayoutManager implementation:
+void DockLayoutManager::OnWindowResized() {
+ Relayout(FORCE_MOVE);
+}
+
+void DockLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
+ if (GetDockEdge(child) == DOCK_EDGE_NONE)
flackr 2013/06/03 22:03:43 Do we expect windows to get added to the dock cont
varkha 2013/06/04 03:13:50 Done.
+ return;
+ child->AddObserver(this);
+ Relayout(FORCE_MOVE);
+}
+
+void DockLayoutManager::OnWillRemoveWindowFromLayout(aura::Window* child) {
+}
+
+void DockLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {
+ SetDockEdge(child, DOCK_EDGE_NONE);
+ child->RemoveObserver(this);
+
+ if (dragged_window_ == child)
+ dragged_window_ = NULL;
+
+ Relayout(DO_NOT_FORCE_MOVE);
+}
+
+void DockLayoutManager::OnChildWindowVisibilityChanged(aura::Window* child,
+ bool visible) {
+ Relayout(DO_NOT_FORCE_MOVE);
+}
+
+void DockLayoutManager::SetChildBounds(aura::Window* child,
+ const gfx::Rect& requested_bounds) {
stevenjb 2013/06/03 18:19:03 nit: align
varkha 2013/06/03 21:03:17 Done.
+ SetChildBoundsDirect(child, requested_bounds);
+ Relayout(DO_NOT_FORCE_MOVE);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DockLayoutManager, ash::ShellObserver implementation:
+
+void DockLayoutManager::OnShelfAlignmentChanged(
+ aura::RootWindow* root_window) {
+ ForceMove force_move(DO_NOT_FORCE_MOVE);
+ if (dock_container_->GetRootWindow() == root_window) {
stevenjb 2013/06/03 18:19:03 nit: Early exit instead
varkha 2013/06/03 21:03:17 Done.
+ if (launcher_ && launcher_->shelf_widget()) {
+ // We do not allow launcher and dock on the same side. Switch side that
+ // the dock is attached to and move all dock windows to that new side
+ ShelfAlignment shelf_alignment =
+ launcher_->shelf_widget()->GetAlignment();
+ if (alignment_ == DOCK_ALIGNMENT_LEFT &&
+ shelf_alignment == SHELF_ALIGNMENT_LEFT) {
+ force_move = FORCE_MOVE;
+ for (size_t i = 0; i < dock_container_->children().size(); ++i)
+ SetDockEdge(dock_container_->children()[i], DOCK_EDGE_RIGHT);
+ } else if (alignment_ == DOCK_ALIGNMENT_RIGHT &&
+ shelf_alignment == SHELF_ALIGNMENT_RIGHT) {
stevenjb 2013/06/03 18:19:03 nit: align
varkha 2013/06/03 21:03:17 Done.
+ force_move = FORCE_MOVE;
+ for (size_t i = 0; i < dock_container_->children().size(); ++i)
+ SetDockEdge(dock_container_->children()[i], DOCK_EDGE_LEFT);
+ }
+ }
+ Relayout(force_move);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// DockLayoutManager, WindowObserver implementation:
+
+void DockLayoutManager::OnWindowPropertyChanged(aura::Window* window,
+ const void* key,
+ intptr_t old) {
stevenjb 2013/06/03 18:19:03 nit: align
varkha 2013/06/03 21:03:17 Done.
+ if (key == ash::internal::kDockEdge &&
+ GetDockEdge(window) != static_cast<DockEdge>(old)) {
+ DockEdge edge = GetDockEdge(window);
+ if (edge == DOCK_EDGE_NONE && window->GetRootWindow()) {
+ // Reparenting will cause Relayout and possible dock resize.
+ window->SetDefaultParentByRootWindow(window->GetRootWindow(),
+ window->GetBoundsInScreen());
+ // A maximized workspace may be active so we may need to switch
+ // to a parent workspace of the window being dragged out.
+ internal::WorkspaceController* workspace_controller =
+ GetRootWindowController(
+ window->GetRootWindow())->workspace_controller();
+ workspace_controller->SetActiveWorkspaceByWindow(window);
+ }
+ }
+
+ if (key == aura::client::kShowStateKey) {
flackr 2013/06/03 22:03:43 nit: else if
varkha 2013/06/04 03:13:50 Done.
+ // The window property will still be set, but no actual change will occur
+ // until WillChangeVisibilityState is called when the shelf is visible again
+ if (shelf_hidden_)
+ return;
+ ui::WindowShowState new_state =
+ window->GetProperty(aura::client::kShowStateKey);
+ if (new_state == ui::SHOW_STATE_MINIMIZED)
+ MinimizeWindow(window);
+ else
+ RestoreWindow(window);
+ }
+}
+
+void DockLayoutManager::OnWindowVisibilityChanged(
+ aura::Window* window, bool visible) {
stevenjb 2013/06/03 18:19:03 One parameter per line in function declaration or
varkha 2013/06/03 21:03:17 Done.
+ if (visible)
+ window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DockLayoutManager, aura::client::ActivationChangeObserver implementation:
+
+void DockLayoutManager::OnWindowActivated(aura::Window* gained_active,
+ aura::Window* lost_active) {
+ // Ignore if the window that is not managed by this was activated.
+ if (gained_active &&
+ gained_active->parent() == dock_container_) {
stevenjb 2013/06/03 18:19:03 One line? In which case no {}
varkha 2013/06/03 21:03:17 Done.
+ UpdateStacking(gained_active);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DockLayoutManager, ShelfLayoutManagerObserver implementation:
+
+void DockLayoutManager::WillChangeVisibilityState(
+ ShelfVisibilityState new_state) {
+ // On entering / leaving full screen mode the shelf visibility state is
+ // changed to / from SHELF_HIDDEN. In this state, docked windows should hide
+ // to allow the full-screen application to use the full screen.
+
+ // TODO: ShelfLayoutManager::UpdateVisibilityState sets state to
stevenjb 2013/06/03 18:19:03 TODO(varkha)
varkha 2013/06/03 21:03:17 Done.
+ // SHELF_AUTO_HIDE when in immersive mode. We need to distinguish this from
+ // when shelf enters auto-hide state based on mouse hover when auto-hide
+ // setting is enabled and hide all windows (immersive mode should hide dock).
+ shelf_hidden_ = new_state == ash::SHELF_HIDDEN;
+ for (size_t i = 0; i < dock_container_->children().size(); ++i) {
+ aura::Window* window = dock_container_->children()[i];
+ if (shelf_hidden_) {
+ if (window->IsVisible())
+ MinimizeWindow(window);
+ } else {
+ if (window->GetProperty(aura::client::kShowStateKey) !=
+ ui::SHOW_STATE_MINIMIZED) {
+ RestoreWindow(window);
+ }
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DockLayoutManager private implementation:
+
+void DockLayoutManager::MinimizeWindow(aura::Window* window) {
+ views::corewm::SetWindowVisibilityAnimationType(
+ window, WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE);
+ ui::Layer* layer = window->layer();
+ ui::ScopedLayerAnimationSettings window_slide_settings(layer->GetAnimator());
+ window_slide_settings.SetPreemptionStrategy(
+ ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
+ window_slide_settings.SetTransitionDuration(
+ base::TimeDelta::FromMilliseconds(kWindowSlideDurationMilliseconds));
flackr 2013/06/03 22:03:43 It looks like there's nothing immediately here to
varkha 2013/06/04 03:13:50 Done.
+ window->Hide();
+ if (wm::IsActiveWindow(window))
+ wm::DeactivateWindow(window);
+ Relayout(DO_NOT_FORCE_MOVE);
+}
+
+void DockLayoutManager::RestoreWindow(aura::Window* window) {
+ window->Show();
+ Relayout(DO_NOT_FORCE_MOVE);
+}
+
+void DockLayoutManager::Relayout(ForceMove force_move) {
+ if (in_layout_)
+ return;
+ base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true);
+
+ if (dock_container_->children().empty()) {
+ alignment_ = DOCK_ALIGNMENT_NONE;
+ return;
+ }
+
+ gfx::Rect dock_bounds = dock_container_->bounds();
+ aura::Window* active_window = NULL;
+ std::vector<aura::Window*> visible_windows;
+ alignment_ =
+ GetDockEdge(dock_container_->children()[0]) == DOCK_EDGE_LEFT ?
+ DOCK_ALIGNMENT_LEFT : DOCK_ALIGNMENT_RIGHT;
stevenjb 2013/06/03 18:19:03 nit: align
varkha 2013/06/03 21:03:17 Done.
+ for (size_t i = 0; i < dock_container_->children().size(); ++i) {
+ aura::Window* window(dock_container_->children()[i]);
+
+ // Consider the dragged window as part of the layout as long as it is
+ // touching the launcher.
flackr 2013/06/03 22:03:43 This comment seems obsolete.
varkha 2013/06/04 03:13:50 Done.
+ if (!window->IsVisible() ||
+ window->GetProperty(aura::client::kShowStateKey) ==
+ ui::SHOW_STATE_MINIMIZED)
+ continue;
+
+ // If the shelf is currently hidden (full-screen mode), hide window until
+ // full-screen mode is exited.
+ if (shelf_hidden_) {
+ // The call to Hide does not set the minimize property, so the window will
+ // be restored when the shelf becomes visible again.
+ window->Hide();
+ continue;
+ }
+
+ if (window->HasFocus() ||
+ window->Contains(
+ aura::client::GetFocusClient(window)->GetFocusedWindow())) {
+ DCHECK(!active_window);
+ active_window = window;
+ }
+ visible_windows.push_back(window);
flackr 2013/06/03 22:03:43 Building this list is unnecessary. Merge the body
varkha 2013/06/04 03:13:50 Done.
+ }
+
+ for (size_t i = 0; i < visible_windows.size(); ++i) {
+ gfx::Rect bounds = visible_windows[i]->GetTargetBounds();
+ switch (alignment_) {
+ case DOCK_ALIGNMENT_LEFT:
+ if (force_move == FORCE_MOVE ||
flackr 2013/06/03 22:03:43 As mentioned earlier, I think any windows in this
varkha 2013/06/04 03:13:50 Done. Convinced ;)
+ bounds.x() - dock_bounds.x() < kMagnetismWidth)
+ bounds.set_x(0);
+ break;
+ case DOCK_ALIGNMENT_RIGHT:
+ if (force_move == FORCE_MOVE ||
+ dock_bounds.right() - bounds.right() < kMagnetismWidth)
+ bounds.set_x(dock_bounds.right() - bounds.width());
+ break;
+ case DOCK_ALIGNMENT_NONE:
+ break;
+ }
+ SetChildBoundsDirect(visible_windows[i], bounds);
+ }
+
+ UpdateStacking(active_window);
+}
+
+void DockLayoutManager::UpdateStacking(aura::Window* active_window) {
+ // TODO: Implement restacking to ensure that all docked windows are at least
stevenjb 2013/06/03 18:19:03 TODO(varkha)
varkha 2013/06/03 21:03:17 Done.
+ // partially visible and selectable.
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// keyboard::KeyboardControllerObserver implementation:
+
+void DockLayoutManager::OnKeyboardBoundsChanging(
+ const gfx::Rect& keyboard_bounds) {
+ // This bounds change will have caused a change to the Shelf which does not
+ // propagate automatically to this class, so manually recalculate bounds.
+ OnWindowResized();
+}
+
+} // namespace internal
+} // namespace ash

Powered by Google App Engine
This is Rietveld 408576698