Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / ui / app_list / views / app_list_view.cc
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.
4
5 #include "ui/app_list/views/app_list_view.h"
6
7 #include "base/command_line.h"
8 #include "base/strings/string_util.h"
9 #include "base/win/windows_version.h"
10 #include "ui/app_list/app_list_constants.h"
11 #include "ui/app_list/app_list_model.h"
12 #include "ui/app_list/app_list_view_delegate.h"
13 #include "ui/app_list/pagination_model.h"
14 #include "ui/app_list/signin_delegate.h"
15 #include "ui/app_list/speech_ui_model.h"
16 #include "ui/app_list/views/app_list_background.h"
17 #include "ui/app_list/views/app_list_main_view.h"
18 #include "ui/app_list/views/app_list_view_observer.h"
19 #include "ui/app_list/views/search_box_view.h"
20 #include "ui/app_list/views/signin_view.h"
21 #include "ui/app_list/views/speech_view.h"
22 #include "ui/base/ui_base_switches.h"
23 #include "ui/compositor/layer.h"
24 #include "ui/compositor/scoped_layer_animation_settings.h"
25 #include "ui/gfx/image/image_skia.h"
26 #include "ui/gfx/insets.h"
27 #include "ui/gfx/path.h"
28 #include "ui/gfx/skia_util.h"
29 #include "ui/views/bubble/bubble_frame_view.h"
30 #include "ui/views/bubble/bubble_window_targeter.h"
31 #include "ui/views/controls/textfield/textfield.h"
32 #include "ui/views/layout/fill_layout.h"
33 #include "ui/views/widget/widget.h"
34
35 #if defined(USE_AURA)
36 #include "ui/aura/window.h"
37 #include "ui/aura/root_window.h"
38 #if defined(OS_WIN)
39 #include "ui/base/win/shell.h"
40 #endif
41 #if !defined(OS_CHROMEOS)
42 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
43 #endif
44 #endif  // defined(USE_AURA)
45
46 namespace app_list {
47
48 namespace {
49
50 void (*g_next_paint_callback)();
51
52 // The margin from the edge to the speech UI.
53 const int kSpeechUIMargin = 12;
54
55 // The vertical position for the appearing animation of the speech UI.
56 const float kSpeechUIAppearingPosition = 12;
57
58 // The distance between the arrow tip and edge of the anchor view.
59 const int kArrowOffset = 10;
60
61 // Determines whether the current environment supports shadows bubble borders.
62 bool SupportsShadow() {
63 #if defined(OS_WIN)
64   // Shadows are not supported on Windows without Aero Glass.
65   if (!ui::win::IsAeroGlassEnabled() ||
66       CommandLine::ForCurrentProcess()->HasSwitch(
67           switches::kDisableDwmComposition)) {
68     return false;
69   }
70 #elif defined(OS_LINUX) && !defined(USE_ASH)
71   // Shadows are not supported on (non-ChromeOS) Linux.
72   return false;
73 #endif
74   return true;
75 }
76
77 }  // namespace
78
79 // An animation observer to hide the view at the end of the animation.
80 class HideViewAnimationObserver : public ui::ImplicitAnimationObserver {
81  public:
82   HideViewAnimationObserver()
83       : frame_(NULL),
84         target_(NULL) {
85   }
86
87   virtual ~HideViewAnimationObserver() {
88     if (target_)
89       StopObservingImplicitAnimations();
90   }
91
92   void SetTarget(views::View* target) {
93     if (!target_)
94       StopObservingImplicitAnimations();
95     target_ = target;
96   }
97
98   void set_frame(views::BubbleFrameView* frame) { frame_ = frame; }
99
100  private:
101   // Overridden from ui::ImplicitAnimationObserver:
102   virtual void OnImplicitAnimationsCompleted() OVERRIDE {
103     if (target_) {
104       target_->SetVisible(false);
105       target_ = NULL;
106
107       // Should update the background by invoking SchedulePaint().
108       frame_->SchedulePaint();
109     }
110   }
111
112   views::BubbleFrameView* frame_;
113   views::View* target_;
114
115   DISALLOW_COPY_AND_ASSIGN(HideViewAnimationObserver);
116 };
117
118 ////////////////////////////////////////////////////////////////////////////////
119 // AppListView:
120
121 AppListView::AppListView(AppListViewDelegate* delegate)
122     : delegate_(delegate),
123       app_list_main_view_(NULL),
124       signin_view_(NULL),
125       speech_view_(NULL),
126       animation_observer_(new HideViewAnimationObserver()) {
127   CHECK(delegate);
128
129   delegate_->AddObserver(this);
130   delegate_->GetSpeechUI()->AddObserver(this);
131 }
132
133 AppListView::~AppListView() {
134   delegate_->GetSpeechUI()->RemoveObserver(this);
135   delegate_->RemoveObserver(this);
136   animation_observer_.reset();
137   // Remove child views first to ensure no remaining dependencies on delegate_.
138   RemoveAllChildViews(true);
139 }
140
141 void AppListView::InitAsBubbleAttachedToAnchor(
142     gfx::NativeView parent,
143     PaginationModel* pagination_model,
144     views::View* anchor,
145     const gfx::Vector2d& anchor_offset,
146     views::BubbleBorder::Arrow arrow,
147     bool border_accepts_events) {
148   SetAnchorView(anchor);
149   InitAsBubbleInternal(
150       parent, pagination_model, arrow, border_accepts_events, anchor_offset);
151 }
152
153 void AppListView::InitAsBubbleAtFixedLocation(
154     gfx::NativeView parent,
155     PaginationModel* pagination_model,
156     const gfx::Point& anchor_point_in_screen,
157     views::BubbleBorder::Arrow arrow,
158     bool border_accepts_events) {
159   SetAnchorView(NULL);
160   SetAnchorRect(gfx::Rect(anchor_point_in_screen, gfx::Size()));
161   InitAsBubbleInternal(
162       parent, pagination_model, arrow, border_accepts_events, gfx::Vector2d());
163 }
164
165 void AppListView::SetBubbleArrow(views::BubbleBorder::Arrow arrow) {
166   GetBubbleFrameView()->bubble_border()->set_arrow(arrow);
167   SizeToContents();  // Recalcuates with new border.
168   GetBubbleFrameView()->SchedulePaint();
169 }
170
171 void AppListView::SetAnchorPoint(const gfx::Point& anchor_point) {
172   SetAnchorRect(gfx::Rect(anchor_point, gfx::Size()));
173 }
174
175 void AppListView::SetDragAndDropHostOfCurrentAppList(
176     ApplicationDragAndDropHost* drag_and_drop_host) {
177   app_list_main_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
178 }
179
180 void AppListView::ShowWhenReady() {
181   app_list_main_view_->ShowAppListWhenReady();
182 }
183
184 void AppListView::Close() {
185   app_list_main_view_->Close();
186   delegate_->Dismiss();
187 }
188
189 void AppListView::UpdateBounds() {
190   SizeToContents();
191 }
192
193 gfx::Size AppListView::GetPreferredSize() {
194   return app_list_main_view_->GetPreferredSize();
195 }
196
197 void AppListView::Paint(gfx::Canvas* canvas) {
198   views::BubbleDelegateView::Paint(canvas);
199   if (g_next_paint_callback) {
200     g_next_paint_callback();
201     g_next_paint_callback = NULL;
202   }
203 }
204
205 void AppListView::OnThemeChanged() {
206 #if defined(OS_WIN)
207   GetWidget()->Close();
208 #endif
209 }
210
211 bool AppListView::ShouldHandleSystemCommands() const {
212   return true;
213 }
214
215 void AppListView::Prerender() {
216   app_list_main_view_->Prerender();
217 }
218
219 void AppListView::OnProfilesChanged() {
220   SigninDelegate* signin_delegate =
221       delegate_ ? delegate_->GetSigninDelegate() : NULL;
222   bool show_signin_view = signin_delegate && signin_delegate->NeedSignin();
223
224   signin_view_->SetVisible(show_signin_view);
225   app_list_main_view_->SetVisible(!show_signin_view);
226   app_list_main_view_->search_box_view()->InvalidateMenu();
227 }
228
229 void AppListView::SetProfileByPath(const base::FilePath& profile_path) {
230   delegate_->SetProfileByPath(profile_path);
231   app_list_main_view_->ModelChanged();
232 }
233
234 void AppListView::AddObserver(AppListViewObserver* observer) {
235   observers_.AddObserver(observer);
236 }
237
238 void AppListView::RemoveObserver(AppListViewObserver* observer) {
239   observers_.RemoveObserver(observer);
240 }
241
242 // static
243 void AppListView::SetNextPaintCallback(void (*callback)()) {
244   g_next_paint_callback = callback;
245 }
246
247 #if defined(OS_WIN)
248 HWND AppListView::GetHWND() const {
249 #if defined(USE_AURA)
250   gfx::NativeWindow window =
251       GetWidget()->GetTopLevelWidget()->GetNativeWindow();
252   return window->GetDispatcher()->host()->GetAcceleratedWidget();
253 #else
254   return GetWidget()->GetTopLevelWidget()->GetNativeWindow();
255 #endif
256 }
257 #endif
258
259 void AppListView::InitAsBubbleInternal(gfx::NativeView parent,
260                                        PaginationModel* pagination_model,
261                                        views::BubbleBorder::Arrow arrow,
262                                        bool border_accepts_events,
263                                        const gfx::Vector2d& anchor_offset) {
264   app_list_main_view_ = new AppListMainView(delegate_.get(),
265                                             pagination_model,
266                                             parent);
267   AddChildView(app_list_main_view_);
268 #if defined(USE_AURA)
269   app_list_main_view_->SetPaintToLayer(true);
270   app_list_main_view_->SetFillsBoundsOpaquely(false);
271   app_list_main_view_->layer()->SetMasksToBounds(true);
272 #endif
273
274   signin_view_ =
275       new SigninView(delegate_->GetSigninDelegate(),
276                      app_list_main_view_->GetPreferredSize().width());
277   AddChildView(signin_view_);
278
279   // Speech recognition is available only when the start page exists.
280   if (delegate_ && delegate_->GetSpeechRecognitionContents()) {
281     speech_view_ = new SpeechView(delegate_.get());
282     speech_view_->SetVisible(false);
283 #if defined(USE_AURA)
284     speech_view_->SetPaintToLayer(true);
285     speech_view_->SetFillsBoundsOpaquely(false);
286     speech_view_->layer()->SetOpacity(0.0f);
287 #endif
288     AddChildView(speech_view_);
289   }
290
291   OnProfilesChanged();
292   set_color(kContentsBackgroundColor);
293   set_margins(gfx::Insets());
294   set_move_with_anchor(true);
295   set_parent_window(parent);
296   set_close_on_deactivate(false);
297   set_close_on_esc(false);
298   set_anchor_view_insets(gfx::Insets(kArrowOffset + anchor_offset.y(),
299                                      kArrowOffset + anchor_offset.x(),
300                                      kArrowOffset - anchor_offset.y(),
301                                      kArrowOffset - anchor_offset.x()));
302   set_border_accepts_events(border_accepts_events);
303   set_shadow(SupportsShadow() ? views::BubbleBorder::BIG_SHADOW
304                               : views::BubbleBorder::NO_SHADOW_OPAQUE_BORDER);
305   views::BubbleDelegateView::CreateBubble(this);
306   SetBubbleArrow(arrow);
307
308 #if defined(USE_AURA)
309   aura::Window* window = GetWidget()->GetNativeWindow();
310   window->layer()->SetMasksToBounds(true);
311   GetBubbleFrameView()->set_background(new AppListBackground(
312       GetBubbleFrameView()->bubble_border()->GetBorderCornerRadius(),
313       app_list_main_view_));
314   set_background(NULL);
315   window->SetEventTargeter(scoped_ptr<ui::EventTargeter>(
316       new views::BubbleWindowTargeter(this)));
317 #else
318   set_background(new AppListBackground(
319       GetBubbleFrameView()->bubble_border()->GetBorderCornerRadius(),
320       app_list_main_view_));
321
322   // On non-aura the bubble has two widgets, and it's possible for the border
323   // to be shown independently in odd situations. Explicitly hide the bubble
324   // widget to ensure that any WM_WINDOWPOSCHANGED messages triggered by the
325   // window manager do not have the SWP_SHOWWINDOW flag set which would cause
326   // the border to be shown. See http://crbug.com/231687 .
327   GetWidget()->Hide();
328 #endif
329
330   if (delegate_)
331     delegate_->ViewInitialized();
332 }
333
334 void AppListView::OnBeforeBubbleWidgetInit(
335     views::Widget::InitParams* params,
336     views::Widget* widget) const {
337 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
338   if (delegate_ && delegate_->ForceNativeDesktop())
339     params->native_widget = new views::DesktopNativeWidgetAura(widget);
340 #endif
341 #if defined(OS_WIN)
342   // Windows 7 and higher offer pinning to the taskbar, but we need presence
343   // on the taskbar for the user to be able to pin us. So, show the window on
344   // the taskbar for these versions of Windows.
345   if (base::win::GetVersion() >= base::win::VERSION_WIN7)
346     params->force_show_in_taskbar = true;
347 #elif defined(OS_LINUX)
348   // Set up a custom WM_CLASS for the app launcher window. This allows task
349   // switchers in X11 environments to distinguish it from main browser windows.
350   params->wm_class_name = kAppListWMClass;
351   // Show the window in the taskbar, even though it is a bubble, which would not
352   // normally be shown.
353   params->force_show_in_taskbar = true;
354 #endif
355 }
356
357 views::View* AppListView::GetInitiallyFocusedView() {
358   return app_list_main_view_->search_box_view()->search_box();
359 }
360
361 gfx::ImageSkia AppListView::GetWindowIcon() {
362   if (delegate_)
363     return delegate_->GetWindowIcon();
364
365   return gfx::ImageSkia();
366 }
367
368 bool AppListView::WidgetHasHitTestMask() const {
369   return true;
370 }
371
372 void AppListView::GetWidgetHitTestMask(gfx::Path* mask) const {
373   DCHECK(mask);
374   mask->addRect(gfx::RectToSkRect(
375       GetBubbleFrameView()->GetContentsBounds()));
376 }
377
378 bool AppListView::AcceleratorPressed(const ui::Accelerator& accelerator) {
379   // The accelerator is added by BubbleDelegateView.
380   if (accelerator.key_code() == ui::VKEY_ESCAPE) {
381     if (app_list_main_view_->search_box_view()->HasSearch()) {
382       app_list_main_view_->search_box_view()->ClearSearch();
383     } else {
384       GetWidget()->Deactivate();
385       Close();
386     }
387     return true;
388   }
389
390   return false;
391 }
392
393 void AppListView::Layout() {
394   const gfx::Rect contents_bounds = GetContentsBounds();
395   app_list_main_view_->SetBoundsRect(contents_bounds);
396   signin_view_->SetBoundsRect(contents_bounds);
397
398   if (speech_view_) {
399     gfx::Rect speech_bounds = contents_bounds;
400     int preferred_height = speech_view_->GetPreferredSize().height();
401     speech_bounds.Inset(kSpeechUIMargin, kSpeechUIMargin);
402     speech_bounds.set_height(std::min(speech_bounds.height(),
403                                       preferred_height));
404     speech_bounds.Inset(-speech_view_->GetInsets());
405     speech_view_->SetBoundsRect(speech_bounds);
406   }
407 }
408
409 void AppListView::OnWidgetDestroying(views::Widget* widget) {
410   BubbleDelegateView::OnWidgetDestroying(widget);
411   if (delegate_ && widget == GetWidget())
412     delegate_->ViewClosing();
413 }
414
415 void AppListView::OnWidgetActivationChanged(views::Widget* widget,
416                                             bool active) {
417   // Do not called inherited function as the bubble delegate auto close
418   // functionality is not used.
419   if (widget == GetWidget())
420     FOR_EACH_OBSERVER(AppListViewObserver, observers_,
421                       OnActivationChanged(widget, active));
422 }
423
424 void AppListView::OnWidgetVisibilityChanged(views::Widget* widget,
425                                             bool visible) {
426   BubbleDelegateView::OnWidgetVisibilityChanged(widget, visible);
427
428   if (widget != GetWidget())
429     return;
430
431   // We clear the search when hiding so the next time the app list appears it is
432   // not showing search results.
433   if (!visible)
434     app_list_main_view_->search_box_view()->ClearSearch();
435
436   // Whether we need to signin or not may have changed since last time we were
437   // shown.
438   Layout();
439 }
440
441 void AppListView::OnSpeechRecognitionStateChanged(
442     SpeechRecognitionState new_state) {
443   if (signin_view_->visible() || !speech_view_)
444     return;
445
446   bool recognizing = (new_state == SPEECH_RECOGNITION_RECOGNIZING ||
447                       new_state == SPEECH_RECOGNITION_IN_SPEECH);
448   // No change for this class.
449   if (speech_view_->visible() == recognizing)
450     return;
451
452   if (recognizing)
453     speech_view_->Reset();
454
455 #if defined(USE_AURA)
456   animation_observer_->set_frame(GetBubbleFrameView());
457   gfx::Transform speech_transform;
458   speech_transform.Translate(
459       0, SkFloatToMScalar(kSpeechUIAppearingPosition));
460   if (recognizing)
461     speech_view_->layer()->SetTransform(speech_transform);
462
463   {
464     ui::ScopedLayerAnimationSettings main_settings(
465         app_list_main_view_->layer()->GetAnimator());
466     if (recognizing) {
467       animation_observer_->SetTarget(app_list_main_view_);
468       main_settings.AddObserver(animation_observer_.get());
469     }
470     app_list_main_view_->layer()->SetOpacity(recognizing ? 0.0f : 1.0f);
471   }
472
473   {
474     ui::ScopedLayerAnimationSettings speech_settings(
475         speech_view_->layer()->GetAnimator());
476     if (!recognizing) {
477       animation_observer_->SetTarget(speech_view_);
478       speech_settings.AddObserver(animation_observer_.get());
479     }
480
481     speech_view_->layer()->SetOpacity(recognizing ? 1.0f : 0.0f);
482     if (recognizing)
483       speech_view_->layer()->SetTransform(gfx::Transform());
484     else
485       speech_view_->layer()->SetTransform(speech_transform);
486   }
487
488   if (recognizing)
489     speech_view_->SetVisible(true);
490   else
491     app_list_main_view_->SetVisible(true);
492 #else
493   speech_view_->SetVisible(recognizing);
494   app_list_main_view_->SetVisible(!recognizing);
495
496   // Needs to schedule paint of AppListView itself, to repaint the background.
497   GetBubbleFrameView()->SchedulePaint();
498 #endif
499 }
500
501 }  // namespace app_list