Index: macosx/tkMacOSXMouseEvent.c ================================================================== --- macosx/tkMacOSXMouseEvent.c +++ macosx/tkMacOSXMouseEvent.c @@ -46,19 +46,21 @@ */ @implementation TKApplication(TKMouseEvent) - (NSEvent *) tkProcessMouseEvent: (NSEvent *) theEvent { -#ifdef TK_MAC_DEBUG_EVENTS - TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, theEvent); -#endif NSWindow* eventWindow = [theEvent window]; NSEventType eventType = [theEvent type]; + TkWindow *winPtr, *grabWinPtr; + Tk_Window tkwin; #if 0 NSTrackingArea *trackingArea = nil; NSInteger eventNumber, clickCount, buttonNumber; #endif +#ifdef TK_MAC_DEBUG_EVENTS + TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, theEvent); +#endif switch (eventType) { case NSMouseEntered: case NSMouseExited: case NSCursorUpdate: case NSLeftMouseDown: @@ -86,55 +88,98 @@ } _windowWithMouse = eventWindow; [_windowWithMouse retain]; } - /* Create an Xevent to add to the Tk queue. */ + /* + * Compute the mouse position in Tk screen coordinates (global) and in + * the Tk coordinates of its containing Tk Window. + */ + NSPoint global, local = [theEvent locationInWindow]; - if (eventWindow) { /* local will be in window coordinates. */ + + /* + * If the event has no NSWindow, try using the cached NSWindow from the + * last mouse event. + */ + + if (eventWindow == NULL) { + eventWindow == _windowWithMouse; + } + if (eventWindow) { + + /* + * Set the local mouse position to its NSWindow flipped coordinates, + * with the origin at top left, and the global mouse position to the + * flipped screen coordinates. + */ + global = [eventWindow tkConvertPointToScreen: local]; local.y = [eventWindow frame].size.height - local.y; global.y = tkMacOSXZeroScreenHeight - global.y; - } else { /* local will be in screen coordinates. */ - if (_windowWithMouse ) { - eventWindow = _windowWithMouse; - global = local; - local = [eventWindow tkConvertPointFromScreen: local]; - local.y = [eventWindow frame].size.height - local.y; - global.y = tkMacOSXZeroScreenHeight - global.y; - } else { /* We have no window. Use the screen???*/ - local.y = tkMacOSXZeroScreenHeight - local.y; - global = local; - } - } - - TkWindow *winPtr = TkMacOSXGetTkWindow(eventWindow); - Tk_Window tkwin = (Tk_Window) winPtr; - - if (tkwin) { - TkWindow *grabWinPtr = winPtr->dispPtr->grabWinPtr; - if (grabWinPtr && - grabWinPtr != winPtr && - !winPtr->dispPtr->grabFlags && /* this means the grab is local. */ - grabWinPtr->mainPtr == winPtr->mainPtr) { - return theEvent; - } + + } else { + + /* + * As a last resort, with no NSWindow to work with, set both local and + * global to the screen coordinates. + */ + + local.y = tkMacOSXZeroScreenHeight - local.y; + global = local; + } + + /* + * Find the toplevel which corresponds to the event NSWindow. + */ + + winPtr = TkMacOSXGetTkWindow(eventWindow); + if (winPtr == NULL) { + tkwin = TkMacOSXGetCapture(); + winPtr = (TkWindow *)tkwin; } else { - tkwin = TkMacOSXGetCapture(); + tkwin = (Tk_Window) winPtr; } if (!tkwin) { TkMacOSXDbgMsg("tkwin == NULL"); return theEvent; /* Give up. No window for this event. */ - } else { - winPtr = (TkWindow *)tkwin; + } + + /* + * If another toplevel has a grab, we ignore the event. + */ + + grabWinPtr = winPtr->dispPtr->grabWinPtr; + if (grabWinPtr && + grabWinPtr != winPtr && + !winPtr->dispPtr->grabFlags && /* this means the grab is local. */ + grabWinPtr->mainPtr == winPtr->mainPtr) { + return theEvent; } + /* + * Convert local from NSWindow flipped coordinates to the toplevel's + * coordinates. + */ + local.x -= winPtr->wmInfoPtr->xInParent; local.y -= winPtr->wmInfoPtr->yInParent; + /* + * Find the containing Tk window, and convert local into the coordinates + * of the Tk window. (The converted local coordinates are only needed + * for scrollwheel events.) + */ + int win_x, win_y; tkwin = Tk_TopCoordsToWindow(tkwin, local.x, local.y, &win_x, &win_y); + local.x = win_x; + local.y = win_y; + + /* + * Generate an XEvent for this mouse event. + */ unsigned int state = 0; NSInteger button = [theEvent buttonNumber]; EventRef eventRef = (EventRef)[theEvent eventRef]; UInt32 buttons; @@ -180,15 +225,25 @@ if (modifiers & NSFunctionKeyMask) { state |= Mod4Mask; } if (eventType != NSScrollWheel) { + + /* + * For normal mouse events, Tk_UpdatePointer will send the XEvent. + */ + #ifdef TK_MAC_DEBUG_EVENTS TKLog(@"UpdatePointer %p x %f.0 y %f.0 %d", tkwin, global.x, global.y, state); #endif Tk_UpdatePointer(tkwin, global.x, global.y, state); - } else { /* handle scroll wheel event */ + } else { + + /* + * For scroll wheel events we need to send the XEvent here. + */ + CGFloat delta; int coarseDelta; XEvent xEvent; xEvent.type = MouseWheelEvent;