📄 mimetmac.cpp
字号:
/////////////////////////////////////////////////////////////////////////////
// Name: src/mac/carbon/mimetype.cpp
// Purpose: Mac Carbon implementation for wx MIME-related classes
// Author: Ryan Norton
// Modified by:
// Created: 04/16/2005
// RCS-ID: $Id: mimetmac.cpp,v 1.38 2006/05/03 04:12:42 PC Exp $
// Copyright: (c) 2005 Ryan Norton (<wxprojects@comcast.net>)
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
//
// TODO: Search Info[-macos](classic).plist dictionary in addition
// to Internet Config database.
//
// Maybe try a brainstorm a way to change the wxMimeTypesManager API
// to get info from a file instead/addition to current get all stuff
// API so that we can use Launch Services to get MIME type info.
//
// Implement GetIcon from one of the FinderInfo functions - or
// use Launch Services and search that app's plist for the icon.
//
// Put some special juice in for the print command.
//
// for compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_MIMETYPE
#include "wx/mac/mimetype.h"
#ifndef WX_PRECOMP
#include "wx/dynarray.h"
#include "wx/string.h"
#include "wx/intl.h"
#include "wx/log.h"
#if wxUSE_GUI
#include "wx/icon.h"
#endif
#endif
#include "wx/file.h"
#include "wx/confbase.h"
#include "wx/mac/private.h"
// other standard headers
#include <ctype.h>
#ifndef __DARWIN__
#include <InternetConfig.h>
#include <CoreServices.h>
#endif
// START CODE SAMPLE FROM TECHNOTE 1002 (http://developer.apple.com/technotes/tn/tn1002.html)
// IsRemoteVolume can be used to find out if the
// volume referred to by vRefNum is a remote volume
// located somewhere on a network. the volume's attribute
// flags (copied from the GetVolParmsInfoBuffer structure)
// are returned in the longword pointed to by vMAttrib.
OSErr IsRemoteVolume(short vRefNum, Boolean *isRemote, long *vMAttrib)
{
HParamBlockRec volPB;
GetVolParmsInfoBuffer volinfo;
OSErr err;
volPB.ioParam.ioVRefNum = vRefNum;
volPB.ioParam.ioNamePtr = NULL;
volPB.ioParam.ioBuffer = (Ptr)&volinfo;
volPB.ioParam.ioReqCount = sizeof(volinfo);
err = PBHGetVolParmsSync( &volPB );
if (err == noErr)
{
*isRemote = (volinfo.vMServerAdr != 0);
*vMAttrib = volinfo.vMAttrib;
}
return err;
}
// BuildVolumeList fills the array pointed to by vols with
// a list of the currently mounted volumes. If includeRemote
// is true, then remote server volumes will be included in
// the list. When remote server volumes are included in the
// list, they will be added to the end of the list. On entry,
// *count should contain the size of the array pointed to by
// vols. On exit, *count will be set to the number of id numbers
// placed in the array. If vMAttribMask is non-zero, then
// only volumes with matching attributes are added to the
// list of volumes. bits in the vMAttribMask should use the
// same encoding as bits in the vMAttrib field of
// the GetVolParmsInfoBuffer structure.
OSErr BuildVolumeList(Boolean includeRemote, short *vols,
long *count, long vMAttribMask)
{
HParamBlockRec volPB;
Boolean isRemote;
OSErr err = noErr;
long nlocal, nremote;
long vMAttrib;
// set up and check parameters
volPB.volumeParam.ioNamePtr = NULL;
nlocal = nremote = 0;
if (*count == 0)
return noErr;
// iterate through volumes
for (volPB.volumeParam.ioVolIndex = 1;
PBHGetVInfoSync(&volPB) == noErr;
volPB.volumeParam.ioVolIndex++)
{
// skip remote volumes, if necessary
err = IsRemoteVolume(volPB.volumeParam.ioVRefNum, &isRemote, &vMAttrib);
if (err != noErr)
goto bail;
if ((includeRemote || !isRemote) && ((vMAttrib & vMAttribMask) == vMAttribMask))
{
// add local volumes at the front; remote volumes at the end
if (isRemote)
vols[nlocal + nremote++] = volPB.volumeParam.ioVRefNum;
else
{
if (nremote > 0)
BlockMoveData(
vols + nlocal,
vols + nlocal + 1,
nremote * sizeof(short) );
vols[nlocal++] = volPB.volumeParam.ioVRefNum;
}
// list full?
if ((nlocal + nremote) >= *count)
break;
}
}
bail:
*count = (nlocal + nremote);
return err;
}
// FindApplication iterates through mounted volumes
// searching for an application with the given creator
// type. If includeRemote is true, then remote volumes
// will be searched (after local ones) for an application
// with the creator type.
//
// Hacked to output to appName
//
#define kMaxVols 20
OSErr FindApplication(OSType appCreator, Boolean includeRemote, Str255 appName, FSSpec* appSpec)
{
short rRefNums[kMaxVols];
long i, volCount;
DTPBRec desktopPB;
OSErr err;
// get a list of volumes - with desktop files
volCount = kMaxVols;
err = BuildVolumeList(includeRemote, rRefNums, &volCount, (1 << bHasDesktopMgr) );
if (err != noErr)
return err;
// iterate through the list
for (i=0; i<volCount; i++)
{
// has a desktop file?
desktopPB.ioCompletion = NULL;
desktopPB.ioVRefNum = rRefNums[i];
desktopPB.ioNamePtr = NULL;
desktopPB.ioIndex = 0;
err = PBDTGetPath( &desktopPB );
if (err != noErr)
continue;
// has the correct app??
desktopPB.ioFileCreator = appCreator;
desktopPB.ioNamePtr = appName;
err = PBDTGetAPPLSync( &desktopPB );
if (err != noErr)
continue;
// make a file spec referring to it
err = FSMakeFSSpec( rRefNums[i], desktopPB.ioAPPLParID, appName, appSpec );
if (err != noErr)
continue;
// found it!
return noErr;
}
return fnfErr;
}
// END CODE SAMPLE FROM TECHNOTE 1002 (http://developer.apple.com/technotes/tn/tn1002.html)
// yeah, duplicated code
pascal OSErr FSpGetFullPath( const FSSpec *spec,
short *fullPathLength,
Handle *fullPath )
{
OSErr result, realResult;
FSSpec tempSpec;
CInfoPBRec pb;
*fullPathLength = 0;
*fullPath = NULL;
// default to noErr
realResult = result = noErr;
// work around Nav Services "bug" (it returns invalid FSSpecs with empty names)
#if 0
if ( spec->name[0] == 0 )
{
result = FSMakeFSSpecCompat(spec->vRefNum, spec->parID, spec->name, &tempSpec);
}
else
{
#endif
// Make a copy of the input FSSpec that can be modified
BlockMoveData( spec, &tempSpec, sizeof(FSSpec) );
if ( result == noErr )
{
if ( tempSpec.parID == fsRtParID )
{
// object is a volume
// Add a colon to make it a full pathname
++tempSpec.name[0];
tempSpec.name[tempSpec.name[0]] = ':';
// We're done
result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
}
else
{
// object isn't a volume
// Is the object a file or a directory?
pb.dirInfo.ioNamePtr = tempSpec.name;
pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
pb.dirInfo.ioDrDirID = tempSpec.parID;
pb.dirInfo.ioFDirIndex = 0;
result = PBGetCatInfoSync( &pb );
// Allow file/directory name at end of path to not exist.
realResult = result;
if ((result == noErr) || (result == fnfErr))
{
// if the object is a directory, append a colon so full pathname ends with colon
if ((result == noErr) && (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0)
{
++tempSpec.name[0];
tempSpec.name[tempSpec.name[0]] = ':';
}
// Put the object name in first
result = PtrToHand( &tempSpec.name[1], fullPath, tempSpec.name[0] );
if ( result == noErr )
{
// Get the ancestor directory names
pb.dirInfo.ioNamePtr = tempSpec.name;
pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
pb.dirInfo.ioDrParID = tempSpec.parID;
// loop until we have an error or find the root directory
do
{
pb.dirInfo.ioFDirIndex = -1;
pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
result = PBGetCatInfoSync(&pb);
if ( result == noErr )
{
// Append colon to directory name
++tempSpec.name[0];
tempSpec.name[tempSpec.name[0]] = ':';
// Add directory name to beginning of fullPath
(void)Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1], tempSpec.name[0]);
result = MemError();
}
}
while ( (result == noErr) && (pb.dirInfo.ioDrDirID != fsRtDirID) );
}
}
}
}
if ( result == noErr )
{
// Return the length
*fullPathLength = GetHandleSize( *fullPath );
result = realResult; // return realResult in case it was fnfErr
}
else
{
// Dispose of the handle and return NULL and zero length
if ( *fullPath != NULL )
{
DisposeHandle( *fullPath );
*fullPath = NULL;
}
*fullPathLength = 0;
}
return result;
}
//
// On the mac there are two ways to open a file - one is through apple events and the
// finder, another is through mime types.
//
// So, really there are two ways to implement wxFileType...
//
// Mime types are only available on OS 8.1+ through the InternetConfig API
//
// Much like the old-style file manager, it has 3 levels of flexibility for its methods -
// Low - which means you have to iterate yourself through the mime database
// Medium - which lets you sort of cache the database if you want to use lowlevel functions
// High - which requires access to the database every time
//
// We want to be efficient (i.e. professional :) ) about it, so we use a combo of low
// and mid-level functions
//
// TODO: Should we call ICBegin/ICEnd? Then where?
//
// debug helper
inline void wxLogMimeDebug(const wxChar* szMsg, OSStatus status)
{
wxLogDebug(wxString::Format(wxT("%s LINE:%i OSERROR:%i"), szMsg, __LINE__, (int)status));
}
// in case we're compiling in non-GUI mode
class WXDLLEXPORT wxIcon;
bool wxFileTypeImpl::SetCommand(const wxString& cmd, const wxString& verb, bool overwriteprompt)
{
wxASSERT_MSG( m_manager != NULL , wxT("Bad wxFileType") );
return false;
}
bool wxFileTypeImpl::SetDefaultIcon(const wxString& strIcon, int index)
{
wxASSERT_MSG( m_manager != NULL , wxT("Bad wxFileType") );
return false;
}
bool wxFileTypeImpl::GetOpenCommand(wxString *openCmd,
const wxFileType::MessageParameters& params) const
{
wxString cmd = GetCommand(wxT("open"));
*openCmd = wxFileType::ExpandCommand(cmd, params);
return !openCmd->empty();
}
bool
wxFileTypeImpl::GetPrintCommand(
wxString *printCmd,
const wxFileType::MessageParameters& params) const
{
wxString cmd = GetCommand(wxT("print"));
*printCmd = wxFileType::ExpandCommand(cmd, params);
return !printCmd->empty();
}
//
// Internet Config vs. Launch Services
//
// From OS 8 on there was internet config...
// However, OSX and its finder does not use info
// from Internet Config at all - the Internet Config
// database ONLY CONTAINS APPS THAT ARE CLASSIC APPS
// OR REGISTERED THROUGH INTERNET CONFIG
//
// Therefore on OSX in order for the open command to be useful
// we need to go straight to launch services
//
#if defined(__DARWIN__)
//on darwin, use launch services
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -