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/platform_util.h"
      6 
      7 #include <Carbon/Carbon.h>
      8 #import <Cocoa/Cocoa.h>
      9 #include <CoreServices/CoreServices.h>
     10 
     11 #include "base/files/file_path.h"
     12 #include "base/logging.h"
     13 #include "base/mac/mac_logging.h"
     14 #include "base/mac/scoped_aedesc.h"
     15 #include "base/strings/sys_string_conversions.h"
     16 #include "url/gurl.h"
     17 
     18 namespace platform_util {
     19 
     20 void ShowItemInFolder(Profile* profile, const base::FilePath& full_path) {
     21   DCHECK([NSThread isMainThread]);
     22   NSString* path_string = base::SysUTF8ToNSString(full_path.value());
     23   if (!path_string || ![[NSWorkspace sharedWorkspace] selectFile:path_string
     24                                         inFileViewerRootedAtPath:nil])
     25     LOG(WARNING) << "NSWorkspace failed to select file " << full_path.value();
     26 }
     27 
     28 // This function opens a file.  This doesn't use LaunchServices or NSWorkspace
     29 // because of two bugs:
     30 //  1. Incorrect app activation with com.apple.quarantine:
     31 //     http://crbug.com/32921
     32 //  2. Silent no-op for unassociated file types: http://crbug.com/50263
     33 // Instead, an AppleEvent is constructed to tell the Finder to open the
     34 // document.
     35 void OpenItem(Profile* profile, const base::FilePath& full_path) {
     36   DCHECK([NSThread isMainThread]);
     37   NSString* path_string = base::SysUTF8ToNSString(full_path.value());
     38   if (!path_string)
     39     return;
     40 
     41   // Create the target of this AppleEvent, the Finder.
     42   base::mac::ScopedAEDesc<AEAddressDesc> address;
     43   const OSType finderCreatorCode = 'MACS';
     44   OSErr status = AECreateDesc(typeApplSignature,  // type
     45                               &finderCreatorCode,  // data
     46                               sizeof(finderCreatorCode),  // dataSize
     47                               address.OutPointer());  // result
     48   if (status != noErr) {
     49     OSSTATUS_LOG(WARNING, status) << "Could not create OpenItem() AE target";
     50     return;
     51   }
     52 
     53   // Build the AppleEvent data structure that instructs Finder to open files.
     54   base::mac::ScopedAEDesc<AppleEvent> theEvent;
     55   status = AECreateAppleEvent(kCoreEventClass,  // theAEEventClass
     56                               kAEOpenDocuments,  // theAEEventID
     57                               address,  // target
     58                               kAutoGenerateReturnID,  // returnID
     59                               kAnyTransactionID,  // transactionID
     60                               theEvent.OutPointer());  // result
     61   if (status != noErr) {
     62     OSSTATUS_LOG(WARNING, status) << "Could not create OpenItem() AE event";
     63     return;
     64   }
     65 
     66   // Create the list of files (only ever one) to open.
     67   base::mac::ScopedAEDesc<AEDescList> fileList;
     68   status = AECreateList(NULL,  // factoringPtr
     69                         0,  // factoredSize
     70                         false,  // isRecord
     71                         fileList.OutPointer());  // resultList
     72   if (status != noErr) {
     73     OSSTATUS_LOG(WARNING, status) << "Could not create OpenItem() AE file list";
     74     return;
     75   }
     76 
     77   // Add the single path to the file list.  C-style cast to avoid both a
     78   // static_cast and a const_cast to get across the toll-free bridge.
     79   CFURLRef pathURLRef = (CFURLRef)[NSURL fileURLWithPath:path_string];
     80   FSRef pathRef;
     81   if (CFURLGetFSRef(pathURLRef, &pathRef)) {
     82     status = AEPutPtr(fileList.OutPointer(),  // theAEDescList
     83                       0,  // index
     84                       typeFSRef,  // typeCode
     85                       &pathRef,  // dataPtr
     86                       sizeof(pathRef));  // dataSize
     87     if (status != noErr) {
     88       OSSTATUS_LOG(WARNING, status)
     89           << "Could not add file path to AE list in OpenItem()";
     90       return;
     91     }
     92   } else {
     93     LOG(WARNING) << "Could not get FSRef for path URL in OpenItem()";
     94     return;
     95   }
     96 
     97   // Attach the file list to the AppleEvent.
     98   status = AEPutParamDesc(theEvent.OutPointer(),  // theAppleEvent
     99                           keyDirectObject,  // theAEKeyword
    100                           fileList);  // theAEDesc
    101   if (status != noErr) {
    102     OSSTATUS_LOG(WARNING, status)
    103         << "Could not put the AE file list the path in OpenItem()";
    104     return;
    105   }
    106 
    107   // Send the actual event.  Do not care about the reply.
    108   base::mac::ScopedAEDesc<AppleEvent> reply;
    109   status = AESend(theEvent,  // theAppleEvent
    110                   reply.OutPointer(),  // reply
    111                   kAENoReply + kAEAlwaysInteract,  // sendMode
    112                   kAENormalPriority,  // sendPriority
    113                   kAEDefaultTimeout,  // timeOutInTicks
    114                   NULL, // idleProc
    115                   NULL);  // filterProc
    116   if (status != noErr) {
    117     OSSTATUS_LOG(WARNING, status)
    118         << "Could not send AE to Finder in OpenItem()";
    119   }
    120 }
    121 
    122 void OpenExternal(Profile* profile, const GURL& url) {
    123   DCHECK([NSThread isMainThread]);
    124   NSString* url_string = base::SysUTF8ToNSString(url.spec());
    125   NSURL* ns_url = [NSURL URLWithString:url_string];
    126   if (!ns_url || ![[NSWorkspace sharedWorkspace] openURL:ns_url])
    127     LOG(WARNING) << "NSWorkspace failed to open URL " << url;
    128 }
    129 
    130 gfx::NativeWindow GetTopLevel(gfx::NativeView view) {
    131   return [view window];
    132 }
    133 
    134 gfx::NativeView GetParent(gfx::NativeView view) {
    135   return nil;
    136 }
    137 
    138 bool IsWindowActive(gfx::NativeWindow window) {
    139   return [window isKeyWindow] || [window isMainWindow];
    140 }
    141 
    142 void ActivateWindow(gfx::NativeWindow window) {
    143   [window makeKeyAndOrderFront:nil];
    144 }
    145 
    146 bool IsVisible(gfx::NativeView view) {
    147   // A reasonable approximation of how you'd expect this to behave.
    148   return (view &&
    149           ![view isHiddenOrHasHiddenAncestor] &&
    150           [view window] &&
    151           [[view window] isVisible]);
    152 }
    153 
    154 bool IsSwipeTrackingFromScrollEventsEnabled() {
    155   SEL selector = @selector(isSwipeTrackingFromScrollEventsEnabled);
    156   return [NSEvent respondsToSelector:selector]
    157       && [NSEvent performSelector:selector];
    158 }
    159 
    160 }  // namespace platform_util
    161