0

Auto hide app list on Windows when it loses focus.

This is a bit tricky as the app list should not hide when the taskbar gets focus. Handling this involves using a timer, when the app list does not have focus, to check whether either the taskbar or the app list has focus. Once one of these is not true the app list is closed.

This change also ensures that the app list is never opened multiple times.

Also includes is a bit of cleanup:
- AppListController has been renamed to AppListControllerDelegate
- a singleton AppListController has been introduced for Windows, similar to ash
- default implementations have been added to AppListControllerDelegate where it makes sense.

BUG=152847, 152846


Review URL: https://chromiumcodereview.appspot.com/11094019

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@161474 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
benwells@chromium.org
2012-10-12 01:54:17 +00:00
parent fc39aa16fd
commit 50fdd24953
18 changed files with 274 additions and 115 deletions

@ -279,6 +279,14 @@ class ExampleAppListViewDelegate : public app_list::AppListViewDelegate {
Shell::GetInstance()->ToggleAppList();
}
virtual void ViewClosing() OVERRIDE {
// Nothing needs to be done.
}
virtual void ViewActivationChanged(bool active) OVERRIDE {
// Nothing needs to be done.
}
app_list::AppListModel* model_;
DISALLOW_COPY_AND_ASSIGN(ExampleAppListViewDelegate);

