static void InitializeEvent( XEvent *eventPtr, /* Event structure to initialize. */ TkWindow *winPtr, /* Window to make event relative to. */ int type, /* Message type. */ int x, int y, /* Root coords of event. */ int state, /* State flags. */ int detail) /* Detail value. */ { eventPtr->type = type; eventPtr->xany.serial = LastKnownRequestProcessed(winPtr->display); eventPtr->xany.send_event = False; eventPtr->xany.display = winPtr->display; eventPtr->xcrossing.root = RootWindow(winPtr->display, winPtr->screenNum); eventPtr->xcrossing.time = TkpGetMS(); eventPtr->xcrossing.x_root = x; eventPtr->xcrossing.y_root = y; switch (type) { case EnterNotify: case LeaveNotify: eventPtr->xcrossing.mode = NotifyNormal; eventPtr->xcrossing.state = state; eventPtr->xcrossing.detail = detail; eventPtr->xcrossing.focus = False; break; case MotionNotify: eventPtr->xmotion.state = state; eventPtr->xmotion.is_hint = detail; break; case ButtonPress: case ButtonRelease: eventPtr->xbutton.state = state; eventPtr->xbutton.button = detail; break; } TkChangeEventWindow(eventPtr, winPtr); }
int TkPointerEvent( register XEvent *eventPtr, /* Pointer to the event. */ TkWindow *winPtr) /* Tk's information for window where event was * reported. */ { register TkWindow *winPtr2; TkDisplay *dispPtr = winPtr->dispPtr; unsigned int serial; int outsideGrabTree = 0; int ancestorOfGrab = 0; int appGrabbed = 0; /* Non-zero means event is being reported to * an application that is affected by the * grab. */ /* * Collect information about the grab (if any). */ switch (TkGrabState(winPtr)) { case TK_GRAB_IN_TREE: appGrabbed = 1; break; case TK_GRAB_ANCESTOR: appGrabbed = 1; outsideGrabTree = 1; ancestorOfGrab = 1; break; case TK_GRAB_EXCLUDED: appGrabbed = 1; outsideGrabTree = 1; break; } if ((eventPtr->type == EnterNotify) || (eventPtr->type == LeaveNotify)) { /* * Keep track of what window the mouse is *really* over. Any events * that we generate have a special send_event value, which is detected * below and used to ignore the event for purposes of setting * serverWinPtr. */ if (eventPtr->xcrossing.send_event != GENERATED_GRAB_EVENT_MAGIC) { if ((eventPtr->type == LeaveNotify) && (winPtr->flags & TK_TOP_HIERARCHY)) { dispPtr->serverWinPtr = NULL; } else { dispPtr->serverWinPtr = winPtr; } } /* * When a grab is active, X continues to report enter and leave events * for windows outside the tree of the grab window: * 1. Detect these events and ignore them except for windows above the * grab window. * 2. Allow Enter and Leave events to pass through the windows above * the grab window, but never let them end up with the pointer *in* * one of those windows. */ if (dispPtr->grabWinPtr != NULL) { if (outsideGrabTree && appGrabbed) { if (!ancestorOfGrab) { return 0; } switch (eventPtr->xcrossing.detail) { case NotifyInferior: return 0; case NotifyAncestor: eventPtr->xcrossing.detail = NotifyVirtual; break; case NotifyNonlinear: eventPtr->xcrossing.detail = NotifyNonlinearVirtual; break; } } /* * Make buttons have the same grab-like behavior inside a grab as * they do outside a grab: do this by ignoring enter and leave * events except for the window in which the button was pressed. */ if ((dispPtr->buttonWinPtr != NULL) && (winPtr != dispPtr->buttonWinPtr)) { return 0; } } return 1; } if (!appGrabbed) { return 1; } if (eventPtr->type == MotionNotify) { /* * When grabs are active, X reports motion events relative to the * window under the pointer. Instead, it should report the events * relative to the window the button went down in, if there is a * button down. Otherwise, if the pointer window is outside the * subtree of the grab window, the events should be reported relative * to the grab window. Otherwise, the event should be reported to the * pointer window. */ winPtr2 = winPtr; if (dispPtr->buttonWinPtr != NULL) { winPtr2 = dispPtr->buttonWinPtr; } else if (outsideGrabTree || (dispPtr->serverWinPtr == NULL)) { winPtr2 = dispPtr->grabWinPtr; } if (winPtr2 != winPtr) { TkChangeEventWindow(eventPtr, winPtr2); Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_HEAD); return 0; } return 1; } /* * Process ButtonPress and ButtonRelease events: * 1. Keep track of whether a button is down and what window it went down * in. * 2. If the first button goes down outside the grab tree, pretend it went * down in the grab window. Note: it's important to redirect events to * the grab window like this in order to make things like menus work, * where button presses outside the grabbed menu need to be seen. An * application can always ignore the events if they occur outside its * window. * 3. If a button press or release occurs outside the window where the * first button was pressed, retarget the event so it's reported to the * window where the first button was pressed. * 4. If the last button is released in a window different than where the * first button was pressed, generate Enter/Leave events to move the * mouse from the button window to its current window. * 5. If the grab is set at a time when a button is already down, or if * the window where the button was pressed was deleted, then * dispPtr->buttonWinPtr will stay NULL. Just forget about the * auto-grab for the button press; events will go to whatever window * contains the pointer. If this window isn't in the grab tree then * redirect events to the grab window. * 6. When a button is pressed during a local grab, the X server sets a * grab of its own, since it doesn't even know about our local grab. * This causes enter and leave events no longer to be generated in the * same way as for global grabs. To eliminate this problem, set a * temporary global grab when the first button goes down and release it * when the last button comes up. */ if ((eventPtr->type == ButtonPress) || (eventPtr->type == ButtonRelease)) { winPtr2 = dispPtr->buttonWinPtr; if (winPtr2 == NULL) { if (outsideGrabTree) { winPtr2 = dispPtr->grabWinPtr; /* Note 5. */ } else { winPtr2 = winPtr; /* Note 5. */ } } if (eventPtr->type == ButtonPress) { if ((eventPtr->xbutton.state & ALL_BUTTONS) == 0) { if (outsideGrabTree) { TkChangeEventWindow(eventPtr, dispPtr->grabWinPtr); Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_HEAD); return 0; /* Note 2. */ } if (!(dispPtr->grabFlags & GRAB_GLOBAL)) { /* Note 6. */ serial = NextRequest(dispPtr->display); if (XGrabPointer(dispPtr->display, dispPtr->grabWinPtr->window, True, ButtonPressMask|ButtonReleaseMask|ButtonMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime) == 0) { EatGrabEvents(dispPtr, serial); if (XGrabKeyboard(dispPtr->display, winPtr->window, False, GrabModeAsync, GrabModeAsync, CurrentTime) == 0) { dispPtr->grabFlags |= GRAB_TEMP_GLOBAL; } else { XUngrabPointer(dispPtr->display, CurrentTime); } } } dispPtr->buttonWinPtr = winPtr; return 1; } } else { if ((eventPtr->xbutton.state & ALL_BUTTONS) == buttonStates[eventPtr->xbutton.button - Button1]) { ReleaseButtonGrab(dispPtr); /* Note 4. */ } } if (winPtr2 != winPtr) { TkChangeEventWindow(eventPtr, winPtr2); Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_HEAD); return 0; /* Note 3. */ } } return 1; }