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

Unified 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 side-by-side diff with in-line comments
Download patch
« 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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ash/wm/dock/docked_window_layout_manager.cc
diff --git a/ash/wm/dock/docked_window_layout_manager.cc b/ash/wm/dock/docked_window_layout_manager.cc
new file mode 100644
index 0000000000000000000000000000000000000000..552ea123051e40dc66fa5cb96d5361a0e225cf9a
--- /dev/null
+++ b/ash/wm/dock/docked_window_layout_manager.cc
@@ -0,0 +1,369 @@
+// Copyright (c) 2013 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/docked_window_layout_manager.h"
+
+#include "ash/launcher/launcher.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/window_util.h"
+#include "base/auto_reset.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/gfx/rect.h"
+
+namespace ash {
+namespace internal {
+
+namespace {
+
+DockedWindowLayoutManager* GetDockLayoutManager(aura::Window* window,
+ const gfx::Point& location) {
+ gfx::Rect near_location(location, gfx::Size());
+ aura::Window* dock = Shell::GetContainer(
+ wm::GetRootWindowMatching(near_location),
+ kShellWindowId_DockedContainer);
+ return static_cast<internal::DockedWindowLayoutManager*>(
+ dock->layout_manager());
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// DockLayoutManager public implementation:
+DockedWindowLayoutManager::DockedWindowLayoutManager(
+ aura::Window* dock_container)
+ : dock_container_(dock_container),
+ in_layout_(false),
+ dragged_window_(NULL),
+ launcher_(NULL),
+ shelf_layout_manager_(NULL),
+ shelf_hidden_(false),
+ alignment_(DOCKED_ALIGNMENT_NONE) {
+ DCHECK(dock_container);
+ aura::client::GetActivationClient(Shell::GetPrimaryRootWindow())->
+ AddObserver(this);
+ Shell::GetInstance()->AddShellObserver(this);
+}
+
+DockedWindowLayoutManager::~DockedWindowLayoutManager() {
+ launcher_ = NULL;
+ for (size_t i = 0; i < dock_container_->children().size(); ++i)
+ dock_container_->children()[i]->RemoveObserver(this);
+ if (shelf_layout_manager_)
+ shelf_layout_manager_->RemoveObserver(this);
+ aura::client::GetActivationClient(Shell::GetPrimaryRootWindow())->
+ RemoveObserver(this);
+ Shell::GetInstance()->RemoveShellObserver(this);
+}
+
+void DockedWindowLayoutManager::StartDragging(aura::Window* window) {
+ if (window->parent() != dock_container_)
+ return;
+ DCHECK(!dragged_window_);
+ dragged_window_ = window;
+ Relayout();
+}
+
+void DockedWindowLayoutManager::FinishDragging() {
+ dragged_window_ = NULL;
+ Relayout();
+}
+
+// static
+bool DockedWindowLayoutManager::ShouldWindowDock(aura::Window* window,
+ const gfx::Point& location) {
+ DockedWindowLayoutManager* layout_manager = GetDockLayoutManager(window,
+ location);
+ const gfx::Rect& bounds(window->GetBoundsInScreen());
+ gfx::Rect dock_bounds = layout_manager->dock_container_->GetBoundsInScreen();
+ // Possible sides of the screen that a window can be touching.
+ enum DockedEdge {
+ DOCKED_EDGE_NONE,
+ DOCKED_EDGE_LEFT,
+ DOCKED_EDGE_RIGHT,
+ } dock_edge = DOCKED_EDGE_NONE;
+ if (bounds.x() == dock_bounds.x() &&
+ layout_manager->alignment_ != DOCKED_ALIGNMENT_RIGHT) {
+ dock_edge = DOCKED_EDGE_LEFT;
+ } else if (bounds.right() == dock_bounds.right() &&
+ layout_manager->alignment_ != DOCKED_ALIGNMENT_LEFT) {
+ dock_edge = DOCKED_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 == DOCKED_EDGE_LEFT) ||
+ (shelf_alignment == SHELF_ALIGNMENT_RIGHT &&
+ dock_edge == DOCKED_EDGE_RIGHT)) {
+ dock_edge = DOCKED_EDGE_NONE;
+ }
+ }
+ return dock_edge != DOCKED_EDGE_NONE;
+}
+
+void DockedWindowLayoutManager::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);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DockLayoutManager, aura::LayoutManager implementation:
+void DockedWindowLayoutManager::OnWindowResized() {
+ Relayout();
+}
+
+void DockedWindowLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
+ child->AddObserver(this);
+ Relayout();
+}
+
+void DockedWindowLayoutManager::OnWillRemoveWindowFromLayout(
+ aura::Window* child) {
+}
+
+void DockedWindowLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {
+ child->RemoveObserver(this);
+ Relayout();
+}
+
+void DockedWindowLayoutManager::OnChildWindowVisibilityChanged(
+ aura::Window* child,
+ bool visible) {
+ if (visible)
+ child->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
+ Relayout();
+}
+
+void DockedWindowLayoutManager::SetChildBounds(
+ aura::Window* child,
+ const gfx::Rect& requested_bounds) {
+ // Whenever one of our windows is moved or resized we need to enforce layout.
+ SetChildBoundsDirect(child, requested_bounds);
+ Relayout();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DockLayoutManager, ash::ShellObserver implementation:
+
+void DockedWindowLayoutManager::OnShelfAlignmentChanged(
+ aura::RootWindow* root_window) {
+ if (dock_container_->GetRootWindow() != root_window)
+ return;
+
+ if (!launcher_ || !launcher_->shelf_widget())
+ return;
+
+ if (alignment_ == DOCKED_ALIGNMENT_NONE)
+ return;
+
+ // It should not be possible to have empty children() while alignment is set
+ // to anything other than DOCKED_ALIGNMENT_NONE - see Relayout.
+ if (dock_container_->children().empty()) {
+ LOG(ERROR) << "No children and alignment set to " << alignment_;
+ return;
+ }
+ aura::Window* window = dock_container_->children()[0];
+ const gfx::Rect& dock_bounds = dock_container_->bounds();
+ gfx::Rect bounds = window->bounds();
+
+ // 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.
+ // We actually only need to move the first window and the rest will follow
+ // in Relayout
+ ShelfAlignment shelf_alignment =
+ launcher_->shelf_widget()->GetAlignment();
+ if (alignment_ == DOCKED_ALIGNMENT_LEFT &&
+ shelf_alignment == SHELF_ALIGNMENT_LEFT) {
+ bounds.set_x(dock_bounds.right() - bounds.width());
+ SetChildBoundsDirect(window, bounds);
+ } else if (alignment_ == DOCKED_ALIGNMENT_RIGHT &&
+ shelf_alignment == SHELF_ALIGNMENT_RIGHT) {
+ bounds.set_x(0);
+ SetChildBoundsDirect(window, bounds);
+ }
+ Relayout();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// DockLayoutManager, WindowObserver implementation:
+
+void DockedWindowLayoutManager::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;
+ if (wm::IsWindowMinimized(window))
+ MinimizeWindow(window);
+ else
+ RestoreWindow(window);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DockLayoutManager, aura::client::ActivationChangeObserver implementation:
+
+void DockedWindowLayoutManager::OnWindowActivated(aura::Window* gained_active,
+ aura::Window* lost_active) {
+ // Ignore if the window that is not managed by this was activated.
+ aura::Window* ancestor = NULL;
+ for (aura::Window* parent = gained_active;
+ parent; parent = parent->parent()) {
+ if (parent->parent() == dock_container_) {
+ ancestor = parent;
+ break;
+ }
+ }
+ if (ancestor)
+ UpdateStacking(ancestor);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DockLayoutManager, ShelfLayoutManagerObserver implementation:
+
+void DockedWindowLayoutManager::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 docked
+ // windows).
+ shelf_hidden_ = new_state == ash::SHELF_HIDDEN;
+ {
+ // prevent Relayout from getting called multiple times during this
+ base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true);
+ 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 (!wm::IsWindowMinimized(window))
+ RestoreWindow(window);
+ }
+ }
+ }
+ Relayout();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DockLayoutManager private implementation:
+
+void DockedWindowLayoutManager::MinimizeWindow(aura::Window* window) {
+ window->Hide();
+ if (wm::IsActiveWindow(window))
+ wm::DeactivateWindow(window);
+}
+
+void DockedWindowLayoutManager::RestoreWindow(aura::Window* window) {
+ window->Show();
+}
+
+void DockedWindowLayoutManager::Relayout() {
+ if (in_layout_)
+ return;
+ base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true);
+
+ if (dock_container_->children().empty()) {
+ alignment_ = DOCKED_ALIGNMENT_NONE;
+ return;
+ }
+
+ gfx::Rect dock_bounds = dock_container_->bounds();
+ aura::Window* active_window = NULL;
+ std::vector<aura::Window*> visible_windows;
+ alignment_ = DOCKED_ALIGNMENT_ANY;
+ for (size_t i = 0; i < dock_container_->children().size(); ++i) {
+ aura::Window* window(dock_container_->children()[i]);
+
+ if (!window->IsVisible() || wm::IsWindowMinimized(window))
+ 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;
+ }
+
+ gfx::Rect bounds = window->GetTargetBounds();
+ if (window != dragged_window_ && alignment_ == DOCKED_ALIGNMENT_ANY) {
+ if (bounds.x() == 0)
+ alignment_ = DOCKED_ALIGNMENT_LEFT;
+ else if (bounds.right() == dock_bounds.right())
+ alignment_ = DOCKED_ALIGNMENT_RIGHT;
+ }
+
+ if (window->HasFocus() ||
+ window->Contains(
+ aura::client::GetFocusClient(window)->GetFocusedWindow())) {
+ DCHECK(!active_window);
+ active_window = window;
+ }
+
+ // all docked windows remain stuck to the screen edge
+ if (window != dragged_window_) {
+ switch (alignment_) {
+ case DOCKED_ALIGNMENT_LEFT:
+ bounds.set_x(0);
+ break;
+ case DOCKED_ALIGNMENT_RIGHT:
+ case DOCKED_ALIGNMENT_ANY:
+ bounds.set_x(dock_bounds.right() - bounds.width());
+ break;
+ case DOCKED_ALIGNMENT_NONE:
+ NOTREACHED() << "Relayout called when dock alignment is 'NONE'";
+ break;
+ }
+ }
+ SetChildBoundsDirect(window, bounds);
+ }
+
+ UpdateStacking(active_window);
+}
+
+void DockedWindowLayoutManager::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 DockedWindowLayoutManager::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
« 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