@ -6,6 +6,24 @@
#include "build/build_config.h"
AppListControllerDelegate::~AppListControllerDelegate() {}
void AppListControllerDelegate::ViewClosing() {}
void AppListControllerDelegate::ViewActivationChanged(bool active) {}
bool AppListControllerDelegate::IsAppPinned(const std::string& extension_id) {
return false;
}
void AppListControllerDelegate::PinApp(const std::string& extension_id) {}
void AppListControllerDelegate::UnpinApp(const std::string& extension_id) {}
void AppListControllerDelegate::ShowCreateShortcutsDialog(
Profile* profile,
const std::string& extension_id) {}
namespace app_list_controller {
#if !defined(OS_WIN)

@ -12,23 +12,29 @@ class Profile;
// Interface to allow the view delegate to call out to whatever is controlling
// the app list. This will have different implementations for different
// platforms.
class AppListController {
class AppListControllerDelegate {
public:
virtual ~AppListController() {}
virtual ~AppListControllerDelegate();
// Handle the controller being closed.
// Close the view.
virtual void CloseView() = 0;
// Handle the view being closed.
virtual void ViewClosing();
// Handle the view being activated or deactivated.
virtual void ViewActivationChanged(bool active);
// Control of pinning apps.
virtual bool IsAppPinned(const std::string& extension_id) = 0;
virtual void PinApp(const std::string& extension_id) = 0;
virtual void UnpinApp(const std::string& extension_id) = 0;
virtual bool IsAppPinned(const std::string& extension_id);
virtual void PinApp(const std::string& extension_id);
virtual void UnpinApp(const std::string& extension_id);
virtual bool CanPin() = 0;
// Whether the controller supports showing the Create Shortcuts dialog.
virtual bool CanShowCreateShortcutsDialog() = 0;
virtual void ShowCreateShortcutsDialog(Profile* profile,
const std::string& extension_id) = 0;
const std::string& extension_id);
// App has been clicked on in the app list.
virtual void ActivateApp(Profile* profile,

@ -10,7 +10,7 @@
#include "chrome/browser/ui/app_list/search_builder.h"
#include "content/public/browser/user_metrics.h"
AppListViewDelegate::AppListViewDelegate(AppListController* controller)
AppListViewDelegate::AppListViewDelegate(AppListControllerDelegate* controller)
: controller_(controller) {}
AppListViewDelegate::~AppListViewDelegate() {}
@ -68,3 +68,11 @@ void AppListViewDelegate::InvokeSearchResultAction(
void AppListViewDelegate::Close() {
controller_->CloseView();
}
void AppListViewDelegate::ViewClosing() {
controller_->ViewClosing();
}
void AppListViewDelegate::ViewActivationChanged(bool active) {
controller_->ViewActivationChanged(active);
}

@ -19,7 +19,7 @@ class SearchBuilder;
class AppListViewDelegate : public app_list::AppListViewDelegate {
public:
// The delegate will take ownership of the controller.
explicit AppListViewDelegate(AppListController* controller);
explicit AppListViewDelegate(AppListControllerDelegate* controller);
virtual ~AppListViewDelegate();
private:
@ -35,10 +35,12 @@ class AppListViewDelegate : public app_list::AppListViewDelegate {
int action_index,
int event_flags) OVERRIDE;
virtual void Close() OVERRIDE;
virtual void ViewClosing() OVERRIDE;
virtual void ViewActivationChanged(bool active) OVERRIDE;
scoped_ptr<AppsModelBuilder> apps_builder_;
scoped_ptr<SearchBuilder> search_builder_;
scoped_ptr<AppListController> controller_;
scoped_ptr<AppListControllerDelegate> controller_;
DISALLOW_COPY_AND_ASSIGN(AppListViewDelegate);
};

@ -39,7 +39,7 @@ bool AppPrecedes(const ExtensionAppItem* app1, const ExtensionAppItem* app2) {
AppsModelBuilder::AppsModelBuilder(Profile* profile,
app_list::AppListModel::Apps* model,
AppListController* controller)
AppListControllerDelegate* controller)
: profile_(profile),
controller_(controller),
model_(model),

@ -14,7 +14,7 @@
#include "ui/app_list/app_list_model.h"
#include "ui/base/models/list_model_observer.h"
class AppListController;
class AppListControllerDelegate;
class ExtensionAppItem;
class Profile;
@ -23,7 +23,7 @@ class AppsModelBuilder : public content::NotificationObserver,
public:
AppsModelBuilder(Profile* profile,
app_list::AppListModel::Apps* model,
AppListController* controller);
AppListControllerDelegate* controller);
virtual ~AppsModelBuilder();
// Populates the model.
@ -63,7 +63,7 @@ class AppsModelBuilder : public content::NotificationObserver,
virtual void ListItemsChanged(size_t start, size_t count) OVERRIDE;
Profile* profile_;
AppListController* controller_;
AppListControllerDelegate* controller_;
// Sub apps model of AppListModel that represents apps grid view.
app_list::AppListModel::Apps* model_;

@ -133,7 +133,7 @@ bool MenuItemHasLauncherContext(const extensions::MenuItem* item) {
ExtensionAppItem::ExtensionAppItem(Profile* profile,
const Extension* extension,
AppListController* controller)
AppListControllerDelegate* controller)
: ChromeAppListItem(TYPE_APP),
profile_(profile),
extension_id_(extension->id()),

@ -13,7 +13,7 @@
#include "sync/api/string_ordinal.h"
#include "ui/base/models/simple_menu_model.h"
class AppListController;
class AppListControllerDelegate;
class ExtensionResource;
class Profile;
class SkBitmap;
@ -30,7 +30,7 @@ class ExtensionAppItem : public ChromeAppListItem,
public:
ExtensionAppItem(Profile* profile,
const extensions::Extension* extension,
AppListController* controller);
AppListControllerDelegate* controller);
virtual ~ExtensionAppItem();
// Gets extension associated with this model. Returns NULL if extension
@ -75,7 +75,7 @@ class ExtensionAppItem : public ChromeAppListItem,
Profile* profile_;
const std::string extension_id_;
AppListController* controller_;
AppListControllerDelegate* controller_;
scoped_ptr<extensions::IconImage> icon_;
scoped_ptr<ui::SimpleMenuModel> context_menu_model_;

@ -295,7 +295,7 @@ SearchBuilder::SearchBuilder(
Profile* profile,
app_list::SearchBoxModel* search_box,
app_list::AppListModel::SearchResults* results,
AppListController* list_controller)
AppListControllerDelegate* list_controller)
: profile_(profile),
search_box_(search_box),
results_(results),

@ -16,7 +16,7 @@ class SearchBoxModel;
class SearchResult;
}
class AppListController;
class AppListControllerDelegate;
class AutocompleteController;
class AutocompleteResult;
class Profile;
@ -27,7 +27,7 @@ class SearchBuilder : public AutocompleteControllerDelegate {
SearchBuilder(Profile* profile,
app_list::SearchBoxModel* search_box,
app_list::AppListModel::SearchResults* results,
AppListController* list_controller);
AppListControllerDelegate* list_controller);
virtual ~SearchBuilder();
void StartSearch();
@ -60,7 +60,7 @@ class SearchBuilder : public AutocompleteControllerDelegate {
scoped_ptr<AutocompleteController> controller_;
// The controller of the app list. Owned by the app list delegate.
AppListController* list_controller_;
AppListControllerDelegate* list_controller_;
DISALLOW_COPY_AND_ASSIGN(SearchBuilder);
};

