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

Side by Side 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 unified diff | Download patch
« ash/wm/window_cycle_list.h ('K') | « ash/wm/window_cycle_list.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ash/wm/window_cycle_list.h" 5 #include "ash/wm/window_cycle_list.h"
6 6
7 #include "ash/aura/wm_window_aura.h"
8 #include "ash/common/ash_switches.h"
9 #include "ash/common/shell_window_ids.h"
7 #include "ash/common/wm/mru_window_tracker.h" 10 #include "ash/common/wm/mru_window_tracker.h"
8 #include "ash/common/wm/window_state.h" 11 #include "ash/common/wm/window_state.h"
12 #include "ash/common/wm_root_window_controller.h"
13 #include "ash/common/wm_shell.h"
9 #include "ash/common/wm_window.h" 14 #include "ash/common/wm_window.h"
10 #include "ash/shell.h" 15 #include "ash/shell.h"
16 #include "ash/wm/forwarding_layer_delegate.h"
11 #include "ash/wm/window_animations.h" 17 #include "ash/wm/window_animations.h"
12 #include "ash/wm/window_util.h" 18 #include "ash/wm/window_util.h"
19 #include "base/command_line.h"
20 #include "ui/compositor/layer_tree_owner.h"
21 #include "ui/views/background.h"
22 #include "ui/views/layout/box_layout.h"
23 #include "ui/views/painter.h"
24 #include "ui/views/view.h"
25 #include "ui/views/widget/widget.h"
26 #include "ui/wm/core/window_util.h"
13 27
14 namespace ash { 28 namespace ash {
15 29
16 // Returns the window immediately below |window| in the current container. 30 // Returns the window immediately below |window| in the current container.
17 WmWindow* GetWindowBelow(WmWindow* window) { 31 WmWindow* GetWindowBelow(WmWindow* window) {
18 WmWindow* parent = window->GetParent(); 32 WmWindow* parent = window->GetParent();
19 if (!parent) 33 if (!parent)
20 return nullptr; 34 return nullptr;
21 const WmWindow::Windows children = parent->GetChildren(); 35 const WmWindow::Windows children = parent->GetChildren();
22 auto iter = std::find(children.begin(), children.end(), window); 36 auto iter = std::find(children.begin(), children.end(), window);
(...skipping 24 matching lines...) Expand all
47 61
48 // The window immediately below where window_ belongs. 62 // The window immediately below where window_ belongs.
49 WmWindow* stack_window_above_; 63 WmWindow* stack_window_above_;
50 64
51 // If true, minimize window_ on going out of scope. 65 // If true, minimize window_ on going out of scope.
52 bool minimized_; 66 bool minimized_;
53 67
54 DISALLOW_COPY_AND_ASSIGN(ScopedShowWindow); 68 DISALLOW_COPY_AND_ASSIGN(ScopedShowWindow);
55 }; 69 };
56 70
71 // A view that mirrors a single window. Paint calls to this view are forwarded
72 // to the underlying window.
73 class WindowMirrorView : public views::View, public ::wm::LayerDelegateFactory {
74 public:
75 WindowMirrorView() : target_(nullptr) {}
76 ~WindowMirrorView() override {}
77
78 void Init(WmWindow* window) {
79 DCHECK(!target_);
80
81 SetPaintToLayer(true);
82 target_ = window;
83
84 layer_owner_ = ::wm::RecreateLayers(
85 window->GetInternalWidget()->GetNativeView(), this);
86 mirror_layer()->parent()->Remove(mirror_layer());
87 layer()->Add(mirror_layer());
88 mirror_layer()->SetVisible(true);
89 }
90
91 // views::View:
92 gfx::Size GetPreferredSize() const override {
93 const int kMaxWidth = 800;
94 const int kMaxHeight = 600;
95
96 gfx::Size target_size = target_->GetBounds().size();
97 if (target_size.width() <= kMaxWidth &&
98 target_size.height() <= kMaxHeight) {
99 return target_size;
100 }
101
102 float scale =
103 std::min(kMaxWidth / static_cast<float>(target_size.width()),
104 kMaxHeight / static_cast<float>(target_size.height()));
105 return gfx::ScaleToCeiledSize(target_size, scale, scale);
106 }
107
108 void Layout() override {
109 // Position at 0, 0.
110 mirror_layer()->SetBounds(gfx::Rect(target_->GetBounds().size()));
111
112 // Scale down if necessary.
113 gfx::Size allotted_size = size();
114 gfx::Transform mirror_transform;
115 if (allotted_size != target_->GetBounds().size()) {
116 float scale = width() / static_cast<float>(target_->GetBounds().width());
117 mirror_transform.Scale(scale, scale);
118 }
119 mirror_layer()->SetTransform(mirror_transform);
120 }
121
122 // ::wm::LayerDelegateFactory:
123 ui::LayerDelegate* CreateDelegate(ui::LayerDelegate* delegate) override {
124 if (!delegate)
125 return nullptr;
126 delegates_.push_back(
127 base::WrapUnique(new ForwardingLayerDelegate(target_, delegate)));
128 return delegates_.back().get();
129 }
130
131 private:
132 ui::Layer* mirror_layer() { return layer_owner_->root(); }
133
134 WmWindow* target_;
135
136 std::unique_ptr<ui::LayerTreeOwner> layer_owner_;
137 std::vector<std::unique_ptr<ForwardingLayerDelegate>> delegates_;
138
139 DISALLOW_COPY_AND_ASSIGN(WindowMirrorView);
140 };
141
142 // A view that shows a collection of windows the user can tab through.
143 class WindowCycleView : public views::View {
144 public:
145 WindowCycleView(const WindowCycleList::WindowList& windows)
Daniel Erat 2016/07/06 22:04:47 add 'explicit'
Evan Stade 2016/07/06 23:02:59 Done.
146 : mirror_container_(new views::View()),
147 selector_view_(new views::View()),
148 target_window_(nullptr) {
149 SetPaintToLayer(true);
150 layer()->SetFillsBoundsOpaquely(false);
151
152 // TODO(estade): adjust constants in this function (colors, spacing, corner
153 // radius) as per mocks.
154 const float kCornerRadius = 5;
155 set_background(views::Background::CreateBackgroundPainter(
156 true, views::Painter::CreateSolidRoundRectPainter(
157 SkColorSetA(SK_ColorBLACK, 0xA5), kCornerRadius)));
158
159 views::BoxLayout* layout =
160 new views::BoxLayout(views::BoxLayout::kHorizontal, 25, 25, 20);
161 layout->set_cross_axis_alignment(
162 views::BoxLayout::CROSS_AXIS_ALIGNMENT_START);
163 mirror_container_->SetLayoutManager(layout);
164
165 for (WmWindow* window : windows) {
166 WindowMirrorView* view = new WindowMirrorView();
167 view->Init(window);
168 window_view_map_[window] = view;
169 mirror_container_->AddChildView(view);
170 }
171
172 selector_view_->set_background(views::Background::CreateBackgroundPainter(
173 true, views::Painter::CreateSolidRoundRectPainter(SK_ColorBLUE,
174 kCornerRadius)));
175
176 AddChildView(selector_view_);
177 AddChildView(mirror_container_);
178 SetTargetWindow(windows.front());
179 }
180
181 ~WindowCycleView() override {}
182
183 void SetTargetWindow(WmWindow* target) {
184 target_window_ = target;
185 if (GetWidget())
186 Layout();
187 }
188
189 void HandleWindowDestruction(WmWindow* destroying_window,
190 WmWindow* new_target) {
191 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
192 destroying_view->parent()->RemoveChildView(destroying_view);
193 SetTargetWindow(new_target);
194 }
195
196 // views::View overrides:
197 gfx::Size GetPreferredSize() const override {
198 return mirror_container_->GetPreferredSize();
199 }
200
201 void Layout() override {
202 views::View* target_view = window_view_map_[target_window_];
203 gfx::RectF target_bounds(target_view->GetLocalBounds());
204 views::View::ConvertRectToTarget(target_view, this, &target_bounds);
205 target_bounds.Inset(gfx::InsetsF(-15));
206 selector_view_->SetBoundsRect(gfx::ToEnclosingRect(target_bounds));
207
208 mirror_container_->SetBoundsRect(GetLocalBounds());
209 }
210
211 WmWindow* target_window() { return target_window_; }
212
213 private:
214 std::map<WmWindow*, WindowMirrorView*> window_view_map_;
215 views::View* mirror_container_;
216 views::View* selector_view_;
217 WmWindow* target_window_;
218
219 DISALLOW_COPY_AND_ASSIGN(WindowCycleView);
220 };
221
57 ScopedShowWindow::ScopedShowWindow() 222 ScopedShowWindow::ScopedShowWindow()
58 : window_(nullptr), stack_window_above_(nullptr), minimized_(false) {} 223 : window_(nullptr), stack_window_above_(nullptr), minimized_(false) {}
59 224
60 ScopedShowWindow::~ScopedShowWindow() { 225 ScopedShowWindow::~ScopedShowWindow() {
61 if (window_) { 226 if (window_) {
62 window_->GetParent()->RemoveObserver(this); 227 window_->GetParent()->RemoveObserver(this);
63 228
64 // Restore window's stacking position. 229 // Restore window's stacking position.
65 if (stack_window_above_) 230 if (stack_window_above_)
66 window_->GetParent()->StackChildAbove(window_, stack_window_above_); 231 window_->GetParent()->StackChildAbove(window_, stack_window_above_);
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
99 if (params.target == window_) { 264 if (params.target == window_) {
100 CancelRestore(); 265 CancelRestore();
101 } else if (params.target == stack_window_above_) { 266 } else if (params.target == stack_window_above_) {
102 // If the window this window was above is removed, use the next window down 267 // If the window this window was above is removed, use the next window down
103 // as the restore marker. 268 // as the restore marker.
104 stack_window_above_ = GetWindowBelow(stack_window_above_); 269 stack_window_above_ = GetWindowBelow(stack_window_above_);
105 } 270 }
106 } 271 }
107 272
108 WindowCycleList::WindowCycleList(const WindowList& windows) 273 WindowCycleList::WindowCycleList(const WindowList& windows)
109 : windows_(windows), current_index_(0) { 274 : windows_(windows),
275 current_index_(0),
276 cycle_view_(nullptr),
277 cycle_ui_widget_(nullptr) {
110 ash::Shell::GetInstance()->mru_window_tracker()->SetIgnoreActivations(true); 278 ash::Shell::GetInstance()->mru_window_tracker()->SetIgnoreActivations(true);
111 279
112 for (WmWindow* window : windows_) 280 for (WmWindow* window : windows_)
113 window->AddObserver(this); 281 window->AddObserver(this);
282
283 if (ShouldShowUi()) {
284 WmWindow* root_window = WmShell::Get()->GetPrimaryRootWindow();
285 views::Widget* widget = new views::Widget;
286 views::Widget::InitParams params;
287 params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
288 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
289 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
290 params.accept_events = true;
291 root_window->GetRootWindowController()
292 ->ConfigureWidgetInitParamsForContainer(
293 widget, kShellWindowId_OverlayContainer, &params);
294 widget->Init(params);
295
296 cycle_view_ = new WindowCycleView(windows_);
297
298 widget->SetContentsView(cycle_view_);
299 gfx::Rect widget_rect = widget->GetWorkAreaBoundsInScreen();
300 widget_rect.ClampToCenteredSize(cycle_view_->GetPreferredSize());
301 widget->SetBounds(widget_rect);
302 widget->Show();
303 cycle_ui_widget_ = widget;
304 }
114 } 305 }
115 306
116 WindowCycleList::~WindowCycleList() { 307 WindowCycleList::~WindowCycleList() {
117 ash::Shell::GetInstance()->mru_window_tracker()->SetIgnoreActivations(false); 308 ash::Shell::GetInstance()->mru_window_tracker()->SetIgnoreActivations(false);
118 for (WmWindow* window : windows_) { 309 for (WmWindow* window : windows_) {
119 // TODO(oshima): Remove this once crbug.com/483491 is fixed. 310 // TODO(oshima): Remove this once crbug.com/483491 is fixed.
120 CHECK(window); 311 CHECK(window);
121 window->RemoveObserver(this); 312 window->RemoveObserver(this);
122 } 313 }
123 if (showing_window_) 314 if (showing_window_)
124 showing_window_->CancelRestore(); 315 showing_window_->CancelRestore();
316
317 if (cycle_view_) {
318 cycle_view_->target_window()->Show();
319 cycle_view_->target_window()->GetWindowState()->Activate();
320 }
321
322 delete cycle_ui_widget_;
125 } 323 }
126 324
127 void WindowCycleList::Step(WindowCycleController::Direction direction) { 325 void WindowCycleList::Step(WindowCycleController::Direction direction) {
128 if (windows_.empty()) 326 if (windows_.empty())
129 return; 327 return;
130 328
131 // When there is only one window, we should give feedback to the user. If the 329 // When there is only one window, we should give feedback to the user. If the
132 // window is minimized, we should also show it. 330 // window is minimized, we should also show it.
133 if (windows_.size() == 1) { 331 if (windows_.size() == 1) {
134 windows_[0]->Animate(::wm::WINDOW_ANIMATION_TYPE_BOUNCE); 332 windows_[0]->Animate(::wm::WINDOW_ANIMATION_TYPE_BOUNCE);
135 windows_[0]->Show(); 333 windows_[0]->Show();
136 windows_[0]->GetWindowState()->Activate(); 334 windows_[0]->GetWindowState()->Activate();
137 return; 335 return;
138 } 336 }
139 337
140 DCHECK(static_cast<size_t>(current_index_) < windows_.size()); 338 DCHECK(static_cast<size_t>(current_index_) < windows_.size());
141 339
142 // We're in a valid cycle, so step forward or backward. 340 // We're in a valid cycle, so step forward or backward.
143 current_index_ += direction == WindowCycleController::FORWARD ? 1 : -1; 341 current_index_ += direction == WindowCycleController::FORWARD ? 1 : -1;
144 342
145 // Wrap to window list size. 343 // Wrap to window list size.
146 current_index_ = (current_index_ + windows_.size()) % windows_.size(); 344 current_index_ = (current_index_ + windows_.size()) % windows_.size();
147 DCHECK(windows_[current_index_]); 345 DCHECK(windows_[current_index_]);
148 346
149 // Make sure the next window is visible. 347 if (cycle_view_) {
150 showing_window_.reset(new ScopedShowWindow); 348 cycle_view_->SetTargetWindow(windows_[current_index_]);
151 showing_window_->Show(windows_[current_index_]); 349 } else {
350 // Make sure the next window is visible.
351 showing_window_.reset(new ScopedShowWindow);
352 showing_window_->Show(windows_[current_index_]);
353 }
152 } 354 }
153 355
154 void WindowCycleList::OnWindowDestroying(WmWindow* window) { 356 void WindowCycleList::OnWindowDestroying(WmWindow* window) {
155 window->RemoveObserver(this); 357 window->RemoveObserver(this);
156 358
157 WindowList::iterator i = std::find(windows_.begin(), windows_.end(), window); 359 WindowList::iterator i = std::find(windows_.begin(), windows_.end(), window);
158 // TODO(oshima): Change this back to DCHECK once crbug.com/483491 is fixed. 360 // TODO(oshima): Change this back to DCHECK once crbug.com/483491 is fixed.
159 CHECK(i != windows_.end()); 361 CHECK(i != windows_.end());
160 int removed_index = static_cast<int>(i - windows_.begin()); 362 int removed_index = static_cast<int>(i - windows_.begin());
161 windows_.erase(i); 363 windows_.erase(i);
162 if (current_index_ > removed_index || 364 if (current_index_ > removed_index ||
163 current_index_ == static_cast<int>(windows_.size())) { 365 current_index_ == static_cast<int>(windows_.size())) {
164 current_index_--; 366 current_index_--;
165 } 367 }
368
369 if (cycle_view_)
370 cycle_view_->HandleWindowDestruction(window, windows_[current_index_]);
371 }
372
373 bool WindowCycleList::ShouldShowUi() {
374 return windows_.size() > 1 &&
375 base::CommandLine::ForCurrentProcess()->HasSwitch(
376 switches::kAshEnableWindowCycleUi);
166 } 377 }
167 378
168 } // namespace ash 379 } // namespace ash
OLDNEW
« 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