summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-14 03:53:45 +0000
committersadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-14 03:55:03 +0000
commit1d359848a45de76562b8f62d78dd6599a5897653 (patch)
tree669d1240f3a09e0f2ef88bf496194e766448b7a8
parent34afc93c435d2155a3a43e278fec32eff87d20dc (diff)
downloadchromium_src-1d359848a45de76562b8f62d78dd6599a5897653.zip
chromium_src-1d359848a45de76562b8f62d78dd6599a5897653.tar.gz
chromium_src-1d359848a45de76562b8f62d78dd6599a5897653.tar.bz2
athena: Allow getting into split-view mode from overview-mode.
When a window is dragged horizontally in the overview-mode, create an OverviewToolbar object. The toolbar shows a couple of ActionButtons for 'close' and 'split' options. If the user drags (and drops) the window over the 'split' button, then the split-view mode is triggered. The buttons are highlighted (scaled up 50%) to indicate the action that will be performed. BUG=402598 R=mfomitchev@chromium.org, mukai@chromium.org Review URL: https://codereview.chromium.org/459613008 Cr-Commit-Position: refs/heads/master@{#289454} git-svn-id: svn://svn.chromium.org/chrome/trunk/src@289454 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--athena/athena.gyp3
-rw-r--r--athena/resources/athena_resources.grd2
-rw-r--r--athena/resources/default_100_percent/overview_split.pngbin0 -> 4264 bytes
-rw-r--r--athena/resources/default_100_percent/overview_trash.pngbin0 -> 4583 bytes
-rw-r--r--athena/wm/DEPS1
-rw-r--r--athena/wm/overview_toolbar.cc196
-rw-r--r--athena/wm/overview_toolbar.h68
-rw-r--r--athena/wm/split_view_controller.cc37
-rw-r--r--athena/wm/split_view_controller.h5
-rw-r--r--athena/wm/window_manager_impl.cc8
-rw-r--r--athena/wm/window_overview_mode.cc74
-rw-r--r--athena/wm/window_overview_mode.h6
12 files changed, 388 insertions, 12 deletions
diff --git a/athena/athena.gyp b/athena/athena.gyp
index 87a175a..a8ae58c 100644
--- a/athena/athena.gyp
+++ b/athena/athena.gyp
@@ -18,6 +18,7 @@
'../ui/events/events.gyp:events_base',
'../ui/strings/ui_strings.gyp:ui_strings',
'../ui/views/views.gyp:views',
+ 'resources/athena_resources.gyp:athena_resources',
],
'defines': [
'ATHENA_IMPLEMENTATION',
@@ -73,6 +74,8 @@
'wm/bezel_controller.h',
'wm/mru_window_tracker.cc',
'wm/mru_window_tracker.h',
+ 'wm/overview_toolbar.cc',
+ 'wm/overview_toolbar.h',
'wm/public/window_list_provider.h',
'wm/public/window_manager.h',
'wm/public/window_manager_observer.h',
diff --git a/athena/resources/athena_resources.grd b/athena/resources/athena_resources.grd
index ee1665a..12e2ff4 100644
--- a/athena/resources/athena_resources.grd
+++ b/athena/resources/athena_resources.grd
@@ -11,6 +11,8 @@
<structures fallback_to_low_resolution="true">
<!-- KEEP THESE IN ALPHABETICAL ORDER! -->
<structure type="chrome_scaled_image" name="IDR_ATHENA_BACKGROUND" file="background_wallpaper.png" />
+ <structure type="chrome_scaled_image" name="IDR_ATHENA_OVERVIEW_SPLIT" file="overview_split.png" />
+ <structure type="chrome_scaled_image" name="IDR_ATHENA_OVERVIEW_TRASH" file="overview_trash.png" />
</structures>
</release>
</grit>
diff --git a/athena/resources/default_100_percent/overview_split.png b/athena/resources/default_100_percent/overview_split.png
new file mode 100644
index 0000000..3874397
--- /dev/null
+++ b/athena/resources/default_100_percent/overview_split.png
Binary files differ
diff --git a/athena/resources/default_100_percent/overview_trash.png b/athena/resources/default_100_percent/overview_trash.png
new file mode 100644
index 0000000..c8ffde1
--- /dev/null
+++ b/athena/resources/default_100_percent/overview_trash.png
Binary files differ
diff --git a/athena/wm/DEPS b/athena/wm/DEPS
index a3cece5..2777ab4 100644
--- a/athena/wm/DEPS
+++ b/athena/wm/DEPS
@@ -1,6 +1,7 @@
include_rules = [
"+athena/common",
"+athena/input/public",
+ "+athena/resources",
"+athena/screen/public",
"+ui/aura",
"+ui/base",
diff --git a/athena/wm/overview_toolbar.cc b/athena/wm/overview_toolbar.cc
new file mode 100644
index 0000000..5c7de40
--- /dev/null
+++ b/athena/wm/overview_toolbar.cc
@@ -0,0 +1,196 @@
+// 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 "athena/wm/overview_toolbar.h"
+
+#include "athena/common/closure_animation_observer.h"
+#include "athena/resources/grit/athena_resources.h"
+#include "base/bind.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "ui/aura/window.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/compositor/layer.h"
+#include "ui/compositor/layer_delegate.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/events/event.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/transform.h"
+
+namespace {
+
+const int kActionButtonImageSize = 54;
+const int kActionButtonTextSize = 20;
+const int kActionButtonPaddingFromRight = 32;
+}
+
+namespace athena {
+
+class ActionButton : public ui::LayerDelegate {
+ public:
+ ActionButton(int resource_id, const std::string& label)
+ : resource_id_(resource_id), label_(base::UTF8ToUTF16(label)) {
+ layer_.reset(new ui::Layer(ui::LAYER_TEXTURED));
+ layer_->set_delegate(this);
+ layer_->SetFillsBoundsOpaquely(false);
+ layer_->SetVisible(true);
+ layer_->SetOpacity(0);
+ }
+
+ virtual ~ActionButton() {}
+
+ static void DestroyAfterFadeout(scoped_ptr<ActionButton> button) {
+ ui::Layer* layer = button->layer();
+ ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
+ settings.AddObserver(new ClosureAnimationObserver(
+ base::Bind(&ActionButton::DestroyImmediately, base::Passed(&button))));
+ layer->SetOpacity(0);
+ }
+
+ void SetPosition(const gfx::Point& position) {
+ layer_->SetBounds(
+ gfx::Rect(position,
+ gfx::Size(kActionButtonImageSize,
+ kActionButtonImageSize + kActionButtonTextSize)));
+ }
+
+ ui::Layer* layer() { return layer_.get(); }
+
+ private:
+ static void DestroyImmediately(scoped_ptr<ActionButton> button) {
+ button.reset();
+ }
+
+ // ui::LayerDelegate:
+ virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE {
+ ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
+ canvas->DrawImageInt(*bundle.GetImageSkiaNamed(resource_id_), 0, 0);
+ gfx::ShadowValues shadow;
+ shadow.push_back(gfx::ShadowValue(gfx::Point(0, 1), 2, SK_ColorBLACK));
+ shadow.push_back(gfx::ShadowValue(gfx::Point(0, -1), 2, SK_ColorBLACK));
+ canvas->DrawStringRectWithShadows(label_,
+ gfx::FontList(),
+ SK_ColorWHITE,
+ gfx::Rect(0,
+ kActionButtonImageSize,
+ kActionButtonImageSize,
+ kActionButtonTextSize),
+ 0,
+ gfx::Canvas::TEXT_ALIGN_CENTER,
+ shadow);
+ }
+
+ virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE {}
+ virtual base::Closure PrepareForLayerBoundsChange() OVERRIDE {
+ return base::Closure();
+ }
+
+ int resource_id_;
+ base::string16 label_;
+ scoped_ptr<ui::Layer> layer_;
+
+ DISALLOW_COPY_AND_ASSIGN(ActionButton);
+};
+
+OverviewToolbar::OverviewToolbar(aura::Window* container)
+ : shown_(false),
+ close_(new ActionButton(IDR_ATHENA_OVERVIEW_TRASH, "Close")),
+ split_(new ActionButton(IDR_ATHENA_OVERVIEW_SPLIT, "Split")),
+ current_action_(ACTION_TYPE_NONE),
+ container_bounds_(container->bounds()) {
+ const int kPaddingFromBottom = 200;
+ const int kPaddingBetweenButtons = 200;
+
+ int x = container_bounds_.right() -
+ (kActionButtonPaddingFromRight + kActionButtonImageSize);
+ int y = container_bounds_.bottom() -
+ (kPaddingFromBottom + kActionButtonImageSize);
+ split_->SetPosition(gfx::Point(x, y));
+ y -= kPaddingBetweenButtons;
+ close_->SetPosition(gfx::Point(x, y));
+
+ container->layer()->Add(split_->layer());
+ container->layer()->Add(close_->layer());
+}
+
+OverviewToolbar::~OverviewToolbar() {
+ // If the buttons are visible, then fade them out, instead of destroying them
+ // immediately.
+ if (shown_) {
+ ActionButton::DestroyAfterFadeout(split_.Pass());
+ ActionButton::DestroyAfterFadeout(close_.Pass());
+ }
+}
+
+OverviewToolbar::ActionType OverviewToolbar::GetHighlightAction(
+ const ui::GestureEvent& event) const {
+ if (IsEventOverButton(split_.get(), event))
+ return ACTION_TYPE_SPLIT;
+ if (IsEventOverButton(close_.get(), event))
+ return ACTION_TYPE_CLOSE;
+ return ACTION_TYPE_NONE;
+}
+
+void OverviewToolbar::SetHighlightAction(ActionType action) {
+ if (current_action_ == action)
+ return;
+ current_action_ = action;
+ if (!shown_) {
+ ShowActionButtons();
+ } else {
+ TransformButton(close_.get());
+ TransformButton(split_.get());
+ }
+}
+
+void OverviewToolbar::ShowActionButtons() {
+ if (!shown_)
+ ToggleActionButtonsVisibility();
+}
+
+void OverviewToolbar::HideActionButtons() {
+ if (shown_)
+ ToggleActionButtonsVisibility();
+}
+
+void OverviewToolbar::ToggleActionButtonsVisibility() {
+ shown_ = !shown_;
+ TransformButton(close_.get());
+ TransformButton(split_.get());
+}
+
+bool OverviewToolbar::IsEventOverButton(ActionButton* button,
+ const ui::GestureEvent& event) const {
+ const int kBoundsInsetForTarget = 30;
+ gfx::RectF bounds = button->layer()->bounds();
+ bounds.Inset(-kBoundsInsetForTarget, -kBoundsInsetForTarget);
+ return bounds.Contains(event.location());
+}
+
+gfx::Transform OverviewToolbar::ComputeTransformFor(
+ ActionButton* button) const {
+ if (!shown_)
+ return gfx::Transform();
+
+ const float kHighlightScale = 1.5;
+ bool button_is_highlighted =
+ (current_action_ == ACTION_TYPE_CLOSE && button == close_.get()) ||
+ (current_action_ == ACTION_TYPE_SPLIT && button == split_.get());
+ gfx::Transform transform;
+ if (button_is_highlighted) {
+ transform.Translate(-kActionButtonImageSize * (kHighlightScale - 1) / 2, 0);
+ transform.Scale(kHighlightScale, kHighlightScale);
+ }
+ return transform;
+}
+
+void OverviewToolbar::TransformButton(ActionButton* button) {
+ ui::ScopedLayerAnimationSettings split_settings(
+ button->layer()->GetAnimator());
+ split_settings.SetTweenType(gfx::Tween::SMOOTH_IN_OUT);
+ button->layer()->SetTransform(ComputeTransformFor(button));
+ button->layer()->SetOpacity(shown_ ? 1 : 0);
+}
+
+} // namespace athena
diff --git a/athena/wm/overview_toolbar.h b/athena/wm/overview_toolbar.h
new file mode 100644
index 0000000..a6fdb3b
--- /dev/null
+++ b/athena/wm/overview_toolbar.h
@@ -0,0 +1,68 @@
+// 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 ATHENA_WM_OVERVIEW_TOOLBAR_H_
+#define ATHENA_WM_OVERVIEW_TOOLBAR_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace aura {
+class Window;
+}
+
+namespace gfx {
+class Transform;
+}
+
+namespace ui {
+class GestureEvent;
+}
+
+namespace athena {
+
+class ActionButton;
+
+// Responsible for showing action-buttons at the right edge of the screen during
+// overview mode.
+class OverviewToolbar {
+ public:
+ enum ActionType {
+ ACTION_TYPE_NONE,
+ ACTION_TYPE_CLOSE,
+ ACTION_TYPE_SPLIT,
+ };
+
+ explicit OverviewToolbar(aura::Window* container);
+ virtual ~OverviewToolbar();
+
+ ActionType current_action() const { return current_action_; }
+
+ // Returns the action the gesture-event is targeting.
+ ActionType GetHighlightAction(const ui::GestureEvent& event) const;
+
+ void SetHighlightAction(ActionType action);
+ void ShowActionButtons();
+ void HideActionButtons();
+
+ private:
+ void ToggleActionButtonsVisibility();
+ bool IsEventOverButton(ActionButton* button,
+ const ui::GestureEvent& event) const;
+ gfx::Transform ComputeTransformFor(ActionButton* button) const;
+ void TransformButton(ActionButton* button);
+
+ bool shown_;
+ scoped_ptr<ActionButton> close_;
+ scoped_ptr<ActionButton> split_;
+ ActionType current_action_;
+ const gfx::Rect container_bounds_;
+
+ DISALLOW_COPY_AND_ASSIGN(OverviewToolbar);
+};
+
+} // namespace athena
+
+#endif // ATHENA_WM_OVERVIEW_TOOLBAR_H_
diff --git a/athena/wm/split_view_controller.cc b/athena/wm/split_view_controller.cc
index 595a61a..cde4657 100644
--- a/athena/wm/split_view_controller.cc
+++ b/athena/wm/split_view_controller.cc
@@ -67,6 +67,43 @@ bool SplitViewController::IsSplitViewModeActive() const {
return state_ == ACTIVE;
}
+void SplitViewController::ActivateSplitMode(aura::Window* left,
+ aura::Window* right) {
+ aura::Window::Windows windows = window_list_provider_->GetWindowList();
+ aura::Window::Windows::reverse_iterator iter = windows.rbegin();
+ if (state_ == ACTIVE) {
+ if (!left)
+ left = left_window_;
+ if (!right)
+ right = right_window_;
+ }
+
+ if (!left && iter != windows.rend()) {
+ left = *iter;
+ iter++;
+ if (left == right && iter != windows.rend()) {
+ left = *iter;
+ iter++;
+ }
+ }
+
+ if (!right && iter != windows.rend()) {
+ right = *iter;
+ iter++;
+ if (right == left && iter != windows.rend()) {
+ right = *iter;
+ iter++;
+ }
+ }
+
+ state_ = ACTIVE;
+ left_window_ = left;
+ right_window_ = right;
+ container_->StackChildAtTop(right_window_);
+ container_->StackChildAtTop(left_window_);
+ UpdateLayout(true);
+}
+
void SplitViewController::UpdateLayout(bool animate) {
if (!left_window_)
return;
diff --git a/athena/wm/split_view_controller.h b/athena/wm/split_view_controller.h
index 337b75b..d7dc20c 100644
--- a/athena/wm/split_view_controller.h
+++ b/athena/wm/split_view_controller.h
@@ -33,6 +33,11 @@ class SplitViewController : public BezelController::ScrollDelegate,
bool IsSplitViewModeActive() const;
+ // Activates split-view mode with |left| and |right| windows. If |left| and/or
+ // |right| is NULL, then the first window in the window-list (which is neither
+ // |left| nor |right|) is selected instead.
+ void ActivateSplitMode(aura::Window* left, aura::Window* right);
+
private:
enum State {
// Split View mode is not active. |left_window_| and |right_window| are
diff --git a/athena/wm/window_manager_impl.cc b/athena/wm/window_manager_impl.cc
index 37daf43..4d75263 100644
--- a/athena/wm/window_manager_impl.cc
+++ b/athena/wm/window_manager_impl.cc
@@ -60,6 +60,8 @@ class WindowManagerImpl : public WindowManager,
// WindowOverviewModeDelegate:
virtual void OnSelectWindow(aura::Window* window) OVERRIDE;
+ virtual void OnSplitViewMode(aura::Window* left,
+ aura::Window* right) OVERRIDE;
// aura::WindowObserver
virtual void OnWindowAdded(aura::Window* new_window) OVERRIDE;
@@ -211,6 +213,12 @@ void WindowManagerImpl::OnSelectWindow(aura::Window* window) {
SetInOverview(false);
}
+void WindowManagerImpl::OnSplitViewMode(aura::Window* left,
+ aura::Window* right) {
+ SetInOverview(false);
+ split_view_controller_->ActivateSplitMode(left, right);
+}
+
void WindowManagerImpl::OnWindowAdded(aura::Window* new_window) {
if (new_window->type() == ui::wm::WINDOW_TYPE_NORMAL)
SetInOverview(false);
diff --git a/athena/wm/window_overview_mode.cc b/athena/wm/window_overview_mode.cc
index 91ee8c9..b36ec11 100644
--- a/athena/wm/window_overview_mode.cc
+++ b/athena/wm/window_overview_mode.cc
@@ -9,6 +9,7 @@
#include <vector>
#include "athena/common/closure_animation_observer.h"
+#include "athena/wm/overview_toolbar.h"
#include "athena/wm/public/window_list_provider.h"
#include "base/bind.h"
#include "base/macros.h"
@@ -290,6 +291,7 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
void DragWindow(const ui::GestureEvent& event) {
CHECK(dragged_window_);
CHECK_EQ(ui::ET_GESTURE_SCROLL_UPDATE, event.type());
+ CHECK(overview_toolbar_);
gfx::Vector2dF dragged_distance =
dragged_start_location_ - event.location();
WindowOverviewState* dragged_state =
@@ -299,11 +301,50 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
transform.Translate(-dragged_distance.x(), 0);
dragged_window_->SetTransform(transform);
+ // Update the toolbar.
+ const int kMinDistanceForActionButtons = 20;
+ if (fabs(dragged_distance.x()) > kMinDistanceForActionButtons)
+ overview_toolbar_->ShowActionButtons();
+ else
+ overview_toolbar_->HideActionButtons();
+
+ // See if the touch-point is above one of the action-buttons.
+ OverviewToolbar::ActionType new_action =
+ overview_toolbar_->GetHighlightAction(event);
+
+ // If the touch-point is not above any of the action buttons, then highlight
+ // the close-button by default, if the user has dragged enough to close the
+ // window.
+ if (new_action == OverviewToolbar::ACTION_TYPE_NONE) {
+ if (fabs(dragged_distance.x()) > kMinDistanceForDismissal)
+ new_action = OverviewToolbar::ACTION_TYPE_CLOSE;
+ else
+ new_action = OverviewToolbar::ACTION_TYPE_NONE;
+ }
+ OverviewToolbar::ActionType previous_action =
+ overview_toolbar_->current_action();
+ overview_toolbar_->SetHighlightAction(new_action);
+
+ // If the user has selected to get into split-view mode, then show the
+ // window with full opacity. Otherwise, fade it out as it closes. Animate
+ // the opacity if transitioning to/from the split-view button.
+ bool animate_opacity =
+ (new_action != previous_action) &&
+ ((new_action == OverviewToolbar::ACTION_TYPE_SPLIT) ||
+ (previous_action == OverviewToolbar::ACTION_TYPE_SPLIT));
float ratio = std::min(
1.f, std::abs(dragged_distance.x()) / kMinDistanceForDismissal);
float opacity =
- gfx::Tween::FloatValueBetween(ratio, kMaxOpacity, kMinOpacity);
- dragged_window_->layer()->SetOpacity(opacity);
+ (new_action == OverviewToolbar::ACTION_TYPE_SPLIT)
+ ? 1
+ : gfx::Tween::FloatValueBetween(ratio, kMaxOpacity, kMinOpacity);
+ if (animate_opacity) {
+ ui::ScopedLayerAnimationSettings settings(
+ dragged_window_->layer()->GetAnimator());
+ dragged_window_->layer()->SetOpacity(opacity);
+ } else {
+ dragged_window_->layer()->SetOpacity(opacity);
+ }
}
bool ShouldCloseDragWindow(const ui::GestureEvent& event) const {
@@ -382,6 +423,19 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
dragged_window_ = NULL;
}
+ void EndDragWindow(const ui::GestureEvent& gesture) {
+ CHECK(dragged_window_);
+ CHECK(overview_toolbar_);
+ OverviewToolbar::ActionType action = overview_toolbar_->current_action();
+ overview_toolbar_.reset();
+ if (action == OverviewToolbar::ACTION_TYPE_SPLIT)
+ delegate_->OnSplitViewMode(NULL, dragged_window_);
+ else if (ShouldCloseDragWindow(gesture))
+ CloseDragWindow(gesture);
+ else
+ RestoreDragWindow();
+ }
+
// ui::EventHandler:
virtual void OnMouseEvent(ui::MouseEvent* mouse) OVERRIDE {
if (mouse->type() == ui::ET_MOUSE_PRESSED) {
@@ -412,6 +466,8 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
std::abs(gesture->details().scroll_y_hint()) * 2) {
dragged_start_location_ = gesture->location();
dragged_window_ = SelectWindowAt(gesture);
+ if (dragged_window_)
+ overview_toolbar_.reset(new OverviewToolbar(container_));
}
} else if (gesture->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
if (dragged_window_)
@@ -420,19 +476,12 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
DoScroll(gesture->details().scroll_y());
gesture->SetHandled();
} else if (gesture->type() == ui::ET_GESTURE_SCROLL_END) {
- if (dragged_window_) {
- if (ShouldCloseDragWindow(*gesture))
- CloseDragWindow(*gesture);
- else
- RestoreDragWindow();
- }
+ if (dragged_window_)
+ EndDragWindow(*gesture);
gesture->SetHandled();
} else if (gesture->type() == ui::ET_SCROLL_FLING_START) {
if (dragged_window_) {
- if (ShouldCloseDragWindow(*gesture))
- CloseDragWindow(*gesture);
- else
- RestoreDragWindow();
+ EndDragWindow(*gesture);
} else {
CreateFlingerFor(*gesture);
AddAnimationObserver();
@@ -477,6 +526,7 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
aura::Window* dragged_window_;
gfx::Point dragged_start_location_;
+ scoped_ptr<OverviewToolbar> overview_toolbar_;
DISALLOW_COPY_AND_ASSIGN(WindowOverviewModeImpl);
};
diff --git a/athena/wm/window_overview_mode.h b/athena/wm/window_overview_mode.h
index a95a0fb..157b525 100644
--- a/athena/wm/window_overview_mode.h
+++ b/athena/wm/window_overview_mode.h
@@ -16,6 +16,12 @@ class WindowOverviewModeDelegate {
virtual ~WindowOverviewModeDelegate() {}
virtual void OnSelectWindow(aura::Window* window) = 0;
+
+ // Gets into split-view mode with |left| on the left-side of the screen, and
+ // |right| on the right-side. If |left| or |right| is NULL, then the delegate
+ // selects the best option in its place.
+ virtual void OnSplitViewMode(aura::Window* left,
+ aura::Window* right) = 0;
};
class WindowOverviewMode {