diff options
Diffstat (limited to 'generic/tkBind.c')
-rw-r--r-- | generic/tkBind.c | 320 |
1 files changed, 195 insertions, 125 deletions
diff --git a/generic/tkBind.c b/generic/tkBind.c index 1be3677..ceaa468 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -4,10 +4,10 @@ * This file provides functions that associate Tcl commands with X events * or sequences of X events. * - * Copyright (c) 1989-1994 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * Copyright (c) 1998 by Scriptics Corporation. - * Copyright (c) 2018-2019 by Gregor Cramer. + * Copyright © 1989-1994 The Regents of the University of California. + * Copyright © 1994-1997 Sun Microsystems, Inc. + * Copyright © 1998 Scriptics Corporation. + * Copyright © 2018-2019 Gregor Cramer. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -62,21 +62,21 @@ * equivalent sequences. However it is logical to give <Double-1> higher precedence * since it is more specific. Indeed <Double-1> 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. + * This is achieved by setting PREFER_MOST_SPECIALIZED_EVENT to 1. */ #ifndef PREFER_MOST_SPECIALIZED_EVENT -# define PREFER_MOST_SPECIALIZED_EVENT 0 +# define PREFER_MOST_SPECIALIZED_EVENT 1 #endif /* * Traditionally motion events can be combined with buttons in this way: <B1-B2-Motion>. - * However it should be allowed to express this as <Motion-1-2> in addition. This can be - * achieved by setting SUPPORT_ADDITIONAL_MOTION_SYNTAX to 1. + * However it should be allowed to express this as <Motion-1-2> in addition. This is achieved + * by setting SUPPORT_ADDITIONAL_MOTION_SYNTAX to 1. */ #ifndef SUPPORT_ADDITIONAL_MOTION_SYNTAX -# define SUPPORT_ADDITIONAL_MOTION_SYNTAX 0 /* set to 1 if wanted */ +# define SUPPORT_ADDITIONAL_MOTION_SYNTAX 1 #endif /* @@ -432,7 +432,9 @@ static const ModInfo modArray[] = { {"Shift", ShiftMask, 0}, {"Lock", LockMask, 0}, {"Meta", META_MASK, 0}, +#ifndef TK_NO_DEPRECATED {"M", META_MASK, 0}, +#endif {"Alt", ALT_MASK, 0}, {"Extended", EXTENDED_MASK, 0}, {"B1", Button1Mask, 0}, @@ -445,15 +447,35 @@ 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}, +#ifdef MAC_OSX_TK {"Command", Mod1Mask, 0}, +#elif defined (_WIN32) + {"Command", ControlMask, 0}, +#else + {"Command", META_MASK, 0}, +#endif {"Mod2", Mod2Mask, 0}, {"M2", Mod2Mask, 0}, +#ifdef MAC_OSX_TK {"Option", Mod2Mask, 0}, +#else + {"Option", ALT_MASK, 0}, +#endif {"Mod3", Mod3Mask, 0}, {"M3", Mod3Mask, 0}, + {"Num", Mod3Mask, 0}, {"Mod4", Mod4Mask, 0}, + {"Fn", Mod4Mask, 0}, {"M4", Mod4Mask, 0}, {"Mod5", Mod5Mask, 0}, {"M5", Mod5Mask, 0}, @@ -486,10 +508,14 @@ typedef struct { static const EventInfo eventArray[] = { {"Key", KeyPress, KeyPressMask}, +#ifndef TK_NO_DEPRECATED {"KeyPress", KeyPress, KeyPressMask}, +#endif {"KeyRelease", KeyRelease, KeyPressMask|KeyReleaseMask}, {"Button", ButtonPress, ButtonPressMask}, +#ifndef TK_NO_DEPRECATED {"ButtonPress", ButtonPress, ButtonPressMask}, +#endif {"ButtonRelease", ButtonRelease, ButtonPressMask|ButtonReleaseMask}, {"Motion", MotionNotify, ButtonPressMask|PointerMotionMask}, {"Enter", EnterNotify, EnterWindowMask}, @@ -723,7 +749,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, unsigned *eventMaskPtr); -static void DoWarp(ClientData clientData); static PSList * GetLookupForEvent(LookupTables* lookupPtr, const Event *eventPtr, Tcl_Obj *object, int onlyConsiderDetailedEvents); static void ClearLookupTable(LookupTables *lookupTables, ClientData object); @@ -785,8 +810,10 @@ static unsigned GetButtonNumber( const char *field) { + unsigned button; assert(field); - return (field[0] >= '1' && field[0] <= '5' && field[1] == '\0') ? field[0] - '0' : 0; + button = (field[0] >= '1' && field[0] <= '9' && field[1] == '\0') ? field[0] - '0' : 0; + return (button > 3) ? (button + 4) : button; } static Time @@ -985,7 +1012,11 @@ ButtonNumberFromState( if (state & Button2Mask) { return 2; } if (state & Button3Mask) { return 3; } if (state & Button4Mask) { return 4; } - return 5; + if (state & Button5Mask) { return 5; } + if (state & Button6Mask) { return 6; } + if (state & Button7Mask) { return 7; } + if (state & Button8Mask) { return 8; } + return 9; } static void @@ -1274,49 +1305,49 @@ TkBindInit( assert(NoSymbol == 0L); /* this must be a union, not a struct, otherwise comparison with NULL will not work */ - assert(Tk_Offset(Detail, name) == Tk_Offset(Detail, info)); + assert(offsetof(Detail, name) == offsetof(Detail, info)); /* we use some constraints about X*Event */ - assert(Tk_Offset(XButtonEvent, time) == Tk_Offset(XMotionEvent, time)); - assert(Tk_Offset(XButtonEvent, x_root) == Tk_Offset(XMotionEvent, x_root)); - assert(Tk_Offset(XButtonEvent, y_root) == Tk_Offset(XMotionEvent, y_root)); - assert(Tk_Offset(XCreateWindowEvent, border_width) == Tk_Offset(XConfigureEvent, border_width)); - assert(Tk_Offset(XCreateWindowEvent, width) == Tk_Offset(XConfigureEvent, width)); - assert(Tk_Offset(XCreateWindowEvent, window) == Tk_Offset(XCirculateRequestEvent, window)); - assert(Tk_Offset(XCreateWindowEvent, window) == Tk_Offset(XConfigureEvent, window)); - assert(Tk_Offset(XCreateWindowEvent, window) == Tk_Offset(XGravityEvent, window)); - assert(Tk_Offset(XCreateWindowEvent, window) == Tk_Offset(XMapEvent, window)); - assert(Tk_Offset(XCreateWindowEvent, window) == Tk_Offset(XReparentEvent, window)); - assert(Tk_Offset(XCreateWindowEvent, window) == Tk_Offset(XUnmapEvent, window)); - assert(Tk_Offset(XCreateWindowEvent, x) == Tk_Offset(XConfigureEvent, x)); - assert(Tk_Offset(XCreateWindowEvent, x) == Tk_Offset(XGravityEvent, x)); - assert(Tk_Offset(XCreateWindowEvent, y) == Tk_Offset(XConfigureEvent, y)); - assert(Tk_Offset(XCreateWindowEvent, y) == Tk_Offset(XGravityEvent, y)); - assert(Tk_Offset(XCrossingEvent, time) == Tk_Offset(XEnterWindowEvent, time)); - assert(Tk_Offset(XCrossingEvent, time) == Tk_Offset(XLeaveWindowEvent, time)); - assert(Tk_Offset(XCrossingEvent, time) == Tk_Offset(XKeyEvent, time)); - assert(Tk_Offset(XKeyEvent, root) == Tk_Offset(XButtonEvent, root)); - assert(Tk_Offset(XKeyEvent, root) == Tk_Offset(XCrossingEvent, root)); - assert(Tk_Offset(XKeyEvent, root) == Tk_Offset(XMotionEvent, root)); - assert(Tk_Offset(XKeyEvent, state) == Tk_Offset(XButtonEvent, state)); - assert(Tk_Offset(XKeyEvent, state) == Tk_Offset(XMotionEvent, state)); - assert(Tk_Offset(XKeyEvent, subwindow) == Tk_Offset(XButtonEvent, subwindow)); - assert(Tk_Offset(XKeyEvent, subwindow) == Tk_Offset(XCrossingEvent, subwindow)); - assert(Tk_Offset(XKeyEvent, subwindow) == Tk_Offset(XMotionEvent, subwindow)); - assert(Tk_Offset(XKeyEvent, time) == Tk_Offset(XButtonEvent, time)); - assert(Tk_Offset(XKeyEvent, time) == Tk_Offset(XMotionEvent, time)); - assert(Tk_Offset(XKeyEvent, x) == Tk_Offset(XButtonEvent, x)); - assert(Tk_Offset(XKeyEvent, x) == Tk_Offset(XCrossingEvent, x)); - assert(Tk_Offset(XKeyEvent, x) == Tk_Offset(XMotionEvent, x)); - assert(Tk_Offset(XKeyEvent, x_root) == Tk_Offset(XButtonEvent, x_root)); - assert(Tk_Offset(XKeyEvent, x_root) == Tk_Offset(XCrossingEvent, x_root)); - assert(Tk_Offset(XKeyEvent, x_root) == Tk_Offset(XMotionEvent, x_root)); - assert(Tk_Offset(XKeyEvent, y) == Tk_Offset(XButtonEvent, y)); - assert(Tk_Offset(XKeyEvent, y) == Tk_Offset(XCrossingEvent, y)); - assert(Tk_Offset(XKeyEvent, y) == Tk_Offset(XMotionEvent, y)); - assert(Tk_Offset(XKeyEvent, y_root) == Tk_Offset(XButtonEvent, y_root)); - assert(Tk_Offset(XKeyEvent, y_root) == Tk_Offset(XCrossingEvent, y_root)); - assert(Tk_Offset(XKeyEvent, y_root) == Tk_Offset(XMotionEvent, y_root)); + assert(offsetof(XButtonEvent, time) == offsetof(XMotionEvent, time)); + assert(offsetof(XButtonEvent, x_root) == offsetof(XMotionEvent, x_root)); + assert(offsetof(XButtonEvent, y_root) == offsetof(XMotionEvent, y_root)); + assert(offsetof(XCreateWindowEvent, border_width) == offsetof(XConfigureEvent, border_width)); + assert(offsetof(XCreateWindowEvent, width) == offsetof(XConfigureEvent, width)); + assert(offsetof(XCreateWindowEvent, window) == offsetof(XCirculateRequestEvent, window)); + assert(offsetof(XCreateWindowEvent, window) == offsetof(XConfigureEvent, window)); + assert(offsetof(XCreateWindowEvent, window) == offsetof(XGravityEvent, window)); + assert(offsetof(XCreateWindowEvent, window) == offsetof(XMapEvent, window)); + assert(offsetof(XCreateWindowEvent, window) == offsetof(XReparentEvent, window)); + assert(offsetof(XCreateWindowEvent, window) == offsetof(XUnmapEvent, window)); + assert(offsetof(XCreateWindowEvent, x) == offsetof(XConfigureEvent, x)); + assert(offsetof(XCreateWindowEvent, x) == offsetof(XGravityEvent, x)); + assert(offsetof(XCreateWindowEvent, y) == offsetof(XConfigureEvent, y)); + assert(offsetof(XCreateWindowEvent, y) == offsetof(XGravityEvent, y)); + assert(offsetof(XCrossingEvent, time) == offsetof(XEnterWindowEvent, time)); + assert(offsetof(XCrossingEvent, time) == offsetof(XLeaveWindowEvent, time)); + assert(offsetof(XCrossingEvent, time) == offsetof(XKeyEvent, time)); + assert(offsetof(XKeyEvent, root) == offsetof(XButtonEvent, root)); + assert(offsetof(XKeyEvent, root) == offsetof(XCrossingEvent, root)); + assert(offsetof(XKeyEvent, root) == offsetof(XMotionEvent, root)); + assert(offsetof(XKeyEvent, state) == offsetof(XButtonEvent, state)); + assert(offsetof(XKeyEvent, state) == offsetof(XMotionEvent, state)); + assert(offsetof(XKeyEvent, subwindow) == offsetof(XButtonEvent, subwindow)); + assert(offsetof(XKeyEvent, subwindow) == offsetof(XCrossingEvent, subwindow)); + assert(offsetof(XKeyEvent, subwindow) == offsetof(XMotionEvent, subwindow)); + assert(offsetof(XKeyEvent, time) == offsetof(XButtonEvent, time)); + assert(offsetof(XKeyEvent, time) == offsetof(XMotionEvent, time)); + assert(offsetof(XKeyEvent, x) == offsetof(XButtonEvent, x)); + assert(offsetof(XKeyEvent, x) == offsetof(XCrossingEvent, x)); + assert(offsetof(XKeyEvent, x) == offsetof(XMotionEvent, x)); + assert(offsetof(XKeyEvent, x_root) == offsetof(XButtonEvent, x_root)); + assert(offsetof(XKeyEvent, x_root) == offsetof(XCrossingEvent, x_root)); + assert(offsetof(XKeyEvent, x_root) == offsetof(XMotionEvent, x_root)); + assert(offsetof(XKeyEvent, y) == offsetof(XButtonEvent, y)); + assert(offsetof(XKeyEvent, y) == offsetof(XCrossingEvent, y)); + assert(offsetof(XKeyEvent, y) == offsetof(XMotionEvent, y)); + assert(offsetof(XKeyEvent, y_root) == offsetof(XButtonEvent, y_root)); + assert(offsetof(XKeyEvent, y_root) == offsetof(XCrossingEvent, y_root)); + assert(offsetof(XKeyEvent, y_root) == offsetof(XMotionEvent, y_root)); /* * Initialize the static data structures used by the binding package. They @@ -2982,8 +3013,8 @@ ExpandPercents( while (1) { char numStorage[TCL_INTEGER_SPACE]; const char *string; - Tcl_WideInt number; /* signed */ - Tcl_WideUInt unumber; /* unsigned */ + long long number; /* signed */ + unsigned long long unumber; /* unsigned */ /* * Find everything up to the next % character and append it to the @@ -4049,6 +4080,9 @@ HandleEventGenerate( return TCL_ERROR; } if (flags & BUTTON) { + if (number >= Button4) { + number += (Button8 - Button4); + } event.general.xbutton.button = number; } else { badOpt = 1; @@ -4424,10 +4458,19 @@ HandleEventGenerate( 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; - } + /* + * 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 directly here. + */ + + if (!dispPtr->warpWindow) { + TkpWarpPointer(dispPtr); + XForceScreenSaver(dispPtr->display, ScreenSaverReset); + } } /* @@ -4511,9 +4554,9 @@ NameToWindow( /* *------------------------------------------------------------------------- * - * DoWarp -- + * TkDoWarpWrtWin -- * - * Perform warping of mouse pointer. Executed as an idle handler only. + * Perform warping of mouse pointer with respect to a window. * * Results: * None @@ -4524,33 +4567,34 @@ NameToWindow( *------------------------------------------------------------------------- */ -static void -DoWarp( - ClientData clientData) +void +TkDoWarpWrtWin( + TkDisplay *dispPtr) { - TkDisplay *dispPtr = (TkDisplay *)clientData; - - assert(clientData); + assert(dispPtr); /* - * 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 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 || - (Tk_IsMapped(dispPtr->warpWindow) && Tk_WindowId(dispPtr->warpWindow) != None)) { - TkpWarpPointer(dispPtr); - XForceScreenSaver(dispPtr->display, ScreenSaverReset); - } - if (dispPtr->warpWindow) { - Tcl_Release(dispPtr->warpWindow); - dispPtr->warpWindow = NULL; + + /* + * 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; } - dispPtr->flags &= ~TK_DISPLAY_IN_WARP; } /* @@ -5002,7 +5046,7 @@ ParseEventDescription( "NON_BUTTON"); } #if SUPPORT_ADDITIONAL_MOTION_SYNTAX - patPtr->modMask |= TkGetButtonMask(button); + patPtr->modMask |= Tk_GetButtonMask(button); p = SkipFieldDelims(p); while (*p && *p != '>') { p = SkipFieldDelims(GetField(p, field, sizeof(field))); @@ -5012,7 +5056,7 @@ ParseEventDescription( patPtr, 0, Tcl_ObjPrintf("bad button number \"%s\"", field), "BUTTON"); } - patPtr->modMask |= TkGetButtonMask(button); + patPtr->modMask |= Tk_GetButtonMask(button); } patPtr->info = ButtonNumberFromState(patPtr->modMask); #endif @@ -5190,16 +5234,16 @@ GetPatternObj( } case ButtonPress: case ButtonRelease: - assert(patPtr->info <= Button5); - Tcl_AppendPrintfToObj(patternObj, "-%u", (unsigned) patPtr->info); + assert(patPtr->info <= 13); + Tcl_AppendPrintfToObj(patternObj, "-%u", (unsigned) ((patPtr->info > 7) ? (patPtr->info - 4) : patPtr->info)); break; #if PRINT_SHORT_MOTION_SYNTAX case MotionNotify: { unsigned mask = patPtr->modMask; while (mask & ALL_BUTTONS) { unsigned button = ButtonNumberFromState(mask); - Tcl_AppendPrintfToObj(patternObj, "-%u", button); - mask &= ~TkGetButtonMask(button); + Tcl_AppendPrintfToObj(patternObj, "-%u", (button > 7) ? (button - 4) : button); + mask &= ~Tk_GetButtonMask(button); } break; } @@ -5236,14 +5280,48 @@ TkStringToKeysym( const char *name) /* Name of a keysym. */ { #ifdef REDO_KEYSYM_LOOKUP - Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&keySymTable, name); - + Tcl_HashEntry *hPtr; +#endif /* REDO_KEYSYM_LOOKUP */ + int keysym; + + size_t len = TkUtfToUniChar(name, &keysym); + if (name[len] == '\0') { + if (!Tcl_UniCharIsPrint(keysym)) { + /* This form not supported */ + } else if ((unsigned)(keysym - 0x21) <= 0x5D) { + return keysym; + } else if ((unsigned)(keysym - 0xA1) <= 0x5E) { + return keysym; + } else if (keysym == 0x20AC) { + return 0x20AC; + } else { + return keysym + 0x1000000; + } + } +#ifdef REDO_KEYSYM_LOOKUP + if ((name[0] == 'U') && ((unsigned)(name[1] - '0') <= 9)) { + char *p = (char *)name + 1; + keysym = strtol(p, &p, 16); + if ((p >= name + 5) && (p <= name + 9) && !*p && (keysym >= 0x20) + && ((unsigned)(keysym - 0x7F) > 0x20)) { + if ((unsigned)(keysym - 0x21) <= 0x5D) { + return keysym; + } else if ((unsigned)(keysym - 0xA1) <= 0x5E) { + return keysym; + } else if (keysym == 0x20AC) { + return keysym; + } + return keysym + 0x1000000; + } + } +#endif +#ifdef REDO_KEYSYM_LOOKUP + hPtr = Tcl_FindHashEntry(&keySymTable, name); if (hPtr) { return (KeySym) Tcl_GetHashValue(hPtr); } - assert(name); - if (strlen(name) == 1u) { - KeySym keysym = (KeySym) (unsigned char) name[0]; + if (((unsigned)(name[0]-1) < 0x7F) && !name[1]) { + keysym = (unsigned char) name[0]; if (TkKeysymToString(keysym)) { return keysym; @@ -5276,16 +5354,37 @@ TkKeysymToString( KeySym keysym) { #ifdef REDO_KEYSYM_LOOKUP - Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&nameTable, (char *)keysym); + Tcl_HashEntry *hPtr; +#endif + + if ((unsigned)(keysym - 0x21) <= 0x5D) { + keysym += 0x1000000; + } else if ((unsigned)(keysym - 0xA1) <= 0x5E) { + keysym += 0x1000000; + } else if (keysym == 0x20AC) { + keysym += 0x1000000; + } + if ((keysym >= 0x1000020) && (keysym <= 0x110FFFF) + && ((unsigned)(keysym - 0x100007F) > 0x20)) { + char buf[10]; + if (Tcl_UniCharIsPrint(keysym-0x1000000)) { + buf[TkUniCharToUtf(keysym - 0x1000000, buf)] = '\0'; + } else if (keysym >= 0x1010000) { + sprintf(buf, "U%08X", (int)(keysym - 0x1000000)); + } else { + sprintf(buf, "U%04X", (int)(keysym - 0x1000000)); + } + return Tk_GetUid(buf); + } + +#ifdef REDO_KEYSYM_LOOKUP + hPtr = Tcl_FindHashEntry(&nameTable, INT2PTR(keysym)); if (hPtr) { return (const char *)Tcl_GetHashValue(hPtr); } #endif /* REDO_KEYSYM_LOOKUP */ - if (keysym > (KeySym)0x1008FFFF) { - return NULL; - } return XKeysymToString(keysym); } @@ -5321,35 +5420,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) { - Tcl_CancelIdleCall(DoWarp, dispPtr); - dispPtr->flags &= ~TK_DISPLAY_IN_WARP; - } -} - -/* - *---------------------------------------------------------------------- - * * TkpDumpPS -- * * Dump given pattern sequence to stdout. |