| 
									
										
										
										
											2014-10-31 11:17:05 -07:00
										 |  |  | // Copyright (c) 2013 GitHub, Inc. | 
					
						
							| 
									
										
										
										
											2014-04-25 17:49:37 +08:00
										 |  |  | // Use of this source code is governed by the MIT license that can be | 
					
						
							| 
									
										
										
										
											2013-04-29 20:41:11 +08:00
										 |  |  | // found in the LICENSE file. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-16 08:30:26 +08:00
										 |  |  | #include "atom/common/platform_util.h" | 
					
						
							| 
									
										
										
										
											2013-04-29 20:41:11 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <Carbon/Carbon.h> | 
					
						
							|  |  |  | #import <Cocoa/Cocoa.h> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "base/files/file_path.h" | 
					
						
							| 
									
										
										
										
											2016-06-20 21:14:17 +09:00
										 |  |  | #include "base/files/file_util.h" | 
					
						
							| 
									
										
										
										
											2013-04-29 20:41:11 +08:00
										 |  |  | #include "base/logging.h" | 
					
						
							|  |  |  | #include "base/mac/mac_logging.h" | 
					
						
							|  |  |  | #include "base/mac/scoped_aedesc.h" | 
					
						
							|  |  |  | #include "base/strings/sys_string_conversions.h" | 
					
						
							| 
									
										
										
										
											2015-12-24 12:43:07 +08:00
										 |  |  | #include "net/base/mac/url_conversions.h" | 
					
						
							| 
									
										
										
										
											2013-12-11 15:48:19 +08:00
										 |  |  | #include "url/gurl.h" | 
					
						
							| 
									
										
										
										
											2013-04-29 20:41:11 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace platform_util { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-12 14:22:29 -07:00
										 |  |  | bool ShowItemInFolder(const base::FilePath& path) { | 
					
						
							| 
									
										
										
										
											2016-06-20 21:14:17 +09:00
										 |  |  |   // The API only takes absolute path. | 
					
						
							|  |  |  |   base::FilePath full_path = | 
					
						
							|  |  |  |       path.IsAbsolute() ? path : base::MakeAbsoluteFilePath(path); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-29 20:41:11 +08:00
										 |  |  |   DCHECK([NSThread isMainThread]); | 
					
						
							|  |  |  |   NSString* path_string = base::SysUTF8ToNSString(full_path.value()); | 
					
						
							|  |  |  |   if (!path_string || ![[NSWorkspace sharedWorkspace] selectFile:path_string | 
					
						
							| 
									
										
										
										
											2016-09-12 14:22:29 -07:00
										 |  |  |                                         inFileViewerRootedAtPath:@""]) { | 
					
						
							| 
									
										
										
										
											2013-04-29 20:41:11 +08:00
										 |  |  |     LOG(WARNING) << "NSWorkspace failed to select file " << full_path.value(); | 
					
						
							| 
									
										
										
										
											2016-09-12 14:22:29 -07:00
										 |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2013-04-29 20:41:11 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This function opens a file.  This doesn't use LaunchServices or NSWorkspace | 
					
						
							|  |  |  | // because of two bugs: | 
					
						
							|  |  |  | //  1. Incorrect app activation with com.apple.quarantine: | 
					
						
							|  |  |  | //     http://crbug.com/32921 | 
					
						
							|  |  |  | //  2. Silent no-op for unassociated file types: http://crbug.com/50263 | 
					
						
							|  |  |  | // Instead, an AppleEvent is constructed to tell the Finder to open the | 
					
						
							|  |  |  | // document. | 
					
						
							| 
									
										
										
										
											2016-09-12 14:29:06 -07:00
										 |  |  | bool OpenItem(const base::FilePath& full_path) { | 
					
						
							| 
									
										
										
										
											2013-04-29 20:41:11 +08:00
										 |  |  |   DCHECK([NSThread isMainThread]); | 
					
						
							|  |  |  |   NSString* path_string = base::SysUTF8ToNSString(full_path.value()); | 
					
						
							|  |  |  |   if (!path_string) | 
					
						
							| 
									
										
										
										
											2016-09-12 14:29:06 -07:00
										 |  |  |     return false; | 
					
						
							| 
									
										
										
										
											2013-04-29 20:41:11 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Create the target of this AppleEvent, the Finder. | 
					
						
							|  |  |  |   base::mac::ScopedAEDesc<AEAddressDesc> address; | 
					
						
							|  |  |  |   const OSType finderCreatorCode = 'MACS'; | 
					
						
							|  |  |  |   OSErr status = AECreateDesc(typeApplSignature,  // type | 
					
						
							|  |  |  |                               &finderCreatorCode,  // data | 
					
						
							|  |  |  |                               sizeof(finderCreatorCode),  // dataSize | 
					
						
							|  |  |  |                               address.OutPointer());  // result | 
					
						
							|  |  |  |   if (status != noErr) { | 
					
						
							|  |  |  |     OSSTATUS_LOG(WARNING, status) << "Could not create OpenItem() AE target"; | 
					
						
							| 
									
										
										
										
											2016-09-12 14:29:06 -07:00
										 |  |  |     return false; | 
					
						
							| 
									
										
										
										
											2013-04-29 20:41:11 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Build the AppleEvent data structure that instructs Finder to open files. | 
					
						
							|  |  |  |   base::mac::ScopedAEDesc<AppleEvent> theEvent; | 
					
						
							|  |  |  |   status = AECreateAppleEvent(kCoreEventClass,  // theAEEventClass | 
					
						
							|  |  |  |                               kAEOpenDocuments,  // theAEEventID | 
					
						
							|  |  |  |                               address,  // target | 
					
						
							|  |  |  |                               kAutoGenerateReturnID,  // returnID | 
					
						
							|  |  |  |                               kAnyTransactionID,  // transactionID | 
					
						
							|  |  |  |                               theEvent.OutPointer());  // result | 
					
						
							|  |  |  |   if (status != noErr) { | 
					
						
							|  |  |  |     OSSTATUS_LOG(WARNING, status) << "Could not create OpenItem() AE event"; | 
					
						
							| 
									
										
										
										
											2016-09-12 14:29:06 -07:00
										 |  |  |     return false; | 
					
						
							| 
									
										
										
										
											2013-04-29 20:41:11 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Create the list of files (only ever one) to open. | 
					
						
							|  |  |  |   base::mac::ScopedAEDesc<AEDescList> fileList; | 
					
						
							|  |  |  |   status = AECreateList(NULL,  // factoringPtr | 
					
						
							|  |  |  |                         0,  // factoredSize | 
					
						
							|  |  |  |                         false,  // isRecord | 
					
						
							|  |  |  |                         fileList.OutPointer());  // resultList | 
					
						
							|  |  |  |   if (status != noErr) { | 
					
						
							|  |  |  |     OSSTATUS_LOG(WARNING, status) << "Could not create OpenItem() AE file list"; | 
					
						
							| 
									
										
										
										
											2016-09-12 14:29:06 -07:00
										 |  |  |     return false; | 
					
						
							| 
									
										
										
										
											2013-04-29 20:41:11 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Add the single path to the file list.  C-style cast to avoid both a | 
					
						
							|  |  |  |   // static_cast and a const_cast to get across the toll-free bridge. | 
					
						
							|  |  |  |   CFURLRef pathURLRef = (CFURLRef)[NSURL fileURLWithPath:path_string]; | 
					
						
							|  |  |  |   FSRef pathRef; | 
					
						
							|  |  |  |   if (CFURLGetFSRef(pathURLRef, &pathRef)) { | 
					
						
							|  |  |  |     status = AEPutPtr(fileList.OutPointer(),  // theAEDescList | 
					
						
							|  |  |  |                       0,  // index | 
					
						
							|  |  |  |                       typeFSRef,  // typeCode | 
					
						
							|  |  |  |                       &pathRef,  // dataPtr | 
					
						
							|  |  |  |                       sizeof(pathRef));  // dataSize | 
					
						
							|  |  |  |     if (status != noErr) { | 
					
						
							|  |  |  |       OSSTATUS_LOG(WARNING, status) | 
					
						
							|  |  |  |           << "Could not add file path to AE list in OpenItem()"; | 
					
						
							| 
									
										
										
										
											2016-09-12 14:29:06 -07:00
										 |  |  |       return false; | 
					
						
							| 
									
										
										
										
											2013-04-29 20:41:11 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     LOG(WARNING) << "Could not get FSRef for path URL in OpenItem()"; | 
					
						
							| 
									
										
										
										
											2016-09-12 14:29:06 -07:00
										 |  |  |     return false; | 
					
						
							| 
									
										
										
										
											2013-04-29 20:41:11 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Attach the file list to the AppleEvent. | 
					
						
							|  |  |  |   status = AEPutParamDesc(theEvent.OutPointer(),  // theAppleEvent | 
					
						
							|  |  |  |                           keyDirectObject,  // theAEKeyword | 
					
						
							|  |  |  |                           fileList);  // theAEDesc | 
					
						
							|  |  |  |   if (status != noErr) { | 
					
						
							|  |  |  |     OSSTATUS_LOG(WARNING, status) | 
					
						
							|  |  |  |         << "Could not put the AE file list the path in OpenItem()"; | 
					
						
							| 
									
										
										
										
											2016-09-12 14:29:06 -07:00
										 |  |  |     return false; | 
					
						
							| 
									
										
										
										
											2013-04-29 20:41:11 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Send the actual event.  Do not care about the reply. | 
					
						
							|  |  |  |   base::mac::ScopedAEDesc<AppleEvent> reply; | 
					
						
							|  |  |  |   status = AESend(theEvent,  // theAppleEvent | 
					
						
							|  |  |  |                   reply.OutPointer(),  // reply | 
					
						
							|  |  |  |                   kAENoReply + kAEAlwaysInteract,  // sendMode | 
					
						
							|  |  |  |                   kAENormalPriority,  // sendPriority | 
					
						
							|  |  |  |                   kAEDefaultTimeout,  // timeOutInTicks | 
					
						
							|  |  |  |                   NULL, // idleProc | 
					
						
							|  |  |  |                   NULL);  // filterProc | 
					
						
							|  |  |  |   if (status != noErr) { | 
					
						
							|  |  |  |     OSSTATUS_LOG(WARNING, status) | 
					
						
							|  |  |  |         << "Could not send AE to Finder in OpenItem()"; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-09-12 14:29:06 -07:00
										 |  |  |   return status == noErr; | 
					
						
							| 
									
										
										
										
											2013-04-29 20:41:11 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-16 15:55:37 -08:00
										 |  |  | bool OpenExternal(const GURL& url, bool activate) { | 
					
						
							| 
									
										
										
										
											2013-04-29 20:41:11 +08:00
										 |  |  |   DCHECK([NSThread isMainThread]); | 
					
						
							| 
									
										
										
										
											2015-12-24 12:43:07 +08:00
										 |  |  |   NSURL* ns_url = net::NSURLWithGURL(url); | 
					
						
							| 
									
										
										
										
											2015-06-12 13:54:42 +08:00
										 |  |  |   if (!ns_url) { | 
					
						
							| 
									
										
										
										
											2015-06-10 11:06:22 -04:00
										 |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-06-12 13:54:42 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   CFURLRef openingApp = NULL; | 
					
						
							|  |  |  |   OSStatus status = LSGetApplicationForURL((CFURLRef)ns_url, | 
					
						
							|  |  |  |                                            kLSRolesAll, | 
					
						
							|  |  |  |                                            NULL, | 
					
						
							|  |  |  |                                            &openingApp); | 
					
						
							|  |  |  |   if (status != noErr) { | 
					
						
							|  |  |  |     return false; | 
					
						
							| 
									
										
										
										
											2015-06-10 11:06:22 -04:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-06-12 13:54:42 +08:00
										 |  |  |   CFRelease(openingApp);  // NOT A BUG; LSGetApplicationForURL retains for us | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-02 23:01:00 -08:00
										 |  |  |   NSUInteger launchOptions = NSWorkspaceLaunchDefault; | 
					
						
							| 
									
										
										
										
											2016-02-16 15:55:37 -08:00
										 |  |  |   if (!activate) | 
					
						
							|  |  |  |     launchOptions |= NSWorkspaceLaunchWithoutActivation; | 
					
						
							| 
									
										
										
										
											2016-02-02 23:01:00 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return [[NSWorkspace sharedWorkspace] openURLs: @[ns_url] | 
					
						
							|  |  |  |                                         withAppBundleIdentifier: nil | 
					
						
							|  |  |  |                                         options: launchOptions | 
					
						
							|  |  |  |                                         additionalEventParamDescriptor: NULL | 
					
						
							|  |  |  |                                         launchIdentifiers: NULL]; | 
					
						
							| 
									
										
										
										
											2013-04-29 20:41:11 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-27 18:31:57 +05:30
										 |  |  | bool MoveItemToTrash(const base::FilePath& full_path) { | 
					
						
							| 
									
										
										
										
											2013-04-29 21:57:05 +08:00
										 |  |  |   NSString* path_string = base::SysUTF8ToNSString(full_path.value()); | 
					
						
							| 
									
										
										
										
											2015-06-18 13:09:02 +08:00
										 |  |  |   BOOL status = [[NSFileManager defaultManager] | 
					
						
							|  |  |  |                 trashItemAtURL:[NSURL fileURLWithPath:path_string] | 
					
						
							|  |  |  |                 resultingItemURL:nil | 
					
						
							|  |  |  |                 error:nil]; | 
					
						
							|  |  |  |   if (!path_string || !status) | 
					
						
							| 
									
										
										
										
											2013-04-29 21:57:05 +08:00
										 |  |  |     LOG(WARNING) << "NSWorkspace failed to move file " << full_path.value() | 
					
						
							|  |  |  |                  << " to trash"; | 
					
						
							| 
									
										
										
										
											2015-04-08 19:31:46 +05:30
										 |  |  |   return status; | 
					
						
							| 
									
										
										
										
											2013-04-29 21:57:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-29 22:10:03 +08:00
										 |  |  | void Beep() { | 
					
						
							|  |  |  |   NSBeep(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-29 20:41:11 +08:00
										 |  |  | }  // namespace platform_util |