summaryrefslogtreecommitdiffstats
path: root/ash
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-30 15:16:57 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-30 15:16:57 +0000
commitb5f3060dafc8514114fadff3011a3921a0f29bc6 (patch)
tree6be43c40161f7dd0ce58062b0f8ced76c7536a9c /ash
parentada425fc5d779300bd32c38db7ad571ba3855288 (diff)
downloadchromium_src-b5f3060dafc8514114fadff3011a3921a0f29bc6.zip
chromium_src-b5f3060dafc8514114fadff3011a3921a0f29bc6.tar.gz
chromium_src-b5f3060dafc8514114fadff3011a3921a0f29bc6.tar.bz2
Handful of workspace changes:
. Correctly deal with fullscreen. . wires up grid size and sets it appropriately. . maxes windows open initially maximized if necessary. I've also wired up showing a menu when you right click on the desktop that lets you configure things. This is only temporary, but I figure worthwhile to play with various settings. BUG=111285 TEST=none R=ben@chromium.org Review URL: https://chromiumcodereview.appspot.com/9295024 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@119674 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash')
-rw-r--r--ash/desktop_background/desktop_background_view.cc5
-rw-r--r--ash/shell.cc11
-rw-r--r--ash/shell.h5
-rw-r--r--ash/wm/property_util.h12
-rw-r--r--ash/wm/workspace/workspace_event_filter.h3
-rw-r--r--ash/wm/workspace/workspace_layout_manager.cc34
-rw-r--r--ash/wm/workspace/workspace_layout_manager.h4
-rw-r--r--ash/wm/workspace/workspace_manager.cc111
-rw-r--r--ash/wm/workspace/workspace_manager.h50
-rw-r--r--ash/wm/workspace/workspace_manager_unittest.cc117
-rw-r--r--ash/wm/workspace_controller.cc117
-rw-r--r--ash/wm/workspace_controller.h61
12 files changed, 408 insertions, 122 deletions
diff --git a/ash/desktop_background/desktop_background_view.cc b/ash/desktop_background/desktop_background_view.cc
index 27401cf..1db7390 100644
--- a/ash/desktop_background/desktop_background_view.cc
+++ b/ash/desktop_background/desktop_background_view.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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.
@@ -44,7 +44,8 @@ bool DesktopBackgroundView::OnMousePressed(const views::MouseEvent& event) {
}
void DesktopBackgroundView::OnMouseReleased(const views::MouseEvent& event) {
- Shell::GetInstance()->ToggleOverview();
+ if (event.IsRightMouseButton())
+ Shell::GetInstance()->ShowBackgroundMenu(GetWidget(), event.location());
}
views::Widget* CreateDesktopBackground() {
diff --git a/ash/shell.cc b/ash/shell.cc
index b889e0b..1d56dae 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -372,9 +372,10 @@ size_t Shell::GetRootWindowEventFilterCount() const {
aura::RootWindow::GetInstance()->event_filter())->GetFilterCount();
}
-void Shell::ToggleOverview() {
+void Shell::ShowBackgroundMenu(views::Widget* widget,
+ const gfx::Point& location) {
if (workspace_controller_.get())
- workspace_controller_->ToggleOverview();
+ workspace_controller_->ShowMenu(widget, location);
}
void Shell::ToggleAppList() {
@@ -486,12 +487,6 @@ void Shell::SetupNormalWindowMode() {
// Workspace manager has its own layout managers.
workspace_controller_.reset(
new internal::WorkspaceController(default_container));
- workspace_controller_->SetLauncherModel(launcher_->model());
- default_container->SetEventFilter(
- new internal::WorkspaceEventFilter(default_container));
- default_container->SetLayoutManager(
- new internal::WorkspaceLayoutManager(
- workspace_controller_->workspace_manager()));
} else {
// Default layout manager.
internal::ToplevelLayoutManager* toplevel_layout_manager =
diff --git a/ash/shell.h b/ash/shell.h
index a1dcb76..ab4da7b 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -24,6 +24,7 @@ class RootWindow;
class Window;
}
namespace gfx {
+class Point;
class Rect;
class Size;
}
@@ -88,8 +89,8 @@ class ASH_EXPORT Shell {
void RemoveRootWindowEventFilter(aura::EventFilter* filter);
size_t GetRootWindowEventFilterCount() const;
- // Toggles between overview mode and normal mode.
- void ToggleOverview();
+ // Shows the background menu over |widget|.
+ void ShowBackgroundMenu(views::Widget* widget, const gfx::Point& location);
// Toggles app list.
void ToggleAppList();
diff --git a/ash/wm/property_util.h b/ash/wm/property_util.h
index 916a24a..5eec8ba 100644
--- a/ash/wm/property_util.h
+++ b/ash/wm/property_util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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.
@@ -6,6 +6,8 @@
#define ASH_WM_PROPERTY_UTIL_H_
#pragma once
+#include "ash/ash_export.h"
+
namespace aura {
class Window;
}
@@ -18,19 +20,19 @@ namespace ash {
// Sets the restore bounds property on |window|. Deletes existing bounds value
// if exists.
-void SetRestoreBounds(aura::Window* window, const gfx::Rect& bounds);
+ASH_EXPORT void SetRestoreBounds(aura::Window* window, const gfx::Rect& bounds);
// Same as SetRestoreBounds(), but does nothing if the restore bounds have
// already been set. The bounds used are the bounds of the window.
-void SetRestoreBoundsIfNotSet(aura::Window* window);
+ASH_EXPORT void SetRestoreBoundsIfNotSet(aura::Window* window);
// Returns the restore bounds property on |window|. NULL if the
// restore bounds property does not exist for |window|. |window|
// owns the bounds object.
-const gfx::Rect* GetRestoreBounds(aura::Window* window);
+ASH_EXPORT const gfx::Rect* GetRestoreBounds(aura::Window* window);
// Deletes and clears the restore bounds property on |window|.
-void ClearRestoreBounds(aura::Window* window);
+ASH_EXPORT void ClearRestoreBounds(aura::Window* window);
}
diff --git a/ash/wm/workspace/workspace_event_filter.h b/ash/wm/workspace/workspace_event_filter.h
index 6224c10..c38beaf 100644
--- a/ash/wm/workspace/workspace_event_filter.h
+++ b/ash/wm/workspace/workspace_event_filter.h
@@ -40,7 +40,7 @@ class WorkspaceEventFilter : public ToplevelWindowEventFilter,
// If the mouse is currently over a portion of the window that should
// trigger a drag or resize, drag_state_ is set appropriately and true
// is returned. If the mouse is not over a portion of the window that should
- // trigger a more or resize, drag_state_ is not updated and false is returend.
+ // trigger a more or resize, drag_state_ is not updated and false is returned.
bool UpdateDragState();
// Updates the top-level window under the mouse so that we can change
@@ -48,6 +48,7 @@ class WorkspaceEventFilter : public ToplevelWindowEventFilter,
void UpdateHoveredWindow(aura::Window* toplevel);
DragState drag_state_;
+
// Top-level window under the mouse cursor.
aura::Window* hovered_window_;
diff --git a/ash/wm/workspace/workspace_layout_manager.cc b/ash/wm/workspace/workspace_layout_manager.cc
index 99409e7..e876d96 100644
--- a/ash/wm/workspace/workspace_layout_manager.cc
+++ b/ash/wm/workspace/workspace_layout_manager.cc
@@ -34,13 +34,11 @@ WorkspaceLayoutManager::~WorkspaceLayoutManager() {}
void WorkspaceLayoutManager::PrepareForMoveOrResize(
aura::Window* drag,
aura::MouseEvent* event) {
- workspace_manager_->set_ignored_window(drag);
}
void WorkspaceLayoutManager::CancelMoveOrResize(
aura::Window* drag,
aura::MouseEvent* event) {
- workspace_manager_->set_ignored_window(NULL);
}
void WorkspaceLayoutManager::ProcessMove(
@@ -54,14 +52,12 @@ void WorkspaceLayoutManager::EndMove(
aura::Window* drag,
aura::MouseEvent* evnet) {
// TODO: see comment in ProcessMove.
- workspace_manager_->set_ignored_window(NULL);
}
void WorkspaceLayoutManager::EndResize(
aura::Window* drag,
aura::MouseEvent* evnet) {
// TODO: see comment in ProcessMove.
- workspace_manager_->set_ignored_window(NULL);
}
////////////////////////////////////////////////////////////////////////////////
@@ -75,8 +71,23 @@ void WorkspaceLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
if (!workspace_manager_->IsManagedWindow(child))
return;
- if (child->IsVisible())
+ if (child->IsVisible()) {
workspace_manager_->AddWindow(child);
+ } else if (window_util::IsWindowMaximized(child) ||
+ workspace_manager_->ShouldMaximize(child)) {
+ if (!GetRestoreBounds(child))
+ SetRestoreBounds(child, child->GetTargetBounds());
+ if (!window_util::IsWindowMaximized(child))
+ window_util::MaximizeWindow(child);
+ SetChildBoundsDirect(child,
+ gfx::Screen::GetMonitorWorkAreaNearestWindow(child));
+ } else if (window_util::IsWindowFullscreen(child)) {
+ SetChildBoundsDirect(child,
+ gfx::Screen::GetMonitorAreaNearestWindow(child));
+ } else {
+ SetChildBoundsDirect(
+ child, workspace_manager_->AlignBoundsToGrid(child->GetTargetBounds()));
+ }
}
void WorkspaceLayoutManager::OnWillRemoveWindowFromLayout(
@@ -99,14 +110,17 @@ void WorkspaceLayoutManager::OnChildWindowVisibilityChanged(
void WorkspaceLayoutManager::SetChildBounds(
aura::Window* child,
const gfx::Rect& requested_bounds) {
- // Allow setting the bounds for any window we don't care about, isn't visible,
- // or we're setting the bounds of. All other request are dropped on the floor.
if (child == workspace_manager_->ignored_window() ||
- !workspace_manager_->IsManagedWindow(child) || !child->IsVisible() ||
- (!window_util::IsWindowMaximized(child) &&
- !window_util::IsWindowFullscreen(child))) {
+ !workspace_manager_->IsManagedWindow(child)) {
+ // Allow requests for |ignored_window_| or unmanaged windows.
SetChildBoundsDirect(child, requested_bounds);
+ } else if (!window_util::IsWindowMaximized(child) &&
+ !window_util::IsWindowFullscreen(child)) {
+ // Align normal windows to the grid.
+ SetChildBoundsDirect(
+ child, workspace_manager_->AlignBoundsToGrid(requested_bounds));
}
+ // All other requests we ignore.
}
} // namespace internal
diff --git a/ash/wm/workspace/workspace_layout_manager.h b/ash/wm/workspace/workspace_layout_manager.h
index 4a1ca87..7be5143 100644
--- a/ash/wm/workspace/workspace_layout_manager.h
+++ b/ash/wm/workspace/workspace_layout_manager.h
@@ -46,10 +46,10 @@ class ASH_EXPORT WorkspaceLayoutManager : public aura::LayoutManager {
void ProcessMove(aura::Window* window, aura::MouseEvent* event);
// Invoked when a user finished moving window.
- void EndMove(aura::Window* drag, aura::MouseEvent* evnet);
+ void EndMove(aura::Window* drag, aura::MouseEvent* event);
// Invoked when a user finished resizing window.
- void EndResize(aura::Window* drag, aura::MouseEvent* evnet);
+ void EndResize(aura::Window* drag, aura::MouseEvent* event);
// Overridden from aura::LayoutManager:
virtual void OnWindowResized() OVERRIDE;
diff --git a/ash/wm/workspace/workspace_manager.cc b/ash/wm/workspace/workspace_manager.cc
index 9fc41e9..78cd418 100644
--- a/ash/wm/workspace/workspace_manager.cc
+++ b/ash/wm/workspace/workspace_manager.cc
@@ -46,6 +46,24 @@ void SetWindowLayerVisibility(const std::vector<aura::Window*>& windows,
}
}
+// TODO(sky): this is a copy of that in ToplevelWindowEventFilter. Figure out
+// the right place to put it.
+int AlignToGrid(int location, int grid_size) {
+ if (grid_size <= 1 || location % grid_size == 0)
+ return location;
+ return floor(static_cast<float>(location) / static_cast<float>(grid_size) +
+ .5f) * grid_size;
+}
+
+gfx::Rect AlignRectToGrid(const gfx::Rect& rect, int grid_size) {
+ if (grid_size <= 1)
+ return rect;
+ return gfx::Rect(AlignToGrid(rect.x(), grid_size),
+ AlignToGrid(rect.y(), grid_size),
+ AlignToGrid(rect.width(), grid_size),
+ AlignToGrid(rect.height(), grid_size));
+}
+
}
namespace ash {
@@ -54,13 +72,18 @@ namespace internal {
////////////////////////////////////////////////////////////////////////////////
// WindowManager, public:
+// static
+const int WorkspaceManager::kOpenMaximizedThreshold = 1600;
+
WorkspaceManager::WorkspaceManager(aura::Window* contents_view)
: contents_view_(contents_view),
active_workspace_(NULL),
workspace_size_(
gfx::Screen::GetMonitorAreaNearestWindow(contents_view_).size()),
is_overview_(false),
- ignored_window_(NULL) {
+ ignored_window_(NULL),
+ grid_size_(0),
+ open_new_windows_maximized_(true) {
DCHECK(contents_view);
}
@@ -79,27 +102,39 @@ bool WorkspaceManager::IsManagedWindow(aura::Window* window) const {
!window->transient_parent();
}
+bool WorkspaceManager::ShouldMaximize(aura::Window* window) const {
+ return !window->GetProperty(aura::client::kShowStateKey) &&
+ open_new_windows_maximized_ &&
+ contents_view_->bounds().width() < kOpenMaximizedThreshold;
+}
+
void WorkspaceManager::AddWindow(aura::Window* window) {
DCHECK(IsManagedWindow(window));
if (FindBy(window))
return; // Already know about this window.
- window->AddObserver(this);
-
if (!window->GetProperty(aura::client::kShowStateKey)) {
- // TODO: set maximized if width < x.
- window->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
+ if (ShouldMaximize(window)) {
+ window->SetIntProperty(aura::client::kShowStateKey,
+ ui::SHOW_STATE_MAXIMIZED);
+ } else {
+ window->SetIntProperty(aura::client::kShowStateKey,
+ ui::SHOW_STATE_NORMAL);
+ }
}
- // TODO: handle fullscreen.
- if (window_util::IsWindowMaximized(window)) {
- if (!GetRestoreBounds(window))
- SetRestoreBounds(window, window->GetTargetBounds());
- else
- SetWindowBounds(window, GetWorkAreaBounds());
+ if (window_util::IsWindowMaximized(window) ||
+ window_util::IsWindowFullscreen(window)) {
+ SetFullScreenOrMaximizedBounds(window);
+ } else {
+ if (grid_size_ > 1)
+ SetWindowBounds(window, AlignBoundsToGrid(window->GetTargetBounds()));
}
+ // Add the observer after we change the state in anyway.
+ window->AddObserver(this);
+
Workspace* workspace = NULL;
Workspace::Type type_for_window = Workspace::TypeForWindow(window);
switch (type_for_window) {
@@ -178,6 +213,12 @@ void WorkspaceManager::SetWorkspaceSize(const gfx::Size& workspace_size) {
}
}
+gfx::Rect WorkspaceManager::AlignBoundsToGrid(const gfx::Rect& bounds) {
+ if (grid_size_ <= 1)
+ return bounds;
+ return AlignRectToGrid(bounds, grid_size_);
+}
+
void WorkspaceManager::OnWindowPropertyChanged(aura::Window* window,
const char* name,
void* old) {
@@ -186,14 +227,18 @@ void WorkspaceManager::OnWindowPropertyChanged(aura::Window* window,
if (name != aura::client::kShowStateKey)
return;
- // TODO: handle fullscreen.
- bool is_maximized = window->GetIntProperty(name) == ui::SHOW_STATE_MAXIMIZED;
- bool was_maximized =
- (old == reinterpret_cast<void*>(ui::SHOW_STATE_MAXIMIZED));
- if (is_maximized == was_maximized)
- return;
- MaximizedStateChanged(window);
+ DCHECK(FindBy(window));
+
+ Workspace::Type old_type = FindBy(window)->type();
+ Workspace::Type new_type = Workspace::TypeForWindow(window);
+ if (new_type != old_type) {
+ OnTypeOfWorkspacedNeededChanged(window);
+ } else if (new_type == Workspace::TYPE_MAXIMIZED) {
+ // Even though the type didn't change, the window may have gone from
+ // maximized to fullscreen. Adjust the bounds appropriately.
+ SetFullScreenOrMaximizedBounds(window);
+ }
}
////////////////////////////////////////////////////////////////////////////////
@@ -272,8 +317,6 @@ int WorkspaceManager::GetWorkspaceIndexContaining(aura::Window* window) const {
void WorkspaceManager::SetWindowBounds(aura::Window* window,
const gfx::Rect& bounds) {
- // TODO: I suspect it's possible for this to be invoked when ignored_window_
- // is non-NULL.
ignored_window_ = window;
window->SetBounds(bounds);
ignored_window_ = NULL;
@@ -283,25 +326,33 @@ void WorkspaceManager::SetWindowBoundsFromRestoreBounds(aura::Window* window) {
Workspace* workspace = FindBy(window);
DCHECK(workspace);
const gfx::Rect* restore = GetRestoreBounds(window);
+ gfx::Rect bounds;
if (restore) {
- SetWindowBounds(window,
- restore->AdjustToFit(workspace->GetWorkAreaBounds()));
+ bounds = restore->AdjustToFit(workspace->GetWorkAreaBounds());
} else {
- SetWindowBounds(window, window->bounds().AdjustToFit(
- workspace->GetWorkAreaBounds()));
+ bounds = window->bounds().AdjustToFit(workspace->GetWorkAreaBounds());
}
+ SetWindowBounds(window, AlignRectToGrid(bounds, grid_size_));
ash::ClearRestoreBounds(window);
}
-void WorkspaceManager::MaximizedStateChanged(aura::Window* window) {
+void WorkspaceManager::SetFullScreenOrMaximizedBounds(aura::Window* window) {
+ if (!GetRestoreBounds(window))
+ SetRestoreBounds(window, window->GetTargetBounds());
+ if (window_util::IsWindowMaximized(window))
+ SetWindowBounds(window, GetWorkAreaBounds());
+ else if (window_util::IsWindowFullscreen(window))
+ SetWindowBounds(window, gfx::Screen::GetMonitorAreaNearestWindow(window));
+}
+
+void WorkspaceManager::OnTypeOfWorkspacedNeededChanged(aura::Window* window) {
+ // TODO: needs to handle transitioning to split.
DCHECK(IsManagedWindow(window));
- bool is_maximized = window_util::IsWindowMaximized(window);
Workspace* current_workspace = FindBy(window);
DCHECK(current_workspace);
- if (is_maximized) {
+ if (Workspace::TypeForWindow(window) == Workspace::TYPE_MAXIMIZED) {
// Unmaximized -> maximized; create a new workspace (unless current only has
// one window).
- SetRestoreBounds(window, window->GetTargetBounds());
if (current_workspace->num_windows() != 1) {
current_workspace->RemoveWindow(window);
Workspace* workspace = new Workspace(this);
@@ -311,7 +362,7 @@ void WorkspaceManager::MaximizedStateChanged(aura::Window* window) {
} else {
current_workspace->SetType(Workspace::TYPE_MAXIMIZED);
}
- SetWindowBounds(window, GetWorkAreaBounds());
+ SetFullScreenOrMaximizedBounds(window);
} else {
// Maximized -> unmaximized; move window to unmaximized workspace (or reuse
// current if there isn't one).
@@ -326,10 +377,8 @@ void WorkspaceManager::MaximizedStateChanged(aura::Window* window) {
} else {
current_workspace->SetType(Workspace::TYPE_NORMAL);
}
-
SetWindowBoundsFromRestoreBounds(window);
}
-
SetActiveWorkspace(current_workspace);
}
diff --git a/ash/wm/workspace/workspace_manager.h b/ash/wm/workspace/workspace_manager.h
index 055893e..b081cb2 100644
--- a/ash/wm/workspace/workspace_manager.h
+++ b/ash/wm/workspace/workspace_manager.h
@@ -31,12 +31,19 @@ class WorkspaceManagerTest;
// WorkspaceManager manages multiple workspaces in the desktop.
class ASH_EXPORT WorkspaceManager : public aura::WindowObserver{
public:
+ // If open_new_windows_maximized() is true and the size of the viewport is
+ // smaller than this value, newly created windows are forced maximized.
+ static const int kOpenMaximizedThreshold;
+
explicit WorkspaceManager(aura::Window* viewport);
virtual ~WorkspaceManager();
// Returns true if |window| should be managed by the WorkspaceManager.
bool IsManagedWindow(aura::Window* window) const;
+ // Returns true if |window| should be maximized.
+ bool ShouldMaximize(aura::Window* window) const;
+
// Adds/removes a window creating/destroying workspace as necessary.
void AddWindow(aura::Window* window);
void RemoveWindow(aura::Window* window);
@@ -62,13 +69,28 @@ class ASH_EXPORT WorkspaceManager : public aura::WindowObserver{
// Sets the size of a single workspace (all workspaces have the same size).
void SetWorkspaceSize(const gfx::Size& workspace_size);
- // Sets/Returns the ignored window that the workspace manager does not
- // set bounds on.
- void set_ignored_window(aura::Window* ignored_window) {
- ignored_window_ = ignored_window;
- }
+ // Returns the window the layout manager should allow the size to be set for.
+ // TODO: maybe this should be set on WorkspaceLayoutManager.
aura::Window* ignored_window() { return ignored_window_; }
+ // Sets whether newly added windows open maximized. This is only applicable if
+ // the size of the root window is less than kOpenMaximizedThreshold. Default
+ // is true.
+ void set_open_new_windows_maximized(bool value) {
+ open_new_windows_maximized_ = value;
+ }
+ bool open_new_windows_maximized() const {
+ return open_new_windows_maximized_;
+ }
+
+ // Sets the size of the grid. Newly added windows are forced to align to the
+ // size of the grid.
+ void set_grid_size(int size) { grid_size_ = size; }
+ int grid_size() const { return grid_size_; }
+
+ // Returns a bounds aligned to the grid. Returns |bounds| if grid_size is 0.
+ gfx::Rect AlignBoundsToGrid(const gfx::Rect& bounds);
+
// Overriden from aura::WindowObserver:
virtual void OnWindowPropertyChanged(aura::Window* window,
const char* name,
@@ -78,6 +100,11 @@ class ASH_EXPORT WorkspaceManager : public aura::WindowObserver{
friend class Workspace;
friend class WorkspaceManagerTest;
+ // See description above getter.
+ void set_ignored_window(aura::Window* ignored_window) {
+ ignored_window_ = ignored_window;
+ }
+
void AddWorkspace(Workspace* workspace);
void RemoveWorkspace(Workspace* workspace);
@@ -104,8 +131,11 @@ class ASH_EXPORT WorkspaceManager : public aura::WindowObserver{
// it fits in the the windows current workspace.
void SetWindowBoundsFromRestoreBounds(aura::Window* window);
- // Invoked when the maximized state of |window| changes.
- void MaximizedStateChanged(aura::Window* window);
+ // Reset the bounds of |window|. Use when |window| is fullscreen or maximized.
+ void SetFullScreenOrMaximizedBounds(aura::Window* window);
+
+ // Invoked when the type of workspace needed for |window| changes.
+ void OnTypeOfWorkspacedNeededChanged(aura::Window* window);
// Returns the Workspace whose type is TYPE_NORMAL, or NULL if there isn't
// one.
@@ -127,6 +157,12 @@ class ASH_EXPORT WorkspaceManager : public aura::WindowObserver{
// The window that WorkspaceManager does not set the bounds on.
aura::Window* ignored_window_;
+ // See description above setter.
+ int grid_size_;
+
+ // See description above setter.
+ bool open_new_windows_maximized_;
+
DISALLOW_COPY_AND_ASSIGN(WorkspaceManager);
};
diff --git a/ash/wm/workspace/workspace_manager_unittest.cc b/ash/wm/workspace/workspace_manager_unittest.cc
index 623ffe4..2c736cc 100644
--- a/ash/wm/workspace/workspace_manager_unittest.cc
+++ b/ash/wm/workspace/workspace_manager_unittest.cc
@@ -6,6 +6,8 @@
#include "ash/shell_window_ids.h"
#include "ash/wm/activation_controller.h"
+#include "ash/wm/property_util.h"
+#include "ash/wm/window_util.h"
#include "ash/wm/workspace/workspace.h"
#include "ash/wm/workspace/workspace_layout_manager.h"
#include "ui/aura/client/aura_constants.h"
@@ -14,6 +16,7 @@
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/window.h"
#include "ui/base/ui_base_types.h"
+#include "ui/gfx/screen.h"
using aura::Window;
@@ -43,8 +46,17 @@ class WorkspaceManagerTest : public aura::test::AuraTestBase {
aura::test::AuraTestBase::TearDown();
}
+ aura::Window* CreateTestWindowUnparented() {
+ aura::Window* window = new aura::Window(NULL);
+ window->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
+ window->SetType(aura::client::WINDOW_TYPE_NORMAL);
+ window->Init(ui::Layer::LAYER_TEXTURED);
+ return window;
+ }
+
aura::Window* CreateTestWindow() {
aura::Window* window = new aura::Window(NULL);
+ window->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
window->SetType(aura::client::WINDOW_TYPE_NORMAL);
window->Init(ui::Layer::LAYER_TEXTURED);
window->SetParent(viewport());
@@ -63,6 +75,10 @@ class WorkspaceManagerTest : public aura::test::AuraTestBase {
return manager_->GetWorkAreaBounds();
}
+ gfx::Rect GetFullscreenBounds(aura::Window* window) {
+ return gfx::Screen::GetMonitorAreaNearestWindow(window);
+ }
+
Workspace* active_workspace() {
return manager_->active_workspace_;
}
@@ -284,5 +300,106 @@ TEST_F(WorkspaceManagerTest, ChangeBoundsOfNormalWindow) {
EXPECT_EQ(500, w1->bounds().height());
}
+// Assertions around open new windows maximized.
+TEST_F(WorkspaceManagerTest, OpenNewWindowsMaximized) {
+ scoped_ptr<Window> w1(CreateTestWindowUnparented());
+
+ // Default is true for open new windows maximized.
+ EXPECT_TRUE(manager_->open_new_windows_maximized());
+ // SHOW_STATE_DEFAULT should end up maximized.
+ w1->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_DEFAULT);
+ w1->SetBounds(gfx::Rect(50, 51, 52, 53));
+ w1->SetParent(viewport());
+ // Maximized state and bounds should be set as soon as w1 is added to the
+ // parent.
+ EXPECT_TRUE(window_util::IsWindowMaximized(w1.get()));
+ EXPECT_EQ(gfx::Screen::GetMonitorWorkAreaNearestWindow(w1.get()),
+ w1->bounds());
+ w1->Show();
+ EXPECT_TRUE(window_util::IsWindowMaximized(w1.get()));
+ EXPECT_EQ(gfx::Screen::GetMonitorWorkAreaNearestWindow(w1.get()),
+ w1->bounds());
+ // Restored bounds should be saved.
+ ASSERT_TRUE(GetRestoreBounds(w1.get()));
+ EXPECT_EQ(gfx::Rect(50, 51, 52, 53), *GetRestoreBounds(w1.get()));
+
+ // Show state normal should end up normal.
+ scoped_ptr<Window> w2(CreateTestWindow());
+ w2->SetBounds(gfx::Rect(60, 61, 62, 63));
+ w2->Show();
+ EXPECT_EQ(gfx::Rect(60, 61, 62, 63), w2->bounds());
+ EXPECT_EQ(ui::SHOW_STATE_NORMAL,
+ w2->GetIntProperty(aura::client::kShowStateKey));
+
+ // If open news windows maximized is false, SHOW_STATE_DEFAULT should end as
+ // SHOW_STATE_NORMAL.
+ manager_->set_open_new_windows_maximized(false);
+ scoped_ptr<Window> w3(CreateTestWindowUnparented());
+ // Show state default should end up normal when open new windows maximized is
+ // false.
+ w3->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_DEFAULT);
+ w3->SetBounds(gfx::Rect(70, 71, 72, 73));
+ w3->SetParent(viewport());
+ w3->Show();
+ EXPECT_EQ(gfx::Rect(70, 71, 72, 73), w3->bounds());
+ EXPECT_EQ(ui::SHOW_STATE_NORMAL,
+ w3->GetIntProperty(aura::client::kShowStateKey));
+}
+
+// Assertions around grid size.
+TEST_F(WorkspaceManagerTest, SnapToGrid) {
+ manager_->set_grid_size(8);
+
+ // Verify snap to grid when bounds are set before parented.
+ scoped_ptr<Window> w1(CreateTestWindowUnparented());
+ w1->SetBounds(gfx::Rect(1, 6, 25, 30));
+ w1->SetParent(viewport());
+ EXPECT_EQ(gfx::Rect(0, 8, 24, 32), w1->bounds());
+
+ // Verify snap to grid when bounds are set after parented.
+ w1.reset(CreateTestWindow());
+ w1->SetBounds(gfx::Rect(1, 6, 25, 30));
+ EXPECT_EQ(gfx::Rect(0, 8, 24, 32), w1->bounds());
+}
+
+// Assertions around a fullscreen window.
+TEST_F(WorkspaceManagerTest, SingleFullscreenWindow) {
+ scoped_ptr<Window> w1(CreateTestWindow());
+ w1->SetBounds(gfx::Rect(0, 0, 250, 251));
+ // Make the window fullscreen.
+ w1->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
+ w1->Show();
+
+ // Should be 1 workspace, TYPE_MAXIMIZED with w1.
+ ASSERT_EQ(1u, workspaces().size());
+ EXPECT_EQ(Workspace::TYPE_MAXIMIZED, workspaces()[0]->type());
+ ASSERT_EQ(1u, workspaces()[0]->windows().size());
+ EXPECT_EQ(w1.get(), workspaces()[0]->windows()[0]);
+ EXPECT_EQ(GetFullscreenBounds(w1.get()).width(), w1->bounds().width());
+ EXPECT_EQ(GetFullscreenBounds(w1.get()).height(), w1->bounds().height());
+
+ // Restore the window.
+ w1->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
+
+ // Should be 1 workspace, TYPE_NORMAL with w1.
+ ASSERT_EQ(1u, workspaces().size());
+ EXPECT_EQ(Workspace::TYPE_NORMAL, workspaces()[0]->type());
+ ASSERT_EQ(1u, workspaces()[0]->windows().size());
+ EXPECT_EQ(w1.get(), workspaces()[0]->windows()[0]);
+ EXPECT_EQ(250, w1->bounds().width());
+ EXPECT_EQ(251, w1->bounds().height());
+
+ // Back to fullscreen.
+ w1->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
+ ASSERT_EQ(1u, workspaces().size());
+ EXPECT_EQ(Workspace::TYPE_MAXIMIZED, workspaces()[0]->type());
+ ASSERT_EQ(1u, workspaces()[0]->windows().size());
+ EXPECT_EQ(w1.get(), workspaces()[0]->windows()[0]);
+ EXPECT_EQ(GetFullscreenBounds(w1.get()).width(), w1->bounds().width());
+ EXPECT_EQ(GetFullscreenBounds(w1.get()).height(), w1->bounds().height());
+ ASSERT_TRUE(GetRestoreBounds(w1.get()));
+ EXPECT_EQ(gfx::Rect(0, 0, 250, 251), *GetRestoreBounds(w1.get()));
+}
+
} // namespace internal
} // namespace ash
diff --git a/ash/wm/workspace_controller.cc b/ash/wm/workspace_controller.cc
index 8f9d7cf..b91cdeb 100644
--- a/ash/wm/workspace_controller.cc
+++ b/ash/wm/workspace_controller.cc
@@ -4,31 +4,45 @@
#include "ash/wm/workspace_controller.h"
-#include "ash/launcher/launcher.h"
-#include "ash/launcher/launcher_model.h"
#include "ash/shell.h"
#include "ash/wm/window_util.h"
+#include "ash/wm/workspace/workspace_event_filter.h"
#include "ash/wm/workspace/workspace_layout_manager.h"
#include "ash/wm/workspace/workspace_manager.h"
+#include "base/utf_string_conversions.h"
#include "ui/aura/client/activation_client.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
+#include "ui/views/controls/menu/menu_model_adapter.h"
+#include "ui/views/controls/menu/menu_runner.h"
namespace ash {
namespace internal {
+namespace {
+
+// Size of the grid when a grid is enabled.
+const int kGridSize = 8;
+
+} // namespace
+
WorkspaceController::WorkspaceController(aura::Window* viewport)
- : workspace_manager_(new WorkspaceManager(viewport)),
- launcher_model_(NULL),
- ignore_move_event_(false) {
+ : viewport_(viewport),
+ workspace_manager_(new WorkspaceManager(viewport)),
+ layout_manager_(NULL),
+ event_filter_(NULL) {
+ event_filter_ = new WorkspaceEventFilter(viewport);
+ viewport->SetEventFilter(event_filter_);
+ layout_manager_ = new WorkspaceLayoutManager(workspace_manager_.get());
+ viewport->SetLayoutManager(layout_manager_);
aura::RootWindow::GetInstance()->AddRootWindowObserver(this);
aura::RootWindow::GetInstance()->AddObserver(this);
+ workspace_manager_->set_grid_size(kGridSize);
+ event_filter_->set_grid_size(kGridSize);
}
WorkspaceController::~WorkspaceController() {
- if (launcher_model_)
- launcher_model_->RemoveObserver(this);
aura::RootWindow::GetInstance()->RemoveObserver(this);
aura::RootWindow::GetInstance()->RemoveRootWindowObserver(this);
}
@@ -37,22 +51,28 @@ void WorkspaceController::ToggleOverview() {
workspace_manager_->SetOverview(!workspace_manager_->is_overview());
}
-void WorkspaceController::SetLauncherModel(LauncherModel* launcher_model) {
- DCHECK(!launcher_model_);
- launcher_model_ = launcher_model;
- launcher_model_->AddObserver(this);
+void WorkspaceController::ShowMenu(views::Widget* widget,
+ const gfx::Point& location) {
+ ui::SimpleMenuModel menu_model(this);
+ // This is just for testing and will be ripped out before we ship, so none of
+ // the strings are localized.
+ menu_model.AddCheckItem(MENU_SNAP_TO_GRID,
+ ASCIIToUTF16("Snap to grid"));
+ menu_model.AddCheckItem(MENU_OPEN_MAXIMIZED,
+ ASCIIToUTF16("Maximize new windows"));
+ views::MenuModelAdapter menu_model_adapter(&menu_model);
+ menu_runner_.reset(new views::MenuRunner(menu_model_adapter.CreateMenu()));
+ if (menu_runner_->RunMenuAt(
+ widget, NULL, gfx::Rect(location, gfx::Size()),
+ views::MenuItemView::TOPRIGHT, views::MenuRunner::HAS_MNEMONICS) ==
+ views::MenuRunner::MENU_DELETED)
+ return;
}
-////////////////////////////////////////////////////////////////////////////////
-// WorkspaceController, aura::RootWindowObserver overrides:
-
void WorkspaceController::OnRootWindowResized(const gfx::Size& new_size) {
workspace_manager_->SetWorkspaceSize(new_size);
}
-////////////////////////////////////////////////////////////////////////////////
-// WorkspaceController, aura::WindowObserver overrides:
-
void WorkspaceController::OnWindowPropertyChanged(aura::Window* window,
const char* key,
void* old) {
@@ -60,27 +80,62 @@ void WorkspaceController::OnWindowPropertyChanged(aura::Window* window,
workspace_manager_->SetActiveWorkspaceByWindow(GetActiveWindow());
}
-////////////////////////////////////////////////////////////////////////////////
-// WorkspaceController, ash::LauncherModelObserver overrides:
+bool WorkspaceController::IsCommandIdChecked(int command_id) const {
+ switch (static_cast<MenuItem>(command_id)) {
+ case MENU_SNAP_TO_GRID:
+ return workspace_manager_->grid_size() != 0;
+
+ case MENU_OPEN_MAXIMIZED:
+ return workspace_manager_->open_new_windows_maximized();
-void WorkspaceController::LauncherItemAdded(int index) {
+ default:
+ break;
+ }
+ return false;
}
-void WorkspaceController::LauncherItemRemoved(int index) {
+bool WorkspaceController::IsCommandIdEnabled(int command_id) const {
+ switch (static_cast<MenuItem>(command_id)) {
+ case MENU_OPEN_MAXIMIZED:
+ return workspace_manager_->contents_view()->bounds().width() <
+ WorkspaceManager::kOpenMaximizedThreshold;
+
+ default:
+ return true;
+ }
+ return true;
}
-void WorkspaceController::LauncherItemMoved(int start_index, int target_index) {
- if (ignore_move_event_)
- return;
- // TODO: there is no longer a 1-1 mapping between the launcher and windows;
- // decide how we want to handle it.
- DCHECK(launcher_model_);
- NOTIMPLEMENTED();
+void WorkspaceController::ExecuteCommand(int command_id) {
+ switch (static_cast<MenuItem>(command_id)) {
+ case MENU_SNAP_TO_GRID: {
+ int size = workspace_manager_->grid_size() == 0 ? kGridSize : 0;
+ workspace_manager_->set_grid_size(size);
+ event_filter_->set_grid_size(size);
+ if (!size)
+ return;
+ for (size_t i = 0; i < viewport_->children().size(); ++i) {
+ aura::Window* window = viewport_->children()[i];
+ if (!window_util::IsWindowMaximized(window) &&
+ !window_util::IsWindowFullscreen(window)) {
+ window->SetBounds(workspace_manager_->AlignBoundsToGrid(
+ window->GetTargetBounds()));
+ }
+ }
+ break;
+ }
+
+ case MENU_OPEN_MAXIMIZED:
+ workspace_manager_->set_open_new_windows_maximized(
+ !workspace_manager_->open_new_windows_maximized());
+ break;
+ }
}
-void WorkspaceController::LauncherItemChanged(
- int index,
- const ash::LauncherItem& old_item) {
+bool WorkspaceController::GetAcceleratorForCommandId(
+ int command_id,
+ ui::Accelerator* accelerator) {
+ return false;
}
} // namespace internal
diff --git a/ash/wm/workspace_controller.h b/ash/wm/workspace_controller.h
index 9e541d9..b582898 100644
--- a/ash/wm/workspace_controller.h
+++ b/ash/wm/workspace_controller.h
@@ -6,48 +6,55 @@
#define ASH_WM_WORKSPACE_CONTROLLER_H_
#pragma once
-#include "ash/launcher/launcher_model_observer.h"
+#include "ash/ash_export.h"
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "ui/aura/root_window_observer.h"
#include "ui/aura/window_observer.h"
-#include "ash/ash_export.h"
+#include "ui/base/models/simple_menu_model.h"
namespace aura {
class Window;
}
namespace gfx {
+class Point;
class Size;
}
-namespace ash {
-class LauncherModel;
+namespace views {
+class MenuRunner;
+class Widget;
+}
+namespace ash {
namespace internal {
+class WorkspaceEventFilter;
+class WorkspaceLayoutManager;
class WorkspaceManager;
-// WorkspaceController owns a WorkspaceManager. WorkspaceController bridges
-// events from RootWindowObserver translating them to WorkspaceManager, and
-// a move event between Launcher and Workspace.
+// WorkspaceController acts as a central place that ties together all the
+// various workspace pieces: WorkspaceManager, WorkspaceLayoutManager and
+// WorkspaceEventFilter.
class ASH_EXPORT WorkspaceController :
public aura::RootWindowObserver,
public aura::WindowObserver,
- public ash::LauncherModelObserver {
+ public ui::SimpleMenuModel::Delegate {
public:
- explicit WorkspaceController(aura::Window* workspace_viewport);
+ explicit WorkspaceController(aura::Window* viewport);
virtual ~WorkspaceController();
void ToggleOverview();
- void SetLauncherModel(LauncherModel* launcher_model);
-
// Returns the workspace manager that this controler owns.
WorkspaceManager* workspace_manager() {
return workspace_manager_.get();
}
+ // Shows the menu allowing you to configure various aspects of workspaces.
+ void ShowMenu(views::Widget* widget, const gfx::Point& location);
+
// aura::RootWindowObserver overrides:
virtual void OnRootWindowResized(const gfx::Size& new_size) OVERRIDE;
@@ -56,23 +63,31 @@ class ASH_EXPORT WorkspaceController :
const char* key,
void* old) OVERRIDE;
- // Invoked after an item has been added to the model.
- virtual void LauncherItemAdded(int index) OVERRIDE;
- virtual void LauncherItemRemoved(int index) OVERRIDE;
- virtual void LauncherItemMoved(int start_index, int target_index) OVERRIDE;
- virtual void LauncherItemChanged(int index,
- const ash::LauncherItem& old_item) OVERRIDE;
- virtual void LauncherItemWillChange(int index) OVERRIDE {}
+ // ui::SimpleMenuModel::Delegate overrides:
+ virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
+ virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
+ virtual void ExecuteCommand(int command_id) OVERRIDE;
+ virtual bool GetAcceleratorForCommandId(
+ int command_id,
+ ui::Accelerator* accelerator) OVERRIDE;
private:
+ enum MenuItem {
+ MENU_SNAP_TO_GRID,
+ MENU_OPEN_MAXIMIZED,
+ };
+
+ aura::Window* viewport_;
+
scoped_ptr<WorkspaceManager> workspace_manager_;
- // Owned by Launcher.
- LauncherModel* launcher_model_;
+ // Owned by the window its attached to.
+ WorkspaceLayoutManager* layout_manager_;
+
+ // Owned the window set on.
+ WorkspaceEventFilter* event_filter_;
- // True while the controller is moving window either on workspace or launcher.
- // Used to prevent infinite recursive call between the workspace and launcher.
- bool ignore_move_event_;
+ scoped_ptr<views::MenuRunner> menu_runner_;
DISALLOW_COPY_AND_ASSIGN(WorkspaceController);
};