diff options
-rw-r--r-- | generic/tkEvent.c | 2 | ||||
-rw-r--r-- | generic/tkInt.h | 7 | ||||
-rw-r--r-- | generic/tkSelect.c | 4 | ||||
-rw-r--r-- | generic/tkTextIndex.c | 4 | ||||
-rw-r--r-- | generic/tkWindow.c | 27 | ||||
-rw-r--r-- | macosx/tkMacOSXMouseEvent.c | 53 | ||||
-rw-r--r-- | tests/event.test | 5 | ||||
-rw-r--r-- | tests/textTag.test | 2 | ||||
-rw-r--r-- | tests/window.test | 33 | ||||
-rw-r--r-- | unix/tkUnixFont.c | 16 | ||||
-rw-r--r-- | win/tkWinMenu.c | 7 | ||||
-rw-r--r-- | win/tkWinX.c | 58 |
12 files changed, 167 insertions, 51 deletions
diff --git a/generic/tkEvent.c b/generic/tkEvent.c index bb9b12d..698e9e1 100644 --- a/generic/tkEvent.c +++ b/generic/tkEvent.c @@ -1151,7 +1151,7 @@ Tk_HandleEvent( eventPtr->xany.send_event = -1; eventPtr->xkey.keycode = (but & 1) ? -120 : 120; if (but > Button5) { - eventPtr->xkey.state ^= ShiftMask; + eventPtr->xkey.state |= ShiftMask; } } } diff --git a/generic/tkInt.h b/generic/tkInt.h index 3303a5b..8a6e3f7 100644 --- a/generic/tkInt.h +++ b/generic/tkInt.h @@ -701,6 +701,10 @@ typedef struct TkMainInfo { struct TkMainInfo *nextPtr; /* Next in list of all main windows managed by * this process. */ Tcl_HashTable busyTable; /* Information used by [tk busy] command. */ + Tcl_ObjCmdProc *tclUpdateObjProc; + /* Saved Tcl [update] command, used to restore + * Tcl's version of [update] after Tk is shut + * down */ } TkMainInfo; /* @@ -1262,9 +1266,6 @@ MODULE_SCOPE int Tk_SelectionObjCmd(ClientData clientData, MODULE_SCOPE int Tk_SendObjCmd(ClientData clientData, Tcl_Interp *interp,int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tk_SendObjCmd(ClientData clientData, - Tcl_Interp *interp, int objc, - Tcl_Obj *const objv[]); MODULE_SCOPE int Tk_SpinboxObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); diff --git a/generic/tkSelect.c b/generic/tkSelect.c index 449dc1d..a9064df 100644 --- a/generic/tkSelect.c +++ b/generic/tkSelect.c @@ -1399,12 +1399,12 @@ HandleTclCommand( cmdInfoPtr->charOffset += Tcl_NumUtfChars(string, -1); cmdInfoPtr->buffer[0] = '\0'; } else { - int ch; + Tcl_UniChar ch = 0; p = string; string += count; numChars = 0; while (p < string) { - p += TkUtfToUniChar(p, &ch); + p += Tcl_UtfToUniChar(p, &ch); numChars++; } cmdInfoPtr->charOffset += numChars; diff --git a/generic/tkTextIndex.c b/generic/tkTextIndex.c index 7d55331..ade889b 100644 --- a/generic/tkTextIndex.c +++ b/generic/tkTextIndex.c @@ -480,7 +480,7 @@ TkTextMakeCharIndex( TkTextSegment *segPtr; char *p, *start, *end; int index, offset; - int ch; + Tcl_UniChar ch = 0; indexPtr->tree = tree; if (lineIndex < 0) { @@ -527,7 +527,7 @@ TkTextMakeCharIndex( return indexPtr; } charIndex--; - offset = TkUtfToUniChar(p, &ch); + offset = Tcl_UtfToUniChar(p, &ch); index += offset; } } else { diff --git a/generic/tkWindow.c b/generic/tkWindow.c index 2a98876..dcaaf69 100644 --- a/generic/tkWindow.c +++ b/generic/tkWindow.c @@ -93,6 +93,7 @@ static const XSetWindowAttributes defAtts= { #define PASSMAINWINDOW 2 #define WINMACONLY 4 #define USEINITPROC 8 +#define SAVEUPDATECMD 16 /* better only be one of these! */ typedef int (TkInitProc)(Tcl_Interp *interp, ClientData clientData); typedef struct { @@ -126,7 +127,7 @@ static const TkCmd commands[] = { {"selection", Tk_SelectionObjCmd, PASSMAINWINDOW}, {"tk", (Tcl_ObjCmdProc *)(void *)TkInitTkCmd, USEINITPROC|PASSMAINWINDOW|ISSAFE}, {"tkwait", Tk_TkwaitObjCmd, PASSMAINWINDOW|ISSAFE}, - {"update", Tk_UpdateObjCmd, PASSMAINWINDOW|ISSAFE}, + {"update", Tk_UpdateObjCmd, PASSMAINWINDOW|ISSAFE|SAVEUPDATECMD}, {"winfo", Tk_WinfoObjCmd, PASSMAINWINDOW|ISSAFE}, {"wm", Tk_WmObjCmd, PASSMAINWINDOW}, @@ -876,6 +877,7 @@ TkCreateMainWindow( Tcl_InitHashTable(&mainPtr->imageTable, TCL_STRING_KEYS); mainPtr->strictMotif = 0; mainPtr->alwaysShowSelection = 0; + mainPtr->tclUpdateObjProc = NULL; if (Tcl_LinkVar(interp, "tk_strictMotif", (char *) &mainPtr->strictMotif, TCL_LINK_BOOLEAN) != TCL_OK) { Tcl_ResetResult(interp); @@ -915,6 +917,8 @@ TkCreateMainWindow( isSafe = Tcl_IsSafe(interp); for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) { + Tcl_CmdInfo cmdInfo; + if (cmdPtr->objProc == NULL) { Tcl_Panic("TkCreateMainWindow: builtin command with NULL string and object procs"); } @@ -934,6 +938,11 @@ TkCreateMainWindow( } else { clientData = NULL; } + if ((cmdPtr->flags & SAVEUPDATECMD) && + Tcl_GetCommandInfo(interp, cmdPtr->name, &cmdInfo) && + cmdInfo.isNativeObjectProc && !cmdInfo.objClientData && !cmdInfo.deleteProc) { + mainPtr->tclUpdateObjProc = cmdInfo.objProc; + } if (cmdPtr->flags & USEINITPROC) { ((TkInitProc *)(void *)cmdPtr->objProc)(interp, clientData); } else { @@ -1496,10 +1505,20 @@ Tk_DestroyWindow( */ if ((winPtr->mainPtr->interp != NULL) && - !Tcl_InterpDeleted(winPtr->mainPtr->interp)) { + !Tcl_InterpDeleted(winPtr->mainPtr->interp)) { for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) { - Tcl_CreateObjCommand(winPtr->mainPtr->interp, cmdPtr->name, - TkDeadAppObjCmd, NULL, NULL); + if ((cmdPtr->flags & SAVEUPDATECMD) && + winPtr->mainPtr->tclUpdateObjProc != NULL) { + /* Restore Tcl's version of [update] */ + Tcl_CreateObjCommand(winPtr->mainPtr->interp, + cmdPtr->name, + winPtr->mainPtr->tclUpdateObjProc, + NULL, NULL); + } else { + Tcl_CreateObjCommand(winPtr->mainPtr->interp, + cmdPtr->name, TkDeadAppObjCmd, + NULL, NULL); + } } Tcl_CreateObjCommand(winPtr->mainPtr->interp, "send", TkDeadAppObjCmd, NULL, NULL); diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c index 46f20bc..7241e13 100644 --- a/macosx/tkMacOSXMouseEvent.c +++ b/macosx/tkMacOSXMouseEvent.c @@ -25,6 +25,13 @@ typedef struct { Point local; } MouseEventData; +typedef struct { + uint64_t wheelTickPrev; /* For high resolution wheels. */ + double vWheelAcc; /* For high resolution wheels (vertical). */ + double hWheelAcc; /* For high resolution wheels (horizontal). */ +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; + static Tk_Window captureWinPtr = NULL; /* Current capture window; may be * NULL. */ @@ -309,6 +316,8 @@ enum { } else { CGFloat delta; XEvent xEvent; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); /* * For scroll wheel events we need to send the XEvent here. @@ -323,19 +332,43 @@ enum { xEvent.xany.display = Tk_Display(target); xEvent.xany.window = Tk_WindowId(target); - delta = [theEvent deltaY] * 120; +#define WHEEL_DELTA 120 +#define WHEEL_DELAY 300000000 + uint64_t wheelTick = clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW); + Bool timeout = (wheelTick - tsdPtr->wheelTickPrev) >= WHEEL_DELAY; + if (timeout) { + tsdPtr->vWheelAcc = tsdPtr->hWheelAcc = 0; + } + tsdPtr->wheelTickPrev = wheelTick; + delta = [theEvent deltaY]; if (delta != 0.0) { - xEvent.xbutton.state = state; - xEvent.xkey.keycode = (delta > 0) ? ceil(delta) : floor(delta); - xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin)); - Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL); + delta = (tsdPtr->vWheelAcc += delta); + if (timeout && fabs(delta) < 1.0) { + delta = ((delta < 0.0) ? -1.0 : 1.0); + } + if (fabs(delta) >= 0.6) { + int intDelta = round(delta); + xEvent.xbutton.state = state; + xEvent.xkey.keycode = WHEEL_DELTA * intDelta; + tsdPtr->vWheelAcc -= intDelta; + xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin)); + Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL); + } } - delta = [theEvent deltaX] * 120; + delta = [theEvent deltaX]; if (delta != 0.0) { - xEvent.xbutton.state = state | ShiftMask; - xEvent.xkey.keycode = (delta > 0) ? ceil(delta) : floor(delta); - xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin)); - Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL); + delta = (tsdPtr->hWheelAcc += delta); + if (timeout && fabs(delta) < 1.0) { + delta = ((delta < 0.0) ? -1.0 : 1.0); + } + if (fabs(delta) >= 0.6) { + int intDelta = round(delta); + xEvent.xbutton.state = state | ShiftMask; + xEvent.xkey.keycode = WHEEL_DELTA * intDelta; + tsdPtr->hWheelAcc -= intDelta; + xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin)); + Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL); + } } } return theEvent; diff --git a/tests/event.test b/tests/event.test index 4b485c1..03405dd 100644 --- a/tests/event.test +++ b/tests/event.test @@ -828,9 +828,10 @@ test event-9 {no <Enter> event is generated for the container window when its pack propagate .top 0 bind .top <Enter> {lappend res %W} pack [frame .top.f -bg green -width 50 -height 50] -anchor se -side bottom - update + tkwait visibility .top.f event generate .top.f <Motion> -warp 1 -x 25 -y 25 ; # <Enter> sent to .top and .top.f - after 50 ; update + after 50 ; # Win specific - wait for SendInput to be executed + update ; # idletasks not enough destroy .top.f ; # no <Enter> event sent update set res diff --git a/tests/textTag.test b/tests/textTag.test index e60920c..b703a81 100644 --- a/tests/textTag.test +++ b/tests/textTag.test @@ -1353,6 +1353,8 @@ test textTag-16.2 {TkTextPickCurrent procedure} -constraints { .t configure -font $textWidgetFont -wrap none } -body { .t tag configure big -font $bigFont + # update needed here to stabilize the test + update event gen .t <ButtonRelease-1> -state 0x100 -x $x4 -y $y4 event gen .t <Motion> -x $x5 -y $y5 set x [.t index current] diff --git a/tests/window.test b/tests/window.test index dec2cc4..8a56d5a 100644 --- a/tests/window.test +++ b/tests/window.test @@ -263,6 +263,38 @@ test window-2.11 {Tk_DestroyWindow, don't reanimate a half-dead window} -constra list $error $msg } -result {0 YES} +test window-2.12 {Test for ticket [9b6065d1fd] - restore Tcl [update] command} -constraints { + unixOrWin +} -body { + set code [loadTkCommand] + append code { + after 1000 {set forever 1} + after 100 {destroy .} + after 200 {catch bell msg; puts "ringing the bell -> $msg"} + after 250 {update idletasks} + after 300 {update} + puts "waiting" + vwait forever + puts "done waiting" + catch {bell} msg + puts "bell -> $msg" + catch update msg + puts "update -> $msg" + } + set script [makeFile $code script] + if {[catch {exec [interpreter] $script -geometry 10x10+0+0} msg]} { + set error 1 + } else { + set error 0 + } + removeFile script + list $error $msg +} -result {0 {waiting +ringing the bell -> can't invoke "bell" command: application has been destroyed +done waiting +bell -> can't invoke "bell" command: application has been destroyed +update -> }} + test window-3.1 {Tk_MakeWindowExist procedure, stacking order and menubars} -constraints { unix testmenubar @@ -342,6 +374,7 @@ test window-5.1 {Tk_MakeWindowExist procedure, stacking order and menubars} -con } -result {} + # cleanup cleanupTests return diff --git a/unix/tkUnixFont.c b/unix/tkUnixFont.c index e30c07a..ccb9b30 100644 --- a/unix/tkUnixFont.c +++ b/unix/tkUnixFont.c @@ -238,6 +238,7 @@ static unsigned RankAttributes(FontAttributes *wantPtr, static void ReleaseFont(UnixFont *fontPtr); static void ReleaseSubFont(Display *display, SubFont *subFontPtr); static int SeenName(const char *name, Tcl_DString *dsPtr); +#if TCL_MAJOR_VERSION < 9 static int Ucs2beToUtfProc(void *clientData, const char*src, int srcLen, int flags, Tcl_EncodingState*statePtr, char *dst, int dstLen, int *srcReadPtr, @@ -246,6 +247,7 @@ static int UtfToUcs2beProc(void *clientData, const char*src, int srcLen, int flags, Tcl_EncodingState*statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr); +#endif /* *------------------------------------------------------------------------- @@ -312,7 +314,9 @@ TkpFontPkgInit( Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); SubFont dummy; int i; +#if TCL_MAJOR_VERSION < 9 Tcl_Encoding ucs2; +#endif if (tsdPtr->controlFamily.encoding == NULL) { @@ -333,6 +337,7 @@ TkpFontPkgInit( * if it doesn't exist yet. It is used in iso10646 fonts. */ +#if TCL_MAJOR_VERSION < 9 ucs2 = Tcl_GetEncoding(NULL, "ucs-2be"); if (ucs2 == NULL) { Tcl_EncodingType ucs2type = {"ucs-2be", Ucs2beToUtfProc, UtfToUcs2beProc, NULL, NULL, 2}; @@ -340,6 +345,7 @@ TkpFontPkgInit( } else { Tcl_FreeEncoding(ucs2); } +#endif Tcl_CreateThreadExitHandler(FontPkgCleanup, NULL); } } @@ -458,6 +464,7 @@ ControlUtfProc( *------------------------------------------------------------------------- */ +#if TCL_MAJOR_VERSION < 9 static int Ucs2beToUtfProc( TCL_UNUSED(void *), /* Not used. */ @@ -554,6 +561,14 @@ Ucs2beToUtfProc( *------------------------------------------------------------------------- */ +#if defined(USE_TCL_STUBS) +/* Since the UCS-2BE encoding is only used when Tk 8.7 is dynamically loaded in Tcl 8.6, + * make sure that Tcl_UtfCharComplete is ALWAYS the pre-TIP #575 version, + * even though Tk 8.7 is being compiled with -DTCL_NO_DEPRECATED! */ +# undef Tcl_UtfCharComplete +# define Tcl_UtfCharComplete ((int (*)(const char *, int))(void *)((&tclStubsPtr->tcl_PkgProvideEx)[326])) +#endif + static int UtfToUcs2beProc( TCL_UNUSED(void *), /* TableEncodingData that specifies @@ -627,6 +642,7 @@ UtfToUcs2beProc( *dstCharsPtr = numChars; return result; } +#endif /* *--------------------------------------------------------------------------- diff --git a/win/tkWinMenu.c b/win/tkWinMenu.c index 02daf16..24e64f1 100644 --- a/win/tkWinMenu.c +++ b/win/tkWinMenu.c @@ -511,7 +511,7 @@ GetEntryText( : Tcl_GetString(mePtr->accelPtr); const char *p, *next; Tcl_DString itemString; - int ch; + Tcl_UniChar ch = 0; /* * We have to construct the string with an ampersand preceeding the @@ -528,16 +528,17 @@ GetEntryText( if (*p == '&') { Tcl_DStringAppend(&itemString, "&", 1); } - next = p + TkUtfToUniChar(p, &ch); + next = p + Tcl_UtfToUniChar(p, &ch); Tcl_DStringAppend(&itemString, p, (int) (next - p)); } + ch = 0; if (mePtr->accelLength > 0) { Tcl_DStringAppend(&itemString, "\t", 1); for (p = accel, i = 0; *p != '\0'; i++, p = next) { if (*p == '&') { Tcl_DStringAppend(&itemString, "&", 1); } - next = p + TkUtfToUniChar(p, &ch); + next = p + Tcl_UtfToUniChar(p, &ch); Tcl_DStringAppend(&itemString, p, (int) (next - p)); } } diff --git a/win/tkWinX.c b/win/tkWinX.c index 7361df6..4a2e514 100644 --- a/win/tkWinX.c +++ b/win/tkWinX.c @@ -80,10 +80,9 @@ typedef struct { * screen. */ int updatingClipboard; /* If 1, we are updating the clipboard. */ int surrogateBuffer; /* Buffer for first of surrogate pair. */ - DWORD vWheelTickPrev; /* For high resolution wheels (vertical). */ - DWORD hWheelTickPrev; /* For high resolution wheels (horizontal). */ - short vWheelAcc; /* For high resolution wheels (vertical). */ - short hWheelAcc; /* For high resolution wheels (horizontal). */ + DWORD wheelTickPrev; /* For high resolution wheels. */ + int vWheelAcc; /* For high resolution wheels (vertical). */ + int hWheelAcc; /* For high resolution wheels (horizontal). */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; @@ -521,7 +520,6 @@ TkpOpenDisplay( Display *display; ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - DWORD initialWheelTick; if (tsdPtr->winDisplay != NULL) { if (!strcmp(tsdPtr->winDisplay->display->display_name, display_name)) { @@ -538,9 +536,7 @@ TkpOpenDisplay( ZeroMemory(tsdPtr->winDisplay, sizeof(TkDisplay)); tsdPtr->winDisplay->display = display; tsdPtr->updatingClipboard = FALSE; - initialWheelTick = GetTickCount(); - tsdPtr->vWheelTickPrev = initialWheelTick; - tsdPtr->hWheelTickPrev = initialWheelTick; + tsdPtr->wheelTickPrev = GetTickCount(); tsdPtr->vWheelAcc = 0; tsdPtr->hWheelAcc = 0; @@ -1141,14 +1137,15 @@ GenerateXEvent( */ DWORD wheelTick = GetTickCount(); + BOOL timeout = wheelTick - tsdPtr->wheelTickPrev >= 300; + int intDelta; - if (wheelTick - tsdPtr->vWheelTickPrev < 1500) { - tsdPtr->vWheelAcc += (short) HIWORD(wParam); - } else { - tsdPtr->vWheelAcc = (short) HIWORD(wParam); + tsdPtr->wheelTickPrev = wheelTick; + if (timeout) { + tsdPtr->vWheelAcc = tsdPtr->hWheelAcc = 0; } - tsdPtr->vWheelTickPrev = wheelTick; - if (abs(tsdPtr->vWheelAcc) < WHEEL_DELTA) { + tsdPtr->vWheelAcc += (short) HIWORD(wParam); + if (!tsdPtr->vWheelAcc || (!timeout && abs(tsdPtr->vWheelAcc) < WHEEL_DELTA * 6 / 10)) { return; } @@ -1160,11 +1157,17 @@ GenerateXEvent( * TkpGetString. [Bug 1118340]. */ + intDelta = (abs(tsdPtr->vWheelAcc) + WHEEL_DELTA/2) / WHEEL_DELTA * WHEEL_DELTA; + if (intDelta == 0) { + intDelta = (tsdPtr->vWheelAcc < 0) ? -WHEEL_DELTA : WHEEL_DELTA; + } else if (tsdPtr->vWheelAcc < 0) { + intDelta = -intDelta; + } event.x.type = MouseWheelEvent; event.x.xany.send_event = -1; event.key.nbytes = 0; - event.x.xkey.keycode = tsdPtr->vWheelAcc / WHEEL_DELTA * WHEEL_DELTA; - tsdPtr->vWheelAcc = tsdPtr->vWheelAcc % WHEEL_DELTA; + event.x.xkey.keycode = intDelta; + tsdPtr->vWheelAcc -= intDelta; break; } case WM_MOUSEHWHEEL: { @@ -1173,14 +1176,15 @@ GenerateXEvent( */ DWORD wheelTick = GetTickCount(); + BOOL timeout = wheelTick - tsdPtr->wheelTickPrev >= 300; + int intDelta; - if (wheelTick - tsdPtr->hWheelTickPrev < 1500) { - tsdPtr->hWheelAcc -= (short) HIWORD(wParam); - } else { - tsdPtr->hWheelAcc = -((short) HIWORD(wParam)); + tsdPtr->wheelTickPrev = wheelTick; + if (timeout) { + tsdPtr->vWheelAcc = tsdPtr->hWheelAcc = 0; } - tsdPtr->hWheelTickPrev = wheelTick; - if (abs(tsdPtr->hWheelAcc) < WHEEL_DELTA) { + tsdPtr->hWheelAcc -= (short) HIWORD(wParam); + if (!tsdPtr->hWheelAcc || (!timeout && abs(tsdPtr->hWheelAcc) < WHEEL_DELTA * 6 / 10)) { return; } @@ -1192,12 +1196,18 @@ GenerateXEvent( * TkpGetString. [Bug 1118340]. */ + intDelta = (abs(tsdPtr->hWheelAcc) + WHEEL_DELTA/2) / WHEEL_DELTA * WHEEL_DELTA; + if (intDelta == 0) { + intDelta = (tsdPtr->hWheelAcc < 0) ? -WHEEL_DELTA : WHEEL_DELTA; + } else if (tsdPtr->hWheelAcc < 0) { + intDelta = -intDelta; + } event.x.type = MouseWheelEvent; event.x.xany.send_event = -1; event.key.nbytes = 0; event.x.xkey.state |= ShiftMask; - event.x.xkey.keycode = tsdPtr->hWheelAcc / WHEEL_DELTA * WHEEL_DELTA; - tsdPtr->hWheelAcc = tsdPtr->hWheelAcc % WHEEL_DELTA; + event.x.xkey.keycode = intDelta; + tsdPtr->hWheelAcc -= intDelta; break; } case WM_SYSKEYDOWN: |