home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / util / comm / news102.sit / NewsWatcher / source / userint.c < prev    next >
C/C++ Source or Header  |  1991-04-03  |  60KB  |  2,457 lines

  1. /*----------------------------------------------------------
  2. #
  3. #    NewsWatcher    - Macintosh NNTP Client Application
  4. #
  5. #    Written by Steven Falkenburg
  6. #    ⌐1990 Apple Computer, Inc.
  7. #
  8. #-----------------------------------------------------------
  9. #
  10. #    userint.c
  11. #
  12. #    This code segment contains the main program which controls
  13. #    the user interface for NewsWatcher.
  14. #
  15. #-----------------------------------------------------------*/
  16.  
  17. #pragma segment userint
  18.  
  19. #include "compat.h"
  20.  
  21. #ifdef PROTOS
  22.  
  23. #include <Types.h>
  24. #include <QuickDraw.h>
  25. #include <Fonts.h>
  26. #include <Windows.h>
  27. #include <Menus.h>
  28. #include <TextEdit.h>
  29. #include <Dialogs.h>
  30. #include <OSUtils.h>
  31. #include <Desk.h>
  32. #include <ToolUtils.h>
  33. #include <OSEvents.h>
  34. #include <Lists.h>
  35. #include <CursorCtl.h>
  36. #include <Packages.h>
  37. #include <Scrap.h>
  38. #include <Resources.h>
  39. #include <StdLib.h>
  40. #include <CType.h>
  41. #include <Script.h>
  42. #include <Printing.h>
  43. #include <Traps.h>
  44. #include <SegLoad.h>
  45. #endif
  46.  
  47. #include <String.h>
  48.  
  49. #include "nntp.h"
  50. #include "commands.h"
  51. #include "userint.h"
  52. #include "newsprocess.h"
  53. #include "ScrollStuff.h"
  54. #include "netstuff.h"
  55. #include "miscstuff.h"
  56. #include "printstuff.h"
  57. #include "NNTPLow.h"
  58.  
  59. #ifndef    _Unimplemented
  60. #define _Unimplemented                    0xA89F
  61. #define _WaitNextEvent                    0xA860
  62. #endif
  63.  
  64. /* globals */
  65.  
  66. Handle    gLifeBoat;                            /* lifeboat memory -- de-allocated when memory gets low */
  67. Boolean    gSinking = true;                    /* flag set after lifeboat has been jettisoned */
  68. Boolean gOutOfMemory = false;                /* flag set when out of memory - and luck */
  69.  
  70. Boolean    gDone = true;                        /* flag set true upon program termination */
  71. Boolean gCancel = false;                    /* flag set when user cancels an action */
  72. short    gMoveModalProc;                        /* proc ID for movable modal dialog */
  73. Boolean    gInBackground = false;                /* background/foreground flag */
  74. Rect    desktopExtent;
  75. Boolean    gHasColorQD;
  76. Boolean gAuthenticated = false;                /* true when user has been authenticated */
  77. char     gPass[256];                            /* password */
  78. TEHandle gFrontTE;
  79. Boolean gHasWaitNextEvent = false;            /* true if WaitNextEvent available */
  80. TPrefRec gPrefs;                            /* preferences */
  81. Cursor    gIBeamCurs,gWatchCurs;
  82.  
  83. static    MenuHandle    gTheMenu[kNumMenus];    /* pull-down menu storage */
  84. static    Rect        gDragRect,gWindLimits;    /* drag/resize limit rectangles */
  85. static    ListHandle     gTheList;
  86. static    Boolean        gClicked = false;
  87. static    Boolean        gScrapDirty,gScrapChanged;
  88. static    short        gScrapCompare;
  89. static    WindowPtr    gGroupWindow;
  90.  
  91. /* main program - calls other things */
  92.  
  93. void main(void)
  94. {
  95.     MoreMasters();
  96.     MoreMasters();
  97.     MoreMasters();
  98.     MoreMasters();
  99.     MoreMasters();
  100.     InitStuff();
  101.     MainEvent();
  102.     ExitToShell();    /* Yes, you really do need to do this! */
  103. }
  104.  
  105.  
  106. /* InitStuff: initializes macintosh managers */
  107.  
  108. void InitStuff(void)
  109. {
  110.     EventRecord ev;
  111.     SysEnvRec theEnv;
  112.     short tNumber;
  113.     
  114.     gLifeBoat = NewHandle(kLifeBoatSize);
  115.     if (MemError() == noErr)
  116.         gSinking = false;
  117.     MoveHHi(gLifeBoat);
  118.     HLock(gLifeBoat);
  119.     
  120.     InitGraf(&QDTHEPORT);
  121.     InitFonts();
  122.     InitWindows();
  123.     InitMenus();
  124.     TEInit();
  125.     InitDialogs(nil);
  126.     InitCursor();
  127.     InitCursorCtl(nil);
  128.     InitPrint();
  129.     
  130.     FlushEvents(everyEvent,0);
  131.     EventAvail(everyEvent,&ev);
  132.     
  133.     desktopExtent = (**GetGrayRgn()).rgnBBox;
  134.  
  135.     gMoveModalProc = 2053;
  136.     
  137.     if (SysEnvirons(1,&theEnv) == noErr && theEnv.systemVersion >= 1792)
  138.         gMoveModalProc = 5;
  139.     gHasColorQD = theEnv.hasColorQD;
  140.     
  141.     if  (( theEnv.machineType > envMachUnknown ) &&
  142.         ( theEnv.machineType < envMacII ) ) {        /* it's a 512KE, Plus, or SE */
  143.         tNumber = _WaitNextEvent & 0x03FF;
  144.         if ( tNumber > 0x01FF )                    /* which means the tool traps */
  145.             tNumber = _Unimplemented;            /* only go to 0x01FF */
  146.     }
  147.     gHasWaitNextEvent = NGetTrapAddress(tNumber, ToolTrap) != GetTrapAddress(_Unimplemented);
  148.  
  149.     
  150.     SetRect(&gDragRect,4,24,desktopExtent.right-4,desktopExtent.bottom-4);
  151.     SetRect(&gWindLimits,50,50,6000,6000);
  152.     gIBeamCurs = **(GetCursor(iBeamCursor));
  153.     gWatchCurs = **(GetCursor(watchCursor));
  154.     
  155.     ReadPrefs(&gPrefs);
  156.     SetUpMenus();
  157.     StartNNTP();
  158.  
  159.     gScrapCompare = InfoScrap()->scrapCount + 1;
  160.     gScrapDirty = false;
  161.     ReadDeskScrap();
  162.  
  163.     CloseStatusWindow();
  164.  
  165.     SetUpWindows();
  166.     CheckGroups();
  167.  
  168.     CloseStatusWindow();
  169.  
  170.     DoStartUp();
  171.     gDone = false;
  172.     
  173. }
  174.  
  175.  
  176. /* SetUpMenus: draws the pull-down menus onto the screen */
  177.  
  178. void SetUpMenus(void)
  179. {
  180.     short i;
  181.     
  182.     for (i=0; i<kNumMenus; i++)
  183.         gTheMenu[i] = GetMenu(i+kMenuOffset);
  184.     AddResMenu(gTheMenu[kAppleMenu],'DRVR');
  185.     AddResMenu(gTheMenu[kFontMenu],'FONT');
  186.     for (i=0; i<kNumMenus; i++)
  187.         InsertMenu(gTheMenu[i],0);
  188.     DrawMenuBar();
  189. }
  190.  
  191.  
  192. /* SetUpWindows: creates an initial, empty window */
  193.  
  194. void SetUpWindows(void)
  195. {
  196.     WindowPtr theWind;
  197.     TwindowInfo *theInfo;
  198.     GrafPtr savePort;
  199.     extern short gNumGroups;
  200.     extern TGroup *gGroupList;
  201.     Point firstOffset;
  202.     Point thePt;
  203.  
  204.     SetPt(&firstOffset,kOffLeft,kOffTop);
  205.     theInfo = (TwindowInfo *) GetWRefCon(gGroupWindow = theWind = MakeNewWindow(cGroup,false,firstOffset,"\pNewsgroups"));
  206.  
  207.     theInfo->numGroups = gNumGroups;
  208.     theInfo->data2 = (unsigned long) gGroupList;
  209.     theInfo->parentGroup = nil;
  210.     theInfo->parentWindow = nil;
  211.     theInfo->childList = nil;
  212.     
  213.     MakeGroupList((ListHandle)theInfo->data,gNumGroups,gGroupList);
  214.     SetPt(&thePt,0,0);
  215.     LSetSelect(true,thePt,(ListHandle)theInfo->data);
  216.     
  217.     GetPort(&savePort);
  218.     SetPort(theWind);
  219.  
  220.     SizeWindow(theWind,gPrefs.groupWindowSize.right-gPrefs.groupWindowSize.left,
  221.                     gPrefs.groupWindowSize.bottom-gPrefs.groupWindowSize.top,true);
  222.     SizeContents(gPrefs.groupWindowSize.right-gPrefs.groupWindowSize.left,
  223.                     gPrefs.groupWindowSize.bottom-gPrefs.groupWindowSize.top,theWind);
  224.     MoveWindow(theWind,gPrefs.groupWindowSize.left,gPrefs.groupWindowSize.top,false);
  225.  
  226.     CloseStatusWindow();
  227.     if (gPrefs.openWindowsZoomed)
  228.         DoZoom(theWind,inZoomOut);
  229.  
  230.     if (!gPrefs.groupWindowVisible) {
  231.         gPrefs.groupWindowVisible = !gPrefs.groupWindowVisible;
  232.         HideShowGroups();
  233.     }
  234.     else
  235.         ShowWindow(theWind);
  236.  
  237.     InvalRect(&theWind->portRect);
  238.     SetPort(savePort);
  239.     
  240.     gFrontTE = nil;
  241. }
  242.  
  243.  
  244. /*    NewGroupWindow creates a new user group window */
  245.  
  246. WindowPtr NewGroupWindow(char *groupName)
  247. {
  248.     WindowPtr theWind;
  249.     TwindowInfo *theInfo;
  250.     Point firstOffset;
  251.     
  252.     SetPt(&firstOffset,kOffLeft,kOffTop);
  253.     
  254.     theInfo = (TwindowInfo *) GetWRefCon(theWind = MakeNewWindow(cUserGroup,true,firstOffset,groupName));
  255.     BlockMove(groupName,theInfo->diskFile,groupName[0]+1);
  256.     theInfo->changed = false;
  257.     theInfo->numGroups = 0;
  258.     theInfo->saved = false;
  259.     theInfo->data2 = nil;
  260.     theInfo->childList = nil;
  261.     theInfo->parentWindow = nil;
  262.     ShowWindow(theWind);
  263.     return theWind;
  264. }
  265.  
  266.  
  267. /*    MyOffSet offsets a window so no two windows are at the same origin and the
  268.     windows do not hang off of the screen.
  269. */
  270.  
  271. Rect *MyOffSet(Rect *theRect)
  272. {
  273.     WindowPtr wind;
  274.     Rect firstRect;
  275.     
  276.     firstRect = *theRect;
  277.     wind = FrontWindow();
  278.  
  279.     while (wind) {
  280.         if ((theRect->top == (-wind->portBits.bounds.top)) && (theRect->left == (-wind->portBits.bounds.left))) {
  281.             OffsetRect(theRect,gPrefs.windowOffset.h,gPrefs.windowOffset.v);
  282.             if (theRect->right > desktopExtent.right) {
  283.                 OffsetRect(&firstRect,0,gPrefs.windowOffset.v+2);
  284.                 *theRect = firstRect;
  285.             }
  286.             if (theRect->bottom > desktopExtent.bottom) {
  287.                 OffsetRect(&firstRect,gPrefs.windowOffset.h+2,0);
  288.                 *theRect = firstRect;
  289.             }
  290.             wind = FrontWindow();
  291.         }
  292.         else
  293.             wind = (WindowPtr) ((WindowPeek) wind)->nextWindow;
  294.     }
  295.     
  296.     if (theRect->top > desktopExtent.bottom)
  297.         theRect->top = desktopExtent.bottom - 10;
  298.     if (theRect->left > desktopExtent.right)
  299.         theRect->left = desktopExtent.right - 10;
  300.     if (theRect->bottom > desktopExtent.bottom && theRect->top < (desktopExtent.bottom-64))
  301.         theRect->bottom = desktopExtent.bottom;
  302.     if (theRect->right > desktopExtent.right && theRect->left < (desktopExtent.right-64))
  303.         theRect->right = desktopExtent.right;
  304.         
  305.     return(theRect);
  306. }
  307.  
  308.  
  309. /*    MakeNewWindow is the low-level procedure to make a new NewsWatcher window.
  310.     Depending on what type is needed, the window will have different
  311.     features.
  312. */
  313.  
  314. WindowPtr MakeNewWindow(short type,Boolean hasClose,Point topLeft,char *title)
  315. {
  316.     
  317.     WindowPtr theWindow;
  318.     TwindowInfo *theInfo;
  319.     Rect bounds;
  320.     short rightMark;
  321.     
  322.     if (!gPrefs.parentWindows)
  323.         SetPt(&topLeft,kOffLeft,kOffTop);
  324.         
  325.     switch (type) {
  326.         case cGroup:
  327.         case cNewGroup:
  328.         case cUserGroup:
  329.             rightMark = topLeft.h+300;
  330.             break;
  331.         case cSubject:
  332.             rightMark = topLeft.h+400;
  333.             break;
  334.         case cMessage:
  335.         case cMiscMessage:
  336.         case cSendMessage:
  337.         case cPostMessage:
  338.             rightMark = topLeft.h+495;
  339.             break;
  340.     }
  341.  
  342.     SetRect(&bounds,topLeft.h,topLeft.v,rightMark,kHeightWindow+topLeft.v);    
  343.     theWindow = NewWindow(nil,MyOffSet(&bounds),"\pUntitled",false,zoomDocProc,(WindowPtr)-1,hasClose,nil);
  344.     
  345.     theInfo = (TwindowInfo *) MyNewPtr(sizeof(TwindowInfo));
  346.     if (MyMemErr() != noErr)
  347.         return nil;
  348.         
  349.     theInfo->kind = type;
  350.     switch (type) {
  351.         case cGroup:
  352.         case cNewGroup:
  353.             theInfo->filter[0] = '\0';
  354.             theInfo->filterLen = 0;
  355.             theInfo->data = (Handle)NewList(theWindow);
  356.             (**((ListHandle)theInfo->data)).listFlags = 0;
  357.             break;
  358.         case cUserGroup:
  359.         case cSubject:
  360.             theInfo->filter[0] = '\0';
  361.             theInfo->filterLen = 0;
  362.             theInfo->data = (Handle)NewList(theWindow);
  363.             LDoDraw(true,(ListHandle)theInfo->data);
  364.             break;
  365.         case cMessage:
  366.         case cMiscMessage:
  367.         case cPostMessage:
  368.         case cSendMessage:
  369.             theInfo->data = (Handle)NewText(theWindow);
  370.             MakeScrollers(theWindow);
  371.             break;
  372.     }
  373.     if (type == cGroup || type == cNewGroup || type == cUserGroup)
  374.         (**((ListHandle)theInfo->data)).lClikLoop = (ProcPtr) DoClikLoop;
  375.  
  376.     SetWRefCon(theWindow,(long)theInfo);
  377.     SetWTitle(theWindow,(StringPtr) title);
  378.     AddWindowsMenu(theWindow);
  379.     return theWindow;
  380. }
  381.  
  382.  
  383. /*    MakeScrollers adds scroll bars to textedit windows */
  384.  
  385. void MakeScrollers(WindowPtr theWindow)
  386. {
  387.     Rect windowRect,hScrollRect,vScrollRect;
  388.     
  389.     windowRect = theWindow->portRect;
  390.     
  391.     SetRect(&hScrollRect,-1,(windowRect.bottom-windowRect.top - 15),
  392.             (windowRect.right-windowRect.left - 14),
  393.             (windowRect.bottom-windowRect.top + 1));
  394.     SetRect(&vScrollRect,(windowRect.right-windowRect.left - 15),-1,
  395.             (windowRect.right-windowRect.left+1),
  396.             (windowRect.bottom-windowRect.top-14));
  397.     SetCRefCon(NewControl(theWindow,&vScrollRect,"\p",true,0,0,0,16,0),kVRef);
  398.     SetCRefCon(NewControl(theWindow,&hScrollRect,"\p",true,0,0,kMaxColumns,16,1),kHRef);
  399. }
  400.  
  401.  
  402. /*    NewList makes a new list manager list for list windows */
  403.  
  404. ListHandle NewList(WindowPtr theWindow)
  405. {
  406.     ListHandle theList;
  407.     
  408.     Point thePt;
  409.     Rect listRect,sizeRect;
  410.     GrafPtr savePort;
  411.     short fontNum;
  412.     
  413.     SetPt(&thePt,0,0);
  414.     SetRect(&sizeRect,0,0,1,0);
  415.     SetRect(&listRect,theWindow->portRect.left,theWindow->portRect.top,theWindow->portRect.right-15,theWindow->portRect.bottom-15);
  416.     GetPort(&savePort);
  417.     SetPort(theWindow);
  418.     
  419.     GetFNum(gPrefs.listFont,&fontNum);
  420.     TextFont(fontNum);
  421.     TextSize(gPrefs.listSize);
  422.     theList = LNew(&listRect,&sizeRect,thePt,kLDEFProc,theWindow,false,true,false,true);
  423.     (**theList).selFlags |= lNoNilHilite;
  424.     SetPort(savePort);
  425.     return theList;
  426. }
  427.  
  428.  
  429. /*    DoClikLoop is the click loop routine for list windows in newswatcher.  It
  430.     handles subscribing to and re-ordering of groups.
  431. */
  432.  
  433. pascal Boolean DoClikLoop(void)
  434. {    
  435.     Rect cellRect;
  436.     Cell lastClicked;
  437.     Point thePt;
  438.     static Point firstPt;
  439.     long theClick;
  440.     
  441.     if (!gClicked) {
  442.         gClicked = true;
  443.         GetMouse(&firstPt);
  444.         return true;
  445.     }
  446.  
  447. #ifdef THINK_C
  448.     theClick = LLastClick(gTheList);
  449.     lastClicked = * ((Cell *) &theClick);
  450. #else
  451.     #pragma unused (theClick)
  452.     lastClicked = LLastClick(gTheList);
  453. #endif
  454.  
  455.     LRect(&cellRect,lastClicked,gTheList);
  456.     GetMouse(&thePt);
  457.     
  458.     if (PtInRect(thePt,&cellRect)) {
  459.         return true;
  460.     }
  461.     else {
  462.         TrackClick(firstPt);
  463.         return false;
  464.     }
  465. }
  466.  
  467.  
  468. /*    TrackClick is called by the clickLoop routine when the mouse goes outside
  469.     the boundaries of the cell clicked in.
  470. */
  471.  
  472. void TrackClick(Point thePt)
  473. {
  474.     RgnHandle dragRgn;
  475.     Rect cellRect;
  476.     Cell curCell,firstCell,lastCell,countCell;
  477.     Point curPt;
  478.     GrafPtr fullPort,savePort;
  479.     WindowPtr theWindow,startWindow;
  480.     TwindowInfo *info;
  481.     short part,cellHeight,diff;
  482.     char cellData[512];
  483.     short dataLen;
  484.     TGroup *curGroup,*curPrev,*firstGroup,*firstPrev,*lastGroup;
  485.     
  486.     startWindow = FrontWindow();
  487.     info = (TwindowInfo *)GetWRefCon(startWindow);
  488.  
  489.     dragRgn = NewRgn();
  490.     
  491.     SetPt(&curCell,0,0);
  492.     SetPt(&firstCell,0,0);
  493.     SetPt(&lastCell,0,0);
  494.     OpenRgn();
  495.     LGetSelect(true,&firstCell,gTheList);
  496.     while (LGetSelect(true,&curCell,gTheList)) {
  497.         LRect(&cellRect,curCell,gTheList);
  498.         FrameRect(&cellRect);
  499.         lastCell = curCell;
  500.         curCell.v++;
  501.     }
  502.     
  503.     CloseRgn(dragRgn);
  504.     
  505.     GetMouse(&curPt);
  506.     SubPt(curPt,&thePt);
  507.     OffsetRgn(dragRgn,-thePt.h,-thePt.v);
  508.     LocalToGlobal(&curPt);
  509.     
  510.     SetPt(&thePt,0,0);
  511.     LocalToGlobal(&thePt);
  512.     OffsetRgn(dragRgn,thePt.h,thePt.v);
  513.     
  514.     fullPort = (GrafPtr) MyNewPtr(sizeof(GrafPort));
  515.     if (MyMemErr() != noErr)
  516.         return;
  517.     
  518.     GetPort(&savePort);
  519.     OpenPort(fullPort);
  520.     CopyRgn(GetGrayRgn(),fullPort->visRgn);
  521.     fullPort->portRect = desktopExtent;
  522.     
  523.     DragGrayRgn(dragRgn,curPt,&desktopExtent,&desktopExtent,noConstraint,nil);
  524.     DisposeRgn(dragRgn);
  525.     GetMouse(&curPt);
  526.     LocalToGlobal(&curPt);
  527.     
  528.     SetPort(savePort);
  529.     ClosePort(fullPort);
  530.     MyDisposPtr((Ptr)fullPort);
  531.     
  532.     part = FindWindow(curPt,&theWindow);
  533.     
  534.     switch (info->kind) {
  535.         case cGroup:
  536.         case cNewGroup:
  537.             if (part == inContent) {
  538.                 if (((TwindowInfo *)GetWRefCon(theWindow))->kind == cUserGroup) {
  539.                     SubscribeSelected((TwindowInfo *)GetWRefCon(startWindow),gTheList,theWindow);
  540.                 }
  541.                 else
  542.                     SysBeep(1);
  543.             }
  544.             break;
  545.         case cUserGroup:
  546.             if (theWindow == startWindow && part == inContent) {
  547.                 LDoDraw(false,gTheList);
  548.                 GlobalToLocal(&curPt);
  549.                 cellHeight = cellRect.bottom - cellRect.top;
  550.                 if (cellHeight == 0)
  551.                     cellHeight=1;
  552.                 curCell.v = (**gTheList).visible.top + (curPt.v / cellHeight);
  553.                 curCell.h = 0;
  554.                 
  555.                 if (curCell.v < firstCell.v || curCell.v > lastCell.v) {
  556.                     curCell.v = LAddRow((lastCell.v - firstCell.v + 1),curCell.v,gTheList);
  557.                     
  558.                     /* re-order linked list */
  559.  
  560.                     if (curCell.v > 0) {
  561.                         curPrev = NthGroup((TGroup *)info->data2,curCell.v-1);
  562.                         curGroup = curPrev->next;
  563.                     }
  564.                     else {
  565.                         curPrev = nil;
  566.                         curGroup = (TGroup *)info->data2;
  567.                     }
  568.                     
  569.                     if (firstCell.v > 0) {
  570.                         firstPrev = NthGroup((TGroup *)info->data2,firstCell.v-1);
  571.                         firstGroup = firstPrev->next;
  572.                     }
  573.                     else {
  574.                         firstPrev = nil;
  575.                         firstGroup = (TGroup *)info->data2;
  576.                     }
  577.                     
  578.                     lastGroup = NthGroup((TGroup *)info->data2,lastCell.v);
  579.  
  580.                     if (!firstGroup || !lastGroup) {
  581.                         SysBeep(1);
  582.                         return;
  583.                     }
  584.                         
  585.                     if (curPrev)
  586.                         curPrev->next = firstGroup;
  587.                     else
  588.                         info->data2 = (unsigned long) firstGroup;
  589.                     
  590.                     if (firstPrev)
  591.                         firstPrev->next = lastGroup->next;
  592.                     else
  593.                         info->data2 = (unsigned long) (lastGroup->next);
  594.                         
  595.                     lastGroup->next = curGroup;
  596.  
  597.                     if (curCell.v < firstCell.v) {
  598.                         diff = (lastCell.v - firstCell.v + 1);
  599.                         firstCell.v += diff;
  600.                         lastCell.v += diff;
  601.                     }
  602.                     countCell.h = 0;
  603.                     for (countCell.v = firstCell.v; countCell.v <= lastCell.v; countCell.v++,curCell.v++) {
  604.                         dataLen = 512;
  605.                         LGetCell(cellData,&dataLen,countCell,gTheList);
  606.                         LSetCell(cellData,dataLen,curCell,gTheList);
  607.                     }
  608.                     LDelRow((lastCell.v - firstCell.v + 1),firstCell.v,gTheList);
  609.                 }
  610.                 else
  611.                     SysBeep(1);
  612.                 InvalRect(&startWindow->portRect);
  613.                 LDoDraw(true,gTheList);
  614.             }
  615.             else
  616.                 SysBeep(1);
  617.             break;
  618.         default:
  619.             SysBeep(1);
  620.             break;
  621.     }
  622. }
  623.  
  624.  
  625. /*    NthGroup gets the nth group out of the user group linked list.
  626. */
  627.  
  628. TGroup *NthGroup(TGroup *head,short index)
  629. {
  630.     short i;
  631.     TGroup *curGroup;
  632.     
  633.     for (i=0,curGroup = head;
  634.         i<index && curGroup;
  635.         i++,curGroup = curGroup->next)
  636.         ;
  637.     return curGroup;
  638. }
  639.  
  640.  
  641. /*    NewText creates a new textedit record for message windows.
  642. */
  643.  
  644. TEHandle NewText(WindowPtr theWindow)
  645. {
  646.     TEHandle theTE;
  647.     Rect theRect;
  648.     short fontNum;
  649.     
  650.     SetPort(theWindow);
  651.     
  652.     GetFNum(gPrefs.textFont,&fontNum);
  653.     TextFont(fontNum);
  654.     TextSize(gPrefs.textSize);
  655.     
  656.     SetRect(&theRect,theWindow->portRect.left,theWindow->portRect.top,theWindow->portRect.right-15,
  657.                     theWindow->portRect.bottom-15);
  658.     InsetRect(&theRect,kTextMargin,kTextMargin);
  659.  
  660.     theTE = TENew(&theRect,&theRect);
  661.     (**theTE).crOnly = -1;
  662.     SetClikLoop(AutoScroll,theTE);
  663.     
  664.     return theTE;
  665. }
  666.  
  667.  
  668. /* DoCloseWindow removes a window from the screen */
  669.  
  670. Boolean DoCloseWindow(WindowPtr theWind)
  671. {
  672.     TwindowInfo *info;
  673.     TGroup *tmpPtr,*tmpPtr2;
  674.     TReadRec *tmpPtr3,*tmpPtr4;
  675.     TSubject *tmpSubject;
  676.     WindowPtr childWindows;
  677.     Handle tmpHandle;
  678.     Point offPt;
  679.     GrafPtr savePort;
  680.     
  681.     RemoveWindowsMenu(theWind);
  682.     DoActivate(theWind,false,false);
  683.     
  684.     info = (TwindowInfo *)GetWRefCon(theWind);
  685.     switch (info->kind) {
  686.         case cGroup:
  687.             /* don't dispose data if main group window -- need to save that later */
  688.             LDispose((ListHandle)info->data);
  689.             gPrefs.groupWindowSize = theWind->portRect;
  690.             SetPt(&offPt,0,0);
  691.             GetPort(&savePort);
  692.             SetPort(theWind);
  693.             LocalToGlobal(&offPt);
  694.             SetPort(savePort);
  695.             OffsetRect(&gPrefs.groupWindowSize,offPt.h,offPt.v);
  696.             DisposeWindow(theWind);
  697.             MyDisposPtr((Ptr)info);
  698.             break;
  699.         case cNewGroup:
  700.             LDispose((ListHandle)info->data);
  701.             tmpHandle = RecoverHandle((Ptr)info->data2);
  702.             if (tmpHandle && MyMemErr()==noErr) {
  703.                 HUnlock(tmpHandle);
  704.                 MyDisposHandle(tmpHandle);
  705.             }
  706.             DisposeWindow(theWind);
  707.             MyDisposPtr((Ptr)info);
  708.             break;
  709.         case cSubject:
  710.             if (info->parentWindow)
  711.                 RemoveChild(info->parentWindow,theWind);
  712.             if (info->parentGroup) 
  713.                 MarkReadMsgs(info);
  714.             HLock((Handle)info->data2);
  715.             tmpSubject = (TSubject *) *((Handle)(info->data2));
  716.             HUnlock((Handle)info->data2);
  717.             MyDisposHandle((Handle)info->data2);
  718.             LDispose((ListHandle)info->data);
  719.             MyDisposPtr((Ptr)info);
  720.             
  721.             /* remove references within message windows */
  722.             
  723.             childWindows = (WindowPtr)(((WindowPeek)theWind)->nextWindow);
  724.             while (childWindows!=nil) {
  725.                 info = (TwindowInfo *)GetWRefCon(childWindows);
  726.                 if (info->kind == cMessage && info->parentWindow == theWind)
  727.                     info->parentWindow = nil;
  728.                 childWindows = (WindowPtr)(((WindowPeek)childWindows)->nextWindow);
  729.             }
  730.             DisposeWindow(theWind);
  731.             break;
  732.             
  733.         case cUserGroup:
  734.             while (info->childList)
  735.                 DoCloseWindow(info->childList->childWindow);
  736.             if (info->changed && !(CheckForSave(theWind)))
  737.                 return false;
  738.             LDispose((ListHandle)info->data);
  739.             for (tmpPtr = (TGroup *)info->data2; tmpPtr!=nil;) {
  740.                 tmpPtr2 = tmpPtr;
  741.                 tmpPtr = tmpPtr->next;
  742.                 for (tmpPtr3 = tmpPtr2->read; tmpPtr3!=nil;) {
  743.                     tmpPtr4 = tmpPtr3;
  744.                     tmpPtr3 = tmpPtr3->next;
  745.                     MyDisposPtr((Ptr)tmpPtr4);
  746.                 }
  747.                 MyDisposPtr((Ptr)tmpPtr2);
  748.             }
  749.             MyDisposPtr((Ptr)info);
  750.             DisposeWindow(theWind);
  751.             break;
  752.         
  753.         case cPostMessage:
  754.         case cSendMessage:
  755.             if (info->changed && !CheckForSend(theWind))
  756.                 return false;
  757.         case cMessage:
  758.         case cMiscMessage:
  759.             TEDispose((TEHandle)info->data);
  760.             MyDisposPtr((Ptr)info);
  761.             DisposeWindow(theWind);
  762.             gFrontTE = nil;
  763.             break;
  764.     }
  765.     return true;
  766. }
  767.  
  768.  
  769. /* ShowAbout: shows the about box */
  770.  
  771. void ShowAbout(void)
  772. {
  773.     DialogPtr theDlg;
  774.     short item;
  775.     
  776.     theDlg = GetNewDialog(kAboutID,nil,(WindowPtr)-1L);
  777.     OutlineOK(theDlg);
  778.     
  779.     do
  780.         ModalDialog(CmdKeyFilter,&item);
  781.     while (item != okButton);
  782.             
  783.     DisposDialog(theDlg);
  784.     
  785. }
  786.  
  787.  
  788. /* MainEvent: main event loop- dispatches to other handlers */
  789.  
  790. void MainEvent(void)
  791. {
  792.     EventRecord ev;
  793.     RgnHandle    cursorRgn;
  794.     Boolean        gotEvt;
  795.     
  796.     cursorRgn = NewRgn();
  797.     do {
  798.         gCancel = false;
  799.         
  800.         if (IsMovableModal(FrontWindow()))
  801.             CloseStatusWindow();
  802.         
  803.         if (gHasWaitNextEvent)
  804.             gotEvt = WaitNextEvent(everyEvent,&ev,kSleepTime,cursorRgn);
  805.         else {
  806.             gotEvt = GetNextEvent(everyEvent,&ev);
  807.             SystemTask();
  808.         }
  809.         
  810.         FixCursor(ev.where,cursorRgn);
  811.         if (gotEvt) {
  812.             switch (ev.what) {
  813.                 case mouseDown:
  814.                     HandleMouseDowns(&ev);
  815.                     break;
  816.                 case keyDown:
  817.                 case autoKey:
  818.                     HandleKeyDowns(&ev);
  819.                     break;
  820.                 case activateEvt:
  821.                     HandleActivates(&ev);
  822.                     break;
  823.                 case updateEvt:
  824.                     HandleUpdates((WindowPtr)(ev.message));
  825.                     break;
  826.                 case app4Evt:
  827.                     HandleSREvt(ev.message);
  828.                     break;
  829.             }
  830.             FixCursor(ev.where,cursorRgn);
  831.         }
  832.     
  833.         if (gFrontTE)
  834.             TEIdle(gFrontTE);
  835.     }        
  836.     while (!gDone);
  837.     
  838.     /* clear private user info before quitting */
  839.     
  840.     Logout();    
  841.     DisposeRgn(cursorRgn);
  842.     
  843.     CloseNewsConnection();
  844.     WritePrefs(&gPrefs);
  845.     WriteGroups();
  846. }
  847.  
  848.  
  849. /*    IsAppWindow returns true if the window belongs to the application
  850. */
  851.  
  852. Boolean IsAppWindow(WindowPtr window)
  853. {
  854.     short        windowKind;
  855.     
  856.     if (window == nil)
  857.         return(false);
  858.     else {
  859.         windowKind = ((WindowPeek) window)->windowKind;
  860.         return ((windowKind >= userKind) || (windowKind == dialogKind));
  861.     }
  862. }
  863.  
  864.  
  865. /*    IsDAWindow returns true if the window is a DA window
  866. */
  867.  
  868. Boolean IsDAWindow(WindowPtr window)
  869. {
  870.     if ( window == nil )
  871.         return(false);
  872.     else    /* DA windows have negative windowKinds */
  873.         return (((WindowPeek) window)->windowKind < 0);
  874. }
  875.  
  876.  
  877. /*    IsMovableModal returns true if the window is a movable modal
  878.     (this will be the status window).
  879. */
  880.  
  881. Boolean IsMovableModal(WindowPtr window)
  882. {
  883.     return (IsAppWindow(window) && ((TwindowInfo *)GetWRefCon(window))->kind==cMoveModal);
  884. }
  885.  
  886.  
  887. /*    FixCursor sets up the type of cursor needed, depending on where the mouse
  888.     pointer is located.  This routine is called in conjunction with WaitNextEvent.
  889. */
  890.  
  891. void FixCursor(Point mouse,RgnHandle region)
  892. {
  893.     WindowPtr    frontMost;
  894.     RgnHandle    arrowRgn,iBeamRgn;
  895.     Rect        iBeamRect;
  896.     Point        topLeftPt,botRightPt;
  897.     
  898.     frontMost = FrontWindow();
  899.     if ((!gInBackground) && (!IsDAWindow(frontMost))) {
  900.         arrowRgn = NewRgn();
  901.         iBeamRgn = NewRgn();
  902.         SetRectRgn(arrowRgn,-32768,-32768,32767,32767);
  903.         if (IsAppWindow(frontMost) && gFrontTE ) {
  904.             iBeamRect = (**gFrontTE).viewRect;
  905.             SetPort(frontMost);
  906.             SetPt(&topLeftPt,iBeamRect.left,iBeamRect.top);
  907.             SetPt(&botRightPt,iBeamRect.right,iBeamRect.bottom);
  908.             LocalToGlobal(&topLeftPt);
  909.             LocalToGlobal(&botRightPt);
  910.             iBeamRect.left = topLeftPt.h;
  911.             iBeamRect.top = topLeftPt.v;
  912.             iBeamRect.right = botRightPt.h;
  913.             iBeamRect.bottom = botRightPt.v;
  914.             RectRgn(iBeamRgn,&iBeamRect);
  915.             SetOrigin(-frontMost->portBits.bounds.left, -frontMost->portBits.bounds.top);
  916.             SectRgn(iBeamRgn, frontMost->visRgn, iBeamRgn);
  917.             SetOrigin(0,0);
  918.         }
  919.         DiffRgn(arrowRgn,iBeamRgn,arrowRgn);
  920.         if (PtInRgn(mouse,iBeamRgn)) {
  921.             SetCursor(&gIBeamCurs);
  922.             CopyRgn(iBeamRgn,region);
  923.         }
  924.         else {
  925.             SetCursor(&QDARROW);
  926.             CopyRgn(arrowRgn,region);
  927.         }
  928.         DisposeRgn(arrowRgn);
  929.         DisposeRgn(iBeamRgn);
  930.     }
  931. }
  932.  
  933.  
  934.  
  935. /* HandleSREvt: Handles suspend/resume events- activates main window */
  936.  
  937. void HandleSREvt(long message)
  938. {
  939.     SetCursor(&QDARROW);
  940.     if ((message >> 24) == kSRMess)
  941.         if ((message & 1) != 0) {
  942.             gInBackground = false;
  943.             DoActivate(FrontWindow(),true,true);
  944.         }
  945.         else {
  946.             gInBackground = true;
  947.             DoActivate(FrontWindow(),false,true);
  948.         }
  949. }
  950.  
  951.  
  952. /* HandleActivates: Handles activate events */
  953.  
  954. void HandleActivates(EventRecord *ev)
  955. {
  956.     DoActivate((WindowPtr)ev->message,((ev->modifiers & activeFlag) != 0),((ev->modifiers & 0x0002) != 0)); 
  957. }
  958.  
  959.  
  960. /*    DoActivate activates/deactivates windows */
  961.  
  962. void DoActivate(WindowPtr theWind,Boolean actFlag,Boolean chFlag)
  963. {
  964.     TwindowInfo *theInfo;
  965.     GrafPtr savePort;
  966.     Rect growBoxRect;
  967.     short fontNum;
  968.     
  969.     if (IsAppWindow(theWind)) {
  970.         theInfo = (TwindowInfo *)GetWRefCon(theWind);
  971.         switch (theInfo->kind) {
  972.             case cGroup:
  973.             case cNewGroup:
  974.             case cUserGroup:
  975.             case cSubject:
  976.                 LActivate(actFlag,(ListHandle)theInfo->data);
  977.                 if (actFlag) {
  978.                     GetFNum(gPrefs.listFont,&fontNum);
  979.                     SwitchFont(fontNum,gPrefs.listSize);
  980.                     gTheList = (ListHandle)theInfo->data;
  981.                 }
  982.                 break;
  983.             case cMessage:
  984.             case cMiscMessage:
  985.             case cPostMessage:
  986.             case cSendMessage:
  987.                 if (actFlag) {
  988.                     GetFNum(gPrefs.textFont,&fontNum);
  989.                     SwitchFont(fontNum,gPrefs.textSize);
  990.                     ShowControl( ((WindowPeek) theWind)->controlList );
  991.                     ShowControl( (*(((WindowPeek) theWind)->controlList))->nextControl);
  992.                     TEActivate((TEHandle)theInfo->data);
  993.                     gFrontTE = (TEHandle)theInfo->data;
  994.                 }
  995.                 else {
  996.                     HideControl( ((WindowPeek) theWind)->controlList );
  997.                     HideControl( (*(((WindowPeek) theWind)->controlList))->nextControl);
  998.                     TEDeactivate((TEHandle)theInfo->data);
  999.                     gFrontTE = nil;
  1000.                 }
  1001.                 break;
  1002.             case cMoveModal:
  1003.                 break;
  1004.         }
  1005.         GetPort(&savePort);
  1006.         SetPort(theWind);
  1007.         SetRect(&growBoxRect,theWind->portRect.right-15,theWind->portRect.top,
  1008.                     theWind->portRect.right,theWind->portRect.bottom);
  1009.         InvalRect(&growBoxRect);
  1010.         SetPort(savePort);
  1011.  
  1012.         if (chFlag)
  1013.             if (actFlag) {
  1014.                 ReadDeskScrap();
  1015.                 DisableItem(gTheMenu[kEditMenu],kUndoItem);
  1016.                 DisableItem(gTheMenu[kEditMenu],kCutItem);
  1017.                 DisableItem(gTheMenu[kEditMenu],kCopyItem);
  1018.                 DisableItem(gTheMenu[kEditMenu],kPasteItem);
  1019.                 DisableItem(gTheMenu[kEditMenu],kClearItem);
  1020.             }
  1021.             else {
  1022.                 WriteDeskScrap();
  1023.                 EnableItem(gTheMenu[kEditMenu],kUndoItem);
  1024.                 EnableItem(gTheMenu[kEditMenu],kCutItem);
  1025.                 EnableItem(gTheMenu[kEditMenu],kCopyItem);
  1026.                 EnableItem(gTheMenu[kEditMenu],kPasteItem);
  1027.                 EnableItem(gTheMenu[kEditMenu],kClearItem);
  1028.             }
  1029.         EnableItems(theInfo->kind,actFlag);
  1030.         DisableItems(theInfo->kind,actFlag);
  1031.     }
  1032. }
  1033.  
  1034.  
  1035. /*    EnableItems enables menu items, depending on whether or not
  1036.     the type of window being activated is of a certain type
  1037. */
  1038.  
  1039. void EnableItems(short kind,Boolean actFlag)
  1040. {
  1041.     switch (kind) {
  1042.         case cGroup:
  1043.             if (!actFlag) {
  1044.                 EnableItem(gTheMenu[kSpecialMenu],kNextItem);
  1045.                 EnableItem(gTheMenu[kFileMenu],kCloseItem);
  1046.                 EnableItem(gTheMenu[kFileMenu],kSaveItem);
  1047.                 EnableItem(gTheMenu[kFileMenu],kSaveAsItem);
  1048.             }
  1049.             else {
  1050.                 EnableItem(gTheMenu[kSpecialMenu],kSubscribeItem);
  1051.                 EnableItem(gTheMenu[kSpecialMenu],kReadItem);
  1052.                 EnableItem(gTheMenu[kEditMenu],kSearchItem);
  1053.             }
  1054.             break;
  1055.         case cNewGroup:
  1056.             if (!actFlag) {
  1057.                 EnableItem(gTheMenu[kSpecialMenu],kNextItem);
  1058.                 EnableItem(gTheMenu[kFileMenu],kSaveItem);
  1059.                 EnableItem(gTheMenu[kFileMenu],kSaveAsItem);
  1060.             }
  1061.             else {
  1062.                 EnableItem(gTheMenu[kSpecialMenu],kSubscribeItem);
  1063.                 EnableItem(gTheMenu[kSpecialMenu],kReadItem);
  1064.                 EnableItem(gTheMenu[kEditMenu],kSearchItem);
  1065.             }
  1066.             break;
  1067.         case cUserGroup:
  1068.             if (actFlag) {
  1069.                 EnableItem(gTheMenu[kSpecialMenu],kNextItem);
  1070.                 EnableItem(gTheMenu[kFileMenu],kCloseItem);
  1071.                 EnableItem(gTheMenu[kFileMenu],kSaveItem);
  1072.                 EnableItem(gTheMenu[kFileMenu],kSaveAsItem);
  1073.                 EnableItem(gTheMenu[kSpecialMenu],kMarkReadItem);
  1074.                 EnableItem(gTheMenu[kSpecialMenu],kMarkUnreadItem);
  1075.                 EnableItem(gTheMenu[kNetMenu],kPutNetItem);
  1076.                 EnableItem(gTheMenu[kSpecialMenu],kUnsubscribeItem);
  1077.                 EnableItem(gTheMenu[kSpecialMenu],kReadItem);
  1078.                 EnableItem(gTheMenu[kEditMenu],kSearchItem);
  1079.             }
  1080.             break;
  1081.         case cSubject:
  1082.             if (actFlag) {
  1083.                 EnableItem(gTheMenu[kSpecialMenu],kMarkReadItem);
  1084.                 EnableItem(gTheMenu[kSpecialMenu],kMarkUnreadItem);
  1085.                 EnableItem(gTheMenu[kSpecialMenu],kReadItem);
  1086.             }
  1087.             else {
  1088.                 EnableItem(gTheMenu[kFileMenu],kSaveItem);
  1089.                 EnableItem(gTheMenu[kFileMenu],kSaveAsItem);
  1090.             }
  1091.             break;
  1092.         case cMessage:
  1093.             if (actFlag) {
  1094.                 EnableItem(gTheMenu[kEditMenu],kCopyItem);
  1095.                 EnableItem(gTheMenu[kEditMenu],kRotItem);
  1096.                 EnableItem(gTheMenu[kSpecialMenu],kFollowUpItem);
  1097.                 EnableItem(gTheMenu[kSpecialMenu],kRespondItem);
  1098.                 EnableItem(gTheMenu[kSpecialMenu],kViewRefItem);
  1099.                 EnableItem(gTheMenu[kFileMenu],kPrintItem);
  1100.             }
  1101.             else {
  1102.                 EnableItem(gTheMenu[kEditMenu],kSearchItem);
  1103.                 EnableItem(gTheMenu[kEditMenu],kNarrowItem);
  1104.             }
  1105.             break;
  1106.         case cMiscMessage:
  1107.             if (actFlag) {
  1108.                 EnableItem(gTheMenu[kEditMenu],kCopyItem);
  1109.                 EnableItem(gTheMenu[kFileMenu],kPrintItem);
  1110.                 EnableItem(gTheMenu[kEditMenu],kRotItem);
  1111.             }
  1112.             else {
  1113.                 EnableItem(gTheMenu[kSpecialMenu],kNextItem);
  1114.                 EnableItem(gTheMenu[kEditMenu],kSearchItem);
  1115.                 EnableItem(gTheMenu[kEditMenu],kNarrowItem);
  1116.             }
  1117.             break;
  1118.         case cSendMessage:
  1119.         case cPostMessage:
  1120.             if (actFlag) {
  1121.                 EnableItem(gTheMenu[kEditMenu],kCopyItem);
  1122.                 EnableItem(gTheMenu[kEditMenu],kCutItem);
  1123.                 EnableItem(gTheMenu[kEditMenu],kClearItem);
  1124.                 EnableItem(gTheMenu[kEditMenu],kPasteItem);
  1125.                 EnableItem(gTheMenu[kEditMenu],kRotItem);
  1126.                 EnableItem(gTheMenu[kSpecialMenu],kSendItem);
  1127.             }
  1128.             else {
  1129.                 EnableItem(gTheMenu[kEditMenu],kSearchItem);
  1130.                 EnableItem(gTheMenu[kEditMenu],kNarrowItem);
  1131.             }
  1132.             break;
  1133.     }
  1134. }
  1135.  
  1136.  
  1137. /*    DisableItems disables items which are appropriate to the window which
  1138.     is being enabled/disabled.
  1139. */
  1140.  
  1141. void DisableItems(short kind,Boolean actFlag)
  1142. {
  1143.     switch (kind) {
  1144.         case cGroup:
  1145.             if (actFlag) {
  1146.                 DisableItem(gTheMenu[kSpecialMenu],kNextItem);
  1147.                 DisableItem(gTheMenu[kFileMenu],kCloseItem);
  1148.                 DisableItem(gTheMenu[kFileMenu],kSaveItem);
  1149.                 DisableItem(gTheMenu[kFileMenu],kSaveAsItem);
  1150.             }
  1151.             else {
  1152.                 DisableItem(gTheMenu[kSpecialMenu],kSubscribeItem);
  1153.                 DisableItem(gTheMenu[kSpecialMenu],kReadItem);
  1154.                 DisableItem(gTheMenu[kEditMenu],kSearchItem);
  1155.             }
  1156.             break;
  1157.         case cNewGroup:
  1158.             if (actFlag) {
  1159.                 DisableItem(gTheMenu[kSpecialMenu],kNextItem);
  1160.                 DisableItem(gTheMenu[kFileMenu],kSaveItem);
  1161.                 DisableItem(gTheMenu[kFileMenu],kSaveAsItem);
  1162.             }
  1163.             else {
  1164.                 DisableItem(gTheMenu[kSpecialMenu],kSubscribeItem);
  1165.                 DisableItem(gTheMenu[kSpecialMenu],kReadItem);
  1166.                 DisableItem(gTheMenu[kEditMenu],kSearchItem);
  1167.             }
  1168.             break;
  1169.         case cUserGroup:
  1170.             if (!actFlag) {
  1171.                 DisableItem(gTheMenu[kSpecialMenu],kMarkReadItem);
  1172.                 DisableItem(gTheMenu[kSpecialMenu],kMarkUnreadItem);
  1173.                 DisableItem(gTheMenu[kNetMenu],kPutNetItem);
  1174.                 DisableItem(gTheMenu[kSpecialMenu],kUnsubscribeItem);
  1175.                 DisableItem(gTheMenu[kSpecialMenu],kReadItem);
  1176.                 DisableItem(gTheMenu[kEditMenu],kSearchItem);
  1177.             }
  1178.             break;
  1179.         case cSubject:
  1180.             if (!actFlag) {
  1181.                 DisableItem(gTheMenu[kSpecialMenu],kMarkReadItem);
  1182.                 DisableItem(gTheMenu[kSpecialMenu],kMarkUnreadItem);
  1183.                 DisableItem(gTheMenu[kSpecialMenu],kReadItem);
  1184.             }
  1185.             else {
  1186.                 DisableItem(gTheMenu[kFileMenu],kSaveItem);
  1187.                 DisableItem(gTheMenu[kFileMenu],kSaveAsItem);
  1188.             }
  1189.             break;
  1190.         case cMessage:
  1191.             if (!actFlag) {
  1192.                 DisableItem(gTheMenu[kEditMenu],kRotItem);
  1193.                 DisableItem(gTheMenu[kSpecialMenu],kFollowUpItem);
  1194.                 DisableItem(gTheMenu[kSpecialMenu],kRespondItem);
  1195.                 DisableItem(gTheMenu[kSpecialMenu],kViewRefItem);
  1196.                 DisableItem(gTheMenu[kFileMenu],kPrintItem);
  1197.             }
  1198.             else {
  1199.                 DisableItem(gTheMenu[kEditMenu],kSearchItem);
  1200.                 DisableItem(gTheMenu[kEditMenu],kNarrowItem);
  1201.             }
  1202.             break;
  1203.         case cMiscMessage:
  1204.             if (!actFlag) {
  1205.                 DisableItem(gTheMenu[kEditMenu],kRotItem);
  1206.                 DisableItem(gTheMenu[kEditMenu],kCopyItem);
  1207.                 DisableItem(gTheMenu[kFileMenu],kPrintItem);
  1208.             }
  1209.             else {
  1210.                 DisableItem(gTheMenu[kSpecialMenu],kNextItem);
  1211.                 DisableItem(gTheMenu[kEditMenu],kSearchItem);
  1212.                 DisableItem(gTheMenu[kEditMenu],kNarrowItem);
  1213.             }
  1214.             break;
  1215.         case cSendMessage:
  1216.         case cPostMessage:
  1217.             if (!actFlag) {
  1218.                 DisableItem(gTheMenu[kEditMenu],kCopyItem);
  1219.                 DisableItem(gTheMenu[kEditMenu],kCutItem);
  1220.                 DisableItem(gTheMenu[kEditMenu],kClearItem);
  1221.                 DisableItem(gTheMenu[kEditMenu],kPasteItem);
  1222.                 DisableItem(gTheMenu[kEditMenu],kRotItem);
  1223.                 DisableItem(gTheMenu[kSpecialMenu],kSendItem);
  1224.             }
  1225.             else {
  1226.                 DisableItem(gTheMenu[kEditMenu],kSearchItem);
  1227.                 DisableItem(gTheMenu[kEditMenu],kNarrowItem);
  1228.             }
  1229.             break;
  1230.     }
  1231. }
  1232.  
  1233.  
  1234. /*    ReadDeskScrap reads the clipboard into the TE scrap.
  1235. */
  1236.  
  1237. void ReadDeskScrap(void)
  1238. {
  1239.     long    scrapLength,ignore;
  1240.     OSErr    result;
  1241.     
  1242.     if (gScrapCompare != InfoScrap()->scrapCount) {
  1243.         if ((scrapLength = GetScrap(nil,'TEXT',&ignore))>0)
  1244.             if ((result = TEFromScrap()) != noErr)
  1245.                 scrapLength = result;
  1246.         if (scrapLength > 0)
  1247.             EnableItem(gTheMenu[kEditMenu],kPasteItem);
  1248.         else {
  1249.             TESetScrapLen(0);
  1250.             DisableItem(gTheMenu[kEditMenu],kPasteItem);
  1251.         }
  1252.         gScrapCompare = InfoScrap()->scrapCount;
  1253.     }
  1254. }
  1255.  
  1256.  
  1257. /*    WriteDeskScrap writes TE scrap to the clipboard
  1258. */
  1259.  
  1260. void WriteDeskScrap(void)
  1261. {
  1262.     OSErr    result;
  1263.     
  1264.     if (gScrapDirty) {
  1265.         gScrapCompare = ZeroScrap();
  1266.         result = TEToScrap();
  1267.         gScrapDirty = false;
  1268.     }
  1269. }
  1270.  
  1271.  
  1272.  
  1273. /* HandleUpdates: Handles update events */
  1274.  
  1275. void HandleUpdates(WindowPtr wind)
  1276. {
  1277.     GrafPtr savePort;
  1278.     
  1279.     GetPort(&savePort);
  1280.     SetPort(wind);
  1281.     BeginUpdate(wind);
  1282.     if (!IsMovableModal(wind)) {
  1283.         EraseRect(&wind->portRect);
  1284.         DrawMainWindow(wind);
  1285.     }
  1286.     else
  1287.         UpdateStatus();
  1288.     EndUpdate(wind);
  1289.     SetPort(savePort);
  1290. }
  1291.  
  1292.  
  1293. /* HandleMouseDown: Handles mouse down events */
  1294.  
  1295. void HandleMouseDowns(EventRecord *ev)
  1296. {
  1297.     WindowPtr theWindow;
  1298.     short part;
  1299.     
  1300.     part = FindWindow(ev->where,&theWindow);
  1301.     
  1302.     if (!(IsMovableModal(FrontWindow()) && !IsMovableModal(theWindow)))
  1303.         switch (part) {
  1304.             case inMenuBar:
  1305.                 if (!IsMovableModal(FrontWindow()))
  1306.                     DoCommand(MenuSelect(ev->where));
  1307.                 break;
  1308.             case inSysWindow:
  1309.                 SystemClick(ev,theWindow);
  1310.                 break;
  1311.             case inDrag:
  1312.                 DoDrag(theWindow,ev->where);
  1313.                 break;
  1314.             case inGrow:
  1315.                 DoGrow(theWindow,ev->where);
  1316.                 break;
  1317.             case inGoAway:
  1318.                 if (TrackGoAway(theWindow,ev->where)) {
  1319.                     DoCloseWindow(FrontWindow());
  1320.                 }
  1321.                 break;
  1322.             case inZoomIn:
  1323.             case inZoomOut:
  1324.                 if (TrackBox(theWindow,ev->where,FindWindow(ev->where,&theWindow)))
  1325.                     DoZoom(theWindow,FindWindow(ev->where,&theWindow));
  1326.                 break;
  1327.             case inContent:
  1328.                 HandleContent(theWindow,ev);
  1329.                 break;
  1330.         }
  1331. }
  1332.  
  1333.  
  1334. /* DoDrag: Handles drag window events */
  1335.  
  1336. void DoDrag(WindowPtr window,Point globMouse)
  1337. {
  1338.     if (window != FrontWindow())
  1339.         SelectWindow(window);
  1340.  
  1341.     DragWindow(window,globMouse,&gDragRect);
  1342.     SetPort(window);
  1343. }
  1344.  
  1345.  
  1346. /* DoGrow: Handles grow window events */
  1347.  
  1348. void DoGrow(WindowPtr window,Point globMouse)
  1349. {
  1350.     long        newSize;
  1351.     Rect        tmpRect;
  1352.     GrafPtr        tempPort;
  1353.     
  1354.     if ((newSize = GrowWindow(window,globMouse,&gWindLimits)) != 0) {
  1355.         GetPort(&tempPort);
  1356.         SetPort(window);
  1357.         SetRect(&tmpRect,window->portRect.right-15-kTextMargin,window->portRect.top,
  1358.                     window->portRect.right,window->portRect.bottom);
  1359.         InvalRect(&tmpRect);
  1360.         SetRect(&tmpRect,window->portRect.left,window->portRect.bottom-15-kTextMargin,
  1361.                     window->portRect.right-16,window->portRect.bottom);
  1362.         InvalRect(&tmpRect);
  1363.         
  1364.         SizeWindow(window,LoWord(newSize),HiWord(newSize),true);
  1365.         SizeContents(LoWord(newSize),HiWord(newSize),window);
  1366.         
  1367.         SetRect(&tmpRect,window->portRect.right-15,window->portRect.top,
  1368.                     window->portRect.right,window->portRect.bottom);
  1369.         InvalRect(&tmpRect);
  1370.         SetRect(&tmpRect,window->portRect.left,window->portRect.bottom-15,
  1371.                     window->portRect.right-15,window->portRect.bottom);
  1372.         InvalRect(&tmpRect);
  1373.         
  1374.         SetPort(tempPort);
  1375.     }
  1376. }
  1377.  
  1378.  
  1379. /*    Re-sizes the window's contents, handling all types of windows
  1380. */
  1381.  
  1382. void SizeContents(short width,short height,WindowPtr wind)
  1383. {
  1384.     TwindowInfo *theInfo;
  1385.     TEHandle    theTE;
  1386.     Rect        tmpRect;
  1387.     short        lineHeight;
  1388.     Point        tmpPt;
  1389.     
  1390.     theInfo = (TwindowInfo *) GetWRefCon(wind);
  1391.  
  1392.     switch (theInfo->kind) {
  1393.         case cGroup:
  1394.         case cNewGroup:
  1395.         case cUserGroup:
  1396.         case cSubject:
  1397.             LSize(width-15,height-15,(ListHandle)theInfo->data);
  1398.             SetPt(&tmpPt,0,0);
  1399.             LRect(&tmpRect,tmpPt,(ListHandle)theInfo->data);
  1400.             SetPt(&tmpPt,width-15,tmpRect.bottom-tmpRect.top);
  1401.             LCellSize(tmpPt,(ListHandle)theInfo->data);
  1402.             InvalRect(&wind->portRect);
  1403.             break;
  1404.         case cMessage:
  1405.         case cMiscMessage:
  1406.         case cPostMessage:
  1407.         case cSendMessage:
  1408.             theTE = (TEHandle)(theInfo->data);
  1409.             if ((**theTE).viewRect.bottom < (wind->portRect.bottom - 15)) {
  1410.                 tmpRect = (**theTE).viewRect;
  1411.                 tmpRect.top = tmpRect.bottom;
  1412.                 tmpRect.bottom = wind->portRect.bottom - 15;
  1413.                 InvalRect(&tmpRect);
  1414.                 
  1415.             }
  1416.             lineHeight = (**theTE).lineHeight;
  1417.             tmpRect = wind->portRect;
  1418.             SetRect(&tmpRect,wind->portRect.left,wind->portRect.top,
  1419.                     wind->portRect.right-15,wind->portRect.bottom-15);
  1420.             tmpRect.top = (((tmpRect.bottom - tmpRect.top) / 
  1421.                     lineHeight) * lineHeight) + tmpRect.top - lineHeight - kTextMargin;
  1422.             InvalRect(&tmpRect);
  1423.             
  1424.             RedoControls(wind);
  1425.             FixText(wind);
  1426.             InvalRect(&wind->portRect);
  1427.             break;
  1428.     }
  1429. }
  1430.  
  1431.  
  1432. /*    ToggleZoom toggles the window zoomed state of the active window.
  1433.     The window will only be grown as big as it needs to be to contain
  1434.     all of the data.  Also, whichever monitor contains the majority of
  1435.     the window will be the destination for the window.
  1436. */
  1437.  
  1438. void ToggleZoom(WindowPtr theWindow)
  1439. {
  1440.     WStateData **stateHndl;
  1441.     Rect windRect;
  1442.     Point locToGlobPt;
  1443.     GrafPtr savePort;
  1444.     
  1445.     if (!IsAppWindow(theWindow))
  1446.         return;
  1447.     
  1448.     /* get frontwindow rect in global coords */
  1449.     
  1450.     GetPort(&savePort);
  1451.     SetPort(theWindow);
  1452.     windRect = theWindow->portRect;
  1453.     SetPt(&locToGlobPt,windRect.left,windRect.top);
  1454.     LocalToGlobal(&locToGlobPt);
  1455.     windRect.left = locToGlobPt.h;
  1456.     windRect.top = locToGlobPt.v;
  1457.     SetPt(&locToGlobPt,windRect.right,windRect.bottom);
  1458.     LocalToGlobal(&locToGlobPt);
  1459.     windRect.right = locToGlobPt.h;
  1460.     windRect.bottom = locToGlobPt.v;
  1461.     SetPort(savePort);
  1462.     stateHndl = (WStateData **) ((WindowPeek)theWindow)->dataHandle;
  1463.  
  1464.     if (EqualRect(&(**stateHndl).userState,&windRect))
  1465.         DoZoom(theWindow,inZoomOut);
  1466.     else
  1467.         DoZoom(theWindow,inZoomIn);
  1468. }
  1469.  
  1470.  
  1471. /* DoZoom: Handles zoom-window events -- from Apple Technical Note #??? */
  1472.  
  1473. void DoZoom(WindowPtr theWindow,short zoomDir)
  1474. {
  1475.     Rect windRect, theSect, zoomRect, tmpRect;
  1476.     GDHandle nthDevice,dominantGDevice;
  1477.     long sectArea,greatestArea;
  1478.     short bias;
  1479.     Boolean sectFlag;
  1480.     GrafPtr savePort;
  1481.     Point locToGlobPt;
  1482.     WStateData **stateHndl;
  1483.     Rect stdRect,userRect;
  1484.     
  1485.     GetPort(&savePort);
  1486.     SetPort(theWindow);
  1487.     EraseRect(&theWindow->portRect);
  1488.     
  1489.     stateHndl = (WStateData **) ((WindowPeek)theWindow)->dataHandle;
  1490.     
  1491.     if (zoomDir == inZoomOut && gHasColorQD) {
  1492.         windRect = theWindow->portRect;
  1493.         SetPt(&locToGlobPt,windRect.left,windRect.top);
  1494.         LocalToGlobal(&locToGlobPt);
  1495.         windRect.left = locToGlobPt.h;
  1496.         windRect.top = locToGlobPt.v;
  1497.         SetPt(&locToGlobPt,windRect.right,windRect.bottom);
  1498.         LocalToGlobal(&locToGlobPt);
  1499.         windRect.right = locToGlobPt.h;
  1500.         windRect.bottom = locToGlobPt.v;
  1501.         
  1502.         /* calc height of title bar */
  1503.         
  1504.         bias = windRect.top - 23;
  1505.         windRect.top -= bias;
  1506.         
  1507.         nthDevice = GetDeviceList();
  1508.         dominantGDevice = 0;
  1509.         greatestArea = 0;
  1510.         while (nthDevice != nil)
  1511.             if (TestDeviceAttribute(nthDevice,screenDevice) &&
  1512.                 TestDeviceAttribute(nthDevice,screenActive)) {
  1513.                     sectFlag = SectRect(&windRect,&((**nthDevice).gdRect),&theSect);
  1514.                     sectArea = (long)(theSect.right - theSect.left) * (long)(theSect.bottom - theSect.top);
  1515.                     if (sectArea > greatestArea) {
  1516.                         greatestArea = sectArea;
  1517.                         dominantGDevice = nthDevice;
  1518.                     }
  1519.                     nthDevice = GetNextDevice(nthDevice);
  1520.             }
  1521.         
  1522.         if (dominantGDevice == GetMainDevice())
  1523.             bias += GetMBarHeight();
  1524.         
  1525.         if (dominantGDevice)
  1526.             tmpRect = (**dominantGDevice).gdRect;
  1527.         else
  1528.             tmpRect = desktopExtent;
  1529.             
  1530.         SetRect(&zoomRect,tmpRect.left+3,tmpRect.top+bias+3,tmpRect.right-3,tmpRect.bottom-3);
  1531.         
  1532.         (**stateHndl).stdState = zoomRect;
  1533.     }
  1534.     
  1535.     stdRect = (**stateHndl).stdState;
  1536.     userRect = (**stateHndl).userState;
  1537.     CalcZoom(theWindow,&stdRect,&userRect);
  1538.     (**stateHndl).stdState = stdRect;
  1539.     (**stateHndl).userState = userRect;
  1540.     
  1541.     ZoomWindow(theWindow,zoomDir,true);
  1542.  
  1543.     InvalRect(&theWindow->portRect);
  1544.     SizeContents(theWindow->portRect.right-theWindow->portRect.left,theWindow->portRect.bottom-theWindow->portRect.top,theWindow);
  1545.     SetRect(&tmpRect,theWindow->portRect.left,theWindow->portRect.bottom-16,
  1546.                 theWindow->portRect.right,theWindow->portRect.bottom);
  1547.     InvalRect(&tmpRect);
  1548.     
  1549.     SetPort(savePort);
  1550. }
  1551.  
  1552.  
  1553. /*    CalcZoom Calculates the maximum needed size for the window.
  1554. */
  1555.  
  1556. void CalcZoom(WindowPtr window,Rect *zoomRect,Rect *userRect)
  1557. {
  1558.     TwindowInfo *info;
  1559.     ListHandle theList;
  1560.     TEHandle theTE;
  1561.     long width,height,tmpWidth;
  1562.     Rect finalRect;
  1563.     short i;
  1564.     short offset,length;
  1565.     Cell theCell;
  1566.     
  1567.     info = (TwindowInfo *)GetWRefCon(window);
  1568.     finalRect = *zoomRect;
  1569.     
  1570.     switch (info->kind) {
  1571.         case cGroup:
  1572.         case cNewGroup:
  1573.         case cUserGroup:
  1574.         case cSubject:
  1575.             theList = (ListHandle) ((TwindowInfo *)GetWRefCon(window))->data;
  1576.             height = 20 + ((**theList).dataBounds.bottom - (**theList).dataBounds.top) * (**theList).cellSize.v;
  1577.             SetPt(&theCell,0,0);
  1578.             HLock((Handle)(**theList).cells);
  1579.             (**theList).port->txFace = bold;
  1580.             for (width=0,theCell.v=(**theList).dataBounds.top; theCell.v< (**theList).dataBounds.bottom; theCell.v++) {
  1581.                 LFind(&offset,&length,theCell,theList);
  1582.                 tmpWidth = TextWidth((Ptr)*((**theList).cells),offset,length);
  1583.                 if (tmpWidth > width)
  1584.                     width = tmpWidth;
  1585.             }
  1586.             width += 25;
  1587.             HUnlock((Handle)(**theList).cells);        
  1588.             break;
  1589.         case cMessage:
  1590.         case cMiscMessage:
  1591.         case cSendMessage:
  1592.         case cPostMessage:
  1593.             theTE = (TEHandle) ((TwindowInfo *)GetWRefCon(window))->data;
  1594.             height = 36 + (**theTE).nLines * (**theTE).lineHeight;
  1595.             HLock((Handle)(**theTE).hText);
  1596.             for (width=0,i=0; i<((**theTE).nLines-1); i++) {
  1597.                 tmpWidth = TextWidth((Ptr)(*(**theTE).hText)+(**theTE).lineStarts[i],0,(**theTE).lineStarts[i+1] - (**theTE).lineStarts[i]);
  1598.                 if ( tmpWidth > width )
  1599.                     width = tmpWidth;
  1600.             }
  1601.             HUnlock((Handle)(**theTE).hText);
  1602.             width += (2*kTextMargin) + 18;
  1603.             break;
  1604.     }
  1605.     
  1606.     if (height < 64)
  1607.         height = 64;
  1608.     if (width < 64)
  1609.         width = 64;
  1610.         
  1611.     if ( (finalRect.right-finalRect.left) > width ) {
  1612.         finalRect.right = userRect->left+width;
  1613.         finalRect.left = userRect->left;
  1614.     }
  1615.     if ( (finalRect.bottom-finalRect.top) > height ) {
  1616.         finalRect.bottom = userRect->top+height;
  1617.         finalRect.top = userRect->top;
  1618.     }
  1619.     if (finalRect.bottom > zoomRect->bottom) {
  1620.         OffsetRect(&finalRect,0,-(finalRect.bottom-zoomRect->bottom));
  1621.     }
  1622.     if (finalRect.right > zoomRect->right) {
  1623.         OffsetRect(&finalRect,-(finalRect.right-zoomRect->right),0);
  1624.     }
  1625.     if (finalRect.top < zoomRect->top) {
  1626.         OffsetRect(&finalRect,0,zoomRect->top - finalRect.top);
  1627.         if (finalRect.bottom > zoomRect->bottom)
  1628.             finalRect.bottom = zoomRect->bottom;
  1629.     }
  1630.     if (finalRect.left < zoomRect->left) {
  1631.         OffsetRect(&finalRect,zoomRect->left - finalRect.left,0);
  1632.         if (finalRect.right > zoomRect->right)
  1633.             finalRect.right = zoomRect->right;
  1634.     }
  1635.     *zoomRect = finalRect;
  1636. }
  1637.  
  1638.  
  1639.  
  1640. /* HandleKeyDowns: handles keypress events */
  1641.  
  1642. void HandleKeyDowns(EventRecord *ev)
  1643. {
  1644.     short theChar;
  1645.     WindowPtr theWindow;
  1646.     
  1647.     theWindow = FrontWindow();
  1648.     
  1649.     theChar = ev->message & charCodeMask;
  1650.     if ((ev->modifiers & cmdKey) != 0)
  1651.         DoCommand(MenuKey(theChar));
  1652.     else if (IsAppWindow(theWindow))
  1653.         switch (((TwindowInfo *)GetWRefCon(theWindow))->kind) {
  1654.             case cGroup:
  1655.             case cNewGroup:
  1656.             case cUserGroup:
  1657.             case cSubject:
  1658.                 HandleListKey(theChar);
  1659.                 break;
  1660.             case cMessage:
  1661.             case cMiscMessage:
  1662.                 if (theChar >= 0x1C && theChar <= 0x1F) {
  1663.                     TEKey(theChar,(TEHandle)((TwindowInfo *)GetWRefCon(theWindow))->data);
  1664.                     CheckInsertion(theWindow);
  1665.                 }
  1666.                 break;
  1667.             case cPostMessage:
  1668.             case cSendMessage:
  1669.                 TEKey(theChar,(TEHandle)((TwindowInfo *)GetWRefCon(theWindow))->data);
  1670.                 AdjustScrollBar(theWindow);
  1671.                 CheckInsertion(theWindow);
  1672.                 break;
  1673.             default:
  1674.                 SysBeep(1);
  1675.                 break;
  1676.         }
  1677.  
  1678. }
  1679.  
  1680.  
  1681. /*    HandleListKey handles keydown events in list manager windows.  The
  1682.     current selection is changed to one matching the typed substring
  1683. */
  1684.  
  1685. void HandleListKey(char theChar)
  1686. {
  1687.     ListHandle theList;
  1688.     static long lastDown = 0;
  1689.     static short numChars = 0;
  1690.     static char searchStr[256];
  1691.     Cell theCell,tmpCell;
  1692.     
  1693.     theList = (ListHandle) ((TwindowInfo *)GetWRefCon(FrontWindow()))->data;
  1694.  
  1695.     switch (theChar) {
  1696.         case CR:
  1697.             ReadMessage(FrontWindow());
  1698.             return;
  1699.         case 0x1C:
  1700.         case 0x1E:
  1701.             SetPt(&tmpCell,0,0);
  1702.             while (LGetSelect(true,&tmpCell,theList)) {
  1703.                 LSetSelect(false,tmpCell,theList);
  1704.                 tmpCell.v++;
  1705.             }
  1706.             if (tmpCell.v > 1)
  1707.                 tmpCell.v -= 2;
  1708.             else
  1709.                 tmpCell.v--;
  1710.             LSetSelect(true,tmpCell,theList);
  1711.             LAutoScroll(theList);
  1712.             break;
  1713.         case 0x1D:
  1714.         case 0x1F:
  1715.             SetPt(&tmpCell,0,0);
  1716.             while (LGetSelect(true,&tmpCell,theList)) {
  1717.                 LSetSelect(false,tmpCell,theList);
  1718.                 tmpCell.v++;
  1719.             }
  1720.             if (tmpCell.v >= (**theList).dataBounds.bottom)
  1721.                 tmpCell.v--;
  1722.             LSetSelect(true,tmpCell,theList);
  1723.             LAutoScroll(theList);
  1724.             break;
  1725.         default:
  1726.             SetPt(&theCell,0,0);
  1727.             if ((TickCount()-lastDown) > (2*GetDblTime()))
  1728.                 numChars = 0;
  1729.             lastDown = TickCount();
  1730.             searchStr[numChars++] = theChar;
  1731.             
  1732.             if (LSearch(searchStr,numChars,CompareStart,&theCell,theList)) {
  1733.                 SetPt(&tmpCell,0,0);
  1734.                 while (LGetSelect(true,&tmpCell,theList)) {
  1735.                     LSetSelect(false,tmpCell,theList);
  1736.                     tmpCell.v++;
  1737.                 }
  1738.                 LSetSelect(true,theCell,theList);
  1739.                 LAutoScroll(theList);
  1740.             }
  1741.             break;
  1742.     }
  1743. }
  1744.  
  1745.  
  1746. /* DoCommand: Process pull-down menu requests */
  1747.  
  1748. void DoCommand(long mResult)
  1749. {
  1750.     int        selItem,selMenu,temp;
  1751.     Str255    name;
  1752.     GrafPtr    tempPort;
  1753.     WindowPtr theWindow;
  1754.     
  1755.     theWindow = FrontWindow();
  1756.     
  1757.     if (IsMovableModal(theWindow))
  1758.         return;
  1759.         
  1760.     selItem = LoWord(mResult);
  1761.     selMenu = HiWord(mResult);
  1762.     switch (selMenu) {
  1763.         case kAppleMenu+kMenuOffset:
  1764.             if (selItem>2) {
  1765.                 GetPort(&tempPort);
  1766.                 SetCursor(&QDARROW);
  1767.                 GetItem(gTheMenu[kAppleMenu],selItem,&name);
  1768.                 temp = OpenDeskAcc(&name);
  1769.                 SetPort(tempPort);
  1770.             }
  1771.             else ShowAbout();
  1772.             break;
  1773.             
  1774.         case kFileMenu+kMenuOffset:
  1775.             switch (selItem) {
  1776.                 case kNewItem:
  1777.                     NewGroupWindow("\pUntitled Groups");
  1778.                     break;
  1779.                 case kCloseItem:
  1780.                     if (theWindow)
  1781.                         DoCloseWindow(theWindow);
  1782.                     break;
  1783.                 case kOpenItem:
  1784.                     DoOpenFile();
  1785.                     break;
  1786.                 case kSaveItem:
  1787.                     if (theWindow)
  1788.                         switch (((TwindowInfo *)GetWRefCon(theWindow))->kind) {
  1789.                             case cMessage:
  1790.                             case cMiscMessage:
  1791.                                 DoSaveMessage((TwindowInfo *)GetWRefCon(theWindow));
  1792.                                 break;
  1793.                             case cPostMessage:
  1794.                             case cSendMessage:
  1795.                                 DoSaveWindow(theWindow);
  1796.                                 break;
  1797.                             default:
  1798.                                 DoSaveFile(theWindow);
  1799.                                 break;
  1800.                         }
  1801.                     break;
  1802.                 case kSaveAsItem:
  1803.                     if (theWindow)
  1804.                         switch (((TwindowInfo *)GetWRefCon(theWindow))->kind) {
  1805.                             case cMessage:
  1806.                             case cMiscMessage:
  1807.                                 DoSaveMessage((TwindowInfo *)GetWRefCon(theWindow));
  1808.                                 break;
  1809.                             case cPostMessage:
  1810.                             case cSendMessage:
  1811.                                 DoSaveWindow(theWindow);
  1812.                                 break;
  1813.                             default:
  1814.                                 DoSaveAsFile(theWindow);
  1815.                                 break;
  1816.                         }
  1817.                     break;
  1818.                 case kPageSetupItem:
  1819.                     DoPageSetup();
  1820.                     break;
  1821.                 case kPrintItem:
  1822.                     DoPrint();
  1823.                     break;
  1824.                 case kPrefItem:
  1825.                     SetPrefs(&gPrefs);
  1826.                     break;
  1827.                 case kQuitItem:
  1828.                     if (DoQuitStuff())
  1829.                         gDone = true;
  1830.                     break;
  1831.             }
  1832.             break;
  1833.             
  1834.         case kEditMenu+kMenuOffset:
  1835.             if (!(SystemEdit(selItem-1)))
  1836.                 switch (selItem) {
  1837.                     case kUndoItem:
  1838.                         break;
  1839.                     case kCutItem:
  1840.                         if (IsAppWindow(theWindow))
  1841.                             switch (((TwindowInfo *)GetWRefCon(theWindow))->kind) {
  1842.                                 case cPostMessage:
  1843.                                 case cSendMessage:
  1844.                                     TECut(gFrontTE);
  1845.                                     AdjustScrollBar(theWindow);
  1846.                                     CheckInsertion(theWindow);
  1847.                                     gScrapDirty = true;
  1848.                                     break;
  1849.                             }
  1850.                         break;
  1851.                     case kClearItem:
  1852.                         if (IsAppWindow(theWindow))
  1853.                             switch (((TwindowInfo *)GetWRefCon(theWindow))->kind) {
  1854.                                 case cPostMessage:
  1855.                                 case cSendMessage:
  1856.                                     TEDelete(gFrontTE);
  1857.                                     AdjustScrollBar(theWindow);
  1858.                                     CheckInsertion(theWindow);
  1859.                                     break;
  1860.                             }
  1861.                         break;
  1862.                     case kPasteItem:
  1863.                         if (IsAppWindow(theWindow))
  1864.                             switch (((TwindowInfo *)GetWRefCon(theWindow))->kind) {
  1865.                                 case cPostMessage:
  1866.                                 case cSendMessage:
  1867.                                     TEPaste(gFrontTE);
  1868.                                     AdjustScrollBar(theWindow);
  1869.                                     CheckInsertion(theWindow);
  1870.                                     break;
  1871.                             }
  1872.                         break;
  1873.                     case kCopyItem:
  1874.                         if (gFrontTE) {
  1875.                             TECopy(gFrontTE);
  1876.                             gScrapDirty = true;
  1877.                             EnableItem(gTheMenu[kEditMenu],kPasteItem);
  1878.                         }
  1879.                         break;
  1880.                     case kRotItem:
  1881.                         DoRot();
  1882.                         break;
  1883.                     case kNarrowItem:
  1884.                         DoNarrowSelection();
  1885.                         break;
  1886.                     case kSearchItem:
  1887.                         DoSearch();
  1888.                         break;
  1889.                     case kSelectAllItem:
  1890.                         DoSelectAll();
  1891.                         break;
  1892.                 }
  1893.             break;
  1894.             
  1895.         case kSpecialMenu+kMenuOffset:
  1896.             switch (selItem) {
  1897.                 case kMarkReadItem:
  1898.                 case kMarkUnreadItem:
  1899.                     if (theWindow)
  1900.                         switch (((TwindowInfo *)GetWRefCon(theWindow))->kind) {
  1901.                             case cSubject:
  1902.                                 DoMarkArticleRead((selItem == kMarkReadItem));
  1903.                                 break;
  1904.                             case cUserGroup:
  1905.                                 DoMarkGroupRead((selItem == kMarkReadItem));
  1906.                                 break;
  1907.                         }
  1908.                     break;
  1909.                 case kReadItem:
  1910.                     ReadMessage(theWindow);
  1911.                     break;
  1912.                 case kNextItem:
  1913.                     DoNextMessage();
  1914.                     break;
  1915.                 case kViewRefItem:
  1916.                     OpenReferences();
  1917.                     break;
  1918.                 case kSendItem:
  1919.                     if (theWindow && DoSendMsg((TwindowInfo *)GetWRefCon(theWindow)))
  1920.                         DoCloseWindow(theWindow);
  1921.                     break;
  1922.                 case kFollowUpItem:
  1923.                     MakeFollowUp();
  1924.                     break;
  1925.                 case kRespondItem:
  1926.                     MakeRespond();
  1927.                     break;
  1928.                 case kPostItem:
  1929.                     MakePost();
  1930.                     break;
  1931.                 case kSubscribeItem:
  1932.                     HandleSubscribe();
  1933.                     break;
  1934.                 case kUnsubscribeItem:
  1935.                     HandleUnsubscribe();
  1936.                     break;
  1937.             }
  1938.             break;
  1939.             
  1940.         case kNetMenu+kMenuOffset:
  1941.             switch (selItem) {
  1942.                 case kGetNetItem:
  1943.                     GetFromNet();
  1944.                     break;
  1945.                 case kPutNetItem:
  1946.                     SendToNet();
  1947.                     break;
  1948.                 case kSetNNTPItem:
  1949.                     ChangeServerAddress(true);
  1950.                     break;
  1951.                 case kSetSMTPItem:
  1952.                     ChangeServerAddress(false);
  1953.                     break;
  1954.             }
  1955.             break;
  1956.             
  1957.         case kFontMenu+kMenuOffset:
  1958.             ChangeFont(selItem);
  1959.             break;
  1960.             
  1961.         case kSizeMenu+kMenuOffset:
  1962.             ChangeSize(selItem);
  1963.             break;
  1964.             
  1965.         case kWindowsMenu+kMenuOffset:
  1966.             switch (selItem) {
  1967.                 case kHideShowWind:
  1968.                     HideShowGroups();
  1969.                     break;
  1970.                 case kSendToBack:
  1971.                     if (IsAppWindow(theWindow))
  1972.                         SendBehind(theWindow,nil);
  1973.                     break;
  1974.                 case kZoomWindow:
  1975.                     if (theWindow)
  1976.                         ToggleZoom(theWindow);
  1977.                     break;
  1978.                 default:
  1979.                     SelectWindowsMenu(selItem);
  1980.                     break;
  1981.             }
  1982.      }
  1983.     HiliteMenu(0);
  1984. }
  1985.  
  1986.  
  1987. /* HandleContent: Handles mouse-downs within content of window */
  1988.  
  1989. void HandleContent(WindowPtr theWindow,EventRecord *ev)
  1990. {
  1991.     GrafPtr savePort;
  1992.     TwindowInfo *theInfo;
  1993.     short part;
  1994.     Boolean extendClick;
  1995.     TEHandle theTE;
  1996.     ControlHandle control;
  1997.     Cell theCell;
  1998.     
  1999.     if (IsMovableModal(FrontWindow()))
  2000.         return;
  2001.         
  2002.     if (theWindow != FrontWindow()) {
  2003.         SelectWindow(theWindow);
  2004.         return;
  2005.     }
  2006.     
  2007.     GetPort(&savePort);
  2008.     SetPort(theWindow);
  2009.     GlobalToLocal(&ev->where);
  2010.  
  2011.     theInfo = (TwindowInfo *) GetWRefCon(theWindow);
  2012.     
  2013.     switch (theInfo->kind) {
  2014.         case cGroup:
  2015.         case cNewGroup:
  2016.             if (LClick(ev->where,ev->modifiers,(ListHandle)theInfo->data)) {
  2017.                 SetPt(&theCell,0,0);
  2018.                 while (LGetSelect(true,&theCell,(ListHandle)theInfo->data)) {
  2019.                 HandleGroupSelect(theCell,theWindow);
  2020.                     theCell.v++;
  2021.                 }
  2022.             }
  2023.             break;
  2024.         case cUserGroup:
  2025.             if (LClick(ev->where,ev->modifiers,(ListHandle)theInfo->data)) {
  2026.                 SetPt(&theCell,0,0);
  2027.                 while (LGetSelect(true,&theCell,(ListHandle)theInfo->data)) {
  2028.                     HandleUserGroupSelect(theCell,theWindow);
  2029.                     theCell.v++;
  2030.                 }
  2031.             }
  2032.             break;
  2033.         case cSubject:
  2034.             if (LClick(ev->where,ev->modifiers,(ListHandle)theInfo->data)) {
  2035.                 SetPt(&theCell,0,0);
  2036.                 while (LGetSelect(true,&theCell,(ListHandle)theInfo->data)) {
  2037.                     HandleSubjectSelect(theCell,theWindow);
  2038.                     theCell.v++;
  2039.                 }
  2040.             }
  2041.             break;
  2042.         case cMessage:
  2043.         case cMiscMessage:
  2044.         case cPostMessage:
  2045.         case cSendMessage:
  2046.             theTE = (TEHandle)((TwindowInfo *)GetWRefCon(theWindow))->data;
  2047.             if ((part = FindControl(ev->where,theWindow,&control)) != 0)
  2048.                 DoScrollers(control,part,ev->where);
  2049.             else {
  2050.                 if (PtInRect(ev->where,&((**theTE).viewRect))) {
  2051.                     extendClick = ((ev->modifiers & shiftKey) != 0);
  2052.                     TEClick(ev->where,extendClick,theTE);
  2053.                 }
  2054.             }
  2055.             break;
  2056.     }
  2057.     gClicked = false;
  2058.     SetPort(savePort);
  2059. }
  2060.  
  2061.  
  2062. /*    DrawMainWindow is called to re-draw window contents in response
  2063.     to update events.
  2064. */
  2065.  
  2066. void DrawMainWindow(WindowPtr wind)
  2067. {
  2068.     TwindowInfo *theInfo;
  2069.     
  2070.     DrawGrowIcon(wind);
  2071.     theInfo = (TwindowInfo *) GetWRefCon(wind);    
  2072.     switch (theInfo->kind) {
  2073.         case cGroup:
  2074.         case cNewGroup:
  2075.         case cUserGroup:
  2076.         case cSubject:
  2077.             LUpdate(wind->visRgn,(ListHandle)theInfo->data);
  2078.             break;
  2079.         case cMessage:
  2080.         case cMiscMessage:
  2081.         case cPostMessage:
  2082.         case cSendMessage:
  2083.             UpdtControl(wind,wind->visRgn);
  2084.             TEUpdate(&wind->portRect,(TEHandle)theInfo->data);
  2085.             break;
  2086.     }
  2087. }
  2088.  
  2089.  
  2090. /*    RedoControls is called when a window is re-sized and the controls
  2091.     for the window need to be moved/resized
  2092. */
  2093.  
  2094. void RedoControls(WindowPtr window)
  2095. {    
  2096.     HideControl(vScrollCont(window));
  2097.     HideControl(vScrollCont(window));
  2098.     MoveControl(vScrollCont(window),window->portRect.right-15,window->portRect.top-1);
  2099.     SizeControl(vScrollCont(window),16,window->portRect.bottom - window->portRect.top - 13);
  2100.     MoveControl(hScrollCont(window),window->portRect.left-1,window->portRect.bottom-15);
  2101.     SizeControl(hScrollCont(window),window->portRect.right - window->portRect.left - 13,16);
  2102.     ShowControl(vScrollCont(window));
  2103.     ShowControl(hScrollCont(window));
  2104. }
  2105.  
  2106.  
  2107. /*    FixText is called when a textedit window has been re-sized and the text
  2108.     needs to be re-flowed.
  2109. */
  2110.  
  2111. void FixText(WindowPtr window)
  2112. {    
  2113.     short        controlLine,charPos;
  2114.     Rect        viewRect;
  2115.     short        lineHeight;
  2116.     TEHandle    theTE;
  2117.     
  2118.     theTE = (TEHandle)(((TwindowInfo *)GetWRefCon(window))->data);
  2119.  
  2120.     lineHeight = (**theTE).lineHeight;
  2121.     viewRect = window->portRect;
  2122.     viewRect.top = viewRect.top;
  2123.     viewRect.right = viewRect.right - 15;
  2124.     viewRect.bottom = viewRect.bottom - 15;
  2125.     InsetRect(&viewRect,kTextMargin,kTextMargin);
  2126.     viewRect.bottom = (((viewRect.bottom - viewRect.top) / 
  2127.                     lineHeight) * lineHeight) + viewRect.top;
  2128.     (**theTE).destRect = viewRect;
  2129.     (**theTE).viewRect = viewRect;
  2130.     TECalText(theTE);
  2131.     controlLine = GetCtlValue(vScrollCont(window));
  2132.     charPos = (**theTE).lineStarts[controlLine];
  2133.     AdjustScrollBar(window);
  2134.     ScrollChar(window,charPos,false);
  2135. }
  2136.  
  2137.  
  2138. /* DoStartUp: processes start-up events (printing/opening) */
  2139.  
  2140. Boolean DoStartUp(void)
  2141. {
  2142.     short theMessage,nDocs,thisDoc;
  2143.     AppFile    docInfo;
  2144.     Boolean    result;
  2145.     
  2146.     CountAppFiles(&theMessage,&nDocs);
  2147.     if (nDocs != 0) {
  2148.         for (thisDoc=1; thisDoc<=nDocs; thisDoc++) {
  2149.             GetAppFiles(thisDoc,&docInfo);
  2150.             if (docInfo.fType=='NEWS') {
  2151.                 if (result = LoOpenFile(docInfo.fName,docInfo.vRefNum))
  2152.                     return true;
  2153.  
  2154.                 ClrAppFiles(thisDoc);
  2155.                 if (theMessage == appPrint) {
  2156.                     gDone = true;
  2157.                     return false;
  2158.                 }
  2159.             }
  2160.             else {
  2161.                 SysBeep(1);
  2162.                 return false;
  2163.             }
  2164.         }
  2165.         return true;
  2166.     }
  2167.     else return false;
  2168. }
  2169.  
  2170.  
  2171. /*    DoQuitStuff handles events prior to the quitting of the application.
  2172.     All windows must be closed, and the scrap must be written.
  2173. */
  2174.  
  2175. Boolean DoQuitStuff(void)
  2176. {
  2177.     WindowPtr curWindow,tmpWindow;
  2178.     Boolean stillQuit = true;
  2179.     
  2180.     curWindow = FrontWindow();
  2181.     while (curWindow!=nil && stillQuit) {
  2182.         while (curWindow && !(IsAppWindow(curWindow)))
  2183.             curWindow = (WindowPtr) ((WindowPeek)curWindow)->nextWindow;
  2184.         if (curWindow) {
  2185.             tmpWindow = curWindow;
  2186.             curWindow = (WindowPtr) ((WindowPeek)curWindow)->nextWindow;
  2187.             stillQuit &= DoCloseWindow(tmpWindow);
  2188.         }
  2189.     }
  2190.     WriteDeskScrap();
  2191.     return stillQuit;
  2192. }
  2193.  
  2194.  
  2195. /*    HideShowGroups hides/shows the main groups window.
  2196. */
  2197.  
  2198. void HideShowGroups(void)
  2199. {
  2200.     extern TPrefRec gPrefs;
  2201.     
  2202.     
  2203.     if (gPrefs.groupWindowVisible) {
  2204.         HideWindow(gGroupWindow);
  2205.         RemoveWindowsMenu(gGroupWindow);
  2206.         SetItem(gTheMenu[kWindowsMenu],kHideShowWind,kShowText);
  2207.     }
  2208.     else {
  2209.         ShowWindow(gGroupWindow);
  2210.         AddWindowsMenu(gGroupWindow);
  2211.         SetItem(gTheMenu[kWindowsMenu],kHideShowWind,kHideText);
  2212.     }
  2213.     gPrefs.groupWindowVisible = !gPrefs.groupWindowVisible;
  2214. }
  2215.  
  2216.  
  2217. /* ChangeFont is executed when the user selects a different font from the menu */
  2218.  
  2219. void ChangeFont(short item)
  2220. {
  2221.     short i,fontNum;
  2222.     TwindowInfo *info;
  2223.     Str255 fontName;
  2224.     GrafPtr savePort;
  2225.     short theSize;
  2226.     WindowPtr theWindow;
  2227.     
  2228.     theWindow = FrontWindow();
  2229.     
  2230.     for (i=1; i<=CountMItems(gTheMenu[kFontMenu]); i++)
  2231.         CheckItem(gTheMenu[kFontMenu],i,false);
  2232.     CheckItem(gTheMenu[kFontMenu],item,true);
  2233.     
  2234.     GetItem(gTheMenu[kFontMenu],item,fontName);
  2235.     GetFNum(fontName,&fontNum);
  2236.  
  2237.     if (theWindow)
  2238.         info = (TwindowInfo *)GetWRefCon(theWindow);
  2239.     else
  2240.         return;
  2241.     
  2242.     if (info->kind <= cSubject) {
  2243.         theSize = gPrefs.listSize;
  2244.         BlockMove(fontName,gPrefs.listFont,fontName[0]+1);
  2245.     }
  2246.     else {
  2247.         BlockMove(fontName,gPrefs.textFont,fontName[0]+1);
  2248.         (**(TEHandle)info->data).txFont = fontNum;
  2249.         theSize = gPrefs.textSize;
  2250.     }
  2251.  
  2252.     GetPort(&savePort);
  2253.     SetPort(theWindow);
  2254.     TextFont(fontNum);
  2255.     UpdateFontStuff(theWindow);
  2256.     InvalRect(&theWindow->portRect);
  2257.     SetPort(savePort);
  2258.     
  2259.     UpdateSizeMenu(fontNum,theSize);
  2260. }
  2261.  
  2262.  
  2263. /* SwitchFont is executed on activate events to update font menu */
  2264.  
  2265. void SwitchFont(short fontNumber,short size)
  2266. {
  2267.     short i,numItems;
  2268.     Str255 fontName,itemName;
  2269.     
  2270.     numItems = CountMItems(gTheMenu[kFontMenu]);
  2271.     
  2272.     for (i=1; i<=numItems; i++)
  2273.         CheckItem(gTheMenu[kFontMenu],i,false);
  2274.  
  2275.     GetFontName(fontNumber,fontName);
  2276.     for (i=1; i<=numItems; i++) {
  2277.         GetItem(gTheMenu[kFontMenu],i,itemName);
  2278.         if (EqualString(itemName,fontName,true,true))
  2279.             CheckItem(gTheMenu[kFontMenu],i,true);
  2280.     }
  2281.     UpdateSizeMenu(fontNumber,size);
  2282. }
  2283.  
  2284.  
  2285. /* UpdateSizeMenu is executed on activate events to update size menu */
  2286.  
  2287. void UpdateSizeMenu(short fontNumber,short theSize)
  2288. {
  2289.     Str255 sizeStr;
  2290.     long size;
  2291.     short i,j;
  2292.     
  2293.     for (i=1; i<=CountMItems(gTheMenu[kSizeMenu]); i++) {
  2294.         GetItem(gTheMenu[kSizeMenu],i,sizeStr);
  2295.         for (j=1; j<=sizeStr[0]; j++)
  2296.             if (sizeStr[j] == ' ')
  2297.                 sizeStr[0] = j-1;
  2298.         StringToNum(sizeStr,&size);
  2299.         CheckItem(gTheMenu[kSizeMenu],i,false);
  2300.         if (RealFont(fontNumber,(short)size))
  2301.             SetItemStyle(gTheMenu[kSizeMenu],i,outline);
  2302.         else
  2303.             SetItemStyle(gTheMenu[kSizeMenu],i,0);
  2304.         if (size == theSize)
  2305.             CheckItem(gTheMenu[kSizeMenu],i,true);
  2306.     }
  2307. }
  2308.  
  2309.  
  2310. /* ChangeSize is called when the user changes the font size */
  2311.  
  2312. void ChangeSize(short item)
  2313. {
  2314.     Str255 sizeStr;
  2315.     long size;
  2316.     short i;
  2317.     GrafPtr savePort;
  2318.     TwindowInfo *info;
  2319.     short theFont;
  2320.     WindowPtr theWindow;
  2321.     
  2322.     theWindow = FrontWindow();
  2323.         
  2324.     GetItem(gTheMenu[kSizeMenu],item,sizeStr);
  2325.     for (i=1; i<=sizeStr[0]; i++)
  2326.         if (sizeStr[i] == ' ')
  2327.             sizeStr[0] = i-1;
  2328.     StringToNum(sizeStr,&size);
  2329.     
  2330.     if (theWindow)
  2331.         info = (TwindowInfo *)GetWRefCon(theWindow);
  2332.     else
  2333.         return;
  2334.     
  2335.     if (info->kind <= cSubject) {
  2336.         GetFNum(gPrefs.listFont,&theFont);
  2337.         gPrefs.listSize = size;
  2338.     }
  2339.     else {
  2340.         GetFNum(gPrefs.textFont,&theFont);
  2341.         gPrefs.textSize = size;
  2342.     }
  2343.  
  2344.     GetPort(&savePort);
  2345.     SetPort(theWindow);
  2346.     TextSize(size);
  2347.     UpdateSizeMenu(theFont,size);
  2348.     UpdateFontStuff(theWindow);
  2349.     InvalRect(&theWindow->portRect);
  2350.     SetPort(savePort);
  2351.  
  2352. }
  2353.  
  2354.  
  2355. /*    UpdateFontStuff updates the font information for a window */
  2356.  
  2357. void UpdateFontStuff(WindowPtr window)
  2358. {
  2359.     FontInfo fontInfo;
  2360.     TwindowInfo *info;
  2361.     ListHandle theList;
  2362.     TEHandle theTE;
  2363.     Point newSize;
  2364.     
  2365.     if (!window)
  2366.         return;
  2367.         
  2368.     GetFontInfo(&fontInfo);
  2369.     info = (TwindowInfo *)GetWRefCon(window);
  2370.     
  2371.     switch (info->kind) {
  2372.         case cGroup:
  2373.         case cNewGroup:
  2374.         case cUserGroup:
  2375.         case cSubject:
  2376.             theList = (ListHandle)info->data;
  2377.             newSize.h = (**theList).cellSize.h;
  2378.             newSize.v = fontInfo.ascent+fontInfo.descent+fontInfo.leading;
  2379.             LCellSize(newSize,theList);
  2380.             break;
  2381.         case cMessage:
  2382.         case cMiscMessage:
  2383.         case cSendMessage:
  2384.         case cPostMessage:
  2385.             theTE = (TEHandle)info->data;
  2386.             (**theTE).txFont = window->txFont;
  2387.             (**theTE).txFace = window->txFace;
  2388.             (**theTE).txMode = window->txMode;
  2389.             (**theTE).txSize = window->txSize;
  2390.             (**theTE).lineHeight = fontInfo.ascent+fontInfo.descent+fontInfo.leading;
  2391.             (**theTE).fontAscent = fontInfo.ascent;
  2392.             break;
  2393.         default:
  2394.             SysBeep(1);
  2395.     }
  2396. }
  2397.  
  2398.  
  2399. /*    RemoveWindowsMenu removes a window's title from the windows menu when the
  2400.     window is closed, etc...
  2401. */
  2402.  
  2403. void RemoveWindowsMenu(WindowPtr wind)
  2404. {
  2405.     short item;
  2406.     Str255 name,itemString;
  2407.     
  2408.     if (!wind)
  2409.         return;
  2410.         
  2411.     GetWTitle(wind,name);
  2412.     for (item=kFirstWindOffset; item<=CountMItems(gTheMenu[kWindowsMenu]); item++) {
  2413.         GetItem(gTheMenu[kWindowsMenu],item,itemString);
  2414.         if (EqualString(name,itemString,true,true)) {
  2415.             DelMenuItem(gTheMenu[kWindowsMenu],item);
  2416.             return;
  2417.         }
  2418.     }
  2419. }
  2420.  
  2421.  
  2422. /*    AddWindowsMenu adds a window's title to the windows menu.
  2423. */
  2424.  
  2425. void AddWindowsMenu(WindowPtr wind)
  2426. {
  2427.     Str255 name;
  2428.     
  2429.     if (!wind)
  2430.         return;
  2431.         
  2432.     GetWTitle(wind,name);
  2433.     InsMenuItem(gTheMenu[kWindowsMenu],"\pnew item",kFirstWindOffset-1);
  2434.     SetItem(gTheMenu[kWindowsMenu],kFirstWindOffset,name);
  2435. }
  2436.  
  2437.  
  2438. /*    SelectWindowsMenu is called when a user selects an item from the windows
  2439.     menu.  The selected window is brought to the front.
  2440. */
  2441.  
  2442. void SelectWindowsMenu(short item)
  2443. {
  2444.     Str255 name,itemString;
  2445.     WindowPtr window;
  2446.     
  2447.     GetItem(gTheMenu[kWindowsMenu],item,itemString);
  2448.     TitleFilter(itemString);
  2449.     for (window = FrontWindow(); window != nil; window = (WindowPtr) ((WindowPeek)window)->nextWindow) {
  2450.         GetWTitle(window,name);
  2451.         if (EqualString(name,itemString,true,true)) {
  2452.             SelectWindow(window);
  2453.             return;
  2454.         }
  2455.     }
  2456. }
  2457.