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
7#include <map>
8
9#include "apps/shell_window_registry.h"
10#include "base/bind.h"
11#include "base/logging.h"
12#include "base/memory/singleton.h"
13#include "base/message_loop/message_loop.h"
14#include "chrome/browser/chrome_notification_types.h"
15#include "chrome/browser/lifetime/application_lifetime.h"
16#include "chrome/browser/ui/app_list/app_list_service.h"
17#include "content/public/browser/notification_observer.h"
18#include "content/public/browser/notification_registrar.h"
19#include "content/public/browser/notification_service.h"
20
21namespace apps {
22
23namespace {
24
25void TerminateIfNoShellWindows() {
26  bool shell_windows_left =
27      apps::ShellWindowRegistry::IsShellWindowRegisteredInAnyProfile(0);
28  if (!shell_windows_left && !AppListService::Get(
29          chrome::HOST_DESKTOP_TYPE_NATIVE)->IsAppListVisible()) {
30    chrome::AttemptExit();
31  }
32}
33
34class AppShimHandlerRegistry : public content::NotificationObserver {
35 public:
36  static AppShimHandlerRegistry* GetInstance() {
37    return Singleton<AppShimHandlerRegistry,
38                     LeakySingletonTraits<AppShimHandlerRegistry> >::get();
39  }
40
41  AppShimHandler* GetForAppMode(const std::string& app_mode_id) const {
42    HandlerMap::const_iterator it = handlers_.find(app_mode_id);
43    if (it != handlers_.end())
44      return it->second;
45
46    return default_handler_;
47  }
48
49  bool SetForAppMode(const std::string& app_mode_id, AppShimHandler* handler) {
50    bool inserted_or_removed = handler ?
51        handlers_.insert(HandlerMap::value_type(app_mode_id, handler)).second :
52        handlers_.erase(app_mode_id) == 1;
53    DCHECK(inserted_or_removed);
54    return inserted_or_removed;
55  }
56
57  void SetDefaultHandler(AppShimHandler* handler) {
58    DCHECK_NE(default_handler_ == NULL, handler == NULL);
59    default_handler_ = handler;
60  }
61
62  void MaybeTerminate() {
63    if (!browser_opened_ever_) {
64      // Post this to give ShellWindows a chance to remove themselves from the
65      // registry.
66      base::MessageLoop::current()->PostTask(
67          FROM_HERE,
68          base::Bind(&TerminateIfNoShellWindows));
69    }
70  }
71
72 private:
73  friend struct DefaultSingletonTraits<AppShimHandlerRegistry>;
74  typedef std::map<std::string, AppShimHandler*> HandlerMap;
75
76  AppShimHandlerRegistry()
77      : default_handler_(NULL),
78        browser_opened_ever_(false) {
79    registrar_.Add(
80        this, chrome::NOTIFICATION_BROWSER_OPENED,
81        content::NotificationService::AllBrowserContextsAndSources());
82  }
83
84  virtual ~AppShimHandlerRegistry() {}
85
86  // content::NotificationObserver override:
87  virtual void Observe(
88      int type,
89      const content::NotificationSource& source,
90      const content::NotificationDetails& details) OVERRIDE {
91    DCHECK_EQ(chrome::NOTIFICATION_BROWSER_OPENED, type);
92    registrar_.Remove(
93        this, chrome::NOTIFICATION_BROWSER_OPENED,
94        content::NotificationService::AllBrowserContextsAndSources());
95    browser_opened_ever_ = true;
96  }
97
98  HandlerMap handlers_;
99  AppShimHandler* default_handler_;
100  content::NotificationRegistrar registrar_;
101  bool browser_opened_ever_;
102
103  DISALLOW_COPY_AND_ASSIGN(AppShimHandlerRegistry);
104};
105
106}  // namespace
107
108// static
109void AppShimHandler::RegisterHandler(const std::string& app_mode_id,
110                                     AppShimHandler* handler) {
111  DCHECK(handler);
112  AppShimHandlerRegistry::GetInstance()->SetForAppMode(app_mode_id, handler);
113}
114
115// static
116void AppShimHandler::RemoveHandler(const std::string& app_mode_id) {
117  AppShimHandlerRegistry::GetInstance()->SetForAppMode(app_mode_id, NULL);
118}
119
120// static
121AppShimHandler* AppShimHandler::GetForAppMode(const std::string& app_mode_id) {
122  return AppShimHandlerRegistry::GetInstance()->GetForAppMode(app_mode_id);
123}
124
125// static
126void AppShimHandler::SetDefaultHandler(AppShimHandler* handler) {
127  AppShimHandlerRegistry::GetInstance()->SetDefaultHandler(handler);
128}
129
130// static
131void AppShimHandler::MaybeTerminate() {
132  AppShimHandlerRegistry::GetInstance()->MaybeTerminate();
133}
134
135}  // namespace apps
136