int XGrabPointer( Display *display, Window grab_window, Bool owner_events, unsigned int event_mask, int pointer_mode, int keyboard_mode, Window confine_to, Cursor cursor, Time time) { ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); display->request++; tsdPtr->grabWinPtr = (TkWindow *) Tk_IdToWindow(display, grab_window); tsdPtr->restrictWinPtr = NULL; TkpSetCapture(tsdPtr->grabWinPtr); if (TkPositionInTree(tsdPtr->lastWinPtr, tsdPtr->grabWinPtr) != TK_GRAB_IN_TREE) { UpdateCursor(tsdPtr->grabWinPtr); } return GrabSuccess; }
int TkGrabState( TkWindow *winPtr) /* Window for which grab information is * needed. */ { TkWindow *grabWinPtr = winPtr->dispPtr->grabWinPtr; if (grabWinPtr == NULL) { return TK_GRAB_NONE; } if ((winPtr->mainPtr != grabWinPtr->mainPtr) && !(winPtr->dispPtr->grabFlags & GRAB_GLOBAL)) { return TK_GRAB_NONE; } return TkPositionInTree(winPtr, grabWinPtr); }
void Tk_UpdatePointer( Tk_Window tkwin, /* Window to which pointer event is reported. * May be NULL. */ int x, int y, /* Pointer location in root coords. */ int state) /* Modifier state mask. */ { ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); TkWindow *winPtr = (TkWindow *)tkwin; TkWindow *targetWinPtr; XPoint pos; XEvent event; int changes = (state ^ tsdPtr->lastState) & ALL_BUTTONS; int type, b, mask; pos.x = x; pos.y = y; /* * Use the current keyboard state, but the old mouse button state since we * haven't generated the button events yet. */ tsdPtr->lastState = (state & ~ALL_BUTTONS) | (tsdPtr->lastState & ALL_BUTTONS); /* * Generate Enter/Leave events. If the pointer has crossed window * boundaries, update the current mouse position so we don't generate * redundant motion events. */ if (GenerateEnterLeave(winPtr, x, y, tsdPtr->lastState)) { tsdPtr->lastPos = pos; } /* * Generate ButtonPress/ButtonRelease events based on the differences * between the current button state and the last known button state. */ for (b = Button1; b <= Button5; b++) { mask = ButtonMask(b); if (changes & mask) { if (state & mask) { type = ButtonPress; /* * ButtonPress - Set restrict window if we aren't grabbed, or * if this is the first button down. */ if (!tsdPtr->restrictWinPtr) { if (!tsdPtr->grabWinPtr) { /* * Mouse is not grabbed, so set a button grab. */ tsdPtr->restrictWinPtr = winPtr; TkpSetCapture(tsdPtr->restrictWinPtr); } else if ((tsdPtr->lastState & ALL_BUTTONS) == 0) { /* * Mouse is in a non-button grab, so ensure the button * grab is inside the grab tree. */ if (TkPositionInTree(winPtr, tsdPtr->grabWinPtr) == TK_GRAB_IN_TREE) { tsdPtr->restrictWinPtr = winPtr; } else { tsdPtr->restrictWinPtr = tsdPtr->grabWinPtr; } TkpSetCapture(tsdPtr->restrictWinPtr); } } } else { type = ButtonRelease; /* * ButtonRelease - Release the mouse capture and clear the * restrict window when the last button is released. If we * are in a global grab, restore the grab window capture. */ if ((tsdPtr->lastState & ALL_BUTTONS) == mask) { TkpSetCapture(tsdPtr->grabWinPtr); } /* * If we are releasing a restrict window, then we need to send * the button event followed by mouse motion from the restrict * window to the current mouse position. */ if (tsdPtr->restrictWinPtr) { InitializeEvent(&event, tsdPtr->restrictWinPtr, type, x, y, tsdPtr->lastState, b); Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); tsdPtr->lastState &= ~mask; tsdPtr->lastWinPtr = tsdPtr->restrictWinPtr; tsdPtr->restrictWinPtr = NULL; GenerateEnterLeave(winPtr, x, y, tsdPtr->lastState); tsdPtr->lastPos = pos; continue; } } /* * If a restrict window is set, make sure the pointer event is * reported relative to that window. Otherwise, if a global grab * is in effect then events outside of windows managed by Tk * should be reported to the grab window. */ if (tsdPtr->restrictWinPtr) { targetWinPtr = tsdPtr->restrictWinPtr; } else if (tsdPtr->grabWinPtr && !winPtr) { targetWinPtr = tsdPtr->grabWinPtr; } else { targetWinPtr = winPtr; } /* * If we still have a target window, send the event. */ if (targetWinPtr != NULL) { InitializeEvent(&event, targetWinPtr, type, x, y, tsdPtr->lastState, b); Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); } /* * Update the state for the next iteration. */ tsdPtr->lastState = (type == ButtonPress) ? (tsdPtr->lastState | mask) : (tsdPtr->lastState & ~mask); tsdPtr->lastPos = pos; } } /* * Make sure the cursor window is up to date. */ if (tsdPtr->restrictWinPtr) { targetWinPtr = tsdPtr->restrictWinPtr; } else if (tsdPtr->grabWinPtr) { targetWinPtr = (TkPositionInTree(winPtr, tsdPtr->grabWinPtr) == TK_GRAB_IN_TREE) ? winPtr : tsdPtr->grabWinPtr; } else { targetWinPtr = winPtr; } UpdateCursor(targetWinPtr); /* * If no other events caused the position to be updated, generate a motion * event. */ if (tsdPtr->lastPos.x != pos.x || tsdPtr->lastPos.y != pos.y) { if (tsdPtr->restrictWinPtr) { targetWinPtr = tsdPtr->restrictWinPtr; } else if (tsdPtr->grabWinPtr && !winPtr) { targetWinPtr = tsdPtr->grabWinPtr; } if (targetWinPtr != NULL) { InitializeEvent(&event, targetWinPtr, MotionNotify, x, y, tsdPtr->lastState, NotifyNormal); Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); } tsdPtr->lastPos = pos; } }
static int GenerateEnterLeave( TkWindow *winPtr, /* Current Tk window (or NULL). */ int x, int y, /* Current mouse position in root coords. */ int state) /* State flags. */ { int crossed = 0; /* 1 if mouse crossed a window boundary */ ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); TkWindow *restrictWinPtr = tsdPtr->restrictWinPtr; TkWindow *lastWinPtr = tsdPtr->lastWinPtr; if (winPtr != tsdPtr->lastWinPtr) { if (restrictWinPtr) { int newPos, oldPos; newPos = TkPositionInTree(winPtr, restrictWinPtr); oldPos = TkPositionInTree(lastWinPtr, restrictWinPtr); /* * Check if the mouse crossed into or out of the restrict window. * If so, we need to generate an Enter or Leave event. */ if ((newPos != oldPos) && ((newPos == TK_GRAB_IN_TREE) || (oldPos == TK_GRAB_IN_TREE))) { XEvent event; int type, detail; if (newPos == TK_GRAB_IN_TREE) { type = EnterNotify; } else { type = LeaveNotify; } if ((oldPos == TK_GRAB_ANCESTOR) || (newPos == TK_GRAB_ANCESTOR)) { detail = NotifyAncestor; } else { detail = NotifyVirtual; } InitializeEvent(&event, restrictWinPtr, type, x, y, state, detail); Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); } } else { TkWindow *targetPtr; if ((lastWinPtr == NULL) || (lastWinPtr->window == None)) { targetPtr = winPtr; } else { targetPtr = lastWinPtr; } if (targetPtr && (targetPtr->window != None)) { XEvent event; /* * Generate appropriate Enter/Leave events. */ InitializeEvent(&event, targetPtr, LeaveNotify, x, y, state, NotifyNormal); TkInOutEvents(&event, lastWinPtr, winPtr, LeaveNotify, EnterNotify, TCL_QUEUE_TAIL); crossed = 1; } } tsdPtr->lastWinPtr = winPtr; } return crossed; }