@ -7,41 +7,38 @@
#include "ash/shell.h"
#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
AppListControllerAsh::AppListControllerAsh() {}
AppListControllerDelegateAsh::AppListControllerDelegateAsh() {}
AppListControllerAsh::~AppListControllerAsh() {}
AppListControllerDelegateAsh::~AppListControllerDelegateAsh() {}
void AppListControllerAsh::CloseView() {
void AppListControllerDelegateAsh::CloseView() {
DCHECK(ash::Shell::HasInstance());
if (ash::Shell::GetInstance()->GetAppListTargetVisibility())
ash::Shell::GetInstance()->ToggleAppList();
}
bool AppListControllerAsh::IsAppPinned(const std::string& extension_id) {
bool AppListControllerDelegateAsh::IsAppPinned(
const std::string& extension_id) {
return ChromeLauncherController::instance()->IsAppPinned(extension_id);
}
void AppListControllerAsh::PinApp(const std::string& extension_id) {
void AppListControllerDelegateAsh::PinApp(const std::string& extension_id) {
ChromeLauncherController::instance()->PinAppWithID(extension_id);
}
void AppListControllerAsh::UnpinApp(const std::string& extension_id) {
void AppListControllerDelegateAsh::UnpinApp(const std::string& extension_id) {
ChromeLauncherController::instance()->UnpinAppsWithID(extension_id);
}
bool AppListControllerAsh::CanPin() {
bool AppListControllerDelegateAsh::CanPin() {
return ChromeLauncherController::instance()->CanPin();
}
bool AppListControllerAsh::CanShowCreateShortcutsDialog() {
bool AppListControllerDelegateAsh::CanShowCreateShortcutsDialog() {
return false;
}
void AppListControllerAsh::ShowCreateShortcutsDialog(
Profile* profile,
const std::string& extension_id) {}
void AppListControllerAsh::ActivateApp(Profile* profile,
void AppListControllerDelegateAsh::ActivateApp(Profile* profile,
const std::string& extension_id,
int event_flags) {
ChromeLauncherController::instance()->OpenAppID(extension_id,

@ -9,27 +9,24 @@
#include "base/compiler_specific.h"
#include "chrome/browser/ui/app_list/app_list_controller.h"
class AppListControllerAsh : public AppListController {
class AppListControllerDelegateAsh : public AppListControllerDelegate {
public:
AppListControllerAsh();
virtual ~AppListControllerAsh();
AppListControllerDelegateAsh();
virtual ~AppListControllerDelegateAsh();
private:
// AppListController overrides:
// AppListControllerDelegate overrides:
virtual void CloseView() OVERRIDE;
virtual bool IsAppPinned(const std::string& extension_id) OVERRIDE;
virtual void PinApp(const std::string& extension_id) OVERRIDE;
virtual void UnpinApp(const std::string& extension_id) OVERRIDE;
virtual bool CanPin() OVERRIDE;
virtual bool CanShowCreateShortcutsDialog() OVERRIDE;
virtual void ShowCreateShortcutsDialog(
Profile* profile,
const std::string& extension_id) OVERRIDE;
virtual void ActivateApp(Profile* profile,
const std::string& extension_id,
int event_flags) OVERRIDE;
DISALLOW_COPY_AND_ASSIGN(AppListControllerAsh);
DISALLOW_COPY_AND_ASSIGN(AppListControllerDelegateAsh);
};
#endif // CHROME_BROWSER_UI_ASH_APP_LIST_APP_LIST_CONTROLLER_ASH_H_

@ -325,7 +325,7 @@ app_list::AppListViewDelegate*
DCHECK(ash::Shell::HasInstance());
// Shell will own the created delegate, and the delegate will own
// the controller.
return new AppListViewDelegate(new AppListControllerAsh());
return new AppListViewDelegate(new AppListControllerDelegateAsh());
}
ash::LauncherDelegate* ChromeShellDelegate::CreateLauncherDelegate(

@ -7,6 +7,8 @@
#include "base/command_line.h"
#include "base/lazy_instance.h"
#include "base/path_service.h"
#include "base/time.h"
#include "base/timer.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser_process.h"
@ -38,17 +40,16 @@ namespace {
// amount.
static const int kAnchorOffset = 25;
class AppListControllerWin : public AppListController {
class AppListControllerDelegateWin : public AppListControllerDelegate {
public:
AppListControllerWin();
virtual ~AppListControllerWin();
AppListControllerDelegateWin();
virtual ~AppListControllerDelegateWin();
private:
// AppListController overrides:
virtual void CloseView() OVERRIDE;
virtual bool IsAppPinned(const std::string& extension_id) OVERRIDE;
virtual void PinApp(const std::string& extension_id) OVERRIDE;
virtual void UnpinApp(const std::string& extension_id) OVERRIDE;
virtual void ViewClosing() OVERRIDE;
virtual void ViewActivationChanged(bool active) OVERRIDE;
virtual bool CanPin() OVERRIDE;
virtual bool CanShowCreateShortcutsDialog() OVERRIDE;
virtual void ShowCreateShortcutsDialog(
@ -58,36 +59,85 @@ class AppListControllerWin : public AppListController {
const std::string& extension_id,
int event_flags) OVERRIDE;
DISALLOW_COPY_AND_ASSIGN(AppListControllerWin);
DISALLOW_COPY_AND_ASSIGN(AppListControllerDelegateWin);
};
AppListControllerWin::AppListControllerWin() {
// 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 {
public:
AppListController() : current_view_(NULL) {}
~AppListController() {}
void ShowAppList();
void CloseAppList();
void AppListClosing();
void AppListActivationChanged(bool active);
private:
// Utility methods for showing the app list.
void GetArrowLocationAndUpdateAnchor(
const gfx::Rect& work_area,
int min_space_x,
int min_space_y,
views::BubbleBorder::ArrowLocation* arrow,
gfx::Point* anchor);
void UpdateArrowPositionAndAnchorPoint(app_list::AppListView* view);
CommandLine GetAppListCommandLine();
string16 GetAppListIconPath();
string16 GetAppModelId();
// Check if the app list or the taskbar has focus. The app list is kept
// visible whenever either of these have focus, which allows it to be
// pinned but will hide it if it otherwise loses focus. This is checked
// periodically whenever the app list does not have focus.
void CheckTaskbarOrViewHasFocus();
// Weak pointer. The view manages its own lifetime.
app_list::AppListView* current_view_;
// Timer used to check if the taskbar or app list is active. Using a timer
// means we don't need to hook Windows, which is apparently not possible
// since Vista (and is not nice at any time).
base::RepeatingTimer<AppListController> timer_;
app_list::PaginationModel pagination_model_;
DISALLOW_COPY_AND_ASSIGN(AppListController);
};
base::LazyInstance<AppListController>::Leaky g_app_list_controller =
LAZY_INSTANCE_INITIALIZER;
AppListControllerDelegateWin::AppListControllerDelegateWin() {
browser::StartKeepAlive();
}
AppListControllerWin::~AppListControllerWin() {
AppListControllerDelegateWin::~AppListControllerDelegateWin() {
browser::EndKeepAlive();
}
void AppListControllerWin::CloseView() {}
void AppListControllerDelegateWin::CloseView() {
g_app_list_controller.Get().CloseAppList();
}
bool AppListControllerWin::IsAppPinned(const std::string& extension_id) {
void AppListControllerDelegateWin::ViewActivationChanged(bool active) {
g_app_list_controller.Get().AppListActivationChanged(active);
}
void AppListControllerDelegateWin::ViewClosing() {
g_app_list_controller.Get().AppListClosing();
}
bool AppListControllerDelegateWin::CanPin() {
return false;
}
void AppListControllerWin::PinApp(const std::string& extension_id) {}
void AppListControllerWin::UnpinApp(const std::string& extension_id) {}
bool AppListControllerWin::CanPin() {
return false;
}
bool AppListControllerWin::CanShowCreateShortcutsDialog() {
bool AppListControllerDelegateWin::CanShowCreateShortcutsDialog() {
return true;
}
void AppListControllerWin::ShowCreateShortcutsDialog(
void AppListControllerDelegateWin::ShowCreateShortcutsDialog(
Profile* profile,
const std::string& extension_id) {
ExtensionService* service = profile->GetExtensionService();
@ -98,9 +148,9 @@ void AppListControllerWin::ShowCreateShortcutsDialog(
chrome::ShowCreateChromeAppShortcutsDialog(NULL, profile, extension);
}
void AppListControllerWin::ActivateApp(Profile* profile,
const std::string& extension_id,
int event_flags) {
void AppListControllerDelegateWin::ActivateApp(Profile* profile,
const std::string& extension_id,
int event_flags) {
ExtensionService* service = profile->GetExtensionService();
DCHECK(service);
const extensions::Extension* extension = service->GetInstalledExtension(
@ -110,25 +160,66 @@ void AppListControllerWin::ActivateApp(Profile* profile,
profile, extension, extension_misc::LAUNCH_TAB, NEW_FOREGROUND_TAB));
}
// The AppListResources class manages global resources needed for the app
// list to operate.
class AppListResources {
public:
AppListResources::AppListResources() {}
void AppListController::ShowAppList() {
#if !defined(USE_AURA)
// If there is already a view visible, activate it.
if (current_view_) {
current_view_->Show();
return;
}
app_list::PaginationModel* pagination_model() { return &pagination_model_; }
// 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()));
gfx::Point cursor = gfx::Screen::GetCursorScreenPoint();
current_view_->InitAsBubble(GetDesktopWindow(),
&pagination_model_,
NULL,
cursor,
views::BubbleBorder::BOTTOM_LEFT);
private:
app_list::PaginationModel pagination_model_;
UpdateArrowPositionAndAnchorPoint(current_view_);
HWND hwnd =
current_view_->GetWidget()->GetTopLevelWidget()->GetNativeWindow();
ui::win::SetAppIdForWindow(GetAppModelId(), hwnd);
CommandLine relaunch = GetAppListCommandLine();
ui::win::SetRelaunchDetailsForWindow(
relaunch.GetCommandLineString(),
l10n_util::GetStringUTF16(IDS_APP_LIST_SHORTCUT_NAME),
hwnd);
string16 icon_path = GetAppListIconPath();
ui::win::SetAppIconForWindow(icon_path, hwnd);
current_view_->Show();
#endif
}
DISALLOW_COPY_AND_ASSIGN(AppListResources);
};
void AppListController::CloseAppList() {
if (current_view_)
current_view_->GetWidget()->Close();
}
void GetArrowLocationAndUpdateAnchor(const gfx::Rect& work_area,
int min_space_x,
int min_space_y,
views::BubbleBorder::ArrowLocation* arrow,
gfx::Point* anchor) {
void AppListController::AppListClosing() {
current_view_ = NULL;
timer_.Stop();
}
void AppListController::AppListActivationChanged(bool active) {
if (active) {
timer_.Stop();
return;
}
timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(1), this,
&AppListController::CheckTaskbarOrViewHasFocus);
}
void AppListController::GetArrowLocationAndUpdateAnchor(
const gfx::Rect& work_area,
int min_space_x,
int min_space_y,
views::BubbleBorder::ArrowLocation* arrow,
gfx::Point* anchor) {
// First ensure anchor is within the work area.
if (!work_area.Contains(*anchor)) {
anchor->set_x(std::max(anchor->x(), work_area.x()));
@ -162,7 +253,8 @@ void GetArrowLocationAndUpdateAnchor(const gfx::Rect& work_area,
anchor->Offset(-kAnchorOffset, 0);
}
void UpdateArrowPositionAndAnchorPoint(app_list::AppListView* view) {
void AppListController::UpdateArrowPositionAndAnchorPoint(
app_list::AppListView* view) {
static const int kArrowSize = 10;
static const int kPadding = 20;
@ -185,7 +277,7 @@ void UpdateArrowPositionAndAnchorPoint(app_list::AppListView* view) {
view->SetAnchorPoint(anchor);
}
CommandLine GetAppListCommandLine() {
CommandLine AppListController::GetAppListCommandLine() {
CommandLine* current = CommandLine::ForCurrentProcess();
CommandLine command_line(current->GetProgram());
@ -199,7 +291,7 @@ CommandLine GetAppListCommandLine() {
return command_line;
}
string16 GetAppListIconPath() {
string16 AppListController::GetAppListIconPath() {
FilePath icon_path;
if (!PathService::Get(base::DIR_MODULE, &icon_path))
return string16();
@ -212,7 +304,7 @@ string16 GetAppListIconPath() {
return result;
}
string16 GetAppModelId() {
string16 AppListController::GetAppModelId() {
static const wchar_t kAppListId[] = L"ChromeAppList";
// The AppModelId should be the same for all profiles in a user data directory
// but different for different user data directories, so base it on the
@ -223,40 +315,42 @@ string16 GetAppModelId() {
initial_profile_path);
}
base::LazyInstance<AppListResources>::Leaky g_app_list_resources =
LAZY_INSTANCE_INITIALIZER;
void AppListController::CheckTaskbarOrViewHasFocus() {
// Don't bother checking if the view has been closed.
if (!current_view_)
return;
// First get the taskbar and jump lists windows (the jump list is the
// context menu which the taskbar uses).
HWND jump_list_hwnd = FindWindow(L"DV2ControlHost", NULL);
HWND taskbar_hwnd = FindWindow(L"Shell_TrayWnd", NULL);
HWND app_list_hwnd =
current_view_->GetWidget()->GetTopLevelWidget()->GetNativeWindow();
// Get the focused window, and check if it is one of these windows. Keep
// checking it's parent until either we find one of these windows, or there
// is no parent left.
HWND focused_hwnd = GetForegroundWindow();
while (focused_hwnd) {
if (focused_hwnd == jump_list_hwnd ||
focused_hwnd == taskbar_hwnd ||
focused_hwnd == app_list_hwnd) {
return;
}
focused_hwnd = GetParent(focused_hwnd);
}
// If we get here, the focused window is not the taskbar, it's context menu,
// or the app list, so close the app list.
CloseAppList();
}
} // namespace
namespace app_list_controller {
void ShowAppList() {
#if !defined(USE_AURA)
// 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.
app_list::AppListView* view = new app_list::AppListView(
new AppListViewDelegate(new AppListControllerWin()));
gfx::Point cursor = gfx::Screen::GetCursorScreenPoint();
view->InitAsBubble(
GetDesktopWindow(),
g_app_list_resources.Get().pagination_model(),
NULL,
cursor,
views::BubbleBorder::BOTTOM_LEFT);
UpdateArrowPositionAndAnchorPoint(view);
HWND hwnd = view->GetWidget()->GetTopLevelWidget()->GetNativeWindow();
ui::win::SetAppIdForWindow(GetAppModelId(), hwnd);
CommandLine relaunch = GetAppListCommandLine();
ui::win::SetRelaunchDetailsForWindow(
relaunch.GetCommandLineString(),
l10n_util::GetStringUTF16(IDS_APP_LIST_SHORTCUT_NAME),
hwnd);
string16 icon_path = GetAppListIconPath();
ui::win::SetAppIconForWindow(icon_path, hwnd);
view->Show();
#endif
g_app_list_controller.Get().ShowAppList();
}
} // namespace app_list_controller

@ -195,4 +195,18 @@ void AppListView::InvokeResultAction(const SearchResult& result,
delegate_->InvokeSearchResultAction(result, action_index, event_flags);
}
void AppListView::OnWidgetClosing(views::Widget* widget) {
BubbleDelegateView::OnWidgetClosing(widget);
if (delegate_.get() && widget == GetWidget())
delegate_->ViewClosing();
}
void AppListView::OnWidgetActivationChanged(views::Widget* widget,
bool active) {
// Do not called inherited function as the bubble delegate auto close
// functionality is not used.
if (delegate_.get() && widget == GetWidget())
delegate_->ViewActivationChanged(active);
}
} // namespace app_list

@ -12,6 +12,10 @@
#include "ui/app_list/search_result_list_view_delegate.h"
#include "ui/views/bubble/bubble_delegate.h"
namespace views {
class Widget;
}
namespace app_list {
class AppListModel;
@ -73,6 +77,11 @@ class APP_LIST_EXPORT AppListView : public views::BubbleDelegateView,
int action_index,
int event_flags) OVERRIDE;
// Overridden from views::WidgetObserver:
virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE;
virtual void OnWidgetActivationChanged(views::Widget* widget, bool active)
OVERRIDE;
scoped_ptr<AppListModel> model_;
scoped_ptr<AppListViewDelegate> delegate_;

@ -46,6 +46,12 @@ class APP_LIST_EXPORT AppListViewDelegate {
// Invoked to close app list.
virtual void Close() = 0;
// Invoked when the app list is closing.
virtual void ViewClosing() = 0;
// Invoked when the app list's activated state changes.
virtual void ViewActivationChanged(bool active) = 0;
};
} // namespace app_list