summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--macosx/tkMacOSXConstants.h5
-rw-r--r--macosx/tkMacOSXInit.c19
-rw-r--r--macosx/tkMacOSXMouseEvent.c369
-rw-r--r--macosx/tkMacOSXPrivate.h12
-rw-r--r--macosx/tkMacOSXSubwindows.c16
-rw-r--r--macosx/tkMacOSXTest.c28
-rw-r--r--macosx/tkMacOSXWindowEvent.c57
-rw-r--r--macosx/tkMacOSXWm.c3
-rw-r--r--unix/Makefile.in13
-rw-r--r--win/Makefile.in9
-rwxr-xr-xwin/tkUuid.h.in1
11 files changed, 321 insertions, 211 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];
diff --git a/unix/Makefile.in b/unix/Makefile.in
index b4cca52..0451422 100644
--- a/unix/Makefile.in
+++ b/unix/Makefile.in
@@ -1244,7 +1244,7 @@ tkImgPhInstance.o: $(GENERIC_DIR)/tkImgPhInstance.c $(GENERIC_DIR)/tkImgPhoto.h
tkOldTest.o: $(GENERIC_DIR)/tkOldTest.c
$(CC) -c $(APP_CC_SWITCHES) $(GENERIC_DIR)/tkOldTest.c
-tkTest.o: $(GENERIC_DIR)/tkTest.c
+tkTest.o: $(GENERIC_DIR)/tkTest.c tkUuid.h
$(CC) -c $(APP_CC_SWITCHES) $(GENERIC_DIR)/tkTest.c
tkText.o: $(GENERIC_DIR)/tkText.c
@@ -1583,6 +1583,11 @@ ttkWidget.o: $(TTK_DIR)/ttkWidget.c
ttkMacOSXTheme.o: $(MAC_OSX_DIR)/ttkMacOSXTheme.c
$(CC) -c $(CC_SWITCHES) $(MAC_OSX_DIR)/ttkMacOSXTheme.c
+tkUuid.h: $(TOP_DIR)/manifest.uuid
+ echo "#define TK_VERSION_UUID \\" >$@
+ cat $(TOP_DIR)/manifest.uuid >>$@
+ echo "" >>$@
+
.c.o:
$(CC) -c $(CC_SWITCHES) $<
@@ -1678,10 +1683,10 @@ $(UNIX_DIR)/tkConfig.h.in: $(MAC_OSX_DIR)/configure
cd $(MAC_OSX_DIR); autoheader; touch $@
$(TOP_DIR)/manifest.uuid:
- printf "git." >$(TOP_DIR)/manifest.uuid
- git rev-parse HEAD >>$(TOP_DIR)/manifest.uuid
+ printf "git-" >$(TOP_DIR)/manifest.uuid
+ (cd $(TOP_DIR); git rev-parse HEAD >>$(TOP_DIR)/manifest.uuid || printf "unknown" >$(TOP_DIR)/manifest.uuid)
-dist: $(UNIX_DIR)/configure $(UNIX_DIR)/tkConfig.h.in $(UNIX_DIR)/tk.pc.in $(MAC_OSX_DIR)/configure $(TOP_DIR)/doc/man.macros $(TOP_DIR)/manifest.uuid
+dist: $(UNIX_DIR)/configure $(UNIX_DIR)/tkConfig.h.in $(UNIX_DIR)/tk.pc.in $(MAC_OSX_DIR)/configure $(TOP_DIR)/doc/man.macros $(TOP_DIR)/manifest.uuid
rm -rf $(DISTDIR)
$(INSTALL_DATA_DIR) $(DISTDIR)/unix
$(DIST_INSTALL_DATA) $(TOP_DIR)/manifest.uuid $(DISTDIR)
diff --git a/win/Makefile.in b/win/Makefile.in
index c95c5a4..94ac2aa 100644
--- a/win/Makefile.in
+++ b/win/Makefile.in
@@ -688,6 +688,15 @@ $(TKTEST): testMain.$(OBJEXT) $(TEST_DLL_FILE) @LIBRARIES@ $(TK_STUB_LIB_FILE) w
${TEST_DLL_FILE}: ${TKTEST_OBJS} ${TK_STUB_LIB_FILE}
@MAKE_DLL@ ${TKTEST_OBJS} $(TK_STUB_LIB_FILE) $(SHLIB_LD_LIBS)
+$(TOP_DIR)/manifest.uuid:
+ printf "git-" >$(TOP_DIR)/manifest.uuid
+ (cd $(TOP_DIR); git rev-parse HEAD >>$(TOP_DIR)/manifest.uuid || printf "unknown" >$(TOP_DIR)/manifest.uuid)
+
+tkUuid.h: $(TOP_DIR)/manifest.uuid
+ echo "#define TK_VERSION_UUID \\" >$@
+ cat $(TOP_DIR)/manifest.uuid >>$@
+ echo "" >>$@
+
# Msys make requires this next rule for some reason.
$(TCL_SRC_DIR)/win/cat.c:
diff --git a/win/tkUuid.h.in b/win/tkUuid.h.in
new file mode 100755
index 0000000..5a70a8f
--- /dev/null
+++ b/win/tkUuid.h.in
@@ -0,0 +1 @@
+#define TK_VERSION_UUID \