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/apps/scoped_keep_alive.h"
     10 #include "chrome/browser/profiles/profile.h"
     11 #include "chrome/browser/ui/app_list/app_list_shower_delegate.h"
     12 #include "chrome/browser/ui/app_list/app_list_view_delegate.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     // This can be reached by pressing the dismiss accelerator. To prevent
     65     // events from being processed with a destroyed dispatcher, delay the reset
     66     // of the keep alive.
     67     ResetKeepAliveSoon();
     68   }
     69 }
     70 
     71 void AppListShower::HandleViewBeingDestroyed() {
     72   app_list_ = NULL;
     73   profile_ = NULL;
     74 
     75   // We may end up here as the result of the OS deleting the AppList's
     76   // widget (WidgetObserver::OnWidgetDestroyed). If this happens and there
     77   // are no browsers around then deleting the keep alive will result in
     78   // deleting the Widget again (by way of CloseAllSecondaryWidgets). When
     79   // the stack unravels we end up back in the Widget that was deleted and
     80   // crash. By delaying deletion of the keep alive we ensure the Widget has
     81   // correctly been destroyed before ending the keep alive so that
     82   // CloseAllSecondaryWidgets() won't attempt to delete the AppList's Widget
     83   // again.
     84   ResetKeepAliveSoon();
     85 }
     86 
     87 bool AppListShower::IsAppListVisible() const {
     88   return app_list_ && app_list_->GetWidget()->IsVisible();
     89 }
     90 
     91 void AppListShower::WarmupForProfile(Profile* profile) {
     92   DCHECK(!profile_);
     93   CreateViewForProfile(profile);
     94   app_list_->Prerender();
     95 }
     96 
     97 bool AppListShower::HasView() const {
     98   return !!app_list_;
     99 }
    100 
    101 app_list::AppListView* AppListShower::MakeViewForCurrentProfile() {
    102   // The app list view manages its own lifetime.
    103   app_list::AppListView* view =
    104       new app_list::AppListView(delegate_->GetViewDelegateForCreate());
    105   gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
    106   view->InitAsBubbleAtFixedLocation(NULL,
    107                                     0,
    108                                     cursor,
    109                                     views::BubbleBorder::FLOAT,
    110                                     false /* border_accepts_events */);
    111   return view;
    112 }
    113 
    114 void AppListShower::UpdateViewForNewProfile() {
    115   app_list_->SetProfileByPath(profile_->GetPath());
    116 }
    117 
    118 void AppListShower::Show() {
    119   app_list_->GetWidget()->Show();
    120   if (!window_icon_updated_) {
    121     app_list_->GetWidget()->GetTopLevelWidget()->UpdateWindowIcon();
    122     window_icon_updated_ = true;
    123   }
    124   app_list_->GetWidget()->Activate();
    125 }
    126 
    127 void AppListShower::Hide() {
    128   app_list_->GetWidget()->Hide();
    129 }
    130 
    131 void AppListShower::ResetKeepAliveSoon() {
    132   if (base::MessageLoop::current()) {  // NULL in tests.
    133     base::MessageLoop::current()->PostTask(
    134         FROM_HERE,
    135         base::Bind(&AppListShower::ResetKeepAlive, base::Unretained(this)));
    136     return;
    137   }
    138   ResetKeepAlive();
    139 }
    140 
    141 void AppListShower::ResetKeepAlive() {
    142   keep_alive_.reset();
    143 }
    144