home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tkisrc04.zip / tk / os2 / tkOS2Pointer.c < prev    next >
C/C++ Source or Header  |  1998-08-10  |  28KB  |  1,046 lines

  1. /* 
  2.  * tkOS2Pointer.c --
  3.  *
  4.  *    OS/2 PM specific mouse tracking code.
  5.  *
  6.  * Copyright (c) 1996-1997 Illya Vaes
  7.  * Copyright (c) 1995 Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  */
  12.  
  13.  
  14. #include "tkOS2Int.h"
  15.  
  16. /*
  17.  * Check for enter/leave events every MOUSE_TIMER_INTERVAL milliseconds.
  18.  */
  19.  
  20. #define MOUSE_TIMER_INTERVAL 250
  21.  
  22. /*
  23.  * Mask that selects any of the state bits corresponding to buttons,
  24.  * plus masks that select individual buttons' bits:
  25.  */
  26.  
  27. #define ALL_BUTTONS \
  28.     (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask)
  29. static unsigned int buttonStates[] = {
  30.     Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask
  31. };
  32.  
  33. /*
  34.  * Declarations of static variables used in the grab module.
  35.  */
  36.  
  37. static int captured;        /* 1 if mouse events outside of Tk windows
  38.                  * will be reported, else 0. */
  39. static TkWindow *grabWinPtr;    /* Window that defines the top of the grab
  40.                  * tree in a global grab. */
  41. static TkWindow *keyboardWinPtr;/* Current keyboard grab window. */
  42. static TkWindow *restrictWinPtr;
  43.                 /* Window to which all mouse
  44.                    events will be reported. */
  45.  
  46. /*
  47.  * Declarations of static variables used in mouse position tracking.
  48.  */
  49.  
  50. static POINTL lastMousePos;    /* Last known mouse position. */
  51. static HWND lastMouseWindow;    /* Last known mouse window. */
  52. static TkWindow *lastMouseWinPtr;
  53.                 /* Last window mouse was seen in.  Used to
  54.                  * detect Enter/Leave events. */
  55. static Tcl_TimerToken mouseTimer;
  56.                 /* Handle to the latest mouse timer. */
  57. static int mouseTimerSet;    /* Non-zero if the mouse timer is active. */
  58.  
  59. /*
  60.  * Forward declarations of procedures used in this file.
  61.  */
  62.  
  63. static void        InitializeCrossingEvent (
  64.                     XEvent *eventPtr, TkWindow *winPtr,
  65.                 long x, long y);
  66. static void        MouseTimerProc (ClientData clientData);
  67. static int        UpdateMousePosition (HWND hwnd,
  68.                 TkWindow *winPtr, long x, long y);
  69.  
  70. /*
  71.  *----------------------------------------------------------------------
  72.  *
  73.  * TkOS2PointerInit --
  74.  *
  75.  *    Initialize the mouse pointer module.
  76.  *
  77.  * Results:
  78.  *    None.
  79.  *
  80.  * Side effects:
  81.  *    Initializes various static variables.
  82.  *
  83.  *----------------------------------------------------------------------
  84.  */
  85.  
  86. void
  87. TkOS2PointerInit()
  88. {
  89. #ifdef DEBUG
  90.     printf("TkOS2PointerInit\n");
  91. #endif
  92.     captured = 0;
  93.     grabWinPtr = NULL;
  94.     keyboardWinPtr = NULL;
  95.     restrictWinPtr = NULL;
  96.  
  97.     mouseTimerSet = 0;
  98.     rc = WinQueryPointerPos(HWND_DESKTOP, &lastMousePos);
  99. #ifdef DEBUG
  100.     if (rc != TRUE) {
  101.         printf("WinQueryPointerPos ERROR %x\n", WinGetLastError(hab));
  102.     } else {
  103.         printf("WinQueryPointerPos OK: (%d,%d)\n", lastMousePos.x,
  104.                lastMousePos.y);
  105.     }
  106. #endif
  107.     lastMouseWindow = WinWindowFromPoint(HWND_DESKTOP, &lastMousePos, TRUE);
  108.     lastMouseWinPtr = NULL;
  109. }
  110.  
  111. /*
  112.  *----------------------------------------------------------------------
  113.  *
  114.  * TkOS2PointerDeadWindow --
  115.  *
  116.  *    Clean up pointer module state when a window is destroyed.
  117.  *
  118.  * Results:
  119.  *    None.
  120.  *
  121.  * Side effects:
  122.  *    May change the grab module settings.
  123.  *
  124.  *----------------------------------------------------------------------
  125.  */
  126.  
  127. void
  128. TkOS2PointerDeadWindow(winPtr)
  129.     TkWindow *winPtr;
  130. {
  131. #ifdef DEBUG
  132.     printf("TkOS2PointerDeadWindow, winPtr %x, lastMouseWinPtr %x,
  133.            grabWinPtr %x, restrictWinPtr %x\n", lastMouseWinPtr, grabWinPtr,
  134.            restrictWinPtr);
  135. #endif
  136.     if (winPtr == lastMouseWinPtr) {
  137. #ifdef DEBUG
  138.         printf("    Setting lastMouseWinPtr to NULL\n");
  139. #endif
  140.     lastMouseWinPtr = NULL;
  141.     }
  142.     if (winPtr == grabWinPtr) {
  143. #ifdef DEBUG
  144.         printf("    Setting grabWinPtr to NULL\n");
  145. #endif
  146.     grabWinPtr = NULL;
  147.     }
  148.     if (winPtr == restrictWinPtr) {
  149. #ifdef DEBUG
  150.         printf("    Setting restrictWinPtr to NULL\n");
  151. #endif
  152.     restrictWinPtr = NULL;
  153.     }
  154.     if (!(restrictWinPtr || grabWinPtr)) {
  155.         BOOL rc;
  156. #ifdef DEBUG
  157.         printf("    Releasing capture\n");
  158. #endif
  159.     captured = 0;
  160.     /* Release capture */
  161.     rc = WinSetCapture(HWND_DESKTOP, NULLHANDLE);
  162. #ifdef DEBUG
  163.         if (rc == FALSE) {
  164.             printf("WinSetCapture NULLHANDLE ERROR %x\n", WinGetLastError(hab));
  165.         } else {
  166.             printf("    WinSetCapture NULLHANDLE OK\n");
  167.         }
  168. #endif
  169.     }
  170. #ifdef DEBUG
  171.     else {
  172.         printf("    ELSE Releasing capture, rwp %x, gwp %x\n", restrictWinPtr,
  173.                grabWinPtr);
  174.     }
  175. #endif
  176. }
  177.  
  178. /*
  179.  *----------------------------------------------------------------------
  180.  *
  181.  * TkOS2PointerEvent --
  182.  *
  183.  *    This procedure is called for each pointer-related event,
  184.  *    before the event is queued.  It simulates X style automatic
  185.  *    grabs so that button release events are not lost.  It also
  186.  *    updates the pointer position so enter/leave events will be
  187.  *    correctly generated.
  188.  *
  189.  * Results:
  190.  *    Returns 0 if the event should be discarded.
  191.  *
  192.  * Side effects:
  193.  *    Changes the current mouse capture window. 
  194.  *
  195.  *----------------------------------------------------------------------
  196.  */
  197.  
  198. void
  199. TkOS2PointerEvent(eventPtr, winPtr)
  200.     XEvent *eventPtr;        /* Event to process */
  201.     TkWindow *winPtr;        /* Window to which event was reported. */
  202. {
  203.     POINTL pos;
  204.     HWND hwnd;
  205.     TkOS2Drawable *todPtr;
  206.  
  207. #ifdef DEBUG
  208.     printf("TkOS2PointerEvent, x_root %d, y_root %d, winPtr %x, display %x\n",
  209.            eventPtr->xmotion.x_root, eventPtr->xmotion.y_root, winPtr,
  210.            winPtr->display);
  211. #endif
  212.  
  213.     /*
  214.      * If the mouse is captured, OS/2 PM will report all pointer
  215.      * events to the capture window.  So, we need to determine which
  216.      * window the mouse is really over and change the event.  Note
  217.      * that the computed hwnd may point to a window not owned by Tk,
  218.      * or a toplevel decorative frame, so winPtr can be NULL.
  219.      */
  220.  
  221.     if (captured) {
  222.     pos.x = eventPtr->xmotion.x_root;
  223.         /* Translate Y coordinate to PM */
  224.     pos.y = yScreen - eventPtr->xmotion.y_root;
  225. #ifdef DEBUG
  226.         printf("    captured, eventPtr %x, %d,%d (PM %d)\n", eventPtr,
  227.                eventPtr->xmotion.x_root, eventPtr->xmotion.y_root, pos.y);
  228. #endif
  229.         hwnd = WinWindowFromPoint(HWND_DESKTOP, &pos, TRUE);
  230.     todPtr = TkOS2GetDrawableFromHandle(hwnd);
  231.     if (todPtr && (todPtr->type == TOD_WINDOW)) {
  232.         winPtr = TkOS2GetWinPtr(todPtr);
  233.     } else {
  234.         winPtr = NULL;
  235.     }
  236. #ifdef DEBUG
  237.         printf("    hwnd %x, todPtr %x, winPtr %x\n", hwnd, todPtr, winPtr);
  238. #endif
  239.     } else {
  240.     hwnd = TkOS2GetHWND(Tk_WindowId(winPtr));
  241. #ifdef DEBUG
  242.         printf("    not captured, hwnd %x\n", hwnd);
  243. #endif
  244.     }
  245.  
  246.     switch (eventPtr->type) {
  247.     case MotionNotify: 
  248. #ifdef DEBUG
  249.             printf("    MotionNotify, winPtr %x, display %x\n", winPtr,
  250.                    winPtr!=NULL ? winPtr->display : 0x0);
  251. #endif
  252.  
  253.         /*
  254.          * If updating the mouse position caused an enter or leave
  255.          * event to be generated, we discard the motion event.
  256.          */
  257.  
  258.         if (UpdateMousePosition(hwnd, winPtr, eventPtr->xmotion.x_root,
  259.             eventPtr->xmotion.y_root)) {
  260.         return;
  261.         }
  262.         break;
  263.  
  264.     case ButtonPress:
  265. #ifdef DEBUG
  266.             printf("    ButtonPress\n");
  267. #endif
  268.  
  269.         /*
  270.          * Set mouse capture and the restrict window if we are
  271.          * currently unrestricted.  However, If this is not the
  272.          * first button pressed and we are already grabbed, do not
  273.          * change anything.
  274.          */
  275.  
  276.         if (!restrictWinPtr) {
  277.         if (!grabWinPtr) {
  278.             /*
  279.              * Mouse was ungrabbed, so set a button grab.
  280.              */
  281.  
  282.             restrictWinPtr = winPtr;
  283.             captured = 1;
  284.             rc = WinSetCapture(HWND_DESKTOP, hwnd);
  285. #ifdef DEBUG
  286.                     if (rc == FALSE) {
  287.                         printf("    Button grab WinSetCapture ERROR %x\n",
  288.                                WinGetLastError(hab));
  289.                     } else {
  290.                         printf("    Button grab WinSetCapture OK\n");
  291.                     }
  292. #endif
  293.         } else if ((eventPtr->xmotion.state & ALL_BUTTONS) == 0) {
  294.  
  295.             /*
  296.              * Mouse was grabbed, but not in a button grab.
  297.              * Make sure the new restrict window is inside the
  298.              * current grab tree.
  299.              */
  300.  
  301.             if (TkPositionInTree(winPtr, grabWinPtr)
  302.                 == TK_GRAB_IN_TREE) {
  303.             restrictWinPtr = winPtr;
  304.             } else {
  305.             restrictWinPtr = grabWinPtr;
  306.             }
  307.             captured = 1;
  308.             rc = WinSetCapture(HWND_DESKTOP,
  309.                           TkOS2GetHWND(Tk_WindowId(restrictWinPtr)));
  310. #ifdef DEBUG
  311.                     if (rc == FALSE) {
  312.                         printf("    Window grab %x WinSetCapture ERROR %x\n",
  313.                                TkOS2GetHWND(Tk_WindowId(restrictWinPtr)),
  314.                                WinGetLastError(hab));
  315.                     } else {
  316.                         printf("    Window grab %x WinSetCapture OK\n",
  317.                                TkOS2GetHWND(Tk_WindowId(restrictWinPtr)));
  318.                     }
  319. #endif
  320.         }
  321.         }
  322.         break;
  323.  
  324.     case ButtonRelease:
  325. #ifdef DEBUG
  326.             printf("    ButtonRelease\n");
  327. #endif
  328.  
  329.         /*
  330.          * Release the mouse capture when the last button is
  331.          * released and we aren't in a global grab.
  332.          */
  333.             
  334.         if ((eventPtr->xbutton.state & ALL_BUTTONS)
  335.             == buttonStates[eventPtr->xbutton.button - Button1]) {
  336.         if (!grabWinPtr) {
  337.             captured = 0;
  338.                 rc = WinSetCapture(HWND_DESKTOP, NULLHANDLE);
  339. #ifdef DEBUG
  340.                     if (rc == FALSE) {
  341.                         printf("    WinSetCapture NULLHANDLE ERROR %x\n",
  342.                                WinGetLastError(hab));
  343.                     } else {
  344.                         printf("    WinSetCapture NULLHANDLE OK\n");
  345.                     }
  346. #endif
  347.         }
  348. #ifdef DEBUG
  349.                 else {
  350.                     printf("    ELSE Releasing capture, gwp %x\n", grabWinPtr);
  351.                 }
  352. #endif
  353.  
  354.         /*
  355.          * If we are releasing a restrict window, then we need
  356.          * to send the button event followed by mouse motion from
  357.          * the restrict window the the current mouse position.
  358.          */
  359.  
  360.         if (restrictWinPtr) {
  361.             if (Tk_WindowId(restrictWinPtr) != eventPtr->xany.window) {
  362.             TkChangeEventWindow(eventPtr, restrictWinPtr);
  363.             }
  364.             Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_TAIL);
  365.             lastMouseWinPtr = restrictWinPtr;
  366.             restrictWinPtr = NULL;
  367.             UpdateMousePosition(hwnd, winPtr, eventPtr->xmotion.x_root,
  368.                 eventPtr->xmotion.y_root);
  369.             return;
  370.         }
  371.         }
  372.         break;
  373.     }
  374.  
  375.     /*
  376.      * If a restrict window is set, make sure the pointer event is reported
  377.      * relative to that window.  Otherwise, if a global grab is in effect
  378.      * then events outside of window managed by Tk should be reported to the
  379.      * grab window.
  380.      */
  381.  
  382.     if (restrictWinPtr) {
  383.     winPtr = restrictWinPtr;
  384.     } else if (grabWinPtr && !winPtr) {
  385.     winPtr = grabWinPtr;
  386.     }
  387.  
  388.     /*
  389.      * If the target window has changed, update the coordinates in the event.
  390.      */
  391.  
  392.     if (winPtr && Tk_WindowId(winPtr) != eventPtr->xany.window) {
  393.     TkChangeEventWindow(eventPtr, winPtr);
  394.     }
  395.     Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_TAIL);
  396. }
  397.  
  398. /*
  399.  *----------------------------------------------------------------------
  400.  *
  401.  * XGrabPointer --
  402.  *
  403.  *    Capture the mouse so event are reported outside of toplevels.
  404.  *    Note that this is a very limited implementation that only
  405.  *    supports GrabModeAsync and owner_events True.
  406.  *
  407.  * Results:
  408.  *    NB! The following remark from the Sun team is not true, this
  409.  *    generates an errant program. Must always return GrabSuccess.
  410.  *    AlreadyGrabbed if we cannot grab, GrabSuccess otherwise.
  411.  *
  412.  * Side effects:
  413.  *    Turns on mouse capture, sets the global grab pointer, and
  414.  *    clears any window restrictions.
  415.  *
  416.  *----------------------------------------------------------------------
  417.  */
  418.  
  419. int
  420. XGrabPointer(display, grab_window, owner_events, event_mask, pointer_mode,
  421.     keyboard_mode, confine_to, cursor, time)
  422.     Display* display;
  423.     Window grab_window;
  424.     Bool owner_events;
  425.     unsigned int event_mask;
  426.     int pointer_mode;
  427.     int keyboard_mode;
  428.     Window confine_to;
  429.     Cursor cursor;
  430.     Time time;
  431. {
  432.     HWND hwnd = TkOS2GetHWND(grab_window);
  433.  
  434. #ifdef DEBUG
  435.     printf("XGrabPointer\n");
  436. #endif
  437.  
  438.     grabWinPtr = TkOS2GetWinPtr(grab_window);
  439.     captured = 1;
  440.     restrictWinPtr = NULL;
  441.     rc = WinSetCapture(HWND_DESKTOP, hwnd);
  442. #ifdef DEBUG
  443.     if (rc == FALSE) {
  444.         printf("    WinSetCapture %x ERROR %x\n", hwnd, WinGetLastError(hab));
  445.     } else {
  446.         printf("    WinSetCapture %x OK\n", hwnd);
  447.     }
  448. #endif
  449.     if (TkPositionInTree(lastMouseWinPtr, grabWinPtr) == TK_GRAB_IN_TREE) {
  450.         TkOS2UpdateCursor(lastMouseWinPtr);
  451.     } else {
  452.         TkOS2UpdateCursor(grabWinPtr);
  453.     }
  454.     return GrabSuccess;
  455. }
  456.  
  457. /*
  458.  *----------------------------------------------------------------------
  459.  *
  460.  * XUngrabPointer --
  461.  *
  462.  *    Release the current grab.
  463.  *
  464.  * Results:
  465.  *    None.
  466.  *
  467.  * Side effects:
  468.  *    Releases the mouse capture.
  469.  *
  470.  *----------------------------------------------------------------------
  471.  */
  472.  
  473. void
  474. XUngrabPointer(display, time)
  475.     Display* display;
  476.     Time time;
  477. {
  478. #ifdef DEBUG
  479.     printf("XUngrabPointer\n");
  480. #endif
  481.     captured = 0;
  482.     grabWinPtr = NULL;
  483.     restrictWinPtr = NULL;
  484.     rc = WinSetCapture(HWND_DESKTOP, NULLHANDLE);
  485. #ifdef DEBUG
  486.     if (rc == FALSE) {
  487.         printf("    WinSetCapture NULLHANDLE ERROR %x\n", WinGetLastError(hab));
  488.     } else {
  489.         printf("    WinSetCapture NULLHANDLE OK\n");
  490.     }
  491.     printf("    calling TkOS2UpdateCursor with lastMouseWinPtr %x, display %x\n",
  492.            lastMouseWinPtr,
  493.            lastMouseWinPtr != 0 ? lastMouseWinPtr->display : 0x0);
  494. #endif
  495.     TkOS2UpdateCursor(lastMouseWinPtr);
  496. }
  497.  
  498. /*
  499.  *----------------------------------------------------------------------
  500.  *
  501.  * XGrabKeyboard --
  502.  *
  503.  *    Simulates a keyboard grab by setting the focus.
  504.  *
  505.  * Results:
  506.  *    Always returns GrabSuccess.
  507.  *
  508.  * Side effects:
  509.  *    Sets the keyboard focus to the specified window.
  510.  *
  511.  *----------------------------------------------------------------------
  512.  */
  513.  
  514. int
  515. XGrabKeyboard(display, grab_window, owner_events, pointer_mode,
  516.     keyboard_mode, time)
  517.     Display* display;
  518.     Window grab_window;
  519.     Bool owner_events;
  520.     int pointer_mode;
  521.     int keyboard_mode;
  522.     Time time;
  523. {
  524. #ifdef DEBUG
  525.     printf("XGrabKeyboard\n");
  526. #endif
  527.  
  528.     keyboardWinPtr = TkOS2GetWinPtr(grab_window);
  529.     return GrabSuccess;
  530. }
  531.  
  532. /*
  533.  *----------------------------------------------------------------------
  534.  *
  535.  * XUngrabKeyboard --
  536.  *
  537.  *    Releases the simulated keyboard grab.
  538.  *
  539.  * Results:
  540.  *    None.
  541.  *
  542.  * Side effects:
  543.  *    Sets the keyboard focus back to the value before the grab.
  544.  *
  545.  *----------------------------------------------------------------------
  546.  */
  547.  
  548. void
  549. XUngrabKeyboard(display, time)
  550.     Display* display;
  551.     Time time;
  552. {
  553. #ifdef DEBUG
  554.     printf("XUngrabKeyboard\n");
  555. #endif
  556.  
  557.     keyboardWinPtr = NULL;
  558. }
  559.  
  560. /*
  561.  *----------------------------------------------------------------------
  562.  *
  563.  * InitializeCrossingEvent --
  564.  *
  565.  *    Initializes the common fields for enter/leave events.
  566.  *
  567.  * Results:
  568.  *    None.
  569.  *
  570.  * Side effects:
  571.  *    Fills in the specified event structure.
  572.  *
  573.  *----------------------------------------------------------------------
  574.  */
  575.  
  576. static void
  577. InitializeCrossingEvent(eventPtr, winPtr, x, y)
  578.     XEvent *eventPtr;        /* Event structure to initialize. */
  579.     TkWindow *winPtr;        /* Window to make event relative to. */
  580.     long x, y;            /* Root coords of event. */
  581. {
  582. #ifdef DEBUG
  583.     printf("InitializeCrossingEvent ev %x winPtr %x, (%d,%d)\n", eventPtr,
  584.            winPtr, x, y);
  585. #endif
  586.     eventPtr->xcrossing.serial = LastKnownRequestProcessed(winPtr->display);
  587.     eventPtr->xcrossing.serial = winPtr->display->request++;
  588.     eventPtr->xcrossing.send_event = 0;
  589.     eventPtr->xcrossing.display = winPtr->display;
  590.     eventPtr->xcrossing.root = RootWindow(winPtr->display, winPtr->screenNum);
  591.     eventPtr->xcrossing.time = TkCurrentTime(winPtr->dispPtr);
  592.     eventPtr->xcrossing.x_root = x;
  593.     /* This is an X Event, so we leave Y in X11 coordinates */
  594.     eventPtr->xcrossing.y_root = y;
  595.     eventPtr->xcrossing.state = TkOS2GetModifierState(WM_MOUSEMOVE, 0, 0, 0);
  596.     eventPtr->xcrossing.mode = NotifyNormal;
  597.     eventPtr->xcrossing.focus = False;
  598. }
  599.  
  600. /*
  601.  *----------------------------------------------------------------------
  602.  *
  603.  * UpdateMousePosition --
  604.  *
  605.  *    Update the current mouse window and position, and generate
  606.  *    any enter/leave events that are needed.  Will schedule a
  607.  *    timer to check the mouse position if the pointer is still
  608.  *    inside a Tk window.
  609.  *
  610.  * Results:
  611.  *    Returns 1 if enter/leave events were generated.
  612.  *
  613.  * Side effects:
  614.  *    May generate enter/leave events and schedule a timer.
  615.  *
  616.  *----------------------------------------------------------------------
  617.  */
  618.  
  619. int
  620. UpdateMousePosition(hwnd, winPtr, x, y)
  621.     HWND hwnd;            /* current mouse window */
  622.     TkWindow *winPtr;        /* current Tk window (or NULL)  */
  623.     long x;            /* current mouse position in */
  624.     long y;             /* root coordinates, X11 coordinates */
  625. {
  626.     int crossed = 0;        /* 1 if mouse crossed a window boundary */
  627.     TkWindow *cursorWinPtr;
  628.  
  629. #ifdef DEBUG
  630.     printf("UpdateMousePosition winPtr %x (display %x), lastMouseWinPtr %x (display %x), restrictWinPtr %x (display %x)\n",
  631.            winPtr, winPtr!=NULL ? winPtr->display : 0x0, lastMouseWinPtr,
  632.            lastMouseWinPtr!=NULL ? lastMouseWinPtr->display : 0x0,
  633.            restrictWinPtr, restrictWinPtr!=NULL ? restrictWinPtr->display : 0x0);
  634. #endif
  635.  
  636.     if (winPtr != lastMouseWinPtr) {
  637.     if (restrictWinPtr) {
  638.         int newPos, oldPos;
  639.  
  640.         newPos = TkPositionInTree(winPtr, restrictWinPtr);
  641.         oldPos = TkPositionInTree(lastMouseWinPtr, restrictWinPtr);
  642.  
  643.         /*
  644.          * Check if the mouse crossed into or out of the restrict
  645.          * window.  If so, we need to generate an Enter or Leave event.
  646.          */
  647.  
  648.         if ((newPos != oldPos) && ((newPos == TK_GRAB_IN_TREE)
  649.             || (oldPos == TK_GRAB_IN_TREE))) {
  650.         XEvent event;
  651.  
  652. #ifdef DEBUG
  653.                 printf("calling InitializeCrossingEvent, restrictWinPtr %x\n",
  654.                        restrictWinPtr);
  655. #endif
  656.         InitializeCrossingEvent(&event, restrictWinPtr, x, y);
  657.         if (newPos == TK_GRAB_IN_TREE) {
  658.             event.type = EnterNotify;
  659.         } else {
  660.             event.type = LeaveNotify;
  661.         }
  662.         if ((oldPos == TK_GRAB_ANCESTOR)
  663.             || (newPos == TK_GRAB_ANCESTOR)) {
  664.             event.xcrossing.detail = NotifyAncestor;
  665.         } else {
  666.             event.xcrossing.detail = NotifyVirtual;
  667.         }
  668.         TkChangeEventWindow(&event, restrictWinPtr);
  669.         Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  670.         }
  671.  
  672.     } else {
  673.         TkWindow *targetPtr;
  674.  
  675. #ifdef DEBUG
  676.             printf("    lastMouseWinPtr %x, lMWP->window %x\n", lastMouseWinPtr,
  677.                    lastMouseWinPtr!=NULL ? lastMouseWinPtr->window : -1);
  678. #endif
  679.         if ((lastMouseWinPtr == NULL)
  680.         || (lastMouseWinPtr->window == None)) {
  681. #ifdef DEBUG
  682.                 printf("    setting targetPtr to winPtr %x, display %x\n",
  683.                        winPtr, winPtr!=NULL ? winPtr->display : 0x0);
  684. #endif
  685.         targetPtr = winPtr;
  686.         } else {
  687.         targetPtr = lastMouseWinPtr;
  688. #ifdef DEBUG
  689.                 printf("    setting targetPtr to lastMouseWinPtr %x, display %x\n",
  690.                        lastMouseWinPtr,
  691.                        lastMouseWinPtr!=NULL ? lastMouseWinPtr->display : 0x0);
  692. #endif
  693.         }
  694.  
  695.         if (targetPtr && (targetPtr->window != None)) {
  696.         XEvent event;
  697.  
  698.         /*
  699.          * Generate appropriate Enter/Leave events.
  700.          */
  701.  
  702. #ifdef DEBUG
  703.                  printf("calling InitializeCrossingEvent, targetPtr %x\n",
  704.                         targetPtr);
  705. #endif
  706.         InitializeCrossingEvent(&event, targetPtr, x, y);
  707.  
  708.         TkInOutEvents(&event, lastMouseWinPtr, winPtr, LeaveNotify,
  709.             EnterNotify, TCL_QUEUE_TAIL);
  710.  
  711.         if (TkPositionInTree(winPtr, grabWinPtr) == TK_GRAB_IN_TREE) {
  712.             TkOS2UpdateCursor(winPtr);
  713.         } else {
  714.             TkOS2UpdateCursor(grabWinPtr);
  715.         }
  716.         crossed = 1;
  717.         }
  718.     }
  719.     lastMouseWinPtr = winPtr;
  720.     }
  721.  
  722.     /*
  723.      * Make sure the cursor reflects the current mouse position.
  724.      */
  725.  
  726.     if (restrictWinPtr) {
  727.         cursorWinPtr = restrictWinPtr;
  728.     } else if (grabWinPtr) {
  729.         cursorWinPtr = (TkPositionInTree(winPtr, grabWinPtr)
  730.                 == TK_GRAB_IN_TREE) ? winPtr : grabWinPtr;
  731.     } else {
  732.         cursorWinPtr = winPtr;
  733.     }
  734.     TkOS2UpdateCursor(cursorWinPtr);
  735.  
  736.     lastMouseWindow = hwnd;
  737.     lastMousePos.x = x;
  738.     lastMousePos.y = yScreen - y;
  739. #ifdef DEBUG
  740.     printf("UpdateMousePosition: x %d, y %d (lastMousePos.y %d)\n", x, y,
  741.            lastMousePos.y);
  742. #endif
  743.  
  744.     /*
  745.      * Ensure the mouse timer is set if we are still inside a Tk window.
  746.      */
  747.  
  748.     if (winPtr != NULL && !mouseTimerSet) {
  749.     mouseTimerSet = 1;
  750.     mouseTimer = Tcl_CreateTimerHandler(MOUSE_TIMER_INTERVAL,
  751.                                             MouseTimerProc, NULL);
  752.     }
  753.  
  754.     return crossed;
  755. }
  756.  
  757. /*
  758.  *----------------------------------------------------------------------
  759.  *
  760.  * MouseTimerProc --
  761.  *
  762.  *    Check the current mouse position and look for enter/leave 
  763.  *    events.
  764.  *
  765.  * Results:
  766.  *    None.
  767.  *
  768.  * Side effects:
  769.  *    May schedule a new timer and/or generate enter/leave events.
  770.  *
  771.  *----------------------------------------------------------------------
  772.  */
  773.  
  774. void
  775. MouseTimerProc(clientData)
  776.     ClientData clientData;
  777. {
  778.     POINTL pos;
  779.     HWND hwnd;
  780.     TkOS2Drawable *todPtr;
  781.     TkWindow *winPtr;
  782.  
  783. #ifdef DEBUG
  784.     printf("MouseTimerProc\n");
  785. #endif
  786.  
  787.     mouseTimerSet = 0;
  788.  
  789.     /*
  790.      * Get the current mouse position and window.  Don't do anything
  791.      * if the mouse hasn't moved since the last time we looked.
  792.      */
  793.  
  794.     WinQueryPointerPos(HWND_DESKTOP, &pos);
  795.     if (pos.x == lastMousePos.x && pos.y == lastMousePos.y) {
  796.     /* Mouse hasn't moved */
  797.     hwnd = lastMouseWindow;
  798.     } else {
  799.         /* Mouse has moved, redetermine window */
  800.         hwnd = WinWindowFromPoint(HWND_DESKTOP, &pos, TRUE);
  801.     }
  802.  
  803.     /*
  804.      * Check to see if the current window is managed by Tk.
  805.      */
  806.  
  807.     if (hwnd == lastMouseWindow) {
  808.     winPtr = lastMouseWinPtr;
  809.     } else {
  810.     todPtr = TkOS2GetDrawableFromHandle(hwnd);
  811.     if (todPtr && (todPtr->type == TOD_WINDOW)) {
  812.         winPtr = TkOS2GetWinPtr(todPtr);
  813.     } else {
  814.         winPtr = NULL;
  815.     }
  816.     }
  817.  
  818.     /*
  819.      * Generate enter/leave events.
  820.      */
  821.  
  822.     UpdateMousePosition(hwnd, winPtr, pos.x, yScreen - pos.y);
  823. }
  824.  
  825. /*
  826.  *----------------------------------------------------------------------
  827.  *
  828.  * TkGetPointerCoords --
  829.  *
  830.  *    Fetch the position of the mouse pointer.
  831.  *
  832.  * Results:
  833.  *    *xPtr and *yPtr are filled in with the root coordinates
  834.  *    of the mouse pointer for the display.
  835.  *
  836.  * Side effects:
  837.  *    None.
  838.  *
  839.  *----------------------------------------------------------------------
  840.  */
  841.  
  842. void
  843. TkGetPointerCoords(tkwin, xPtr, yPtr)
  844.     Tk_Window tkwin;        /* Window that identifies screen on which
  845.                  * lookup is to be done. */
  846.     int *xPtr, *yPtr;        /* Store pointer coordinates here. */
  847. {
  848.     POINTL pos;
  849.  
  850. #ifdef DEBUG
  851.     printf("TkGetPointerCoords\n");
  852. #endif
  853.  
  854.     WinQueryPointerPos(HWND_DESKTOP, &pos);
  855.     *xPtr = pos.x;
  856.     /* Translate from PM to X coordinates */
  857.     *yPtr = yScreen - pos.y;
  858. }
  859.  
  860. /*
  861.  *----------------------------------------------------------------------
  862.  *
  863.  * XQueryPointer --
  864.  *
  865.  *    Check the current state of the mouse.  This is not a complete
  866.  *    implementation of this function.  It only computes the root
  867.  *    coordinates and the current mask.
  868.  *
  869.  * Results:
  870.  *    Sets root_x_return, root_y_return, and mask_return.  Returns
  871.  *    true on success.
  872.  *
  873.  * Side effects:
  874.  *    None.
  875.  *
  876.  *----------------------------------------------------------------------
  877.  */
  878.  
  879. Bool
  880. XQueryPointer(display, w, root_return, child_return, root_x_return,
  881.     root_y_return, win_x_return, win_y_return, mask_return)
  882.     Display* display;
  883.     Window w;
  884.     Window* root_return;
  885.     Window* child_return;
  886.     int* root_x_return;
  887.     int* root_y_return;
  888.     int* win_x_return;
  889.     int* win_y_return;
  890.     unsigned int* mask_return;
  891. {
  892. #ifdef DEBUG
  893.     printf("XQueryPointer\n");
  894. #endif
  895.     TkGetPointerCoords(NULL, root_x_return, root_y_return);
  896.     *mask_return = TkOS2GetModifierState(WM_MOUSEMOVE, 0, 0, 0);    
  897.     return True;
  898. }
  899.  
  900. /*
  901.  *----------------------------------------------------------------------
  902.  *
  903.  * XGetInputFocus --
  904.  *
  905.  *    Retrieves the current keyboard focus window.
  906.  *
  907.  * Results:
  908.  *    Returns the current focus window.
  909.  *
  910.  * Side effects:
  911.  *    None.
  912.  *
  913.  *----------------------------------------------------------------------
  914.  */
  915.  
  916. void
  917. XGetInputFocus(display, focus_return, revert_to_return)
  918.     Display *display;
  919.     Window *focus_return;
  920.     int *revert_to_return;
  921. {
  922.     HWND hwnd = WinQueryFocus(HWND_DESKTOP);
  923.     TkOS2Drawable *todPtr = TkOS2GetDrawableFromHandle(hwnd);
  924.  
  925. #ifdef DEBUG
  926.     printf("XGetInputFocus\n");
  927. #endif
  928.  
  929.     /*
  930.      * The focus window may be a Tk window or a window manager decorative
  931.      * frame.
  932.      */
  933.  
  934.     if (todPtr) {
  935.     *focus_return = Tk_WindowId(TkOS2GetWinPtr(todPtr));
  936.     } else {
  937.     *focus_return = NULLHANDLE;
  938.     }
  939.     *revert_to_return = RevertToParent;
  940. }
  941.  
  942. /*
  943.  *----------------------------------------------------------------------
  944.  *
  945.  * XSetInputFocus --
  946.  *
  947.  *    Set the current focus window.
  948.  *
  949.  * Results:
  950.  *    None.
  951.  *
  952.  * Side effects:
  953.  *    Changes the keyboard focus and causes the selected window to
  954.  *    be activated.
  955.  *
  956.  *----------------------------------------------------------------------
  957.  */
  958.  
  959. void
  960. XSetInputFocus(display, focus, revert_to, time)
  961.     Display* display;
  962.     Window focus;
  963.     int revert_to;
  964.     Time time;
  965. {
  966.     HWND hwnd = TkOS2GetHWND(focus);
  967. #ifdef DEBUG
  968.     printf("XSetInputFocus\n");
  969. #endif
  970.     WinSetFocus(HWND_DESKTOP, hwnd);
  971. }
  972.  
  973. /*
  974.  *----------------------------------------------------------------------
  975.  *
  976.  * XDefineCursor --
  977.  *
  978.  *      This function is called to update the cursor on a window.
  979.  *      Since the mouse might be in the specified window, we need to
  980.  *      check the specified window against the current mouse position
  981.  *      and grab state.
  982.  *
  983.  * Results:
  984.  *      None.
  985.  *
  986.  * Side effects:
  987.  *      May update the cursor.
  988.  *
  989.  *----------------------------------------------------------------------
  990.  */
  991.  
  992. void
  993. XDefineCursor(display, w, cursor)
  994.     Display* display;
  995.     Window w;
  996.     Cursor cursor;
  997. {
  998.     TkWindow *winPtr = TkOS2GetWinPtr(w);
  999.  
  1000. #ifdef DEBUG
  1001.     printf("XDefineCursor\n");
  1002. #endif
  1003.  
  1004.     if (restrictWinPtr) {
  1005.  
  1006.         /*
  1007.          * If there is a restrict window, then we only update the cursor
  1008.          * if the restrict window is the window being modified.
  1009.          */
  1010.  
  1011.         if (winPtr == restrictWinPtr) {
  1012.             goto update;
  1013.         }
  1014.     } else if (grabWinPtr) {
  1015.  
  1016.         /*
  1017.          * If a grab is in effect, then we only update the cursor if the mouse
  1018.          * pointer is outside the grab tree and the specified window is the
  1019.          * grab window, or the pointer is inside the grab tree and the
  1020.          * specified window is also the pointer window.
  1021.          */
  1022.  
  1023.         if (TkPositionInTree(lastMouseWinPtr, grabWinPtr) == TK_GRAB_IN_TREE) {
  1024.             if (winPtr == lastMouseWinPtr) {
  1025.                 goto update;
  1026.             }
  1027.         } else if (winPtr == grabWinPtr) {
  1028.             goto update;
  1029.         }
  1030.     } else {
  1031.  
  1032.         /*
  1033.          * Otherwise, we only update the cursor if the specified window
  1034.          * contains the mouse pointer.
  1035.          */
  1036.  
  1037.         if (winPtr == lastMouseWinPtr) {
  1038.             goto update;
  1039.         }
  1040.     }
  1041.     return;
  1042.  
  1043. update:
  1044.     TkOS2UpdateCursor(winPtr);
  1045. }
  1046.