Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/platform_util.h" | 5 #include "chrome/browser/platform_util.h" |
| 6 | 6 |
| 7 #include <Carbon/Carbon.h> | 7 #include <Carbon/Carbon.h> |
| 8 #import <Cocoa/Cocoa.h> | 8 #import <Cocoa/Cocoa.h> |
| 9 #include <CoreServices/CoreServices.h> | 9 #include <CoreServices/CoreServices.h> |
| 10 | 10 |
| 11 #include "base/bind.h" | |
| 12 #include "base/files/file_util.h" | |
| 11 #include "base/files/file_path.h" | 13 #include "base/files/file_path.h" |
| 12 #include "base/logging.h" | 14 #include "base/logging.h" |
| 13 #include "base/mac/mac_logging.h" | 15 #include "base/mac/mac_logging.h" |
| 14 #import "base/mac/mac_util.h" | 16 #import "base/mac/mac_util.h" |
| 15 #import "base/mac/sdk_forward_declarations.h" | 17 #import "base/mac/sdk_forward_declarations.h" |
| 16 #include "base/mac/scoped_aedesc.h" | 18 #include "base/mac/scoped_aedesc.h" |
| 17 #include "base/strings/sys_string_conversions.h" | 19 #include "base/strings/sys_string_conversions.h" |
| 20 #include "chrome/browser/platform_util_internal.h" | |
| 21 #include "content/public/browser/browser_thread.h" | |
| 18 #include "url/gurl.h" | 22 #include "url/gurl.h" |
| 19 | 23 |
| 20 namespace platform_util { | 24 namespace platform_util { |
| 21 | 25 |
| 22 void ShowItemInFolder(Profile* profile, const base::FilePath& full_path) { | 26 void ShowItemInFolder(Profile* profile, const base::FilePath& full_path) { |
| 23 DCHECK([NSThread isMainThread]); | 27 DCHECK([NSThread isMainThread]); |
| 24 NSString* path_string = base::SysUTF8ToNSString(full_path.value()); | 28 NSString* path_string = base::SysUTF8ToNSString(full_path.value()); |
| 25 if (!path_string || ![[NSWorkspace sharedWorkspace] selectFile:path_string | 29 if (!path_string || ![[NSWorkspace sharedWorkspace] selectFile:path_string |
| 26 inFileViewerRootedAtPath:nil]) | 30 inFileViewerRootedAtPath:nil]) |
| 27 LOG(WARNING) << "NSWorkspace failed to select file " << full_path.value(); | 31 LOG(WARNING) << "NSWorkspace failed to select file " << full_path.value(); |
| 28 } | 32 } |
| 29 | 33 |
| 30 void OpenItem(Profile* profile, const base::FilePath& full_path) { | 34 // This function opens a file. This doesn't use LaunchServices or NSWorkspace |
|
Robert Sesek
2015/02/05 00:52:29
This comment isn't accurate anymore (c.f. lines 47
asanka
2015/02/05 18:07:25
Comment removed.
| |
| 35 // because of two bugs: | |
| 36 // 1. Incorrect app activation with com.apple.quarantine: | |
| 37 // http://crbug.com/32921 | |
| 38 // 2. Silent no-op for unassociated file types: http://crbug.com/50263 | |
| 39 // Instead, an AppleEvent is constructed to tell the Finder to open the | |
| 40 // document. | |
| 41 void OpenFileOnMainThread(const base::FilePath& full_path) { | |
| 31 DCHECK([NSThread isMainThread]); | 42 DCHECK([NSThread isMainThread]); |
| 32 NSString* path_string = base::SysUTF8ToNSString(full_path.value()); | 43 NSString* path_string = base::SysUTF8ToNSString(full_path.value()); |
| 33 if (!path_string) | 44 if (!path_string) |
| 34 return; | 45 return; |
| 35 | 46 |
| 36 // On Mavericks or later, NSWorkspaceLaunchWithErrorPresentation will | 47 // On Mavericks or later, NSWorkspaceLaunchWithErrorPresentation will |
| 37 // properly handle Finder activation for quarantined files | 48 // properly handle Finder activation for quarantined files |
| 38 // (http://crbug.com/32921) and unassociated file types | 49 // (http://crbug.com/32921) and unassociated file types |
| 39 // (http://crbug.com/50263). | 50 // (http://crbug.com/50263). |
| 40 if (base::mac::IsOSMavericksOrLater()) { | 51 if (base::mac::IsOSMavericksOrLater()) { |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 57 // instruct the Finder to open the file. | 68 // instruct the Finder to open the file. |
| 58 | 69 |
| 59 // Create the target of this AppleEvent, the Finder. | 70 // Create the target of this AppleEvent, the Finder. |
| 60 base::mac::ScopedAEDesc<AEAddressDesc> address; | 71 base::mac::ScopedAEDesc<AEAddressDesc> address; |
| 61 const OSType finderCreatorCode = 'MACS'; | 72 const OSType finderCreatorCode = 'MACS'; |
| 62 OSErr status = AECreateDesc(typeApplSignature, // type | 73 OSErr status = AECreateDesc(typeApplSignature, // type |
| 63 &finderCreatorCode, // data | 74 &finderCreatorCode, // data |
| 64 sizeof(finderCreatorCode), // dataSize | 75 sizeof(finderCreatorCode), // dataSize |
| 65 address.OutPointer()); // result | 76 address.OutPointer()); // result |
| 66 if (status != noErr) { | 77 if (status != noErr) { |
| 67 OSSTATUS_LOG(WARNING, status) << "Could not create OpenItem() AE target"; | 78 OSSTATUS_LOG(WARNING, status) << "Could not create OpenFile() AE target"; |
| 68 return; | 79 return; |
| 69 } | 80 } |
| 70 | 81 |
| 71 // Build the AppleEvent data structure that instructs Finder to open files. | 82 // Build the AppleEvent data structure that instructs Finder to open files. |
| 72 base::mac::ScopedAEDesc<AppleEvent> theEvent; | 83 base::mac::ScopedAEDesc<AppleEvent> theEvent; |
| 73 status = AECreateAppleEvent(kCoreEventClass, // theAEEventClass | 84 status = AECreateAppleEvent(kCoreEventClass, // theAEEventClass |
| 74 kAEOpenDocuments, // theAEEventID | 85 kAEOpenDocuments, // theAEEventID |
| 75 address, // target | 86 address, // target |
| 76 kAutoGenerateReturnID, // returnID | 87 kAutoGenerateReturnID, // returnID |
| 77 kAnyTransactionID, // transactionID | 88 kAnyTransactionID, // transactionID |
| 78 theEvent.OutPointer()); // result | 89 theEvent.OutPointer()); // result |
| 79 if (status != noErr) { | 90 if (status != noErr) { |
| 80 OSSTATUS_LOG(WARNING, status) << "Could not create OpenItem() AE event"; | 91 OSSTATUS_LOG(WARNING, status) << "Could not create OpenFile() AE event"; |
| 81 return; | 92 return; |
| 82 } | 93 } |
| 83 | 94 |
| 84 // Create the list of files (only ever one) to open. | 95 // Create the list of files (only ever one) to open. |
| 85 base::mac::ScopedAEDesc<AEDescList> fileList; | 96 base::mac::ScopedAEDesc<AEDescList> fileList; |
| 86 status = AECreateList(NULL, // factoringPtr | 97 status = AECreateList(NULL, // factoringPtr |
| 87 0, // factoredSize | 98 0, // factoredSize |
| 88 false, // isRecord | 99 false, // isRecord |
| 89 fileList.OutPointer()); // resultList | 100 fileList.OutPointer()); // resultList |
| 90 if (status != noErr) { | 101 if (status != noErr) { |
| 91 OSSTATUS_LOG(WARNING, status) << "Could not create OpenItem() AE file list"; | 102 OSSTATUS_LOG(WARNING, status) << "Could not create OpenFile() AE file list"; |
| 92 return; | 103 return; |
| 93 } | 104 } |
| 94 | 105 |
| 95 // Add the single path to the file list. C-style cast to avoid both a | 106 // Add the single path to the file list. C-style cast to avoid both a |
| 96 // static_cast and a const_cast to get across the toll-free bridge. | 107 // static_cast and a const_cast to get across the toll-free bridge. |
| 97 CFURLRef pathURLRef = (CFURLRef)[NSURL fileURLWithPath:path_string]; | 108 CFURLRef pathURLRef = (CFURLRef)[NSURL fileURLWithPath:path_string]; |
| 98 FSRef pathRef; | 109 FSRef pathRef; |
| 99 if (CFURLGetFSRef(pathURLRef, &pathRef)) { | 110 if (CFURLGetFSRef(pathURLRef, &pathRef)) { |
| 100 status = AEPutPtr(fileList.OutPointer(), // theAEDescList | 111 status = AEPutPtr(fileList.OutPointer(), // theAEDescList |
| 101 0, // index | 112 0, // index |
| 102 typeFSRef, // typeCode | 113 typeFSRef, // typeCode |
| 103 &pathRef, // dataPtr | 114 &pathRef, // dataPtr |
| 104 sizeof(pathRef)); // dataSize | 115 sizeof(pathRef)); // dataSize |
| 105 if (status != noErr) { | 116 if (status != noErr) { |
| 106 OSSTATUS_LOG(WARNING, status) | 117 OSSTATUS_LOG(WARNING, status) |
| 107 << "Could not add file path to AE list in OpenItem()"; | 118 << "Could not add file path to AE list in OpenFile()"; |
| 108 return; | 119 return; |
| 109 } | 120 } |
| 110 } else { | 121 } else { |
| 111 LOG(WARNING) << "Could not get FSRef for path URL in OpenItem()"; | 122 LOG(WARNING) << "Could not get FSRef for path URL in OpenFile()"; |
| 112 return; | 123 return; |
| 113 } | 124 } |
| 114 | 125 |
| 115 // Attach the file list to the AppleEvent. | 126 // Attach the file list to the AppleEvent. |
| 116 status = AEPutParamDesc(theEvent.OutPointer(), // theAppleEvent | 127 status = AEPutParamDesc(theEvent.OutPointer(), // theAppleEvent |
| 117 keyDirectObject, // theAEKeyword | 128 keyDirectObject, // theAEKeyword |
| 118 fileList); // theAEDesc | 129 fileList); // theAEDesc |
| 119 if (status != noErr) { | 130 if (status != noErr) { |
| 120 OSSTATUS_LOG(WARNING, status) | 131 OSSTATUS_LOG(WARNING, status) |
| 121 << "Could not put the AE file list the path in OpenItem()"; | 132 << "Could not put the AE file list the path in OpenFile()"; |
| 122 return; | 133 return; |
| 123 } | 134 } |
| 124 | 135 |
| 125 // Send the actual event. Do not care about the reply. | 136 // Send the actual event. Do not care about the reply. |
| 126 base::mac::ScopedAEDesc<AppleEvent> reply; | 137 base::mac::ScopedAEDesc<AppleEvent> reply; |
| 127 status = AESend(theEvent, // theAppleEvent | 138 status = AESend(theEvent, // theAppleEvent |
| 128 reply.OutPointer(), // reply | 139 reply.OutPointer(), // reply |
| 129 kAENoReply + kAEAlwaysInteract, // sendMode | 140 kAENoReply + kAEAlwaysInteract, // sendMode |
| 130 kAENormalPriority, // sendPriority | 141 kAENormalPriority, // sendPriority |
| 131 kAEDefaultTimeout, // timeOutInTicks | 142 kAEDefaultTimeout, // timeOutInTicks |
| 132 NULL, // idleProc | 143 NULL, // idleProc |
| 133 NULL); // filterProc | 144 NULL); // filterProc |
| 134 if (status != noErr) { | 145 if (status != noErr) { |
| 135 OSSTATUS_LOG(WARNING, status) | 146 OSSTATUS_LOG(WARNING, status) |
| 136 << "Could not send AE to Finder in OpenItem()"; | 147 << "Could not send AE to Finder in OpenFile()"; |
| 137 } | 148 } |
| 138 } | 149 } |
| 139 | 150 |
| 151 namespace internal { | |
| 152 | |
| 153 void PlatformOpenVerifiedItem(const base::FilePath& path, OpenItemType type) { | |
| 154 switch (type) { | |
| 155 case OPEN_FILE: | |
| 156 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, | |
| 157 base::Bind(&OpenFileOnMainThread, path)); | |
| 158 return; | |
| 159 case OPEN_FOLDER: | |
| 160 NSString* path_string = base::SysUTF8ToNSString(path.value()); | |
| 161 if (!path_string) | |
| 162 return; | |
| 163 [[NSWorkspace sharedWorkspace] openFile:path_string | |
|
Robert Sesek
2015/02/05 00:52:29
Does:
NSURL* url = [NSURL fileURLWithPath:path_
asanka
2015/02/05 18:07:25
I tried this, but it doesn't have the intended eff
Robert Sesek
2015/02/05 23:37:55
I think the only difference between this method an
| |
| 164 withApplication:@"Finder"]; | |
| 165 return; | |
| 166 } | |
| 167 } | |
| 168 } | |
|
Robert Sesek
2015/02/05 00:52:29
nit: blank line before, and " // namespace intern
asanka
2015/02/05 18:07:25
Done.
| |
| 169 | |
| 140 void OpenExternal(Profile* profile, const GURL& url) { | 170 void OpenExternal(Profile* profile, const GURL& url) { |
| 141 DCHECK([NSThread isMainThread]); | 171 DCHECK([NSThread isMainThread]); |
| 142 NSString* url_string = base::SysUTF8ToNSString(url.spec()); | 172 NSString* url_string = base::SysUTF8ToNSString(url.spec()); |
| 143 NSURL* ns_url = [NSURL URLWithString:url_string]; | 173 NSURL* ns_url = [NSURL URLWithString:url_string]; |
| 144 if (!ns_url || ![[NSWorkspace sharedWorkspace] openURL:ns_url]) | 174 if (!ns_url || ![[NSWorkspace sharedWorkspace] openURL:ns_url]) |
| 145 LOG(WARNING) << "NSWorkspace failed to open URL " << url; | 175 LOG(WARNING) << "NSWorkspace failed to open URL " << url; |
| 146 } | 176 } |
| 147 | 177 |
| 148 gfx::NativeWindow GetTopLevel(gfx::NativeView view) { | 178 gfx::NativeWindow GetTopLevel(gfx::NativeView view) { |
| 149 return [view window]; | 179 return [view window]; |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 175 [[view window] isVisible]); | 205 [[view window] isVisible]); |
| 176 } | 206 } |
| 177 | 207 |
| 178 bool IsSwipeTrackingFromScrollEventsEnabled() { | 208 bool IsSwipeTrackingFromScrollEventsEnabled() { |
| 179 SEL selector = @selector(isSwipeTrackingFromScrollEventsEnabled); | 209 SEL selector = @selector(isSwipeTrackingFromScrollEventsEnabled); |
| 180 return [NSEvent respondsToSelector:selector] | 210 return [NSEvent respondsToSelector:selector] |
| 181 && [NSEvent performSelector:selector]; | 211 && [NSEvent performSelector:selector]; |
| 182 } | 212 } |
| 183 | 213 |
| 184 } // namespace platform_util | 214 } // namespace platform_util |
| OLD | NEW |