Index: ash/wm/window_selector.cc |
diff --git a/ash/wm/window_selector.cc b/ash/wm/window_selector.cc |
index f9de84c1019ea54e5f79025943effc5f193c84e2..9ba9bfe04812510ead621f1cc57585b7ac17c083 100644 |
--- a/ash/wm/window_selector.cc |
+++ b/ash/wm/window_selector.cc |
@@ -12,29 +12,273 @@ |
#include "ash/wm/window_selector_delegate.h" |
#include "ash/wm/window_util.h" |
#include "base/memory/scoped_ptr.h" |
+#include "third_party/skia/include/core/SkColor.h" |
#include "ui/aura/client/aura_constants.h" |
+#include "ui/aura/client/screen_position_client.h" |
#include "ui/aura/root_window.h" |
#include "ui/aura/window.h" |
#include "ui/base/events/event.h" |
+#include "ui/compositor/layer_animation_observer.h" |
#include "ui/compositor/scoped_layer_animation_settings.h" |
+#include "ui/gfx/display.h" |
#include "ui/gfx/interpolated_transform.h" |
#include "ui/gfx/transform_util.h" |
+#include "ui/views/corewm/shadow_types.h" |
#include "ui/views/corewm/window_animations.h" |
+#include "ui/views/corewm/window_util.h" |
+#include "ui/views/widget/widget.h" |
namespace ash { |
namespace { |
const float kCardAspectRatio = 4.0f / 3.0f; |
-const int kWindowMargin = 20; |
+const int kWindowMargin = 30; |
const int kMinCardsMajor = 3; |
const int kOverviewTransitionMilliseconds = 100; |
+const SkColor kWindowSelectorSelectionColor = SK_ColorBLACK; |
+const float kWindowSelectorSelectionOpacity = 0.5f; |
+const int kWindowSelectorSelectionPadding = 15; |
-// Applies a transform to |window| to fit within |target_bounds| while |
-// maintaining its aspect ratio. |
-void TransformWindowToFitBounds(aura::Window* window, |
- const gfx::Rect& target_bounds) { |
- const gfx::Rect bounds = window->bounds(); |
+// Creates a copy of |window| with |recreated_layer| in the |target_root|. |
+views::Widget* CreateCopyOfWindow(aura::RootWindow* target_root, |
+ aura::Window* src_window, |
+ ui::Layer* recreated_layer) { |
+ views::Widget* widget = new views::Widget; |
+ views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); |
+ params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; |
+ params.parent = src_window->parent(); |
+ params.can_activate = false; |
+ params.keep_on_top = true; |
+ widget->set_focus_on_creation(false); |
+ widget->Init(params); |
+ widget->SetVisibilityChangedAnimationsEnabled(false); |
+ std::string name = src_window->name() + " (Copy)"; |
+ widget->GetNativeWindow()->SetName(name); |
+ views::corewm::SetShadowType(widget->GetNativeWindow(), |
+ views::corewm::SHADOW_TYPE_RECTANGULAR); |
+ |
+ // Set the bounds in the target root window. |
+ gfx::Display target_display = |
+ Shell::GetScreen()->GetDisplayNearestWindow(target_root); |
+ aura::client::ScreenPositionClient* screen_position_client = |
+ aura::client::GetScreenPositionClient(src_window->GetRootWindow()); |
+ if (screen_position_client && target_display.is_valid()) { |
+ screen_position_client->SetBounds(widget->GetNativeWindow(), |
+ src_window->GetBoundsInScreen(), target_display); |
+ } else { |
+ widget->SetBounds(src_window->GetBoundsInScreen()); |
+ } |
+ widget->StackAbove(src_window); |
+ |
+ // Move the |recreated_layer| to the newly created window. |
+ recreated_layer->set_delegate(src_window->layer()->delegate()); |
+ gfx::Rect layer_bounds = recreated_layer->bounds(); |
+ layer_bounds.set_origin(gfx::Point(0, 0)); |
+ recreated_layer->SetBounds(layer_bounds); |
+ recreated_layer->SetVisible(false); |
+ recreated_layer->parent()->Remove(recreated_layer); |
+ |
+ aura::Window* window = widget->GetNativeWindow(); |
+ recreated_layer->SetVisible(true); |
+ window->layer()->Add(recreated_layer); |
+ window->layer()->StackAtTop(recreated_layer); |
+ window->layer()->SetOpacity(1); |
+ window->Show(); |
+ return widget; |
+} |
+ |
+// An observer which closes the widget and deletes the layer after an |
+// animation finishes. |
+class CleanupWidgetAfterAnimationObserver : public ui::LayerAnimationObserver { |
+ public: |
+ CleanupWidgetAfterAnimationObserver(views::Widget* widget, ui::Layer* layer); |
+ |
+ virtual void OnLayerAnimationEnded( |
+ ui::LayerAnimationSequence* sequence) OVERRIDE; |
+ virtual void OnLayerAnimationAborted( |
+ ui::LayerAnimationSequence* sequence) OVERRIDE; |
+ virtual void OnLayerAnimationScheduled( |
+ ui::LayerAnimationSequence* sequence) OVERRIDE; |
+ |
+ protected: |
+ virtual ~CleanupWidgetAfterAnimationObserver(); |
+ |
+ private: |
+ views::Widget* widget_; |
+ ui::Layer* layer_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(CleanupWidgetAfterAnimationObserver); |
+}; |
+ |
+CleanupWidgetAfterAnimationObserver::CleanupWidgetAfterAnimationObserver( |
+ views::Widget* widget, |
+ ui::Layer* layer) |
+ : widget_(widget), |
+ layer_(layer) { |
+ widget_->GetNativeWindow()->layer()->GetAnimator()->AddObserver(this); |
+} |
+ |
+void CleanupWidgetAfterAnimationObserver::OnLayerAnimationEnded( |
+ ui::LayerAnimationSequence* sequence) { |
+ delete this; |
+} |
+ |
+void CleanupWidgetAfterAnimationObserver::OnLayerAnimationAborted( |
+ ui::LayerAnimationSequence* sequence) { |
+ delete this; |
+} |
+ |
+void CleanupWidgetAfterAnimationObserver::OnLayerAnimationScheduled( |
+ ui::LayerAnimationSequence* sequence) { |
+} |
+ |
+CleanupWidgetAfterAnimationObserver::~CleanupWidgetAfterAnimationObserver() { |
+ widget_->GetNativeWindow()->layer()->GetAnimator()->RemoveObserver(this); |
+ widget_->Close(); |
+ widget_ = NULL; |
+ if (layer_) { |
+ views::corewm::DeepDeleteLayers(layer_); |
+ layer_ = NULL; |
+ } |
+} |
+ |
+// The animation settings used for window selector animations. |
+class WindowSelectorAnimationSettings |
+ : public ui::ScopedLayerAnimationSettings { |
+ public: |
+ WindowSelectorAnimationSettings(aura::Window* window) : |
+ ui::ScopedLayerAnimationSettings(window->layer()->GetAnimator()) { |
+ SetPreemptionStrategy( |
+ ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
+ SetTransitionDuration( |
+ base::TimeDelta::FromMilliseconds(kOverviewTransitionMilliseconds)); |
+ } |
+ |
+ virtual ~WindowSelectorAnimationSettings() { |
+ } |
+}; |
+ |
+} // namespace |
+ |
+// TODO(flackr): Split up into separate file under subdirectory in ash/wm. |
+class WindowSelectorWindow { |
+ public: |
+ explicit WindowSelectorWindow(aura::Window* window); |
+ virtual ~WindowSelectorWindow(); |
+ |
+ aura::Window* window() { return window_; } |
+ const aura::Window* window() const { return window_; } |
+ |
+ // Returns true if this window selector window contains the |target|. This is |
+ // used to determine if an event targetted this window. |
+ bool Contains(const aura::Window* target) const; |
+ |
+ // Restores this window on exit rather than returning it to a minimized state |
+ // if it was minimized on entering overview mode. |
+ void RestoreWindowOnExit(); |
+ |
+ // Informs the WindowSelectorWindow that the window being watched was |
+ // destroyed. This resets the internal window pointer to avoid calling |
+ // anything on the window at destruction time. |
+ void OnWindowDestroyed(); |
+ |
+ // Applies a transform to the window to fit within |target_bounds| while |
+ // maintaining its aspect ratio. |
+ void TransformToFitBounds(aura::RootWindow* root_window, |
+ const gfx::Rect& target_bounds); |
+ |
+ gfx::Rect bounds() { return fit_bounds_; } |
+ |
+ private: |
+ // A weak pointer to the real window in the overview. |
+ aura::Window* window_; |
+ |
+ // A copy of the window used to transition the window to another root. |
+ views::Widget* window_copy_; |
+ |
+ // A weak pointer to a deep copy of the window's layers. |
+ ui::Layer* layer_; |
+ |
+ // If true, the window was minimized and should be restored if the window |
+ // was not selected. |
+ bool minimized_; |
+ |
+ // The original transform of the window before entering overview mode. |
+ gfx::Transform original_transform_; |
+ |
+ // The bounds this window is fit to. |
+ gfx::Rect fit_bounds_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(WindowSelectorWindow); |
+}; |
+ |
+WindowSelectorWindow::WindowSelectorWindow(aura::Window* window) |
+ : window_(window), |
+ window_copy_(NULL), |
+ layer_(NULL), |
+ minimized_(window->GetProperty(aura::client::kShowStateKey) == |
+ ui::SHOW_STATE_MINIMIZED), |
+ original_transform_(window->layer()->transform()) { |
+ if (minimized_) |
+ window_->Show(); |
+} |
+ |
+WindowSelectorWindow::~WindowSelectorWindow() { |
+ if (window_) { |
+ WindowSelectorAnimationSettings animation_settings(window_); |
+ gfx::Transform transform; |
+ window_->SetTransform(original_transform_); |
+ if (minimized_) { |
+ // Setting opacity 0 and visible false ensures that the property change |
+ // to SHOW_STATE_MINIMIZED will not animate the window from its original |
+ // bounds to the minimized position. |
+ window_->layer()->SetOpacity(0); |
+ window_->layer()->SetVisible(false); |
+ window_->SetProperty(aura::client::kShowStateKey, |
+ ui::SHOW_STATE_MINIMIZED); |
+ } |
+ } |
+ // If a copy of the window was created, clean it up. |
+ if (window_copy_) { |
+ if (window_) { |
+ // If the initial window wasn't destroyed, the copy needs to be animated |
+ // out. CleanupWidgetAfterAnimationObserver will destroy the widget and |
+ // layer after the animation is complete. |
+ new CleanupWidgetAfterAnimationObserver(window_copy_, layer_); |
+ WindowSelectorAnimationSettings animation_settings( |
+ window_copy_->GetNativeWindow()); |
+ window_copy_->GetNativeWindow()->SetTransform(original_transform_); |
+ } else { |
+ window_copy_->Close(); |
+ if (layer_) |
+ views::corewm::DeepDeleteLayers(layer_); |
+ } |
+ window_copy_ = NULL; |
+ layer_ = NULL; |
+ } |
+} |
+ |
+bool WindowSelectorWindow::Contains(const aura::Window* window) const { |
+ if (window_copy_ && window_copy_->GetNativeWindow()->Contains(window)) |
+ return true; |
+ return window_->Contains(window); |
+} |
+ |
+void WindowSelectorWindow::RestoreWindowOnExit() { |
+ minimized_ = false; |
+ original_transform_ = gfx::Transform(); |
+} |
+ |
+void WindowSelectorWindow::OnWindowDestroyed() { |
+ window_ = NULL; |
+} |
+ |
+void WindowSelectorWindow::TransformToFitBounds( |
+ aura::RootWindow* root_window, |
+ const gfx::Rect& target_bounds) { |
+ fit_bounds_ = target_bounds; |
+ const gfx::Rect bounds = window_->GetBoundsInScreen(); |
float scale = std::min(1.0f, |
std::min(static_cast<float>(target_bounds.width()) / bounds.width(), |
static_cast<float>(target_bounds.height()) / bounds.height())); |
@@ -45,137 +289,186 @@ void TransformWindowToFitBounds(aura::Window* window, |
transform.Translate(target_bounds.x() - bounds.x() + offset.x(), |
target_bounds.y() - bounds.y() + offset.y()); |
transform.Scale(scale, scale); |
- // TODO(flackr): The window bounds or transform could change during overview |
- // mode. WindowSelector should create a copy of the window so that the |
- // displayed windows are not affected by changes happening in the background. |
- // This will be necessary for alt-tab cycling as well, as some windows will |
- // be coming from other displays: http://crbug.com/263481. |
- window->SetTransform(transform); |
+ if (root_window != window_->GetRootWindow()) { |
+ if (!window_copy_) { |
+ DCHECK(!layer_); |
+ layer_ = views::corewm::RecreateWindowLayers(window_, true); |
+ window_copy_ = CreateCopyOfWindow(root_window, window_, layer_); |
+ } |
+ WindowSelectorAnimationSettings animation_settings( |
+ window_copy_->GetNativeWindow()); |
+ window_copy_->GetNativeWindow()->SetTransform(transform); |
+ } |
+ WindowSelectorAnimationSettings animation_settings(window_); |
+ window_->SetTransform(transform); |
} |
-} // namespace |
+// A comparator for locating a given target window. |
+struct WindowSelectorWindowComparator |
+ : public std::unary_function<WindowSelectorWindow*, bool> { |
+ explicit WindowSelectorWindowComparator(const aura::Window* target_window) |
+ : target(target_window) { |
+ } |
+ |
+ bool operator()(const WindowSelectorWindow* window) const { |
+ return target == window->window(); |
+ } |
+ |
+ const aura::Window* target; |
+}; |
WindowSelector::WindowSelector(const WindowList& windows, |
+ WindowSelector::Mode mode, |
WindowSelectorDelegate* delegate) |
- : delegate_(delegate) { |
+ : mode_(mode), |
+ delegate_(delegate), |
+ selected_window_(0), |
+ selection_root_(NULL) { |
DCHECK(delegate_); |
for (size_t i = 0; i < windows.size(); ++i) { |
windows[i]->AddObserver(this); |
- WindowDetails details; |
- details.window = windows[i]; |
- details.minimized = windows[i]->GetProperty(aura::client::kShowStateKey) == |
- ui::SHOW_STATE_MINIMIZED; |
- details.original_transform = windows[i]->layer()->transform(); |
- if (details.minimized) { |
- windows[i]->Show(); |
- } |
- windows_.push_back(details); |
+ windows_.push_back(new WindowSelectorWindow(windows[i])); |
} |
+ if (mode == WindowSelector::CYCLE) |
+ selection_root_ = ash::Shell::GetActiveRootWindow(); |
PositionWindows(); |
ash::Shell::GetInstance()->AddPreTargetHandler(this); |
} |
WindowSelector::~WindowSelector() { |
for (size_t i = 0; i < windows_.size(); i++) { |
- ui::ScopedLayerAnimationSettings animation_settings( |
- windows_[i].window->layer()->GetAnimator()); |
- animation_settings.SetPreemptionStrategy( |
- ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
- animation_settings.SetTransitionDuration( |
- base::TimeDelta::FromMilliseconds(kOverviewTransitionMilliseconds)); |
- windows_[i].window->RemoveObserver(this); |
- gfx::Transform transform; |
- windows_[i].window->SetTransform(windows_[i].original_transform); |
- if (windows_[i].minimized) { |
- // Setting opacity 0 and visible false ensures that the property change |
- // to SHOW_STATE_MINIMIZED will not animate the window from its original |
- // bounds to the minimized position. |
- windows_[i].window->layer()->SetOpacity(0); |
- windows_[i].window->layer()->SetVisible(false); |
- windows_[i].window->SetProperty(aura::client::kShowStateKey, |
- ui::SHOW_STATE_MINIMIZED); |
- } |
+ windows_[i]->window()->RemoveObserver(this); |
} |
ash::Shell::GetInstance()->RemovePreTargetHandler(this); |
} |
+void WindowSelector::Step(WindowSelector::Direction direction) { |
+ DCHECK(windows_.size() > 0); |
+ if (!selection_widget_) |
+ InitializeSelectionWidget(); |
+ selected_window_ = (selected_window_ + windows_.size() + |
+ (direction == WindowSelector::FORWARD ? 1 : -1)) % windows_.size(); |
+ UpdateSelectionLocation(true); |
+} |
+ |
+void WindowSelector::SelectWindow() { |
+ delegate_->OnWindowSelected(windows_[selected_window_]->window()); |
+} |
+ |
void WindowSelector::OnEvent(ui::Event* event) { |
- // TODO(flackr): This will prevent anything else from working while overview |
- // mode is active. This should only stop events from being sent to the windows |
- // in the overview but still allow interaction with the launcher / tray and |
- // hotkeys http://crbug.com/264289. |
- EventHandler::OnEvent(event); |
- event->StopPropagation(); |
+ ui::EventHandler::OnEvent(event); |
+ |
+ // If the event is targetted at any of the windows in the overview, then |
+ // prevent it from propagating. |
+ aura::Window* target = static_cast<aura::Window*>(event->target()); |
+ for (size_t i = 0; i < windows_.size(); ++i) { |
+ if (windows_[i]->Contains(target)) { |
+ event->StopPropagation(); |
+ break; |
+ } |
+ } |
} |
void WindowSelector::OnMouseEvent(ui::MouseEvent* event) { |
if (event->type() != ui::ET_MOUSE_RELEASED) |
return; |
- aura::Window* target = static_cast<aura::Window*>(event->target()); |
- if (!target->HitTest(event->location())) |
+ WindowSelectorWindow* target = GetEventTarget(event); |
+ if (!target) |
return; |
- HandleSelectionEvent(event); |
+ HandleSelectionEvent(target); |
} |
void WindowSelector::OnGestureEvent(ui::GestureEvent* event) { |
if (event->type() != ui::ET_GESTURE_TAP) |
return; |
- HandleSelectionEvent(event); |
+ WindowSelectorWindow* target = GetEventTarget(event); |
+ if (!target) |
+ return; |
+ |
+ HandleSelectionEvent(target); |
} |
void WindowSelector::OnWindowDestroyed(aura::Window* window) { |
- std::vector<WindowDetails>::iterator iter = |
- std::find(windows_.begin(), windows_.end(), window); |
+ ScopedVector<WindowSelectorWindow>::iterator iter = |
+ std::find_if(windows_.begin(), windows_.end(), |
+ WindowSelectorWindowComparator(window)); |
DCHECK(iter != windows_.end()); |
+ size_t deleted_index = iter - windows_.begin(); |
+ (*iter)->OnWindowDestroyed(); |
windows_.erase(iter); |
if (windows_.empty()) { |
delegate_->OnSelectionCanceled(); |
return; |
} |
+ if (selected_window_ >= deleted_index) { |
+ if (selected_window_ > deleted_index) |
+ selected_window_--; |
+ selected_window_ = selected_window_ % windows_.size(); |
+ UpdateSelectionLocation(true); |
+ } |
PositionWindows(); |
} |
-void WindowSelector::HandleSelectionEvent(ui::Event* event) { |
+WindowSelectorWindow* 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->HitTest(event->location())) |
+ return NULL; |
for (size_t i = 0; i < windows_.size(); i++) { |
- if (windows_[i].window->Contains(target)) { |
- // The selected window should not be minimized when window selection is |
- // ended. |
- windows_[i].minimized = false; |
- windows_[i].original_transform = gfx::Transform(); |
- |
- // The delegate may delete the WindowSelector, assume the object may no |
- // longer valid after calling this. |
- delegate_->OnWindowSelected(windows_[i].window); |
- return; |
- } |
+ if (windows_[i]->Contains(target)) |
+ return windows_[i]; |
} |
+ return NULL; |
+} |
+ |
+void WindowSelector::HandleSelectionEvent(WindowSelectorWindow* target) { |
+ // The selected window should not be minimized when window selection is |
+ // ended. |
+ target->RestoreWindowOnExit(); |
+ delegate_->OnWindowSelected(target->window()); |
} |
void WindowSelector::PositionWindows() { |
- Shell::RootWindowList root_window_list = Shell::GetAllRootWindows(); |
- for (size_t i = 0; i < root_window_list.size(); ++i) { |
- PositionWindowsOnRoot(root_window_list[i]); |
+ if (selection_root_) { |
+ DCHECK_EQ(mode_, CYCLE); |
+ std::vector<WindowSelectorWindow*> windows; |
+ for (size_t i = 0; i < windows_.size(); ++i) |
+ windows.push_back(windows_[i]); |
+ PositionWindowsOnRoot(selection_root_, windows); |
+ } else { |
+ DCHECK_EQ(mode_, OVERVIEW); |
+ Shell::RootWindowList root_window_list = Shell::GetAllRootWindows(); |
+ for (size_t i = 0; i < root_window_list.size(); ++i) |
+ PositionWindowsFromRoot(root_window_list[i]); |
} |
} |
-void WindowSelector::PositionWindowsOnRoot(aura::RootWindow* root_window) { |
- gfx::Size window_size; |
- gfx::Rect total_bounds = ScreenAsh::GetDisplayWorkAreaBoundsInParent( |
- Shell::GetContainer(root_window, |
- internal::kShellWindowId_DefaultContainer)); |
- |
- std::vector<WindowDetails> windows; |
+void WindowSelector::PositionWindowsFromRoot(aura::RootWindow* root_window) { |
+ std::vector<WindowSelectorWindow*> windows; |
for (size_t i = 0; i < windows_.size(); ++i) { |
- if (windows_[i].window->GetRootWindow() == root_window) |
+ if (windows_[i]->window()->GetRootWindow() == root_window) |
windows.push_back(windows_[i]); |
} |
+ PositionWindowsOnRoot(root_window, windows); |
+} |
+ |
+void WindowSelector::PositionWindowsOnRoot( |
+ aura::RootWindow* root_window, |
+ const std::vector<WindowSelectorWindow*>& windows) { |
if (windows.empty()) |
return; |
+ gfx::Size window_size; |
+ gfx::Rect total_bounds = ScreenAsh::ConvertRectToScreen(root_window, |
+ ScreenAsh::GetDisplayWorkAreaBoundsInParent( |
+ Shell::GetContainer(root_window, |
+ internal::kShellWindowId_DefaultContainer))); |
+ |
// Find the minimum number of windows per row that will fit all of the |
// windows on screen. |
size_t columns = std::max( |
@@ -195,12 +488,6 @@ void WindowSelector::PositionWindowsOnRoot(aura::RootWindow* root_window) { |
int y_offset = total_bounds.y() + (total_bounds.height() - |
rows * window_size.height()) / 2; |
for (size_t i = 0; i < windows.size(); ++i) { |
- ui::ScopedLayerAnimationSettings animation_settings( |
- windows[i].window->layer()->GetAnimator()); |
- animation_settings.SetPreemptionStrategy( |
- ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
- animation_settings.SetTransitionDuration( |
- base::TimeDelta::FromMilliseconds(kOverviewTransitionMilliseconds)); |
gfx::Transform transform; |
int column = i % columns; |
int row = i / columns; |
@@ -209,7 +496,48 @@ void WindowSelector::PositionWindowsOnRoot(aura::RootWindow* root_window) { |
window_size.width(), |
window_size.height()); |
target_bounds.Inset(kWindowMargin, kWindowMargin); |
- TransformWindowToFitBounds(windows[i].window, target_bounds); |
+ windows[i]->TransformToFitBounds(root_window, target_bounds); |
+ } |
+} |
+ |
+void WindowSelector::InitializeSelectionWidget() { |
+ selection_widget_.reset(new views::Widget); |
+ views::Widget::InitParams params; |
+ params.type = views::Widget::InitParams::TYPE_POPUP; |
+ params.can_activate = false; |
+ params.keep_on_top = false; |
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
+ params.opacity = views::Widget::InitParams::OPAQUE_WINDOW; |
+ params.parent = Shell::GetContainer( |
+ selection_root_, |
+ internal::kShellWindowId_DefaultContainer); |
+ params.accept_events = false; |
+ selection_widget_->set_focus_on_creation(false); |
+ selection_widget_->Init(params); |
+ views::View* content_view = new views::View; |
+ content_view->set_background( |
+ views::Background::CreateSolidBackground(kWindowSelectorSelectionColor)); |
+ selection_widget_->SetContentsView(content_view); |
+ UpdateSelectionLocation(false); |
+ selection_widget_->GetNativeWindow()->parent()->StackChildAtBottom( |
+ selection_widget_->GetNativeWindow()); |
+ selection_widget_->Show(); |
+ selection_widget_->GetNativeWindow()->layer()->SetOpacity( |
+ kWindowSelectorSelectionOpacity); |
+} |
+ |
+void WindowSelector::UpdateSelectionLocation(bool animate) { |
+ if (!selection_widget_) |
+ return; |
+ gfx::Rect target_bounds = windows_[selected_window_]->bounds(); |
+ target_bounds.Inset(-kWindowSelectorSelectionPadding, |
+ -kWindowSelectorSelectionPadding); |
+ if (animate) { |
+ WindowSelectorAnimationSettings animation_settings( |
+ selection_widget_->GetNativeWindow()); |
+ selection_widget_->SetBounds(target_bounds); |
+ } else { |
+ selection_widget_->SetBounds(target_bounds); |
} |
} |