Update path of checkdeps to buildtools checkout
[chromium-blink-merge.git] / ui / app_list / views / app_list_view.cc
blobe1da9a150cde08af5f355a71d37fcc411e989f74
1 // Copyright (c) 2012 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.
5 #include "ui/app_list/views/app_list_view.h"
7 #include <algorithm>
9 #include "base/command_line.h"
10 #include "base/strings/string_util.h"
11 #include "base/win/windows_version.h"
12 #include "ui/app_list/app_list_constants.h"
13 #include "ui/app_list/app_list_model.h"
14 #include "ui/app_list/app_list_view_delegate.h"
15 #include "ui/app_list/pagination_model.h"
16 #include "ui/app_list/signin_delegate.h"
17 #include "ui/app_list/speech_ui_model.h"
18 #include "ui/app_list/views/app_list_background.h"
19 #include "ui/app_list/views/app_list_folder_view.h"
20 #include "ui/app_list/views/app_list_main_view.h"
21 #include "ui/app_list/views/app_list_view_observer.h"
22 #include "ui/app_list/views/apps_container_view.h"
23 #include "ui/app_list/views/contents_view.h"
24 #include "ui/app_list/views/search_box_view.h"
25 #include "ui/app_list/views/signin_view.h"
26 #include "ui/app_list/views/speech_view.h"
27 #include "ui/base/ui_base_switches.h"
28 #include "ui/compositor/layer.h"
29 #include "ui/compositor/layer_animation_observer.h"
30 #include "ui/compositor/scoped_layer_animation_settings.h"
31 #include "ui/gfx/canvas.h"
32 #include "ui/gfx/image/image_skia.h"
33 #include "ui/gfx/insets.h"
34 #include "ui/gfx/path.h"
35 #include "ui/gfx/skia_util.h"
36 #include "ui/views/bubble/bubble_frame_view.h"
37 #include "ui/views/bubble/bubble_window_targeter.h"
38 #include "ui/views/controls/textfield/textfield.h"
39 #include "ui/views/layout/fill_layout.h"
40 #include "ui/views/widget/widget.h"
42 #if defined(USE_AURA)
43 #include "ui/aura/window.h"
44 #include "ui/aura/window_tree_host.h"
45 #if defined(OS_WIN)
46 #include "ui/base/win/shell.h"
47 #endif
48 #if !defined(OS_CHROMEOS)
49 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
50 #endif
51 #endif // defined(USE_AURA)
53 namespace app_list {
55 namespace {
57 // The margin from the edge to the speech UI.
58 const int kSpeechUIMargin = 12;
60 // The vertical position for the appearing animation of the speech UI.
61 const float kSpeechUIAppearingPosition = 12;
63 // The distance between the arrow tip and edge of the anchor view.
64 const int kArrowOffset = 10;
66 // Determines whether the current environment supports shadows bubble borders.
67 bool SupportsShadow() {
68 #if defined(OS_WIN)
69 // Shadows are not supported on Windows without Aero Glass.
70 if (!ui::win::IsAeroGlassEnabled() ||
71 CommandLine::ForCurrentProcess()->HasSwitch(
72 switches::kDisableDwmComposition)) {
73 return false;
75 #elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
76 // Shadows are not supported on (non-ChromeOS) Linux.
77 return false;
78 #endif
79 return true;
82 // The background for the App List overlay, which appears as a white rounded
83 // rectangle with the given radius and the same size as the target view.
84 class AppListOverlayBackground : public views::Background {
85 public:
86 AppListOverlayBackground(int corner_radius)
87 : corner_radius_(corner_radius) {};
88 virtual ~AppListOverlayBackground() {};
90 // Overridden from views::Background:
91 virtual void Paint(gfx::Canvas* canvas, views::View* view) const OVERRIDE {
92 SkPaint paint;
93 paint.setStyle(SkPaint::kFill_Style);
94 paint.setColor(SK_ColorWHITE);
95 canvas->DrawRoundRect(view->GetContentsBounds(), corner_radius_, paint);
98 private:
99 const int corner_radius_;
101 DISALLOW_COPY_AND_ASSIGN(AppListOverlayBackground);
104 } // namespace
106 // An animation observer to hide the view at the end of the animation.
107 class HideViewAnimationObserver : public ui::ImplicitAnimationObserver {
108 public:
109 HideViewAnimationObserver()
110 : frame_(NULL),
111 target_(NULL) {
114 virtual ~HideViewAnimationObserver() {
115 if (target_)
116 StopObservingImplicitAnimations();
119 void SetTarget(views::View* target) {
120 if (!target_)
121 StopObservingImplicitAnimations();
122 target_ = target;
125 void set_frame(views::BubbleFrameView* frame) { frame_ = frame; }
127 private:
128 // Overridden from ui::ImplicitAnimationObserver:
129 virtual void OnImplicitAnimationsCompleted() OVERRIDE {
130 if (target_) {
131 target_->SetVisible(false);
132 target_ = NULL;
134 // Should update the background by invoking SchedulePaint().
135 frame_->SchedulePaint();
139 views::BubbleFrameView* frame_;
140 views::View* target_;
142 DISALLOW_COPY_AND_ASSIGN(HideViewAnimationObserver);
145 ////////////////////////////////////////////////////////////////////////////////
146 // AppListView:
148 AppListView::AppListView(AppListViewDelegate* delegate)
149 : delegate_(delegate),
150 app_list_main_view_(NULL),
151 signin_view_(NULL),
152 speech_view_(NULL),
153 overlay_view_(NULL),
154 animation_observer_(new HideViewAnimationObserver()) {
155 CHECK(delegate);
157 delegate_->AddObserver(this);
158 delegate_->GetSpeechUI()->AddObserver(this);
161 AppListView::~AppListView() {
162 delegate_->GetSpeechUI()->RemoveObserver(this);
163 delegate_->RemoveObserver(this);
164 animation_observer_.reset();
165 // Remove child views first to ensure no remaining dependencies on delegate_.
166 RemoveAllChildViews(true);
169 void AppListView::InitAsBubbleAttachedToAnchor(
170 gfx::NativeView parent,
171 PaginationModel* pagination_model,
172 views::View* anchor,
173 const gfx::Vector2d& anchor_offset,
174 views::BubbleBorder::Arrow arrow,
175 bool border_accepts_events) {
176 SetAnchorView(anchor);
177 InitAsBubbleInternal(
178 parent, pagination_model, arrow, border_accepts_events, anchor_offset);
181 void AppListView::InitAsBubbleAtFixedLocation(
182 gfx::NativeView parent,
183 PaginationModel* pagination_model,
184 const gfx::Point& anchor_point_in_screen,
185 views::BubbleBorder::Arrow arrow,
186 bool border_accepts_events) {
187 SetAnchorView(NULL);
188 SetAnchorRect(gfx::Rect(anchor_point_in_screen, gfx::Size()));
189 InitAsBubbleInternal(
190 parent, pagination_model, arrow, border_accepts_events, gfx::Vector2d());
193 void AppListView::SetBubbleArrow(views::BubbleBorder::Arrow arrow) {
194 GetBubbleFrameView()->bubble_border()->set_arrow(arrow);
195 SizeToContents(); // Recalcuates with new border.
196 GetBubbleFrameView()->SchedulePaint();
199 void AppListView::SetAnchorPoint(const gfx::Point& anchor_point) {
200 SetAnchorRect(gfx::Rect(anchor_point, gfx::Size()));
203 void AppListView::SetDragAndDropHostOfCurrentAppList(
204 ApplicationDragAndDropHost* drag_and_drop_host) {
205 app_list_main_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
208 void AppListView::ShowWhenReady() {
209 app_list_main_view_->ShowAppListWhenReady();
212 void AppListView::Close() {
213 app_list_main_view_->Close();
214 delegate_->Dismiss();
217 void AppListView::UpdateBounds() {
218 SizeToContents();
221 void AppListView::SetAppListOverlayVisible(bool visible) {
222 DCHECK(overlay_view_);
223 overlay_view_->SetVisible(visible);
226 bool AppListView::ShouldCenterWindow() const {
227 return delegate_->ShouldCenterWindow();
230 gfx::Size AppListView::GetPreferredSize() const {
231 return app_list_main_view_->GetPreferredSize();
234 void AppListView::Paint(gfx::Canvas* canvas, const views::CullSet& cull_set) {
235 views::BubbleDelegateView::Paint(canvas, cull_set);
236 if (!next_paint_callback_.is_null()) {
237 next_paint_callback_.Run();
238 next_paint_callback_.Reset();
242 void AppListView::OnThemeChanged() {
243 #if defined(OS_WIN)
244 GetWidget()->Close();
245 #endif
248 bool AppListView::ShouldHandleSystemCommands() const {
249 return true;
252 void AppListView::Prerender() {
253 app_list_main_view_->Prerender();
256 void AppListView::OnProfilesChanged() {
257 SigninDelegate* signin_delegate =
258 delegate_ ? delegate_->GetSigninDelegate() : NULL;
259 bool show_signin_view = signin_delegate && signin_delegate->NeedSignin();
261 signin_view_->SetVisible(show_signin_view);
262 app_list_main_view_->SetVisible(!show_signin_view);
263 app_list_main_view_->search_box_view()->InvalidateMenu();
266 void AppListView::SetProfileByPath(const base::FilePath& profile_path) {
267 delegate_->SetProfileByPath(profile_path);
268 app_list_main_view_->ModelChanged();
271 void AppListView::AddObserver(AppListViewObserver* observer) {
272 observers_.AddObserver(observer);
275 void AppListView::RemoveObserver(AppListViewObserver* observer) {
276 observers_.RemoveObserver(observer);
279 // static
280 void AppListView::SetNextPaintCallback(const base::Closure& callback) {
281 next_paint_callback_ = callback;
284 #if defined(OS_WIN)
285 HWND AppListView::GetHWND() const {
286 #if defined(USE_AURA)
287 gfx::NativeWindow window =
288 GetWidget()->GetTopLevelWidget()->GetNativeWindow();
289 return window->GetHost()->GetAcceleratedWidget();
290 #else
291 return GetWidget()->GetTopLevelWidget()->GetNativeWindow();
292 #endif
294 #endif
296 void AppListView::InitAsBubbleInternal(gfx::NativeView parent,
297 PaginationModel* pagination_model,
298 views::BubbleBorder::Arrow arrow,
299 bool border_accepts_events,
300 const gfx::Vector2d& anchor_offset) {
301 app_list_main_view_ = new AppListMainView(delegate_.get(),
302 pagination_model,
303 parent);
304 AddChildView(app_list_main_view_);
305 #if defined(USE_AURA)
306 app_list_main_view_->SetPaintToLayer(true);
307 app_list_main_view_->SetFillsBoundsOpaquely(false);
308 app_list_main_view_->layer()->SetMasksToBounds(true);
309 #endif
311 signin_view_ =
312 new SigninView(delegate_->GetSigninDelegate(),
313 app_list_main_view_->GetPreferredSize().width());
314 AddChildView(signin_view_);
316 // Speech recognition is available only when the start page exists.
317 if (delegate_ && delegate_->GetSpeechRecognitionContents()) {
318 speech_view_ = new SpeechView(delegate_.get());
319 speech_view_->SetVisible(false);
320 #if defined(USE_AURA)
321 speech_view_->SetPaintToLayer(true);
322 speech_view_->SetFillsBoundsOpaquely(false);
323 speech_view_->layer()->SetOpacity(0.0f);
324 #endif
325 AddChildView(speech_view_);
328 OnProfilesChanged();
329 set_color(kContentsBackgroundColor);
330 set_margins(gfx::Insets());
331 set_parent_window(parent);
332 set_close_on_deactivate(false);
333 set_close_on_esc(false);
334 set_anchor_view_insets(gfx::Insets(kArrowOffset + anchor_offset.y(),
335 kArrowOffset + anchor_offset.x(),
336 kArrowOffset - anchor_offset.y(),
337 kArrowOffset - anchor_offset.x()));
338 set_border_accepts_events(border_accepts_events);
339 set_shadow(SupportsShadow() ? views::BubbleBorder::BIG_SHADOW
340 : views::BubbleBorder::NO_SHADOW_OPAQUE_BORDER);
341 views::BubbleDelegateView::CreateBubble(this);
342 SetBubbleArrow(arrow);
344 #if defined(USE_AURA)
345 aura::Window* window = GetWidget()->GetNativeWindow();
346 window->layer()->SetMasksToBounds(true);
347 GetBubbleFrameView()->set_background(new AppListBackground(
348 GetBubbleFrameView()->bubble_border()->GetBorderCornerRadius(),
349 app_list_main_view_));
350 set_background(NULL);
351 window->SetEventTargeter(scoped_ptr<ui::EventTargeter>(
352 new views::BubbleWindowTargeter(this)));
353 #else
354 set_background(new AppListBackground(
355 GetBubbleFrameView()->bubble_border()->GetBorderCornerRadius(),
356 app_list_main_view_));
358 // On non-aura the bubble has two widgets, and it's possible for the border
359 // to be shown independently in odd situations. Explicitly hide the bubble
360 // widget to ensure that any WM_WINDOWPOSCHANGED messages triggered by the
361 // window manager do not have the SWP_SHOWWINDOW flag set which would cause
362 // the border to be shown. See http://crbug.com/231687 .
363 GetWidget()->Hide();
364 #endif
366 // To make the overlay view, construct a view with a white background, rather
367 // than a white rectangle in it. This is because we need overlay_view_ to be
368 // drawn to its own layer (so it appears correctly in the foreground).
369 const float kOverlayOpacity = 0.75f;
370 overlay_view_ = new views::View();
371 overlay_view_->SetPaintToLayer(true);
372 overlay_view_->layer()->SetOpacity(kOverlayOpacity);
373 overlay_view_->SetBoundsRect(GetContentsBounds());
374 overlay_view_->SetVisible(false);
376 // On platforms that don't support a shadow, the rounded border of the app
377 // list is constructed _inside_ the view, so a rectangular background goes
378 // over the border in the rounded corners. To fix this, give the background a
379 // corner radius 1px smaller than the outer border, so it just reaches but
380 // doesn't cover it.
381 const int kOverlayCornerRadius =
382 GetBubbleFrameView()->bubble_border()->GetBorderCornerRadius();
383 overlay_view_->set_background(new AppListOverlayBackground(
384 kOverlayCornerRadius - (SupportsShadow() ? 0 : 1)));
386 AddChildView(overlay_view_);
388 if (delegate_)
389 delegate_->ViewInitialized();
392 void AppListView::OnBeforeBubbleWidgetInit(
393 views::Widget::InitParams* params,
394 views::Widget* widget) const {
395 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
396 if (delegate_ && delegate_->ForceNativeDesktop())
397 params->native_widget = new views::DesktopNativeWidgetAura(widget);
398 #endif
399 #if defined(OS_WIN)
400 // Windows 7 and higher offer pinning to the taskbar, but we need presence
401 // on the taskbar for the user to be able to pin us. So, show the window on
402 // the taskbar for these versions of Windows.
403 if (base::win::GetVersion() >= base::win::VERSION_WIN7)
404 params->force_show_in_taskbar = true;
405 #elif defined(OS_LINUX)
406 // Set up a custom WM_CLASS for the app launcher window. This allows task
407 // switchers in X11 environments to distinguish it from main browser windows.
408 params->wm_class_name = kAppListWMClass;
409 // Show the window in the taskbar, even though it is a bubble, which would not
410 // normally be shown.
411 params->force_show_in_taskbar = true;
412 #endif
415 views::View* AppListView::GetInitiallyFocusedView() {
416 return app_list_main_view_->search_box_view()->search_box();
419 gfx::ImageSkia AppListView::GetWindowIcon() {
420 if (delegate_)
421 return delegate_->GetWindowIcon();
423 return gfx::ImageSkia();
426 bool AppListView::WidgetHasHitTestMask() const {
427 return true;
430 void AppListView::GetWidgetHitTestMask(gfx::Path* mask) const {
431 DCHECK(mask);
432 mask->addRect(gfx::RectToSkRect(
433 GetBubbleFrameView()->GetContentsBounds()));
436 bool AppListView::AcceleratorPressed(const ui::Accelerator& accelerator) {
437 // The accelerator is added by BubbleDelegateView.
438 if (accelerator.key_code() == ui::VKEY_ESCAPE) {
439 if (app_list_main_view_->search_box_view()->HasSearch()) {
440 app_list_main_view_->search_box_view()->ClearSearch();
441 } else if (app_list_main_view_->contents_view()
442 ->apps_container_view()
443 ->IsInFolderView()) {
444 app_list_main_view_->contents_view()
445 ->apps_container_view()
446 ->app_list_folder_view()
447 ->CloseFolderPage();
448 return true;
449 } else {
450 GetWidget()->Deactivate();
451 Close();
453 return true;
456 return false;
459 void AppListView::Layout() {
460 const gfx::Rect contents_bounds = GetContentsBounds();
461 app_list_main_view_->SetBoundsRect(contents_bounds);
462 signin_view_->SetBoundsRect(contents_bounds);
464 if (speech_view_) {
465 gfx::Rect speech_bounds = contents_bounds;
466 int preferred_height = speech_view_->GetPreferredSize().height();
467 speech_bounds.Inset(kSpeechUIMargin, kSpeechUIMargin);
468 speech_bounds.set_height(std::min(speech_bounds.height(),
469 preferred_height));
470 speech_bounds.Inset(-speech_view_->GetInsets());
471 speech_view_->SetBoundsRect(speech_bounds);
475 void AppListView::SchedulePaintInRect(const gfx::Rect& rect) {
476 BubbleDelegateView::SchedulePaintInRect(rect);
477 if (GetBubbleFrameView())
478 GetBubbleFrameView()->SchedulePaint();
481 void AppListView::OnWidgetDestroying(views::Widget* widget) {
482 BubbleDelegateView::OnWidgetDestroying(widget);
483 if (delegate_ && widget == GetWidget())
484 delegate_->ViewClosing();
487 void AppListView::OnWidgetActivationChanged(views::Widget* widget,
488 bool active) {
489 // Do not called inherited function as the bubble delegate auto close
490 // functionality is not used.
491 if (widget == GetWidget())
492 FOR_EACH_OBSERVER(AppListViewObserver, observers_,
493 OnActivationChanged(widget, active));
496 void AppListView::OnWidgetVisibilityChanged(views::Widget* widget,
497 bool visible) {
498 BubbleDelegateView::OnWidgetVisibilityChanged(widget, visible);
500 if (widget != GetWidget())
501 return;
503 if (!visible)
504 app_list_main_view_->ResetForShow();
506 // Whether we need to signin or not may have changed since last time we were
507 // shown.
508 Layout();
511 void AppListView::OnSpeechRecognitionStateChanged(
512 SpeechRecognitionState new_state) {
513 if (signin_view_->visible() || !speech_view_)
514 return;
516 bool recognizing = (new_state == SPEECH_RECOGNITION_RECOGNIZING ||
517 new_state == SPEECH_RECOGNITION_IN_SPEECH);
518 // No change for this class.
519 if (speech_view_->visible() == recognizing)
520 return;
522 if (recognizing)
523 speech_view_->Reset();
525 #if defined(USE_AURA)
526 animation_observer_->set_frame(GetBubbleFrameView());
527 gfx::Transform speech_transform;
528 speech_transform.Translate(
529 0, SkFloatToMScalar(kSpeechUIAppearingPosition));
530 if (recognizing)
531 speech_view_->layer()->SetTransform(speech_transform);
534 ui::ScopedLayerAnimationSettings main_settings(
535 app_list_main_view_->layer()->GetAnimator());
536 if (recognizing) {
537 animation_observer_->SetTarget(app_list_main_view_);
538 main_settings.AddObserver(animation_observer_.get());
540 app_list_main_view_->layer()->SetOpacity(recognizing ? 0.0f : 1.0f);
544 ui::ScopedLayerAnimationSettings speech_settings(
545 speech_view_->layer()->GetAnimator());
546 if (!recognizing) {
547 animation_observer_->SetTarget(speech_view_);
548 speech_settings.AddObserver(animation_observer_.get());
551 speech_view_->layer()->SetOpacity(recognizing ? 1.0f : 0.0f);
552 if (recognizing)
553 speech_view_->layer()->SetTransform(gfx::Transform());
554 else
555 speech_view_->layer()->SetTransform(speech_transform);
558 if (recognizing)
559 speech_view_->SetVisible(true);
560 else
561 app_list_main_view_->SetVisible(true);
562 #else
563 speech_view_->SetVisible(recognizing);
564 app_list_main_view_->SetVisible(!recognizing);
566 // Needs to schedule paint of AppListView itself, to repaint the background.
567 GetBubbleFrameView()->SchedulePaint();
568 #endif
571 } // namespace app_list