home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / Utilities / Fiend-1.4.1-src / DockMgrView.m < prev    next >
Encoding:
Text File  |  1995-12-02  |  61.5 KB  |  2,439 lines

  1. #import <math.h>
  2. #import <sys/types.h>
  3. #import <sys/stat.h>
  4. #import "Fiend.h"
  5. #import "FiendWraps.h"
  6. #import "IconDragView.h"
  7. #import "ProgressView.h"
  8. #import "Controller.h"
  9. #import "Dock.h"
  10. #import "DockMgrView.h"
  11. #import <mach/mach.h>
  12. #import <misckit/misckit.h>
  13. #import <drivers/event_status_driver.h>
  14.  
  15. @interface Application(CtxtNum)
  16. - (int)contextNum;
  17. @end
  18.  
  19. @implementation Application(CtxtNum)
  20. - (int)contextNum
  21. {
  22.     return contextNum;
  23. }
  24. @end
  25.  
  26. @implementation DockMgrView
  27.  
  28. static NXSize    screenSize;
  29.  
  30. static void
  31. doScanIcons(DPSTimedEntry te, double timeNow, void *data)
  32. {
  33.     [(id)data scanIcons];
  34. }
  35.  
  36. static int
  37. compareWins(const void *winA, const void *winB)
  38. {
  39.     float        aX = ((struct winRec *)winA)->xOffset;
  40.     float        aY = ((struct winRec *)winA)->yOffset;
  41.     float        bX = ((struct winRec *)winB)->xOffset;
  42.     float        bY = ((struct winRec *)winB)->yOffset;
  43.     float        r1 = sqrt((aX*aX)+(aY*aY));
  44.     float        r2 = sqrt((bX*bX)+(bY*bY));
  45.  
  46.     if (r1 > r2)
  47.         return 1;
  48.     else if (r1 == r2)
  49.         return 0;
  50.     else
  51.         return -1;
  52. }
  53.  
  54. void
  55. fiendUnhideContext(int context, BOOL raise, BOOL makeActive, BOOL hideOthers)
  56. {
  57.     if (context < 0) return;
  58.  
  59.     NX_DURING
  60.         PSWUnhideContext(context, raise, makeActive, hideOthers);
  61.         NXPing();
  62.     NX_HANDLER
  63.         NXReportError(&NXLocalHandler);
  64.         switch (NXLocalHandler.code) {
  65.           case dps_err_ps:
  66.             NXLogError("PS error in fiendUnhideContext: %d, %d, %d, %d",
  67.                        context, raise, makeActive, hideOthers);
  68.             break;
  69.           default:
  70.             NX_RERAISE();
  71.         }
  72.     NX_ENDHANDLER
  73. }
  74.  
  75. + initialize
  76. {
  77.     [DockMgrView setVersion:DOCKMGRVERSION];
  78.     return self;
  79. }
  80.  
  81. - setupImage:image name:(const char *)imgName size:(NXSize *)aSize
  82. {
  83.  
  84.     if (image)    {
  85.         if (strcmp(imgName, "NXAppTile"))
  86.             [image recache];
  87.         else    {
  88.             [image free];
  89.             image = [[NXImage findImageNamed:imgName] copyFromZone:[self zone]];
  90.             [image setScalable:YES];
  91.         }
  92.     }
  93.     else    {
  94.         image = [[NXImage findImageNamed:imgName] copyFromZone:[self zone]];
  95.         [image setScalable:YES];
  96.     }
  97.     [image setSize:aSize];
  98.     return image;
  99. }
  100.  
  101. - setupImages:(NXRect *)theRect
  102. {
  103.     NXSize        theSize = theRect->size;
  104.  
  105.     appTileImage = [self setupImage:appTileImage name:"NXAppTile" size:&theSize];
  106.  
  107.     theSize.width *= 0.75; theSize.height *= 0.75;
  108.     theImage = [self setupImage:theImage name:"FiendIcon" size:&theSize];
  109.     theAltImage = [self setupImage:theAltImage name:"AltFiendIcon" size:&theSize];
  110.     theLoadImage = [self setupImage:theLoadImage name:"LoadIcon" size:&theSize];
  111.  
  112.     [raiseButton getFrame:theRect];
  113.  
  114.     rbImage = [self setupImage:rbImage name:"diamond" size:&theRect->size];
  115.     rbAltImage = [self setupImage:rbAltImage name:"altDiamond" size:&theRect->size];
  116.  
  117.     [nextLevelButton getFrame:theRect];
  118.  
  119.     nbImage = [self setupImage:nbImage name:"tryButton" size:&theRect->size];
  120.     nbAltImage = [self setupImage:nbAltImage name:"tryAltButton" size:&theRect->size];
  121.  
  122.     pbImage = [self setupImage:pbImage name:"rTryButton" size:&theRect->size];
  123.     pbAltImage = [self setupImage:pbAltImage name:"rTryAltButton" size:&theRect->size];
  124.  
  125.     return self;
  126. }
  127.  
  128. - setup:(const NXRect *)theFrame
  129. {
  130.     NXRect        levelFrame;
  131.     NXRect        raiseFrame;
  132.     NXRect        frameCopy = *theFrame;
  133.     const char *const    types[1] = {NXFilenamePboardType};
  134.  
  135.     showDock = !strcmp(NXGetDefaultValue([NXApp appName], SHOW_DOCK), "YES");
  136.     dockSunken = !strcmp(NXGetDefaultValue([NXApp appName], SINK_DOCK), "YES");
  137.     dockLocked = !strcmp(NXGetDefaultValue([NXApp appName], DOCK_LOCKED), "YES");
  138.     followLevels = !strcmp(NXGetDefaultValue([NXApp appName], FOLLOW_LEVS), "YES");
  139.  
  140.     [self registerForDraggedTypes:types count:1];
  141.     [self setAutodisplay:NO];
  142.  
  143.     fiendSound = [Sound findSoundFor:"Fiend"];
  144.     destroySound = [Sound findSoundFor:"Destroy"];
  145.  
  146.     dockNameCell = [[TextFieldCell allocFromZone:[self zone]] initTextCell:""];
  147.     [dockNameCell setAlignment:NX_LEFTALIGNED];
  148.     [dockNameCell setBackgroundTransparent:YES];
  149.     [dockNameCell setTextGray:NX_BLACK];
  150.     [[dockNameCell setEditable:YES] setEnabled:YES];
  151.  
  152.     dockNumberCell = [[TextFieldCell allocFromZone:[self zone]] initTextCell:""];
  153.     [dockNumberCell setAlignment:NX_LEFTALIGNED];
  154.     [dockNumberCell setBackgroundTransparent:YES];
  155.     [dockNumberCell setTextGray:NX_BLACK];
  156.     [self setDockNameCellFont:(NXRect *)theFrame];
  157.  
  158.     fieldEditor = [window getFieldEditor:YES for:NXApp];
  159.  
  160.     [self getRaiseFrame:&levelFrame levelFrame:&raiseFrame from:(NXRect *)theFrame];
  161.     raiseButton = [[Button allocFromZone:[self zone]] initFrame:&raiseFrame icon:"" tag:0
  162.                    target:self action:@selector(raiseButtonAction:) key:'\0' enabled:YES];
  163.     [[raiseButton setType:NX_MOMENTARYCHANGE] setBordered:NO];
  164.  
  165.     prevLevelButton = [[Button allocFromZone:[self zone]] initFrame:&levelFrame icon:"" tag:0
  166.                        target:self action:@selector(levelButtonAction:) key:'\0' enabled:YES];
  167.     [[prevLevelButton setType:NX_MOMENTARYCHANGE] setBordered:NO];
  168.  
  169.     NX_Y(&levelFrame) = -1.0 + NX_MAXY(&raiseFrame) + (NX_Y(&raiseFrame)-NX_MAXY(&levelFrame));
  170.     NXIntegralRect(&levelFrame);
  171.     nextLevelButton = [[Button allocFromZone:[self zone]] initFrame:&levelFrame icon:"" tag:0
  172.                        target:self action:@selector(levelButtonAction:) key:'\0' enabled:YES];
  173.     [[nextLevelButton setType:NX_MOMENTARYCHANGE] setBordered:NO];
  174.  
  175.     frameCopy = *theFrame;
  176.     [self setupImages:&frameCopy];
  177.  
  178.     [[raiseButton setImage:rbImage] setAltImage:rbAltImage];
  179.     [[nextLevelButton setImage:nbImage] setAltImage:nbAltImage];
  180.     [[prevLevelButton setImage:pbImage] setAltImage:pbAltImage];
  181.     [self addSubview:raiseButton];
  182.     [self addSubview:nextLevelButton];
  183.     [self addSubview:prevLevelButton];
  184.  
  185.     return self;
  186. }
  187.  
  188. - startFiendLauncher
  189. {
  190.     char    path[MAXPATHLEN+1];
  191.  
  192.     sprintf(path, "%s/%s", [(NXBundle *)[NXBundle mainBundle] directory], LAUNCH_PROG);
  193.     if (access(path, X_OK) == -1)    {
  194.         NXLogError("fiend_launcher not found or not executable - terminating");
  195.         [NXApp terminate:self];
  196.     }
  197.  
  198.     launchProc = [[MiscSubprocess allocFromZone:[self zone]]
  199.                          init:NULL withDelegate:self];
  200.     [launchProc setExecArgs:path :path :""];
  201.     [launchProc execute:NULL];
  202.  
  203.     return self;
  204. }
  205.  
  206. - killLauncher
  207. {
  208.     [launchProc terminate:self];
  209.     return self;
  210. }
  211.  
  212. - subprocess:sender error:(const char *)errorString
  213. {
  214.     NXLogError("Error with fiend_launcher: %s", errorString);
  215.     [NXApp terminate:self];
  216.     return self;
  217. }
  218.  
  219. - initFrame:(const NXRect *)theFrame withWindow:aWindow
  220. {
  221.     NXEventHandle    theHandle = NXOpenEventStatus();
  222.  
  223.     [NXApp getScreenSize:&screenSize];
  224.  
  225.     editing = NO;
  226.     [super initFrame:theFrame];
  227.     [[aWindow setContentView:self] free];
  228.  
  229.     [self setup:theFrame];
  230.  
  231.     clickTime = NXClickTime(theHandle);
  232.     NXCloseEventStatus(theHandle);
  233.  
  234.     dockList = [[List allocFromZone:[self zone]] init];
  235.     stickyDock = [[[Dock allocFromZone:NXCreateZone(vm_page_size/4, vm_page_size/4, YES)]
  236.                            initMgrView:self] setSticky];
  237.     [self readDocks];
  238.     [self startFiendLauncher];
  239.     followTimer = scanTimer = (DPSTimedEntry)(-1);
  240.  
  241.     [self setNameCell];
  242.     windowsNeedUpdate = showDock;
  243.  
  244.     return self;
  245. }
  246.  
  247. - free
  248. {
  249.     [theImage free];
  250.     [theAltImage free];
  251.     [theLoadImage free];
  252.     [appTileImage free];
  253.     [dockNameCell free];
  254.     [dockNumberCell free];
  255.     [raiseButton free];
  256.     [nextLevelButton free];
  257.     [prevLevelButton free];
  258.  
  259.     [fiendSound free];
  260.     [destroySound free];
  261.  
  262.     [stickyDock free];
  263.     [[dockList freeObjects] free];
  264.  
  265.     return [super free];
  266. }
  267.  
  268. - startScanTimer
  269. {
  270.     float    timerValue = atof(NXGetDefaultValue([NXApp appName], SCAN_TIME));
  271.  
  272.     if (timerValue < 0.0)
  273.         return self;
  274.  
  275.     if (scanTimer == (DPSTimedEntry)(-1))
  276.         scanTimer = DPSAddTimedEntry(timerValue, &doScanIcons, self, NX_BASETHRESHOLD);
  277.  
  278.     return self;
  279. }
  280.  
  281. - stopScanTimer
  282. {
  283.     if (scanTimer != (DPSTimedEntry)(-1))    {
  284.         DPSRemoveTimedEntry(scanTimer);
  285.         scanTimer = (DPSTimedEntry)(-1);
  286.     }
  287.     return self;
  288. }
  289.  
  290. - fade
  291. {
  292.     id            theSound;
  293.     int            j;
  294.     NXPoint        imagePt;
  295.     float        cellHeight;
  296.     int            fadeIn = 350;
  297.     int            fadeOut = 350;
  298.     int            stay = 1000;
  299.     float        width = NX_WIDTH(&frame);
  300.     float        height = NX_HEIGHT(&frame);
  301.     NXRect        workRect = {{0.0, 0.0}, {0.0, 0.0}};
  302.     NXRect        imageRect = {{0.0, 0.0}, {0.0, 0.0}};
  303.     id            daveImage = [NXImage findImageNamed:"Dave"];
  304.     id            tempImage = [appTileImage copyFromZone:[self zone]];
  305.     id            origImage = [appTileImage copyFromZone:[self zone]];
  306.  
  307.     [self stopScanTimer];
  308.  
  309.     [dockNameCell calcCellSize:&workRect.size];
  310.     cellHeight = NX_HEIGHT(&workRect);
  311.  
  312.     [theImage getSize:&imageRect.size];
  313.     NXIntegralRect(&imageRect);
  314.     [[daveImage setScalable:YES] setSize:&imageRect.size];
  315.  
  316.     imagePt.x = -3.0*width/64.0 + rint((width - NX_WIDTH(&imageRect))/2.0);
  317.     imagePt.y = rint((height - NX_HEIGHT(&imageRect))/2.0) - cellHeight/2.0;
  318.     workRect.size = imageRect.size;
  319.     workRect.origin = imagePt;
  320.     NX_WIDTH(&workRect) -= 2.0*width/64.0;
  321.  
  322.     [tempImage lockFocus];
  323.     [daveImage composite:NX_SOVER fromRect:&imageRect toPoint:&imagePt];
  324.     [tempImage unlockFocus];
  325.  
  326.     [origImage lockFocus];
  327.     [theImage composite:NX_SOVER fromRect:&imageRect toPoint:&imagePt];
  328.     [origImage unlockFocus];
  329.  
  330.     theSound = [[Sound allocFromZone:[self zone]] initFromSection:"Ahhhhh"];
  331.     [theSound play];
  332.     [self lockFocus];
  333.     for(j = 0; j <= fadeIn; j++)    {
  334.         [origImage composite:NX_SOVER fromRect:&workRect toPoint:&imagePt];
  335.         [tempImage dissolve:(float)j/(float)fadeIn fromRect:&workRect toPoint:&imagePt];
  336.         [window flushWindow];
  337.         NXPing();
  338.     }
  339.     thread_switch(THREAD_NULL, SWITCH_OPTION_WAIT, stay);
  340.     for(j = fadeOut; j >= 0; j--)    {
  341.         [origImage composite:NX_SOVER fromRect:&workRect toPoint:&imagePt];
  342.         [tempImage dissolve:(float)j/(float)fadeOut fromRect:&workRect toPoint:&imagePt];
  343.         [window flushWindow];
  344.         NXPing();
  345.     }
  346.     [self unlockFocus];
  347.  
  348.     [tempImage free];
  349.     [daveImage free];
  350.  
  351.     [self display];
  352.     [self startScanTimer];
  353.  
  354.     [theSound perform:@selector(free) with:nil afterDelay:1000.0 cancelPrevious:YES];
  355.  
  356.     return self;
  357. }
  358.  
  359. - twist
  360. {
  361.     id            theSound;
  362.     int            j;
  363.     float        i;
  364.     NXPoint        p;
  365.     NXPoint        imagePt;
  366.     float        origWidth;
  367.     float        cellHeight;
  368.     float        width = NX_WIDTH(&frame);
  369.     float        height = NX_HEIGHT(&frame);
  370.     NXRect        workRect = {{0.0, 0.0}, {0.0, 0.0}};
  371.     NXRect        imageRect = {{0.0, 0.0}, {0.0, 0.0}};
  372.     id            tempImage = [theImage copyFromZone:[self zone]];
  373.     id            eraseImage = [theImage copyFromZone:[self zone]];
  374.  
  375.     [self stopScanTimer];
  376.  
  377.     [dockNameCell calcCellSize:&workRect.size];
  378.     cellHeight = NX_HEIGHT(&workRect);
  379.  
  380.     [tempImage getSize:&imageRect.size];
  381.     NXIntegralRect(&imageRect);
  382.  
  383.     imagePt.x = -3.0*width/64.0 + rint((width - NX_WIDTH(&imageRect))/2.0);
  384.     imagePt.y = rint((height - NX_HEIGHT(&imageRect))/2.0) - cellHeight/2.0;
  385.  
  386.     [eraseImage lockFocus];
  387.     [appTileImage composite:NX_SIN fromRect:&frame toPoint:&frame.origin];
  388.     [eraseImage unlockFocus];
  389.  
  390.     theSound = [[Sound allocFromZone:[self zone]] initFromSection:"hahaha"];
  391.     [theSound play];
  392.     [self lockFocus];
  393.     for(j = 0; j < 10; j++)    {
  394.         [tempImage getSize:&workRect.size];
  395.         origWidth = NX_WIDTH(&workRect);
  396.         p.y = rint((height - NX_HEIGHT(&workRect))/2.0) - cellHeight/2.0;
  397.         p.x = -3.0*width/64.0 + rint((width - NX_WIDTH(&workRect))/2.0);
  398.         for(i = 0.0; i <= origWidth/4.0; i+=1.0)    {
  399.             NX_WIDTH(&workRect)-= 4.0;
  400.             p.x = -3.0*width/64.0 + rint((width - NX_WIDTH(&workRect))/2.0);
  401.             [tempImage setSize:&workRect.size];
  402.             [eraseImage composite:NX_SOVER fromRect:&imageRect toPoint:&imagePt];
  403.             [tempImage composite:NX_SOVER fromRect:&workRect toPoint:&p];
  404.             [tempImage recache];
  405.             [window flushWindow];
  406.         }
  407.         for(i = 0.0; i <= origWidth/4.0; i+=1.0)    {
  408.             NX_WIDTH(&workRect)+= 4.0;
  409.             p.x = -3.0*width/64.0 + rint((width - NX_WIDTH(&workRect))/2.0);
  410.             [tempImage setSize:&workRect.size];
  411.             [eraseImage composite:NX_SOVER fromRect:&imageRect toPoint:&imagePt];
  412.             [tempImage composite:NX_SOVER fromRect:&workRect toPoint:&p];
  413.             [window flushWindow];
  414.             [tempImage recache];
  415.         }
  416.     }
  417.     [self unlockFocus];
  418.  
  419.     [eraseImage free];
  420.     [tempImage free];
  421.  
  422.     [self display];
  423.     [self startScanTimer];
  424.  
  425.     [theSound perform:@selector(free) with:nil afterDelay:1000.0 cancelPrevious:YES];
  426.  
  427.     return self;
  428. }
  429.  
  430. - updateWindows:(NXPoint *)thePoint
  431. {
  432.     [currentDock updateWindows:thePoint usePlace:NO followLevels:followLevels];
  433.     [stickyDock updateWindows:thePoint usePlace:NO followLevels:followLevels];
  434.     return self;
  435. }
  436.  
  437. - drawSelf:(const NXRect *)rects:(int)rectCount
  438. {
  439.     float    cellHeight;
  440.     NXPoint    p;
  441.     NXPoint    imagePt;
  442.     NXRect    winFrame;
  443.     NXPoint    goAwayPt = {-1000.0, -1000.0};
  444.     NXRect    imageRect = {{0.0, 0.0}, {0.0, 0.0}};
  445.     float    width = frame.size.width;
  446.     float    height = frame.size.height;
  447.     id        image = (showDock) ? theImage : theAltImage;
  448.     BOOL    showDockIndex = !strcmp(NXGetDefaultValue([NXApp appName], SHOW_DCKIDX), "YES");
  449.  
  450.     [appTileImage composite:NX_COPY fromRect:&frame toPoint:&frame.origin];
  451.  
  452.     [dockNameCell calcCellSize:&imageRect.size];
  453.     cellHeight = NX_HEIGHT(&imageRect);
  454.     NX_X(&imageRect) = 2.0; NX_Y(&imageRect) = height - cellHeight - 1.0;
  455.     if (NX_MAXX(&imageRect) > width-2.0)
  456.         NX_WIDTH(&imageRect) = width - 4.0;
  457.     [dockNameCell drawSelf:&imageRect inView:self];
  458.  
  459.     if (showDockIndex)    {
  460.         [dockNumberCell calcCellSize:&imageRect.size];
  461.         NX_Y(&imageRect) = height/32.0;
  462.         [dockNumberCell drawSelf:&imageRect inView:self];
  463.     }
  464.  
  465.     if (dockLocked)    {
  466.         float    x = atof(NXGetDefaultValue([NXApp appName], "LIX"));
  467.         float    y = atof(NXGetDefaultValue([NXApp appName], "LIY"));
  468.         float    r = atof(NXGetDefaultValue([NXApp appName], "LIR"));
  469.         ([self shouldDrawColor]) ? NXSetColor(NX_COLORRED) : PSsetgray(NX_DKGRAY);
  470.         PSarc(x*width/64.0, y*height/64.0, r*width/64.0, 0.0, 360.0);
  471.         PSfill();
  472.         PSsetgray(NX_BLACK); PSsetlinewidth(0.0);
  473.         PSarc(x*width/64.0, y*height/64.0, r*width/64.0, 0.0, 360.0);
  474.         PSstroke();
  475.     }
  476.  
  477.     NX_X(&imageRect) = NX_Y(&imageRect) = 0.0;
  478.     [image getSize:&imageRect.size];
  479.     imagePt.x = -3.0*height/64.0 + rint((width - NX_WIDTH(&imageRect))/2.0);
  480.     imagePt.y = rint((height - NX_HEIGHT(&imageRect))/2.0) - cellHeight/2.0;
  481.     NXIntegralRect(&imageRect);
  482.     [image composite:NX_SOVER fromRect:&imageRect toPoint:&imagePt];
  483.  
  484.     if (windowsNeedUpdate)    {
  485.         p = (showDock) ? frame.origin : goAwayPt;
  486.         [window convertBaseToScreen:&p];
  487.         [window getFrame:&winFrame];
  488.         [currentDock setFrame:&winFrame];
  489.         [stickyDock setFrame:&winFrame];
  490.         [self updateWindows:&p];
  491.         windowsNeedUpdate = NO;
  492.     }
  493.  
  494.     return self;
  495. }
  496.  
  497. - add:aView toStickyDock:(BOOL)flag owner:dock
  498. {
  499.     int        junk;
  500.     char    *viewPath;
  501.     NXPoint    offset;
  502.     NXRect    winFrame;
  503.     id        refDock = (dock == nil) ? currentDock : dock;
  504.  
  505.     if (aView == nil)
  506.         return nil;
  507.  
  508.     if (flag)    {
  509.         [refDock getOffset:&offset forWindow:[aView window]];
  510.         [stickyDock addStickyWindow:[aView window] atOffset:&offset];
  511.     }
  512.     else    {
  513.         [aView getData:(void **)&viewPath andLength:&junk];
  514.         [stickyDock removeStickyWindow:[aView window]];
  515.         if (!showDock)
  516.             [[aView window] moveTo:-1000.0 :-1000.0];
  517.         else if ([currentDock indexOfPath:viewPath exact:YES] == -1)    {
  518.             int level = [self findLevelContaining:viewPath switch:NO];
  519.             id    oldDock = [dockList objectAt:level];
  520.             [oldDock removeWindow:[aView window]];
  521.             [currentDock addWindow:[aView window] withPath:viewPath];
  522.         }
  523.     }
  524.     [stickyDock getFrame:&winFrame];
  525.     [stickyDock updateWindows:&winFrame.origin usePlace:NO followLevels:NO];
  526.     return self;
  527. }
  528.  
  529. - setDockNameCellFont:(NXRect *)aRect
  530. {
  531.     float    fontSize;
  532.     BOOL    boldDockFont = !strcmp(NXGetDefaultValue([NXApp appName], DOCK_BLDFNT), "YES");
  533.     BOOL    bigDockFont = !strcmp(NXGetDefaultValue([NXApp appName], DOCK_BIGFNT), "YES");
  534.  
  535.     fontSize = (bigDockFont) ? 12.0 : 10.0;
  536.     fontSize *= (NX_WIDTH(aRect)/64.0);
  537.     fontSize = (fontSize < 6.0) ? 6.0 : fontSize;
  538.     fontSize = (fontSize > 18.0) ? 18.0 : fontSize;
  539.     fontSize = (int)fontSize;
  540.  
  541.     if (!boldDockFont)    {
  542.         [dockNameCell setFont:[Font systemFontOfSize:fontSize matrix:NX_FLIPPEDMATRIX]];
  543.         [dockNumberCell setFont:[Font systemFontOfSize:fontSize-1.0 matrix:NX_FLIPPEDMATRIX]];
  544.     }
  545.     else    {
  546.         [dockNameCell setFont:[Font boldSystemFontOfSize:fontSize matrix:NX_FLIPPEDMATRIX]];
  547.         [dockNumberCell setFont:[Font boldSystemFontOfSize:fontSize-1.0 matrix:NX_FLIPPEDMATRIX]];
  548.     }
  549.     return self;
  550. }
  551.  
  552. - deleteView:aView
  553. {
  554.     BOOL    useSound = !strcmp(NXGetDefaultValue([NXApp appName], USE_SOUND), "YES");
  555.  
  556.     [aView perform:@selector(delayedActivate) with:nil afterDelay:-1.0 cancelPrevious:YES];
  557.     [self perform:@selector(delayedUnsetGhost:) with:aView afterDelay:-1.0 cancelPrevious:YES];
  558.     [currentDock deleteView:aView quickly:NO unvanish:YES];
  559.     [self display];
  560.     [self perform:@selector(writeDocks) with:nil afterDelay:100.0 cancelPrevious:YES];
  561.     if (useSound)
  562.         [destroySound play];
  563.     return self;
  564. }
  565.  
  566. - addLevel
  567. {
  568.     id        newDock;
  569.     NXRect    dockFrame = frame;
  570.     NXPoint    goAwayPt = {-1000.0, -1000.0};
  571.  
  572.     [[self window] convertBaseToScreen:&dockFrame.origin];
  573.     newDock = [[Dock allocFromZone:NXCreateZone(vm_page_size, vm_page_size, YES)] initMgrView:self];
  574.     [newDock setIsLoaded:YES];
  575.     [newDock setFiendSound:fiendSound destroySound:destroySound];
  576.  
  577.     [currentDock updateWindows:&goAwayPt usePlace:NO followLevels:followLevels];
  578.     [dockList addObject:newDock];
  579.     currentDock = newDock;
  580.     currentDockIndex = [dockList count]-1;
  581.     
  582.     windowsNeedUpdate = YES;
  583.     [self setNameCell];
  584.     [[NXApp delegate] updateMenus];
  585.  
  586.     return self;
  587. }
  588.  
  589. - deleteLevel
  590. {
  591.     int        status;
  592.     NXZone    *theZone = [currentDock zone];
  593.     NXPoint    goAwayPt = {-1000.0, -1000.0};
  594.  
  595.     if ([dockList count] == 1)    {
  596.         NXBeep();
  597.         NXRunAlertPanel([NXApp appName],
  598.                         "This is the last dock level - cannot delete",
  599.                         NULL, NULL, NULL);
  600.         return nil;
  601.     }
  602.     else    {
  603.         NXBeep();
  604.         status = NXRunAlertPanel([NXApp appName],
  605.                                  "Really delete this level?",
  606.                                  "No", "Go ahead", NULL);
  607.         if (status == NX_ALERTDEFAULT)
  608.             return self;
  609.     }
  610.  
  611.     [dockList removeObjectAt:currentDockIndex];
  612.     [currentDock updateWindows:&goAwayPt usePlace:NO followLevels:NO];
  613.     [currentDock free];
  614.     NXDestroyZone(theZone);
  615.     currentDockIndex = (currentDockIndex > 1) ? currentDockIndex - 1 : 0;
  616.  
  617.     currentDock = [dockList objectAt:currentDockIndex];
  618.     if (![currentDock isLoaded])
  619.         [currentDock createWindowsFromStores:YES stickyWindows:NO];
  620.     windowsNeedUpdate = YES;
  621.     [self setNameCell];
  622.     [[NXApp delegate] updateMenus];
  623.  
  624.     return self;
  625. }
  626.  
  627. - raiseButtonAction:sender
  628. {
  629.     int        flags = [sender mouseDownFlags];
  630.  
  631.     if (flags & NX_COMMANDMASK)
  632.         fiendUnhideContext([NXApp contextNum], 1, 1, 1);
  633.     else if ((flags & NX_CONTROLMASK) && showDock)
  634.         [currentDock rotateOffsets];
  635.     else
  636.         [NXApp unhide:self];
  637.  
  638.     return self;
  639. }
  640.  
  641. - levelButtonAction:sender
  642. {
  643.     if (sender == nextLevelButton)    {
  644.         if ([sender mouseDownFlags] & NX_SHIFTMASK)
  645.             [self previousLevel];
  646.         else
  647.             [self nextLevel];
  648.     }
  649.     else if (sender == prevLevelButton)    {
  650.         if ([sender mouseDownFlags] & NX_SHIFTMASK)
  651.             [self nextLevel];
  652.         else
  653.             [self previousLevel];
  654.     }
  655.  
  656.     return self;
  657. }
  658.  
  659. - nextLevel
  660. {
  661.     int        theLevel;
  662.  
  663.     if ([dockList count] < 2)    {
  664.         NXBeep();
  665.         return self;
  666.     }
  667.  
  668.     theLevel = currentDockIndex + 1;
  669.     theLevel %= [dockList count];
  670.     [self gotoDockLevel:theLevel];
  671.  
  672.     return self;
  673. }    
  674.  
  675. - previousLevel
  676. {
  677.     int        theLevel;
  678.  
  679.     if ([dockList count] < 2)    {
  680.         NXBeep();
  681.         return nil;
  682.     }
  683.  
  684.     theLevel = currentDockIndex - 1;
  685.     if (theLevel < 0)
  686.         theLevel = [dockList count]-1;
  687.     [self gotoDockLevel:theLevel];
  688.  
  689.     return self;
  690. }
  691.  
  692.  
  693. - moveIconsTo:(int)newLevel
  694. {
  695.     if (![currentDock hasSelectedCells] || [stickyDock hasSelectedCells])    {
  696.         NXBeep();
  697.         NXRunAlertPanel([NXApp appName],
  698.                         "No icons to move!",
  699.                         NULL, NULL, NULL);
  700.         [self deselectAll:self];
  701.         return nil;
  702.     }
  703.  
  704.     if (![currentDock copy:self toPasteboard:[Pasteboard new] andCut:YES sndEnable:NO])    {
  705.         NXBeep();
  706.         [self deselectAll:self];
  707.         return self;
  708.     }
  709.  
  710.     [self gotoDockLevel:newLevel];
  711.  
  712.     [currentDock paste:self sndEnable:NO];
  713.     [self deselectAll:self];
  714.     [[NXApp delegate] updateMenus];
  715.     [self perform:@selector(writeDocks) with:nil afterDelay:100.0 cancelPrevious:YES];
  716.  
  717.     return self;
  718. }
  719.  
  720. - moveLevelTo:(int)newLevel
  721. {
  722.     if (newLevel == currentDockIndex)
  723.         return self;
  724.  
  725.     if (newLevel < 0 || newLevel >= [dockList count])    {
  726.         NXRunAlertPanel([NXApp appName],
  727.                         "Level %d is out of range!",
  728.                         NULL, NULL, NULL, newLevel+1);
  729.         return nil;
  730.     }
  731.  
  732.     [dockList removeObjectAt:currentDockIndex];
  733.     [dockList insertObject:currentDock at:newLevel];
  734.  
  735.     currentDockIndex = newLevel;
  736.     [self setNameCell];
  737.     [[NXApp delegate] updateMenus];
  738.  
  739.     return self;
  740. }
  741.  
  742.  
  743. - clearDockLevel
  744. {
  745.     int        status;
  746.  
  747.     NXBeep();
  748.     status = NXRunAlertPanel([NXApp appName],
  749.                              "Really clear this level?",
  750.                              "No", "Go Ahead", NULL);
  751.     if (status == NX_ALERTDEFAULT)
  752.         return self;                   
  753.  
  754.     [currentDock empty];
  755.     [[NXApp delegate] updateMenus];
  756.  
  757.     return self;
  758. }
  759.  
  760. - setLaunchFlagsFor:aView
  761. {
  762.     int        index;
  763.     char    *path = (char *)[(IconView *)aView data];
  764.  
  765.     if ([currentDock indexOfPath:(char *)path exact:YES] != -1)    {
  766.         [currentDock setLaunchFlagsFor:aView];
  767.         return self;
  768.     }
  769.  
  770.     index = [self findLevelContaining:(char *)[(IconView *)aView data] switch:NO];
  771.     if (index != NX_NOT_IN_LIST)    {
  772.         [[dockList objectAt:index] setLaunchFlagsFor:aView];
  773.         return self;
  774.     }
  775.     return nil;
  776. }
  777.  
  778. - redisplayAllIcons
  779. {
  780.     id        *dock;
  781.     int        i;
  782.     int        count = [dockList count];
  783.     id        *dockListPtr = (count > 0) ? NX_ADDRESS(dockList) : (id *)NULL;
  784.  
  785.     for(i = 0, dock = dockListPtr; i < count; i++, dock++)
  786.         [*dock redisplayIcons];
  787.  
  788.     return self;
  789. }
  790.  
  791. - inspectIcon:sender
  792. {
  793.     id            iconView;
  794.     int            len;
  795.     char        *path;
  796.  
  797.     if (iconInspector == nil)
  798.         [NXApp loadNibSection:"DockIconInspector.nib" owner:self withNames:NO];
  799.  
  800.     if ([sender isKindOf:[IconView class]])
  801.         iconView = sender;
  802.     else    {
  803.         iconView  = [currentDock selectedCell];
  804.         if (iconView == nil)    {
  805.             iconView = [stickyDock selectedCell];
  806.             if (iconView == nil)    {
  807.                 NXBeep();
  808.                 return self;
  809.             }
  810.         }
  811.     }
  812.  
  813.     [iconView getData:(void **)&path andLength:&len];
  814.     [iconPathField setStringValue:path];
  815.  
  816.     [iconSwitchMatrix setState:[iconView autoLaunch] at:0 :0];
  817.     [iconSwitchMatrix setState:[iconView autoScan] at:0 :1];
  818.     [iconSwitchMatrix setState:[iconView isSticky] at:0 :2];
  819.  
  820.     [[iconSwitchMatrix cellAt:0 :0] setEnabled:(strcmp(path, WKSPC_FILE) != 0)];
  821.     [[iconSwitchMatrix cellAt:0 :1]
  822.      setEnabled:(strcmp(path, WKSPC_FILE) != 0 && [iconView isApp])];
  823.  
  824.     [NXApp runModalFor:iconInspector];
  825.  
  826.     if (inspectorButtonTag == 1)    {
  827.         BOOL    state;
  828.  
  829.         state = [[iconSwitchMatrix cellAt:0 :0] state];
  830.         if (state != [iconView autoLaunch])
  831.             [iconView setAutoLaunch:state];
  832.  
  833.         state = [[iconSwitchMatrix cellAt:0 :1] state];
  834.         if (state != [iconView autoScan])
  835.             [iconView setAutoScan:state];
  836.  
  837.         state = [[iconSwitchMatrix cellAt:0 :2] state];
  838.         if (state != [iconView isSticky])    {
  839.             [iconView setSticky:state];
  840.             [self add:iconView toStickyDock:[iconView isSticky] owner:nil];
  841.         }
  842.  
  843.         [self setLaunchFlagsFor:iconView];
  844.         [iconView display];
  845.     }
  846.  
  847.     [currentDock select:NO all:self];
  848.     [self perform:@selector(writeDocks) with:nil afterDelay:100.0 cancelPrevious:YES];
  849.     [[NXApp delegate] updateMenus];
  850.     return self;
  851. }
  852.  
  853. - (int)findLevelContaining:(const char *)aPath switch:(BOOL)flag
  854. {
  855.     id        *dock;
  856.     int        i;
  857.     int        count = [dockList count];
  858.     id        *dockListPtr = (count > 0) ? NX_ADDRESS(dockList) : (id *)NULL;
  859.  
  860.     if ([currentDock indexOfPath:(char *)aPath exact:!flag] != -1)
  861.         i = currentDockIndex;
  862.     else    {
  863.         for(i = 0, dock = dockListPtr; i < count; i++, dock++)    {
  864.             if (*dock == currentDock)
  865.                 continue;
  866.             if ([*dock indexOfPath:(char *)aPath exact:!flag] != -1)
  867.                 break;
  868.         }
  869.         if (i == count)    {
  870.             if (flag)    {
  871.                 NXBeep();
  872.                 NXRunAlertPanel([NXApp appName],
  873.                                 "Icon for '%s' not found...",
  874.                                 NULL, NULL, NULL, aPath);
  875.             }
  876.             return -1;
  877.         }
  878.     }
  879.  
  880.     if (flag)    {
  881.         [self gotoDockLevel:i];
  882.         [currentDock select:YES iconWithPath:(char *)aPath];
  883.         NXPing();
  884.         thread_switch(THREAD_NULL, SWITCH_OPTION_WAIT, 1500);
  885.         [currentDock select:NO iconWithPath:(char *)aPath];
  886.         NXPing();
  887.     }
  888.  
  889.     return i;
  890. }
  891.  
  892. - (int)totalIconCount
  893. {
  894.     id        *dock;
  895.     int        i;
  896.     int        total = 0;
  897.     int        count = [dockList count];
  898.     id        *dockListPtr = (count > 0) ? NX_ADDRESS(dockList) : (id *)NULL;
  899.     
  900.     for(i = 0, dock = dockListPtr; i < count; i++, dock++)
  901.         total += [*dock iconCount];
  902.     return total;
  903. }
  904.  
  905. - sendCurrentToBottom
  906. {
  907.     return [self moveLevelTo:[dockList count]-1];
  908. }
  909.  
  910. - bringCurrentToTop
  911. {
  912.     return [self moveLevelTo:0];
  913. }
  914.  
  915. - gotoDockLevel:(int)aLevel
  916. {
  917.     id        tempImage = theImage;
  918.     id        oldDock = currentDock;
  919.     NXPoint    goAwayPt = {-1000.0, -1000.0};
  920.  
  921.     if (aLevel < 0 || aLevel >= [dockList count])    {
  922.         NXRunAlertPanel([NXApp appName],
  923.                         "Level %d out of range!",
  924.                         NULL, NULL, NULL, aLevel+1);
  925.         return nil;
  926.     }
  927.  
  928.     if (aLevel == currentDockIndex)
  929.         return self;
  930.  
  931.     if (editing)
  932.         [window endEditingFor:nil];
  933.  
  934.     [oldDock updateWindows:&goAwayPt usePlace:NO followLevels:followLevels];
  935.     [oldDock select:NO all:self];
  936.  
  937.     currentDockIndex = aLevel;
  938.     currentDock = [dockList objectAt:currentDockIndex];
  939.  
  940.     showDock = YES;
  941.     [self setNameCell];
  942.     if (![currentDock isLoaded])    {
  943.         theImage = theLoadImage;
  944.         [self display];
  945.         [currentDock createWindowsFromStores:YES stickyWindows:NO];
  946.         theImage = tempImage;
  947.     }
  948.  
  949.     windowsNeedUpdate = YES;
  950.     [self display];
  951.  
  952.     [[NXApp delegate] updateMenus];
  953.  
  954.     return self;
  955. }        
  956.  
  957. - gotoNamedLevel:(char *)aName
  958. {
  959.     int        i;
  960.     int        count = [dockList count];
  961.  
  962.     for(i = 0; i < count; i++)    {
  963.         if (strstr([[dockList objectAt:i] name], aName))
  964.             break;
  965.     }
  966.     if (i == count)    {
  967.         NXBeep();
  968.         NXRunAlertPanel([NXApp appName],
  969.                         "Level '%s' does not exist!!",
  970.                         NULL, NULL, NULL, aName);
  971.         return self;
  972.     }
  973.     [self gotoDockLevel:i];
  974.  
  975.     return self;
  976. }
  977.  
  978. - (int)hasSelectedCells
  979. {
  980.     return ([(Dock *)currentDock hasSelectedCells] + [(Dock *)stickyDock hasSelectedCells]);
  981. }
  982.  
  983. - copy:sender toPasteboard:pb andCut:(BOOL)cutFlag
  984. {
  985.     if (![currentDock copy:nil toPasteboard:pb andCut:cutFlag sndEnable:YES])    {
  986.         NXBeep();
  987.         return self;
  988.     }
  989.     if (cutFlag)    {
  990.         [[NXApp delegate] updateMenus];
  991.         [self perform:@selector(writeDocks) with:nil afterDelay:100.0 cancelPrevious:YES];
  992.     }
  993.     return self;
  994. }
  995.  
  996. - paste:sender toPasteboard:pb
  997. {
  998.     NXRect        winFrame;
  999.  
  1000.     [self stopScanTimer];
  1001.     [IconView resetProcessTable];
  1002.     [window getFrame:&winFrame];
  1003.     [stickyDock setFrame:&winFrame];
  1004.     [currentDock setFrame:&winFrame];
  1005.     [currentDock paste:self toPasteboard:pb sndEnable:YES];
  1006.     [self startScanTimer];
  1007.     [[NXApp delegate] updateMenus];
  1008.     [self perform:@selector(writeDocks) with:nil afterDelay:100.0 cancelPrevious:YES];
  1009.     return self;
  1010. }
  1011.  
  1012. - paste:sender
  1013. {
  1014.     return [self paste:sender toPasteboard:[Pasteboard new]];
  1015. }
  1016.  
  1017. - (int)currentDockIndex
  1018. {
  1019.     return currentDockIndex;
  1020. }
  1021.  
  1022. - deselectAll:sender
  1023. {
  1024.     [stickyDock select:NO all:self];
  1025.     [currentDock select:NO all:self];
  1026.     [[NXApp delegate] updateMenus];
  1027.     return self;
  1028. }
  1029.  
  1030. - delayedUnsetGhost:(IconView *)iconView
  1031. {
  1032.     if ([iconView isGhost])
  1033.         [[iconView setGhost:NO] display];
  1034.     return self;
  1035. }
  1036.  
  1037. - launch:(const char *)aProgram autolaunch:(BOOL)flag
  1038. {
  1039.     char    path[MAXPATHLEN+1];
  1040.  
  1041.     sprintf(path, "%d %s", (int)flag, aProgram);
  1042.     [launchProc send:path];
  1043.  
  1044.     return self;
  1045. }
  1046.  
  1047. - app:theApp applicationWillLaunch:(const char *)theAppName
  1048. {
  1049.     id        *dock;
  1050.     id        appWin;
  1051.     id        appIconView;
  1052.     int        i;
  1053.     int        count = [dockList count];
  1054.     id        *dockListPtr = (count > 0) ? NX_ADDRESS(dockList) : (id *)NULL;
  1055.  
  1056.     for(i = 0, dock = dockListPtr; i < count; i++, dock++)    {
  1057.         if ((appWin = [*dock findWindowForName:theAppName]) != nil)    {
  1058.             if (appWin == *dock)
  1059.                 break;
  1060.             appIconView = [appWin contentView];
  1061.             if (![appIconView isLaunched])    {
  1062.                 [[appIconView setGhost:YES] display];
  1063.                 [self perform:@selector(delayedUnsetGhost:) with:appIconView
  1064.                  afterDelay:60000 cancelPrevious:YES];
  1065.             }
  1066.             break;
  1067.         }
  1068.     }
  1069.     return self;
  1070. }
  1071.  
  1072. - app:theApp applicationDidLaunch:(const char *)theAppName
  1073. {
  1074.     id        *dock;
  1075.     id        appWin;
  1076.     int        i;
  1077.     int        pid;
  1078.     int        dockIndx;
  1079.     char    shortName[MAXPATHLEN+1];
  1080.     id        appIconView = nil;
  1081.     int        count = [dockList count];
  1082.     id        *dockListPtr = (count > 0) ? NX_ADDRESS(dockList) : (id *)NULL;
  1083.     int        retries = atoi(NXGetDefaultValue([NXApp appName], PTAB_RETRIES));
  1084.     float    activeDelay = 1000.0*atof(NXGetDefaultValue([NXApp appName], ACTIVE_DELAY));
  1085.     BOOL    hideIcons = !strcmp(NXGetDefaultValue([NXApp appName], HIDE_ICONS), "YES");
  1086.  
  1087.     [self stopScanTimer];
  1088.     [IconView getShortName:shortName from:theAppName];
  1089.  
  1090.     if ((theApp == self) && ((pid = [IconView getLastPidFor:shortName]) == -1))    {
  1091.         [self startScanTimer];
  1092.         return self;
  1093.     }
  1094.  
  1095.     appIconView = appWin = nil;
  1096.     for(i = 0, dock = dockListPtr; i < count; i++, dock++)    {
  1097.         if ((dockIndx = [*dock indexOfPath:(char *)theAppName exact:YES]) != -1)    {
  1098.             thread_switch(THREAD_NULL, SWITCH_OPTION_WAIT, 200);
  1099.             [IconView resetProcessTable];
  1100.             pid = [IconView getLastPidFor:shortName];
  1101.             while(pid == -1 && --retries)    {
  1102.                 thread_switch(THREAD_NULL, SWITCH_OPTION_WAIT, 500);
  1103.                 [IconView resetProcessTable];
  1104.                 pid = [IconView getLastPidFor:shortName];
  1105.             }
  1106.             if (pid == -1)    {
  1107.                 NXLogError("Never found pid for %s!!", shortName);
  1108.                 [self startScanTimer];
  1109.                 return self;
  1110.             }
  1111.  
  1112.             if (hideIcons)    {
  1113.                 int appIcon = [IconView getIconForPid:pid];
  1114.                 [[*dock appIconStore] replaceElementAt:dockIndx with:(void *)&appIcon];
  1115.                 if (appIcon > 0 && !onNeXTDock(theAppName, (int)screenSize.height))
  1116.                     PSWMove(-1000.0, -1000.0, appIcon);
  1117.             }
  1118.  
  1119.             if ((appWin = [*dock findWindowForName:theAppName]) == *dock)
  1120.                 break;
  1121.             appIconView = [appWin contentView];
  1122.             if ([appIconView appPid] == -1)    {
  1123.                 [appIconView getAppPid];
  1124.                 if ([appIconView appPid] != -1)    {
  1125.                     [[[[appIconView setGhost:NO] setLaunched:YES] refreshIcon] display];
  1126.                     NXPing();
  1127.                 }
  1128.             }
  1129.             break;
  1130.         }
  1131.     }
  1132.  
  1133.     if (appIconView != nil && [appIconView appPid] != -1 &&
  1134.         [appIconView fiendLaunch] && activeDelay > 0.0)    {
  1135.         [appIconView perform:@selector(delayedActivate) with:nil
  1136.          afterDelay:activeDelay cancelPrevious:YES];
  1137.     }
  1138.     if (appIconView != nil) [appIconView setFiendLaunch:NO];
  1139.  
  1140.     [self startScanTimer];
  1141.  
  1142.     return self;
  1143. }
  1144.  
  1145. - app:theApp applicationDidTerminate:(const char *)theAppName
  1146. {
  1147.     id        *dock;
  1148.     id        appWin;
  1149.     id        appIconView;
  1150.     int        i;
  1151.     int        pid;
  1152.     int        ctxt;
  1153.     int        appIcon;
  1154.     int        dockIndx;
  1155.     char    shortName[MAXPATHLEN+1];
  1156.     int        count = [dockList count];
  1157.     id        *dockListPtr = (count > 0) ? NX_ADDRESS(dockList) : (id *)NULL;
  1158.     BOOL    hideIcons = !strcmp(NXGetDefaultValue([NXApp appName], HIDE_ICONS), "YES");
  1159.  
  1160.     [IconView getShortName:shortName from:theAppName];
  1161.     if (!strcmp(shortName, "Fiend"))
  1162.         return self;
  1163.  
  1164.     appWin = nil;
  1165.     [self stopScanTimer];
  1166.     thread_switch(THREAD_NULL, SWITCH_OPTION_WAIT, 100);
  1167.     [IconView resetProcessTable];
  1168.     for(i = 0, dock = dockListPtr; i < count; i++, dock++)    {
  1169.         if ((dockIndx = [*dock indexOfPath:(char *)theAppName exact:YES]) != -1)    {
  1170.             appWin = [*dock findWindowForName:theAppName];
  1171.             if (appWin != *dock)       {
  1172.                 appIconView = [appWin contentView];
  1173.                 [appIconView getAppPid];
  1174.                 [[appIconView setLaunched:[appIconView isLaunched]] display];
  1175.                 appIcon = [IconView getIconForPid:[appIconView appPid]];
  1176.             }
  1177.             else
  1178.                 [IconView getCtxt:&ctxt pid:&pid andIcon:&appIcon forPath:(char *)theAppName];
  1179.  
  1180.             [[*dock appIconStore] replaceElementAt:dockIndx with:(void *)&appIcon];
  1181.             if (appIcon != -1 && hideIcons && !onNeXTDock(theAppName, (int)screenSize.height))
  1182.                 PSWMove(-1000.0, -1000.0, appIcon);
  1183.  
  1184.             break;
  1185.         }        
  1186.     }
  1187.     [self startScanTimer];
  1188.     return self;
  1189. }
  1190.  
  1191. - restoreIcons
  1192. {
  1193. //    if ([stickyDock isShowing])
  1194.         [stickyDock restoreIcons];
  1195. //    if (showDock)
  1196.         [currentDock restoreIcons];
  1197.     return self;
  1198. }
  1199.  
  1200. - scanIcons
  1201. {
  1202.     if (scanTimer != (DPSTimedEntry)(-1))    {
  1203.         if ([stickyDock isShowing])
  1204.             [stickyDock scanIcons];
  1205.         if (showDock)
  1206.             [currentDock scanIcons];
  1207.     }
  1208.     return self;
  1209. }
  1210.  
  1211. - (NXDragOperation)draggingEntered:(id <NXDraggingInfo>)sender
  1212. {
  1213.     int            len;
  1214.     char        *path;
  1215.     char        *dragString;
  1216.     NXAtom        testAtom;
  1217.     int            level = 0;
  1218.     BOOL        oldItemOnDock = -10;
  1219.     BOOL        oldAcceptDrag = -10;
  1220.     BOOL        localSrc = [sender isDraggingSourceLocal];
  1221.     BOOL        strict = !strcmp(NXGetDefaultValue([NXApp appName], DSTRICT_COPY), "YES");
  1222. /*    BOOL        promiscuous = !strcmp(NXGetDefaultValue([NXApp appName], "DockPromiscuous"), "YES");*/
  1223.     Pasteboard    *pb = [Pasteboard newName:NXDragPboard];
  1224.     NXDragOperation    mask = [sender draggingSourceOperationMask];
  1225.  
  1226.     [pb types];
  1227.     [pb readType:NXFilenamePboardType data:&dragString length:&len];
  1228.  
  1229.     acceptDrag = itemOnDock = NO;
  1230.     path = strtok(dragString, "\t");
  1231.     while(path && strlen(path))    {
  1232.         testAtom = NXUniqueString(path);
  1233.         /* if item is on this dock, we accept/nuke if it came from this dock also; */
  1234.         /* if it did not come from the dock, we just refuse it */
  1235.         if ((level = [self findLevelContaining:testAtom switch:NO]) >= 0)    {
  1236.             itemOnDock = YES;
  1237.             if (localSrc)
  1238.                 acceptDrag = NO;
  1239.         }
  1240.         else
  1241.             acceptDrag = YES;
  1242.  
  1243.         if ((oldAcceptDrag != -10 && oldAcceptDrag != acceptDrag) ||
  1244.             (oldItemOnDock != -10 && oldItemOnDock != itemOnDock))    {
  1245.             NXBeep();
  1246.             acceptDrag = NO;
  1247.             [pb deallocatePasteboardData:dragString length:len];
  1248.             NXLogError("Drag rejected: some dragged files are already on level %d of the Fiend Dock", level);
  1249.             return NX_DragOperationNone;
  1250.         }
  1251.         oldAcceptDrag = acceptDrag;
  1252.         oldItemOnDock = itemOnDock;
  1253.         path = strtok(NULL, "\t");
  1254.     }
  1255.  
  1256.     [pb deallocatePasteboardData:dragString length:len];
  1257.  
  1258.     if (acceptDrag)    {
  1259.         if (itemOnDock)
  1260.             return NX_DragOperationGeneric;
  1261.         else if (localSrc)
  1262.             return NX_DragOperationGeneric;
  1263.         else if (strict && mask == NX_DragOperationCopy)
  1264.             return NX_DragOperationCopy;
  1265.         else if (!strict && (mask & NX_DragOperationCopy))
  1266.             return NX_DragOperationCopy;
  1267.         else
  1268.             return NX_DragOperationNone;
  1269.     }
  1270.     else    {
  1271.         NXBeep();
  1272.         NXLogError("Drag rejected: some dragged files are already on level %d of the Fiend Dock", level);
  1273.     }
  1274.  
  1275.     return NX_DragOperationNone;
  1276. }
  1277.  
  1278. - concludeDragOperation:(id <NXDraggingInfo>)sender
  1279. {
  1280.     id        win;
  1281.     int        len;
  1282.     int        index;
  1283.     char    *path;
  1284.     char    *dragString;
  1285.     NXAtom    pathAtom;
  1286.     NXRect    winFrame;
  1287.     BOOL    added = NO;
  1288.     id        dockWinList = [currentDock dockWindowList];
  1289.     BOOL    useSound = !strcmp(NXGetDefaultValue([NXApp appName], USE_SOUND), "YES");
  1290.     BOOL    hideIcons = !strcmp(NXGetDefaultValue([NXApp appName], HIDE_ICONS), "YES");
  1291.     Pasteboard    *pb = [Pasteboard newName:NXDragPboard];
  1292.  
  1293.     [pb types];
  1294.     [IconView resetProcessTable];
  1295.     [window getFrame:&winFrame];
  1296.     [currentDock setFrame:&winFrame];
  1297.     [pb readType:NXFilenamePboardType data:&dragString length:&len];
  1298.     path = strtok(dragString, "\t");
  1299.     while(path && strlen(path))    {
  1300.         pathAtom = NXUniqueString(path);
  1301.         if (acceptDrag)    {
  1302.             if (!itemOnDock)    {
  1303.                 if (!showDock)
  1304.                     [self setShowDock:YES];
  1305.                 [currentDock getNextFrame:&winFrame];
  1306.                 win = [currentDock addWindowForPath:pathAtom at:&winFrame];
  1307.                 if (hideIcons)
  1308.                     [[win contentView] vanishIcon];
  1309.                 added = YES;
  1310.             }
  1311.             else    {
  1312.                 win = [[sender draggingSource] window];
  1313.                 index = [dockWinList indexOf:win];
  1314.                 if (index == NX_NOT_IN_LIST)    {
  1315.                     [currentDock getNextFrame:&winFrame];
  1316.                     win = [currentDock addWindowForPath:pathAtom at:&winFrame];
  1317.                     if (hideIcons)
  1318.                          [[win contentView] vanishIcon];
  1319.                     added = YES;
  1320.                 }
  1321.                 else    {
  1322.                     NXLogError("WHOA!! We shouldn't be here...");
  1323.                     abort();
  1324.                 }
  1325.             }
  1326.         }
  1327.         path = strtok(NULL, "\t");
  1328.     }        
  1329.  
  1330.     if (added && useSound)    {
  1331.         [[NXApp delegate] updateMenus];
  1332.         [fiendSound play];
  1333.     }
  1334.  
  1335.     [pb deallocatePasteboardData:dragString length:len];
  1336.     [self perform:@selector(writeDocks) with:nil afterDelay:100.0 cancelPrevious:YES];
  1337.  
  1338.     return self;
  1339. }
  1340.  
  1341. - getRaiseFrame:(NXRect *)raiseFrame levelFrame:(NXRect *)levelFrame from:(NXRect *)refFrame
  1342. {
  1343.     float    width = NX_WIDTH(refFrame);
  1344.     float    height = NX_HEIGHT(refFrame);
  1345.     float    levelX = atof(NXGetDefaultValue([NXApp appName], "LBX"));
  1346.     float    levelY = atof(NXGetDefaultValue([NXApp appName], "LBY"));
  1347.     float    levelWidth = atof(NXGetDefaultValue([NXApp appName], "LBW"));
  1348.     float    levelHeight = atof(NXGetDefaultValue([NXApp appName], "LBH"));
  1349.     float    raiseX = atof(NXGetDefaultValue([NXApp appName], "RBX"));
  1350.     float    raiseY = atof(NXGetDefaultValue([NXApp appName], "RBY"));
  1351.     float    raiseWidth = atof(NXGetDefaultValue([NXApp appName], "RBW"));
  1352.     float    raiseHeight = atof(NXGetDefaultValue([NXApp appName], "RBH"));
  1353.  
  1354.     NXUpdateDefaults();
  1355.  
  1356.     NXSetRect(levelFrame,
  1357.               width*levelX/64.0, height*levelY/64.0,
  1358.               levelWidth*width/64.0, levelHeight*height/64.0);
  1359.     NXIntegralRect(levelFrame);
  1360.  
  1361.     NXSetRect(raiseFrame,
  1362.               raiseX*width/64.0, raiseY*height/64.0,
  1363.               raiseWidth*width/64.0, raiseHeight*height/64.0);
  1364.     NXIntegralRect(raiseFrame);
  1365.  
  1366.     return self;
  1367. }
  1368.  
  1369. - sizeTo:(NXCoord)width :(NXCoord)height
  1370. {
  1371.     NXRect    raiseFrame;
  1372.     NXRect    levelFrame;
  1373.     NXRect    newFrame = frame;
  1374.  
  1375.     if (!raiseButton)
  1376.         return self;
  1377.  
  1378.     [super sizeTo:width :height];
  1379.  
  1380.     NX_WIDTH(&newFrame) = width;
  1381.     NX_HEIGHT(&newFrame) = height;
  1382.  
  1383.     [self getRaiseFrame:&levelFrame levelFrame:&raiseFrame from:&newFrame];
  1384.     [raiseButton setFrame:&raiseFrame];
  1385.     [prevLevelButton setFrame:&levelFrame];
  1386.  
  1387.     NX_Y(&levelFrame) = -1.0 + NX_MAXY(&raiseFrame) + (NX_Y(&raiseFrame)-NX_MAXY(&levelFrame));
  1388.     NXIntegralRect(&levelFrame);
  1389.     [nextLevelButton setFrame:&levelFrame];
  1390.  
  1391.     [self setupImages:&newFrame];
  1392.     [[raiseButton setImage:rbImage] setAltImage:rbAltImage];
  1393.     [[nextLevelButton setImage:nbImage] setAltImage:nbAltImage];
  1394.     [[prevLevelButton setImage:pbImage] setAltImage:pbAltImage];
  1395.  
  1396.     return self;
  1397. }
  1398.  
  1399. - setIconSize:(int)aValue
  1400. {
  1401.     id            *dock;
  1402.     int            i;
  1403.     int            count = [dockList count];
  1404.     NXPoint        offscreenPt = {-1000.0, -1000.0};
  1405.     NXRect        winFrame = {{-1000.0, -1000.0}, {aValue, aValue}};
  1406.     id            *dockListPtr = (count > 0) ? NX_ADDRESS(dockList) : (id *)NULL;
  1407.  
  1408.     if ((int)NX_WIDTH(&frame) == aValue)
  1409.         return self;
  1410.  
  1411.     [currentDock updateWindows:&offscreenPt usePlace:NO followLevels:NO];
  1412.     [stickyDock updateWindows:&offscreenPt usePlace:NO followLevels:NO];
  1413.  
  1414.     [[stickyDock empty] setFrame:&winFrame];
  1415.     [self setDockNameCellFont:&winFrame];
  1416.  
  1417.     [IconView resetCachedDockImages];
  1418.     [IconView setCachedDockImageSize:&winFrame.size];
  1419.     [window disableFlushWindow];
  1420.     [[window sizeWindow:aValue :aValue] display];
  1421.     [[window reenableFlushWindow] flushWindowIfNeeded];
  1422.     for(i = 0, dock = dockListPtr; i < count; i++, dock++)    {
  1423.         [*dock setFrame:&frame];
  1424.         [*dock createWindowsFromStores:[*dock isLoaded] stickyWindows:YES];
  1425.     }
  1426.     windowsNeedUpdate = YES;
  1427.  
  1428.     return self;
  1429. }
  1430.  
  1431. - modalDone:sender
  1432. {
  1433.     inspectorButtonTag = [[sender selectedCell] tag];
  1434.     [[sender window] orderOut:self];
  1435.     [NXApp stopModal];
  1436.     return self;
  1437. }
  1438.  
  1439. - (int)iconSize
  1440. {
  1441.     return (int)NX_WIDTH(&frame);
  1442. }
  1443.  
  1444. - getSlotOriginForPoint:(NXPoint *)aPoint
  1445. {
  1446.     NXCoord        x;
  1447.     NXCoord        y;
  1448.     NXCoord        newX;
  1449.     NXCoord        newY;
  1450.     NXPoint        testPoint;
  1451.     float        width = NX_WIDTH(&frame);
  1452.     float        height = NX_HEIGHT(&frame);
  1453.     NXPoint        org = {0.0, 0.0};
  1454.  
  1455.     [window convertBaseToScreen:&org];
  1456.  
  1457.     testPoint.x = aPoint->x + width/2.0;
  1458.     testPoint.y = aPoint->y + height/2.0;
  1459.     x = testPoint.x - ((org.x > testPoint.x) ? org.x + width : org.x);
  1460.     y = testPoint.y - ((org.y > testPoint.y) ? org.y + height : org.y);
  1461.  
  1462.     newX = width * abs((int)(x/width));
  1463.     newX *= (x > 0.0) ? 1.0 : -1.0;
  1464.  
  1465.     newY = height * abs((int)(y/height));
  1466.     newY *= (y > 0.0) ? 1.0 : -1.0;
  1467.  
  1468.     aPoint->x = org.x + newX;
  1469.     aPoint->y = org.y + newY;
  1470.  
  1471.     return self;
  1472. }
  1473.  
  1474. static BOOL hilightingDone;
  1475.  
  1476. - hilightNewSlot
  1477. {
  1478.     id            underView;
  1479.     BOOL        preDelete;
  1480.     NXPoint        mousePoint;
  1481.     NXRect        mouseRect = frame;
  1482.     NXPoint        screenPoint = {0.0, 0.0};
  1483.     static id        theView;
  1484.     static NXRect    savedRect;
  1485.     static NXPoint    oldPoint;
  1486.  
  1487.     hilightingDone = NO;
  1488.     if (dragView == nil)    {
  1489.         theView = nil;
  1490.         oldPoint = screenPoint;
  1491.         hilightingDone = YES;
  1492.         return self;
  1493.     }
  1494.     else if (theView != dragView)    {
  1495.         theView = dragView;
  1496.         [theView getFrame:&savedRect];
  1497.         [[theView window] convertBaseToScreen:&savedRect.origin];
  1498.     }
  1499.  
  1500.     [window getMouseLocation:&mousePoint];
  1501.     [window convertBaseToScreen:&screenPoint];
  1502.     [window convertBaseToScreen:&mousePoint];
  1503.  
  1504.     mousePoint.x -= mouseOffset.x;
  1505.     mousePoint.y -= mouseOffset.y;
  1506.     [self getSlotOriginForPoint:&mousePoint];
  1507.     if ((mousePoint.x == oldPoint.x && mousePoint.y == oldPoint.y))    {
  1508.         hilightingDone = YES;
  1509.         return self;
  1510.     }
  1511.     oldPoint = mousePoint;
  1512.  
  1513.     mouseRect.origin = mousePoint;
  1514.     preDelete = [dragView preDelete];
  1515.     underView = [currentDock viewAtPosition:&mouseRect besides:dragView];
  1516.     if (underView == nil &&
  1517.         ![stickyDock viewAtPosition:&mouseRect besides:dragView] &&
  1518.         !(mousePoint.x == screenPoint.x && mousePoint.y == screenPoint.y))    {
  1519.         if (preDelete)    {
  1520. //            [[dragView window] disableFlushWindow];
  1521.             [[dragView setPreDelete:NO] display];
  1522. //            [[[dragView window] reenableFlushWindow] flushWindowIfNeeded];
  1523.         }
  1524.         [[dragView window] moveTo:mousePoint.x :mousePoint.y];
  1525.     }
  1526.     else    {
  1527.         [[dragView window] moveTo:NX_X(&savedRect) :NX_Y(&savedRect)];
  1528.         if (mousePoint.x == screenPoint.x && mousePoint.y == screenPoint.y)    {
  1529.             if (![dragView isSticky] && !preDelete)    {
  1530. //                [[dragView window] disableFlushWindow];
  1531.                 [[dragView setPreDelete:YES] display];
  1532. //                [[[dragView window] reenableFlushWindow] flushWindow];
  1533.             }
  1534.         }
  1535.         else if (preDelete)    {
  1536. //            [[dragView window] disableFlushWindow];
  1537.             [[dragView setPreDelete:NO] display];
  1538. //            [[[dragView window] reenableFlushWindow] flushWindowIfNeeded];
  1539.         }
  1540.     }
  1541.  
  1542. //    NXPing();
  1543.     hilightingDone = YES;
  1544.     return self;
  1545. }
  1546.  
  1547. - setKeepDraggedIcons:(BOOL)flag
  1548. {
  1549.     keepDraggedIcons = flag;
  1550.     return self;
  1551. }
  1552.  
  1553. - draggedImage:anImage endedAt:(NXPoint *)screenPoint deposited:(BOOL)didDeposit
  1554. {
  1555.     id            win;
  1556.     id            parentDock;
  1557.     int            index;
  1558.     int            level;
  1559.     NXRect        screenFrame;
  1560.     NXRect        iconFrame;
  1561.     NXSize        iconSize;
  1562.     NXPoint        *offset;
  1563.     NXPoint        testPoint;
  1564.  
  1565.     [self stopScanTimer];
  1566.     if (!dragView)    {
  1567.         if (didDeposit && !keepDraggedIcons)    {
  1568.             [currentDock deleteSelectedCells];
  1569.             [self startScanTimer];
  1570.         }
  1571.         return self;
  1572.     }
  1573.  
  1574.     [dragView freeGState];
  1575.     if (followTimer != (DPSTimedEntry)(-1))    {
  1576.         DPSRemoveTimedEntry(followTimer);
  1577.         followTimer = (DPSTimedEntry)(-1);
  1578.         DPSSetTracking(1);
  1579.     }
  1580.  
  1581.     [window getFrame:&screenFrame];
  1582.     [anImage getSize:&iconSize];
  1583.  
  1584.     testPoint.x = screenPoint->x + iconSize.width/2.0;
  1585.     testPoint.y = screenPoint->y + iconSize.height/2.0;
  1586.     if (![dragView isSticky] && NXPointInRect(&testPoint, &screenFrame))    {
  1587.         [self deleteView:dragView];
  1588.         dragView = nil;
  1589.     }
  1590.     else    {
  1591.         [self hilightNewSlot];
  1592.         win = [dragView window];
  1593.         [win getFrame:&iconFrame];
  1594.         [[dragView setPreDelete:NO] display];
  1595.         level = [self findLevelContaining:(char *)[(IconView *)dragView data] switch:NO];
  1596.         dragView = nil;
  1597.         [self hilightNewSlot];
  1598.         if (level != -1)    {
  1599.             parentDock = [dockList objectAt:level];
  1600.             if ((index = [[parentDock dockWindowList] indexOf:win]) != NX_NOT_IN_LIST)    {
  1601.                 offset = (NXPoint *)[[parentDock filePositionStore] elementAt:index];
  1602.                 offset->x = (NX_X(&iconFrame)-NX_X(&screenFrame))/NX_WIDTH(&iconFrame);
  1603.                 offset->y = (NX_Y(&iconFrame)-NX_Y(&screenFrame))/NX_HEIGHT(&iconFrame);
  1604.             }
  1605.         }
  1606.         if ((index = [[stickyDock dockWindowList] indexOf:win]) != NX_NOT_IN_LIST)    {
  1607.             offset = (NXPoint *)[[stickyDock filePositionStore] elementAt:index];
  1608.             offset->x = (NX_X(&iconFrame)-NX_X(&screenFrame))/NX_WIDTH(&iconFrame);
  1609.             offset->y = (NX_Y(&iconFrame)-NX_Y(&screenFrame))/NX_HEIGHT(&iconFrame);
  1610.         }
  1611.     }
  1612.  
  1613.     [self perform:@selector(writeDocks) with:nil afterDelay:100.0 cancelPrevious:YES];
  1614.     [[NXApp delegate] updateMenus];
  1615.     [self startScanTimer];
  1616.     return self;
  1617. }
  1618.  
  1619. - rotateOffsets
  1620. {
  1621.     if (!showDock)    {
  1622.         NXBeep();
  1623.         return self;
  1624.     }        
  1625.     [currentDock rotateOffsets];
  1626.     return self;
  1627. }
  1628.  
  1629. - handleMouseMoved:(NXEvent *)event
  1630. {
  1631.     int            i;
  1632.     int            *wins;
  1633.     int            delay;
  1634.     int            winCount;
  1635.     int            theWinNum;
  1636.     long         lastTime;
  1637.     NXRect        theRect;
  1638.     NXPoint        p;
  1639.     NXEvent        *newEvent;
  1640.     NXPoint        offsetPt = {0.0, 0.0};
  1641.     NXPoint        origPt = event->location;
  1642.     int            mask = NX_LMOUSEDRAGGEDMASK|NX_LMOUSEUPMASK;
  1643.     struct winRec    *winRecs;
  1644.  
  1645.     [window convertBaseToScreen:&offsetPt];
  1646.  
  1647.     winCount = 0;
  1648.     wins = (int *)NULL;
  1649.     winRecs = (struct winRec *)NXZoneMalloc([self zone], 0);
  1650.  
  1651.     if (showDock)
  1652.         winCount = [currentDock addToWinRecArray:&winRecs presentCount:&winCount];
  1653.     if ([stickyDock isShowing])
  1654.         winCount = [stickyDock addToWinRecArray:&winRecs presentCount:&winCount];
  1655.  
  1656.     if (winCount > 0)    {
  1657.         wins = (int *)NXZoneMalloc([self zone], sizeof(int) * winCount);
  1658.         qsort((void *)winRecs, winCount, sizeof(struct winRec), compareWins);
  1659.         for(i = 0; i < winCount; i++) wins[i] = winRecs[i].winNum;
  1660.     }
  1661.     NXConvertWinNumToGlobal([window windowNum], &theWinNum);
  1662.  
  1663.     p = offsetPt;
  1664.     newEvent = event;
  1665.     delay = (int)rint((float)winCount/1.5);
  1666.     if (delay > 6) delay = 6;
  1667.     origPt = newEvent->location;
  1668.     while (newEvent && newEvent->type != NX_MOUSEUP)    {
  1669.         lastTime = newEvent->time;
  1670.         [window getMouseLocation:&p];
  1671.         p.x -= origPt.x; p.y -= origPt.y;
  1672.         PSWMoveWindowsInTandem(p.x, p.y, theWinNum, winCount, wins);
  1673.         NXPing();
  1674.         do    {
  1675.             newEvent = [NXApp getNextEvent:mask];
  1676.             p.x = newEvent->location.x - origPt.x;
  1677.             p.y = newEvent->location.y - origPt.y;
  1678.         } while((newEvent->time - lastTime < delay) && (fabs(p.x) > 1.0 && fabs(p.y) > 1.0)
  1679.                 && (newEvent->type != NX_MOUSEUP));
  1680.     }
  1681.  
  1682.     PScurrentwindowbounds([window windowNum], &theRect.origin.x, &theRect.origin.y,
  1683.                           &theRect.size.width, &theRect.size.height);
  1684.     [window moveTo:NX_X(&theRect) :NX_Y(&theRect)];
  1685. //    [window saveFrameUsingName:"DockWindow"];
  1686.     [currentDock setFrame:&theRect];
  1687.  
  1688.     if (showDock)
  1689.         [currentDock updateWindows:&theRect.origin usePlace:NO followLevels:NO];
  1690.     if ([stickyDock isShowing])    {
  1691.         [stickyDock setFrame:&theRect];
  1692.         [stickyDock updateWindows:&theRect.origin usePlace:NO followLevels:NO];
  1693.     }
  1694.  
  1695.     if (winCount)
  1696.         NXZoneFree([self zone], wins);
  1697.     NXZoneFree([self zone], winRecs);
  1698.  
  1699.     return self;
  1700. }
  1701.  
  1702. - textDidEnd:sender endChar:(unsigned short)whyEnd
  1703. {
  1704.     char        buffer[DOCKNAMELEN+1];
  1705.  
  1706.     if (editing)    {
  1707.         editing = NO;
  1708.         [self startScanTimer];
  1709.         [sender getSubstring:buffer start:0 length:DOCKNAMELEN];
  1710.         [dockNameCell endEditing:sender];
  1711.         [dockNameCell setBackgroundTransparent:YES];
  1712.         [[self nameLevel:buffer] display];
  1713.     }
  1714.     return self;
  1715. }
  1716.  
  1717. - (BOOL)textWillChange:sender
  1718. {
  1719.     return !editing;
  1720. }
  1721.  
  1722. - doNamePopup:(NXRect *)cellRect
  1723. {
  1724.     int        i;
  1725.     char    *namePtr;
  1726.     char    string[30];
  1727.     int        count = [dockList count];
  1728.     id        popupList = [[PopUpList allocFromZone:[self zone]] init];
  1729.     NXRect    aRect = {{1.0, NX_Y(cellRect)}, {NX_WIDTH(&frame)*1.3, 1.0+NX_HEIGHT(cellRect)}};
  1730.     id        popupButton = [[Button allocFromZone:[self zone]] initFrame:&aRect
  1731.                          title:"" tag:0 target:nil action:(SEL)NULL key:'\0' enabled:YES];
  1732.  
  1733.     [[[popupList itemList] renewRows:count cols:1] sizeToCells];
  1734.     for(i = 0; i < count; i++)    {
  1735.         namePtr = (char *)[[dockList objectAt:i] name];
  1736.         if (!strlen(namePtr))    {
  1737.             sprintf(string, "%d-%d", i+1, count);
  1738.             string[DOCKNAMELEN+1] = '\0';
  1739.             namePtr = string;
  1740.         }                    
  1741.         [[[[popupList itemList] cellAt:i :0] setTitle:namePtr] setTag:i];
  1742.     }
  1743.  
  1744.     [self addSubview:popupButton];
  1745.     NXAttachPopUpList(popupButton, popupList);
  1746.     [popupList setFont:[dockNameCell font]];
  1747.  
  1748.     if (strlen(namePtr = (char *)[[dockList objectAt:currentDockIndex] name]))
  1749.         [popupButton setTitle:namePtr];
  1750.     else    {
  1751.         sprintf(string, "%d-%d", currentDockIndex+1, count);
  1752.         string[DOCKNAMELEN+1] = '\0';
  1753.         [popupButton setTitle:string];
  1754.     }
  1755.     [popupList popUp:popupButton];
  1756.  
  1757.     [popupButton removeFromSuperview];
  1758.     [self display]; NXPing();
  1759.     [self gotoDockLevel:[[[popupList itemList] selectedCell] tag]];
  1760.     [popupList free];
  1761.     [popupButton free];
  1762.  
  1763.     return self;
  1764. }
  1765.  
  1766. - doEdit:(NXRect *)cellRect
  1767. {
  1768.     editing = YES;
  1769.     [window endEditingFor:nil];
  1770.     [dockNameCell setBackgroundTransparent:NO];
  1771.     [self display]; NXPing();
  1772.     [dockNameCell select:cellRect inView:self editor:fieldEditor
  1773.      delegate:self start:0 length:strlen([currentDock name])];
  1774.     return self;
  1775. }
  1776.  
  1777. - (BOOL)dockLocked
  1778. {
  1779.     return dockLocked;
  1780. }
  1781.  
  1782. - setDockLocked:(BOOL)flag
  1783. {
  1784.     dockLocked = flag;
  1785.     [self display];
  1786.     return self;
  1787. }
  1788.  
  1789. - mouseDown:(NXEvent *)event
  1790. {
  1791.     int            selCnt;
  1792.     int            savedMask;
  1793.     BOOL        alt;
  1794.     BOOL        ctrl;
  1795.     BOOL        shift;
  1796.     BOOL        command;
  1797.     NXRect        cellRect;
  1798.     NXEvent        eventCopy = *event;
  1799.     NXPoint        origPt = event->location;
  1800.     int            mask = NX_LMOUSEDRAGGEDMASK|NX_LMOUSEUPMASK;
  1801.  
  1802.     [self stopScanTimer];
  1803.  
  1804.     alt = (event->flags & NX_ALTERNATEMASK) ? YES : NO;
  1805.     ctrl = (event->flags & NX_CONTROLMASK) ? YES : NO;
  1806.     shift = (event->flags & NX_SHIFTMASK) ? YES : NO;
  1807.     command = (event->flags & NX_COMMANDMASK) ? YES : NO;
  1808.  
  1809.     [dockNameCell calcCellSize:&cellRect.size];
  1810.     NX_X(&cellRect) = 2.0;
  1811.     NX_Y(&cellRect) = NX_HEIGHT(&frame) - NX_HEIGHT(&cellRect) - 1.0;
  1812.     NX_WIDTH(&cellRect) = NX_WIDTH(&frame) - 4.0;
  1813.  
  1814.     if (!editing && NXMouseInRect(&event->location, &cellRect, NO))    {
  1815.         if (shift || ![NXApp isActive])
  1816.             [self doNamePopup:&cellRect];
  1817.         else if ([NXApp isActive])
  1818.             [self doEdit:&cellRect];
  1819.  
  1820.         [self startScanTimer];
  1821.         return [nextResponder mouseDown:event];
  1822.     }
  1823.  
  1824.     NXSetRect(&cellRect,
  1825.               24.0*NX_WIDTH(&frame)/64.0, 36.0*NX_HEIGHT(&frame)/64.0,
  1826.               NX_WIDTH(&frame)/32.0, NX_HEIGHT(&frame)/32.0);
  1827.     savedMask = [window addToEventMask:mask];
  1828.  
  1829.     event = [NXApp getNextEvent:NX_MOUSEUPMASK|NX_MOUSEDRAGGEDMASK];
  1830.     switch(event->type)    {
  1831.     case NX_MOUSEUP:
  1832.         if (showDock && NX_WIDTH(&frame) >= 64.0)    {
  1833.             if (NXMouseInRect(&event->location, &cellRect, NO))    {
  1834.                 [self twist];
  1835.                 return self;
  1836.             }
  1837.             NX_X(&cellRect) += 11.0*NX_WIDTH(&frame)/64.0;
  1838.             if (NXMouseInRect(&event->location, &cellRect, NO))    {
  1839.                 [self fade];
  1840.                 return self;
  1841.             }
  1842.         }
  1843.         
  1844.         if (!ctrl && !command && ((!shift && !alt) || (alt && shift && !showDock)))
  1845.             [self setShowDock:!showDock];
  1846.         else if (showDock && ctrl)
  1847.             [currentDock rotateOffsets];
  1848.         else if (showDock && command)
  1849.             (shift) ? [self previousLevel] : [self nextLevel];
  1850.         else if (showDock && shift && alt)
  1851.             [self setShowDock:NO leaveStickyIcons:YES];
  1852.         else if (shift)
  1853.             [self setDockLocked:!dockLocked];
  1854.         else if (alt)
  1855.             [self sinkDock:!dockSunken];
  1856.         else if (command || ctrl)
  1857.             NXBeep();
  1858.  
  1859.         if (editing)
  1860.             [window endEditingFor:nil];
  1861.  
  1862.         break;
  1863.  
  1864.     case NX_MOUSEDRAGGED:
  1865.         if (!shift && (selCnt = [(Dock *)currentDock hasSelectedCells]) != 0)    {
  1866.             NXImage     *dragImage;
  1867.             Pasteboard    *pb = [Pasteboard newName:NXDragPboard];
  1868.  
  1869.             if (selCnt == 1)
  1870.                 dragImage = [IconView getImageForPath:[currentDock selectedCellPath]
  1871.                                       fileIcon:YES zone:[self zone]];
  1872.             else
  1873.                 dragImage = [[NXImage allocFromZone:[self zone]] initFromSection:"Sheaf"];
  1874.  
  1875.             dragView = nil;
  1876.             keepDraggedIcons = (alt) ? YES : NO;
  1877.             [self copy:self toPasteboard:pb andCut:NO];
  1878.             [self dragImage:dragImage at:&frame.origin offset:&frame.origin event:&eventCopy
  1879.                   pasteboard:pb source:self slideBack:YES];
  1880.  
  1881.             [currentDock select:NO all:self];
  1882.             [dragImage free];
  1883.         }
  1884.         else if (!dockLocked || shift)    {
  1885.             eventCopy = *event;
  1886.             eventCopy.location = origPt;
  1887.             [self handleMouseMoved:&eventCopy];
  1888.         }
  1889.         else
  1890.             NXBeep();
  1891.         break;
  1892.     }
  1893.  
  1894.     [window setEventMask:savedMask];
  1895.     [self startScanTimer];
  1896.     [[NXApp delegate] updateMenus];
  1897.     return self;
  1898. }
  1899.         
  1900. - addWorkspace
  1901. {
  1902.     int            level;
  1903.     NXAtom        wkspcAtom = NXUniqueStringNoCopy(WKSPC_FILE);
  1904.  
  1905.     if ((level = [self findLevelContaining:wkspcAtom switch:NO]) == -1)
  1906.         [currentDock addWindowForPath:(NXAtom)wkspcAtom at:(NXRect *)NULL];
  1907.     else    {
  1908.         NXBeep();
  1909.         NXRunAlertPanel([NXApp appName],
  1910.                         "Fiend Dock already contains %s on level %d...",
  1911.                         NULL, NULL, NULL, wkspcAtom, level+1);
  1912.     }
  1913.     [[NXApp delegate] updateMenus];
  1914.     return self;
  1915. }
  1916.  
  1917. - addRecycler
  1918. {
  1919.     int            level;
  1920.     char        recyclerString[MAXPATHLEN+1];
  1921.     NXAtom        recyclerAtom;
  1922.  
  1923.     sprintf(recyclerString, "%s/%s", NXHomeDirectory(), RECYC_FILE);
  1924.     recyclerAtom = NXUniqueString(recyclerString);
  1925.  
  1926.     if ((level = [self findLevelContaining:recyclerAtom switch:NO]) == -1)
  1927.         [currentDock addWindowForPath:(NXAtom)recyclerAtom at:(NXRect *)NULL];
  1928.     else    {
  1929.         NXBeep();
  1930.         NXRunAlertPanel([NXApp appName],
  1931.                         "Fiend Dock already contains Recycler on level %d...",
  1932.                         NULL, NULL, NULL, level+1);
  1933.     }
  1934.     [[NXApp delegate] updateMenus];
  1935.     return self;
  1936. }
  1937.  
  1938. - currentDock
  1939. {
  1940.     return currentDock;
  1941. }
  1942.  
  1943. - windowDidResignKey:sender
  1944. {
  1945.     if (editing)
  1946.         [window endEditingFor:nil];
  1947.  
  1948.     return self;
  1949. }
  1950.  
  1951. - setShowDock:(BOOL)flag
  1952. {
  1953.     return [self setShowDock:flag leaveStickyIcons:NO];
  1954. }
  1955.  
  1956. - setFollowLevels:(BOOL)flag
  1957. {
  1958.     followLevels = flag;
  1959.     return self;
  1960. }
  1961.  
  1962. - setShowDock:(BOOL)flag leaveStickyIcons:(BOOL)leaveFlag
  1963. {
  1964.     NXPoint    thePoint = {-1000.0, -1000.0};
  1965.  
  1966.     showDock = flag;
  1967.     if (showDock)    {
  1968.         thePoint = frame.origin;
  1969.         [window convertBaseToScreen:&thePoint];
  1970.         [self startScanTimer];
  1971.         [self display];
  1972.         [currentDock updateWindows:&thePoint usePlace:NO followLevels:NO];
  1973.         [stickyDock updateWindows:&thePoint usePlace:NO followLevels:NO];
  1974.     }
  1975.     else    {
  1976.         [currentDock updateWindows:&thePoint usePlace:NO followLevels:NO];
  1977.         if (!leaveFlag)    {
  1978.             [self stopScanTimer];
  1979.             [stickyDock updateWindows:&thePoint usePlace:NO followLevels:NO];
  1980.         }
  1981.         [self display];
  1982.     }
  1983.  
  1984.     return self;
  1985. }
  1986.  
  1987. - (BOOL)showDock
  1988. {
  1989.     return showDock;
  1990. }
  1991.  
  1992. - (FILE *)findDockFile:(char *)path
  1993. {
  1994.     int            i;
  1995.     int            count;
  1996.     FILE        *f;
  1997.     NXScreen    *screens;
  1998.     NXRect        screenRect = {{0.0, 0.0}, {0.0, 0.0}};
  1999.  
  2000.     [NXApp getScreens:&screens count:&count];
  2001.     for(i = 0; i < count; i++)
  2002.         NXUnionRect(&screens[i].screenBounds, &screenRect);
  2003.  
  2004.     sprintf(path, "%s/.AppInfo/Fiend/%s.%.0f.%.0f",    NXHomeDirectory(),
  2005.             FIENDDOCK_FILE, NX_WIDTH(&screenRect), NX_HEIGHT(&screenRect));
  2006.     if ((f = fopen(path, "r")) == (FILE *)NULL)    {
  2007.         NXLogError("Couldn't find %s, trying %s~", path, path);
  2008.         strcat(path, "~");
  2009.         if ((f = fopen(path, "r")) == (FILE *)NULL)    {
  2010.             sprintf(path, "%s/.AppInfo/Fiend/%s", NXHomeDirectory(), FIENDDOCK_FILE);
  2011.             NXLogError("...trying %s", path);
  2012.             if ((f = fopen(path, "r")) == (FILE *)NULL)    {
  2013.                 sprintf(path, "%s/.FiendDock", NXHomeDirectory());
  2014.                 NXLogError("...trying %s", path);
  2015.                 if ((f = fopen(path, "r")) == (FILE *)NULL)
  2016.                     return f;
  2017.             }
  2018.         }
  2019.     }
  2020.     return f;
  2021. }
  2022.  
  2023. - buildEmptyDock
  2024. {
  2025.     currentDock = [[Dock allocFromZone:NXCreateZone(vm_page_size/4, vm_page_size/4, YES)]
  2026.                            initMgrView:self];
  2027.     [currentDock setIsLoaded:YES];
  2028.     currentDockIndex = 0;
  2029.     [currentDock setFiendSound:fiendSound destroySound:destroySound];
  2030.     [dockList addObject:currentDock];
  2031.     return self;
  2032. }
  2033.  
  2034. - loadDock:(int)dockIndex of:(int)count from:(FILE *)f version:(int)version showProgress:(BOOL)showProgress
  2035. {
  2036.     id            dock;
  2037.     id            filePosStore;
  2038.     id            fileNameStore;
  2039.     id            appIconStore;
  2040.     id            launchFlagStore;
  2041.     int            j;
  2042.     int            iconCount;
  2043.     int            scanCount;
  2044.     int            autoLaunch;
  2045.     char        name[200];
  2046.     char        path[200];
  2047.     char        string[1000];
  2048.     char        workString[100];
  2049.     NXAtom        pathAtom;
  2050.     NXPoint        offset;
  2051.     int            dummy = -1;
  2052.  
  2053.     dock = [[Dock allocFromZone:NXCreateZone(vm_page_size/4, vm_page_size/4, YES)]
  2054.                     initMgrView:self];
  2055.     [dock setFiendSound:fiendSound destroySound:destroySound];
  2056.     [dockList addObject:dock];
  2057.     filePosStore = [dock filePositionStore];
  2058.     fileNameStore = [dock fileNameStore];
  2059.     launchFlagStore = [dock launchFlagStore];
  2060.     appIconStore = [dock appIconStore];
  2061.     fgets(string, 999, f);
  2062.     if (version == 4)    {
  2063.         scanCount = sscanf(string, "%d %[^\n]", &iconCount, name);
  2064.         if (scanCount == 2)    {
  2065.             [(Dock *)dock setName:name];
  2066.             sprintf(workString, "Loading Dock '%s'...", name);
  2067.         }
  2068.         else
  2069.             sprintf(workString, "Loading level %d-%d...", dockIndex+1, count);
  2070.     }
  2071.     else    {
  2072.         sprintf(workString, "Loading level %d-%d...", dockIndex+1, count);
  2073.         sscanf(string, "%d", &iconCount);
  2074.     }
  2075.     if (showProgress)
  2076.         [[NXApp delegate] setProgressFieldString:workString];
  2077.  
  2078.     for(j = 0; j < iconCount; j++)    {
  2079.         fgets(string, 999, f);
  2080.         if (version == 2)    {
  2081.             autoLaunch = DOCK_NONE;
  2082.             sscanf(string, "%f %f %[^\n]", &offset.x, &offset.y, path);
  2083.         }
  2084.         else
  2085.             sscanf(string, "%d %f %f %[^\n]", &autoLaunch, &offset.x, &offset.y, path);
  2086.         pathAtom = NXUniqueString(path);
  2087.         [filePosStore addElement:(void *)&offset];
  2088.         [fileNameStore addElement:(void *)&pathAtom];
  2089.         [launchFlagStore addElement:(void *)&autoLaunch];
  2090.         [appIconStore addElement:(void *)&dummy];
  2091.         if (showProgress)
  2092.             [[NXApp delegate] setProgressViewRatio:
  2093.                               ((float)dockIndex + (float)j/(float)iconCount)/(float)count];
  2094.     }
  2095.  
  2096.     return dock;
  2097. }
  2098.  
  2099. - readDocks
  2100. {
  2101.     id            dock;
  2102.     int            i;
  2103.     int            count;
  2104.     int            version;
  2105.     int            scanCount;
  2106.     char        path[200];
  2107.     FILE        *f;
  2108.     NXPoint        screenPt = frame.origin;
  2109.     int            defDockIndex = atoi(NXGetDefaultValue([NXApp appName], CUR_DOCK))-1;
  2110.     BOOL        showProgress = !strcmp(NXGetDefaultValue([NXApp appName], SHOW_PROG), "YES");
  2111.     BOOL        disableLazyLoad = !strcmp(NXGetDefaultValue([NXApp appName], "DisableLazyLoad"), "YES");
  2112.     NXRect        winFrame = {{-1000.0, -1000.0}, {NX_WIDTH(&frame), NX_HEIGHT(&frame)}};
  2113.  
  2114.     [window convertBaseToScreen:&screenPt];
  2115.     [IconView resetProcessTable];
  2116.  
  2117.     if (showProgress)
  2118.         [[NXApp delegate] setProgressViewRatio:0.0];
  2119.  
  2120.     if ((f = [self findDockFile:path]) == (FILE *)NULL)    {
  2121.         NXLogError("No FiendDock file found!!");
  2122.         [self buildEmptyDock];
  2123.         [[NXApp delegate] setProgressViewRatio:1.0];
  2124.         return self;
  2125.     }
  2126.  
  2127.     currentDockIndex = -1;
  2128.     [stickyDock setFrame:&winFrame];
  2129.     scanCount = fscanf(f, "%d %d\n", &version, &count);
  2130.     if (scanCount != 2 && !strrchr(path, '~'))    {
  2131.         NXLogError("%s is empty - trying backup", path);
  2132.         fclose(f);
  2133.         strcat(path, "~");
  2134.         if (((f = fopen(path, "r")) == NULL) || fscanf(f, "%d %d\n", &version, &count) != 2)    {
  2135.             NXLogError("Backup is not found or empty - building empty dock");
  2136.             if (showProgress)
  2137.                 [[NXApp delegate] setProgressViewRatio:1.0];
  2138.             [self buildEmptyDock];
  2139.             return self;
  2140.         }
  2141.     }
  2142.     else if (scanCount != 2)    {
  2143.         NXLogError("%s is empty - building empty dock", path);
  2144.         if (showProgress)
  2145.             [[NXApp delegate] setProgressViewRatio:1.0];
  2146.         [self buildEmptyDock];
  2147.         return self;
  2148.     }
  2149.  
  2150.     for(i = 0; i < count; i++)    {
  2151.         dock = [self loadDock:i of:count from:f version:version showProgress:showProgress];
  2152.         if (showProgress)
  2153.             [[NXApp delegate] setProgressViewRatio:(float)(i+1)/(float)count];
  2154.         if ((int)i == defDockIndex)    {
  2155.             currentDock = dock;
  2156.             currentDockIndex = defDockIndex;
  2157.         }
  2158.     }
  2159.  
  2160.     if (currentDockIndex < 0)    {
  2161.         currentDock = [dockList objectAt:0];
  2162.         currentDockIndex = 0;
  2163.     }
  2164.  
  2165.     fclose(f);
  2166.  
  2167.     if (showProgress && disableLazyLoad)    {
  2168.         [[[NXApp delegate] setProgressFieldString:"Creating Dock Icons..."]
  2169.                            setProgressViewRatio:1.0/(float)count];
  2170.     }
  2171.     [currentDock createWindowsFromStores:YES stickyWindows:YES];
  2172.     for(i = 0; i < count; i++)   {
  2173.         dock = [dockList objectAt:i];
  2174.         if (dock != currentDock)
  2175.             [dock createWindowsFromStores:disableLazyLoad stickyWindows:YES];
  2176.         if (showProgress && disableLazyLoad)
  2177.             [[NXApp delegate] setProgressViewRatio:(float)(i+2)/(float)count];
  2178.     }
  2179.  
  2180.     for(i = 0; i < count; i++)
  2181.         [[[dockList objectAt:i] checkLaunchStatus] scanIcons];
  2182.  
  2183.     return self;
  2184. }
  2185.  
  2186. - performAutolaunches
  2187. {
  2188.     int            i;
  2189.     NXPoint        pt;
  2190.     int            count = [dockList count];
  2191.  
  2192.     [window getMouseLocation:&pt];
  2193.     for(i = 0; i < count; i++)
  2194.         [[dockList objectAt:i] performAutolaunches];
  2195.     return self;
  2196. }
  2197.  
  2198. - writeDocks
  2199. {
  2200.     id            dock;
  2201.     id            dockWinList;
  2202.     id            filePosStore;
  2203.     id            fileNameStore;
  2204.     id          launchFlagStore;
  2205.     int            i;
  2206.     int            j;
  2207.     int            count;
  2208.     int            statRet;
  2209.     int            iconCount;
  2210.     int            autoLaunchFlag;
  2211.     char        *path2;
  2212.     char        path[MAXPATHLEN+1];
  2213.     FILE        *f;
  2214.     NXPoint        *p;
  2215.     NXScreen    *screens;
  2216.     struct stat    theStat;
  2217.     NXRect        screenRect = {{0.0, 0.0}, {0.0, 0.0}};
  2218.  
  2219.     [NXApp getScreens:&screens count:&count];
  2220.     for(i = 0; i < count; i++)
  2221.         NXUnionRect(&screens[i].screenBounds, &screenRect);
  2222.  
  2223.     sprintf(path, "%s/.AppInfo/Fiend/%s.%.0f.%.0f",    NXHomeDirectory(),
  2224.             FIENDDOCK_FILE, NX_WIDTH(&screenRect), NX_HEIGHT(&screenRect));
  2225.  
  2226.     path2 = (char *)malloc(strlen(path)+2);
  2227.     sprintf(path2, "%s~", path);
  2228.     rename(path, path2);
  2229.  
  2230.     if ((f = fopen(path, "w")) == NULL)    {
  2231.         NXBeep();
  2232.         NXRunAlertPanel([NXApp appName],
  2233.                         "Could not open %s to save Fiend Dock!!",
  2234.                         NULL, NULL, NULL, path);
  2235.         rename(path2, path);
  2236.         free(path2);
  2237.         return nil;
  2238.     }
  2239.  
  2240.     count = [dockList count];
  2241.     if (fprintf(f, "%d %d\n", DOCKMGRVERSION, count) < 0)    {
  2242.         perror("Fiend 'writeDocks'");
  2243.         fclose(f);
  2244.         unlink(path);
  2245.         rename(path2, path);
  2246.         free(path2);
  2247.         return nil;
  2248.     }
  2249.     for(i = 0; i < count; i++)    {
  2250.         dock = [dockList objectAt:i];
  2251.         dockWinList = [dock dockWindowList];
  2252.         fileNameStore = [dock fileNameStore];
  2253.         filePosStore = [dock filePositionStore];
  2254.         launchFlagStore = [dock launchFlagStore];
  2255.         iconCount = [fileNameStore count];
  2256.         if (strlen([dock name]))    {
  2257.             if (fprintf(f, "%d %s\n", iconCount, [dock name]) < 0)    {
  2258.                 perror("Fiend 'writeDocks'");
  2259.                 fclose(f);
  2260.                 unlink(path);
  2261.                 rename(path2, path);
  2262.                 free(path2);
  2263.                 return nil;
  2264.             }
  2265.         }
  2266.         else    {
  2267.             if (fprintf(f, "%d\n", iconCount) < 0)    {
  2268.                 perror("Fiend 'writeDocks'");
  2269.                 fclose(f);
  2270.                 unlink(path);
  2271.                 rename(path2, path);
  2272.                 free(path2);
  2273.                 return nil;
  2274.             }
  2275.         }
  2276.         for(j = 0; j < iconCount; j++)    {
  2277.             p = (NXPoint *)[filePosStore elementAt:j];
  2278.             autoLaunchFlag = *(int *)[launchFlagStore elementAt:j];
  2279.             if (fprintf(f, "%d %6.0f%6.0f  %s\n", autoLaunchFlag, p->x, p->y,
  2280.                     *(char **)[fileNameStore elementAt:j]) < 0)    {
  2281.                 perror("Fiend 'writeDocks'");
  2282.                 fclose(f);
  2283.                 unlink(path);
  2284.                 rename(path2, path);
  2285.                 free(path2);
  2286.                 return nil;
  2287.             }
  2288.         }
  2289.     }
  2290.  
  2291.     fclose(f);
  2292.     sprintf(path2, "%s/.AppInfo/Fiend/FiendDock", NXHomeDirectory());
  2293.     statRet = stat(path2, &theStat);
  2294.     if (((statRet != -1) && (theStat.st_mode & S_IFLNK)) || statRet == -1)    {
  2295.         unlink(path2);
  2296.         symlink(path, path2);
  2297.     }
  2298.  
  2299.     free(path2);
  2300.     return self;
  2301. }
  2302.  
  2303. - sinkDock:(BOOL)flag
  2304. {
  2305.     id        *dock;
  2306.     int        i;
  2307.     int        count = [dockList count];
  2308.     int        lowerLevel = atoi(NXGetDefaultValue([NXApp appName], DCKLWR_LEVEL));
  2309.     int        upperLevel = atoi(NXGetDefaultValue([NXApp appName], DCKUPR_LEVEL));
  2310.     int        newLevel = (flag) ? lowerLevel : upperLevel;
  2311.     id        *dockListPtr = (count > 0) ? NX_ADDRESS(dockList) : (id *)NULL;
  2312.  
  2313.     dockSunken = flag;
  2314.     NXWriteDefault([NXApp appName], SINK_DOCK, (dockSunken)?"YES":"NO");
  2315.     PSsetwindowlevel(newLevel, [window windowNum]);
  2316.     for(i = 0, dock = dockListPtr; i < count; i++, dock++)
  2317.         [*dock setWindowTier:newLevel];
  2318.  
  2319.     return self;
  2320. }
  2321.  
  2322. - nameLevel:(char *)aName
  2323. {
  2324.     [(Dock *)currentDock setName:aName];
  2325.     [self setNameCell];
  2326.     return self;
  2327. }
  2328.  
  2329. - vanishDocks:(BOOL)flag
  2330. {
  2331.     int        i;
  2332.     int        count = [dockList count];
  2333.  
  2334.     for(i = 0; i < count; i++)
  2335.         [[dockList objectAt:i] vanishIcons:flag];
  2336.     return self;
  2337. }
  2338.  
  2339. - (NXDragOperation)draggingUpdated:(id <NXDraggingInfo>)sender
  2340. {
  2341.     BOOL            localSrc = [sender isDraggingSourceLocal];
  2342.     BOOL            strict = !strcmp(NXGetDefaultValue([NXApp appName], DSTRICT_COPY), "YES");
  2343.     NXDragOperation    mask = [sender draggingSourceOperationMask];
  2344.  
  2345.     if (acceptDrag)    {
  2346.         if (localSrc)
  2347.             return (mask == NX_DragOperationCopy) ? NX_DragOperationAll : NX_DragOperationGeneric;
  2348.         else if (strict &&  mask == NX_DragOperationCopy)
  2349.             return NX_DragOperationCopy;
  2350.         else if (!strict && (mask & NX_DragOperationCopy))
  2351.             return NX_DragOperationCopy;
  2352.         else
  2353.             return NX_DragOperationNone;
  2354.     }
  2355.     return NX_DragOperationNone;
  2356. }
  2357.  
  2358. - draggingExited:(id <NXDraggingInfo>)sender
  2359. {
  2360.     return self;
  2361. }
  2362.  
  2363. - (BOOL) prepareForDragOperation:sender
  2364. {
  2365.     return YES;
  2366. }
  2367.  
  2368. - (BOOL) performDragOperation:(id <NXDraggingInfo>)sender
  2369. {
  2370.     return acceptDrag;
  2371. }
  2372.  
  2373. - (BOOL)acceptsFirstMouse
  2374. {
  2375.     return YES;
  2376. }
  2377.  
  2378. - (BOOL)acceptsFirstResponder
  2379. {
  2380.     return editing;
  2381. }
  2382.  
  2383. - setNameCell
  2384. {
  2385.     char        string[30];
  2386.  
  2387.     if (!strlen([currentDock name]))    {
  2388.         sprintf(string, "%d-%d", currentDockIndex+1, [dockList count]);
  2389.         string[DOCKNAMELEN+1] = '\0';
  2390.         [dockNameCell setStringValue:string];
  2391.     }
  2392.     else
  2393.         [dockNameCell setStringValue:[currentDock name]];
  2394.  
  2395.     [dockNumberCell setIntValue:currentDockIndex+1];
  2396.  
  2397.     return self;
  2398. }
  2399.  
  2400. - stickyDock
  2401. {
  2402.     return stickyDock;
  2403. }
  2404.  
  2405. static void
  2406. followMouse(DPSTimedEntry timedEntry, double timeNow, void *data)
  2407. {
  2408.     if (hilightingDone)
  2409.         [(id)data hilightNewSlot];
  2410.     return;
  2411. }
  2412.  
  2413. - setDragView:theView andOffset:(NXPoint *)offset
  2414. {
  2415.     dragView = theView;
  2416.     if (theView != nil)    {
  2417. //        DPSSetTracking(0);
  2418.         mouseOffset = *offset;
  2419. //        [theView allocateGState];
  2420.         [self hilightNewSlot];
  2421.         if (followTimer == (DPSTimedEntry)(-1))
  2422.             followTimer = DPSAddTimedEntry(0.15, &followMouse, self, 28);
  2423.     }
  2424.  
  2425.     return self;
  2426. }
  2427.  
  2428. - (NXDragOperation)draggingSourceOperationMaskForLocal:(BOOL)flag
  2429. {
  2430.     return (dragView) ? NX_DragOperationPrivate : NX_DragOperationAll;
  2431. }
  2432.  
  2433. - (int)levelCount
  2434. {
  2435.     return [dockList count];
  2436. }
  2437.  
  2438. @end
  2439.