1// Copyright (c) 2012 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 "chrome/browser/shell_integration.h" 6 7#include "base/mac/bundle_locations.h" 8#include "base/mac/mac_util.h" 9#include "base/mac/foundation_util.h" 10#include "chrome/common/chrome_version_info.h" 11#import "third_party/mozilla/NSWorkspace+Utils.h" 12 13ShellIntegration::DefaultWebClientSetPermission 14 ShellIntegration::CanSetAsDefaultBrowser() { 15 if (chrome::VersionInfo::GetChannel() != 16 chrome::VersionInfo::CHANNEL_CANARY) { 17 return SET_DEFAULT_UNATTENDED; 18 } 19 20 return SET_DEFAULT_NOT_ALLOWED; 21} 22 23// Sets Chromium as default browser to be used by the operating system. This 24// applies only for the current user. Returns false if this cannot be done, or 25// if the operation fails. 26bool ShellIntegration::SetAsDefaultBrowser() { 27 if (CanSetAsDefaultBrowser() != SET_DEFAULT_UNATTENDED) 28 return false; 29 30 // We really do want the outer bundle here, not the main bundle since setting 31 // a shortcut to Chrome as the default browser doesn't make sense. 32 NSString* identifier = [base::mac::OuterBundle() bundleIdentifier]; 33 if (!identifier) 34 return false; 35 36 [[NSWorkspace sharedWorkspace] setDefaultBrowserWithIdentifier:identifier]; 37 return true; 38} 39 40// Sets Chromium as the default application to be used by the operating system 41// for the given protocol. This applies only for the current user. Returns false 42// if this cannot be done, or if the operation fails. 43bool ShellIntegration::SetAsDefaultProtocolClient(const std::string& protocol) { 44 if (protocol.empty()) 45 return false; 46 47 if (CanSetAsDefaultProtocolClient() != SET_DEFAULT_UNATTENDED) 48 return false; 49 50 // We really do want the main bundle here since it makes sense to set an 51 // app shortcut as a default protocol handler. 52 NSString* identifier = [base::mac::MainBundle() bundleIdentifier]; 53 if (!identifier) 54 return false; 55 56 NSString* protocol_ns = [NSString stringWithUTF8String:protocol.c_str()]; 57 OSStatus return_code = 58 LSSetDefaultHandlerForURLScheme(base::mac::NSToCFCast(protocol_ns), 59 base::mac::NSToCFCast(identifier)); 60 return return_code == noErr; 61} 62 63namespace { 64 65// Returns true if |identifier| is the bundle id of the default browser. 66bool IsIdentifierDefaultBrowser(NSString* identifier) { 67 NSString* default_browser = 68 [[NSWorkspace sharedWorkspace] defaultBrowserIdentifier]; 69 if (!default_browser) 70 return false; 71 72 // We need to ensure we do the comparison case-insensitive as LS doesn't 73 // persist the case of our bundle id. 74 NSComparisonResult result = 75 [default_browser caseInsensitiveCompare:identifier]; 76 return result == NSOrderedSame; 77} 78 79// Returns true if |identifier| is the bundle id of the default client 80// application for the given protocol. 81bool IsIdentifierDefaultProtocolClient(NSString* identifier, 82 NSString* protocol) { 83 CFStringRef default_client_cf = 84 LSCopyDefaultHandlerForURLScheme(base::mac::NSToCFCast(protocol)); 85 NSString* default_client = static_cast<NSString*>( 86 base::mac::CFTypeRefToNSObjectAutorelease(default_client_cf)); 87 if (!default_client) 88 return false; 89 90 // We need to ensure we do the comparison case-insensitive as LS doesn't 91 // persist the case of our bundle id. 92 NSComparisonResult result = 93 [default_client caseInsensitiveCompare:identifier]; 94 return result == NSOrderedSame; 95} 96 97} // namespace 98 99// Attempt to determine if this instance of Chrome is the default browser and 100// return the appropriate state. (Defined as being the handler for HTTP/HTTPS 101// protocols; we don't want to report "no" here if the user has simply chosen 102// to open HTML files in a text editor and FTP links with an FTP client.) 103ShellIntegration::DefaultWebClientState ShellIntegration::GetDefaultBrowser() { 104 // We really do want the outer bundle here, since this we want to know the 105 // status of the main Chrome bundle and not a shortcut. 106 NSString* my_identifier = [base::mac::OuterBundle() bundleIdentifier]; 107 if (!my_identifier) 108 return UNKNOWN_DEFAULT; 109 110 return IsIdentifierDefaultBrowser(my_identifier) ? IS_DEFAULT : NOT_DEFAULT; 111} 112 113// Returns true if Firefox is the default browser for the current user. 114bool ShellIntegration::IsFirefoxDefaultBrowser() { 115 return IsIdentifierDefaultBrowser(@"org.mozilla.firefox"); 116} 117 118// Attempt to determine if this instance of Chrome is the default client 119// application for the given protocol and return the appropriate state. 120ShellIntegration::DefaultWebClientState 121 ShellIntegration::IsDefaultProtocolClient(const std::string& protocol) { 122 if (protocol.empty()) 123 return UNKNOWN_DEFAULT; 124 125 // We really do want the main bundle here since it makes sense to set an 126 // app shortcut as a default protocol handler. 127 NSString* my_identifier = [base::mac::MainBundle() bundleIdentifier]; 128 if (!my_identifier) 129 return UNKNOWN_DEFAULT; 130 131 NSString* protocol_ns = [NSString stringWithUTF8String:protocol.c_str()]; 132 return IsIdentifierDefaultProtocolClient(my_identifier, protocol_ns) ? 133 IS_DEFAULT : NOT_DEFAULT; 134} 135