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 21 namespace apps { 22 23 namespace { 24 25 void 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 34 class 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 109 void 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 116 void AppShimHandler::RemoveHandler(const std::string& app_mode_id) { 117 AppShimHandlerRegistry::GetInstance()->SetForAppMode(app_mode_id, NULL); 118 } 119 120 // static 121 AppShimHandler* AppShimHandler::GetForAppMode(const std::string& app_mode_id) { 122 return AppShimHandlerRegistry::GetInstance()->GetForAppMode(app_mode_id); 123 } 124 125 // static 126 void AppShimHandler::SetDefaultHandler(AppShimHandler* handler) { 127 AppShimHandlerRegistry::GetInstance()->SetDefaultHandler(handler); 128 } 129 130 // static 131 void AppShimHandler::MaybeTerminate() { 132 AppShimHandlerRegistry::GetInstance()->MaybeTerminate(); 133 } 134 135 } // namespace apps 136