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

Unified Diff: ash/wm/window_cycle_list.cc

Issue 2129773002: [CrOS] Initial rough cut of alt-tab window cycling UI. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: self review Created 4 years, 5 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/window_cycle_list.h ('K') | « ash/wm/window_cycle_list.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ash/wm/window_cycle_list.cc
diff --git a/ash/wm/window_cycle_list.cc b/ash/wm/window_cycle_list.cc
index 240fc1ff18b0745298932d73f07c51e99363dd67..c287646fe4f409d518701b1277ce1d902487acbc 100644
--- a/ash/wm/window_cycle_list.cc
+++ b/ash/wm/window_cycle_list.cc
@@ -4,12 +4,26 @@
#include "ash/wm/window_cycle_list.h"
+#include "ash/aura/wm_window_aura.h"
+#include "ash/common/ash_switches.h"
+#include "ash/common/shell_window_ids.h"
#include "ash/common/wm/mru_window_tracker.h"
#include "ash/common/wm/window_state.h"
+#include "ash/common/wm_root_window_controller.h"
+#include "ash/common/wm_shell.h"
#include "ash/common/wm_window.h"
#include "ash/shell.h"
+#include "ash/wm/forwarding_layer_delegate.h"
#include "ash/wm/window_animations.h"
#include "ash/wm/window_util.h"
+#include "base/command_line.h"
+#include "ui/compositor/layer_tree_owner.h"
+#include "ui/views/background.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/painter.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+#include "ui/wm/core/window_util.h"
namespace ash {
@@ -54,6 +68,157 @@ class ScopedShowWindow : public WmWindowObserver {
DISALLOW_COPY_AND_ASSIGN(ScopedShowWindow);
};
+// A view that mirrors a single window. Paint calls to this view are forwarded
+// to the underlying window.
+class WindowMirrorView : public views::View, public ::wm::LayerDelegateFactory {
+ public:
+ WindowMirrorView() : target_(nullptr) {}
+ ~WindowMirrorView() override {}
+
+ void Init(WmWindow* window) {
+ DCHECK(!target_);
+
+ SetPaintToLayer(true);
+ target_ = window;
+
+ layer_owner_ = ::wm::RecreateLayers(
+ window->GetInternalWidget()->GetNativeView(), this);
+ mirror_layer()->parent()->Remove(mirror_layer());
+ layer()->Add(mirror_layer());
+ mirror_layer()->SetVisible(true);
+ }
+
+ // views::View:
+ gfx::Size GetPreferredSize() const override {
+ const int kMaxWidth = 800;
+ const int kMaxHeight = 600;
+
+ gfx::Size target_size = target_->GetBounds().size();
+ if (target_size.width() <= kMaxWidth &&
+ target_size.height() <= kMaxHeight) {
+ return target_size;
+ }
+
+ float scale =
+ std::min(kMaxWidth / static_cast<float>(target_size.width()),
+ kMaxHeight / static_cast<float>(target_size.height()));
+ return gfx::ScaleToCeiledSize(target_size, scale, scale);
+ }
+
+ void Layout() override {
+ // Position at 0, 0.
+ mirror_layer()->SetBounds(gfx::Rect(target_->GetBounds().size()));
+
+ // Scale down if necessary.
+ gfx::Size allotted_size = size();
+ gfx::Transform mirror_transform;
+ if (allotted_size != target_->GetBounds().size()) {
+ float scale = width() / static_cast<float>(target_->GetBounds().width());
+ mirror_transform.Scale(scale, scale);
+ }
+ mirror_layer()->SetTransform(mirror_transform);
+ }
+
+ // ::wm::LayerDelegateFactory:
+ ui::LayerDelegate* CreateDelegate(ui::LayerDelegate* delegate) override {
+ if (!delegate)
+ return nullptr;
+ delegates_.push_back(
+ base::WrapUnique(new ForwardingLayerDelegate(target_, delegate)));
+ return delegates_.back().get();
+ }
+
+ private:
+ ui::Layer* mirror_layer() { return layer_owner_->root(); }
+
+ WmWindow* target_;
+
+ std::unique_ptr<ui::LayerTreeOwner> layer_owner_;
+ std::vector<std::unique_ptr<ForwardingLayerDelegate>> delegates_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowMirrorView);
+};
+
+// A view that shows a collection of windows the user can tab through.
+class WindowCycleView : public views::View {
+ public:
+ WindowCycleView(const WindowCycleList::WindowList& windows)
Daniel Erat 2016/07/06 22:04:47 add 'explicit'
Evan Stade 2016/07/06 23:02:59 Done.
+ : mirror_container_(new views::View()),
+ selector_view_(new views::View()),
+ target_window_(nullptr) {
+ SetPaintToLayer(true);
+ layer()->SetFillsBoundsOpaquely(false);
+
+ // TODO(estade): adjust constants in this function (colors, spacing, corner
+ // radius) as per mocks.
+ const float kCornerRadius = 5;
+ set_background(views::Background::CreateBackgroundPainter(
+ true, views::Painter::CreateSolidRoundRectPainter(
+ SkColorSetA(SK_ColorBLACK, 0xA5), kCornerRadius)));
+
+ views::BoxLayout* layout =
+ new views::BoxLayout(views::BoxLayout::kHorizontal, 25, 25, 20);
+ layout->set_cross_axis_alignment(
+ views::BoxLayout::CROSS_AXIS_ALIGNMENT_START);
+ mirror_container_->SetLayoutManager(layout);
+
+ for (WmWindow* window : windows) {
+ WindowMirrorView* view = new WindowMirrorView();
+ view->Init(window);
+ window_view_map_[window] = view;
+ mirror_container_->AddChildView(view);
+ }
+
+ selector_view_->set_background(views::Background::CreateBackgroundPainter(
+ true, views::Painter::CreateSolidRoundRectPainter(SK_ColorBLUE,
+ kCornerRadius)));
+
+ AddChildView(selector_view_);
+ AddChildView(mirror_container_);
+ SetTargetWindow(windows.front());
+ }
+
+ ~WindowCycleView() override {}
+
+ void SetTargetWindow(WmWindow* target) {
+ target_window_ = target;
+ if (GetWidget())
+ Layout();
+ }
+
+ void HandleWindowDestruction(WmWindow* destroying_window,
+ WmWindow* new_target) {
+ views::View* destroying_view = window_view_map_[destroying_window];
Daniel Erat 2016/07/06 22:04:47 maybe DCHECK that it's present in the map?
Evan Stade 2016/07/06 23:02:59 Wouldn't the deref on the next line crash if it we
Daniel Erat 2016/07/06 23:47:30 yeah, i just prefer failed checks to segfaults sin
+ destroying_view->parent()->RemoveChildView(destroying_view);
+ SetTargetWindow(new_target);
+ }
+
+ // views::View overrides:
+ gfx::Size GetPreferredSize() const override {
+ return mirror_container_->GetPreferredSize();
+ }
+
+ void Layout() override {
+ views::View* target_view = window_view_map_[target_window_];
+ gfx::RectF target_bounds(target_view->GetLocalBounds());
+ views::View::ConvertRectToTarget(target_view, this, &target_bounds);
+ target_bounds.Inset(gfx::InsetsF(-15));
+ selector_view_->SetBoundsRect(gfx::ToEnclosingRect(target_bounds));
+
+ mirror_container_->SetBoundsRect(GetLocalBounds());
+ }
+
+ WmWindow* target_window() { return target_window_; }
+
+ private:
+ std::map<WmWindow*, WindowMirrorView*> window_view_map_;
+ views::View* mirror_container_;
+ views::View* selector_view_;
+ WmWindow* target_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowCycleView);
+};
+
ScopedShowWindow::ScopedShowWindow()
: window_(nullptr), stack_window_above_(nullptr), minimized_(false) {}
@@ -106,11 +271,37 @@ void ScopedShowWindow::OnWindowTreeChanging(WmWindow* window,
}
WindowCycleList::WindowCycleList(const WindowList& windows)
- : windows_(windows), current_index_(0) {
+ : windows_(windows),
+ current_index_(0),
+ cycle_view_(nullptr),
+ cycle_ui_widget_(nullptr) {
ash::Shell::GetInstance()->mru_window_tracker()->SetIgnoreActivations(true);
for (WmWindow* window : windows_)
window->AddObserver(this);
+
+ if (ShouldShowUi()) {
+ WmWindow* root_window = WmShell::Get()->GetPrimaryRootWindow();
+ views::Widget* widget = new views::Widget;
+ views::Widget::InitParams params;
+ params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
+ params.accept_events = true;
+ root_window->GetRootWindowController()
+ ->ConfigureWidgetInitParamsForContainer(
+ widget, kShellWindowId_OverlayContainer, &params);
+ widget->Init(params);
+
+ cycle_view_ = new WindowCycleView(windows_);
+
+ widget->SetContentsView(cycle_view_);
+ gfx::Rect widget_rect = widget->GetWorkAreaBoundsInScreen();
+ widget_rect.ClampToCenteredSize(cycle_view_->GetPreferredSize());
+ widget->SetBounds(widget_rect);
+ widget->Show();
+ cycle_ui_widget_ = widget;
+ }
}
WindowCycleList::~WindowCycleList() {
@@ -122,6 +313,13 @@ WindowCycleList::~WindowCycleList() {
}
if (showing_window_)
showing_window_->CancelRestore();
+
+ if (cycle_view_) {
+ cycle_view_->target_window()->Show();
+ cycle_view_->target_window()->GetWindowState()->Activate();
+ }
+
+ delete cycle_ui_widget_;
}
void WindowCycleList::Step(WindowCycleController::Direction direction) {
@@ -146,9 +344,13 @@ void WindowCycleList::Step(WindowCycleController::Direction direction) {
current_index_ = (current_index_ + windows_.size()) % windows_.size();
DCHECK(windows_[current_index_]);
- // Make sure the next window is visible.
- showing_window_.reset(new ScopedShowWindow);
- showing_window_->Show(windows_[current_index_]);
+ if (cycle_view_) {
+ cycle_view_->SetTargetWindow(windows_[current_index_]);
+ } else {
+ // Make sure the next window is visible.
+ showing_window_.reset(new ScopedShowWindow);
+ showing_window_->Show(windows_[current_index_]);
+ }
}
void WindowCycleList::OnWindowDestroying(WmWindow* window) {
@@ -163,6 +365,15 @@ void WindowCycleList::OnWindowDestroying(WmWindow* window) {
current_index_ == static_cast<int>(windows_.size())) {
current_index_--;
}
+
+ if (cycle_view_)
+ cycle_view_->HandleWindowDestruction(window, windows_[current_index_]);
+}
+
+bool WindowCycleList::ShouldShowUi() {
+ return windows_.size() > 1 &&
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kAshEnableWindowCycleUi);
}
} // namespace ash
« ash/wm/window_cycle_list.h ('K') | « ash/wm/window_cycle_list.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698