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 void OpenFileOnMainThread(const base::FilePath& full_path) { |
31 DCHECK([NSThread isMainThread]); | 35 DCHECK([NSThread isMainThread]); |
32 NSString* path_string = base::SysUTF8ToNSString(full_path.value()); | 36 NSString* path_string = base::SysUTF8ToNSString(full_path.value()); |
33 if (!path_string) | 37 if (!path_string) |
34 return; | 38 return; |
35 | 39 |
36 // On Mavericks or later, NSWorkspaceLaunchWithErrorPresentation will | 40 // On Mavericks or later, NSWorkspaceLaunchWithErrorPresentation will |
37 // properly handle Finder activation for quarantined files | 41 // properly handle Finder activation for quarantined files |
38 // (http://crbug.com/32921) and unassociated file types | 42 // (http://crbug.com/32921) and unassociated file types |
39 // (http://crbug.com/50263). | 43 // (http://crbug.com/50263). |
40 if (base::mac::IsOSMavericksOrLater()) { | 44 if (base::mac::IsOSMavericksOrLater()) { |
(...skipping 16 matching lines...) Expand all Loading... |
57 // instruct the Finder to open the file. | 61 // instruct the Finder to open the file. |
58 | 62 |
59 // Create the target of this AppleEvent, the Finder. | 63 // Create the target of this AppleEvent, the Finder. |
60 base::mac::ScopedAEDesc<AEAddressDesc> address; | 64 base::mac::ScopedAEDesc<AEAddressDesc> address; |
61 const OSType finderCreatorCode = 'MACS'; | 65 const OSType finderCreatorCode = 'MACS'; |
62 OSErr status = AECreateDesc(typeApplSignature, // type | 66 OSErr status = AECreateDesc(typeApplSignature, // type |
63 &finderCreatorCode, // data | 67 &finderCreatorCode, // data |
64 sizeof(finderCreatorCode), // dataSize | 68 sizeof(finderCreatorCode), // dataSize |
65 address.OutPointer()); // result | 69 address.OutPointer()); // result |
66 if (status != noErr) { | 70 if (status != noErr) { |
67 OSSTATUS_LOG(WARNING, status) << "Could not create OpenItem() AE target"; | 71 OSSTATUS_LOG(WARNING, status) << "Could not create OpenFile() AE target"; |
68 return; | 72 return; |
69 } | 73 } |
70 | 74 |
71 // Build the AppleEvent data structure that instructs Finder to open files. | 75 // Build the AppleEvent data structure that instructs Finder to open files. |
72 base::mac::ScopedAEDesc<AppleEvent> theEvent; | 76 base::mac::ScopedAEDesc<AppleEvent> theEvent; |
73 status = AECreateAppleEvent(kCoreEventClass, // theAEEventClass | 77 status = AECreateAppleEvent(kCoreEventClass, // theAEEventClass |
74 kAEOpenDocuments, // theAEEventID | 78 kAEOpenDocuments, // theAEEventID |
75 address, // target | 79 address, // target |
76 kAutoGenerateReturnID, // returnID | 80 kAutoGenerateReturnID, // returnID |
77 kAnyTransactionID, // transactionID | 81 kAnyTransactionID, // transactionID |
78 theEvent.OutPointer()); // result | 82 theEvent.OutPointer()); // result |
79 if (status != noErr) { | 83 if (status != noErr) { |
80 OSSTATUS_LOG(WARNING, status) << "Could not create OpenItem() AE event"; | 84 OSSTATUS_LOG(WARNING, status) << "Could not create OpenFile() AE event"; |
81 return; | 85 return; |
82 } | 86 } |
83 | 87 |
84 // Create the list of files (only ever one) to open. | 88 // Create the list of files (only ever one) to open. |
85 base::mac::ScopedAEDesc<AEDescList> fileList; | 89 base::mac::ScopedAEDesc<AEDescList> fileList; |
86 status = AECreateList(NULL, // factoringPtr | 90 status = AECreateList(NULL, // factoringPtr |
87 0, // factoredSize | 91 0, // factoredSize |
88 false, // isRecord | 92 false, // isRecord |
89 fileList.OutPointer()); // resultList | 93 fileList.OutPointer()); // resultList |
90 if (status != noErr) { | 94 if (status != noErr) { |
91 OSSTATUS_LOG(WARNING, status) << "Could not create OpenItem() AE file list"; | 95 OSSTATUS_LOG(WARNING, status) << "Could not create OpenFile() AE file list"; |
92 return; | 96 return; |
93 } | 97 } |
94 | 98 |
95 // Add the single path to the file list. C-style cast to avoid both a | 99 // 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. | 100 // static_cast and a const_cast to get across the toll-free bridge. |
97 CFURLRef pathURLRef = (CFURLRef)[NSURL fileURLWithPath:path_string]; | 101 CFURLRef pathURLRef = (CFURLRef)[NSURL fileURLWithPath:path_string]; |
98 FSRef pathRef; | 102 FSRef pathRef; |
99 if (CFURLGetFSRef(pathURLRef, &pathRef)) { | 103 if (CFURLGetFSRef(pathURLRef, &pathRef)) { |
100 status = AEPutPtr(fileList.OutPointer(), // theAEDescList | 104 status = AEPutPtr(fileList.OutPointer(), // theAEDescList |
101 0, // index | 105 0, // index |
102 typeFSRef, // typeCode | 106 typeFSRef, // typeCode |
103 &pathRef, // dataPtr | 107 &pathRef, // dataPtr |
104 sizeof(pathRef)); // dataSize | 108 sizeof(pathRef)); // dataSize |
105 if (status != noErr) { | 109 if (status != noErr) { |
106 OSSTATUS_LOG(WARNING, status) | 110 OSSTATUS_LOG(WARNING, status) |
107 << "Could not add file path to AE list in OpenItem()"; | 111 << "Could not add file path to AE list in OpenFile()"; |
108 return; | 112 return; |
109 } | 113 } |
110 } else { | 114 } else { |
111 LOG(WARNING) << "Could not get FSRef for path URL in OpenItem()"; | 115 LOG(WARNING) << "Could not get FSRef for path URL in OpenFile()"; |
112 return; | 116 return; |
113 } | 117 } |
114 | 118 |
115 // Attach the file list to the AppleEvent. | 119 // Attach the file list to the AppleEvent. |
116 status = AEPutParamDesc(theEvent.OutPointer(), // theAppleEvent | 120 status = AEPutParamDesc(theEvent.OutPointer(), // theAppleEvent |
117 keyDirectObject, // theAEKeyword | 121 keyDirectObject, // theAEKeyword |
118 fileList); // theAEDesc | 122 fileList); // theAEDesc |
119 if (status != noErr) { | 123 if (status != noErr) { |
120 OSSTATUS_LOG(WARNING, status) | 124 OSSTATUS_LOG(WARNING, status) |
121 << "Could not put the AE file list the path in OpenItem()"; | 125 << "Could not put the AE file list the path in OpenFile()"; |
122 return; | 126 return; |
123 } | 127 } |
124 | 128 |
125 // Send the actual event. Do not care about the reply. | 129 // Send the actual event. Do not care about the reply. |
126 base::mac::ScopedAEDesc<AppleEvent> reply; | 130 base::mac::ScopedAEDesc<AppleEvent> reply; |
127 status = AESend(theEvent, // theAppleEvent | 131 status = AESend(theEvent, // theAppleEvent |
128 reply.OutPointer(), // reply | 132 reply.OutPointer(), // reply |
129 kAENoReply + kAEAlwaysInteract, // sendMode | 133 kAENoReply + kAEAlwaysInteract, // sendMode |
130 kAENormalPriority, // sendPriority | 134 kAENormalPriority, // sendPriority |
131 kAEDefaultTimeout, // timeOutInTicks | 135 kAEDefaultTimeout, // timeOutInTicks |
132 NULL, // idleProc | 136 NULL, // idleProc |
133 NULL); // filterProc | 137 NULL); // filterProc |
134 if (status != noErr) { | 138 if (status != noErr) { |
135 OSSTATUS_LOG(WARNING, status) | 139 OSSTATUS_LOG(WARNING, status) |
136 << "Could not send AE to Finder in OpenItem()"; | 140 << "Could not send AE to Finder in OpenFile()"; |
137 } | 141 } |
138 } | 142 } |
139 | 143 |
| 144 namespace internal { |
| 145 |
| 146 void PlatformOpenVerifiedItem(const base::FilePath& path, OpenItemType type) { |
| 147 switch (type) { |
| 148 case OPEN_FILE: |
| 149 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, |
| 150 base::Bind(&OpenFileOnMainThread, path)); |
| 151 return; |
| 152 case OPEN_FOLDER: |
| 153 NSString* path_string = base::SysUTF8ToNSString(path.value()); |
| 154 if (!path_string) |
| 155 return; |
| 156 // Note that there exists a TOCTOU race between the time that |path| was |
| 157 // verified as being a directory and when NSWorkspace invokes Finder (or |
| 158 // alternative) to open |path_string|. |
| 159 [[NSWorkspace sharedWorkspace] openFile:path_string]; |
| 160 return; |
| 161 } |
| 162 } |
| 163 |
| 164 } // namespace internal |
| 165 |
140 void OpenExternal(Profile* profile, const GURL& url) { | 166 void OpenExternal(Profile* profile, const GURL& url) { |
141 DCHECK([NSThread isMainThread]); | 167 DCHECK([NSThread isMainThread]); |
142 NSString* url_string = base::SysUTF8ToNSString(url.spec()); | 168 NSString* url_string = base::SysUTF8ToNSString(url.spec()); |
143 NSURL* ns_url = [NSURL URLWithString:url_string]; | 169 NSURL* ns_url = [NSURL URLWithString:url_string]; |
144 if (!ns_url || ![[NSWorkspace sharedWorkspace] openURL:ns_url]) | 170 if (!ns_url || ![[NSWorkspace sharedWorkspace] openURL:ns_url]) |
145 LOG(WARNING) << "NSWorkspace failed to open URL " << url; | 171 LOG(WARNING) << "NSWorkspace failed to open URL " << url; |
146 } | 172 } |
147 | 173 |
148 gfx::NativeWindow GetTopLevel(gfx::NativeView view) { | 174 gfx::NativeWindow GetTopLevel(gfx::NativeView view) { |
149 return [view window]; | 175 return [view window]; |
(...skipping 25 matching lines...) Expand all Loading... |
175 [[view window] isVisible]); | 201 [[view window] isVisible]); |
176 } | 202 } |
177 | 203 |
178 bool IsSwipeTrackingFromScrollEventsEnabled() { | 204 bool IsSwipeTrackingFromScrollEventsEnabled() { |
179 SEL selector = @selector(isSwipeTrackingFromScrollEventsEnabled); | 205 SEL selector = @selector(isSwipeTrackingFromScrollEventsEnabled); |
180 return [NSEvent respondsToSelector:selector] | 206 return [NSEvent respondsToSelector:selector] |
181 && [NSEvent performSelector:selector]; | 207 && [NSEvent performSelector:selector]; |
182 } | 208 } |
183 | 209 |
184 } // namespace platform_util | 210 } // namespace platform_util |
OLD | NEW |