tkPointer.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:17k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tkPointer.c --
  3.  *
  4.  * This file contains functions for emulating the X server
  5.  * pointer and grab state machine.  This file is used by the
  6.  * Mac and Windows platforms to generate appropriate enter/leave
  7.  * events, and to update the global grab window information.
  8.  *
  9.  * Copyright (c) 1996 by Sun Microsystems, Inc.
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  *
  14.  * RCS: @(#) $Id: tkPointer.c,v 1.7 2002/08/31 06:12:25 das Exp $
  15.  */
  16. #include "tkInt.h"
  17. #ifdef __WIN32__
  18. #include "tkWinInt.h"
  19. #endif
  20. #if defined(MAC_TCL)
  21. #include "tkMacInt.h"
  22. #define Cursor XCursor
  23. #endif
  24. #if defined(MAC_OSX_TK)
  25. #include "tkMacOSXInt.h"
  26. #define Cursor XCursor
  27. #endif
  28. /*
  29.  * Mask that selects any of the state bits corresponding to buttons,
  30.  * plus masks that select individual buttons' bits:
  31.  */
  32. #define ALL_BUTTONS 
  33. (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask)
  34. static unsigned int buttonMasks[] = {
  35.     Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask
  36. };
  37. #define ButtonMask(b) (buttonMasks[(b)-Button1])
  38. typedef struct ThreadSpecificData {
  39.     TkWindow *grabWinPtr;         /* Window that defines the top of the
  40.  * grab tree in a global grab. */
  41.     int lastState;         /* Last known state flags. */
  42.     XPoint lastPos;                 /* Last reported mouse position. */
  43.     TkWindow *lastWinPtr;         /* Last reported mouse window. */
  44.     TkWindow *restrictWinPtr;     /* Window to which all mouse events
  45.  * will be reported. */
  46.     TkWindow *cursorWinPtr;         /* Window that is currently
  47.  * controlling the global cursor. */
  48. } ThreadSpecificData;
  49. static Tcl_ThreadDataKey dataKey;
  50. /*
  51.  * Forward declarations of procedures used in this file.
  52.  */
  53. static int GenerateEnterLeave _ANSI_ARGS_((TkWindow *winPtr,
  54.     int x, int y, int state));
  55. static void InitializeEvent _ANSI_ARGS_((XEvent* eventPtr,
  56.     TkWindow *winPtr, int type, int x, int y,
  57.     int state, int detail));
  58. static void UpdateCursor _ANSI_ARGS_((TkWindow *winPtr));
  59. /*
  60.  *----------------------------------------------------------------------
  61.  *
  62.  * InitializeEvent --
  63.  *
  64.  * Initializes the common fields for several X events.
  65.  *
  66.  * Results:
  67.  * None.
  68.  *
  69.  * Side effects:
  70.  * Fills in the specified event structure.
  71.  *
  72.  *----------------------------------------------------------------------
  73.  */
  74. static void
  75. InitializeEvent(eventPtr, winPtr, type, x, y, state, detail)
  76.     XEvent* eventPtr; /* Event structure to initialize. */
  77.     TkWindow *winPtr; /* Window to make event relative to. */
  78.     int type; /* Message type. */
  79.     int x, y; /* Root coords of event. */
  80.     int state; /* State flags. */
  81.     int detail; /* Detail value. */
  82. {
  83.     eventPtr->type = type;
  84.     eventPtr->xany.serial = LastKnownRequestProcessed(winPtr->display);
  85.     eventPtr->xany.send_event = False;
  86.     eventPtr->xany.display = winPtr->display;
  87.     eventPtr->xcrossing.root = RootWindow(winPtr->display, winPtr->screenNum);
  88.     eventPtr->xcrossing.time = TkpGetMS();
  89.     eventPtr->xcrossing.x_root = x;
  90.     eventPtr->xcrossing.y_root = y;
  91.     switch (type) {
  92. case EnterNotify:
  93. case LeaveNotify:
  94.     eventPtr->xcrossing.mode = NotifyNormal;
  95.     eventPtr->xcrossing.state = state;
  96.     eventPtr->xcrossing.detail = detail;
  97.     eventPtr->xcrossing.focus = False;
  98.     break;
  99. case MotionNotify:
  100.     eventPtr->xmotion.state = state;
  101.     eventPtr->xmotion.is_hint = detail;
  102.     break;
  103. case ButtonPress:
  104. case ButtonRelease:
  105.     eventPtr->xbutton.state = state;
  106.     eventPtr->xbutton.button = detail;
  107.     break;
  108.     }
  109.     TkChangeEventWindow(eventPtr, winPtr);
  110. }
  111. /*
  112.  *----------------------------------------------------------------------
  113.  *
  114.  * GenerateEnterLeave --
  115.  *
  116.  * Update the current mouse window and position, and generate
  117.  * any enter/leave events that are needed.
  118.  *
  119.  * Results:
  120.  * Returns 1 if enter/leave events were generated.
  121.  *
  122.  * Side effects:
  123.  * May insert events into the Tk event queue.
  124.  *
  125.  *----------------------------------------------------------------------
  126.  */
  127. static int
  128. GenerateEnterLeave(winPtr, x, y, state)
  129.     TkWindow *winPtr; /* Current Tk window (or NULL). */
  130.     int x,y; /* Current mouse position in root coords. */
  131.     int state; /* State flags. */
  132. {
  133.     int crossed = 0; /* 1 if mouse crossed a window boundary */
  134.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  135.             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  136.     TkWindow *restrictWinPtr = tsdPtr->restrictWinPtr;
  137.     TkWindow *lastWinPtr = tsdPtr->lastWinPtr;
  138.     if (winPtr != tsdPtr->lastWinPtr) {
  139. if (restrictWinPtr) {
  140.     int newPos, oldPos;
  141.     newPos = TkPositionInTree(winPtr, restrictWinPtr);
  142.     oldPos = TkPositionInTree(lastWinPtr, restrictWinPtr);
  143.     /*
  144.      * Check if the mouse crossed into or out of the restrict
  145.      * window.  If so, we need to generate an Enter or Leave event.
  146.      */
  147.     if ((newPos != oldPos) && ((newPos == TK_GRAB_IN_TREE)
  148.     || (oldPos == TK_GRAB_IN_TREE))) {
  149. XEvent event;
  150. int type, detail;
  151. if (newPos == TK_GRAB_IN_TREE) {
  152.     type = EnterNotify;
  153. } else {
  154.     type = LeaveNotify;
  155. }
  156. if ((oldPos == TK_GRAB_ANCESTOR)
  157. || (newPos == TK_GRAB_ANCESTOR)) {
  158.     detail = NotifyAncestor;
  159. } else {
  160.     detail = NotifyVirtual;
  161. }
  162. InitializeEvent(&event, restrictWinPtr, type, x, y,
  163. state, detail);
  164. Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  165.     }
  166. } else {
  167.     TkWindow *targetPtr;
  168.     if ((lastWinPtr == NULL)
  169. || (lastWinPtr->window == None)) {
  170. targetPtr = winPtr;
  171.     } else {
  172. targetPtr = lastWinPtr;
  173.     }
  174.     if (targetPtr && (targetPtr->window != None)) {
  175. XEvent event;
  176. /*
  177.  * Generate appropriate Enter/Leave events.
  178.  */
  179. InitializeEvent(&event, targetPtr, LeaveNotify, x, y, state,
  180. NotifyNormal);
  181. TkInOutEvents(&event, lastWinPtr, winPtr, LeaveNotify,
  182. EnterNotify, TCL_QUEUE_TAIL);
  183. crossed = 1;
  184.     }
  185. }
  186. tsdPtr->lastWinPtr = winPtr;
  187.     }
  188.     return crossed;
  189. }
  190. /*
  191.  *----------------------------------------------------------------------
  192.  *
  193.  * Tk_UpdatePointer --
  194.  *
  195.  * This function updates the pointer state machine given an
  196.  * the current window, position and modifier state.
  197.  *
  198.  * Results:
  199.  * None.
  200.  *
  201.  * Side effects:
  202.  * May queue new events and update the grab state.
  203.  *
  204.  *----------------------------------------------------------------------
  205.  */
  206. void
  207. Tk_UpdatePointer(tkwin, x, y, state)
  208.     Tk_Window tkwin; /* Window to which pointer event
  209.  * is reported. May be NULL. */
  210.     int x, y; /* Pointer location in root coords. */
  211.     int state; /* Modifier state mask. */
  212. {
  213.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  214.             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  215.     TkWindow *winPtr = (TkWindow *)tkwin;
  216.     TkWindow *targetWinPtr;
  217.     XPoint pos;
  218.     XEvent event;
  219.     int changes = (state ^ tsdPtr->lastState) & ALL_BUTTONS;
  220.     int type, b, mask;
  221.     pos.x = x;
  222.     pos.y = y;
  223.     /*
  224.      * Use the current keyboard state, but the old mouse button
  225.      * state since we haven't generated the button events yet.
  226.      */
  227.     tsdPtr->lastState = (state & ~ALL_BUTTONS) | (tsdPtr->lastState
  228.     & ALL_BUTTONS);
  229.     /*
  230.      * Generate Enter/Leave events.  If the pointer has crossed window
  231.      * boundaries, update the current mouse position so we don't generate
  232.      * redundant motion events.
  233.      */
  234.     if (GenerateEnterLeave(winPtr, x, y, tsdPtr->lastState)) {
  235. tsdPtr->lastPos = pos;
  236.     }
  237.     /*
  238.      * Generate ButtonPress/ButtonRelease events based on the differences
  239.      * between the current button state and the last known button state.
  240.      */
  241.     for (b = Button1; b <= Button3; b++) {
  242. mask = ButtonMask(b);
  243. if (changes & mask) {
  244.     if (state & mask) {
  245. type = ButtonPress;
  246.         /*
  247.  * ButtonPress - Set restrict window if we aren't grabbed, or
  248.  * if this is the first button down.
  249.  */
  250. if (!tsdPtr->restrictWinPtr) {
  251.     if (!tsdPtr->grabWinPtr) {
  252. /*
  253.  * Mouse is not grabbed, so set a button grab.
  254.  */
  255. tsdPtr->restrictWinPtr = winPtr;
  256. TkpSetCapture(tsdPtr->restrictWinPtr);
  257.     } else if ((tsdPtr->lastState & ALL_BUTTONS) == 0) {
  258. /*
  259.  * Mouse is in a non-button grab, so ensure
  260.  * the button grab is inside the grab tree.
  261.  */
  262. if (TkPositionInTree(winPtr, tsdPtr->grabWinPtr)
  263. == TK_GRAB_IN_TREE) {
  264.     tsdPtr->restrictWinPtr = winPtr;
  265. } else {
  266.     tsdPtr->restrictWinPtr = tsdPtr->grabWinPtr;
  267. }
  268. TkpSetCapture(tsdPtr->restrictWinPtr);
  269.     }
  270. }
  271.     } else {
  272. type = ButtonRelease;
  273.         /*
  274.  * ButtonRelease - Release the mouse capture and clear the
  275.  * restrict window when the last button is released and we
  276.  * aren't in a global grab.
  277.  */
  278. if ((tsdPtr->lastState & ALL_BUTTONS) == mask) {
  279.     if (!tsdPtr->grabWinPtr) {
  280. TkpSetCapture(NULL);
  281.     }
  282. }
  283. /*
  284.  * If we are releasing a restrict window, then we need
  285.  * to send the button event followed by mouse motion from
  286.  * the restrict window to the current mouse position.
  287.  */
  288. if (tsdPtr->restrictWinPtr) {
  289.     InitializeEvent(&event, tsdPtr->restrictWinPtr, type, x, y,
  290.     tsdPtr->lastState, b);
  291.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  292.     tsdPtr->lastState &= ~mask;
  293.     tsdPtr->lastWinPtr = tsdPtr->restrictWinPtr;
  294.     tsdPtr->restrictWinPtr = NULL;
  295.     GenerateEnterLeave(winPtr, x, y, tsdPtr->lastState);
  296.     tsdPtr->lastPos = pos;
  297.     continue;
  298. }
  299.     }
  300.     /*
  301.      * If a restrict window is set, make sure the pointer event
  302.      * is reported relative to that window.  Otherwise, if a
  303.      * global grab is in effect then events outside of windows
  304.      * managed by Tk should be reported to the grab window.
  305.      */
  306.     if (tsdPtr->restrictWinPtr) {
  307. targetWinPtr = tsdPtr->restrictWinPtr;
  308.     } else if (tsdPtr->grabWinPtr && !winPtr) {
  309. targetWinPtr = tsdPtr->grabWinPtr;
  310.     } else {
  311. targetWinPtr = winPtr;
  312.     }
  313.     /*
  314.      * If we still have a target window, send the event.
  315.      */
  316.     if (winPtr != NULL) {
  317. InitializeEvent(&event, targetWinPtr, type, x, y,
  318. tsdPtr->lastState, b);
  319. Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  320.     }
  321.     /*
  322.      * Update the state for the next iteration.
  323.      */
  324.     tsdPtr->lastState = (type == ButtonPress)
  325. ? (tsdPtr->lastState | mask) : (tsdPtr->lastState & ~mask);
  326.     tsdPtr->lastPos = pos;
  327. }
  328.     }
  329.     /*
  330.      * Make sure the cursor window is up to date.
  331.      */
  332.     if (tsdPtr->restrictWinPtr) {
  333. targetWinPtr = tsdPtr->restrictWinPtr;
  334.     } else if (tsdPtr->grabWinPtr) {
  335. targetWinPtr = (TkPositionInTree(winPtr, tsdPtr->grabWinPtr)
  336. == TK_GRAB_IN_TREE) ? winPtr : tsdPtr->grabWinPtr;
  337.     } else {
  338. targetWinPtr = winPtr;
  339.     }
  340.     UpdateCursor(targetWinPtr);
  341.     /*
  342.      * If no other events caused the position to be updated,
  343.      * generate a motion event.
  344.      */
  345.     if (tsdPtr->lastPos.x != pos.x || tsdPtr->lastPos.y != pos.y) {
  346. if (tsdPtr->restrictWinPtr) {
  347.     targetWinPtr = tsdPtr->restrictWinPtr;
  348. } else if (tsdPtr->grabWinPtr && !winPtr) {
  349.     targetWinPtr = tsdPtr->grabWinPtr;
  350. }
  351. if (targetWinPtr != NULL) {
  352.     InitializeEvent(&event, targetWinPtr, MotionNotify, x, y,
  353.     tsdPtr->lastState, NotifyNormal);
  354.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  355. }
  356. tsdPtr->lastPos = pos;
  357.     }
  358. }
  359. /*
  360.  *----------------------------------------------------------------------
  361.  *
  362.  * XGrabPointer --
  363.  *
  364.  * Capture the mouse so event are reported outside of toplevels.
  365.  * Note that this is a very limited implementation that only
  366.  * supports GrabModeAsync and owner_events True.
  367.  *
  368.  * Results:
  369.  * Always returns GrabSuccess.
  370.  *
  371.  * Side effects:
  372.  * Turns on mouse capture, sets the global grab pointer, and
  373.  * clears any window restrictions.
  374.  *
  375.  *----------------------------------------------------------------------
  376.  */
  377. int
  378. XGrabPointer(display, grab_window, owner_events, event_mask, pointer_mode,
  379. keyboard_mode, confine_to, cursor, time)
  380.     Display* display;
  381.     Window grab_window;
  382.     Bool owner_events;
  383.     unsigned int event_mask;
  384.     int pointer_mode;
  385.     int keyboard_mode;
  386.     Window confine_to;
  387.     Cursor cursor;
  388.     Time time;
  389. {
  390.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  391.             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  392.     display->request++;
  393.     tsdPtr->grabWinPtr = (TkWindow *) Tk_IdToWindow(display, grab_window);
  394.     tsdPtr->restrictWinPtr = NULL;
  395.     TkpSetCapture(tsdPtr->grabWinPtr);
  396.     if (TkPositionInTree(tsdPtr->lastWinPtr, tsdPtr->grabWinPtr) 
  397.             != TK_GRAB_IN_TREE) {
  398. UpdateCursor(tsdPtr->grabWinPtr);
  399.     }
  400.     return GrabSuccess;
  401. }
  402. /*
  403.  *----------------------------------------------------------------------
  404.  *
  405.  * XUngrabPointer --
  406.  *
  407.  * Release the current grab.
  408.  *
  409.  * Results:
  410.  * None.
  411.  *
  412.  * Side effects:
  413.  * Releases the mouse capture.
  414.  *
  415.  *----------------------------------------------------------------------
  416.  */
  417. void
  418. XUngrabPointer(display, time)
  419.     Display* display;
  420.     Time time;
  421. {
  422.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  423.             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  424.     display->request++;
  425.     tsdPtr->grabWinPtr = NULL;
  426.     tsdPtr->restrictWinPtr = NULL;
  427.     TkpSetCapture(NULL);
  428.     UpdateCursor(tsdPtr->lastWinPtr);
  429. }
  430. /*
  431.  *----------------------------------------------------------------------
  432.  *
  433.  * TkPointerDeadWindow --
  434.  *
  435.  * Clean up pointer module state when a window is destroyed.
  436.  *
  437.  * Results:
  438.  * None.
  439.  *
  440.  * Side effects:
  441.  * May release the current capture window.
  442.  *
  443.  *----------------------------------------------------------------------
  444.  */
  445. void
  446. TkPointerDeadWindow(winPtr)
  447.     TkWindow *winPtr;
  448. {
  449.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  450.             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  451.     if (winPtr == tsdPtr->lastWinPtr) {
  452. tsdPtr->lastWinPtr = NULL;
  453.     }
  454.     if (winPtr == tsdPtr->grabWinPtr) {
  455. tsdPtr->grabWinPtr = NULL;
  456.     }
  457.     if (winPtr == tsdPtr->restrictWinPtr) {
  458. tsdPtr->restrictWinPtr = NULL;
  459.     }
  460.     if (!(tsdPtr->restrictWinPtr || tsdPtr->grabWinPtr)) {
  461. TkpSetCapture(NULL);
  462.     }
  463. }
  464. /*
  465.  *----------------------------------------------------------------------
  466.  *
  467.  * UpdateCursor --
  468.  *
  469.  * Set the windows global cursor to the cursor associated with
  470.  * the given Tk window.
  471.  *
  472.  * Results:
  473.  * None.
  474.  *
  475.  * Side effects:
  476.  * Changes the mouse cursor.
  477.  *
  478.  *----------------------------------------------------------------------
  479.  */
  480. static void
  481. UpdateCursor(winPtr)
  482.     TkWindow *winPtr;
  483. {
  484.     Cursor cursor = None;
  485.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  486.             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  487.     /*
  488.      * A window inherits its cursor from its parent if it doesn't
  489.      * have one of its own.  Top level windows inherit the default
  490.      * cursor.
  491.      */
  492.     tsdPtr->cursorWinPtr = winPtr;
  493.     while (winPtr != NULL) {
  494. if (winPtr->atts.cursor != None) {
  495.     cursor = winPtr->atts.cursor;
  496.     break;
  497. } else if (winPtr->flags & TK_TOP_HIERARCHY) {
  498.     break;
  499. }
  500. winPtr = winPtr->parentPtr;
  501.     }
  502.     TkpSetCursor((TkpCursor) cursor);
  503. }
  504. /*
  505.  *----------------------------------------------------------------------
  506.  *
  507.  * XDefineCursor --
  508.  *
  509.  * This function is called to update the cursor on a window.
  510.  * Since the mouse might be in the specified window, we need to
  511.  * check the specified window against the current mouse position
  512.  * and grab state.
  513.  *
  514.  * Results:
  515.  * None.
  516.  *
  517.  * Side effects:
  518.  * May update the cursor.
  519.  *
  520.  *----------------------------------------------------------------------
  521.  */
  522. void
  523. XDefineCursor(display, w, cursor)
  524.     Display* display;
  525.     Window w;
  526.     Cursor cursor;
  527. {
  528.     TkWindow *winPtr = (TkWindow *)Tk_IdToWindow(display, w);
  529.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  530.             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  531.     if (tsdPtr->cursorWinPtr == winPtr) {
  532. UpdateCursor(winPtr);
  533.     }
  534.     display->request++;
  535. }
  536. /*
  537.  *----------------------------------------------------------------------
  538.  *
  539.  * TkGenerateActivateEvents --
  540.  *
  541.  * This function is called by the Mac and Windows window manager
  542.  * routines when a toplevel window is activated or deactivated.
  543.  * Activate/Deactivate events will be sent to every subwindow of
  544.  * the toplevel followed by a FocusIn/FocusOut message.
  545.  *
  546.  * Results:
  547.  * None.
  548.  *
  549.  * Side effects:
  550.  * Generates X events.
  551.  *
  552.  *----------------------------------------------------------------------
  553.  */
  554. void
  555. TkGenerateActivateEvents(winPtr, active)
  556.     TkWindow *winPtr; /* Toplevel to activate. */
  557.     int active; /* Non-zero if the window is being
  558.  * activated, else 0.*/
  559. {
  560.     XEvent event;
  561.     
  562.     /* 
  563.      * Generate Activate and Deactivate events.  This event
  564.      * is sent to every subwindow in a toplevel window.
  565.      */
  566.     event.xany.serial = winPtr->display->request++;
  567.     event.xany.send_event = False;
  568.     event.xany.display = winPtr->display;
  569.     event.xany.window = winPtr->window;
  570.     event.xany.type = active ? ActivateNotify : DeactivateNotify;
  571.     TkQueueEventForAllChildren(winPtr, &event);
  572.     
  573. }