This is IconDragView.m in view mode; [Download] [Up]
#import <GKappkit/GKappkit.h> #import "IconDragView.h" #import "ShelfView.h" #import "MonsterShelf.h" #import <appkit/appkit.h> #import <mach/mach.h> #import <bsd/sys/file.h> int mouseMoved(NXPoint *o, int n, int mask); typedef enum { Unknown, SameDeviceOperation, WriteNotAllowed, CrossDeviceOperation } DragStatus; @implementation IconDragView : IconView - initFrame:(const NXRect *) newFrame image:anImage data:(const void *) someData andLength:(unsigned int) newLength useSize:(BOOL) sizeValid useTile:(BOOL) showTile { const char *const types[1] = {NXFilenamePboardType}; altImage = nil; selected = NO; [self registerForDraggedTypes:types count:1]; [super initFrame:newFrame image:anImage data:someData andLength:newLength useSize:sizeValid useTile:showTile]; return self; } - free { [altImage free]; return [super free]; } - drawSelf:(const NXRect *) rects :(int) rectCount { id tImage = image; image = altImage ? altImage : image; [super drawSelf:rects :rectCount]; image = tImage; return self; } - image { return image; } - getData:(void **) aPtr andLength:(unsigned int *) aLength { *aPtr = data; *aLength = length; return self; } - mouseDown:(NXEvent *) e { BOOL shift, control; NXPoint mousePoint, offset; unsigned int mask = NX_LMOUSEDRAGGEDMASK|NX_LMOUSEUPMASK; NXEvent saveEvent; BOOL newState; shift = (e->flags & NX_SHIFTMASK) ? YES : NO; control = (e->flags & NX_CONTROLMASK) ? YES : NO; mousePoint = e->location; saveEvent = *e; [window addToEventMask:mask]; /* * Handle selection */ if (shift && selected) newState = NO; else newState = YES; if (!shift && newState) [superview deselectAll:self]; if (newState != selected) { selected = newState; [self display]; } /* * Detect drag */ if (mouseMoved(&mousePoint, 2, mask)) { NXPoint imagePoint; [self getImagePoint:&imagePoint andTilePoint:NULL andHilitePoint:NULL]; offset.x = mousePoint.x - e->location.x; offset.y = mousePoint.y - e->location.y; [self setState:NO]; [superview setDragView:self onEvent:&saveEvent withOffset:&offset atLocation:&imagePoint]; return self; } /* * If no drag, try to get workspace to do something */ if (selected) { BOOL delivered = NO; id workspace = [Application workspace]; NXPoint imageLoc, upperRight; NXRect superRect; NXEvent newEvent; [self getImagePoint:&imageLoc andTilePoint:NULL andHilitePoint:NULL]; [self convertPoint:&imageLoc toView:nil]; [window convertBaseToScreen:&imageLoc]; imageLoc.y++; /* grody! necessary to make images line up */ [superview getFrame:&superRect]; upperRight.x = superRect.origin.x + superRect.size.width - 32; upperRight.y = superRect.origin.y + superRect.size.height - 32; /* * Before animating the icon, check for double click. If we * see a second click come in, then open the file. Otherwise, * just select it in Workspace. */ if (![NXApp peekNextEvent:NX_LMOUSEDOWNMASK into:&newEvent waitFor:0.2 threshold:NX_MODALRESPTHRESHOLD]) { [workspace slideImage:image from:&imageLoc to:&upperRight]; delivered = [workspace selectFile:data inFileViewerRootedAt:""]; } else { // activate, so the called app gets activated... [NXApp activateSelf:YES]; [workspace slideImage:image from:&imageLoc to:&upperRight]; (void) [NXApp getNextEvent:NX_LMOUSEDOWNMASK]; delivered = [workspace openFile:data]; } if (!delivered) NXBeep(); [self setState:NO]; } return self; } - (BOOL) acceptsFirstMouse { return YES; } - (BOOL) acceptsFirstResponder { return NO; } #define OPEN_DIR_ICON_FILE ".opendir.tiff" #define DEFAULT_OPEN_DIR_FILE "/usr/lib/NextStep/Workspace.app/WM.app/openFolder.tiff" #define OPEN_HIGHLIGHT "OpenHighlight.tiff" - getOpenImageForDirectory:(const char *) dirname { struct stat st; char buf[MAXPATHLEN]; id newImage = nil; /* * See if there's a .opendir.tiff */ strncpy(buf, dirname, sizeof(buf)); strncat(buf, "/", sizeof(buf)); strncat(buf, OPEN_DIR_ICON_FILE, sizeof(buf)); if (access(buf, R_OK) == 0) { newImage = [[NXImage allocFromZone:[self zone]] initFromFile:buf]; if (newImage) return newImage; } /* * Before we use the default image, see if this thing is the * root of a mounted file system, and use the appropriate icon * if it is. */ if (stat(dirname, &st) >= 0 && st.st_ino == 2) { NXSize size; [image getSize:&size]; newImage = [[NXImage allocFromZone:[self zone]] initSize:&size]; if ([newImage lockFocus]) { NXPoint zeroPoint = {0,0}; id highlight; if(highlight=[[self module]loadImage:OPEN_HIGHLIGHT]) { [image composite:NX_COPY toPoint:&zeroPoint]; [highlight composite:NX_SOVER toPoint:&zeroPoint]; [newImage unlockFocus]; return newImage; } } } if (access(DEFAULT_OPEN_DIR_FILE, R_OK) == 0) newImage = [[NXImage allocFromZone:[self zone]] initFromFile:DEFAULT_OPEN_DIR_FILE]; if (newImage != nil) return newImage; else return image; } /* * Figure out the various parameters of the drag. */ - (DragStatus) dragStatusForPath:(char *) dragPath { char *destinationPath; unsigned int junk; struct stat st; [self getData:(void **) &destinationPath andLength:&junk]; /* * See if we should be a dragging destination. We need some way to * make this extendible. One way would be to associate a remote * object with the node, and ask it what it means to drag the * incoming object over the one on the screen... * * For now, interpret the data as a string. Stat it to see if it's * a directory, and if it is, say yes subject to access constraints. */ if (stat(destinationPath, &st) < 0 || (st.st_mode & S_IFMT) != S_IFDIR) return WriteNotAllowed; if (access(destinationPath, W_OK|X_OK) < 0) return WriteNotAllowed; /* * Cool! We're a directory. Check the directory from which we're * dragging, and see it's the same as this one, or if it's contained * in this one. */ if (stat(destinationPath, &st) < 0) return Unknown; else { dev_t destDev = st.st_dev; ino_t destIno = st.st_ino; if (lstat(dragPath, &st) >= 0 && st.st_dev == destDev && destIno == st.st_ino) return WriteNotAllowed; } /* * Handle the case where the dragging destination and the dragging * source are on different file systems. In this case, we want to * copy by default, not move. */ if (stat(destinationPath, &st) >= 0) { dev_t destinationDevice = st.st_dev; if (lstat(dragPath, &st) >= 0) if (st.st_dev != destinationDevice) return CrossDeviceOperation; else return SameDeviceOperation; } return Unknown; } /* * Figure out what the drag operation should be for dragging a view onto * another view. */ - (NXDragOperation) dragOperationForContext:(id <NXDraggingInfo>) dragInfo { NXDragOperation op = NX_DragOperationNone; NXDragOperation maskOp = [dragInfo draggingSourceOperationMask]; id pb = [Pasteboard newName:NXDragPboard]; char *dragPath, *nextPath; unsigned int junk; BOOL first = YES; [pb readType:NXFilenamePboardType data:&dragPath length:&junk]; /* * We might have been asked to drag multiple files. Loop over all of * them to see if they all have the same drag op. Fail if they don't! */ nextPath = dragPath; do { char path[MAXPATHLEN]; NXDragOperation thisOp = maskOp; strncpy(path, nextPath, MAXPATHLEN); if (index(path, '\t')) *index(path, '\t') = '\0'; switch ([self dragStatusForPath:path]) { case WriteNotAllowed: case Unknown: thisOp = NX_DragOperationNone; break; case CrossDeviceOperation: if (maskOp & NX_DragOperationCopy) { thisOp = NX_DragOperationCopy; break; } /* fall through */ case SameDeviceOperation: if (maskOp & NX_DragOperationGeneric) { thisOp = NX_DragOperationGeneric; break; } /* fall through */ default: break; } /* * Bail out of this operation isn't the same as the last one! */ if (first) { op = thisOp; first = NO; } else if (op != thisOp) return NX_DragOperationNone; /* * Advance to next file */ nextPath = index(nextPath, '\t'); if (nextPath == NULL) break; else nextPath++; } while (1); return op; } /* * Be a dragging destination... */ - (NXDragOperation)draggingEntered:(id <NXDraggingInfo>)sender { lastDragOp = [self dragOperationForContext:sender]; /* * If we're going to do the drag, use the alternate image. */ if (lastDragOp != NX_DragOperationNone) { NXSize imageSize; altImage = [self getOpenImageForDirectory:data]; [image getSize:&imageSize]; [altImage setScalable:YES]; [altImage setSize:&imageSize]; [self display]; } return lastDragOp; } - (NXDragOperation)draggingUpdated:(id <NXDraggingInfo>)sender { lastDragOp = [self dragOperationForContext:sender]; return lastDragOp; } - draggingExited:(id <NXDraggingInfo>)sender { /* * Reset image to original image. */ [altImage free]; altImage = nil; [self display]; [window flushWindow]; return self; } /* * Eat the result... */ - (BOOL) prepareForDragOperation:sender { return YES; } - (BOOL) performDragOperation:(id <NXDraggingInfo>)sender { return YES; } - concludeDragOperation:(id <NXDraggingInfo>)sender { id workspace = [Application workspace]; id pb = [Pasteboard newName:NXDragPboard]; const char *wsmOp; char *pbData; unsigned int pbLength; switch (lastDragOp) { case NX_DragOperationGeneric: wsmOp = WSM_MOVE_OPERATION; break; case NX_DragOperationLink: wsmOp = WSM_LINK_OPERATION; break; case NX_DragOperationCopy: wsmOp = WSM_COPY_OPERATION; break; default: return NO; } [pb readType:NXFilenamePboardType data:&pbData length:&pbLength]; [workspace performFileOperation:wsmOp source:"/" destination:data files:pbData options:NULL]; return [self draggingExited:sender]; } - (BOOL) isOnRemovableMedia { struct stat st; char *mountedList = NULL; id workspace = [Application workspace]; if (stat(data, &st) < 0) device = 0; else device = st.st_dev; removable = NO; if ([workspace respondsTo:@selector(getMountedRemovableMedia:)] && [workspace getMountedRemovableMedia:&mountedList]) [self perform:@selector(isOnRemovableDevice:) withPaths:mountedList]; if (mountedList) free(mountedList); return removable; } - isOnRemovableDevice:(const char *)path { struct stat st; if (path && stat(path, &st) >= 0) removable |= (device == st.st_dev); return self; } @end /* * Returns true if mouse is dragged more than n pixels from 'o', * false if the mouse button is lifted. If the mouse button is * lifted, the mouseUp event is not consumed. */ int mouseMoved(NXPoint *o, int n, int mask) { NXEvent e; NXPoint p; float dx, dy; do { [NXApp peekNextEvent:mask into:&e waitFor:0x7fffffff threshold:NX_MODALRESPTHRESHOLD]; p = e.location; if (e.type == NX_LMOUSEUP) break; (void) [NXApp getNextEvent:mask]; /* throw it away */ dx = abs(p.x - o->x); dy = abs(p.y - o->y); } while ((dy < (float) n) && (dx < (float) n)); *o = p; return e.type != NX_LMOUSEUP; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.