| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2010 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 // On Mac, shortcuts can't have command-line arguments. Instead, produce small |
| 6 // app bundles which locate the Chromium framework and load it, passing the |
| 7 // appropriate data. This is the code for such an app bundle. It should be kept |
| 8 // minimal and do as little work as possible (with as much work done on |
| 9 // framework side as possible). |
| 10 |
| 11 #include <dlfcn.h> |
| 12 #include <stdio.h> |
| 13 #include <stdlib.h> |
| 14 #include <string.h> |
| 15 |
| 16 #include <CoreFoundation/CoreFoundation.h> |
| 17 #import <Foundation/Foundation.h> |
| 18 |
| 19 #include "chrome/common/app_mode_common_mac.h" |
| 20 |
| 21 namespace { |
| 22 |
| 23 // Checks that condition |x| is true. If not, outputs |msg| (together with |
| 24 // source filename and line number) and exits. |
| 25 #define CHECK_MSG(x, msg) if (!(x)) check_msg_helper(__FILE__, __LINE__, msg); |
| 26 void check_msg_helper(const char* file, int line, const char* msg) { |
| 27 fprintf(stderr, "%s (%d): %s\n", file, line, msg); |
| 28 exit(1); |
| 29 } |
| 30 |
| 31 // Converts an NSString to a UTF8 C string (which is allocated, and may be freed |
| 32 // using |free()|). If |s| is nil or can't produce such a string, this returns |
| 33 // |NULL|. |
| 34 char* NSStringToUTF8CString(NSString* s) { |
| 35 CHECK_MSG([s isKindOfClass:[NSString class]], "expected an NSString"); |
| 36 const char* cstring = [s UTF8String]; |
| 37 return cstring ? strdup(cstring) : NULL; |
| 38 } |
| 39 |
| 40 // Converts an NSString to a file-system representation C string (which is |
| 41 // allocated, and may be freed using |free()|). If |s| is nil or can't produce |
| 42 // such a string, this returns |NULL|. |
| 43 char* NSStringToFSCString(NSString* s) { |
| 44 CHECK_MSG([s isKindOfClass:[NSString class]], "expected an NSString"); |
| 45 const char* cstring = [s fileSystemRepresentation]; |
| 46 return cstring ? strdup(cstring) : NULL; |
| 47 } |
| 48 |
| 49 } // namespace |
| 50 |
| 51 __attribute__((visibility("default"))) |
| 52 int main(int argc, char** argv) { |
| 53 app_mode::ChromeAppModeInfo info; |
| 54 info.major_version = 0; // v0.1 |
| 55 info.minor_version = 1; |
| 56 info.argc = argc; |
| 57 info.argv = argv; |
| 58 |
| 59 // The Cocoa APIs are a bit more convenient; for this an autorelease pool is |
| 60 // needed. |
| 61 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
| 62 |
| 63 // Get the browser bundle path. |
| 64 // TODO(viettrungluu): more fun |
| 65 NSString* cr_bundle_path = |
| 66 [(NSString*)CFPreferencesCopyAppValue( |
| 67 app_mode::kLastRunAppBundlePathPrefsKey, |
| 68 app_mode::kAppPrefsID) autorelease]; |
| 69 CHECK_MSG(cr_bundle_path, "couldn't get browser bundle path"); |
| 70 |
| 71 // Get the browser bundle. |
| 72 NSBundle* cr_bundle = [NSBundle bundleWithPath:cr_bundle_path]; |
| 73 CHECK_MSG(cr_bundle, "couldn't get browser bundle"); |
| 74 |
| 75 // Get the current browser version. |
| 76 NSString* cr_version = |
| 77 [cr_bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; |
| 78 CHECK_MSG(cr_version, "couldn't get browser version"); |
| 79 |
| 80 // Get the current browser versioned directory. |
| 81 NSArray* cr_versioned_path_components = |
| 82 [NSArray arrayWithObjects:cr_bundle_path, |
| 83 @"Contents", |
| 84 @"Versions", |
| 85 cr_version, |
| 86 nil]; |
| 87 NSString* cr_versioned_path = |
| 88 [[NSString pathWithComponents:cr_versioned_path_components] |
| 89 stringByStandardizingPath]; |
| 90 CHECK_MSG(cr_versioned_path, "couldn't get browser versioned path"); |
| 91 // And copy it, since |cr_versioned_path| will go away with the pool. |
| 92 info.chrome_versioned_path = NSStringToFSCString(cr_versioned_path); |
| 93 |
| 94 // Get the current main bundle, i.e., that of the app loader that's running. |
| 95 NSBundle* app_bundle = [NSBundle mainBundle]; |
| 96 CHECK_MSG(app_bundle, "couldn't get loader bundle"); |
| 97 // Optional, so okay if it's NULL. |
| 98 info.app_mode_bundle_path = NSStringToFSCString([app_bundle bundlePath]); |
| 99 |
| 100 // Read information about the this app shortcut from the Info.plist. |
| 101 // Don't check for null-ness on optional items. |
| 102 NSDictionary* info_plist = [app_bundle infoDictionary]; |
| 103 CHECK_MSG(info_plist, "couldn't get loader Info.plist"); |
| 104 |
| 105 info.app_mode_id = NSStringToUTF8CString( |
| 106 [info_plist objectForKey:@"CrAppModeShortcutID"]); |
| 107 CHECK_MSG(info.app_mode_id, "couldn't get app shortcut ID"); |
| 108 |
| 109 info.app_mode_short_name = NSStringToUTF8CString( |
| 110 [info_plist objectForKey:@"CrAppModeShortcutShortName"]); |
| 111 |
| 112 info.app_mode_name = NSStringToUTF8CString( |
| 113 [info_plist objectForKey:@"CrAppModeShortcutName"]); |
| 114 |
| 115 info.app_mode_url = NSStringToUTF8CString( |
| 116 [info_plist objectForKey:@"CrAppModeShortcutURL"]); |
| 117 CHECK_MSG(info.app_mode_url, "couldn't get app shortcut URL"); |
| 118 |
| 119 // Get the framework path. |
| 120 NSString* cr_bundle_exe = |
| 121 [cr_bundle objectForInfoDictionaryKey:@"CFBundleExecutable"]; |
| 122 NSString* cr_framework_path = |
| 123 [cr_versioned_path stringByAppendingPathComponent: |
| 124 [cr_bundle_exe stringByAppendingString:@" Framework.framework"]]; |
| 125 cr_framework_path = |
| 126 [cr_framework_path stringByAppendingPathComponent: |
| 127 [cr_bundle_exe stringByAppendingString:@" Framework"]]; |
| 128 |
| 129 // Open the framework. |
| 130 void* cr_dylib = dlopen([cr_framework_path fileSystemRepresentation], |
| 131 RTLD_LAZY); |
| 132 CHECK_MSG(cr_dylib, "couldn't load framework"); |
| 133 |
| 134 // Drain the pool as late as possible. |
| 135 [pool drain]; |
| 136 |
| 137 typedef int (*StartFun)(const app_mode::ChromeAppModeInfo*); |
| 138 StartFun ChromeAppModeStart = (StartFun)dlsym(cr_dylib, "ChromeAppModeStart"); |
| 139 CHECK_MSG(ChromeAppModeStart, "couldn't get entry point"); |
| 140 |
| 141 // Exit instead of returning to avoid the the removal of |main()| from stack |
| 142 // backtraces under tail call optimization. |
| 143 int rv = ChromeAppModeStart(&info); |
| 144 exit(rv); |
| 145 } |
| OLD | NEW |