home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Apple Macintosh Developer Technical Support
- **
- ** File: Drag.c
- ** Written by: Eric Soldan
- **
- ** Copyright © 1993 Apple Computer, Inc.
- ** All rights reserved.
- */
-
- /* You may incorporate this sample code into your applications without
- ** restriction, though the sample code has been provided "AS IS" and the
- ** responsibility for its operation is 100% yours. However, what you are
- ** not permitted to do is to redistribute the source as "DSC Sample Code"
- ** after having made changes. If you're going to re-distribute the source,
- ** we require that you make it clear in the source that the code was
- ** descended from Apple Sample Code, but that you've made changes. */
-
-
-
- /*****************************************************************************/
-
-
-
- #include "App.h" /* Get the application includes/typedefs, etc. */
- #include "App.defs.h" /* Get various application definitions. */
- #include "App.protos.h" /* Get the prototypes for the application. */
-
- #ifndef __FOLDERS__
- #include <Folders.h>
- #endif
-
- #ifndef __GESTALTEQU__
- #include <GestaltEqu.h>
- #endif
-
- #ifndef __TREEOBJ2__
- #include "TreeObj2.h"
- #endif
-
- static pascal OSErr DefaultDragTrackingHandler(DragTrackingMessage msg, WindowPtr wnd, void *refcon, DragReference dragRef);
- static pascal OSErr DefaultDragReceiveHandler(WindowPtr wnd, void *refcon, DragReference dragRef);
-
- static OSErr GetDragData(FileRecHndl frHndl, Point pt, Handle *retDragData, RgnHandle *retDragRgn);
- static Boolean DropLocationIsFinderTrash(AEDesc *dropLocation);
-
- static Boolean gCanAcceptItems, gWindowHilited;
-
-
-
- /*****************************************************************************/
- /*****************************************************************************/
-
-
-
- #pragma segment Drag
- Boolean DragDropAvailable(void)
- {
- long result;
-
- if (Gestalt(gestaltDragMgrAttr, &result)) return (false);
-
- if (!(result & (1 << gestaltDragMgrPresent))) return(false);
-
- #ifdef powerc
- if (!(result & (1 << gestaltPPCDragLibPresent))) return(false);
- #endif
-
- return(true);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- #pragma segment Drag
- OSErr ManageDragHandlers(WindowPtr window, Boolean install)
- {
- OSErr err;
- static DragTrackingHandlerUPP dragTrackingUPP;
- static DragReceiveHandlerUPP dragReceiveUPP;
-
- if (!DragDropAvailable()) return(paramErr);
-
- if (!dragTrackingUPP) {
- dragTrackingUPP = NewDragTrackingHandlerProc(DefaultDragTrackingHandler);
- dragReceiveUPP = NewDragReceiveHandlerProc (DefaultDragReceiveHandler);
- }
-
- if (install) {
- err = InstallTrackingHandler(dragTrackingUPP, window, nil);
- if (!err)
- err = InstallReceiveHandler(dragReceiveUPP, window, nil);
- return(err);
- }
- else {
- RemoveTrackingHandler(dragTrackingUPP, window);
- RemoveReceiveHandler(dragReceiveUPP, window);
- return(noErr);
- }
- }
-
-
-
- /*****************************************************************************/
-
-
-
- #pragma segment Drag
- static pascal OSErr DefaultDragTrackingHandler(DragTrackingMessage msg, WindowPtr wnd, void *refcon, DragReference dragRef)
- {
- #ifndef __MWERKS__
- #pragma unused (refcon)
- #endif
-
- unsigned short count, index;
- unsigned long flavorFlags, attr;
- ItemReference theItem;
- RgnHandle rgn;
- Point theMouse, localMouse;
- OSErr err;
- Rect contRct;
-
- if ((msg != dragTrackingEnterHandler) && (!gCanAcceptItems)) return(noErr);
-
- GetDragAttributes(dragRef, &attr);
-
- switch (msg) {
-
- case dragTrackingEnterHandler:
- /* We get called with this message the first time that a drag enters ANY
- ** window in our application. Check to see if all of the drag items contain
- ** 'DDOC'. We only accept a drag if all of the items in the drag can be accepted. */
-
- gCanAcceptItems = true;
- CountDragItems(dragRef, &count);
-
- for (index = 1; index <= count; index++) {
- GetDragItemReferenceNumber(dragRef, index, &theItem);
- err = GetFlavorFlags(dragRef, theItem, 'DDOC', &flavorFlags);
- if (err != noErr) {
- gCanAcceptItems = false;
- break;
- }
- }
- break;
-
- case dragTrackingEnterWindow:
- /* We receive an EnterWindow message each time a drag enters one of our
- ** application's windows. We initialize our global variables for tracking
- ** the drag through the window. */
-
- break;
-
- case dragTrackingInWindow:
-
- /* We receive InWindow messages as long as the mouse is in one of our windows
- ** during a drag. We draw the window highlighting when we get these messages. */
-
- GetDragMouse(dragRef, &theMouse, 0L);
- localMouse = theMouse;
- GlobalToLocal(&localMouse);
-
- /* Show or hide the window highlighting when the mouse enters or leaves the
- ** TextEdit field in our window (we don't want to show the highlighting when
- ** the mouse is over the window title bar or over the scroll bars). */
-
- GetContentRect(wnd, &contRct);
- if (attr & dragHasLeftSenderWindow) {
- if (PtInRect(localMouse, &contRct)) {
- if (!gWindowHilited) {
- RectRgn(rgn = NewRgn(), &contRct);
- ShowDragHilite(dragRef, rgn, true);
- DisposeRgn(rgn);
- }
- gWindowHilited = true;
- } else {
- if (gWindowHilited)
- HideDragHilite(dragRef);
- gWindowHilited = false;
- }
- }
- break;
-
- case dragTrackingLeaveWindow:
- if ((gWindowHilited) && (attr & dragHasLeftSenderWindow))
- HideDragHilite(dragRef);
-
- gWindowHilited = false;
- break;
-
- case dragTrackingLeaveHandler:
- break;
-
- }
-
- return(noErr);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- #pragma segment Drag
- static pascal OSErr DefaultDragReceiveHandler(WindowPtr wnd, void *refcon, DragReference dragRef)
- {
- #ifndef __MWERKS__
- #pragma unused (refcon)
- #endif
-
- OSErr err;
- unsigned short items, index;
- short cnum;
- ItemReference theItem;
- DragAttributes attr;
- Handle data;
- Size dataSize;
- short mouseDownModifiers, mouseUpModifiers, dragMove;
- Point mouseLoc, pinnedMouseLoc, initialLoc, locPt;
- TreeObjHndl dragRoot, root, cobj;
- FileRecHndl frHndl;
- ClickInfo click;
- Boolean change;
-
- if (!gCanAcceptItems) return(dragNotAcceptedErr);
-
- SetPort(wnd);
-
- GetDragAttributes(dragRef, &attr);
- GetDragModifiers(dragRef, 0L, &mouseDownModifiers, &mouseUpModifiers);
-
- dragMove = (
- (attr & dragInsideSenderWindow) &&
- (!((mouseDownModifiers | mouseUpModifiers) & optionKey))
- );
-
- GetDragMouse(dragRef, &mouseLoc, &pinnedMouseLoc);
- locPt = mouseLoc;
- GlobalToLocal(&locPt);
-
- frHndl = (FileRecHndl)GetWRefCon(wnd);
- root = (*frHndl)->d.doc.root;
- NewDocumentUndo(frHndl);
-
- CountDragItems(dragRef, &items);
-
- change = false;
- for (index = 1; index <= items; ++index) {
-
- /* Get the item's reference number, so we can refer to it. */
-
- GetDragItemReferenceNumber(dragRef, index, &theItem);
-
- /* Try to get the flags for a 'DDOC' flavor. If this returns noErr,
- ** then we know that a 'DDOC' flavor exists in the item. */
-
- err = GetFlavorDataSize(dragRef, theItem, 'DDOC', &dataSize);
-
- if (!err) {
-
- data = NewHandle(dataSize);
- if (!data) return(memFullErr);
-
- HLock(data);
- GetFlavorData(dragRef, theItem, 'DDOC', *data, &dataSize, 0L);
- HUnlock(data);
- dragRoot = NewRootObj(ROOTOBJ, 0);
- err = HReadTree(dragRoot, data);
- DisposeHandle(data);
- if (err) {
- DisposeObjAndOffspring(dragRoot);
- return(err);
- }
-
- if (dragMove) {
- if (wnd == FrontWindowOfType(kwIsDocument, true)) {
- GetDragOrigin(dragRef, &initialLoc);
- click.message = CLICKDRAG;
- click.offset.h = mouseLoc.h - initialLoc.h;
- click.offset.v = mouseLoc.v - initialLoc.v;
- for (cnum = (*root)->numChildren; cnum;) {
- cobj = GetChildHndl(root, --cnum);
- if (mDerefCommon(cobj)->selected) {
- ModifyChild(MOVE_EDIT, root, cnum, true);
- DoFTreeMethod(cobj, CLICKMESSAGE, (long)&click);
- change = true;
- }
- }
- }
- else dragMove = false;
- }
-
- if (!dragMove) {
- if (!change)
- DoTreeSelect(root, SELECTOFF); /* Turn off current document selections. */
- for (cnum = (*dragRoot)->numChildren; cnum;) {
- cobj = GetChildHndl(dragRoot, --cnum);
- click.message = CLICKDRAG;
- click.offset = locPt;
- DoFTreeMethod(cobj, CLICKMESSAGE, (long)&click);
- CopyChild(DRAGDROP_EDIT, dragRoot, cnum, root, 0, true);
- change = true;
- }
- }
-
- DisposeObjAndOffspring(dragRoot);
- }
- }
-
- if (change) {
- BeginContent(wnd);
- DoImageDocument(frHndl);
- EndContent(wnd);
- SetWindowDirty(wnd);
- gWindowHilited = false;
- }
-
- return(noErr);
- }
-
-
-
- /*****************************************************************************/
- /*****************************************************************************/
- /*****************************************************************************/
-
-
-
- #pragma segment Drag
- static OSErr GetDragData(FileRecHndl frHndl, Point pt, Handle *retDragData, RgnHandle *retDragRgn)
- {
- TreeObjHndl root, cobj;
- Handle dragData;
- RgnHandle dragRgn, rgn;
- short numChildren, cnum;
- OSErr err;
- ClickInfo click;
- Rect rr;
-
- *retDragData = nil;
- *retDragRgn = nil;
-
- root = (*frHndl)->d.doc.root;
- dragData = NewHandle(0);
- dragRgn = NewRgn();
-
- numChildren = (*root)->numChildren;
- (*root)->numChildren = 0;
- err = HWriteTree(root, dragData);
- (*root)->numChildren = numChildren;
- if (err) {
- DisposeHandle(dragData);
- return(err);
- }
- (*(TreeObjHndl)dragData)->numChildren = mDerefRoot(root)->numSelected;
-
- for (cnum = 0; cnum < (*root)->numChildren; ++cnum) {
- cobj = GetChildHndl(root, cnum);
- if (mDerefCommon(cobj)->selected) {
- DoFTreeMethod(cobj, GETRGNMESSAGE, (long)dragRgn);
- click.message = CLICKDRAG;
- click.offset.h = -pt.h;
- click.offset.v = -pt.v;
- DoFTreeMethod(cobj, CLICKMESSAGE, (long)&click); /* Set click-point to 0,0. */
- err = HWriteTree(cobj, dragData);
- click.offset = pt;
- DoFTreeMethod(cobj, CLICKMESSAGE, (long)&click); /* Fix it up. */
- if (err) {
- DisposeHandle(dragData);
- DisposeRgn (dragRgn);
- return(err);
- }
- }
- }
- if (GetHandleSize((Handle)dragRgn) > 10000) {
- root = (*frHndl)->d.doc.root;
- rr = GetSelectedArea(root);
- RectRgn(dragRgn, &rr);
- click.message = HITTESTOBJ;
- click.localEvent.where = pt;
- cobj = DoTreeHitTest(root, &click);
- if (cobj) {
- rgn = (RgnHandle)DoTreeObjMethod(cobj, GETRGNMESSAGE, (long)dragRgn);
- DiffRgn(dragRgn, rgn, dragRgn);
- DisposeRgn(rgn);
- }
- }
-
- *retDragData = dragData;
- *retDragRgn = dragRgn;
- return(noErr);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- #pragma segment Drag
- static Boolean DropLocationIsFinderTrash(AEDesc *dropLocation)
- {
- OSErr err;
- 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;
-
- err = PBGetCatInfo(&thePB, false);
-
- HUnlock(dropSpec.dataHandle);
- AEDisposeDesc(&dropSpec);
-
- if (err != noErr)
- return(false);
-
- /* If the err 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);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- #pragma segment Drag
- OSErr DoDrag(FileRecHndl frHndl, EventRecord *event)
- {
- OSErr err;
- Handle dragData;
- RgnHandle dragRgn, rgn, oldClip;
- DragReference dragRef;
- Point pt;
- Rect rr;
- DragAttributes attr;
- AEDesc dropLoc;
- short mouseDownModifiers, mouseUpModifiers, dragCopy, i;
- TreeObjHndl root, cobj;
- WindowPtr oldPort;
- PicHandle pic;
-
- if (!DragDropAvailable()) return(paramErr); /* No mgr, no drag. */
-
- err = NewDrag(&dragRef);
- if (err) return(err);
-
- pt = event->where;
- GlobalToLocal(&pt);
- err = GetDragData(frHndl, pt, &dragData, &dragRgn);
- if (err) return(err);
-
- pt.h = pt.v = 0;
- LocalToGlobal(&pt);
- OffsetRgn(dragRgn, pt.h, pt.v);
-
- HLock(dragData);
- err = AddDragItemFlavor(dragRef, 1, 'DDOC', *dragData, GetHandleSize(dragData), 0);
- DisposeHandle(dragData);
- if (err) {
- DisposeRgn(dragRgn);
- DisposeDrag(dragRef);
- return(err);
- }
-
- oldPort = SetFilePort(frHndl);
- GetClip(oldClip = NewRgn());
- rr = GetDataArea(root = (*frHndl)->d.doc.root);
- pic = OpenPicture(&rr);
- ClipRect(&rr);
- for (i = (*root)->numChildren; i;) {
- cobj = GetChildHndl(root, --i);
- if (mDerefCommon(cobj)->selected)
- DoTreeDraw(cobj, DRAWOBJ);
- }
- ClosePicture();
- SetClip(oldClip);
- DisposeRgn(oldClip);
- SetPort(oldPort);
- HLock((Handle)pic);
- err = AddDragItemFlavor(dragRef, 1, 'PICT', *pic, GetHandleSize((Handle)pic), 0);
- KillPicture(pic);
-
- rr = (*dragRgn)->rgnBBox;
- SetDragItemBounds(dragRef, 1, &rr);
-
- CopyRgn(dragRgn, rgn = NewRgn());
- InsetRgn(rgn, 1, 1);
- DiffRgn(dragRgn, rgn, dragRgn);
- DisposeRgn(rgn);
- err = TrackDrag(dragRef, event, dragRgn);
-
- if ((err) && (err != userCanceledErr)) {
- DisposeDrag(dragRef);
- DisposeRgn(dragRgn);
- return(err);
- }
-
- GetDragAttributes(dragRef, &attr);
- if (!(attr & dragInsideSenderApplication)) {
- GetDropLocation(dragRef, &dropLoc);
- GetDragModifiers(dragRef, 0L, &mouseDownModifiers, &mouseUpModifiers);
- dragCopy = (mouseDownModifiers | mouseUpModifiers) & optionKey;
-
- if ((!dragCopy) && (DropLocationIsFinderTrash(&dropLoc)))
- DoDelete(frHndl);
-
- AEDisposeDesc(&dropLoc);
- }
-
- DisposeDrag(dragRef);
- DisposeRgn(dragRgn);
-
- return(noErr);
- }
-
-
-
-