17dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On Mac, one can't make shortcuts with command-line arguments. Instead, we 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// produce small app bundles which locate the Chromium framework and load it, 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// passing the appropriate data. This is the entry point into the framework for 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// those app bundles. 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#import <Cocoa/Cocoa.h> 1158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include <vector> 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/at_exit.h" 14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/command_line.h" 1558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/files/file_path.h" 161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 18fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch#include "base/mac/bundle_locations.h" 1958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/mac/foundation_util.h" 20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/mac/launch_services_util.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/mac/mac_logging.h" 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/mac/mac_util.h" 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/mac/scoped_nsautorelease_pool.h" 24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/mac/scoped_nsobject.h" 2546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/mac/sdk_forward_declarations.h" 267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/message_loop/message_loop.h" 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/path_service.h" 28424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/strings/string_number_conversions.h" 29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/sys_string_conversions.h" 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/thread.h" 31fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch#include "chrome/common/chrome_constants.h" 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/chrome_paths.h" 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h" 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/mac/app_mode_common.h" 351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/common/mac/app_shim_messages.h" 361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/grit/generated_resources.h" 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ipc/ipc_channel_proxy.h" 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ipc/ipc_listener.h" 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ipc/ipc_message.h" 40fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch#include "ui/base/l10n/l10n_util.h" 411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/base/resource/resource_bundle.h" 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 45f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Timeout in seconds to wait for a reply for the initial Apple Event. Note that 46f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// kAEDefaultTimeout on Mac is "about one minute" according to Apple's 47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// documentation, but is no longer supported for asynchronous Apple Events. 48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int kPingChromeTimeoutSeconds = 60; 49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const app_mode::ChromeAppModeInfo* g_info; 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::Thread* g_io_thread = NULL; 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)class AppShimController; 56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 5758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// An application delegate to catch user interactions and send the appropriate 5858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// IPC messages to Chrome. 59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)@interface AppShimDelegate : NSObject<NSApplicationDelegate> { 60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) @private 6158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) AppShimController* appShimController_; // Weak, initially NULL. 62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) BOOL terminateNow_; 63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) BOOL terminateRequested_; 6458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) std::vector<base::FilePath> filesToOpenAtStartup_; 65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 6758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// The controller is initially NULL. Setting it indicates to the delegate that 6858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// the controller has finished initialization. 6958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)- (void)setController:(AppShimController*)controller; 7058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 7158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Gets files that were queued because the controller was not ready. 7258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Returns whether any FilePaths were added to |out|. 7358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)- (BOOL)getFilesToOpenAtStartup:(std::vector<base::FilePath>*)out; 7458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 7558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// If the controller is ready, this sends a FocusApp with the files to open. 7658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Otherwise, this adds the files to |filesToOpenAtStartup_|. 7758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Takes an array of NSString*. 7858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)- (void)openFiles:(NSArray*)filename; 7958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 8058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Terminate immediately. This is necessary as we override terminate: to send 8158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// a QuitApp message. 82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)- (void)terminateNow; 83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)@end 85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The AppShimController is responsible for communication with the main Chrome 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// process, and generally controls the lifetime of the app shim process. 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class AppShimController : public IPC::Listener { 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AppShimController(); 9158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual ~AppShimController(); 9258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 9358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Called when the main Chrome process responds to the Apple Event ping that 9458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // was sent, or when the ping fails (if |success| is false). 9558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) void OnPingChromeReply(bool success); 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Called |kPingChromeTimeoutSeconds| after startup, to allow a timeout on the 98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // ping event to be detected. 99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) void OnPingChromeTimeout(); 100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Connects to Chrome and sends a LaunchApp message. 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void Init(); 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Create a channel from |socket_path| and send a LaunchApp message. 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) void CreateChannelAndSendLaunchApp(const base::FilePath& socket_path); 1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 107fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch // Builds main menu bar items. 108fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch void SetUpMenu(); 109fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch 110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void SendSetAppHidden(bool hidden); 111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void SendQuitApp(); 113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 11458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Called when the app is activated, e.g. by clicking on it in the dock, by 11558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // dropping a file on the dock icon, or by Cmd+Tabbing to it. 11658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Returns whether the message was sent. 11758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) bool SendFocusApp(apps::AppShimFocusType focus_type, 11858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const std::vector<base::FilePath>& files); 119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // IPC::Listener implemetation. 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void OnChannelError() OVERRIDE; 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If Chrome failed to launch the app, |success| will be false and the app 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // shim process should die. 1277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch void OnLaunchAppDone(apps::AppShimLaunchResult result); 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 12958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Hide this app. 13058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) void OnHide(); 13158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 132424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // Requests user attention. 133424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) void OnRequestUserAttention(); 13403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) void OnSetUserAttention(apps::AppShimAttentionType attention_type); 135424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Terminates the app shim process. 137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void Close(); 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::FilePath user_data_dir_; 1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_ptr<IPC::ChannelProxy> channel_; 14158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::scoped_nsobject<AppShimDelegate> delegate_; 142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool launch_app_done_; 143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bool ping_chrome_reply_received_; 14403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) NSInteger attention_request_id_; 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(AppShimController); 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 14958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)AppShimController::AppShimController() 1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : delegate_([[AppShimDelegate alloc] init]), 151f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) launch_app_done_(false), 15203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) ping_chrome_reply_received_(false), 15303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) attention_request_id_(0) { 15458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Since AppShimController is created before the main message loop starts, 15558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // NSApp will not be set, so use sharedApplication. 15658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) [[NSApplication sharedApplication] setDelegate:delegate_]; 15758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 15858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 15958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)AppShimController::~AppShimController() { 16058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Un-set the delegate since NSApplication does not retain it. 161f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) [[NSApplication sharedApplication] setDelegate:nil]; 16258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 16358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 16458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void AppShimController::OnPingChromeReply(bool success) { 165f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ping_chrome_reply_received_ = true; 16658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!success) { 16758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) [NSApp terminate:nil]; 16858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 16958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 17058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 17158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) Init(); 17258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 174f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void AppShimController::OnPingChromeTimeout() { 175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!ping_chrome_reply_received_) 176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) [NSApp terminate:nil]; 177f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AppShimController::Init() { 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(g_io_thread); 181fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch 182fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch SetUpMenu(); 183fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch 184424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // Chrome will relaunch shims when relaunching apps. 185424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (base::mac::IsOSLionOrLater()) 186424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) [NSApp disableRelaunchOnLogin]; 187424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 188a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // The user_data_dir for shims actually contains the app_data_path. 189a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // I.e. <user_data_dir>/<profile_dir>/Web Applications/_crx_extensionid/ 1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) user_data_dir_ = g_info->user_data_dir.DirName().DirName().DirName(); 1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CHECK(!user_data_dir_.empty()); 1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::FilePath symlink_path = 1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) user_data_dir_.Append(app_mode::kAppShimSocketSymlinkName); 1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::FilePath socket_path; 1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!base::ReadSymbolicLink(symlink_path, &socket_path)) { 1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // The path in the user data dir is not a symlink, try connecting directly. 1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateChannelAndSendLaunchApp(symlink_path); 2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) app_mode::VerifySocketPermissions(socket_path); 204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateChannelAndSendLaunchApp(socket_path); 2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AppShimController::CreateChannelAndSendLaunchApp( 2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::FilePath& socket_path) { 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IPC::ChannelHandle handle(socket_path.value()); 21146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) channel_ = IPC::ChannelProxy::Create(handle, 21246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) IPC::Channel::MODE_NAMED_CLIENT, 21346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) this, 21446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) g_io_thread->message_loop_proxy().get()); 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 216424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) bool launched_by_chrome = 217424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) CommandLine::ForCurrentProcess()->HasSwitch( 218424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) app_mode::kLaunchedByChromeProcessId); 21958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) apps::AppShimLaunchType launch_type = launched_by_chrome ? 22058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) apps::APP_SHIM_LAUNCH_REGISTER_ONLY : apps::APP_SHIM_LAUNCH_NORMAL; 22158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 22258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) [delegate_ setController:this]; 223868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 22458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) std::vector<base::FilePath> files; 22558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) [delegate_ getFilesToOpenAtStartup:&files]; 22658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 22758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) channel_->Send(new AppShimHostMsg_LaunchApp( 22858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) g_info->profile_dir, g_info->app_mode_id, launch_type, files)); 229868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 230868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 231fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdochvoid AppShimController::SetUpMenu() { 232fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch NSString* title = base::SysUTF16ToNSString(g_info->app_mode_name); 233fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch 234fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch // Create a main menu since [NSApp mainMenu] is nil. 235fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch base::scoped_nsobject<NSMenu> main_menu([[NSMenu alloc] initWithTitle:title]); 236fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch 237fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch // The title of the first item is replaced by OSX with the name of the app and 238fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch // bold styling. Create a dummy item for this and make it hidden. 239fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch NSMenuItem* dummy_item = [main_menu addItemWithTitle:title 240fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch action:nil 241fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch keyEquivalent:@""]; 242fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch base::scoped_nsobject<NSMenu> dummy_submenu( 243fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch [[NSMenu alloc] initWithTitle:title]); 244fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch [dummy_item setSubmenu:dummy_submenu]; 245fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch [dummy_item setHidden:YES]; 246fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch 247fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch // Construct an unbolded app menu, to match how it appears in the Chrome menu 248fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch // bar when the app is focused. 249fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch NSMenuItem* item = [main_menu addItemWithTitle:title 250fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch action:nil 251fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch keyEquivalent:@""]; 252fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch base::scoped_nsobject<NSMenu> submenu([[NSMenu alloc] initWithTitle:title]); 253fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch [item setSubmenu:submenu]; 254fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch 255fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch // Add a quit entry. 256fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch NSString* quit_localized_string = 257fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch l10n_util::GetNSStringF(IDS_EXIT_MAC, g_info->app_mode_name); 258fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch [submenu addItemWithTitle:quit_localized_string 259fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch action:@selector(terminate:) 260fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch keyEquivalent:@"q"]; 261fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch 26268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // Add File, Edit, and Window menus. These are just here to make the 26368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // transition smoother, i.e. from another application to the shim then to 26468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // Chrome. 26568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) [main_menu addItemWithTitle:l10n_util::GetNSString(IDS_FILE_MENU_MAC) 26668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) action:nil 26768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) keyEquivalent:@""]; 26868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) [main_menu addItemWithTitle:l10n_util::GetNSString(IDS_EDIT_MENU_MAC) 26968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) action:nil 27068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) keyEquivalent:@""]; 27168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) [main_menu addItemWithTitle:l10n_util::GetNSString(IDS_WINDOW_MENU_MAC) 27268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) action:nil 27368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) keyEquivalent:@""]; 27468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 275fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch [NSApp setMainMenu:main_menu]; 276fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch} 277fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch 278eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid AppShimController::SendQuitApp() { 279868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) channel_->Send(new AppShimHostMsg_QuitApp); 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AppShimController::OnMessageReceived(const IPC::Message& message) { 2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool handled = true; 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IPC_BEGIN_MESSAGE_MAP(AppShimController, message) 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IPC_MESSAGE_HANDLER(AppShimMsg_LaunchApp_Done, OnLaunchAppDone) 28658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) IPC_MESSAGE_HANDLER(AppShimMsg_Hide, OnHide) 287424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) IPC_MESSAGE_HANDLER(AppShimMsg_RequestUserAttention, OnRequestUserAttention) 28803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) IPC_MESSAGE_HANDLER(AppShimMsg_SetUserAttention, OnSetUserAttention) 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IPC_MESSAGE_UNHANDLED(handled = false) 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IPC_END_MESSAGE_MAP() 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return handled; 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AppShimController::OnChannelError() { 296868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Close(); 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid AppShimController::OnLaunchAppDone(apps::AppShimLaunchResult result) { 3007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (result != apps::APP_SHIM_LAUNCH_SUCCESS) { 301868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Close(); 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 304868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 30558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) std::vector<base::FilePath> files; 30658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if ([delegate_ getFilesToOpenAtStartup:&files]) 30758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) SendFocusApp(apps::APP_SHIM_FOCUS_OPEN_FILES, files); 30858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 309eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch launch_app_done_ = true; 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 31258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void AppShimController::OnHide() { 31358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) [NSApp hide:nil]; 31458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 31558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 316424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void AppShimController::OnRequestUserAttention() { 31703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) OnSetUserAttention(apps::APP_SHIM_ATTENTION_INFORMATIONAL); 31803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} 31903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 32003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void AppShimController::OnSetUserAttention( 32103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) apps::AppShimAttentionType attention_type) { 32203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) switch (attention_type) { 32303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) case apps::APP_SHIM_ATTENTION_CANCEL: 32403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) [NSApp cancelUserAttentionRequest:attention_request_id_]; 32503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) attention_request_id_ = 0; 32603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) break; 32703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) case apps::APP_SHIM_ATTENTION_CRITICAL: 32803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) attention_request_id_ = [NSApp requestUserAttention:NSCriticalRequest]; 32903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) break; 33003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) case apps::APP_SHIM_ATTENTION_INFORMATIONAL: 33103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) attention_request_id_ = 33203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) [NSApp requestUserAttention:NSInformationalRequest]; 33303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) break; 33403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) case apps::APP_SHIM_ATTENTION_NUM_TYPES: 33503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) NOTREACHED(); 33603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 337424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 338424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 339868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void AppShimController::Close() { 34058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) [delegate_ terminateNow]; 3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 34358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool AppShimController::SendFocusApp(apps::AppShimFocusType focus_type, 34458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const std::vector<base::FilePath>& files) { 345eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (launch_app_done_) { 34658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) channel_->Send(new AppShimHostMsg_FocusApp(focus_type, files)); 34758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return true; 348eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 34958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 35058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return false; 351eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 352eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 353eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid AppShimController::SendSetAppHidden(bool hidden) { 354eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch channel_->Send(new AppShimHostMsg_SetAppHidden(hidden)); 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 357868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)@implementation AppShimDelegate 358868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 35958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)- (BOOL)getFilesToOpenAtStartup:(std::vector<base::FilePath>*)out { 36058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (filesToOpenAtStartup_.empty()) 36158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return NO; 36258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 36358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) out->insert(out->end(), 36458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) filesToOpenAtStartup_.begin(), 36558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) filesToOpenAtStartup_.end()); 36658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) filesToOpenAtStartup_.clear(); 36758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return YES; 36858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 36958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 37058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)- (void)setController:(AppShimController*)controller { 37158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) appShimController_ = controller; 37258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 37358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 37458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)- (void)openFiles:(NSArray*)filenames { 37558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) std::vector<base::FilePath> filePaths; 37658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) for (NSString* filename in filenames) 37758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) filePaths.push_back(base::mac::NSStringToFilePath(filename)); 37858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 37958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // If the AppShimController is ready, try to send a FocusApp. If that fails, 38058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // (e.g. if launching has not finished), enqueue the files. 38158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (appShimController_ && 38258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) appShimController_->SendFocusApp(apps::APP_SHIM_FOCUS_OPEN_FILES, 38358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) filePaths)) { 38458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 385868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 38658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 38758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) filesToOpenAtStartup_.insert(filesToOpenAtStartup_.end(), 38858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) filePaths.begin(), 38958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) filePaths.end()); 390868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 391868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 39258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)- (BOOL)application:(NSApplication*)app 39358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) openFile:(NSString*)filename { 39458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) [self openFiles:@[filename]]; 395eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return YES; 396eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 397eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 39858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)- (void)application:(NSApplication*)app 39958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) openFiles:(NSArray*)filenames { 40058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) [self openFiles:filenames]; 40158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) [app replyToOpenOrPrint:NSApplicationDelegateReplySuccess]; 40258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 40358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 40458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)- (BOOL)applicationOpenUntitledFile:(NSApplication*)app { 40558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (appShimController_) { 40658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return appShimController_->SendFocusApp(apps::APP_SHIM_FOCUS_REOPEN, 40758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) std::vector<base::FilePath>()); 40858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 40958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 41058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return NO; 41158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 41258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 413eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch- (void)applicationWillBecomeActive:(NSNotification*)notification { 41458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (appShimController_) { 41558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) appShimController_->SendFocusApp(apps::APP_SHIM_FOCUS_NORMAL, 41658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) std::vector<base::FilePath>()); 41758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 418eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 419eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 420868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)- (NSApplicationTerminateReply) 421868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) applicationShouldTerminate:(NSApplication*)sender { 42258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (terminateNow_ || !appShimController_) 423868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return NSTerminateNow; 424868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 425eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch appShimController_->SendQuitApp(); 426868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Wait for the channel to close before terminating. 427868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) terminateRequested_ = YES; 428868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return NSTerminateLater; 429868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 430868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 431eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch- (void)applicationWillHide:(NSNotification*)notification { 43258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (appShimController_) 43358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) appShimController_->SendSetAppHidden(true); 434eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 435eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 436eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch- (void)applicationWillUnhide:(NSNotification*)notification { 43758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (appShimController_) 43858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) appShimController_->SendSetAppHidden(false); 439eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 440eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 441868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)- (void)terminateNow { 442868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (terminateRequested_) { 443868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) [NSApp replyToApplicationShouldTerminate:NSTerminateNow]; 444868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return; 445868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 446868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 447868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) terminateNow_ = YES; 448868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) [NSApp terminate:nil]; 449868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 450868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 451868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)@end 452868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//----------------------------------------------------------------------------- 4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// A ReplyEventHandler is a helper class to send an Apple Event to a process 4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// and call a callback when the reply returns. 4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This is used to 'ping' the main Chrome process -- once Chrome has sent back 4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// an Apple Event reply, it's guaranteed that it has opened the IPC channel 4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// that the app shim will connect to. 4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)@interface ReplyEventHandler : NSObject { 4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Callback<void(bool)> onReply_; 4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AEDesc replyEvent_; 4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Sends an Apple Event to the process identified by |psn|, and calls |replyFn| 4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// when the reply is received. Internally this creates a ReplyEventHandler, 4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// which will delete itself once the reply event has been received. 4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)+ (void)pingProcess:(const ProcessSerialNumber&)psn 4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) andCall:(base::Callback<void(bool)>)replyFn; 4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)@end 4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)@interface ReplyEventHandler (PrivateMethods) 4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Initialise the reply event handler. Doesn't register any handlers until 4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// |-pingProcess:| is called. |replyFn| is the function to be called when the 4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Apple Event reply arrives. 4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)- (id)initWithCallback:(base::Callback<void(bool)>)replyFn; 4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Sends an Apple Event ping to the process identified by |psn| and registers 4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// to listen for a reply. 4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)- (void)pingProcess:(const ProcessSerialNumber&)psn; 4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Called when a response is received from the target process for the ping sent 4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// by |-pingProcess:|. 4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)- (void)message:(NSAppleEventDescriptor*)event 4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) withReply:(NSAppleEventDescriptor*)reply; 4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Calls |onReply_|, passing it |success| to specify whether the ping was 4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// successful. 4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)- (void)closeWithSuccess:(bool)success; 4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)@end 4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)@implementation ReplyEventHandler 4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)+ (void)pingProcess:(const ProcessSerialNumber&)psn 4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) andCall:(base::Callback<void(bool)>)replyFn { 4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The object will release itself when the reply arrives, or possibly earlier 4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // if an unrecoverable error occurs. 4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ReplyEventHandler* handler = 4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) [[ReplyEventHandler alloc] initWithCallback:replyFn]; 4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) [handler pingProcess:psn]; 5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)@end 5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)@implementation ReplyEventHandler (PrivateMethods) 5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)- (id)initWithCallback:(base::Callback<void(bool)>)replyFn { 5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if ((self = [super init])) { 5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) onReply_ = replyFn; 5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return self; 5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)- (void)pingProcess:(const ProcessSerialNumber&)psn { 5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Register the reply listener. 5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NSAppleEventManager* em = [NSAppleEventManager sharedAppleEventManager]; 5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) [em setEventHandler:self 5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) andSelector:@selector(message:withReply:) 5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) forEventClass:'aevt' 5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) andEventID:'ansr']; 5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Craft the Apple Event to send. 5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NSAppleEventDescriptor* target = [NSAppleEventDescriptor 5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) descriptorWithDescriptorType:typeProcessSerialNumber 5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bytes:&psn 5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) length:sizeof(psn)]; 5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NSAppleEventDescriptor* initial_event = 5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) [NSAppleEventDescriptor 5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) appleEventWithEventClass:app_mode::kAEChromeAppClass 5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) eventID:app_mode::kAEChromeAppPing 5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) targetDescriptor:target 5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) returnID:kAutoGenerateReturnID 5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) transactionID:kAnyTransactionID]; 530f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 531f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Note that AESendMessage effectively ignores kAEDefaultTimeout, because this 532f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // call does not pass kAEWantReceipt (which is deprecated and unsupported on 533f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Mac). Instead, rely on OnPingChromeTimeout(). 5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) OSStatus status = AESendMessage( 5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) [initial_event aeDesc], &replyEvent_, kAEQueueReply, kAEDefaultTimeout); 5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (status != noErr) { 5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) OSSTATUS_LOG(ERROR, status) << "AESendMessage"; 5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) [self closeWithSuccess:false]; 5392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)- (void)message:(NSAppleEventDescriptor*)event 5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) withReply:(NSAppleEventDescriptor*)reply { 5442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) [self closeWithSuccess:true]; 5452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)- (void)closeWithSuccess:(bool)success { 5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) onReply_.Run(success); 5492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NSAppleEventManager* em = [NSAppleEventManager sharedAppleEventManager]; 5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) [em removeEventHandlerForEventClass:'aevt' andEventID:'ansr']; 5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) [self release]; 5522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)@end 5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//----------------------------------------------------------------------------- 5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" { 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |ChromeAppModeStart()| is the point of entry into the framework from the app 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// mode loader. 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)__attribute__((visibility("default"))) 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int ChromeAppModeStart(const app_mode::ChromeAppModeInfo* info); 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // extern "C" 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int ChromeAppModeStart(const app_mode::ChromeAppModeInfo* info) { 567868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) CommandLine::Init(info->argc, info->argv); 568868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::mac::ScopedNSAutoreleasePool scoped_pool; 5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::AtExitManager exit_manager; 5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) chrome::RegisterPathProvider(); 5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (info->major_version < app_mode::kCurrentChromeAppModeInfoMajorVersion) { 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_LOG(ERROR, "App Mode Loader too old."); 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (info->major_version > app_mode::kCurrentChromeAppModeInfoMajorVersion) { 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_LOG(ERROR, "Browser Framework too old to load App Shortcut."); 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) g_info = info; 5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 584fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch // Set bundle paths. This loads the bundles. 585fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch base::mac::SetOverrideOuterBundlePath(g_info->chrome_outer_bundle_path); 586fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch base::mac::SetOverrideFrameworkBundlePath( 587fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch g_info->chrome_versioned_path.Append(chrome::kFrameworkName)); 588fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch 589fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch // Calculate the preferred locale used by Chrome. 590fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch // We can't use l10n_util::OverrideLocaleWithCocoaLocale() because it calls 591fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch // [base::mac::OuterBundle() preferredLocalizations] which gets localizations 592fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch // from the bundle of the running app (i.e. it is equivalent to 593fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch // [[NSBundle mainBundle] preferredLocalizations]) instead of the target 594fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch // bundle. 595fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch NSArray* preferred_languages = [NSLocale preferredLanguages]; 596fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch NSArray* supported_languages = [base::mac::OuterBundle() localizations]; 597fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch std::string preferred_localization; 598fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch for (NSString* language in preferred_languages) { 599fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch if ([supported_languages containsObject:language]) { 600fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch preferred_localization = base::SysNSStringToUTF8(language); 601fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch break; 602fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch } 603fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch } 604fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch std::string locale = l10n_util::NormalizeLocale( 605fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch l10n_util::GetApplicationLocale(preferred_localization)); 606fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch 607fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch // Load localized strings. 6086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ui::ResourceBundle::InitSharedInstanceWithLocale( 6096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) locale, NULL, ui::ResourceBundle::DO_NOT_LOAD_COMMON_RESOURCES); 610fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch 6112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Launch the IO thread. 6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Thread::Options io_thread_options; 613a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) io_thread_options.message_loop_type = base::MessageLoop::TYPE_IO; 6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Thread *io_thread = new base::Thread("CrAppShimIO"); 6152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) io_thread->StartWithOptions(io_thread_options); 6162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) g_io_thread = io_thread; 6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 618868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Find already running instances of Chrome. 619424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) pid_t pid = -1; 620424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) std::string chrome_process_id = CommandLine::ForCurrentProcess()-> 621424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) GetSwitchValueASCII(app_mode::kLaunchedByChromeProcessId); 622424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (!chrome_process_id.empty()) { 623424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (!base::StringToInt(chrome_process_id, &pid)) 624424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) LOG(FATAL) << "Invalid PID: " << chrome_process_id; 625424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } else { 626424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) NSString* chrome_bundle_id = [base::mac::OuterBundle() bundleIdentifier]; 627424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) NSArray* existing_chrome = [NSRunningApplication 628424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) runningApplicationsWithBundleIdentifier:chrome_bundle_id]; 629424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if ([existing_chrome count] > 0) 630424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) pid = [[existing_chrome objectAtIndex:0] processIdentifier]; 631424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 632868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 633f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) AppShimController controller; 634f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::MessageLoopForUI main_message_loop; 635f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) main_message_loop.set_thread_name("MainThread"); 636f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::PlatformThread::SetName("CrAppShimMain"); 637868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 638f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // In tests, launching Chrome does nothing, and we won't get a ping response, 639f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // so just assume the socket exists. 640f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (pid == -1 && 641f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) !CommandLine::ForCurrentProcess()->HasSwitch( 642f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) app_mode::kLaunchedForTest)) { 643f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Launch Chrome if it isn't already running. 644f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ProcessSerialNumber psn; 645868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) CommandLine command_line(CommandLine::NO_PROGRAM); 646868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) command_line.AppendSwitch(switches::kSilentLaunch); 6475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 6485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // If the shim is the app launcher, pass --show-app-list when starting a new 6495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Chrome process to inform startup codepaths and load the correct profile. 6505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (info->app_mode_id == app_mode::kAppListModeId) { 6515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) command_line.AppendSwitch(switches::kShowAppList); 6525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else { 6535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) command_line.AppendSwitchPath(switches::kProfileDirectory, 6545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) info->profile_dir); 6555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 6565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 657868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool success = 658fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch base::mac::OpenApplicationWithPath(base::mac::OuterBundlePath(), 659868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) command_line, 660bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch kLSLaunchDefaults, 661868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) &psn); 662868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!success) 663868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return 1; 66458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 665f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::Callback<void(bool)> on_ping_chrome_reply = 666f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::Bind(&AppShimController::OnPingChromeReply, 667f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::Unretained(&controller)); 668f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 669f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // This code abuses the fact that Apple Events sent before the process is 670f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // fully initialized don't receive a reply until its run loop starts. Once 671f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // the reply is received, Chrome will have opened its IPC port, guaranteed. 672f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) [ReplyEventHandler pingProcess:psn 673f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) andCall:on_ping_chrome_reply]; 674f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 675f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) main_message_loop.PostDelayedTask( 676f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) FROM_HERE, 677f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::Bind(&AppShimController::OnPingChromeTimeout, 678f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::Unretained(&controller)), 679f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::TimeDelta::FromSeconds(kPingChromeTimeoutSeconds)); 680f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } else { 681f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Chrome already running. Proceed to init. This could still fail if Chrome 682f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // is still starting up or shutting down, but the process will exit quickly, 683f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // which is preferable to waiting for the Apple Event to timeout after one 684f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // minute. 685f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) main_message_loop.PostTask( 686f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) FROM_HERE, 687f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::Bind(&AppShimController::Init, 688f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::Unretained(&controller))); 689f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) main_message_loop.Run(); 6922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 0; 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 694