Chromium Code Reviews| 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 7f4672c36edbc19cd01e3f42c53e4887316f4742..001170348c51648d4e31afaaf0821472e4fce138 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" |
| @@ -17,6 +18,7 @@ |
| #include "chrome/browser/extensions/extension_prefs.h" |
| #include "chrome/browser/extensions/extension_service.h" |
| #include "chrome/browser/lifetime/application_lifetime.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,6 +29,7 @@ |
| #include "chrome/browser/ui/views/browser_dialogs.h" |
| #include "chrome/common/chrome_constants.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" |
| @@ -118,22 +121,46 @@ class AppListControllerDelegateWin : public AppListControllerDelegate { |
| // list to operate, and controls when the app list is opened and closed. |
| class AppListController { |
| 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(); |
| + |
| + // 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_; } |
| 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. |
| bool SnapArrowLocationToTaskbarEdge( |
| const gfx::Display& display, |
| @@ -162,6 +189,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_; |
| @@ -169,6 +199,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); |
| }; |
| @@ -241,15 +279,122 @@ 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) {} |
| + |
| +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)); |
| + // A profile has been shown since last time, so we don't care about this |
| + // profile loading anymore. |
| + if (profile_load_sequence_id != profile_load_sequence_id_) |
| + return; |
| + |
| + switch (status) { |
| + case Profile::CREATE_STATUS_CREATED: |
| + break; |
| + case Profile::CREATE_STATUS_INITIALIZED: |
| + ShowAppList(profile); |
| + DecrementPendingProfileLoads(); |
| + break; |
| + case Profile::CREATE_STATUS_FAIL: |
| + DecrementPendingProfileLoads(); |
| + break; |
| + } |
| + if (status == Profile::CREATE_STATUS_INITIALIZED) |
| + ShowAppList(profile); |
|
benwells
2013/01/22 01:21:59
Can you remove this extra ShowAppList?
koz (OOO until 15th September)
2013/01/22 02:23:49
Done.
|
| +} |
| + |
| +void AppListController::IncrementPendingProfileLoads() { |
| + pending_profile_loads_++; |
| + if (pending_profile_loads_ == 1) |
| + browser::StartKeepAlive(); |
| +} |
| + |
| +void AppListController::DecrementPendingProfileLoads() { |
| + pending_profile_loads_--; |
| + if (pending_profile_loads_ == 0) |
| + browser::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; |
| + browser::StartKeepAlive(); |
| + } |
| + |
| + DCHECK(current_view_ && app_list_is_showing_); |
| + gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint(); |
| + UpdateArrowPositionAndAnchorPoint(cursor); |
| + current_view_->Show(); |
| + current_view_->GetWidget()->Activate(); |
| +} |
| + |
| +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_, |
| @@ -271,22 +416,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; |
| - browser::StartKeepAlive(); |
| - gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint(); |
| - UpdateArrowPositionAndAnchorPoint(cursor); |
| - current_view_->Show(); |
| - current_view_->GetWidget()->Activate(); |
| -#endif |
| -} |
| - |
| void AppListController::DismissAppList() { |
| if (current_view_ && app_list_is_showing_ && can_close_app_list_) { |
| current_view_->GetWidget()->Hide(); |
| @@ -554,18 +683,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; |
| @@ -584,13 +713,37 @@ void InitAppList() { |
| 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); |
| +} |
| + |
| +FilePath GetAppListProfilePath(const FilePath& user_data_dir) { |
| + PrefService* local_state = g_browser_process->local_state(); |
| + DCHECK(local_state); |
| + |
| + std::string app_list_profile; |
| + if (local_state->HasPrefPath(prefs::kAppListProfile)) |
| + app_list_profile = local_state->GetString(prefs::kAppListProfile); |
| + |
| + // If the user has no profile preference for the app launcher, default to the |
| + // last browser profile used. |
| + if (app_list_profile.empty() && |
| + local_state->HasPrefPath(prefs::kProfileLastUsed)) |
| + app_list_profile = local_state->GetString(prefs::kProfileLastUsed); |
| + |
| + std::string profile_path = app_list_profile.empty() ? |
| + chrome::kInitialProfile : |
| + app_list_profile; |
| + |
| + return user_data_dir.AppendASCII(profile_path); |
| } |
| } // namespace chrome |