diff options
-rw-r--r-- | generic/tkBind.c | 94 | ||||
-rw-r--r-- | generic/tkGrab.c | 25 | ||||
-rw-r--r-- | generic/tkInt.h | 7 | ||||
-rw-r--r-- | generic/tkWindow.c | 2 | ||||
-rw-r--r-- | tests/bind.test | 19 |
5 files changed, 66 insertions, 81 deletions
diff --git a/generic/tkBind.c b/generic/tkBind.c index af6ab15..992d881 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -717,7 +717,6 @@ static int NameToWindow(Tcl_Interp *interp, Tk_Window main, Tcl_Obj *objPtr, Tk_Window *tkwinPtr); static unsigned ParseEventDescription(Tcl_Interp *interp, const char **eventStringPtr, TkPattern *patPtr, EventMask *eventMaskPtr); -static void DoWarp(ClientData clientData); static PSList * GetLookupForEvent(LookupTables* lookupPtr, const Event *eventPtr, Tcl_Obj *object, int onlyConsiderDetailedEvents); static void ClearLookupTable(LookupTables *lookupTables, ClientData object); @@ -4364,10 +4363,19 @@ HandleEventGenerate( dispPtr->warpX = event.general.xmotion.x; dispPtr->warpY = event.general.xmotion.y; - if (!(dispPtr->flags & TK_DISPLAY_IN_WARP)) { - Tcl_DoWhenIdle(DoWarp, dispPtr); - dispPtr->flags |= TK_DISPLAY_IN_WARP; - } + /* + * Warping with respect to a window will be done when Tk_handleEvent + * below will run the event handlers and in particular TkPointerEvent. + * This allows to make grabs and warping work together robustly, that + * is without depending on a precise sequence of events. + * Warping with respect to the whole screen (i.e. dispPtr->warpWindow + * is NULL) is run directly here. + */ + + if (!dispPtr->warpWindow) { + TkpWarpPointer(dispPtr); + XForceScreenSaver(dispPtr->display, ScreenSaverReset); + } } /* @@ -4451,46 +4459,47 @@ NameToWindow( /* *------------------------------------------------------------------------- * - * DoWarp -- + * TkDoWarpWrtWin -- * - * Perform Warping of X pointer. Executed as an idle handler only. + * Perform warping of mouse pointer with respect to a window. * * Results: * None * * Side effects: - * X Pointer will move to a new location. + * Mouse pointer moves to a new location. * *------------------------------------------------------------------------- */ -static void -DoWarp( - ClientData clientData) +void +TkDoWarpWrtWin( + TkDisplay *dispPtr) { - TkDisplay *dispPtr = clientData; - - assert(clientData); + assert(dispPtr); /* - * DoWarp was scheduled only if the window was mapped. It needs to be - * still mapped at the time the present idle callback is executed. Also - * one needs to guard against window destruction in the meantime. - * Finally, the case warpWindow == NULL is special in that it means - * the whole screen. + * A NULL warpWindow means warping with respect to the whole screen. + * We want to warp here only if we're warping with respect to a window. */ - if (!dispPtr->warpWindow || - (Tk_IsMapped(dispPtr->warpWindow) && Tk_WindowId(dispPtr->warpWindow) != None)) { - TkpWarpPointer(dispPtr); - XForceScreenSaver(dispPtr->display, ScreenSaverReset); - } - if (dispPtr->warpWindow) { - Tcl_Release(dispPtr->warpWindow); - dispPtr->warpWindow = NULL; + + /* + * Warping with respect to a window can only be done if the window is + * mapped. This was checked in HandleEvent. The window needs to be + * still mapped at the time the present code is executed. Also + * one needs to guard against window destruction in the meantime, + * which could have happened as a side effect of an event handler. + */ + + if (Tk_IsMapped(dispPtr->warpWindow) && Tk_WindowId(dispPtr->warpWindow) != None) { + TkpWarpPointer(dispPtr); + XForceScreenSaver(dispPtr->display, ScreenSaverReset); + } + Tcl_Release(dispPtr->warpWindow); + dispPtr->warpWindow = NULL; } - dispPtr->flags &= ~TK_DISPLAY_IN_WARP; } /* @@ -5261,35 +5270,6 @@ TkpGetBindingXEvent( /* *---------------------------------------------------------------------- * - * TkpCancelWarp -- - * - * This function cancels an outstanding pointer warp and - * is called during tear down of the display. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -TkpCancelWarp( - TkDisplay *dispPtr) -{ - assert(dispPtr); - - if (dispPtr->flags & TK_DISPLAY_IN_WARP) { - Tcl_CancelIdleCall(DoWarp, dispPtr); - dispPtr->flags &= ~TK_DISPLAY_IN_WARP; - } -} - -/* - *---------------------------------------------------------------------- - * * TkpDumpPS -- * * Dump given pattern sequence to stdout. diff --git a/generic/tkGrab.c b/generic/tkGrab.c index 2855637..8f09f50 100644 --- a/generic/tkGrab.c +++ b/generic/tkGrab.c @@ -667,6 +667,9 @@ ReleaseButtonGrab( * This function is called for each pointer-related event, before the * event has been processed. It does various things to make grabs work * correctly. + * Also, this function takes care of warping the mouse pointer with + * respect to a given window, both when there is a grab in effect and + * when there is none. * * Results: * If the return value is 1 it means the event should be processed (event @@ -678,6 +681,7 @@ ReleaseButtonGrab( * Grab state information may be updated. New events may also be pushed * back onto the event queue to replace or augment the one passed in * here. + * The mouse pointer may be moved. * *---------------------------------------------------------------------- */ @@ -774,10 +778,24 @@ TkPointerEvent( return 1; } + if ((eventPtr->type == MotionNotify) && !appGrabbed) { + + /* + * Warp the mouse pointer with respect to window dispPtr->warpWindow + * if such a window was set in HandleEventGenerate. + */ + + TkDoWarpWrtWin(dispPtr); + } + if (!appGrabbed) { return 1; } + /* + * From this point on, there is a grab in effect. + */ + if (eventPtr->type == MotionNotify) { /* * When grabs are active, X reports motion events relative to the @@ -800,6 +818,13 @@ TkPointerEvent( Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_HEAD); return 0; } + + /* + * Warp the mouse pointer with respect to window dispPtr->warpWindow + * if such a window was set in HandleEventGenerate. + */ + + TkDoWarpWrtWin(dispPtr); return 1; } diff --git a/generic/tkInt.h b/generic/tkInt.h index c1bd562d..f5ec1f6 100644 --- a/generic/tkInt.h +++ b/generic/tkInt.h @@ -535,15 +535,12 @@ typedef struct TkDisplay { * Whether to use input methods for this display * TK_DISPLAY_WM_TRACING: (default off) * Whether we should do wm tracing on this display. - * TK_DISPLAY_IN_WARP: (default off) - * Indicates that we are in a pointer warp */ #define TK_DISPLAY_COLLAPSE_MOTION_EVENTS (1 << 0) #define TK_DISPLAY_USE_IM (1 << 1) #define TK_DISPLAY_WM_TRACING (1 << 3) -#define TK_DISPLAY_IN_WARP (1 << 4) -#define TK_DISPLAY_USE_XKB (1 << 5) +#define TK_DISPLAY_USE_XKB (1 << 4) /* * One of the following structures exists for each error handler created by a @@ -1250,8 +1247,8 @@ MODULE_SCOPE int TkInitTkCmd(Tcl_Interp *interp, ClientData clientData); MODULE_SCOPE int TkInitFontchooser(Tcl_Interp *interp, ClientData clientData); +MODULE_SCOPE void TkDoWarpWrtWin(TkDisplay *dispPtr); MODULE_SCOPE void TkpWarpPointer(TkDisplay *dispPtr); -MODULE_SCOPE void TkpCancelWarp(TkDisplay *dispPtr); MODULE_SCOPE int TkListCreateFrame(ClientData clientData, Tcl_Interp *interp, Tcl_Obj *listObj, int toplevel, Tcl_Obj *nameObj); diff --git a/generic/tkWindow.c b/generic/tkWindow.c index 00fb344..93282dc 100644 --- a/generic/tkWindow.c +++ b/generic/tkWindow.c @@ -239,8 +239,6 @@ TkCloseDisplay( { TkClipCleanup(dispPtr); - TkpCancelWarp(dispPtr); - if (dispPtr->name != NULL) { ckfree(dispPtr->name); } diff --git a/tests/bind.test b/tests/bind.test index e68368a..aa91126 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6137,6 +6137,8 @@ test bind-31.7 {virtual event user_data field - unshared, asynch} -setup { } -result {{} {} {TestUserData >b<}} test bind-32.1 {-warp, window was destroyed before the idle callback DoWarp} -setup { + # note: this test is now essentially useless + # since DoWarp no longer exist, not even as an idle callback frame .t.f pack .t.f focus -force .t.f @@ -6636,14 +6638,10 @@ test bind-34.1 {-warp works relatively to a window} -setup { wm geometry .top +200+200 update event generate .top <Motion> -x 20 -y 20 -warp 1 - update idletasks ; # DoWarp is an idle callback - after 50 ; # Win specific - wait for SendInput to be executed set pointerPos1 [winfo pointerxy .top] wm geometry .top +600+600 update event generate .top <Motion> -x 20 -y 20 -warp 1 - update idletasks ; # DoWarp is an idle callback - after 50 ; # Win specific - wait for SendInput to be executed set pointerPos2 [winfo pointerxy .top] # from the first warped position to the second one, the mouse # pointer should have moved the same amount as the window moved @@ -6661,12 +6659,8 @@ test bind-34.2 {-warp works relatively to the screen} -setup { } -body { # Contrary to bind-34.1, we're directly checking screen coordinates event generate {} <Motion> -x 20 -y 20 -warp 1 - update idletasks ; # DoWarp is an idle callback - after 50 ; # Win specific - wait for SendInput to be executed set res [winfo pointerxy .] event generate {} <Motion> -x 200 -y 200 -warp 1 - update idletasks ; # DoWarp is an idle callback - after 50 ; # Win specific - wait for SendInput to be executed lappend res {*}[winfo pointerxy .] } -cleanup { } -result {20 20 200 200} @@ -6684,8 +6678,6 @@ test bind-34.3 {-warp works with null or negative coordinates} -setup { set res {} } -body { event generate {} <Motion> -x 0 -y 0 -warp 1 - update idletasks ; # DoWarp is an idle callback - after 50 ; # Win specific - wait for SendInput to be executed foreach dim [winfo pointerxy .] { if {$dim <= $halo} { lappend res ok @@ -6694,9 +6686,7 @@ test bind-34.3 {-warp works with null or negative coordinates} -setup { } } event generate {} <Motion> -x 100 -y 100 -warp 1 - update idletasks ; after 50 event generate {} <Motion> -x -1 -y -1 -warp 1 - update idletasks ; after 50 foreach dim [winfo pointerxy .] { if {$dim <= $halo} { lappend res ok @@ -6723,8 +6713,6 @@ test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -constraints } } event generate {} <Motion> -warp 1 -x 50 -y 50 - update idletasks ; # DoWarp is an idle callback - after 50 ; # Win specific - wait for SendInput to be executed toplevel .top grab release .top waitForGrab released .top @@ -6737,14 +6725,11 @@ test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -constraints grab .top ; # this will queue events waitForGrab grabbed .top event generate .top.l <Motion> -warp 1 -x 10 -y 10 - update idletasks ; after 50 foreach {x1 y1} [winfo pointerxy .top.l] {} event generate {} <Motion> -warp 1 -x 50 -y 50 - update idletasks ; after 50 grab release .top ; # this will queue events waitForGrab released .top event generate .top.l <Motion> -warp 1 -x 10 -y 10 - update idletasks ; after 50 foreach {x2 y2} [winfo pointerxy .top.l] {} expr {$x1==$x2 && $y1==$y2} } -cleanup { |