Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
TumblerSource/Tumbler_drag.c
// Tumbler_drag.c |
// |
// Dragging routines. The code in this file implements the geometry |
// dragging features of this program. The last function in this file, |
// DoDragObjects is called when a mouseDown is detected in the hilite region |
// of the current object. |
// |
// Here's some background from Nick for debugging this mess. First off the drag manager |
// is not a simple animal. |
// |
// High-level or source-level debuggers won't work with Drag Manager callback routines. |
// That's because of the way the Drag Manager performs process switching. The only |
// high-level debugger that does work with the Drag Manager is VoodooMonkey, an "experimental |
// prototype" debugger you can find on the November Developer CD. Note that VoodooMonkey |
// is unsupported by Apple. The other more-supportable option is to use MacsBug (or your |
// favorite low-level debugger) for real-time debugging. But since this 3d stuff will only |
// work on power macintosh cpu's (unless you have the souce code, which developers don't :0>) |
// MacsBug won't help you much. And I was using a version of CodeWarrior that didn't seem to |
// want to put any symbols in, which means Macsbug is not really an option (debugging what |
// MB thinks is the 68k equivalent of the actual PPC instructions, with no symbols, ain't |
// my idea of fun. And don't think DebugStr will help you any - if you are running with |
// the MetroWerks (MW) high level debugger, your mAchine will crash big time. MW debugger |
// wants to display the debugstr in a nice little dialog, which means it has to do a context |
// switch. Why is this bad... read on McDuff: |
// |
// The Drag Manager is actually making full context switches for each process that has |
// tracking/receive handlers as an object is dragged over a valid drag region. While this |
// may sound a bit drastic or scary, it isn't really that bad because a drag is a modal operation, |
// and as long as the user is dragging an object, the System (namely the Drag Manager) is in |
// control to call tracking and receive handlers as appropriate. So when your receive handler |
// is called and all events pending for your process have been handled, your application is |
// eliglble for a context switch the next time WaitNextEvent is called. And when WNE is called |
// and a context switch occurs, the Drag Manager has lost track over what process is currently |
// the context. This is also why you cannot use source-level debuggers to debug drag handlers, |
// because context switches are controlled by those debuggers, and once you're in a Drag you |
// cannot change the Process Manager state. |
// |
// In case you're interested, one technique that works well for receive handlers is to send an |
// Apple event to yourself with the relevant information about the drag, and process it at |
// WaitNextEvent time. Sending an Apple event to yourself can be done even if you're not the |
// frontmost application, and it allows you to process the Drag at WaitNextEvent time, meaning |
// you can call your Alert routine and change process states without any problems. Another |
// benefit to this approach is that you'll be able to use source level debuggers to work on |
// your receive handlers. |
// |
// The only thing to beware of if you do this (and this is what do here) is to get the PSN |
// directly - AppleEvents.h gives a constant (kCurrentProcess) that you can stick in the low |
// longword of the PSN that will cause the event to essentially be dispatched as a function |
// call, and that is not what we want here. By getting the process serial number (PSN) of |
// our own process and using that in the AppleEvent we ensure that the event is dispatched |
// to our process so we can deal with it in the main event loop, rather than being mapped into |
// and unwanted funtion call (which since we would still be in the drag managers context would |
// prevent us from being able to debug using anything reasonable). Check out Tumbler_AEVT for |
// more details on this. |
// |
// Nitin Gantatra whined so much that I'd stolen the comments above, that I feel compelled to |
// add: |
// |
// Author of lame gratuitous drag manager comments: Jim Luther |
// |
// Author: Nick Thompson, based on the original by |
// Pablo Fernicola, based on Rob Johnson's drag text sample, |
// with extensive stealing from grobbins SimpleDrag sample. |
// |
// Modification history: |
// |
// 11/26/94 nick removed dead code, tightened up the drag code, based on |
// grobbins' excellent simpledrag sample |
// 11/25/94 nick added events for dragging, this lets us do |
// source level debugging of the drag receiver, see Tumbler_aevt. |
// |
// Copyright © 1992-95 Apple Computer, Inc., All Rights Reserved |
// |
// to do: store the document reference as a handle in the window's refcon |
// |
#define NAGELS_DEMO // pre-allocate handles |
#include <QDOffscreen.h> |
#include <Folders.h> |
#include <Drag.h> |
#include <SegLoad.h> |
#include <Types.h> |
#include "Tumbler_globals.h" |
#include "QD3D.h" |
#include "QD3DGroup.h" |
#include "QD3DStorage.h" |
#include "QD3DIO.h" |
#include "QD3DView.h" |
#include "QD3DDrawContext.h" |
#include "QD3DPick.h" |
#include "QD3DShader.h" |
#include "QD3DTransform.h" |
#include "QD3DGroup.h" |
#include "Tumbler_prototypes.h" |
#include "Tumbler_file.h" |
#include "Tumbler_resources.h" |
#include "Tumbler_offscreen.h" |
#include "Tumbler_AEVT.h" // grab our apleEvent handlers and data structures |
// used for debugging |
#include "Tumbler_drag.h" |
// Can use custom drawing procedure. Just uncomment out this line: |
// #define USE_CUSTOM_DRAWING |
// global data for my Drag Manager handlers |
typedef struct DragHandlerGlobals |
{ |
Boolean acceptableDragFlag; |
Boolean windowIsHilightedFlag; |
} ; |
typedef struct DragHandlerGlobals |
DragHandlerGlobals, *DragHandlerGlobalsPtr; |
static DragHandlerGlobals pDragHandlerGlobals; |
//----------------------------------------------------------------------- |
// MyDrawingProc |
// |
// Simple drawing proc for dragging objects. This drawing procedure is very similar to |
// the Drag Manager's built in drawing proc, except that it uses a solid black pattern |
// to draw the region instead of using the dithered gray pattern. |
// |
// DONT USE THIS ON POWERPC as there is a quickdraw bug that leaves artifacts |
// everywhere (talk to Nitin Ganatra for the gory details). |
static |
pascal OSErr MyDrawingProc(DragRegionMessage message, |
RgnHandle showRgn, Point showOrigin, |
RgnHandle hideRgn, Point hideOrigin, |
void *dragDrawingRefCon, DragReference theDragRef) |
{ OSErr result = paramErr; |
RgnHandle tempRgn; |
switch(message) { |
case dragRegionBegin: |
// |
// No initialization necessary for our drawing proc. Make sure noErr |
// is returned, otherwise the Drag Manager will revert back to it's |
// built in drawing proc. |
// |
result = noErr; |
break; |
case dragRegionDraw: |
// |
// Find the difference between the region needed to be shown and the |
// region needed to be hidden. Inverting the difference removes the pixels |
// that must be hidden and shows the pixels that must be shown in one step. |
// |
XorRgn(showRgn, hideRgn, tempRgn = NewRgn()); |
InvertRgn(tempRgn); |
DisposeRgn(tempRgn); |
result = noErr; |
break; |
case dragRegionHide: |
// |
// Simply hide the region given to us by inverting it. |
// |
InvertRgn(hideRgn); |
result = noErr; |
break; |
} |
return(result); |
} |
//------------------------------------------------------------------------------------ |
// MySendDataProc - provides data for the drag when requested. |
static pascal OSErr MySendDataProc(FlavorType theType, void *refCon, |
ItemReference theItem, DragReference theDrag) |
{ |
DocumentPtr theDocument = (DocumentPtr ) refCon; |
unsigned long validSize; |
// so what do they want?? |
if (theType == '3DMF') { |
if( theDocument->documentGroup ) { |
Handle theData; |
TQ3StorageObject storage; |
TQ3FileObject fd; |
TQ3TransformObject xform; |
TQ3GroupPosition position; |
Boolean didAllocate = false; // set to true if we did allocate memory |
if( Q3Object_IsType(theDocument->documentGroup, kQ3DisplayGroupTypeOrdered)) { |
Q3Group_GetFirstPositionOfType(theDocument->documentGroup, kQ3ShapeTypeTransform,&position); |
} else { |
Q3Group_GetFirstPosition(theDocument->documentGroup, &position); |
} |
xform = Q3MatrixTransform_New( &theDocument->modelRotation); |
position = Q3Group_AddObjectBefore(theDocument->documentGroup, position, xform); |
Q3Object_Dispose(xform); |
#ifdef NAGELS_DEMO |
// HO HO HO. Actually we *do* need a way to approximate the |
// size this handle needs to be so we can preflight |
if((theData = NewHandle(1024 * 1024 )) != nil) { // ask for 1M |
MoveHHi( theData ) ; |
HLock( theData ) ; |
didAllocate = true ; |
storage = Q3HandleStorage_New( theData, GetHandleSize( theData ) ); |
} |
else { |
storage = Q3HandleStorage_New( nil, 0 ); |
} |
#else |
storage = Q3HandleStorage_New(nil,0); |
#endif |
if (storage == nil) |
goto bail; |
fd = Q3File_New(); |
if (fd == nil) |
goto bail; |
Q3File_SetStorage(fd, storage); |
Tumbler_WriteScene(fd, |
false, |
theDocument) ; |
Q3HandleStorage_Get(storage, &theData, &validSize); |
HLock(theData); |
SetDragItemFlavorData(theDrag, theItem, '3DMF', (Ptr) *theData, |
validSize, 0L); |
HUnlock(theData); |
Q3Object_Dispose(storage); |
Q3Object_Dispose(fd); |
#ifdef NAGELS_DEMO |
if( didAllocate == true ) { |
DisposeHandle(theData); |
} |
#endif |
} |
else { |
return(badDragFlavorErr); |
} |
} |
else { |
return(badDragFlavorErr); |
} |
return(noErr); |
bail: |
return(badDragFlavorErr); |
} |
//----------------------------------------------------------------------- |
// DragItemsAreAcceptable returns true if the contents (data) of |
// the drag are acceptable by a window of this application |
// |
// DragItemsAreAcceptable is called by the tracking and |
// receive handlers |
Boolean DragItemsAreAcceptable(DragReference theDrag) ; |
Boolean DragItemsAreAcceptable(DragReference theDrag) |
{ |
OSErr retCode; |
unsigned short totalItems; |
ItemReference itemRef; |
Boolean acceptableFlag; |
HFSFlavor currHFSFlavor; |
Size flavorDataSize; |
FlavorFlags currFlavorFlags; |
acceptableFlag = false; |
// this app can only accept the drag of a single item |
retCode = CountDragItems(theDrag, &totalItems); |
if (retCode == noErr && totalItems == 1) { |
// get the reference number of the dragged item |
retCode = GetDragItemReferenceNumber(theDrag, 1, &itemRef); |
if (retCode == noErr) { |
// use GetFlavorFlags to check on flavor existence of PICT data |
// without forcing translation |
if (GetFlavorFlags (theDrag, itemRef, 'PICT', &currFlavorFlags) == noErr) { |
acceptableFlag = true; |
} |
else if (GetFlavorFlags (theDrag, itemRef, '3DMF', &currFlavorFlags) == noErr) { |
acceptableFlag = true; |
} |
else { |
// check if the item is a file spec for a PICT file |
flavorDataSize = sizeof(HFSFlavor); |
retCode = GetFlavorData(theDrag, itemRef, flavorTypeHFS, &currHFSFlavor, |
&flavorDataSize, 0); |
if (retCode == noErr && (currHFSFlavor.fileType == 'PICT' |
|| currHFSFlavor.fileType == '3DMF' |
|| currHFSFlavor.fileType == 'TEXT' )) |
acceptableFlag = true; |
} |
} |
} |
return acceptableFlag; |
} |
//----------------------------------------------------------------------- |
// DragIsNotInSourceWindow returns true if the drag in progress |
// is not in the same window it originated in |
// |
// DragIsNotInSourceWindow is called by the tracking and receive handlers |
// |
// Note that, if this application allowed items to be dragged within |
// its windows, this function would not be appropriate. |
// Instead, hilighting would probably occur in the source window |
// when the dragHasLeftSourceWindow flag is set, and the receive |
// handler wouldn't check this at all |
static |
Boolean DragIsNotInSourceWindow(DragReference theDrag) |
{ |
DragAttributes currDragFlags; |
(void) GetDragAttributes(theDrag, &currDragFlags); |
return ((currDragFlags & dragInsideSenderWindow) == 0); |
} |
//----------------------------------------------------------------------- |
// MouseInContentRgn returns true if the current mouse is in the content |
// area of the window (but not necessarily in the visible rgn) |
static |
Boolean MouseIsInContentRgn(DragReference theDrag, WindowPtr theWindow) |
{ |
Point mousePt; |
(void) GetDragMouse(theDrag, &mousePt, nil); |
return PtInRgn(mousePt, ((WindowPeek) theWindow)->contRgn); |
} |
//----------------------------------------------------------------------- |
// MyReceiveDropHandler |
// |
// Called by the Drag Manager when a drop occurs over one of the DoDragObjects document windows. |
pascal OSErr MyReceiveDropHandler(WindowPtr theWindow, unsigned long handlerRefCon, |
DragReference theDrag); |
pascal OSErr MyReceiveDropHandler(WindowPtr theWindow, unsigned long handlerRefCon, |
DragReference theDrag) |
{ |
OSErr result; |
Rect theRect, srcRect; |
unsigned short items, index; |
ItemReference theItem; |
DragAttributes attributes; |
StScrpHandle stylHandle; |
Size dataSize, pictSize; |
short offset, selStart, selEnd, mouseDownModifiers, mouseUpModifiers, moveText; |
DocumentPtr theDocument = (DocumentPtr ) handlerRefCon; |
Point thePoint; |
TQ3Object objects = nil; |
Boolean dataObtainedFlag; |
OSErr retCode; |
OSType theDragFlavor ; |
Point mouseLoc ; |
dataObtainedFlag = false; |
if (!DragItemsAreAcceptable(theDrag) || |
!MouseIsInContentRgn(theDrag, theWindow) || |
!DragIsNotInSourceWindow(theDrag)) |
return dragNotAcceptedErr; |
// We will only support one item, so get its reference number. |
result = GetDragItemReferenceNumber(theDrag, 1, &theItem); |
if (result != noErr) |
return result; |
GetDragAttributes(theDrag, &attributes); |
GetDragModifiers(theDrag, 0L, &mouseDownModifiers, &mouseUpModifiers); |
// Loop through all of the drag items contained in this drag |
SetRect(&theRect, 0, 0, 0, 0); |
// we ensured above that we only deal with one item being dragged to us... |
// CountDragItems(theDrag, &items); |
// Get the item's reference, so we can refer to it. |
GetDragItemReferenceNumber(theDrag, 1, &theItem); |
// get the location the user dropped the data |
GetDragMouse(theDrag, &mouseLoc, nil ) ; |
// Try to get the flags for a '3DMF' flavor. If this returns noErr, |
// then we know that a '3DMF' flavor exists in the item. |
result = GetFlavorDataSize(theDrag, theItem, '3DMF', &dataSize); |
if (result == noErr) { |
theDragFlavor = '3DMF' ; |
} |
else if((result = GetFlavorDataSize(theDrag, theItem, 'PICT', &dataSize)) == noErr) { |
theDragFlavor = 'PICT' ; |
} |
else { |
// Couldn't get 3DMF or PICT data so try to get HFS-flavor data. |
HFSFlavor theHFSFlavor; |
dataSize = sizeof(HFSFlavor); |
result = GetFlavorData(theDrag, theItem, flavorTypeHFS, |
&theHFSFlavor, &dataSize, 0); |
if(theHFSFlavor.fileType != 'PICT' |
|| theHFSFlavor.fileType != '3DMF' |
|| theHFSFlavor.fileType != 'TEXT' ) { |
result = paramErr ; |
} |
} |
// so we either have nothing or something (in the form of 3DMF or PICT data) |
if (result == noErr) { |
// create a new data handle to hold the data the user just dragged in |
// this needs to be the size of the data, plus the size of the |
myPrivateDataHdl thePrivateData = nil ; |
long recordSize ; |
recordSize = sizeof( myPrivateDataRec ) ; |
// create a handle large enough for the data |
thePrivateData = (myPrivateDataHdl)NewHandle( (long)(dataSize + recordSize)) ; |
if( thePrivateData == nil ) |
return MemError() ; |
(**thePrivateData).myTypeOfData = theDragFlavor ; |
(**thePrivateData).myDocument = theDocument ; // ideally we should store the doc in the windows refcon, this is hacky ??? |
(**thePrivateData).myDataSize = dataSize ; |
(**thePrivateData).myWindow = theWindow ; |
(**thePrivateData).myLocation = mouseLoc ; |
// Lock and load, I dunno if GetFlavorData moves memory, I'm just assuming it may... |
MoveHHi( (Handle)thePrivateData ) ; |
HLock( (Handle)thePrivateData ) ; |
// passing (**thePrivateData) in dereferenced - ASSUMES the hnadle is locked |
GetFlavorData(theDrag, theItem, theDragFlavor, &(**thePrivateData).myData[0], &dataSize, 0L); |
HUnlock( (Handle)thePrivateData ) ; |
// package this puppy up and send it to ourselves |
SendDragRecv( thePrivateData ) ; |
// and dispose of the data |
DisposeHandle((Handle)thePrivateData ) ; |
if (attributes & dragHasLeftSenderWindow) { |
HideDragHilite(theDrag); |
} |
} |
return(noErr); |
bail: |
return(memFullErr); |
} |
//----------------------------------------------------------------------- |
// MyTrackingHandler |
// |
// This is the drag tracking handler for windows in the Dragging application. |
pascal OSErr MyTrackingHandler(short theMessage, WindowPtr theWindow, |
void *handlerRefCon, DragReference theDrag); |
pascal OSErr MyTrackingHandler(short theMessage, WindowPtr theWindow, |
void *handlerRefCon, DragReference theDrag) |
{ |
RgnHandle tempRgn; |
Boolean mouseInContentFlag; |
OSErr retCode; |
retCode = noErr; |
switch (theMessage) { |
case dragTrackingEnterHandler: |
// determine if the items are acceptable and store |
// that flag in the globals, plus reset the |
// hilighted global flag |
pDragHandlerGlobals.acceptableDragFlag = |
DragItemsAreAcceptable(theDrag); |
pDragHandlerGlobals.windowIsHilightedFlag = false; |
// let the drag manager know if we can't accept this drag |
if (!pDragHandlerGlobals.acceptableDragFlag) |
retCode = dragNotAcceptedErr; |
break; |
case dragTrackingEnterWindow: |
case dragTrackingInWindow: |
case dragTrackingLeaveWindow: |
// highlighting of the window during a drag is done |
// here. Do it only if we can accept these items |
// and we're not in the source window... |
if (pDragHandlerGlobals.acceptableDragFlag && |
DragIsNotInSourceWindow(theDrag)) { |
// unless the mouse is leaving the visible area of the |
// window, check if it's in the window's content region |
if (theMessage == dragTrackingLeaveWindow) |
mouseInContentFlag = false; |
else |
mouseInContentFlag = MouseIsInContentRgn(theDrag, theWindow); |
// if the mouse is in the content area and the window |
// is not yet hilighted, then do the hilighting |
if (mouseInContentFlag && |
!pDragHandlerGlobals.windowIsHilightedFlag) { |
// set the proper clip |
ClipRect(&theWindow->portRect); |
// make a region bordering the window content |
tempRgn = NewRgn(); |
RectRgn(tempRgn, &theWindow->portRect); |
// draw the hilight |
if (ShowDragHilite(theDrag, tempRgn, true) == noErr) { |
// remember that hilighting is now on |
pDragHandlerGlobals.windowIsHilightedFlag = true; |
} |
// free up the region |
DisposeRgn(tempRgn); |
} |
// else if the mouse is not in the content region |
// and the window is hilighted, erase the hilight |
else if (!mouseInContentFlag && |
pDragHandlerGlobals.windowIsHilightedFlag) { |
// set the proper clip |
ClipRect(&theWindow->portRect); |
// erase the hilight and restore the port |
if (HideDragHilite(theDrag) == noErr) |
// remember that hilighting is now off |
pDragHandlerGlobals.windowIsHilightedFlag = false; |
} |
} |
break; |
// do nothing for the leaveHandler message |
case dragTrackingLeaveHandler: |
break; |
// let the drag manager know if we didn't recognize the message |
default: |
retCode = paramErr; |
} |
return retCode; |
} |
// |
// DropLocationIsFinderTrash |
// |
// Returns true if the given dropLocation AEDesc is a descriptor of the Finder's Trash. |
// |
static Boolean DropLocationIsFinderTrash(AEDesc *dropLocation) |
{ OSErr result; |
AEDesc dropSpec; |
FSSpec *theSpec; |
CInfoPBRec thePB; |
short trashVRefNum; |
long trashDirID; |
// |
// Coerce the dropLocation descriptor to an FSSpec. If there's no dropLocation or |
// it can't be coerced into an FSSpec, then it couldn't have been the Trash. |
// |
if ((dropLocation->descriptorType != typeNull) && |
(AECoerceDesc(dropLocation, typeFSS, &dropSpec) == noErr)) { |
HLock(dropSpec.dataHandle); |
theSpec = (FSSpec *) *dropSpec.dataHandle; |
// |
// Get the directory ID of the given dropLocation object. |
// |
thePB.dirInfo.ioCompletion = 0L; |
thePB.dirInfo.ioNamePtr = (StringPtr) &theSpec->name; |
thePB.dirInfo.ioVRefNum = theSpec->vRefNum; |
thePB.dirInfo.ioFDirIndex = 0; |
thePB.dirInfo.ioDrDirID = theSpec->parID; |
result = PBGetCatInfo(&thePB, false); |
HUnlock(dropSpec.dataHandle); |
AEDisposeDesc(&dropSpec); |
if (result != noErr) |
return(false); |
// |
// If the result is not a directory, it must not be the Trash. |
// |
if (!(thePB.dirInfo.ioFlAttrib & (1 << 4))) |
return(false); |
// |
// Get information about the Trash folder. |
// |
FindFolder(theSpec->vRefNum, kTrashFolderType, kCreateFolder, &trashVRefNum, &trashDirID); |
// |
// If the directory ID of the dropLocation object is the same as the directory ID |
// returned by FindFolder, then the drop must have occurred into the Trash. |
// |
if (thePB.dirInfo.ioDrDirID == trashDirID) |
return(true); |
} |
return(false); |
} |
// |
// DoDragObjects |
// |
// Drag the selected text in the given document. |
// |
short DoDragObjects(DocumentPtr theDocument, EventRecord *theEvent, RgnHandle hiliteRgn) |
{ |
short result; |
RgnHandle dragRegion, tempRgn; |
Point theLoc; |
DragReference theDrag; |
StScrpHandle theStyl; |
AEDesc dropLocation; |
DragAttributes attributes; |
short mouseDownModifiers, mouseUpModifiers, copyText; |
unsigned long validSize; |
if( theDocument->documentGroup ) { |
Handle theData; |
TQ3StorageObject storage; |
TQ3FileObject fd; |
TQ3GroupPosition position; |
TQ3TransformObject xform; |
DragSendDataUPP mySendDataProcUPP ; |
//Q3Object_Dispose(pickObject); |
CopyRgn(hiliteRgn, dragRegion = NewRgn()); |
SetPt(&theLoc, 0, 0); |
LocalToGlobal(&theLoc); |
OffsetRgn(dragRegion, theLoc.h, theLoc.v); |
// |
// Wait for the mouse to move to the mouse button to be released. If the mouse button was |
// released before the mouse moves, return false. Returing false from DoDragObjects means that |
// a drag operation did not occur. |
// |
if (! WaitMouseMoved(theEvent->where)) { |
return(false); |
} |
// create a new reference for a track to pass to track drag |
NewDrag(&theDrag); |
// We promise '3DMF' and 'PICT'. If a receiver requests either, the Drag Manager |
// will call our MySendDataProc to provide the data at drop time. The MySendDataProc |
// is specified by calling SetDragSendProc. |
AddDragItemFlavor(theDrag, 1, '3DMF', nil, 0L, 0L); |
// AddDragItemFlavor(theDrag, 1, 'PICT', nil, 0L, 0L); |
mySendDataProcUPP = NewDragSendDataProc(MySendDataProc) ; |
SetDragSendProc(theDrag, mySendDataProcUPP, (void *) theDocument); |
// Set the item's bounding rectangle in global coordinates. |
SetDragItemBounds(theDrag, 1, &(**dragRegion).rgnBBox); |
// Prepare the drag region. |
tempRgn = NewRgn(); |
CopyRgn(dragRegion, tempRgn); |
InsetRgn(tempRgn, 1, 1); |
DiffRgn(dragRegion, tempRgn, dragRegion); |
DisposeRgn(tempRgn); |
// on PPC the drawing proc leaves artifacts on the display when |
// highlighting and upon removal of highlighting for a window, so |
// although I may prefer the drawing that my custom proc does, I |
// just use the default. This may be a bug in the drag manager |
// or it may be us, but right now we'll just a void doing this and fix later |
// SetDragDrawingProc(theDrag,NewDragDrawingProc(MyDrawingProc), 0L); |
// Drag the stuff. TrackDrag will return userCanceledErr if the drop zoomed-back |
// for any reason. |
result = TrackDrag(theDrag, theEvent, dragRegion); |
// get rid of the UPP |
DisposeRoutineDescriptor( mySendDataProcUPP ) ; |
if (result != noErr && result != userCanceledErr) { |
return(true); |
} |
// Check to see if the drop occurred in the Finder's Trash. If the drop occurred |
// in the Finder's Trash and a copy operation wasn't specified, delete the |
// source selection. Note that we can continute to get the attributes, drop location |
// modifiers, etc. of the drag until we dispose of it using DisposeDrag. |
GetDragAttributes(theDrag, &attributes); |
if (!(attributes & dragInsideSenderApplication)) { |
GetDropLocation(theDrag, &dropLocation); |
GetDragModifiers(theDrag, 0L, &mouseDownModifiers, &mouseUpModifiers); |
copyText = (mouseDownModifiers | mouseUpModifiers) & optionKey; |
if ((!copyText) && (DropLocationIsFinderTrash(&dropLocation))) { |
theDocument->dirty = true; |
Q3Object_Dispose(theDocument->documentGroup); |
theDocument->documentGroup = nil; |
} |
AEDisposeDesc(&dropLocation); |
} |
// Dispose of the drag. |
DisposeDrag(theDrag); |
DisposeRgn(dragRegion); |
return(true); |
} |
bail: |
return(false); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14