From ac7d8acb9d7b2d18335e5482304f837b1c499360 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 23 Jul 2019 15:24:05 +0000 Subject: Fix [38dc27bd1d]: Tk does not support nor events. Now handle all events up to Button 9. On Windows and Mac, Buttons 8 and 9 are used for the mouse side buttons (as X11 already does). TIP needed for this. --- generic/tkBind.c | 8 ++++++++ generic/tkCanvas.c | 26 +++----------------------- generic/tkEvent.c | 35 ++++++++++++----------------------- generic/tkGrab.c | 13 +------------ generic/tkInt.h | 37 +++++++++++++++++++++++++++++++++++++ generic/tkPointer.c | 14 +------------- generic/tkTextTag.c | 35 ++++++----------------------------- macosx/tkMacOSXMouseEvent.c | 17 +++++++++++------ win/tkWinPointer.c | 6 ++++++ win/tkWinTest.c | 10 ++++++++++ win/tkWinX.c | 17 +++++++++++++++++ 11 files changed, 112 insertions(+), 106 deletions(-) diff --git a/generic/tkBind.c b/generic/tkBind.c index 953d936..15a66f1 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -388,6 +388,14 @@ static const ModInfo modArray[] = { {"Button4", Button4Mask, 0}, {"B5", Button5Mask, 0}, {"Button5", Button5Mask, 0}, + {"B6", Button6Mask, 0}, + {"Button6", Button6Mask, 0}, + {"B7", Button7Mask, 0}, + {"Button7", Button7Mask, 0}, + {"B8", Button8Mask, 0}, + {"Button8", Button8Mask, 0}, + {"B9", Button9Mask, 0}, + {"Button9", Button9Mask, 0}, {"Mod1", Mod1Mask, 0}, {"M1", Mod1Mask, 0}, {"Command", Mod1Mask, 0}, diff --git a/generic/tkCanvas.c b/generic/tkCanvas.c index 10e2ce2..7124d51 100644 --- a/generic/tkCanvas.c +++ b/generic/tkCanvas.c @@ -5092,26 +5092,7 @@ CanvasBindProc( switch (eventPtr->type) { case ButtonPress: case ButtonRelease: - switch (eventPtr->xbutton.button) { - case Button1: - mask = Button1Mask; - break; - case Button2: - mask = Button2Mask; - break; - case Button3: - mask = Button3Mask; - break; - case Button4: - mask = Button4Mask; - break; - case Button5: - mask = Button5Mask; - break; - default: - mask = 0; - break; - } + mask = TkGetButtonMask(eventPtr->xbutton.button); /* * For button press events, repick the current item using the button @@ -5194,7 +5175,7 @@ PickCurrentItem( * ButtonRelease, or MotionNotify. */ { double coords[2]; - int buttonDown; + unsigned int buttonDown; Tk_Item *prevItemPtr; SearchUids *searchUids = GetStaticUids(); @@ -5205,8 +5186,7 @@ PickCurrentItem( * for windows. */ - buttonDown = canvasPtr->state - & (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask); + buttonDown = canvasPtr->state & ALL_BUTTONS; /* * Save information about this event in the canvas. The event in the diff --git a/generic/tkEvent.c b/generic/tkEvent.c index b36d5de..d8501c3 100644 --- a/generic/tkEvent.c +++ b/generic/tkEvent.c @@ -193,7 +193,6 @@ TCL_DECLARE_MUTEX(exitMutex) static void CleanUpTkEvent(XEvent *eventPtr); static void DelayedMotionProc(ClientData clientData); -static int GetButtonMask(unsigned int Button); static unsigned long GetEventMaskFromXEvent(XEvent *eventPtr); static TkWindow * GetTkWindowFromXEvent(XEvent *eventPtr); static void InvokeClientMessageHandlers(ThreadSpecificData *tsdPtr, @@ -524,7 +523,7 @@ RefreshKeyboardMappingIfNeeded( /* *---------------------------------------------------------------------- * - * GetButtonMask -- + * TkGetButtonMask -- * * Return the proper Button${n}Mask for the button. * @@ -537,23 +536,15 @@ RefreshKeyboardMappingIfNeeded( *---------------------------------------------------------------------- */ -static int -GetButtonMask( +static const int buttonMasks[] = { + 0, Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask, Button6Mask, Button7Mask, Button8Mask, Button9Mask +}; + +int +TkGetButtonMask( unsigned int button) { - switch (button) { - case 1: - return Button1Mask; - case 2: - return Button2Mask; - case 3: - return Button3Mask; - case 4: - return Button4Mask; - case 5: - return Button5Mask; - } - return 0; + return (button > Button9) ? 0 : buttonMasks[button]; } /* @@ -582,8 +573,6 @@ UpdateButtonEventState( XEvent *eventPtr) { TkDisplay *dispPtr; - int allButtonsMask = Button1Mask | Button2Mask | Button3Mask - | Button4Mask | Button5Mask; switch (eventPtr->type) { case ButtonPress: @@ -591,19 +580,19 @@ UpdateButtonEventState( dispPtr->mouseButtonWindow = eventPtr->xbutton.window; eventPtr->xbutton.state |= dispPtr->mouseButtonState; - dispPtr->mouseButtonState |= GetButtonMask(eventPtr->xbutton.button); + dispPtr->mouseButtonState |= TkGetButtonMask(eventPtr->xbutton.button); break; case ButtonRelease: dispPtr = TkGetDisplay(eventPtr->xbutton.display); dispPtr->mouseButtonWindow = None; - dispPtr->mouseButtonState &= ~GetButtonMask(eventPtr->xbutton.button); + dispPtr->mouseButtonState &= ~TkGetButtonMask(eventPtr->xbutton.button); eventPtr->xbutton.state |= dispPtr->mouseButtonState; break; case MotionNotify: dispPtr = TkGetDisplay(eventPtr->xmotion.display); - if (dispPtr->mouseButtonState & allButtonsMask) { + if (dispPtr->mouseButtonState & ALL_BUTTONS) { if (eventPtr->xbutton.window != dispPtr->mouseButtonWindow) { /* * This motion event should not be interpreted as a button @@ -611,7 +600,7 @@ UpdateButtonEventState( * button was pressed down in. */ - dispPtr->mouseButtonState &= ~allButtonsMask; + dispPtr->mouseButtonState &= ~ALL_BUTTONS; dispPtr->mouseButtonWindow = None; } else { eventPtr->xmotion.state |= dispPtr->mouseButtonState; diff --git a/generic/tkGrab.c b/generic/tkGrab.c index 917ec69..50d2517 100644 --- a/generic/tkGrab.c +++ b/generic/tkGrab.c @@ -135,17 +135,6 @@ typedef struct NewGrabWinEvent { #define GENERATED_GRAB_EVENT_MAGIC ((Bool) 0x147321ac) /* - * Mask that selects any of the state bits corresponding to buttons, plus - * masks that select individual buttons' bits: - */ - -#define ALL_BUTTONS \ - (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask) -static const unsigned int buttonStates[] = { - Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask -}; - -/* * Forward declarations for functions declared later in this file: */ @@ -883,7 +872,7 @@ TkPointerEvent( } else { if (eventPtr->xbutton.button != AnyButton && ((eventPtr->xbutton.state & ALL_BUTTONS) - == buttonStates[eventPtr->xbutton.button - Button1])) { + == (unsigned int)TkGetButtonMask(eventPtr->xbutton.button))) { ReleaseButtonGrab(dispPtr); /* Note 4. */ } } diff --git a/generic/tkInt.h b/generic/tkInt.h index 77b7725..10888f7 100644 --- a/generic/tkInt.h +++ b/generic/tkInt.h @@ -965,6 +965,43 @@ typedef struct TkpClipMask { #define ALT_MASK (AnyModifier<<2) #define EXTENDED_MASK (AnyModifier<<3) +#ifndef Button6 +# define Button6 6 +#endif +#ifndef Button7 +# define Button7 7 +#endif +#ifndef Button8 +# define Button8 8 +#endif +#ifndef Button9 +# define Button9 9 +#endif + +#ifndef Button6Mask +# define Button6Mask (AnyModifier<<4) +#endif +#ifndef Button7Mask +# define Button7Mask (AnyModifier<<5) +#endif +#ifndef Button8Mask +# define Button8Mask (AnyModifier<<6) +#endif +#ifndef Button9Mask +# define Button9Mask (AnyModifier<<7) +#endif + +/* + * Mask that selects any of the state bits corresponding to buttons, plus + * masks that select individual buttons' bits: + */ + +#define ALL_BUTTONS \ + (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask|Button6Mask|Button7Mask|Button8Mask|Button9Mask) + + +MODULE_SCOPE int TkGetButtonMask(unsigned int); + /* * Object types not declared in tkObj.c need to be mentioned here so they can * be properly registered with Tcl: diff --git a/generic/tkPointer.c b/generic/tkPointer.c index 6e87638..de9d49d 100644 --- a/generic/tkPointer.c +++ b/generic/tkPointer.c @@ -23,18 +23,6 @@ #define Cursor XCursor #endif -/* - * Mask that selects any of the state bits corresponding to buttons, plus - * masks that select individual buttons' bits: - */ - -#define ALL_BUTTONS \ - (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask) -static const unsigned int buttonMasks[] = { - Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask -}; -#define ButtonMask(b) (buttonMasks[(b)-Button1]) - typedef struct { TkWindow *grabWinPtr; /* Window that defines the top of the grab * tree in a global grab. */ @@ -267,7 +255,7 @@ Tk_UpdatePointer( */ for (b = Button1; b <= Button5; b++) { - mask = ButtonMask(b); + mask = TkGetButtonMask(b); if (changes & mask) { if (state & mask) { type = ButtonPress; diff --git a/generic/tkTextTag.c b/generic/tkTextTag.c index cb0993b..bda315e 100644 --- a/generic/tkTextTag.c +++ b/generic/tkTextTag.c @@ -1446,9 +1446,6 @@ TkTextBindProc( TkText *textPtr = clientData; int repick = 0; -# define AnyButtonMask \ - (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask) - textPtr->refCount++; /* @@ -1460,35 +1457,16 @@ TkTextBindProc( if (eventPtr->type == ButtonPress) { textPtr->flags |= BUTTON_DOWN; } else if (eventPtr->type == ButtonRelease) { - int mask; + unsigned int mask; - switch (eventPtr->xbutton.button) { - case Button1: - mask = Button1Mask; - break; - case Button2: - mask = Button2Mask; - break; - case Button3: - mask = Button3Mask; - break; - case Button4: - mask = Button4Mask; - break; - case Button5: - mask = Button5Mask; - break; - default: - mask = 0; - break; - } - if ((eventPtr->xbutton.state & AnyButtonMask) == (unsigned) mask) { + mask = TkGetButtonMask(eventPtr->xbutton.button); + if ((eventPtr->xbutton.state & ALL_BUTTONS) == mask) { textPtr->flags &= ~BUTTON_DOWN; repick = 1; } } else if ((eventPtr->type == EnterNotify) || (eventPtr->type == LeaveNotify)) { - if (eventPtr->xcrossing.state & AnyButtonMask) { + if (eventPtr->xcrossing.state & ALL_BUTTONS) { textPtr->flags |= BUTTON_DOWN; } else { textPtr->flags &= ~BUTTON_DOWN; @@ -1496,7 +1474,7 @@ TkTextBindProc( TkTextPickCurrent(textPtr, eventPtr); goto done; } else if (eventPtr->type == MotionNotify) { - if (eventPtr->xmotion.state & AnyButtonMask) { + if (eventPtr->xmotion.state & ALL_BUTTONS) { textPtr->flags |= BUTTON_DOWN; } else { textPtr->flags &= ~BUTTON_DOWN; @@ -1513,8 +1491,7 @@ TkTextBindProc( unsigned int oldState; oldState = eventPtr->xbutton.state; - eventPtr->xbutton.state &= ~(Button1Mask|Button2Mask - |Button3Mask|Button4Mask|Button5Mask); + eventPtr->xbutton.state &= ~ALL_BUTTONS; if (!(textPtr->flags & DESTROYED)) { TkTextPickCurrent(textPtr, eventPtr); } diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c index 2517769..42fae98 100644 --- a/macosx/tkMacOSXMouseEvent.c +++ b/macosx/tkMacOSXMouseEvent.c @@ -178,22 +178,26 @@ enum { */ unsigned int state = 0; - NSInteger button = [theEvent buttonNumber]; + int button = [theEvent buttonNumber]; + if (++button > 3) { + button += 4; /* Map buttons 4/5 to 8/9 */ + } EventRef eventRef = (EventRef)[theEvent eventRef]; UInt32 buttons; OSStatus err = GetEventParameter(eventRef, kEventParamMouseChord, typeUInt32, NULL, sizeof(UInt32), NULL, &buttons); if (err == noErr) { - state |= (buttons & ((1<<5) - 1)) << 8; - } else if (button < 5) { + state |= (buttons & 0x07) << 8; + state |= (buttons & 0x18) << 12; + } else if (button <= 9) { switch (eventType) { case NSLeftMouseDown: case NSRightMouseDown: case NSLeftMouseDragged: case NSRightMouseDragged: case NSOtherMouseDown: - state |= 1 << (button + 8); + state |= TkGetButtonMask(button); break; default: break; @@ -361,10 +365,11 @@ ButtonModifiers2State( unsigned int state; /* - * Tk supports at most 5 buttons. + * Tk on OSX supports at most 5 buttons. */ - state = (buttonState & ((1<<5) - 1)) << 8; + state = (buttonState & 0x07) * Button1Mask; + state |= (buttonState & 0x18) * (Button8Mask >> 3); if (keyModifiers & alphaLock) { state |= LockMask; diff --git a/win/tkWinPointer.c b/win/tkWinPointer.c index 6f1f840..e3445c7 100644 --- a/win/tkWinPointer.c +++ b/win/tkWinPointer.c @@ -81,6 +81,12 @@ TkWinGetModifierState(void) if (GetKeyState(VK_RBUTTON) & 0x8000) { state |= Button3Mask; } + if (GetKeyState(VK_XBUTTON1) & 0x8000) { + state |= Button8Mask; + } + if (GetKeyState(VK_XBUTTON2) & 0x8000) { + state |= Button9Mask; + } return state; } diff --git a/win/tkWinTest.c b/win/tkWinTest.c index e58ee7c..e386605 100644 --- a/win/tkWinTest.c +++ b/win/tkWinTest.c @@ -287,6 +287,16 @@ TestwineventObjCmd( static const TkStateMap messageMap[] = { {WM_LBUTTONDOWN, "WM_LBUTTONDOWN"}, {WM_LBUTTONUP, "WM_LBUTTONUP"}, + {WM_LBUTTONDBLCLK, "WM_LBUTTONDBLCLK"}, + {WM_MBUTTONDOWN, "WM_MBUTTONDOWN"}, + {WM_MBUTTONUP, "WM_MBUTTONUP"}, + {WM_MBUTTONDBLCLK, "WM_MBUTTONDBLCLK"}, + {WM_RBUTTONDOWN, "WM_RBUTTONDOWN"}, + {WM_RBUTTONUP, "WM_RBUTTONUP"}, + {WM_RBUTTONDBLCLK, "WM_RBUTTONDBLCLK"}, + {WM_XBUTTONDOWN, "WM_XBUTTONDOWN"}, + {WM_XBUTTONUP, "WM_XBUTTONUP"}, + {WM_XBUTTONDBLCLK, "WM_XBUTTONDBLCLK"}, {WM_CHAR, "WM_CHAR"}, {WM_GETTEXT, "WM_GETTEXT"}, {WM_SETTEXT, "WM_SETTEXT"}, diff --git a/win/tkWinX.c b/win/tkWinX.c index db8bc4f..d724282 100644 --- a/win/tkWinX.c +++ b/win/tkWinX.c @@ -884,9 +884,12 @@ Tk_TranslateWinEvent( case WM_MBUTTONDBLCLK: case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: + case WM_XBUTTONDOWN: + case WM_XBUTTONDBLCLK: case WM_LBUTTONUP: case WM_MBUTTONUP: case WM_RBUTTONUP: + case WM_XBUTTONUP: case WM_MOUSEMOVE: Tk_PointerEvent(hwnd, (short) LOWORD(lParam), (short) HIWORD(lParam)); return 1; @@ -1713,6 +1716,14 @@ TkWinResendEvent( msg = WM_RBUTTONDOWN; wparam = MK_RBUTTON; break; + case Button8: + msg = WM_XBUTTONDOWN; + wparam = MAKEWPARAM(MK_XBUTTON1, XBUTTON1); + break; + case Button9: + msg = WM_XBUTTONDOWN; + wparam = MAKEWPARAM(MK_XBUTTON2, XBUTTON2); + break; default: return 0; } @@ -1726,6 +1737,12 @@ TkWinResendEvent( if (eventPtr->xbutton.state & Button3Mask) { wparam |= MK_RBUTTON; } + if (eventPtr->xbutton.state & Button8Mask) { + wparam |= MK_XBUTTON1; + } + if (eventPtr->xbutton.state & Button9Mask) { + wparam |= MK_XBUTTON2; + } if (eventPtr->xbutton.state & ShiftMask) { wparam |= MK_SHIFT; } -- cgit v0.12 From 987d79373dc7dd75d2cc06cd55d34f3cb6624779 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 23 Jul 2019 15:36:38 +0000 Subject: mis-counted modifier bits --- macosx/tkMacOSXMouseEvent.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c index 42fae98..94ebb75 100644 --- a/macosx/tkMacOSXMouseEvent.c +++ b/macosx/tkMacOSXMouseEvent.c @@ -188,8 +188,8 @@ enum { typeUInt32, NULL, sizeof(UInt32), NULL, &buttons); if (err == noErr) { - state |= (buttons & 0x07) << 8; - state |= (buttons & 0x18) << 12; + state |= (buttons & 0x07) * Button1Mask; + state |= (buttons & 0x18) * (Button8Mask >> 3); } else if (button <= 9) { switch (eventType) { case NSLeftMouseDown: -- cgit v0.12 From 2c41264be7ab081b18b9a7dfb177e5835917c4bc Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 24 Jul 2019 13:31:43 +0000 Subject: (cherry-pick): Patch by Arjen sent to core 2018-09-21 Also, do some renumbering of mouse-buttons, such that at script level the XButtons appear to be at 4/5 while - internally - they are at 8/9. --- doc/bind.n | 4 ---- generic/tkBind.c | 33 ++++++++++++++++++-------------- generic/tkEvent.c | 17 ++++++++++++++++- tests/bind.test | 56 ------------------------------------------------------- 4 files changed, 35 insertions(+), 75 deletions(-) diff --git a/doc/bind.n b/doc/bind.n index 7c39cfc..015bad5 100644 --- a/doc/bind.n +++ b/doc/bind.n @@ -114,10 +114,6 @@ Modifiers consist of any of the following values: \fBButton3\fR, \fBB3\fR \fBTriple\fR \fBButton4\fR, \fBB4\fR \fBQuadruple\fR \fBButton5\fR, \fBB5\fR -\fBButton6\fR, \fBB6\fR -\fBButton7\fR, \fBB7\fR -\fBButton8\fR, \fBB8\fR -\fBButton9\fR, \fBB9\fR .DE Where more than one value is listed, separated by commas, the values are equivalent. diff --git a/generic/tkBind.c b/generic/tkBind.c index 15a66f1..a6bd8ca 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -384,18 +384,10 @@ static const ModInfo modArray[] = { {"Button2", Button2Mask, 0}, {"B3", Button3Mask, 0}, {"Button3", Button3Mask, 0}, - {"B4", Button4Mask, 0}, - {"Button4", Button4Mask, 0}, - {"B5", Button5Mask, 0}, - {"Button5", Button5Mask, 0}, - {"B6", Button6Mask, 0}, - {"Button6", Button6Mask, 0}, - {"B7", Button7Mask, 0}, - {"Button7", Button7Mask, 0}, - {"B8", Button8Mask, 0}, - {"Button8", Button8Mask, 0}, - {"B9", Button9Mask, 0}, - {"Button9", Button9Mask, 0}, + {"B4", Button8Mask, 0}, + {"Button4", Button8Mask, 0}, + {"B5", Button9Mask, 0}, + {"Button5", Button9Mask, 0}, {"Mod1", Mod1Mask, 0}, {"M1", Mod1Mask, 0}, {"Command", Mod1Mask, 0}, @@ -1995,6 +1987,9 @@ ExpandPercents( case 'b': if (flags & BUTTON) { number = eventPtr->xbutton.button; + if (eventPtr->xbutton.button >= Button8) { + number += (Button4 - Button8); + } goto doNumber; } goto doString; @@ -3109,6 +3104,9 @@ HandleEventGenerate( return TCL_ERROR; } if (flags & BUTTON) { + if (number >= Button4) { + number += (Button8 - Button4); + } event.general.xbutton.button = number; } else { goto badopt; @@ -3997,7 +3995,7 @@ ParseEventDescription( p = GetField(p, field, FIELD_SIZE); } if (*field != '\0') { - if ((*field >= '1') && (*field <= '9') && (field[1] == '\0')) { + if ((*field >= '1') && (*field <= '5') && (field[1] == '\0')) { if (eventFlags == 0) { patPtr->eventType = ButtonPress; eventMask = ButtonPressMask; @@ -4012,6 +4010,9 @@ ParseEventDescription( goto done; } patPtr->detail.button = (*field - '0'); + if (patPtr->detail.button >= Button4) { + patPtr->detail.button += (Button8 - Button4); + } } else { getKeysym: @@ -4228,7 +4229,11 @@ GetPatternObj( Tcl_AppendToObj(patternObj, string, -1); } } else { - Tcl_AppendPrintfToObj(patternObj, "%d", patPtr->detail.button); + int button = patPtr->detail.button; + if (button >= Button8) { + button += (Button4 - Button8); + } + Tcl_AppendPrintfToObj(patternObj, "%d", button); } } diff --git a/generic/tkEvent.c b/generic/tkEvent.c index d8501c3..02c7de8 100644 --- a/generic/tkEvent.c +++ b/generic/tkEvent.c @@ -580,7 +580,22 @@ UpdateButtonEventState( dispPtr->mouseButtonWindow = eventPtr->xbutton.window; eventPtr->xbutton.state |= dispPtr->mouseButtonState; - dispPtr->mouseButtonState |= TkGetButtonMask(eventPtr->xbutton.button); + if ((eventPtr->xbutton.button >= Button4) && (eventPtr->xbutton.button <= Button7)) { + /* + * Turn the event into a mouse wheel event and queue it + * Note: modelled after the code in tkWinX.c + */ + eventPtr->type = MouseWheelEvent; + eventPtr->xany.send_event = -1; + eventPtr->xkey.nbytes = 0; + eventPtr->xkey.keycode = (eventPtr->xbutton.button & 1) ? 1 : -1; + if (eventPtr->xkey.keycode >= Button6) { + eventPtr->xkey.state |= ShiftMask; + } + Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_TAIL); + } else { + dispPtr->mouseButtonState |= TkGetButtonMask(eventPtr->xbutton.button); + } break; case ButtonRelease: diff --git a/tests/bind.test b/tests/bind.test index ebc39b7..87e8e03 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -5862,62 +5862,6 @@ test bind-27.7 {button names} -setup { } -cleanup { destroy .t.f } -result { {button 5}} -test bind-27.8 {button names} -setup { - frame .t.f -class Test -width 150 -height 100 - pack .t.f - focus -force .t.f - update -} -body { - bind .t.f {lappend x "button 6"} - set x [bind .t.f] - event generate .t.f - event generate .t.f - set x -} -cleanup { - destroy .t.f -} -result { {button 6}} -test bind-27.9 {button names} -setup { - frame .t.f -class Test -width 150 -height 100 - pack .t.f - focus -force .t.f - update -} -body { - bind .t.f {lappend x "button 7"} - set x [bind .t.f] - event generate .t.f - event generate .t.f - set x -} -cleanup { - destroy .t.f -} -result { {button 7}} -test bind-27.10 {button names} -setup { - frame .t.f -class Test -width 150 -height 100 - pack .t.f - focus -force .t.f - update -} -body { - bind .t.f {lappend x "button 8"} - set x [bind .t.f] - event generate .t.f - event generate .t.f - set x -} -cleanup { - destroy .t.f -} -result { {button 8}} -test bind-27.11 {button names} -setup { - frame .t.f -class Test -width 150 -height 100 - pack .t.f - focus -force .t.f - update -} -body { - bind .t.f {lappend x "button 9"} - set x [bind .t.f] - event generate .t.f - event generate .t.f - set x -} -cleanup { - destroy .t.f -} -result { {button 9}} test bind-28.1 {keysym names} -body { bind .t foo -- cgit v0.12 From 89d0c9df2c0159f34bdb8080abef85a21fe9c0bb Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 24 Jul 2019 14:38:37 +0000 Subject: Code simplification: Don't bother keeping track of the Button[n]Mask's for Buttons 4-7, since those are not actually buttons (they are mouse-wheels). This means that Button4Mask/Button5Mask can be used for Buttons 8/9. --- generic/tkBind.c | 8 ++++---- generic/tkEvent.c | 11 +++++++---- generic/tkInt.h | 26 ++++++-------------------- macosx/tkMacOSXMouseEvent.c | 6 ++---- win/tkWinPointer.c | 4 ++-- win/tkWinX.c | 4 ++-- 6 files changed, 23 insertions(+), 36 deletions(-) diff --git a/generic/tkBind.c b/generic/tkBind.c index 8c77d93..3d5bb3e 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -384,10 +384,10 @@ static const ModInfo modArray[] = { {"Button2", Button2Mask, 0}, {"B3", Button3Mask, 0}, {"Button3", Button3Mask, 0}, - {"B4", Button8Mask, 0}, - {"Button4", Button8Mask, 0}, - {"B5", Button9Mask, 0}, - {"Button5", Button9Mask, 0}, + {"B4", Button4Mask, 0}, + {"Button4", Button4Mask, 0}, + {"B5", Button5Mask, 0}, + {"Button5", Button5Mask, 0}, {"Mod1", Mod1Mask, 0}, {"M1", Mod1Mask, 0}, {"Command", Mod1Mask, 0}, diff --git a/generic/tkEvent.c b/generic/tkEvent.c index 02c7de8..a8eaec1 100644 --- a/generic/tkEvent.c +++ b/generic/tkEvent.c @@ -525,7 +525,10 @@ RefreshKeyboardMappingIfNeeded( * * TkGetButtonMask -- * - * Return the proper Button${n}Mask for the button. + * Return the proper Button${n}Mask for the button. Don't care about + * Button4 - Button7, because those are not actually buttons: Those + * are used for the horizontal or vertical mouse wheels. The + * Button4Mask/Button5Mask's are actually used for Button 8 and 9. * * Results: * A button mask. @@ -537,7 +540,7 @@ RefreshKeyboardMappingIfNeeded( */ static const int buttonMasks[] = { - 0, Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask, Button6Mask, Button7Mask, Button8Mask, Button9Mask + 0, Button1Mask, Button2Mask, Button3Mask, 0, 0, 0, 0, Button4Mask, Button5Mask }; int @@ -580,7 +583,7 @@ UpdateButtonEventState( dispPtr->mouseButtonWindow = eventPtr->xbutton.window; eventPtr->xbutton.state |= dispPtr->mouseButtonState; - if ((eventPtr->xbutton.button >= Button4) && (eventPtr->xbutton.button <= Button7)) { + if ((eventPtr->xbutton.button >= Button4) && (eventPtr->xbutton.button < Button8)) { /* * Turn the event into a mouse wheel event and queue it * Note: modelled after the code in tkWinX.c @@ -589,7 +592,7 @@ UpdateButtonEventState( eventPtr->xany.send_event = -1; eventPtr->xkey.nbytes = 0; eventPtr->xkey.keycode = (eventPtr->xbutton.button & 1) ? 1 : -1; - if (eventPtr->xkey.keycode >= Button6) { + if (eventPtr->xkey.keycode > Button5) { eventPtr->xkey.state |= ShiftMask; } Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_TAIL); diff --git a/generic/tkInt.h b/generic/tkInt.h index 10888f7..03ba420 100644 --- a/generic/tkInt.h +++ b/generic/tkInt.h @@ -965,12 +965,11 @@ typedef struct TkpClipMask { #define ALT_MASK (AnyModifier<<2) #define EXTENDED_MASK (AnyModifier<<3) -#ifndef Button6 -# define Button6 6 -#endif -#ifndef Button7 -# define Button7 7 -#endif +/* + * Buttons 8 and 9 are the Xbuttons (left and right side-buttons). On Windows/Mac, those + * are known as Buttons 4 and 5. At script level, they also get the numbers 4 and 5. + */ + #ifndef Button8 # define Button8 8 #endif @@ -978,26 +977,13 @@ typedef struct TkpClipMask { # define Button9 9 #endif -#ifndef Button6Mask -# define Button6Mask (AnyModifier<<4) -#endif -#ifndef Button7Mask -# define Button7Mask (AnyModifier<<5) -#endif -#ifndef Button8Mask -# define Button8Mask (AnyModifier<<6) -#endif -#ifndef Button9Mask -# define Button9Mask (AnyModifier<<7) -#endif - /* * Mask that selects any of the state bits corresponding to buttons, plus * masks that select individual buttons' bits: */ #define ALL_BUTTONS \ - (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask|Button6Mask|Button7Mask|Button8Mask|Button9Mask) + (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask) MODULE_SCOPE int TkGetButtonMask(unsigned int); diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c index fc4d1c2..78363d0 100644 --- a/macosx/tkMacOSXMouseEvent.c +++ b/macosx/tkMacOSXMouseEvent.c @@ -188,8 +188,7 @@ enum { typeUInt32, NULL, sizeof(UInt32), NULL, &buttons); if (err == noErr) { - state |= (buttons & 0x07) * Button1Mask; - state |= (buttons & 0x18) * (Button8Mask >> 3); + state |= (buttons & 0x1F) * Button1Mask; } else if (button <= 9) { switch (eventType) { case NSLeftMouseDown: @@ -368,8 +367,7 @@ ButtonModifiers2State( * Tk on OSX supports at most 5 buttons. */ - state = (buttonState & 0x07) * Button1Mask; - state |= (buttonState & 0x18) * (Button8Mask >> 3); + state = (buttonState & 0x1F) * Button1Mask; if (keyModifiers & alphaLock) { state |= LockMask; diff --git a/win/tkWinPointer.c b/win/tkWinPointer.c index e3445c7..251b5b9 100644 --- a/win/tkWinPointer.c +++ b/win/tkWinPointer.c @@ -82,10 +82,10 @@ TkWinGetModifierState(void) state |= Button3Mask; } if (GetKeyState(VK_XBUTTON1) & 0x8000) { - state |= Button8Mask; + state |= Button4Mask; } if (GetKeyState(VK_XBUTTON2) & 0x8000) { - state |= Button9Mask; + state |= Button5Mask; } return state; } diff --git a/win/tkWinX.c b/win/tkWinX.c index d724282..9d474ac 100644 --- a/win/tkWinX.c +++ b/win/tkWinX.c @@ -1737,10 +1737,10 @@ TkWinResendEvent( if (eventPtr->xbutton.state & Button3Mask) { wparam |= MK_RBUTTON; } - if (eventPtr->xbutton.state & Button8Mask) { + if (eventPtr->xbutton.state & Button4Mask) { wparam |= MK_XBUTTON1; } - if (eventPtr->xbutton.state & Button9Mask) { + if (eventPtr->xbutton.state & Button5Mask) { wparam |= MK_XBUTTON2; } if (eventPtr->xbutton.state & ShiftMask) { -- cgit v0.12 From 5c07a1409bb742e9fe41e7e523146ce75d71580a Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 24 Jul 2019 14:55:51 +0000 Subject: A few more minor adaptations, and make it compile on X11 (XKeyEvent structure doesn't have a nbytes field). --- generic/tkBind.c | 2 +- generic/tkEvent.c | 2 ++ macosx/tkMacOSXMouseEvent.c | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/generic/tkBind.c b/generic/tkBind.c index 3d5bb3e..0208a7a 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -1987,7 +1987,7 @@ ExpandPercents( case 'b': if (flags & BUTTON) { number = eventPtr->xbutton.button; - if (eventPtr->xbutton.button >= Button8) { + if (number >= Button8) { number += (Button4 - Button8); } goto doNumber; diff --git a/generic/tkEvent.c b/generic/tkEvent.c index a8eaec1..e94cdd5 100644 --- a/generic/tkEvent.c +++ b/generic/tkEvent.c @@ -590,7 +590,9 @@ UpdateButtonEventState( */ eventPtr->type = MouseWheelEvent; eventPtr->xany.send_event = -1; +#if defined(_WIN32) || defined(MAC_OSX_TK) eventPtr->xkey.nbytes = 0; +#endif eventPtr->xkey.keycode = (eventPtr->xbutton.button & 1) ? 1 : -1; if (eventPtr->xkey.keycode > Button5) { eventPtr->xkey.state |= ShiftMask; diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c index 78363d0..37e3568 100644 --- a/macosx/tkMacOSXMouseEvent.c +++ b/macosx/tkMacOSXMouseEvent.c @@ -189,7 +189,7 @@ enum { if (err == noErr) { state |= (buttons & 0x1F) * Button1Mask; - } else if (button <= 9) { + } else if (button <= Button9) { switch (eventType) { case NSLeftMouseDown: case NSRightMouseDown: -- cgit v0.12 From f97059c69925b78f7f7e291b86fa2089f58291a6 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 26 Jul 2019 09:06:10 +0000 Subject: Further experiment: Bring scalefactor back to 120 (as it was for win32) --- doc/event.n | 4 ++-- generic/tkBind.c | 4 ++-- generic/tkEvent.c | 2 +- generic/tkPointer.c | 3 +-- library/demos/cscroll.tcl | 8 ++++---- library/listbox.tcl | 8 ++++---- library/scrlbar.tcl | 8 ++++---- library/text.tcl | 8 ++++---- library/ttk/utils.tcl | 35 ++++++++++------------------------- macosx/tkMacOSXMouseEvent.c | 14 ++++++++------ tests/scrollbar.test | 4 ++-- win/tkWinX.c | 4 ++-- 12 files changed, 44 insertions(+), 58 deletions(-) diff --git a/doc/event.n b/doc/event.n index be42fa5..5109794 100644 --- a/doc/event.n +++ b/doc/event.n @@ -119,8 +119,8 @@ for the event. Only valid for virtual events. Corresponds to the for the \fBMouseWheel\fR event. The \fIdelta\fR refers to the direction and magnitude the mouse wheel was rotated. Note the value is not a screen distance but are units of motion in the mouse wheel. -Typically these values are multiples of 40. For example, 40 should -scroll the text widget up 4 lines and \-80 would scroll the text +Typically these values are multiples of 120. For example, 120 should +scroll the text widget up 4 lines and \-240 would scroll the text widget down 8 lines. Of course, other widgets may define different behaviors for mouse wheel motion. This field corresponds to the \fB%D\fR substitution for binding scripts. diff --git a/generic/tkBind.c b/generic/tkBind.c index 03e4a2b..45e07be 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -1996,7 +1996,7 @@ ExpandPercents( if (flags & BUTTON) { number = eventPtr->xbutton.button; if (number >= Button8) { - number += (Button4 - Button8); + number -= (Button8 - Button4); } goto doNumber; } @@ -4239,7 +4239,7 @@ GetPatternObj( } else { int button = patPtr->detail.button; if (button >= Button8) { - button += (Button4 - Button8); + button -= (Button8 - Button4); } Tcl_AppendPrintfToObj(patternObj, "%d", button); } diff --git a/generic/tkEvent.c b/generic/tkEvent.c index dd77c2b..39d9d4b 100644 --- a/generic/tkEvent.c +++ b/generic/tkEvent.c @@ -594,7 +594,7 @@ UpdateButtonEventState( #if defined(_WIN32) || defined(MAC_OSX_TK) eventPtr->xkey.nbytes = 0; #endif - eventPtr->xkey.keycode = (eventPtr->xbutton.button & 1) ? 40 : -40; + eventPtr->xkey.keycode = (eventPtr->xbutton.button & 1) ? 120 : -120; if (eventPtr->xkey.keycode > Button5) { eventPtr->xkey.state |= ShiftMask; } diff --git a/generic/tkPointer.c b/generic/tkPointer.c index af5e311..57680c3 100644 --- a/generic/tkPointer.c +++ b/generic/tkPointer.c @@ -226,8 +226,7 @@ Tk_UpdatePointer( XPoint pos; XEvent event; int changes = (state ^ tsdPtr->lastState) & ALL_BUTTONS; - int type, b; - int mask; + int type, b, mask; pos.x = x; pos.y = y; diff --git a/library/demos/cscroll.tcl b/library/demos/cscroll.tcl index 24d5f89..c709668 100644 --- a/library/demos/cscroll.tcl +++ b/library/demos/cscroll.tcl @@ -59,16 +59,16 @@ $c bind all <1> "scrollButton $c" bind $c <2> "$c scan mark %x %y" bind $c "$c scan dragto %x %y" bind $c { - %W yview scroll [expr {-(%D / 40)}] units + %W yview scroll [expr {-((%D+60) / 120)}] units } bind $c { - %W yview scroll [expr {-(%D / 4)}] units + %W yview scroll [expr {-((%D+6) / 12)}] units } bind $c { - %W xview scroll [expr {-(%D / 40)}] units + %W xview scroll [expr {-((%D+60) / 120)}] units } bind $c { - %W xview scroll [expr {-(%D / 4)}] units + %W xview scroll [expr {-((%D+6) / 12)}] units } proc scrollEnter canvas { diff --git a/library/listbox.tcl b/library/listbox.tcl index fd10fe4..ffd7def 100644 --- a/library/listbox.tcl +++ b/library/listbox.tcl @@ -177,16 +177,16 @@ bind Listbox { } bind Listbox { - %W yview scroll [expr {-(%D / 40)}] units + %W yview scroll [expr {-((%D+60) / 120)}] units } bind Listbox { - %W yview scroll [expr {-(%D / 4)}] units + %W yview scroll [expr {-((%D+6) / 12)}] units } bind Listbox { - %W xview scroll [expr {-(%D / 40)}] units + %W xview scroll [expr {-((%D+60) / 120)}] units } bind Listbox { - %W xview scroll [expr {-(%D / 4)}] units + %W xview scroll [expr {-((%D+6) / 12)}] units } diff --git a/library/scrlbar.tcl b/library/scrlbar.tcl index 93ded56..dae11ae 100644 --- a/library/scrlbar.tcl +++ b/library/scrlbar.tcl @@ -130,16 +130,16 @@ bind Scrollbar <> { } bind Scrollbar { - tk::ScrollByUnits %W v [expr {-(%D / 40)}] + tk::ScrollByUnits %W v [expr {-((%D+60) / 120)}] } bind Scrollbar { - tk::ScrollByUnits %W v [expr {-(%D / 4)}] + tk::ScrollByUnits %W v [expr {-((%D+6) / 12)}] } bind Scrollbar { - tk::ScrollByUnits %W h [expr {-(%D / 40)}] + tk::ScrollByUnits %W h [expr {-((%D+60) / 120)}] } bind Scrollbar { - tk::ScrollByUnits %W h [expr {-(%D / 4)}] + tk::ScrollByUnits %W h [expr {-((%D+6) / 12)}] } # tk::ScrollButtonDown -- diff --git a/library/text.tcl b/library/text.tcl index 9d635de..72da6ff 100644 --- a/library/text.tcl +++ b/library/text.tcl @@ -428,16 +428,16 @@ bind Text { set ::tk::Priv(prevPos) {} bind Text { - %W yview scroll [expr {-(%D)}] pixels + %W yview scroll [expr {-((%D+1)/3)}] pixels } bind Text { - %W yview scroll [expr {-10 * (%D)}] pixels + %W yview scroll [expr {-4 * (%D)}] pixels } bind Text { - %W xview scroll [expr {-(%D)}] pixels + %W xview scroll [expr {-((%D+1)/3)}] pixels } bind Text { - %W xview scroll [expr {-10 * (%D)}] pixels + %W xview scroll [expr {-4 * (%D)}] pixels } # ::tk::TextClosestGap -- diff --git a/library/ttk/utils.tcl b/library/ttk/utils.tcl index 140e061..ad36927 100644 --- a/library/ttk/utils.tcl +++ b/library/ttk/utils.tcl @@ -285,7 +285,8 @@ proc ttk::copyBindings {from to} { # proc ttk::bindMouseWheel {bindtag callback} { - bind $bindtag [append callback { [expr {-(%D/40)}]}] + bind $bindtag [append callback { [expr {-((%D+60)/120)}]}] + bind $bindtag [append callback { [expr {-((%D+6)/12)}]}] } ## Mousewheel bindings for standard scrollable widgets. @@ -296,29 +297,13 @@ proc ttk::bindMouseWheel {bindtag callback} { # standard scrollbar protocol. # -switch -- [tk windowingsystem] { - x11 { - bind TtkScrollable { %W yview scroll -5 units } - bind TtkScrollable { %W yview scroll 5 units } - bind TtkScrollable { %W xview scroll -5 units } - bind TtkScrollable { %W xview scroll 5 units } - } - win32 { - bind TtkScrollable \ - { %W yview scroll [expr {-(%D/120)}] units } - bind TtkScrollable \ - { %W xview scroll [expr {-(%D/120)}] units } - } - aqua { - bind TtkScrollable \ - { %W yview scroll [expr {-(%D)}] units } - bind TtkScrollable \ - { %W xview scroll [expr {-(%D)}] units } - bind TtkScrollable \ - { %W yview scroll [expr {-10*(%D)}] units } - bind TtkScrollable \ - { %W xview scroll [expr {-10*(%D)}] units } - } -} +bind TtkScrollable \ +{ %W yview scroll [expr {-((%D+60)/120)}] units } +bind TtkScrollable \ +{ %W yview scroll [expr {-((%D+6)/12)}] units } +bind TtkScrollable \ +{ %W xview scroll [expr {-((%D+60)/120)}] units } +bind TtkScrollable \ +{ %W xview scroll [expr {-((%D+6)/12)}] units } #*EOF* diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c index ed67bae..92d2daf 100644 --- a/macosx/tkMacOSXMouseEvent.c +++ b/macosx/tkMacOSXMouseEvent.c @@ -267,21 +267,23 @@ enum { xEvent.xany.display = Tk_Display(tkwin); xEvent.xany.window = Tk_WindowId(tkwin); - delta = [theEvent deltaY] * 40; + delta = [theEvent deltaY] * 120; if (delta != 0.0) { - coarseDelta = (delta > -40.0 && delta < 40.0) ? - (signbit(delta) ? -40 : 40 : lround(delta); + coarseDelta = (delta > -120.0 && delta < 120.0) ? + (signbit(delta) ? -120 : 120 : lround(delta); xEvent.xbutton.state = state; xEvent.xkey.keycode = coarseDelta; + xEvent.xkey.nbytes = 0; xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin)); Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL); } - delta = [theEvent deltaX] * 40; + delta = [theEvent deltaX] * 120; if (delta != 0.0) { - coarseDelta = (delta > -40.0 && delta < 40.0) ? - (signbit(delta) ? -40 : 40) : lround(delta); + coarseDelta = (delta > -120.0 && delta < 120.0) ? + (signbit(delta) ? -120 : 120) : lround(delta); xEvent.xbutton.state = state | ShiftMask; xEvent.xkey.keycode = coarseDelta; + xEvent.xkey.nbytes = 0; xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin)); Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL); } diff --git a/tests/scrollbar.test b/tests/scrollbar.test index d235656..e6e6bdd 100644 --- a/tests/scrollbar.test +++ b/tests/scrollbar.test @@ -693,7 +693,7 @@ test scrollbar-10.1 { event on scrollbar} -setup { pack [scrollbar .s -command {.t yview}] -fill y -expand 1 -side left update focus -force .s - event generate .s -delta -150 + event generate .s -delta -120 after 200 {set eventprocessed 1} ; vwait eventprocessed .t index @0,0 } -cleanup { @@ -708,7 +708,7 @@ test scrollbar-10.2 { event on scrollbar} -setup { pack [scrollbar .s -command {.t xview} -orient horizontal] -fill x -expand 1 -side top update focus -force .s - event generate .s -delta -150 + event generate .s -delta -120 after 200 {set eventprocessed 1} ; vwait eventprocessed .t index @0,0 } -cleanup { diff --git a/win/tkWinX.c b/win/tkWinX.c index 8127eef..9d474ac 100644 --- a/win/tkWinX.c +++ b/win/tkWinX.c @@ -1142,7 +1142,7 @@ GenerateXEvent( event.type = MouseWheelEvent; event.xany.send_event = -1; event.xkey.nbytes = 0; - event.xkey.keycode = tsdPtr->vWheelAcc / WHEEL_DELTA * WHEEL_DELTA / 3; + event.xkey.keycode = tsdPtr->vWheelAcc / WHEEL_DELTA * WHEEL_DELTA; tsdPtr->vWheelAcc = tsdPtr->vWheelAcc % WHEEL_DELTA; break; } @@ -1175,7 +1175,7 @@ GenerateXEvent( event.xany.send_event = -1; event.xkey.nbytes = 0; event.xkey.state |= ShiftMask; - event.xkey.keycode = tsdPtr->hWheelAcc / WHEEL_DELTA * WHEEL_DELTA / 3; + event.xkey.keycode = tsdPtr->hWheelAcc / WHEEL_DELTA * WHEEL_DELTA; tsdPtr->hWheelAcc = tsdPtr->hWheelAcc % WHEEL_DELTA; break; } -- cgit v0.12 From 6162cfbddcf8e3a169053a09e42e89f5d7b56b28 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 26 Jul 2019 09:57:24 +0000 Subject: Fix MouseWheel bindings for listbox and scrollbar: This fixes test-failures on Win32. Still to be tested on MacOS and X11 --- generic/tkInt.h | 2 +- library/listbox.tcl | 8 ++++---- library/scrlbar.tcl | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/generic/tkInt.h b/generic/tkInt.h index a3aa36f..07591d1 100644 --- a/generic/tkInt.h +++ b/generic/tkInt.h @@ -981,7 +981,7 @@ typedef struct TkpClipMask { # define Button6Mask (1<<13) #endif #ifndef Button7Mask -# define Button7Mask (1<<13) +# define Button7Mask (1<<14) #endif #ifndef Button8Mask # define Button8Mask (AnyModifier<<4) diff --git a/library/listbox.tcl b/library/listbox.tcl index ffd7def..769fe25 100644 --- a/library/listbox.tcl +++ b/library/listbox.tcl @@ -177,16 +177,16 @@ bind Listbox { } bind Listbox { - %W yview scroll [expr {-((%D+60) / 120)}] units + %W yview scroll [expr {-((%D+15) / 30)}] units } bind Listbox { - %W yview scroll [expr {-((%D+6) / 12)}] units + %W yview scroll [expr {-((%D+1) / 3)}] units } bind Listbox { - %W xview scroll [expr {-((%D+60) / 120)}] units + %W xview scroll [expr {-((%D+15) / 30)}] units } bind Listbox { - %W xview scroll [expr {-((%D+6) / 12)}] units + %W xview scroll [expr {-((%D+1) / 3)}] units } diff --git a/library/scrlbar.tcl b/library/scrlbar.tcl index dae11ae..a20f1a0 100644 --- a/library/scrlbar.tcl +++ b/library/scrlbar.tcl @@ -130,16 +130,16 @@ bind Scrollbar <> { } bind Scrollbar { - tk::ScrollByUnits %W v [expr {-((%D+60) / 120)}] + tk::ScrollByUnits %W v [expr {-((%D+15) / 30)}] } bind Scrollbar { - tk::ScrollByUnits %W v [expr {-((%D+6) / 12)}] + tk::ScrollByUnits %W v [expr {-((%D+1) / 3)}] } bind Scrollbar { - tk::ScrollByUnits %W h [expr {-((%D+60) / 120)}] + tk::ScrollByUnits %W h [expr {-((%D+15) / 30)}] } bind Scrollbar { - tk::ScrollByUnits %W h [expr {-((%D+6) / 12)}] + tk::ScrollByUnits %W h [expr {-((%D+1) / 3)}] } # tk::ScrollButtonDown -- -- cgit v0.12 From 9e83cbe850e17780f646217d932645e2105b605c Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 29 Jul 2019 12:48:00 +0000 Subject: Add support for "(x|y)view scroll number mouseunits" for text widget, and use it in mouse bindings. --- generic/tkTextDisp.c | 20 +++++++++++++++++--- generic/tkUtil.c | 8 ++++---- library/text.tcl | 8 ++++---- tests/entry.test | 4 ++-- tests/spinbox.test | 4 ++-- tests/textDisp.test | 16 ++++++++-------- tests/util.test | 6 +++--- 7 files changed, 40 insertions(+), 26 deletions(-) diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index d4f6b83..2aeec2e 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -631,6 +631,7 @@ static int IsStartOfNotMergedLine(TkText *textPtr, #define TKTEXT_SCROLL_UNITS 3 #define TKTEXT_SCROLL_ERROR 4 #define TKTEXT_SCROLL_PIXELS 5 +#define TKTEXT_SCROLL_MOUSE 6 /* *---------------------------------------------------------------------- @@ -5893,6 +5894,10 @@ TkTextXviewCmd( case TKTEXT_SCROLL_PIXELS: dInfoPtr->newXPixelOffset += count; break; + case TKTEXT_SCROLL_MOUSE: + if (count < 0) count -= 2; + dInfoPtr->newXPixelOffset += (-count)/3; + break; } dInfoPtr->flags |= DINFO_OUT_OF_DATE; @@ -6297,6 +6302,10 @@ TkTextYviewCmd( case TKTEXT_SCROLL_PIXELS: YScrollByPixels(textPtr, count); break; + case TKTEXT_SCROLL_MOUSE: + if (count < 0) count -= 2; + YScrollByPixels(textPtr, (-count)/3); + break; case TKTEXT_SCROLL_UNITS: YScrollByLines(textPtr, count); break; @@ -8770,10 +8779,10 @@ TextGetScrollInfoObj( VIEW_MOVETO, VIEW_SCROLL }; static const char *const units[] = { - "units", "pages", "pixels", NULL + "mouseunits", "pages", "pixels", "units", NULL }; enum viewUnits { - VIEW_SCROLL_UNITS, VIEW_SCROLL_PAGES, VIEW_SCROLL_PIXELS + VIEW_SCROLL_MOUSE, VIEW_SCROLL_PAGES, VIEW_SCROLL_PIXELS, VIEW_SCROLL_UNITS }; int index; @@ -8794,7 +8803,7 @@ TextGetScrollInfoObj( return TKTEXT_SCROLL_MOVETO; case VIEW_SCROLL: if (objc != 5) { - Tcl_WrongNumArgs(interp, 3, objv, "number units|pages|pixels"); + Tcl_WrongNumArgs(interp, 3, objv, "number mouseunits|pages|pixels|units"); return TKTEXT_SCROLL_ERROR; } if (Tcl_GetIndexFromObjStruct(interp, objv[4], units, @@ -8802,6 +8811,11 @@ TextGetScrollInfoObj( return TKTEXT_SCROLL_ERROR; } switch ((enum viewUnits) index) { + case VIEW_SCROLL_MOUSE: + if (Tcl_GetIntFromObj(interp, objv[3], intPtr) != TCL_OK) { + return TKTEXT_SCROLL_ERROR; + } + return TKTEXT_SCROLL_MOUSE; case VIEW_SCROLL_PAGES: if (Tcl_GetIntFromObj(interp, objv[3], intPtr) != TCL_OK) { return TKTEXT_SCROLL_ERROR; diff --git a/generic/tkUtil.c b/generic/tkUtil.c index 2950fe0..4844bc2 100644 --- a/generic/tkUtil.c +++ b/generic/tkUtil.c @@ -668,7 +668,7 @@ Tk_GetScrollInfo( if (argc != 5) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "wrong # args: should be \"%s %s %s\"", - argv[0], argv[1], "scroll number units|pages")); + argv[0], argv[1], "scroll number pages|units")); Tcl_SetErrorCode(interp, "TCL", "WRONGARGS", NULL); return TK_SCROLL_ERROR; } @@ -684,7 +684,7 @@ Tk_GetScrollInfo( } Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "bad argument \"%s\": must be units or pages", argv[4])); + "bad argument \"%s\": must be pages or units", argv[4])); Tcl_SetErrorCode(interp, "TK", "VALUE", "SCROLL_UNITS", NULL); return TK_SCROLL_ERROR; } @@ -746,7 +746,7 @@ Tk_GetScrollInfoObj( return TK_SCROLL_MOVETO; } else if (ArgPfxEq("scroll")) { if (objc != 5) { - Tcl_WrongNumArgs(interp, 2, objv, "scroll number units|pages"); + Tcl_WrongNumArgs(interp, 2, objv, "scroll number pages|units"); return TK_SCROLL_ERROR; } if (Tcl_GetIntFromObj(interp, objv[3], intPtr) != TCL_OK) { @@ -761,7 +761,7 @@ Tk_GetScrollInfoObj( } Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "bad argument \"%s\": must be units or pages", arg)); + "bad argument \"%s\": must be pages or units", arg)); Tcl_SetErrorCode(interp, "TK", "VALUE", "SCROLL_UNITS", NULL); return TK_SCROLL_ERROR; } diff --git a/library/text.tcl b/library/text.tcl index 72da6ff..98255e4 100644 --- a/library/text.tcl +++ b/library/text.tcl @@ -428,16 +428,16 @@ bind Text { set ::tk::Priv(prevPos) {} bind Text { - %W yview scroll [expr {-((%D+1)/3)}] pixels + %W yview scroll %D mouseunits } bind Text { - %W yview scroll [expr {-4 * (%D)}] pixels + %W yview scroll [expr {10 * (%D)}] mouseunits } bind Text { - %W xview scroll [expr {-((%D+1)/3)}] pixels + %W xview scroll %D mouseunits } bind Text { - %W xview scroll [expr {-4 * (%D)}] pixels + %W xview scroll [expr {10 * (%D)}] mouseunits } # ::tk::TextClosestGap -- diff --git a/tests/entry.test b/tests/entry.test index 75a5da8..6207c69 100644 --- a/tests/entry.test +++ b/tests/entry.test @@ -1435,7 +1435,7 @@ test entry-3.71 {EntryWidgetCmd procedure, "xview" widget command} -setup { .e xview scroll 24 } -cleanup { destroy .e -} -returnCodes error -result {wrong # args: should be ".e xview scroll number units|pages"} +} -returnCodes error -result {wrong # args: should be ".e xview scroll number pages|units"} test entry-3.72 {EntryWidgetCmd procedure, "xview" widget command} -setup { entry .e -font {Courier -12} -borderwidth 2 -highlightthickness 2 pack .e @@ -1512,7 +1512,7 @@ test entry-3.77 {EntryWidgetCmd procedure, "xview" widget command} -setup { .e xview scroll 23 foobars } -cleanup { destroy .e -} -returnCodes error -result {bad argument "foobars": must be units or pages} +} -returnCodes error -result {bad argument "foobars": must be pages or units} test entry-3.78 {EntryWidgetCmd procedure, "xview" widget command} -setup { entry .e -font {Courier -12} -borderwidth 2 -highlightthickness 2 pack .e diff --git a/tests/spinbox.test b/tests/spinbox.test index 28ebe68..efd5b63 100644 --- a/tests/spinbox.test +++ b/tests/spinbox.test @@ -1773,7 +1773,7 @@ test spinbox-3.71 {SpinboxWidgetCmd procedure, "xview" widget command} -setup { .e xview scroll 24 } -cleanup { destroy .e -} -returnCodes error -result {wrong # args: should be ".e xview scroll number units|pages"} +} -returnCodes error -result {wrong # args: should be ".e xview scroll number pages|units"} test spinbox-3.72 {SpinboxWidgetCmd procedure, "xview" widget command} -setup { spinbox .e -font {Courier -12} -borderwidth 2 -highlightthickness 2 pack .e @@ -1850,7 +1850,7 @@ test spinbox-3.77 {SpinboxWidgetCmd procedure, "xview" widget command} -setup { .e xview scroll 23 foobars } -cleanup { destroy .e -} -returnCodes error -result {bad argument "foobars": must be units or pages} +} -returnCodes error -result {bad argument "foobars": must be pages or units} test spinbox-3.78 {SpinboxWidgetCmd procedure, "xview" widget command} -setup { spinbox .e -font {Courier -12} -borderwidth 2 -highlightthickness 2 pack .e diff --git a/tests/textDisp.test b/tests/textDisp.test index 5df5467..698f8a7 100644 --- a/tests/textDisp.test +++ b/tests/textDisp.test @@ -1867,10 +1867,10 @@ test textDisp-14.9 {TkTextXviewCmd procedure} { } [list [expr {9.0/14}] 1.0] test textDisp-14.10 {TkTextXviewCmd procedure} { list [catch {.t xview scroll a} msg] $msg -} {1 {wrong # args: should be ".t xview scroll number units|pages|pixels"}} +} {1 {wrong # args: should be ".t xview scroll number mouseunits|pages|pixels|units"}} test textDisp-14.11 {TkTextXviewCmd procedure} { list [catch {.t xview scroll a b c} msg] $msg -} {1 {wrong # args: should be ".t xview scroll number units|pages|pixels"}} +} {1 {wrong # args: should be ".t xview scroll number mouseunits|pages|pixels|units"}} test textDisp-14.12 {TkTextXviewCmd procedure} { list [catch {.t xview scroll gorp units} msg] $msg } {1 {expected integer but got "gorp"}} @@ -1904,7 +1904,7 @@ test textDisp-14.14 {TkTextXviewCmd procedure} { } {2.21 2.20 2.99 2.84} test textDisp-14.15 {TkTextXviewCmd procedure} { list [catch {.t xview scroll 14 globs} msg] $msg -} {1 {bad argument "globs": must be units, pages, or pixels}} +} {1 {bad argument "globs": must be mouseunits, pages, pixels, or units}} test textDisp-14.16 {TkTextXviewCmd procedure} { list [catch {.t xview flounder} msg] $msg } {1 {bad option "flounder": must be moveto or scroll}} @@ -2086,13 +2086,13 @@ test textDisp-16.18 {TkTextYviewCmd procedure, "moveto" roundoff} {textfonts} { } [list [expr {1.0/3}] [expr {5.0/6}]] test textDisp-16.19 {TkTextYviewCmd procedure, "scroll" option} { list [catch {.t yview scroll a} msg] $msg -} {1 {wrong # args: should be ".t yview scroll number units|pages|pixels"}} +} {1 {wrong # args: should be ".t yview scroll number mouseunits|pages|pixels|units"}} test textDisp-16.20 {TkTextYviewCmd procedure, "scroll" option} { list [catch {.t yview scroll a b c} msg] $msg -} {1 {wrong # args: should be ".t yview scroll number units|pages|pixels"}} +} {1 {wrong # args: should be ".t yview scroll number mouseunits|pages|pixels|units"}} test textDisp-16.21 {TkTextYviewCmd procedure, "scroll" option} { list [catch {.t yview scroll badInt bogus} msg] $msg -} {1 {bad argument "bogus": must be units, pages, or pixels}} +} {1 {bad argument "bogus": must be mouseunits, pages, pixels, or units}} test textDisp-16.21.2 {TkTextYviewCmd procedure, "scroll" option} { list [catch {.t yview scroll badInt units} msg] $msg } {1 {expected integer but got "badInt"}} @@ -2104,7 +2104,7 @@ test textDisp-16.22 {TkTextYviewCmd procedure, "scroll" option, back pages} { } {42.0} test textDisp-16.22.1 {TkTextYviewCmd procedure, "scroll" option, back pages} { list [catch {.t yview scroll -3 p} res] $res -} {1 {ambiguous argument "p": must be units, pages, or pixels}} +} {1 {ambiguous argument "p": must be mouseunits, pages, pixels, or units}} test textDisp-16.23 {TkTextYviewCmd procedure, "scroll" option, back pages} { .t yview 50.0 update @@ -2175,7 +2175,7 @@ test textDisp-16.31 {TkTextYviewCmd procedure, "scroll units" option} { } {151.40} test textDisp-16.32 {TkTextYviewCmd procedure} { list [catch {.t yview scroll 12 bogoids} msg] $msg -} {1 {bad argument "bogoids": must be units, pages, or pixels}} +} {1 {bad argument "bogoids": must be mouseunits, pages, pixels, or units}} test textDisp-16.33 {TkTextYviewCmd procedure} { list [catch {.t yview bad_arg 1 2} msg] $msg } {1 {bad option "bad_arg": must be moveto or scroll}} diff --git a/tests/util.test b/tests/util.test index c1ec6a5..d457b50 100644 --- a/tests/util.test +++ b/tests/util.test @@ -28,10 +28,10 @@ test util-1.3 {Tk_GetScrollInfo procedure} -body { } -result {0.5 0.75} test util-1.4 {Tk_GetScrollInfo procedure} -body { .l yview scroll a -} -returnCodes error -result {wrong # args: should be ".l yview scroll number units|pages"} +} -returnCodes error -result {wrong # args: should be ".l yview scroll number pages|units"} test util-1.5 {Tk_GetScrollInfo procedure} -body { .l yview scroll a b c -} -returnCodes error -result {wrong # args: should be ".l yview scroll number units|pages"} +} -returnCodes error -result {wrong # args: should be ".l yview scroll number pages|units"} test util-1.6 {Tk_GetScrollInfo procedure} -body { .l yview scroll xyz units } -returnCodes error -result {expected integer but got "xyz"} @@ -57,7 +57,7 @@ test util-1.10 {Tk_GetScrollInfo procedure} -body { } -result {13} test util-1.11 {Tk_GetScrollInfo procedure} -body { .l yview scroll 3 zips -} -returnCodes error -result {bad argument "zips": must be units or pages} +} -returnCodes error -result {bad argument "zips": must be pages or units} test util-1.12 {Tk_GetScrollInfo procedure} -body { .l yview dropdead 3 times } -returnCodes error -result {unknown option "dropdead": must be moveto or scroll} -- cgit v0.12 From 099f9695819a7024079f79db648c326601bac8b4 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 30 Jul 2019 07:27:43 +0000 Subject: Put (x|y)view scroll options in alphabetical order --- doc/GetScroll.3 | 8 ++++---- doc/canvas.n | 16 ++++++++-------- doc/entry.n | 12 ++++++------ doc/listbox.n | 16 +++++++++------- doc/scrollbar.n | 18 +++++++++--------- doc/spinbox.n | 10 +++++----- doc/text.n | 32 ++++++++++++++++++-------------- doc/ttk_scrollbar.n | 16 ++++++++-------- doc/ttk_widget.n | 14 ++++++++------ 9 files changed, 75 insertions(+), 67 deletions(-) diff --git a/doc/GetScroll.3 b/doc/GetScroll.3 index c0b302d..dd12cca 100644 --- a/doc/GetScroll.3 +++ b/doc/GetScroll.3 @@ -50,18 +50,18 @@ and parses the words starting with \fIobjv\fR[2]. The words starting with \fIobjv\fR[2] must have one of the following forms: .CS \fBmoveto \fIfraction\fR -\fBscroll \fInumber\fB units\fR \fBscroll \fInumber\fB pages\fR +\fBscroll \fInumber\fB units\fR .CE .LP -Any of the \fBmoveto\fR, \fBscroll\fR, \fBunits\fR, and \fBpages\fR +Any of the \fBmoveto\fR, \fBscroll\fR, \fBpages\fR, and \fBunits\fR keywords may be abbreviated. If \fIobjv\fR has the \fBmoveto\fR form, \fBTK_SCROLL_MOVETO\fR is returned as result and \fI*fractionPtr\fR is filled in with the \fIfraction\fR argument to the command, which must be a proper real value. -If \fIobjv\fR has the \fBscroll\fR form, \fBTK_SCROLL_UNITS\fR -or \fBTK_SCROLL_PAGES\fR is returned and \fI*stepsPtr\fR is filled +If \fIobjv\fR has the \fBscroll\fR form, \fBTK_SCROLL_PAGES\fR +or \fBTK_SCROLL_UNITS\fR is returned and \fI*stepsPtr\fR is filled in with the \fInumber\fR value, which must be a proper integer. If an error occurs in parsing the arguments, \fBTK_SCROLL_ERROR\fR is returned and an error message is left in interpreter diff --git a/doc/canvas.n b/doc/canvas.n index bad9113..ddaebcf 100644 --- a/doc/canvas.n +++ b/doc/canvas.n @@ -1147,16 +1147,16 @@ total width of the canvas is off-screen to the left. This command shifts the view in the window left or right according to \fInumber\fR and \fIwhat\fR. \fINumber\fR must be an integer. -\fIWhat\fR must be either \fBunits\fR or \fBpages\fR or an abbreviation +\fIWhat\fR must be either \fBpages\fR or \fBunits\fR or an abbreviation of one of these. -If \fIwhat\fR is \fBunits\fR, the view adjusts left or right in units -of the \fBxScrollIncrement\fR option, if it is greater than zero, -or in units of one-tenth the window's width otherwise. If \fIwhat is \fBpages\fR then the view adjusts in units of nine-tenths the window's width. If \fInumber\fR is negative then information farther to the left becomes visible; if it is positive then information farther to the right becomes visible. +If \fIwhat\fR is \fBunits\fR, the view adjusts left or right in units +of the \fBxScrollIncrement\fR option, if it is greater than zero, +or in units of one-tenth the window's width otherwise. .RE .TP \fIpathName \fByview \fI?args\fR? @@ -1188,15 +1188,15 @@ area is off-screen to the top. This command adjusts the view in the window up or down according to \fInumber\fR and \fIwhat\fR. \fINumber\fR must be an integer. -\fIWhat\fR must be either \fBunits\fR or \fBpages\fR. -If \fIwhat\fR is \fBunits\fR, the view adjusts up or down in units -of the \fByScrollIncrement\fR option, if it is greater than zero, -or in units of one-tenth the window's height otherwise. +\fIWhat\fR must be either \fBpages\fR or \fBunits\fR. If \fIwhat\fR is \fBpages\fR then the view adjusts in units of nine-tenths the window's height. If \fInumber\fR is negative then higher information becomes visible; if it is positive then lower information becomes visible. +If \fIwhat\fR is \fBunits\fR, the view adjusts up or down in units +of the \fByScrollIncrement\fR option, if it is greater than zero, +or in units of one-tenth the window's height otherwise. .RE .SH "OVERVIEW OF ITEM TYPES" .PP diff --git a/doc/entry.n b/doc/entry.n index abbf53d..4589af0 100644 --- a/doc/entry.n +++ b/doc/entry.n @@ -404,14 +404,14 @@ way through the text appears at the left edge of the window. This command shifts the view in the window left or right according to \fInumber\fR and \fIwhat\fR. \fINumber\fR must be an integer. -\fIWhat\fR must be either \fBunits\fR or \fBpages\fR or an abbreviation +\fIWhat\fR must be either \fBpages\fR or \fBunits\fR or an abbreviation of one of these. -If \fIwhat\fR is \fBunits\fR, the view adjusts left or right by -\fInumber\fR average-width characters on the display; if it is -\fBpages\fR then the view adjusts by \fInumber\fR screenfuls. -If \fInumber\fR is negative then characters farther to the left -become visible; if it is positive then characters farther to the right +If \fIwhat\fR is \fBpages\fR then the view adjusts by \fInumber\fR screenfuls. +If \fInumber\fR is negative then characters farther to the left become +visible; if it is positive then characters farther to the right become visible. +If \fIwhat\fR is \fBunits\fR, the view adjusts left or right by +\fInumber\fR average-width characters on the display. .RE .SH "DEFAULT BINDINGS" .PP diff --git a/doc/listbox.n b/doc/listbox.n index 66b75b9..ef3ae1c 100644 --- a/doc/listbox.n +++ b/doc/listbox.n @@ -384,15 +384,16 @@ total width of the listbox text is off-screen to the left. This command shifts the view in the window left or right according to \fInumber\fR and \fIwhat\fR. \fINumber\fR must be an integer. -\fIWhat\fR must be either \fBunits\fR or \fBpages\fR or an abbreviation +\fIWhat\fR must be either \fBpages\fR or \fBunits\fR or an abbreviation of one of these. -If \fIwhat\fR is \fBunits\fR, the view adjusts left or right by -\fInumber\fR character units (the width of the \fB0\fR character) -on the display; if it is \fBpages\fR then the view adjusts by +If \fIwhat\fR is \fBpages\fR then the view adjusts by \fInumber\fR screenfuls. If \fInumber\fR is negative then characters farther to the left become visible; if it is positive then characters farther to the right become visible. +If \fIwhat\fR is \fBunits\fR, the view adjusts left or right by +\fInumber\fR character units (the width of the \fB0\fR character) +on the display. .RE .TP \fIpathName \fByview \fR?\fIargs\fR? @@ -431,13 +432,14 @@ way through the listbox, and so on. This command adjusts the view in the window up or down according to \fInumber\fR and \fIwhat\fR. \fINumber\fR must be an integer. -\fIWhat\fR must be either \fBunits\fR or \fBpages\fR. -If \fIwhat\fR is \fBunits\fR, the view adjusts up or down by -\fInumber\fR lines; if it is \fBpages\fR then +\fIWhat\fR must be either \fBpages\fR or \fBunits\fR. +If \fIwhat\fR is \fBpages\fR then the view adjusts by \fInumber\fR screenfuls. If \fInumber\fR is negative then earlier elements become visible; if it is positive then later elements become visible. +If \fIwhat\fR is \fBunits\fR, the view adjusts up or down by +\fInumber\fR lines. .RE .SH "DEFAULT BINDINGS" .PP diff --git a/doc/scrollbar.n b/doc/scrollbar.n index 4b1d4ba..5a062ce 100644 --- a/doc/scrollbar.n +++ b/doc/scrollbar.n @@ -215,15 +215,6 @@ document. 1.0 refers to the end of the document, 0.333 refers to a point one-third of the way through the document, and so on. .TP -\fIprefix \fBscroll \fInumber \fBunits\fR -. -The widget should adjust its view by \fInumber\fR units. -The units are defined in whatever way makes sense for the widget, -such as characters or lines in a text widget. -\fINumber\fR is either 1, which means one unit should scroll off -the top or left of the window, or \-1, which means that one unit -should scroll off the bottom or right of the window. -.TP \fIprefix \fBscroll \fInumber \fBpages\fR . The widget should adjust its view by \fInumber\fR pages. @@ -233,6 +224,15 @@ is a slight overlap between the old and new views. \fINumber\fR is either 1, which means the next page should become visible, or \-1, which means that the previous page should become visible. +.TP +\fIprefix \fBscroll \fInumber \fBunits\fR +. +The widget should adjust its view by \fInumber\fR units. +The units are defined in whatever way makes sense for the widget, +such as characters or lines in a text widget. +\fINumber\fR is either 1, which means one unit should scroll off +the top or left of the window, or \-1, which means that one unit +should scroll off the bottom or right of the window. .SH "OLD COMMAND SYNTAX" .PP In versions of Tk before 4.0, the \fBset\fR and \fBget\fR widget diff --git a/doc/spinbox.n b/doc/spinbox.n index f2b1ff2..6719ca3 100644 --- a/doc/spinbox.n +++ b/doc/spinbox.n @@ -471,14 +471,14 @@ way through the text appears at the left edge of the window. This command shifts the view in the window left or right according to \fInumber\fR and \fIwhat\fR. \fINumber\fR must be an integer. -\fIWhat\fR must be either \fBunits\fR or \fBpages\fR or an abbreviation +\fIWhat\fR must be either \fBpages\fR or \fBunits\fR or an abbreviation of one of these. -If \fIwhat\fR is \fBunits\fR, the view adjusts left or right by -\fInumber\fR average-width characters on the display; if it is -\fBpages\fR then the view adjusts by \fInumber\fR screenfuls. -If \fInumber\fR is negative then characters farther to the left +If \fIwhat\fR is \fBpages\fR then the view adjusts by \fInumber\fR +screenfuls. If \fInumber\fR is negative then characters farther to the left become visible; if it is positive then characters farther to the right become visible. +If \fIwhat\fR is \fBunits\fR, the view adjusts left or right by +\fInumber\fR average-width characters on the display. .RE .SH "DEFAULT BINDINGS" .PP diff --git a/doc/text.n b/doc/text.n index 250dff7..95a4272 100644 --- a/doc/text.n +++ b/doc/text.n @@ -1930,20 +1930,22 @@ and 1. \fIpathName \fBxview scroll \fInumber what\fR . This command shifts the view in the window left or right according to -\fInumber\fR and \fIwhat\fR. \fIWhat\fR must be \fBunits\fR, \fBpages\fR or -\fBpixels\fR. If \fIwhat\fR is \fBunits\fR or \fBpages\fR then \fInumber\fR -must be an integer, otherwise number may be specified in any of the forms -acceptable to \fBTk_GetPixels\fR, such as +\fInumber\fR and \fIwhat\fR. \fIWhat\fR must be \fBmouseunits\fR, \fBpages\fR, +\fBpixels\fR, or \fBunits\fR. If \fIwhat\fR is \fBmouseunits\fR, \fBpages\fR or +\fBunits\fR then \fInumber\fR must be an integer, otherwise number may be +specified in any of the forms acceptable to \fBTk_GetPixels\fR, such as .QW 2.0c or .QW 1i (the result is rounded to the nearest integer value. If no units are given, -pixels are assumed). If \fIwhat\fR is \fBunits\fR, the view adjusts left or -right by \fInumber\fR average-width characters on the display; if it is -\fBpages\fR then the view adjusts by \fInumber\fR screenfuls; if it is -\fBpixels\fR then the view adjusts by \fInumber\fR pixels. If \fInumber\fR is +pixels are assumed). If \fIwhat\fR is \fBpages\fR then the view adjusts by +\fInumber\fR screenfuls; if it is \fBpixels\fR then the view adjusts by +\fInumber\fR pixels; if it is \fBunits\fR, the view adjusts left or +right by \fInumber\fR average-width characters on the display. If \fInumber\fR is negative then characters farther to the left become visible; if it is positive -then characters farther to the right become visible. +then characters farther to the right become visible. If \fIwhat\fR is +\fBmouseunits\fR then the view adjusts about -\fInumber\fR/3 pixels, since +mouse units work in the other direction than pixels. .RE .TP \fIpathName \fByview \fR?\fIargs\fR? @@ -1978,10 +1980,10 @@ the bottom of the window, and some other pixel is at the top. \fIpathName \fByview scroll \fInumber what\fR . This command adjust the view in the window up or down according to -\fInumber\fR and \fIwhat\fR. \fIWhat\fR must be \fBunits\fR, \fBpages\fR or -\fBpixels\fR. If \fIwhat\fR is \fBunits\fR or \fBpages\fR then \fInumber\fR -must be an integer, otherwise number may be specified in any of the forms -acceptable to \fBTk_GetPixels\fR, such as +\fInumber\fR and \fIwhat\fR. \fIWhat\fR must be \fBmouseunits\fR, \fBpages\fR, +\fBpixels\fR, or \fBunits\fR. If \fIwhat\fR is \fBunits\fR or \fBpages\fR then +\fInumber\fR must be an integer, otherwise number may be specified in any of +the forms acceptable to \fBTk_GetPixels\fR, such as .QW 2.0c or .QW 1i @@ -1991,7 +1993,9 @@ by \fInumber\fR lines on the display; if it is \fBpages\fR then the view adjusts by \fInumber\fR screenfuls; if it is \fBpixels\fR then the view adjusts by \fInumber\fR pixels. If \fInumber\fR is negative then earlier positions in the text become visible; if it is positive then later positions -in the text become visible. +in the text become visible. If \fIwhat\fR is \fBmouseunits\fR then the view +adjusts about -\fInumber\fR/3 pixels, since mouse units work in the other +direction than pixels. .TP \fIpathName \fByview \fR?\fB\-pickplace\fR? \fIindex\fR . diff --git a/doc/ttk_scrollbar.n b/doc/ttk_scrollbar.n index bd80760..08c7f52 100644 --- a/doc/ttk_scrollbar.n +++ b/doc/ttk_scrollbar.n @@ -118,14 +118,6 @@ document. 1.0 refers to the end of the document, 0.333 refers to a point one-third of the way through the document, and so on. .TP -\fIprefix \fBscroll \fInumber \fBunits\fR -The widget should adjust its view by \fInumber\fR units. -The units are defined in whatever way makes sense for the widget, -such as characters or lines in a text widget. -\fINumber\fR is either 1, which means one unit should scroll off -the top or left of the window, or \-1, which means that one unit -should scroll off the bottom or right of the window. -.TP \fIprefix \fBscroll \fInumber \fBpages\fR The widget should adjust its view by \fInumber\fR pages. It is up to the widget to define the meaning of a page; typically @@ -134,6 +126,14 @@ is a slight overlap between the old and new views. \fINumber\fR is either 1, which means the next page should become visible, or \-1, which means that the previous page should become visible. +.TP +\fIprefix \fBscroll \fInumber \fBunits\fR +The widget should adjust its view by \fInumber\fR units. +The units are defined in whatever way makes sense for the widget, +such as characters or lines in a text widget. +\fINumber\fR is either 1, which means one unit should scroll off +the top or left of the window, or \-1, which means that one unit +should scroll off the bottom or right of the window. .SH "WIDGET STATES" .PP The scrollbar automatically sets the \fBdisabled\fR state bit. diff --git a/doc/ttk_widget.n b/doc/ttk_widget.n index b1c280d..2dca269 100644 --- a/doc/ttk_widget.n +++ b/doc/ttk_widget.n @@ -254,14 +254,15 @@ way through the content appears at the left edge of the window. This command shifts the view in the window left or right according to \fInumber\fR and \fIwhat\fR. \fINumber\fR must be an integer. -\fIWhat\fR must be either \fBunits\fR or \fBpages\fR. +\fIWhat\fR must be either \fBpages\fR or \fBunits\fR. '\" or an abbreviation of one of these, but we don't document that. -If \fIwhat\fR is \fBunits\fR, the view adjusts left or right by -\fInumber\fR average-width characters on the display; if it is +If \fIwhat\fR is \fBpages\fR then the view adjusts by \fInumber\fR screenfuls. If \fInumber\fR is negative then characters farther to the left become visible; if it is positive then characters farther to the right become visible. +If \fIwhat\fR is \fBunits\fR, the view adjusts left or right by +\fInumber\fR average-width characters on the display. .RE .TP \fIpathName \fByview \fIargs\fR @@ -293,14 +294,15 @@ way through the content appears at the top edge of the window. This command shifts the view in the window up or down according to \fInumber\fR and \fIwhat\fR. \fINumber\fR must be an integer. -\fIWhat\fR must be either \fBunits\fR or \fBpages\fR. +\fIWhat\fR must be either \fBpages\fR or \fBunits\fR. '\" or an abbreviation of one of these, but we don't document that. -If \fIwhat\fR is \fBunits\fR, the view adjusts up or down by -\fInumber\fR average-width characters on the display; if it is +If \fIwhat\fR is \fBpages\fR then the view adjusts by \fInumber\fR screenfuls. If \fInumber\fR is negative then items farther to the top become visible; if it is positive then items farther to the bottom become visible. +If \fIwhat\fR is \fBunits\fR, the view adjusts up or down by +\fInumber\fR average-width characters on the display. .RE .SH "WIDGET STATES" The widget state is a bitmap of independent state flags. -- cgit v0.12 From 127c180c66bf291cae359b4c83fcfce3961af8be Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 22 Aug 2019 15:02:23 +0000 Subject: Allow using floating-point number in "scroll (x|y)view (units|pages)". They are rounded away from zero towards an integer. --- doc/GetScroll.3 | 3 ++- doc/canvas.n | 3 ++- doc/entry.n | 3 ++- doc/listbox.n | 3 ++- doc/spinbox.n | 3 ++- doc/text.n | 14 +++++--------- doc/ttk_widget.n | 3 ++- generic/tkTextDisp.c | 11 ++++++++++- library/listbox.tcl | 8 ++++---- library/scrlbar.tcl | 8 ++++---- library/ttk/utils.tcl | 12 ++++++------ tests/entry.test | 2 +- tests/spinbox.test | 2 +- tests/textDisp.test | 8 ++++---- tests/util.test | 2 +- 15 files changed, 48 insertions(+), 37 deletions(-) diff --git a/doc/GetScroll.3 b/doc/GetScroll.3 index dd12cca..d61e744 100644 --- a/doc/GetScroll.3 +++ b/doc/GetScroll.3 @@ -62,7 +62,8 @@ is returned as result and \fI*fractionPtr\fR is filled in with the value. If \fIobjv\fR has the \fBscroll\fR form, \fBTK_SCROLL_PAGES\fR or \fBTK_SCROLL_UNITS\fR is returned and \fI*stepsPtr\fR is filled -in with the \fInumber\fR value, which must be a proper integer. +in with the \fInumber\fR value, which must be a integer or a float, +but if it is a float then it is converted to an integer, rounded away from 0. If an error occurs in parsing the arguments, \fBTK_SCROLL_ERROR\fR is returned and an error message is left in interpreter \fIinterp\fR's result. diff --git a/doc/canvas.n b/doc/canvas.n index ddaebcf..95c732e 100644 --- a/doc/canvas.n +++ b/doc/canvas.n @@ -1146,7 +1146,8 @@ total width of the canvas is off-screen to the left. . This command shifts the view in the window left or right according to \fInumber\fR and \fIwhat\fR. -\fINumber\fR must be an integer. +\fINumber\fR must be an integer or a float, but if it is a float then +it is converted to an integer, rounded away from 0. \fIWhat\fR must be either \fBpages\fR or \fBunits\fR or an abbreviation of one of these. If \fIwhat is \fBpages\fR then the view diff --git a/doc/entry.n b/doc/entry.n index 4589af0..dd198a7 100644 --- a/doc/entry.n +++ b/doc/entry.n @@ -403,7 +403,8 @@ way through the text appears at the left edge of the window. \fIpathName \fBxview scroll \fInumber what\fR This command shifts the view in the window left or right according to \fInumber\fR and \fIwhat\fR. -\fINumber\fR must be an integer. +\fINumber\fR must be an integer or a float, but if it is a float then +it is converted to an integer, rounded away from 0. \fIWhat\fR must be either \fBpages\fR or \fBunits\fR or an abbreviation of one of these. If \fIwhat\fR is \fBpages\fR then the view adjusts by \fInumber\fR screenfuls. diff --git a/doc/listbox.n b/doc/listbox.n index ef3ae1c..c2ff09e 100644 --- a/doc/listbox.n +++ b/doc/listbox.n @@ -383,7 +383,8 @@ total width of the listbox text is off-screen to the left. . This command shifts the view in the window left or right according to \fInumber\fR and \fIwhat\fR. -\fINumber\fR must be an integer. +\fINumber\fR must be an integer or a float, but if it is a float then +it is converted to an integer, rounded away from 0. \fIWhat\fR must be either \fBpages\fR or \fBunits\fR or an abbreviation of one of these. If \fIwhat\fR is \fBpages\fR then the view adjusts by diff --git a/doc/spinbox.n b/doc/spinbox.n index 6719ca3..6d0646b 100644 --- a/doc/spinbox.n +++ b/doc/spinbox.n @@ -470,7 +470,8 @@ way through the text appears at the left edge of the window. \fIpathName \fBxview scroll \fInumber what\fR This command shifts the view in the window left or right according to \fInumber\fR and \fIwhat\fR. -\fINumber\fR must be an integer. +\fINumber\fR must be an integer or a float, but if it is a float then +it is converted to an integer, rounded away from 0. \fIWhat\fR must be either \fBpages\fR or \fBunits\fR or an abbreviation of one of these. If \fIwhat\fR is \fBpages\fR then the view adjusts by \fInumber\fR diff --git a/doc/text.n b/doc/text.n index 95a4272..c4128a1 100644 --- a/doc/text.n +++ b/doc/text.n @@ -1930,8 +1930,8 @@ and 1. \fIpathName \fBxview scroll \fInumber what\fR . This command shifts the view in the window left or right according to -\fInumber\fR and \fIwhat\fR. \fIWhat\fR must be \fBmouseunits\fR, \fBpages\fR, -\fBpixels\fR, or \fBunits\fR. If \fIwhat\fR is \fBmouseunits\fR, \fBpages\fR or +\fInumber\fR and \fIwhat\fR. \fIWhat\fR must be \fBpages\fR, +\fBpixels\fR, or \fBunits\fR. If \fIwhat\fR is \fBpages\fR or \fBunits\fR then \fInumber\fR must be an integer, otherwise number may be specified in any of the forms acceptable to \fBTk_GetPixels\fR, such as .QW 2.0c @@ -1943,9 +1943,7 @@ pixels are assumed). If \fIwhat\fR is \fBpages\fR then the view adjusts by \fInumber\fR pixels; if it is \fBunits\fR, the view adjusts left or right by \fInumber\fR average-width characters on the display. If \fInumber\fR is negative then characters farther to the left become visible; if it is positive -then characters farther to the right become visible. If \fIwhat\fR is -\fBmouseunits\fR then the view adjusts about -\fInumber\fR/3 pixels, since -mouse units work in the other direction than pixels. +then characters farther to the right become visible. .RE .TP \fIpathName \fByview \fR?\fIargs\fR? @@ -1980,7 +1978,7 @@ the bottom of the window, and some other pixel is at the top. \fIpathName \fByview scroll \fInumber what\fR . This command adjust the view in the window up or down according to -\fInumber\fR and \fIwhat\fR. \fIWhat\fR must be \fBmouseunits\fR, \fBpages\fR, +\fInumber\fR and \fIwhat\fR. \fIWhat\fR must be \fBpages\fR, \fBpixels\fR, or \fBunits\fR. If \fIwhat\fR is \fBunits\fR or \fBpages\fR then \fInumber\fR must be an integer, otherwise number may be specified in any of the forms acceptable to \fBTk_GetPixels\fR, such as @@ -1993,9 +1991,7 @@ by \fInumber\fR lines on the display; if it is \fBpages\fR then the view adjusts by \fInumber\fR screenfuls; if it is \fBpixels\fR then the view adjusts by \fInumber\fR pixels. If \fInumber\fR is negative then earlier positions in the text become visible; if it is positive then later positions -in the text become visible. If \fIwhat\fR is \fBmouseunits\fR then the view -adjusts about -\fInumber\fR/3 pixels, since mouse units work in the other -direction than pixels. +in the text become visible. .TP \fIpathName \fByview \fR?\fB\-pickplace\fR? \fIindex\fR . diff --git a/doc/ttk_widget.n b/doc/ttk_widget.n index 2dca269..fdacfd0 100644 --- a/doc/ttk_widget.n +++ b/doc/ttk_widget.n @@ -253,7 +253,8 @@ way through the content appears at the left edge of the window. \fIpathName \fBxview scroll \fInumber what\fR This command shifts the view in the window left or right according to \fInumber\fR and \fIwhat\fR. -\fINumber\fR must be an integer. +\fINumber\fR must be an integer or a float, but if it is a float then +it is converted to an integer, rounded away from 0. \fIWhat\fR must be either \fBpages\fR or \fBunits\fR. '\" or an abbreviation of one of these, but we don't document that. If \fIwhat\fR is diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index 33b9720..e6dc988 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -8776,6 +8776,7 @@ TextGetScrollInfoObj( VIEW_SCROLL_PAGES, VIEW_SCROLL_PIXELS, VIEW_SCROLL_UNITS }; int index; + double d; if (Tcl_GetIndexFromObjStruct(interp, objv[2], subcommands, sizeof(char *), "option", 0, &index) != TCL_OK) { @@ -8814,9 +8815,17 @@ TextGetScrollInfoObj( } return TKTEXT_SCROLL_PIXELS; case VIEW_SCROLL_UNITS: - if (Tcl_GetIntFromObj(interp, objv[3], intPtr) != TCL_OK) { + if (Tcl_GetDoubleFromObj(interp, objv[3], &d) != TCL_OK) { return TKTEXT_SCROLL_ERROR; } + if (d > 0) { + *intPtr = ceil(d); + } else { + *intPtr = floor(d); + } + if (dblPtr) { + *dblPtr = d; + } return TKTEXT_SCROLL_UNITS; } } diff --git a/library/listbox.tcl b/library/listbox.tcl index 4a76a18..7400494 100644 --- a/library/listbox.tcl +++ b/library/listbox.tcl @@ -177,16 +177,16 @@ bind Listbox { } bind Listbox { - %W yview scroll [expr {-(%D/30)}] units + %W yview scroll [expr {%D/-30}] units } bind Listbox { - %W yview scroll [expr {-(%D/3)}] units + %W yview scroll [expr {%D/-3}] units } bind Listbox { - %W xview scroll [expr {-(%D/30)}] units + %W xview scroll [expr {%D/-30}] units } bind Listbox { - %W xview scroll [expr {-(%D/3)}] units + %W xview scroll [expr {%D/-3}] units } # ::tk::ListboxBeginSelect -- diff --git a/library/scrlbar.tcl b/library/scrlbar.tcl index d797b24..2b3503a 100644 --- a/library/scrlbar.tcl +++ b/library/scrlbar.tcl @@ -130,16 +130,16 @@ bind Scrollbar <> { } bind Scrollbar { - tk::ScrollByUnits %W v [expr {-(%D / 30)}] + tk::ScrollByUnits %W v [expr {%D/-30.0}] } bind Scrollbar { - tk::ScrollByUnits %W v [expr {-(%D / 3)}] + tk::ScrollByUnits %W v [expr {%D/-3.0}] } bind Scrollbar { - tk::ScrollByUnits %W h [expr {-(%D / 30)}] + tk::ScrollByUnits %W h [expr {%D/-30.0}] } bind Scrollbar { - tk::ScrollByUnits %W h [expr {-(%D / 3)}] + tk::ScrollByUnits %W h [expr {%D/-3.0}] } # tk::ScrollButtonDown -- diff --git a/library/ttk/utils.tcl b/library/ttk/utils.tcl index fc8b4e0..4827aa3 100644 --- a/library/ttk/utils.tcl +++ b/library/ttk/utils.tcl @@ -285,8 +285,8 @@ proc ttk::copyBindings {from to} { # proc ttk::bindMouseWheel {bindtag callback} { - bind $bindtag [append callback { [expr {-(%D / 120)}]}] - bind $bindtag [append callback { [expr {-(%D / 12)}]}] + bind $bindtag [append callback { [expr {%D/-120.0}]}] + bind $bindtag [append callback { [expr {%D/-12.0}]}] } ## Mousewheel bindings for standard scrollable widgets. @@ -298,12 +298,12 @@ proc ttk::bindMouseWheel {bindtag callback} { # bind TtkScrollable \ - { %W yview scroll [expr {-(%D / 120)}] units } + { %W yview scroll [expr {%D/-120}] units } bind TtkScrollable \ - { %W yview scroll [expr {-(%D / 12)}] units } + { %W yview scroll [expr {%D/-12}] units } bind TtkScrollable \ - { %W xview scroll [expr {-(%D / 120)}] units } + { %W xview scroll [expr {%D/-120}] units } bind TtkScrollable \ - { %W xview scroll [expr {-(%D / 12)}] units } + { %W xview scroll [expr {%D/-12}] units } #*EOF* diff --git a/tests/entry.test b/tests/entry.test index 6207c69..47b459d 100644 --- a/tests/entry.test +++ b/tests/entry.test @@ -1446,7 +1446,7 @@ test entry-3.72 {EntryWidgetCmd procedure, "xview" widget command} -setup { .e xview scroll gorp units } -cleanup { destroy .e -} -returnCodes error -result {expected integer but got "gorp"} +} -returnCodes error -result {expected floating-point number but got "gorp"} test entry-3.73 {EntryWidgetCmd procedure, "xview" widget command} -setup { entry .e -font {Courier -12} -borderwidth 2 -highlightthickness 2 pack .e diff --git a/tests/spinbox.test b/tests/spinbox.test index efd5b63..65c5bd9 100644 --- a/tests/spinbox.test +++ b/tests/spinbox.test @@ -1784,7 +1784,7 @@ test spinbox-3.72 {SpinboxWidgetCmd procedure, "xview" widget command} -setup { .e xview scroll gorp units } -cleanup { destroy .e -} -returnCodes error -result {expected integer but got "gorp"} +} -returnCodes error -result {expected floating-point number but got "gorp"} test spinbox-3.73 {SpinboxWidgetCmd procedure, "xview" widget command} -setup { spinbox .e -font {Courier -12} -borderwidth 2 -highlightthickness 2 pack .e diff --git a/tests/textDisp.test b/tests/textDisp.test index 1b6f4c5..c029a69 100644 --- a/tests/textDisp.test +++ b/tests/textDisp.test @@ -1873,7 +1873,7 @@ test textDisp-14.11 {TkTextXviewCmd procedure} { } {1 {wrong # args: should be ".t xview scroll number pages|pixels|units"}} test textDisp-14.12 {TkTextXviewCmd procedure} { list [catch {.t xview scroll gorp units} msg] $msg -} {1 {expected integer but got "gorp"}} +} {1 {expected floating-point number but got "gorp"}} test textDisp-14.13 {TkTextXviewCmd procedure} { .t delete 1.0 end .t insert end xxxxxxxxx\n @@ -2091,11 +2091,11 @@ test textDisp-16.20 {TkTextYviewCmd procedure, "scroll" option} { list [catch {.t yview scroll a b c} msg] $msg } {1 {wrong # args: should be ".t yview scroll number pages|pixels|units"}} test textDisp-16.21 {TkTextYviewCmd procedure, "scroll" option} { - list [catch {.t yview scroll badInt bogus} msg] $msg + list [catch {.t yview scroll bogus bogus} msg] $msg } {1 {bad argument "bogus": must be pages, pixels, or units}} test textDisp-16.21.2 {TkTextYviewCmd procedure, "scroll" option} { - list [catch {.t yview scroll badInt units} msg] $msg -} {1 {expected integer but got "badInt"}} + list [catch {.t yview scroll bogus units} msg] $msg +} {1 {expected floating-point number but got "bogus"}} test textDisp-16.22 {TkTextYviewCmd procedure, "scroll" option, back pages} { .t yview 50.0 update diff --git a/tests/util.test b/tests/util.test index d457b50..c2f4542 100644 --- a/tests/util.test +++ b/tests/util.test @@ -34,7 +34,7 @@ test util-1.5 {Tk_GetScrollInfo procedure} -body { } -returnCodes error -result {wrong # args: should be ".l yview scroll number pages|units"} test util-1.6 {Tk_GetScrollInfo procedure} -body { .l yview scroll xyz units -} -returnCodes error -result {expected integer but got "xyz"} +} -returnCodes error -result {expected floating-point number but got "xyz"} test util-1.7 {Tk_GetScrollInfo procedure} -body { .l yview 0 .l yview scroll 2 pages -- cgit v0.12 From 68fc0a0ef4781d53802b28f569935acedc875a92 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 22 Aug 2019 15:29:53 +0000 Subject: Use some more "(x|y)view scroll units" automatic rounding in bindings. --- library/demos/cscroll.tcl | 15 ++++++++++++++- library/iconlist.tcl | 6 +----- library/listbox.tcl | 8 ++++---- library/ttk/utils.tcl | 8 ++++---- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/library/demos/cscroll.tcl b/library/demos/cscroll.tcl index 7bbb91c..1740f94 100644 --- a/library/demos/cscroll.tcl +++ b/library/demos/cscroll.tcl @@ -58,7 +58,20 @@ $c bind all "scrollLeave $c" $c bind all <1> "scrollButton $c" bind $c <2> "$c scan mark %x %y" bind $c "$c scan dragto %x %y" -if {[tk windowingsystem] eq "aqua" && ![package vsatisfies [package provide Tk] 8.7-]} { +if {[package vsatisfies [package provide Tk] 8.7-]} { + bind $c { + %W yview scroll [expr {%D/-30.0}] units + } + bind $c { + %W yview scroll [expr {%D/-3.0}] units + } + bind $c { + %W xview scroll [expr {%D/-30.0}] units + } + bind $c { + %W xview scroll [expr {%D/-3.0}] units + } +} elseif {[tk windowingsystem] eq "aqua"} { bind $c { %W yview scroll [expr {-(%D)}] units } diff --git a/library/iconlist.tcl b/library/iconlist.tcl index 30352a1..65c66b1 100644 --- a/library/iconlist.tcl +++ b/library/iconlist.tcl @@ -509,11 +509,7 @@ package require Tk 8.6 if {$noScroll || $::tk_strictMotif} { return } - if {$amount > 0} { - $canvas xview scroll [expr {(-119-$amount) / 120}] units - } else { - $canvas xview scroll [expr {-($amount / 120)}] units - } + $canvas xview scroll [expr {$amount/-120.0}] units } method Btn1 {x y} { focus $canvas diff --git a/library/listbox.tcl b/library/listbox.tcl index 7400494..500c32e 100644 --- a/library/listbox.tcl +++ b/library/listbox.tcl @@ -177,16 +177,16 @@ bind Listbox { } bind Listbox { - %W yview scroll [expr {%D/-30}] units + %W yview scroll [expr {%D/-30.0}] units } bind Listbox { - %W yview scroll [expr {%D/-3}] units + %W yview scroll [expr {%D/-3.0}] units } bind Listbox { - %W xview scroll [expr {%D/-30}] units + %W xview scroll [expr {%D/-30.0}] units } bind Listbox { - %W xview scroll [expr {%D/-3}] units + %W xview scroll [expr {%D/-3.0}] units } # ::tk::ListboxBeginSelect -- diff --git a/library/ttk/utils.tcl b/library/ttk/utils.tcl index 4827aa3..3729254 100644 --- a/library/ttk/utils.tcl +++ b/library/ttk/utils.tcl @@ -298,12 +298,12 @@ proc ttk::bindMouseWheel {bindtag callback} { # bind TtkScrollable \ - { %W yview scroll [expr {%D/-120}] units } + { %W yview scroll [expr {%D/-120.0}] units } bind TtkScrollable \ - { %W yview scroll [expr {%D/-12}] units } + { %W yview scroll [expr {%D/-12.0}] units } bind TtkScrollable \ - { %W xview scroll [expr {%D/-120}] units } + { %W xview scroll [expr {%D/-120.0}] units } bind TtkScrollable \ - { %W xview scroll [expr {%D/-12}] units } + { %W xview scroll [expr {%D/-12.0}] units } #*EOF* -- cgit v0.12 From d79922ec294e185a5674469215bc4193c2bee0dc Mon Sep 17 00:00:00 2001 From: fvogel Date: Mon, 6 Jan 2020 20:29:38 +0000 Subject: Reorder code snippet in HandleEventGenerate to make it easier to understand. This changes nothing in how things work. --- generic/tkBind.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/generic/tkBind.c b/generic/tkBind.c index f65d2ee..c744975 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -4361,11 +4361,6 @@ HandleEventGenerate( Tk_Window warpWindow = Tk_IdToWindow(dispPtr->display, event.general.xmotion.window); - if (!(dispPtr->flags & TK_DISPLAY_IN_WARP)) { - Tcl_DoWhenIdle(DoWarp, dispPtr); - dispPtr->flags |= TK_DISPLAY_IN_WARP; - } - if (warpWindow != dispPtr->warpWindow) { if (warpWindow) { Tcl_Preserve(warpWindow); @@ -4378,6 +4373,11 @@ HandleEventGenerate( dispPtr->warpMainwin = mainWin; dispPtr->warpX = event.general.xmotion.x; dispPtr->warpY = event.general.xmotion.y; + + if (!(dispPtr->flags & TK_DISPLAY_IN_WARP)) { + Tcl_DoWhenIdle(DoWarp, dispPtr); + dispPtr->flags |= TK_DISPLAY_IN_WARP; + } } } -- cgit v0.12 From d199c8da2038c0b8253abfe20d282859f654f374 Mon Sep 17 00:00:00 2001 From: fvogel Date: Mon, 6 Jan 2020 21:29:41 +0000 Subject: Add test bind-35.1, currently failing, and demonstrating issue reported in [e3888d5820] (grab on master prevents mouse pointer warp into slave widget) --- tests/bind.test | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/bind.test b/tests/bind.test index 20582df..9d8e3d3 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6689,6 +6689,39 @@ test bind-34.3 {-warp works with null or negative coordinates} -setup { } -cleanup { } -result {0 0 ok ok} +test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -setup { + proc twait {duration} { + set ::_twait 1; after $duration {unset ::_twait} + vwait ::_twait + } + toplevel .top + grab release .top + wm geometry .top 200x200+300+300 + label .top.l -height 5 -width 20 -highlightthickness 2 \ + -highlightbackground black -bg yellow -text "My label" + pack .top.l -side bottom + update + event generate {} -warp 1 -x 0 -y 0 + update idletasks ; # DoWarp is an idle callback + after 50 ; # Win specific - wait for SendInput to be executed +} -body { + event generate .top.l -warp 1 -x 10 -y 10 + update idletasks ; after 50 + foreach {x1 y1} [winfo pointerxy .top.l] {} + event generate {} -warp 1 -x 0 -y 0 + update idletasks ; after 50 + grab .top + twait 1000 + event generate .top.l -warp 1 -x 10 -y 10 + update idletasks ; after 50 + foreach {x2 y2} [winfo pointerxy .top.l] {} + expr {$x1==$x2 && $y1==$y2} +} -cleanup { + destroy .top + unset x1 y1 x2 y2 + rename twait {} +} -result {1} + # cleanup cleanupTests return -- cgit v0.12 From c58fce3de10d06cd39d87798779ef43a68f9954c Mon Sep 17 00:00:00 2001 From: fvogel Date: Sat, 11 Jan 2020 13:34:03 +0000 Subject: Attempt to make bind-35.1 more reliable on Windows. --- tests/bind.test | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/tests/bind.test b/tests/bind.test index 9d8e3d3..9c69269 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6690,10 +6690,6 @@ test bind-34.3 {-warp works with null or negative coordinates} -setup { } -result {0 0 ok ok} test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -setup { - proc twait {duration} { - set ::_twait 1; after $duration {unset ::_twait} - vwait ::_twait - } toplevel .top grab release .top wm geometry .top 200x200+300+300 @@ -6710,8 +6706,9 @@ test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -setup { foreach {x1 y1} [winfo pointerxy .top.l] {} event generate {} -warp 1 -x 0 -y 0 update idletasks ; after 50 - grab .top - twait 1000 + grab .top ; # this will queue events + after 50 + update event generate .top.l -warp 1 -x 10 -y 10 update idletasks ; after 50 foreach {x2 y2} [winfo pointerxy .top.l] {} @@ -6719,7 +6716,6 @@ test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -setup { } -cleanup { destroy .top unset x1 y1 x2 y2 - rename twait {} } -result {1} # cleanup -- cgit v0.12 From 68c075d0e166a5a99400a0b336859ec2b0199d63 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sat, 11 Jan 2020 14:13:24 +0000 Subject: Make bind-35.1 fail on Linux, by swapping the order of the mouse pointer warps with respect to grabs. This prevents the warp prologue (see [e3888d5820]) from playing a role in that test. --- tests/bind.test | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/bind.test b/tests/bind.test index 9c69269..e19b4f1 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6690,6 +6690,9 @@ test bind-34.3 {-warp works with null or negative coordinates} -setup { } -result {0 0 ok ok} test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -setup { + event generate {} -warp 1 -x 1 -y 1 + update idletasks ; # DoWarp is an idle callback + after 50 ; # Win specific - wait for SendInput to be executed toplevel .top grab release .top wm geometry .top 200x200+300+300 @@ -6697,16 +6700,16 @@ test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -setup { -highlightbackground black -bg yellow -text "My label" pack .top.l -side bottom update - event generate {} -warp 1 -x 0 -y 0 - update idletasks ; # DoWarp is an idle callback - after 50 ; # Win specific - wait for SendInput to be executed } -body { + grab .top ; # this will queue events + after 50 + update event generate .top.l -warp 1 -x 10 -y 10 update idletasks ; after 50 foreach {x1 y1} [winfo pointerxy .top.l] {} - event generate {} -warp 1 -x 0 -y 0 + event generate {} -warp 1 -x 1 -y 1 update idletasks ; after 50 - grab .top ; # this will queue events + grab release .top ; # this will queue events after 50 update event generate .top.l -warp 1 -x 10 -y 10 -- cgit v0.12 From 74e39d2280dc73803b1c36f2b19c5cae2c0e3c18 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sun, 19 Jan 2020 14:41:28 +0000 Subject: Put more robustness in bind-35.1 --- tests/bind.test | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/bind.test b/tests/bind.test index e19b4f1..7d5cea5 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6702,6 +6702,7 @@ test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -setup { update } -body { grab .top ; # this will queue events + update after 50 update event generate .top.l -warp 1 -x 10 -y 10 -- cgit v0.12 From c451c122100cf567f7c174e3f5aef08d218bdf3a Mon Sep 17 00:00:00 2001 From: fvogel Date: Sat, 25 Jan 2020 13:06:51 +0000 Subject: Fix [e3888d5820] (Grab on master prevents mouse pointer warp into slave widget) for Linux and Windows. Test bind-35.1 now passes on these platforms. --- generic/tkBind.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/generic/tkBind.c b/generic/tkBind.c index c744975..23b00f7 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -4342,17 +4342,6 @@ HandleEventGenerate( } /* - * Now we have constructed the event, inject it into the event handling - * code. - */ - - if (synch) { - Tk_HandleEvent(&event.general); - } else { - Tk_QueueWindowEvent(&event.general, pos); - } - - /* * We only allow warping if the window is mapped. */ @@ -4379,6 +4368,17 @@ HandleEventGenerate( dispPtr->flags |= TK_DISPLAY_IN_WARP; } } + + /* + * Now we have constructed the event, inject it into the event handling + * code. + */ + + if (synch) { + Tk_HandleEvent(&event.general); + } else { + Tk_QueueWindowEvent(&event.general, pos); + } } Tcl_ResetResult(interp); -- cgit v0.12 From 10304fd48d8ea057e53ed46c983c4147efd1066b Mon Sep 17 00:00:00 2001 From: fvogel Date: Sat, 25 Jan 2020 13:16:36 +0000 Subject: Remove useless generation of NSMouseMoved event when warping the mouse pointer on the mac --- macosx/tkMacOSXMouseEvent.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c index 0ad8492..9a4dc46 100644 --- a/macosx/tkMacOSXMouseEvent.c +++ b/macosx/tkMacOSXMouseEvent.c @@ -662,25 +662,7 @@ TkpWarpPointer( loc.y = TkMacOSXZeroScreenHeight() - pt.y; } - /* - * Generate an NSEvent of type NSMouseMoved. - * - * It is not clear why this is necessary. For example, calling - * event generate $w -warp 1 -x $X -y $Y - * will cause two events to be added to the Tcl queue. - */ - CGWarpMouseCursorPosition(pt); - 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]; } /* -- cgit v0.12 From f782ee2185ebf9d8e37f80913de0c56385178f82 Mon Sep 17 00:00:00 2001 From: fvogel Date: Mon, 27 Jan 2020 21:09:35 +0000 Subject: Avoid interference in bind-35.1 from the hot spots in the corners of the screen featured by some WM on Linux. --- tests/bind.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/bind.test b/tests/bind.test index 7d5cea5..d17ff37 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6690,7 +6690,7 @@ test bind-34.3 {-warp works with null or negative coordinates} -setup { } -result {0 0 ok ok} test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -setup { - event generate {} -warp 1 -x 1 -y 1 + event generate {} -warp 1 -x 50 -y 50 update idletasks ; # DoWarp is an idle callback after 50 ; # Win specific - wait for SendInput to be executed toplevel .top @@ -6708,7 +6708,7 @@ test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -setup { event generate .top.l -warp 1 -x 10 -y 10 update idletasks ; after 50 foreach {x1 y1} [winfo pointerxy .top.l] {} - event generate {} -warp 1 -x 1 -y 1 + event generate {} -warp 1 -x 50 -y 50 update idletasks ; after 50 grab release .top ; # this will queue events after 50 -- cgit v0.12 From 975d3e255028d91c59387c4d16297e98f3bb8f76 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 11 Feb 2020 09:12:45 +0000 Subject: Remove (almost all remaining) traces of DBGX for Windows build. --- win/Makefile.in | 5 +---- win/configure | 51 +++++++++++++-------------------------------------- win/configure.ac | 16 ++-------------- win/rules.vc | 2 +- win/tcl.m4 | 34 +++++++++++----------------------- win/tkConfig.sh.in | 5 +++-- 6 files changed, 31 insertions(+), 82 deletions(-) diff --git a/win/Makefile.in b/win/Makefile.in index 82baeb2..463fff1 100644 --- a/win/Makefile.in +++ b/win/Makefile.in @@ -71,11 +71,8 @@ MAN3_INSTALL_DIR = $(MAN_INSTALL_DIR)/man3 # Directory in which to install manual entries for the built-in Tk commands: MANN_INSTALL_DIR = $(MAN_INSTALL_DIR)/mann -# Libraries built with optimization switches have this additional extension -TK_DBGX = @TK_DBGX@ - # Directory in which to install the pkgIndex.tcl file for loadable Tk -PKG_INSTALL_DIR = $(LIB_INSTALL_DIR)/tk$(VERSION)$(TK_DBGX) +PKG_INSTALL_DIR = $(LIB_INSTALL_DIR)/tk$(VERSION) # Package index file for loadable Tk PKG_INDEX = $(PKG_INSTALL_DIR)/pkgIndex.tcl diff --git a/win/configure b/win/configure index 89f5563..cf8ce5f 100755 --- a/win/configure +++ b/win/configure @@ -664,7 +664,6 @@ EXTRA_CFLAGS CFG_TK_EXPORT_FILE_SUFFIX CFG_TK_UNSHARED_LIB_SUFFIX CFG_TK_SHARED_LIB_SUFFIX -TCL_DBGX TCL_PATCH_LEVEL TCL_MINOR_VERSION TCL_MAJOR_VERSION @@ -675,7 +674,6 @@ TK_STUB_LIB_FLAG TK_STUB_LIB_FILE TK_DLL_FILE TK_LIB_FILE -TK_DBGX TK_PATCH_LEVEL TK_MINOR_VERSION TK_MAJOR_VERSION @@ -3821,15 +3819,6 @@ $as_echo "could not find ${TCL_BIN_DIR}/tclConfig.sh" >&6; } TCL_STUB_LIB_PATH=${TCL_BUILD_STUB_LIB_PATH} fi - # - # eval is required to do the TCL_DBGX substitution - # - - eval "TCL_ZIP_FILE=\"${TCL_ZIP_FILE}\"" - eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" - eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" - eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" - eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" @@ -4232,7 +4221,7 @@ $as_echo_n "checking compiler flags... " >&6; } $as_echo "using static flags" >&6; } runtime= LIBRARIES="\${STATIC_LIBRARIES}" - EXESUFFIX="s\${DBGX}.exe" + EXESUFFIX="s.exe" else # dynamic { $as_echo "$as_me:${as_lineno-$LINENO}: result: using shared flags" >&5 @@ -4247,7 +4236,7 @@ $as_echo "using shared flags" >&6; } runtime= # Add SHLIB_LD_LIBS to the Make rule, not here. - EXESUFFIX="\${DBGX}.exe" + EXESUFFIX=".exe" LIBRARIES="\${SHARED_LIBRARIES}" fi # Link with gcc since ld does not link to default libs like @@ -4258,9 +4247,9 @@ $as_echo "using shared flags" >&6; } -Wl,--out-implib,\$(patsubst %.dll,lib%.a,\$@)" # DLLSUFFIX is separate because it is the building block for # users of tclConfig.sh that may build shared or static. - DLLSUFFIX="\${DBGX}.dll" - LIBSUFFIX="\${DBGX}.a" - LIBFLAGSUFFIX="\${DBGX}" + DLLSUFFIX=".dll" + LIBSUFFIX=".a" + LIBFLAGSUFFIX="" SHLIB_SUFFIX=.dll EXTRA_CFLAGS="${extra_cflags}" @@ -4350,7 +4339,7 @@ $as_echo " Using 64-bit $MACHINE mode" >&6; } $as_echo "using static flags" >&6; } runtime=-MT LIBRARIES="\${STATIC_LIBRARIES}" - EXESUFFIX="s\${DBGX}.exe" + EXESUFFIX="s.exe" else # dynamic { $as_echo "$as_me:${as_lineno-$LINENO}: result: using shared flags" >&5 @@ -4358,7 +4347,7 @@ $as_echo "using shared flags" >&6; } runtime=-MD # Add SHLIB_LD_LIBS to the Make rule, not here. LIBRARIES="\${SHARED_LIBRARIES}" - EXESUFFIX="\${DBGX}.exe" + EXESUFFIX=".exe" case "x`echo \${VisualStudioVersion}`" in x1[4-9]*) lflags="${lflags} -nodefaultlib:libucrt.lib" @@ -4370,9 +4359,9 @@ $as_echo "using shared flags" >&6; } MAKE_DLL="\${SHLIB_LD} \$(LDFLAGS) -out:\$@" # DLLSUFFIX is separate because it is the building block for # users of tclConfig.sh that may build shared or static. - DLLSUFFIX="\${DBGX}.dll" - LIBSUFFIX="\${DBGX}.lib" - LIBFLAGSUFFIX="\${DBGX}" + DLLSUFFIX=".dll" + LIBSUFFIX=".lib" + LIBFLAGSUFFIX="" if test "$do64bit" != "no" ; then case "$do64bit" in @@ -4751,7 +4740,6 @@ fi if test "$tcl_ok" = "no"; then CFLAGS_DEFAULT='$(CFLAGS_OPTIMIZE)' LDFLAGS_DEFAULT='$(LDFLAGS_OPTIMIZE)' - DBGX="" $as_echo "#define NDEBUG 1" >>confdefs.h @@ -4763,7 +4751,6 @@ $as_echo "no" >&6; } else CFLAGS_DEFAULT='$(CFLAGS_DEBUG)' LDFLAGS_DEFAULT='$(LDFLAGS_DEBUG)' - DBGX=g if test "$tcl_ok" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (standard debugging)" >&5 $as_echo "yes (standard debugging)" >&6; } @@ -4798,8 +4785,6 @@ $as_echo "enabled $tcl_ok debugging" >&6; } fi -TK_DBGX=${DBGX} - #-------------------------------------------------------------------- # Embed the manifest if we can determine how #-------------------------------------------------------------------- @@ -4858,7 +4843,7 @@ $as_echo "$result" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tclsh in Tcl build directory" >&5 $as_echo_n "checking for tclsh in Tcl build directory... " >&6; } - BUILD_TCLSH=${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT} + BUILD_TCLSH=${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT} { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_TCLSH" >&5 $as_echo "$BUILD_TCLSH" >&6; } @@ -4949,18 +4934,10 @@ CFG_TK_EXPORT_FILE_SUFFIX=${TK_EXPORT_FILE_SUFFIX} #-------------------------------------------------------------------- if test ${SHARED_BUILD} = 0 -o "$TCL_NEEDS_EXP_FILE" = 0; then - if test "${DBGX}" = "d"; then - RC_DEFINES="${RC_DEFINE} STATIC_BUILD ${RC_DEFINE} DEBUG" - else - RC_DEFINES="${RC_DEFINE} STATIC_BUILD" - fi + RC_DEFINES="${RC_DEFINE} STATIC_BUILD" TK_RES="" else - if test "${DBGX}" = "d"; then - RC_DEFINES="${RC_DEFINE} DEBUG" - else - RC_DEFINES="" - fi + RC_DEFINES="" TK_RES='tk.$(RES)' fi @@ -5007,8 +4984,6 @@ TK_WIN_VERSION="$TK_VERSION.$TK_RELEASE_LEVEL.`echo $TK_PATCH_LEVEL | tr -d ab.` - - # win/tcl.m4 doesn't set (LDFLAGS) diff --git a/win/configure.ac b/win/configure.ac index ca9263f..10728e0 100644 --- a/win/configure.ac +++ b/win/configure.ac @@ -134,8 +134,6 @@ AC_CHECK_HEADER([vssym32.h], [AC_DEFINE(HAVE_VSSYM32_H)], [], SC_ENABLE_SYMBOLS -TK_DBGX=${DBGX} - #-------------------------------------------------------------------- # Embed the manifest if we can determine how #-------------------------------------------------------------------- @@ -194,18 +192,10 @@ CFG_TK_EXPORT_FILE_SUFFIX=${TK_EXPORT_FILE_SUFFIX} #-------------------------------------------------------------------- if test ${SHARED_BUILD} = 0 -o "$TCL_NEEDS_EXP_FILE" = 0; then - if test "${DBGX}" = "d"; then - RC_DEFINES="${RC_DEFINE} STATIC_BUILD ${RC_DEFINE} DEBUG" - else - RC_DEFINES="${RC_DEFINE} STATIC_BUILD" - fi + RC_DEFINES="${RC_DEFINE} STATIC_BUILD" TK_RES="" else - if test "${DBGX}" = "d"; then - RC_DEFINES="${RC_DEFINE} DEBUG" - else - RC_DEFINES="" - fi + RC_DEFINES="" TK_RES='tk.$(RES)' fi @@ -226,7 +216,6 @@ AC_SUBST(TK_VERSION) AC_SUBST(TK_MAJOR_VERSION) AC_SUBST(TK_MINOR_VERSION) AC_SUBST(TK_PATCH_LEVEL) -AC_SUBST(TK_DBGX) AC_SUBST(TK_LIB_FILE) AC_SUBST(TK_DLL_FILE) AC_SUBST(TK_STUB_LIB_FILE) @@ -242,7 +231,6 @@ AC_SUBST(TCL_PATCH_LEVEL) AC_SUBST(TCL_SRC_DIR) AC_SUBST(TCL_BIN_DIR) -AC_SUBST(TCL_DBGX) AC_SUBST(CFG_TK_SHARED_LIB_SUFFIX) AC_SUBST(CFG_TK_UNSHARED_LIB_SUFFIX) AC_SUBST(CFG_TK_EXPORT_FILE_SUFFIX) diff --git a/win/rules.vc b/win/rules.vc index 872b3a0..c29ab0a 100644 --- a/win/rules.vc +++ b/win/rules.vc @@ -1048,7 +1048,7 @@ BUILDDIRTOP =$(BUILDDIRTOP)_$(MACHINE) BUILDDIRTOP =$(BUILDDIRTOP)_VC$(VCVER) !endif -!if !$(DEBUG) || $(DEBUG) && $(UNCHECKED) +!if !$(DEBUG) || $(TCL_VERSION) > 86 || $(DEBUG) && $(UNCHECKED) SUFX = $(SUFX:g=) !endif diff --git a/win/tcl.m4 b/win/tcl.m4 index 225cfdc..8875f82 100644 --- a/win/tcl.m4 +++ b/win/tcl.m4 @@ -280,15 +280,6 @@ AC_DEFUN([SC_LOAD_TCLCONFIG], [ TCL_STUB_LIB_PATH=${TCL_BUILD_STUB_LIB_PATH} fi - # - # eval is required to do the TCL_DBGX substitution - # - - eval "TCL_ZIP_FILE=\"${TCL_ZIP_FILE}\"" - eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" - eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" - eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" - eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" @@ -410,7 +401,6 @@ AC_DEFUN([SC_ENABLE_SHARED], [ # Sets to $(CFLAGS_OPTIMIZE) if false # LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true # Sets to $(LDFLAGS_OPTIMIZE) if false -# DBGX Debug library extension # #------------------------------------------------------------------------ @@ -421,7 +411,6 @@ AC_DEFUN([SC_ENABLE_SYMBOLS], [ if test "$tcl_ok" = "no"; then CFLAGS_DEFAULT='$(CFLAGS_OPTIMIZE)' LDFLAGS_DEFAULT='$(LDFLAGS_OPTIMIZE)' - DBGX="" AC_DEFINE(NDEBUG, 1, [Is no debugging enabled?]) AC_MSG_RESULT([no]) @@ -429,7 +418,6 @@ AC_DEFUN([SC_ENABLE_SYMBOLS], [ else CFLAGS_DEFAULT='$(CFLAGS_DEBUG)' LDFLAGS_DEFAULT='$(LDFLAGS_DEBUG)' - DBGX=g if test "$tcl_ok" = "yes"; then AC_MSG_RESULT([yes (standard debugging)]) fi @@ -651,7 +639,7 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ AC_MSG_RESULT([using static flags]) runtime= LIBRARIES="\${STATIC_LIBRARIES}" - EXESUFFIX="s\${DBGX}.exe" + EXESUFFIX="s.exe" else # dynamic AC_MSG_RESULT([using shared flags]) @@ -665,7 +653,7 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ runtime= # Add SHLIB_LD_LIBS to the Make rule, not here. - EXESUFFIX="\${DBGX}.exe" + EXESUFFIX=".exe" LIBRARIES="\${SHARED_LIBRARIES}" fi # Link with gcc since ld does not link to default libs like @@ -676,9 +664,9 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ -Wl,--out-implib,\$(patsubst %.dll,lib%.a,\[$]@)" # DLLSUFFIX is separate because it is the building block for # users of tclConfig.sh that may build shared or static. - DLLSUFFIX="\${DBGX}.dll" - LIBSUFFIX="\${DBGX}.a" - LIBFLAGSUFFIX="\${DBGX}" + DLLSUFFIX=".dll" + LIBSUFFIX=".a" + LIBFLAGSUFFIX="" SHLIB_SUFFIX=.dll EXTRA_CFLAGS="${extra_cflags}" @@ -750,14 +738,14 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ AC_MSG_RESULT([using static flags]) runtime=-MT LIBRARIES="\${STATIC_LIBRARIES}" - EXESUFFIX="s\${DBGX}.exe" + EXESUFFIX="s.exe" else # dynamic AC_MSG_RESULT([using shared flags]) runtime=-MD # Add SHLIB_LD_LIBS to the Make rule, not here. LIBRARIES="\${SHARED_LIBRARIES}" - EXESUFFIX="\${DBGX}.exe" + EXESUFFIX=".exe" case "x`echo \${VisualStudioVersion}`" in x1[[4-9]]*) lflags="${lflags} -nodefaultlib:libucrt.lib" @@ -769,9 +757,9 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ MAKE_DLL="\${SHLIB_LD} \$(LDFLAGS) -out:\[$]@" # DLLSUFFIX is separate because it is the building block for # users of tclConfig.sh that may build shared or static. - DLLSUFFIX="\${DBGX}.dll" - LIBSUFFIX="\${DBGX}.lib" - LIBFLAGSUFFIX="\${DBGX}" + DLLSUFFIX=".dll" + LIBSUFFIX=".lib" + LIBFLAGSUFFIX="" if test "$do64bit" != "no" ; then case "$do64bit" in @@ -1069,7 +1057,7 @@ AC_DEFUN([SC_PROG_TCLSH], [ AC_DEFUN([SC_BUILD_TCLSH], [ AC_MSG_CHECKING([for tclsh in Tcl build directory]) - BUILD_TCLSH=${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT} + BUILD_TCLSH=${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT} AC_MSG_RESULT($BUILD_TCLSH) AC_SUBST(BUILD_TCLSH) ]) diff --git a/win/tkConfig.sh.in b/win/tkConfig.sh.in index c511312..d93e649 100644 --- a/win/tkConfig.sh.in +++ b/win/tkConfig.sh.in @@ -25,8 +25,9 @@ TK_DEFS='@DEFS@' # Flag, 1: we built a shared lib, 0 we didn't TK_SHARED_BUILD=@TK_SHARED_BUILD@ -# This indicates if Tk was build with debugging symbols -TK_DBGX=@TK_DBGX@ +# TK_DBGX used to be used to distinguish debug vs. non-debug builds. +# This was a righteous pain so the core doesn't do that any more. +TK_DBGX= # The name of the Tk library (may be either a .a file or a shared library): TK_LIB_FILE='@TK_LIB_FILE@' -- cgit v0.12 From 6cb4bec9e847887f703dd319cbb7118e39d05655 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sun, 16 Feb 2020 20:14:43 +0000 Subject: Attempt to make test bind-35.1 more reliable, by waiting for the expected [grab current] value. --- tests/bind.test | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/tests/bind.test b/tests/bind.test index d17ff37..efedae9 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6690,6 +6690,16 @@ test bind-34.3 {-warp works with null or negative coordinates} -setup { } -result {0 0 ok ok} test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -setup { + proc waitForGrab {grabWin in_ni} { + # process events while $grabWin is not in (ni) the current grab window list, + # or while it is (in), but don't spend more than 5 seconds doing this + set i 0 + while {[expr {$grabWin} $in_ni {[grab current]}] && $i < 500} { + after 1 + update + incr i + } + } event generate {} -warp 1 -x 50 -y 50 update idletasks ; # DoWarp is an idle callback after 50 ; # Win specific - wait for SendInput to be executed @@ -6702,17 +6712,14 @@ test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -setup { update } -body { grab .top ; # this will queue events - update - after 50 - update + waitForGrab .top ni event generate .top.l -warp 1 -x 10 -y 10 update idletasks ; after 50 foreach {x1 y1} [winfo pointerxy .top.l] {} event generate {} -warp 1 -x 50 -y 50 update idletasks ; after 50 grab release .top ; # this will queue events - after 50 - update + waitForGrab .top in event generate .top.l -warp 1 -x 10 -y 10 update idletasks ; after 50 foreach {x2 y2} [winfo pointerxy .top.l] {} @@ -6720,6 +6727,7 @@ test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -setup { } -cleanup { destroy .top unset x1 y1 x2 y2 + rename waitForGrab {} } -result {1} # cleanup -- cgit v0.12 From c0f14624f3cdc85d8331b9890f1e4272911f25dc Mon Sep 17 00:00:00 2001 From: fvogel Date: Sun, 16 Feb 2020 20:26:54 +0000 Subject: Don't stress the CPU too much. --- tests/bind.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bind.test b/tests/bind.test index efedae9..e655fbf 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6695,7 +6695,7 @@ test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -setup { # or while it is (in), but don't spend more than 5 seconds doing this set i 0 while {[expr {$grabWin} $in_ni {[grab current]}] && $i < 500} { - after 1 + after 10 update incr i } -- cgit v0.12 From 2eba29238e00ddad8847d54417625dd5dcf4e781 Mon Sep 17 00:00:00 2001 From: fvogel Date: Mon, 17 Feb 2020 22:06:26 +0000 Subject: Refine test bind-35.1 once more since [grab current] returns the eventualGrabWin while we're interested in the grabWin instead. --- generic/tkTest.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++ tests/bind.test | 18 +++++++----- tests/constraints.tcl | 1 + 3 files changed, 91 insertions(+), 7 deletions(-) diff --git a/generic/tkTest.c b/generic/tkTest.c index a8929b9..e3bfd4d 100644 --- a/generic/tkTest.c +++ b/generic/tkTest.c @@ -206,6 +206,9 @@ static int TrivialConfigObjCmd(ClientData dummy, Tcl_Obj * const objv[]); static void TrivialEventProc(ClientData clientData, XEvent *eventPtr); +static int TestgrabObjCmd(ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *const objv[]); /* *---------------------------------------------------------------------- @@ -281,6 +284,9 @@ Tktest_Init( (ClientData) Tk_MainWindow(interp), NULL); #endif /* _WIN32 */ + Tcl_CreateObjCommand(interp, "testgrab", TestgrabObjCmd, + (ClientData) Tk_MainWindow(interp), NULL); + /* * Create test image type. */ @@ -2078,6 +2084,79 @@ CustomOptionFree( } /* + *---------------------------------------------------------------------- + * + * TestgrabObjCmd -- + * + * This function implements the "testgrab" command, which is used to test + * grabbing of windows. + * + * testgrab grabbed $win: returns true if $win is currently grabbed + * testgrab released $win: returns true if $win is currently not grabbed + * + * This function is useful when one wants to test for a grabbing window + * at the moment it is called. [grab current] cannot be used for that + * purpose because it returns the window dereferenced by eventualGrabWinPtr + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +TestgrabObjCmd( + ClientData clientData, /* Main window for application. */ + Tcl_Interp *interp, /* Current interpreter. */ + int objc, /* Number of arguments. */ + Tcl_Obj *const objv[]) /* Argument objects. */ +{ + static const char *const options[] = {"grabbed", "released", NULL}; + enum option {GRABBED, RELEASED}; + int index, res = 0; + Tk_Window mainWin, tkwin; + TkDisplay *dispPtr; + + mainWin = (Tk_Window) clientData; + + if (objc < 3) { + Tcl_WrongNumArgs(interp, 1, objv, "option window"); + return TCL_ERROR; + } + + if (Tcl_GetIndexFromObjStruct(interp, objv[1], options, + sizeof(char *), "command", 0, &index)!= TCL_OK) { + return TCL_ERROR; + } + + tkwin = Tk_NameToWindow(interp, Tcl_GetString(objv[2]), mainWin); + if (tkwin == NULL) { + return TCL_ERROR; + } + dispPtr = ((TkWindow *) tkwin)->dispPtr; + /*printf("TestgrabObjCmd %s, grabWinPtr = %p , tkwin = %p\n", options[index], dispPtr->grabWinPtr, tkwin);fflush(stdout);*/ + + switch ((enum option) index) { + case GRABBED: + if (dispPtr->grabWinPtr == (TkWindow *) tkwin) { + res = 1; + } + break; + case RELEASED: + if (dispPtr->grabWinPtr != (TkWindow *) tkwin) { + res = 1; + } + break; + } + + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(res)); + return TCL_OK; +} + +/* * Local Variables: * mode: c * c-basic-offset: 4 diff --git a/tests/bind.test b/tests/bind.test index dfb046c..a001580 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6707,12 +6707,15 @@ test bind-34.3 {-warp works with null or negative coordinates} -setup { } -cleanup { } -result {ok ok ok ok} -test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -setup { - proc waitForGrab {grabWin in_ni} { - # process events while $grabWin is not in (ni) the current grab window list, - # or while it is (in), but don't spend more than 5 seconds doing this +test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -constraints { + testgrab +} -setup { + proc waitForGrab {type grabWin} { + # process events while $grabWin is not grabbed ($type == "grabbed"), + # or while $grabWin is not released ($type == "released"), but don't + # spend more than 5 seconds doing this set i 0 - while {[expr {$grabWin} $in_ni {[grab current]}] && $i < 500} { + while {![testgrab $type $grabWin] && $i < 500} { after 10 update incr i @@ -6723,6 +6726,7 @@ test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -setup { after 50 ; # Win specific - wait for SendInput to be executed toplevel .top grab release .top + waitForGrab released .top wm geometry .top 200x200+300+300 label .top.l -height 5 -width 20 -highlightthickness 2 \ -highlightbackground black -bg yellow -text "My label" @@ -6730,14 +6734,14 @@ test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -setup { update } -body { grab .top ; # this will queue events - waitForGrab .top ni + waitForGrab grabbed .top event generate .top.l -warp 1 -x 10 -y 10 update idletasks ; after 50 foreach {x1 y1} [winfo pointerxy .top.l] {} event generate {} -warp 1 -x 50 -y 50 update idletasks ; after 50 grab release .top ; # this will queue events - waitForGrab .top in + waitForGrab released .top event generate .top.l -warp 1 -x 10 -y 10 update idletasks ; after 50 foreach {x2 y2} [winfo pointerxy .top.l] {} diff --git a/tests/constraints.tcl b/tests/constraints.tcl index c77fb00..49da142 100644 --- a/tests/constraints.tcl +++ b/tests/constraints.tcl @@ -207,6 +207,7 @@ testConstraint testcolor [llength [info commands testcolor]] testConstraint testcursor [llength [info commands testcursor]] testConstraint testembed [llength [info commands testembed]] testConstraint testfont [llength [info commands testfont]] +testConstraint testgrab [llength [info commands testgrab]] testConstraint testmakeexist [llength [info commands testmakeexist]] testConstraint testmenubar [llength [info commands testmenubar]] testConstraint testmetrics [llength [info commands testmetrics]] -- cgit v0.12 From f85275ba623ef4e7bbd74cee04017c8ed6d5c9a5 Mon Sep 17 00:00:00 2001 From: fvogel Date: Tue, 18 Feb 2020 21:19:57 +0000 Subject: Use TkGrabState() in function TestgrabObjCmd() instead of dispPtr->grabWinPtr to make the code clearer and the interface cleaner. --- generic/tkTest.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/generic/tkTest.c b/generic/tkTest.c index e3bfd4d..1f373ad 100644 --- a/generic/tkTest.c +++ b/generic/tkTest.c @@ -2118,7 +2118,6 @@ TestgrabObjCmd( enum option {GRABBED, RELEASED}; int index, res = 0; Tk_Window mainWin, tkwin; - TkDisplay *dispPtr; mainWin = (Tk_Window) clientData; @@ -2136,17 +2135,17 @@ TestgrabObjCmd( if (tkwin == NULL) { return TCL_ERROR; } - dispPtr = ((TkWindow *) tkwin)->dispPtr; - /*printf("TestgrabObjCmd %s, grabWinPtr = %p , tkwin = %p\n", options[index], dispPtr->grabWinPtr, tkwin);fflush(stdout);*/ + /*printf("TestgrabObjCmd %s, grabWinPtr = %p , tkwin = %p\n", options[index], + ((TkWindow *) tkwin)->dispPtr->grabWinPtr, tkwin);fflush(stdout);*/ switch ((enum option) index) { case GRABBED: - if (dispPtr->grabWinPtr == (TkWindow *) tkwin) { + if (TkGrabState((TkWindow *) tkwin) != TK_GRAB_NONE) { res = 1; } break; case RELEASED: - if (dispPtr->grabWinPtr != (TkWindow *) tkwin) { + if (TkGrabState((TkWindow *) tkwin) == TK_GRAB_NONE) { res = 1; } break; -- cgit v0.12 From 43fb1795b95fb9b238c5058d11dc7b4a415b6942 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sun, 12 Apr 2020 21:30:29 +0000 Subject: Use of IsSubsetOf function is clearer (no functional change). --- generic/tkBind.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tkBind.c b/generic/tkBind.c index 1443270..c1fdc0c 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -2808,7 +2808,7 @@ MatchPatterns( psEntry->expired = 1; /* remove it from promotion list */ - if ((modMask & ~curModMask) == 0) { + if (IsSubsetOf(modMask, curModMask)) { unsigned count = patPtr->info ? curEvent->countDetailed : curEvent->countAny; if (patIndex < PSModMaskArr_Size(psEntry->lastModMaskArr)) { -- cgit v0.12 From a485a445252972c78b1296013f221f7f838c438b Mon Sep 17 00:00:00 2001 From: fvogel Date: Sun, 19 Apr 2020 09:34:18 +0000 Subject: Fix [7655f65ae7]: text positioning issues in entry widgets. This is a patch from Christopher Chavez, slightly modified, and addresses the bug for Windows, Linux and macOS. --- generic/tkEntry.c | 33 ++++++++++++++++++++++++--------- generic/ttk/ttkEntry.c | 39 ++++++++++++++++++++++++++++++--------- 2 files changed, 54 insertions(+), 18 deletions(-) diff --git a/generic/tkEntry.c b/generic/tkEntry.c index 9c53769..27bcfe1 100644 --- a/generic/tkEntry.c +++ b/generic/tkEntry.c @@ -1727,18 +1727,14 @@ DisplayEntry( } } - /* - * Draw the text in two pieces: first the unselected portion, then the - * selected portion on top of it. - */ - - Tk_DrawTextLayout(entryPtr->display, pixmap, entryPtr->textGC, - entryPtr->textLayout, entryPtr->layoutX, entryPtr->layoutY, - entryPtr->leftIndex, entryPtr->numChars); - if (showSelection && (entryPtr->state != STATE_DISABLED) && (entryPtr->selTextGC != entryPtr->textGC) && (entryPtr->selectFirst < entryPtr->selectLast)) { + + /* + * Draw the selected and unselected portions separately. + */ + int selFirst; if (entryPtr->selectFirst < entryPtr->leftIndex) { @@ -1746,9 +1742,28 @@ DisplayEntry( } else { selFirst = entryPtr->selectFirst; } + if (entryPtr->leftIndex < selFirst) { + Tk_DrawTextLayout(entryPtr->display, pixmap, entryPtr->textGC, + entryPtr->textLayout, entryPtr->layoutX, entryPtr->layoutY, + entryPtr->leftIndex, selFirst); + } Tk_DrawTextLayout(entryPtr->display, pixmap, entryPtr->selTextGC, entryPtr->textLayout, entryPtr->layoutX, entryPtr->layoutY, selFirst, entryPtr->selectLast); + if (entryPtr->selectLast < entryPtr->numChars) { + Tk_DrawTextLayout(entryPtr->display, pixmap, entryPtr->textGC, + entryPtr->textLayout, entryPtr->layoutX, entryPtr->layoutY, + entryPtr->selectLast, entryPtr->numChars); + } + } else { + + /* + * Draw the entire visible text + */ + + Tk_DrawTextLayout(entryPtr->display, pixmap, entryPtr->textGC, + entryPtr->textLayout, entryPtr->layoutX, entryPtr->layoutY, + entryPtr->leftIndex, entryPtr->numChars); } if (entryPtr->type == TK_SPINBOX) { diff --git a/generic/ttk/ttkEntry.c b/generic/ttk/ttkEntry.c index 96f3cf2..05b4c3b 100644 --- a/generic/ttk/ttkEntry.c +++ b/generic/ttk/ttkEntry.c @@ -1274,16 +1274,27 @@ static void EntryDisplay(void *clientData, Drawable d) /* Draw the text: */ gc = EntryGetGC(entryPtr, es.foregroundObj, clipRegion); - Tk_DrawTextLayout( - Tk_Display(tkwin), d, gc, entryPtr->entry.textLayout, - entryPtr->entry.layoutX, entryPtr->entry.layoutY, - leftIndex, rightIndex); - XSetClipMask(Tk_Display(tkwin), gc, None); - Tk_FreeGC(Tk_Display(tkwin), gc); - - /* Overwrite the selected portion (if any) in the -selectforeground color: - */ if (showSelection) { + + /* Draw the selected and unselected portions separately. + */ + if (leftIndex < selFirst) { + Tk_DrawTextLayout( + Tk_Display(tkwin), d, gc, entryPtr->entry.textLayout, + entryPtr->entry.layoutX, entryPtr->entry.layoutY, + leftIndex, selFirst); + } + if (selLast < rightIndex) { + Tk_DrawTextLayout( + Tk_Display(tkwin), d, gc, entryPtr->entry.textLayout, + entryPtr->entry.layoutX, entryPtr->entry.layoutY, + selLast, rightIndex); + } + XSetClipMask(Tk_Display(tkwin), gc, None); + Tk_FreeGC(Tk_Display(tkwin), gc); + + /* Draw the selected portion in the -selectforeground color: + */ gc = EntryGetGC(entryPtr, es.selForegroundObj, clipRegion); Tk_DrawTextLayout( Tk_Display(tkwin), d, gc, entryPtr->entry.textLayout, @@ -1291,6 +1302,16 @@ static void EntryDisplay(void *clientData, Drawable d) selFirst, selLast); XSetClipMask(Tk_Display(tkwin), gc, None); Tk_FreeGC(Tk_Display(tkwin), gc); + } else { + + /* Draw the entire visible text + */ + Tk_DrawTextLayout( + Tk_Display(tkwin), d, gc, entryPtr->entry.textLayout, + entryPtr->entry.layoutX, entryPtr->entry.layoutY, + leftIndex, rightIndex); + XSetClipMask(Tk_Display(tkwin), gc, None); + Tk_FreeGC(Tk_Display(tkwin), gc); } /* Drop the region. Note that we have to manually remove the reference to -- cgit v0.12 From 981e941cbfec9cdea31b3bde6666e9a5afc6ea85 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sun, 19 Apr 2020 10:01:26 +0000 Subject: Apply another patch by Christopher Chavez that fixes the jerk of strings on aqua when selecting text (see the ticket). There is no functional change on Windows and Linux in this patch. --- generic/tkFont.c | 27 +++++++++++++++++++++++++++ generic/tkInt.h | 4 ++++ macosx/tkMacOSXFont.c | 20 ++++++++------------ macosx/tkMacOSXInt.h | 2 +- unix/tkUnixFont.c | 32 ++++++++++++++++++++++++++++++++ win/tkWinFont.c | 31 +++++++++++++++++++++++++++++++ 6 files changed, 103 insertions(+), 13 deletions(-) diff --git a/generic/tkFont.c b/generic/tkFont.c index 0ec79a6..3a06719 100644 --- a/generic/tkFont.c +++ b/generic/tkFont.c @@ -2304,6 +2304,10 @@ Tk_DrawTextLayout( * draw from the given text item. A number < 0 * means to draw all characters. */ { +#if 0 + /* Use TkDrawAngledTextLayout() implementation */ + TkDrawAngledTextLayout(display, drawable, gc, layout, x, y, 0.0, firstChar, lastChar); +#else TextLayout *layoutPtr = (TextLayout *) layout; int i, numDisplayChars, drawX; const char *firstByte, *lastByte; @@ -2333,8 +2337,14 @@ Tk_DrawTextLayout( numDisplayChars = lastChar; } lastByte = Tcl_UtfAtIndex(chunkPtr->start, numDisplayChars); +#if TK_DRAW_IN_CONTEXT + TkpDrawCharsInContext(display, drawable, gc, layoutPtr->tkfont, + chunkPtr->start, chunkPtr->numBytes, firstChar, + numDisplayChars - firstChar, x+chunkPtr->x, y+chunkPtr->y); +#else /* !TK_DRAW_IN_CONTEXT */ Tk_DrawChars(display, drawable, gc, layoutPtr->tkfont, firstByte, lastByte - firstByte, x+chunkPtr->x+drawX, y+chunkPtr->y); +#endif /* TK_DRAW_IN_CONTEXT */ } firstChar -= chunkPtr->numChars; lastChar -= chunkPtr->numChars; @@ -2343,6 +2353,7 @@ Tk_DrawTextLayout( } chunkPtr++; } +#endif /* Use TkDrawAngledTextLayout() implementation */ } void @@ -2395,6 +2406,21 @@ TkDrawAngledTextLayout( numDisplayChars = lastChar; } lastByte = Tcl_UtfAtIndex(chunkPtr->start, numDisplayChars); +#if TK_DRAW_IN_CONTEXT + dx = cosA * (chunkPtr->x) + sinA * (chunkPtr->y); + dy = -sinA * (chunkPtr->x) + cosA * (chunkPtr->y); + if (angle == 0.0) { + TkpDrawCharsInContext(display, drawable, gc, + layoutPtr->tkfont, chunkPtr->start, chunkPtr->numBytes, + firstChar, numDisplayChars - firstChar, + (int)(x + dx), (int)(y + dy)); + } else { + TkpDrawAngledCharsInContext(display, drawable, gc, + layoutPtr->tkfont, chunkPtr->start, chunkPtr->numBytes, + firstChar, numDisplayChars - firstChar, + x+dx, y+dy, angle); + } +#else /* !TK_DRAW_IN_CONTEXT */ dx = cosA * (chunkPtr->x + drawX) + sinA * (chunkPtr->y); dy = -sinA * (chunkPtr->x + drawX) + cosA * (chunkPtr->y); if (angle == 0.0) { @@ -2405,6 +2431,7 @@ TkDrawAngledTextLayout( TkDrawAngledChars(display, drawable, gc, layoutPtr->tkfont, firstByte, lastByte - firstByte, x+dx, y+dy, angle); } +#endif /* TK_DRAW_IN_CONTEXT */ } firstChar -= chunkPtr->numChars; lastChar -= chunkPtr->numChars; diff --git a/generic/tkInt.h b/generic/tkInt.h index 8f958ab..2f9efe8 100644 --- a/generic/tkInt.h +++ b/generic/tkInt.h @@ -1231,6 +1231,10 @@ MODULE_SCOPE void TkpDrawCharsInContext(Display * display, Drawable drawable, GC gc, Tk_Font tkfont, const char *source, int numBytes, int rangeStart, int rangeLength, int x, int y); +MODULE_SCOPE void TkpDrawAngledCharsInContext(Display * display, + Drawable drawable, GC gc, Tk_Font tkfont, + const char *source, int numBytes, int rangeStart, + int rangeLength, double x, double y, double angle); MODULE_SCOPE int TkpMeasureCharsInContext(Tk_Font tkfont, const char *source, int numBytes, int rangeStart, int rangeLength, int maxLength, int flags, diff --git a/macosx/tkMacOSXFont.c b/macosx/tkMacOSXFont.c index 2d8168d..01e6d98 100644 --- a/macosx/tkMacOSXFont.c +++ b/macosx/tkMacOSXFont.c @@ -93,10 +93,6 @@ static void InitFont(NSFont *nsFont, static int CreateNamedSystemFont(Tcl_Interp *interp, Tk_Window tkwin, const char *name, TkFontAttributes *faPtr); -static void DrawCharsInContext(Display *display, Drawable drawable, - GC gc, Tk_Font tkfont, const char *source, - int numBytes, int rangeStart, int rangeLength, - int x, int y, double angle); #pragma mark - #pragma mark Font Helpers: @@ -1115,7 +1111,7 @@ done: * Draw a string of characters on the screen. * * With ATSUI we need the line context to do this right, so we have the - * actual implementation in TkpDrawCharsInContext(). + * actual implementation in TkpDrawAngledCharsInContext(). * * Results: * None. @@ -1144,7 +1140,7 @@ Tk_DrawChars( int x, int y) /* Coordinates at which to place origin of the * string when drawing. */ { - DrawCharsInContext(display, drawable, gc, tkfont, source, numBytes, + TkpDrawAngledCharsInContext(display, drawable, gc, tkfont, source, numBytes, 0, numBytes, x, y, 0.0); } @@ -1167,7 +1163,7 @@ TkDrawAngledChars( * string when drawing. */ double angle) /* What angle to put text at, in degrees. */ { - DrawCharsInContext(display, drawable, gc, tkfont, source, numBytes, + TkpDrawAngledCharsInContext(display, drawable, gc, tkfont, source, numBytes, 0, numBytes, x, y, angle); } @@ -1212,12 +1208,12 @@ TkpDrawCharsInContext( * whole (not just the range) string when * drawing. */ { - DrawCharsInContext(display, drawable, gc, tkfont, source, numBytes, + TkpDrawAngledCharsInContext(display, drawable, gc, tkfont, source, numBytes, rangeStart, rangeLength, x, y, 0.0); } -static void -DrawCharsInContext( +void +TkpDrawAngledCharsInContext( Display *display, /* Display on which to draw. */ Drawable drawable, /* Window or pixmap in which to draw. */ GC gc, /* Graphics context for drawing characters. */ @@ -1233,10 +1229,10 @@ DrawCharsInContext( int numBytes, /* Number of bytes in string. */ int rangeStart, /* Index of first byte to draw. */ int rangeLength, /* Length of range to draw in bytes. */ - int x, int y, /* Coordinates at which to place origin of the + double x, double y, /* Coordinates at which to place origin of the * whole (not just the range) string when * drawing. */ - double angle) + double angle) /* What angle to put text at, in degrees. */ { const MacFont *fontPtr = (const MacFont *) tkfont; NSString *string; diff --git a/macosx/tkMacOSXInt.h b/macosx/tkMacOSXInt.h index 9cb75d2..b6b9cca 100644 --- a/macosx/tkMacOSXInt.h +++ b/macosx/tkMacOSXInt.h @@ -180,7 +180,7 @@ MODULE_SCOPE void TkpFreeGCCache(GC gc); #define TK_MACOSX_HANDLE_EVENT_IMMEDIATELY 1024 /* - * Defines for tkTextDisp.c + * Defines for tkTextDisp.c and tkFont.c */ #define TK_LAYOUT_WITH_BASE_CHUNKS 1 diff --git a/unix/tkUnixFont.c b/unix/tkUnixFont.c index 6e7b4c3..a1b969e 100644 --- a/unix/tkUnixFont.c +++ b/unix/tkUnixFont.c @@ -1413,6 +1413,38 @@ TkpDrawCharsInContext( rangeLength, x+widthUntilStart, y); } +/* UNTESTED */ +void +TkpDrawAngledCharsInContext( + Display *display, /* Display on which to draw. */ + Drawable drawable, /* Window or pixmap in which to draw. */ + GC gc, /* Graphics context for drawing characters. */ + Tk_Font tkfont, /* Font in which characters will be drawn; must + * be the same as font used in GC. */ + const char * source, /* UTF-8 string to be displayed. Need not be + * '\0' terminated. All Tk meta-characters + * (tabs, control characters, and newlines) + * should be stripped out of the string that is + * passed to this function. If they are not + * stripped out, they will be displayed as + * regular printing characters. */ + int numBytes, /* Number of bytes in string. */ + int rangeStart, /* Index of first byte to draw. */ + int rangeLength, /* Length of range to draw in bytes. */ + double x, double y, /* Coordinates at which to place origin of the + * whole (not just the range) string when + * drawing. */ + double angle) /* What angle to put text at, in degrees. */ +{ + int widthUntilStart; + + (void) numBytes; /*unused*/ + + Tk_MeasureChars(tkfont, source, rangeStart, -1, 0, &widthUntilStart); + TkDrawAngledChars(display, drawable, gc, tkfont, source + rangeStart, + rangeLength, x+widthUntilStart, y, angle); +} + /* *------------------------------------------------------------------------- * diff --git a/win/tkWinFont.c b/win/tkWinFont.c index cef505a..39abda4 100644 --- a/win/tkWinFont.c +++ b/win/tkWinFont.c @@ -1402,6 +1402,37 @@ TkpDrawCharsInContext( rangeLength, x+widthUntilStart, y); } +/* UNTESTED */ +void +TkpDrawAngledCharsInContext( + Display *display, /* Display on which to draw. */ + Drawable drawable, /* Window or pixmap in which to draw. */ + GC gc, /* Graphics context for drawing characters. */ + Tk_Font tkfont, /* Font in which characters will be drawn; must + * be the same as font used in GC. */ + const char * source, /* UTF-8 string to be displayed. Need not be + * '\0' terminated. All Tk meta-characters + * (tabs, control characters, and newlines) + * should be stripped out of the string that is + * passed to this function. If they are not + * stripped out, they will be displayed as + * regular printing characters. */ + int numBytes, /* Number of bytes in string. */ + int rangeStart, /* Index of first byte to draw. */ + int rangeLength, /* Length of range to draw in bytes. */ + double x, double y, /* Coordinates at which to place origin of the + * whole (not just the range) string when + * drawing. */ + double angle) /* What angle to put text at, in degrees. */ +{ + int widthUntilStart; + (void) numBytes; /*unused*/ + + Tk_MeasureChars(tkfont, source, rangeStart, -1, 0, &widthUntilStart); + TkDrawAngledChars(display, drawable, gc, tkfont, source + rangeStart, + rangeLength, x+widthUntilStart, y, angle); +} + /* *------------------------------------------------------------------------- * -- cgit v0.12 From 5ed4790f7555c57fa47e3467c819aa111c632978 Mon Sep 17 00:00:00 2001 From: fvogel Date: Tue, 21 Apr 2020 06:57:35 +0000 Subject: Apply a third patch from Christopher Chavez. --- unix/tkUnixFont.c | 4 +-- unix/tkUnixRFont.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ win/tkWinFont.c | 4 +-- 3 files changed, 84 insertions(+), 4 deletions(-) diff --git a/unix/tkUnixFont.c b/unix/tkUnixFont.c index a1b969e..c91da55 100644 --- a/unix/tkUnixFont.c +++ b/unix/tkUnixFont.c @@ -1413,7 +1413,6 @@ TkpDrawCharsInContext( rangeLength, x+widthUntilStart, y); } -/* UNTESTED */ void TkpDrawAngledCharsInContext( Display *display, /* Display on which to draw. */ @@ -1437,12 +1436,13 @@ TkpDrawAngledCharsInContext( double angle) /* What angle to put text at, in degrees. */ { int widthUntilStart; + double sinA = sin(angle * PI/180.0), cosA = cos(angle * PI/180.0); (void) numBytes; /*unused*/ Tk_MeasureChars(tkfont, source, rangeStart, -1, 0, &widthUntilStart); TkDrawAngledChars(display, drawable, gc, tkfont, source + rangeStart, - rangeLength, x+widthUntilStart, y, angle); + rangeLength, x+cosA*widthUntilStart, y-sinA*widthUntilStart, angle); } /* diff --git a/unix/tkUnixRFont.c b/unix/tkUnixRFont.c index 2c3d91f..069598f 100644 --- a/unix/tkUnixRFont.c +++ b/unix/tkUnixRFont.c @@ -1300,6 +1300,86 @@ TkDrawAngledChars( } } +/* + *--------------------------------------------------------------------------- + * + * TkpDrawCharsInContext -- + * + * Draw a string of characters on the screen like Tk_DrawChars(), but + * with access to all the characters on the line for context. On X11 this + * context isn't consulted, so we just call Tk_DrawChars(). + * + * Results: + * None. + * + * Side effects: + * Information gets drawn on the screen. + * + *--------------------------------------------------------------------------- + */ + +void +TkpDrawCharsInContext( + Display *display, /* Display on which to draw. */ + Drawable drawable, /* Window or pixmap in which to draw. */ + GC gc, /* Graphics context for drawing characters. */ + Tk_Font tkfont, /* Font in which characters will be drawn; + * must be the same as font used in GC. */ + const char *source, /* UTF-8 string to be displayed. Need not be + * '\0' terminated. All Tk meta-characters + * (tabs, control characters, and newlines) + * should be stripped out of the string that + * is passed to this function. If they are not + * stripped out, they will be displayed as + * regular printing characters. */ + int numBytes, /* Number of bytes in string. */ + int rangeStart, /* Index of first byte to draw. */ + int rangeLength, /* Length of range to draw in bytes. */ + int x, int y) /* Coordinates at which to place origin of the + * whole (not just the range) string when + * drawing. */ +{ + int widthUntilStart; + + (void) numBytes; /*unused*/ + + Tk_MeasureChars(tkfont, source, rangeStart, -1, 0, &widthUntilStart); + Tk_DrawChars(display, drawable, gc, tkfont, source + rangeStart, + rangeLength, x+widthUntilStart, y); +} + +void +TkpDrawAngledCharsInContext( + Display *display, /* Display on which to draw. */ + Drawable drawable, /* Window or pixmap in which to draw. */ + GC gc, /* Graphics context for drawing characters. */ + Tk_Font tkfont, /* Font in which characters will be drawn; must + * be the same as font used in GC. */ + const char * source, /* UTF-8 string to be displayed. Need not be + * '\0' terminated. All Tk meta-characters + * (tabs, control characters, and newlines) + * should be stripped out of the string that is + * passed to this function. If they are not + * stripped out, they will be displayed as + * regular printing characters. */ + int numBytes, /* Number of bytes in string. */ + int rangeStart, /* Index of first byte to draw. */ + int rangeLength, /* Length of range to draw in bytes. */ + double x, double y, /* Coordinates at which to place origin of the + * whole (not just the range) string when + * drawing. */ + double angle) /* What angle to put text at, in degrees. */ +{ + int widthUntilStart; + double sinA = sin(angle * PI/180.0), cosA = cos(angle * PI/180.0); + + (void) numBytes; /*unused*/ + + Tk_MeasureChars(tkfont, source, rangeStart, -1, 0, &widthUntilStart); + TkDrawAngledChars(display, drawable, gc, tkfont, source + rangeStart, + rangeLength, x+cosA*widthUntilStart, y-sinA*widthUntilStart, angle); +} + void TkUnixSetXftClipRegion( TkRegion clipRegion) /* The clipping region to install. */ diff --git a/win/tkWinFont.c b/win/tkWinFont.c index 39abda4..91f8f14 100644 --- a/win/tkWinFont.c +++ b/win/tkWinFont.c @@ -1402,7 +1402,6 @@ TkpDrawCharsInContext( rangeLength, x+widthUntilStart, y); } -/* UNTESTED */ void TkpDrawAngledCharsInContext( Display *display, /* Display on which to draw. */ @@ -1426,11 +1425,12 @@ TkpDrawAngledCharsInContext( double angle) /* What angle to put text at, in degrees. */ { int widthUntilStart; + double sinA = sin(angle * PI/180.0), cosA = cos(angle * PI/180.0); (void) numBytes; /*unused*/ Tk_MeasureChars(tkfont, source, rangeStart, -1, 0, &widthUntilStart); TkDrawAngledChars(display, drawable, gc, tkfont, source + rangeStart, - rangeLength, x+widthUntilStart, y, angle); + rangeLength, x+cosA*widthUntilStart, y-sinA*widthUntilStart, angle); } /* -- cgit v0.12 From 15e5fa342b580bd3d22f1c83bffc4ae1c171cf65 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sat, 2 May 2020 14:19:27 +0000 Subject: Add comments --- generic/tkBind.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/generic/tkBind.c b/generic/tkBind.c index c1fdc0c..c665c97 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -59,7 +59,9 @@ /* * In old implementation (the one that used an event ring), and <1><1> were - * equivalent sequences. However it is logical to give higher precedence. + * equivalent sequences. However it is logical to give higher precedence + * since it is more specific. Indeed includes time and space requirements, + * which is not the case for <1><1>. * This can be achieved by setting PREFER_MOST_SPECIALIZED_EVENT to 1. */ @@ -2192,7 +2194,7 @@ Tk_BindEvent( * Ignore the event completely if it is an Enter, Leave, FocusIn, or * FocusOut event with detail NotifyInferior. The reason for ignoring * these events is that we don't want transitions between a window and its - * children to visible to bindings on the parent: this would cause + * children to be visible to bindings on the parent: this would cause * problems for mega-widgets, since the internal structure of a * mega-widget isn't supposed to be visible to people watching the parent. * -- cgit v0.12 From 0b6034171d1c461e9c7758e6ba29962052d89ad3 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sat, 2 May 2020 16:58:33 +0000 Subject: Add (currently failing) tests bind-33.16, bind-33.17 and bind-33.18 exercising the case reported in bug [16ef161925] --- tests/bind.test | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/tests/bind.test b/tests/bind.test index 7cb515d..8bd215a 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6624,6 +6624,57 @@ test bind-33.15 {prefer last in case of homogeneous equal patterns} -setup { # because both bindings are homogeneous equal, so the most recently defined # must be preferred. } -result {last} +test bind-33.16 {simulate use of the keyboard to trigger a pattern sequence with modifier - bug [16ef161925]} -setup { + pack [frame .t.f] + focus -force .t.f + update + set x {} +} -body { + bind .t.f { lappend x "Esc_Control-c" } + event generate .t.f + event generate .t.f + event generate .t.f + event generate .t.f + event generate .t.f + set x +} -cleanup { + destroy .t.f +} -result {Esc_Control-c} +test bind-33.17 {simulate use of the keyboard to trigger a pattern sequence with modifier - bug [16ef161925]} -setup { + pack [frame .t.f] + focus -force .t.f + update + set x {} +} -body { + bind .t.f { lappend x "Esc_Control-c" } + bind .t.f { lappend x "Esc_Ctrl_L_Control-c" } + event generate .t.f + event generate .t.f + event generate .t.f + event generate .t.f + event generate .t.f + set x +} -cleanup { + destroy .t.f +} -result {Esc_Ctrl_L_Control-c} +test bind-33.18 {simulate use of the keyboard to trigger a pattern sequence with modifier - bug [16ef161925]} -setup { + pack [frame .t.f] + focus -force .t.f + update + set x {} +} -body { + bind .t.f { lappend x "Esc_Control-c" } + bind .t.f { lappend x "Esc_Ctrl_L_Control-c" } + bind .t.f { lappend x "Esc_Ctrl_L(2)_Control-c" } + event generate .t.f + event generate .t.f + event generate .t.f + event generate .t.f + event generate .t.f + set x +} -cleanup { + destroy .t.f +} -result {Esc_Ctrl_L(2)_Control-c} test bind-34.1 {-warp works relatively to a window} -setup { toplevel .top -- cgit v0.12 From 1f9bfb7ca41d15194eecedc6a5875fe3564ecd7c Mon Sep 17 00:00:00 2001 From: fvogel Date: Sat, 2 May 2020 16:59:41 +0000 Subject: Fix proposal for [16ef161925]: binding sequence not working anymore --- generic/tkBind.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/generic/tkBind.c b/generic/tkBind.c index c665c97..105585e 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -2794,6 +2794,7 @@ MatchPatterns( ? psPtr->object == object : VirtPatIsBound(bindPtr, psPtr, object, physPtrPtr)) { TkPattern *patPtr = psPtr->pats + patIndex; + unsigned i; if (patPtr->eventType == (unsigned) curEvent->xev.type && (curEvent->xev.type != CreateNotify @@ -2875,6 +2876,25 @@ MatchPatterns( } } } + + /* + * Modifier key events interlaced between patterns parts of a + * sequence shall not prevent a sequence from ultimately + * matching. Example: when trying to trigger + * from the keyboard, the sequence of events actually seen is + * then (possibly repeating if the key is hold + * down), and finally . At the time is + * seen, we shall keep the pattern sequence in + * the promotion list, otherwise it is impossible to trigger + * it from the keyboard. See bug [16ef161925]. + */ + for (i = 0; i < (unsigned) dispPtr->numModKeyCodes; ++i) { + if (dispPtr->modKeyCodes[i] == curEvent->xev.xkey.keycode) { + DEBUG(psEntry->expired = 0;) + psEntry->keepIt = 1; + } + } + } } } -- cgit v0.12 From b1e49e8fcaf74233197cc64fae57ddefaa7045c0 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sat, 2 May 2020 19:25:08 +0000 Subject: Add new test bind-33.19, further exercising simulation of the keyboard to trigger bindings containing several patterns. --- tests/bind.test | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/bind.test b/tests/bind.test index 8bd215a..7431079 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6675,6 +6675,22 @@ test bind-33.18 {simulate use of the keyboard to trigger a pattern sequence with } -cleanup { destroy .t.f } -result {Esc_Ctrl_L(2)_Control-c} +test bind-33.19 {simulate use of the keyboard to trigger a pattern sequence with modifier - bug [16ef161925]} -setup { + pack [frame .t.f] + focus -force .t.f + update + set x {} +} -body { + bind .t.f { lappend x "Esc_Control-c" } + bind .t.f { lappend x "Esc_Key(2)_Control-c" } + event generate .t.f + event generate .t.f + event generate .t.f + event generate .t.f + set x +} -cleanup { + destroy .t.f +} -result {Esc_Key(2)_Control-c} test bind-34.1 {-warp works relatively to a window} -setup { toplevel .top -- cgit v0.12 From b32ea1d3f743cc4b1a5c07d13006ed0d0d953946 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sat, 2 May 2020 19:33:58 +0000 Subject: Revert my fix proposal [dfa8bbc5] and commit a fix proposal from Gregor. Tests bind-33.16, -17 and -18 fail again. Moreover bind-33.9 now fails (regression). --- generic/tkBind.c | 45 +++++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/generic/tkBind.c b/generic/tkBind.c index 105585e..a39b01b 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -854,18 +854,25 @@ MatchEventNearby( && TestNearbyCoords(rhs->xbutton.y_root, lhs->xbutton.y_root); } +int +IsKeyEventType( + unsigned eventType) +{ + return eventType == KeyPress || eventType == KeyRelease; +} + static int MatchEventRepeat( - const XEvent *lhs, /* previous key event */ - const XEvent *rhs) /* current key event */ + const XKeyEvent *lhs, /* previous key event */ + const XKeyEvent *rhs) /* current key event */ { assert(lhs); assert(rhs); - assert(lhs->type == KeyPress || lhs->type == KeyRelease); + assert(IsKeyEventType(lhs->type)); assert(lhs->type == rhs->type); - /* assert: lhs->xkey.time <= rhs->xkey.time */ - return TestNearbyTime(rhs->xkey.time, lhs->xkey.time); + /* assert: lhs->time <= rhs->time */ + return lhs->keycode == rhs->keycode && TestNearbyTime(lhs->time, rhs->time); } static void @@ -2278,7 +2285,7 @@ Tk_BindEvent( switch (eventPtr->type) { case KeyPress: case KeyRelease: - if (MatchEventRepeat(&curEvent->xev, eventPtr)) { + if (MatchEventRepeat(&curEvent->xev.xkey, &eventPtr->xkey)) { if (curEvent->xev.xkey.keycode == eventPtr->xkey.keycode) { ++curEvent->countDetailed; } else { @@ -2767,6 +2774,7 @@ MatchPatterns( PatSeq *bestPhysPtr; ModMask bestModMask; const PSModMaskArr *bestModMaskArr = NULL; + int isModKeyOnly; assert(dispPtr); assert(bindPtr); @@ -2780,6 +2788,7 @@ MatchPatterns( bestPtr = NULL; bestPhysPtr = NULL; window = curEvent->xev.xany.window; + isModKeyOnly = IsKeyEventType(curEvent->xev.type) && curEvent->xev.xkey.keycode == 0; for (psEntry = PSList_First(psList); psEntry; psEntry = PSList_Next(psEntry)) { if (patIndex == 0 || psEntry->window == window) { @@ -2790,11 +2799,13 @@ MatchPatterns( assert(psPtr->object || patIndex == 0); assert(psPtr->numPats > patIndex); + /* ignore modifier key events */ + psEntry->keepIt = isModKeyOnly; + if (psPtr->object ? psPtr->object == object : VirtPatIsBound(bindPtr, psPtr, object, physPtrPtr)) { TkPattern *patPtr = psPtr->pats + patIndex; - unsigned i; if (patPtr->eventType == (unsigned) curEvent->xev.type && (curEvent->xev.type != CreateNotify @@ -2810,6 +2821,7 @@ MatchPatterns( ModMask curModMask = ResolveModifiers(dispPtr, bindPtr->curModMask); psEntry->expired = 1; /* remove it from promotion list */ + psEntry->keepIt = 0; /* don't keep matching patterns */ if (IsSubsetOf(modMask, curModMask)) { unsigned count = patPtr->info ? curEvent->countDetailed : curEvent->countAny; @@ -2876,25 +2888,6 @@ MatchPatterns( } } } - - /* - * Modifier key events interlaced between patterns parts of a - * sequence shall not prevent a sequence from ultimately - * matching. Example: when trying to trigger - * from the keyboard, the sequence of events actually seen is - * then (possibly repeating if the key is hold - * down), and finally . At the time is - * seen, we shall keep the pattern sequence in - * the promotion list, otherwise it is impossible to trigger - * it from the keyboard. See bug [16ef161925]. - */ - for (i = 0; i < (unsigned) dispPtr->numModKeyCodes; ++i) { - if (dispPtr->modKeyCodes[i] == curEvent->xev.xkey.keycode) { - DEBUG(psEntry->expired = 0;) - psEntry->keepIt = 1; - } - } - } } } -- cgit v0.12 From b0496c8e6eecf19425c2cb2a790737942a052387 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sun, 3 May 2020 09:31:07 +0000 Subject: Now a mixture of my fix with Gregor's fix. All tests from bind.test do pass again. --- generic/tkBind.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/generic/tkBind.c b/generic/tkBind.c index a39b01b..8e08746 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -2774,7 +2774,7 @@ MatchPatterns( PatSeq *bestPhysPtr; ModMask bestModMask; const PSModMaskArr *bestModMaskArr = NULL; - int isModKeyOnly; + int i, isModKeyOnly = 0; assert(dispPtr); assert(bindPtr); @@ -2788,7 +2788,26 @@ MatchPatterns( bestPtr = NULL; bestPhysPtr = NULL; window = curEvent->xev.xany.window; - isModKeyOnly = IsKeyEventType(curEvent->xev.type) && curEvent->xev.xkey.keycode == 0; + + /* + * Modifier key events interlaced between patterns parts of a + * sequence shall not prevent a sequence from ultimately + * matching. Example: when trying to trigger + * from the keyboard, the sequence of events actually seen is + * then (possibly repeating if the key is hold + * down), and finally . At the time is + * seen, we shall keep the pattern sequence in + * the promotion list, otherwise it is impossible to trigger + * it from the keyboard. See bug [16ef161925]. + */ + if (IsKeyEventType(curEvent->xev.type)) { + for (i = 0; i < dispPtr->numModKeyCodes; ++i) { + if (dispPtr->modKeyCodes[i] == curEvent->xev.xkey.keycode) { + isModKeyOnly = 1; + break; + } + } + } for (psEntry = PSList_First(psList); psEntry; psEntry = PSList_Next(psEntry)) { if (patIndex == 0 || psEntry->window == window) { @@ -2799,14 +2818,14 @@ MatchPatterns( assert(psPtr->object || patIndex == 0); assert(psPtr->numPats > patIndex); - /* ignore modifier key events */ - psEntry->keepIt = isModKeyOnly; - if (psPtr->object ? psPtr->object == object : VirtPatIsBound(bindPtr, psPtr, object, physPtrPtr)) { TkPattern *patPtr = psPtr->pats + patIndex; + /* ignore modifier key events */ + psEntry->keepIt = isModKeyOnly; + if (patPtr->eventType == (unsigned) curEvent->xev.type && (curEvent->xev.type != CreateNotify || curEvent->xev.xcreatewindow.parent == window) -- cgit v0.12 From 08125543bb6f0e52cf39ebecfd21cf8371b7ab0f Mon Sep 17 00:00:00 2001 From: fvogel Date: Sun, 3 May 2020 21:06:14 +0000 Subject: Make a bit more use of helper functions. No functional change. --- generic/tkBind.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/generic/tkBind.c b/generic/tkBind.c index 8e08746..dbf8d8f 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -837,6 +837,20 @@ CountSpecialized( return sndCount - fstCount; } +int +IsKeyEventType( + unsigned eventType) +{ + return eventType == KeyPress || eventType == KeyRelease; +} + +int +IsButtonEventType( + unsigned eventType) +{ + return eventType == ButtonPress || eventType == ButtonRelease; +} + static int MatchEventNearby( const XEvent *lhs, /* previous button event */ @@ -844,7 +858,7 @@ MatchEventNearby( { assert(lhs); assert(rhs); - assert(lhs->type == ButtonPress || lhs->type == ButtonRelease); + assert(IsButtonEventType(lhs->type)); assert(lhs->type == rhs->type); /* assert: lhs->xbutton.time <= rhs->xbutton.time */ @@ -854,13 +868,6 @@ MatchEventNearby( && TestNearbyCoords(rhs->xbutton.y_root, lhs->xbutton.y_root); } -int -IsKeyEventType( - unsigned eventType) -{ - return eventType == KeyPress || eventType == KeyRelease; -} - static int MatchEventRepeat( const XKeyEvent *lhs, /* previous key event */ @@ -2509,13 +2516,13 @@ Tk_BindEvent( switch (patPtr->eventType) { case ButtonPress: case ButtonRelease: - if (curEvent->xev.type == KeyPress || curEvent->xev.type == KeyRelease) { + if (IsKeyEventType(curEvent->xev.type)) { RemoveListEntry(&bindPtr->lookupTables.entryPool, psEntry); } break; case KeyPress: case KeyRelease: - if (curEvent->xev.type == ButtonPress || curEvent->xev.type == ButtonRelease) { + if (IsButtonEventType(curEvent->xev.type)) { RemoveListEntry(&bindPtr->lookupTables.entryPool, psEntry); } break; -- cgit v0.12 From 6d7c515937d71090f48a39e7659729339d235879 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sat, 16 May 2020 12:54:26 +0000 Subject: Fix [5c51be6411]: Buffer over-read in Tk_PhotoPutBlock() and Tk_PhotoPutZoomedBlock(). Patch from Christopher Chavez. --- generic/tkImgPhoto.c | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/generic/tkImgPhoto.c b/generic/tkImgPhoto.c index 96c3743..5d2c075 100644 --- a/generic/tkImgPhoto.c +++ b/generic/tkImgPhoto.c @@ -2771,8 +2771,21 @@ Tk_PhotoPutBlock( if (sourceBlock.pixelPtr >= masterPtr->pix32 && sourceBlock.pixelPtr <= masterPtr->pix32 + masterPtr->width * masterPtr->height * 4) { - sourceBlock.pixelPtr = attemptckalloc(sourceBlock.height - * sourceBlock.pitch); + /* + * Fix 0123456789: avoid reading + * + * (sourceBlock.pitch - sourceBlock.width * sourceBlock.pixelSize) + * + * bytes past the end of masterPtr->pix32[] when + * + * blockPtr->pixelPtr > (masterPtr->pix32 + + * 4 * masterPtr->width * masterPtr->height - + * sourceBlock.height * sourceBlock.pitch) + */ + unsigned int cpyLen = (sourceBlock.height - 1) * sourceBlock.pitch + + sourceBlock.width * sourceBlock.pixelSize; + + sourceBlock.pixelPtr = attemptckalloc(cpyLen); if (sourceBlock.pixelPtr == NULL) { if (interp != NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj( @@ -2782,8 +2795,7 @@ Tk_PhotoPutBlock( return TCL_ERROR; } memToFree = sourceBlock.pixelPtr; - memcpy(sourceBlock.pixelPtr, blockPtr->pixelPtr, sourceBlock.height - * sourceBlock.pitch); + memcpy(sourceBlock.pixelPtr, blockPtr->pixelPtr, cpyLen); } @@ -3205,8 +3217,21 @@ Tk_PhotoPutZoomedBlock( if (sourceBlock.pixelPtr >= masterPtr->pix32 && sourceBlock.pixelPtr <= masterPtr->pix32 + masterPtr->width * masterPtr->height * 4) { - sourceBlock.pixelPtr = attemptckalloc(sourceBlock.height - * sourceBlock.pitch); + /* + * Fix 0123456789: avoid reading + * + * (sourceBlock.pitch - sourceBlock.width * sourceBlock.pixelSize) + * + * bytes past the end of masterPtr->pix32[] when + * + * blockPtr->pixelPtr > (masterPtr->pix32 + + * 4 * masterPtr->width * masterPtr->height - + * sourceBlock.height * sourceBlock.pitch) + */ + unsigned int cpyLen = (sourceBlock.height - 1) * sourceBlock.pitch + + sourceBlock.width * sourceBlock.pixelSize; + + sourceBlock.pixelPtr = attemptckalloc(cpyLen); if (sourceBlock.pixelPtr == NULL) { if (interp != NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj( @@ -3216,8 +3241,7 @@ Tk_PhotoPutZoomedBlock( return TCL_ERROR; } memToFree = sourceBlock.pixelPtr; - memcpy(sourceBlock.pixelPtr, blockPtr->pixelPtr, sourceBlock.height - * sourceBlock.pitch); + memcpy(sourceBlock.pixelPtr, blockPtr->pixelPtr, cpyLen); } xEnd = x + width; -- cgit v0.12 From 6032a8780a04056c38959835e506213718674a37 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sat, 16 May 2020 12:55:11 +0000 Subject: Let the bug id be correct --- generic/tkImgPhoto.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/generic/tkImgPhoto.c b/generic/tkImgPhoto.c index 5d2c075..db106f2 100644 --- a/generic/tkImgPhoto.c +++ b/generic/tkImgPhoto.c @@ -2772,7 +2772,7 @@ Tk_PhotoPutBlock( && sourceBlock.pixelPtr <= masterPtr->pix32 + masterPtr->width * masterPtr->height * 4) { /* - * Fix 0123456789: avoid reading + * Fix 5c51be6411: avoid reading * * (sourceBlock.pitch - sourceBlock.width * sourceBlock.pixelSize) * @@ -3218,7 +3218,7 @@ Tk_PhotoPutZoomedBlock( && sourceBlock.pixelPtr <= masterPtr->pix32 + masterPtr->width * masterPtr->height * 4) { /* - * Fix 0123456789: avoid reading + * Fix 5c51be6411: avoid reading * * (sourceBlock.pitch - sourceBlock.width * sourceBlock.pixelSize) * -- cgit v0.12 From 94796510222de972274beb287fa2aaa581dd4a7a Mon Sep 17 00:00:00 2001 From: marc_culler Date: Sat, 16 May 2020 14:20:06 +0000 Subject: Remove code from TkpWarpPointer which was only needed to construct the NSEvent that is no longer being constructed. --- macosx/tkMacOSXMouseEvent.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c index 9a4dc46..e8296e2 100644 --- a/macosx/tkMacOSXMouseEvent.c +++ b/macosx/tkMacOSXMouseEvent.c @@ -641,25 +641,15 @@ TkpWarpPointer( TkDisplay *dispPtr) { CGPoint pt; - 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 { - wNum = 0; - pt.x = loc.x = dispPtr->warpX; + pt.x = dispPtr->warpX; pt.y = dispPtr->warpY; - loc.y = TkMacOSXZeroScreenHeight() - pt.y; } CGWarpMouseCursorPosition(pt); -- cgit v0.12 From 3315ad85a29eee53ac2c7b8b9845f148ff99edaf Mon Sep 17 00:00:00 2001 From: culler Date: Tue, 19 May 2020 20:43:44 +0000 Subject: Aqua: Try processing idle events before each call to [NSApp nextEventMatchingMask ...] --- macosx/tkMacOSXNotify.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c index 96c9a7a..985d7bc 100644 --- a/macosx/tkMacOSXNotify.c +++ b/macosx/tkMacOSXNotify.c @@ -338,6 +338,7 @@ TkMacOSXEventsSetupProc( * Call this with dequeue=NO -- just checking if the queue is empty. */ + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} NSEvent *currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] @@ -407,6 +408,7 @@ TkMacOSXEventsCheckProc( [NSApp _lockAutoreleasePool]; do { + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} modalSession = TkMacOSXGetModalSession(); testEvent = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] @@ -420,6 +422,7 @@ TkMacOSXEventsCheckProc( if (testEvent && [[testEvent window] inLiveResize]) { break; } + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:GetRunLoopMode(modalSession) -- cgit v0.12 -- cgit v0.12 From d6e49238a94a313ec7fa612387ad1c72211ea479 Mon Sep 17 00:00:00 2001 From: bll Date: Wed, 20 May 2020 15:43:52 +0000 Subject: Work around a windows vsapi issue where the size returned for a vsapi element changes upon fetching the size a second time. --- win/ttkWinXPTheme.c | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/win/ttkWinXPTheme.c b/win/ttkWinXPTheme.c index 4391fdd..c32d3cd 100644 --- a/win/ttkWinXPTheme.c +++ b/win/ttkWinXPTheme.c @@ -373,6 +373,10 @@ static Ttk_StateTable tabitem_statemap[] = * <>: * This gives bogus metrics for some parts (in particular, * BP_PUSHBUTTONS). Set the IGNORE_THEMESIZE flag to skip this call. + * + * <>: + * It seems that fetching the part size more than once on checkbuttons + * and radiobuttons does not work properly. */ typedef struct /* XP element specifications */ @@ -390,6 +394,7 @@ typedef struct /* XP element specifications */ # define HEAP_ELEMENT 0x20000000U /* ElementInfo is on heap */ # define HALF_HEIGHT 0x10000000U /* Used by GenericSizedElements */ # define HALF_WIDTH 0x08000000U /* Used by GenericSizedElements */ +# define FETCH_ONCE 0x04000000U /* Used by GenericElementSize See NOTE-GetThemePartSize-2 */ } ElementInfo; typedef struct @@ -407,6 +412,12 @@ typedef struct HDC hDC; HWND hwnd; + /* + * To work around fetch of size returning wrong data + */ + SIZE origSize; + int fetched; + /* For TkWinDrawableReleaseDC: */ Drawable drawable; TkWinDCState dcState; @@ -420,6 +431,7 @@ NewElementData(XPThemeProcs *procs, ElementInfo *info) elementData->procs = procs; elementData->info = info; elementData->hTheme = elementData->hDC = 0; + elementData->fetched = 0; return elementData; } @@ -508,19 +520,28 @@ static void GenericElementSize( return; if (!(elementData->info->flags & IGNORE_THEMESIZE)) { - result = elementData->procs->GetThemePartSize( - elementData->hTheme, - elementData->hDC, - elementData->info->partId, - Ttk_StateTableLookup(elementData->info->statemap, 0), - NULL /*RECT *prc*/, - TS_TRUE, - &size); + if ((elementData->info->flags & FETCH_ONCE) && elementData->fetched) { + size = elementData->origSize; + result = 0; /* non-negative is success */ + } else { + result = elementData->procs->GetThemePartSize( + elementData->hTheme, + elementData->hDC, + elementData->info->partId, + Ttk_StateTableLookup(elementData->info->statemap, 0), + NULL /*RECT *prc*/, + TS_TRUE, + &size); + } if (SUCCEEDED(result)) { *widthPtr = size.cx; *heightPtr = size.cy; } + if ((elementData->info->flags & FETCH_ONCE) && ! elementData->fetched) { + elementData->origSize = size; + elementData->fetched = 1; + } } /* See NOTE-GetThemeMargins @@ -966,9 +987,9 @@ TTK_END_LAYOUT_TABLE static ElementInfo ElementInfoTable[] = { { "Checkbutton.indicator", &GenericElementSpec, L"BUTTON", - BP_CHECKBOX, checkbox_statemap, PAD(0, 0, 4, 0), PAD_MARGINS }, + BP_CHECKBOX, checkbox_statemap, PAD(0, 0, 4, 0), PAD_MARGINS | FETCH_ONCE }, { "Radiobutton.indicator", &GenericElementSpec, L"BUTTON", - BP_RADIOBUTTON, radiobutton_statemap, PAD(0, 0, 4, 0), PAD_MARGINS }, + BP_RADIOBUTTON, radiobutton_statemap, PAD(0, 0, 4, 0), PAD_MARGINS | FETCH_ONCE }, { "Button.button", &GenericElementSpec, L"BUTTON", BP_PUSHBUTTON, pushbutton_statemap, PAD(3, 3, 3, 3), IGNORE_THEMESIZE }, { "Labelframe.border", &GenericElementSpec, L"BUTTON", -- cgit v0.12 From 36975c88f715a973f160b5f6627d89965ebbb06e Mon Sep 17 00:00:00 2001 From: fvogel Date: Sun, 24 May 2020 10:51:11 +0000 Subject: Use S_OK for result instead of directly 0. --- win/ttkWinXPTheme.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/win/ttkWinXPTheme.c b/win/ttkWinXPTheme.c index c32d3cd..f91be9b 100644 --- a/win/ttkWinXPTheme.c +++ b/win/ttkWinXPTheme.c @@ -522,7 +522,7 @@ static void GenericElementSize( if (!(elementData->info->flags & IGNORE_THEMESIZE)) { if ((elementData->info->flags & FETCH_ONCE) && elementData->fetched) { size = elementData->origSize; - result = 0; /* non-negative is success */ + result = S_OK; } else { result = elementData->procs->GetThemePartSize( elementData->hTheme, @@ -538,7 +538,7 @@ static void GenericElementSize( *widthPtr = size.cx; *heightPtr = size.cy; } - if ((elementData->info->flags & FETCH_ONCE) && ! elementData->fetched) { + if ((elementData->info->flags & FETCH_ONCE) && !elementData->fetched) { elementData->origSize = size; elementData->fetched = 1; } -- cgit v0.12 From 5da5fa8645eacfb6a876212e959f93a6603e1c5b Mon Sep 17 00:00:00 2001 From: bll Date: Sun, 24 May 2020 15:00:22 +0000 Subject: Add FETCH_ONCE to the treeview indicator also. --- win/ttkWinXPTheme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win/ttkWinXPTheme.c b/win/ttkWinXPTheme.c index f91be9b..3252a18 100644 --- a/win/ttkWinXPTheme.c +++ b/win/ttkWinXPTheme.c @@ -1058,7 +1058,7 @@ static ElementInfo ElementInfoTable[] = { { "Treeview.field", &GenericElementSpec, L"TREEVIEW", TVP_TREEITEM, treeview_statemap, PAD(1, 1, 1, 1), IGNORE_THEMESIZE }, { "Treeitem.indicator", &TreeIndicatorElementSpec, L"TREEVIEW", - TVP_GLYPH, tvpglyph_statemap, PAD(1,1,6,0), PAD_MARGINS }, + TVP_GLYPH, tvpglyph_statemap, PAD(1,1,6,0), PAD_MARGINS | FETCH_ONCE }, { "Treeheading.border", &GenericElementSpec, L"HEADER", HP_HEADERITEM, header_statemap, PAD(4,0,4,0),0 }, { "sizegrip", &GenericElementSpec, L"STATUS", -- cgit v0.12 From 343083448bf1002eaefaedcee770d7641a653bda Mon Sep 17 00:00:00 2001 From: bll Date: Sun, 24 May 2020 20:58:18 +0000 Subject: Implement a much simpler method to get the proper sizing (nemethi). --- win/ttkWinXPTheme.c | 43 +++++++++++-------------------------------- 1 file changed, 11 insertions(+), 32 deletions(-) diff --git a/win/ttkWinXPTheme.c b/win/ttkWinXPTheme.c index 3252a18..436fe00 100644 --- a/win/ttkWinXPTheme.c +++ b/win/ttkWinXPTheme.c @@ -373,10 +373,6 @@ static Ttk_StateTable tabitem_statemap[] = * <>: * This gives bogus metrics for some parts (in particular, * BP_PUSHBUTTONS). Set the IGNORE_THEMESIZE flag to skip this call. - * - * <>: - * It seems that fetching the part size more than once on checkbuttons - * and radiobuttons does not work properly. */ typedef struct /* XP element specifications */ @@ -394,7 +390,6 @@ typedef struct /* XP element specifications */ # define HEAP_ELEMENT 0x20000000U /* ElementInfo is on heap */ # define HALF_HEIGHT 0x10000000U /* Used by GenericSizedElements */ # define HALF_WIDTH 0x08000000U /* Used by GenericSizedElements */ -# define FETCH_ONCE 0x04000000U /* Used by GenericElementSize See NOTE-GetThemePartSize-2 */ } ElementInfo; typedef struct @@ -412,12 +407,6 @@ typedef struct HDC hDC; HWND hwnd; - /* - * To work around fetch of size returning wrong data - */ - SIZE origSize; - int fetched; - /* For TkWinDrawableReleaseDC: */ Drawable drawable; TkWinDCState dcState; @@ -431,7 +420,6 @@ NewElementData(XPThemeProcs *procs, ElementInfo *info) elementData->procs = procs; elementData->info = info; elementData->hTheme = elementData->hDC = 0; - elementData->fetched = 0; return elementData; } @@ -520,28 +508,19 @@ static void GenericElementSize( return; if (!(elementData->info->flags & IGNORE_THEMESIZE)) { - if ((elementData->info->flags & FETCH_ONCE) && elementData->fetched) { - size = elementData->origSize; - result = S_OK; - } else { - result = elementData->procs->GetThemePartSize( - elementData->hTheme, - elementData->hDC, - elementData->info->partId, - Ttk_StateTableLookup(elementData->info->statemap, 0), - NULL /*RECT *prc*/, - TS_TRUE, - &size); - } + result = elementData->procs->GetThemePartSize( + elementData->hTheme, + NULL, + elementData->info->partId, + Ttk_StateTableLookup(elementData->info->statemap, 0), + NULL /*RECT *prc*/, + TS_TRUE, + &size); if (SUCCEEDED(result)) { *widthPtr = size.cx; *heightPtr = size.cy; } - if ((elementData->info->flags & FETCH_ONCE) && !elementData->fetched) { - elementData->origSize = size; - elementData->fetched = 1; - } } /* See NOTE-GetThemeMargins @@ -987,9 +966,9 @@ TTK_END_LAYOUT_TABLE static ElementInfo ElementInfoTable[] = { { "Checkbutton.indicator", &GenericElementSpec, L"BUTTON", - BP_CHECKBOX, checkbox_statemap, PAD(0, 0, 4, 0), PAD_MARGINS | FETCH_ONCE }, + BP_CHECKBOX, checkbox_statemap, PAD(0, 0, 4, 0), PAD_MARGINS }, { "Radiobutton.indicator", &GenericElementSpec, L"BUTTON", - BP_RADIOBUTTON, radiobutton_statemap, PAD(0, 0, 4, 0), PAD_MARGINS | FETCH_ONCE }, + BP_RADIOBUTTON, radiobutton_statemap, PAD(0, 0, 4, 0), PAD_MARGINS }, { "Button.button", &GenericElementSpec, L"BUTTON", BP_PUSHBUTTON, pushbutton_statemap, PAD(3, 3, 3, 3), IGNORE_THEMESIZE }, { "Labelframe.border", &GenericElementSpec, L"BUTTON", @@ -1058,7 +1037,7 @@ static ElementInfo ElementInfoTable[] = { { "Treeview.field", &GenericElementSpec, L"TREEVIEW", TVP_TREEITEM, treeview_statemap, PAD(1, 1, 1, 1), IGNORE_THEMESIZE }, { "Treeitem.indicator", &TreeIndicatorElementSpec, L"TREEVIEW", - TVP_GLYPH, tvpglyph_statemap, PAD(1,1,6,0), PAD_MARGINS | FETCH_ONCE }, + TVP_GLYPH, tvpglyph_statemap, PAD(1,1,6,0), PAD_MARGINS }, { "Treeheading.border", &GenericElementSpec, L"HEADER", HP_HEADERITEM, header_statemap, PAD(4,0,4,0),0 }, { "sizegrip", &GenericElementSpec, L"STATUS", -- cgit v0.12 From 9ba4c746ec344f1455e03c2f97ca0ae7c95d139f Mon Sep 17 00:00:00 2001 From: culler Date: Fri, 29 May 2020 18:21:55 +0000 Subject: Remove some unnecessary macOS conditional code by using internal stubs. --- generic/tkFont.c | 10 ++++------ generic/tkInt.decls | 9 +++++++++ generic/tkIntDecls.h | 36 ++++++++++++++++++++++++++++++++++++ generic/tkStubInit.c | 20 ++++++++++++++++++++ generic/tkTextDisp.c | 36 +++++++++++++++++++----------------- macosx/tkMacOSXInt.h | 2 -- macosx/tkMacOSXSubwindows.c | 8 +------- macosx/tkMacOSXWindowEvent.c | 35 +++++++++++++++++++++++++---------- macosx/tkMacOSXWm.c | 34 +++++++++++++++++++++++----------- unix/tkUnixPort.h | 2 ++ win/tkWinPort.h | 7 +++++++ 11 files changed, 146 insertions(+), 53 deletions(-) diff --git a/generic/tkFont.c b/generic/tkFont.c index 53855ac..448f918 100644 --- a/generic/tkFont.c +++ b/generic/tkFont.c @@ -13,9 +13,7 @@ #include "tkInt.h" #include "tkFont.h" -#if defined(MAC_OSX_TK) -#include "tkMacOSXInt.h" -#endif + /* * The following structure is used to keep track of all the fonts that exist * in the current application. It must be stored in the TkMainInfo for the @@ -874,18 +872,18 @@ TheWorldHasChanged( ClientData clientData) /* Info about application's fonts. */ { TkFontInfo *fiPtr = clientData; -#if defined(MAC_OSX_TK) /* * On macOS it is catastrophic to recompute all widgets while the * [NSView drawRect] method is drawing. The best that we can do in * that situation is to abort the recomputation and hope for the best. + * This is ignored on other platforms. */ - if (TkpAppIsDrawing()) { + if (TkpAppCanDraw(NULL)) { return; } -#endif + fiPtr->updatePending = 0; RecomputeWidgets(fiPtr->mainPtr->winPtr); } diff --git a/generic/tkInt.decls b/generic/tkInt.decls index bb2057b..da591cb 100644 --- a/generic/tkInt.decls +++ b/generic/tkInt.decls @@ -634,6 +634,15 @@ declare 184 { Tk_Font tkfont, const char *source, int numBytes, double x, double y, double angle) } + +# Support for aqua's inability to draw outside [NSView drawRect:] +declare 185 aqua { + void TkpRedrawWidget(Tk_Window tkwin) +} +declare 186 aqua { + int TkpAppCanDraw(Tk_Window tkwin) +} + ############################################################################## diff --git a/generic/tkIntDecls.h b/generic/tkIntDecls.h index fa1833e..7bf9bd7 100644 --- a/generic/tkIntDecls.h +++ b/generic/tkIntDecls.h @@ -550,6 +550,14 @@ EXTERN void TkDrawAngledChars(Display *display, Drawable drawable, GC gc, Tk_Font tkfont, const char *source, int numBytes, double x, double y, double angle); +#ifdef MAC_OSX_TK /* AQUA */ +/* 185 */ +EXTERN void TkpRedrawWidget(Tk_Window tkwin); +#endif /* AQUA */ +#ifdef MAC_OSX_TK /* AQUA */ +/* 186 */ +EXTERN int TkpAppCanDraw(Tk_Window tkwin); +#endif /* AQUA */ typedef struct TkIntStubs { int magic; @@ -767,6 +775,26 @@ typedef struct TkIntStubs { void (*tkUnderlineAngledTextLayout) (Display *display, Drawable drawable, GC gc, Tk_TextLayout layout, int x, int y, double angle, int underline); /* 182 */ int (*tkIntersectAngledTextLayout) (Tk_TextLayout layout, int x, int y, int width, int height, double angle); /* 183 */ void (*tkDrawAngledChars) (Display *display, Drawable drawable, GC gc, Tk_Font tkfont, const char *source, int numBytes, double x, double y, double angle); /* 184 */ +#if !(defined(_WIN32) || defined(MAC_OSX_TK)) /* X11 */ + void (*reserved185)(void); +#endif /* X11 */ +#if defined(_WIN32) /* WIN */ + void (*reserved185)(void); +#endif /* WIN */ +#ifdef MAC_OSX_TK /* AQUA */ + void (*reserved185)(void); /* Dummy entry for stubs table backwards compatibility */ + void (*tkpRedrawWidget) (Tk_Window tkwin); /* 185 */ +#endif /* AQUA */ +#if !(defined(_WIN32) || defined(MAC_OSX_TK)) /* X11 */ + void (*reserved186)(void); +#endif /* X11 */ +#if defined(_WIN32) /* WIN */ + void (*reserved186)(void); +#endif /* WIN */ +#ifdef MAC_OSX_TK /* AQUA */ + void (*reserved186)(void); /* Dummy entry for stubs table backwards compatibility */ + int (*tkpAppCanDraw) (Tk_Window tkwin); /* 186 */ +#endif /* AQUA */ } TkIntStubs; extern const TkIntStubs *tkIntStubsPtr; @@ -1139,6 +1167,14 @@ extern const TkIntStubs *tkIntStubsPtr; (tkIntStubsPtr->tkIntersectAngledTextLayout) /* 183 */ #define TkDrawAngledChars \ (tkIntStubsPtr->tkDrawAngledChars) /* 184 */ +#ifdef MAC_OSX_TK /* AQUA */ +#define TkpRedrawWidget \ + (tkIntStubsPtr->tkpRedrawWidget) /* 185 */ +#endif /* AQUA */ +#ifdef MAC_OSX_TK /* AQUA */ +#define TkpAppCanDraw \ + (tkIntStubsPtr->tkpAppCanDraw) /* 186 */ +#endif /* AQUA */ #endif /* defined(USE_TK_STUBS) */ diff --git a/generic/tkStubInit.c b/generic/tkStubInit.c index 61c698a..045c86e 100644 --- a/generic/tkStubInit.c +++ b/generic/tkStubInit.c @@ -485,6 +485,26 @@ static const TkIntStubs tkIntStubs = { TkUnderlineAngledTextLayout, /* 182 */ TkIntersectAngledTextLayout, /* 183 */ TkDrawAngledChars, /* 184 */ +#if !(defined(_WIN32) || defined(MAC_OSX_TK)) /* X11 */ + 0, /* 185 */ +#endif /* X11 */ +#if defined(_WIN32) /* WIN */ + 0, /* 185 */ +#endif /* WIN */ +#ifdef MAC_OSX_TK /* AQUA */ + 0, /* 185 */ /* Dummy entry for stubs table backwards compatibility */ + TkpRedrawWidget, /* 185 */ +#endif /* AQUA */ +#if !(defined(_WIN32) || defined(MAC_OSX_TK)) /* X11 */ + 0, /* 186 */ +#endif /* X11 */ +#if defined(_WIN32) /* WIN */ + 0, /* 186 */ +#endif /* WIN */ +#ifdef MAC_OSX_TK /* AQUA */ + 0, /* 186 */ /* Dummy entry for stubs table backwards compatibility */ + TkpAppCanDraw, /* 186 */ +#endif /* AQUA */ }; static const TkIntPlatStubs tkIntPlatStubs = { diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index c848fd2..084fd64 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -20,15 +20,13 @@ #include "tkWinInt.h" #elif defined(__CYGWIN__) #include "tkUnixInt.h" +#elif defined(MAC_OSX_TK) +#include "tkMacOSXInt.h" +#define OK_TO_LOG (!TkpAppCanDraw(textPtr->tkwin)) #endif -#ifdef MAC_OSX_TK -#include "tkMacOSXInt.h" -#define OK_TO_LOG (!TkpAppIsDrawing()) -#define FORCE_DISPLAY(winPtr) TkpDisplayWindow(winPtr) -#else +#if !defined(MAC_OSX_TK) #define OK_TO_LOG 1 -#define FORCE_DISPLAY(winPtr) #endif /* @@ -3157,7 +3155,7 @@ GenerateWidgetViewSyncEvent( */ if (!tkTextDebug) { - FORCE_DISPLAY(textPtr->tkwin); + TkpRedrawWidget(textPtr->tkwin); } if (NewSyncState != OldSyncState) { @@ -4176,11 +4174,23 @@ DisplayText( * warnings. */ Tcl_Interp *interp; + + if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { + /* + * The widget has been deleted. Don't do anything. + */ + + return; + } + #ifdef MAC_OSX_TK /* - * If drawing is disabled, all we need to do is - * clear the REDRAW_PENDING flag. + * If the toplevel is being resized it would be dangerous to try redrawing + * the widget. But we can just clear the REDRAW_PENDING flag and return. + * This display proc will be called again after the widget has been + * reconfigured. */ + TkWindow *winPtr = (TkWindow *)(textPtr->tkwin); MacDrawable *macWin = winPtr->privatePtr; if (macWin && (macWin->flags & TK_DO_NOT_DRAW)){ @@ -4189,14 +4199,6 @@ DisplayText( } #endif - if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { - /* - * The widget has been deleted. Don't do anything. - */ - - return; - } - interp = textPtr->interp; Tcl_Preserve(interp); diff --git a/macosx/tkMacOSXInt.h b/macosx/tkMacOSXInt.h index 9cb75d2..58761d5 100644 --- a/macosx/tkMacOSXInt.h +++ b/macosx/tkMacOSXInt.h @@ -200,8 +200,6 @@ MODULE_SCOPE void TkpClipDrawableToRect(Display *display, Drawable d, int x, MODULE_SCOPE void TkpRetainRegion(TkRegion r); MODULE_SCOPE void TkpReleaseRegion(TkRegion r); MODULE_SCOPE void TkpShiftButton(NSButton *button, NSPoint delta); -MODULE_SCOPE Bool TkpAppIsDrawing(void); -MODULE_SCOPE void TkpDisplayWindow(Tk_Window tkwin); MODULE_SCOPE Bool TkTestLogDisplay(void); MODULE_SCOPE Bool TkMacOSXInDarkMode(Tk_Window tkwin); diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c index 5063fa3..6602564 100644 --- a/macosx/tkMacOSXSubwindows.c +++ b/macosx/tkMacOSXSubwindows.c @@ -698,16 +698,10 @@ XConfigureWindow( if (value_mask & CWStackMode) { NSView *view = TkMacOSXDrawableView(macWin); - Rect bounds; - NSRect r; if (view) { TkMacOSXInvalClipRgns((Tk_Window) winPtr->parentPtr); - TkMacOSXWinBounds(winPtr, &bounds); - r = NSMakeRect(bounds.left, - [view bounds].size.height - bounds.bottom, - bounds.right - bounds.left, bounds.bottom - bounds.top); - [view setNeedsDisplayInRect:r]; + TkpRedrawWidget((Tk_Window) winPtr); } } diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index cb4ffd1..76b2b04 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -382,26 +382,41 @@ extern NSString *NSWindowDidOrderOffScreenNotification; /* *---------------------------------------------------------------------- * - * TkpAppIsDrawing -- + * TkpAppCanDraw -- * * A widget display procedure can call this to determine whether it is - * being run inside of the drawRect method. This is needed for some tests, - * especially of the Text widget, which record data in a global Tcl - * variable and assume that display procedures will be run in a - * predictable sequence as Tcl idle tasks. + * being run inside of the drawRect method. If not, it may be desirable + * for the display procedure to simply clear the REDRAW_PENDING flag + * and return. The widget can be recorded in order to schedule a + * redraw, via and Expose event, from within drawRect. + * + * This is also needed for some tests, especially of the Text widget, + * which record data in a global Tcl variable and assume that display + * procedures will be run in a predictable sequence as Tcl idle tasks. * * Results: - * True only while running the drawRect method of a TKContentView; + * True if called from the drawRect method of a TKContentView with + * tkwin NULL or pointing to a widget in the current focusView. * * Side effects: - * None + * The tkwin parameter may be recorded to handle redrawing the widget + * later. * *---------------------------------------------------------------------- */ -MODULE_SCOPE Bool -TkpAppIsDrawing(void) { - return [NSApp isDrawing]; +int +TkpAppCanDraw(Tk_Window tkwin) { + if (![NSApp isDrawing]) { + return 0; + } + if (tkwin) { + TkWindow *winPtr = (TkWindow *)tkwin; + NSView *view = TkMacOSXDrawableView(winPtr->privatePtr); + return (view == [NSView focusView]); + } else { + return 1; + } } /* diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index 9117159..cab2b9a 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -6174,28 +6174,40 @@ TkMacOSXMakeRealWindowExist( /* *---------------------------------------------------------------------- * - * TkpDisplayWindow -- + * TkpRedrawWidget -- * - * Mark the contentView of this window as needing display so the window - * will be drawn by the window manager. If this is called within the - * drawRect method, do nothing. + * Mark the bounding rectangle of this widget as needing display so the + * widget will be drawn by [NSView drawRect:]. If this is called within + * the drawRect method, do nothing. * * Results: * None. * * Side effects: - * The window's contentView is marked as needing display. + * The widget's bounding rectangle is marked as dirty. * *---------------------------------------------------------------------- */ -MODULE_SCOPE void -TkpDisplayWindow(Tk_Window tkwin) { - if (![NSApp isDrawing]) { - TkWindow *winPtr = (TkWindow *) tkwin; - NSWindow *w = TkMacOSXDrawableWindow(winPtr->window); +void +TkpRedrawWidget(Tk_Window tkwin) { + TkWindow *winPtr = (TkWindow *) tkwin; + NSWindow *w; + Rect tkBounds; + NSRect bounds; - [[w contentView] setNeedsDisplay: YES]; + if ([NSApp isDrawing]) { + return; + } + w = TkMacOSXDrawableWindow(winPtr->window); + if (w) { + NSView *view = [w contentView]; + TkMacOSXWinBounds(winPtr, &tkBounds); + bounds = NSMakeRect(tkBounds.left, + [view bounds].size.height - tkBounds.bottom, + tkBounds.right - tkBounds.left, + tkBounds.bottom - tkBounds.top); + [view setNeedsDisplayInRect:bounds]; } } diff --git a/unix/tkUnixPort.h b/unix/tkUnixPort.h index 09ff558..8fd56fe 100644 --- a/unix/tkUnixPort.h +++ b/unix/tkUnixPort.h @@ -167,6 +167,8 @@ #define TkpButtonSetDefaults() {} #define TkpDestroyButton(butPtr) {} +#define TkpAppCanDraw(tkwin) 1 +#define TkpRedrawWidget(tkwin) #define TkSelUpdateClipboard(a,b) {} #ifndef __CYGWIN__ #define TkSetPixmapColormap(p,c) {} diff --git a/win/tkWinPort.h b/win/tkWinPort.h index 8cc5677..4ef8680 100644 --- a/win/tkWinPort.h +++ b/win/tkWinPort.h @@ -125,4 +125,11 @@ #define TkpCreateNativeBitmap(display, source) None #define TkpGetNativeAppBitmap(display, name, w, h) None +/* + * Other functions not used under Windows + */ + +#define TkpAppCanDraw(tkwin) 1 +#define TkpRedrawWidget(tkwin) + #endif /* _WINPORT */ -- cgit v0.12 From 8bfe6e9b964fb48650e31fac01c29de41ba63d44 Mon Sep 17 00:00:00 2001 From: culler Date: Sat, 30 May 2020 23:13:52 +0000 Subject: A partly but not completely successful attempt to control how drawRect is run. --- generic/tkCanvas.c | 3 + macosx/tkMacOSXDraw.c | 40 ++++++------- macosx/tkMacOSXNotify.c | 115 ++++++++++++++++++++++++++++++++++--- macosx/tkMacOSXPrivate.h | 9 ++- macosx/tkMacOSXSubwindows.c | 73 ++++++++++++++++++------ macosx/tkMacOSXWindowEvent.c | 133 ++++++++++++++++++++----------------------- macosx/tkMacOSXWm.c | 5 +- 7 files changed, 256 insertions(+), 122 deletions(-) diff --git a/generic/tkCanvas.c b/generic/tkCanvas.c index 4d68ade..941e7d2 100644 --- a/generic/tkCanvas.c +++ b/generic/tkCanvas.c @@ -2577,6 +2577,9 @@ DisplayCanvas( #else canvasPtr->drawableXOrigin = canvasPtr->xOrigin; canvasPtr->drawableYOrigin = canvasPtr->yOrigin; +#if 0 + TkpAppCanDraw(tkwin); +#endif pixmap = Tk_WindowId(tkwin); TkpClipDrawableToRect(Tk_Display(tkwin), pixmap, screenX1 - canvasPtr->xOrigin, screenY1 - canvasPtr->yOrigin, diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index e56e666..d2d72e4 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -174,7 +174,9 @@ TkMacOSXBitmapRepFromDrawableRect( if (cg_image) { CGImageRelease(cg_image); } - } else if ((view = TkMacOSXDrawableView(mac_drawable)) != NULL) { + } else if (TkMacOSXDrawableView(mac_drawable) != NULL) { + TKContentView *tkview = (TKContentView *)view; + /* * Convert Tk top-left to NSView bottom-left coordinates. */ @@ -197,7 +199,8 @@ TkMacOSXBitmapRepFromDrawableRect( [view cacheDisplayInRect:view_rect toBitmapImageRep:bitmap_rep]; } else { TkMacOSXDbgMsg("No CGContext - cannot copy from screen to bitmap."); - [view setNeedsDisplay:YES]; + [tkview setTkNeedsDisplay:YES]; + [tkview setTkDirtyRect:[tkview bounds]]; return NULL; } } else { @@ -1622,7 +1625,7 @@ TkMacOSXSetupDrawingContext( if (dc.context) { dc.portBounds = clipBounds = CGContextGetClipBoundingBox(dc.context); } else if (win) { - NSView *view = TkMacOSXDrawableView(macDraw); + TKContentView *view = (TKContentView *)TkMacOSXDrawableView(macDraw); if (!view) { Tcl_Panic("TkMacOSXSetupDrawingContext(): " @@ -1636,31 +1639,22 @@ TkMacOSXSetupDrawingContext( * tells us whether we are being called from one of those methods. * * If the CGContext is not valid then we mark our view as needing - * display in the bounding rectangle of the clipping region and - * return failure. That rectangle should get drawn in a later call - * to drawRect. - * - * As an exception to the above, if mouse buttons are pressed at the - * moment when we fail to obtain a valid context we schedule the entire - * view for a redraw rather than just the clipping region. The purpose - * of this is to make sure that scrollbars get updated correctly. + * display. We could try to optimize by computing a smaller dirty rect + * here. */ if (![NSApp isDrawing] || view != [NSView focusView]) { - NSRect bounds = [view bounds]; - NSRect dirtyNS = bounds; - if ([NSEvent pressedMouseButtons]) { - [view setNeedsDisplay:YES]; - } else { + NSRect dirtyRect = [view bounds]; + if (dc.clipRgn) { + CGRect clipRect; CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0, - .ty = dirtyNS.size.height}; - if (dc.clipRgn) { - CGRect dirtyCG = NSRectToCGRect(dirtyNS); - HIShapeGetBounds(dc.clipRgn, &dirtyCG); - dirtyNS = NSRectToCGRect(CGRectApplyAffineTransform(dirtyCG, t)); - } - [view setNeedsDisplayInRect:dirtyNS]; + .ty = dirtyRect.size.height}; + HIShapeGetBounds(dc.clipRgn, &clipRect); + clipRect = CGRectApplyAffineTransform(clipRect, t); + dirtyRect = NSRectFromCGRect(clipRect); } + [view setTkNeedsDisplay:YES]; + [view setTkDirtyRect:NSUnionRect([view tkDirtyRect], dirtyRect)]; canDraw = false; goto end; } diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c index 985d7bc..f8ac50d 100644 --- a/macosx/tkMacOSXNotify.c +++ b/macosx/tkMacOSXNotify.c @@ -299,6 +299,70 @@ TkMacOSXNotifyExitHandler( /* *---------------------------------------------------------------------- * + * TkMacOSXDrawAllViews -- + * + * This static function is meant to be run as an idle task. It attempts + * to redraw all views which have the tkNeedsDisplay property set to YES. + * This relies on a feature of [NSApp nextEventMatchingMask: ...] which + * is undocumented, namely that it sometimes blocks and calls drawRect + * for all views that need display before it returns. We call it with + * deQueue=NO so that it will not change anything on the AppKit event + * queue, because we only want the side effect that it runs + * drawRect. This function is the only place where NSViews get the + * needsDisplay property set to YES. + * + * The reason for running this as an idle task is to try to arrange that + * all widgets will be fully configured before they are drawn. Any idle + * tasks that might reconfigure them should be higher on the idle queue, + * so they should be run before the display procs are run by drawRect. + * + * If this is called directly with non-NULL clientData parameter then the + * int which it references will be set to the number of windows that need + * display, but the needsDisplay property of those windows will not be + * changed. + * + * Results: + * None. + * + * Side effects: + * Parts of windows my get redrawn. + * + *---------------------------------------------------------------------- + */ + +static void +TkMacOSXDrawAllViews( + ClientData clientData) +{ + int count = 0, *dirtyCount = (int *)clientData; + + for (NSWindow *window in [NSApp windows]) { + if ([[window contentView] isMemberOfClass:[TKContentView class]]) { + TKContentView *view = [window contentView]; + if ([view tkNeedsDisplay]) { + count++; + if (dirtyCount) { + continue; + } + [view setNeedsDisplayInRect:[view tkDirtyRect]]; + } + } else { + [window displayIfNeeded]; + } + } + if (dirtyCount) { + *dirtyCount = count; + } + + [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantPast] + inMode:GetRunLoopMode(TkMacOSXGetModalSession()) + dequeue:NO]; +} + +/* + *---------------------------------------------------------------------- + * * TkMacOSXEventsSetupProc -- * * This procedure implements the setup part of the MacOSX event source. It @@ -334,11 +398,13 @@ TkMacOSXEventsSetupProc( static const Tcl_Time zeroBlockTime = { 0, 0 }; [NSApp _resetAutoreleasePool]; - /* - * Call this with dequeue=NO -- just checking if the queue is empty. - */ + /* + * Call this with dequeue=NO to see if there are any events. If so, + * we set the block time to 0 and stop the heartbeat. Tcl_DoOneEvent + * will call the check proc to collect the events and translate them + * into XEvents. But also, drawRect may run. + */ - while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} NSEvent *currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] @@ -353,7 +419,7 @@ TkMacOSXEventsSetupProc( } else if (!havePeriodicEvents){ /* - * When the user is not generating events we schedule a "hearbeat" + * When the user is not generating events we schedule a "heartbeat" * event to fire every 0.1 seconds. This helps to make the vwait * command more responsive when there is no user input, e.g. when * running the test suite. @@ -362,6 +428,12 @@ TkMacOSXEventsSetupProc( havePeriodicEvents = YES; [NSEvent startPeriodicEventsAfterDelay:0.0 withPeriod:0.1]; } + + /* + * Without this, new windows are sometimes not completely rendered. + */ + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {} + TkMacOSXDrawAllViews(NULL); } } @@ -388,6 +460,7 @@ TkMacOSXEventsCheckProc( int flags) { NSString *runloopMode = [[NSRunLoop currentRunLoop] currentMode]; + int eventsFound = 0; /* * runloopMode will be nil if we are in a Tcl event loop. @@ -408,7 +481,6 @@ TkMacOSXEventsCheckProc( [NSApp _lockAutoreleasePool]; do { - while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} modalSession = TkMacOSXGetModalSession(); testEvent = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] @@ -422,12 +494,12 @@ TkMacOSXEventsCheckProc( if (testEvent && [[testEvent window] inLiveResize]) { break; } - while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:GetRunLoopMode(modalSession) dequeue:YES]; if (currentEvent) { + /* * Generate Xevents. */ @@ -436,9 +508,12 @@ TkMacOSXEventsCheckProc( NSEvent *processedEvent = [NSApp tkProcessEvent:currentEvent]; Tcl_SetServiceMode(oldServiceMode); if (processedEvent) { + eventsFound++; + #ifdef TK_MAC_DEBUG_EVENTS TKLog(@" event: %@", currentEvent); #endif + if (modalSession) { [NSApp _modalSession:modalSession sendEvent:currentEvent]; } else { @@ -446,6 +521,7 @@ TkMacOSXEventsCheckProc( } } } else { + break; } } while (1); @@ -453,8 +529,31 @@ TkMacOSXEventsCheckProc( /* * Now we can unlock the pool. */ - [NSApp _unlockAutoreleasePool]; + + if (eventsFound == 0) { + + /* + * We found no events for Tcl in this iteration of the Tcl event + * loop, so it should proceed to servicing idle tasks. We add an + * idle task to the end of the idle queue which will redisplay all + * of our dirty windows. We want this to happen after all other + * idle tasks have run so that all widgets will be configured + * before they are displayed. The drawRect method "borrows" the + * idle queue while drawing views. That is, it sends expose events + * which cause display procs to be posted as idle tasks and then + * runs an inner event loop to processes those idle tasks. We are + * trying to arrange for the idle queue to be empty when it starts + * that process and empty when it finishes. + */ + + int dirtyCount = 0; + TkMacOSXDrawAllViews(&dirtyCount); + if (dirtyCount > 0) { + Tcl_CancelIdleCall(TkMacOSXDrawAllViews, NULL); + Tcl_DoWhenIdle(TkMacOSXDrawAllViews, NULL); + } + } } } diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h index be69fcd..fdd07ed 100644 --- a/macosx/tkMacOSXPrivate.h +++ b/macosx/tkMacOSXPrivate.h @@ -307,6 +307,8 @@ MODULE_SCOPE int TkMacOSXRegisterServiceWidgetObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE unsigned TkMacOSXAddVirtual(unsigned int keycode); +MODULE_SCOPE void TkMacOSXWinNSBounds(TkWindow *winPtr, NSView *view, + NSRect *bounds); #pragma mark Private Objective-C Classes @@ -418,8 +420,12 @@ VISIBILITY_HIDDEN @private NSString *privateWorkingText; Bool _needsRedisplay; + Bool _tkNeedsDisplay; + NSRect _tkDirtyRect; } @property Bool needsRedisplay; +@property Bool tkNeedsDisplay; +@property NSRect tkDirtyRect; @end @interface TKContentView(TKKeyEvent) @@ -428,7 +434,8 @@ VISIBILITY_HIDDEN @end @interface TKContentView(TKWindowEvent) -- (void) generateExposeEvents: (HIShapeRef) shape; + //(HIShapeRef) shape; +- (void) generateExposeEvents: (NSRect) rect; - (void) tkToolbarButton: (id) sender; @end diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c index 6602564..53e5bf6 100644 --- a/macosx/tkMacOSXSubwindows.c +++ b/macosx/tkMacOSXSubwindows.c @@ -157,6 +157,7 @@ XMapWindow( winPtr->flags |= TK_MAPPED; if (Tk_IsTopLevel(winPtr)) { if (!Tk_IsEmbedded(winPtr)) { + TKContentView *view = [win contentView]; /* * We want to activate Tk when a toplevel is mapped but we must not @@ -169,7 +170,8 @@ XMapWindow( TkMacOSXApplyWindowAttributes(winPtr, win); [win setExcludedFromWindowsMenu:NO]; [NSApp activateIgnoringOtherApps:NO]; - [[win contentView] setNeedsDisplay:YES]; + [view setTkNeedsDisplay:YES]; + [view setTkDirtyRect: [view bounds]]; if ([win canBecomeKeyWindow]) { [win makeKeyAndOrderFront:NSApp]; } else { @@ -215,7 +217,9 @@ XMapWindow( if ([NSApp isDrawing]) { [[win contentView] setNeedsRedisplay:YES]; } else { - [[win contentView] setNeedsDisplay:YES]; + TKContentView *view = [win contentView]; + [view setTkNeedsDisplay:YES]; + [view setTkDirtyRect:[view bounds]]; } /* @@ -332,7 +336,9 @@ XUnmapWindow( if ([NSApp isDrawing]) { [[win contentView] setNeedsRedisplay:YES]; } else { - [[win contentView] setNeedsDisplay:YES]; + TKContentView *view = [win contentView]; + [view setTkNeedsDisplay:YES]; + [view setTkDirtyRect:[view bounds]]; } return Success; } @@ -986,8 +992,9 @@ InvalViewRect( void *ref) { static CGAffineTransform t; - NSView *view = ref; - + TKContentView *view = ref; + NSRect dirtyRect; + if (!view) { return paramErr; } @@ -997,8 +1004,9 @@ InvalViewRect( NSHeight([view bounds])); break; case kHIShapeEnumerateRect: - [view setNeedsDisplayInRect:NSRectFromCGRect( - CGRectApplyAffineTransform(*rect, t))]; + dirtyRect = NSRectFromCGRect(CGRectApplyAffineTransform(*rect, t)); + [view setTkNeedsDisplay:YES]; + [view setTkDirtyRect:NSUnionRect([view tkDirtyRect], dirtyRect)]; break; } return noErr; @@ -1275,16 +1283,15 @@ TkMacOSXInvalClipRgns( * * TkMacOSXWinBounds -- * - * Given a Tk window this function determines the windows bounds in - * relation to the Macintosh window's coordinate system. This is also the - * same coordinate system as the Tk toplevel window in which this window - * is contained. + * Given a Tk window this function determines the window's bounds in + * the coordinate system of the Tk toplevel window in which this window + * is contained. This fills in a Rect struct. * * Results: * None. * * Side effects: - * None. + * Fills in a Rect. * *---------------------------------------------------------------------- */ @@ -1307,16 +1314,15 @@ TkMacOSXWinBounds( * * TkMacOSXWinCGBounds -- * - * Given a Tk window this function determines the windows bounds in - * relation to the Macintosh window's coordinate system. This is also the - * same coordinate system as the Tk toplevel window in which this window - * is contained. + * Given a Tk window this function determines the window's bounds in + * the coordinate system of the Tk toplevel window in which this window + * is contained. This fills in a CGRect struct. * * Results: * None. * * Side effects: - * None. + * Fill in a CGRect. * *---------------------------------------------------------------------- */ @@ -1331,6 +1337,39 @@ TkMacOSXWinCGBounds( bounds->size.width = winPtr->changes.width; bounds->size.height = winPtr->changes.height; } +/* + *---------------------------------------------------------------------- + * + * TkMacOSXWinNSBounds -- + * + * Given a Tk window this function determines the window's bounds in + * the coordinate system of the TKContentView in which this Tk window + * is contained, which has the origin at the lower left corner. This + * fills in an NSRect struct and requires the TKContentView as a + * parameter + * + * Results: + * None. + * + * Side effects: + * Fills in an NSRect. + * + *---------------------------------------------------------------------- + */ + +void +TkMacOSXWinNSBounds( + TkWindow *winPtr, + NSView *view, + NSRect *bounds) +{ + bounds->size.width = winPtr->changes.width; + bounds->size.height = winPtr->changes.height; + bounds->origin.x = winPtr->privatePtr->xOff; + bounds->origin.y = ([view bounds].size.height - + bounds->size.height - + winPtr->privatePtr->yOff); +} /* *---------------------------------------------------------------------- diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 76b2b04..6e8f7c4 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -30,8 +30,8 @@ * Declaration of functions used only in this file */ -static int GenerateUpdates(HIShapeRef updateRgn, - CGRect *updateBounds, TkWindow *winPtr); +static int GenerateUpdates( + CGRect *updateBounds, TkWindow *winPtr); static int GenerateActivateEvents(TkWindow *winPtr, int activeFlag); static void DoWindowActivate(ClientData clientData); @@ -407,16 +407,29 @@ extern NSString *NSWindowDidOrderOffScreenNotification; int TkpAppCanDraw(Tk_Window tkwin) { - if (![NSApp isDrawing]) { - return 0; - } + int result; if (tkwin) { TkWindow *winPtr = (TkWindow *)tkwin; - NSView *view = TkMacOSXDrawableView(winPtr->privatePtr); - return (view == [NSView focusView]); + TKContentView *view = (TKContentView *) TkMacOSXDrawableView( + winPtr->privatePtr); + result = ([NSApp isDrawing] && view == [NSView focusView]); +#if 0 + printf("TkAppCanDraw: %s %d %d \n", Tk_PathName(tkwin), + [NSApp isDrawing], (view == [NSView focusView])); + if (!result) { + NSRect dirtyRect; + TkMacOSXWinNSBounds(winPtr, view, &dirtyRect); + printf("TkpAppCanDraw: dirtyRect for %s is %s\n", + Tk_PathName(tkwin), + NSStringFromRect(dirtyRect).UTF8String); + [view setTkNeedsDisplay:YES]; + [view setTkDirtyRect:dirtyRect]; + } +#endif } else { - return 1; + result = [NSApp isDrawing]; } + return result; } /* @@ -424,9 +437,9 @@ TkpAppCanDraw(Tk_Window tkwin) { * * GenerateUpdates -- * - * Given a Macintosh update region and a Tk window this function geneates + * Given an update rectangle and a Tk window, this function geneates * an X Expose event for the window if it meets the update region. The - * function will then recursivly have each damaged window generate Expose + * function will then recursively have each damaged window generate Expose * events for its child windows. * * Results: @@ -440,39 +453,23 @@ TkpAppCanDraw(Tk_Window tkwin) { static int GenerateUpdates( - HIShapeRef updateRgn, CGRect *updateBounds, TkWindow *winPtr) { TkWindow *childPtr; XEvent event; CGRect bounds, damageBounds; - HIShapeRef boundsRgn, damageRgn; TkMacOSXWinCGBounds(winPtr, &bounds); if (!CGRectIntersectsRect(bounds, *updateBounds)) { return 0; } - if (!HIShapeIntersectsRect(updateRgn, &bounds)) { - return 0; - } /* * Compute the bounding box of the area that the damage occured in. */ - boundsRgn = HIShapeCreateWithRect(&bounds); - damageRgn = HIShapeCreateIntersection(updateRgn, boundsRgn); - if (HIShapeIsEmpty(damageRgn)) { - CFRelease(damageRgn); - CFRelease(boundsRgn); - return 0; - } - HIShapeGetBounds(damageRgn, &damageBounds); - - CFRelease(damageRgn); - CFRelease(boundsRgn); - + damageBounds = CGRectIntersection(bounds, *updateBounds); event.xany.serial = LastKnownRequestProcessed(Tk_Display(winPtr)); event.xany.send_event = false; event.xany.window = Tk_WindowId(winPtr); @@ -486,7 +483,7 @@ GenerateUpdates( Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); #ifdef TK_MAC_DEBUG_DRAWING - TKLog(@"Expose %p {{%d, %d}, {%d, %d}}", event.xany.window, event.xexpose.x, + TKLog(@"Exposed %p {{%d, %d}, {%d, %d}}", event.xany.window, event.xexpose.x, event.xexpose.y, event.xexpose.width, event.xexpose.height); #endif @@ -499,7 +496,7 @@ GenerateUpdates( if (!Tk_IsMapped(childPtr) || Tk_IsTopLevel(childPtr)) { continue; } - GenerateUpdates(updateRgn, updateBounds, childPtr); + GenerateUpdates(updateBounds, childPtr); } /* @@ -509,7 +506,7 @@ GenerateUpdates( if (Tk_IsContainer(winPtr)) { childPtr = TkpGetOtherWindow(winPtr); if (childPtr != NULL && Tk_IsMapped(childPtr)) { - GenerateUpdates(updateRgn, updateBounds, childPtr); + GenerateUpdates(updateBounds, childPtr); } /* @@ -928,10 +925,10 @@ ConfigureRestrictProc( */ static void -RedisplayView( +RedisplayView( ClientData clientdata) { - NSView *view = (NSView *) clientdata; + TKContentView *view = (TKContentView *) clientdata; /* * Make sure that we are not trying to displaying a view that no longer @@ -941,7 +938,8 @@ RedisplayView( for (NSWindow *w in [NSApp windows]) { if ([w contentView] == view) { - [view setNeedsDisplay:YES]; + [view setTkNeedsDisplay:YES]; + [view setTkDirtyRect:[view bounds]]; break; } } @@ -951,13 +949,13 @@ RedisplayView( - (void) drawRect: (NSRect) rect { - const NSRect *rectsBeingDrawn; - NSInteger rectsBeingDrawnCount; #ifdef TK_MAC_DEBUG_DRAWING TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); - if (winPtr) fprintf(stderr, "drawRect: drawing %s\n", - Tk_PathName(winPtr)); + if (winPtr) { + fprintf(stderr, "drawRect: drawing %s in %s\n", + Tk_PathName(winPtr), NSStringFromRect(rect).UTF8String); + } #endif /* @@ -974,23 +972,11 @@ RedisplayView( [NSApp setIsDrawing: YES]; - [self getRectsBeingDrawn:&rectsBeingDrawn count:&rectsBeingDrawnCount]; - CGFloat height = [self bounds].size.height; - HIMutableShapeRef drawShape = HIShapeCreateMutable(); - - while (rectsBeingDrawnCount--) { - CGRect r = NSRectToCGRect(*rectsBeingDrawn++); - #ifdef TK_MAC_DEBUG_DRAWING - fprintf(stderr, "drawRect: %dx%d@(%d,%d)\n", (int)r.size.width, - (int)r.size.height, (int)r.origin.x, (int)r.origin.y); + fprintf(stderr, "drawRect: %s\n", NSStringFromRect(rect).UTF8String; #endif - r.origin.y = height - (r.origin.y + r.size.height); - HIShapeUnionWithRect(drawShape, &r); - } - [self generateExposeEvents:(HIShapeRef)drawShape]; - CFRelease(drawShape); + [self generateExposeEvents:rect]; [NSApp setIsDrawing: NO]; if ([self needsRedisplay]) { @@ -998,6 +984,9 @@ RedisplayView( Tcl_DoWhenIdle(RedisplayView, self); } + [self setTkNeedsDisplay:NO]; + [self setTkDirtyRect:NSZeroRect]; + #ifdef TK_MAC_DEBUG_DRAWING fprintf(stderr, "drawRect: done.\n"); #endif @@ -1056,9 +1045,7 @@ RedisplayView( * Generate and process expose events to redraw the window. */ - HIRect bounds = NSRectToCGRect([self bounds]); - HIShapeRef shape = HIShapeCreateWithRect(&bounds); - [self generateExposeEvents: shape]; + [self generateExposeEvents: [self bounds]]; [w displayIfNeeded]; /* @@ -1076,11 +1063,11 @@ RedisplayView( * pending idle events are processed so the drawing will actually take place. */ -- (void) generateExposeEvents: (HIShapeRef) shape +- (void) generateExposeEvents: (NSRect) rect { unsigned long serial; - CGRect updateBounds; int updatesNeeded; + CGRect updateBounds; TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); ClientData oldArg; Tk_RestrictProc *oldProc; @@ -1089,20 +1076,18 @@ RedisplayView( } /* - * Generate Tk Expose events. - */ - - HIShapeGetBounds(shape, &updateBounds); - - /* - * All of these events will share the same serial number. + * Generate Tk Expose events. All of these events will share the same + * serial number. */ - - serial = LastKnownRequestProcessed(Tk_Display(winPtr)); - updatesNeeded = GenerateUpdates(shape, &updateBounds, winPtr); - + + updateBounds = NSRectToCGRect(rect); + updateBounds.origin.y = ([self bounds].size.height - updateBounds.origin.y + - updateBounds.size.height); + updatesNeeded = GenerateUpdates(&updateBounds, winPtr); if (updatesNeeded) { + serial = LastKnownRequestProcessed(Tk_Display(winPtr)); + /* * First process all of the Expose events. */ @@ -1120,9 +1105,10 @@ RedisplayView( * effect.) * * Fortunately, Tk schedules all drawing to be done while Tcl is idle. - * So we can do the drawing by processing all of the idle events that - * were created when the expose events were processed. + * So we can do the drawing now by processing all of the idle events + * that were created when the expose events were processed. */ + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {} } } @@ -1202,10 +1188,15 @@ RedisplayView( - (BOOL) isOpaque { NSWindow *w = [self window]; - return (w && (([w styleMask] & NSTexturedBackgroundWindowMask) || - ![w isOpaque]) ? NO : YES); + return (w && (([w styleMask] & NSTexturedBackgroundWindowMask) || + ![w isOpaque]) ? NO : YES); } +/* + * On Catalina this is never called and drawRect clips to the rect that + * is passed to it by AppKit. + */ + - (BOOL) wantsDefaultClipping { return NO; diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index cab2b9a..1b51479 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -6201,13 +6201,14 @@ TkpRedrawWidget(Tk_Window tkwin) { } w = TkMacOSXDrawableWindow(winPtr->window); if (w) { - NSView *view = [w contentView]; + TKContentView *view = [w contentView]; TkMacOSXWinBounds(winPtr, &tkBounds); bounds = NSMakeRect(tkBounds.left, [view bounds].size.height - tkBounds.bottom, tkBounds.right - tkBounds.left, tkBounds.bottom - tkBounds.top); - [view setNeedsDisplayInRect:bounds]; + [view setTkNeedsDisplay:YES]; + [view setTkDirtyRect:bounds]; } } -- cgit v0.12 From 4d6ace7f224a40a423390fa6c0bb3c39d4162313 Mon Sep 17 00:00:00 2001 From: culler Date: Sun, 31 May 2020 17:21:57 +0000 Subject: Rename Aqua stub TkpAppCanDraw as TkpWillDrawWidget --- generic/tkFont.c | 2 +- generic/tkInt.decls | 2 +- generic/tkIntDecls.h | 8 ++++---- generic/tkStubInit.c | 2 +- generic/tkTextDisp.c | 4 ++-- macosx/tkMacOSXWindowEvent.c | 4 ++-- unix/tkUnixPort.h | 2 +- win/tkWinPort.h | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/generic/tkFont.c b/generic/tkFont.c index 448f918..e53e3f9 100644 --- a/generic/tkFont.c +++ b/generic/tkFont.c @@ -880,7 +880,7 @@ TheWorldHasChanged( * This is ignored on other platforms. */ - if (TkpAppCanDraw(NULL)) { + if (!TkpWillDrawWidget(NULL)) { return; } diff --git a/generic/tkInt.decls b/generic/tkInt.decls index da591cb..f6e7ea9 100644 --- a/generic/tkInt.decls +++ b/generic/tkInt.decls @@ -640,7 +640,7 @@ declare 185 aqua { void TkpRedrawWidget(Tk_Window tkwin) } declare 186 aqua { - int TkpAppCanDraw(Tk_Window tkwin) + int TkpWillDrawWidget(Tk_Window tkwin) } diff --git a/generic/tkIntDecls.h b/generic/tkIntDecls.h index 7bf9bd7..1344cc6 100644 --- a/generic/tkIntDecls.h +++ b/generic/tkIntDecls.h @@ -556,7 +556,7 @@ EXTERN void TkpRedrawWidget(Tk_Window tkwin); #endif /* AQUA */ #ifdef MAC_OSX_TK /* AQUA */ /* 186 */ -EXTERN int TkpAppCanDraw(Tk_Window tkwin); +EXTERN int TkpWillDrawWidget(Tk_Window tkwin); #endif /* AQUA */ typedef struct TkIntStubs { @@ -793,7 +793,7 @@ typedef struct TkIntStubs { #endif /* WIN */ #ifdef MAC_OSX_TK /* AQUA */ void (*reserved186)(void); /* Dummy entry for stubs table backwards compatibility */ - int (*tkpAppCanDraw) (Tk_Window tkwin); /* 186 */ + int (*tkpWillDrawWidget) (Tk_Window tkwin); /* 186 */ #endif /* AQUA */ } TkIntStubs; @@ -1172,8 +1172,8 @@ extern const TkIntStubs *tkIntStubsPtr; (tkIntStubsPtr->tkpRedrawWidget) /* 185 */ #endif /* AQUA */ #ifdef MAC_OSX_TK /* AQUA */ -#define TkpAppCanDraw \ - (tkIntStubsPtr->tkpAppCanDraw) /* 186 */ +#define TkpWillDrawWidget \ + (tkIntStubsPtr->tkpWillDrawWidget) /* 186 */ #endif /* AQUA */ #endif /* defined(USE_TK_STUBS) */ diff --git a/generic/tkStubInit.c b/generic/tkStubInit.c index 045c86e..4abc637 100644 --- a/generic/tkStubInit.c +++ b/generic/tkStubInit.c @@ -503,7 +503,7 @@ static const TkIntStubs tkIntStubs = { #endif /* WIN */ #ifdef MAC_OSX_TK /* AQUA */ 0, /* 186 */ /* Dummy entry for stubs table backwards compatibility */ - TkpAppCanDraw, /* 186 */ + TkpWillDrawWidget, /* 186 */ #endif /* AQUA */ }; diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index 084fd64..2deeaf2 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -22,7 +22,7 @@ #include "tkUnixInt.h" #elif defined(MAC_OSX_TK) #include "tkMacOSXInt.h" -#define OK_TO_LOG (!TkpAppCanDraw(textPtr->tkwin)) +#define OK_TO_LOG (!TkpWillDrawWidget(textPtr->tkwin)) #endif #if !defined(MAC_OSX_TK) @@ -4174,7 +4174,7 @@ DisplayText( * warnings. */ Tcl_Interp *interp; - + if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { /* * The widget has been deleted. Don't do anything. diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 76b2b04..ee49541 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -382,7 +382,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification; /* *---------------------------------------------------------------------- * - * TkpAppCanDraw -- + * TkpWillDrawWidget -- * * A widget display procedure can call this to determine whether it is * being run inside of the drawRect method. If not, it may be desirable @@ -406,7 +406,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification; */ int -TkpAppCanDraw(Tk_Window tkwin) { +TkpWillDrawWidget(Tk_Window tkwin) { if (![NSApp isDrawing]) { return 0; } diff --git a/unix/tkUnixPort.h b/unix/tkUnixPort.h index 8fd56fe..491a339 100644 --- a/unix/tkUnixPort.h +++ b/unix/tkUnixPort.h @@ -167,7 +167,7 @@ #define TkpButtonSetDefaults() {} #define TkpDestroyButton(butPtr) {} -#define TkpAppCanDraw(tkwin) 1 +#define TkpWillDrawWidget(tkwin) 1 #define TkpRedrawWidget(tkwin) #define TkSelUpdateClipboard(a,b) {} #ifndef __CYGWIN__ diff --git a/win/tkWinPort.h b/win/tkWinPort.h index 4ef8680..dbde9e1 100644 --- a/win/tkWinPort.h +++ b/win/tkWinPort.h @@ -129,7 +129,7 @@ * Other functions not used under Windows */ -#define TkpAppCanDraw(tkwin) 1 +#define TkpWillDrawWidget(tkwin) 1 #define TkpRedrawWidget(tkwin) #endif /* _WINPORT */ -- cgit v0.12 From 11b02278eef59eb2b8412727e92256477ea6188b Mon Sep 17 00:00:00 2001 From: culler Date: Sun, 31 May 2020 21:19:29 +0000 Subject: Add some methods for managing damage rectangles. --- generic/tkCanvas.c | 3 --- macosx/tkMacOSXDraw.c | 10 ++++------ macosx/tkMacOSXPrivate.h | 3 ++- macosx/tkMacOSXSubwindows.c | 5 ++--- macosx/tkMacOSXWindowEvent.c | 23 +++++++++++++++++------ 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/generic/tkCanvas.c b/generic/tkCanvas.c index 941e7d2..4d68ade 100644 --- a/generic/tkCanvas.c +++ b/generic/tkCanvas.c @@ -2577,9 +2577,6 @@ DisplayCanvas( #else canvasPtr->drawableXOrigin = canvasPtr->xOrigin; canvasPtr->drawableYOrigin = canvasPtr->yOrigin; -#if 0 - TkpAppCanDraw(tkwin); -#endif pixmap = Tk_WindowId(tkwin); TkpClipDrawableToRect(Tk_Display(tkwin), pixmap, screenX1 - canvasPtr->xOrigin, screenY1 - canvasPtr->yOrigin, diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index d2d72e4..dcc3d79 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -1646,15 +1646,13 @@ TkMacOSXSetupDrawingContext( if (![NSApp isDrawing] || view != [NSView focusView]) { NSRect dirtyRect = [view bounds]; if (dc.clipRgn) { - CGRect clipRect; CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0, .ty = dirtyRect.size.height}; - HIShapeGetBounds(dc.clipRgn, &clipRect); - clipRect = CGRectApplyAffineTransform(clipRect, t); - dirtyRect = NSRectFromCGRect(clipRect); + HIShapeGetBounds(dc.clipRgn, &clipBounds); + clipBounds = CGRectApplyAffineTransform(clipBounds, t); + dirtyRect = NSRectFromCGRect(clipBounds); } - [view setTkNeedsDisplay:YES]; - [view setTkDirtyRect:NSUnionRect([view tkDirtyRect], dirtyRect)]; + [view addTkDirtyRect:dirtyRect]; canDraw = false; goto end; } diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h index fdd07ed..11dee7c 100644 --- a/macosx/tkMacOSXPrivate.h +++ b/macosx/tkMacOSXPrivate.h @@ -434,7 +434,8 @@ VISIBILITY_HIDDEN @end @interface TKContentView(TKWindowEvent) - //(HIShapeRef) shape; +- (void) addTkDirtyRect: (NSRect) rect; +- (void) clearTkDirtyRect; - (void) generateExposeEvents: (NSRect) rect; - (void) tkToolbarButton: (id) sender; @end diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c index 53e5bf6..c25f600 100644 --- a/macosx/tkMacOSXSubwindows.c +++ b/macosx/tkMacOSXSubwindows.c @@ -994,7 +994,7 @@ InvalViewRect( static CGAffineTransform t; TKContentView *view = ref; NSRect dirtyRect; - + if (!view) { return paramErr; } @@ -1005,8 +1005,7 @@ InvalViewRect( break; case kHIShapeEnumerateRect: dirtyRect = NSRectFromCGRect(CGRectApplyAffineTransform(*rect, t)); - [view setTkNeedsDisplay:YES]; - [view setTkDirtyRect:NSUnionRect([view tkDirtyRect], dirtyRect)]; + [view addTkDirtyRect:dirtyRect]; break; } return noErr; diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 5619454..6c7e9ff 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -399,8 +399,8 @@ extern NSString *NSWindowDidOrderOffScreenNotification; * tkwin NULL or pointing to a widget in the current focusView. * * Side effects: - * The tkwin parameter may be recorded to handle redrawing the widget - * later. + * Currently none. One day the tkwin parameter may be recorded to + * handle redrawing the widget later. * *---------------------------------------------------------------------- */ @@ -925,7 +925,7 @@ ConfigureRestrictProc( */ static void -RedisplayView( +RedisplayView( ClientData clientdata) { TKContentView *view = (TKContentView *) clientdata; @@ -947,6 +947,18 @@ RedisplayView( @implementation TKContentView(TKWindowEvent) +- (void) addTkDirtyRect: (NSRect) rect +{ + _tkNeedsDisplay = YES; + _tkDirtyRect = NSUnionRect(_tkDirtyRect, rect); +} + +- (void) clearTkDirtyRect +{ + _tkNeedsDisplay = NO; + _tkDirtyRect = NSZeroRect; +} + - (void) drawRect: (NSRect) rect { @@ -984,8 +996,7 @@ RedisplayView( Tcl_DoWhenIdle(RedisplayView, self); } - [self setTkNeedsDisplay:NO]; - [self setTkDirtyRect:NSZeroRect]; + [self clearTkDirtyRect]; #ifdef TK_MAC_DEBUG_DRAWING fprintf(stderr, "drawRect: done.\n"); @@ -1079,7 +1090,7 @@ RedisplayView( * Generate Tk Expose events. All of these events will share the same * serial number. */ - + updateBounds = NSRectToCGRect(rect); updateBounds.origin.y = ([self bounds].size.height - updateBounds.origin.y - updateBounds.size.height); -- cgit v0.12 From aeb89ef62c14b00be0853a7539e807bb3937a6f8 Mon Sep 17 00:00:00 2001 From: culler Date: Mon, 1 Jun 2020 21:34:36 +0000 Subject: Better control over when drawRect runs. Add check for drawing outside of the drawRect clipping rectangle. --- generic/tkFont.c | 2 +- macosx/tkMacOSXDraw.c | 55 +++++++++++++++++++++++------------ macosx/tkMacOSXNotify.c | 68 ++++++++++++++++++++++++++------------------ macosx/tkMacOSXPrivate.h | 1 + macosx/tkMacOSXWindowEvent.c | 40 ++++---------------------- tests/canvImg.test | 8 +----- tests/image.test | 17 ++--------- tests/listbox.test | 4 +-- 8 files changed, 90 insertions(+), 105 deletions(-) diff --git a/generic/tkFont.c b/generic/tkFont.c index e53e3f9..17e0aa9 100644 --- a/generic/tkFont.c +++ b/generic/tkFont.c @@ -880,7 +880,7 @@ TheWorldHasChanged( * This is ignored on other platforms. */ - if (!TkpWillDrawWidget(NULL)) { + if (TkpWillDrawWidget(NULL)) { return; } diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index dcc3d79..1ec2cfe 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -1631,30 +1631,47 @@ TkMacOSXSetupDrawingContext( Tcl_Panic("TkMacOSXSetupDrawingContext(): " "no NSView to draw into !"); } + if (dc.clipRgn) { + CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0, + .ty = [view bounds].size.height}; + HIShapeGetBounds(dc.clipRgn, &clipBounds); + clipBounds = CGRectApplyAffineTransform(clipBounds, t); + } + if (![NSApp isDrawing] || view != [NSView focusView]) { - /* - * We can only draw into the view when the current CGContext is valid - * and belongs to the view. Validity can only be guaranteed inside of - * a view's drawRect or setFrame methods. The isDrawing attribute - * tells us whether we are being called from one of those methods. - * - * If the CGContext is not valid then we mark our view as needing - * display. We could try to optimize by computing a smaller dirty rect - * here. - */ + /* + * We can only draw into the view when the current CGContext is + * valid and belongs to the view. Validity can only be guaranteed + * inside of a view's drawRect or setFrame methods. The isDrawing + * attribute tells us whether we are being called from one of those + * methods. If the CGContext is not valid then we mark our view as + * needing display. + */ - if (![NSApp isDrawing] || view != [NSView focusView]) { - NSRect dirtyRect = [view bounds]; if (dc.clipRgn) { - CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0, - .ty = dirtyRect.size.height}; - HIShapeGetBounds(dc.clipRgn, &clipBounds); - clipBounds = CGRectApplyAffineTransform(clipBounds, t); - dirtyRect = NSRectFromCGRect(clipBounds); + [view addTkDirtyRect:clipBounds]; + } else { + [view addTkDirtyRect:[view bounds]]; } - [view addTkDirtyRect:dirtyRect]; canDraw = false; goto end; + } else if (dc.clipRgn) { + + /* + * Drawing can also fail when we are being called from drawRect but + * the clipping region set by drawRect does not contain the clipping + * region of our drawing context. See bug [2a61eca3a8]. + */ + + CGRect currentClip = CGContextGetClipBoundingBox( + [NSGraphicsContext currentContext].CGContext); + if (!NSContainsRect(currentClip, clipBounds)) { + [view addTkDirtyRect:clipBounds]; + // XXXX we should be able to skip drawing but sometimes the clipBounds + // are wrong. + //canDraw = false; + //goto end; + } } dc.view = view; @@ -1686,6 +1703,7 @@ TkMacOSXSetupDrawingContext( CGContextSetTextDrawingMode(dc.context, kCGTextFill); CGContextConcatCTM(dc.context, t); if (dc.clipRgn) { + #ifdef TK_MAC_DEBUG_DRAWING CGContextSaveGState(dc.context); ChkErr(HIShapeReplacePathInCGContext, dc.clipRgn, dc.context); @@ -1693,6 +1711,7 @@ TkMacOSXSetupDrawingContext( CGContextEOFillPath(dc.context); CGContextRestoreGState(dc.context); #endif /* TK_MAC_DEBUG_DRAWING */ + CGRect r; if (!HIShapeIsRectangular(dc.clipRgn) || !CGRectContainsRect( diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c index f8ac50d..7de6bec 100644 --- a/macosx/tkMacOSXNotify.c +++ b/macosx/tkMacOSXNotify.c @@ -307,19 +307,20 @@ TkMacOSXNotifyExitHandler( * is undocumented, namely that it sometimes blocks and calls drawRect * for all views that need display before it returns. We call it with * deQueue=NO so that it will not change anything on the AppKit event - * queue, because we only want the side effect that it runs - * drawRect. This function is the only place where NSViews get the - * needsDisplay property set to YES. + * queue, because we only want the side effect that it runs drawRect. The + * only time when any NSViews have the needsDisplay property set to YES + * is during execution of this function. * - * The reason for running this as an idle task is to try to arrange that - * all widgets will be fully configured before they are drawn. Any idle - * tasks that might reconfigure them should be higher on the idle queue, - * so they should be run before the display procs are run by drawRect. + * The reason for running this function as an idle task is to try to + * arrange that all widgets will be fully configured before they are + * drawn. Any idle tasks that might reconfigure them should be higher on + * the idle queue, so they should be run before the display procs are run + * by drawRect. * - * If this is called directly with non-NULL clientData parameter then the - * int which it references will be set to the number of windows that need - * display, but the needsDisplay property of those windows will not be - * changed. + * If this function is called directly with non-NULL clientData parameter + * then the int which it references will be set to the number of windows + * that need display, but the needsDisplay property of those windows will + * not be changed. * * Results: * None. @@ -330,11 +331,11 @@ TkMacOSXNotifyExitHandler( *---------------------------------------------------------------------- */ -static void +void TkMacOSXDrawAllViews( ClientData clientData) { - int count = 0, *dirtyCount = (int *)clientData; + int count = 0, *dirtyCount = (int *)clientData; for (NSWindow *window in [NSApp windows]) { if ([[window contentView] isMemberOfClass:[TKContentView class]]) { @@ -342,22 +343,37 @@ TkMacOSXDrawAllViews( if ([view tkNeedsDisplay]) { count++; if (dirtyCount) { - continue; + continue; } [view setNeedsDisplayInRect:[view tkDirtyRect]]; + [view setTkDirtyRect:NSZeroRect]; } } else { [window displayIfNeeded]; } } if (dirtyCount) { - *dirtyCount = count; + *dirtyCount = count; } - [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:GetRunLoopMode(TkMacOSXGetModalSession()) dequeue:NO]; + for (NSWindow *window in [NSApp windows]) { + if ([[window contentView] isMemberOfClass:[TKContentView class]]) { + TKContentView *view = [window contentView]; + + /* + * If we did not run drawRect, we set needsDisplay back to NO. + * Note that if drawRect did run it may have added to Tk's dirty + * rect, due to attempts to draw outside of drawRect's dirty rect. + */ + + if ([view tkNeedsDisplay]) { + [view setNeedsDisplay: NO]; + } + } + } } /* @@ -399,10 +415,11 @@ TkMacOSXEventsSetupProc( [NSApp _resetAutoreleasePool]; /* - * Call this with dequeue=NO to see if there are any events. If so, - * we set the block time to 0 and stop the heartbeat. Tcl_DoOneEvent - * will call the check proc to collect the events and translate them - * into XEvents. But also, drawRect may run. + * Call this with dequeue=NO to see if there are any events. If so, we + * set the block time to 0 and stop the heartbeat. Next Tcl_DoOneEvent + * will call Tcl_WaitForEvent, which will poll instead of waiting since + * the block time is 0. Then it will call check proc to collect the + * events and translate them into XEvents. */ NSEvent *currentEvent = @@ -428,11 +445,7 @@ TkMacOSXEventsSetupProc( havePeriodicEvents = YES; [NSEvent startPeriodicEventsAfterDelay:0.0 withPeriod:0.1]; } - - /* - * Without this, new windows are sometimes not completely rendered. - */ - while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {} + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {}; TkMacOSXDrawAllViews(NULL); } } @@ -521,7 +534,6 @@ TkMacOSXEventsCheckProc( } } } else { - break; } } while (1); @@ -529,8 +541,8 @@ TkMacOSXEventsCheckProc( /* * Now we can unlock the pool. */ - [NSApp _unlockAutoreleasePool]; + [NSApp _unlockAutoreleasePool]; if (eventsFound == 0) { /* @@ -552,7 +564,7 @@ TkMacOSXEventsCheckProc( if (dirtyCount > 0) { Tcl_CancelIdleCall(TkMacOSXDrawAllViews, NULL); Tcl_DoWhenIdle(TkMacOSXDrawAllViews, NULL); - } + } } } } diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h index 11dee7c..719b0b1 100644 --- a/macosx/tkMacOSXPrivate.h +++ b/macosx/tkMacOSXPrivate.h @@ -309,6 +309,7 @@ MODULE_SCOPE int TkMacOSXRegisterServiceWidgetObjCmd(ClientData clientData, MODULE_SCOPE unsigned TkMacOSXAddVirtual(unsigned int keycode); MODULE_SCOPE void TkMacOSXWinNSBounds(TkWindow *winPtr, NSView *view, NSRect *bounds); +MODULE_SCOPE void TkMacOSXDrawAllViews(ClientData clientData); #pragma mark Private Objective-C Classes diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 6c7e9ff..0f58c70 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -122,7 +122,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification; */ while (Tcl_ServiceEvent(0)) {} - while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {} /* * NSWindowDidDeminiaturizeNotification is received after @@ -919,32 +919,6 @@ ConfigureRestrictProc( return (eventPtr->type==ConfigureNotify ? TK_PROCESS_EVENT : TK_DEFER_EVENT); } -/* - * If a window gets mapped inside the drawRect method, this will be run as an - * idle task, after drawRect returns, to clean up the mess. - */ - -static void -RedisplayView( - ClientData clientdata) -{ - TKContentView *view = (TKContentView *) clientdata; - - /* - * Make sure that we are not trying to displaying a view that no longer - * exists. Must call [NSApp windows] because [NSApp orderedWindows] excludes - * floating/utility windows and other window panels. - */ - - for (NSWindow *w in [NSApp windows]) { - if ([w contentView] == view) { - [view setTkNeedsDisplay:YES]; - [view setTkDirtyRect:[view bounds]]; - break; - } - } -} - @implementation TKContentView(TKWindowEvent) - (void) addTkDirtyRect: (NSRect) rect @@ -983,21 +957,16 @@ RedisplayView( } [NSApp setIsDrawing: YES]; - -#ifdef TK_MAC_DEBUG_DRAWING - fprintf(stderr, "drawRect: %s\n", NSStringFromRect(rect).UTF8String; -#endif - + [self setTkDirtyRect:NSZeroRect]; [self generateExposeEvents:rect]; + [self setTkNeedsDisplay: NO]; [NSApp setIsDrawing: NO]; if ([self needsRedisplay]) { [self setNeedsRedisplay:NO]; - Tcl_DoWhenIdle(RedisplayView, self); + Tcl_DoWhenIdle(TkMacOSXDrawAllViews, NULL); } - [self clearTkDirtyRect]; - #ifdef TK_MAC_DEBUG_DRAWING fprintf(stderr, "drawRect: done.\n"); #endif @@ -1102,6 +1071,7 @@ RedisplayView( /* * First process all of the Expose events. */ + while (Tcl_ServiceEvent(TCL_IDLE_EVENTS)) {}; oldProc = Tk_RestrictEvents(ExposeRestrictProc, UINT2PTR(serial), &oldArg); while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {}; diff --git a/tests/canvImg.test b/tests/canvImg.test index b60e384..1abea78 100644 --- a/tests/canvImg.test +++ b/tests/canvImg.test @@ -727,12 +727,6 @@ test canvImg-9.1 {DisplayImage procedure} -constraints testImageType -setup { image delete foo } -result {75 150 105 165} -if {[tk windowingsystem] == "aqua" && $tcl_platform(osVersion) > 18} { - # Aqua >= 10.14 will redraw the entire image. - set result_10_1 {{foo display 0 0 30 15}} -} else { - set result_10_1 {{foo display 2 4 6 8}} -} test canvImg-10.1 {TranslateImage procedure} -constraints testImageType -setup { .c delete all update @@ -750,7 +744,7 @@ test canvImg-10.1 {TranslateImage procedure} -constraints testImageType -setup { } -cleanup { .c delete all image delete foo -} -result $result_10_1 +} -result {{foo display 2 4 6 8}} test canvImg-11.1 {TranslateImage procedure} -constraints testImageType -setup { .c delete all diff --git a/tests/image.test b/tests/image.test index da65a66..cac304f 100644 --- a/tests/image.test +++ b/tests/image.test @@ -357,12 +357,6 @@ test image-8.1 {Tk_ImageCmd procedure, "inuse" option} -constraints { catch {destroy .b} } -result [list 0 1] -if {[tk windowingsystem] == "aqua" && $tcl_platform(osVersion) > 18} { - # Aqua >= 10.14 will redraw the entire image in drawRect. - set result_9_1 {{foo display 0 0 30 15}} -} else { - set result_9_1 {{foo display 5 6 7 8}} -} test image-9.1 {Tk_ImageChanged procedure} -constraints testImageType -setup { .c delete all imageCleanup @@ -385,13 +379,8 @@ test image-9.1 {Tk_ImageChanged procedure} -constraints testImageType -setup { } -cleanup { .c delete all imageCleanup -} -result $result_9_1 -if {[tk windowingsystem] == "aqua" && $tcl_platform(osVersion) > 18} { - # Aqua >= 10.14 will redraw the entire image. - set result_9_2 {{foo display 0 0 30 15} {foo display 0 0 30 15}} -} else { - set result_9_2 {{foo display 5 6 25 9} {foo display 0 0 12 14}} -} +} -result {{foo display 5 6 7 8}} + test image-9.2 {Tk_ImageChanged procedure} -constraints testImageType -setup { .c delete all imageCleanup @@ -411,7 +400,7 @@ test image-9.2 {Tk_ImageChanged procedure} -constraints testImageType -setup { } -cleanup { .c delete all imageCleanup -} -result $result_9_2 +} -result {{foo display 5 6 25 9} {foo display 0 0 12 14}} test image-10.1 {Tk_GetImage procedure} -setup { imageCleanup diff --git a/tests/listbox.test b/tests/listbox.test index 14c5c97..8d4ed33 100644 --- a/tests/listbox.test +++ b/tests/listbox.test @@ -2800,13 +2800,13 @@ test listbox-21.16 {ListboxListVarProc, update vertical scrollbar} -setup { test listbox-22.1 {UpdateHScrollbar} -setup { destroy .l } -body { - listbox .l -font $fixed -width 10 -xscrollcommand "record x" set log {} + listbox .l -font $fixed -width 10 -xscrollcommand "record x" pack .l set timeout [after 500 {set log timeout}] vwait log .l insert end "0000000000" - update + update idletasks .l insert end "00000000000000000000" vwait log set log -- cgit v0.12 From 6694505c3ede36fbdf40007bf50495675a8d9455 Mon Sep 17 00:00:00 2001 From: fvogel Date: Tue, 2 Jun 2020 06:16:12 +0000 Subject: A more robust approach to warping with respect to a window: make the call to TkpWarpPointer happen in TkPointerEvent instead of as an idle event. This allows to remove some update/after commands in tests since warping with respect to a window is now synchronous (it happens before event generate $win -warp 1 ... returns). --- generic/tkBind.c | 34 +++++++++++++++++++--------------- generic/tkGrab.c | 37 +++++++++++++++++++++++++++++++++++++ tests/bind.test | 6 ------ 3 files changed, 56 insertions(+), 21 deletions(-) diff --git a/generic/tkBind.c b/generic/tkBind.c index af6ab15..ea1f721 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -4364,8 +4364,21 @@ HandleEventGenerate( dispPtr->warpX = event.general.xmotion.x; dispPtr->warpY = event.general.xmotion.y; + /* + * Warping with respect to a window will be done when Tk_handleEvent + * below will run the event handlers and in particular TkPointerEvent. + * This allows to make grabs and warping work together robustly, that + * is without depending on a precise sequence of events. + * Warping with respect to the whole screen (i.e. dispPtr->warpWindow + * is NULL) is run as an idle task because the event handlers are not + * designed to work without a window (and there is anyway no point in + * making this case sleep with grabs). + */ + if (!(dispPtr->flags & TK_DISPLAY_IN_WARP)) { - Tcl_DoWhenIdle(DoWarp, dispPtr); + if (!dispPtr->warpWindow) { + Tcl_DoWhenIdle(DoWarp, dispPtr); + } dispPtr->flags |= TK_DISPLAY_IN_WARP; } } @@ -4473,23 +4486,14 @@ DoWarp( assert(clientData); /* - * DoWarp was scheduled only if the window was mapped. It needs to be - * still mapped at the time the present idle callback is executed. Also - * one needs to guard against window destruction in the meantime. - * Finally, the case warpWindow == NULL is special in that it means - * the whole screen. + * A non-NULL warpWindow means warping with respect to this window. + * We can only be here if we're warping with respect to the whole screen. */ - if (!dispPtr->warpWindow || - (Tk_IsMapped(dispPtr->warpWindow) && Tk_WindowId(dispPtr->warpWindow) != None)) { - TkpWarpPointer(dispPtr); - XForceScreenSaver(dispPtr->display, ScreenSaverReset); - } + assert(!dispPtr->warpWindow); - if (dispPtr->warpWindow) { - Tcl_Release(dispPtr->warpWindow); - dispPtr->warpWindow = NULL; - } + TkpWarpPointer(dispPtr); + XForceScreenSaver(dispPtr->display, ScreenSaverReset); dispPtr->flags &= ~TK_DISPLAY_IN_WARP; } diff --git a/generic/tkGrab.c b/generic/tkGrab.c index 2855637..0750bd5 100644 --- a/generic/tkGrab.c +++ b/generic/tkGrab.c @@ -774,6 +774,33 @@ TkPointerEvent( return 1; } + if ((eventPtr->type == MotionNotify) && !appGrabbed) { + if ((dispPtr->flags & TK_DISPLAY_IN_WARP)) { + + /* + * A NULL warpWindow means warping with respect to the whole screen. + * We can only be here if we're warping with respect to a window. + */ + + assert(dispPtr->warpWindow); + + /* + * Warping with respect to a window can only be done if the window is + * mapped. This was checked in HandleEvent. The windows needs to be + * still mapped at the time the present code is executed. Also + * one needs to guard against window destruction in the meantime. + */ + + if (Tk_IsMapped(dispPtr->warpWindow) && Tk_WindowId(dispPtr->warpWindow) != None) { + TkpWarpPointer(dispPtr); + XForceScreenSaver(dispPtr->display, ScreenSaverReset); + } + Tcl_Release(dispPtr->warpWindow); + dispPtr->warpWindow = NULL; + dispPtr->flags &= ~TK_DISPLAY_IN_WARP; + } + } + if (!appGrabbed) { return 1; } @@ -800,6 +827,16 @@ TkPointerEvent( Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_HEAD); return 0; } + if ((dispPtr->flags & TK_DISPLAY_IN_WARP)) { + assert(dispPtr->warpWindow); + if (Tk_IsMapped(dispPtr->warpWindow) && Tk_WindowId(dispPtr->warpWindow) != None) { + TkpWarpPointer(dispPtr); + XForceScreenSaver(dispPtr->display, ScreenSaverReset); + } + Tcl_Release(dispPtr->warpWindow); + dispPtr->warpWindow = NULL; + dispPtr->flags &= ~TK_DISPLAY_IN_WARP; + } return 1; } diff --git a/tests/bind.test b/tests/bind.test index a001580..2531a65 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6635,14 +6635,10 @@ test bind-34.1 {-warp works relatively to a window} -setup { wm geometry .top +200+200 update event generate .top -x 20 -y 20 -warp 1 - update idletasks ; # DoWarp is an idle callback - after 50 ; # Win specific - wait for SendInput to be executed set pointerPos1 [winfo pointerxy .t] wm geometry .top +600+600 update event generate .top -x 20 -y 20 -warp 1 - update idletasks ; # DoWarp is an idle callback - after 50 ; # Win specific - wait for SendInput to be executed set pointerPos2 [winfo pointerxy .t] # from the first warped position to the second one, the mouse # pointer should have moved the same amount as the window moved @@ -6736,14 +6732,12 @@ test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -constraints grab .top ; # this will queue events waitForGrab grabbed .top event generate .top.l -warp 1 -x 10 -y 10 - update idletasks ; after 50 foreach {x1 y1} [winfo pointerxy .top.l] {} event generate {} -warp 1 -x 50 -y 50 update idletasks ; after 50 grab release .top ; # this will queue events waitForGrab released .top event generate .top.l -warp 1 -x 10 -y 10 - update idletasks ; after 50 foreach {x2 y2} [winfo pointerxy .top.l] {} expr {$x1==$x2 && $y1==$y2} } -cleanup { -- cgit v0.12 From 7e224c0bcdec400cbdb89459313b1e4ea73bc896 Mon Sep 17 00:00:00 2001 From: fvogel Date: Tue, 2 Jun 2020 06:45:54 +0000 Subject: Warping with respect to the whole screen is now synchronous as well (it is no longer executed as an idle task). This allows to remove some further update/after commands in tests. --- generic/tkBind.c | 17 +++++++---------- tests/bind.test | 13 ++----------- 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/generic/tkBind.c b/generic/tkBind.c index ea1f721..a2f8532 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -717,7 +717,7 @@ static int NameToWindow(Tcl_Interp *interp, Tk_Window main, Tcl_Obj *objPtr, Tk_Window *tkwinPtr); static unsigned ParseEventDescription(Tcl_Interp *interp, const char **eventStringPtr, TkPattern *patPtr, EventMask *eventMaskPtr); -static void DoWarp(ClientData clientData); +static void DoWarp(TkDisplay *dispPtr); static PSList * GetLookupForEvent(LookupTables* lookupPtr, const Event *eventPtr, Tcl_Obj *object, int onlyConsiderDetailedEvents); static void ClearLookupTable(LookupTables *lookupTables, ClientData object); @@ -4376,10 +4376,10 @@ HandleEventGenerate( */ if (!(dispPtr->flags & TK_DISPLAY_IN_WARP)) { + dispPtr->flags |= TK_DISPLAY_IN_WARP; if (!dispPtr->warpWindow) { - Tcl_DoWhenIdle(DoWarp, dispPtr); + DoWarp(dispPtr); } - dispPtr->flags |= TK_DISPLAY_IN_WARP; } } @@ -4466,24 +4466,22 @@ NameToWindow( * * DoWarp -- * - * Perform Warping of X pointer. Executed as an idle handler only. + * Perform warping of mouse pointer with respect to the whole screen. * * Results: * None * * Side effects: - * X Pointer will move to a new location. + * Mouse pointer moves to a new location. * *------------------------------------------------------------------------- */ static void DoWarp( - ClientData clientData) + TkDisplay *dispPtr) { - TkDisplay *dispPtr = clientData; - - assert(clientData); + assert(dispPtr); /* * A non-NULL warpWindow means warping with respect to this window. @@ -5286,7 +5284,6 @@ TkpCancelWarp( assert(dispPtr); if (dispPtr->flags & TK_DISPLAY_IN_WARP) { - Tcl_CancelIdleCall(DoWarp, dispPtr); dispPtr->flags &= ~TK_DISPLAY_IN_WARP; } } diff --git a/tests/bind.test b/tests/bind.test index 2531a65..c677109 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6137,6 +6137,8 @@ test bind-31.7 {virtual event user_data field - unshared, asynch} -setup { } -result {{} {} {TestUserData >b<}} test bind-32.1 {-warp, window was destroyed before the idle callback DoWarp} -setup { + # note: this test is now essentially useless + # since DoWarp no longer is an idle callback frame .t.f pack .t.f focus -force .t.f @@ -6656,12 +6658,8 @@ test bind-34.2 {-warp works relatively to the screen} -setup { } -body { # Contrary to bind-34.1, we're directly checking screen coordinates event generate {} -x 20 -y 20 -warp 1 - update idletasks ; # DoWarp is an idle callback - after 50 ; # Win specific - wait for SendInput to be executed set res [winfo pointerxy .] event generate {} -x 200 -y 200 -warp 1 - update idletasks ; # DoWarp is an idle callback - after 50 ; # Win specific - wait for SendInput to be executed lappend res {*}[winfo pointerxy .] } -cleanup { } -result {20 20 200 200} @@ -6679,8 +6677,6 @@ test bind-34.3 {-warp works with null or negative coordinates} -setup { set res {} } -body { event generate {} -x 0 -y 0 -warp 1 - update idletasks ; # DoWarp is an idle callback - after 50 ; # Win specific - wait for SendInput to be executed foreach dim [winfo pointerxy .] { if {$dim <= $halo} { lappend res ok @@ -6689,9 +6685,7 @@ test bind-34.3 {-warp works with null or negative coordinates} -setup { } } event generate {} -x 100 -y 100 -warp 1 - update idletasks ; after 50 event generate {} -x -1 -y -1 -warp 1 - update idletasks ; after 50 foreach dim [winfo pointerxy .] { if {$dim <= $halo} { lappend res ok @@ -6718,8 +6712,6 @@ test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -constraints } } event generate {} -warp 1 -x 50 -y 50 - update idletasks ; # DoWarp is an idle callback - after 50 ; # Win specific - wait for SendInput to be executed toplevel .top grab release .top waitForGrab released .top @@ -6734,7 +6726,6 @@ test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -constraints event generate .top.l -warp 1 -x 10 -y 10 foreach {x1 y1} [winfo pointerxy .top.l] {} event generate {} -warp 1 -x 50 -y 50 - update idletasks ; after 50 grab release .top ; # this will queue events waitForGrab released .top event generate .top.l -warp 1 -x 10 -y 10 -- cgit v0.12 From 169bf5a922972c64aa154479d588919763f77e88 Mon Sep 17 00:00:00 2001 From: fvogel Date: Tue, 2 Jun 2020 06:52:47 +0000 Subject: Remove the TK_DISPLAY_IN_WARP machinery completely. --- generic/tkBind.c | 38 +++----------------------------------- generic/tkGrab.c | 16 ++++++---------- generic/tkInt.h | 6 +----- generic/tkWindow.c | 2 -- 4 files changed, 10 insertions(+), 52 deletions(-) diff --git a/generic/tkBind.c b/generic/tkBind.c index a2f8532..7fd9e74 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -4375,12 +4375,9 @@ HandleEventGenerate( * making this case sleep with grabs). */ - if (!(dispPtr->flags & TK_DISPLAY_IN_WARP)) { - dispPtr->flags |= TK_DISPLAY_IN_WARP; - if (!dispPtr->warpWindow) { - DoWarp(dispPtr); - } - } + if (!dispPtr->warpWindow) { + DoWarp(dispPtr); + } } /* @@ -4492,7 +4489,6 @@ DoWarp( TkpWarpPointer(dispPtr); XForceScreenSaver(dispPtr->display, ScreenSaverReset); - dispPtr->flags &= ~TK_DISPLAY_IN_WARP; } /* @@ -5263,34 +5259,6 @@ TkpGetBindingXEvent( /* *---------------------------------------------------------------------- * - * TkpCancelWarp -- - * - * This function cancels an outstanding pointer warp and - * is called during tear down of the display. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -TkpCancelWarp( - TkDisplay *dispPtr) -{ - assert(dispPtr); - - if (dispPtr->flags & TK_DISPLAY_IN_WARP) { - dispPtr->flags &= ~TK_DISPLAY_IN_WARP; - } -} - -/* - *---------------------------------------------------------------------- - * * TkpDumpPS -- * * Dump given pattern sequence to stdout. diff --git a/generic/tkGrab.c b/generic/tkGrab.c index 0750bd5..c923608 100644 --- a/generic/tkGrab.c +++ b/generic/tkGrab.c @@ -775,14 +775,13 @@ TkPointerEvent( } if ((eventPtr->type == MotionNotify) && !appGrabbed) { - if ((dispPtr->flags & TK_DISPLAY_IN_WARP)) { - /* - * A NULL warpWindow means warping with respect to the whole screen. - * We can only be here if we're warping with respect to a window. - */ + /* + * A NULL warpWindow means warping with respect to the whole screen. + * We want to warp here only if we're warping with respect to a window. + */ - assert(dispPtr->warpWindow); + if (dispPtr->warpWindow) { /* * Warping with respect to a window can only be done if the window is @@ -797,7 +796,6 @@ TkPointerEvent( } Tcl_Release(dispPtr->warpWindow); dispPtr->warpWindow = NULL; - dispPtr->flags &= ~TK_DISPLAY_IN_WARP; } } @@ -827,15 +825,13 @@ TkPointerEvent( Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_HEAD); return 0; } - if ((dispPtr->flags & TK_DISPLAY_IN_WARP)) { - assert(dispPtr->warpWindow); + if (dispPtr->warpWindow) { if (Tk_IsMapped(dispPtr->warpWindow) && Tk_WindowId(dispPtr->warpWindow) != None) { TkpWarpPointer(dispPtr); XForceScreenSaver(dispPtr->display, ScreenSaverReset); } Tcl_Release(dispPtr->warpWindow); dispPtr->warpWindow = NULL; - dispPtr->flags &= ~TK_DISPLAY_IN_WARP; } return 1; } diff --git a/generic/tkInt.h b/generic/tkInt.h index c1bd562d..cc710d6 100644 --- a/generic/tkInt.h +++ b/generic/tkInt.h @@ -535,15 +535,12 @@ typedef struct TkDisplay { * Whether to use input methods for this display * TK_DISPLAY_WM_TRACING: (default off) * Whether we should do wm tracing on this display. - * TK_DISPLAY_IN_WARP: (default off) - * Indicates that we are in a pointer warp */ #define TK_DISPLAY_COLLAPSE_MOTION_EVENTS (1 << 0) #define TK_DISPLAY_USE_IM (1 << 1) #define TK_DISPLAY_WM_TRACING (1 << 3) -#define TK_DISPLAY_IN_WARP (1 << 4) -#define TK_DISPLAY_USE_XKB (1 << 5) +#define TK_DISPLAY_USE_XKB (1 << 4) /* * One of the following structures exists for each error handler created by a @@ -1251,7 +1248,6 @@ MODULE_SCOPE int TkInitTkCmd(Tcl_Interp *interp, MODULE_SCOPE int TkInitFontchooser(Tcl_Interp *interp, ClientData clientData); MODULE_SCOPE void TkpWarpPointer(TkDisplay *dispPtr); -MODULE_SCOPE void TkpCancelWarp(TkDisplay *dispPtr); MODULE_SCOPE int TkListCreateFrame(ClientData clientData, Tcl_Interp *interp, Tcl_Obj *listObj, int toplevel, Tcl_Obj *nameObj); diff --git a/generic/tkWindow.c b/generic/tkWindow.c index 00fb344..93282dc 100644 --- a/generic/tkWindow.c +++ b/generic/tkWindow.c @@ -239,8 +239,6 @@ TkCloseDisplay( { TkClipCleanup(dispPtr); - TkpCancelWarp(dispPtr); - if (dispPtr->name != NULL) { ckfree(dispPtr->name); } -- cgit v0.12 From 7f9a1328482227ad2462a296bb956c68df2cb2e1 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 2 Jun 2020 09:50:22 +0000 Subject: Fix two (minor) warnings, discovered with gcc-10, using Tcl 9 headers) . --- generic/tkCanvText.c | 2 +- generic/ttk/ttkEntry.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/generic/tkCanvText.c b/generic/tkCanvText.c index 1c8bc04..a1b2358 100644 --- a/generic/tkCanvText.c +++ b/generic/tkCanvText.c @@ -960,7 +960,7 @@ DisplayCanvText( * anti-aliasing colors would blend together. */ - if ((selFirstChar >= 0) && (textPtr->selTextGC != textPtr->gc)) { + if ((selFirstChar != TCL_INDEX_NONE) && (textPtr->selTextGC != textPtr->gc)) { if (0 < selFirstChar) { TkDrawAngledTextLayout(display, drawable, textPtr->gc, textPtr->textLayout, drawableX, drawableY, textPtr->angle, diff --git a/generic/ttk/ttkEntry.c b/generic/ttk/ttkEntry.c index e07617c..cbc3b3f 100644 --- a/generic/ttk/ttkEntry.c +++ b/generic/ttk/ttkEntry.c @@ -1312,7 +1312,7 @@ static void EntryDisplay(void *clientData, Drawable d) } /* Use placeholder text width */ leftIndex = 0; - TkGetStringFromObj(entryPtr->entry.placeholderObj, &rightIndex); + (void)TkGetStringFromObj(entryPtr->entry.placeholderObj, &rightIndex); } else { foregroundObj = es.foregroundObj; } -- cgit v0.12 From f0b89aefda27ec85cef23db0ada5b6e292844a1b Mon Sep 17 00:00:00 2001 From: fvogel Date: Tue, 2 Jun 2020 20:48:00 +0000 Subject: Rename DoWarp to DoWarWrtScreen, add function DoWarpWrtWin to factorize the code a bit. --- generic/tkBind.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++---- generic/tkGrab.c | 32 ++------------------------------ generic/tkInt.h | 1 + tests/bind.test | 4 ++-- 4 files changed, 55 insertions(+), 36 deletions(-) diff --git a/generic/tkBind.c b/generic/tkBind.c index 7fd9e74..6eac1dd 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -717,7 +717,7 @@ static int NameToWindow(Tcl_Interp *interp, Tk_Window main, Tcl_Obj *objPtr, Tk_Window *tkwinPtr); static unsigned ParseEventDescription(Tcl_Interp *interp, const char **eventStringPtr, TkPattern *patPtr, EventMask *eventMaskPtr); -static void DoWarp(TkDisplay *dispPtr); +static void DoWarpWrtScreen(TkDisplay *dispPtr); static PSList * GetLookupForEvent(LookupTables* lookupPtr, const Event *eventPtr, Tcl_Obj *object, int onlyConsiderDetailedEvents); static void ClearLookupTable(LookupTables *lookupTables, ClientData object); @@ -4376,7 +4376,7 @@ HandleEventGenerate( */ if (!dispPtr->warpWindow) { - DoWarp(dispPtr); + DoWarpWrtScreen(dispPtr); } } @@ -4461,7 +4461,7 @@ NameToWindow( /* *------------------------------------------------------------------------- * - * DoWarp -- + * DoWarpWrtScreen -- * * Perform warping of mouse pointer with respect to the whole screen. * @@ -4475,7 +4475,7 @@ NameToWindow( */ static void -DoWarp( +DoWarpWrtScreen( TkDisplay *dispPtr) { assert(dispPtr); @@ -4494,6 +4494,52 @@ DoWarp( /* *------------------------------------------------------------------------- * + * DoWarpWrtWin -- + * + * Perform warping of mouse pointer with respect to a window. + * + * Results: + * None + * + * Side effects: + * Mouse pointer moves to a new location. + * + *------------------------------------------------------------------------- + */ + +void +DoWarpWrtWin( + TkDisplay *dispPtr) +{ + assert(dispPtr); + + /* + * A NULL warpWindow means warping with respect to the whole screen. + * We want to warp here only if we're warping with respect to a window. + */ + + if (dispPtr->warpWindow) { + + /* + * Warping with respect to a window can only be done if the window is + * mapped. This was checked in HandleEvent. The window needs to be + * still mapped at the time the present code is executed. Also + * one needs to guard against window destruction in the meantime, + * which could have happened as a side effect of an event handler. + */ + + if (Tk_IsMapped(dispPtr->warpWindow) && Tk_WindowId(dispPtr->warpWindow) != None) { + TkpWarpPointer(dispPtr); + XForceScreenSaver(dispPtr->display, ScreenSaverReset); + } + Tcl_Release(dispPtr->warpWindow); + dispPtr->warpWindow = NULL; + } +} + +/* + *------------------------------------------------------------------------- + * * GetVirtualEventUid -- * * Determine if the given string is in the proper format for a virtual diff --git a/generic/tkGrab.c b/generic/tkGrab.c index c923608..711bcad 100644 --- a/generic/tkGrab.c +++ b/generic/tkGrab.c @@ -775,28 +775,7 @@ TkPointerEvent( } if ((eventPtr->type == MotionNotify) && !appGrabbed) { - - /* - * A NULL warpWindow means warping with respect to the whole screen. - * We want to warp here only if we're warping with respect to a window. - */ - - if (dispPtr->warpWindow) { - - /* - * Warping with respect to a window can only be done if the window is - * mapped. This was checked in HandleEvent. The windows needs to be - * still mapped at the time the present code is executed. Also - * one needs to guard against window destruction in the meantime. - */ - - if (Tk_IsMapped(dispPtr->warpWindow) && Tk_WindowId(dispPtr->warpWindow) != None) { - TkpWarpPointer(dispPtr); - XForceScreenSaver(dispPtr->display, ScreenSaverReset); - } - Tcl_Release(dispPtr->warpWindow); - dispPtr->warpWindow = NULL; - } + DoWarpWrtWin(dispPtr); } if (!appGrabbed) { @@ -825,14 +804,7 @@ TkPointerEvent( Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_HEAD); return 0; } - if (dispPtr->warpWindow) { - if (Tk_IsMapped(dispPtr->warpWindow) && Tk_WindowId(dispPtr->warpWindow) != None) { - TkpWarpPointer(dispPtr); - XForceScreenSaver(dispPtr->display, ScreenSaverReset); - } - Tcl_Release(dispPtr->warpWindow); - dispPtr->warpWindow = NULL; - } + DoWarpWrtWin(dispPtr); return 1; } diff --git a/generic/tkInt.h b/generic/tkInt.h index cc710d6..5dd1454 100644 --- a/generic/tkInt.h +++ b/generic/tkInt.h @@ -1247,6 +1247,7 @@ MODULE_SCOPE int TkInitTkCmd(Tcl_Interp *interp, ClientData clientData); MODULE_SCOPE int TkInitFontchooser(Tcl_Interp *interp, ClientData clientData); +MODULE_SCOPE void DoWarpWrtWin(TkDisplay *dispPtr); MODULE_SCOPE void TkpWarpPointer(TkDisplay *dispPtr); MODULE_SCOPE int TkListCreateFrame(ClientData clientData, Tcl_Interp *interp, Tcl_Obj *listObj, diff --git a/tests/bind.test b/tests/bind.test index c677109..b9dab48 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6136,9 +6136,9 @@ test bind-31.7 {virtual event user_data field - unshared, asynch} -setup { destroy .t.f } -result {{} {} {TestUserData >b<}} -test bind-32.1 {-warp, window was destroyed before the idle callback DoWarp} -setup { +test bind-32.1 {-warp, window was destroyed before the idle callback DoWarpWrtScreen} -setup { # note: this test is now essentially useless - # since DoWarp no longer is an idle callback + # since DoWarpWrtScreen no longer is an idle callback frame .t.f pack .t.f focus -force .t.f -- cgit v0.12 From d3c2fbd34a2b6d1541f4b904ecf3d6fac896e9d7 Mon Sep 17 00:00:00 2001 From: fvogel Date: Tue, 2 Jun 2020 21:11:28 +0000 Subject: Remove function DoWarpWrtScreen which was called from only one place, and add comments. --- generic/tkBind.c | 41 +++-------------------------------------- generic/tkGrab.c | 20 ++++++++++++++++++++ tests/bind.test | 4 ++-- 3 files changed, 25 insertions(+), 40 deletions(-) diff --git a/generic/tkBind.c b/generic/tkBind.c index 6eac1dd..64bfff2 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -717,7 +717,6 @@ static int NameToWindow(Tcl_Interp *interp, Tk_Window main, Tcl_Obj *objPtr, Tk_Window *tkwinPtr); static unsigned ParseEventDescription(Tcl_Interp *interp, const char **eventStringPtr, TkPattern *patPtr, EventMask *eventMaskPtr); -static void DoWarpWrtScreen(TkDisplay *dispPtr); static PSList * GetLookupForEvent(LookupTables* lookupPtr, const Event *eventPtr, Tcl_Obj *object, int onlyConsiderDetailedEvents); static void ClearLookupTable(LookupTables *lookupTables, ClientData object); @@ -4370,13 +4369,12 @@ HandleEventGenerate( * This allows to make grabs and warping work together robustly, that * is without depending on a precise sequence of events. * Warping with respect to the whole screen (i.e. dispPtr->warpWindow - * is NULL) is run as an idle task because the event handlers are not - * designed to work without a window (and there is anyway no point in - * making this case sleep with grabs). + * is NULL) is run directly here. */ if (!dispPtr->warpWindow) { - DoWarpWrtScreen(dispPtr); + TkpWarpPointer(dispPtr); + XForceScreenSaver(dispPtr->display, ScreenSaverReset); } } @@ -4461,39 +4459,6 @@ NameToWindow( /* *------------------------------------------------------------------------- * - * DoWarpWrtScreen -- - * - * Perform warping of mouse pointer with respect to the whole screen. - * - * Results: - * None - * - * Side effects: - * Mouse pointer moves to a new location. - * - *------------------------------------------------------------------------- - */ - -static void -DoWarpWrtScreen( - TkDisplay *dispPtr) -{ - assert(dispPtr); - - /* - * A non-NULL warpWindow means warping with respect to this window. - * We can only be here if we're warping with respect to the whole screen. - */ - - assert(!dispPtr->warpWindow); - - TkpWarpPointer(dispPtr); - XForceScreenSaver(dispPtr->display, ScreenSaverReset); -} - -/* - *------------------------------------------------------------------------- - * * DoWarpWrtWin -- * * Perform warping of mouse pointer with respect to a window. diff --git a/generic/tkGrab.c b/generic/tkGrab.c index 711bcad..a977ed8 100644 --- a/generic/tkGrab.c +++ b/generic/tkGrab.c @@ -667,6 +667,9 @@ ReleaseButtonGrab( * This function is called for each pointer-related event, before the * event has been processed. It does various things to make grabs work * correctly. + * Also, this function takes care of warping the mouse pointer with + * respect to a given window, both when there is a grab in effect and + * when there is none. * * Results: * If the return value is 1 it means the event should be processed (event @@ -678,6 +681,7 @@ ReleaseButtonGrab( * Grab state information may be updated. New events may also be pushed * back onto the event queue to replace or augment the one passed in * here. + * The mouse pointer may be moved. * *---------------------------------------------------------------------- */ @@ -775,6 +779,12 @@ TkPointerEvent( } if ((eventPtr->type == MotionNotify) && !appGrabbed) { + + /* + * Warp the mouse pointer with respect to window dispPtr->warpWindow + * if such a window was set in HandleEventGenerate. + */ + DoWarpWrtWin(dispPtr); } @@ -782,6 +792,10 @@ TkPointerEvent( return 1; } + /* + * From this point on, there is a grab in effect. + */ + if (eventPtr->type == MotionNotify) { /* * When grabs are active, X reports motion events relative to the @@ -804,6 +818,12 @@ TkPointerEvent( Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_HEAD); return 0; } + + /* + * Warp the mouse pointer with respect to window dispPtr->warpWindow + * if such a window was set in HandleEventGenerate. + */ + DoWarpWrtWin(dispPtr); return 1; } diff --git a/tests/bind.test b/tests/bind.test index b9dab48..70161f0 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6136,9 +6136,9 @@ test bind-31.7 {virtual event user_data field - unshared, asynch} -setup { destroy .t.f } -result {{} {} {TestUserData >b<}} -test bind-32.1 {-warp, window was destroyed before the idle callback DoWarpWrtScreen} -setup { +test bind-32.1 {-warp, window was destroyed before the idle callback DoWarp} -setup { # note: this test is now essentially useless - # since DoWarpWrtScreen no longer is an idle callback + # since DoWarp no longer exist, not even as an idle callback frame .t.f pack .t.f focus -force .t.f -- cgit v0.12 From d45f5ead66cf0fcf7b2f562cd1937b910cc31285 Mon Sep 17 00:00:00 2001 From: fvogel Date: Tue, 2 Jun 2020 21:16:42 +0000 Subject: Rename DoWarpWrtWin --> TkDoWarpWrtWin --- generic/tkBind.c | 4 ++-- generic/tkGrab.c | 4 ++-- generic/tkInt.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/generic/tkBind.c b/generic/tkBind.c index 64bfff2..992d881 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -4459,7 +4459,7 @@ NameToWindow( /* *------------------------------------------------------------------------- * - * DoWarpWrtWin -- + * TkDoWarpWrtWin -- * * Perform warping of mouse pointer with respect to a window. * @@ -4473,7 +4473,7 @@ NameToWindow( */ void -DoWarpWrtWin( +TkDoWarpWrtWin( TkDisplay *dispPtr) { assert(dispPtr); diff --git a/generic/tkGrab.c b/generic/tkGrab.c index a977ed8..8f09f50 100644 --- a/generic/tkGrab.c +++ b/generic/tkGrab.c @@ -785,7 +785,7 @@ TkPointerEvent( * if such a window was set in HandleEventGenerate. */ - DoWarpWrtWin(dispPtr); + TkDoWarpWrtWin(dispPtr); } if (!appGrabbed) { @@ -824,7 +824,7 @@ TkPointerEvent( * if such a window was set in HandleEventGenerate. */ - DoWarpWrtWin(dispPtr); + TkDoWarpWrtWin(dispPtr); return 1; } diff --git a/generic/tkInt.h b/generic/tkInt.h index 5dd1454..f5ec1f6 100644 --- a/generic/tkInt.h +++ b/generic/tkInt.h @@ -1247,7 +1247,7 @@ MODULE_SCOPE int TkInitTkCmd(Tcl_Interp *interp, ClientData clientData); MODULE_SCOPE int TkInitFontchooser(Tcl_Interp *interp, ClientData clientData); -MODULE_SCOPE void DoWarpWrtWin(TkDisplay *dispPtr); +MODULE_SCOPE void TkDoWarpWrtWin(TkDisplay *dispPtr); MODULE_SCOPE void TkpWarpPointer(TkDisplay *dispPtr); MODULE_SCOPE int TkListCreateFrame(ClientData clientData, Tcl_Interp *interp, Tcl_Obj *listObj, -- cgit v0.12 From 09befbb4eac44f8ad13d3d5cf4250cbfc926039a Mon Sep 17 00:00:00 2001 From: fvogel Date: Tue, 2 Jun 2020 21:33:53 +0000 Subject: Fix error (with no consequences) in test bind-34.1 --- tests/bind.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/bind.test b/tests/bind.test index a001580..e62ce8d 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6637,13 +6637,13 @@ test bind-34.1 {-warp works relatively to a window} -setup { event generate .top -x 20 -y 20 -warp 1 update idletasks ; # DoWarp is an idle callback after 50 ; # Win specific - wait for SendInput to be executed - set pointerPos1 [winfo pointerxy .t] + set pointerPos1 [winfo pointerxy .top] wm geometry .top +600+600 update event generate .top -x 20 -y 20 -warp 1 update idletasks ; # DoWarp is an idle callback after 50 ; # Win specific - wait for SendInput to be executed - set pointerPos2 [winfo pointerxy .t] + set pointerPos2 [winfo pointerxy .top] # from the first warped position to the second one, the mouse # pointer should have moved the same amount as the window moved set res 1 -- cgit v0.12 From d4d3034d257d3c52965a56c421faaaade35f1242 Mon Sep 17 00:00:00 2001 From: fvogel Date: Tue, 2 Jun 2020 21:39:28 +0000 Subject: Make test bind-34.1 pass on Debian 10 with KDE/Plasma. --- tests/bind.test | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/bind.test b/tests/bind.test index e62ce8d..e68368a 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6627,6 +6627,7 @@ test bind-33.15 {prefer last in case of homogeneous equal patterns} -setup { test bind-34.1 {-warp works relatively to a window} -setup { toplevel .top + update } -body { # In order to avoid platform-dependent coordinate results due to # decorations and borders, this test warps the pointer twice -- cgit v0.12 From c0f2471d203026409e33969ccdb40cf06ff0f99c Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 2 Jun 2020 21:51:23 +0000 Subject: size_t for Tk_ItemDCharsProc(), with Tcl 9 headers --- generic/tk.h | 41 +++++++++++++++++++---------------------- generic/tkCanvLine.c | 12 ++++++------ generic/tkCanvPoly.c | 16 ++++++++-------- generic/tkCanvText.c | 24 ++++++++++++------------ generic/tkText.c | 49 +++++++++++++++++++++++++------------------------ 5 files changed, 70 insertions(+), 72 deletions(-) diff --git a/generic/tk.h b/generic/tk.h index 5efd2cb..90d4115 100644 --- a/generic/tk.h +++ b/generic/tk.h @@ -1047,13 +1047,17 @@ typedef struct Tk_Item { * lines, circles, etc.) that can form part of a canvas widget. */ -#ifdef USE_OLD_CANVAS +#if defined(USE_OLD_CANVAS) && TCL_MAJOR_VERSION < 9 typedef int (Tk_ItemCreateProc)(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, char **argv); typedef int (Tk_ItemConfigureProc)(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, char **argv, int flags); typedef int (Tk_ItemCoordProc)(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, char **argv); +typedef void (Tk_ItemInsertProc)(Tk_Canvas canvas, Tk_Item *itemPtr, + int beforeThis, char *string); +typedef int (Tk_ItemIndexProc)(Tcl_Interp *interp, Tk_Canvas canvas, + Tk_Item *itemPtr, char *indexString, int *indexPtr); #else typedef int (Tk_ItemCreateProc)(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, Tcl_Obj *const objv[]); @@ -1062,6 +1066,17 @@ typedef int (Tk_ItemConfigureProc)(Tcl_Interp *interp, Tk_Canvas canvas, int flags); typedef int (Tk_ItemCoordProc)(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, Tcl_Obj *const argv[]); +#if TCL_MAJOR_VERSION > 8 +typedef void (Tk_ItemInsertProc)(Tk_Canvas canvas, Tk_Item *itemPtr, + size_t beforeThis, Tcl_Obj *string); +typedef int (Tk_ItemIndexProc)(Tcl_Interp *interp, Tk_Canvas canvas, + Tk_Item *itemPtr, Tcl_Obj *indexString, size_t *indexPtr); +#else +typedef void (Tk_ItemInsertProc)(Tk_Canvas canvas, Tk_Item *itemPtr, + int beforeThis, Tcl_Obj *string); +typedef int (Tk_ItemIndexProc)(Tcl_Interp *interp, Tk_Canvas canvas, + Tk_Item *itemPtr, Tcl_Obj *indexString, int *indexPtr); +#endif #endif /* USE_OLD_CANVAS */ typedef void (Tk_ItemDeleteProc)(Tk_Canvas canvas, Tk_Item *itemPtr, Display *display); @@ -1081,39 +1096,21 @@ typedef void (Tk_ItemScaleProc)(Tk_Canvas canvas, Tk_Item *itemPtr, double scaleY); typedef void (Tk_ItemTranslateProc)(Tk_Canvas canvas, Tk_Item *itemPtr, double deltaX, double deltaY); -#ifdef USE_OLD_CANVAS -typedef int (Tk_ItemIndexProc)(Tcl_Interp *interp, Tk_Canvas canvas, - Tk_Item *itemPtr, char *indexString, int *indexPtr); -#elif TCL_MAJOR_VERSION > 8 -typedef int (Tk_ItemIndexProc)(Tcl_Interp *interp, Tk_Canvas canvas, - Tk_Item *itemPtr, Tcl_Obj *indexString, size_t *indexPtr); -#else -typedef int (Tk_ItemIndexProc)(Tcl_Interp *interp, Tk_Canvas canvas, - Tk_Item *itemPtr, Tcl_Obj *indexString, int *indexPtr); -#endif /* USE_OLD_CANVAS */ #if TCL_MAJOR_VERSION > 8 typedef void (Tk_ItemCursorProc)(Tk_Canvas canvas, Tk_Item *itemPtr, size_t index); typedef size_t (Tk_ItemSelectionProc)(Tk_Canvas canvas, Tk_Item *itemPtr, size_t offset, char *buffer, size_t maxBytes); +typedef void (Tk_ItemDCharsProc)(Tk_Canvas canvas, Tk_Item *itemPtr, + size_t first, size_t last); #else typedef void (Tk_ItemCursorProc)(Tk_Canvas canvas, Tk_Item *itemPtr, int index); typedef int (Tk_ItemSelectionProc)(Tk_Canvas canvas, Tk_Item *itemPtr, int offset, char *buffer, int maxBytes); -#endif -#ifdef USE_OLD_CANVAS -typedef void (Tk_ItemInsertProc)(Tk_Canvas canvas, Tk_Item *itemPtr, - int beforeThis, char *string); -#elif TCL_MAJOR_VERSION > 8 -typedef void (Tk_ItemInsertProc)(Tk_Canvas canvas, Tk_Item *itemPtr, - size_t beforeThis, Tcl_Obj *string); -#else -typedef void (Tk_ItemInsertProc)(Tk_Canvas canvas, Tk_Item *itemPtr, - int beforeThis, Tcl_Obj *string); -#endif /* USE_OLD_CANVAS */ typedef void (Tk_ItemDCharsProc)(Tk_Canvas canvas, Tk_Item *itemPtr, int first, int last); +#endif #ifndef __NO_OLD_CONFIG diff --git a/generic/tkCanvLine.c b/generic/tkCanvLine.c index 484f41c..88ddc97 100644 --- a/generic/tkCanvLine.c +++ b/generic/tkCanvLine.c @@ -97,7 +97,7 @@ static int LineCoords(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int objc, Tcl_Obj *const objv[]); static void LineDeleteCoords(Tk_Canvas canvas, - Tk_Item *itemPtr, int first, int last); + Tk_Item *itemPtr, TkSizeT first, TkSizeT last); static void LineInsert(Tk_Canvas canvas, Tk_Item *itemPtr, TkSizeT beforeThis, Tcl_Obj *obj); static int LineToArea(Tk_Canvas canvas, @@ -1153,8 +1153,8 @@ static void LineDeleteCoords( Tk_Canvas canvas, /* Canvas containing itemPtr. */ Tk_Item *itemPtr, /* Item in which to delete characters. */ - int first, /* Index of first character to delete. */ - int last) /* Index of last character to delete. */ + TkSizeT first, /* Index of first character to delete. */ + TkSizeT last) /* Index of last character to delete. */ { LineItem *linePtr = (LineItem *) itemPtr; int count, i, first1, last1; @@ -1169,13 +1169,13 @@ LineDeleteCoords( first &= -2; last &= -2; - if (first < 0) { + if ((int)first < 0) { first = 0; } - if (last >= length) { + if ((int)last >= length) { last = length-2; } - if (first > last) { + if ((int)first > (int)last) { return; } if (linePtr->firstArrowPtr != NULL) { diff --git a/generic/tkCanvPoly.c b/generic/tkCanvPoly.c index f4f0163..88f63e8 100644 --- a/generic/tkCanvPoly.c +++ b/generic/tkCanvPoly.c @@ -168,7 +168,7 @@ static int PolygonCoords(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int objc, Tcl_Obj *const objv[]); static void PolygonDeleteCoords(Tk_Canvas canvas, - Tk_Item *itemPtr, int first, int last); + Tk_Item *itemPtr, TkSizeT first, TkSizeT last); static void PolygonInsert(Tk_Canvas canvas, Tk_Item *itemPtr, TkSizeT beforeThis, Tcl_Obj *obj); static int PolygonToArea(Tk_Canvas canvas, @@ -1172,23 +1172,23 @@ static void PolygonDeleteCoords( Tk_Canvas canvas, /* Canvas containing itemPtr. */ Tk_Item *itemPtr, /* Item in which to delete characters. */ - int first, /* Index of first character to delete. */ - int last) /* Index of last character to delete. */ + TkSizeT first, /* Index of first character to delete. */ + TkSizeT last) /* Index of last character to delete. */ { PolygonItem *polyPtr = (PolygonItem *) itemPtr; int count, i; int length = 2*(polyPtr->numPoints - polyPtr->autoClosed); - while (first >= length) { + while ((int)first >= length) { first -= length; } - while (first < 0) { + while ((int)first < 0) { first += length; } - while (last >= length) { + while ((int)last >= length) { last -= length; } - while (last < 0) { + while ((int)last < 0) { last += length; } @@ -1215,7 +1215,7 @@ PolygonDeleteCoords( polyPtr->coordPtr[i-count] = polyPtr->coordPtr[i]; } } else { - for (i=last; i<=first; i++) { + for (i=last; i<=(int)first; i++) { polyPtr->coordPtr[i-last] = polyPtr->coordPtr[i]; } } diff --git a/generic/tkCanvText.c b/generic/tkCanvText.c index a1b2358..304e009 100644 --- a/generic/tkCanvText.c +++ b/generic/tkCanvText.c @@ -161,7 +161,7 @@ static int TextCoords(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, Tcl_Obj *const objv[]); static void TextDeleteChars(Tk_Canvas canvas, - Tk_Item *itemPtr, int first, int last); + Tk_Item *itemPtr, TkSizeT first, TkSizeT last); static void TextInsert(Tk_Canvas canvas, Tk_Item *itemPtr, TkSizeT beforeThis, Tcl_Obj *obj); static int TextToArea(Tk_Canvas canvas, @@ -1091,9 +1091,9 @@ static void TextDeleteChars( Tk_Canvas canvas, /* Canvas containing itemPtr. */ Tk_Item *itemPtr, /* Item in which to delete characters. */ - int first, /* Character index of first character to + TkSizeT first, /* Character index of first character to * delete. */ - int last) /* Character index of last character to delete + TkSizeT last) /* Character index of last character to delete * (inclusive). */ { TextItem *textPtr = (TextItem *) itemPtr; @@ -1102,13 +1102,13 @@ TextDeleteChars( Tk_CanvasTextInfo *textInfoPtr = textPtr->textInfoPtr; text = textPtr->text; - if (first < 0) { + if ((int)first < 0) { first = 0; } - if (last >= (int)textPtr->numChars) { + if (last + 1 >= textPtr->numChars + 1) { last = textPtr->numChars - 1; } - if (first > last) { + if (first + 1 > last + 1) { return; } charsRemoved = last + 1 - first; @@ -1132,15 +1132,15 @@ TextDeleteChars( */ if (textInfoPtr->selItemPtr == itemPtr) { - if (textInfoPtr->selectFirst + 1 > (TkSizeT)first + 1) { + if (textInfoPtr->selectFirst + 1 > first + 1) { textInfoPtr->selectFirst -= charsRemoved; if ((int)textInfoPtr->selectFirst + 1 < (int)first + 1) { textInfoPtr->selectFirst = first; } } - if (textInfoPtr->selectLast + 1 >= (TkSizeT)first + 1) { + if (textInfoPtr->selectLast + 1 >= first + 1) { textInfoPtr->selectLast -= charsRemoved; - if (textInfoPtr->selectLast + 1 < (TkSizeT)first) { + if (textInfoPtr->selectLast + 1 < first) { textInfoPtr->selectLast = first - 1; } } @@ -1148,14 +1148,14 @@ TextDeleteChars( textInfoPtr->selItemPtr = NULL; } if ((textInfoPtr->anchorItemPtr == itemPtr) - && (textInfoPtr->selectAnchor + 1 > (TkSizeT)first + 1)) { + && (textInfoPtr->selectAnchor + 1 > first + 1)) { textInfoPtr->selectAnchor -= charsRemoved; - if (textInfoPtr->selectAnchor + 1 < (TkSizeT)first + 1) { + if (textInfoPtr->selectAnchor + 1 < first + 1) { textInfoPtr->selectAnchor = first; } } } - if (textPtr->insertPos + 1 > (TkSizeT)first + 1) { + if (textPtr->insertPos + 1 > first + 1) { textPtr->insertPos -= charsRemoved; if ((int)textPtr->insertPos + 1 < (int)first + 1) { textPtr->insertPos = first; diff --git a/generic/tkText.c b/generic/tkText.c index 2f5991b..39be0b7 100644 --- a/generic/tkText.c +++ b/generic/tkText.c @@ -279,10 +279,10 @@ typedef ClientData SearchAddLineProc(int lineNum, typedef int SearchMatchProc(int lineNum, struct SearchSpec *searchSpecPtr, ClientData clientData, Tcl_Obj *theLine, - int matchOffset, int matchLength); + TkSizeT matchOffset, TkSizeT matchLength); typedef int SearchLineIndexProc(Tcl_Interp *interp, Tcl_Obj *objPtr, struct SearchSpec *searchSpecPtr, - int *linePosPtr, int *offsetPosPtr); + int *linePosPtr, TkSizeT *offsetPosPtr); typedef struct SearchSpec { int exact; /* Whether search is exact or regexp. */ @@ -298,10 +298,10 @@ typedef struct SearchSpec { int all; /* Whether all or the first match should be * reported. */ int startLine; /* First line to examine. */ - int startOffset; /* Index in first line to start at. */ + TkSizeT startOffset1; /* Index in first line to start at. */ int stopLine; /* Last line to examine, or -1 when we search * all available text. */ - int stopOffset; /* Index to stop at, provided stopLine is not + TkSizeT stopOffset1; /* Index to stop at, provided stopLine is not * -1. */ int numLines; /* Total lines which are available. */ int backwards; /* Searching forwards or backwards. */ @@ -410,8 +410,8 @@ static void TextPushUndoAction(TkText *textPtr, Tcl_Obj *undoString, int insert, const TkTextIndex *index1Ptr, const TkTextIndex *index2Ptr); -static int TextSearchIndexInLine(const SearchSpec *searchSpecPtr, - TkTextLine *linePtr, int byteIndex); +static TkSizeT TextSearchIndexInLine(const SearchSpec *searchSpecPtr, + TkTextLine *linePtr, TkSizeT byteIndex); static int TextPeerCmd(TkText *textPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static TkUndoProc TextUndoRedoCallback; @@ -4015,7 +4015,7 @@ TextSearchGetLineIndex( Tcl_Obj *objPtr, /* Contains a textual index like "1.2" */ SearchSpec *searchSpecPtr, /* Contains other search parameters. */ int *linePosPtr, /* For returning the line number. */ - int *offsetPosPtr) /* For returning the text offset in the + TkSizeT *offsetPosPtr) /* For returning the text offset in the * line. */ { const TkTextIndex *indexPtr; @@ -4075,35 +4075,36 @@ TextSearchGetLineIndex( *---------------------------------------------------------------------- */ -static int +static TkSizeT TextSearchIndexInLine( const SearchSpec *searchSpecPtr, /* Search parameters. */ TkTextLine *linePtr, /* The line we're looking at. */ - int byteIndex) /* Index into the line. */ + TkSizeT byteIndex) /* Index into the line. */ { TkTextSegment *segPtr; TkTextIndex curIndex; - int index, leftToScan; + TkSizeT index; + int leftToScan; TkText *textPtr = (TkText *)searchSpecPtr->clientData; index = 0; curIndex.tree = textPtr->sharedTextPtr->tree; curIndex.linePtr = linePtr; curIndex.byteIndex = 0; for (segPtr = linePtr->segPtr, leftToScan = byteIndex; - leftToScan > 0; + leftToScan + 1 > 1; curIndex.byteIndex += segPtr->size, segPtr = segPtr->nextPtr) { if ((segPtr->typePtr == &tkTextCharType) && (searchSpecPtr->searchElide || !TkTextIsElided(textPtr, &curIndex, NULL))) { - if (leftToScan < (int)segPtr->size) { + if (leftToScan + 1 < (int)segPtr->size + 1) { if (searchSpecPtr->exact) { index += leftToScan; } else { index += Tcl_NumUtfChars(segPtr->body.chars, leftToScan); } } else if (searchSpecPtr->exact) { - index += (int)segPtr->size; + index += segPtr->size; } else { index += Tcl_NumUtfChars(segPtr->body.chars, -1); } @@ -4267,9 +4268,9 @@ TextSearchFoundMatch( Tcl_Obj *theLine, /* Text from current line, only accessed for * exact searches, and is allowed to be NULL * for regexp searches. */ - int matchOffset, /* Offset of found item in utf-8 bytes for + TkSizeT matchOffset, /* Offset of found item in utf-8 bytes for * exact search, Unicode chars for regexp. */ - int matchLength) /* Length also in bytes/chars as per search + TkSizeT matchLength) /* Length also in bytes/chars as per search * type. */ { TkSizeT numChars; @@ -4287,7 +4288,7 @@ TextSearchFoundMatch( */ if (searchSpecPtr->backwards ^ - (matchOffset >= searchSpecPtr->stopOffset)) { + (matchOffset + 1 >= searchSpecPtr->stopOffset1 + 1)) { return 0; } } @@ -4312,7 +4313,7 @@ TextSearchFoundMatch( if (searchSpecPtr->strictLimits && lineNum == searchSpecPtr->stopLine) { if (searchSpecPtr->backwards ^ - ((matchOffset + numChars + 1) > (TkSizeT) searchSpecPtr->stopOffset + 1)) { + ((matchOffset + numChars + 1) > searchSpecPtr->stopOffset1 + 1)) { return 0; } } @@ -5663,7 +5664,7 @@ SearchPerform( if (searchSpecPtr->lineIndexProc(interp, fromPtr, searchSpecPtr, &searchSpecPtr->startLine, - &searchSpecPtr->startOffset) != TCL_OK) { + &searchSpecPtr->startOffset1) != TCL_OK) { return TCL_ERROR; } @@ -5694,7 +5695,7 @@ SearchPerform( if (searchSpecPtr->lineIndexProc(interp, toPtr, searchSpecPtr, &searchSpecPtr->stopLine, - &searchSpecPtr->stopOffset) != TCL_OK) { + &searchSpecPtr->stopOffset1) != TCL_OK) { return TCL_ERROR; } } else { @@ -5893,7 +5894,7 @@ SearchCore( } if (lineNum == searchSpecPtr->stopLine && searchSpecPtr->backwards) { - firstOffset = searchSpecPtr->stopOffset; + firstOffset = searchSpecPtr->stopOffset1; } else { firstOffset = 0; } @@ -5927,8 +5928,8 @@ SearchCore( * Only use the last part of the line. */ - if (searchSpecPtr->startOffset > firstOffset) { - firstOffset = searchSpecPtr->startOffset; + if (searchSpecPtr->startOffset1 + 1 > (TkSizeT)firstOffset + 1) { + firstOffset = searchSpecPtr->startOffset1; } if ((firstOffset >= lastOffset) && ((lastOffset != 0) || searchSpecPtr->exact)) { @@ -5939,8 +5940,8 @@ SearchCore( * Use only the first part of the line. */ - if (searchSpecPtr->startOffset < lastOffset) { - lastOffset = searchSpecPtr->startOffset; + if (searchSpecPtr->startOffset1 + 1 < (TkSizeT)lastOffset + 1) { + lastOffset = searchSpecPtr->startOffset1; } } } -- cgit v0.12 From 036a7d32a1d9178d587e502932f33a481483c9fa Mon Sep 17 00:00:00 2001 From: fvogel Date: Tue, 2 Jun 2020 21:56:14 +0000 Subject: Remove proc waitForGrab from test bind-35.1 --- tests/bind.test | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/tests/bind.test b/tests/bind.test index aa91126..d8a6c41 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6698,44 +6698,27 @@ test bind-34.3 {-warp works with null or negative coordinates} -setup { } -cleanup { } -result {ok ok ok ok} -test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -constraints { - testgrab -} -setup { - proc waitForGrab {type grabWin} { - # process events while $grabWin is not grabbed ($type == "grabbed"), - # or while $grabWin is not released ($type == "released"), but don't - # spend more than 5 seconds doing this - set i 0 - while {![testgrab $type $grabWin] && $i < 500} { - after 10 - update - incr i - } - } +test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -setup { event generate {} -warp 1 -x 50 -y 50 toplevel .top grab release .top - waitForGrab released .top wm geometry .top 200x200+300+300 label .top.l -height 5 -width 20 -highlightthickness 2 \ -highlightbackground black -bg yellow -text "My label" pack .top.l -side bottom update } -body { - grab .top ; # this will queue events - waitForGrab grabbed .top + grab .top event generate .top.l -warp 1 -x 10 -y 10 foreach {x1 y1} [winfo pointerxy .top.l] {} event generate {} -warp 1 -x 50 -y 50 - grab release .top ; # this will queue events - waitForGrab released .top + grab release .top event generate .top.l -warp 1 -x 10 -y 10 foreach {x2 y2} [winfo pointerxy .top.l] {} expr {$x1==$x2 && $y1==$y2} } -cleanup { destroy .top unset x1 y1 x2 y2 - rename waitForGrab {} } -result {1} # cleanup -- cgit v0.12 From 932a73175b6850265b0a9af952dfd667e41b9231 Mon Sep 17 00:00:00 2001 From: fvogel Date: Tue, 2 Jun 2020 21:59:29 +0000 Subject: Remove now useless command and test constraint testgrab --- generic/tkTest.c | 78 --------------------------------------------------- tests/constraints.tcl | 1 - 2 files changed, 79 deletions(-) diff --git a/generic/tkTest.c b/generic/tkTest.c index 1f373ad..a8929b9 100644 --- a/generic/tkTest.c +++ b/generic/tkTest.c @@ -206,9 +206,6 @@ static int TrivialConfigObjCmd(ClientData dummy, Tcl_Obj * const objv[]); static void TrivialEventProc(ClientData clientData, XEvent *eventPtr); -static int TestgrabObjCmd(ClientData clientData, - Tcl_Interp *interp, int objc, - Tcl_Obj *const objv[]); /* *---------------------------------------------------------------------- @@ -284,9 +281,6 @@ Tktest_Init( (ClientData) Tk_MainWindow(interp), NULL); #endif /* _WIN32 */ - Tcl_CreateObjCommand(interp, "testgrab", TestgrabObjCmd, - (ClientData) Tk_MainWindow(interp), NULL); - /* * Create test image type. */ @@ -2084,78 +2078,6 @@ CustomOptionFree( } /* - *---------------------------------------------------------------------- - * - * TestgrabObjCmd -- - * - * This function implements the "testgrab" command, which is used to test - * grabbing of windows. - * - * testgrab grabbed $win: returns true if $win is currently grabbed - * testgrab released $win: returns true if $win is currently not grabbed - * - * This function is useful when one wants to test for a grabbing window - * at the moment it is called. [grab current] cannot be used for that - * purpose because it returns the window dereferenced by eventualGrabWinPtr - * - * Results: - * A standard Tcl result. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -TestgrabObjCmd( - ClientData clientData, /* Main window for application. */ - Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ - Tcl_Obj *const objv[]) /* Argument objects. */ -{ - static const char *const options[] = {"grabbed", "released", NULL}; - enum option {GRABBED, RELEASED}; - int index, res = 0; - Tk_Window mainWin, tkwin; - - mainWin = (Tk_Window) clientData; - - if (objc < 3) { - Tcl_WrongNumArgs(interp, 1, objv, "option window"); - return TCL_ERROR; - } - - if (Tcl_GetIndexFromObjStruct(interp, objv[1], options, - sizeof(char *), "command", 0, &index)!= TCL_OK) { - return TCL_ERROR; - } - - tkwin = Tk_NameToWindow(interp, Tcl_GetString(objv[2]), mainWin); - if (tkwin == NULL) { - return TCL_ERROR; - } - /*printf("TestgrabObjCmd %s, grabWinPtr = %p , tkwin = %p\n", options[index], - ((TkWindow *) tkwin)->dispPtr->grabWinPtr, tkwin);fflush(stdout);*/ - - switch ((enum option) index) { - case GRABBED: - if (TkGrabState((TkWindow *) tkwin) != TK_GRAB_NONE) { - res = 1; - } - break; - case RELEASED: - if (TkGrabState((TkWindow *) tkwin) == TK_GRAB_NONE) { - res = 1; - } - break; - } - - Tcl_SetObjResult(interp, Tcl_NewBooleanObj(res)); - return TCL_OK; -} - -/* * Local Variables: * mode: c * c-basic-offset: 4 diff --git a/tests/constraints.tcl b/tests/constraints.tcl index 49da142..c77fb00 100644 --- a/tests/constraints.tcl +++ b/tests/constraints.tcl @@ -207,7 +207,6 @@ testConstraint testcolor [llength [info commands testcolor]] testConstraint testcursor [llength [info commands testcursor]] testConstraint testembed [llength [info commands testembed]] testConstraint testfont [llength [info commands testfont]] -testConstraint testgrab [llength [info commands testgrab]] testConstraint testmakeexist [llength [info commands testmakeexist]] testConstraint testmenubar [llength [info commands testmenubar]] testConstraint testmetrics [llength [info commands testmetrics]] -- cgit v0.12 From 876fc6d65e63ae72fe52d8435ef703efa50fe814 Mon Sep 17 00:00:00 2001 From: marc_culler Date: Wed, 3 Jun 2020 03:23:12 +0000 Subject: Do not draw in the setup proc. Fix the heartbeat so it can wake up Tcl_WaitForEvent. Handle the first drawing of a window. --- macosx/tkMacOSXDraw.c | 22 ++++++------ macosx/tkMacOSXNotify.c | 84 +++++++++++++++++++++++--------------------- macosx/tkMacOSXWindowEvent.c | 21 ++++++++--- 3 files changed, 71 insertions(+), 56 deletions(-) diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index 1ec2cfe..6a63449 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -1658,19 +1658,19 @@ TkMacOSXSetupDrawingContext( } else if (dc.clipRgn) { /* - * Drawing can also fail when we are being called from drawRect but - * the clipping region set by drawRect does not contain the clipping - * region of our drawing context. See bug [2a61eca3a8]. + * Drawing will also fail if we are being called from drawRect but + * the clipping rectangle set by drawRect does not contain the + * clipping region of our drawing context. See bug [2a61eca3a8]. + * If we can't draw all of the clipping region of the drawing + * context then we draw whatever we can, but we also add a dirty + * rectangle so the entire widget will get redrawn in the next + * cycle. */ CGRect currentClip = CGContextGetClipBoundingBox( [NSGraphicsContext currentContext].CGContext); if (!NSContainsRect(currentClip, clipBounds)) { [view addTkDirtyRect:clipBounds]; - // XXXX we should be able to skip drawing but sometimes the clipBounds - // are wrong. - //canDraw = false; - //goto end; } } @@ -1715,10 +1715,10 @@ TkMacOSXSetupDrawingContext( CGRect r; if (!HIShapeIsRectangular(dc.clipRgn) || !CGRectContainsRect( - *HIShapeGetBounds(dc.clipRgn, &r), - CGRectApplyAffineTransform(clipBounds, t))) { - ChkErr(HIShapeReplacePathInCGContext, dc.clipRgn, dc.context); - CGContextEOClip(dc.context); + *HIShapeGetBounds(dc.clipRgn, &r), + CGRectApplyAffineTransform(clipBounds, t))) { + ChkErr(HIShapeReplacePathInCGContext, dc.clipRgn, dc.context); + CGContextEOClip(dc.context); } } if (gc) { diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c index 7de6bec..8bf5e66 100644 --- a/macosx/tkMacOSXNotify.c +++ b/macosx/tkMacOSXNotify.c @@ -398,12 +398,24 @@ TkMacOSXDrawAllViews( *---------------------------------------------------------------------- */ +#define TICK 100 +static Tcl_TimerToken ticker = NULL; + +static void +Heartbeat( + ClientData clientData) +{ + + if (ticker) { + ticker = Tcl_CreateTimerHandler(TICK, Heartbeat, NULL); + } +} + static void TkMacOSXEventsSetupProc( ClientData clientData, int flags) { - static Bool havePeriodicEvents = NO; NSString *runloopMode = [[NSRunLoop currentRunLoop] currentMode]; /* @@ -412,6 +424,7 @@ TkMacOSXEventsSetupProc( if (flags & TCL_WINDOW_EVENTS && !runloopMode) { static const Tcl_Time zeroBlockTime = { 0, 0 }; + [NSApp _resetAutoreleasePool]; /* @@ -427,26 +440,21 @@ TkMacOSXEventsSetupProc( untilDate:[NSDate distantPast] inMode:GetRunLoopMode(TkMacOSXGetModalSession()) dequeue:NO]; - if (currentEvent) { - if (currentEvent.type > 0) { + if (currentEvent && currentEvent.type > 0) { Tcl_SetMaxBlockTime(&zeroBlockTime); - [NSEvent stopPeriodicEvents]; - havePeriodicEvents = NO; - } - } else if (!havePeriodicEvents){ - - /* - * When the user is not generating events we schedule a "heartbeat" - * event to fire every 0.1 seconds. This helps to make the vwait - * command more responsive when there is no user input, e.g. when - * running the test suite. - */ - - havePeriodicEvents = YES; - [NSEvent startPeriodicEventsAfterDelay:0.0 withPeriod:0.1]; - } - while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {}; - TkMacOSXDrawAllViews(NULL); + Tcl_DeleteTimerHandler(ticker); + ticker = NULL; + } else if (ticker == NULL) { + + /* + * When the user is not generating events we schedule a "heartbeat" + * TimerHandler to fire every 200 milliseconds. The handler does + * nothing, but when its timer fires TclWaitForEvent will return, + * causing TkMacOSXCheckProc to be called. + */ + + ticker = Tcl_CreateTimerHandler(TICK, Heartbeat, NULL); + } } } @@ -543,28 +551,24 @@ TkMacOSXEventsCheckProc( */ [NSApp _unlockAutoreleasePool]; - if (eventsFound == 0) { - /* - * We found no events for Tcl in this iteration of the Tcl event - * loop, so it should proceed to servicing idle tasks. We add an - * idle task to the end of the idle queue which will redisplay all - * of our dirty windows. We want this to happen after all other - * idle tasks have run so that all widgets will be configured - * before they are displayed. The drawRect method "borrows" the - * idle queue while drawing views. That is, it sends expose events - * which cause display procs to be posted as idle tasks and then - * runs an inner event loop to processes those idle tasks. We are - * trying to arrange for the idle queue to be empty when it starts - * that process and empty when it finishes. - */ + /* + * Add an idle task to the end of the idle queue which will redisplay + * all of our dirty windows. We want this to happen after all other + * idle tasks have run so that all widgets will be configured before + * they are displayed. The drawRect method "borrows" the idle queue + * while drawing views. That is, it sends expose events which cause + * display procs to be posted as idle tasks and then runs an inner + * event loop to processes those idle tasks. We are trying to arrange + * for the idle queue to be empty when it starts that process and empty + * when it finishes. + */ - int dirtyCount = 0; - TkMacOSXDrawAllViews(&dirtyCount); - if (dirtyCount > 0) { - Tcl_CancelIdleCall(TkMacOSXDrawAllViews, NULL); - Tcl_DoWhenIdle(TkMacOSXDrawAllViews, NULL); - } + int dirtyCount = 0; + TkMacOSXDrawAllViews(&dirtyCount); + if (dirtyCount > 0) { + Tcl_CancelIdleCall(TkMacOSXDrawAllViews, NULL); + Tcl_DoWhenIdle(TkMacOSXDrawAllViews, NULL); } } } diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 0f58c70..d052005 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -38,6 +38,8 @@ static void DoWindowActivate(ClientData clientData); #pragma mark TKApplication(TKWindowEvent) +extern NSString *NSWindowDidOrderOnScreenNotification; + #ifdef TK_MAC_DEBUG_NOTIFICATIONS extern NSString *NSWindowWillOrderOnScreenNotification; extern NSString *NSWindowDidOrderOnScreenNotification; @@ -208,6 +210,18 @@ extern NSString *NSWindowDidOrderOffScreenNotification; return (winPtr ? NO : YES); } +- (void) windowBecameVisible: (NSNotification *) notification +{ + NSWindow *window = [notification object]; + TkWindow *winPtr = TkMacOSXGetTkWindow(window); + if (winPtr) { + TKContentView *view = [window contentView]; + while(Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {}; + [view setTkDirtyRect:[view bounds]]; + TkMacOSXDrawAllViews(NULL); + } +} + #ifdef TK_MAC_DEBUG_NOTIFICATIONS - (void) windowDragStart: (NSNotification *) notification @@ -227,16 +241,12 @@ extern NSString *NSWindowDidOrderOffScreenNotification; NSWindow *w = [notification object]; TkWindow *winPtr = TkMacOSXGetTkWindow(w); + printf("windowMapped\n"); if (winPtr) { //Tk_MapWindow((Tk_Window) winPtr); } } -- (void) windowBecameVisible: (NSNotification *) notification -{ - TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); -} - - (void) windowUnmapped: (NSNotification *) notification { TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); @@ -263,6 +273,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification; observe(NSWindowDidResizeNotification, windowBoundsChanged:); observe(NSWindowDidDeminiaturizeNotification, windowExpanded:); observe(NSWindowDidMiniaturizeNotification, windowCollapsed:); + observe(NSWindowDidOrderOnScreenNotification, windowBecameVisible:); #if !(MAC_OS_X_VERSION_MAX_ALLOWED < 1070) observe(NSWindowDidEnterFullScreenNotification, windowEnteredFullScreen:); -- cgit v0.12 From 9fb818caa0ef424af5d38f5be645c0e911460eda Mon Sep 17 00:00:00 2001 From: fvogel Date: Wed, 3 Jun 2020 05:56:44 +0000 Subject: Remove excess spacing. --- generic/tkGrab.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tkGrab.c b/generic/tkGrab.c index 8f09f50..9a28f62 100644 --- a/generic/tkGrab.c +++ b/generic/tkGrab.c @@ -787,7 +787,7 @@ TkPointerEvent( TkDoWarpWrtWin(dispPtr); } - + if (!appGrabbed) { return 1; } -- cgit v0.12 From ebbce5dd4848c8dd3bf2ea49d23f83fc2343e425 Mon Sep 17 00:00:00 2001 From: oehhar Date: Thu, 4 Jun 2020 19:12:50 +0000 Subject: photo read command: memory error on shrink option did not close the channel --- generic/tkImgPhoto.c | 1 + 1 file changed, 1 insertion(+) diff --git a/generic/tkImgPhoto.c b/generic/tkImgPhoto.c index 96c3743..ab962c1 100644 --- a/generic/tkImgPhoto.c +++ b/generic/tkImgPhoto.c @@ -1106,6 +1106,7 @@ ImgPhotoCmd( Tcl_SetObjResult(interp, Tcl_NewStringObj( TK_PHOTO_ALLOC_FAILURE_MESSAGE, -1)); Tcl_SetErrorCode(interp, "TK", "MALLOC", NULL); + Tcl_Close(NULL, chan); return TCL_ERROR; } } -- cgit v0.12 From f31664f2a7c475db0fcb646accf6f58d78407da8 Mon Sep 17 00:00:00 2001 From: culler Date: Fri, 5 Jun 2020 18:00:00 +0000 Subject: Fixed a bug in TkpDrawAllViews and added a mechanism to prevent Tcl_WaitForEvent from blocking if there is drawing that needs to be done. --- macosx/tkMacOSXDraw.c | 5 ++--- macosx/tkMacOSXNotify.c | 41 ++++++++++++++++++++++------------------- macosx/tkMacOSXPrivate.h | 2 ++ macosx/tkMacOSXSubwindows.c | 9 +++------ macosx/tkMacOSXWindowEvent.c | 9 +++++---- tests/listbox.test | 21 ++++++++------------- 6 files changed, 42 insertions(+), 45 deletions(-) diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index 6a63449..f3d6ba4 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -176,7 +176,7 @@ TkMacOSXBitmapRepFromDrawableRect( } } else if (TkMacOSXDrawableView(mac_drawable) != NULL) { TKContentView *tkview = (TKContentView *)view; - + /* * Convert Tk top-left to NSView bottom-left coordinates. */ @@ -199,8 +199,7 @@ TkMacOSXBitmapRepFromDrawableRect( [view cacheDisplayInRect:view_rect toBitmapImageRep:bitmap_rep]; } else { TkMacOSXDbgMsg("No CGContext - cannot copy from screen to bitmap."); - [tkview setTkNeedsDisplay:YES]; - [tkview setTkDirtyRect:[tkview bounds]]; + [tkview addTkDirtyRect:[tkview bounds]]; return NULL; } } else { diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c index 8bf5e66..daa1321 100644 --- a/macosx/tkMacOSXNotify.c +++ b/macosx/tkMacOSXNotify.c @@ -346,7 +346,6 @@ TkMacOSXDrawAllViews( continue; } [view setNeedsDisplayInRect:[view tkDirtyRect]]; - [view setTkDirtyRect:NSZeroRect]; } } else { [window displayIfNeeded]; @@ -374,6 +373,7 @@ TkMacOSXDrawAllViews( } } } + [NSApp setNeedsToDraw:NO]; } /* @@ -392,13 +392,14 @@ TkMacOSXDrawAllViews( * * Side effects: * - * If NSEvents are queued, then the maximum block time will be set to 0 to - * ensure that control returns immediately to Tcl. + * If NSEvents are queued, or if there is any drawing that needs to be + * done, then the maximum block time will be set to 0 to ensure that + * Tcl_WaitForEvent returns immediately. * *---------------------------------------------------------------------- */ -#define TICK 100 +#define TICK 200 static Tcl_TimerToken ticker = NULL; static void @@ -428,11 +429,13 @@ TkMacOSXEventsSetupProc( [NSApp _resetAutoreleasePool]; /* - * Call this with dequeue=NO to see if there are any events. If so, we - * set the block time to 0 and stop the heartbeat. Next Tcl_DoOneEvent - * will call Tcl_WaitForEvent, which will poll instead of waiting since - * the block time is 0. Then it will call check proc to collect the + * After calling this setup proc, Tcl_DoOneEvent will call + * Tcl_WaitForEvent. Then it will call check proc to collect the * events and translate them into XEvents. + * + * If we have any events waiting or if there is any drawing to be done + * we want Tcl_WaitForEvent to return immediately. So we set the block + * time to 0. We also stop the heartbeat, since we won't need it. */ NSEvent *currentEvent = @@ -440,21 +443,21 @@ TkMacOSXEventsSetupProc( untilDate:[NSDate distantPast] inMode:GetRunLoopMode(TkMacOSXGetModalSession()) dequeue:NO]; - if (currentEvent && currentEvent.type > 0) { - Tcl_SetMaxBlockTime(&zeroBlockTime); - Tcl_DeleteTimerHandler(ticker); - ticker = NULL; + if ((currentEvent) || [NSApp needsToDraw] ) { + Tcl_SetMaxBlockTime(&zeroBlockTime); + Tcl_DeleteTimerHandler(ticker); + ticker = NULL; } else if (ticker == NULL) { - /* - * When the user is not generating events we schedule a "heartbeat" - * TimerHandler to fire every 200 milliseconds. The handler does - * nothing, but when its timer fires TclWaitForEvent will return, - * causing TkMacOSXCheckProc to be called. - */ + /* + * When the user is not generating events we schedule a "heartbeat" + * TimerHandler to fire every 200 milliseconds. The handler does + * nothing, but when its timer fires it causes Tcl_WaitForEvent to + * return. This helps avoid hangs when calling vwait. + */ ticker = Tcl_CreateTimerHandler(TICK, Heartbeat, NULL); - } + } } } diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h index 719b0b1..40bbd9c 100644 --- a/macosx/tkMacOSXPrivate.h +++ b/macosx/tkMacOSXPrivate.h @@ -345,11 +345,13 @@ VISIBILITY_HIDDEN int _poolLock; int _macMinorVersion; Bool _isDrawing; + Bool _needsToDraw; #endif } @property int poolLock; @property int macMinorVersion; @property Bool isDrawing; +@property Bool needsToDraw; @end @interface TKApplication(TKInit) diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c index c25f600..bf59901 100644 --- a/macosx/tkMacOSXSubwindows.c +++ b/macosx/tkMacOSXSubwindows.c @@ -170,8 +170,7 @@ XMapWindow( TkMacOSXApplyWindowAttributes(winPtr, win); [win setExcludedFromWindowsMenu:NO]; [NSApp activateIgnoringOtherApps:NO]; - [view setTkNeedsDisplay:YES]; - [view setTkDirtyRect: [view bounds]]; + [view addTkDirtyRect: [view bounds]]; if ([win canBecomeKeyWindow]) { [win makeKeyAndOrderFront:NSApp]; } else { @@ -218,8 +217,7 @@ XMapWindow( [[win contentView] setNeedsRedisplay:YES]; } else { TKContentView *view = [win contentView]; - [view setTkNeedsDisplay:YES]; - [view setTkDirtyRect:[view bounds]]; + [view addTkDirtyRect:[view bounds]]; } /* @@ -337,8 +335,7 @@ XUnmapWindow( [[win contentView] setNeedsRedisplay:YES]; } else { TKContentView *view = [win contentView]; - [view setTkNeedsDisplay:YES]; - [view setTkDirtyRect:[view bounds]]; + [view addTkDirtyRect:[view bounds]]; } return Success; } diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index d052005..b5e6ee3 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -217,7 +217,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification; if (winPtr) { TKContentView *view = [window contentView]; while(Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {}; - [view setTkDirtyRect:[view bounds]]; + [view addTkDirtyRect:[view bounds]]; TkMacOSXDrawAllViews(NULL); } } @@ -433,8 +433,7 @@ TkpWillDrawWidget(Tk_Window tkwin) { printf("TkpAppCanDraw: dirtyRect for %s is %s\n", Tk_PathName(tkwin), NSStringFromRect(dirtyRect).UTF8String); - [view setTkNeedsDisplay:YES]; - [view setTkDirtyRect:dirtyRect]; + [view addTkDirtyRect:dirtyRect]; } #endif } else { @@ -936,12 +935,14 @@ ConfigureRestrictProc( { _tkNeedsDisplay = YES; _tkDirtyRect = NSUnionRect(_tkDirtyRect, rect); + [NSApp setNeedsToDraw:YES]; } - (void) clearTkDirtyRect { _tkNeedsDisplay = NO; _tkDirtyRect = NSZeroRect; + [NSApp setNeedsToDraw:NO]; } - (void) drawRect: (NSRect) rect @@ -968,7 +969,7 @@ ConfigureRestrictProc( } [NSApp setIsDrawing: YES]; - [self setTkDirtyRect:NSZeroRect]; + [self clearTkDirtyRect]; [self generateExposeEvents:rect]; [self setTkNeedsDisplay: NO]; [NSApp setIsDrawing: NO]; diff --git a/tests/listbox.test b/tests/listbox.test index 8d4ed33..0917e84 100644 --- a/tests/listbox.test +++ b/tests/listbox.test @@ -2666,7 +2666,7 @@ test listbox-21.9 {ListboxListVarProc, test hscrollbar after listvar mod} -setup listbox .l -font $fixed -width 10 -xscrollcommand "record x" -listvar x set log {} pack .l - set timeout [after 500 {set log timeout}] + set timeout [after 500 {set log timeout}] vwait log lappend x "0000000000" update @@ -2684,7 +2684,7 @@ test listbox-21.10 {ListboxListVarProc, test hscrollbar after listvar mod} -setu listbox .l -font $fixed -width 10 -xscrollcommand "record x" -listvar x set log {} pack .l - set timeout [after 500 {set log timeout}] + set timeout [after 500 {set log timeout}] vwait log lappend x "0000000000" update @@ -2764,7 +2764,7 @@ test listbox-21.15 {ListboxListVarProc, update vertical scrollbar} -setup { update set log {} pack .l - set timeout [after 500 {set log timeout}] + set timeout [after 500 {set log timeout}] vwait log update lappend x a b c d e f @@ -2800,20 +2800,20 @@ test listbox-21.16 {ListboxListVarProc, update vertical scrollbar} -setup { test listbox-22.1 {UpdateHScrollbar} -setup { destroy .l } -body { - set log {} listbox .l -font $fixed -width 10 -xscrollcommand "record x" pack .l - set timeout [after 500 {set log timeout}] - vwait log - .l insert end "0000000000" update idletasks + set log {} + set timeout [after 500 {set log timeout}] + .l insert end "0000000000" + vwait log .l insert end "00000000000000000000" vwait log set log } -cleanup { destroy .l after cancel $timeout -} -result [list {x 0 1} {x 0 1} {x 0 0.5}] +} -result [list {x 0 1} {x 0 0.5}] # ConfigureListboxItem @@ -3221,8 +3221,3 @@ option clear # cleanup cleanupTests return - - - - - -- cgit v0.12 From e159a0d79d67dd98e17595c467599e0a54837677 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sat, 6 Jun 2020 07:45:20 +0000 Subject: Update leftover comments that didn't follow the changes made in [0deef053f6] --- generic/tkCanvas.c | 4 ++-- generic/tkListbox.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/generic/tkCanvas.c b/generic/tkCanvas.c index 4d68ade..8230122 100644 --- a/generic/tkCanvas.c +++ b/generic/tkCanvas.c @@ -5556,8 +5556,8 @@ CanvasUpdateScrollbars( Tcl_DString buf; /* - * Save all the relevant values from the canvasPtr, because it might be - * deleted as part of either of the two calls to Tcl_VarEval below. + * Preserve the relevant values from the canvasPtr, because it might be + * deleted as part of either of the two calls to Tcl_EvalEx below. */ interp = canvasPtr->interp; diff --git a/generic/tkListbox.c b/generic/tkListbox.c index d92325f..b00a895 100644 --- a/generic/tkListbox.c +++ b/generic/tkListbox.c @@ -3318,7 +3318,7 @@ ListboxUpdateVScrollbar( /* * We must hold onto the interpreter from the listPtr because the data at - * listPtr might be freed as a result of the Tcl_VarEval. + * listPtr might be freed as a result of the Tcl_EvalEx. */ interp = listPtr->interp; @@ -3390,7 +3390,7 @@ ListboxUpdateHScrollbar( /* * We must hold onto the interpreter because the data referred to at - * listPtr might be freed as a result of the call to Tcl_VarEval. + * listPtr might be freed as a result of the call to Tcl_EvalEx. */ interp = listPtr->interp; -- cgit v0.12 From c6c4a8052b1935186c0efaf8269deac67e050a22 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sat, 6 Jun 2020 15:06:52 +0000 Subject: Make success criterion for test bind-35.1 more specific, so that this same test passes in branch bug-e3888d5820-alt1 but fails in core-8-6-branch (previously bind-35.1 did not fail in core-8-6-branch, in which bug [e3888d5820] is not yet solved). --- tests/bind.test | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/bind.test b/tests/bind.test index d8a6c41..963119e 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6715,7 +6715,10 @@ test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -setup { grab release .top event generate .top.l -warp 1 -x 10 -y 10 foreach {x2 y2} [winfo pointerxy .top.l] {} - expr {$x1==$x2 && $y1==$y2} + # success if the coords are the same with or without the grab, and if they + # are at least at (10,10) inside the window located at (300,300). + # ">=" instead of "==" to take WM-specific decorations into account. + expr {$x1==$x2 && $y1==$y2 && $x1>=310 && $y1>=310} } -cleanup { destroy .top unset x1 y1 x2 y2 -- cgit v0.12 From bcf017e94b644b427d704da23be4bbe164978fff Mon Sep 17 00:00:00 2001 From: culler Date: Sat, 6 Jun 2020 18:53:04 +0000 Subject: A different attempt to make sure new windows are completely drawn. --- macosx/tkMacOSXKeyEvent.c | 3 +-- macosx/tkMacOSXNotify.c | 3 +++ macosx/tkMacOSXWindowEvent.c | 6 +++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/macosx/tkMacOSXKeyEvent.c b/macosx/tkMacOSXKeyEvent.c index e0b0094..bff9e26 100644 --- a/macosx/tkMacOSXKeyEvent.c +++ b/macosx/tkMacOSXKeyEvent.c @@ -255,12 +255,11 @@ static NSUInteger textInputModifiers; */ if (type == NSKeyDown && [theEvent isARepeat]) { + xEvent.xany.type = KeyRelease; Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL); xEvent.xany.type = KeyPress; } - if (xEvent.xany.type == KeyPress) { - } Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL); return theEvent; } diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c index daa1321..3433e56 100644 --- a/macosx/tkMacOSXNotify.c +++ b/macosx/tkMacOSXNotify.c @@ -457,6 +457,9 @@ TkMacOSXEventsSetupProc( */ ticker = Tcl_CreateTimerHandler(TICK, Heartbeat, NULL); + Tcl_CancelIdleCall(TkMacOSXDrawAllViews, NULL); + Tcl_DoWhenIdle(TkMacOSXDrawAllViews, NULL); + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {} } } } diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index b5e6ee3..debe5b8 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -42,7 +42,6 @@ extern NSString *NSWindowDidOrderOnScreenNotification; #ifdef TK_MAC_DEBUG_NOTIFICATIONS extern NSString *NSWindowWillOrderOnScreenNotification; -extern NSString *NSWindowDidOrderOnScreenNotification; extern NSString *NSWindowDidOrderOffScreenNotification; #endif @@ -216,9 +215,10 @@ extern NSString *NSWindowDidOrderOffScreenNotification; TkWindow *winPtr = TkMacOSXGetTkWindow(window); if (winPtr) { TKContentView *view = [window contentView]; - while(Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {}; [view addTkDirtyRect:[view bounds]]; - TkMacOSXDrawAllViews(NULL); + Tcl_CancelIdleCall(TkMacOSXDrawAllViews, NULL); + Tcl_DoWhenIdle(TkMacOSXDrawAllViews, NULL); + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {} } } -- cgit v0.12 From 713dedd103bb6e51fc6ad17c3b8386b91ee34be6 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sat, 6 Jun 2020 19:56:28 +0000 Subject: Take into account that some WM, such as KDE/Plasma with the Aurorae theme engine, need a bit more time to setup a new toplevel and display its content. --- tests/bind.test | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/bind.test b/tests/bind.test index 963119e..8ac5db8 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6707,6 +6707,11 @@ test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -setup { -highlightbackground black -bg yellow -text "My label" pack .top.l -side bottom update + # On KDE/Plasma _with_the_Aurorae_theme_ (at least), setting up the toplevel + # and the label will not be finished after the above 'update'. The WM still + # needs some time before the window is fully ready. For me 50 ms is enough, + # but let's wait more (it depends on computer performance). + after 100 ; update } -body { grab .top event generate .top.l -warp 1 -x 10 -y 10 -- cgit v0.12 From cb7dce629f945d134a4d7595fbbb3b927f8829e2 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sat, 6 Jun 2020 20:51:39 +0000 Subject: Cherry-pick [a6c87041]: Make bind-34.1 pass on Debian 10 with KDE/Plasma by giving the WM a more complete setup for this test. --- tests/bind.test | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/bind.test b/tests/bind.test index e68368a..a2758c5 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6627,6 +6627,7 @@ test bind-33.15 {prefer last in case of homogeneous equal patterns} -setup { test bind-34.1 {-warp works relatively to a window} -setup { toplevel .top + wm geometry .top +100+100 update } -body { # In order to avoid platform-dependent coordinate results due to -- cgit v0.12 From fc3ac7bddfaab3aa339544ced10afdf77c0477c4 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sat, 6 Jun 2020 21:04:19 +0000 Subject: Take into account that some WM, such as KDE/Plasma with the Aurorae theme engine, need a bit more time to setup a new toplevel and display its content. --- tests/bind.test | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/bind.test b/tests/bind.test index a2758c5..fb36445 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6734,6 +6734,11 @@ test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -constraints -highlightbackground black -bg yellow -text "My label" pack .top.l -side bottom update + # On KDE/Plasma _with_the_Aurorae_theme_ (at least), setting up the toplevel + # and the label will not be finished after the above 'update'. The WM still + # needs some time before the window is fully ready. For me 50 ms is enough, + # but let's wait more (it depends on computer performance). + after 100 ; update } -body { grab .top ; # this will queue events waitForGrab grabbed .top -- cgit v0.12 From 94df92d713ad84ae1e93183be6a9927209783795 Mon Sep 17 00:00:00 2001 From: culler Date: Sat, 6 Jun 2020 21:20:19 +0000 Subject: More attempts to make sure new windows are complete. --- macosx/tkMacOSXWindowEvent.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index debe5b8..07965f0 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -39,9 +39,9 @@ static void DoWindowActivate(ClientData clientData); #pragma mark TKApplication(TKWindowEvent) extern NSString *NSWindowDidOrderOnScreenNotification; +extern NSString *NSWindowWillOrderOnScreenNotification; #ifdef TK_MAC_DEBUG_NOTIFICATIONS -extern NSString *NSWindowWillOrderOnScreenNotification; extern NSString *NSWindowDidOrderOffScreenNotification; #endif @@ -218,6 +218,15 @@ extern NSString *NSWindowDidOrderOffScreenNotification; [view addTkDirtyRect:[view bounds]]; Tcl_CancelIdleCall(TkMacOSXDrawAllViews, NULL); Tcl_DoWhenIdle(TkMacOSXDrawAllViews, NULL); + } +} + +- (void) windowMapped: (NSNotification *) notification +{ + NSWindow *w = [notification object]; + TkWindow *winPtr = TkMacOSXGetTkWindow(w); + + if (winPtr) { while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {} } } @@ -235,18 +244,6 @@ extern NSString *NSWindowDidOrderOffScreenNotification; //BOOL start = [[notification name] isEqualToString:NSWindowWillStartLiveResizeNotification]; } -- (void) windowMapped: (NSNotification *) notification -{ - TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); - NSWindow *w = [notification object]; - TkWindow *winPtr = TkMacOSXGetTkWindow(w); - - printf("windowMapped\n"); - if (winPtr) { - //Tk_MapWindow((Tk_Window) winPtr); - } -} - - (void) windowUnmapped: (NSNotification *) notification { TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); @@ -274,6 +271,8 @@ extern NSString *NSWindowDidOrderOffScreenNotification; observe(NSWindowDidDeminiaturizeNotification, windowExpanded:); observe(NSWindowDidMiniaturizeNotification, windowCollapsed:); observe(NSWindowDidOrderOnScreenNotification, windowBecameVisible:); + observe(NSWindowWillOrderOnScreenNotification, windowMapped:); + observe(NSWindowDidOrderOnScreenNotification, windowBecameVisible:); #if !(MAC_OS_X_VERSION_MAX_ALLOWED < 1070) observe(NSWindowDidEnterFullScreenNotification, windowEnteredFullScreen:); @@ -284,8 +283,6 @@ extern NSString *NSWindowDidOrderOffScreenNotification; observe(NSWindowWillMoveNotification, windowDragStart:); observe(NSWindowWillStartLiveResizeNotification, windowLiveResize:); observe(NSWindowDidEndLiveResizeNotification, windowLiveResize:); - observe(NSWindowWillOrderOnScreenNotification, windowMapped:); - observe(NSWindowDidOrderOnScreenNotification, windowBecameVisible:); observe(NSWindowDidOrderOffScreenNotification, windowUnmapped:); #endif #undef observe -- cgit v0.12 From 65275b4068ba0e838ab38828a58122526789d270 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sun, 7 Jun 2020 19:55:26 +0000 Subject: Be even more specific in the result expected from bind-35.1 --- tests/bind.test | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/bind.test b/tests/bind.test index fb36445..e6517e0 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6752,7 +6752,8 @@ test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -constraints event generate .top.l -warp 1 -x 10 -y 10 update idletasks ; after 50 foreach {x2 y2} [winfo pointerxy .top.l] {} - expr {$x1==$x2 && $y1==$y2} + expr {$x1==$x2 && $y1==$y2 && $x1==[winfo rootx .top.l]+10 \ + && $y1==[winfo rooty .top.l]+10} } -cleanup { destroy .top unset x1 y1 x2 y2 -- cgit v0.12 From 8dce88c3bfe67441ecf8b23a5f8ef9946485aa88 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sun, 7 Jun 2020 19:58:45 +0000 Subject: Add comment explaining the result expected for bind-35.1 --- tests/bind.test | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/bind.test b/tests/bind.test index e6517e0..e333c6c 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6752,6 +6752,8 @@ test bind-35.1 {pointer warp with grab on master, bug [e3888d5820]} -constraints event generate .top.l -warp 1 -x 10 -y 10 update idletasks ; after 50 foreach {x2 y2} [winfo pointerxy .top.l] {} + # success if the coords are the same with or without the grab, and if they + # are at (10,10) inside the label widget as requested by the warping expr {$x1==$x2 && $y1==$y2 && $x1==[winfo rootx .top.l]+10 \ && $y1==[winfo rooty .top.l]+10} } -cleanup { -- cgit v0.12 From 84cfc97d7f9469cb9f4406c0f26a15941de718d6 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Sun, 7 Jun 2020 20:10:59 +0000 Subject: Don't use external base64 encoder for Tk's own test-cases. Cherry-picked from tip-529-image-metadata branch (good idea!) --- tests/imgPhoto.test | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/tests/imgPhoto.test b/tests/imgPhoto.test index c45c5fb..50f0688 100644 --- a/tests/imgPhoto.test +++ b/tests/imgPhoto.test @@ -59,14 +59,6 @@ set README [makeFile { set teapotPhotoFile [file join [file dirname [info script]] teapot.ppm] testConstraint hasTeapotPhoto [file exists $teapotPhotoFile] -proc base64ok {} { - expr { - ![catch {package require base64}] - } -} - -testConstraint base64PackageNeeded [base64ok] - test imgPhoto-1.1 {options for photo images} -body { image create photo photo1 -width 79 -height 83 list [photo1 cget -width] [photo1 cget -height] \ @@ -1306,11 +1298,8 @@ test imgPhoto-17.3 {photo write: format guessing from filename} -setup { # Reject corrupted or truncated image [Bug b601ce3ab1]. # WARNING - tests 18.1-18.9 will cause a segfault on 8.5.19 and lower, # and on 8.6.6 and lower. -test imgPhoto-18.1 {Reject corrupted GIF (binary string)} -constraints { - base64PackageNeeded -} -setup { - package require base64 - set data [base64::decode { +test imgPhoto-18.1 {Reject corrupted GIF (binary string)} -setup { + set data [binary decode base64 { R0lGODlhAAQABP8zM/8z/zP/MzP/////M////yH5CiwheLrcLTBCd6Tv2qW16tdK4jhV 5qpraXIvM1JlNyAgOw== }] @@ -1336,11 +1325,8 @@ test imgPhoto-18.3 {Reject corrupted GIF (file)} -setup { } -cleanup { catch {image delete gif1} } -returnCodes error -result {error reading color map|not enough free memory for image buffer} -match regexp -test imgPhoto-18.4 {Reject truncated GIF (binary string)} -constraints { - base64PackageNeeded -} -setup { - package require base64 - set data [base64::decode { +test imgPhoto-18.4 {Reject truncated GIF (binary string)} -setup { + set data [binary decode base64 { R0lGODlhEAAQAMIHAAAAADMz//8zM/8z/zP/MzP///8= }] } -body { @@ -1365,14 +1351,13 @@ test imgPhoto-18.6 {Reject truncated GIF (file)} -setup { catch {image delete gif1} } -returnCodes error -result {error reading color map} test imgPhoto-18.7 {Reject corrupted GIF (> 4Gb) (binary string)} -constraints { - base64PackageNeeded nonPortable + nonPortable } -setup { # About the non portability constraint of this test: see ticket [cc42cc18a5] # If there is insufficient memory, the error message # {not enough free memory for image buffer} should be returned. # Instead, some systems (e.g. FreeBSD 11.1) terminate the test interpreter. - package require base64 - set data [base64::decode { + set data [binary decode base64 { R0lGODlhwmYz//8zM/8z/zP/MzP/////M////yH5Ciwhe LrcLTBCd6Tv2qW16tdK4jhV5qpraXIvM1JlNyAgOw== }] @@ -1410,14 +1395,11 @@ test imgPhoto-18.9 {Reject corrupted GIF (> 4Gb) (file)} -constraints { } -cleanup { catch {image delete gif1} } -returnCodes error -result {error reading color map|not enough free memory for image buffer} -match regexp -test imgPhoto-18.10 {Valid GIF (binary string)} -constraints { - base64PackageNeeded -} -setup { +test imgPhoto-18.10 {Valid GIF (binary string)} -setup { # Test the binary string reader with a valid GIF. # This is not tested elsewhere. # Tests 18.11, 18.12, with matching data, are included for completeness. - package require base64 - set data [base64::decode { + set data [binary decode base64 { R0lGODlhEAAQAMIHAAAAADMz//8zM/8z/zP/MzP/////M////yH5BAEKAAcALAAA AAAQABAAAAMheLrcLTBCd6QV79qlterXB0riOFXmmapraXIvM1IdZTcJADs= }] -- cgit v0.12 From 8b94c471d7cb1f24b1e22e5c64f90197d220fbe2 Mon Sep 17 00:00:00 2001 From: culler Date: Sun, 7 Jun 2020 22:19:45 +0000 Subject: Fix the Redisplay to make new windows complete. --- macosx/tkMacOSXNotify.c | 13 ++++++------- macosx/tkMacOSXSubwindows.c | 10 ++++------ macosx/tkMacOSXWindowEvent.c | 6 ++---- tests/wm.test | 12 ++++++++---- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c index 3433e56..2d25ce1 100644 --- a/macosx/tkMacOSXNotify.c +++ b/macosx/tkMacOSXNotify.c @@ -368,7 +368,7 @@ TkMacOSXDrawAllViews( * rect, due to attempts to draw outside of drawRect's dirty rect. */ - if ([view tkNeedsDisplay]) { + if ([view needsDisplay]) { [view setNeedsDisplay: NO]; } } @@ -412,6 +412,8 @@ Heartbeat( } } +static const Tcl_Time zeroBlockTime = { 0, 0 }; + static void TkMacOSXEventsSetupProc( ClientData clientData, @@ -424,7 +426,6 @@ TkMacOSXEventsSetupProc( */ if (flags & TCL_WINDOW_EVENTS && !runloopMode) { - static const Tcl_Time zeroBlockTime = { 0, 0 }; [NSApp _resetAutoreleasePool]; @@ -435,7 +436,7 @@ TkMacOSXEventsSetupProc( * * If we have any events waiting or if there is any drawing to be done * we want Tcl_WaitForEvent to return immediately. So we set the block - * time to 0. We also stop the heartbeat, since we won't need it. + * time to 0 and stop the heatbeat. */ NSEvent *currentEvent = @@ -453,13 +454,11 @@ TkMacOSXEventsSetupProc( * When the user is not generating events we schedule a "heartbeat" * TimerHandler to fire every 200 milliseconds. The handler does * nothing, but when its timer fires it causes Tcl_WaitForEvent to - * return. This helps avoid hangs when calling vwait. + * return. This helps avoid hangs when calling vwait during the + * non-regression tests. */ ticker = Tcl_CreateTimerHandler(TICK, Heartbeat, NULL); - Tcl_CancelIdleCall(TkMacOSXDrawAllViews, NULL); - Tcl_DoWhenIdle(TkMacOSXDrawAllViews, NULL); - while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {} } } } diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c index bf59901..a0f445f 100644 --- a/macosx/tkMacOSXSubwindows.c +++ b/macosx/tkMacOSXSubwindows.c @@ -213,12 +213,11 @@ XMapWindow( TkMacOSXInvalClipRgns((Tk_Window) winPtr->parentPtr); } - if ([NSApp isDrawing]) { - [[win contentView] setNeedsRedisplay:YES]; - } else { + if (![NSApp isDrawing]) { TKContentView *view = [win contentView]; [view addTkDirtyRect:[view bounds]]; } + [[win contentView] setNeedsRedisplay:YES]; /* * Generate VisibilityNotify events for window and all mapped children. @@ -331,12 +330,11 @@ XUnmapWindow( TkMacOSXUpdateClipRgn(parentPtr); } winPtr->flags &= ~TK_MAPPED; - if ([NSApp isDrawing]) { - [[win contentView] setNeedsRedisplay:YES]; - } else { + if (![NSApp isDrawing]) { TKContentView *view = [win contentView]; [view addTkDirtyRect:[view bounds]]; } + [[win contentView] setNeedsRedisplay:YES]; return Success; } diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 07965f0..9edbd69 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -968,13 +968,11 @@ ConfigureRestrictProc( [NSApp setIsDrawing: YES]; [self clearTkDirtyRect]; [self generateExposeEvents:rect]; - [self setTkNeedsDisplay: NO]; - [NSApp setIsDrawing: NO]; - if ([self needsRedisplay]) { [self setNeedsRedisplay:NO]; - Tcl_DoWhenIdle(TkMacOSXDrawAllViews, NULL); + [self addTkDirtyRect: [self bounds]]; } + [NSApp setIsDrawing:NO]; #ifdef TK_MAC_DEBUG_DRAWING fprintf(stderr, "drawRect: done.\n"); diff --git a/tests/wm.test b/tests/wm.test index 4d0d73b..9e6d8ce 100644 --- a/tests/wm.test +++ b/tests/wm.test @@ -2310,6 +2310,11 @@ test wm-forget-1.4 "pack into unmapped toplevel causes crash" -body { test wm-forget-2 {bug [e9112ef96e] - [wm forget] doesn't completely} -setup { catch {destroy .l .f.b .f} set res {} + if {[tk windowingsystem] == "aqua"} { + proc doUpdate {} {update idletasks} + } else { + proc doUpdate {} {update} + } } -body { label .l -text "Top Dot" frame .f @@ -2317,16 +2322,15 @@ test wm-forget-2 {bug [e9112ef96e] - [wm forget] doesn't completely} -setup { pack .l -side top pack .f.b pack .f -side bottom - update set res [winfo manager .f] pack forget .f - update + doUpdate lappend res [winfo manager .f] wm manage .f - update + doUpdate lappend res [winfo manager .f] wm forget .f - update + doUpdate lappend res [winfo manager .f] } -cleanup { destroy .l .f.b .f -- cgit v0.12 From a51d1909f467d11adf3d095e1fa302f161929cbb Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 8 Jun 2020 09:29:02 +0000 Subject: Add "-fno-common" to SHARED_CFLAGS on various platforms (e.g. Linux, CYGWIN). This is the default with gcc-10, so better make sure it doesn't cause problems. --- unix/configure | 15 ++++++++------- unix/tcl.m4 | 15 ++++++++------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/unix/configure b/unix/configure index dceb0a1..13c36a9 100755 --- a/unix/configure +++ b/unix/configure @@ -4241,7 +4241,7 @@ fi CFLAGS_OPTIMIZE=-O2 CFLAGS_WARNING="-Wall -Wextra -Wwrite-strings -Wpointer-arith" case "${CC}" in - *++) + *++|*++-*) ;; *) CFLAGS_WARNING="${CFLAGS_WARNING} -Wc++-compat -Wdeclaration-after-statement" @@ -4514,7 +4514,7 @@ fi LD_SEARCH_FLAGS="" ;; CYGWIN_*) - SHLIB_CFLAGS="" + SHLIB_CFLAGS="-fno-common" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".dll" DL_OBJS="tclLoadDl.o" @@ -4897,7 +4897,7 @@ fi fi ;; Linux*|GNU*|NetBSD-Debian) - SHLIB_CFLAGS="-fPIC" + SHLIB_CFLAGS="-fPIC -fno-common" SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE="-O2" @@ -5033,7 +5033,6 @@ fi ;; DragonFly-*|FreeBSD-*) # This configuration from FreeBSD Ports. - SHLIB_CFLAGS="-fPIC" SHLIB_LD="${CC} -shared" SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,-soname,\$@" SHLIB_SUFFIX=".so" @@ -5421,7 +5420,6 @@ fi QNX-6*) # QNX RTP # This may work for all QNX, but it was only reported for v6. - SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" @@ -5765,9 +5763,12 @@ fi AIX-*) ;; BSD/OS*) ;; CYGWIN_*) ;; - IRIX*) ;; - NetBSD-*|DragonFly-*|FreeBSD-*|OpenBSD-*) ;; + HP_UX*) ;; Darwin-*) ;; + IRIX*) ;; + Linux*|GNU*) ;; + NetBSD-*|OpenBSD-*) ;; + OSF1-V*) ;; SCO_SV-3.2*) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac diff --git a/unix/tcl.m4 b/unix/tcl.m4 index 0a2920b..aed464f 100644 --- a/unix/tcl.m4 +++ b/unix/tcl.m4 @@ -968,7 +968,7 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ CFLAGS_OPTIMIZE=-O2 CFLAGS_WARNING="-Wall -Wextra -Wwrite-strings -Wpointer-arith" case "${CC}" in - *++) + *++|*++-*) ;; *) CFLAGS_WARNING="${CFLAGS_WARNING} -Wc++-compat -Wdeclaration-after-statement" @@ -1084,7 +1084,7 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ LD_SEARCH_FLAGS="" ;; CYGWIN_*) - SHLIB_CFLAGS="" + SHLIB_CFLAGS="-fno-common" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".dll" DL_OBJS="tclLoadDl.o" @@ -1269,7 +1269,7 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ ]) ;; Linux*|GNU*|NetBSD-Debian) - SHLIB_CFLAGS="-fPIC" + SHLIB_CFLAGS="-fPIC -fno-common" SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE="-O2" @@ -1364,7 +1364,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ ;; DragonFly-*|FreeBSD-*) # This configuration from FreeBSD Ports. - SHLIB_CFLAGS="-fPIC" SHLIB_LD="${CC} -shared" SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,-soname,\$[@]" SHLIB_SUFFIX=".so" @@ -1558,7 +1557,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ QNX-6*) # QNX RTP # This may work for all QNX, but it was only reported for v6. - SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" @@ -1786,9 +1784,12 @@ dnl # preprocessing tests use only CPPFLAGS. AIX-*) ;; BSD/OS*) ;; CYGWIN_*) ;; - IRIX*) ;; - NetBSD-*|DragonFly-*|FreeBSD-*|OpenBSD-*) ;; + HP_UX*) ;; Darwin-*) ;; + IRIX*) ;; + Linux*|GNU*) ;; + NetBSD-*|OpenBSD-*) ;; + OSF1-V*) ;; SCO_SV-3.2*) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac]) -- cgit v0.12 From 25b8569df74d9afc67272322fe89a9ff6dc05a2e Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 8 Jun 2020 10:31:10 +0000 Subject: When TK_NO_DEPRECATED is defined or when Tk is compiled with Tcl 9 headers, no longer support the oldImageType. --- generic/tk.h | 2 +- generic/tkDecls.h | 1 + generic/tkImgPhoto.c | 24 +++++++++++++++++++++--- generic/tkOldTest.c | 8 ++++++-- generic/tkStubInit.c | 1 + tests/image.test | 6 ++++-- 6 files changed, 34 insertions(+), 8 deletions(-) diff --git a/generic/tk.h b/generic/tk.h index 90d4115..cec87b3 100644 --- a/generic/tk.h +++ b/generic/tk.h @@ -1301,7 +1301,7 @@ typedef struct Tk_Outline { */ typedef struct Tk_ImageType Tk_ImageType; -#ifdef USE_OLD_IMAGE +#if !defined(TK_NO_DEPRECATED) && TCL_MAJOR_VERSION < 9 && defined(USE_OLD_IMAGE) typedef int (Tk_ImageCreateProc) (Tcl_Interp *interp, char *name, int argc, char **argv, Tk_ImageType *typePtr, Tk_ImageMaster master, ClientData *masterDataPtr); diff --git a/generic/tkDecls.h b/generic/tkDecls.h index 0d52f2f..8753b2d 100644 --- a/generic/tkDecls.h +++ b/generic/tkDecls.h @@ -1757,6 +1757,7 @@ extern const TkStubs *tkStubsPtr; #undef Tk_PhotoPutBlock_Panic #undef Tk_PhotoPutZoomedBlock_Panic #undef Tk_PhotoSetSize_Panic +#undef Tk_CreateOldPhotoImageFormat #endif /* TK_NO_DEPRECATED */ #undef TCL_STORAGE_CLASS diff --git a/generic/tkImgPhoto.c b/generic/tkImgPhoto.c index 684f10b..5b6d0d3 100644 --- a/generic/tkImgPhoto.c +++ b/generic/tkImgPhoto.c @@ -135,9 +135,11 @@ typedef struct { Tk_PhotoImageFormat *formatList; /* Pointer to the first in the list of known * photo image formats.*/ +#if !defined(TK_NO_DEPRECATED) && TCL_MAJOR_VERSION < 9 Tk_PhotoImageFormat *oldFormatList; /* Pointer to the first in the list of known * photo image formats.*/ +#endif int initialized; /* Set to 1 if we've initialized the * structure. */ } ThreadSpecificData; @@ -226,11 +228,13 @@ PhotoFormatThreadExitProc( Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); (void)dummy; +#if !defined(TK_NO_DEPRECATED) && TCL_MAJOR_VERSION < 9 while (tsdPtr->oldFormatList != NULL) { freePtr = tsdPtr->oldFormatList; tsdPtr->oldFormatList = tsdPtr->oldFormatList->nextPtr; ckfree(freePtr); } +#endif while (tsdPtr->formatList != NULL) { freePtr = tsdPtr->formatList; tsdPtr->formatList = tsdPtr->formatList->nextPtr; @@ -258,6 +262,7 @@ PhotoFormatThreadExitProc( *---------------------------------------------------------------------- */ +#if !defined(TK_NO_DEPRECATED) && TCL_MAJOR_VERSION < 9 void Tk_CreateOldPhotoImageFormat( const Tk_PhotoImageFormat *formatPtr) @@ -278,6 +283,7 @@ Tk_CreateOldPhotoImageFormat( copyPtr->nextPtr = tsdPtr->oldFormatList; tsdPtr->oldFormatList = copyPtr; } +#endif void Tk_CreatePhotoImageFormat( @@ -296,10 +302,13 @@ Tk_CreatePhotoImageFormat( } copyPtr = (Tk_PhotoImageFormat *)ckalloc(sizeof(Tk_PhotoImageFormat)); *copyPtr = *formatPtr; +#if !defined(TK_NO_DEPRECATED) && TCL_MAJOR_VERSION < 9 if (isupper((unsigned char) *formatPtr->name)) { copyPtr->nextPtr = tsdPtr->oldFormatList; tsdPtr->oldFormatList = copyPtr; - } else { + } else +#endif + { /* for compatibility with aMSN: make a copy of formatPtr->name */ char *name = (char *)ckalloc(strlen(formatPtr->name) + 1); strcpy(name, formatPtr->name); @@ -732,6 +741,7 @@ ImgPhotoCmd( } } } +#if !defined(TK_NO_DEPRECATED) && TCL_MAJOR_VERSION < 9 if (stringWriteProc == NULL) { oldformat = 1; for (imageFormat = tsdPtr->oldFormatList; imageFormat != NULL; @@ -747,6 +757,7 @@ ImgPhotoCmd( } } } +#endif if (stringWriteProc == NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "image string format \"%s\" is %s", @@ -1339,6 +1350,7 @@ ImgPhotoCmd( } } } +#if !defined(TK_NO_DEPRECATED) && TCL_MAJOR_VERSION < 9 if (imageFormat == NULL) { oldformat = 1; for (imageFormat = tsdPtr->oldFormatList; imageFormat != NULL; @@ -1353,6 +1365,7 @@ ImgPhotoCmd( } } } +#endif if (usedExt && !matched) { /* * If we didn't find one and we're using file extensions as the @@ -2394,7 +2407,8 @@ MatchFileFormat( * here. */ int *oldformat) /* Returns 1 if the old image API is used. */ { - int matched = 0, useoldformat = 0; + int matched = 0; + int useoldformat = 0; Tk_PhotoImageFormat *formatPtr; ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); @@ -2441,7 +2455,8 @@ MatchFileFormat( } } } - if (formatPtr == NULL) { +#if !defined(TK_NO_DEPRECATED) && TCL_MAJOR_VERSION < 9 +if (formatPtr == NULL) { useoldformat = 1; for (formatPtr = tsdPtr->oldFormatList; formatPtr != NULL; formatPtr = formatPtr->nextPtr) { @@ -2475,6 +2490,7 @@ MatchFileFormat( } } } +#endif if (formatPtr == NULL) { if ((formatObj != NULL) && !matched) { @@ -2594,6 +2610,7 @@ MatchStringFormat( } } +#if !defined(TK_NO_DEPRECATED) && TCL_MAJOR_VERSION < 9 if (formatPtr == NULL) { useoldformat = 1; for (formatPtr = tsdPtr->oldFormatList; formatPtr != NULL; @@ -2623,6 +2640,7 @@ MatchStringFormat( } } } +#endif if (formatPtr == NULL) { /* diff --git a/generic/tkOldTest.c b/generic/tkOldTest.c index d9e8053..0702347 100644 --- a/generic/tkOldTest.c +++ b/generic/tkOldTest.c @@ -24,6 +24,7 @@ #endif #include "tkInt.h" +#if !defined(TK_NO_DEPRECATED) && (TCL_MAJOR_VERSION < 9) /* * The following data structure represents the master for a test image: */ @@ -84,7 +85,7 @@ static Tk_ImageType imageType = { static int ImageObjCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj * const objv[]); - +#endif /* *---------------------------------------------------------------------- @@ -113,7 +114,9 @@ TkOldTestInit( if (!initialized) { initialized = 1; +#if !defined(TK_NO_DEPRECATED) && (TCL_MAJOR_VERSION < 9) Tk_CreateImageType(&imageType); +#endif } return TCL_OK; } @@ -133,7 +136,7 @@ TkOldTestInit( * *---------------------------------------------------------------------- */ - +#if !defined(TK_NO_DEPRECATED) && (TCL_MAJOR_VERSION < 9) static int ImageCreate( Tcl_Interp *interp, /* Interpreter for application containing @@ -400,6 +403,7 @@ ImageDelete( ckfree(timPtr->varName); ckfree(timPtr); } +#endif /* * Local Variables: diff --git a/generic/tkStubInit.c b/generic/tkStubInit.c index a0125a8..5880d7b 100644 --- a/generic/tkStubInit.c +++ b/generic/tkStubInit.c @@ -70,6 +70,7 @@ static int TkWinGetPlatformId(void) { #define Tk_PhotoPutBlock_Panic 0 #define Tk_PhotoPutZoomedBlock_Panic 0 #define Tk_PhotoSetSize_Panic 0 +#define Tk_CreateOldPhotoImageFormat 0 #else static void doNothing(void) diff --git a/tests/image.test b/tests/image.test index da65a66..ee3f3d9 100644 --- a/tests/image.test +++ b/tests/image.test @@ -308,11 +308,13 @@ test image-5.7 {Tk_ImageCmd procedure, "type" option} -constraints { } -returnCodes error -result {image "myimage" doesn't exist} -test image-6.1 {Tk_ImageCmd procedure, "types" option} -body { +test image-6.1 {Tk_ImageCmd procedure, "types" option} -constraints { + testImageType +} -body { image types x } -returnCodes error -result {wrong # args: should be "image types"} test image-6.2 {Tk_ImageCmd procedure, "types" option} -constraints { - testImageType + testOldImageType } -body { lsort [image types] } -result {bitmap oldtest photo test} -- cgit v0.12 From 50d501f90b85fcd0a3beaf485da84379975c9504 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 8 Jun 2020 12:41:00 +0000 Subject: Fix [2790615]: "update" performs Tk callbacks in its own stack frame. by adding TCL_EVAL_GLOBAL in a lot of places. --- generic/tkCanvPs.c | 2 +- generic/tkCanvas.c | 4 ++-- generic/tkEntry.c | 2 +- generic/tkListbox.c | 4 ++-- generic/tkMenu.c | 2 +- generic/tkText.c | 2 +- generic/tkTextDisp.c | 4 ++-- generic/tkWindow.c | 2 +- macosx/tkMacOSXScale.c | 2 +- unix/tkUnixScale.c | 2 +- 10 files changed, 13 insertions(+), 13 deletions(-) diff --git a/generic/tkCanvPs.c b/generic/tkCanvPs.c index 2cb4d27..bcd1d13 100644 --- a/generic/tkCanvPs.c +++ b/generic/tkCanvPs.c @@ -193,7 +193,7 @@ TkCanvPostscriptCmd( * such. */ - result = Tcl_EvalEx(interp, "::tk::ensure_psenc_is_loaded", -1, 0); + result = Tcl_EvalEx(interp, "::tk::ensure_psenc_is_loaded", -1, TCL_EVAL_GLOBAL); if (result != TCL_OK) { return result; } diff --git a/generic/tkCanvas.c b/generic/tkCanvas.c index 8230122..9f661bc 100644 --- a/generic/tkCanvas.c +++ b/generic/tkCanvas.c @@ -5588,7 +5588,7 @@ CanvasUpdateScrollbars( Tcl_DStringAppend(&buf, xScrollCmd, -1); Tcl_DStringAppend(&buf, " ", -1); Tcl_DStringAppend(&buf, Tcl_GetString(fractions), -1); - result = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, 0); + result = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, TCL_EVAL_GLOBAL); Tcl_DStringFree(&buf); Tcl_DecrRefCount(fractions); if (result != TCL_OK) { @@ -5606,7 +5606,7 @@ CanvasUpdateScrollbars( Tcl_DStringAppend(&buf, yScrollCmd, -1); Tcl_DStringAppend(&buf, " ", -1); Tcl_DStringAppend(&buf, Tcl_GetString(fractions), -1); - result = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, 0); + result = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, TCL_EVAL_GLOBAL); Tcl_DStringFree(&buf); Tcl_DecrRefCount(fractions); if (result != TCL_OK) { diff --git a/generic/tkEntry.c b/generic/tkEntry.c index fc5ba63..468eabe 100644 --- a/generic/tkEntry.c +++ b/generic/tkEntry.c @@ -3007,7 +3007,7 @@ EntryUpdateScrollbar( Tcl_DStringAppend(&buf, firstStr, -1); Tcl_DStringAppend(&buf, " ", -1); Tcl_DStringAppend(&buf, lastStr, -1); - code = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, 0); + code = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, TCL_EVAL_GLOBAL); Tcl_DStringFree(&buf); if (code != TCL_OK) { Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( diff --git a/generic/tkListbox.c b/generic/tkListbox.c index b00a895..514b349 100644 --- a/generic/tkListbox.c +++ b/generic/tkListbox.c @@ -3329,7 +3329,7 @@ ListboxUpdateVScrollbar( Tcl_DStringAppend(&buf, firstStr, -1); Tcl_DStringAppend(&buf, " ", -1); Tcl_DStringAppend(&buf, lastStr, -1); - result = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, 0); + result = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, TCL_EVAL_GLOBAL); Tcl_DStringFree(&buf); if (result != TCL_OK) { Tcl_AddErrorInfo(interp, @@ -3401,7 +3401,7 @@ ListboxUpdateHScrollbar( Tcl_DStringAppend(&buf, firstStr, -1); Tcl_DStringAppend(&buf, " ", -1); Tcl_DStringAppend(&buf, lastStr, -1); - result = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, 0); + result = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, TCL_EVAL_GLOBAL); Tcl_DStringFree(&buf); if (result != TCL_OK) { Tcl_AddErrorInfo(interp, diff --git a/generic/tkMenu.c b/generic/tkMenu.c index 318930f..f43bbe0 100644 --- a/generic/tkMenu.c +++ b/generic/tkMenu.c @@ -1019,7 +1019,7 @@ TkInvokeMenu( Tcl_DStringInit(&ds); Tcl_DStringAppend(&ds, "tk::TearOffMenu ", -1); Tcl_DStringAppend(&ds, Tk_PathName(menuPtr->tkwin), -1); - result = Tcl_EvalEx(interp, Tcl_DStringValue(&ds), -1, 0); + result = Tcl_EvalEx(interp, Tcl_DStringValue(&ds), -1, TCL_EVAL_GLOBAL); Tcl_DStringFree(&ds); } else if ((mePtr->type == CHECK_BUTTON_ENTRY) && (mePtr->namePtr != NULL)) { diff --git a/generic/tkText.c b/generic/tkText.c index b696647..2ddfea1 100644 --- a/generic/tkText.c +++ b/generic/tkText.c @@ -5039,7 +5039,7 @@ DumpSegment( Tcl_DStringAppend(&buf, Tcl_GetString(command), -1); Tcl_DStringAppend(&buf, " ", -1); Tcl_DStringAppend(&buf, Tcl_GetString(tuple), -1); - code = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, 0); + code = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, TCL_EVAL_GLOBAL); Tcl_DStringFree(&buf); if (code != TCL_OK) { Tcl_AddErrorInfo(interp, diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index 2deeaf2..93b56aa 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -6527,7 +6527,7 @@ GetXView( Tcl_DStringAppend(&buf, textPtr->xScrollCmd, -1); Tcl_DStringAppend(&buf, buf1, -1); Tcl_DStringAppend(&buf, buf2, -1); - code = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, 0); + code = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, TCL_EVAL_GLOBAL); Tcl_DStringFree(&buf); if (code != TCL_OK) { Tcl_AddErrorInfo(interp, @@ -6812,7 +6812,7 @@ GetYView( Tcl_DStringAppend(&buf, textPtr->yScrollCmd, -1); Tcl_DStringAppend(&buf, buf1, -1); Tcl_DStringAppend(&buf, buf2, -1); - code = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, 0); + code = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, TCL_EVAL_GLOBAL); Tcl_DStringFree(&buf); if (code != TCL_OK) { Tcl_AddErrorInfo(interp, diff --git a/generic/tkWindow.c b/generic/tkWindow.c index 121bb5a..8ec18e2 100644 --- a/generic/tkWindow.c +++ b/generic/tkWindow.c @@ -3339,7 +3339,7 @@ Initialize( tcl_findLibrary tk $tk_version $tk_patchLevel tk.tcl TK_LIBRARY tk_library\n\ }\n\ }\n\ -tkInit", -1, 0); +tkInit", -1, TCL_EVAL_GLOBAL); } if (code == TCL_OK) { /* diff --git a/macosx/tkMacOSXScale.c b/macosx/tkMacOSXScale.c index 0195ffb..6ea9f14 100644 --- a/macosx/tkMacOSXScale.c +++ b/macosx/tkMacOSXScale.c @@ -179,7 +179,7 @@ TkpDisplayScale( Tcl_DStringAppend(&buf, scalePtr->command, -1); Tcl_DStringAppend(&buf, " ", -1); Tcl_DStringAppend(&buf, string, -1); - result = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, 0); + result = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, TCL_EVAL_GLOBAL); Tcl_DStringFree(&buf); if (result != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (command executed by scale)"); diff --git a/unix/tkUnixScale.c b/unix/tkUnixScale.c index 778c010..9c6e4f3 100644 --- a/unix/tkUnixScale.c +++ b/unix/tkUnixScale.c @@ -575,7 +575,7 @@ TkpDisplayScale( Tcl_DStringAppend(&buf, scalePtr->command, -1); Tcl_DStringAppend(&buf, " ", -1); Tcl_DStringAppend(&buf, string, -1); - result = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, 0); + result = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, TCL_EVAL_GLOBAL); Tcl_DStringFree(&buf); if (result != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (command executed by scale)"); -- cgit v0.12 From 28010d48e92cd516ab264586ddeff2233cc5eb4a Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 9 Jun 2020 07:23:05 +0000 Subject: Remove many unnessesaary curly-braces in testcases --- tests/bind.test | 266 ++++++++++++++++++++-------------------- tests/busy.test | 8 +- tests/button.test | 80 ++++++------ tests/canvPs.test | 4 +- tests/canvText.test | 16 +-- tests/canvas.test | 24 ++-- tests/config.test | 50 ++++---- tests/dialog.test | 4 +- tests/entry.test | 148 +++++++++++----------- tests/font.test | 52 ++++---- tests/fontchooser.test | 8 +- tests/frame.test | 64 +++++----- tests/geometry.test | 2 +- tests/grid.test | 28 ++--- tests/image.test | 2 +- tests/imgBmap.test | 2 +- tests/imgListFormat.test | 2 +- tests/imgPNG.test | 2 +- tests/imgPhoto.test | 12 +- tests/imgSVGnano.test | 4 +- tests/listbox.test | 112 ++++++++--------- tests/menu.test | 50 ++++---- tests/menubut.test | 24 ++-- tests/message.test | 14 +-- tests/pack.test | 12 +- tests/panedwindow.test | 4 +- tests/place.test | 16 +-- tests/safePrimarySelection.test | 32 ++--- tests/scale.test | 48 ++++---- tests/spinbox.test | 144 +++++++++++----------- tests/text.test | 156 +++++++++++------------ tests/textDisp.test | 2 +- tests/textTag.test | 18 +-- tests/textWind.test | 4 +- tests/tk.test | 12 +- tests/ttk/entry.test | 10 +- tests/ttk/spinbox.test | 2 +- tests/ttk/treeview.test | 4 +- tests/unixEmbed.test | 4 +- tests/unixSelect.test | 4 +- tests/util.test | 8 +- tests/visual.test | 8 +- tests/winDialog.test | 22 ++-- tests/winFont.test | 12 +- tests/winWm.test | 2 +- tests/winfo.test | 22 ++-- tests/wm.test | 14 +-- 47 files changed, 769 insertions(+), 769 deletions(-) diff --git a/tests/bind.test b/tests/bind.test index adc628a..d516a6e 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -971,7 +971,7 @@ test bind-13.35 {Tk_BindEvent procedure: execute binding} -setup { return $x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-13.38 {Tk_BindEvent procedure: binding gets to run} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1054,7 +1054,7 @@ test bind-15.1 {MatchPatterns procedure, ignoring type mismatches} -setup { return $x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-15.2 {MatchPatterns procedure, ignoring type mismatches} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1072,7 +1072,7 @@ test bind-15.2 {MatchPatterns procedure, ignoring type mismatches} -setup { return $x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-15.3 {MatchPatterns procedure, ignoring type mismatches} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1087,7 +1087,7 @@ test bind-15.3 {MatchPatterns procedure, ignoring type mismatches} -setup { return $x } -cleanup { destroy .t.f -} -result {0} +} -result 0 test bind-15.4 {MatchPatterns procedure, ignoring type mismatches} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1103,7 +1103,7 @@ test bind-15.4 {MatchPatterns procedure, ignoring type mismatches} -setup { return $x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-15.5 {MatchPatterns procedure, ignoring type mismatches} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1119,7 +1119,7 @@ test bind-15.5 {MatchPatterns procedure, ignoring type mismatches} -setup { return $x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-15.6 {MatchPatterns procedure, ignoring type mismatches} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1136,7 +1136,7 @@ test bind-15.6 {MatchPatterns procedure, ignoring type mismatches} -setup { return $x } -cleanup { destroy .t.f -} -result {0} +} -result 0 test bind-15.7 {MatchPatterns procedure, ignoring type mismatches} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1153,7 +1153,7 @@ test bind-15.7 {MatchPatterns procedure, ignoring type mismatches} -setup { return $x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-15.8 {MatchPatterns procedure, ignoring type mismatches} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1168,7 +1168,7 @@ test bind-15.8 {MatchPatterns procedure, ignoring type mismatches} -setup { return $x } -cleanup { destroy .t.f -} -result {0} +} -result 0 test bind-15.9 {MatchPatterns procedure, modifier checks} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1181,7 +1181,7 @@ test bind-15.9 {MatchPatterns procedure, modifier checks} -setup { return $x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-15.10 {MatchPatterns procedure, modifier checks} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1194,7 +1194,7 @@ test bind-15.10 {MatchPatterns procedure, modifier checks} -setup { return $x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-15.11 {MatchPatterns procedure, modifier checks} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1207,7 +1207,7 @@ test bind-15.11 {MatchPatterns procedure, modifier checks} -setup { return $x } -cleanup { destroy .t.f -} -result {0} +} -result 0 test bind-15.12 {MatchPatterns procedure, ignore modifier presses and releases} -constraints { nonPortable } -setup { @@ -1226,7 +1226,7 @@ test bind-15.12 {MatchPatterns procedure, ignore modifier presses and releases} return $x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-15.13 {MatchPatterns procedure, checking detail} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1240,7 +1240,7 @@ test bind-15.13 {MatchPatterns procedure, checking detail} -setup { return $x } -cleanup { destroy .t.f -} -result {0} +} -result 0 test bind-15.14 {MatchPatterns procedure, checking "nearby"} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1257,7 +1257,7 @@ test bind-15.14 {MatchPatterns procedure, checking "nearby"} -setup { return $x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-15.15 {MatchPatterns procedure, checking "nearby"} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1274,7 +1274,7 @@ test bind-15.15 {MatchPatterns procedure, checking "nearby"} -setup { return $x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-15.16 {MatchPatterns procedure, checking "nearby"} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1291,7 +1291,7 @@ test bind-15.16 {MatchPatterns procedure, checking "nearby"} -setup { return $x } -cleanup { destroy .t.f -} -result {0} +} -result 0 test bind-15.17 {MatchPatterns procedure, checking "nearby"} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1308,7 +1308,7 @@ test bind-15.17 {MatchPatterns procedure, checking "nearby"} -setup { return $x } -cleanup { destroy .t.f -} -result {0} +} -result 0 test bind-15.18 {MatchPatterns procedure, checking "nearby"} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1325,7 +1325,7 @@ test bind-15.18 {MatchPatterns procedure, checking "nearby"} -setup { return $x } -cleanup { destroy .t.f -} -result {0} +} -result 0 test bind-15.19 {MatchPatterns procedure, checking "nearby"} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1342,7 +1342,7 @@ test bind-15.19 {MatchPatterns procedure, checking "nearby"} -setup { return $x } -cleanup { destroy .t.f -} -result {0} +} -result 0 test bind-15.20 {MatchPatterns procedure, checking "nearby"} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1359,7 +1359,7 @@ test bind-15.20 {MatchPatterns procedure, checking "nearby"} -setup { return $x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-15.21 {MatchPatterns procedure, checking "nearby"} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1376,7 +1376,7 @@ test bind-15.21 {MatchPatterns procedure, checking "nearby"} -setup { return $x } -cleanup { destroy .t.f -} -result {0} +} -result 0 test bind-15.22 {MatchPatterns procedure, time wrap-around} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1391,7 +1391,7 @@ test bind-15.22 {MatchPatterns procedure, time wrap-around} -setup { return $x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-15.23 {MatchPatterns procedure, time wrap-around} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1406,7 +1406,7 @@ test bind-15.23 {MatchPatterns procedure, time wrap-around} -setup { return $x } -cleanup { destroy .t.f -} -result {0} +} -result 0 test bind-15.24 {MatchPatterns procedure, virtual event} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1479,7 +1479,7 @@ test bind-15.27 {MatchPatterns procedure, conflict resolution} -setup { return $x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-15.28 {MatchPatterns procedure, conflict resolution} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1493,7 +1493,7 @@ test bind-15.28 {MatchPatterns procedure, conflict resolution} -setup { return $x } -cleanup { destroy .t.f -} -result {0} +} -result 0 test bind-15.29 {MatchPatterns procedure, conflict resolution} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1525,7 +1525,7 @@ test bind-15.30 {MatchPatterns procedure, conflict resolution} -setup { return $x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-15.31 {MatchPatterns procedure, conflict resolution} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1539,7 +1539,7 @@ test bind-15.31 {MatchPatterns procedure, conflict resolution} -setup { return $x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-15.32 {MatchPatterns procedure, conflict resolution} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1553,7 +1553,7 @@ test bind-15.32 {MatchPatterns procedure, conflict resolution} -setup { return $x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-15.33 {MatchPatterns procedure, conflict resolution} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1601,7 +1601,7 @@ test bind-16.2 {ExpandPercents procedure} -setup { set x } -cleanup { destroy .t.f -} -result {1234} +} -result 1234 test bind-16.3 {ExpandPercents procedure} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1628,7 +1628,7 @@ test bind-16.4 {ExpandPercents procedure} -setup { set x } -cleanup { destroy .t.f -} -result {3} +} -result 3 test bind-16.5 {ExpandPercents procedure} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1641,7 +1641,7 @@ test bind-16.5 {ExpandPercents procedure} -setup { set x } -cleanup { destroy .t.f -} -result {47} +} -result 47 test bind-16.6 {ExpandPercents procedure} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1745,7 +1745,7 @@ test bind-16.13 {ExpandPercents procedure} -setup { return $x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-16.14 {ExpandPercents procedure} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1784,7 +1784,7 @@ test bind-16.16 {ExpandPercents procedure} -setup { set x } -cleanup { destroy .t.f -} -result {146} +} -result 146 test bind-16.17 {ExpandPercents procedure} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1850,7 +1850,7 @@ test bind-16.21 {ExpandPercents procedure} -setup { return $x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-16.22 {ExpandPercents procedure} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1863,7 +1863,7 @@ test bind-16.22 {ExpandPercents procedure} -setup { return $x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-16.23 {ExpandPercents procedure} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1876,7 +1876,7 @@ test bind-16.23 {ExpandPercents procedure} -setup { return $x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-16.24 {ExpandPercents procedure} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1916,7 +1916,7 @@ test bind-16.26 {ExpandPercents procedure} -setup { set x } -cleanup { destroy .t.f -} -result {1402} +} -result 1402 test bind-16.27 {ExpandPercents procedure} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1929,7 +1929,7 @@ test bind-16.27 {ExpandPercents procedure} -setup { set x } -cleanup { destroy .t.f -} -result {1023} +} -result 1023 test bind-16.28 {ExpandPercents procedure} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -1982,7 +1982,7 @@ test bind-16.31 {ExpandPercents procedure} -setup { set x } -cleanup { destroy .t.f -} -result {4294} +} -result 4294 test bind-16.32 {ExpandPercents procedure} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -2061,7 +2061,7 @@ test bind-16.36 {ExpandPercents procedure} -setup { set x } -cleanup { destroy .t.f -} -result {24} +} -result 24 test bind-16.37 {ExpandPercents procedure} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -2074,7 +2074,7 @@ test bind-16.37 {ExpandPercents procedure} -setup { return $x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-16.38 {ExpandPercents procedure} -constraints { nonPortable } -setup { @@ -2109,7 +2109,7 @@ test bind-16.39 {ExpandPercents procedure} -setup { set x } -cleanup { destroy .t.f -} -result {32} +} -result 32 test bind-16.40 {ExpandPercents procedure} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -2135,7 +2135,7 @@ test bind-16.41 {ExpandPercents procedure} -setup { set x } -cleanup { destroy .t.f -} -result {2} +} -result 2 test bind-16.42 {ExpandPercents procedure} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -2321,7 +2321,7 @@ test bind-17.16 {event command: generate} -setup { set x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-17.17 {event command: generate} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -2463,7 +2463,7 @@ test bind-19.11 {DeleteVirtualEvent procedure: owned by 1, only} -setup { set x } -cleanup { destroy .t.f -} -result {101} +} -result 101 test bind-19.12 {DeleteVirtualEvent procedure: owned by 1, first in chain} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -2801,7 +2801,7 @@ test bind-22.11 {HandleEventGenerate} -setup { set x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-22.12 {HandleEventGenerate} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -2814,7 +2814,7 @@ test bind-22.12 {HandleEventGenerate} -setup { set x } -cleanup { destroy .t.f -} -result {4} +} -result 4 test bind-22.13 {HandleEventGenerate} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -2828,7 +2828,7 @@ test bind-22.13 {HandleEventGenerate} -setup { set x } -cleanup { destroy .t.f -} -result {100} +} -result 100 test bind-22.14 {HandleEventGenerate} -setup { frame .t.f -class Test -width 150 -height 100 pack .t.f @@ -2984,7 +2984,7 @@ test bind-22.25 {HandleEventGenerate: options -borderwidth 2i} -setu expr {[winfo pixels .t.f 2i] eq $x} } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-22.26 {HandleEventGenerate: options -borderwidth 2i} -setup { frame .t.f -class Test -width 150 -height 100 @@ -3078,7 +3078,7 @@ test bind-22.32 {HandleEventGenerate: options -count 20} -setup { return $x } -cleanup { destroy .t.f -} -result {20} +} -result 20 test bind-22.33 {HandleEventGenerate: options -count 20} -setup { frame .t.f -class Test -width 150 -height 100 @@ -3186,7 +3186,7 @@ test bind-22.39 {HandleEventGenerate: options -focus 1} -setup { return $x } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-22.40 {HandleEventGenerate: options -focus 1} -setup { frame .t.f -class Test -width 150 -height 100 @@ -3226,7 +3226,7 @@ test bind-22.42 {HandleEventGenerate: options -height 2i} -setup { expr {$x eq [winfo pixels .t.f 2i]} } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-22.43 {HandleEventGenerate: options -height 2i} -setup { frame .t.f -class Test -width 150 -height 100 @@ -3240,7 +3240,7 @@ test bind-22.43 {HandleEventGenerate: options -height 2i} -setup { expr {$x eq [winfo pixels .t.f 2i]} } -cleanup { destroy .t.f -} -result {1} +} -result 1 test bind-22.44 {HandleEventGenerate: options -height 2i} -setup { frame .t.f -class Test -width 150 -height 100 @@ -3280,7 +3280,7 @@ test bind-22.46 {HandleEventGenerate: options -keycode 20} -setup { return $x } -cleanup { destroy .t.f -} -result {20} +} -result 20 test bind-22.47 {HandleEventGenerate: options