home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / mac / tkMacWindowMgr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  38.0 KB  |  1,590 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tkMacWindowMgr.c --
  3.  *
  4.  *    Implements common window manager functions for the Macintosh.
  5.  *
  6.  * Copyright (c) 1995-1997 Sun Microsystems, Inc.
  7.  *
  8.  * See the file "license.terms" for information on usage and redistribution
  9.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  10.  *
  11.  * SCCS: @(#) tkMacWindowMgr.c 1.50 97/08/07 14:47:39
  12.  */
  13.  
  14. #include <Events.h>
  15. #include <Dialogs.h>
  16. #include <EPPC.h>
  17. #include <Windows.h>
  18. #include <ToolUtils.h>
  19. #include <DiskInit.h>
  20. #include <LowMem.h>
  21. #include <Timer.h>
  22.  
  23. #include "tkInt.h"
  24. #include "tkPort.h"
  25. #include "tkMacInt.h"
  26.  
  27. #define TK_DEFAULT_ABOUT 128
  28.  
  29. /*
  30.  * Declarations of global variables defined in this file.
  31.  */
  32.  
  33. int tkMacAppInFront = true;         /* Boolean variable for determining 
  34.                       * if we are the frontmost app. */
  35. Tk_Window tkMacFocusWin = NULL;      /* Window to which all mouse
  36.                           * events will be reported. */
  37.  
  38. /*
  39.  *  Non-standard event types that can be passed to HandleEvent.
  40.  * These are defined and used by Netscape's plugin architecture.
  41.  */
  42. #define getFocusEvent       (osEvt + 16)
  43. #define loseFocusEvent      (osEvt + 17)
  44. #define adjustCursorEvent   (osEvt + 18)
  45.  
  46. /*
  47.  * Declarations of static variables used in this file.
  48.  */
  49.  
  50. static int     gEatButtonUp = 0;     /* 1 if we need to eat the next
  51.                       * up event */
  52. static Tk_Window gGrabWinPtr = NULL;     /* Current grab window, NULL if no grab. */
  53. static Tk_Window gKeyboardWinPtr = NULL; /* Current keyboard grab window. */
  54. static RgnHandle gDamageRgn = NULL;     /* Damage region used for handling
  55.                       * screen updates. */
  56. /*
  57.  * Forward declarations of procedures used in this file.
  58.  */
  59.  
  60. static void    BringWindowForward _ANSI_ARGS_((WindowRef wRef));
  61. static int     CheckEventsAvail _ANSI_ARGS_((void));
  62. static int     GenerateActivateEvents _ANSI_ARGS_((EventRecord *eventPtr,
  63.             Window window));
  64. static int     GenerateFocusEvents _ANSI_ARGS_((EventRecord *eventPtr,
  65.             Window window));
  66. static int    GenerateKeyEvent _ANSI_ARGS_((EventRecord *eventPtr,
  67.             Window window));
  68. static int    GenerateUpdateEvent _ANSI_ARGS_((EventRecord *eventPtr,
  69.             Window window));
  70. static void     GenerateUpdates _ANSI_ARGS_((RgnHandle updateRgn,
  71.             TkWindow *winPtr));
  72. static int     GeneratePollingEvents _ANSI_ARGS_((void));    
  73. static int     GeneratePollingEvents2 _ANSI_ARGS_((Window window));    
  74. static OSErr    TellWindowDefProcToCalcRegions _ANSI_ARGS_((WindowRef wRef));
  75. static int    WindowManagerMouse _ANSI_ARGS_((EventRecord *theEvent,
  76.             Window window));
  77.  
  78.  
  79. /*
  80.  *----------------------------------------------------------------------
  81.  *
  82.  * WindowManagerMouse --
  83.  *
  84.  *    This function determines if a button event is a "Window Manager"
  85.  *    function or an event that should be passed to Tk's event
  86.  *    queue.
  87.  *
  88.  * Results:
  89.  *    Return true if event was placed on Tk's event queue.
  90.  *
  91.  * Side effects:
  92.  *    Depends on where the button event occurs.
  93.  *
  94.  *----------------------------------------------------------------------
  95.  */
  96.  
  97. static int
  98. WindowManagerMouse(
  99.     EventRecord *eventPtr,    /* Macintosh event record. */
  100.     Window window)        /* Window pointer. */
  101. {
  102.     WindowRef whichWindow, frontWindow;
  103.     Tk_Window tkwin;
  104.     Point where, where2;
  105.     int xOffset, yOffset;
  106.     short windowPart;
  107.                 
  108.     frontWindow = FrontWindow();
  109.  
  110.     /* 
  111.      * The window manager only needs to know about mouse down events
  112.      * and sometimes we need to "eat" the mouse up.  Otherwise, we
  113.      * just pass the event to Tk.
  114.      */
  115.     if (eventPtr->what == mouseUp) {
  116.     if (gEatButtonUp) {
  117.         gEatButtonUp = false;
  118.         return false;
  119.     }
  120.     return TkGenerateButtonEvent(eventPtr->where.h, eventPtr->where.v, 
  121.         window, TkMacButtonKeyState());
  122.     }
  123.  
  124.     windowPart = FindWindow(eventPtr->where, &whichWindow);
  125.     tkwin = Tk_IdToWindow(tkDisplayList->display, window);
  126.     switch (windowPart) {
  127.     case inSysWindow:
  128.         SystemClick(eventPtr, (GrafPort *) whichWindow);
  129.         return false;
  130.     case inDrag:
  131.         if (whichWindow != frontWindow) {
  132.         if (!(eventPtr->modifiers & cmdKey)) {
  133.             if ((gGrabWinPtr != NULL) && (gGrabWinPtr != tkwin)) {
  134.             SysBeep(1);
  135.             return false;
  136.             }
  137.         }
  138.         }
  139.  
  140.         /*
  141.          * Call DragWindow to move the window around.  It will
  142.          * also eat the mouse up event.
  143.          */
  144.         SetPort((GrafPort *) whichWindow);
  145.         where.h = where.v = 0;
  146.         LocalToGlobal(&where);
  147.         DragWindow(whichWindow, eventPtr->where,
  148.             &tcl_macQdPtr->screenBits.bounds);
  149.         gEatButtonUp = false;
  150.             
  151.         where2.h = where2.v = 0;
  152.         LocalToGlobal(&where2);
  153.         if (EqualPt(where, where2)) {
  154.         return false;
  155.         }
  156.  
  157.         TkMacWindowOffset(whichWindow, &xOffset, &yOffset);
  158.         where2.h -= xOffset;
  159.         where2.v -= yOffset;
  160.         TkGenWMConfigureEvent(tkwin, where2.h, where2.v,
  161.             -1, -1, TK_LOCATION_CHANGED);
  162.         return true;
  163.     case inGrow:
  164.     case inContent:
  165.         if (whichWindow != frontWindow ) {
  166.         /*
  167.          * This click moves the window forward.  We don't want
  168.          * the corasponding mouse-up to be reported to the application
  169.          * or else it will mess up some Tk scripts.
  170.          */
  171.         if ((gGrabWinPtr != NULL) && (gGrabWinPtr != tkwin)) {
  172.             SysBeep(1);
  173.             return false;
  174.         }
  175.         BringWindowForward(whichWindow);
  176.         gEatButtonUp = true;
  177.         SetPort((GrafPort *) whichWindow);
  178.         return false;
  179.         } else {
  180.         /*
  181.          * Generally the content region is the domain of Tk
  182.          * sub-windows.  However, one exception is the grow
  183.          * region.  A button down in this area will be handled
  184.          * by the window manager.  Note: this means that Tk 
  185.          * may not get button down events in this area!
  186.          */
  187.  
  188.         if (TkMacGrowToplevel(whichWindow, eventPtr->where) == true) {
  189.             return true;
  190.         } else {
  191.             return TkGenerateButtonEvent(eventPtr->where.h,
  192.                 eventPtr->where.v, window, TkMacButtonKeyState());
  193.         }
  194.         }
  195.     case inGoAway:
  196.         if (TrackGoAway( whichWindow, eventPtr->where)) {
  197.         if (tkwin == NULL) {
  198.             return false;
  199.         }
  200.         TkGenWMDestroyEvent(tkwin);
  201.         return true;
  202.         }
  203.         return false;
  204.     case inMenuBar:
  205.         {
  206.         int oldMode;
  207.         KeyMap theKeys;
  208.  
  209.         GetKeys(theKeys);
  210.         oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
  211.         TkMacClearMenubarActive();
  212.         TkMacHandleMenuSelect(MenuSelect(eventPtr->where),
  213.             theKeys[1] & 4);
  214.         Tcl_SetServiceMode(oldMode);
  215.         return true; /* TODO: may not be on event on queue. */
  216.         }
  217.     case inZoomIn:
  218.     case inZoomOut:
  219.         if (TkMacZoomToplevel(whichWindow, eventPtr->where, windowPart)
  220.             == true) {
  221.         return true;
  222.         } else {
  223.         return false;
  224.         }
  225.     default:
  226.         return false;
  227.     }
  228. }
  229.  
  230. /*
  231.  *----------------------------------------------------------------------
  232.  *
  233.  * TkAboutDlg --
  234.  *
  235.  *    Displays the default Tk About box.  This code uses Macintosh
  236.  *    resources to define the content of the About Box.
  237.  *
  238.  * Results:
  239.  *    None.
  240.  *
  241.  * Side effects:
  242.  *    None.
  243.  *
  244.  *----------------------------------------------------------------------
  245.  */
  246.  
  247. void 
  248. TkAboutDlg()
  249. {
  250.     DialogPtr aboutDlog;
  251.     short itemHit = -9;
  252.     
  253.     aboutDlog = GetNewDialog(128, NULL, (void*)(-1));
  254.     
  255.     if (!aboutDlog) {
  256.     return;
  257.     }
  258.     
  259.     SelectWindow((WindowRef) aboutDlog);
  260.     
  261.     while (itemHit != 1) {
  262.     ModalDialog( NULL, &itemHit);
  263.     }
  264.     DisposDialog(aboutDlog);
  265.     aboutDlog = NULL;
  266.     
  267.     SelectWindow(FrontWindow());
  268.  
  269.     return;
  270. }
  271.  
  272. /*
  273.  *----------------------------------------------------------------------
  274.  *
  275.  * GenerateUpdateEvent --
  276.  *
  277.  *    Given a Macintosh update event this function generates all the
  278.  *    X update events needed by Tk.
  279.  *
  280.  * Results:
  281.  *    True if event(s) are generated - false otherwise.  
  282.  *
  283.  * Side effects:
  284.  *    Additional events may be place on the Tk event queue.
  285.  *
  286.  *----------------------------------------------------------------------
  287.  */
  288.  
  289. static int
  290. GenerateUpdateEvent(
  291.     EventRecord *eventPtr,    /* Incoming Mac event */
  292.     Window window)        /* Root X window for event. */
  293. {
  294.     WindowRef macWindow;
  295.     register TkWindow *winPtr;
  296.     
  297.     winPtr = (TkWindow *) Tk_IdToWindow(tkDisplayList->display, window);
  298.  
  299.     if (winPtr == NULL) {
  300.      return false;
  301.     }
  302.     
  303.     if (gDamageRgn == NULL) {
  304.     gDamageRgn = NewRgn();
  305.     }
  306.  
  307.     /*
  308.      * After the call to BeginUpdate the visable region (visRgn) of the 
  309.      * window is equal to the intersection of the real visable region and
  310.      * the update region for this event.  We use this region in all of our
  311.      * calculations.
  312.      */
  313.  
  314.     if (eventPtr->message != NULL) {
  315.     macWindow = (WindowRef) TkMacGetDrawablePort(window);
  316.     BeginUpdate(macWindow);
  317.     GenerateUpdates(macWindow->visRgn, winPtr);
  318.     EndUpdate(macWindow);
  319.     return true;
  320.     } else {
  321.     /*
  322.      * This event didn't come from the system.  This might
  323.      * occur if we are running from inside of Netscape.
  324.      * In this we shouldn't call BeginUpdate as the vis region
  325.      * may be NULL.
  326.      */
  327.     RgnHandle rgn;
  328.     Rect bounds;
  329.     
  330.     rgn = NewRgn();
  331.     TkMacWinBounds(winPtr, &bounds);
  332.     RectRgn(rgn, &bounds);
  333.     GenerateUpdates(rgn, winPtr);
  334.     DisposeRgn(rgn);
  335.     return true;
  336.     }
  337. }
  338.  
  339. /*
  340.  *----------------------------------------------------------------------
  341.  *
  342.  * GenerateUpdates --
  343.  *
  344.  *    Given a Macintosh update region and a Tk window this function
  345.  *    geneates a X damage event for the window if it is within the
  346.  *    update region.  The function will then recursivly have each
  347.  *    damaged window generate damage events for its child windows.
  348.  *
  349.  * Results:
  350.  *    None.
  351.  *
  352.  * Side effects:
  353.  *    Additional events may be place on the Tk event queue.
  354.  *
  355.  *----------------------------------------------------------------------
  356.  */
  357.  
  358. static void
  359. GenerateUpdates(
  360.     RgnHandle updateRgn,
  361.     TkWindow *winPtr)
  362. {
  363.     TkWindow *childPtr;
  364.     XEvent event;
  365.     Rect bounds;
  366.  
  367.     TkMacWinBounds(winPtr, &bounds);
  368.     
  369.     if (bounds.top > (*updateRgn)->rgnBBox.bottom ||
  370.         (*updateRgn)->rgnBBox.top > bounds.bottom ||
  371.         bounds.left > (*updateRgn)->rgnBBox.right ||
  372.         (*updateRgn)->rgnBBox.left > bounds.right ||
  373.         !RectInRgn(&bounds, updateRgn)) {
  374.     return;
  375.     }
  376.  
  377.     event.xany.serial = Tk_Display(winPtr)->request;
  378.     event.xany.send_event = false;
  379.     event.xany.window = Tk_WindowId(winPtr);
  380.     event.xany.display = Tk_Display(winPtr);
  381.     
  382.     event.type = Expose;
  383.  
  384.     /* 
  385.      * Compute the bounding box of the area that the damage occured in.
  386.      */
  387.  
  388.     /*
  389.      * CopyRgn(TkMacVisableClipRgn(winPtr), rgn);
  390.      * TODO: this call doesn't work doing resizes!!!
  391.      */
  392.     RectRgn(gDamageRgn, &bounds);
  393.     SectRgn(gDamageRgn, updateRgn, gDamageRgn);
  394.     OffsetRgn(gDamageRgn, -bounds.left, -bounds.top);
  395.     event.xexpose.x = (**gDamageRgn).rgnBBox.left;
  396.     event.xexpose.y = (**gDamageRgn).rgnBBox.top;
  397.     event.xexpose.width = (**gDamageRgn).rgnBBox.right -
  398.     (**gDamageRgn).rgnBBox.left;
  399.     event.xexpose.height = (**gDamageRgn).rgnBBox.bottom -
  400.     (**gDamageRgn).rgnBBox.top;
  401.     event.xexpose.count = 0;
  402.     
  403.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  404.  
  405.     /*
  406.      * Generate updates for the children of this window
  407.      */
  408.      
  409.     for (childPtr = winPtr->childList; childPtr != NULL;
  410.                        childPtr = childPtr->nextPtr) {
  411.     if (!Tk_IsMapped(childPtr) || Tk_IsTopLevel(childPtr)) {
  412.         continue;
  413.     }
  414.  
  415.     GenerateUpdates(updateRgn, childPtr);
  416.     }
  417.     
  418.     /*
  419.      * Generate updates for any contained windows
  420.      */
  421.  
  422.     if (Tk_IsContainer(winPtr)) {
  423.     childPtr = TkpGetOtherWindow(winPtr);
  424.     if (childPtr != NULL && Tk_IsMapped(childPtr)) {
  425.         GenerateUpdates(updateRgn, childPtr);
  426.     }
  427.         
  428.     /*
  429.      * NOTE: Here we should handle out of process embedding.
  430.      */
  431.             
  432.     }    
  433.  
  434.     return;
  435. }
  436.  
  437. /*
  438.  *----------------------------------------------------------------------
  439.  *
  440.  * TkGenerateButtonEvent --
  441.  *
  442.  *    Given a global x & y position and the button key status this 
  443.  *    procedure generates the appropiate X button event.  It also 
  444.  *    handles the state changes needed to implement implicit grabs.
  445.  *
  446.  * Results:
  447.  *    True if event(s) are generated - false otherwise.
  448.  *
  449.  * Side effects:
  450.  *    Additional events may be place on the Tk event queue.
  451.  *    Grab state may also change.
  452.  *
  453.  *----------------------------------------------------------------------
  454.  */
  455.  
  456. int
  457. TkGenerateButtonEvent(
  458.     int x,        /* X location of mouse */
  459.     int y,        /* Y location of mouse */
  460.     Window window,    /* X Window containing button event. */
  461.     unsigned int state)    /* Button Key state suitable for X event */
  462. {
  463.     WindowRef whichWin, frontWin;
  464.     Point where;
  465.     Tk_Window tkwin;
  466.     int dummy;
  467.  
  468.     /* 
  469.      * ButtonDown events will always occur in the front
  470.      * window.  ButtonUp events, however, may occur anywhere
  471.      * on the screen.  ButtonUp events should only be sent
  472.      * to Tk if in the front window or during an implicit grab.
  473.      */
  474.     where.h = x;
  475.     where.v = y;
  476.     FindWindow(where, &whichWin);
  477.     frontWin = FrontWindow();
  478.             
  479.     if ((frontWin == NULL) || (frontWin != whichWin && gGrabWinPtr == NULL)) {
  480.     return false;
  481.     }
  482.  
  483.     tkwin = Tk_IdToWindow(tkDisplayList->display, window);
  484.     
  485.     GlobalToLocal(&where);
  486.     if (tkwin != NULL) {
  487.     tkwin = Tk_TopCoordsToWindow(tkwin, where.h, where.v, &dummy, &dummy);
  488.     }
  489.  
  490.     Tk_UpdatePointer(tkwin, x,  y, state);
  491.  
  492.     return true;
  493. }
  494.  
  495. /*
  496.  *----------------------------------------------------------------------
  497.  *
  498.  * GenerateActivateEvents --
  499.  *
  500.  *    Generate Activate/Deactivate events from a Macintosh Activate 
  501.  *    event.  Note, the activate-on-foreground bit must be set in the 
  502.  *    SIZE flags to ensure we get Activate/Deactivate in addition to 
  503.  *    Susspend/Resume events.
  504.  *
  505.  * Results:
  506.  *    Returns true if events were generate.
  507.  *
  508.  * Side effects:
  509.  *    Queue events on Tk's event queue.
  510.  *
  511.  *----------------------------------------------------------------------
  512.  */
  513.  
  514. static int
  515. GenerateActivateEvents(
  516.     EventRecord *eventPtr,    /* Incoming Mac event */
  517.     Window window)        /* Root X window for event. */
  518. {
  519.     TkWindow *winPtr;
  520.     
  521.     winPtr = (TkWindow *) Tk_IdToWindow(tkDisplayList->display, window);
  522.     if (winPtr == NULL || winPtr->window == None) {
  523.     return false;
  524.     }
  525.  
  526.     TkGenerateActivateEvents(winPtr,
  527.         (eventPtr->modifiers & activeFlag) ? 1 : 0);
  528.     return true;
  529. }
  530.  
  531. /*
  532.  *----------------------------------------------------------------------
  533.  *
  534.  * XSetInputFocus --
  535.  *
  536.  *    Change the focus window for the application.
  537.  *
  538.  * Results:
  539.  *    None.
  540.  *
  541.  * Side effects:
  542.  *    May change the window used by Key events.
  543.  *
  544.  *----------------------------------------------------------------------
  545.  */
  546.  
  547. void
  548. XSetInputFocus(
  549.     Display* display,
  550.     Window focus,
  551.     int revert_to,
  552.     Time time)
  553. {
  554.     Tk_Window tkwin;
  555.     
  556.     display->request++;
  557.     tkwin = Tk_IdToWindow(tkDisplayList->display, focus);
  558.     if (tkwin == NULL) {
  559.     return;
  560.     }
  561.     
  562.     tkMacFocusWin = tkwin;
  563. }
  564.  
  565. /*
  566.  *----------------------------------------------------------------------
  567.  *
  568.  * TkpChangeFocus --
  569.  *
  570.  *    This procedure is a syub on the Mac because we always own the
  571.  *    focus if we are a front most application.
  572.  *
  573.  * Results:
  574.  *    None.
  575.  *
  576.  * Side effects:
  577.  *    None.
  578.  *
  579.  *----------------------------------------------------------------------
  580.  */
  581.  
  582. void
  583. TkpChangeFocus(winPtr, force)
  584.     TkWindow *winPtr;        /* Window that is to receive the X focus. */
  585.     int force;            /* Non-zero means claim the focus even
  586.                  * if it didn't originally belong to
  587.                  * topLevelPtr's application. */
  588. {
  589.     Tk_Window tkwin;
  590.     
  591.     /*
  592.      * Change the focus on the Mac.  (The same as XSetFocus.)  Don't
  593.      * set the focus to a window that's marked override-redirect.
  594.      */
  595.  
  596.     if (winPtr->atts.override_redirect) {
  597.     return;
  598.     }
  599.     tkDisplayList->display->request++;
  600.     tkwin = Tk_IdToWindow(tkDisplayList->display, winPtr->window);
  601.     if (tkwin == NULL) {
  602.     return;
  603.     }
  604.     
  605.     tkMacFocusWin = tkwin;
  606.  
  607.     /*
  608.      * Remember the current serial number for the X server and issue
  609.      * a dummy server request.  This marks the position at which we
  610.      * changed the focus, so we can distinguish FocusIn and FocusOut
  611.      * events on either side of the mark.
  612.      */
  613.  
  614.     winPtr->mainPtr->focusSerial = NextRequest(winPtr->display);
  615.     return;
  616. }
  617.  
  618. /*
  619.  *----------------------------------------------------------------------
  620.  *
  621.  * GenerateFocusEvents --
  622.  *
  623.  *    Generate FocusIn/FocusOut events from a Macintosh Activate 
  624.  *    event.  Note, the activate-on-foreground bit must be set in 
  625.  *    the SIZE flags to ensure we get Activate/Deactivate in addition 
  626.  *    to Susspend/Resume events.
  627.  *
  628.  * Results:
  629.  *    Returns true if events were generate.
  630.  *
  631.  * Side effects:
  632.  *    Queue events on Tk's event queue.
  633.  *
  634.  *----------------------------------------------------------------------
  635.  */
  636.  
  637. static int
  638. GenerateFocusEvents(
  639.     EventRecord *eventPtr,    /* Incoming Mac event */
  640.     Window window)        /* Root X window for event. */
  641. {
  642.     XEvent event;
  643.     Tk_Window tkwin;
  644.     
  645.     tkwin = Tk_IdToWindow(tkDisplayList->display, window);
  646.     if (tkwin == NULL) {
  647.     return false;
  648.     }
  649.  
  650.     /* 
  651.      * Generate FocusIn and FocusOut events.  This event
  652.      * is only sent to the toplevel window.
  653.      */
  654.     if (eventPtr->modifiers & activeFlag) {
  655.     event.xany.type = FocusIn;
  656.     tkMacFocusWin = tkwin;
  657.     } else {
  658.     event.xany.type = FocusOut;
  659.     }
  660.  
  661.     event.xany.serial = tkDisplayList->display->request;
  662.     event.xany.send_event = False;
  663.     event.xfocus.display = tkDisplayList->display;
  664.     event.xfocus.window = window;
  665.     event.xfocus.mode = NotifyNormal;
  666.     event.xfocus.detail = NotifyDetailNone;
  667.  
  668.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  669.     return true;
  670. }
  671.  
  672. /*
  673.  *----------------------------------------------------------------------
  674.  *
  675.  * GenerateKeyEvent --
  676.  *
  677.  *    Given Macintosh keyUp, keyDown & autoKey events this function
  678.  *    generates the appropiate X key events.
  679.  *
  680.  * Results:
  681.  *    True if event(s) are generated - false otherwise.
  682.  *
  683.  * Side effects:
  684.  *    Additional events may be place on the Tk event queue.
  685.  *
  686.  *----------------------------------------------------------------------
  687.  */
  688.  
  689. static int
  690. GenerateKeyEvent(
  691.     EventRecord *eventPtr,    /* Incoming Mac event */
  692.     Window window)        /* Root X window for event. */
  693. {
  694.     Point where;
  695.     Tk_Window tkwin;
  696.     XEvent event;
  697.  
  698.     /*
  699.      * The focus window is set during FocusIn events and
  700.      * explicit calls to XSetInputFocus.  We just use that
  701.      * value.  Tk will make sure the event gets to the *real*
  702.      * window the focus belongs to.
  703.      */
  704.     tkwin = tkMacFocusWin;
  705.     if (tkwin == NULL) {
  706.     return false;
  707.     }
  708.     where.v = eventPtr->where.v;
  709.     where.h = eventPtr->where.h;
  710.  
  711.     event.xany.send_event = False;
  712.     event.xkey.same_screen = true;
  713.     event.xkey.subwindow = None;
  714.     event.xkey.time = TkpGetMS();
  715.  
  716.     event.xkey.x_root = where.h;
  717.     event.xkey.y_root = where.v;
  718.     GlobalToLocal(&where);
  719.     Tk_TopCoordsToWindow(tkwin, where.h, where.v, 
  720.         &event.xkey.x, &event.xkey.y);
  721.     event.xkey.keycode = eventPtr->message;
  722.  
  723.     event.xany.serial = Tk_Display(tkwin)->request;
  724.     event.xkey.window = Tk_WindowId(tkwin);
  725.     event.xkey.display = Tk_Display(tkwin);
  726.     event.xkey.root = XRootWindow(Tk_Display(tkwin), 0);
  727.     event.xkey.state = TkMacButtonKeyState();
  728.  
  729.     if (eventPtr->what == keyDown) {
  730.     event.xany.type = KeyPress;
  731.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  732.     } else if (eventPtr->what == keyUp) {
  733.     event.xany.type = KeyRelease;
  734.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  735.     } else {
  736.     /*
  737.      * Autokey events send multiple XKey events.
  738.      *
  739.      * Note: the last KeyRelease will always be missed with
  740.      * this scheme.  However, most Tk scripts don't look for
  741.      * KeyUp events so we should be OK.
  742.      */
  743.     event.xany.type = KeyRelease;
  744.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  745.     event.xany.type = KeyPress;
  746.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  747.     }
  748.     return true;
  749. }
  750.  
  751. /*
  752.  *----------------------------------------------------------------------
  753.  *
  754.  * GeneratePollingEvents --
  755.  *
  756.  *    This function polls the mouse position and generates X Motion,
  757.  *    Enter & Leave events.  The cursor is also updated at this
  758.  *    time.
  759.  *
  760.  * Results:
  761.  *    True if event(s) are generated - false otherwise.  
  762.  *
  763.  * Side effects:
  764.  *    Additional events may be place on the Tk event queue.
  765.  *    The cursor may be changed.
  766.  *
  767.  *----------------------------------------------------------------------
  768.  */
  769.  
  770. static int
  771. GeneratePollingEvents()
  772. {
  773.     Tk_Window tkwin, rootwin;
  774.     Window window;
  775.     WindowRef whichwindow, frontWin;
  776.     Point whereLocal, whereGlobal;
  777.     Boolean inContentRgn;
  778.     short part;
  779.     int local_x, local_y;
  780.     int generatedEvents = false;
  781.     
  782.     /*
  783.      * First we get the current mouse position and determine
  784.      * what Tk window the mouse is over (if any).
  785.      */
  786.     frontWin = FrontWindow();
  787.     if (frontWin == NULL) {
  788.     return false;
  789.     }
  790.     SetPort((GrafPort *) frontWin);
  791.    
  792.     GetMouse(&whereLocal);
  793.     whereGlobal = whereLocal;
  794.     LocalToGlobal(&whereGlobal);
  795.     
  796.     part = FindWindow(whereGlobal, &whichwindow);
  797.     inContentRgn = (part == inContent || part == inGrow);
  798.  
  799.     if ((frontWin != whichwindow) || !inContentRgn) {
  800.     tkwin = NULL;
  801.     } else {
  802.     window = TkMacGetXWindow(whichwindow);
  803.     rootwin = Tk_IdToWindow(tkDisplayList->display, window);
  804.     if (rootwin == NULL) {
  805.         tkwin = NULL;
  806.     } else {
  807.         tkwin = Tk_TopCoordsToWindow(rootwin, whereLocal.h, whereLocal.v, 
  808.             &local_x, &local_y);
  809.     }
  810.     }
  811.     
  812.     /*
  813.      * The following call will generate the appropiate X events and
  814.      * adjust any state that Tk must remember.
  815.      */
  816.     Tk_UpdatePointer(tkwin, whereGlobal.h,  whereGlobal.v, TkMacButtonKeyState());
  817.     
  818.     /*
  819.      * Finally, we make sure the proper cursor is installed.  The installation
  820.      * is polled to 1) make our resize hack work, and 2) make sure we have the 
  821.      * proper cursor even if someone else changed the cursor out from under
  822.      * us.
  823.      */
  824.     if ((gGrabWinPtr == NULL) && (part == inGrow) && 
  825.         TkMacResizable((TkWindow *) tkwin) && 
  826.         (TkMacGetScrollbarGrowWindow((TkWindow *) tkwin) == NULL)) {
  827.     TkMacInstallCursor(1);
  828.     } else {
  829.     TkMacInstallCursor(0);
  830.     }
  831.  
  832.     return true;
  833. }
  834.  
  835. /*
  836.  *----------------------------------------------------------------------
  837.  *
  838.  * GeneratePollingEvents2 --
  839.  *
  840.  *    This function polls the mouse position and generates X Motion,
  841.  *    Enter & Leave events.  The cursor is also updated at this
  842.  *    time.  NOTE: this version is for Netscape!!!
  843.  *
  844.  * Results:
  845.  *    True if event(s) are generated - false otherwise.  
  846.  *
  847.  * Side effects:
  848.  *    Additional events may be place on the Tk event queue.
  849.  *    The cursor may be changed.
  850.  *
  851.  *----------------------------------------------------------------------
  852.  */
  853.  
  854. static int
  855. GeneratePollingEvents2(
  856.     Window window)
  857. {
  858.     Tk_Window tkwin, rootwin;
  859.     WindowRef whichwindow, frontWin;
  860.     Point whereLocal, whereGlobal;
  861.     int local_x, local_y;
  862.     int generatedEvents = false;
  863.     Rect bounds;
  864.     
  865.     /*
  866.      * First we get the current mouse position and determine
  867.      * what Tk window the mouse is over (if any).
  868.      */
  869.     frontWin = FrontWindow();
  870.     if (frontWin == NULL) {
  871.     return false;
  872.     }
  873.     SetPort((GrafPort *) frontWin);
  874.    
  875.     GetMouse(&whereLocal);
  876.     whereGlobal = whereLocal;
  877.     LocalToGlobal(&whereGlobal);
  878.  
  879.     /*
  880.      * Determine if we are in a Tk window or not.
  881.      */
  882.     whichwindow = (WindowRef) TkMacGetDrawablePort(window);
  883.     if (whichwindow != frontWin) {
  884.     tkwin = NULL;
  885.     } else {
  886.     rootwin = Tk_IdToWindow(tkDisplayList->display, window);
  887.     TkMacWinBounds((TkWindow *) rootwin, &bounds);
  888.     if (!PtInRect(whereLocal, &bounds)) {
  889.         tkwin = NULL;
  890.     } else {
  891.         tkwin = Tk_TopCoordsToWindow(rootwin, whereLocal.h, whereLocal.v, 
  892.             &local_x, &local_y);
  893.     }
  894.     }
  895.  
  896.     /*
  897.      * The following call will generate the appropiate X events and
  898.      * adjust any state that Tk must remember.
  899.      */
  900.     Tk_UpdatePointer(tkwin, whereGlobal.h,  whereGlobal.v, TkMacButtonKeyState());
  901.     
  902.     /*
  903.      * Finally, we make sure the proper cursor is installed.  The installation
  904.      * is polled to 1) make our resize hack work, and 2) make sure we have the 
  905.      * proper cursor even if someone else changed the cursor out from under
  906.      * us.
  907.      */
  908.     TkMacInstallCursor(0);
  909.  
  910.     return true;
  911. }
  912.  
  913. /*
  914.  *----------------------------------------------------------------------
  915.  *
  916.  * TkMacButtonKeyState --
  917.  *
  918.  *    Returns the current state of the button & modifier keys.
  919.  *
  920.  * Results:
  921.  *    A bitwise inclusive OR of a subset of the following:
  922.  *    Button1Mask, ShiftMask, LockMask, ControlMask, Mod?Mask,
  923.  *    Mod?Mask.
  924.  *
  925.  * Side effects:
  926.  *    None.
  927.  *
  928.  *----------------------------------------------------------------------
  929.  */
  930.  
  931. unsigned int
  932. TkMacButtonKeyState()
  933. {
  934.     unsigned int state = 0;
  935.     KeyMap theKeys;
  936.  
  937.     if (Button() & !gEatButtonUp) {
  938.     state |= Button1Mask;
  939.     }
  940.  
  941.     GetKeys(theKeys);
  942.  
  943.     if (theKeys[1] & 2) {
  944.     state |= LockMask;
  945.     }
  946.  
  947.     if (theKeys[1] & 1) {
  948.     state |= ShiftMask;
  949.     }
  950.  
  951.     if (theKeys[1] & 8) {
  952.     state |= ControlMask;
  953.     }
  954.  
  955.     if (theKeys[1] & 32768) {
  956.     state |= Mod1Mask;        /* command key */
  957.     }
  958.  
  959.     if (theKeys[1] & 4) {
  960.     state |= Mod2Mask;        /* option key */
  961.     }
  962.  
  963.     return state;
  964. }
  965.  
  966. /*
  967.  *----------------------------------------------------------------------
  968.  *
  969.  * XGrabKeyboard --
  970.  *
  971.  *    Simulates a keyboard grab by setting the focus.
  972.  *
  973.  * Results:
  974.  *    Always returns GrabSuccess.
  975.  *
  976.  * Side effects:
  977.  *    Sets the keyboard focus to the specified window.
  978.  *
  979.  *----------------------------------------------------------------------
  980.  */
  981.  
  982. int
  983. XGrabKeyboard(
  984.     Display* display,
  985.     Window grab_window,
  986.     Bool owner_events,
  987.     int pointer_mode,
  988.     int keyboard_mode,
  989.     Time time)
  990. {
  991.     gKeyboardWinPtr = Tk_IdToWindow(display, grab_window);
  992.     return GrabSuccess;
  993. }
  994.  
  995. /*
  996.  *----------------------------------------------------------------------
  997.  *
  998.  * XUngrabKeyboard --
  999.  *
  1000.  *    Releases the simulated keyboard grab.
  1001.  *
  1002.  * Results:
  1003.  *    None.
  1004.  *
  1005.  * Side effects:
  1006.  *    Sets the keyboard focus back to the value before the grab.
  1007.  *
  1008.  *----------------------------------------------------------------------
  1009.  */
  1010.  
  1011. void
  1012. XUngrabKeyboard(
  1013.     Display* display,
  1014.     Time time)
  1015. {
  1016.     gKeyboardWinPtr = NULL;
  1017. }
  1018.  
  1019. /*
  1020.  *----------------------------------------------------------------------
  1021.  *
  1022.  * XQueryPointer --
  1023.  *
  1024.  *    Check the current state of the mouse.  This is not a complete
  1025.  *    implementation of this function.  It only computes the root
  1026.  *    coordinates and the current mask.
  1027.  *
  1028.  * Results:
  1029.  *    Sets root_x_return, root_y_return, and mask_return.  Returns
  1030.  *    true on success.
  1031.  *
  1032.  * Side effects:
  1033.  *    None.
  1034.  *
  1035.  *----------------------------------------------------------------------
  1036.  */
  1037.  
  1038. Bool
  1039. XQueryPointer(
  1040.     Display* display,
  1041.     Window w,
  1042.     Window* root_return,
  1043.     Window* child_return,
  1044.     int* root_x_return,
  1045.     int* root_y_return,
  1046.     int* win_x_return,
  1047.     int* win_y_return,
  1048.     unsigned int* mask_return)
  1049. {
  1050.     Point where;
  1051.  
  1052.     GetMouse(&where);
  1053.     LocalToGlobal(&where);
  1054.     *root_x_return = where.h;
  1055.     *root_y_return = where.v;
  1056.     *mask_return = TkMacButtonKeyState();    
  1057.     return True;
  1058. }
  1059.  
  1060. /*
  1061.  *----------------------------------------------------------------------
  1062.  *
  1063.  * TkMacGenerateTime --
  1064.  *
  1065.  *    Returns the total number of ticks from startup  This function
  1066.  *    is used to generate the time of generated X events.
  1067.  *
  1068.  * Results:
  1069.  *    Returns the current time (ticks from startup).
  1070.  *
  1071.  * Side effects:
  1072.  *    None.
  1073.  *
  1074.  *----------------------------------------------------------------------
  1075.  */
  1076.  
  1077. Time
  1078. TkMacGenerateTime()
  1079. {
  1080.     return (Time) LMGetTicks();
  1081. }
  1082.  
  1083. /*
  1084.  *----------------------------------------------------------------------
  1085.  *
  1086.  * TkMacConvertEvent --
  1087.  *
  1088.  *    This function converts a Macintosh event into zero or more
  1089.  *    Tcl events.
  1090.  *
  1091.  * Results:
  1092.  *    Returns 1 if event added to Tcl queue, 0 otherwse.
  1093.  *
  1094.  * Side effects:
  1095.  *    May add events to Tcl's event queue.
  1096.  *
  1097.  *----------------------------------------------------------------------
  1098.  */
  1099.  
  1100. int
  1101. TkMacConvertEvent(
  1102.     EventRecord *eventPtr)
  1103. {
  1104.     WindowRef whichWindow;
  1105.     Window window;
  1106.     int eventFound = false;
  1107.     
  1108.     switch (eventPtr->what) {
  1109.     case nullEvent:
  1110.     case adjustCursorEvent:
  1111.         if (GeneratePollingEvents()) {
  1112.         eventFound = true;
  1113.         }
  1114.         break;
  1115.     case updateEvt:
  1116.         whichWindow = (WindowRef)eventPtr->message;    
  1117.         window = TkMacGetXWindow(whichWindow);
  1118.         if (GenerateUpdateEvent(eventPtr, window)) {
  1119.         eventFound = true;
  1120.         }
  1121.         break;
  1122.     case mouseDown:
  1123.     case mouseUp:
  1124.         FindWindow(eventPtr->where, &whichWindow);
  1125.         window = TkMacGetXWindow(whichWindow);
  1126.         if (WindowManagerMouse(eventPtr, window)) {
  1127.         eventFound = true;
  1128.         }
  1129.         break;
  1130.     case autoKey:
  1131.     case keyDown:
  1132.         /*
  1133.          * Handle menu-key events here.  If it is *not*
  1134.          * a menu key - just fall through to handle as a
  1135.          * normal key event.
  1136.          */
  1137.         if ((eventPtr->modifiers & cmdKey) == cmdKey) {
  1138.         long menuResult;
  1139.         int oldMode;
  1140.  
  1141.         oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
  1142.         menuResult = MenuKey(eventPtr->message & charCodeMask);
  1143.         Tcl_SetServiceMode(oldMode);
  1144.  
  1145.         if (HiWord(menuResult) != 0) {
  1146.             TkMacHandleMenuSelect(menuResult, false);
  1147.             break;
  1148.         }
  1149.         }
  1150.     case keyUp:
  1151.         whichWindow = FrontWindow();
  1152.         window = TkMacGetXWindow(whichWindow);
  1153.         eventFound |= GenerateKeyEvent(eventPtr, window);
  1154.         break;
  1155.     case activateEvt:
  1156.         window = TkMacGetXWindow((WindowRef) eventPtr->message);
  1157.         eventFound |= GenerateActivateEvents(eventPtr, window);
  1158.         eventFound |= GenerateFocusEvents(eventPtr, window);
  1159.         break;
  1160.     case getFocusEvent:
  1161.         eventPtr->modifiers |= activeFlag;
  1162.         window = TkMacGetXWindow((WindowRef) eventPtr->message);
  1163.         eventFound |= GenerateFocusEvents(eventPtr, window);
  1164.         break;
  1165.     case loseFocusEvent:
  1166.         eventPtr->modifiers &= ~activeFlag;
  1167.         window = TkMacGetXWindow((WindowRef) eventPtr->message);
  1168.         eventFound |= GenerateFocusEvents(eventPtr, window);
  1169.         break;
  1170.     case kHighLevelEvent:
  1171.         TkMacDoHLEvent(eventPtr);
  1172.         /* TODO: should return true if events were placed on event queue. */
  1173.         break;
  1174.     case osEvt:
  1175.         /*
  1176.          * Do clipboard conversion.
  1177.          */
  1178.         switch ((eventPtr->message & osEvtMessageMask) >> 24) {
  1179.         case mouseMovedMessage:
  1180.             if (GeneratePollingEvents()) {
  1181.             eventFound = true;
  1182.             }
  1183.             break;
  1184.         case suspendResumeMessage:
  1185.             if (!(eventPtr->message & resumeFlag)) {
  1186.             TkSuspendClipboard();
  1187.             }
  1188.             tkMacAppInFront = (eventPtr->message & resumeFlag);
  1189.             break;
  1190.         }
  1191.         break;
  1192.     case diskEvt:
  1193.         /* 
  1194.          * Disk insertion. 
  1195.          */
  1196.         if (HiWord(eventPtr->message) != noErr) {
  1197.         Point pt;
  1198.             
  1199.         DILoad();
  1200.         pt.v = pt.h = 120;      /* parameter ignored in sys 7 */
  1201.         DIBadMount(pt, eventPtr->message);
  1202.         DIUnload();
  1203.         }
  1204.         break;
  1205.     }
  1206.     
  1207.     return eventFound;
  1208. }
  1209.  
  1210. /*
  1211.  *----------------------------------------------------------------------
  1212.  *
  1213.  * TkMacConvertTkEvent --
  1214.  *
  1215.  *    This function converts a Macintosh event into zero or more
  1216.  *    Tcl events.
  1217.  *
  1218.  * Results:
  1219.  *    Returns 1 if event added to Tcl queue, 0 otherwse.
  1220.  *
  1221.  * Side effects:
  1222.  *    May add events to Tcl's event queue.
  1223.  *
  1224.  *----------------------------------------------------------------------
  1225.  */
  1226.  
  1227. int
  1228. TkMacConvertTkEvent(
  1229.     EventRecord *eventPtr,
  1230.     Window window)
  1231. {
  1232.     int eventFound = false;
  1233.     Point where;
  1234.     
  1235.     switch (eventPtr->what) {
  1236.     case nullEvent:
  1237.     case adjustCursorEvent:
  1238.         if (GeneratePollingEvents2(window)) {
  1239.         eventFound = true;
  1240.         }
  1241.         break;
  1242.     case updateEvt:
  1243.         if (GenerateUpdateEvent(eventPtr, window)) {
  1244.         eventFound = true;
  1245.         }
  1246.         break;
  1247.     case mouseDown:
  1248.     case mouseUp:
  1249.         GetMouse(&where);
  1250.         LocalToGlobal(&where);
  1251.         eventFound |= TkGenerateButtonEvent(where.h, where.v, 
  1252.         window, TkMacButtonKeyState());
  1253.         break;
  1254.     case autoKey:
  1255.     case keyDown:
  1256.         /*
  1257.          * Handle menu-key events here.  If it is *not*
  1258.          * a menu key - just fall through to handle as a
  1259.          * normal key event.
  1260.          */
  1261.         if ((eventPtr->modifiers & cmdKey) == cmdKey) {
  1262.         long menuResult = MenuKey(eventPtr->message & charCodeMask);
  1263.         
  1264.         if (HiWord(menuResult) != 0) {
  1265.             TkMacHandleMenuSelect(menuResult, false);
  1266.             break;
  1267.         }
  1268.         }
  1269.     case keyUp:
  1270.         eventFound |= GenerateKeyEvent(eventPtr, window);
  1271.         break;
  1272.     case activateEvt:
  1273.         eventFound |= GenerateActivateEvents(eventPtr, window);
  1274.         eventFound |= GenerateFocusEvents(eventPtr, window);
  1275.         break;
  1276.     case getFocusEvent:
  1277.         eventPtr->modifiers |= activeFlag;
  1278.         eventFound |= GenerateFocusEvents(eventPtr, window);
  1279.         break;
  1280.     case loseFocusEvent:
  1281.         eventPtr->modifiers &= ~activeFlag;
  1282.         eventFound |= GenerateFocusEvents(eventPtr, window);
  1283.         break;
  1284.     case kHighLevelEvent:
  1285.         TkMacDoHLEvent(eventPtr);
  1286.         /* TODO: should return true if events were placed on event queue. */
  1287.         break;
  1288.     case osEvt:
  1289.         /*
  1290.          * Do clipboard conversion.
  1291.          */
  1292.         switch ((eventPtr->message & osEvtMessageMask) >> 24) {
  1293.         case mouseMovedMessage:
  1294.             if (GeneratePollingEvents2(window)) {
  1295.             eventFound = true;
  1296.             }
  1297.             break;
  1298.         case suspendResumeMessage:
  1299.             if (!(eventPtr->message & resumeFlag)) {
  1300.             TkSuspendClipboard();
  1301.             }
  1302.             tkMacAppInFront = (eventPtr->message & resumeFlag);
  1303.             break;
  1304.         }
  1305.         break;
  1306.     case diskEvt:
  1307.         /* 
  1308.          * Disk insertion. 
  1309.          */
  1310.         if (HiWord(eventPtr->message) != noErr) {
  1311.         Point pt;
  1312.             
  1313.         DILoad();
  1314.         pt.v = pt.h = 120;      /* parameter ignored in sys 7 */
  1315.         DIBadMount(pt, eventPtr->message);
  1316.         DIUnload();
  1317.         }
  1318.         break;
  1319.     }
  1320.     
  1321.     return eventFound;
  1322. }
  1323.  
  1324. /*
  1325.  *----------------------------------------------------------------------
  1326.  *
  1327.  * CheckEventsAvail --
  1328.  *
  1329.  *    Checks to see if events are available on the Macintosh queue.
  1330.  *    This function looks for both queued events (eg. key & button)
  1331.  *    and generated events (update).
  1332.  *
  1333.  * Results:
  1334.  *    True is events exist, false otherwise.
  1335.  *
  1336.  * Side effects:
  1337.  *    None.
  1338.  *
  1339.  *----------------------------------------------------------------------
  1340.  */
  1341.  
  1342. static int
  1343. CheckEventsAvail()
  1344. {
  1345.     QHdrPtr evPtr;
  1346.     WindowPeek macWinPtr;
  1347.     
  1348.     evPtr = GetEvQHdr();
  1349.     if (evPtr->qHead != NULL) {
  1350.     return true;
  1351.     }
  1352.     
  1353.     macWinPtr = (WindowPeek) FrontWindow();
  1354.     while (macWinPtr != NULL) {
  1355.     if (!EmptyRgn(macWinPtr->updateRgn)) {
  1356.         return true;
  1357.     }
  1358.     macWinPtr = macWinPtr->nextWindow;
  1359.     }
  1360.     return false;
  1361. }
  1362.  
  1363. /*
  1364.  *----------------------------------------------------------------------
  1365.  *
  1366.  * TkpSetCapture --
  1367.  *
  1368.  *    This function captures the mouse so that all future events
  1369.  *    will be reported to this window, even if the mouse is outside
  1370.  *    the window.  If the specified window is NULL, then the mouse
  1371.  *    is released. 
  1372.  *
  1373.  * Results:
  1374.  *    None.
  1375.  *
  1376.  * Side effects:
  1377.  *    Sets the capture flag and captures the mouse.
  1378.  *
  1379.  *----------------------------------------------------------------------
  1380.  */
  1381.  
  1382. void
  1383. TkpSetCapture(
  1384.     TkWindow *winPtr)            /* Capture window, or NULL. */
  1385. {
  1386.     while ((winPtr != NULL) && !Tk_IsTopLevel(winPtr)) {
  1387.     winPtr = winPtr->parentPtr;
  1388.     }
  1389.     gGrabWinPtr = (Tk_Window) winPtr;
  1390. }
  1391.  
  1392. /*
  1393.  *----------------------------------------------------------------------
  1394.  *
  1395.  * TkMacWindowOffset --
  1396.  *
  1397.  *    Determines the x and y offset from the orgin of the toplevel
  1398.  *    window dressing (the structure region, ie. title bar) and the
  1399.  *    orgin of the content area.
  1400.  *
  1401.  * Results:
  1402.  *    The x & y offset in pixels.
  1403.  *
  1404.  * Side effects:
  1405.  *    None.
  1406.  *
  1407.  *----------------------------------------------------------------------
  1408.  */
  1409.  
  1410. void
  1411. TkMacWindowOffset(
  1412.     WindowRef wRef,
  1413.     int *xOffset,
  1414.     int *yOffset)
  1415. {
  1416.     OSErr err = noErr;
  1417.     WindowPeek wPeek = (WindowPeek) wRef;
  1418.     RgnHandle strucRgn = wPeek->strucRgn;
  1419.     RgnHandle contRgn = wPeek->contRgn;
  1420.     Rect strucRect, contRect;
  1421.  
  1422.     if (!EmptyRgn(strucRgn) && !EmptyRgn(contRgn)) {
  1423.     strucRect = (**strucRgn).rgnBBox;
  1424.     contRect = (**contRgn).rgnBBox;
  1425.     } else {        
  1426.     /*
  1427.      * The current window's regions are not up to date.
  1428.      * Probably because the window isn't visable.  What we
  1429.      * will do is save the old regions, have the window calculate
  1430.      * what the regions should be, and then restore it self.
  1431.      */
  1432.     strucRgn = NewRgn( );
  1433.     contRgn = NewRgn( );
  1434.  
  1435.     if (!strucRgn || !contRgn) {
  1436.         err = MemError( );
  1437.     } else {
  1438.         CopyRgn(wPeek->strucRgn, strucRgn);
  1439.         CopyRgn(wPeek->contRgn, contRgn);
  1440.  
  1441.         if (!(err = TellWindowDefProcToCalcRegions(wRef))) {
  1442.         strucRect = (**(wPeek->strucRgn)).rgnBBox;
  1443.         contRect = (**(wPeek->contRgn)).rgnBBox;
  1444.         }
  1445.  
  1446.         CopyRgn(strucRgn, wPeek->strucRgn);
  1447.         CopyRgn(contRgn, wPeek->contRgn);
  1448.     }
  1449.  
  1450.     if (contRgn) {
  1451.         DisposeRgn(contRgn);
  1452.     }
  1453.         
  1454.     if (strucRgn) {
  1455.         DisposeRgn(strucRgn);
  1456.     }
  1457.     }
  1458.  
  1459.     if (!err) {
  1460.     *xOffset = contRect.left - strucRect.left;
  1461.     *yOffset = contRect.top - strucRect.top;
  1462.     } else {
  1463.     *xOffset = 0;
  1464.     *yOffset = 0;
  1465.     }
  1466.  
  1467.     return;
  1468. }
  1469.  
  1470. /*
  1471.  *----------------------------------------------------------------------
  1472.  *
  1473.  * TellWindowDefProcToCalcRegions --
  1474.  *
  1475.  *    Force a Macintosh window to recalculate it's content and
  1476.  *    structure regions.
  1477.  *
  1478.  * Results:
  1479.  *    An OS error.
  1480.  *
  1481.  * Side effects:
  1482.  *    The windows content and structure regions may be updated.
  1483.  *
  1484.  *----------------------------------------------------------------------
  1485.  */
  1486.  
  1487. static OSErr 
  1488. TellWindowDefProcToCalcRegions(
  1489.     WindowRef wRef)
  1490. {
  1491.     OSErr err = noErr;
  1492.     SInt8 hState;
  1493.     Handle wdef = ((WindowPeek) wRef)->windowDefProc;
  1494.  
  1495.     /*
  1496.      * Load and lock the window definition procedure for
  1497.      * the window.
  1498.      */
  1499.     hState = HGetState(wdef);
  1500.     if (!(err = MemError())) {
  1501.     LoadResource(wdef);
  1502.     if (!(err = ResError())) {
  1503.         MoveHHi(wdef);
  1504.         err = MemError();
  1505.         if (err == memLockedErr) {
  1506.             err = noErr;
  1507.         } else if (!err) {
  1508.         HLock(wdef);
  1509.         err = MemError();
  1510.         }
  1511.     }
  1512.     }
  1513.     
  1514.     /*
  1515.      * Assuming there are no errors we now call the window definition 
  1516.      * procedure to tell it to calculate the regions for the window.
  1517.      */
  1518.     if (err == noErr) {
  1519.     (void) CallWindowDefProc((WindowDefProcPtr) *wdef,
  1520.         GetWVariant(wRef), wRef, wCalcRgns, 0);
  1521.  
  1522.     HSetState(wdef, hState);
  1523.     if (!err) {
  1524.          err = MemError();
  1525.     }
  1526.     }
  1527.  
  1528.     return err;
  1529. }
  1530.  
  1531. /*
  1532.  *----------------------------------------------------------------------
  1533.  *
  1534.  * BringWindowForward --
  1535.  *
  1536.  *    Bring this background window to the front.  We also set state
  1537.  *    so Tk thinks the button is currently up.
  1538.  *
  1539.  * Results:
  1540.  *    None.
  1541.  *
  1542.  * Side effects:
  1543.  *    The window is brought forward.
  1544.  *
  1545.  *----------------------------------------------------------------------
  1546.  */
  1547.  
  1548. static void 
  1549. BringWindowForward(
  1550.     WindowRef wRef)
  1551. {
  1552.     SelectWindow(wRef);
  1553. }
  1554.  
  1555. /*
  1556.  *----------------------------------------------------------------------
  1557.  *
  1558.  * TkpGetMS --
  1559.  *
  1560.  *    Return a relative time in milliseconds.  It doesn't matter
  1561.  *    when the epoch was.
  1562.  *
  1563.  * Results:
  1564.  *    Number of milliseconds.
  1565.  *
  1566.  * Side effects:
  1567.  *    None.
  1568.  *
  1569.  *----------------------------------------------------------------------
  1570.  */
  1571.  
  1572. unsigned long
  1573. TkpGetMS()
  1574. {
  1575.     long long * int64Ptr;
  1576.     UnsignedWide micros;
  1577.     
  1578.     Microseconds(µs);
  1579.     int64Ptr = (long long *) µs;
  1580.  
  1581.     /*
  1582.      * We need 64 bit math to do this.  This is available in CW 11
  1583.      * and on.  Other's will need to use a different scheme.
  1584.      */
  1585.  
  1586.     *int64Ptr /= 1000;
  1587.  
  1588.     return (long) *int64Ptr;
  1589. }
  1590.