summaryrefslogtreecommitdiffstats
path: root/macosx
diff options
context:
space:
mode:
authorculler <culler>2019-10-20 03:30:55 (GMT)
committerculler <culler>2019-10-20 03:30:55 (GMT)
commite6205be11fd0b37b2b401d6f269b3023a36e960d (patch)
treee813b8f482289815b02f22362fe3c9ffab8629fd /macosx
parent3c4afbb99a505d4162648d8050ea7c993abbca61 (diff)
parent1a24593842aae88beb8e408ac1770f7a36d91954 (diff)
downloadtk-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.c67
-rw-r--r--macosx/tkMacOSXTest.c100
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: