diff options
author | jan.nijtmans <nijtmans@users.sourceforge.net> | 2021-11-24 10:48:04 (GMT) |
---|---|---|
committer | jan.nijtmans <nijtmans@users.sourceforge.net> | 2021-11-24 10:48:04 (GMT) |
commit | a76a39c11215d1540aef83b53115c54bf6e6a880 (patch) | |
tree | c15e50c5a7736975ff4bfc7dcc4b0e84033c01de /macosx | |
parent | d815dabf0d14778b19acc0bd6b9264756d25d5c4 (diff) | |
parent | 6b9b678f9baccfa26a0f82519ef19ed3284f7bfe (diff) | |
download | tk-a76a39c11215d1540aef83b53115c54bf6e6a880.zip tk-a76a39c11215d1540aef83b53115c54bf6e6a880.tar.gz tk-a76a39c11215d1540aef83b53115c54bf6e6a880.tar.bz2 |
Merge 8.6
Diffstat (limited to 'macosx')
-rw-r--r-- | macosx/tkMacOSXConstants.h | 5 | ||||
-rw-r--r-- | macosx/tkMacOSXInit.c | 19 | ||||
-rw-r--r-- | macosx/tkMacOSXMouseEvent.c | 369 | ||||
-rw-r--r-- | macosx/tkMacOSXPrivate.h | 12 | ||||
-rw-r--r-- | macosx/tkMacOSXSubwindows.c | 16 | ||||
-rw-r--r-- | macosx/tkMacOSXTest.c | 28 | ||||
-rw-r--r-- | macosx/tkMacOSXWindowEvent.c | 57 | ||||
-rw-r--r-- | macosx/tkMacOSXWm.c | 3 |
8 files changed, 302 insertions, 207 deletions
diff --git a/macosx/tkMacOSXConstants.h b/macosx/tkMacOSXConstants.h index db5c78e..2341cb8 100644 --- a/macosx/tkMacOSXConstants.h +++ b/macosx/tkMacOSXConstants.h @@ -83,7 +83,6 @@ typedef NSInteger NSModalResponse; #define NSInformationalAlertStyle NSAlertStyleInformational #define NSCriticalAlertStyle NSAlertStyleCritical #define NSCenterTextAlignment NSTextAlignmentCenter -#define NSAnyEventMask NSEventMaskAny #define NSApplicationDefinedMask NSEventMaskApplicationDefined #define NSUtilityWindowMask NSWindowStyleMaskUtilityWindow #define NSNonactivatingPanelMask NSWindowStyleMaskNonactivatingPanel @@ -97,6 +96,10 @@ typedef NSInteger NSModalResponse; #define NSBorderlessWindowMask NSWindowStyleMaskBorderless #define NSFullScreenWindowMask NSWindowStyleMaskFullScreen #define NSAlphaFirstBitmapFormat NSBitmapFormatAlphaFirst +#define NSAnyEventMask NSEventMaskAny +#define NSLeftMouseDownMask NSEventMaskLeftMouseDown +#define NSMouseMovedMask NSEventMaskMouseMoved +#define NSLeftMouseDraggedMask NSEventMaskLeftMouseDragged #endif #if MAC_OS_X_VERSION_MIN_REQUIRED >= 101400 diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c index e8c5d8d..dfdde24 100644 --- a/macosx/tkMacOSXInit.c +++ b/macosx/tkMacOSXInit.c @@ -14,6 +14,7 @@ */ #include "tkMacOSXPrivate.h" +#include "tkMacOSXConstants.h" #include <dlfcn.h> #include <objc/objc-auto.h> #include <sys/stat.h> @@ -43,6 +44,10 @@ static int TkMacOSXGetAppPathCmd(ClientData cd, Tcl_Interp *ip, @synthesize isDrawing = _isDrawing; @synthesize needsToDraw = _needsToDraw; @synthesize isSigned = _isSigned; +@synthesize tkLiveResizeEnded = _tkLiveResizeEnded; +@synthesize tkPointerWindow = _tkPointerWindow; +@synthesize tkEventTarget = _tkEventTarget; +@synthesize tkButtonState = _tkButtonState; @end /* @@ -163,6 +168,20 @@ static int TkMacOSXGetAppPathCmd(ClientData cd, Tcl_Interp *ip, [NSApp activateIgnoringOtherApps: YES]; /* + * Add an event monitor so we continue to receive NSMouseMoved and + * NSMouseDragged events when the mouse moves outside of the key + * window. The handler simply returns the events it receives, so + * they can be processed in the same way as for other events. + */ + + [NSEvent addLocalMonitorForEventsMatchingMask:(NSMouseMovedMask | + NSLeftMouseDraggedMask) + handler:^NSEvent *(NSEvent *event) + { + return event; + }]; + + /* * Process events to ensure that the root window is fully initialized. See * ticket 56a1823c73. */ diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c index 2bd4ae2..9004678 100644 --- a/macosx/tkMacOSXMouseEvent.c +++ b/macosx/tkMacOSXMouseEvent.c @@ -36,8 +36,6 @@ static Tk_Window captureWinPtr = NULL; /* Current capture window; may be * NULL. */ static int GenerateButtonEvent(MouseEventData *medPtr); -static unsigned int ButtonModifiers2State(UInt32 buttonState, - UInt32 keyModifiers); #pragma mark TKApplication(TKMouseEvent) @@ -47,54 +45,91 @@ enum { /* * 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 - * had changed. The new behavior was that if the mouse were ever moved outside - * of a window, all subsequent NSMouseMoved NSEvents would have a Nil window + * window attribute pointing to the key window. As of 10.8 this behavior had + * changed. The new behavior was that if the mouse were ever moved outside of + * a window, all subsequent NSMouseMoved NSEvents would have a Nil window * attribute until the mouse returned to the window. In 11.1 it changed again. * The window attribute can be non-nil, but referencing a window which does not * belong to the application. */ +/* The basic job of tkProcessMouseEvent is to generate a call to + * TkUpdatePointer. That function receives a Tk_Window which (ignoring cases + * when a grab is in effect) should be the highest window within the focused + * toplevel that contains the pointer, as well as the pointer location in + * screen coordinates and the current button state. Tk maintains a cache of + * these three values. A change in any of these values causes TkUpdatePointer + * to generate, respectively, Enter/Leave events, or Motion events, or + * button Press/Release events. The Tk_Window value is allowed to be NULL, + * which indicates that the pointer is not in the focused toplevel. + * + * Enter or Leave events for toplevel windows are generated when the Tk_Window + * value changes to or from NULL. This is problematic on macOS due to the fact + * that TkUpdatePointer does not generate Motion events when the Tk_Window + * value is NULL. A consequence of this is that TkUpdatePointer will either + * fail to generate correct Enter/Leave events for toplevels or else be unable + * to generate Motion events when the pointer is outside of the focus window. + * It is important to be able to generate such events because otherwise a + * scrollbar on the edge of a toplevel becomes unusable. Any time that the + * pointer wanders out of the window during a scroll, the scroll will stop. + * That is an extremely annoying and unexpected behavior. Much of the code in + * this module, including the trickiest parts, is devoted to working around + * this problem. The other tricky parts are related to transcribing Apple's + * NSMouseEntered, NSMouseExited, and NSLeftMouseDragged events into a form + * that makes sense to Tk. + */ + + @implementation TKApplication(TKMouseEvent) + - (NSEvent *) tkProcessMouseEvent: (NSEvent *) theEvent { NSWindow *eventWindow = [theEvent window]; NSEventType eventType = [theEvent type]; - NSRect viewFrame = [[eventWindow contentView] frame]; + TKContentView *contentView = [eventWindow contentView]; NSPoint location = [theEvent locationInWindow]; + NSPoint viewLocation = [contentView convertPoint:location fromView:nil]; TkWindow *winPtr = NULL, *grabWinPtr; - Tk_Window tkwin = NULL, capture, target; + Tk_Window tkwin = NULL, capture; + static Tk_Window target = NULL, dragTarget = NULL; NSPoint local, global; NSInteger button; - Bool inTitleBar = NO; int win_x, win_y; unsigned int buttonState = 0; - static int validPresses = 0, ignoredPresses = 0; + Bool isTestingEvent = NO; + Bool isMotionEvent = NO; + Bool isOutside = NO; + static Bool isDragging = NO; #ifdef TK_MAC_DEBUG_EVENTS TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, theEvent); #endif /* - * If this event is not for a Tk toplevel, it should just be passed up the - * responder chain. However, there is an exception for synthesized events, - * which are used in testing. Those events are recognized by having their - * both the windowNumber and the eventNumber set to -1. + * If this event is not for a Tk toplevel, it should normally just be + * passed up the responder chain. However, there is are two exceptions. + * One is for synthesized events, which are used in testing. Those events + * are recognized by having their timestamp set to 0. The other is for + * motion events sent by the local event monitor, which will have their + * window attribute set to nil. */ - if (eventWindow && ![eventWindow isMemberOfClass:[TKWindow class]]) { - if ([theEvent windowNumber] != -1 || [theEvent eventNumber] != -1) + if (![eventWindow isMemberOfClass:[TKWindow class]]) { + if ([theEvent timestamp] == 0) { + isTestingEvent = YES; + eventWindow = [NSApp keyWindow]; + } + if (eventType == NSLeftMouseDragged || + eventType == NSMouseMoved) { + eventWindow = [NSApp keyWindow]; + isMotionEvent = YES; + } + if (!isTestingEvent && !isMotionEvent) { return theEvent; + } + } else if (!NSPointInRect(viewLocation, [contentView bounds])) { + isOutside = YES; } - - /* - * Check if the event is located in the titlebar. - */ - - if (eventWindow) { - inTitleBar = viewFrame.size.height < location.y; - } - button = [theEvent buttonNumber] + Button1; if ((button & -2) == Button2) { button ^= 1; /* Swap buttons 2/3 */ @@ -105,37 +140,50 @@ enum { buttonState &= ~Tk_GetButtonMask(button); break; case NSLeftMouseDragged: + isDragging = YES; + dragTarget = target; case NSRightMouseDragged: case NSOtherMouseDragged: + isMotionEvent = YES; case NSRightMouseDown: case NSOtherMouseDown: buttonState |= Tk_GetButtonMask(button); break; case NSMouseEntered: - if ([eventWindow respondsToSelector:@selector(mouseInResizeArea)] && - !inTitleBar) { - [(TKWindow *)eventWindow setMouseInResizeArea:YES]; + if (![eventWindow isKeyWindow] || isOutside) { + return theEvent; } + [NSApp setTkLiveResizeEnded:NO]; + [NSApp setTkPointerWindow:[NSApp tkEventTarget]]; break; case NSMouseExited: - if ([eventWindow respondsToSelector:@selector(mouseInResizeArea)]) { - [(TKWindow *)eventWindow setMouseInResizeArea:NO]; - break; + if (![eventWindow isKeyWindow] || !isOutside) { + return theEvent; } + [NSApp setTkPointerWindow:nil]; + break; case NSLeftMouseUp: + isDragging = NO; case NSLeftMouseDown: /* - * Ignore mouse button events which arrive while the app is inactive. - * These events will be resent after activation, causing duplicate - * actions when an app is activated by a bound mouse event. See ticket - * [7bda9882cb]. + * Ignore left mouse button events which arrive while the app is + * inactive. These events will be resent after activation, causing + * duplicate actions when an app is activated by a bound mouse event + * (see ticket [7bda9882cb]. Also, ignore left mouse button events in + * the titlebar (see tickets [d72abe6b54] and [39cbacb9e8]). */ - if (! [NSApp isActive]) { + if (![NSApp isActive] || isOutside) { return theEvent; } + break; case NSMouseMoved: + if (eventWindow && eventWindow != [NSApp keyWindow]) { + return theEvent; + } + isMotionEvent = YES; + break; case NSScrollWheel: #if 0 case NSCursorUpdate: @@ -148,77 +196,68 @@ enum { } /* - * Update the button state. We ignore left button presses that start a - * resize or occur in the title bar. See tickets [d72abe6b54] and - * [39cbacb9e8]. + * Update the button state. We ignore left button presses that occur + * outside of the ContentView. We also ignore the first left button press + * after a live resize ends. (Apple sends the button press event that + * started the resize after the resize ends. It should not be seen by Tk.) + * See tickets [d72abe6b54] and [39cbacb9e8]. */ if (eventType == NSLeftMouseDown) { - if ([eventWindow respondsToSelector:@selector(mouseInResizeArea)] && - [(TKWindow *) eventWindow mouseInResizeArea]) { - - /* - * When the left button is pressed in the resize area, we receive - * NSMouseDown, but when it is released we do not receive - * NSMouseUp. So ignore the event and clear the button state but - * do not change the ignoredPresses count. - */ - - buttonState &= ~Tk_GetButtonMask(Button1); - return theEvent; - } - if (inTitleBar) { - ignoredPresses++; - return theEvent; + if (!isTestingEvent) { + NSRect bounds = [contentView bounds]; + NSRect grip = NSMakeRect(bounds.size.width - 10, 0, 10, 10); + bounds = NSInsetRect(bounds, 2.0, 2.0); + if (!NSPointInRect(viewLocation, bounds)) { + return theEvent; + } + if (NSPointInRect(viewLocation, grip)) { + return theEvent; + } + if ([NSApp tkLiveResizeEnded]) { + [NSApp setTkLiveResizeEnded:NO]; + return theEvent; + } } - validPresses++; buttonState |= Tk_GetButtonMask(Button1); } - if (eventType == NSLeftMouseUp) { - if (ignoredPresses > 0) { - ignoredPresses--; - } else if (validPresses > 0) { - validPresses--; - } - if (validPresses == 0) { - buttonState &= ~Tk_GetButtonMask(Button1); - } - } /* - * Find an appropriate NSWindow to attach to this event, and its - * associated Tk window. + * Find the toplevel window for the event. If a capture has been + * set this may involve redirecting the event. */ capture = TkpGetCapture(); - if (eventWindow) { - winPtr = TkMacOSXGetTkWindow(eventWindow); - } else if (capture) { + if (capture) { winPtr = (TkWindow *) capture; eventWindow = TkMacOSXGetNSWindowForDrawable(winPtr->window); if (!eventWindow) { return theEvent; } - } - if (!winPtr) { - eventWindow = [NSApp mainWindow]; - winPtr = TkMacOSXGetTkWindow(eventWindow); + } else { + if (isDragging) { + winPtr = TkMacOSXGetHostToplevel((TkWindow *)dragTarget)->winPtr; + } else { + winPtr = [NSApp tkEventTarget]; + } } if (!winPtr) { /* - * We couldn't find a Tk window for this event. We have to ignore it. + * If we couldn't find a toplevel for this event we have to ignore it. + * (But this should never happen.) */ #ifdef TK_MAC_DEBUG_EVENTS TkMacOSXDbgMsg("Event received with no Tk window."); #endif + return theEvent; } tkwin = (Tk_Window) winPtr; /* - * Compute the mouse position in local (window) and global (screen) + * Compute the mouse position in local (toplevel) and global (screen) * coordinates. These are Tk coordinates, meaning that the local origin is * at the top left corner of the containing toplevel and the global origin * is at top left corner of the primary screen. @@ -240,19 +279,36 @@ enum { local.x -= (topPtr->wmInfoPtr->xInParent + contPtr->changes.x); local.y -= (topPtr->wmInfoPtr->yInParent + contPtr->changes.y); } - } else { - local.x -= winPtr->wmInfoPtr->xInParent; - local.y -= winPtr->wmInfoPtr->yInParent; + } + else { + if (winPtr && winPtr->wmInfoPtr) { + local.x -= winPtr->wmInfoPtr->xInParent; + local.y -= winPtr->wmInfoPtr->yInParent; + } else { + return theEvent; + } } /* - * Use the local coordinates to find the Tk window which should receive - * this event. Also convert local into the coordinates of that window. - * (The converted local coordinates are only needed for scrollwheel - * events.) + * Use the toplevel coordinates to decide which Tk window should receive + * this event. Also convert the toplevel coordinates into the coordinate + * system of that window. These converted coordinates are needed for + * XEvents that we generate, namely ScrollWheel events and Motion events + * when the mouse is outside of the focused toplevel. */ - target = Tk_TopCoordsToWindow(tkwin, local.x, local.y, &win_x, &win_y); + if (isDragging) { + TkWindow *w = (TkWindow *) dragTarget; + win_x = global.x; + win_y = global.y; + for (; w != NULL; w = w->parentPtr) { + win_x -= Tk_X(w); + win_y -= Tk_Y(w); + } + target = dragTarget; + } else { + target = Tk_TopCoordsToWindow(tkwin, local.x, local.y, &win_x, &win_y); + } /* * Ignore the event if a local grab is in effect and the Tk window is @@ -280,7 +336,7 @@ enum { } /* - * Generate an XEvent for this mouse event. + * Translate the current button state into Tk's format. */ unsigned int state = buttonState; @@ -307,30 +363,61 @@ enum { if (modifiers & NSFunctionKeyMask) { state |= Mod4Mask; } + [NSApp setTkButtonState:state]; - if (eventType != NSScrollWheel) { + /* + * Send XEvents. We do this here for Motion events outside of the focused + * toplevel and for MouseWheel events. In other cases the XEvents will be + * sent when we call TkUpdatePointer. + */ - /* - * For normal mouse events, Tk_UpdatePointer will send the appropriate - * XEvents using its cached state information. Unfortunately, it will - * also recompute the local coordinates. - */ + if (eventType != NSScrollWheel) { + if (isDragging) { -#ifdef TK_MAC_DEBUG_EVENTS - TKLog(@"UpdatePointer %p x %.1f y %.1f %d", - target, global.x, global.y, state); -#endif + /* + * When dragging the mouse into the resize area Apple shows the + * left button to be up, which confuses TkUpdatePointer. So + * we make sure that the button state appears the way that Tk + * expects. + */ - Tk_UpdatePointer(target, global.x, global.y, state); + state |= Tk_GetButtonMask(Button1); + } + if (eventType == NSMouseEntered) { + Tk_UpdatePointer((Tk_Window) [NSApp tkPointerWindow], + global.x, global.y, state); + } else if (eventType == NSMouseExited) { + if (isDragging) { + Tk_UpdatePointer((Tk_Window) [NSApp tkPointerWindow], + global.x, global.y, state); + } else { + Tk_UpdatePointer(NULL, global.x, global.y, state); + } + } else if (eventType == NSMouseMoved || + eventType == NSLeftMouseDragged) { + if ([NSApp tkPointerWindow]) { + Tk_UpdatePointer(target, global.x, global.y, state); + } else { + static XEvent xEvent = {0}; + + xEvent.type = MotionNotify; + xEvent.xany.send_event = false; + xEvent.xany.display = Tk_Display(target); + xEvent.xany.window = Tk_WindowId(target); + xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin)); + xEvent.xmotion.x = win_x; + xEvent.xmotion.y = win_y; + xEvent.xmotion.x_root = global.x; + xEvent.xmotion.y_root = global.y; + xEvent.xmotion.state = state; + Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL); + } + } else { + Tk_UpdatePointer(target, global.x, global.y, state); + } } else { CGFloat delta; - XEvent xEvent; - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - - /* - * For scroll wheel events we need to send the XEvent here. - */ + static XEvent xEvent = {0}; xEvent.type = MouseWheelEvent; xEvent.xbutton.x = win_x; @@ -343,6 +430,8 @@ enum { #define WHEEL_DELTA 120 #define WHEEL_DELAY 300000000 + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); uint64_t wheelTick = clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW); Bool timeout = (wheelTick - tsdPtr->wheelTickPrev) >= WHEEL_DELAY; if (timeout) { @@ -406,79 +495,7 @@ enum { unsigned int TkMacOSXButtonKeyState(void) { - UInt32 buttonState = 0, keyModifiers; - int isFrontProcess = (GetCurrentEvent() && Tk_MacOSXIsAppInFront()); - - buttonState = isFrontProcess ? GetCurrentEventButtonState() : - GetCurrentButtonState(); - keyModifiers = isFrontProcess ? GetCurrentEventKeyModifiers() : - GetCurrentKeyModifiers(); - - return ButtonModifiers2State(buttonState, keyModifiers); -} - -/* - *---------------------------------------------------------------------- - * - * ButtonModifiers2State -- - * - * Converts Carbon mouse button state and modifier values into a Tk - * button/modifier state. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static unsigned int -ButtonModifiers2State( - UInt32 buttonState, - UInt32 keyModifiers) -{ - unsigned int state; - - /* - * Tk on OSX supports at most 9 buttons. - */ - - state = (buttonState & 0x079) * Button1Mask; - /* Handle swapped buttons 2/3 */ - if (buttonState & 0x02) { - state |= Button3Mask; - } - if (buttonState & 0x04) { - state |= Button2Mask; - } - /* Handle buttons 8/9 */ - state |= (buttonState & 0x180) * (Button8Mask >> 7); - - if (keyModifiers & alphaLock) { - state |= LockMask; - } - if (keyModifiers & shiftKey) { - state |= ShiftMask; - } - if (keyModifiers & controlKey) { - state |= ControlMask; - } - if (keyModifiers & cmdKey) { - state |= Mod1Mask; /* command key */ - } - if (keyModifiers & optionKey) { - state |= Mod2Mask; /* option key */ - } - if (keyModifiers & kEventKeyModifierNumLockMask) { - state |= Mod3Mask; - } - if (keyModifiers & kEventKeyModifierFnMask) { - state |= Mod4Mask; - } - - return state; + return [NSApp tkButtonState]; } /* diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h index 0de2805..d546c49 100644 --- a/macosx/tkMacOSXPrivate.h +++ b/macosx/tkMacOSXPrivate.h @@ -331,6 +331,7 @@ VISIBILITY_HIDDEN NSArray *_defaultHelpMenuItems, *_defaultFileMenuItems; NSAutoreleasePool *_mainPool; NSThread *_backgoundLoop; + Bool _tkLiveResizeEnded; #ifdef __i386__ /* The Objective C runtime used on i386 requires this. */ @@ -339,6 +340,10 @@ VISIBILITY_HIDDEN Bool _isDrawing; Bool _needsToDraw; Bool _isSigned; + Bool _tkLiveResizeEnded; + TkWindow *_tkPointerWindow; + TkWindow *_tkEventTarget; + unsigned int _tkButtonState; #endif } @@ -347,6 +352,10 @@ VISIBILITY_HIDDEN @property Bool isDrawing; @property Bool needsToDraw; @property Bool isSigned; +@property Bool tkLiveResizeEnded; +@property TkWindow *tkPointerWindow; +@property TkWindow *tkEventTarget; +@property unsigned int tkButtonState; @end @interface TKApplication(TKInit) @@ -421,6 +430,7 @@ VISIBILITY_HIDDEN NSString *privateWorkingText; Bool _tkNeedsDisplay; NSRect _tkDirtyRect; + NSTrackingArea *trackingArea; } @property Bool tkNeedsDisplay; @property NSRect tkDirtyRect; @@ -448,11 +458,9 @@ VISIBILITY_HIDDEN { #ifdef __i386__ /* The Objective C runtime used on i386 requires this. */ - Bool _mouseInResizeArea; Window _tkWindow; #endif } -@property Bool mouseInResizeArea; @property Window tkWindow; @end diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c index 8b55c38..e8d8b22 100644 --- a/macosx/tkMacOSXSubwindows.c +++ b/macosx/tkMacOSXSubwindows.c @@ -148,6 +148,8 @@ XMapWindow( TkWindow *winPtr = macWin->winPtr; NSWindow *win = TkMacOSXGetNSWindowForDrawable(window); static Bool initialized = NO; + NSPoint mouse = [NSEvent mouseLocation]; + int x = mouse.x, y = TkMacOSXZeroScreenHeight() - mouse.y; /* * Under certain situations it's possible for this function to be called @@ -185,6 +187,16 @@ XMapWindow( [win orderFrontRegardless]; } } + + /* + * Call Tk_UpdatePointer to tell Tk whether the pointer is in the + * new window. + */ + + NSPoint viewLocation = [view convertPoint:mouse fromView:nil]; + if (NSPointInRect(viewLocation, NSInsetRect([view bounds], 2, 2))) { + Tk_UpdatePointer((Tk_Window) winPtr, x, y, [NSApp tkButtonState]); + } } else { TkWindow *contWinPtr = TkpGetOtherWindow(winPtr); @@ -296,6 +308,9 @@ XUnmapWindow( TkWindow *winPtr = macWin->winPtr; TkWindow *parentPtr = winPtr->parentPtr; NSWindow *win = TkMacOSXGetNSWindowForDrawable(window); + NSPoint mouse = [NSEvent mouseLocation]; + int x = mouse.x, y = TkMacOSXZeroScreenHeight() - mouse.y; + int state = TkMacOSXButtonKeyState(); if (!window) { return BadWindow; @@ -356,6 +371,7 @@ XUnmapWindow( if (view != [NSView focusView]) { [view addTkDirtyRect:[view bounds]]; } + Tk_UpdatePointer(NULL, x, y, state); return Success; } diff --git a/macosx/tkMacOSXTest.c b/macosx/tkMacOSXTest.c index 60167ca..26d68d9 100644 --- a/macosx/tkMacOSXTest.c +++ b/macosx/tkMacOSXTest.c @@ -198,7 +198,6 @@ PressButtonObjCmd( Tcl_Obj *const objv[]) { int x = 0, y = 0, i, value; - NSInteger signal = -1; CGPoint pt; NSPoint loc; NSEvent *motion, *press, *release; @@ -234,40 +233,39 @@ PressButtonObjCmd( loc.y = ScreenHeight - y; /* - * We set the window number and the eventNumber to -1 as a signal to - * processMouseEvent. + * We set the timestamp to 0 as a signal to processMouseEvent. */ CGWarpMouseCursorPosition(pt); motion = [NSEvent mouseEventWithType:NSMouseMoved location:loc modifierFlags:0 - timestamp:GetCurrentEventTime() - windowNumber:signal + timestamp:0 + windowNumber:0 context:nil - eventNumber:signal + eventNumber:0 clickCount:1 - pressure:0.0]; + pressure:0]; [NSApp postEvent:motion atStart:NO]; press = [NSEvent mouseEventWithType:NSLeftMouseDown location:loc modifierFlags:0 - timestamp:GetCurrentEventTime() - windowNumber:signal + timestamp:0 + windowNumber:0 context:nil - eventNumber:signal + eventNumber:0 clickCount:1 - pressure:0.0]; + pressure:0]; [NSApp postEvent:press atStart:NO]; release = [NSEvent mouseEventWithType:NSLeftMouseUp location:loc modifierFlags:0 - timestamp:GetCurrentEventTime() - windowNumber:signal + timestamp:0 + windowNumber:0 context:nil - eventNumber:signal + eventNumber:0 clickCount:1 - pressure:-1.0]; + pressure:0]; [NSApp postEvent:release atStart:NO]; return TCL_OK; } diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index d8986c0..edd6c68 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -52,13 +52,33 @@ extern NSString *NSWindowDidOrderOffScreenNotification; #ifdef TK_MAC_DEBUG_NOTIFICATIONS TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); #endif - BOOL activate = [[notification name] - isEqualToString:NSWindowDidBecomeKeyNotification]; NSWindow *w = [notification object]; TkWindow *winPtr = TkMacOSXGetTkWindow(w); + NSString *name = [notification name]; + Bool flag = [name isEqualToString:NSWindowDidBecomeKeyNotification]; + if (winPtr && flag) { + NSPoint location = [NSEvent mouseLocation]; + int x = location.x; + int y = floor(TkMacOSXZeroScreenHeight() - location.y); + /* + * The Tk event target persists when there is no key window but + * gets reset when a new window becomes the key window. + */ + + [NSApp setTkEventTarget: winPtr]; + + /* + * Call Tk_UpdatePointer if the pointer is in the window. + */ + NSView *view = [w contentView]; + NSPoint viewLocation = [view convertPoint:location fromView:nil]; + if (NSPointInRect(viewLocation, NSInsetRect([view bounds], 2, 2))) { + Tk_UpdatePointer((Tk_Window) winPtr, x, y, [NSApp tkButtonState]); + } + } if (winPtr && Tk_IsMapped(winPtr)) { - GenerateActivateEvents(winPtr, activate); + GenerateActivateEvents(winPtr, flag); } } @@ -240,17 +260,22 @@ extern NSString *NSWindowDidOrderOffScreenNotification; } } -#ifdef TK_MAC_DEBUG_NOTIFICATIONS - -- (void) windowDragStart: (NSNotification *) notification +- (void) windowLiveResize: (NSNotification *) notification { - TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); + NSString *name = [notification name]; + if ([name isEqualToString:NSWindowWillStartLiveResizeNotification]) { + // printf("Starting live resize.\n"); + } else if ([name isEqualToString:NSWindowDidEndLiveResizeNotification]) { + [self setTkLiveResizeEnded:YES]; + // printf("Ending live resize\n"); + } } -- (void) windowLiveResize: (NSNotification *) notification +#ifdef TK_MAC_DEBUG_NOTIFICATIONS + +- (void) windowDragStart: (NSNotification *) notification { TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); - //BOOL start = [[notification name] isEqualToString:NSWindowWillStartLiveResizeNotification]; } - (void) windowUnmapped: (NSNotification *) notification @@ -281,6 +306,8 @@ extern NSString *NSWindowDidOrderOffScreenNotification; observe(NSWindowDidMiniaturizeNotification, windowCollapsed:); observe(NSWindowWillOrderOnScreenNotification, windowMapped:); observe(NSWindowDidOrderOnScreenNotification, windowBecameVisible:); + observe(NSWindowWillStartLiveResizeNotification, windowLiveResize:); + observe(NSWindowDidEndLiveResizeNotification, windowLiveResize:); #if !(MAC_OS_X_VERSION_MAX_ALLOWED < 1070) observe(NSWindowDidEnterFullScreenNotification, windowEnteredFullScreen:); @@ -289,8 +316,6 @@ extern NSString *NSWindowDidOrderOffScreenNotification; #ifdef TK_MAC_DEBUG_NOTIFICATIONS observe(NSWindowWillMoveNotification, windowDragStart:); - observe(NSWindowWillStartLiveResizeNotification, windowLiveResize:); - observe(NSWindowDidEndLiveResizeNotification, windowLiveResize:); observe(NSWindowDidOrderOffScreenNotification, windowUnmapped:); #endif #undef observe @@ -961,6 +986,16 @@ ConfigureRestrictProc( */ self.layer.delegate = (id) self; + trackingArea = [[NSTrackingArea alloc] + initWithRect:[self bounds] + options:(NSTrackingMouseEnteredAndExited | + NSTrackingMouseMoved | + NSTrackingEnabledDuringMouseDrag | + NSTrackingInVisibleRect | + NSTrackingActiveAlways) + owner:self + userInfo:nil]; + [self addTrackingArea:trackingArea]; } return self; } diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index b081c4a..b8b4b2f 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -365,7 +365,6 @@ static void RemoveTransient(TkWindow *winPtr); @end @implementation TKWindow: NSWindow -@synthesize mouseInResizeArea = _mouseInResizeArea; @synthesize tkWindow = _tkWindow; @end @@ -6305,7 +6304,7 @@ TkMacOSXMakeRealWindowExist( [window setContentView:contentView]; [contentView release]; [window setDelegate:NSApp]; - [window setAcceptsMouseMovedEvents:YES]; + [window setAcceptsMouseMovedEvents:NO]; [window setReleasedWhenClosed:NO]; if (styleMask & NSUtilityWindowMask) { [(TKPanel*)window setFloatingPanel:YES]; |