blob: cb177c96618151444546b0441d13fa68d69eefe8 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/app_list/app_list_shower_views.h"
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/app_list/app_list_shower_delegate.h"
#include "chrome/browser/ui/app_list/app_list_view_delegate.h"
#include "chrome/browser/ui/app_list/scoped_keep_alive.h"
#include "ui/app_list/views/app_list_view.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/screen.h"
AppListShower::AppListShower(AppListShowerDelegate* delegate)
: delegate_(delegate),
profile_(NULL),
app_list_(NULL),
window_icon_updated_(false) {
}
AppListShower::~AppListShower() {
}
void AppListShower::ShowForProfile(Profile* requested_profile) {
// If the app list is already displaying |profile| just activate it (in case
// we have lost focus).
if (IsAppListVisible() && (requested_profile == profile_)) {
Show();
return;
}
if (!HasView()) {
CreateViewForProfile(requested_profile);
} else if (requested_profile != profile_) {
profile_ = requested_profile;
UpdateViewForNewProfile();
}
keep_alive_.reset(new ScopedKeepAlive);
if (!IsAppListVisible())
delegate_->MoveNearCursor(app_list_);
Show();
}
gfx::NativeWindow AppListShower::GetWindow() {
if (!IsAppListVisible())
return NULL;
return app_list_->GetWidget()->GetNativeWindow();
}
void AppListShower::CreateViewForProfile(Profile* requested_profile) {
profile_ = requested_profile;
app_list_ = MakeViewForCurrentProfile();
delegate_->OnViewCreated();
}
void AppListShower::DismissAppList() {
if (HasView()) {
Hide();
delegate_->OnViewDismissed();
keep_alive_.reset();
}
}
void AppListShower::HandleViewBeingDestroyed() {
app_list_ = NULL;
profile_ = NULL;
// We may end up here as the result of the OS deleting the AppList's
// widget (WidgetObserver::OnWidgetDestroyed). If this happens and there
// are no browsers around then deleting the keep alive will result in
// deleting the Widget again (by way of CloseAllSecondaryWidgets). When
// the stack unravels we end up back in the Widget that was deleted and
// crash. By delaying deletion of the keep alive we ensure the Widget has
// correctly been destroyed before ending the keep alive so that
// CloseAllSecondaryWidgets() won't attempt to delete the AppList's Widget
// again.
if (base::MessageLoop::current()) { // NULL in tests.
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&AppListShower::ResetKeepAlive, base::Unretained(this)));
return;
}
keep_alive_.reset();
}
bool AppListShower::IsAppListVisible() const {
return app_list_ && app_list_->GetWidget()->IsVisible();
}
void AppListShower::WarmupForProfile(Profile* profile) {
DCHECK(!profile_);
CreateViewForProfile(profile);
app_list_->Prerender();
}
bool AppListShower::HasView() const {
return !!app_list_;
}
app_list::AppListView* AppListShower::MakeViewForCurrentProfile() {
// The view delegate will be owned by the app list view. The app list view
// manages its own lifetime.
AppListViewDelegate* view_delegate = new AppListViewDelegate(
profile_, delegate_->GetControllerDelegateForCreate());
app_list::AppListView* view = new app_list::AppListView(view_delegate);
gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
view->InitAsBubbleAtFixedLocation(NULL,
0,
cursor,
views::BubbleBorder::FLOAT,
false /* border_accepts_events */);
return view;
}
void AppListShower::UpdateViewForNewProfile() {
app_list_->SetProfileByPath(profile_->GetPath());
}
void AppListShower::Show() {
app_list_->GetWidget()->Show();
if (!window_icon_updated_) {
app_list_->GetWidget()->GetTopLevelWidget()->UpdateWindowIcon();
window_icon_updated_ = true;
}
app_list_->GetWidget()->Activate();
}
void AppListShower::Hide() {
app_list_->GetWidget()->Hide();
}
void AppListShower::ResetKeepAlive() {
keep_alive_.reset();
}