| Index: chrome/browser/ui/views/app_list/app_list_controller_win.cc
|
| diff --git a/chrome/browser/ui/views/app_list/app_list_controller_win.cc b/chrome/browser/ui/views/app_list/app_list_controller_win.cc
|
| index 3fc63bcecb1a14b3a480ef87374e723d119d54b7..28a3a0db5eb1ac5b5b0222877d760e364e673f76 100644
|
| --- a/chrome/browser/ui/views/app_list/app_list_controller_win.cc
|
| +++ b/chrome/browser/ui/views/app_list/app_list_controller_win.cc
|
| @@ -7,6 +7,7 @@
|
| #include "base/command_line.h"
|
| #include "base/file_util.h"
|
| #include "base/lazy_instance.h"
|
| +#include "base/memory/weak_ptr.h"
|
| #include "base/path_service.h"
|
| #include "base/time.h"
|
| #include "base/timer.h"
|
| @@ -18,6 +19,7 @@
|
| #include "chrome/browser/extensions/extension_service.h"
|
| #include "chrome/browser/lifetime/application_lifetime.h"
|
| #include "chrome/browser/platform_util.h"
|
| +#include "chrome/browser/prefs/pref_service.h"
|
| #include "chrome/browser/profiles/profile.h"
|
| #include "chrome/browser/profiles/profile_manager.h"
|
| #include "chrome/browser/shell_integration.h"
|
| @@ -27,7 +29,9 @@
|
| #include "chrome/browser/ui/extensions/application_launch.h"
|
| #include "chrome/browser/ui/views/browser_dialogs.h"
|
| #include "chrome/common/chrome_constants.h"
|
| +#include "chrome/common/chrome_notification_types.h"
|
| #include "chrome/common/chrome_switches.h"
|
| +#include "chrome/common/pref_names.h"
|
| #include "chrome/installer/util/util_constants.h"
|
| #include "content/public/browser/browser_thread.h"
|
| #include "grit/chromium_strings.h"
|
| @@ -145,24 +149,62 @@ class AppListControllerDelegateWin : public AppListControllerDelegate {
|
|
|
| // The AppListController class manages global resources needed for the app
|
| // list to operate, and controls when the app list is opened and closed.
|
| -class AppListController {
|
| +class AppListController : public ProfileInfoCacheObserver {
|
| public:
|
| - AppListController()
|
| - : current_view_(NULL),
|
| - can_close_app_list_(true),
|
| - app_list_is_showing_(false) {}
|
| - ~AppListController() {}
|
| + AppListController();
|
|
|
| void set_can_close(bool can_close) { can_close_app_list_ = can_close; }
|
| bool can_close() { return can_close_app_list_; }
|
| - void CreateAppList();
|
| - void ShowAppList();
|
| + Profile* profile() const { return profile_; }
|
| + bool app_list_is_showing() const { return app_list_is_showing_; }
|
| +
|
| + // Creates the app list view and populates it from |profile|, but doesn't
|
| + // show it. Does nothing if the view already exists.
|
| + void InitView(Profile* profile);
|
| +
|
| + // Activates the app list at the current mouse cursor location, creating the
|
| + // app list if necessary.
|
| + void ShowAppList(Profile* profile);
|
| +
|
| + // Update the profile path stored in local prefs, load it (if not already
|
| + // loaded), and show the app list.
|
| + void SetProfilePath(const FilePath& profile_file_path);
|
| +
|
| void DismissAppList();
|
| void AppListClosing();
|
| void AppListActivationChanged(bool active);
|
| app_list::AppListView* GetView() { return current_view_; }
|
|
|
| + // TODO(koz): Split the responsibility for tracking profiles into a
|
| + // platform-independent class.
|
| + // Overidden from ProfileInfoCacheObserver.
|
| + void OnProfileAdded(const FilePath& profilePath) OVERRIDE {}
|
| + // We need to watch for profile removal to keep kAppListProfile updated.
|
| + void OnProfileWillBeRemoved(const FilePath& profile_path) OVERRIDE;
|
| + void OnProfileWasRemoved(const FilePath& profile_path,
|
| + const string16& profile_name) OVERRIDE {}
|
| + void OnProfileNameChanged(const FilePath& profile_path,
|
| + const string16& profile_name) OVERRIDE {}
|
| + void OnProfileAvatarChanged(const FilePath& profile_path) OVERRIDE {}
|
| +
|
| private:
|
| + // Loads a profile asynchronously and calls OnProfileLoaded() when done.
|
| + void LoadProfileAsync(const FilePath& profile_file_path);
|
| +
|
| + // Callback for asynchronous profile load.
|
| + void OnProfileLoaded(int profile_load_sequence_id,
|
| + Profile* profile,
|
| + Profile::CreateStatus status);
|
| +
|
| + // We need to keep the browser alive while we are loading a profile as that
|
| + // shows intent to show the app list. These two functions track our pending
|
| + // profile loads and start or end browser keep alive accordingly.
|
| + void IncrementPendingProfileLoads();
|
| + void DecrementPendingProfileLoads();
|
| +
|
| + // Create or recreate, and initialize |current_view_| from |profile|.
|
| + void PopulateViewFromProfile(Profile* profile);
|
| +
|
| // Utility methods for showing the app list.
|
| void SnapArrowLocationToTaskbarEdge(
|
| const gfx::Display& display,
|
| @@ -191,6 +233,9 @@ class AppListController {
|
|
|
| app_list::PaginationModel pagination_model_;
|
|
|
| + // The profile the AppList is currently displaying.
|
| + Profile* profile_;
|
| +
|
| // True if the controller can close the app list.
|
| bool can_close_app_list_;
|
|
|
| @@ -198,6 +243,14 @@ class AppListController {
|
| // browser process keep-alives active.
|
| bool app_list_is_showing_;
|
|
|
| + // Incremented to indicate that pending profile loads are no longer valid.
|
| + int profile_load_sequence_id_;
|
| +
|
| + // How many profile loads are pending.
|
| + int pending_profile_loads_;
|
| +
|
| + base::WeakPtrFactory<AppListController> weak_factory_;
|
| +
|
| DISALLOW_COPY_AND_ASSIGN(AppListController);
|
| };
|
|
|
| @@ -297,15 +350,135 @@ void AppListControllerDelegateWin::LaunchApp(
|
| profile, extension, NEW_FOREGROUND_TAB));
|
| }
|
|
|
| -void AppListController::CreateAppList() {
|
| -#if !defined(USE_AURA)
|
| +AppListController::AppListController()
|
| + : current_view_(NULL),
|
| + profile_(NULL),
|
| + can_close_app_list_(true),
|
| + app_list_is_showing_(false),
|
| + profile_load_sequence_id_(0),
|
| + pending_profile_loads_(0),
|
| + weak_factory_(this) {
|
| + ProfileManager* profile_manager = g_browser_process->profile_manager();
|
| + profile_manager->GetProfileInfoCache().AddObserver(this);
|
| +}
|
| +
|
| +void AppListController::OnProfileWillBeRemoved(const FilePath& profile_path) {
|
| + // If the profile the app list uses just got deleted, reset it to the last
|
| + // used profile.
|
| + PrefService* local_state = g_browser_process->local_state();
|
| + std::string app_list_last_profile = local_state->GetString(
|
| + prefs::kAppListProfile);
|
| + if (profile_path.BaseName().MaybeAsASCII() == app_list_last_profile) {
|
| + local_state->SetString(prefs::kAppListProfile,
|
| + local_state->GetString(prefs::kProfileLastUsed));
|
| + }
|
| +}
|
| +
|
| +void AppListController::SetProfilePath(const FilePath& profile_file_path) {
|
| + g_browser_process->local_state()->SetString(
|
| + prefs::kAppListProfile,
|
| + profile_file_path.BaseName().MaybeAsASCII());
|
| + ProfileManager* profile_manager = g_browser_process->profile_manager();
|
| + Profile* profile = profile_manager->GetProfileByPath(profile_file_path);
|
| +
|
| + if (!profile) {
|
| + LoadProfileAsync(profile_file_path);
|
| + return;
|
| + }
|
| +
|
| + ShowAppList(profile);
|
| +}
|
| +
|
| +void AppListController::LoadProfileAsync(const FilePath& profile_file_path) {
|
| + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| +
|
| + // Invalidate any pending profile path loads.
|
| + profile_load_sequence_id_++;
|
| +
|
| + IncrementPendingProfileLoads();
|
| +
|
| + ProfileManager* profile_manager = g_browser_process->profile_manager();
|
| + profile_manager->CreateProfileAsync(
|
| + profile_file_path,
|
| + base::Bind(&AppListController::OnProfileLoaded,
|
| + weak_factory_.GetWeakPtr(), profile_load_sequence_id_),
|
| + string16(), string16(), false);
|
| +}
|
| +
|
| +void AppListController::OnProfileLoaded(int profile_load_sequence_id,
|
| + Profile* profile,
|
| + Profile::CreateStatus status) {
|
| + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| + switch (status) {
|
| + case Profile::CREATE_STATUS_CREATED:
|
| + break;
|
| + case Profile::CREATE_STATUS_INITIALIZED:
|
| + // Only show if there has been no other profile shown since this load
|
| + // started.
|
| + if (profile_load_sequence_id == profile_load_sequence_id_)
|
| + ShowAppList(profile);
|
| + DecrementPendingProfileLoads();
|
| + break;
|
| + case Profile::CREATE_STATUS_FAIL:
|
| + DecrementPendingProfileLoads();
|
| + break;
|
| + }
|
| +
|
| +}
|
| +
|
| +void AppListController::IncrementPendingProfileLoads() {
|
| + pending_profile_loads_++;
|
| + if (pending_profile_loads_ == 1)
|
| + chrome::StartKeepAlive();
|
| +}
|
| +
|
| +void AppListController::DecrementPendingProfileLoads() {
|
| + pending_profile_loads_--;
|
| + if (pending_profile_loads_ == 0)
|
| + chrome::EndKeepAlive();
|
| +}
|
| +
|
| +void AppListController::ShowAppList(Profile* profile) {
|
| + DCHECK(profile);
|
| +
|
| + // Invalidate any pending profile path loads.
|
| + profile_load_sequence_id_++;
|
| +
|
| + // Do nothing if the app list is already displaying |profile|.
|
| + if (app_list_is_showing_ && (profile == profile_))
|
| + return;
|
| +
|
| + DismissAppList();
|
| + PopulateViewFromProfile(profile);
|
| +
|
| + if (!app_list_is_showing_) {
|
| + app_list_is_showing_ = true;
|
| + chrome::StartKeepAlive();
|
| + }
|
| +
|
| + DCHECK(current_view_ && app_list_is_showing_);
|
| + gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
|
| + UpdateArrowPositionAndAnchorPoint(cursor);
|
| + current_view_->Show();
|
| + current_view_->GetWidget()->Activate();
|
| + current_view_->GetWidget()->SetAlwaysOnTop(true);
|
| +}
|
| +
|
| +void AppListController::InitView(Profile* profile) {
|
| if (current_view_)
|
| return;
|
| + PopulateViewFromProfile(profile);
|
| +}
|
|
|
| +void AppListController::PopulateViewFromProfile(Profile* profile) {
|
| +#if !defined(USE_AURA)
|
| + if (profile == profile_)
|
| + return;
|
| + profile_ = profile;
|
| // The controller will be owned by the view delegate, and the delegate is
|
| // owned by the app list view. The app list view manages it's own lifetime.
|
| current_view_ = new app_list::AppListView(
|
| - new AppListViewDelegate(new AppListControllerDelegateWin()));
|
| + new AppListViewDelegate(new AppListControllerDelegateWin(), profile_));
|
| gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
|
| current_view_->InitAsBubble(GetDesktopWindow(),
|
| &pagination_model_,
|
| @@ -326,23 +499,6 @@ void AppListController::CreateAppList() {
|
| #endif
|
| }
|
|
|
| -void AppListController::ShowAppList() {
|
| -#if !defined(USE_AURA)
|
| - if (!current_view_)
|
| - CreateAppList();
|
| -
|
| - if (app_list_is_showing_)
|
| - return;
|
| - app_list_is_showing_ = true;
|
| - chrome::StartKeepAlive();
|
| - gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
|
| - UpdateArrowPositionAndAnchorPoint(cursor);
|
| - current_view_->Show();
|
| - current_view_->GetWidget()->Activate();
|
| - current_view_->GetWidget()->SetAlwaysOnTop(true);
|
| -#endif
|
| -}
|
| -
|
| void AppListController::DismissAppList() {
|
| if (current_view_ && app_list_is_showing_ && can_close_app_list_) {
|
| current_view_->GetWidget()->Hide();
|
| @@ -614,18 +770,18 @@ void CheckAppListTaskbarShortcutOnFileThread(const FilePath& user_data_dir,
|
| }
|
| }
|
|
|
| -void CreateAppList() {
|
| - g_app_list_controller.Get().CreateAppList();
|
| +void InitView(Profile* profile) {
|
| + g_app_list_controller.Get().InitView(profile);
|
| }
|
|
|
| } // namespace
|
|
|
| namespace chrome {
|
|
|
| -void InitAppList() {
|
| - // Check that the presence of the app list shortcut matches the flag
|
| - // kShowAppListShortcut. This will either create or delete a shortcut
|
| - // file in the user data directory.
|
| +void InitAppList(Profile* profile) {
|
| + // Check that the app list shortcut matches the flag kShowAppListShortcut.
|
| + // This will either create or delete a shortcut file in the user data
|
| + // directory.
|
| // TODO(benwells): Remove this and the flag once the app list installation
|
| // is implemented.
|
| static bool checked_shortcut = false;
|
| @@ -639,18 +795,36 @@ void InitAppList() {
|
| GetAppModelId()));
|
| }
|
|
|
| + // Instantiate AppListController so it listens for profile deletions.
|
| + g_app_list_controller.Get();
|
| +
|
| // Post a task to create the app list. This is posted to not impact startup
|
| // time.
|
| const int kInitWindowDelay = 5;
|
| MessageLoop::current()->PostDelayedTask(
|
| FROM_HERE,
|
| - base::Bind(&CreateAppList),
|
| + base::Bind(&InitView, profile),
|
| base::TimeDelta::FromSeconds(kInitWindowDelay));
|
| }
|
|
|
| -void ShowAppList() {
|
| - // Create the App list.
|
| - g_app_list_controller.Get().ShowAppList();
|
| +void ShowAppList(Profile* profile) {
|
| + g_app_list_controller.Get().ShowAppList(profile);
|
| +}
|
| +
|
| +void SetAppListProfile(const FilePath& profile_file_path) {
|
| + g_app_list_controller.Get().SetProfilePath(profile_file_path);
|
| +}
|
| +
|
| +void DismissAppList() {
|
| + g_app_list_controller.Get().DismissAppList();
|
| +}
|
| +
|
| +Profile* GetCurrentAppListProfile() {
|
| + return g_app_list_controller.Get().profile();
|
| +}
|
| +
|
| +bool IsAppListVisible() {
|
| + return g_app_list_controller.Get().app_list_is_showing();
|
| }
|
|
|
| } // namespace chrome
|
|
|