mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-12 14:37:50 +00:00
2032 lines
52 KiB
C++
2032 lines
52 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||
*
|
||
* The contents of this file are subject to the Netscape Public License
|
||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||
* http://www.mozilla.org/NPL/
|
||
*
|
||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||
* for the specific language governing rights and limitations under the
|
||
* NPL.
|
||
*
|
||
* The Initial Developer of this code under the NPL is Netscape
|
||
* Communications Corporation. Portions created by Netscape are
|
||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||
* Reserved.
|
||
*/
|
||
|
||
/***********************************************************************************
|
||
* macutil.cp
|
||
*
|
||
* Various mac utility routines
|
||
*
|
||
***********************************************************************************/
|
||
|
||
#include <stdarg.h>
|
||
|
||
#include <Traps.h>
|
||
#include <LPlaceHolder.h>
|
||
#include <LHandleStream.h>
|
||
//#include <LTextEngine.h>
|
||
#include "macutil.h"
|
||
#include "resgui.h"
|
||
#include "uprefd.h"
|
||
#include "ufilemgr.h"
|
||
#include "uerrmgr.h"
|
||
#include "xp.h"
|
||
#include "cstring.h"
|
||
#include "xpassert.h"
|
||
#include "xp_trace.h"
|
||
#include "macgui.h"
|
||
#include "prefapi.h"
|
||
#include "MoreDesktopMgr.h"
|
||
extern "C" {
|
||
#include "asyncCursors.h"
|
||
}
|
||
|
||
#ifndef MOZ_NGLAYOUT
|
||
#include "CSimpleTextView.h"
|
||
#endif
|
||
|
||
#include "mfinder.h" // needed for workaround function to bug in Apple's
|
||
// ::TruncText and ::TruncString - andrewb 6/20/97
|
||
|
||
#include "MoreMixedMode.h"
|
||
#include "PascalString.h"
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
Layout Utilities
|
||
-----------------------------------------------------------------------------*/
|
||
|
||
// Another mlanett special
|
||
static void GetImageRect( LView* view, SPoint32* topLeft, SPoint32* botRight );
|
||
static void GetImageRect( LView* view, SPoint32* topLeft, SPoint32* botRight )
|
||
{
|
||
/*
|
||
Return the visible image of this view.
|
||
*/
|
||
SPoint32 frameLocation;
|
||
SDimension16 frameSize;
|
||
SPoint32 imageLocation;
|
||
|
||
view->GetFrameLocation( frameLocation );
|
||
view->GetFrameSize( frameSize );
|
||
view->GetImageLocation( imageLocation );
|
||
|
||
// convert local rectangle to image rectangle
|
||
topLeft->h = frameLocation.h - imageLocation.h; // frameLocation.h - portOrigin.h - imageLocation.h;
|
||
botRight->h = topLeft->h + frameSize.width;
|
||
topLeft->v = frameLocation.v - imageLocation.v; // frameLocation.v - portOrigin.v - imageLocation.v;
|
||
botRight->v = topLeft->v + frameSize.height;
|
||
}
|
||
|
||
void RevealInImage( LView* view, SPoint32 selTopLeft, SPoint32 selBotRight )
|
||
{
|
||
/*
|
||
Scroll the minimum amount necessary to reveal this image rectangle.
|
||
In this diagram, the selection is scrolled above the visible rectangle.
|
||
Therefore selection-top is less than image-top, so we need to scroll
|
||
down by above-amount.
|
||
/---\
|
||
/---| |
|
||
| \---/
|
||
v
|
||
/--------------\
|
||
| |
|
||
| |
|
||
| |
|
||
| |
|
||
\--------------/
|
||
*/
|
||
SPoint32 iTopLeft;
|
||
SPoint32 iBotRight;
|
||
|
||
GetImageRect( view, &iTopLeft, &iBotRight );
|
||
|
||
Int32 aboveAmount = selTopLeft.v - 20 - iTopLeft.v;
|
||
Int32 belowAmount = selTopLeft.v + 20 - iTopLeft.v;
|
||
Int32 leftAmount = selTopLeft.h - iTopLeft.h;
|
||
Int32 rightAmount = selBotRight.h - iBotRight.h;
|
||
|
||
if ( aboveAmount < 0 )
|
||
view->ScrollImageBy( 0, aboveAmount, TRUE );
|
||
else if ( ( selBotRight.v - iBotRight.v ) > 0 )
|
||
{
|
||
// don't scroll the top off!
|
||
// belowAmount and aboveAmount are negative
|
||
// belowAmount must be (absolute) less than aboveAmount
|
||
view->ScrollImageBy( 0, belowAmount > aboveAmount ? aboveAmount : belowAmount, TRUE );
|
||
}
|
||
|
||
if ( leftAmount < 0 )
|
||
view->ScrollImageBy( leftAmount, 0, TRUE );
|
||
else if ( rightAmount > 0 )
|
||
{
|
||
// don't scroll the left off!
|
||
// belowAmount and leftAmount are negative
|
||
// belowAmount must be (absolute) less than aboveAmount
|
||
view->ScrollImageBy( rightAmount > leftAmount? leftAmount: rightAmount, 0, TRUE );
|
||
}
|
||
}
|
||
|
||
Boolean TooDifferent( const Point& a, const Point& b )
|
||
{
|
||
return abs( b.h - a.h ) >= MOUSE_HYSTERESIS || abs( b.v - a.v ) >= MOUSE_HYSTERESIS;
|
||
}
|
||
|
||
short WaitForMouseAction( const Point& initial, long clickStart, long delay )
|
||
{
|
||
Point current;
|
||
long now;
|
||
|
||
while ( ::StillDown() )
|
||
{
|
||
::GetMouse( ¤t );
|
||
if ( TooDifferent( initial, current ) )
|
||
return MOUSE_DRAGGING;
|
||
now = ::TickCount();
|
||
if ( abs( now - clickStart ) > delay)
|
||
return MOUSE_TIMEOUT;
|
||
}
|
||
|
||
return MOUSE_UP_EARLY;
|
||
}
|
||
|
||
|
||
int // offset
|
||
CalcCurrentSelected (lo_FormElementSelectData * selectData, Boolean fromDefaults)
|
||
{
|
||
int offset = 0;
|
||
|
||
lo_FormElementOptionData * optionData;
|
||
PA_LOCK(optionData, lo_FormElementOptionData *, selectData->options);
|
||
for (int i=0; i<selectData->option_cnt; i++) {
|
||
char * itemName = NULL;
|
||
PA_LOCK(itemName, char*, optionData[i].text_value);
|
||
if (fromDefaults) {
|
||
if (optionData[i].def_selected) {
|
||
offset = i;
|
||
break;
|
||
}
|
||
}
|
||
else {
|
||
if (optionData[i].selected) {
|
||
offset = i;
|
||
break;
|
||
}
|
||
}
|
||
PA_UNLOCK(optionData[i].text_value);
|
||
}
|
||
PA_UNLOCK(selectData->options);
|
||
|
||
return offset;
|
||
}
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
Generic Utilities
|
||
-----------------------------------------------------------------------------*/
|
||
|
||
Rect CenterInRect( Point thing, Rect destSpace )
|
||
{
|
||
Point destSize;
|
||
Point centeredSize;
|
||
Rect centeredThing;
|
||
|
||
destSize.h = destSpace.right - destSpace.left;
|
||
destSize.v = destSpace.bottom - destSpace.top;
|
||
centeredSize.h = MIN( destSize.h, thing.h );
|
||
centeredSize.v = MIN( destSize.v, thing.v );
|
||
centeredThing.left = destSpace.left + ( destSize.h - centeredSize.h ) / 2;
|
||
centeredThing.top = destSpace.top + ( destSize.v - centeredSize.v ) / 2;
|
||
centeredThing.right = centeredThing.left + centeredSize.h;
|
||
centeredThing.bottom = centeredThing.top + centeredSize.v;
|
||
return centeredThing;
|
||
}
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
String Copying
|
||
-----------------------------------------------------------------------------*/
|
||
|
||
unsigned char* CopyString( unsigned char* destination, const unsigned char* source )
|
||
{
|
||
BlockMove (source, destination, source[0]+1);
|
||
return destination;
|
||
}
|
||
|
||
unsigned char* CopyString( unsigned char* destination, const char* source )
|
||
{
|
||
destination[0] = strlen (source);
|
||
BlockMove (source, destination + 1, destination[0]);
|
||
return destination;
|
||
}
|
||
|
||
char* CopyString( char* destination, const unsigned char* source )
|
||
{
|
||
BlockMove (source + 1, destination, source[0]);
|
||
destination[source[0]] = 0;
|
||
return destination;
|
||
}
|
||
|
||
char* CopyString( char* destination, const char* source )
|
||
{
|
||
register int length = strlen (source);
|
||
BlockMove (source, destination, length + 1);
|
||
return destination;
|
||
}
|
||
|
||
void CopyAlloc(char ** destination, StringPtr source)
|
||
{
|
||
// NET_SACopy frees a non-null destination itself
|
||
//if (*destination != NULL)
|
||
// XP_FREE(*destination);
|
||
p2cstr(source);
|
||
|
||
// We don't really want to delete any existing storage for destination so borrow
|
||
// some code from NET_SACopy and skip the XP_FREE of destination
|
||
//NET_SACopy(destination, (char*)source);
|
||
if (! source)
|
||
{
|
||
*destination = NULL;
|
||
}
|
||
else
|
||
{
|
||
*destination = (char *) XP_ALLOC (XP_STRLEN((const char *)source) + 1);
|
||
if (*destination != NULL)
|
||
XP_STRCPY (*destination, (const char *)source);
|
||
}
|
||
|
||
c2pstr((char*)source);
|
||
}
|
||
|
||
// Takes colons out of a string
|
||
void StripColons( CStr31& fileName )
|
||
{
|
||
short count;
|
||
|
||
for ( count = 1; count <= fileName.Length(); count++ )
|
||
if ( fileName[count] == ':' )
|
||
fileName[count] = ' ';
|
||
}
|
||
|
||
// strips single instances of ch from the given string.
|
||
// If ch appears twice in a row, the second one is not removed.
|
||
void StripChar( CStr255& str, char ch )
|
||
{
|
||
int len = str.Length();
|
||
for (short i = 1; i <= len; i++)
|
||
if (str[i] == ch) {
|
||
BlockMoveData(&str[i + 1], &str[i], len - i);
|
||
i++;
|
||
len -= 1;
|
||
}
|
||
str[0] = len;
|
||
}
|
||
|
||
// <20> Takes a string of text (dragged/pasted), and turns
|
||
// it into a URL (strips CR, whitespace preceeding/trailing <>
|
||
void CleanUpTextToURL(char* text)
|
||
{
|
||
if (text == NULL)
|
||
return;
|
||
|
||
long len = XP_STRLEN(text);
|
||
|
||
int i=0;
|
||
|
||
if (text[0] == '<') // Swallow the surrounding '<' and '>'
|
||
::BlockMoveData(&text[1], &text[0], len);
|
||
|
||
while (text[i] != 0) // Loop till whitespace
|
||
{
|
||
if (XP_IS_SPACE(text[i]))
|
||
break;
|
||
i++;
|
||
}
|
||
if (text[i-1] == '>') // Swallow the ending '>'
|
||
i--;
|
||
|
||
text[i] = 0;
|
||
}
|
||
|
||
void CleanUpLocationString (CStr255 & url)
|
||
{
|
||
// Strips spaces & returns at end of url (happens often
|
||
// when you paste into url box)
|
||
int last;
|
||
while ((last = url.Length()) != 0) {
|
||
if (url[last] == '\n' || url[last] == ' ' || url[last] == '\r')
|
||
url.Length()--;
|
||
else break;
|
||
}
|
||
}
|
||
|
||
// TRUE if the key is down. Bypasses the event loop
|
||
Boolean IsThisKeyDown(const UInt8 theKey)
|
||
{
|
||
KeyMap map;
|
||
|
||
GetKeys(map);
|
||
|
||
return ((*((UInt8 *)map + (theKey >> 3)) >> (theKey & 7)) & 1) != 0;
|
||
} // IsThisKeyDown - don's improved non-union (as in struct) version
|
||
|
||
|
||
|
||
// A mess that figures out if cmd-. was pressed
|
||
/* Borrowed from tech note 263 */
|
||
|
||
#define kMaskModifiers 0xFE00 // we need the modifiers without the
|
||
// command key for KeyTrans
|
||
#define kMaskVirtualKey 0x0000FF00 // get virtual key from event message
|
||
// for KeyTrans
|
||
#define kUpKeyMask 0x0080
|
||
#define kShiftWord 8 // we shift the virtual key to mask it
|
||
// into the keyCode for KeyTrans
|
||
#define kMaskASCII1 0x00FF0000 // get the key out of the ASCII1 byte
|
||
#define kMaskASCII2 0x000000FF // get the key out of the ASCII2 byte
|
||
#define kPeriod 0x2E // ascii for a period
|
||
Boolean CmdPeriod()
|
||
{
|
||
EvQElPtr eventQ = (EvQElPtr)LMGetEventQueue()->qHead;
|
||
|
||
while (eventQ != NULL)
|
||
{
|
||
EventRecord * theEvent = (EventRecord *)&eventQ->evtQWhat;
|
||
|
||
UInt16 keyCode;
|
||
UInt32 state;
|
||
long virtualKey, keyInfo, lowChar, highChar, keyCId;
|
||
Handle hKCHR;
|
||
Ptr KCHRPtr;
|
||
|
||
|
||
if (((*theEvent).what == keyDown) || ((*theEvent).what == autoKey)) {
|
||
|
||
// see if the command key is down. If it is, find out the ASCII
|
||
// equivalent for the accompanying key.
|
||
|
||
if ((*theEvent).modifiers & cmdKey ) {
|
||
|
||
virtualKey = ((*theEvent).message & kMaskVirtualKey) >> kShiftWord;
|
||
// And out the command key and Or in the virtualKey
|
||
keyCode = short(((*theEvent).modifiers & kMaskModifiers) | virtualKey);
|
||
state = 0;
|
||
|
||
|
||
hKCHR = nil; /* set this to nil before starting */
|
||
KCHRPtr = (Ptr)GetScriptManagerVariable(smKCHRCache);
|
||
|
||
if ( !KCHRPtr ) {
|
||
keyCId = ::GetScriptVariable(short(GetScriptManagerVariable(smKeyScript)), smScriptKeys);
|
||
|
||
hKCHR = GetResource('KCHR',short(keyCId));
|
||
KCHRPtr = *hKCHR;
|
||
}
|
||
if (KCHRPtr) {
|
||
keyInfo = KeyTranslate(KCHRPtr, keyCode, &state);
|
||
if (hKCHR)
|
||
ReleaseResource(hKCHR);
|
||
} else
|
||
keyInfo = (*theEvent).message;
|
||
|
||
lowChar = keyInfo & kMaskASCII2;
|
||
highChar = (keyInfo & kMaskASCII1) >> 16;
|
||
if (lowChar == kPeriod || highChar == kPeriod)
|
||
return TRUE;
|
||
|
||
} // end the command key is down
|
||
} // end key down event
|
||
eventQ = (EvQElPtr)eventQ->qLink;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
// Sets button state and redraws it
|
||
void SetEnable( LPane* button, Boolean enable )
|
||
{
|
||
if ( !button->IsEnabled() && enable )
|
||
button->Enable();
|
||
else if ( button->IsEnabled() && !enable )
|
||
button->Disable();
|
||
}
|
||
|
||
// Changes the string to something acceptable to mac menu manager
|
||
void CreateMenuString( CStr255& itemName )
|
||
{
|
||
itemName=NET_UnEscape(itemName);
|
||
if ( itemName.Length() > 50 ) // Cut it down to reasonable size
|
||
{
|
||
itemName.Length() = 50;
|
||
itemName += "...";
|
||
}
|
||
if ( itemName.Length() && itemName[ 1 ] == '-' )
|
||
itemName[ 1 ] = '<EFBFBD>';
|
||
}
|
||
|
||
// TextHandleToHardLineBreaks
|
||
// converts TextEdit handle to text handle that has hard carriage returns.
|
||
|
||
Handle TextHandleToHardLineBreaks( CSimpleTextView &inTextView )
|
||
{
|
||
Handle theOldText = inTextView.GetTextHandle();
|
||
ThrowIfNULL_(theOldText);
|
||
|
||
SInt32 theTotalLength = inTextView.GetTextLength();
|
||
|
||
// TextRangeT theTotalRange = inEngine->GetTotalRange();
|
||
|
||
// Int32 theLineCount = inEngine->CountParts(theTotalRange, cLine);
|
||
|
||
Int32 theLineCount = inTextView.CountLines();
|
||
|
||
// text will expand by at most as many line breaks as there are lines
|
||
Handle theNewText = ::NewHandle(theTotalLength + theLineCount);
|
||
ThrowIfNULL_(theNewText);
|
||
|
||
// Lock down both text buffers
|
||
StHandleLocker theOldLock(theOldText);
|
||
StHandleLocker theNewLock(theNewText);
|
||
|
||
Int32 theBreakCount = 0;
|
||
Int32 theNewTextOffset = 0;
|
||
SInt32 lineStart = 0;
|
||
SInt32 lineEnd = 0;
|
||
|
||
Boolean bEatAgain = false;
|
||
|
||
for (Int32 theIndex = 1; theIndex <= theLineCount; theIndex++)
|
||
{
|
||
// TextRangeT theLineRange;
|
||
// inEngine->FindNthPart(theTotalRange, cLine, theIndex, &theLineRange);
|
||
|
||
// Waste appears to be Zero based rather than 1
|
||
inTextView.GetLineRange( theIndex - 1, &lineStart, &lineEnd );
|
||
|
||
::BlockMoveData(*theOldText + lineStart, *theNewText + theNewTextOffset, lineEnd - lineStart );
|
||
theNewTextOffset += lineEnd - lineStart;
|
||
|
||
Boolean eatNextLine = ((theIndex + 1) < theLineCount) && // This is to prevent overflow on end
|
||
(((*theOldText)[lineStart] == '>' &&
|
||
(*theOldText)[lineEnd + 1] != '>')) ||
|
||
bEatAgain;
|
||
|
||
if ((*theNewText)[theNewTextOffset -1 ] == CR)
|
||
{
|
||
(*theNewText)[theNewTextOffset - 1] = CR;
|
||
bEatAgain = false;
|
||
}
|
||
else
|
||
{
|
||
if (eatNextLine)
|
||
bEatAgain = true; // Only
|
||
else
|
||
{
|
||
(*theNewText)[++theNewTextOffset - 1] = CR;
|
||
bEatAgain = false;
|
||
}
|
||
}
|
||
}
|
||
|
||
::SetHandleSize(theNewText, theNewTextOffset); // Reduce the size of the handle
|
||
return theNewText;
|
||
}
|
||
|
||
|
||
void ConstrainTo( const long& min, const long& max, long& value )
|
||
{
|
||
XP_WARN_ASSERT( min <= value && value <= max );
|
||
if ( value < min )
|
||
value = min;
|
||
else if ( value > max )
|
||
value = max;
|
||
}
|
||
|
||
void * StructCopy(const void * struc, UInt32 size)
|
||
{
|
||
if (struc == NULL)
|
||
return NULL;
|
||
|
||
void * newStruct = XP_ALLOC(size);
|
||
if (newStruct == NULL)
|
||
return NULL;
|
||
::BlockMoveData(struc, newStruct, size);
|
||
return newStruct;
|
||
}
|
||
|
||
|
||
void SetMenuSize( LStdPopupMenu* popup, short shouldBe )
|
||
{
|
||
MenuHandle menu;
|
||
short count;
|
||
|
||
menu = popup->GetMacMenuH();
|
||
count = ::CountMItems( menu );
|
||
|
||
while ( shouldBe > count )
|
||
{
|
||
InsertMenuItem( menu, "\p ", count );
|
||
count++;
|
||
}
|
||
|
||
while ( shouldBe < count )
|
||
{
|
||
DeleteMenuItem( menu, count );
|
||
count--;
|
||
}
|
||
|
||
popup->SetMinValue( 1 );
|
||
popup->SetMaxValue( shouldBe );
|
||
}
|
||
|
||
void SetMenuSizeForLGAPopup( LGAPopup* popup, short shouldBe )
|
||
{
|
||
MenuHandle menu;
|
||
short count;
|
||
|
||
menu = popup->GetMacMenuH();
|
||
count = ::CountMItems( menu );
|
||
|
||
while ( shouldBe > count )
|
||
{
|
||
InsertMenuItem( menu, "\p ", count );
|
||
count++;
|
||
}
|
||
|
||
while ( shouldBe < count )
|
||
{
|
||
DeleteMenuItem( menu, count );
|
||
count--;
|
||
}
|
||
|
||
popup->SetMinValue( 1 );
|
||
popup->SetMaxValue( shouldBe );
|
||
}
|
||
|
||
void SetMenuItem( CommandT whichItem, Boolean toState )
|
||
{
|
||
ResIDT menuID;
|
||
MenuHandle menu = NULL;
|
||
Int16 item;
|
||
LMenuBar* currentMenuBar;
|
||
|
||
currentMenuBar = LMenuBar::GetCurrentMenuBar();
|
||
|
||
if (currentMenuBar)
|
||
currentMenuBar->FindMenuItem( whichItem, menuID, menu, item );
|
||
if (menu)
|
||
{
|
||
if ( toState )
|
||
SetItemMark( menu, item, checkMark );
|
||
else
|
||
SetItemMark( menu, item, noMark );
|
||
}
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// <09> myStringToNum [static]
|
||
// ---------------------------------------------------------------------------
|
||
// Utility used the USizeMenu routines to convert strings to numbers that
|
||
// ignores anything that's not a number
|
||
|
||
#define IsNumber_( x ) (( x ) >= '0' && ( x ) <= '9')
|
||
|
||
void myStringToNum( const CStr255& inString, Int32* outNum )
|
||
{
|
||
CStr255 temp;
|
||
short j = 1;
|
||
|
||
for ( short i = 1; i <= inString[ 0 ]; i++ )
|
||
{
|
||
if ( IsNumber_( inString[ i ] ) )
|
||
temp[ j++ ] = inString[ i ];
|
||
}
|
||
|
||
temp[0] = j - 1;
|
||
if (temp.Length() > 0)
|
||
StringToNum( temp, outNum );
|
||
}
|
||
|
||
short PointsToPixels( short inPoints, short iRes )
|
||
{
|
||
return ( (float)inPoints / 120.0 ) * iRes;
|
||
}
|
||
|
||
void SetCaptionDescriptor( LCaption* captionToSet, const CStr255& newText,
|
||
const TruncCode trunc )
|
||
{
|
||
XP_ASSERT( captionToSet );
|
||
|
||
CStr255 tempText( newText );
|
||
SDimension16 captionSize;
|
||
|
||
captionToSet->GetFrameSize( captionSize );
|
||
|
||
// DANGER! There is a hideous crashing bug in Apple's ::TruncString
|
||
// (and ::TruncText) when called with TruncMiddle
|
||
if (trunc == truncMiddle)
|
||
MiddleTruncationThatWorks(tempText, captionSize.width - 4);
|
||
else
|
||
TruncString( captionSize.width - 4, tempText, trunc );
|
||
captionToSet->SetDescriptor( tempText );
|
||
captionToSet->Refresh();
|
||
}
|
||
|
||
void GetDateTimeString( CStr255& dateTime )
|
||
{
|
||
unsigned long dt;
|
||
|
||
::GetDateTime( &dt );
|
||
::DateString( dt, longDate, dateTime, NULL );
|
||
}
|
||
|
||
unsigned short GetTextLengthInPixels( LTextEditView* textEdit );
|
||
unsigned short GetTextLengthInPixels( LTextEditView* textEdit )
|
||
{
|
||
XP_ASSERT( textEdit );
|
||
|
||
unsigned short width = 0;
|
||
TEHandle macTEH = NULL;
|
||
Handle text = NULL;
|
||
short length = 0;
|
||
|
||
// <20> this sets up the current port with the right text traits
|
||
if ( textEdit->FocusDraw() )
|
||
{
|
||
macTEH = textEdit->GetMacTEH();
|
||
XP_ASSERT( macTEH );
|
||
|
||
text = (*macTEH)->hText;
|
||
if ( text )
|
||
{
|
||
length = (*macTEH)->teLength;
|
||
HLock( text );
|
||
width = TextWidth( *text, 0, length );
|
||
HUnlock( text );
|
||
}
|
||
}
|
||
return width;
|
||
}
|
||
|
||
// Could be optimized
|
||
char * GetPaneDescriptor(LPane * pane)
|
||
{
|
||
char * ret = nil;
|
||
CStr255 ptempStr;
|
||
pane->GetDescriptor(ptempStr);
|
||
cstring ctempStr((unsigned char*)ptempStr);
|
||
if (ctempStr.length() > 0)
|
||
StrAllocCopy(ret, ctempStr);
|
||
return ret;
|
||
}
|
||
|
||
void TurnOn( LControl* control )
|
||
{
|
||
control->SetValue( TRUE );
|
||
control->BroadcastMessage( msg_ControlClicked, (void*)control );
|
||
}
|
||
|
||
Boolean SetPopupToNamedItem( LStdPopupMenu* whichMenu, const CStr255& itemText )
|
||
{
|
||
MenuHandle menuH;
|
||
short menuSize;
|
||
Str255 fontName;
|
||
|
||
menuH = whichMenu->GetMacMenuH();
|
||
menuSize = CountMItems( menuH );
|
||
|
||
for ( short i = 1; i <= menuSize; i++ )
|
||
{
|
||
::GetMenuItemText( menuH, i, fontName );
|
||
if ( itemText == (CStr255)fontName )
|
||
{
|
||
whichMenu->SetValue( i );
|
||
return TRUE;
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
Boolean SetLGAPopupToNamedItem( LGAPopup* whichMenu, const CStr255& itemText )
|
||
{
|
||
MenuHandle menuH;
|
||
short menuSize;
|
||
Str255 fontName;
|
||
|
||
menuH = whichMenu->GetMacMenuH();
|
||
menuSize = CountMItems( menuH );
|
||
|
||
for ( short i = 1; i <= menuSize; i++ )
|
||
{
|
||
::GetMenuItemText( menuH, i, fontName );
|
||
if ( itemText == (CStr255)fontName )
|
||
{
|
||
whichMenu->SetValue( i );
|
||
return TRUE;
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
unsigned long GetFreeSpaceInBytes( short vRefNum )
|
||
{
|
||
HVolumeParam pb;
|
||
OSErr err;
|
||
unsigned long result;
|
||
|
||
pb.ioCompletion = NULL;
|
||
pb.ioVolIndex = 0;
|
||
pb.ioNamePtr = NULL;
|
||
pb.ioVRefNum = vRefNum;
|
||
|
||
err = PBHGetVInfoSync( (HParmBlkPtr)&pb );
|
||
|
||
if ( err == noErr )
|
||
result = pb.ioVFrBlk * pb.ioVAlBlkSiz;
|
||
else
|
||
result = 0;
|
||
|
||
return result;
|
||
}
|
||
|
||
// <20> force a window to appear on the desktop
|
||
void ForceWindowOnScreen( LWindow* window )
|
||
{
|
||
// <20><>get the desktop region
|
||
StRegion desktopRgn( LMGetGrayRgn() );
|
||
|
||
Rect windowFrame;
|
||
window->CalcPortFrameRect( windowFrame );
|
||
windowFrame = PortToGlobalRect( window, windowFrame );
|
||
|
||
StRegion windowRgn( windowFrame );
|
||
|
||
StRegion destRgn;
|
||
Rect newRect;
|
||
|
||
::SectRgn( windowRgn, desktopRgn, destRgn );
|
||
|
||
if ( ::EmptyRgn( destRgn ) ||
|
||
!::EqualRgn( destRgn, windowRgn ) )
|
||
{
|
||
newRect = (**(static_cast<RgnHandle>(destRgn))).rgnBBox;
|
||
|
||
// <20> add 20 for title, 20 for menu bar
|
||
newRect.top = 40 + 2;
|
||
newRect.bottom = newRect.top + ( windowFrame.bottom - windowFrame.top );
|
||
newRect.left = 2;
|
||
newRect.right = newRect.left + ( windowFrame.right - windowFrame.left );
|
||
|
||
window->DoSetBounds( newRect );
|
||
}
|
||
|
||
}
|
||
|
||
void GrowWindowToScreenHeight( LWindow* win )
|
||
{
|
||
GDHandle device;
|
||
Rect windowFrame;
|
||
|
||
win->CalcPortFrameRect( windowFrame );
|
||
windowFrame = PortToGlobalRect( win, windowFrame );
|
||
|
||
device = WindowOnSingleDevice( win );
|
||
if ( device )
|
||
{
|
||
windowFrame.bottom = (**device).gdRect.bottom - 5;
|
||
win->DoSetBounds( windowFrame );
|
||
}
|
||
}
|
||
|
||
static
|
||
Boolean WillBeVisible( Rect& windowRect )
|
||
{
|
||
Rect newRect;
|
||
Boolean result = FALSE;
|
||
|
||
StRegion desktopRgn( LMGetGrayRgn() );
|
||
StRegion windowRgn( windowRect );
|
||
StRegion destRgn;
|
||
|
||
::SectRgn( windowRgn, desktopRgn, destRgn );
|
||
|
||
newRect = (**static_cast<RgnHandle>(destRgn)).rgnBBox;
|
||
|
||
if ( EmptyRgn( destRgn ) )
|
||
result = FALSE;
|
||
else if ( !EqualRect( &newRect, &windowRect ) )
|
||
result = FALSE;
|
||
else
|
||
result = TRUE;
|
||
|
||
return result;
|
||
}
|
||
|
||
void StaggerWindow( LWindow* win )
|
||
{
|
||
WindowPtr nextWindow;
|
||
LWindow* similarWindow;
|
||
Rect similarBounds;
|
||
Rect bounds;
|
||
Boolean changed = FALSE;
|
||
|
||
win->CalcPortFrameRect( bounds );
|
||
bounds = PortToGlobalRect( win, bounds );
|
||
// <20><>find the window with the same ID
|
||
// if it has the same top left corner, offset our rect by 20, 5
|
||
nextWindow = ::FrontWindow();
|
||
while ( nextWindow )
|
||
{
|
||
similarWindow = LWindow::FetchWindowObject( nextWindow );
|
||
nextWindow = (WindowPtr)( (WindowPeek)nextWindow )->nextWindow;
|
||
if ( similarWindow &&
|
||
similarWindow->GetPaneID() == win->GetPaneID() )
|
||
{
|
||
similarWindow->CalcPortFrameRect( similarBounds );
|
||
similarBounds = PortToGlobalRect( similarWindow, similarBounds );
|
||
|
||
if ( ( similarBounds.top == bounds.top ) &&
|
||
( similarBounds.left == bounds.left ) )
|
||
{
|
||
::OffsetRect( &bounds, 5, 20) ;
|
||
changed = TRUE;
|
||
// <20> loop again, because we might run into another window
|
||
nextWindow = ::FrontWindow();
|
||
}
|
||
}
|
||
}
|
||
if ( changed )
|
||
win->DoSetBounds( bounds );
|
||
}
|
||
|
||
GDHandle WindowOnSingleDevice( LWindow* win )
|
||
{
|
||
// <20> loop thru all GDevices
|
||
Rect windowFrame;
|
||
GDHandle device;
|
||
|
||
win->CalcPortFrameRect( windowFrame );
|
||
windowFrame = PortToGlobalRect( win, windowFrame );
|
||
|
||
device = GetDeviceList();
|
||
|
||
while ( device )
|
||
{
|
||
if ( UDrawingUtils::IsActiveScreenDevice( device ) )
|
||
{
|
||
Rect intersection;
|
||
// <20> find intersection of Window with this active screen Device
|
||
if ( ::SectRect( &windowFrame, &(**device).gdRect, &intersection ) )
|
||
{
|
||
// <20> window intersects this Device
|
||
if ( ::EqualRect( &windowFrame, &intersection ) )
|
||
return device;
|
||
}
|
||
|
||
}
|
||
device = GetNextDevice( device );
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
#define SAVE_VERSION 23
|
||
|
||
// <20> saving/restoring of the window's default state
|
||
Boolean RestoreDefaultWindowState(LWindow* inWindow)
|
||
{
|
||
if (inWindow == NULL)
|
||
return false;
|
||
|
||
// We are responsible for disposing of the window data
|
||
Handle theWindowData = CPrefs::ReadWindowData(inWindow->GetPaneID());
|
||
if (theWindowData == NULL)
|
||
return false;
|
||
|
||
// The destructor of the stream will kill the window data
|
||
LHandleStream stream(theWindowData);
|
||
|
||
Int32 version;
|
||
stream.ReadData(&version, sizeof( version ) );
|
||
if ( version != SAVE_VERSION )
|
||
return false;
|
||
|
||
Rect theWindowBounds;
|
||
stream.ReadData(&theWindowBounds, sizeof(theWindowBounds));
|
||
|
||
if (theWindowBounds.right > theWindowBounds.left &&
|
||
theWindowBounds.bottom > theWindowBounds.top &&
|
||
WillBeVisible(theWindowBounds) )
|
||
inWindow->DoSetBounds(theWindowBounds);
|
||
|
||
inWindow->RestorePlace(&stream);
|
||
ForceWindowOnScreen(inWindow);
|
||
|
||
return true;
|
||
}
|
||
|
||
void StoreDefaultWindowState( LWindow* win )
|
||
{
|
||
if ( !win )
|
||
return;
|
||
|
||
LHandleStream stream;
|
||
Rect windowBounds;
|
||
Int32 version = SAVE_VERSION;
|
||
|
||
stream.WriteData( &version, sizeof( version ) );
|
||
|
||
win->EstablishPort();
|
||
win->CalcPortFrameRect( windowBounds );
|
||
windowBounds = PortToGlobalRect( win, windowBounds );
|
||
stream.WriteData( &windowBounds, sizeof( windowBounds ) );
|
||
|
||
win->SavePlace( &stream );
|
||
|
||
CPrefs::WriteWindowData( stream.GetDataHandle(), win->GetPaneID() );
|
||
}
|
||
|
||
// Is front window modal? Used for command enabling
|
||
Boolean IsFrontWindowModal()
|
||
{
|
||
return UDesktop::FrontWindowIsModal();
|
||
}
|
||
|
||
// <20><>Fetch a window title resource and fill in the current profile name
|
||
void GetUserWindowTitle(short id, CStr255& title)
|
||
{
|
||
char profileName[32] = "";
|
||
int len = 32;
|
||
PREF_GetCharPref("profile.name", profileName, &len);
|
||
|
||
::GetIndString( title, WINDOW_TITLES_RESID, id );
|
||
|
||
StringParamText(title, profileName);
|
||
}
|
||
|
||
|
||
// Returns true if we are the front application
|
||
Boolean IsFrontApplication()
|
||
{
|
||
ProcessSerialNumber netscapeProcess;
|
||
ProcessSerialNumber frontProcess;
|
||
Boolean inFront;
|
||
|
||
OSErr err = ::GetCurrentProcess( &netscapeProcess );
|
||
if ( err != noErr )
|
||
return FALSE;
|
||
err = ::GetFrontProcess( &frontProcess );
|
||
if ( err != noErr )
|
||
return FALSE;
|
||
err = ::SameProcess( &frontProcess, &netscapeProcess, &inFront );
|
||
if ( err != noErr )
|
||
return FALSE;
|
||
return inFront;
|
||
}
|
||
|
||
void MakeFrontApplication()
|
||
{
|
||
ProcessSerialNumber netscapeProcess;
|
||
OSErr err = ::GetCurrentProcess( &netscapeProcess );
|
||
if (err == noErr)
|
||
SetFrontProcess(&netscapeProcess);
|
||
}
|
||
|
||
void FrameSubpaneSubtle( LView* view, LPane* pane )
|
||
{
|
||
Rect subFrame;
|
||
|
||
GetSubpaneRect( view, pane, subFrame );
|
||
::InsetRect( &subFrame, -1, -1 );
|
||
UGraphics::FrameRectSubtle( subFrame, true );
|
||
}
|
||
|
||
void GetSubpaneRgn( LView* view, LPane* pane, RgnHandle rgn )
|
||
{
|
||
Rect frame;
|
||
GetSubpaneRect( view, pane, frame );
|
||
::RectRgn( rgn, &frame );
|
||
}
|
||
|
||
void GetSubpaneRect( LView* view, LPane* pane, Rect& frame )
|
||
{
|
||
XP_ASSERT( view );
|
||
XP_ASSERT( pane );
|
||
pane->CalcPortFrameRect( frame );
|
||
view->PortToLocalPoint( *(Point*)&( frame.top ) );
|
||
view->PortToLocalPoint( *(Point*)&( frame.bottom) );
|
||
}
|
||
|
||
void WriteVersionTag( LStream* stream, Int32 version )
|
||
{
|
||
stream->WriteData( &version, sizeof( version ) );
|
||
}
|
||
|
||
Boolean ReadVersionTag( LStream* stream, Int32 version )
|
||
{
|
||
Int32 versionTag;
|
||
stream->ReadData( &versionTag, sizeof( versionTag ) );
|
||
return ( versionTag == version );
|
||
}
|
||
|
||
void TrySetCursor( int whichCursor )
|
||
{
|
||
Cursor** c = GetCursor( whichCursor );
|
||
if ( c )
|
||
SetCursor( *c );
|
||
#ifdef DEBUG
|
||
else
|
||
SysBeep( 1 );
|
||
#endif
|
||
}
|
||
|
||
void StripNewline( CStr255& msg )
|
||
{
|
||
if ( msg[ msg.Length() ] == '\n' )
|
||
msg[ msg.Length() ] = 0;
|
||
}
|
||
|
||
void StripDoubleCRs( CStr255& msg )
|
||
{
|
||
Boolean lastCR = FALSE;
|
||
for ( UInt32 i = 1; i < msg.Length(); i++ )
|
||
{
|
||
if ( msg[ i ] == CR)
|
||
{
|
||
if ( lastCR )
|
||
{
|
||
msg[ i - 1 ] = ' ';
|
||
lastCR = FALSE;
|
||
}
|
||
else
|
||
lastCR = TRUE;
|
||
}
|
||
else
|
||
lastCR = FALSE;
|
||
}
|
||
}
|
||
|
||
int ConvertCRtoLF(CStr255 & msg)
|
||
{
|
||
int ret = 0;
|
||
for ( long i = 1; i <= msg[0]; i++ )
|
||
if ( msg[ i ] == LF )
|
||
{
|
||
msg[ i ] = CR;
|
||
ret++;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
void RectFromTwoPoints( Point p1, Point p2, Rect &outRect)
|
||
{
|
||
outRect.top = MIN( p1.v, p2.v );
|
||
outRect.bottom = MAX( p1.v, p2.v );
|
||
outRect.left = MIN( p1.h, p2.h );
|
||
outRect.right = MAX( p1.h, p2.h );
|
||
}
|
||
|
||
// Return true if inEnclosingRect encloses any portion of inCheckRect
|
||
Boolean RectInRect(const Rect *inCheckRect, const Rect *inEnclosingRect) {
|
||
|
||
return (!::EmptyRect(inEnclosingRect) &&
|
||
!((inCheckRect->right <= inEnclosingRect->left) ||
|
||
(inCheckRect->bottom <= inEnclosingRect->top) ||
|
||
(inCheckRect->left >= inEnclosingRect->right) ||
|
||
(inCheckRect->top >= inEnclosingRect->bottom)));
|
||
}
|
||
|
||
const RGBColor rgbBlack = { 0x0000, 0x0000, 0x0000 };
|
||
const RGBColor rgbWhite = { 0xFFFF, 0xFFFF, 0xFFFF };
|
||
|
||
|
||
void DrawAntsRect( Rect&r, short mode )
|
||
{
|
||
::PenPat( &(UQDGlobals::GetQDGlobals()->gray) );
|
||
::PenMode( mode );
|
||
::RGBForeColor( &rgbBlack );
|
||
::RGBBackColor( &rgbWhite );
|
||
::FrameRect( &r );
|
||
}
|
||
|
||
void SafeGetFontInfo(ResIDT textTraits, FontInfo &outFontInfo)
|
||
{
|
||
StTextState textState;
|
||
UTextTraits::SetPortTextTraits(textTraits);
|
||
|
||
::GetFontInfo(&outFontInfo);
|
||
}
|
||
|
||
void FrameButton( const Rect& box, Boolean pushed )
|
||
{
|
||
UGraphics::FrameRectSubtle(box, pushed);
|
||
}
|
||
|
||
void HiliteRect( const Rect& r )
|
||
{
|
||
LMSetHiliteMode( LMGetHiliteMode() & ! ( 1 << hiliteBit ) ) ;
|
||
::InvertRect( &r );
|
||
}
|
||
|
||
void HiliteRgn( const RgnHandle& r )
|
||
{
|
||
LMSetHiliteMode( LMGetHiliteMode() & ! ( 1 << hiliteBit ) ) ;
|
||
::InvertRgn( r );
|
||
}
|
||
|
||
LPane* FindPaneHitBy( const Point& globalMouse )
|
||
{
|
||
Int16 part;
|
||
WindowPtr macWindowP;
|
||
LPane* inPane = NULL;
|
||
|
||
part = ::FindWindow( globalMouse, &macWindowP );
|
||
if ( macWindowP && part == inContent )
|
||
{
|
||
LWindow* whichWin;
|
||
whichWin = LWindow::FetchWindowObject( macWindowP );
|
||
if ( whichWin )
|
||
{
|
||
Point localMouse;
|
||
LPane* nextPane;
|
||
|
||
localMouse = globalMouse;
|
||
whichWin->GlobalToPortPoint( localMouse );
|
||
inPane = whichWin->FindSubPaneHitBy( localMouse.h, localMouse.v );
|
||
nextPane = inPane;
|
||
while ( nextPane )
|
||
{
|
||
inPane = nextPane;
|
||
nextPane = nextPane->FindSubPaneHitBy( localMouse.h, localMouse.v );
|
||
}
|
||
}
|
||
}
|
||
return inPane;
|
||
}
|
||
|
||
// ---------------------------------------------------------------
|
||
// Good 'ol Mac File Utilities
|
||
// ---------------------------------------------------------------
|
||
|
||
|
||
/*----------------------------------------------------------------------
|
||
Get a full pathname given a sig and type
|
||
In: sig of process to look for ('MOSS' for nav but should use emSignature instead)
|
||
type of process to look for (typically APPL)
|
||
Out:Returns the file path as a nul-terminated allocated block
|
||
that must be freed by the caller using XP_FREE.
|
||
Returns NULL on error;
|
||
|
||
------------------------------------------------------------------------*/
|
||
char *PathURLFromProcessSignature (OSType sig, OSType type)
|
||
{
|
||
ProcessSerialNumber targetPSN; // return process number
|
||
FSSpec targetFileSpec; // return file spec
|
||
char *appPath = NULL;
|
||
char *urlPath = NULL;
|
||
char prefix[] = "file://";
|
||
OSErr err;
|
||
|
||
// Get the file spec of our app
|
||
err = FindProcessBySignature(sig, type, targetPSN, &targetFileSpec);
|
||
if (err != noErr) return NULL;
|
||
|
||
appPath = CFileMgr::EncodedPathNameFromFSSpec(targetFileSpec, true);
|
||
if (appPath == NULL) return NULL;
|
||
|
||
urlPath = (char *)XP_ALLOC(strlen(appPath) + strlen(prefix) + 1);
|
||
if (urlPath == NULL) {
|
||
XP_FREE(appPath);
|
||
return NULL;
|
||
}
|
||
|
||
XP_STRCPY(urlPath, prefix);
|
||
XP_STRCPY(urlPath + strlen(prefix), appPath),
|
||
|
||
XP_FREE(appPath);
|
||
|
||
return urlPath;
|
||
}
|
||
|
||
// Given a process signature, gets its serial number
|
||
ProcessSerialNumber GetPSNBySig( OSType sig )
|
||
{
|
||
OSErr err;
|
||
FSSpec fileSpec;
|
||
ProcessInfoRec info;
|
||
ProcessSerialNumber psn;
|
||
|
||
info.processAppSpec = &fileSpec;
|
||
psn.highLongOfPSN = 0;
|
||
psn.lowLongOfPSN = kNoProcess;
|
||
while ( GetNextProcess( &psn ) == noErr)
|
||
{
|
||
info.processInfoLength = sizeof( ProcessInfoRec );
|
||
info.processName = NULL;
|
||
err= GetProcessInformation( &psn, &info );
|
||
if ( info.processSignature == sig )
|
||
return psn;
|
||
}
|
||
Throw_( paramErr );
|
||
return psn;
|
||
}
|
||
|
||
#define NO_PROCESS -1 // Constant used to indicate that there is no process in the PSN
|
||
// Creates an NoProcess serial number
|
||
ProcessSerialNumber MakeNoProcessPSN()
|
||
{
|
||
ProcessSerialNumber psn;
|
||
psn.highLongOfPSN = NO_PROCESS;
|
||
psn.lowLongOfPSN = NO_PROCESS;
|
||
return psn;
|
||
}
|
||
|
||
// Do we have a process
|
||
Boolean HasProcess( const ProcessSerialNumber& psn )
|
||
{
|
||
return ( ( psn.highLongOfPSN != NO_PROCESS ) ||
|
||
( psn.lowLongOfPSN!=NO_PROCESS ) );
|
||
}
|
||
|
||
// Given an application signature, finds the process
|
||
OSErr FindProcessBySignature(OSType sig,
|
||
OSType processType,
|
||
ProcessSerialNumber& psn,
|
||
FSSpec* fileSpec)
|
||
{
|
||
OSErr err;
|
||
|
||
ProcessInfoRec info;
|
||
|
||
psn.highLongOfPSN = 0;
|
||
psn.lowLongOfPSN = kNoProcess;
|
||
do
|
||
{
|
||
err= GetNextProcess(&psn);
|
||
if( err == noErr )
|
||
{
|
||
|
||
info.processInfoLength = sizeof(ProcessInfoRec);
|
||
info.processName = NULL;
|
||
info.processAppSpec = fileSpec;
|
||
|
||
err= GetProcessInformation(&psn, &info);
|
||
}
|
||
} while( (err == noErr) &&
|
||
((info.processSignature != sig) ||
|
||
(info.processType != processType)));
|
||
|
||
if( err == noErr )
|
||
psn = info.processNumber;
|
||
|
||
return err;
|
||
} // FindProcessBySignature
|
||
|
||
|
||
extern Boolean HasAppleEventObjects();
|
||
|
||
// On the 68K, the OSL glue checks to see whether it is
|
||
// installed. If it's not, the functions do nothing. On the PPC,
|
||
// if the Code Fragment Manager is unable to resolve an OSL
|
||
// stub, it performs an ExitToShell. Therefore we must
|
||
// insure that the OSL is available before calling any of
|
||
// its functions. These are called throughout PowerPlant's
|
||
// LModel* classes.
|
||
|
||
// gestaltObjectSupportLibraryInSystem = 1,
|
||
// gestaltObjectSupportLibraryPowerPCSupport = 2
|
||
// gestaltAppleEventsPresent
|
||
// gestaltScriptingSupport
|
||
// gestaltOSLInSystem <20><><EFBFBD> not gestaltObjectSupportLibraryPowerPCSupport
|
||
Boolean HasAppleEventObjects()
|
||
{
|
||
static Boolean isKnown = false, isInstalled = false;
|
||
|
||
|
||
if (!isKnown)
|
||
{
|
||
long attr = 0;
|
||
Boolean ae = UEnvironment::HasGestaltAttribute(gestaltAppleEventsAttr, gestaltAppleEventsPresent);
|
||
Boolean ppc = UEnvironment::HasGestaltAttribute(gestaltAppleEventsAttr, gestaltOSLInSystem);
|
||
#ifdef powerc
|
||
isInstalled = ae && ppc;
|
||
#else
|
||
isInstalled = 1; // we're linked with glue which always works
|
||
#endif
|
||
isKnown = true;
|
||
}
|
||
return isInstalled;
|
||
}
|
||
|
||
/*----------------------------------------------------------------------------
|
||
GetDropLocationDirectory
|
||
|
||
Given an 'alis' drop location AEDesc, return the volume reference
|
||
number and directory ID of the directory.
|
||
|
||
Entry: dropLocation = pointer to 'alis' AEDesc record.
|
||
|
||
Exit: function result = error code.
|
||
*volumeID = volume reference number.
|
||
*directoryID = directory ID.
|
||
|
||
From Apple "HFS Drag Sample" sample code.
|
||
----------------------------------------------------------------------------*/
|
||
OSErr GetDropLocationDirectory (AEDesc *dropLocation, long *directoryID, short *volumeID)
|
||
{
|
||
OSErr result;
|
||
AEDesc targetDescriptor; // 'fss ' descriptor for target directory
|
||
FSSpec targetLocation; // FSSpec for target directory
|
||
CInfoPBRec getTargetInfo; // paramBlock to get targetDirID
|
||
|
||
// Coerce the 'alis' descriptor to a 'fss ' descriptor
|
||
result = AECoerceDesc(dropLocation, typeFSS, &targetDescriptor);
|
||
if (result != noErr)
|
||
return (result);
|
||
|
||
// Extract the FSSpec from targetDescriptor
|
||
BlockMoveData((Ptr)(*targetDescriptor.dataHandle), (Ptr)&targetLocation, sizeof(FSSpec));
|
||
|
||
result = AEDisposeDesc(&targetDescriptor);
|
||
if (result != noErr)
|
||
return (result);
|
||
|
||
// Use PBGetCatInfo to get the directoryID of the target directory from the FSSpec
|
||
|
||
getTargetInfo.dirInfo.ioNamePtr = targetLocation.name;
|
||
getTargetInfo.dirInfo.ioVRefNum = targetLocation.vRefNum;
|
||
getTargetInfo.dirInfo.ioFDirIndex = 0;
|
||
getTargetInfo.dirInfo.ioDrDirID = targetLocation.parID;
|
||
|
||
result = PBGetCatInfoSync(&getTargetInfo);
|
||
if (result != noErr)
|
||
return (result);
|
||
|
||
// return directory ID and volume reference number
|
||
|
||
*directoryID = getTargetInfo.dirInfo.ioDrDirID;
|
||
*volumeID = targetLocation.vRefNum;
|
||
|
||
return result;
|
||
}
|
||
|
||
/*----------------------------------------------------------------------------
|
||
DragTargetWasTrash
|
||
|
||
Check to see if the target of a drag and drop was the Finder trashcan.
|
||
|
||
Entry: dragRef = drag reference.
|
||
|
||
Exit: function result = true if target was trash.
|
||
----------------------------------------------------------------------------*/
|
||
|
||
Boolean DragTargetWasTrash (DragReference dragRef)
|
||
{
|
||
AEDesc dropLocation;
|
||
OSErr err = noErr;
|
||
long dropDirID, trashDirID;
|
||
short dropVRefNum, trashVRefNum;
|
||
|
||
err = GetDropLocation(dragRef, &dropLocation);
|
||
if (err != noErr) return false;
|
||
|
||
if (dropLocation.descriptorType == typeNull) goto exit;
|
||
|
||
err = GetDropLocationDirectory(&dropLocation, &dropDirID, &dropVRefNum);
|
||
if (err != noErr) goto exit;
|
||
|
||
err = FindFolder(dropVRefNum, kTrashFolderType, false, &trashVRefNum,
|
||
&trashDirID);
|
||
if (err != noErr) goto exit;
|
||
|
||
if (dropVRefNum != trashVRefNum || dropDirID != trashDirID) goto exit;
|
||
|
||
AEDisposeDesc(&dropLocation);
|
||
return true;
|
||
|
||
exit:
|
||
|
||
AEDisposeDesc(&dropLocation);
|
||
return false;
|
||
}
|
||
|
||
|
||
long LArrowControl::fLastTicks = 0;
|
||
long LArrowControl::fDelay = 20;
|
||
long LArrowControl::fHits = 0;
|
||
|
||
LArrowControl::LArrowControl( const SPaneInfo& inPaneInfo, MessageT valueMessage ):
|
||
LControl( inPaneInfo, valueMessage, 0, 0, 0 )
|
||
{
|
||
mCurrPict = mArrowsPict;
|
||
}
|
||
|
||
void LArrowControl::HiliteControl( Int16 inHotSpot, Boolean inCurrInside )
|
||
{
|
||
if ( inCurrInside )
|
||
{
|
||
if ( inHotSpot == mTopHalf )
|
||
mCurrPict = mArrowsTopLit;
|
||
else if ( inHotSpot == mBottomHalf )
|
||
mCurrPict = mArrowsBotLit;
|
||
}
|
||
else
|
||
mCurrPict = mArrowsPict;
|
||
|
||
DrawSelf();
|
||
}
|
||
|
||
void LArrowControl::DrawSelf()
|
||
{
|
||
PicHandle macPictureH = GetPicture( mCurrPict );
|
||
if ( macPictureH )
|
||
{
|
||
Rect pictureBounds;
|
||
|
||
CalcLocalFrameRect( pictureBounds );
|
||
::DrawPicture( macPictureH, &pictureBounds );
|
||
|
||
}
|
||
}
|
||
|
||
Boolean LArrowControl::PointInHotSpot( Point inPoint, Int16 inHotSpot ) const
|
||
{
|
||
Rect localFrame;
|
||
Int16 midPoint;
|
||
|
||
CalcLocalFrameRect( localFrame );
|
||
midPoint = ( localFrame.bottom - localFrame.top ) / 2;
|
||
|
||
if ( inHotSpot == mTopHalf )
|
||
localFrame.bottom = midPoint;
|
||
else
|
||
localFrame.top = midPoint;
|
||
|
||
return PtInRect( inPoint, &localFrame );
|
||
}
|
||
|
||
Int16 LArrowControl::FindHotSpot( Point inPoint ) const
|
||
{
|
||
Rect localFrame;
|
||
Int16 midPoint;
|
||
|
||
CalcLocalFrameRect( localFrame );
|
||
midPoint = ( localFrame.bottom - localFrame.top ) / 2;
|
||
|
||
if ( inPoint.v < midPoint )
|
||
return mTopHalf;
|
||
else
|
||
return mBottomHalf;
|
||
}
|
||
|
||
void LArrowControl::HotSpotAction( Int16 inHotSpot, Boolean inCurrInside, Boolean inPrevInside )
|
||
{
|
||
|
||
if ( inCurrInside != inPrevInside )
|
||
{
|
||
FocusDraw();
|
||
HiliteControl( inHotSpot, inCurrInside );
|
||
}
|
||
|
||
if ( inCurrInside )
|
||
{
|
||
if ( ( ::TickCount() - fLastTicks ) < fDelay )
|
||
return;
|
||
|
||
if ( fDelay == 0 )
|
||
fDelay = 20;
|
||
|
||
fHits++;
|
||
if ( fHits > 6 )
|
||
fDelay = 5;
|
||
|
||
fLastTicks = TickCount();
|
||
|
||
BroadcastMessage( mValueMessage, &inHotSpot );
|
||
}
|
||
else
|
||
{
|
||
fHits = 0;
|
||
fDelay = 20;
|
||
}
|
||
}
|
||
|
||
void LArrowControl::HotSpotResult( Int16 /*inHotSpot*/ )
|
||
{
|
||
mCurrPict = mArrowsPict;
|
||
|
||
DrawSelf();
|
||
|
||
fHits = 0;
|
||
fDelay = 0;
|
||
}
|
||
|
||
/*=============================================================================
|
||
File & Stream Classes Utilities
|
||
=============================================================================*/
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
StOpenResFile opens the resource fork and closes it later
|
||
-----------------------------------------------------------------------------*/
|
||
|
||
StOpenResFile::StOpenResFile (LFile *file, short perms)
|
||
{
|
||
fFile = file;
|
||
file->OpenResourceFork (perms);
|
||
}
|
||
|
||
StOpenResFile::~StOpenResFile ()
|
||
{
|
||
// LAM may not be required to UpdateResFile
|
||
// CloseResFile is supposed to call UpdateResFile
|
||
//::UpdateResFile (fFile->GetResourceForkRefNum());
|
||
fFile->CloseResourceFork();
|
||
}
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
StUseResFile uses an open resource fork and stops using it later.
|
||
-----------------------------------------------------------------------------*/
|
||
|
||
StUseResFile::StUseResFile( short refnum )
|
||
{
|
||
fPrevResFile = CurResFile();
|
||
|
||
if (refnum != -1)
|
||
UseResFile( refnum );
|
||
}
|
||
|
||
StUseResFile::~StUseResFile()
|
||
{
|
||
UseResFile( fPrevResFile );
|
||
}
|
||
|
||
//========================================================================================
|
||
// CLASS CStringListRsrc
|
||
//========================================================================================
|
||
|
||
typedef short** IntegerHandle;
|
||
//----------------------------------------------------------------------------------------
|
||
// CStringListRsrc::GetString:
|
||
//----------------------------------------------------------------------------------------
|
||
|
||
void CStringListRsrc::GetString(short index, CStr255& theString) const
|
||
{
|
||
if (fStrListID != 0)
|
||
GetIndString(theString, fStrListID, index);
|
||
} // CStringListRsrc::GetString
|
||
|
||
//----------------------------------------------------------------------------------------
|
||
// CStringListRsrc::FindString:
|
||
//----------------------------------------------------------------------------------------
|
||
|
||
short CStringListRsrc::FindString(const CStr255& theString, Boolean addString)
|
||
{
|
||
CStr255 testString;
|
||
short numStrings = this->CountStrings();
|
||
|
||
for (short i = 1; i <= numStrings; ++i)
|
||
{
|
||
this->GetString(i, testString);
|
||
|
||
if (testString == theString)
|
||
return i; // found it! return the index
|
||
}
|
||
|
||
// CString is not found, should we add it?
|
||
if (addString == kAddString)
|
||
return this->AppendString(theString); // added it! return the index
|
||
|
||
// CString not found...sigh!
|
||
return 0;
|
||
} // CStringListRsrc::FindString
|
||
|
||
//----------------------------------------------------------------------------------------
|
||
// CStringListRsrc::AppendString:
|
||
//----------------------------------------------------------------------------------------
|
||
|
||
short CStringListRsrc::AppendString(const CStr255& theString)
|
||
{
|
||
long result;
|
||
short totalStringLength = theString.Length() + kLengthByte;
|
||
Handle aHandle = Get1Resource('STR#', fStrListID);
|
||
if (aHandle)
|
||
{
|
||
if (!*aHandle)
|
||
::LoadResource(aHandle);
|
||
|
||
if (*aHandle)
|
||
{
|
||
SInt8 flags = ::HGetState(aHandle);
|
||
::HNoPurge(aHandle);
|
||
Size itsSize = GetHandleSize(aHandle);
|
||
if (itsSize > 0)
|
||
{
|
||
short numStrings = this->CountStrings();
|
||
SetHandleSize(aHandle, itsSize + totalStringLength);
|
||
(**((IntegerHandle) aHandle)) = ++numStrings; // increment the count of strings in the STR# resource
|
||
|
||
// needs a failure handler
|
||
result = Munger(aHandle, itsSize, NULL, totalStringLength, &theString, totalStringLength);
|
||
if (result > 0)
|
||
{
|
||
// mark it as changed
|
||
ChangedResource(aHandle);
|
||
::HSetState(aHandle, flags);
|
||
|
||
return numStrings;
|
||
}
|
||
::HSetState(aHandle, flags);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// must create the resource...
|
||
aHandle = NewHandle(sizeof(short) + totalStringLength);
|
||
(**((IntegerHandle) aHandle)) = 1; // set the count of strings in the STR# resource
|
||
result = Munger(aHandle, sizeof(short), NULL, totalStringLength, &theString, totalStringLength);
|
||
if (result > 0)
|
||
{
|
||
AddResource(aHandle, 'STR#', fStrListID, fStrListRsrcName);
|
||
ThrowIfResError_(); // if fails, it's most likely because the file is read-only
|
||
|
||
SetResAttrs(aHandle, resPurgeable);
|
||
|
||
// Need the following ChangedResource call because the SetResAttrs call on the previous
|
||
// line cleared the "resChanged" attribute of the resource.
|
||
ChangedResource(aHandle);
|
||
|
||
return 1;
|
||
}
|
||
}
|
||
return 0;
|
||
} // CStringListRsrc::AppendString
|
||
|
||
//----------------------------------------------------------------------------------------
|
||
// CStringListRsrc::ClearAll:
|
||
//----------------------------------------------------------------------------------------
|
||
|
||
void CStringListRsrc::ClearAll()
|
||
{
|
||
Handle aHandle = Get1Resource('STR#', fStrListID);
|
||
if (aHandle)
|
||
{
|
||
if (!*aHandle)
|
||
::LoadResource(aHandle);
|
||
|
||
if (*aHandle)
|
||
{
|
||
SInt8 flags = ::HGetState(aHandle);
|
||
::HNoPurge(aHandle);
|
||
SetHandleSize(aHandle, sizeof(short));
|
||
(**((IntegerHandle) aHandle)) = 0; // set the count of strings in the STR# resource
|
||
|
||
// mark it as changed
|
||
ChangedResource(aHandle);
|
||
::HSetState(aHandle, flags);
|
||
}
|
||
}
|
||
} // CStringListRsrc::ClearAll
|
||
|
||
//----------------------------------------------------------------------------------------
|
||
// CStringListRsrc::CountStrings:
|
||
//----------------------------------------------------------------------------------------
|
||
|
||
short CStringListRsrc::CountStrings() const
|
||
{
|
||
// return the leading integer in the STR# resource:
|
||
//
|
||
// type 'STR#' {
|
||
// integer = $$Countof(StringArray);
|
||
// array StringArray {
|
||
// pstring;
|
||
// };
|
||
// };
|
||
|
||
Handle aHandle = Get1Resource('STR#', fStrListID);
|
||
if (aHandle)
|
||
{
|
||
if (!*aHandle)
|
||
::LoadResource(aHandle);
|
||
|
||
if (*aHandle)
|
||
return **((IntegerHandle) aHandle);
|
||
}
|
||
return 0;
|
||
} // CStringListRsrc::CountStrings
|
||
|
||
//----------------------------------------------------------------------------------------
|
||
// CStringListRsrc::GetListName:
|
||
//----------------------------------------------------------------------------------------
|
||
|
||
void CStringListRsrc::GetListName(CStr255& theString)
|
||
{
|
||
// Do we have the name in our field?
|
||
if ( fStrListRsrcName.Length () > 0 )
|
||
theString = fStrListRsrcName;
|
||
else // We don't have the name so try and get it from the resource
|
||
{
|
||
short itsRsrcID;
|
||
CStr255 itsName;
|
||
ResType itsType;
|
||
|
||
// Get the resource's handle
|
||
Handle aHandle = Get1Resource('STR#', fStrListID);
|
||
if (aHandle)
|
||
{
|
||
// Extract the resource info from the handle
|
||
GetResInfo ( aHandle, &itsRsrcID, &itsType, itsName );
|
||
if ( itsName.Length () > 0 )
|
||
{
|
||
theString = itsName;
|
||
|
||
// Store the name in our field
|
||
fStrListRsrcName = theString;
|
||
}
|
||
|
||
ReleaseResource ( aHandle );
|
||
}
|
||
else // Sorry we don't have anything so return an empty CString
|
||
theString = CStr255::sEmptyString;
|
||
|
||
}
|
||
} // CStringListRsrc::GetListName
|
||
|
||
//----------------------------------------------------------------------------------------
|
||
// CStringListRsrc::RemoveAt:
|
||
//----------------------------------------------------------------------------------------
|
||
|
||
void CStringListRsrc::RemoveAt(short index)
|
||
{
|
||
if ((index > 0) && (index <= this->CountStrings()))
|
||
{
|
||
Handle aHandle = Get1Resource('STR#', fStrListID);
|
||
if (aHandle)
|
||
{
|
||
if (!*aHandle)
|
||
::LoadResource(aHandle);
|
||
|
||
if (*aHandle)
|
||
{
|
||
SInt8 flags = ::HGetState(aHandle);
|
||
::HNoPurge(aHandle);
|
||
|
||
Size originalSize = GetHandleSize(aHandle);
|
||
|
||
// determine the accumulated size
|
||
Size accumulatedSize = sizeof(short); // the accumulated size is the size of the count
|
||
for (short i = 1; i < index; ++i)
|
||
accumulatedSize += (*((CStringPtr) (*aHandle + accumulatedSize))).Length() + kLengthByte;
|
||
|
||
// determine the actual CString size
|
||
Size stringSize = (*((CStringPtr) (*aHandle + accumulatedSize))).Length() + kLengthByte;
|
||
|
||
// move the the data in the handle
|
||
BlockMoveData(*aHandle + accumulatedSize + stringSize, *aHandle + accumulatedSize,
|
||
originalSize - accumulatedSize - stringSize);
|
||
|
||
// trim the handle down to its new size
|
||
SetHandleSize(aHandle, originalSize - stringSize);
|
||
|
||
// decrement count of strings in STR# resource
|
||
--(**((IntegerHandle) aHandle));
|
||
|
||
// mark it as changed
|
||
ChangedResource(aHandle);
|
||
|
||
::HSetState(aHandle, flags);
|
||
}
|
||
#if qDebugMsg
|
||
else
|
||
fprintf(stderr, "CStringListRsrc::RemoveAt can't load STR# = %d.\n", fStrListID);
|
||
#endif
|
||
}
|
||
#if qDebugMsg
|
||
else
|
||
fprintf(stderr, "CStringListRsrc::RemoveAt can't find STR# = %d.\n", fStrListID);
|
||
#endif
|
||
}
|
||
#if qDebugMsg
|
||
else
|
||
fprintf(stderr, "CStringListRsrc::RemoveAt there's no CString at %d to remove!\n", index);
|
||
#endif
|
||
} // CStringListRsrc::RemoveAt
|
||
|
||
//----------------------------------------------------------------------------------------
|
||
// CStringListRsrc::ReplaceAt:
|
||
//----------------------------------------------------------------------------------------
|
||
|
||
void CStringListRsrc::ReplaceAt(const CStr255& theString, short index)
|
||
{
|
||
if ((index > 0) && (index <= this->CountStrings()))
|
||
{
|
||
Handle aHandle = Get1Resource('STR#', fStrListID);
|
||
if (aHandle)
|
||
{
|
||
if (!*aHandle)
|
||
::LoadResource(aHandle);
|
||
|
||
if (*aHandle)
|
||
{
|
||
SInt8 flags = ::HGetState(aHandle);
|
||
::HNoPurge(aHandle);
|
||
|
||
Size newStringSize = theString.Length() + kLengthByte; // the actual CString size
|
||
Size originalSize = GetHandleSize(aHandle);
|
||
|
||
// determine the accumulated size of the valid portion of the resource
|
||
Size accumulatedSize = sizeof(short); // the accumulated size is the size of the count
|
||
for (short i = 1; i < index; ++i)
|
||
accumulatedSize += (*((CStringPtr) (*aHandle + accumulatedSize))).Length() + kLengthByte;
|
||
|
||
// determine the actual CString size
|
||
Size oldStringSize = (*((CStringPtr) (*aHandle + accumulatedSize))).Length() + kLengthByte;
|
||
|
||
// determine the new handle size
|
||
Size newHandleSize = originalSize + (newStringSize - oldStringSize);
|
||
|
||
// determine whether to grow or shrink the handle?
|
||
if (newStringSize > oldStringSize)
|
||
{
|
||
// grow the handle
|
||
SetHandleSize(aHandle, newHandleSize);
|
||
|
||
// move the bytes
|
||
BlockMoveData(*aHandle + accumulatedSize + oldStringSize, *aHandle + accumulatedSize + newStringSize,
|
||
originalSize - accumulatedSize - oldStringSize);
|
||
}
|
||
else if (oldStringSize > newStringSize)
|
||
{
|
||
// move the bytes
|
||
BlockMoveData(*aHandle + accumulatedSize + oldStringSize, *aHandle + accumulatedSize + newStringSize,
|
||
originalSize - accumulatedSize - oldStringSize);
|
||
|
||
// shrink the handle
|
||
SetHandleSize(aHandle, newHandleSize);
|
||
}
|
||
|
||
// assign the CString
|
||
*((CStr255*) (*aHandle + accumulatedSize)) = theString;
|
||
|
||
// mark it as changed
|
||
ChangedResource(aHandle);
|
||
|
||
::HSetState(aHandle, flags);
|
||
}
|
||
#if qDebugMsg
|
||
else
|
||
fprintf(stderr, "CStringListRsrc::ReplaceAt can't load STR# = %d.\n", fStrListID);
|
||
#endif
|
||
}
|
||
#if qDebugMsg
|
||
else
|
||
fprintf(stderr, "CStringListRsrc::ReplaceAt can't find STR# = %d.\n", fStrListID);
|
||
#endif
|
||
}
|
||
#if qDebugMsg
|
||
else
|
||
fprintf(stderr, "CStringListRsrc::ReplaceAt there's no CString at %d to replace!\n", index);
|
||
#endif
|
||
} // CStringListRsrc::ReplaceAt
|
||
|
||
|
||
|
||
|
||
StWatchCursor::StWatchCursor() { ::SetCursor( (CursPtr)*(::GetCursor(watchCursor)) ); }
|
||
StWatchCursor::~StWatchCursor() { ::SetCursor( &(UQDGlobals::GetQDGlobals()->arrow) ); }
|
||
|
||
//-----------------------------------
|
||
void StringParamText(
|
||
CStr255& ioFormatString,
|
||
SInt32 inReplaceNumber0,
|
||
SInt32 inReplaceNumber1,
|
||
SInt32 inReplaceNumber2,
|
||
SInt32 inReplaceNumber3)
|
||
// Replace the characters "^0" ..."^3"within ioString with numerals.
|
||
// If "^0" or "^1" is not found in ioString, the method does nothing.
|
||
//-----------------------------------
|
||
{
|
||
char t0[15], t1[15], t2[15], t3[15];
|
||
sprintf(t0, "%ld", inReplaceNumber0);
|
||
sprintf(t1, "%ld", inReplaceNumber1);
|
||
sprintf(t2, "%ld", inReplaceNumber2);
|
||
sprintf(t3, "%ld", inReplaceNumber3);
|
||
::StringParamText(ioFormatString, t0, t1, t2, t3);
|
||
}
|
||
|
||
//-----------------------------------
|
||
void StringParamText(
|
||
CStr255& ioFormatString,
|
||
const char* inReplaceText0,
|
||
const char* inReplaceText1,
|
||
const char* inReplaceText2,
|
||
const char* inReplaceText3)
|
||
// Replace the substrings "^0" ..."^3" within ioString with inReplaceText0 ... inReplaceText3.
|
||
// (substring is just removed if inReplaceTextn is null).
|
||
// If any of the substrings "^0"..."^3" is not found in ioString, nothing happens there.
|
||
//-----------------------------------
|
||
{
|
||
LStr255 resultString = (ConstStringPtr)&ioFormatString;
|
||
char target[] = "^0";
|
||
const char* replaceString[] = {
|
||
inReplaceText0,
|
||
inReplaceText1,
|
||
inReplaceText2,
|
||
inReplaceText3 };
|
||
for (int i = 0; i < 4; i++)
|
||
{
|
||
UInt8 position = resultString.Find(target, 1);
|
||
if ( position )
|
||
{
|
||
const char* rs = replaceString[i];
|
||
if ( rs )
|
||
resultString.Replace(position, 2, rs, strlen(rs));
|
||
else
|
||
resultString.Remove(position, 2);
|
||
}
|
||
target[1]++; // morph it into "^1" etc. ASCII standard supports this.
|
||
}
|
||
ioFormatString = (ConstStringPtr)resultString;
|
||
}
|
||
|
||
// This code is taken from June 97 Dev.CD
|
||
enum
|
||
{
|
||
kPromisedFlavor = 'fssP',
|
||
kPromisedFlavorFindFile = 'rWm1'
|
||
};
|
||
|
||
static Size MinimumBytesForFSSpec (const FSSpec *fss)
|
||
{
|
||
//
|
||
// Some senders don't bother sending the unused bytes of the
|
||
// file name. This function helps make sure the FSSpec is
|
||
// minimally sane by computing the minimum number of bytes it
|
||
// would take to store it.
|
||
//
|
||
// THIS FUNCTION CANNOT MOVE MEMORY.
|
||
//
|
||
|
||
return sizeof (*fss) - sizeof (fss->name) + *(fss->name) + 1;
|
||
}
|
||
|
||
OSErr GetHFSFlavorFromPromise
|
||
(DragReference dragRef, ItemReference itemRef,
|
||
HFSFlavor *hfs, Boolean isSupposedlyFromFindFile)
|
||
{
|
||
OSErr err = noErr;
|
||
PromiseHFSFlavor phfs;
|
||
Size size = sizeof (phfs);
|
||
|
||
err = GetFlavorData
|
||
(dragRef,itemRef,flavorTypePromiseHFS,&phfs,&size,0);
|
||
|
||
if (!err)
|
||
{
|
||
if (size != sizeof (phfs))
|
||
err = cantGetFlavorErr;
|
||
else
|
||
{
|
||
Boolean isFromFindFile =
|
||
phfs.promisedFlavor == kPromisedFlavorFindFile;
|
||
|
||
if (isSupposedlyFromFindFile != isFromFindFile)
|
||
err = paramErr;
|
||
else
|
||
{
|
||
size = sizeof (hfs->fileSpec);
|
||
err = GetFlavorData
|
||
(dragRef,itemRef,phfs.promisedFlavor,
|
||
&(hfs->fileSpec),&size,0);
|
||
|
||
if (!err)
|
||
{
|
||
Size minSize = MinimumBytesForFSSpec
|
||
(&(hfs->fileSpec));
|
||
|
||
if (size < minSize)
|
||
err = cantGetFlavorErr;
|
||
else
|
||
{
|
||
hfs->fileType = phfs.fileType;
|
||
hfs->fileCreator = phfs.fileCreator;
|
||
hfs->fdFlags = phfs.fdFlags;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return err;
|
||
}
|
||
// End of cut and paste
|
||
|
||
|
||
StSpinningBeachBallCursor::StSpinningBeachBallCursor ()
|
||
{
|
||
startAsyncCursors();
|
||
}
|
||
|
||
StSpinningBeachBallCursor::~StSpinningBeachBallCursor()
|
||
{
|
||
stopAsyncCursors();
|
||
}
|