home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / Utilities / Fiend-1.4.1-src / IconDragView.m < prev    next >
Encoding:
Text File  |  1995-12-01  |  16.6 KB  |  709 lines

  1. #import <math.h>
  2. #import "Fiend.h"
  3. #import "Dock.h"
  4. #import "IconDragView.h"
  5. #import "ShelfView.h"
  6. #import "DockMgrView.h"
  7. #import "Controller.h"
  8. #import "FiendWraps.h"
  9.  
  10. #import <appkit/appkit.h>
  11. #import <mach/mach.h>
  12. #import <bsd/sys/file.h>
  13.  
  14.  
  15. static id    destroySound;
  16. int mouseMoved(NXPoint *o, int n, int mask);
  17.  
  18. typedef enum { Unknown,
  19.                SameDeviceOperation,
  20.                WriteNotAllowed,
  21.                CrossDeviceOperation,
  22.                ApplicationDirectory } DragStatus;
  23.  
  24.  
  25. @implementation IconDragView : IconView
  26.  
  27. + initialize
  28. {
  29.     destroySound = [Sound findSoundFor:"Destroy"];
  30.     return self;
  31. }
  32.  
  33. - initFrame:(const NXRect *)newFrame image:anImage data:(const void *)someData
  34.   andLength:(unsigned int) newLength useSize:(BOOL)sizeValid onDock:(BOOL)dockFlag
  35. {
  36.     const char *const    types[1] = {NXFilenamePboardType};
  37.  
  38.     [self registerForDraggedTypes:types count:1];
  39.     [super initFrame:newFrame image:anImage data:someData andLength:newLength
  40.            useSize:sizeValid onDock:dockFlag];
  41.  
  42.     altImage = nil;
  43.     selected = NO;
  44.     dockDrag = NO;
  45.  
  46.     return self;
  47. }
  48.  
  49.  
  50. - free
  51. {
  52.     [altImage free];
  53.     return [super free];
  54. }
  55.  
  56. - sizeTo:(NXCoord) width :(NXCoord) height
  57. {
  58.     NXSize    aSize;
  59.  
  60.     [super sizeTo:width :height];
  61.     if (altImage)    {
  62.         [image getSize:&aSize];
  63.         [altImage setSize:&aSize];
  64.     }
  65.     return self;
  66. }
  67.  
  68. - drawSelf:(const NXRect *) rects :(int) rectCount
  69. {
  70.     id    tImage = image;
  71.  
  72.     if (altImage)
  73.         image = altImage;
  74.     [super drawSelf:rects :rectCount];
  75.     image = tImage;
  76.  
  77.     return self;
  78. }
  79.  
  80.  
  81. - image
  82. {
  83.     return image;
  84. }
  85.  
  86.  
  87. - getData:(void **) aPtr andLength:(unsigned int *) aLength
  88. {
  89.     *aPtr = data;
  90.     *aLength = length;
  91.     return self;
  92. }
  93.  
  94. - handleMouseMoved:(NXEvent *)saveEvent imagePt:(NXPoint *)imgPt offsetPt:(NXPoint *)offPt
  95. {
  96.     NXPoint        imageLoc;
  97.     NXPoint        mousePoint = saveEvent->location;
  98.     Pasteboard     *pboard = [Pasteboard newName:NXDragPboard];
  99.  
  100.     if (onDock)
  101.         [dockMgrView stopScanTimer];
  102.  
  103.     if (!onDock)
  104.         [superview setDragView:self onEvent:saveEvent withOffset:offPt atLocation:imgPt];
  105.     else if (saveEvent->flags & NX_ALTERNATEMASK)    {
  106.         NXImage        *dragImage = [IconView getImageForPath:data fileIcon:YES zone:[self zone]];
  107.  
  108.         [pboard declareTypes:&NXFilenamePboardType num:1 owner:nil];
  109.         [pboard writeType:NXFilenamePboardType data:data length:strlen(data)];
  110.         [self dragImage:dragImage at:&frame.origin offset:offPt
  111.               event:saveEvent pasteboard:pboard source:dockMgrView slideBack:NO];
  112.         [dragImage free];
  113.     }
  114.     else if (1 /*!sticky*/)    {
  115.         const char    *types[] = {FIEND_PBTYPE};
  116.         NXImage     *dragImage = [[NXImage allocFromZone:[self zone]] initSize:&frame.size];
  117.  
  118.         [pboard declareTypes:types num:1 owner:nil];
  119.         [pboard writeType:FIEND_PBTYPE data:data length:strlen(data)];
  120.  
  121.         [self getImagePoint:&imageLoc andHilitePoint:NULL];
  122.         if ([dragImage lockFocus])    {
  123.             PScomposite(0.0, 0.0, NX_WIDTH(&frame), NX_HEIGHT(&frame),
  124.                         [window gState], 0.0, 0.0, NX_COPY);
  125.             [dragImage unlockFocus];
  126.         }
  127.  
  128.         [dockMgrView setDragView:self andOffset:&mousePoint];
  129.         [[self setGhost:YES] display];
  130.         NXPing();
  131.  
  132.         dockDrag = YES;
  133.         [self dragImage:dragImage at:&frame.origin offset:offPt
  134.               event:saveEvent pasteboard:pboard source:dockMgrView slideBack:NO];
  135.         [dragImage free];
  136.         dockDrag = NO;
  137.  
  138.         [[self setGhost:NO] display];
  139.         NXPing();
  140.     }
  141.     else if (sticky)    {
  142.         NXRunAlertPanel([NXApp appName],
  143.                         "Can't delete sticky icons!",
  144.                         NULL, NULL, NULL);
  145.         NXBeep();
  146.     }
  147.  
  148.     if (onDock)
  149.         [dockMgrView startScanTimer];
  150.  
  151.     return self;
  152. }
  153.  
  154. static void
  155. getDockLoc(NXPoint *p, NXSize *size)
  156. {
  157.     char    string[100];
  158.     const char    *ret;
  159.  
  160.     p->x = p->y = -1.0;
  161.     if (size->height != ORIG_SCREEN_HEIGHT)    {
  162.         sprintf(string, "DockOriginYForHt%d", (int)size->height);
  163.         ret = NXGetDefaultValue("Workspace", string);
  164.         if (ret)
  165.             p->y = atoi(ret);
  166.         sprintf(string, "DockOriginXForHt%d", (int)size->height);
  167.         ret = NXGetDefaultValue("Workspace", string);
  168.         if (ret)
  169.             p->x = atoi(ret);
  170.     }
  171.     else    {
  172.         ret = NXGetDefaultValue("Workspace", "DockOriginY");
  173.         if (ret)
  174.             p->y = atoi(ret);
  175.         ret = NXGetDefaultValue("Workspace", "DockOriginX");
  176.         if (ret)
  177.             p->x = atoi(ret);
  178.     }
  179.     if (p->x < 0.0)
  180.         p->x = size->width - 67.0;
  181.     if (p->y < 0.0)
  182.         p->y = size->height - 64.0;
  183. }
  184.  
  185. - (BOOL)handleSingleClick:(NXEvent *)e
  186. {
  187.     int            newStat;
  188.     NXPoint        imageLoc;
  189.     NXPoint        upperRight;
  190.     BOOL        delivered = NO;
  191.     BOOL        alt = (e->flags & NX_ALTERNATEMASK) ? YES : NO;
  192.     BOOL        shift = (e->flags & NX_SHIFTMASK) ? YES : NO;
  193.     BOOL        control = (e->flags & NX_CONTROLMASK) ? YES : NO;
  194.     BOOL        command = (e->flags & NX_COMMANDMASK) ? YES : NO;
  195.     BOOL        noFlags = (!command && !shift && !control && !alt);
  196.     BOOL        justCommand = (command && !alt && !shift && !control);
  197.     BOOL        useSound = !strcmp(NXGetDefaultValue([NXApp appName], USE_SOUND), "YES");
  198.     BOOL        demandDockCommand = !strcmp(NXGetDefaultValue([NXApp appName], ENAB_DCLCK), "NO");
  199.     BOOL        demandShelfCommand = !strcmp(NXGetDefaultValue([NXApp appName], ENAB_SCLCK), "NO");
  200.     struct stat    buf;
  201.     const char    *path = (const char *)data;
  202.  
  203.     if (onDock)    {
  204.         if (ghost)    {
  205.             ghost = NO;
  206.             [self display];
  207.         }
  208.         [[NXApp delegate] deselectShelf];
  209.     }
  210.     else
  211.         [[NXApp delegate] deselectDock];
  212.  
  213.     if ((onDock && ((noFlags && !demandDockCommand) || (justCommand && demandDockCommand))) ||
  214.         (!onDock && ((noFlags && !demandShelfCommand) || (justCommand && demandShelfCommand))))    {
  215.         [self getImagePoint:&imageLoc andHilitePoint:NULL];
  216.         [self convertPoint:&imageLoc toView:nil];
  217.         [window convertBaseToScreen:&imageLoc];
  218.  
  219.         getDockLoc(&upperRight, &screenSize);
  220.         if (onDock)
  221.             [[dockMgrView currentDock] select:NO all:self];
  222.         else
  223.             [superview deselectAll:self];
  224.  
  225.         [self setState:YES];
  226.         [[Application workspace] slideImage:image from:&imageLoc to:&upperRight];
  227.         delivered = [[Application workspace] selectFile:path inFileViewerRootedAt:""];
  228.         if (delivered)
  229.             [[Application workspace] launchApplication:"WM"];
  230.         [self setState:NO];
  231.  
  232.         if (!(autoScan && isLaunched) && ((newStat = stat(path, &buf)) != statReturn))    {
  233.             statReturn = newStat;
  234.             [self restoreIconImage];
  235.         }
  236.     }
  237.     else if (control)    {
  238.         if (!onDock)    {
  239.             [superview perform:@selector(deleteView:)
  240.                        with:self afterDelay:0.0 cancelPrevious:YES];
  241.             [superview perform:@selector(writeShelf)
  242.                        with:nil afterDelay:1000.0 cancelPrevious:YES];
  243.             [[NXApp delegate] perform:@selector(updateMenus)
  244.                        with:nil afterDelay:1000.0 cancelPrevious:NO];
  245.             delivered = YES;
  246.             if (useSound)
  247.                 [destroySound play:self];
  248.         }
  249.         else    {
  250.             if (!sticky)    {
  251.                 [dockMgrView deleteView:self];
  252.                 delivered = YES;
  253.             }
  254.             else    {
  255.                 NXLogError("%s is flagged as persistent - can't delete", path);
  256.                 NXBeep();
  257.             }
  258.         }
  259.     }
  260.     else if (shift && command && onDock)    {
  261.         [dockMgrView inspectIcon:self];
  262.         delivered = YES;
  263.     }
  264.     else if (shift)    {
  265.         [NXApp unhide:self];
  266.         [self setState:!selected];
  267.         delivered = YES;
  268.     }
  269.     else if (alt && onDock)    {
  270.         if (!(autoScan && isLaunched) && ((newStat = stat(path, &buf)) != statReturn))    {
  271.             statReturn = newStat;
  272.             [self restoreIconImage];
  273.         }
  274.         [dockMgrView app:dockMgrView applicationDidLaunch:path];
  275.         delivered = YES;
  276.     }
  277.     else    {
  278.         if (onDock)
  279.             [[dockMgrView currentDock] select:NO all:self];
  280.         else
  281.             [superview deselectAll:self];
  282.         delivered = YES;
  283.     }
  284.  
  285.     return delivered;
  286. }
  287.  
  288. - delayedActivate
  289. {
  290.     if (appCtxt > 0)
  291.         fiendUnhideContext(appCtxt, 1, 1, 0);
  292.  
  293.     return self;
  294. }
  295.  
  296. - (BOOL)handleDoubleClick:(NXEvent *)e
  297. {
  298.     int            newStat;
  299.     NXPoint        imageLoc;
  300.     NXPoint        upperRight;
  301.     struct stat    buf;
  302.     BOOL        delivered = NO;
  303.     BOOL        alt = (e->flags & NX_ALTERNATEMASK) ? YES : NO;
  304.     BOOL        cmd = (e->flags & NX_COMMANDMASK) ? YES : NO;
  305.     const char    *path = (const char *)data;
  306.     float        delay = 1000.0 * atof(NXGetDefaultValue([NXApp appName], ACTIVE_DELAY));
  307.     BOOL        closePostLaunch = !strcmp(NXGetDefaultValue([NXApp appName], CLOSE_PSTLNCH), "YES");
  308.  
  309.     if (!autoScan && ((newStat = stat(path, &buf)) != statReturn))    {
  310.         statReturn = newStat;
  311.         [self restoreIconImage];
  312.     }
  313.     if (!isApp)    {
  314.         [self getImagePoint:&imageLoc andHilitePoint:NULL];
  315.         [self convertPoint:&imageLoc toView:nil];
  316.         [window convertBaseToScreen:&imageLoc];
  317.  
  318.         getDockLoc(&upperRight, &screenSize);
  319.         [[Application workspace] slideImage:image from:&imageLoc to:&upperRight];
  320.         delivered = [[Application workspace] openFile:path];
  321.     }
  322.     else if (cmd && isLaunched)    {
  323.         fiendUnhideContext(appCtxt, 1, 1, 1);
  324.         delivered = YES;
  325.     }
  326.     else if (!alt)    {
  327.         if (!isLaunched)    {
  328.             if (!onDock)
  329.                 [self setState:YES];
  330.             else
  331.                 [self setGhost:YES];
  332.  
  333.             [self display];
  334.             NXPing();
  335.  
  336.             if (onDock)    {
  337.                 [self setFiendLaunch:YES];
  338.                 [dockMgrView launch:path autolaunch:NO];
  339.             }
  340.             else
  341.                 [[Application workspace] launchApplication:path];
  342.  
  343.             if (!onDock)    {
  344.                 [self setState:NO];
  345.                 [self display];
  346.             }
  347.         }
  348.         else
  349.             fiendUnhideContext(appCtxt, 1, 1, 0);
  350.         delivered = YES;
  351.     }
  352.     else if (!onDock && alt)    {
  353.         delivered = [[Application workspace] openFile:path];
  354.         [self perform:@selector(delayedActivate) with:nil afterDelay:delay cancelPrevious:YES];
  355.     }
  356.     if (onDock && closePostLaunch && delivered)
  357.         [dockMgrView setShowDock:NO];
  358.  
  359.     return delivered;
  360. }
  361.  
  362. - mouseDown:(NXEvent *) e
  363. {
  364.     int            savedMask;
  365.     NXPoint        mousePoint;
  366.     NXPoint        offset;
  367.     NXEvent        newEvent;
  368.     NXEvent        savedEvent;
  369.     BOOL        delivered = NO;
  370.     int            mask = NX_LMOUSEDRAGGEDMASK|NX_LMOUSEUPMASK;
  371.  
  372.     savedEvent = *e;
  373.     mousePoint = e->location;
  374.     savedMask = [window addToEventMask:mask];
  375.     if (mouseMoved(&mousePoint, 2, mask)) {
  376.         offset.x = mousePoint.x - e->location.x;
  377.         offset.y = mousePoint.y - e->location.y;
  378.         [self handleMouseMoved:&savedEvent imagePt:&imagePoint offsetPt:&offset];
  379.     }
  380.     else    {
  381.         if (![NXApp peekNextEvent:NX_LMOUSEDOWNMASK into:&newEvent
  382.                     waitFor:0.2 threshold:NX_MODALRESPTHRESHOLD])    {
  383.             delivered = [self handleSingleClick:&savedEvent];
  384.         }
  385.         else    {
  386.             (void)[NXApp getNextEvent:NX_LMOUSEDOWNMASK];
  387.             delivered = [self handleDoubleClick:&savedEvent];
  388.         }
  389.         if (!delivered)
  390.             NXBeep();
  391.     }
  392.  
  393.     [[NXApp delegate] updateMenus];
  394.     [window setEventMask:savedMask];
  395.     return self;
  396. }
  397.  
  398.  
  399. - (NXDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal
  400. {
  401.     return NX_DragOperationAll;
  402. }
  403.  
  404. - (BOOL) acceptsFirstMouse
  405. {
  406.     return YES;
  407. }
  408.  
  409.  
  410. - (BOOL) acceptsFirstResponder
  411. {
  412.     return NO;
  413. }
  414.  
  415. - getOpenImageForDirectory:(const char *) dirname
  416. {
  417.     struct stat    st;
  418.     char    buf[MAXPATHLEN+1];
  419.     id        newImage = nil;
  420.  
  421.     strncpy(buf, dirname, sizeof(buf));
  422.     strncat(buf, "/", sizeof(buf));
  423.     strncat(buf, OPEN_DIR_ICON_FILE, sizeof(buf));
  424.     if (access(buf, R_OK) == 0) {
  425.         newImage = [[NXImage allocFromZone:[self zone]] initFromFile:buf];
  426.         if (newImage)
  427.             return newImage;
  428.     }
  429.  
  430.     if (stat(dirname, &st) >= 0 && st.st_ino == 2) {
  431.         NXSize size;
  432.         [image getSize:&size];
  433.         newImage = [[NXImage allocFromZone:[self zone]] initSize:&size];
  434.         if ([newImage lockFocus]) {
  435.             NXPoint        zeroPoint = {0,0};
  436.             id            highlight = [NXImage allocFromZone:[self zone]];
  437.             char        buf[MAXPATHLEN+1];
  438.             NXBundle   *bundle;
  439.  
  440.             bundle = [NXBundle bundleForClass:[self class]];
  441.             if ([bundle getPath:buf forResource:OPEN_HIGHLIGHT ofType:"tiff"]) {
  442.                 [[[highlight initFromFile:buf] setScalable:YES] setSize:&size];
  443.                 [image composite:NX_COPY toPoint:&zeroPoint];
  444.                 [highlight composite:NX_SOVER toPoint:&zeroPoint];
  445.                 [newImage unlockFocus];
  446.                 return newImage;
  447.             }
  448.         }
  449.     }
  450.  
  451.     if (access(DEFAULT_OPEN_DIR_FILE, R_OK) == 0)
  452.         newImage = [[NXImage allocFromZone:[self zone]] initFromFile:DEFAULT_OPEN_DIR_FILE];
  453.  
  454.     if (newImage != nil)
  455.         return newImage;
  456.     else
  457.         return image;
  458. }
  459.  
  460.  
  461. /*
  462.  *  Figure out the various parameters of the drag.
  463.  */
  464. - (DragStatus) dragStatusForPath:(char *)dragPath
  465. {
  466.     char        *destinationPath;
  467.     unsigned int    junk;
  468.     struct stat        st;
  469.  
  470.     [self getData:(void **) &destinationPath andLength:&junk];
  471.  
  472.     if (!strcmp(destinationPath, dragPath))
  473.         return WriteNotAllowed;
  474.  
  475.     if (IS_APP_PATH(destinationPath))    {
  476.         dragDestType = NXApplicationFileType;
  477.         return ApplicationDirectory;
  478.     }
  479.  
  480.     if (stat(destinationPath, &st) < 0 || (st.st_mode & S_IFMT) != S_IFDIR)
  481.         return WriteNotAllowed;
  482.     if (access(destinationPath, W_OK|X_OK) < 0)
  483.         return WriteNotAllowed;
  484.  
  485.     dragDestType = NXDirectoryFileType;
  486.     if (stat(destinationPath, &st) < 0)
  487.         return Unknown;
  488.     else {
  489.         dev_t    destDev = st.st_dev;
  490.         ino_t    destIno = st.st_ino;
  491.  
  492.         if (lstat(dragPath, &st) >= 0 &&
  493.             st.st_dev == destDev && destIno == st.st_ino)
  494.             return WriteNotAllowed;
  495.     }
  496.  
  497.     if (stat(destinationPath, &st) >= 0) {
  498.         dev_t    destinationDevice = st.st_dev;
  499.         if (lstat(dragPath, &st) >= 0)
  500.             if (st.st_dev != destinationDevice)
  501.                 return CrossDeviceOperation;
  502.             else
  503.                 return SameDeviceOperation;
  504.     }
  505.  
  506.     return Unknown;
  507. }
  508.  
  509.  
  510. - (NXDragOperation) dragOperationForContext:(id <NXDraggingInfo>) dragInfo
  511. {
  512.     unsigned int    junk;
  513.     char            *dragPath;
  514.     char            *nextPath;
  515.     BOOL            first = YES;
  516.     NXDragOperation    op = NX_DragOperationNone;
  517.     id                pb = [Pasteboard newName:NXDragPboard];
  518.     NXDragOperation    maskOp = [dragInfo draggingSourceOperationMask];
  519.  
  520.     [pb types];
  521.     [pb readType:NXFilenamePboardType data:&dragPath length:&junk];
  522.  
  523.     nextPath = dragPath;
  524.     do {
  525.         char        path[MAXPATHLEN+1];
  526.         NXDragOperation    thisOp = maskOp;
  527.  
  528.         strncpy(path, nextPath, MAXPATHLEN);
  529.         if (index(path, '\t'))
  530.             *index(path, '\t') = '\0';
  531.  
  532.         switch ([self dragStatusForPath:path]) {
  533.         case WriteNotAllowed:
  534.         case Unknown:
  535.             thisOp = NX_DragOperationNone;
  536.             break;
  537.  
  538.         case ApplicationDirectory:
  539.             if (maskOp == NX_DragOperationGeneric)
  540.                 thisOp = NX_DragOperationGeneric;
  541.             else
  542.                 thisOp = NX_DragOperationNone;
  543.             break;
  544.  
  545.         case CrossDeviceOperation:
  546.             if (maskOp & NX_DragOperationCopy) {
  547.                 thisOp = NX_DragOperationCopy;
  548.                 break;
  549.             }
  550.  
  551.         case SameDeviceOperation:
  552.             if (maskOp & NX_DragOperationGeneric) {
  553.                 thisOp = NX_DragOperationGeneric;
  554.                 break;
  555.             }
  556.  
  557.         default:
  558.             break;
  559.         }
  560.  
  561.         if (first) {
  562.             op = thisOp;
  563.             first = NO;
  564.         }
  565.         else    {
  566.             if (op != thisOp)    {
  567.                 [pb deallocatePasteboardData:dragPath length:junk];
  568.                 return NX_DragOperationNone;
  569.             }
  570.         }
  571.  
  572.         nextPath = index(nextPath, '\t');
  573.         if (nextPath == NULL)
  574.             break;
  575.         else
  576.             nextPath++;
  577.  
  578.     } while (1);
  579.  
  580.     [pb deallocatePasteboardData:dragPath length:junk];
  581.  
  582.     return op;
  583. }
  584.  
  585.  
  586. - (NXDragOperation)draggingEntered:(id <NXDraggingInfo>)sender
  587. {
  588.     lastDragOp = [self dragOperationForContext:sender];
  589.     if (lastDragOp == NX_DragOperationPrivate || lastDragOp == NX_DragOperationNone)
  590.         return NX_DragOperationNone;
  591.     else if (dragDestType == NXDirectoryFileType) {
  592.         NXSize    imageSize;
  593.  
  594.         altImage = [self getOpenImageForDirectory:data];
  595.  
  596.         [image getSize:&imageSize];
  597.         [altImage setScalable:YES];
  598.         [altImage setSize:&imageSize];
  599.  
  600.         [self display];
  601.     }
  602.  
  603.     return lastDragOp;
  604. }
  605.  
  606.  
  607. - (NXDragOperation)draggingUpdated:(id <NXDraggingInfo>)sender
  608. {
  609.     lastDragOp = [self dragOperationForContext:sender];
  610.     return lastDragOp;
  611. }
  612.  
  613.  
  614. - draggingExited:(id <NXDraggingInfo>)sender
  615. {
  616.     [altImage free];
  617.     altImage = nil;
  618.     [self display];
  619.     [window flushWindow];
  620.     return self;
  621. }
  622.  
  623.  
  624. - (BOOL) prepareForDragOperation:sender
  625. {
  626.     return YES;
  627. }
  628.  
  629. - (BOOL) performDragOperation:(id <NXDraggingInfo>)sender
  630. {
  631.     return YES;
  632. }
  633.  
  634.  
  635. - concludeDragOperation:(id <NXDraggingInfo>)sender
  636. {
  637.     char            *path;
  638.     char            *dragPath;
  639.     const char        *wsmOp;
  640.     unsigned int    pbLength;
  641.     id                workspace = [Application workspace];
  642.     id                pb = [Pasteboard newName:NXDragPboard];
  643.  
  644.     [pb types];
  645.     [pb readType:NXFilenamePboardType data:&dragPath length:&pbLength];
  646.  
  647.     if (dragDestType == NXDirectoryFileType)    {
  648.         switch (lastDragOp) {
  649.         case NX_DragOperationGeneric:
  650.             wsmOp = WSM_MOVE_OPERATION;
  651.             break;
  652.         case NX_DragOperationLink:
  653.             wsmOp = WSM_LINK_OPERATION;
  654.             break;
  655.         case NX_DragOperationCopy:
  656.             wsmOp = WSM_COPY_OPERATION;
  657.             break;
  658.         default:
  659.             [pb deallocatePasteboardData:dragPath length:pbLength];
  660.             return NO;
  661.         }
  662.         [workspace performFileOperation:wsmOp source:"/" destination:data
  663.                    files:dragPath options:NULL];
  664.     }
  665.     else if (dragDestType == NXApplicationFileType && lastDragOp == NX_DragOperationGeneric)    {
  666.         path = strtok(dragPath, "\t");
  667.         while(path && strlen(path))    {
  668.             [workspace openFile:path withApplication:data andDeactivate:NO];
  669.             path = strtok(NULL, "\t");
  670.         }
  671.     }
  672.     [pb deallocatePasteboardData:dragPath length:pbLength];
  673.  
  674.     return [self draggingExited:sender];
  675. }
  676.  
  677. @end
  678.  
  679.  
  680. /*
  681.  * Returns true if mouse is dragged more than n pixels from 'o',
  682.  * false if the mouse button is lifted.  If the mouse button is
  683.  * lifted, the mouseUp event is not consumed.
  684.  */
  685. int
  686. mouseMoved(NXPoint *o, int n, int mask)
  687. {
  688.     NXEvent e;
  689.     NXPoint p;
  690.     float   dx, dy;
  691.  
  692.     do {
  693.         [NXApp peekNextEvent:mask into:&e waitFor:0x7fffffff
  694.          threshold:NX_MODALRESPTHRESHOLD];
  695.         p = e.location;
  696.         if (e.type == NX_LMOUSEUP)
  697.             break;
  698.  
  699.         (void) [NXApp getNextEvent:mask]; /* throw it away */
  700.         dx = abs(p.x - o->x);
  701.         dy = abs(p.y - o->y);
  702.  
  703.     } while ((dy < (float) n) && (dx < (float) n));
  704.     *o = p;
  705.  
  706.     return e.type != NX_LMOUSEUP;
  707. }
  708.  
  709.