Home | History | Annotate | Download | only in browser
      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 
     13 ShellIntegration::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.
     26 bool 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.
     43 bool 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 
     63 namespace {
     64 
     65 // Returns true if |identifier| is the bundle id of the default browser.
     66 bool 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.
     81 bool 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.)
    103 ShellIntegration::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.
    114 bool 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.
    120 ShellIntegration::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