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

Unified Diff: ash/wm/overview/window_selector.cc

Issue 280423008: Merge WindowOverview into WindowSelector (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« ash/wm/overview/window_selector.h ('K') | « ash/wm/overview/window_selector.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ash/wm/overview/window_selector.cc
diff --git a/ash/wm/overview/window_selector.cc b/ash/wm/overview/window_selector.cc
index 3d9bdf745308580587020e20b67783ed97110acb..9abedb6e44831b8e93adc59cffbf2555731a2481 100644
--- a/ash/wm/overview/window_selector.cc
+++ b/ash/wm/overview/window_selector.cc
@@ -6,12 +6,17 @@
#include <algorithm>
+#include "ash/accessibility_delegate.h"
#include "ash/ash_switches.h"
+#include "ash/metrics/user_metrics_recorder.h"
#include "ash/root_window_controller.h"
+#include "ash/screen_util.h"
#include "ash/shell.h"
+#include "ash/shell_window_ids.h"
#include "ash/switchable_windows.h"
-#include "ash/wm/overview/window_overview.h"
+#include "ash/wm/overview/scoped_transform_overview_window.h"
#include "ash/wm/overview/window_selector_delegate.h"
+#include "ash/wm/overview/window_selector_item.h"
#include "ash/wm/overview/window_selector_panels.h"
#include "ash/wm/overview/window_selector_window.h"
#include "ash/wm/window_state.h"
@@ -19,9 +24,18 @@
#include "base/command_line.h"
#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"
#include "ui/aura/window_observer.h"
+#include "ui/compositor/layer_animation_observer.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/events/event.h"
+#include "ui/gfx/screen.h"
+#include "ui/views/background.h"
+#include "ui/views/widget/widget.h"
#include "ui/wm/core/window_util.h"
#include "ui/wm/public/activation_client.h"
@@ -29,20 +43,94 @@ namespace ash {
namespace {
-// A comparator for locating a given selectable window.
+// Conceptually the window overview is a table or grid of cells having this
+// fixed aspect ratio. The number of columns is determined by maximizing the
+// 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;
+
+// The duration of transition animations on the overview selector.
+const int kOverviewSelectorTransitionMilliseconds = 100;
+
+// The color and opacity of the overview selector.
+const SkColor kWindowOverviewSelectionColor = SK_ColorBLACK;
+const float kWindowOverviewSelectionOpacity = 0.5f;
+
+// The padding or amount of the window selector widget visible around the edges
+// of the currently selected window.
+const int kWindowOverviewSelectionPadding = 25;
+
+// A comparator for locating a given target window.
struct WindowSelectorItemComparator
: public std::unary_function<WindowSelectorItem*, bool> {
- explicit WindowSelectorItemComparator(const aura::Window* window)
- : window_(window) {
+ explicit WindowSelectorItemComparator(const aura::Window* target_window)
+ : target(target_window) {
}
bool operator()(WindowSelectorItem* window) const {
- return window->HasSelectableWindow(window_);
+ return window->TargetedWindow(target) != NULL;
}
- const aura::Window* window_;
+ const aura::Window* target;
};
+// An observer which holds onto the passed widget until the animation is
+// complete.
+class CleanupWidgetAfterAnimationObserver : public ui::LayerAnimationObserver {
+ public:
+ explicit CleanupWidgetAfterAnimationObserver(
+ scoped_ptr<views::Widget> widget);
+
+ // ui::LayerAnimationObserver:
+ virtual void OnLayerAnimationEnded(
+ ui::LayerAnimationSequence* sequence) OVERRIDE;
+ virtual void OnLayerAnimationAborted(
+ ui::LayerAnimationSequence* sequence) OVERRIDE;
+ virtual void OnLayerAnimationScheduled(
+ ui::LayerAnimationSequence* sequence) OVERRIDE;
+
+ private:
+ virtual ~CleanupWidgetAfterAnimationObserver();
+
+ scoped_ptr<views::Widget> widget_;
+
+ DISALLOW_COPY_AND_ASSIGN(CleanupWidgetAfterAnimationObserver);
+};
+
+CleanupWidgetAfterAnimationObserver::CleanupWidgetAfterAnimationObserver(
+ scoped_ptr<views::Widget> widget)
+ : widget_(widget.Pass()) {
+ widget_->GetNativeWindow()->layer()->GetAnimator()->AddObserver(this);
+}
+
+CleanupWidgetAfterAnimationObserver::~CleanupWidgetAfterAnimationObserver() {
+ widget_->GetNativeWindow()->layer()->GetAnimator()->RemoveObserver(this);
+}
+
+void CleanupWidgetAfterAnimationObserver::OnLayerAnimationEnded(
+ ui::LayerAnimationSequence* sequence) {
+ delete this;
+}
+
+void CleanupWidgetAfterAnimationObserver::OnLayerAnimationAborted(
+ ui::LayerAnimationSequence* sequence) {
+ delete this;
+}
+
+void CleanupWidgetAfterAnimationObserver::OnLayerAnimationScheduled(
+ ui::LayerAnimationSequence* sequence) {
+}
+
+} // namespace
+
// A comparator for locating a selectable window given a targeted window.
struct WindowSelectorItemTargetComparator
: public std::unary_function<WindowSelectorItem*, bool> {
@@ -82,8 +170,6 @@ void UpdateShelfVisibility() {
}
}
-} // namespace
-
WindowSelector::WindowSelector(const WindowList& windows,
WindowSelectorDelegate* delegate)
: delegate_(delegate),
@@ -153,7 +239,30 @@ WindowSelector::~WindowSelector() {
}
Shell::GetInstance()->activation_client()->RemoveObserver(this);
aura::Window::Windows root_windows = Shell::GetAllRootWindows();
- window_overview_.reset();
+
+ const aura::WindowTracker::Windows hidden_windows(hidden_windows_.windows());
+ for (aura::WindowTracker::Windows::const_iterator iter =
+ hidden_windows.begin(); iter != hidden_windows.end(); ++iter) {
+ ui::ScopedLayerAnimationSettings settings(
+ (*iter)->layer()->GetAnimator());
+ settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
+ ScopedTransformOverviewWindow::kTransitionMilliseconds));
+ settings.SetPreemptionStrategy(
+ ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
+ (*iter)->layer()->SetOpacity(1);
+ (*iter)->Show();
+ }
+
+ if (cursor_client_)
+ cursor_client_->UnlockCursor();
+ ash::Shell* shell = ash::Shell::GetInstance();
+ shell->RemovePreTargetHandler(this);
+ shell->GetScreen()->RemoveObserver(this);
+ UMA_HISTOGRAM_MEDIUM_TIMES(
+ "Ash.WindowSelector.TimeInOverview",
+ base::Time::Now() - overview_start_time_);
+ shell->OnOverviewModeEnding();
+
// Clearing the window list resets the ignored_by_shelf flag on the windows.
windows_.clear();
UpdateShelfVisibility();
@@ -175,6 +284,64 @@ void WindowSelector::CancelSelection() {
delegate_->OnSelectionCanceled();
}
+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)
+ 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::OnDisplayBoundsChanged(const gfx::Display& display) {
+ PositionWindows(/* animate */ false);
+}
+
+void WindowSelector::OnDisplayAdded(const gfx::Display& display) {
+}
+
+void WindowSelector::OnDisplayRemoved(const gfx::Display& display) {
+}
+
void WindowSelector::OnWindowAdded(aura::Window* new_window) {
if (new_window->type() != ui::wm::WINDOW_TYPE_NORMAL &&
new_window->type() != ui::wm::WINDOW_TYPE_PANEL) {
@@ -215,16 +382,12 @@ void WindowSelector::OnWindowDestroying(aura::Window* window) {
CancelSelection();
return;
}
- if (window_overview_)
- window_overview_->OnWindowsChanged();
+ PositionWindows(true);
}
void WindowSelector::OnWindowBoundsChanged(aura::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds) {
- if (!window_overview_)
- return;
-
ScopedVector<WindowSelectorItem>::iterator iter =
std::find_if(windows_.begin(), windows_.end(),
WindowSelectorItemTargetComparator(window));
@@ -258,15 +421,134 @@ void WindowSelector::OnAttemptToReactivateWindow(aura::Window* request_active,
}
void WindowSelector::StartOverview() {
- DCHECK(!window_overview_);
- // Remove focus from active window before entering overview.
tdanderson 2014/05/13 23:25:32 Keep this comment in.
Nina 2014/05/14 13:52:54 Done.
aura::client::GetFocusClient(
Shell::GetPrimaryRootWindow())->FocusWindow(NULL);
- window_overview_.reset(new WindowOverview(this, &windows_));
+ Shell* shell = Shell::GetInstance();
+ shell->OnOverviewModeStarting();
+
+ for (WindowSelectorItemList::iterator iter = windows_.begin();
+ iter != windows_.end(); ++iter) {
+ (*iter)->PrepareForOverview();
+ }
+ 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);
+ HideAndTrackNonOverviewWindows();
+ // Send an a11y alert.
+ shell->accessibility_delegate()->TriggerAccessibilityAlert(
+ A11Y_ALERT_WINDOW_OVERVIEW_MODE_ENTERED);
+
UpdateShelfVisibility();
}
+void WindowSelector::PositionWindows(bool animate) {
+ aura::Window::Windows root_window_list = Shell::GetAllRootWindows();
+ for (size_t i = 0; i < root_window_list.size(); ++i)
+ PositionWindowsFromRoot(root_window_list[i], animate);
+}
+
+void WindowSelector::PositionWindowsFromRoot(aura::Window* root_window,
+ bool animate) {
+ std::vector<WindowSelectorItem*> windows;
+ for (WindowSelectorItemList::iterator iter = windows_.begin();
+ iter != windows_.end(); ++iter) {
+ if ((*iter)->GetRootWindow() == root_window)
+ windows.push_back(*iter);
+ }
+
+ if (windows.empty())
+ return;
+
+ gfx::Size window_size;
+ gfx::Rect total_bounds = ScreenUtil::ConvertRectToScreen(
+ root_window,
+ ScreenUtil::GetDisplayWorkAreaBoundsInParent(
+ Shell::GetContainer(root_window, kShellWindowId_DefaultContainer)));
+
+ // Find the minimum number of windows per row that will fit all of the
+ // windows on screen.
+ size_t columns = std::max(
+ total_bounds.width() > total_bounds.height() ? kMinCardsMajor : 1,
+ static_cast<int>(ceil(sqrt(total_bounds.width() * windows.size() /
+ (kCardAspectRatio * total_bounds.height())))));
+ size_t rows = ((windows.size() + columns - 1) / columns);
+ window_size.set_width(std::min(
+ static_cast<int>(total_bounds.width() / columns),
+ static_cast<int>(total_bounds.height() * kCardAspectRatio / rows)));
+ window_size.set_height(window_size.width() / kCardAspectRatio);
+
+ // Calculate the X and Y offsets necessary to center the grid.
+ int x_offset = total_bounds.x() + ((windows.size() >= columns ? 0 :
+ (columns - windows.size()) * window_size.width()) +
+ (total_bounds.width() - columns * window_size.width())) / 2;
+ int y_offset = total_bounds.y() + (total_bounds.height() -
+ rows * window_size.height()) / 2;
+ for (size_t i = 0; i < windows.size(); ++i) {
+ gfx::Transform transform;
+ int column = i % columns;
+ int row = i / columns;
+ gfx::Rect target_bounds(window_size.width() * column + x_offset,
+ 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);
+ }
+}
+
+void WindowSelector::HideAndTrackNonOverviewWindows() {
+ // Add the windows to hidden_windows first so that if any are destroyed
+ // while hiding them they are tracked.
+ aura::Window::Windows root_windows = Shell::GetAllRootWindows();
+ for (aura::Window::Windows::const_iterator root_iter = root_windows.begin();
+ root_iter != root_windows.end(); ++root_iter) {
+ for (size_t i = 0; i < kSwitchableWindowContainerIdsLength; ++i) {
+ aura::Window* container = Shell::GetContainer(*root_iter,
+ kSwitchableWindowContainerIds[i]);
+ for (aura::Window::Windows::const_iterator iter =
+ container->children().begin(); iter != container->children().end();
+ ++iter) {
+ if (GetTargetedWindow(*iter) || !(*iter)->IsVisible())
+ continue;
+ hidden_windows_.Add(*iter);
+ }
+ }
+ }
+
+ // Copy the window list as it can change during iteration.
+ const aura::WindowTracker::Windows hidden_windows(hidden_windows_.windows());
+ for (aura::WindowTracker::Windows::const_iterator iter =
+ hidden_windows.begin(); iter != hidden_windows.end(); ++iter) {
+ if (!hidden_windows_.Contains(*iter))
+ continue;
+ ui::ScopedLayerAnimationSettings settings(
+ (*iter)->layer()->GetAnimator());
+ settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
+ ScopedTransformOverviewWindow::kTransitionMilliseconds));
+ settings.SetPreemptionStrategy(
+ ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
+ (*iter)->Hide();
+ // Hiding the window can result in it being destroyed.
+ if (!hidden_windows_.Contains(*iter))
+ continue;
+ (*iter)->layer()->SetOpacity(0);
+ }
+}
+
void WindowSelector::ResetFocusRestoreWindow(bool focus) {
if (!restore_focus_window_)
return;
@@ -283,4 +565,25 @@ 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
« ash/wm/overview/window_selector.h ('K') | « ash/wm/overview/window_selector.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698