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

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: Dock with zero width (no logs) 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 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..07acf47c058cb0b439c6c905920f7735af3a9a4f
--- /dev/null
+++ b/ash/wm/dock/dock_layout_manager.cc
@@ -0,0 +1,368 @@
+// 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/shell_window_ids.h"
+#include "ash/wm/coordinate_conversion.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"
Jun Mukai 2013/06/10 20:40:57 unnecessary include?
varkha 2013/06/10 21:09:47 Done.
+#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 {
+
+const int kMagnetismWidth = 32;
+
+// Duration for window animations.
+const int kWindowSlideDurationMilliseconds = 50;
+
+DockLayoutManager* GetDockLayoutManager(aura::Window* window) {
+ aura::Window* dock = Shell::GetContainer(
+ window->GetRootWindow(),
+ kShellWindowId_DockContainer);
+ return static_cast<internal::DockLayoutManager*>(dock->layout_manager());
+}
+
+} // 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();
+}
+
+void DockLayoutManager::FinishDragging() {
+ dragged_window_ = NULL;
+ Relayout();
+}
+
+DockEdge DockLayoutManager::FindDockEdge(aura::Window* window) {
+ DockLayoutManager* layout_manager = GetDockLayoutManager(window);
+ const gfx::Rect& bounds(window->bounds());
+ gfx::Rect dock_bounds = layout_manager->dock_container_->bounds();
+ DockEdge dock_edge = DOCK_EDGE_NONE;
+ if (bounds.x() == dock_bounds.x() &&
+ layout_manager->alignment_ != DOCK_ALIGNMENT_RIGHT) {
+ dock_edge = DOCK_EDGE_LEFT;
+ } else
+ if (bounds.right() == dock_bounds.right() &&
flackr 2013/06/10 20:58:07 Move if on previous line with else, i.e. "} else i
+ layout_manager->alignment_ != DOCK_ALIGNMENT_LEFT) {
+ dock_edge = DOCK_EDGE_RIGHT;
+ }
+
+ // do not allow dock on the same side as launcher shelf
+ if (layout_manager->launcher_ && layout_manager->launcher_->shelf_widget()) {
+ ShelfAlignment shelf_alignment =
+ layout_manager->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)) {
+ 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();
+}
+
+void DockLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
+ if (!IsWindowDocked(child))
flackr 2013/06/10 20:58:07 We add undocked windows to the dock container now?
varkha 2013/06/12 04:52:13 Not anymore.
+ return;
+
+ child->AddObserver(this);
+ Relayout();
+}
+
+void DockLayoutManager::OnWillRemoveWindowFromLayout(aura::Window* child) {
+}
+
+void DockLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {
+ if (!child->HasObserver(this))
+ return;
+
+ child->RemoveObserver(this);
+ SetDockEdge(child, DOCK_EDGE_NONE);
+
+ if (dragged_window_ == child)
+ dragged_window_ = NULL;
+
+ Relayout();
+}
+
+void DockLayoutManager::OnChildWindowVisibilityChanged(aura::Window* child,
+ bool visible) {
+ Relayout();
+}
+
+void DockLayoutManager::SetChildBounds(aura::Window* child,
+ const gfx::Rect& requested_bounds) {
+ SetChildBoundsDirect(child, requested_bounds);
+ Relayout();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DockLayoutManager, ash::ShellObserver implementation:
+
+void DockLayoutManager::OnShelfAlignmentChanged(
+ aura::RootWindow* root_window) {
+ if (dock_container_->GetRootWindow() != root_window)
+ return;
+
+ if (!launcher_ || !launcher_->shelf_widget())
+ return;
+
+ // 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) {
+ 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) {
+ for (size_t i = 0; i < dock_container_->children().size(); ++i)
+ SetDockEdge(dock_container_->children()[i], DOCK_EDGE_LEFT);
+ }
+ Relayout();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// DockLayoutManager, WindowObserver implementation:
+
+void DockLayoutManager::OnWindowPropertyChanged(aura::Window* window,
+ const void* key,
+ intptr_t old) {
+ if (key != aura::client::kShowStateKey)
+ return;
+ // 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) {
+ 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_)
+ 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(varkha): ShelfLayoutManager::UpdateVisibilityState sets state to
+ // 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) {
+ window->Hide();
+ if (wm::IsActiveWindow(window))
+ wm::DeactivateWindow(window);
+ Relayout();
+}
+
+void DockLayoutManager::RestoreWindow(aura::Window* window) {
+ window->Show();
+ Relayout();
+}
+
+void DockLayoutManager::Relayout() {
+ 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;
+ for (size_t i = 0; i < dock_container_->children().size(); ++i) {
+ aura::Window* window(dock_container_->children()[i]);
+
+ 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;
+ }
+
+ gfx::Rect bounds = window->GetTargetBounds();
+ switch (alignment_) {
+ case DOCK_ALIGNMENT_LEFT:
+ if (window != dragged_window_ ||
+ abs(bounds.x() - dock_bounds.x()) < kMagnetismWidth) {
+ bounds.set_x(0);
+ }
+ break;
+ case DOCK_ALIGNMENT_RIGHT:
+ if (window != dragged_window_ ||
+ abs(dock_bounds.right() - bounds.right()) < kMagnetismWidth) {
+ bounds.set_x(dock_bounds.right() - bounds.width());
+ }
+ break;
+ case DOCK_ALIGNMENT_NONE:
+ NOTREACHED() << "Relayout called when dock alignment is 'NONE'";
+ break;
+ }
+ SetChildBoundsDirect(window, bounds);
+ }
+
+ UpdateStacking(active_window);
+}
+
+void DockLayoutManager::UpdateStacking(aura::Window* active_window) {
+ // TODO(varkha): Implement restacking to ensure that all docked windows are at
+ // least 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