This is IconView.m in view mode; [Download] [Up]
/* IconView.m */ #import <objc/List.h> #import <appkit/Bitmap.h> #import <appkit/Listener.h> #import <appkit/graphics.h> #import <dpsclient/psops.h> #import <dpsclient/wraps.h> #import <strings.h> #import <libc.h> #import <math.h> #import "MyApp.h" #import "DockSpeaker.h" #import "IconView.h" #define UPPER_RIGHT 1 #define LOWER_RIGHT 2 @implementation IconView + new:(char *)name :icon :(int)xCoord :(int)yCoord { self = [super new]; /* copy the app's name */ appName = (char *)malloc(strlen(name) + 1); strcpy(appName, name); /* initialize bitmap locations */ bitmap = icon; activeBitmap = [Bitmap findBitmapFor:"active"]; /* save location in dock grid */ xGridLocation = xCoord; yGridLocation = yCoord; /* figure out if we're the dock window */ if (!strcmp(appName, "Dock")) { theDock = YES; altDocAppHidden = NO; } /* initialize */ highLighted = NO; active = NO; appsPSContext = 0; return self; } - initialize:list :(int)minX :(int)minY :(int)maxX :(int)maxY /* give the dock the bounding box and list of all app windows */ { xMin = minX; xMax = maxX; yMin = minY; yMax = maxY; windowList = list; /* create the drawing order lists for moving diagonally */ upperRight = [self createOrderedListForCorner:UPPER_RIGHT]; lowerRight = [self createOrderedListForCorner:LOWER_RIGHT]; return self; } - createOrderedListForCorner:(int)corner /* returns a list of windows ordered based on the corner parameter */ /* (this is the order in which they should be moved when moving toward */ /* this corner */ { int i, x1, y1, x2, y2, j; id list, tempList, iconWindow; list = [List new]; tempList = [List new]; i = [windowList count]; /* insert all windows into the temporary list (ordered by x position) */ while (i--) { iconWindow = [windowList objectAt:i]; [[iconWindow contentView] coordinates:&x1 :&y1]; j = 0; while (j < [tempList count]) { [[[tempList objectAt:j] contentView] coordinates:&x2 :&y2]; /* sort by x position */ if (corner == UPPER_RIGHT && x1 >= x2) { break; } else if (x1 >= x2) { break; } j++; } if (j == [tempList count]) { [tempList addObject:iconWindow]; } else if (![tempList insertObject:iconWindow at:j]) { [tempList addObject:iconWindow]; } } i = [tempList count]; /* insert tempList windows into the final list, sorted by x and y */ while (i--) { iconWindow = [tempList objectAt:i]; [[iconWindow contentView] coordinates:&x1 :&y1]; j = 0; while (j < [list count]) { [[[list objectAt:j] contentView] coordinates:&x2 :&y2]; /* sort by y */ if (corner == UPPER_RIGHT && x1 >= x2 && y1 >= y2) { break; } else if (x1 >= x2 && y1 <= y2) { break; } j++; } if (j == [list count]) { [list addObject:iconWindow]; } else if (![list insertObject:iconWindow at:j]) { [list addObject:iconWindow]; } } [tempList free]; return list; } - drawSelf:(const NXRect *)rects :(int)rectCount { NXRect drawRect; int numBitmaps; NXPoint origin, activePoint; /* initialize a drawing rectangle */ drawRect.origin.x = drawRect.origin.y = 0.0; drawRect.size.width = drawRect.size.height = 64.0; origin.x = origin.y = 8.0; if (!theDock) { /* if we're not the dock, draw our bezel */ NXDrawButton(&drawRect, 0); NXInsetRect(&drawRect, 1.0, 1.0); NXDrawButton(&drawRect, 0); NXInsetRect(&drawRect, -1.0, -1.0); /* draw our 48x48-bit icon */ [bitmap composite:NX_SOVER toPoint:&origin]; activePoint.x = 64.0 - 2.0 - 18.0; activePoint.y = drawRect.origin.y + 4.0; /* draw the three dots if our program isn't active */ if (!active) { [activeBitmap composite:NX_COPY toPoint:&activePoint]; } /* highlight ourself if we're getting our app to run or unhide */ if (highLighted) { NXInsetRect(&drawRect, 2.0, 2.0); NXHighlightRect(&drawRect); } } else { /* we're the dock so just copy our 64x64-bit icon into ourself */ origin.x = origin.y = 0.0; [bitmap composite:NX_COPY toPoint:&origin]; } return self; } #define MOVEMASK (NX_MOUSEUPMASK|NX_MOUSEDRAGGEDMASK) - mouseDown:(NXEvent *)theEvent { NXPoint mouseDownLocation; NXEvent *currentEvent; NXCoord oldX, oldY, newX, newY, dx, dy, x, y; NXRect frameRect; int windowNum; /* if we're not the dock, see if we should unhide our application */ if (!theDock) { [self handleNonDock:theEvent]; return self; } /* hide or unhide the dock's menus and icon window if a double click */ if (theEvent->data.mouse.click == 2) { [self hideOrUnhide]; } [window addToEventMask:MOVEMASK]; /* get the dock window's location */ [window getFrame:&frameRect]; /* convert the mouse's location to global (screen) coordinates */ mouseDownLocation = theEvent->location; PScurrenttoscreen(mouseDownLocation.x, mouseDownLocation.y, &oldX, &oldY); /* initialization */ newX = frameRect.origin.x; newY = frameRect.origin.y; currentEvent = [NXApp getNextEvent:MOVEMASK]; while (currentEvent->type != NX_MOUSEUP) { /* things get messed up if we move our window and ask the window */ /* to convert our mouse location to screen coordinates, so we */ /* use this call instead to get the mouse's screen location */ PScurrentmouse(0, &x, &y); /* offset from previous mouse location */ dx = x - oldX; dy = y - oldY; /* compute the dock window's proposed origin */ newX = dx + frameRect.origin.x; newY = dy + frameRect.origin.y; /* make sure this is ok (and fix it if not) */ [self checkCoords:&newX :&newY]; /* move everyone the correct amount */ [self moveWindows:(newX - frameRect.origin.x) :(newY - frameRect.origin.y)]; /* get our new origin and save the current mouse location */ [window getFrame:&frameRect]; oldX = x; oldY = y; /* wait for another mouse event */ currentEvent = [NXApp getNextEvent:MOVEMASK]; } /* impose the NeXT dock's grid behaviour on the window positions */ [self snapToGrid:&newX :&newY]; [self moveWindows:(newX - frameRect.origin.x) :(newY - frameRect.origin.y)]; return self; } - checkCoords:(float *)x :(float *)y /* constrain the dock window's location based on the bounding box */ { float maxX, maxY; if (*x < 4) *x = 4; if (*y < 0) *y = 0; maxX = (xMax - xMin) * 64.0 + 4.0; maxY = (yMax - yMin) * 64.0; if (*y > maxY) *y = maxY; if (*x > maxX) *x = maxX; return self; } - snapToGrid:(float *)x :(float *)y /* make sure windows lay on 64-bit boundaries */ { *x = rint((*x - 4) / 64.0) * 64.0 + 4.0; *y = rint(*y / 64.0) * 64.0; return self; } - moveWindows:(float)dx :(float)dy /* move the windows dx and dy */ { int numberOfWindows, startX, stopX, startY, stopY, i; id theList, moveWindow; NXRect frameRect; BOOL reverse; /* note that when moving to upper left, we can use the lower right */ /* window list, just traverse it in the opposite direction */ if (dx <= 0 && dy < 0) { theList = upperRight; reverse = YES; } else if (dx >= 0 && dy > 0) { theList = upperRight; reverse = NO; } else if (dx < 0 && dy >= 0) { theList = lowerRight; reverse = YES; } else { /* (dx > 0 && dy <= 0) */ theList = lowerRight; reverse = NO; } numberOfWindows = [theList count]; if (!reverse) { i = 0; while (i < numberOfWindows) { moveWindow = [theList objectAt:i++]; [moveWindow getFrame:&frameRect]; [moveWindow moveTo:(frameRect.origin.x + dx) :(frameRect.origin.y + dy)]; } } else { i = numberOfWindows; while (i--) { moveWindow = [theList objectAt:i]; [moveWindow getFrame:&frameRect]; [moveWindow moveTo:(frameRect.origin.x + dx) :(frameRect.origin.y + dy)]; } } return self; } - handleNonDock:(NXEvent *)theEvent /* click in a non-dock window */ { port_t appPort; int flag; /* only concern ourselves with double clicks */ if (theEvent->data.mouse.click == 2) { /* simulate NeXT dock functionality */ highLighted = YES; [self display]; [NXApp deactivateSelf]; /* get the WorkSpace to make sure our app is running */ appPort = NXPortFromName((rindex(appName, '/') + 1), NULL); if (appPort == PORT_NULL) { /* something went wrong */ highLighted = NO; [self display]; [NXApp activateSelf:YES]; return self; } /* now unhide the app (just like the WorkSpace) */ [[NXApp appSpeaker] setSendPort:appPort]; [[NXApp appSpeaker] unhide]; /* save our app's PostScript context (for a later version, maybe) */ appsPSContext = [NXApp activeApp]; /* all done, so show app is active and unhighlight ourselves */ highLighted = NO; active = YES; [self display]; } return self; } - hideOrUnhide /* hide or unhide the dock app's menu */ { if (altDocAppHidden) { [[NXApp mainMenu] orderFront:self]; altDocAppHidden = NO; } else { [[NXApp mainMenu] orderOut:self]; altDocAppHidden = YES; } return self; } - (BOOL)theDock { return theDock; } - coordinates:(int *)xCoord :(int *)yCoord /* return our grid coordinates */ { *xCoord = xGridLocation; *yCoord = yGridLocation; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.