diff options
-rw-r--r-- | ash/ash.gyp | 4 | ||||
-rw-r--r-- | ash/wm/maximize_mode/maximize_mode_window_manager.cc | 2 | ||||
-rw-r--r-- | ash/wm/overview/scoped_transform_overview_window.cc | 4 | ||||
-rw-r--r-- | ash/wm/overview/scoped_transform_overview_window.h | 10 | ||||
-rw-r--r-- | ash/wm/overview/transparent_activate_window_button.cc | 72 | ||||
-rw-r--r-- | ash/wm/overview/transparent_activate_window_button.h | 39 | ||||
-rw-r--r-- | ash/wm/overview/window_selector.cc | 126 | ||||
-rw-r--r-- | ash/wm/overview/window_selector.h | 26 | ||||
-rw-r--r-- | ash/wm/overview/window_selector_controller.cc | 15 | ||||
-rw-r--r-- | ash/wm/overview/window_selector_controller.h | 3 | ||||
-rw-r--r-- | ash/wm/overview/window_selector_delegate.h | 7 | ||||
-rw-r--r-- | ash/wm/overview/window_selector_item.cc | 33 | ||||
-rw-r--r-- | ash/wm/overview/window_selector_item.h | 15 | ||||
-rw-r--r-- | ash/wm/overview/window_selector_panels.cc | 68 | ||||
-rw-r--r-- | ash/wm/overview/window_selector_panels.h | 3 | ||||
-rw-r--r-- | ash/wm/overview/window_selector_unittest.cc | 115 | ||||
-rw-r--r-- | ash/wm/overview/window_selector_window.cc | 6 | ||||
-rw-r--r-- | ash/wm/overview/window_selector_window.h | 2 |
18 files changed, 336 insertions, 214 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp index b42fe07..7ed1c8c 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp @@ -1,4 +1,4 @@ -#a Copyright (c) 2012 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. @@ -597,6 +597,8 @@ 'wm/window_cycle_controller.h', 'wm/window_cycle_list.cc', 'wm/window_cycle_list.h', + 'wm/overview/transparent_activate_window_button.cc', + 'wm/overview/transparent_activate_window_button.h', 'wm/overview/window_selector_controller.cc', 'wm/overview/window_selector_controller.h', 'wm/overview/window_selector_delegate.h', 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; |