summaryrefslogtreecommitdiffstats
path: root/athena/wm
diff options
context:
space:
mode:
Diffstat (limited to 'athena/wm')
-rw-r--r--athena/wm/bezel_controller.cc84
-rw-r--r--athena/wm/bezel_controller.h12
-rw-r--r--athena/wm/mru_window_tracker.cc53
-rw-r--r--athena/wm/mru_window_tracker.h49
-rw-r--r--athena/wm/public/window_list_provider.h27
-rw-r--r--athena/wm/public/window_manager.h2
-rw-r--r--athena/wm/public/window_manager_observer.h4
-rw-r--r--athena/wm/split_view_controller.cc248
-rw-r--r--athena/wm/split_view_controller.h79
-rw-r--r--athena/wm/window_manager_impl.cc25
-rw-r--r--athena/wm/window_overview_mode.cc63
-rw-r--r--athena/wm/window_overview_mode.h7
12 files changed, 561 insertions, 92 deletions
diff --git a/athena/wm/bezel_controller.cc b/athena/wm/bezel_controller.cc
index fb62155..a4e8156 100644
--- a/athena/wm/bezel_controller.cc
+++ b/athena/wm/bezel_controller.cc
@@ -6,6 +6,10 @@
#include "ui/aura/window.h"
#include "ui/events/event_handler.h"
+#include "ui/gfx/display.h"
+#include "ui/gfx/geometry/point_conversions.h"
+#include "ui/gfx/screen.h"
+#include "ui/wm/core/coordinate_conversion.h"
namespace athena {
namespace {
@@ -15,7 +19,7 @@ namespace {
// So setting this width fairly high for now.
const float kBezelWidth = 20.0f;
-const float kScrollPositionNone = -100;
+const float kScrollDeltaNone = 0;
bool ShouldProcessGesture(ui::EventType event_type) {
return event_type == ui::ET_GESTURE_SCROLL_UPDATE ||
@@ -24,6 +28,24 @@ bool ShouldProcessGesture(ui::EventType event_type) {
event_type == ui::ET_GESTURE_END;
}
+gfx::Display GetDisplay(aura::Window* window) {
+ gfx::Screen* screen = gfx::Screen::GetScreenFor(window);
+ return screen->GetDisplayNearestWindow(window);
+}
+
+float GetDistance(const gfx::PointF& location,
+ aura::Window* window,
+ BezelController::Bezel bezel) {
+ DCHECK(bezel == BezelController::BEZEL_LEFT ||
+ bezel == BezelController::BEZEL_RIGHT);
+ // Convert location from window coordinates to screen coordinates.
+ gfx::Point point_in_screen(gfx::ToRoundedPoint(location));
+ wm::ConvertPointToScreen(window, &point_in_screen);
+ return bezel == BezelController::BEZEL_LEFT
+ ? point_in_screen.x()
+ : point_in_screen.x() - GetDisplay(window).bounds().width();
+}
+
} // namespace
BezelController::BezelController(aura::Window* container)
@@ -34,25 +56,22 @@ BezelController::BezelController(aura::Window* container)
left_right_delegate_(NULL) {
}
-float BezelController::GetDistance(const gfx::PointF& position,
- BezelController::Bezel bezel) {
- DCHECK(bezel == BEZEL_LEFT || bezel == BEZEL_RIGHT);
- return bezel == BEZEL_LEFT
- ? position.x()
- : position.x() - container_->GetBoundsInScreen().width();
+void BezelController::SetState(BezelController::State state) {
+ // Use SetState(State, float) if |state| is one of the BEZEL_SCROLLING states.
+ DCHECK_NE(state, BEZEL_SCROLLING_TWO_FINGERS);
+ DCHECK_NE(state, BEZEL_SCROLLING_ONE_FINGER);
+ SetState(state, kScrollDeltaNone);
}
void BezelController::SetState(BezelController::State state,
- const gfx::PointF& scroll_position) {
+ float scroll_delta) {
if (!left_right_delegate_ || state == state_)
return;
- if (state == BEZEL_SCROLLING_TWO_FINGERS) {
- float delta = GetDistance(scroll_position, scroll_bezel_);
- left_right_delegate_->ScrollBegin(scroll_bezel_, delta);
- } else if (state_ == BEZEL_SCROLLING_TWO_FINGERS) {
+ if (state == BEZEL_SCROLLING_TWO_FINGERS)
+ left_right_delegate_->ScrollBegin(scroll_bezel_, scroll_delta);
+ else if (state_ == BEZEL_SCROLLING_TWO_FINGERS)
left_right_delegate_->ScrollEnd();
- }
state_ = state;
if (state == NONE) {
scroll_bezel_ = BEZEL_NONE;
@@ -62,10 +81,10 @@ void BezelController::SetState(BezelController::State state,
// Only implemented for LEFT and RIGHT bezels ATM.
BezelController::Bezel BezelController::GetBezel(const gfx::PointF& location) {
+ int screen_width = GetDisplay(container_).bounds().width();
if (location.x() < kBezelWidth) {
return BEZEL_LEFT;
- } else if (location.x() >
- container_->GetBoundsInScreen().width() - kBezelWidth) {
+ } else if (location.x() > screen_width - kBezelWidth) {
return BEZEL_RIGHT;
} else {
return BEZEL_NONE;
@@ -73,7 +92,7 @@ BezelController::Bezel BezelController::GetBezel(const gfx::PointF& location) {
}
void BezelController::OnGestureEvent(ui::GestureEvent* event) {
- // TODO (mfomitchev): Currently we aren't retargetting or consuming any of the
+ // TODO(mfomitchev): Currently we aren't retargetting or consuming any of the
// touch events. This means that content can prevent the generation of gesture
// events and two-finger scroll won't work. Possible solution to this problem
// is hosting our own gesture recognizer or retargetting touch events at the
@@ -92,11 +111,15 @@ void BezelController::OnGestureEvent(ui::GestureEvent* event) {
const gfx::PointF& event_location = event->location_f();
const ui::GestureEventDetails& event_details = event->details();
int num_touch_points = event_details.touch_points();
+ float scroll_delta = kScrollDeltaNone;
+ if (scroll_bezel_ != BEZEL_NONE) {
+ aura::Window* target_window = static_cast<aura::Window*>(event->target());
+ scroll_delta = GetDistance(event_location, target_window, scroll_bezel_);
+ }
if (type == ui::ET_GESTURE_BEGIN) {
if (num_touch_points > 2) {
- SetState(IGNORE_CURRENT_SCROLL,
- gfx::Point(kScrollPositionNone, kScrollPositionNone));
+ SetState(IGNORE_CURRENT_SCROLL);
return;
}
BezelController::Bezel event_bezel = GetBezel(event->location_f());
@@ -104,12 +127,10 @@ void BezelController::OnGestureEvent(ui::GestureEvent* event) {
case NONE:
scroll_bezel_ = event_bezel;
scroll_target_ = event->target();
- if (event_bezel != BEZEL_LEFT && event_bezel != BEZEL_RIGHT) {
- SetState(IGNORE_CURRENT_SCROLL,
- gfx::Point(kScrollPositionNone, kScrollPositionNone));
- } else {
- SetState(BEZEL_GESTURE_STARTED, event_location);
- }
+ if (event_bezel != BEZEL_LEFT && event_bezel != BEZEL_RIGHT)
+ SetState(IGNORE_CURRENT_SCROLL);
+ else
+ SetState(BEZEL_GESTURE_STARTED);
break;
case IGNORE_CURRENT_SCROLL:
break;
@@ -120,12 +141,11 @@ void BezelController::OnGestureEvent(ui::GestureEvent* event) {
DCHECK_NE(scroll_bezel_, BEZEL_NONE);
if (event_bezel != scroll_bezel_) {
- SetState(IGNORE_CURRENT_SCROLL,
- gfx::Point(kScrollPositionNone, kScrollPositionNone));
+ SetState(IGNORE_CURRENT_SCROLL);
return;
}
if (state_ == BEZEL_SCROLLING_ONE_FINGER)
- SetState(BEZEL_SCROLLING_TWO_FINGERS, event_location);
+ SetState(BEZEL_SCROLLING_TWO_FINGERS);
break;
case BEZEL_SCROLLING_TWO_FINGERS:
// Should've exited above
@@ -138,10 +158,9 @@ void BezelController::OnGestureEvent(ui::GestureEvent* event) {
CHECK(scroll_target_);
if (num_touch_points == 1) {
- SetState(NONE, gfx::Point(kScrollPositionNone, kScrollPositionNone));
+ SetState(NONE);
} else {
- SetState(IGNORE_CURRENT_SCROLL,
- gfx::Point(kScrollPositionNone, kScrollPositionNone));
+ SetState(IGNORE_CURRENT_SCROLL);
}
} else if (type == ui::ET_GESTURE_SCROLL_BEGIN) {
DCHECK(state_ == IGNORE_CURRENT_SCROLL || state_ == BEZEL_GESTURE_STARTED);
@@ -149,19 +168,18 @@ void BezelController::OnGestureEvent(ui::GestureEvent* event) {
return;
if (num_touch_points == 1) {
- SetState(BEZEL_SCROLLING_ONE_FINGER, event_location);
+ SetState(BEZEL_SCROLLING_ONE_FINGER, scroll_delta);
return;
}
DCHECK_EQ(num_touch_points, 2);
- SetState(BEZEL_SCROLLING_TWO_FINGERS, event_location);
+ SetState(BEZEL_SCROLLING_TWO_FINGERS, scroll_delta);
if (left_right_delegate_->CanScroll())
event->SetHandled();
} else if (type == ui::ET_GESTURE_SCROLL_UPDATE) {
if (state_ != BEZEL_SCROLLING_TWO_FINGERS)
return;
- float scroll_delta = GetDistance(event_location, scroll_bezel_);
left_right_delegate_->ScrollUpdate(scroll_delta);
if (left_right_delegate_->CanScroll())
event->SetHandled();
diff --git a/athena/wm/bezel_controller.h b/athena/wm/bezel_controller.h
index 30fe974..7bec71a 100644
--- a/athena/wm/bezel_controller.h
+++ b/athena/wm/bezel_controller.h
@@ -35,12 +35,15 @@ class BezelController : public ui::EventHandler {
virtual ~ScrollDelegate() {}
// Beginning of a bezel scroll gesture started from the |bezel|.
+ // |delta| is the difference between the x-coordinate of the current scroll
+ // position and the bezel. It will be zero or negative for the right bezel.
virtual void ScrollBegin(Bezel bezel, float delta) = 0;
// End of the current bezel scroll
virtual void ScrollEnd() = 0;
// Update of the scroll position for the currently active bezel scroll.
+ // |delta| has the same meaning as in ScrollBegin().
virtual void ScrollUpdate(float delta) = 0;
// Should return false if the delegate isn't going to react to the scroll
@@ -67,11 +70,10 @@ class BezelController : public ui::EventHandler {
BEZEL_SCROLLING_TWO_FINGERS,
};
- // Calculates the distance from |position| to the |bezel|.
- float GetDistance(const gfx::PointF& position, Bezel bezel);
-
- // |scroll_position| only needs to be passed in the scrolling state
- void SetState(State state, const gfx::PointF& scroll_position);
+ void SetState(State state);
+ // |scroll_delta| only needs to be passed when |state| is one of the
+ // BEZEL_SROLLING states.
+ void SetState(State state, float scroll_delta);
// Returns the bezel corresponding to the |location| or BEZEL_NONE if the
// location is outside of the bezel area.
diff --git a/athena/wm/mru_window_tracker.cc b/athena/wm/mru_window_tracker.cc
new file mode 100644
index 0000000..b2cda0c
--- /dev/null
+++ b/athena/wm/mru_window_tracker.cc
@@ -0,0 +1,53 @@
+// 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/mru_window_tracker.h"
+
+#include "ui/aura/window.h"
+
+namespace athena {
+
+MruWindowTracker::MruWindowTracker(aura::Window* container)
+ : container_(container) {
+ container->AddObserver(this);
+}
+
+MruWindowTracker::~MruWindowTracker() {
+ if (container_)
+ container_->RemoveObserver(this);
+}
+
+aura::Window::Windows MruWindowTracker::GetWindowList() const {
+ return aura::Window::Windows(mru_windows_.begin(), mru_windows_.end());
+}
+
+void MruWindowTracker::MoveToFront(aura::Window* window) {
+ DCHECK(window);
+ CHECK_EQ(container_, window->parent());
+ std::list<aura::Window*>::iterator it =
+ std::find(mru_windows_.begin(), mru_windows_.end(), window);
+ DCHECK(it != mru_windows_.end());
+ mru_windows_.erase(it);
+ mru_windows_.push_back(window);
+}
+
+// Overridden from WindowObserver:
+void MruWindowTracker::OnWillRemoveWindow(aura::Window* window) {
+ std::list<aura::Window*>::iterator it =
+ std::find(mru_windows_.begin(), mru_windows_.end(), window);
+ if (it == mru_windows_.end()) {
+ // All normal windows should be tracked in mru_windows_
+ DCHECK_NE(window->type(), ui::wm::WINDOW_TYPE_NORMAL);
+ return;
+ }
+ mru_windows_.erase(it);
+}
+
+void MruWindowTracker::OnWindowAdded(aura::Window* new_window) {
+ // We are only interested in ordering normal windows.
+ if (new_window->type() == ui::wm::WINDOW_TYPE_NORMAL)
+ mru_windows_.push_back(new_window);
+}
+
+} // namespace athena
diff --git a/athena/wm/mru_window_tracker.h b/athena/wm/mru_window_tracker.h
new file mode 100644
index 0000000..0ec9d98
--- /dev/null
+++ b/athena/wm/mru_window_tracker.h
@@ -0,0 +1,49 @@
+// 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_MRU_WINDOW_TRACKER_H_
+#define ATHENA_WM_MRU_WINDOW_TRACKER_H_
+
+#include <list>
+
+#include "athena/wm/public/window_list_provider.h"
+#include "ui/aura/window_observer.h"
+
+namespace aura {
+class Window;
+}
+
+namespace athena {
+
+// Maintains a most recently used list of windows. This is used for window
+// cycling and overview mode.
+class MruWindowTracker : public WindowListProvider,
+ public aura::WindowObserver {
+ public:
+ explicit MruWindowTracker(aura::Window* container);
+ virtual ~MruWindowTracker();
+
+ // Overridden from WindowListProvider
+ virtual aura::Window::Windows GetWindowList() const OVERRIDE;
+
+ // Updates the mru_windows_ list to move |window| to the front.
+ // |window| must be the child of |container_|.
+ virtual void MoveToFront(aura::Window* window) OVERRIDE;
+
+ private:
+ // Overridden from WindowObserver:
+ virtual void OnWillRemoveWindow(aura::Window* window) OVERRIDE;
+ virtual void OnWindowAdded(aura::Window* new_window) OVERRIDE;
+
+ // List of windows that have been used in the container, sorted by most
+ // recently used.
+ std::list<aura::Window*> mru_windows_;
+ aura::Window* container_;
+
+ DISALLOW_COPY_AND_ASSIGN(MruWindowTracker);
+};
+
+} // namespace athena
+
+#endif // ATHENA_WM_MRU_WINDOW_TRACKER_H_
diff --git a/athena/wm/public/window_list_provider.h b/athena/wm/public/window_list_provider.h
new file mode 100644
index 0000000..7ffadf4
--- /dev/null
+++ b/athena/wm/public/window_list_provider.h
@@ -0,0 +1,27 @@
+// 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_PUBLIC_WINDOW_LIST_PROVIDER_H_
+#define ATHENA_WM_PUBLIC_WINDOW_LIST_PROVIDER_H_
+
+#include "athena/athena_export.h"
+#include "ui/aura/window.h"
+
+namespace athena {
+
+// Interface for an ordered list of aura::Window objects.
+class ATHENA_EXPORT WindowListProvider {
+ public:
+ virtual ~WindowListProvider() {}
+
+ // Returns an ordered list of windows.
+ virtual aura::Window::Windows GetWindowList() const = 0;
+
+ // Moves the window to the front of the list.
+ virtual void MoveToFront(aura::Window* window) = 0;
+};
+
+} // namespace athena
+
+#endif // ATHENA_WM_PUBLIC_WINDOW_LIST_PROVIDER_H_
diff --git a/athena/wm/public/window_manager.h b/athena/wm/public/window_manager.h
index 23aab7f..04e2cce 100644
--- a/athena/wm/public/window_manager.h
+++ b/athena/wm/public/window_manager.h
@@ -24,6 +24,8 @@ class ATHENA_EXPORT WindowManager {
virtual void ToggleOverview() = 0;
+ virtual bool IsOverviewModeActive() = 0;
+
virtual void AddObserver(WindowManagerObserver* observer) = 0;
virtual void RemoveObserver(WindowManagerObserver* observer) = 0;
};
diff --git a/athena/wm/public/window_manager_observer.h b/athena/wm/public/window_manager_observer.h
index e7f6bcf..216b58c 100644
--- a/athena/wm/public/window_manager_observer.h
+++ b/athena/wm/public/window_manager_observer.h
@@ -13,10 +13,10 @@ class ATHENA_EXPORT WindowManagerObserver {
public:
virtual ~WindowManagerObserver() {}
- // Called when the overview mode is displayed.
+ // Called immediately before the overview mode is displayed.
virtual void OnOverviewModeEnter() = 0;
- // Called when going out of overview mode.
+ // Called immediately after going out of the overview mode.
virtual void OnOverviewModeExit() = 0;
};
diff --git a/athena/wm/split_view_controller.cc b/athena/wm/split_view_controller.cc
index 7da3675..595a61a 100644
--- a/athena/wm/split_view_controller.cc
+++ b/athena/wm/split_view_controller.cc
@@ -4,29 +4,273 @@
#include "athena/wm/split_view_controller.h"
+#include <cmath>
+
+#include "athena/wm/public/window_list_provider.h"
+#include "athena/wm/public/window_manager.h"
+#include "base/bind.h"
#include "ui/aura/window.h"
+#include "ui/compositor/layer_animation_observer.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/events/event_handler.h"
+#include "ui/gfx/display.h"
+#include "ui/gfx/screen.h"
namespace athena {
+namespace {
+
+// An animation observer that runs a callback at the end of the animation, and
+// destroys itself.
+class CallbackAnimationObserver : public ui::ImplicitAnimationObserver {
+ public:
+ explicit CallbackAnimationObserver(const base::Closure& closure)
+ : closure_(closure) {}
+
+ virtual ~CallbackAnimationObserver() {}
+
+ private:
+ // Overridden from ui::ImplicitAnimationObserver:
+ virtual void OnImplicitAnimationsCompleted() OVERRIDE {
+ if (!closure_.is_null())
+ closure_.Run();
+ delete this;
+ }
-SplitViewController::SplitViewController() {
+ const base::Closure closure_;
+
+ DISALLOW_COPY_AND_ASSIGN(CallbackAnimationObserver);
+};
+
+} // namespace
+
+SplitViewController::SplitViewController(
+ aura::Window* container,
+ WindowListProvider* window_list_provider,
+ WindowManager* window_manager)
+ : state_(INACTIVE),
+ container_(container),
+ window_manager_(window_manager),
+ window_list_provider_(window_list_provider),
+ current_activity_window_(NULL),
+ left_window_(NULL),
+ right_window_(NULL),
+ separator_position_(0),
+ weak_factory_(this) {
+ window_manager->AddObserver(this);
}
SplitViewController::~SplitViewController() {
+ window_manager_->RemoveObserver(this);
+}
+
+bool SplitViewController::IsSplitViewModeActive() const {
+ return state_ == ACTIVE;
+}
+
+void SplitViewController::UpdateLayout(bool animate) {
+ if (!left_window_)
+ return;
+ CHECK(right_window_);
+ gfx::Transform left_transform;
+ gfx::Transform right_transform;
+ int container_width = container_->GetBoundsInScreen().width();
+ if (state_ == ACTIVE) {
+ // This method should only be called once in ACTIVE state when
+ // the left and rightwindows are still full screen and need to be resized.
+ CHECK_EQ(left_window_->bounds().width(), container_width);
+ CHECK_EQ(right_window_->bounds().width(), container_width);
+ // Windows should be resized via an animation when entering the ACTIVE
+ // state.
+ CHECK(animate);
+ // We scale the windows here, but when the animation finishes, we reset
+ // the scaling and update the window bounds to the proper size - see
+ // OnAnimationCompleted().
+ left_transform.Scale(.5, 1);
+ right_transform.Scale(.5, 1);
+ right_transform.Translate(container_width, 0);
+ } else {
+ left_transform.Translate(separator_position_ - container_width, 0);
+ right_transform.Translate(separator_position_, 0);
+ }
+ left_window_->Show();
+ right_window_->Show();
+ SetWindowTransform(left_window_, left_transform, animate);
+ SetWindowTransform(right_window_, right_transform, animate);
+}
+
+void SplitViewController::SetWindowTransform(aura::Window* window,
+ const gfx::Transform& transform,
+ bool animate) {
+ if (animate) {
+ scoped_refptr<ui::LayerAnimator> animator = window->layer()->GetAnimator();
+ ui::ScopedLayerAnimationSettings settings(animator);
+ settings.SetPreemptionStrategy(
+ ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
+ settings.AddObserver(new CallbackAnimationObserver(
+ base::Bind(&SplitViewController::OnAnimationCompleted,
+ weak_factory_.GetWeakPtr(),
+ window)));
+ window->SetTransform(transform);
+ } else {
+ window->SetTransform(transform);
+ }
+}
+
+void SplitViewController::OnAnimationCompleted(aura::Window* window) {
+ DCHECK(window == left_window_ || window == right_window_);
+ if (state_ == ACTIVE) {
+ gfx::Rect window_bounds = gfx::Rect(container_->bounds().size());
+ int container_width = window_bounds.width();
+ window_bounds.set_width(container_width / 2);
+ window->SetTransform(gfx::Transform());
+ if (window == left_window_) {
+ left_window_->SetBounds(window_bounds);
+ } else {
+ window_bounds.set_x(container_width / 2);
+ right_window_->SetBounds(window_bounds);
+ }
+ } else {
+ int container_width = container_->bounds().width();
+ window->SetTransform(gfx::Transform());
+ if (window == left_window_) {
+ if (separator_position_ == 0)
+ left_window_->Hide();
+ if (state_ == INACTIVE)
+ left_window_ = NULL;
+ } else {
+ if (separator_position_ == container_width)
+ right_window_->Hide();
+ if (state_ == INACTIVE)
+ right_window_ = NULL;
+ }
+ }
}
+void SplitViewController::UpdateSeparatorPositionFromScrollDelta(float delta) {
+ gfx::Screen* screen = gfx::Screen::GetScreenFor(container_);
+ const gfx::Rect& display_bounds =
+ screen->GetDisplayNearestWindow(container_).bounds();
+ gfx::Rect container_bounds = container_->GetBoundsInScreen();
+ separator_position_ =
+ delta > 0 ? ((int)delta) + display_bounds.x() - container_bounds.x()
+ : display_bounds.right() - container_bounds.x() + delta;
+}
+
+aura::Window* SplitViewController::GetCurrentActivityWindow() {
+ if (!current_activity_window_) {
+ aura::Window::Windows windows = window_list_provider_->GetWindowList();
+ if (windows.empty())
+ return NULL;
+ current_activity_window_ = windows.back();
+ }
+ return current_activity_window_;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Begin BezelController::ScrollDelegate overrides.
void SplitViewController::ScrollBegin(BezelController::Bezel bezel,
float delta) {
+ if (!CanScroll())
+ return;
+ state_ = SCROLLING;
+ aura::Window* current_window = GetCurrentActivityWindow();
+ CHECK(current_window);
+
+ aura::Window::Windows windows = window_list_provider_->GetWindowList();
+ CHECK(windows.size() >= 2);
+ aura::Window::Windows::const_iterator it =
+ std::find(windows.begin(), windows.end(), current_window);
+ CHECK(it != windows.end());
+
+ if (delta > 0) {
+ right_window_ = current_window;
+ // reverse iterator points to the position before normal iterator |it|
+ aura::Window::Windows::const_reverse_iterator rev_it(it);
+ // circle to end if needed.
+ left_window_ = rev_it == windows.rend() ? windows.back() : *(rev_it);
+ } else {
+ left_window_ = current_window;
+ ++it;
+ // circle to front if needed.
+ right_window_ = it == windows.end() ? windows.front() : *it;
+ }
+
+ CHECK(left_window_);
+ CHECK(right_window_);
+
+ // TODO(oshima|mfomitchev): crbug.com/388362
+ // Until we are properly hiding off-screen windows in window manager:
+ // Loop through all windows and hide them
+ for (it = windows.begin(); it != windows.end(); ++it) {
+ if (*it != left_window_ && *it != right_window_)
+ (*it)->Hide();
+ }
+
+ UpdateSeparatorPositionFromScrollDelta(delta);
+ UpdateLayout(false);
}
+// Max distance from the scroll end position to the middle of the screen where
+// we would go into the split view mode.
+const int kMaxDistanceFromMiddle = 120;
void SplitViewController::ScrollEnd() {
+ if (state_ != SCROLLING)
+ return;
+
+ int container_width = container_->GetBoundsInScreen().width();
+ if (std::abs(container_width / 2 - separator_position_) <=
+ kMaxDistanceFromMiddle) {
+ state_ = ACTIVE;
+ separator_position_ = container_width / 2;
+ } else if (separator_position_ < container_width / 2) {
+ separator_position_ = 0;
+ current_activity_window_ = right_window_;
+ state_ = INACTIVE;
+ } else {
+ separator_position_ = container_width;
+ current_activity_window_ = left_window_;
+ state_ = INACTIVE;
+ }
+ UpdateLayout(true);
}
void SplitViewController::ScrollUpdate(float delta) {
+ if (state_ != SCROLLING)
+ return;
+ UpdateSeparatorPositionFromScrollDelta(delta);
+ UpdateLayout(false);
}
bool SplitViewController::CanScroll() {
- return false;
+ // TODO(mfomitchev): return false in vertical orientation, in full screen.
+ bool result = (!window_manager_->IsOverviewModeActive() &&
+ !IsSplitViewModeActive() &&
+ window_list_provider_->GetWindowList().size() >= 2);
+ return result;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// WindowManagerObserver overrides
+void SplitViewController::OnOverviewModeEnter() {
+ if (state_ == ACTIVE) {
+ CHECK(left_window_);
+ CHECK(right_window_);
+ window_list_provider_->MoveToFront(right_window_);
+ window_list_provider_->MoveToFront(left_window_);
+ // TODO(mfomitchev): This shouldn't be done here, but the overview mode's
+ // transition animation currently looks bad if the starting transform of
+ // any window is not gfx::Transform().
+ right_window_->SetTransform(gfx::Transform());
+ } else if (current_activity_window_) {
+ window_list_provider_->MoveToFront(current_activity_window_);
+ }
+ state_ = INACTIVE;
+ left_window_ = NULL;
+ right_window_ = NULL;
+ current_activity_window_ = NULL;
+}
+
+void SplitViewController::OnOverviewModeExit() {
}
} // namespace athena
diff --git a/athena/wm/split_view_controller.h b/athena/wm/split_view_controller.h
index e0652de..337b75b 100644
--- a/athena/wm/split_view_controller.h
+++ b/athena/wm/split_view_controller.h
@@ -6,24 +6,99 @@
#define ATHENA_WM_SPLIT_VIEW_CONTROLLER_H_
#include "athena/wm/bezel_controller.h"
+#include "athena/wm/public/window_manager_observer.h"
+#include "athena/wm/window_overview_mode.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+
+namespace gfx {
+class Transform;
+}
namespace athena {
+class WindowListProvider;
+class WindowManager;
+class WindowOverviewModeDelegate;
// Responsible for entering split view mode, exiting from split view mode, and
// laying out the windows in split view mode.
-class SplitViewController : public BezelController::ScrollDelegate {
+class SplitViewController : public BezelController::ScrollDelegate,
+ public WindowManagerObserver {
public:
- SplitViewController();
+ SplitViewController(aura::Window* container,
+ WindowListProvider* window_list_provider,
+ WindowManager* window_manager);
+
virtual ~SplitViewController();
+ bool IsSplitViewModeActive() const;
+
private:
+ enum State {
+ // Split View mode is not active. |left_window_| and |right_window| are
+ // NULL.
+ INACTIVE,
+ // Two windows |left_window_| and |right_window| are shown side by side and
+ // there is a horizontal scroll in progress which is dragging the separator
+ // between the two windows.
+ SCROLLING,
+ // Split View mode is active with |left_window_| and |right_window| showing
+ // side by side each occupying half the screen. No scroll in progress.
+ ACTIVE
+ };
+
+ void UpdateLayout(bool animate);
+
+ void SetWindowTransform(aura::Window* left_window,
+ const gfx::Transform& transform,
+ bool animate);
+
+ void OnAnimationCompleted(aura::Window* window);
+
+ void UpdateSeparatorPositionFromScrollDelta(float delta);
+
+ // Returns the current activity shown to the user. Persists through the
+ // SCROLLING and ACTIVE states and gets updated if the current activity goes
+ // off screen when the user switches between activities.
+ aura::Window* GetCurrentActivityWindow();
+
// BezelController::ScrollDelegate overrides.
virtual void ScrollBegin(BezelController::Bezel bezel, float delta) OVERRIDE;
virtual void ScrollEnd() OVERRIDE;
virtual void ScrollUpdate(float delta) OVERRIDE;
virtual bool CanScroll() OVERRIDE;
+ // WindowManagerObserver
+ virtual void OnOverviewModeEnter() OVERRIDE;
+ virtual void OnOverviewModeExit() OVERRIDE;
+
+ State state_;
+
+ aura::Window* container_;
+
+ // Window Manager which owns this SplitViewController.
+ // Must be non NULL for the duration of the lifetime.
+ WindowManager* window_manager_;
+
+ // Provider of the list of windows to cycle through. Not owned.
+ WindowListProvider* window_list_provider_;
+
+ // Keeps track of the current activity shown as the user switches between
+ // activities. Persists through the SCROLLING and ACTIVE states. Gets reset
+ // to NULL when overview mode is activated.
+ aura::Window* current_activity_window_;
+
+ // Windows for the left and right activities shown in SCROLLING and ACTIVE
+ // states. In INACTIVE state these are NULL.
+ aura::Window* left_window_;
+ aura::Window* right_window_;
+
+ // Position of the separator between left_window_ and right_window_ in
+ // container_ coordinates (along the x axis).
+ int separator_position_;
+
+ base::WeakPtrFactory<SplitViewController> weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(SplitViewController);
};
diff --git a/athena/wm/window_manager_impl.cc b/athena/wm/window_manager_impl.cc
index 560252a..37daf43 100644
--- a/athena/wm/window_manager_impl.cc
+++ b/athena/wm/window_manager_impl.cc
@@ -10,6 +10,7 @@
#include "athena/input/public/accelerator_manager.h"
#include "athena/screen/public/screen_manager.h"
#include "athena/wm/bezel_controller.h"
+#include "athena/wm/mru_window_tracker.h"
#include "athena/wm/public/window_manager_observer.h"
#include "athena/wm/split_view_controller.h"
#include "athena/wm/title_drag_controller.h"
@@ -41,6 +42,8 @@ class WindowManagerImpl : public WindowManager,
// WindowManager:
virtual void ToggleOverview() OVERRIDE;
+ virtual bool IsOverviewModeActive() OVERRIDE;
+
private:
enum Command {
CMD_TOGGLE_OVERVIEW,
@@ -74,6 +77,7 @@ class WindowManagerImpl : public WindowManager,
virtual void OnTitleDragCanceled(aura::Window* window) OVERRIDE;
scoped_ptr<aura::Window> container_;
+ scoped_ptr<MruWindowTracker> mru_window_tracker_;
scoped_ptr<WindowOverviewMode> overview_;
scoped_ptr<BezelController> bezel_controller_;
scoped_ptr<SplitViewController> split_view_controller_;
@@ -112,8 +116,10 @@ WindowManagerImpl::WindowManagerImpl() {
container_.reset(ScreenManager::Get()->CreateDefaultContainer(params));
container_->SetLayoutManager(new AthenaContainerLayoutManager);
container_->AddObserver(this);
+ mru_window_tracker_.reset(new MruWindowTracker(container_.get()));
bezel_controller_.reset(new BezelController(container_.get()));
- split_view_controller_.reset(new SplitViewController());
+ split_view_controller_.reset(new SplitViewController(
+ container_.get(), mru_window_tracker_.get(), this));
bezel_controller_->set_left_right_delegate(split_view_controller_.get());
container_->AddPreTargetHandler(bezel_controller_.get());
title_drag_controller_.reset(new TitleDragController(container_.get(), this));
@@ -127,6 +133,7 @@ WindowManagerImpl::WindowManagerImpl() {
WindowManagerImpl::~WindowManagerImpl() {
overview_.reset();
+ mru_window_tracker_.reset();
if (container_) {
container_->RemoveObserver(this);
container_->RemovePreTargetHandler(bezel_controller_.get());
@@ -154,15 +161,26 @@ void WindowManagerImpl::ToggleOverview() {
SetInOverview(overview_.get() == NULL);
}
+bool WindowManagerImpl::IsOverviewModeActive() {
+ return overview_;
+}
+
void WindowManagerImpl::SetInOverview(bool active) {
bool in_overview = !!overview_;
if (active == in_overview)
return;
if (active) {
- overview_ = WindowOverviewMode::Create(container_.get(), this);
FOR_EACH_OBSERVER(WindowManagerObserver, observers_,
OnOverviewModeEnter());
+ // Re-stack all windows in the order defined by mru_window_tracker_.
+ aura::Window::Windows window_list = mru_window_tracker_->GetWindowList();
+ aura::Window::Windows::iterator it;
+ for (it = window_list.begin(); it != window_list.end(); ++it)
+ container_->StackChildAtTop(*it);
+ overview_ = WindowOverviewMode::Create(container_.get(),
+ mru_window_tracker_.get(),
+ this);
} else {
overview_.reset();
FOR_EACH_OBSERVER(WindowManagerObserver, observers_,
@@ -188,8 +206,7 @@ void WindowManagerImpl::RemoveObserver(WindowManagerObserver* observer) {
}
void WindowManagerImpl::OnSelectWindow(aura::Window* window) {
- CHECK_EQ(container_.get(), window->parent());
- container_->StackChildAtTop(window);
+ mru_window_tracker_->MoveToFront(window);
wm::ActivateWindow(window);
SetInOverview(false);
}
diff --git a/athena/wm/window_overview_mode.cc b/athena/wm/window_overview_mode.cc
index efad0b1..91ee8c9 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/public/window_list_provider.h"
#include "base/bind.h"
#include "base/macros.h"
#include "ui/aura/scoped_window_targeter.h"
@@ -50,10 +51,6 @@ namespace athena {
namespace {
-bool ShouldShowWindowInOverviewMode(aura::Window* window) {
- return window->type() == ui::wm::WINDOW_TYPE_NORMAL;
-}
-
// Gets the transform for the window in its current state.
gfx::Transform GetTransformForState(WindowOverviewState* state) {
return gfx::Tween::TransformValueBetween(state->progress,
@@ -108,8 +105,10 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
public ui::CompositorAnimationObserver {
public:
WindowOverviewModeImpl(aura::Window* container,
+ const WindowListProvider* window_list_provider,
WindowOverviewModeDelegate* delegate)
: container_(container),
+ window_list_provider_(window_list_provider),
delegate_(delegate),
scoped_targeter_(new aura::ScopedWindowTargeter(
container,
@@ -127,13 +126,10 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
virtual ~WindowOverviewModeImpl() {
container_->set_target_handler(container_->delegate());
RemoveAnimationObserver();
- const aura::Window::Windows& windows = container_->children();
- for (aura::Window::Windows::const_iterator iter = windows.begin();
- iter != windows.end();
- ++iter) {
- if ((*iter)->GetProperty(kWindowOverviewState))
- RestoreWindowState(*iter);
- }
+ aura::Window::Windows windows = window_list_provider_->GetWindowList();
+ if (windows.empty())
+ return;
+ std::for_each(windows.begin(), windows.end(), &RestoreWindowState);
}
private:
@@ -141,10 +137,8 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
// positions. The transforms are set in the |kWindowOverviewState| property of
// the windows.
void ComputeTerminalStatesForAllWindows() {
- const aura::Window::Windows& windows = container_->children();
- size_t window_count = std::count_if(windows.begin(), windows.end(),
- ShouldShowWindowInOverviewMode);
-
+ aura::Window::Windows windows = window_list_provider_->GetWindowList();
+ size_t window_count = windows.size();
size_t index = 0;
const gfx::Size container_size = container_->bounds().size();
@@ -153,10 +147,8 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
for (aura::Window::Windows::const_reverse_iterator iter = windows.rbegin();
iter != windows.rend();
- ++iter) {
+ ++iter, ++index) {
aura::Window* window = (*iter);
- if (!ShouldShowWindowInOverviewMode(window))
- continue;
gfx::Transform top_transform;
int top = (window_count - index - 1) * kGapBetweenWindowsTop;
@@ -176,27 +168,20 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
state->progress = 0.f;
window->SetProperty(kWindowOverviewState, state);
wm::SetShadowType(window, wm::SHADOW_TYPE_RECTANGULAR_ALWAYS_ACTIVE);
-
- index++;
}
}
// Sets the initial position for the windows for the overview mode.
void SetInitialWindowStates() {
+ aura::Window::Windows windows = window_list_provider_->GetWindowList();
+ size_t window_count = windows.size();
// The initial overview state of the topmost three windows.
const float kInitialProgress[] = { 0.5f, 0.05f, 0.01f };
- size_t index = 0;
- const aura::Window::Windows& windows = container_->children();
- for (aura::Window::Windows::const_reverse_iterator iter = windows.rbegin();
- iter != windows.rend();
- ++iter) {
- aura::Window* window = (*iter);
- if (!window->GetProperty(kWindowOverviewState))
- continue;
-
+ for (size_t i = 0; i < window_count; ++i) {
float progress = 0.f;
- if (index < arraysize(kInitialProgress))
- progress = kInitialProgress[index];
+ aura::Window* window = windows[window_count - 1 - i];
+ if (i < arraysize(kInitialProgress))
+ progress = kInitialProgress[i];
scoped_refptr<ui::LayerAnimator> animator =
window->layer()->GetAnimator();
@@ -217,7 +202,6 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(250));
SetWindowProgress(window, progress);
}
- index++;
}
}
@@ -244,7 +228,7 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
void DoScroll(float delta_y) {
const float kEpsilon = 1e-3f;
float delta_y_p = std::abs(delta_y) / GetScrollableHeight();
- const aura::Window::Windows& windows = container_->children();
+ aura::Window::Windows windows = window_list_provider_->GetWindowList();
if (delta_y < 0) {
// Scroll up. Start with the top-most (i.e. behind-most in terms of
// z-index) window, and try to scroll them up.
@@ -253,8 +237,6 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
++iter) {
aura::Window* window = (*iter);
WindowOverviewState* state = window->GetProperty(kWindowOverviewState);
- if (!state)
- continue;
if (state->progress > kEpsilon) {
// It is possible to scroll |window| up. Scroll it up, and update
// |delta_y_p| for the next window.
@@ -266,14 +248,12 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
} else {
// Scroll down. Start with the bottom-most (i.e. front-most in terms of
// z-index) window, and try to scroll them down.
- for (aura::Window::Windows::const_reverse_iterator iter =
- windows.rbegin();
+ aura::Window::Windows::const_reverse_iterator iter;
+ for (iter = windows.rbegin();
delta_y_p > kEpsilon && iter != windows.rend();
++iter) {
aura::Window* window = (*iter);
WindowOverviewState* state = window->GetProperty(kWindowOverviewState);
- if (!state)
- continue;
if (1.f - state->progress > kEpsilon) {
// It is possible to scroll |window| down. Scroll it down, and update
// |delta_y_p| for the next window.
@@ -489,6 +469,8 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
const float kMinOpacity = 0.2f;
aura::Window* container_;
+ // Provider of the stack of windows to show in the overview mode. Not owned.
+ const WindowListProvider* window_list_provider_;
WindowOverviewModeDelegate* delegate_;
scoped_ptr<aura::ScopedWindowTargeter> scoped_targeter_;
scoped_ptr<ui::FlingCurve> fling_;
@@ -504,9 +486,10 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
// static
scoped_ptr<WindowOverviewMode> WindowOverviewMode::Create(
aura::Window* container,
+ const WindowListProvider* window_list_provider,
WindowOverviewModeDelegate* delegate) {
return scoped_ptr<WindowOverviewMode>(
- new WindowOverviewModeImpl(container, delegate));
+ new WindowOverviewModeImpl(container, window_list_provider, delegate));
}
} // namespace athena
diff --git a/athena/wm/window_overview_mode.h b/athena/wm/window_overview_mode.h
index 46eb249..a95a0fb 100644
--- a/athena/wm/window_overview_mode.h
+++ b/athena/wm/window_overview_mode.h
@@ -6,12 +6,10 @@
#define ATHENA_WM_WINDOW_OVERVIEW_MODE_H_
#include "base/memory/scoped_ptr.h"
-
-namespace aura {
-class Window;
-}
+#include "ui/aura/window.h"
namespace athena {
+class WindowListProvider;
class WindowOverviewModeDelegate {
public:
@@ -26,6 +24,7 @@ class WindowOverviewMode {
static scoped_ptr<WindowOverviewMode> Create(
aura::Window* container,
+ const WindowListProvider* window_list_provider,
WindowOverviewModeDelegate* delegate);
};