summaryrefslogtreecommitdiffstats
path: root/ash/wm
diff options
context:
space:
mode:
authornsatragno@chromium.org <nsatragno@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-29 19:11:08 +0000
committernsatragno@chromium.org <nsatragno@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-29 19:11:08 +0000
commitdf547c6d208020e0cf6da2f4075e0b5c399b3db5 (patch)
tree353d275fc73eefd9cd01928d36462d54e4727137 /ash/wm
parent78a68137b2ac1e0e4b8bf7d574eaaa44287ce854 (diff)
downloadchromium_src-df547c6d208020e0cf6da2f4075e0b5c399b3db5.zip
chromium_src-df547c6d208020e0cf6da2f4075e0b5c399b3db5.tar.gz
chromium_src-df547c6d208020e0cf6da2f4075e0b5c399b3db5.tar.bz2
Using tap gesture instead of touch to activate windows in overview mode
This brings some improvements over the old touch event handling: * Window is activated on the full tap gesture, which is consistent with the mouse click event handling. * The user can now cancel the gesture by sliding the finger out of the window bounds without releasing it (not activating any window). * In the future it is going to be much easier to add support for other gestures, e.g. fling to dismiss. Just handling the tap is not sufficient as the browser window might consume touches, therefore preventing the generation of tap gestures under our current architecture. To circumvent this, I'm adding a transparent window on top of the overview items, which covers the entire bounding box. An added feature is that the transparent window covers the entire bounding box, even for panels, making them easier to click. As a subproduct of this patch locking the cursor is no longer necessary, so we fix a bug related to that, too. Finally, by handling the OnWindowActivated instead of manually restoring the windows when they are clicked, we fix a bug caused by activating the window from the shelf. BUG=336601,322688,368671,374283 TEST=WindowSelectorTest.BasicGesture, WindowSelectorTest.WindowDoesNotReceiveEvents, WindowSelectorTest.CloseButton Review URL: https://codereview.chromium.org/269423008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@273537 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash/wm')
-rw-r--r--ash/wm/maximize_mode/maximize_mode_window_manager.cc2
-rw-r--r--ash/wm/overview/scoped_transform_overview_window.cc4
-rw-r--r--ash/wm/overview/scoped_transform_overview_window.h10
-rw-r--r--ash/wm/overview/transparent_activate_window_button.cc72
-rw-r--r--ash/wm/overview/transparent_activate_window_button.h39
-rw-r--r--ash/wm/overview/window_selector.cc126
-rw-r--r--ash/wm/overview/window_selector.h26
-rw-r--r--ash/wm/overview/window_selector_controller.cc15
-rw-r--r--ash/wm/overview/window_selector_controller.h3
-rw-r--r--ash/wm/overview/window_selector_delegate.h7
-rw-r--r--ash/wm/overview/window_selector_item.cc33
-rw-r--r--ash/wm/overview/window_selector_item.h15
-rw-r--r--ash/wm/overview/window_selector_panels.cc68
-rw-r--r--ash/wm/overview/window_selector_panels.h3
-rw-r--r--ash/wm/overview/window_selector_unittest.cc115
-rw-r--r--ash/wm/overview/window_selector_window.cc6
-rw-r--r--ash/wm/overview/window_selector_window.h2
17 files changed, 333 insertions, 213 deletions
diff --git a/ash/wm/maximize_mode/maximize_mode_window_manager.cc b/ash/wm/maximize_mode/maximize_mode_window_manager.cc
index 15278bf..788f3bf 100644
--- a/ash/wm/maximize_mode/maximize_mode_window_manager.cc
+++ b/ash/wm/maximize_mode/maximize_mode_window_manager.cc
@@ -31,7 +31,7 @@ void CancelOverview() {
WindowSelectorController* controller =
Shell::GetInstance()->window_selector_controller();
if (controller && controller->IsSelecting())
- controller->OnSelectionCanceled();
+ controller->OnSelectionEnded();
}
} // namespace
diff --git a/ash/wm/overview/scoped_transform_overview_window.cc b/ash/wm/overview/scoped_transform_overview_window.cc
index bf7cff9..afc5b00 100644
--- a/ash/wm/overview/scoped_transform_overview_window.cc
+++ b/ash/wm/overview/scoped_transform_overview_window.cc
@@ -5,9 +5,11 @@
#include "ash/wm/overview/scoped_transform_overview_window.h"
#include "ash/screen_util.h"
-#include "ash/shell.h"
+#include "ash/shell_window_ids.h"
#include "ash/wm/overview/scoped_window_copy.h"
+#include "ash/wm/overview/window_selector_item.h"
#include "ash/wm/window_state.h"
+#include "ash/wm/window_util.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/window.h"
diff --git a/ash/wm/overview/scoped_transform_overview_window.h b/ash/wm/overview/scoped_transform_overview_window.h
index 2bc1b0f..7338754 100644
--- a/ash/wm/overview/scoped_transform_overview_window.h
+++ b/ash/wm/overview/scoped_transform_overview_window.h
@@ -6,9 +6,11 @@
#define ASH_WM_OVERVIEW_SCOPED_TRANSFORM_OVERVIEW_WINDOW_H_
#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/transform.h"
+#include "ui/views/widget/widget.h"
namespace aura {
class Window;
@@ -49,7 +51,7 @@ class ScopedTransformOverviewWindow {
virtual ~ScopedTransformOverviewWindow();
// Returns true if this window selector window contains the |target|. This is
- // used to determine if an event targetted this window.
+ // used to determine if an event targeted this window.
bool Contains(const aura::Window* target) const;
// Returns the original bounds of all transformed windows.
@@ -73,9 +75,9 @@ class ScopedTransformOverviewWindow {
// Sets |transform| on the window and a copy of the window if the target
// |root_window| is not the window's root window. If |animate| the transform
// is animated in, otherwise it is immediately applied.
- void SetTransform(aura::Window* root_window,
- const gfx::Transform& transform,
- bool animate);
+ virtual void SetTransform(aura::Window* root_window,
+ const gfx::Transform& transform,
+ bool animate);
aura::Window* window() const { return window_; }
diff --git a/ash/wm/overview/transparent_activate_window_button.cc b/ash/wm/overview/transparent_activate_window_button.cc
new file mode 100644
index 0000000..216f0f3
--- /dev/null
+++ b/ash/wm/overview/transparent_activate_window_button.cc
@@ -0,0 +1,72 @@
+// Copyright 2014 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/overview/transparent_activate_window_button.h"
+
+#include "ash/shell.h"
+#include "ash/shell_window_ids.h"
+#include "ash/wm/window_state.h"
+#include "ui/views/controls/button/custom_button.h"
+#include "ui/views/widget/widget.h"
+
+namespace ash {
+
+namespace {
+
+// Transparent button that handles events which activate windows in overview
+// mode.
+class TransparentButton : public views::CustomButton {
+ public:
+ explicit TransparentButton(views::ButtonListener* listener)
+ : CustomButton(listener) {
+ }
+ virtual ~TransparentButton() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TransparentButton);
+};
+
+// Initializes the event handler transparent window.
+views::Widget* InitEventHandler(aura::Window* root_window) {
+ views::Widget* widget = new views::Widget;
+ views::Widget::InitParams params;
+ params.type = views::Widget::InitParams::TYPE_POPUP;
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
+ params.accept_events = true;
+ params.parent = Shell::GetContainer(root_window,
+ ash::kShellWindowId_OverlayContainer);
+ widget->set_focus_on_creation(false);
+ widget->Init(params);
+ widget->Show();
+
+ aura::Window* handler = widget->GetNativeWindow();
+ handler->parent()->StackChildAtBottom(handler);
+
+ return widget;
+}
+
+} // namespace
+
+TransparentActivateWindowButton::TransparentActivateWindowButton(
+ aura::Window* activate_window)
+ : event_handler_widget_(InitEventHandler(activate_window->GetRootWindow())),
+ activate_window_(activate_window) {
+ views::View* transparent_button = new TransparentButton(this);
+ event_handler_widget_->SetContentsView(transparent_button);
+}
+
+void TransparentActivateWindowButton::SetBounds(const gfx::Rect& bounds) {
+ event_handler_widget_->SetBounds(bounds);
+}
+
+TransparentActivateWindowButton::~TransparentActivateWindowButton() {
+}
+
+void TransparentActivateWindowButton::ButtonPressed(views::Button* sender,
+ const ui::Event& event) {
+ wm::GetWindowState(activate_window_)->Activate();
+}
+
+} // namespace ash
diff --git a/ash/wm/overview/transparent_activate_window_button.h b/ash/wm/overview/transparent_activate_window_button.h
new file mode 100644
index 0000000..cf4c509
--- /dev/null
+++ b/ash/wm/overview/transparent_activate_window_button.h
@@ -0,0 +1,39 @@
+// Copyright 2014 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.
+
+#ifndef ASH_WM_OVERVIEW_TRANSPARENT_ACTIVATE_WINDOW_BUTTON_H_
+#define ASH_WM_OVERVIEW_TRANSPARENT_ACTIVATE_WINDOW_BUTTON_H_
+
+#include "base/macros.h"
+#include "ui/views/controls/button/button.h"
+
+namespace ash {
+
+// Transparent window that covers window selector items and handles mouse and
+// gestures on overview mode for them.
+class TransparentActivateWindowButton : public views::ButtonListener {
+ public:
+ explicit TransparentActivateWindowButton(aura::Window* activate_window);
+ virtual ~TransparentActivateWindowButton();
+
+ // Sets the bounds of the transparent window.
+ void SetBounds(const gfx::Rect& bounds);
+
+ // views::ButtonListener:
+ virtual void ButtonPressed(views::Button* sender,
+ const ui::Event& event) OVERRIDE;
+
+ private:
+ // The transparent window event handler widget itself.
+ scoped_ptr<views::Widget> event_handler_widget_;
+
+ // Pointer to the window that the button activates.
+ aura::Window* activate_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(TransparentActivateWindowButton);
+};
+
+} // namespace ash
+
+#endif // ASH_WM_OVERVIEW_TRANSPARENT_ACTIVATE_WINDOW_BUTTON_H_
diff --git a/ash/wm/overview/window_selector.cc b/ash/wm/overview/window_selector.cc
index 04fbccb..cb66caa 100644
--- a/ash/wm/overview/window_selector.cc
+++ b/ash/wm/overview/window_selector.cc
@@ -25,7 +25,6 @@
#include "base/metrics/histogram.h"
#include "base/strings/string_number_conversions.h"
#include "third_party/skia/include/core/SkColor.h"
-#include "ui/aura/client/cursor_client.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/window.h"
#include "ui/aura/window_event_dispatcher.h"
@@ -48,11 +47,6 @@ namespace {
// area of them based on the number of windows.
const float kCardAspectRatio = 4.0f / 3.0f;
-// In the conceptual overview table, the window margin is the space reserved
-// around the window within the cell. This margin does not overlap so the
-// closest distance between adjacent windows will be twice this amount.
-const int kWindowMargin = 30;
-
// The minimum number of cards along the major axis (i.e. horizontally on a
// landscape orientation).
const int kMinCardsMajor = 3;
@@ -126,7 +120,7 @@ struct WindowSelectorItemTargetComparator
}
bool operator()(WindowSelectorItem* window) const {
- return window->TargetedWindow(target) != NULL;
+ return window->Contains(target);
}
const aura::Window* target;
@@ -199,7 +193,7 @@ WindowSelector::WindowSelector(const WindowList& windows,
windows_.push_back(item);
}
// Verify that the window has been added to an item in overview.
- CHECK(item->TargetedWindow(windows[i]));
+ CHECK(item->Contains(windows[i]));
}
UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.Items", windows_.size());
@@ -244,8 +238,6 @@ WindowSelector::~WindowSelector() {
(*iter)->Show();
}
- if (cursor_client_)
- cursor_client_->UnlockCursor();
shell->RemovePreTargetHandler(this);
shell->GetScreen()->RemoveObserver(this);
UMA_HISTOGRAM_MEDIUM_TIMES(
@@ -261,68 +253,18 @@ WindowSelector::~WindowSelector() {
UpdateShelfVisibility();
}
-void WindowSelector::SelectWindow(aura::Window* window) {
- ResetFocusRestoreWindow(false);
- ScopedVector<WindowSelectorItem>::iterator iter =
- std::find_if(windows_.begin(), windows_.end(),
- WindowSelectorItemTargetComparator(window));
- DCHECK(iter != windows_.end());
- // The selected window should not be minimized when window selection is
- // ended.
- (*iter)->RestoreWindowOnExit(window);
- delegate_->OnWindowSelected(window);
-}
-
void WindowSelector::CancelSelection() {
- delegate_->OnSelectionCanceled();
+ delegate_->OnSelectionEnded();
}
void WindowSelector::OnKeyEvent(ui::KeyEvent* event) {
- if (GetTargetedWindow(static_cast<aura::Window*>(event->target())))
- event->StopPropagation();
if (event->type() != ui::ET_KEY_PRESSED)
return;
- if (event->key_code() == ui::VKEY_ESCAPE)
+ if (event->key_code() == ui::VKEY_ESCAPE) {
CancelSelection();
-}
-
-void WindowSelector::OnMouseEvent(ui::MouseEvent* event) {
- aura::Window* target = GetEventTarget(event);
- if (!target)
- return;
-
- event->SetHandled();
- if (event->type() != ui::ET_MOUSE_RELEASED)
- return;
-
- SelectWindow(target);
-}
-
-void WindowSelector::OnScrollEvent(ui::ScrollEvent* event) {
- // Set the handled flag to prevent delivering scroll events to the window but
- // still allowing other pretarget handlers to process the scroll event.
- if (GetTargetedWindow(static_cast<aura::Window*>(event->target())))
event->SetHandled();
-}
-
-void WindowSelector::OnTouchEvent(ui::TouchEvent* event) {
- // Existing touches should be allowed to continue. This prevents getting
- // stuck in a gesture or with pressed fingers being tracked elsewhere.
- if (event->type() != ui::ET_TOUCH_PRESSED)
- return;
-
- aura::Window* target = GetEventTarget(event);
- if (!target)
- return;
-
- // TODO(flackr): StopPropogation prevents generation of gesture events.
- // We should find a better way to prevent events from being delivered to
- // the window, perhaps a transparent window in front of the target window
- // or using EventClientImpl::CanProcessEventsWithinSubtree and then a tap
- // gesture could be used to activate the window.
- event->SetHandled();
- SelectWindow(target);
+ }
}
void WindowSelector::OnDisplayAdded(const gfx::Display& display) {
@@ -400,6 +342,14 @@ void WindowSelector::OnWindowActivated(aura::Window* gained_active,
aura::Window* lost_active) {
if (ignore_activations_ || !gained_active)
return;
+
+ ScopedVector<WindowSelectorItem>::iterator iter = std::find_if(
+ windows_.begin(), windows_.end(),
+ WindowSelectorItemComparator(gained_active));
+
+ if (iter != windows_.end())
+ (*iter)->RestoreWindowOnExit(gained_active);
+
// Don't restore focus on exit if a window was just activated.
ResetFocusRestoreWindow(false);
CancelSelection();
@@ -407,11 +357,7 @@ void WindowSelector::OnWindowActivated(aura::Window* gained_active,
void WindowSelector::OnAttemptToReactivateWindow(aura::Window* request_active,
aura::Window* actual_active) {
- if (ignore_activations_)
- return;
- // Don't restore focus on exit if a window was just activated.
- ResetFocusRestoreWindow(false);
- CancelSelection();
+ OnWindowActivated(request_active, actual_active);
}
void WindowSelector::StartOverview() {
@@ -428,17 +374,6 @@ void WindowSelector::StartOverview() {
}
PositionWindows(/* animate */ true);
DCHECK(!windows_.empty());
- cursor_client_ = aura::client::GetCursorClient(
- windows_.front()->GetRootWindow());
- if (cursor_client_) {
- cursor_client_->SetCursor(ui::kCursorPointer);
- cursor_client_->ShowCursor();
- // TODO(flackr): Only prevent cursor changes for windows in the overview.
- // This will be easier to do without exposing the overview mode code if the
- // cursor changes are moved to ToplevelWindowEventHandler::HandleMouseMoved
- // as suggested there.
- cursor_client_->LockCursor();
- }
shell->PrependPreTargetHandler(this);
shell->GetScreen()->AddObserver(this);
shell->metrics()->RecordUserMetricsAction(UMA_WINDOW_OVERVIEW);
@@ -450,6 +385,15 @@ void WindowSelector::StartOverview() {
UpdateShelfVisibility();
}
+bool WindowSelector::Contains(const aura::Window* window) {
+ for (WindowSelectorItemList::iterator iter = windows_.begin();
+ iter != windows_.end(); ++iter) {
+ if ((*iter)->Contains(window))
+ return true;
+ }
+ return false;
+}
+
void WindowSelector::PositionWindows(bool animate) {
aura::Window::Windows root_window_list = Shell::GetAllRootWindows();
for (size_t i = 0; i < root_window_list.size(); ++i)
@@ -500,7 +444,6 @@ void WindowSelector::PositionWindowsFromRoot(aura::Window* root_window,
window_size.height() * row + y_offset,
window_size.width(),
window_size.height());
- target_bounds.Inset(kWindowMargin, kWindowMargin);
windows[i]->SetBounds(root_window, target_bounds, animate);
}
}
@@ -517,7 +460,7 @@ void WindowSelector::HideAndTrackNonOverviewWindows() {
for (aura::Window::Windows::const_iterator iter =
container->children().begin(); iter != container->children().end();
++iter) {
- if (GetTargetedWindow(*iter) || !(*iter)->IsVisible())
+ if (Contains(*iter) || !(*iter)->IsVisible())
continue;
hidden_windows_.Add(*iter);
}
@@ -560,25 +503,4 @@ void WindowSelector::ResetFocusRestoreWindow(bool focus) {
restore_focus_window_ = NULL;
}
-aura::Window* WindowSelector::GetEventTarget(ui::LocatedEvent* event) {
- aura::Window* target = static_cast<aura::Window*>(event->target());
- // If the target window doesn't actually contain the event location (i.e.
- // mouse down over the window and mouse up elsewhere) then do not select the
- // window.
- if (!target->ContainsPoint(event->location()))
- return NULL;
-
- return GetTargetedWindow(target);
-}
-
-aura::Window* WindowSelector::GetTargetedWindow(aura::Window* window) {
- for (WindowSelectorItemList::iterator iter = windows_.begin();
- iter != windows_.end(); ++iter) {
- aura::Window* selected = (*iter)->TargetedWindow(window);
- if (selected)
- return selected;
- }
- return NULL;
-}
-
} // namespace ash
diff --git a/ash/wm/overview/window_selector.h b/ash/wm/overview/window_selector.h
index bfb0c14..158df2c 100644
--- a/ash/wm/overview/window_selector.h
+++ b/ash/wm/overview/window_selector.h
@@ -22,10 +22,7 @@
namespace aura {
class RootWindow;
class Window;
-namespace client {
-class CursorClient;
-} // namespace client
-} // namespace aura
+}
namespace gfx {
class Rect;
@@ -55,17 +52,11 @@ class ASH_EXPORT WindowSelector
WindowSelectorDelegate* delegate);
virtual ~WindowSelector();
- // Choose |window| from the available windows to select.
- void SelectWindow(aura::Window* window);
-
// Cancels window selection.
void CancelSelection();
// ui::EventHandler:
virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
- virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
- virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE;
- virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
// gfx::DisplayObserver:
virtual void OnDisplayAdded(const gfx::Display& display) OVERRIDE;
@@ -93,6 +84,10 @@ class ASH_EXPORT WindowSelector
// Begins positioning windows such that all windows are visible on the screen.
void StartOverview();
+ // Returns true if a window is contained in the overview, and therefore should
+ // not be hidden prior to entering overview mode.
+ bool Contains(const aura::Window* window);
+
// Position all of the windows based on the current selection mode.
void PositionWindows(bool animate);
// Position all of the windows from |root_window| on |root_window|.
@@ -105,14 +100,6 @@ class ASH_EXPORT WindowSelector
// |focus|, restores focus to the stored window.
void ResetFocusRestoreWindow(bool focus);
- // Returns the target of |event| or NULL if the event is not targeted at
- // any of the windows in the selector.
- aura::Window* GetEventTarget(ui::LocatedEvent* event);
-
- // Returns the top-level window selected by targeting |window| or NULL if
- // no overview window was found for |window|.
- aura::Window* GetTargetedWindow(aura::Window* window);
-
// The collection of items in the overview wrapped by a helper class which
// restores their state and helps transform them to other root windows.
ScopedVector<WindowSelectorItem> windows_;
@@ -133,9 +120,6 @@ class ASH_EXPORT WindowSelector
// used to prevent handling the resulting expected activation.
bool ignore_activations_;
- // The cursor client used to lock the current cursor during overview.
- aura::client::CursorClient* cursor_client_;
-
// The time when overview was started.
base::Time overview_start_time_;
diff --git a/ash/wm/overview/window_selector_controller.cc b/ash/wm/overview/window_selector_controller.cc
index 5daf324..ea74ff0 100644
--- a/ash/wm/overview/window_selector_controller.cc
+++ b/ash/wm/overview/window_selector_controller.cc
@@ -38,7 +38,7 @@ bool WindowSelectorController::CanSelect() {
void WindowSelectorController::ToggleOverview() {
if (IsSelecting()) {
- OnSelectionCanceled();
+ OnSelectionEnded();
} else {
// Don't start overview if window selection is not allowed.
if (!CanSelect())
@@ -59,21 +59,14 @@ bool WindowSelectorController::IsSelecting() {
return window_selector_.get() != NULL;
}
-void WindowSelectorController::OnWindowSelected(aura::Window* window) {
- wm::ActivateWindow(window);
+// TODO(nsatragno): Make WindowSelectorController observe the activation of
+// windows, so we can remove WindowSelectorDelegate.
+void WindowSelectorController::OnSelectionEnded() {
window_selector_.reset();
last_selection_time_ = base::Time::Now();
- Shell::GetInstance()->mru_window_tracker()->SetIgnoreActivations(false);
-}
-
-void WindowSelectorController::OnSelectionCanceled() {
- window_selector_.reset();
- last_selection_time_ = base::Time::Now();
- Shell::GetInstance()->mru_window_tracker()->SetIgnoreActivations(false);
}
void WindowSelectorController::OnSelectionStarted() {
- Shell::GetInstance()->mru_window_tracker()->SetIgnoreActivations(true);
Shell* shell = Shell::GetInstance();
shell->metrics()->RecordUserMetricsAction(UMA_WINDOW_SELECTION);
if (!last_selection_time_.is_null()) {
diff --git a/ash/wm/overview/window_selector_controller.h b/ash/wm/overview/window_selector_controller.h
index 1152c1e..09872c3 100644
--- a/ash/wm/overview/window_selector_controller.h
+++ b/ash/wm/overview/window_selector_controller.h
@@ -45,8 +45,7 @@ class ASH_EXPORT WindowSelectorController
bool IsSelecting();
// WindowSelectorDelegate:
- virtual void OnWindowSelected(aura::Window* window) OVERRIDE;
- virtual void OnSelectionCanceled() OVERRIDE;
+ virtual void OnSelectionEnded() OVERRIDE;
private:
friend class WindowSelectorTest;
diff --git a/ash/wm/overview/window_selector_delegate.h b/ash/wm/overview/window_selector_delegate.h
index 2bce3ca..af3e646 100644
--- a/ash/wm/overview/window_selector_delegate.h
+++ b/ash/wm/overview/window_selector_delegate.h
@@ -17,11 +17,8 @@ namespace ash {
// Implement this class to handle the selection event from WindowSelector.
class ASH_EXPORT WindowSelectorDelegate {
public:
- // Invoked when a window is selected.
- virtual void OnWindowSelected(aura::Window* window) = 0;
-
- // Invoked if selection is canceled.
- virtual void OnSelectionCanceled() = 0;
+ // Invoked if selection is ended.
+ virtual void OnSelectionEnded() = 0;
protected:
virtual ~WindowSelectorDelegate() {}
diff --git a/ash/wm/overview/window_selector_item.cc b/ash/wm/overview/window_selector_item.cc
index 77d06f3..eac1e7e 100644
--- a/ash/wm/overview/window_selector_item.cc
+++ b/ash/wm/overview/window_selector_item.cc
@@ -8,6 +8,7 @@
#include "ash/shell.h"
#include "ash/shell_window_ids.h"
#include "ash/wm/overview/scoped_transform_overview_window.h"
+#include "ash/wm/overview/transparent_activate_window_button.h"
#include "base/auto_reset.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/aura/window.h"
@@ -19,6 +20,11 @@
namespace ash {
+// In the conceptual overview table, the window margin is the space reserved
+// around the window within the cell. This margin does not overlap so the
+// closest distance between adjacent windows will be twice this amount.
+static const int kWindowMargin = 30;
+
// Foreground label color.
static const SkColor kLabelColor = SK_ColorWHITE;
@@ -87,9 +93,21 @@ void WindowSelectorItem::SetBounds(aura::Window* root_window,
base::AutoReset<bool> auto_reset_in_bounds_update(&in_bounds_update_, true);
root_window_ = root_window;
target_bounds_ = target_bounds;
- SetItemBounds(root_window, target_bounds, animate);
+
+ // Set the bounds of the transparent window handler to cover the entire
+ // bounding box area.
+ if (!activate_window_button_) {
+ activate_window_button_.reset(
+ new TransparentActivateWindowButton(SelectionWindow()));
+ }
+ activate_window_button_->SetBounds(target_bounds);
+
// TODO(nsatragno): Handle window title updates.
UpdateWindowLabels(target_bounds, root_window, animate);
+
+ gfx::Rect inset_bounds(target_bounds);
+ inset_bounds.Inset(kWindowMargin, kWindowMargin);
+ SetItemBounds(root_window, inset_bounds, animate);
}
void WindowSelectorItem::RecomputeWindowTransforms() {
@@ -97,7 +115,9 @@ void WindowSelectorItem::RecomputeWindowTransforms() {
return;
DCHECK(root_window_);
base::AutoReset<bool> auto_reset_in_bounds_update(&in_bounds_update_, true);
- SetItemBounds(root_window_, target_bounds_, false);
+ gfx::Rect inset_bounds(target_bounds_);
+ inset_bounds.Inset(kWindowMargin, kWindowMargin);
+ SetItemBounds(root_window_, inset_bounds, false);
}
void WindowSelectorItem::UpdateWindowLabels(const gfx::Rect& window_bounds,
@@ -121,7 +141,9 @@ void WindowSelectorItem::UpdateWindowLabels(const gfx::Rect& window_bounds,
window_label_.reset(CreateWindowLabel(root_window,
SelectionWindow()->title()));
label_bounds.set_height(window_label_->
- GetContentsView()->GetPreferredSize().height());
+ GetContentsView()->GetPreferredSize().height());
+ label_bounds.set_y(label_bounds.y() - window_label_->
+ GetContentsView()->GetPreferredSize().height());
window_label_->GetNativeWindow()->SetBounds(label_bounds);
ui::Layer* layer = window_label_->GetNativeWindow()->layer();
@@ -141,7 +163,9 @@ void WindowSelectorItem::UpdateWindowLabels(const gfx::Rect& window_bounds,
layer->SetOpacity(1);
} else {
label_bounds.set_height(window_label_->
- GetContentsView()->GetPreferredSize().height());
+ GetContentsView()->GetPreferredSize().height());
+ label_bounds.set_y(label_bounds.y() - window_label_->
+ GetContentsView()->GetPreferredSize().height());
if (animate) {
ui::ScopedLayerAnimationSettings settings(
window_label_->GetNativeWindow()->layer()->GetAnimator());
@@ -154,7 +178,6 @@ void WindowSelectorItem::UpdateWindowLabels(const gfx::Rect& window_bounds,
window_label_->GetNativeWindow()->SetBounds(label_bounds);
}
}
-
}
} // namespace ash
diff --git a/ash/wm/overview/window_selector_item.h b/ash/wm/overview/window_selector_item.h
index d1cfaf3..7b2fcb8 100644
--- a/ash/wm/overview/window_selector_item.h
+++ b/ash/wm/overview/window_selector_item.h
@@ -19,6 +19,7 @@ class Widget;
}
namespace ash {
+class TransparentActivateWindowButton;
// This class represents an item in overview mode. An item can have one or more
// windows, of which only one can be activated by keyboard (i.e. alt+tab) but
@@ -39,9 +40,8 @@ class WindowSelectorItem {
// window.
virtual bool HasSelectableWindow(const aura::Window* window) = 0;
- // Returns the targeted window given the event |target| window.
- // Returns NULL if no Window in this item was selected.
- virtual aura::Window* TargetedWindow(const aura::Window* target) = 0;
+ // Returns true if |target| is contained in this WindowSelectorItem.
+ virtual bool Contains(const aura::Window* target) = 0;
// Restores |window| on exiting window overview rather than returning it
// to its previous state.
@@ -76,8 +76,9 @@ class WindowSelectorItem {
const gfx::Rect& target_bounds() { return target_bounds_; }
protected:
- // Sets the bounds of this selector item to |target_bounds| in |root_window|.
- // If |animate| the windows are animated from their current location.
+ // Sets the bounds of this selector's items to |target_bounds| in
+ // |root_window|. If |animate| the windows are animated from their current
+ // location.
virtual void SetItemBounds(aura::Window* root_window,
const gfx::Rect& target_bounds,
bool animate) = 0;
@@ -111,6 +112,10 @@ class WindowSelectorItem {
// Label under the window displaying its active tab name.
scoped_ptr<views::Widget> window_label_;
+ // Transparent window on top of the real windows in the overview that
+ // activates them on click or tap.
+ scoped_ptr<TransparentActivateWindowButton> activate_window_button_;
+
DISALLOW_COPY_AND_ASSIGN(WindowSelectorItem);
};
diff --git a/ash/wm/overview/window_selector_panels.cc b/ash/wm/overview/window_selector_panels.cc
index bd165b2..588bf3b 100644
--- a/ash/wm/overview/window_selector_panels.cc
+++ b/ash/wm/overview/window_selector_panels.cc
@@ -4,16 +4,18 @@
#include "ash/wm/overview/window_selector_panels.h"
+#include "ash/screen_util.h"
#include "ash/shell.h"
#include "ash/shell_window_ids.h"
#include "ash/wm/overview/scoped_transform_overview_window.h"
+#include "ash/wm/overview/transparent_activate_window_button.h"
#include "ash/wm/panels/panel_layout_manager.h"
-#include "ui/aura/client/screen_position_client.h"
+#include "ash/wm/window_util.h"
#include "ui/aura/window.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/layer_animation_sequence.h"
-#include "ui/views/widget/widget.h"
+#include "ui/views/controls/button/button.h"
namespace ash {
@@ -22,7 +24,8 @@ namespace {
const int kPanelCalloutFadeInDurationMilliseconds = 50;
// This class extends ScopedTransformOverviewMode to hide and show the callout
-// widget for a panel window when entering / leaving overview mode.
+// widget for a panel window when entering / leaving overview mode, as well as
+// to add a transparent button for each panel window.
class ScopedTransformPanelWindow : public ScopedTransformOverviewWindow {
public:
ScopedTransformPanelWindow(aura::Window* window);
@@ -31,6 +34,11 @@ class ScopedTransformPanelWindow : public ScopedTransformOverviewWindow {
// ScopedTransformOverviewWindow overrides:
virtual void PrepareForOverview() OVERRIDE;
+ virtual void SetTransform(
+ aura::Window* root_window,
+ const gfx::Transform& transform,
+ bool animate) OVERRIDE;
+
private:
// Returns the callout widget for the transformed panel.
views::Widget* GetCalloutWidget();
@@ -41,8 +49,13 @@ class ScopedTransformPanelWindow : public ScopedTransformOverviewWindow {
// Trigger relayout
void Relayout();
+ // Returns the panel window bounds after the transformation.
+ gfx::Rect GetTransformedBounds();
+
bool callout_visible_;
+ scoped_ptr<TransparentActivateWindowButton> window_button_;
+
DISALLOW_COPY_AND_ASSIGN(ScopedTransformPanelWindow);
};
@@ -59,6 +72,15 @@ ScopedTransformPanelWindow::~ScopedTransformPanelWindow() {
void ScopedTransformPanelWindow::PrepareForOverview() {
ScopedTransformOverviewWindow::PrepareForOverview();
GetCalloutWidget()->GetLayer()->SetOpacity(0.0f);
+ window_button_.reset(new TransparentActivateWindowButton(window()));
+}
+
+void ScopedTransformPanelWindow::SetTransform(
+ aura::Window* root_window,
+ const gfx::Transform& transform,
+ bool animate) {
+ ScopedTransformOverviewWindow::SetTransform(root_window, transform, animate);
+ window_button_->SetBounds(GetTransformedBounds());
}
views::Widget* ScopedTransformPanelWindow::GetCalloutWidget() {
@@ -81,6 +103,19 @@ void ScopedTransformPanelWindow::RestoreCallout() {
sequence.release());
}
+gfx::Rect ScopedTransformPanelWindow::GetTransformedBounds() {
+ gfx::RectF bounds(ScreenUtil::ConvertRectToScreen(
+ window()->GetRootWindow(), window()->layer()->bounds()));
+ gfx::Transform new_transform;
+ new_transform.Translate(bounds.x(),
+ bounds.y());
+ new_transform.PreconcatTransform(window()->layer()->GetTargetTransform());
+ new_transform.Translate(-bounds.x(),
+ -bounds.y());
+ new_transform.TransformRect(&bounds);
+ return ToEnclosingRect(bounds);
+}
+
} // namespace
WindowSelectorPanels::WindowSelectorPanels() {
@@ -106,13 +141,13 @@ bool WindowSelectorPanels::HasSelectableWindow(const aura::Window* window) {
return false;
}
-aura::Window* WindowSelectorPanels::TargetedWindow(const aura::Window* target) {
+bool WindowSelectorPanels::Contains(const aura::Window* target) {
for (WindowList::const_iterator iter = transform_windows_.begin();
iter != transform_windows_.end(); ++iter) {
if ((*iter)->Contains(target))
- return (*iter)->window();
+ return true;
}
- return NULL;
+ return false;
}
void WindowSelectorPanels::RestoreWindowOnExit(aura::Window* window) {
@@ -145,10 +180,25 @@ bool WindowSelectorPanels::empty() const {
}
void WindowSelectorPanels::PrepareForOverview() {
- for (WindowList::iterator iter = transform_windows_.begin();
- iter != transform_windows_.end(); ++iter) {
- (*iter)->PrepareForOverview();
+ // |panel_windows| will hold all the windows in the panel container, sorted
+ // according to their stacking order.
+ const aura::Window::Windows panels =
+ transform_windows_[0]->window()->parent()->children();
+
+ // Call PrepareForOverview() in the reverse stacking order so that the
+ // transparent windows that handle the events are in the correct stacking
+ // order.
+ size_t transformed_windows = 0;
+ for (aura::Window::Windows::const_reverse_iterator iter = panels.rbegin();
+ iter != panels.rend(); iter++) {
+ for (size_t j = 0; j < transform_windows_.size(); ++j) {
+ if (transform_windows_[j]->window() == (*iter)) {
+ transform_windows_[j]->PrepareForOverview();
+ transformed_windows++;
+ }
+ }
}
+ DCHECK(transformed_windows == transform_windows_.size());
}
void WindowSelectorPanels::SetItemBounds(aura::Window* root_window,
diff --git a/ash/wm/overview/window_selector_panels.h b/ash/wm/overview/window_selector_panels.h
index 88c31a2..7d2131c 100644
--- a/ash/wm/overview/window_selector_panels.h
+++ b/ash/wm/overview/window_selector_panels.h
@@ -9,6 +9,7 @@
#include "base/compiler_specific.h"
#include "base/memory/scoped_vector.h"
#include "ui/gfx/rect.h"
+#include "ui/views/controls/button/button.h"
namespace ash {
@@ -29,7 +30,7 @@ class WindowSelectorPanels : public WindowSelectorItem {
// WindowSelectorItem:
virtual aura::Window* GetRootWindow() OVERRIDE;
virtual bool HasSelectableWindow(const aura::Window* window) OVERRIDE;
- virtual aura::Window* TargetedWindow(const aura::Window* target) OVERRIDE;
+ virtual bool Contains(const aura::Window* target) OVERRIDE;
virtual void RestoreWindowOnExit(aura::Window* window) OVERRIDE;
virtual aura::Window* SelectionWindow() OVERRIDE;
virtual void RemoveWindow(const aura::Window* window) OVERRIDE;
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc
index 2141040..9178ab1 100644
--- a/ash/wm/overview/window_selector_unittest.cc
+++ b/ash/wm/overview/window_selector_unittest.cc
@@ -198,7 +198,7 @@ TEST_F(WindowSelectorTest, A11yAlertOnOverviewMode) {
A11Y_ALERT_WINDOW_OVERVIEW_MODE_ENTERED);
}
-// Tests entering overview mode with two windows and selecting one.
+// Tests entering overview mode with two windows and selecting one by clicking.
TEST_F(WindowSelectorTest, Basic) {
gfx::Rect bounds(0, 0, 400, 400);
aura::Window* root_window = Shell::GetPrimaryRootWindow();
@@ -225,12 +225,6 @@ TEST_F(WindowSelectorTest, Basic) {
// item.
EXPECT_TRUE(WindowsOverlapping(panel1.get(), panel2.get()));
- // The cursor should be visible and locked as a pointer
- EXPECT_EQ(ui::kCursorPointer,
- root_window->GetHost()->last_cursor().native_type());
- EXPECT_TRUE(aura::client::GetCursorClient(root_window)->IsCursorLocked());
- EXPECT_TRUE(aura::client::GetCursorClient(root_window)->IsCursorVisible());
-
// Clicking window 1 should activate it.
ClickWindow(window1.get());
EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
@@ -241,6 +235,78 @@ TEST_F(WindowSelectorTest, Basic) {
EXPECT_FALSE(aura::client::GetCursorClient(root_window)->IsCursorLocked());
}
+// Tests selecting a window by tapping on it.
+TEST_F(WindowSelectorTest, BasicGesture) {
+ gfx::Rect bounds(0, 0, 400, 400);
+ scoped_ptr<aura::Window> window1(CreateWindow(bounds));
+ scoped_ptr<aura::Window> window2(CreateWindow(bounds));
+ wm::ActivateWindow(window1.get());
+ EXPECT_EQ(window1.get(), GetFocusedWindow());
+ ToggleOverview();
+ EXPECT_EQ(NULL, GetFocusedWindow());
+ aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
+ window2.get());
+ generator.GestureTapAt(gfx::ToEnclosingRect(
+ GetTransformedTargetBounds(window2.get())).CenterPoint());
+ EXPECT_EQ(window2.get(), GetFocusedWindow());
+}
+
+// Tests that a window does not receive located events when in overview mode.
+TEST_F(WindowSelectorTest, WindowDoesNotReceiveEvents) {
+ gfx::Rect window_bounds(20, 10, 200, 300);
+ aura::Window* root_window = Shell::GetPrimaryRootWindow();
+ scoped_ptr<aura::Window> window(CreateWindow(window_bounds));
+
+ gfx::Point point1(window_bounds.x() + 10, window_bounds.y() + 10);
+
+ ui::MouseEvent event1(ui::ET_MOUSE_PRESSED, point1, point1,
+ ui::EF_NONE, ui::EF_NONE);
+
+ ui::EventTarget* root_target = root_window;
+ ui::EventTargeter* targeter = root_target->GetEventTargeter();
+
+ // The event should target the window because we are still not in overview
+ // mode.
+ EXPECT_EQ(window, static_cast<aura::Window*>(
+ targeter->FindTargetForEvent(root_target, &event1)));
+
+ ToggleOverview();
+
+ // The bounds have changed, take that into account.
+ gfx::RectF bounds = GetTransformedBoundsInRootWindow(window.get());
+ gfx::Point point2(bounds.x() + 10, bounds.y() + 10);
+ ui::MouseEvent event2(ui::ET_MOUSE_PRESSED, point2, point2,
+ ui::EF_NONE, ui::EF_NONE);
+
+ // Now the transparent window should be intercepting this event.
+ EXPECT_NE(window, static_cast<aura::Window*>(
+ targeter->FindTargetForEvent(root_target, &event2)));
+}
+
+// Tests that clicking on the close button effectively closes the window.
+TEST_F(WindowSelectorTest, CloseButton) {
+ scoped_ptr<aura::Window> window1(CreateWindow(gfx::Rect(200, 300, 250, 450)));
+
+ // We need a widget for the close button the work, a bare window will crash.
+ scoped_ptr<views::Widget> widget(new views::Widget);
+ views::Widget::InitParams params;
+ params.bounds = gfx::Rect(0, 0, 400, 400);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.parent = window1->parent();
+ widget->Init(params);
+ widget->Show();
+ ToggleOverview();
+
+ aura::Window* window2 = widget->GetNativeWindow();
+ gfx::RectF bounds = GetTransformedBoundsInRootWindow(window2);
+ gfx::Point point(bounds.top_right().x() - 1, bounds.top_right().y() - 1);
+ aura::test::EventGenerator event_generator(window2->GetRootWindow(), point);
+
+ EXPECT_FALSE(widget->IsClosed());
+ event_generator.ClickLeftButton();
+ EXPECT_TRUE(widget->IsClosed());
+}
+
// Tests entering overview mode with two windows and selecting one.
TEST_F(WindowSelectorTest, FullscreenWindow) {
gfx::Rect bounds(0, 0, 400, 400);
@@ -625,39 +691,6 @@ TEST_F(WindowSelectorTest, DISABLED_DragDropInProgress) {
RunAllPendingInMessageLoop();
}
-TEST_F(WindowSelectorTest, HitTestingInOverview) {
- gfx::Rect window_bounds(20, 10, 200, 300);
- aura::Window* root_window = Shell::GetPrimaryRootWindow();
- scoped_ptr<aura::Window> window1(CreateWindow(window_bounds));
- scoped_ptr<aura::Window> window2(CreateWindow(window_bounds));
-
- ToggleOverview();
- gfx::RectF bounds1 = GetTransformedBoundsInRootWindow(window1.get());
- gfx::RectF bounds2 = GetTransformedBoundsInRootWindow(window2.get());
- EXPECT_NE(bounds1.ToString(), bounds2.ToString());
-
- ui::EventTarget* root_target = root_window;
- ui::EventTargeter* targeter = root_target->GetEventTargeter();
- aura::Window* windows[] = { window1.get(), window2.get() };
- for (size_t w = 0; w < arraysize(windows); ++w) {
- gfx::RectF bounds = GetTransformedBoundsInRootWindow(windows[w]);
- // The close button covers the top-right corner of the window so we skip
- // this in hit testing.
- gfx::Point points[] = {
- gfx::Point(bounds.x(), bounds.y()),
- gfx::Point(bounds.x(), bounds.bottom() - 1),
- gfx::Point(bounds.right() - 1, bounds.bottom() - 1),
- };
-
- for (size_t p = 0; p < arraysize(points); ++p) {
- ui::MouseEvent event(ui::ET_MOUSE_MOVED, points[p], points[p],
- ui::EF_NONE, ui::EF_NONE);
- EXPECT_EQ(windows[w],
- targeter->FindTargetForEvent(root_target, &event));
- }
- }
-}
-
// Test that a label is created under the window on entering overview mode.
TEST_F(WindowSelectorTest, CreateLabelUnderWindow) {
scoped_ptr<aura::Window> window(CreateWindow(gfx::Rect(0, 0, 100, 100)));
@@ -702,7 +735,7 @@ TEST_F(WindowSelectorTest, CreateLabelUnderPanel) {
EXPECT_EQ(label->text(), panel1_title);
}
-// Tests that overview updates the window postions if the display orientation
+// Tests that overview updates the window positions if the display orientation
// changes.
TEST_F(WindowSelectorTest, DisplayOrientationChanged) {
if (!SupportsHostWindowResize())
diff --git a/ash/wm/overview/window_selector_window.cc b/ash/wm/overview/window_selector_window.cc
index c93feef..6aad03f 100644
--- a/ash/wm/overview/window_selector_window.cc
+++ b/ash/wm/overview/window_selector_window.cc
@@ -63,10 +63,8 @@ bool WindowSelectorWindow::HasSelectableWindow(const aura::Window* window) {
return transform_window_.window() == window;
}
-aura::Window* WindowSelectorWindow::TargetedWindow(const aura::Window* target) {
- if (transform_window_.Contains(target))
- return transform_window_.window();
- return NULL;
+bool WindowSelectorWindow::Contains(const aura::Window* target) {
+ return transform_window_.Contains(target);
}
void WindowSelectorWindow::RestoreWindowOnExit(aura::Window* window) {
diff --git a/ash/wm/overview/window_selector_window.h b/ash/wm/overview/window_selector_window.h
index f7f45c2..11b0ebd 100644
--- a/ash/wm/overview/window_selector_window.h
+++ b/ash/wm/overview/window_selector_window.h
@@ -32,7 +32,7 @@ class WindowSelectorWindow : public WindowSelectorItem,
// WindowSelectorItem:
virtual aura::Window* GetRootWindow() OVERRIDE;
virtual bool HasSelectableWindow(const aura::Window* window) OVERRIDE;
- virtual aura::Window* TargetedWindow(const aura::Window* target) OVERRIDE;
+ virtual bool Contains(const aura::Window* target) OVERRIDE;
virtual void RestoreWindowOnExit(aura::Window* window) OVERRIDE;
virtual aura::Window* SelectionWindow() OVERRIDE;
virtual void RemoveWindow(const aura::Window* window) OVERRIDE;