diff options
author | culler <culler> | 2019-10-20 03:30:55 (GMT) |
---|---|---|
committer | culler <culler> | 2019-10-20 03:30:55 (GMT) |
commit | e6205be11fd0b37b2b401d6f269b3023a36e960d (patch) | |
tree | e813b8f482289815b02f22362fe3c9ffab8629fd /macosx | |
parent | 3c4afbb99a505d4162648d8050ea7c993abbca61 (diff) | |
parent | 1a24593842aae88beb8e408ac1770f7a36d91954 (diff) | |
download | tk-e6205be11fd0b37b2b401d6f269b3023a36e960d.zip tk-e6205be11fd0b37b2b401d6f269b3023a36e960d.tar.gz tk-e6205be11fd0b37b2b401d6f269b3023a36e960d.tar.bz2 |
Fix [ee946e4ebd]: on macOS local grabs only work for toplevels.
Diffstat (limited to 'macosx')
-rw-r--r-- | macosx/tkMacOSXMouseEvent.c | 67 | ||||
-rw-r--r-- | macosx/tkMacOSXTest.c | 100 |
2 files changed, 150 insertions, 17 deletions
diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c index 5b8793c..b973c52 100644 --- a/macosx/tkMacOSXMouseEvent.c +++ b/macosx/tkMacOSXMouseEvent.c @@ -36,6 +36,7 @@ static unsigned int ButtonModifiers2State(UInt32 buttonState, enum { NSWindowWillMoveEventType = 20 }; + /* * In OS X 10.6 an NSEvent of type NSMouseMoved would always have a non-Nil * window attribute pointing to the active window. As of 10.8 this behavior @@ -144,15 +145,28 @@ enum { } /* - * If another toplevel has a grab, we ignore the event. + * Ignore the event if a local grab is in effect and the Tk event window is + * not in the grabber's subtree. */ grabWinPtr = winPtr->dispPtr->grabWinPtr; - if (grabWinPtr && - grabWinPtr != winPtr && - !winPtr->dispPtr->grabFlags && /* this means the grab is local. */ - grabWinPtr->mainPtr == winPtr->mainPtr) { - return theEvent; + if (grabWinPtr && /* There is a grab in effect ... */ + !winPtr->dispPtr->grabFlags && /* and it is a local grab ... */ + grabWinPtr->mainPtr == winPtr->mainPtr){ /* in the same application. */ + Tk_Window tkwin2, tkEventWindow = Tk_CoordsToWindow(global.x, global.y, tkwin); + if (!tkEventWindow) { + return theEvent; + } + for (tkwin2 = tkEventWindow; + !Tk_IsTopLevel(tkwin2); + tkwin2 = Tk_Parent(tkwin2)) { + if (tkwin2 == (Tk_Window) grabWinPtr) { + break; + } + } + if (tkwin2 != (Tk_Window) grabWinPtr) { + return theEvent; + } } /* @@ -228,6 +242,7 @@ enum { } if (eventType != NSScrollWheel) { + /* * For normal mouse events, Tk_UpdatePointer will send the XEvent. */ @@ -238,6 +253,7 @@ enum { #endif Tk_UpdatePointer(tkwin, global.x, global.y, state); } else { + /* * For scroll wheel events we need to send the XEvent here. */ @@ -504,7 +520,7 @@ TkGenerateButtonEventForXPointer( * TkGenerateButtonEvent -- * * Given a global x & y position and the button key status this procedure - * generates the appropiate X button event. It also handles the state + * generates the appropriate X button event. It also handles the state * changes needed to implement implicit grabs. * * Results: @@ -578,6 +594,7 @@ GenerateButtonEvent( TkDisplay *dispPtr; #if UNUSED + /* * ButtonDown events will always occur in the front window. ButtonUp * events, however, may occur anywhere on the screen. ButtonUp events @@ -610,30 +627,46 @@ TkpWarpPointer( TkDisplay *dispPtr) { CGPoint pt; - UInt32 buttonState; + NSPoint loc; + int wNum; if (dispPtr->warpWindow) { int x, y; - + TkWindow *winPtr = (TkWindow *) dispPtr->warpWindow; + TkWindow *topPtr = winPtr->privatePtr->toplevel->winPtr; + NSWindow *w = TkMacOSXDrawableWindow(winPtr->window); + wNum = [w windowNumber]; Tk_GetRootCoords(dispPtr->warpWindow, &x, &y); pt.x = x + dispPtr->warpX; pt.y = y + dispPtr->warpY; + loc.x = dispPtr->warpX; + loc.y = Tk_Height(topPtr) - dispPtr->warpY; } else { - pt.x = dispPtr->warpX; + wNum = 0; + pt.x = loc.x = dispPtr->warpX; pt.y = dispPtr->warpY; + loc.y = tkMacOSXZeroScreenHeight - pt.y; } /* - * Tell the OSX core to generate the events to make it happen. + * Generate an NSEvent of type NSMouseMoved. + * + * It is not clear why this is necessary. For example, calling + * event generate $w <Motion> -warp 1 -x $X -y $Y + * will cause two <Motion> events to be added to the Tcl queue. */ - buttonState = [NSEvent pressedMouseButtons]; - CGEventType type = kCGEventMouseMoved; - CGEventRef theEvent = CGEventCreateMouseEvent(NULL, type, pt, - buttonState); CGWarpMouseCursorPosition(pt); - CGEventPost(kCGHIDEventTap, theEvent); - CFRelease(theEvent); + NSEvent *warpEvent = [NSEvent mouseEventWithType:NSMouseMoved + location:loc + modifierFlags:0 + timestamp:GetCurrentEventTime() + windowNumber:wNum + context:nil + eventNumber:0 + clickCount:1 + pressure:0.0]; + [NSApp postEvent:warpEvent atStart:NO]; } /* diff --git a/macosx/tkMacOSXTest.c b/macosx/tkMacOSXTest.c index f109b7a..09736e6 100644 --- a/macosx/tkMacOSXTest.c +++ b/macosx/tkMacOSXTest.c @@ -13,6 +13,7 @@ */ #include "tkMacOSXPrivate.h" +#include "tkMacOSXConstants.h" /* * Forward declarations of procedures defined later in this file: @@ -22,6 +23,8 @@ static int DebuggerObjCmd (ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); #endif +static int PressButtonObjCmd (ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]); /* @@ -52,6 +55,7 @@ TkplatformtestInit( #if MAC_OS_X_VERSION_MAX_ALLOWED < 1080 Tcl_CreateObjCommand(interp, "debugger", DebuggerObjCmd, NULL, NULL); #endif + Tcl_CreateObjCommand(interp, "pressbutton", PressButtonObjCmd, NULL, NULL); return TCL_OK; } @@ -119,6 +123,102 @@ TkTestLogDisplay(void) { } } +/* + *---------------------------------------------------------------------- + * + * PressButtonObjCmd -- + * + * This Tcl command simulates a button press at a specific screen + * location. It injects NSEvents into the NSApplication event queue, + * as opposed to adding events to the Tcl queue as event generate + * would do. One application is for testing the grab command. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +static int +PressButtonObjCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + int x, y, i, value, wNum; + CGPoint pt; + NSPoint loc; + NSEvent *motion, *press, *release; + NSArray *screens = [NSScreen screens]; + CGFloat ScreenHeight = 0; + enum {X=1, Y}; + + if (screens && [screens count]) { + ScreenHeight = [[screens objectAtIndex:0] frame].size.height; + } + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "x y"); + return TCL_ERROR; + } + for (i = 1; i < objc; i++) { + if (Tcl_GetIntFromObj(interp,objv[i],&value) != TCL_OK) { + return TCL_ERROR; + } + switch (i) { + case X: + x = value; + break; + case Y: + y = value; + break; + default: + break; + } + } + pt.x = loc.x = x; + pt.y = y; + loc.y = ScreenHeight - y; + wNum = 0; + CGWarpMouseCursorPosition(pt); + motion = [NSEvent mouseEventWithType:NSMouseMoved + location:loc + modifierFlags:0 + timestamp:GetCurrentEventTime() + windowNumber:wNum + context:nil + eventNumber:0 + clickCount:1 + pressure:0.0]; + [NSApp postEvent:motion atStart:NO]; + press = [NSEvent mouseEventWithType:NSLeftMouseDown + location:loc + modifierFlags:0 + timestamp:GetCurrentEventTime() + windowNumber:wNum + context:nil + eventNumber:1 + clickCount:1 + pressure:0.0]; + [NSApp postEvent:press atStart:NO]; + release = [NSEvent mouseEventWithType:NSLeftMouseUp + location:loc + modifierFlags:0 + timestamp:GetCurrentEventTime() + windowNumber:wNum + context:nil + eventNumber:2 + clickCount:1 + pressure:0.0]; + [NSApp postEvent:release atStart:NO]; + return TCL_OK; +} + /* * Local Variables: |