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

Side by Side Diff: ash/wm/overview/window_selector.cc

Issue 2087153003: Moves common code in ash/wm/overview to ash/common/wm/overview (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 6 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
« no previous file with comments | « ash/wm/overview/window_selector.h ('k') | ash/wm/overview/window_selector_controller.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ash/wm/overview/window_selector.h"
6
7 #include <algorithm>
8 #include <functional>
9 #include <set>
10 #include <utility>
11 #include <vector>
12
13 #include "ash/common/accessibility_delegate.h"
14 #include "ash/common/accessibility_types.h"
15 #include "ash/common/ash_switches.h"
16 #include "ash/common/material_design/material_design_controller.h"
17 #include "ash/common/metrics/user_metrics_action.h"
18 #include "ash/common/shelf/wm_shelf.h"
19 #include "ash/common/shell_window_ids.h"
20 #include "ash/common/wm/mru_window_tracker.h"
21 #include "ash/common/wm/panels/panel_layout_manager.h"
22 #include "ash/common/wm/switchable_windows.h"
23 #include "ash/common/wm/window_state.h"
24 #include "ash/common/wm/wm_screen_util.h"
25 #include "ash/common/wm_lookup.h"
26 #include "ash/common/wm_root_window_controller.h"
27 #include "ash/common/wm_shell.h"
28 #include "ash/common/wm_window.h"
29 #include "ash/wm/overview/window_grid.h"
30 #include "ash/wm/overview/window_selector_delegate.h"
31 #include "ash/wm/overview/window_selector_item.h"
32 #include "base/auto_reset.h"
33 #include "base/command_line.h"
34 #include "base/metrics/histogram.h"
35 #include "third_party/skia/include/core/SkPaint.h"
36 #include "third_party/skia/include/core/SkPath.h"
37 #include "ui/base/resource/resource_bundle.h"
38 #include "ui/compositor/scoped_layer_animation_settings.h"
39 #include "ui/display/screen.h"
40 #include "ui/events/event.h"
41 #include "ui/gfx/canvas.h"
42 #include "ui/gfx/paint_vector_icon.h"
43 #include "ui/gfx/skia_util.h"
44 #include "ui/gfx/vector_icons.h"
45 #include "ui/views/border.h"
46 #include "ui/views/controls/image_view.h"
47 #include "ui/views/controls/textfield/textfield.h"
48 #include "ui/views/layout/box_layout.h"
49
50 namespace ash {
51
52 namespace {
53
54 // The proportion of screen width that the text filter takes.
55 const float kTextFilterScreenProportion = 0.25;
56
57 // The amount of padding surrounding the text in the text filtering textbox.
58 const int kTextFilterHorizontalPadding = 8;
59 const int kTextFilterHorizontalPaddingMD = 10;
60
61 // The distance between the top of the screen and the top edge of the
62 // text filtering textbox.
63 const int kTextFilterDistanceFromTop = 32;
64
65 // The height of the text filtering textbox.
66 const int kTextFilterHeight = 32;
67 const int kTextFilterHeightMD = 40;
68
69 // Distance from top of overview to the top of text filtering textbox as a
70 // proportion of the total overview area with Material Design.
71 const float kTextFilterTopScreenProportion = 0.02f;
72
73 // Width of the text filter area with Material Design.
74 const int kTextFilterWidthMD = 280;
75
76 // The font style used for text filtering textbox.
77 static const ::ui::ResourceBundle::FontStyle kTextFilterFontStyle =
78 ::ui::ResourceBundle::FontStyle::MediumFont;
79 static const ::ui::ResourceBundle::FontStyle kTextFilterFontStyleMD =
80 ::ui::ResourceBundle::FontStyle::BaseFont;
81
82 // The color of the text and its background in the text filtering textbox.
83 const SkColor kTextFilterTextColor = SK_ColorWHITE;
84 const SkColor kTextFilterTextColorMD = SkColorSetARGB(222, 0, 0, 0);
85 const SkColor kTextFilterBackgroundColor = SkColorSetARGB(180, 0, 0, 0);
86 const SkColor kTextFilterBackgroundColorMD = SK_ColorWHITE;
87
88 // The color or search icon with Material Design.
89 const SkColor kTextFilterIconColorMD = SkColorSetARGB(138, 0, 0, 0);
90
91 // The size of search icon with Material Design.
92 const int kTextFilterIconSize = 20;
93
94 // The radius used for the rounded corners on the text filtering textbox.
95 const int kTextFilterCornerRadius = 1;
96 const int kTextFilterCornerRadiusMD = 2;
97
98 // A comparator for locating a grid with a given root window.
99 struct RootWindowGridComparator {
100 explicit RootWindowGridComparator(const WmWindow* root_window)
101 : root_window_(root_window) {}
102
103 bool operator()(const std::unique_ptr<WindowGrid>& grid) const {
104 return grid->root_window() == root_window_;
105 }
106
107 const WmWindow* root_window_;
108 };
109
110 // A comparator for locating a selectable window given a targeted window.
111 struct WindowSelectorItemTargetComparator {
112 explicit WindowSelectorItemTargetComparator(const WmWindow* target_window)
113 : target(target_window) {}
114
115 bool operator()(WindowSelectorItem* window) const {
116 return window->GetWindow() == target;
117 }
118
119 const WmWindow* target;
120 };
121
122 // A comparator for locating a selector item for a given root.
123 struct WindowSelectorItemForRoot {
124 explicit WindowSelectorItemForRoot(const WmWindow* root)
125 : root_window(root) {}
126
127 bool operator()(WindowSelectorItem* item) const {
128 return item->root_window() == root_window;
129 }
130
131 const WmWindow* root_window;
132 };
133
134 // A View having rounded corners and a specified background color which is
135 // only painted within the bounds defined by the rounded corners.
136 // TODO(tdanderson): This duplicates code from RoundedImageView. Refactor these
137 // classes and move into ui/views.
138 class RoundedContainerView : public views::View {
139 public:
140 RoundedContainerView(int corner_radius, SkColor background)
141 : corner_radius_(corner_radius),
142 background_(background) {
143 }
144
145 ~RoundedContainerView() override {}
146
147 void OnPaint(gfx::Canvas* canvas) override {
148 views::View::OnPaint(canvas);
149
150 SkScalar radius = SkIntToScalar(corner_radius_);
151 const SkScalar kRadius[8] = {radius, radius, radius, radius,
152 radius, radius, radius, radius};
153 SkPath path;
154 gfx::Rect bounds(size());
155 path.addRoundRect(gfx::RectToSkRect(bounds), kRadius);
156
157 SkPaint paint;
158 paint.setAntiAlias(true);
159 canvas->ClipPath(path, true);
160 canvas->DrawColor(background_);
161 }
162
163 private:
164 int corner_radius_;
165 SkColor background_;
166
167 DISALLOW_COPY_AND_ASSIGN(RoundedContainerView);
168 };
169
170 // Triggers a shelf visibility update on all root window controllers.
171 void UpdateShelfVisibility() {
172 for (WmWindow* root : WmShell::Get()->GetAllRootWindows())
173 root->GetRootWindowController()->GetShelf()->UpdateVisibilityState();
174 }
175
176 gfx::Rect GetTextFilterPosition(WmWindow* root_window) {
177 if (ash::MaterialDesignController::IsOverviewMaterial()) {
178 gfx::Rect total_bounds =
179 root_window->ConvertRectToScreen(wm::GetDisplayWorkAreaBoundsInParent(
180 root_window->GetChildByShellWindowId(
181 kShellWindowId_DefaultContainer)));
182 return gfx::Rect(0.5 * (total_bounds.width() -
183 std::min(kTextFilterWidthMD, total_bounds.width())),
184 total_bounds.height() * kTextFilterTopScreenProportion,
185 std::min(kTextFilterWidthMD, total_bounds.width()),
186 kTextFilterHeightMD);
187 }
188 return gfx::Rect(
189 0.5 * root_window->GetBounds().width() *
190 (1 - kTextFilterScreenProportion),
191 kTextFilterDistanceFromTop,
192 root_window->GetBounds().width() * kTextFilterScreenProportion,
193 kTextFilterHeight);
194 }
195
196 // Initializes the text filter on the top of the main root window and requests
197 // focus on its textfield. With Material Design uses |image| to place an icon
198 // to the left of the text field.
199 views::Widget* CreateTextFilter(views::TextfieldController* controller,
200 WmWindow* root_window,
201 const gfx::ImageSkia& image,
202 int* text_filter_bottom) {
203 views::Widget* widget = new views::Widget;
204 views::Widget::InitParams params;
205 params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
206 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
207 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
208 params.accept_events = true;
209 params.bounds = GetTextFilterPosition(root_window);
210 *text_filter_bottom = params.bounds.bottom();
211 root_window->GetRootWindowController()->ConfigureWidgetInitParamsForContainer(
212 widget, kShellWindowId_OverlayContainer, &params);
213 widget->Init(params);
214
215 // Use |container| to specify the padding surrounding the text and to give
216 // the textfield rounded corners.
217 const bool material = ash::MaterialDesignController::IsOverviewMaterial();
218 views::View* container = new RoundedContainerView(
219 material ? kTextFilterCornerRadiusMD : kTextFilterCornerRadius,
220 material ? kTextFilterBackgroundColorMD : kTextFilterBackgroundColor);
221 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
222 const ::ui::ResourceBundle::FontStyle font_style =
223 material ? kTextFilterFontStyleMD : kTextFilterFontStyle;
224 const int text_height =
225 std::max(kTextFilterIconSize, bundle.GetFontList(font_style).GetHeight());
226 DCHECK(text_height);
227 const int vertical_padding = (params.bounds.height() - text_height) / 2;
228 const int horizontal_padding =
229 material ? kTextFilterHorizontalPaddingMD : kTextFilterHorizontalPadding;
230 views::BoxLayout* layout =
231 new views::BoxLayout(views::BoxLayout::kHorizontal, horizontal_padding,
232 vertical_padding, horizontal_padding);
233 container->SetLayoutManager(layout);
234
235 views::Textfield* textfield = new views::Textfield;
236 textfield->set_controller(controller);
237 textfield->SetBorder(views::Border::NullBorder());
238 if (material) {
239 textfield->SetBackgroundColor(kTextFilterBackgroundColorMD);
240 textfield->SetTextColor(kTextFilterTextColorMD);
241 views::ImageView* image_view = new views::ImageView;
242 image_view->SetImage(image);
243 container->AddChildView(image_view);
244 } else {
245 textfield->SetBackgroundColor(SK_ColorTRANSPARENT);
246 textfield->SetTextColor(kTextFilterTextColor);
247 }
248 textfield->SetFontList(bundle.GetFontList(font_style));
249 container->AddChildView(textfield);
250 layout->SetFlexForView(textfield, 1);
251 widget->SetContentsView(container);
252
253 // The textfield initially contains no text, so shift its position to be
254 // outside the visible bounds of the screen.
255 gfx::Transform transform;
256 transform.Translate(0, -params.bounds.bottom());
257 WmLookup::Get()->GetWindowForWidget(widget)->SetTransform(transform);
258 widget->Show();
259 textfield->RequestFocus();
260
261 return widget;
262 }
263
264 } // namespace
265
266 // static
267 bool WindowSelector::IsSelectable(WmWindow* window) {
268 wm::WindowState* state = window->GetWindowState();
269 if (state->GetStateType() == wm::WINDOW_STATE_TYPE_DOCKED ||
270 state->GetStateType() == wm::WINDOW_STATE_TYPE_DOCKED_MINIMIZED) {
271 return false;
272 }
273 return state->IsUserPositionable();
274 }
275
276 WindowSelector::WindowSelector(WindowSelectorDelegate* delegate)
277 : delegate_(delegate),
278 restore_focus_window_(WmShell::Get()->GetFocusedWindow()),
279 ignore_activations_(false),
280 selected_grid_index_(0),
281 overview_start_time_(base::Time::Now()),
282 num_key_presses_(0),
283 num_items_(0),
284 showing_selection_widget_(false),
285 text_filter_string_length_(0),
286 num_times_textfield_cleared_(0),
287 restoring_minimized_windows_(false),
288 text_filter_bottom_(0) {
289 DCHECK(delegate_);
290 }
291
292 WindowSelector::~WindowSelector() {
293 RemoveAllObservers();
294 }
295
296 // NOTE: The work done in Init() is not done in the constructor because it may
297 // cause other, unrelated classes, (ie PanelLayoutManager) to make indirect
298 // calls to restoring_minimized_windows() on a partially constructed object.
299 void WindowSelector::Init(const WindowList& windows) {
300 if (restore_focus_window_)
301 restore_focus_window_->AddObserver(this);
302
303 WmShell* shell = WmShell::Get();
304
305 std::vector<WmWindow*> root_windows = shell->GetAllRootWindows();
306 std::sort(root_windows.begin(), root_windows.end(),
307 [](const WmWindow* a, const WmWindow* b) {
308 // Since we don't know if windows are vertically or horizontally
309 // oriented we use both x and y position. This may be confusing
310 // if you have 3 or more monitors which are not strictly
311 // horizontal or vertical but that case is not yet supported.
312 return (a->GetBoundsInScreen().x() + a->GetBoundsInScreen().y()) <
313 (b->GetBoundsInScreen().x() + b->GetBoundsInScreen().y());
314 });
315
316 for (WmWindow* root : root_windows) {
317 // Observed switchable containers for newly created windows on all root
318 // windows.
319 for (size_t i = 0; i < wm::kSwitchableWindowContainerIdsLength; ++i) {
320 WmWindow* container =
321 root->GetChildByShellWindowId(wm::kSwitchableWindowContainerIds[i]);
322 container->AddObserver(this);
323 observed_windows_.insert(container);
324 }
325
326 // Hide the callout widgets for panels. It is safe to call this for
327 // root windows that don't contain any panel windows.
328 PanelLayoutManager::Get(root)->SetShowCalloutWidgets(false);
329
330 std::unique_ptr<WindowGrid> grid(new WindowGrid(root, windows, this));
331 if (grid->empty())
332 continue;
333 num_items_ += grid->size();
334 grid_list_.push_back(std::move(grid));
335 }
336
337 {
338 // The calls to WindowGrid::PrepareForOverview() and CreateTextFilter(...)
339 // requires some LayoutManagers (ie PanelLayoutManager) to perform layouts
340 // so that windows are correctly visible and properly animated in overview
341 // mode. Otherwise these layouts should be suppressed during overview mode
342 // so they don't conflict with overview mode animations. The
343 // |restoring_minimized_windows_| flag enables the PanelLayoutManager to
344 // make this decision.
345 base::AutoReset<bool> auto_restoring_minimized_windows(
346 &restoring_minimized_windows_, true);
347
348 // Do not call PrepareForOverview until all items are added to window_list_
349 // as we don't want to cause any window updates until all windows in
350 // overview are observed. See http://crbug.com/384495.
351 for (std::unique_ptr<WindowGrid>& window_grid : grid_list_) {
352 window_grid->PrepareForOverview();
353 window_grid->PositionWindows(true);
354 }
355
356 if (ash::MaterialDesignController::IsOverviewMaterial()) {
357 search_image_ =
358 gfx::CreateVectorIcon(gfx::VectorIconId::OMNIBOX_SEARCH,
359 kTextFilterIconSize, kTextFilterIconColorMD);
360 }
361 WmWindow* root_window = shell->GetPrimaryRootWindow();
362 text_filter_widget_.reset(CreateTextFilter(this, root_window, search_image_,
363 &text_filter_bottom_));
364 }
365
366 DCHECK(!grid_list_.empty());
367 UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.Items", num_items_);
368
369 shell->AddActivationObserver(this);
370
371 display::Screen::GetScreen()->AddObserver(this);
372 shell->RecordUserMetricsAction(UMA_WINDOW_OVERVIEW);
373 // Send an a11y alert.
374 WmShell::Get()->GetAccessibilityDelegate()->TriggerAccessibilityAlert(
375 A11Y_ALERT_WINDOW_OVERVIEW_MODE_ENTERED);
376
377 UpdateShelfVisibility();
378 }
379
380 // NOTE: The work done in Shutdown() is not done in the destructor because it
381 // may cause other, unrelated classes, (ie PanelLayoutManager) to make indirect
382 // calls to restoring_minimized_windows() on a partially destructed object.
383 void WindowSelector::Shutdown() {
384 ResetFocusRestoreWindow(true);
385 RemoveAllObservers();
386
387 std::vector<WmWindow*> root_windows = WmShell::Get()->GetAllRootWindows();
388 for (WmWindow* window : root_windows) {
389 // Un-hide the callout widgets for panels. It is safe to call this for
390 // root_windows that don't contain any panel windows.
391 PanelLayoutManager::Get(window)->SetShowCalloutWidgets(true);
392 }
393
394 size_t remaining_items = 0;
395 for (std::unique_ptr<WindowGrid>& window_grid : grid_list_) {
396 for (WindowSelectorItem* window_selector_item : window_grid->window_list())
397 window_selector_item->RestoreWindow();
398 remaining_items += window_grid->size();
399 }
400
401 DCHECK(num_items_ >= remaining_items);
402 UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.OverviewClosedItems",
403 num_items_ - remaining_items);
404 UMA_HISTOGRAM_MEDIUM_TIMES("Ash.WindowSelector.TimeInOverview",
405 base::Time::Now() - overview_start_time_);
406
407 // Record metrics related to text filtering.
408 UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.TextFilteringStringLength",
409 text_filter_string_length_);
410 UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.TextFilteringTextfieldCleared",
411 num_times_textfield_cleared_);
412 if (text_filter_string_length_) {
413 UMA_HISTOGRAM_MEDIUM_TIMES(
414 "Ash.WindowSelector.TimeInOverviewWithTextFiltering",
415 base::Time::Now() - overview_start_time_);
416 UMA_HISTOGRAM_COUNTS_100(
417 "Ash.WindowSelector.ItemsWhenTextFilteringUsed",
418 remaining_items);
419 }
420
421 // Clearing the window list resets the ignored_by_shelf flag on the windows.
422 grid_list_.clear();
423 UpdateShelfVisibility();
424 }
425
426 void WindowSelector::RemoveAllObservers() {
427 for (WmWindow* window : observed_windows_)
428 window->RemoveObserver(this);
429
430 WmShell::Get()->RemoveActivationObserver(this);
431 display::Screen::GetScreen()->RemoveObserver(this);
432 if (restore_focus_window_)
433 restore_focus_window_->RemoveObserver(this);
434 }
435
436 void WindowSelector::CancelSelection() {
437 delegate_->OnSelectionEnded();
438 }
439
440 void WindowSelector::OnGridEmpty(WindowGrid* grid) {
441 size_t index = 0;
442 for (auto iter = grid_list_.begin(); iter != grid_list_.end(); ++iter) {
443 if (grid == (*iter).get()) {
444 index = iter - grid_list_.begin();
445 grid_list_.erase(iter);
446 break;
447 }
448 }
449 if (index > 0 && selected_grid_index_ >= index) {
450 selected_grid_index_--;
451 // If the grid which became empty was the one with the selected window, we
452 // need to select a window on the newly selected grid.
453 if (selected_grid_index_ == index - 1)
454 Move(LEFT, true);
455 }
456 if (grid_list_.empty())
457 CancelSelection();
458 }
459
460 void WindowSelector::SelectWindow(WmWindow* window) {
461 // Record UMA_WINDOW_OVERVIEW_ACTIVE_WINDOW_CHANGED if the user is selecting
462 // a window other than the window that was active prior to entering overview
463 // mode (i.e., the window at the front of the MRU list).
464 std::vector<WmWindow*> window_list =
465 WmShell::Get()->GetMruWindowTracker()->BuildMruWindowList();
466 if (!window_list.empty() && window_list[0] != window) {
467 WmShell::Get()->RecordUserMetricsAction(
468 UMA_WINDOW_OVERVIEW_ACTIVE_WINDOW_CHANGED);
469 }
470
471 window->GetWindowState()->Activate();
472 }
473
474 bool WindowSelector::HandleKeyEvent(views::Textfield* sender,
475 const ui::KeyEvent& key_event) {
476 if (key_event.type() != ui::ET_KEY_PRESSED)
477 return false;
478
479 switch (key_event.key_code()) {
480 case ui::VKEY_ESCAPE:
481 CancelSelection();
482 break;
483 case ui::VKEY_UP:
484 num_key_presses_++;
485 Move(WindowSelector::UP, true);
486 break;
487 case ui::VKEY_DOWN:
488 num_key_presses_++;
489 Move(WindowSelector::DOWN, true);
490 break;
491 case ui::VKEY_RIGHT:
492 case ui::VKEY_TAB:
493 num_key_presses_++;
494 Move(WindowSelector::RIGHT, true);
495 break;
496 case ui::VKEY_LEFT:
497 num_key_presses_++;
498 Move(WindowSelector::LEFT, true);
499 break;
500 case ui::VKEY_RETURN:
501 // Ignore if no item is selected.
502 if (!grid_list_[selected_grid_index_]->is_selecting())
503 return false;
504 UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.ArrowKeyPresses",
505 num_key_presses_);
506 UMA_HISTOGRAM_CUSTOM_COUNTS(
507 "Ash.WindowSelector.KeyPressesOverItemsRatio",
508 (num_key_presses_ * 100) / num_items_, 1, 300, 30);
509 WmShell::Get()->RecordUserMetricsAction(UMA_WINDOW_OVERVIEW_ENTER_KEY);
510 SelectWindow(
511 grid_list_[selected_grid_index_]->SelectedWindow()->GetWindow());
512 break;
513 default:
514 // Not a key we are interested in, allow the textfield to handle it.
515 return false;
516 }
517 return true;
518 }
519
520 void WindowSelector::OnDisplayAdded(const display::Display& display) {}
521
522 void WindowSelector::OnDisplayRemoved(const display::Display& display) {
523 // TODO(flackr): Keep window selection active on remaining displays.
524 CancelSelection();
525 }
526
527 void WindowSelector::OnDisplayMetricsChanged(const display::Display& display,
528 uint32_t metrics) {
529 PositionWindows(/* animate */ false);
530 RepositionTextFilterOnDisplayMetricsChange();
531 }
532
533 void WindowSelector::OnWindowTreeChanged(WmWindow* window,
534 const TreeChangeParams& params) {
535 // Only care about newly added children of |observed_windows_|.
536 if (!observed_windows_.count(window) ||
537 !observed_windows_.count(params.new_parent)) {
538 return;
539 }
540
541 WmWindow* new_window = params.target;
542 if (!IsSelectable(new_window))
543 return;
544
545 for (size_t i = 0; i < wm::kSwitchableWindowContainerIdsLength; ++i) {
546 if (new_window->GetParent()->GetShellWindowId() ==
547 wm::kSwitchableWindowContainerIds[i] &&
548 !new_window->GetTransientParent()) {
549 // The new window is in one of the switchable containers, abort overview.
550 CancelSelection();
551 return;
552 }
553 }
554 }
555
556 void WindowSelector::OnWindowDestroying(WmWindow* window) {
557 window->RemoveObserver(this);
558 observed_windows_.erase(window);
559 if (window == restore_focus_window_)
560 restore_focus_window_ = nullptr;
561 }
562
563 void WindowSelector::OnWindowActivated(WmWindow* gained_active,
564 WmWindow* lost_active) {
565 if (ignore_activations_ || !gained_active ||
566 gained_active == GetTextFilterWidgetWindow()) {
567 return;
568 }
569
570 auto grid =
571 std::find_if(grid_list_.begin(), grid_list_.end(),
572 RootWindowGridComparator(gained_active->GetRootWindow()));
573 if (grid == grid_list_.end())
574 return;
575 const std::vector<WindowSelectorItem*> windows = (*grid)->window_list();
576
577 auto iter = std::find_if(windows.begin(), windows.end(),
578 WindowSelectorItemTargetComparator(gained_active));
579
580 if (iter != windows.end())
581 (*iter)->ShowWindowOnExit();
582
583 // Don't restore focus on exit if a window was just activated.
584 ResetFocusRestoreWindow(false);
585 CancelSelection();
586 }
587
588 void WindowSelector::OnAttemptToReactivateWindow(WmWindow* request_active,
589 WmWindow* actual_active) {
590 OnWindowActivated(request_active, actual_active);
591 }
592
593 void WindowSelector::ContentsChanged(views::Textfield* sender,
594 const base::string16& new_contents) {
595 text_filter_string_length_ = new_contents.length();
596 if (!text_filter_string_length_)
597 num_times_textfield_cleared_++;
598
599 bool should_show_selection_widget = !new_contents.empty();
600 if (showing_selection_widget_ != should_show_selection_widget) {
601 WmWindow* text_filter_widget_window = GetTextFilterWidgetWindow();
602 ui::ScopedLayerAnimationSettings animation_settings(
603 text_filter_widget_window->GetLayer()->GetAnimator());
604 animation_settings.SetPreemptionStrategy(
605 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
606 animation_settings.SetTweenType(showing_selection_widget_ ?
607 gfx::Tween::FAST_OUT_LINEAR_IN : gfx::Tween::LINEAR_OUT_SLOW_IN);
608
609 gfx::Transform transform;
610 if (should_show_selection_widget) {
611 transform.Translate(0, 0);
612 text_filter_widget_window->SetOpacity(1);
613 } else {
614 transform.Translate(0, -text_filter_bottom_);
615 text_filter_widget_window->SetOpacity(0);
616 }
617
618 text_filter_widget_window->SetTransform(transform);
619 showing_selection_widget_ = should_show_selection_widget;
620 }
621 for (auto iter = grid_list_.begin(); iter != grid_list_.end(); iter++)
622 (*iter)->FilterItems(new_contents);
623
624 // If the selection widget is not active, execute a Move() command so that it
625 // shows up on the first undimmed item.
626 if (grid_list_[selected_grid_index_]->is_selecting())
627 return;
628 Move(WindowSelector::RIGHT, false);
629 }
630
631 WmWindow* WindowSelector::GetTextFilterWidgetWindow() {
632 return WmLookup::Get()->GetWindowForWidget(text_filter_widget_.get());
633 }
634
635 void WindowSelector::PositionWindows(bool animate) {
636 for (std::unique_ptr<WindowGrid>& grid : grid_list_)
637 grid->PositionWindows(animate);
638 }
639
640 void WindowSelector::RepositionTextFilterOnDisplayMetricsChange() {
641 WmWindow* root_window = WmShell::Get()->GetPrimaryRootWindow();
642 const gfx::Rect rect = GetTextFilterPosition(root_window);
643 text_filter_bottom_ = rect.bottom();
644 text_filter_widget_->SetBounds(rect);
645
646 gfx::Transform transform;
647 transform.Translate(
648 0, text_filter_string_length_ == 0 ? -text_filter_bottom_ : 0);
649 GetTextFilterWidgetWindow()->SetTransform(transform);
650 }
651
652 void WindowSelector::ResetFocusRestoreWindow(bool focus) {
653 if (!restore_focus_window_)
654 return;
655 if (focus) {
656 base::AutoReset<bool> restoring_focus(&ignore_activations_, true);
657 restore_focus_window_->Activate();
658 }
659 // If the window is in the observed_windows_ list it needs to continue to be
660 // observed.
661 if (observed_windows_.find(restore_focus_window_) ==
662 observed_windows_.end()) {
663 restore_focus_window_->RemoveObserver(this);
664 }
665 restore_focus_window_ = nullptr;
666 }
667
668 void WindowSelector::Move(Direction direction, bool animate) {
669 // Direction to move if moving past the end of a display.
670 int display_direction = (direction == RIGHT || direction == DOWN) ? 1 : -1;
671
672 // If this is the first move and it's going backwards, start on the last
673 // display.
674 if (display_direction == -1 && !grid_list_.empty() &&
675 !grid_list_[selected_grid_index_]->is_selecting()) {
676 selected_grid_index_ = grid_list_.size() - 1;
677 }
678
679 // Keep calling Move() on the grids until one of them reports no overflow or
680 // we made a full cycle on all the grids.
681 for (size_t i = 0;
682 i <= grid_list_.size() &&
683 grid_list_[selected_grid_index_]->Move(direction, animate); i++) {
684 selected_grid_index_ =
685 (selected_grid_index_ + display_direction + grid_list_.size()) %
686 grid_list_.size();
687 }
688 }
689
690 } // namespace ash
OLDNEW
« no previous file with comments | « ash/wm/overview/window_selector.h ('k') | ash/wm/overview/window_selector_controller.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698