diff options
-rw-r--r-- | apps/DEPS | 1 | ||||
-rw-r--r-- | apps/app_shim/app_shim_handler_mac.h | 3 | ||||
-rw-r--r-- | apps/app_shim/app_shim_host_mac.cc | 8 | ||||
-rw-r--r-- | apps/app_shim/app_shim_host_mac.h | 3 | ||||
-rw-r--r-- | apps/app_shim/app_shim_host_mac_unittest.cc | 10 | ||||
-rw-r--r-- | apps/app_shim/app_shim_messages.h | 6 | ||||
-rw-r--r-- | apps/app_shim/extension_app_shim_handler_mac.cc | 20 | ||||
-rw-r--r-- | apps/app_shim/extension_app_shim_handler_mac.h | 1 | ||||
-rw-r--r-- | apps/apps.gypi | 2 | ||||
-rw-r--r-- | chrome/app/chrome_main_app_mode_mac.mm | 74 | ||||
-rw-r--r-- | chrome/browser/ui/app_list/app_list_service_mac.mm | 5 |
11 files changed, 121 insertions, 12 deletions
@@ -11,6 +11,7 @@ include_rules = [ "+chrome/browser/profiles", "+chrome/browser/shell_integration.h", "+chrome/browser/ui/extensions/application_launch.h", + "+chrome/browser/ui/extensions/native_app_window.h", "+chrome/browser/ui/extensions/shell_window.h", "+chrome/browser/ui/host_desktop.h", "+chrome/browser/ui/web_applications/web_app_ui.h", diff --git a/apps/app_shim/app_shim_handler_mac.h b/apps/app_shim/app_shim_handler_mac.h index 507fe5f..e4a35fb 100644 --- a/apps/app_shim/app_shim_handler_mac.h +++ b/apps/app_shim/app_shim_handler_mac.h @@ -55,6 +55,9 @@ class AppShimHandler { // Invoked by the shim host when the shim process receives a focus event. virtual void OnShimFocus(Host* host) = 0; + // Invoked by the shim host when the shim process receives a quit event. + virtual void OnShimQuit(Host* host) = 0; + protected: AppShimHandler() {} virtual ~AppShimHandler() {} diff --git a/apps/app_shim/app_shim_host_mac.cc b/apps/app_shim/app_shim_host_mac.cc index ad63e93..07c9903 100644 --- a/apps/app_shim/app_shim_host_mac.cc +++ b/apps/app_shim/app_shim_host_mac.cc @@ -47,6 +47,7 @@ bool AppShimHost::OnMessageReceived(const IPC::Message& message) { IPC_BEGIN_MESSAGE_MAP(AppShimHost, message) IPC_MESSAGE_HANDLER(AppShimHostMsg_LaunchApp, OnLaunchApp) IPC_MESSAGE_HANDLER(AppShimHostMsg_FocusApp, OnFocus) + IPC_MESSAGE_HANDLER(AppShimHostMsg_QuitApp, OnQuit) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -85,6 +86,13 @@ void AppShimHost::OnFocus() { handler->OnShimFocus(this); } +void AppShimHost::OnQuit() { + DCHECK(CalledOnValidThread()); + apps::AppShimHandler* handler = apps::AppShimHandler::GetForAppMode(app_id_); + if (handler) + handler->OnShimQuit(this); +} + Profile* AppShimHost::FetchProfileForDirectory(const std::string& profile_dir) { ProfileManager* profileManager = g_browser_process->profile_manager(); // Even though the name of this function is "unsafe", there's no security diff --git a/apps/app_shim/app_shim_host_mac.h b/apps/app_shim/app_shim_host_mac.h index e68380c..dd31047 100644 --- a/apps/app_shim/app_shim_host_mac.h +++ b/apps/app_shim/app_shim_host_mac.h @@ -62,6 +62,9 @@ class AppShimHost : public IPC::Listener, // Cmd+Tabbed to it.) void OnFocus(); + // Called when the app shim process notifies that the app should quit. + void OnQuit(); + // apps::AppShimHandler::Host overrides: virtual void OnAppClosed() OVERRIDE; virtual Profile* GetProfile() const OVERRIDE; diff --git a/apps/app_shim/app_shim_host_mac_unittest.cc b/apps/app_shim/app_shim_host_mac_unittest.cc index f9a8e4d..0a7ef2b 100644 --- a/apps/app_shim/app_shim_host_mac_unittest.cc +++ b/apps/app_shim/app_shim_host_mac_unittest.cc @@ -72,7 +72,10 @@ Profile* TestingAppShimHost::FetchProfileForDirectory( class AppShimHostTest : public testing::Test, public apps::AppShimHandler { public: - AppShimHostTest() : launch_count_(0), close_count_(0), focus_count_(0) {} + AppShimHostTest() : launch_count_(0), + close_count_(0), + focus_count_(0), + quit_count_(0) {} TestingAppShimHost* host() { return host_.get(); } TestingProfile* profile() { return profile_.get(); } @@ -98,10 +101,12 @@ class AppShimHostTest : public testing::Test, virtual void OnShimClose(Host* host) OVERRIDE { ++close_count_; } virtual void OnShimFocus(Host* host) OVERRIDE { ++focus_count_; } + virtual void OnShimQuit(Host* host) OVERRIDE { ++quit_count_; } int launch_count_; int close_count_; int focus_count_; + int quit_count_; private: virtual void SetUp() OVERRIDE { @@ -135,6 +140,9 @@ TEST_F(AppShimHostTest, TestLaunchAppWithHandler) { EXPECT_TRUE(host()->ReceiveMessage(new AppShimHostMsg_FocusApp())); EXPECT_EQ(1, focus_count_); + EXPECT_TRUE(host()->ReceiveMessage(new AppShimHostMsg_QuitApp())); + EXPECT_EQ(1, quit_count_); + SimulateDisconnect(); EXPECT_EQ(1, close_count_); apps::AppShimHandler::RemoveHandler(kTestAppId); diff --git a/apps/app_shim/app_shim_messages.h b/apps/app_shim/app_shim_messages.h index 6a6cc6d..5b8c194 100644 --- a/apps/app_shim/app_shim_messages.h +++ b/apps/app_shim/app_shim_messages.h @@ -25,3 +25,9 @@ IPC_MESSAGE_CONTROL2(AppShimHostMsg_LaunchApp, // clicking on the app's icon in the dock or by selecting it with Cmd+Tab. In // response, Chrome brings the app's windows to the foreground. IPC_MESSAGE_CONTROL0(AppShimHostMsg_FocusApp) + +// Sent when the shim process receives a request to terminate. Once all of the +// app's windows have closed, and the extension is unloaded, the AppShimHost +// closes the channel. The shim process then completes the terminate request +// and exits. +IPC_MESSAGE_CONTROL0(AppShimHostMsg_QuitApp) diff --git a/apps/app_shim/extension_app_shim_handler_mac.cc b/apps/app_shim/extension_app_shim_handler_mac.cc index 9d31d69..902e0c2 100644 --- a/apps/app_shim/extension_app_shim_handler_mac.cc +++ b/apps/app_shim/extension_app_shim_handler_mac.cc @@ -12,6 +12,7 @@ #include "chrome/browser/extensions/extension_system.h" #include "chrome/browser/extensions/shell_window_registry.h" #include "chrome/browser/ui/extensions/application_launch.h" +#include "chrome/browser/ui/extensions/native_app_window.h" #include "chrome/browser/ui/extensions/shell_window.h" #include "ui/base/cocoa/focus_window_set.h" @@ -73,13 +74,26 @@ void ExtensionAppShimHandler::OnShimFocus(Host* host) { const extensions::ShellWindowRegistry::ShellWindowList windows = registry->GetShellWindowsForApp(host->GetAppId()); std::set<gfx::NativeWindow> native_windows; - for (extensions::ShellWindowRegistry::const_iterator i = windows.begin(); - i != windows.end(); ++i) { - native_windows.insert((*i)->GetNativeWindow()); + for (extensions::ShellWindowRegistry::const_iterator it = windows.begin(); + it != windows.end(); ++it) { + native_windows.insert((*it)->GetNativeWindow()); } ui::FocusWindowSet(native_windows); } +void ExtensionAppShimHandler::OnShimQuit(Host* host) { + if (!host->GetProfile()) + return; + + extensions::ShellWindowRegistry::ShellWindowList windows = + extensions::ShellWindowRegistry::Get(host->GetProfile())-> + GetShellWindowsForApp(host->GetAppId()); + for (extensions::ShellWindowRegistry::const_iterator it = windows.begin(); + it != windows.end(); ++it) { + (*it)->GetBaseWindow()->Close(); + } +} + bool ExtensionAppShimHandler::LaunchApp(Profile* profile, const std::string& app_id) { extensions::ExtensionSystem* extension_system = diff --git a/apps/app_shim/extension_app_shim_handler_mac.h b/apps/app_shim/extension_app_shim_handler_mac.h index ea9a8c7..86c86e1 100644 --- a/apps/app_shim/extension_app_shim_handler_mac.h +++ b/apps/app_shim/extension_app_shim_handler_mac.h @@ -28,6 +28,7 @@ class ExtensionAppShimHandler : public AppShimHandler, virtual bool OnShimLaunch(Host* host) OVERRIDE; virtual void OnShimClose(Host* host) OVERRIDE; virtual void OnShimFocus(Host* host) OVERRIDE; + virtual void OnShimQuit(Host* host) OVERRIDE; protected: typedef std::map<std::pair<Profile*, std::string>, AppShimHandler::Host*> diff --git a/apps/apps.gypi b/apps/apps.gypi index 92a677e..49681a2 100644 --- a/apps/apps.gypi +++ b/apps/apps.gypi @@ -36,8 +36,8 @@ 'app_shim/app_shim_host_mac.h', 'app_shim/app_shim_host_manager_mac.h', 'app_shim/app_shim_host_manager_mac.mm', - 'app_shim/extension_app_shim_handler_mac.h', 'app_shim/extension_app_shim_handler_mac.cc', + 'app_shim/extension_app_shim_handler_mac.h', 'field_trial_names.cc', 'field_trial_names.h', 'pref_names.cc', diff --git a/chrome/app/chrome_main_app_mode_mac.mm b/chrome/app/chrome_main_app_mode_mac.mm index 1de3fe5..e464612 100644 --- a/chrome/app/chrome_main_app_mode_mac.mm +++ b/chrome/app/chrome_main_app_mode_mac.mm @@ -17,6 +17,7 @@ #include "base/mac/mac_logging.h" #include "base/mac/mac_util.h" #include "base/mac/scoped_nsautorelease_pool.h" +#include "base/memory/scoped_nsobject.h" #include "base/message_loop.h" #include "base/path_service.h" #include "base/strings/sys_string_conversions.h" @@ -36,6 +37,21 @@ base::Thread* g_io_thread = NULL; } // namespace +class AppShimController; + +@interface AppShimDelegate : NSObject<NSApplicationDelegate> { + @private + AppShimController* appShimController_; // Weak. Owns us. + BOOL terminateNow_; + BOOL terminateRequested_; +} + +- (id)initWithController:(AppShimController*)controller; + +- (void)terminateNow; + +@end + // The AppShimController is responsible for communication with the main Chrome // process, and generally controls the lifetime of the app shim process. class AppShimController : public IPC::Listener { @@ -45,6 +61,9 @@ class AppShimController : public IPC::Listener { // Connects to Chrome and sends a LaunchApp message. void Init(); + // Sends a QuitApp message to Chrome. + void QuitApp(); + private: // IPC::Listener implemetation. virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; @@ -58,10 +77,11 @@ class AppShimController : public IPC::Listener { // dock or by Cmd+Tabbing to it. void OnDidActivateApplication(); - // Quits the app shim process. - void Quit(); + // Terminates the app shim process. + void Close(); IPC::ChannelProxy* channel_; + scoped_nsobject<AppShimDelegate> nsapp_delegate_; DISALLOW_COPY_AND_ASSIGN(AppShimController); }; @@ -77,7 +97,7 @@ void AppShimController::Init() { base::FilePath user_data_dir; if (!chrome::GetUserDataDirectoryForBrowserBundle(chrome_bundle, &user_data_dir)) { - Quit(); + Close(); return; } @@ -89,6 +109,14 @@ void AppShimController::Init() { channel_->Send(new AppShimHostMsg_LaunchApp( g_info->profile_dir.value(), g_info->app_mode_id)); + + nsapp_delegate_.reset([[AppShimDelegate alloc] initWithController:this]); + DCHECK(![NSApp delegate]); + [NSApp setDelegate:nsapp_delegate_]; +} + +void AppShimController::QuitApp() { + channel_->Send(new AppShimHostMsg_QuitApp); } bool AppShimController::OnMessageReceived(const IPC::Message& message) { @@ -103,12 +131,12 @@ bool AppShimController::OnMessageReceived(const IPC::Message& message) { void AppShimController::OnChannelError() { LOG(ERROR) << "App shim channel error."; - Quit(); + Close(); } void AppShimController::OnLaunchAppDone(bool success) { if (!success) { - Quit(); + Close(); return; } [[[NSWorkspace sharedWorkspace] notificationCenter] @@ -123,14 +151,46 @@ void AppShimController::OnLaunchAppDone(bool success) { }]; } -void AppShimController::Quit() { - [NSApp terminate:nil]; +void AppShimController::Close() { + [nsapp_delegate_ terminateNow]; } void AppShimController::OnDidActivateApplication() { channel_->Send(new AppShimHostMsg_FocusApp); } +@implementation AppShimDelegate + +- (id)initWithController:(AppShimController*)controller { + if ((self = [super init])) { + appShimController_ = controller; + } + return self; +} + +- (NSApplicationTerminateReply) + applicationShouldTerminate:(NSApplication*)sender { + if (terminateNow_) + return NSTerminateNow; + + appShimController_->QuitApp(); + // Wait for the channel to close before terminating. + terminateRequested_ = YES; + return NSTerminateLater; +} + +- (void)terminateNow { + if (terminateRequested_) { + [NSApp replyToApplicationShouldTerminate:NSTerminateNow]; + return; + } + + terminateNow_ = YES; + [NSApp terminate:nil]; +} + +@end + //----------------------------------------------------------------------------- // A ReplyEventHandler is a helper class to send an Apple Event to a process diff --git a/chrome/browser/ui/app_list/app_list_service_mac.mm b/chrome/browser/ui/app_list/app_list_service_mac.mm index 677ed2b..254527b 100644 --- a/chrome/browser/ui/app_list/app_list_service_mac.mm +++ b/chrome/browser/ui/app_list/app_list_service_mac.mm @@ -64,6 +64,7 @@ class AppListServiceMac : public AppListServiceImpl, virtual bool OnShimLaunch(apps::AppShimHandler::Host* host) OVERRIDE; virtual void OnShimClose(apps::AppShimHandler::Host* host) OVERRIDE; virtual void OnShimFocus(apps::AppShimHandler::Host* host) OVERRIDE; + virtual void OnShimQuit(apps::AppShimHandler::Host* host) OVERRIDE; private: friend struct DefaultSingletonTraits<AppListServiceMac>; @@ -285,6 +286,10 @@ void AppListServiceMac::OnShimFocus(apps::AppShimHandler::Host* host) { DismissAppList(); } +void AppListServiceMac::OnShimQuit(apps::AppShimHandler::Host* host) { + DismissAppList(); +} + enum DockLocation { DockLocationOtherDisplay, DockLocationBottom, |