home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1997 July / macformat52.iso / mac / Shareware Plus / Developers / MacFloater Folder / MacFloater.c next >
Encoding:
C/C++ Source or Header  |  1997-04-24  |  15.9 KB  |  608 lines

  1. /*    MacFloater.cpp
  2.  *
  3.  *        This is the implementation of the floating window stuff. This
  4.  *    requires the routine 'DoActivate' to be a valid subroutine which can
  5.  *    be called to activate the window's contents, and this also requires
  6.  *    that the 'activeEvt' of the event loop gets ignored...
  7.  */
  8.  
  9. #include "MacFloater.h"                        /* Float library support    */
  10. #include <LowMem.h>                            /* LMGetMBarHeight()        */
  11.  
  12. /************************************************************************/
  13. /*                                                                        */
  14. /*    Search Routines                                                        */
  15. /*                                                                        */
  16. /************************************************************************/
  17.  
  18. /*    MFrontWindow
  19.  *
  20.  *        Find the frontmost non-floater. This searches down the linked
  21.  *    list of windows that is maintained internaly by the Macintosh OS
  22.  *    (the linked list kept through the WindowRecord field 'nextWindow')
  23.  *    until I find a window which has the proper type.
  24.  */
  25.  
  26. WindowPtr MFrontWindow(void)
  27. {
  28.     WindowPeek w;
  29.     
  30.     w = (WindowPeek)FrontWindow();
  31.     for (;;) {
  32.         if (w == NULL) break;
  33.         if (w->windowKind != KFloatingWindow) {
  34.             if (w->visible) break;
  35.         }
  36.         w = w->nextWindow;                    /* Nope, this ain't it. Go on. */
  37.     }
  38.     return (WindowPtr)w;
  39. }
  40.  
  41. /*    MLastFloater
  42.  *
  43.  *        Get the last floater window position. This is not similar to
  44.  *    anything in the Macintosh OS, but is very useful for figuring out
  45.  *    where new non-floater windows go.
  46.  */
  47.  
  48. WindowPtr MLastFloater(void)
  49. {
  50.     WindowPeek w;
  51.     WindowPeek prev;
  52.     
  53.     prev = NULL;
  54.     w = (WindowPeek)FrontWindow();
  55.     while (w && (w->windowKind == KFloatingWindow)) {
  56.         prev = w;
  57.         w = w->nextWindow;
  58.     }
  59.     return (WindowPtr)prev;
  60. }
  61.  
  62. /************************************************************************/
  63. /*                                                                        */
  64. /*    Selection Routines                                                    */
  65. /*                                                                        */
  66. /************************************************************************/
  67.  
  68. /*    MSelectWindow
  69.  *
  70.  *        Like select window, except for floating windows. If this is called
  71.  *    with a floating window, it brings the floating window to the front of
  72.  *    all of the floating windows. If called on a non-floater, this brings
  73.  *    the non-floating window frontmost.
  74.  */
  75.  
  76. void MSelectWindow(WindowPtr w)
  77. {
  78.     short isFloater;
  79.     WindowPtr current;
  80.     WindowPtr last;
  81.     
  82.     /*
  83.      *  Based on what kind of window this is (floating, nonfloating)
  84.      *    initialize some interesting variables for later
  85.      */
  86.     
  87.     if (((WindowPeek)w)->windowKind == KFloatingWindow) {
  88.         current = FrontWindow();
  89.         isFloater = 1;
  90.     } else {
  91.         isFloater = 0;
  92.         current = MFrontWindow();
  93.         last = MLastFloater();
  94.     }
  95.     
  96.     /*
  97.      *  Now if we are not the current window, do the selection
  98.      */
  99.     
  100.     if (current != w) {
  101.         if (isFloater) {
  102.             /*
  103.              *  Bringing a floater forward can be done by bringing the
  104.              *    thing all the way to the front.
  105.              */
  106.             
  107.             BringToFront(w);
  108.         } else {
  109.             if (last == NULL) {
  110.                 /*
  111.                  *  This is a standard window, but there are no floaters
  112.                  */
  113.                 
  114.                 HiliteWindow(current,0);    /* Unhilite this window        */
  115.                 DoActivate(current,0);        /* And deactivate it        */
  116.                 BringToFront(w);            /* Bring this one frontmost    */
  117.                 HiliteWindow(w,1);
  118.                 DoActivate(w,1);            /* ###6 Need System 6 tests.*/
  119.             } else {
  120.                 HiliteWindow(current,0);    /* Unhilite this window        */
  121.                 DoActivate(current,0);        /* And deactivate it        */
  122.                 SendBehind(w,last);
  123.                 
  124. #ifdef PREVERSION7
  125.                 /*
  126.                  *  The following two routines are only needed if this
  127.                  *    were to run under an operating system earlier than
  128.                  *    System 7. But as we are not going to do that, well,
  129.                  *    these routines simply are not needed; the routine
  130.                  *    'SendBehind' does the right thing.
  131.                  */
  132.                 
  133.                 PaintOne((WindowPeek)w,((WindowPeek)w)->strucRgn);
  134.                 CalcVis((WindowPeek)w);
  135. #endif
  136.  
  137.                 HiliteWindow(w,1);
  138.                 DoActivate(w,1);            /* ###6 Need System 6 tests.*/
  139.             }                                /* PaintOne & CalcVis        */
  140.         }
  141.     }
  142. }
  143.  
  144. /*    MDragWindow
  145.  *
  146.  *        Do the drag window thing
  147.  */
  148.  
  149. void MDragWindow(WindowPtr windowToDrag, Point startPoint, const Rect *draggingBounds)
  150. {
  151.     Rect        dragRect;
  152.     KeyMap        keyMap;
  153.     GrafPtr        savePort;
  154.     GrafPtr        windowManagerPort;
  155.     RgnHandle    dragRegion;
  156.     RgnHandle    windowContentRegion;
  157.     long        dragResult;
  158.     short        topLimit;
  159.     short        newHorizontalWindowPosition;
  160.     short        newVerticalWindowPosition;
  161.     short        horizontalOffset;
  162.     short        verticalOffset;
  163.     Boolean        commandKeyDown = false;
  164.     
  165.     if (WaitMouseUp()) {
  166.         /*
  167.          * Adjust the top of the dragging rectangle so that it’s below 
  168.          * the menu bar
  169.          */
  170.     
  171.         topLimit = LMGetMBarHeight() + 4;
  172.         dragRect = *draggingBounds;
  173.         if (dragRect.top < topLimit) dragRect.top = topLimit;
  174.     
  175.         /* Set up the Window Manager port. */
  176.     
  177.         GetPort(&savePort);
  178.         GetWMgrPort(&windowManagerPort);
  179.         SetPort(windowManagerPort);
  180.         SetClip(GetGrayRgn());
  181.         
  182.         /*
  183.          * Check to see if the command key is down.  If it is, don’t bring the window to the
  184.          * front after the move.  Trying to do Pascal stuff in C is so much fun.  GetKeys()
  185.          * is a total pain to try to use properly from C, so I’m going to hard code where the
  186.          * command key is in the KeyMap array.
  187.          */
  188.          
  189.         GetKeys(keyMap);
  190.         if (keyMap[1] & 0x8000) commandKeyDown = true;
  191.         if ((commandKeyDown == true) || 
  192.                 (((WindowPeek)windowToDrag)->windowKind != KFloatingWindow)) {
  193.             
  194.             if (commandKeyDown == false)
  195.     
  196.         /*
  197.          * If there are floating windows, clip the dragging outline 
  198.          * to draw behind the floaters.
  199.          */
  200.          
  201.                 ClipAbove(MFrontWindow());
  202.             else
  203.             
  204.         /*
  205.          * If the command key was down, clip the outline to draw behind any windows above
  206.          * the window being dragged.
  207.          */
  208.          
  209.                 ClipAbove(windowToDrag);
  210.         }
  211.             
  212.         /* Create a region to drag */
  213.     
  214.         dragRegion = NewRgn();
  215.         CopyRgn(((WindowPeek)windowToDrag)->strucRgn, dragRegion);
  216.         
  217.         /* Drag the window around */
  218.     
  219.         dragResult = DragGrayRgn(dragRegion, startPoint, &dragRect, &dragRect, noConstraint, nil);
  220.     
  221.         /* Restore the port for coordinate conversion. */
  222.     
  223.         SetPort(savePort);
  224.  
  225.         if (dragResult != 0) {
  226.             horizontalOffset = dragResult & 0xFFFF;
  227.             verticalOffset = dragResult >> 16;
  228.     
  229.         /* Only move it if it stayed inside the dragging box. */
  230.     
  231.             if (verticalOffset != -32768) {
  232.                 windowContentRegion = ((WindowPeek)windowToDrag)->contRgn;
  233.                 newHorizontalWindowPosition = (**windowContentRegion).rgnBBox.left + horizontalOffset;
  234.                 newVerticalWindowPosition = (**windowContentRegion).rgnBBox.top + verticalOffset;
  235.                 
  236.                 MoveWindow((WindowPtr) windowToDrag, newHorizontalWindowPosition, newVerticalWindowPosition, false);
  237.                 
  238.             }
  239.         }
  240.     
  241.         /* Bring the window forward if the command key wasn’t down */
  242.     
  243.         if (commandKeyDown == false)
  244.             MSelectWindow(windowToDrag);
  245.     
  246.         /* Get rid of the dragging region */
  247.     
  248.         DisposeRgn(dragRegion);
  249.     }
  250. }
  251.  
  252. /*    MGetWindowList
  253.  *
  254.  *        Get the window list top
  255.  */
  256.  
  257. static WindowPtr MGetWindowList(void)
  258. {
  259.     return (*(WindowPtr *)0x09D6);
  260. }
  261.  
  262. /*    MValidateWindowList
  263.  *
  264.  *        Validation of the window list's order
  265.  */
  266.  
  267. static void MValidateWindowList(void)
  268. {
  269.     WindowPtr    currentWindow = MGetWindowList();
  270.     WindowPtr    lastFloatingWindow = MLastFloater();
  271.     WindowPtr    firstFloatingWindow = nil;
  272.     WindowPtr    documentWindowsToMove = nil;
  273.     WindowPtr    lastDocumentWindowAdded = nil;
  274.     WindowPtr    previousWindow = nil;
  275.     
  276.     if (currentWindow) {
  277.     
  278.     /*
  279.      * First, gather up all the document windows in front of floating windows. We iterate
  280.      * through the window list until a floating window is encountered.
  281.      */
  282.         do {
  283.             if (((WindowPeek)currentWindow)->windowKind == KFloatingWindow) {
  284.                 firstFloatingWindow = currentWindow;
  285.                 break;
  286.             }
  287.             else {
  288.                 ((WindowPeek)previousWindow)->nextWindow = ((WindowPeek)currentWindow)->nextWindow;
  289.  
  290.                 if (documentWindowsToMove == nil)
  291.                     documentWindowsToMove = currentWindow;
  292.                 else
  293.                     ((WindowPeek)lastDocumentWindowAdded)->nextWindow = (WindowPeek)currentWindow;
  294.                 lastDocumentWindowAdded = currentWindow;
  295.                 
  296.                 previousWindow = currentWindow;
  297.                 currentWindow = (WindowPtr)(((WindowPeek)currentWindow)->nextWindow);
  298.             }
  299.         } while (currentWindow);
  300.         
  301.     /* Now put them back in their place. */
  302.     
  303.         if (documentWindowsToMove && firstFloatingWindow) {
  304.             ((WindowPeek)lastDocumentWindowAdded)->nextWindow = ((WindowPeek)lastFloatingWindow)->nextWindow;
  305.             ((WindowPeek)lastFloatingWindow)->nextWindow = (WindowPeek)documentWindowsToMove;
  306.             
  307.     /*
  308.      * If the first window in the window list was a document window, and there are
  309.      * floating windows, then make the floating window the first window in the window
  310.      * list.
  311.      */
  312.             if (documentWindowsToMove == MGetWindowList())
  313.                 (*(WindowPtr *)0x09D6) = firstFloatingWindow;
  314.         }
  315.     }
  316. }
  317.  
  318. /*    MShowWindow
  319.  *
  320.  *        How to show this window and make it visible
  321.  */
  322.  
  323. void MShowWindow(WindowPtr windowToShow)
  324. {
  325.     WindowPtr            windowBehind;
  326.     WindowPtr            frontNonFloatingWindow;
  327.     short                windowClass;
  328.     Boolean                windowIsInFront = false;
  329.     
  330.     if (((WindowPeek)windowToShow)->visible != false) return;
  331.         
  332.     windowClass = ((WindowPeek)windowToShow)->windowKind;
  333.     
  334.     /* Handle special case of movable modal dialog. */
  335.     
  336.     if (windowClass == dialogKind) {
  337.         /* Unhilite the frontmost document window */
  338.         windowBehind = MFrontWindow();
  339.         if (windowBehind != NULL) {
  340.             HiliteWindow(windowBehind,0);
  341.             DoActivate(windowBehind,0);
  342.         }
  343.         
  344.         ((WindowPeek)windowToShow)->hilited = true;    /* Hilite this        */
  345.         ShowHide((WindowPtr)windowToShow,true);        /* Show this        */
  346.         DoActivate(windowToShow,1);                    /* Activate this    */
  347.         return;
  348.     }
  349.     
  350.     /*
  351.      * If the window behind the window to show is currently the frontmost document window,
  352.      * unhighlight it, and highlight the new front window.
  353.      */
  354.      
  355.     if (windowClass != KFloatingWindow) {
  356.         windowBehind = (WindowPtr)(((WindowPeek)windowToShow)->nextWindow);
  357.         if (windowBehind == MFrontWindow()) {
  358.             if (windowBehind != NULL) {
  359.                 HiliteWindow(windowBehind,0);
  360.                 DoActivate(windowBehind,0);
  361.             }
  362.  
  363.             /* Set the highlight state so the window appears highlighted from the start. */
  364.  
  365.             ((WindowPeek)windowToShow)->hilited = true;
  366.             windowIsInFront = true;
  367.         }
  368.     } else {
  369.     
  370.     /*
  371.      * A floating window is about to be shown. Make sure the windows in the 
  372.      * window list are all in the right place.
  373.      */
  374.     
  375.         MValidateWindowList();
  376.             
  377.         frontNonFloatingWindow = MFrontWindow();
  378.         ((WindowPeek)windowToShow)->hilited = true;
  379.         windowIsInFront = true;
  380.     }
  381.     
  382.     /* Show the window */
  383.     
  384.     ShowHide((WindowPtr) windowToShow, true);
  385.     
  386.     /* If this is the new frontmost document window or a floating window, send it an activate event */
  387.     
  388.     if (windowIsInFront) {
  389.         DoActivate(windowToShow,1);
  390.     }
  391. }
  392.  
  393. /*    MHideWindow
  394.  *
  395.  *        How to hide this window
  396.  */
  397.  
  398. void MHideWindow(WindowPtr windowToHide)
  399. {
  400.     WindowPtr            frontFloater;
  401.     WindowPtr            frontNonFloater;
  402.     WindowPtr            lastFloater;
  403.     WindowPtr            windowBehind;
  404.     short                windowClass;
  405.     
  406.     /* Don’t do anything if the window is already invisible. */
  407.     
  408.     if (((WindowPeek)windowToHide)->visible == false) return;
  409.  
  410.     /* Handle special case of movable modal dialog */
  411.     
  412.     windowClass = ((WindowPeek)windowToHide)->windowKind;
  413.     if (windowClass == dialogKind) {
  414.         /* Hide the window */
  415.         ShowHide(windowToHide,false);
  416.         
  417.         /* Hilite the frontmost document window */
  418.         frontNonFloater = MFrontWindow();
  419.         if (frontNonFloater != NULL) {
  420.             HiliteWindow(frontNonFloater,1);
  421.             DoActivate(frontNonFloater,1);
  422.         }
  423.         return;
  424.     }
  425.     
  426.     /* Get the first visible floating window, if any. */
  427.     
  428.     frontFloater = FrontWindow();
  429.     if (((WindowPeek)frontFloater)->windowKind != KFloatingWindow) frontFloater = nil;
  430.         
  431.     /* Get the first visible document window, if any. */
  432.     
  433.     frontNonFloater = MFrontWindow();
  434.     
  435.     /* Hide the window. */
  436.     
  437.     ShowHide((WindowPtr) windowToHide, false);
  438.     
  439.     /*
  440.      * If the frontmost floating window is being hidden, move it behind the floating window
  441.      * behind it, if there is one.
  442.      */
  443.     if (windowToHide == frontFloater) {
  444.         windowBehind = (WindowPtr)(((WindowPeek)windowToHide)->nextWindow);
  445.         
  446.     /* Only do the rearrangement if there’s another floating window. */
  447.     
  448.         if ((windowBehind != nil) && (((WindowPeek)windowBehind)->windowKind == KFloatingWindow)) {
  449.             ((WindowPeek)windowToHide)->nextWindow = ((WindowPeek)windowBehind)->nextWindow;
  450.             ((WindowPeek)windowBehind)->nextWindow = (WindowPeek)windowToHide;
  451.             (*(WindowPtr *)0x09D6) = windowBehind;
  452.         }
  453.     }
  454.     else {
  455.     
  456.     /* If the frontmost document window is behind hidden, send it behind the window
  457.      * behind it.
  458.      */
  459.         if (windowToHide == frontNonFloater) {
  460.             windowBehind = (WindowPtr)(((WindowPeek)windowToHide)->nextWindow);
  461.             
  462.             if (windowBehind != nil) {
  463.                 ((WindowPeek)windowToHide)->nextWindow = ((WindowPeek)windowBehind)->nextWindow;
  464.                 ((WindowPeek)windowBehind)->nextWindow = (WindowPeek)windowToHide;
  465.                 
  466.     /* Set the next link of the last floating window to point to the previously second
  467.      * to front document window. If there was no floating window, change the beginning
  468.      * of the window list.
  469.      */
  470.                 lastFloater = MLastFloater();
  471.                 if (lastFloater != nil)
  472.                     ((WindowPeek)lastFloater)->nextWindow = (WindowPeek)windowBehind;
  473.                 else
  474.                     (*(WindowPtr *)0x09D6) = windowBehind;
  475.                 
  476.     /* The window behind it is now the front document window.  Highlight it and send it
  477.      * and activate event.
  478.      */            
  479.                 HiliteWindow(windowBehind,1);
  480.                 DoActivate(windowBehind,1);
  481.             }
  482.         }
  483.     }
  484. }
  485.  
  486. /************************************************************************/
  487. /*                                                                        */
  488. /*    Window Creation                                                        */
  489. /*                                                                        */
  490. /************************************************************************/
  491.  
  492. /*    MNewWindow
  493.  *
  494.  *        Do the same thing as the NewWindow call, but open the window
  495.  *    right behind the floater
  496.  */
  497.  
  498. WindowPtr MNewWindow(Ptr st, Rect *bounds, unsigned char *title, Boolean vis, short wDef, WindowPtr behind, Boolean goAway, long refCon)
  499. {
  500.     WindowPtr w;
  501.     
  502.     /* Reset the behind pointer depending on the order of this thing */
  503.  
  504.     if ((wDef >= 2048) && (wDef <= 2063)) {
  505.         /*
  506.          *  If the 'wDef' parameter (the window definition) is between
  507.          *    2048 and 2063, this is a floating window definition function.
  508.          *    (This coorisponds to a 'WDEF' resource of 128
  509.          */
  510.         
  511.         if (behind == NULL) {
  512.             behind = MLastFloater();
  513.             if (behind == NULL) behind = (WindowPtr)-1L;
  514.         }
  515.     } else if ((wDef == 1) || (wDef == 5)) {
  516.         behind = (WindowPtr)-1L;            /* always in front. */
  517.     } else {
  518.         if (behind == (WindowPtr)-1L) {
  519.             behind = MLastFloater();
  520.             if (behind == NULL) behind = (WindowPtr)-1L;
  521.         }
  522.     }
  523.     
  524.     /* Get the current front window for deactivation, and create it */
  525.     
  526.     w = NewWindow(st,bounds,title,false,wDef,behind,goAway,refCon);
  527.     if (w == NULL) return NULL;
  528.     
  529.     /* Do the activation/deactivation if this window is visible */
  530.     if ((wDef >= 2048) && (wDef <= 2063)) {
  531.         ((WindowPeek)w)->windowKind = KFloatingWindow;
  532.     } else {
  533.         ((WindowPeek)w)->windowKind = KNormalWindow;
  534.     }
  535.     if (vis) MShowWindow(w);
  536.     return w;
  537. }
  538.  
  539. /*    MNewCWindow
  540.  *
  541.  *        Do the same thing as the NewWindow call, but open the window
  542.  *    right behind the floater
  543.  */
  544.  
  545. WindowPtr MNewCWindow(Ptr st, Rect *bounds, unsigned char *title, Boolean vis, short wDef, WindowPtr behind, Boolean goAway, long refCon)
  546. {
  547.     WindowPtr w;
  548.     
  549.     /* Reset the behind pointer depending on the order of this thing */
  550.  
  551.     if ((wDef >= 2048) && (wDef <= 2063)) {
  552.         /*
  553.          *  If the 'wDef' parameter (the window definition) is between
  554.          *    2048 and 2063, this is a floating window definition function.
  555.          *    (This coorisponds to a 'WDEF' resource of 128
  556.          */
  557.         
  558.         if (behind == NULL) {
  559.             behind = MLastFloater();
  560.             if (behind == NULL) behind = (WindowPtr)-1L;
  561.         }
  562.     } else if ((wDef == 1) || (wDef == 5)) {
  563.         behind = (WindowPtr)-1L;            /* always in front. */
  564.     } else {
  565.         if (behind == (WindowPtr)-1L) {
  566.             behind = MLastFloater();
  567.             if (behind == NULL) behind = (WindowPtr)-1L;
  568.         }
  569.     }
  570.     
  571.     /* Get the current front window for deactivation, and create it */
  572.     
  573.     w = NewCWindow(st,bounds,title,false,wDef,behind,goAway,refCon);
  574.     if (w == NULL) return NULL;
  575.     
  576.     /* Do the activation/deactivation if this window is visible */
  577.     if ((wDef >= 2048) && (wDef <= 2063)) {
  578.         ((WindowPeek)w)->windowKind = KFloatingWindow;
  579.     } else {
  580.         ((WindowPeek)w)->windowKind = KNormalWindow;
  581.     }
  582.     if (vis) MShowWindow(w);
  583.     return w;
  584. }
  585.  
  586. /*    MCloseWindow
  587.  *
  588.  *        This handles closing the window.
  589.  */
  590.  
  591. void MCloseWindow(WindowPtr w)
  592. {
  593.     if (((WindowPeek)w)->visible) MHideWindow(w);
  594.     CloseWindow(w);
  595. }
  596.  
  597. /*    MDisposeWindow
  598.  *
  599.  *        This handles closing the window.
  600.  */
  601.  
  602. void MDisposeWindow(WindowPtr w)
  603. {
  604.     if (((WindowPeek)w)->visible) MHideWindow(w);
  605.     DisposeWindow(w);
  606. }
  607.  
  608.