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 "base/callback.h"
8 #include "base/command_line.h"
9 #include "base/strings/string_util.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/views/app_list_background.h"
16 #include "ui/app_list/views/app_list_main_view.h"
17 #include "ui/app_list/views/search_box_view.h"
18 #include "ui/app_list/views/signin_view.h"
19 #include "ui/base/ui_base_switches.h"
20 #include "ui/gfx/image/image_skia.h"
21 #include "ui/gfx/insets.h"
22 #include "ui/gfx/path.h"
23 #include "ui/gfx/skia_util.h"
24 #include "ui/views/bubble/bubble_frame_view.h"
25 #include "ui/views/controls/textfield/textfield.h"
26 #include "ui/views/layout/fill_layout.h"
27 #include "ui/views/widget/widget.h"
30 #include "ui/aura/window.h"
31 #include "ui/aura/root_window.h"
33 #include "ui/base/win/shell.h"
35 #if !defined(OS_CHROMEOS)
36 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
38 #endif // defined(USE_AURA)
44 base::Closure g_next_paint_callback;
46 // The distance between the arrow tip and edge of the anchor view.
47 const int kArrowOffset = 10;
51 ////////////////////////////////////////////////////////////////////////////////
54 AppListView::AppListView(AppListViewDelegate* delegate)
55 : model_(new AppListModel),
57 app_list_main_view_(NULL),
60 delegate_->InitModel(model_.get());
61 model_->AddObserver(this);
64 AppListView::~AppListView() {
65 model_->RemoveObserver(this);
66 // Models are going away, ensure their references are cleared.
67 RemoveAllChildViews(true);
70 void AppListView::InitAsBubbleAttachedToAnchor(
71 gfx::NativeView parent,
72 PaginationModel* pagination_model,
74 const gfx::Vector2d& anchor_offset,
75 views::BubbleBorder::Arrow arrow,
76 bool border_accepts_events) {
77 SetAnchorView(anchor);
79 parent, pagination_model, arrow, border_accepts_events, anchor_offset);
82 void AppListView::InitAsBubbleAtFixedLocation(
83 gfx::NativeView parent,
84 PaginationModel* pagination_model,
85 const gfx::Point& anchor_point_in_screen,
86 views::BubbleBorder::Arrow arrow,
87 bool border_accepts_events) {
89 set_anchor_rect(gfx::Rect(anchor_point_in_screen, gfx::Size()));
91 parent, pagination_model, arrow, border_accepts_events, gfx::Vector2d());
94 void AppListView::SetBubbleArrow(views::BubbleBorder::Arrow arrow) {
95 GetBubbleFrameView()->bubble_border()->set_arrow(arrow);
96 SizeToContents(); // Recalcuates with new border.
97 GetBubbleFrameView()->SchedulePaint();
100 void AppListView::SetAnchorPoint(const gfx::Point& anchor_point) {
101 set_anchor_rect(gfx::Rect(anchor_point, gfx::Size()));
102 SizeToContents(); // Repositions view relative to the anchor.
105 void AppListView::SetDragAndDropHostOfCurrentAppList(
106 ApplicationDragAndDropHost* drag_and_drop_host) {
107 app_list_main_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
110 void AppListView::ShowWhenReady() {
111 app_list_main_view_->ShowAppListWhenReady();
114 void AppListView::Close() {
115 app_list_main_view_->Close();
117 delegate_->Dismiss();
119 GetWidget()->Close();
122 void AppListView::UpdateBounds() {
126 gfx::Size AppListView::GetPreferredSize() {
127 return app_list_main_view_->GetPreferredSize();
130 void AppListView::Paint(gfx::Canvas* canvas) {
131 views::BubbleDelegateView::Paint(canvas);
132 if (!g_next_paint_callback.is_null()) {
133 g_next_paint_callback.Run();
134 g_next_paint_callback.Reset();
138 bool AppListView::ShouldHandleSystemCommands() const {
142 void AppListView::Prerender() {
143 app_list_main_view_->Prerender();
146 void AppListView::OnSigninStatusChanged() {
147 signin_view_->SetVisible(!model_->signed_in());
148 app_list_main_view_->SetVisible(model_->signed_in());
149 app_list_main_view_->search_box_view()->InvalidateMenu();
152 void AppListView::SetProfileByPath(const base::FilePath& profile_path) {
153 delegate_->SetProfileByPath(profile_path);
156 void AppListView::AddObserver(Observer* observer) {
157 observers_.AddObserver(observer);
160 void AppListView::RemoveObserver(Observer* observer) {
161 observers_.RemoveObserver(observer);
165 void AppListView::SetNextPaintCallback(const base::Closure& callback) {
166 g_next_paint_callback = callback;
170 HWND AppListView::GetHWND() const {
171 #if defined(USE_AURA)
172 gfx::NativeWindow window =
173 GetWidget()->GetTopLevelWidget()->GetNativeWindow();
174 return window->GetDispatcher()->GetAcceleratedWidget();
176 return GetWidget()->GetTopLevelWidget()->GetNativeWindow();
181 void AppListView::InitAsBubbleInternal(gfx::NativeView parent,
182 PaginationModel* pagination_model,
183 views::BubbleBorder::Arrow arrow,
184 bool border_accepts_events,
185 const gfx::Vector2d& anchor_offset) {
186 app_list_main_view_ = new AppListMainView(delegate_.get(),
190 AddChildView(app_list_main_view_);
191 #if defined(USE_AURA)
192 app_list_main_view_->SetPaintToLayer(true);
193 app_list_main_view_->SetFillsBoundsOpaquely(false);
194 app_list_main_view_->layer()->SetMasksToBounds(true);
197 signin_view_ = new SigninView(
198 delegate_ ? delegate_->GetSigninDelegate()
200 app_list_main_view_->GetPreferredSize().width());
201 AddChildView(signin_view_);
203 OnSigninStatusChanged();
204 set_color(kContentsBackgroundColor);
205 set_margins(gfx::Insets());
206 set_move_with_anchor(true);
207 set_parent_window(parent);
208 set_close_on_deactivate(false);
209 set_close_on_esc(false);
210 set_anchor_view_insets(gfx::Insets(kArrowOffset + anchor_offset.y(),
211 kArrowOffset + anchor_offset.x(),
212 kArrowOffset - anchor_offset.y(),
213 kArrowOffset - anchor_offset.x()));
214 set_border_accepts_events(border_accepts_events);
215 set_shadow(views::BubbleBorder::BIG_SHADOW);
216 #if defined(USE_AURA) && defined(OS_WIN)
217 if (!ui::win::IsAeroGlassEnabled() ||
218 CommandLine::ForCurrentProcess()->HasSwitch(
219 switches::kDisableDwmComposition)) {
220 set_shadow(views::BubbleBorder::NO_SHADOW_OPAQUE_BORDER);
223 views::BubbleDelegateView::CreateBubble(this);
224 SetBubbleArrow(arrow);
226 #if defined(USE_AURA)
227 GetWidget()->GetNativeWindow()->layer()->SetMasksToBounds(true);
228 GetBubbleFrameView()->set_background(new AppListBackground(
229 GetBubbleFrameView()->bubble_border()->GetBorderCornerRadius(),
230 app_list_main_view_));
231 set_background(NULL);
233 set_background(new AppListBackground(
234 GetBubbleFrameView()->bubble_border()->GetBorderCornerRadius(),
235 app_list_main_view_));
237 // On non-aura the bubble has two widgets, and it's possible for the border
238 // to be shown independently in odd situations. Explicitly hide the bubble
239 // widget to ensure that any WM_WINDOWPOSCHANGED messages triggered by the
240 // window manager do not have the SWP_SHOWWINDOW flag set which would cause
241 // the border to be shown. See http://crbug.com/231687 .
246 void AppListView::OnBeforeBubbleWidgetInit(
247 views::Widget::InitParams* params,
248 views::Widget* widget) const {
249 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
250 if (delegate_ && delegate_->ForceNativeDesktop())
251 params->native_widget = new views::DesktopNativeWidgetAura(widget);
255 views::View* AppListView::GetInitiallyFocusedView() {
256 return app_list_main_view_->search_box_view()->search_box();
259 gfx::ImageSkia AppListView::GetWindowIcon() {
261 return delegate_->GetWindowIcon();
263 return gfx::ImageSkia();
266 bool AppListView::WidgetHasHitTestMask() const {
270 void AppListView::GetWidgetHitTestMask(gfx::Path* mask) const {
272 mask->addRect(gfx::RectToSkRect(
273 GetBubbleFrameView()->GetContentsBounds()));
276 bool AppListView::AcceleratorPressed(const ui::Accelerator& accelerator) {
277 // The accelerator is added by BubbleDelegateView.
278 if (accelerator.key_code() == ui::VKEY_ESCAPE) {
279 if (app_list_main_view_->search_box_view()->HasSearch()) {
280 app_list_main_view_->search_box_view()->ClearSearch();
282 GetWidget()->Deactivate();
291 void AppListView::Layout() {
292 const gfx::Rect contents_bounds = GetContentsBounds();
293 app_list_main_view_->SetBoundsRect(contents_bounds);
294 signin_view_->SetBoundsRect(contents_bounds);
297 void AppListView::OnWidgetDestroying(views::Widget* widget) {
298 BubbleDelegateView::OnWidgetDestroying(widget);
299 if (delegate_ && widget == GetWidget())
300 delegate_->ViewClosing();
303 void AppListView::OnWidgetActivationChanged(views::Widget* widget,
305 // Do not called inherited function as the bubble delegate auto close
306 // functionality is not used.
307 if (widget == GetWidget())
308 FOR_EACH_OBSERVER(Observer, observers_,
309 OnActivationChanged(widget, active));
312 void AppListView::OnWidgetVisibilityChanged(views::Widget* widget,
314 BubbleDelegateView::OnWidgetVisibilityChanged(widget, visible);
316 if (widget != GetWidget())
319 // We clear the search when hiding so the next time the app list appears it is
320 // not showing search results.
322 app_list_main_view_->search_box_view()->ClearSearch();
324 // Whether we need to signin or not may have changed since last time we were
329 void AppListView::OnAppListModelSigninStatusChanged() {
330 OnSigninStatusChanged();
333 void AppListView::OnAppListModelUsersChanged() {
334 OnSigninStatusChanged();
337 } // namespace app_list