app_list_service_mac.mm revision a93a17c8d99d686bd4a1511e5504e5e6cc9fcadf
1// Copyright 2013 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 "apps/app_shim/app_shim_handler_mac.h"
6#include "base/bind.h"
7#include "base/lazy_instance.h"
8#include "base/memory/scoped_nsobject.h"
9#include "base/memory/singleton.h"
10#include "base/message_loop.h"
11#include "base/observer_list.h"
12#include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
13#include "chrome/browser/ui/app_list/app_list_service.h"
14#include "chrome/browser/ui/app_list/app_list_service_impl.h"
15#include "chrome/browser/ui/app_list/app_list_view_delegate.h"
16#include "chrome/browser/ui/extensions/application_launch.h"
17#include "chrome/common/mac/app_mode_common.h"
18#import "ui/app_list/cocoa/app_list_view_controller.h"
19#import "ui/app_list/cocoa/app_list_window_controller.h"
20
21namespace gfx {
22class ImageSkia;
23}
24
25namespace {
26
27// AppListServiceMac manages global resources needed for the app list to
28// operate, and controls when the app list is opened and closed.
29class AppListServiceMac : public AppListServiceImpl,
30                          public apps::AppShimHandler {
31 public:
32  virtual ~AppListServiceMac() {}
33
34  static AppListServiceMac* GetInstance() {
35    return Singleton<AppListServiceMac,
36                     LeakySingletonTraits<AppListServiceMac> >::get();
37  }
38
39  void CreateAppList(Profile* profile);
40  NSWindow* GetNativeWindow();
41
42  // AppListService overrides:
43  virtual void Init(Profile* initial_profile) OVERRIDE;
44  virtual void ShowAppList(Profile* requested_profile) OVERRIDE;
45  virtual void DismissAppList() OVERRIDE;
46  virtual bool IsAppListVisible() const OVERRIDE;
47  virtual void EnableAppList() OVERRIDE;
48
49  // AppShimHandler overrides:
50  virtual bool OnShimLaunch(apps::AppShimHandler::Host* host) OVERRIDE;
51  virtual void OnShimClose(apps::AppShimHandler::Host* host) OVERRIDE;
52  virtual void OnShimFocus(apps::AppShimHandler::Host* host) OVERRIDE;
53
54 private:
55  friend struct DefaultSingletonTraits<AppListServiceMac>;
56
57  AppListServiceMac() {}
58
59  scoped_nsobject<AppListWindowController> window_controller_;
60
61  // App shim hosts observing when the app list is dismissed. In normal user
62  // usage there should only be one. However, it can't be guaranteed, so use
63  // an ObserverList rather than handling corner cases.
64  ObserverList<apps::AppShimHandler::Host> observers_;
65
66  DISALLOW_COPY_AND_ASSIGN(AppListServiceMac);
67};
68
69class AppListControllerDelegateCocoa : public AppListControllerDelegate {
70 public:
71  AppListControllerDelegateCocoa();
72  virtual ~AppListControllerDelegateCocoa();
73
74 private:
75  // AppListControllerDelegate overrides:
76  virtual void DismissView() OVERRIDE;
77  virtual gfx::NativeWindow GetAppListWindow() OVERRIDE;
78  virtual bool CanPin() OVERRIDE;
79  virtual bool CanShowCreateShortcutsDialog() OVERRIDE;
80  virtual void ActivateApp(Profile* profile,
81                           const extensions::Extension* extension,
82                           int event_flags) OVERRIDE;
83  virtual void LaunchApp(Profile* profile,
84                         const extensions::Extension* extension,
85                         int event_flags) OVERRIDE;
86
87  DISALLOW_COPY_AND_ASSIGN(AppListControllerDelegateCocoa);
88};
89
90AppListControllerDelegateCocoa::AppListControllerDelegateCocoa() {}
91
92AppListControllerDelegateCocoa::~AppListControllerDelegateCocoa() {}
93
94void AppListControllerDelegateCocoa::DismissView() {
95  AppListServiceMac::GetInstance()->DismissAppList();
96}
97
98gfx::NativeWindow AppListControllerDelegateCocoa::GetAppListWindow() {
99  return AppListServiceMac::GetInstance()->GetNativeWindow();
100}
101
102bool AppListControllerDelegateCocoa::CanPin() {
103  return false;
104}
105
106bool AppListControllerDelegateCocoa::CanShowCreateShortcutsDialog() {
107  // TODO(tapted): Return true when create shortcuts menu is tested on mac.
108  return false;
109}
110
111void AppListControllerDelegateCocoa::ActivateApp(
112    Profile* profile, const extensions::Extension* extension, int event_flags) {
113  LaunchApp(profile, extension, event_flags);
114}
115
116void AppListControllerDelegateCocoa::LaunchApp(
117    Profile* profile, const extensions::Extension* extension, int event_flags) {
118  chrome::OpenApplication(chrome::AppLaunchParams(
119      profile, extension, NEW_FOREGROUND_TAB));
120}
121
122void AppListServiceMac::CreateAppList(Profile* requested_profile) {
123  if (profile() == requested_profile)
124    return;
125
126  // The Objective C objects might be released at some unknown point in the
127  // future, so explicitly clear references to C++ objects.
128  [[window_controller_ appListViewController]
129      setDelegate:scoped_ptr<app_list::AppListViewDelegate>(NULL)];
130
131  SetProfile(requested_profile);
132  scoped_ptr<app_list::AppListViewDelegate> delegate(
133      new AppListViewDelegate(new AppListControllerDelegateCocoa(), profile()));
134  window_controller_.reset([[AppListWindowController alloc] init]);
135  [[window_controller_ appListViewController] setDelegate:delegate.Pass()];
136}
137
138void AppListServiceMac::Init(Profile* initial_profile) {
139  static bool init_called = false;
140  if (init_called)
141    return;
142
143  init_called = true;
144  apps::AppShimHandler::RegisterHandler(app_mode::kAppListModeId,
145                                        AppListServiceMac::GetInstance());
146}
147
148void AppListServiceMac::ShowAppList(Profile* requested_profile) {
149  InvalidatePendingProfileLoads();
150
151  if (IsAppListVisible() && (requested_profile == profile())) {
152    DCHECK(window_controller_);
153    [[window_controller_ window] makeKeyAndOrderFront:nil];
154    [NSApp activateIgnoringOtherApps:YES];
155    return;
156  }
157
158  SaveProfilePathToLocalState(requested_profile->GetPath());
159
160  DismissAppList();
161  CreateAppList(requested_profile);
162
163  DCHECK(window_controller_);
164  [[window_controller_ window] makeKeyAndOrderFront:nil];
165  [NSApp activateIgnoringOtherApps:YES];
166}
167
168void AppListServiceMac::DismissAppList() {
169  if (!IsAppListVisible())
170    return;
171
172  [[window_controller_ window] close];
173
174  FOR_EACH_OBSERVER(apps::AppShimHandler::Host,
175                    observers_,
176                    OnAppClosed());
177}
178
179bool AppListServiceMac::IsAppListVisible() const {
180  return [[window_controller_ window] isVisible];
181}
182
183void AppListServiceMac::EnableAppList() {
184  // TODO(tapted): Implement enable logic here for OSX.
185}
186
187NSWindow* AppListServiceMac::GetNativeWindow() {
188  return [window_controller_ window];
189}
190
191bool AppListServiceMac::OnShimLaunch(apps::AppShimHandler::Host* host) {
192  ShowForSavedProfile();
193  observers_.AddObserver(host);
194  return true;
195}
196
197void AppListServiceMac::OnShimClose(apps::AppShimHandler::Host* host) {
198  observers_.RemoveObserver(host);
199  DismissAppList();
200}
201
202void AppListServiceMac::OnShimFocus(apps::AppShimHandler::Host* host) {
203  DismissAppList();
204}
205
206}  // namespace
207
208// static
209AppListService* AppListService::Get() {
210  return AppListServiceMac::GetInstance();
211}
212
213// static
214void AppListService::InitAll(Profile* initial_profile) {
215  Get()->Init(initial_profile);
216}
217