Home | History | Annotate | Download | only in app_list
      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
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/ui/app_list/app_list_shower_views.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/message_loop/message_loop.h"
      9 #include "chrome/browser/profiles/profile.h"
     10 #include "chrome/browser/ui/app_list/app_list_shower_delegate.h"
     11 #include "chrome/browser/ui/app_list/app_list_view_delegate.h"
     12 #include "chrome/browser/ui/app_list/scoped_keep_alive.h"
     13 #include "ui/app_list/views/app_list_view.h"
     14 #include "ui/gfx/geometry/point.h"
     15 #include "ui/gfx/screen.h"
     16 
     17 AppListShower::AppListShower(AppListShowerDelegate* delegate)
     18     : delegate_(delegate),
     19       profile_(NULL),
     20       app_list_(NULL),
     21       window_icon_updated_(false) {
     22 }
     23 
     24 AppListShower::~AppListShower() {
     25 }
     26 
     27 void AppListShower::ShowForProfile(Profile* requested_profile) {
     28   // If the app list is already displaying |profile| just activate it (in case
     29   // we have lost focus).
     30   if (IsAppListVisible() && (requested_profile == profile_)) {
     31     Show();
     32     return;
     33   }
     34 
     35   if (!HasView()) {
     36     CreateViewForProfile(requested_profile);
     37   } else if (requested_profile != profile_) {
     38     profile_ = requested_profile;
     39     UpdateViewForNewProfile();
     40   }
     41 
     42   keep_alive_.reset(new ScopedKeepAlive);
     43   if (!IsAppListVisible())
     44     delegate_->MoveNearCursor(app_list_);
     45   Show();
     46 }
     47 
     48 gfx::NativeWindow AppListShower::GetWindow() {
     49   if (!IsAppListVisible())
     50     return NULL;
     51   return app_list_->GetWidget()->GetNativeWindow();
     52 }
     53 
     54 void AppListShower::CreateViewForProfile(Profile* requested_profile) {
     55   profile_ = requested_profile;
     56   app_list_ = MakeViewForCurrentProfile();
     57   delegate_->OnViewCreated();
     58 }
     59 
     60 void AppListShower::DismissAppList() {
     61   if (HasView()) {
     62     Hide();
     63     delegate_->OnViewDismissed();
     64     keep_alive_.reset();
     65   }
     66 }
     67 
     68 void AppListShower::HandleViewBeingDestroyed() {
     69   app_list_ = NULL;
     70   profile_ = NULL;
     71 
     72   // We may end up here as the result of the OS deleting the AppList's
     73   // widget (WidgetObserver::OnWidgetDestroyed). If this happens and there
     74   // are no browsers around then deleting the keep alive will result in
     75   // deleting the Widget again (by way of CloseAllSecondaryWidgets). When
     76   // the stack unravels we end up back in the Widget that was deleted and
     77   // crash. By delaying deletion of the keep alive we ensure the Widget has
     78   // correctly been destroyed before ending the keep alive so that
     79   // CloseAllSecondaryWidgets() won't attempt to delete the AppList's Widget
     80   // again.
     81   if (base::MessageLoop::current()) {  // NULL in tests.
     82     base::MessageLoop::current()->PostTask(
     83         FROM_HERE,
     84         base::Bind(&AppListShower::ResetKeepAlive, base::Unretained(this)));
     85     return;
     86   }
     87   keep_alive_.reset();
     88 }
     89 
     90 bool AppListShower::IsAppListVisible() const {
     91   return app_list_ && app_list_->GetWidget()->IsVisible();
     92 }
     93 
     94 void AppListShower::WarmupForProfile(Profile* profile) {
     95   DCHECK(!profile_);
     96   CreateViewForProfile(profile);
     97   app_list_->Prerender();
     98 }
     99 
    100 bool AppListShower::HasView() const {
    101   return !!app_list_;
    102 }
    103 
    104 app_list::AppListView* AppListShower::MakeViewForCurrentProfile() {
    105   // The view delegate will be owned by the app list view. The app list view
    106   // manages its own lifetime.
    107   AppListViewDelegate* view_delegate = new AppListViewDelegate(
    108       profile_, delegate_->GetControllerDelegateForCreate());
    109   app_list::AppListView* view = new app_list::AppListView(view_delegate);
    110   gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
    111   view->InitAsBubbleAtFixedLocation(NULL,
    112                                     0,
    113                                     cursor,
    114                                     views::BubbleBorder::FLOAT,
    115                                     false /* border_accepts_events */);
    116   return view;
    117 }
    118 
    119 void AppListShower::UpdateViewForNewProfile() {
    120   app_list_->SetProfileByPath(profile_->GetPath());
    121 }
    122 
    123 void AppListShower::Show() {
    124   app_list_->GetWidget()->Show();
    125   if (!window_icon_updated_) {
    126     app_list_->GetWidget()->GetTopLevelWidget()->UpdateWindowIcon();
    127     window_icon_updated_ = true;
    128   }
    129   app_list_->GetWidget()->Activate();
    130 }
    131 
    132 void AppListShower::Hide() {
    133   app_list_->GetWidget()->Hide();
    134 }
    135 
    136 void AppListShower::ResetKeepAlive() {
    137   keep_alive_.reset();
    138 }
    139