tkBind.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:133k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * There's a percent sequence here.  Process it.
  3.  */
  4. number = 0;
  5. string = "??";
  6. switch (before[1]) {
  7.     case '#':
  8. number = eventPtr->xany.serial;
  9. goto doNumber;
  10.     case 'a':
  11. if (flags & CONFIG) {
  12.     TkpPrintWindowId(numStorage, eventPtr->xconfigure.above);
  13.     string = numStorage;
  14. }
  15. goto doString;
  16.     case 'b':
  17. if (flags & BUTTON) {
  18.     number = eventPtr->xbutton.button;
  19.     goto doNumber;
  20. }
  21. goto doString;
  22.     case 'c':
  23. if (flags & EXPOSE) {
  24.     number = eventPtr->xexpose.count;
  25.     goto doNumber;
  26. }
  27. goto doString;
  28.     case 'd':
  29. if (flags & (CROSSING|FOCUS)) {
  30.     if (flags & FOCUS) {
  31. number = eventPtr->xfocus.detail;
  32.     } else {
  33. number = eventPtr->xcrossing.detail;
  34.     }
  35.     string = TkFindStateString(notifyDetail, number);
  36. } else if (flags & CONFIGREQ) {
  37.     if (eventPtr->xconfigurerequest.value_mask & CWStackMode) {
  38. string = TkFindStateString(configureRequestDetail,
  39. eventPtr->xconfigurerequest.detail);
  40.     } else {
  41. string = "";
  42.     }
  43. }
  44. goto doString;
  45.     case 'f':
  46. if (flags & CROSSING) {
  47.     number = eventPtr->xcrossing.focus;
  48.     goto doNumber;
  49. }
  50. goto doString;
  51.     case 'h':
  52. if (flags & EXPOSE) {
  53.     number = eventPtr->xexpose.height;
  54. } else if (flags & (CONFIG)) {
  55.     number = eventPtr->xconfigure.height;
  56. } else if (flags & CREATE) {
  57.     number = eventPtr->xcreatewindow.height;
  58. } else if (flags & CONFIGREQ) {
  59.     number =  eventPtr->xconfigurerequest.height;
  60. } else if (flags & RESIZEREQ) {
  61.     number =  eventPtr->xresizerequest.height;
  62. } else {
  63.     goto doString;
  64. }
  65. goto doNumber;
  66.     case 'i':
  67. if (flags & CREATE) {
  68.     TkpPrintWindowId(numStorage, eventPtr->xcreatewindow.window);
  69. } else if (flags & CONFIGREQ) {
  70.     TkpPrintWindowId(numStorage, eventPtr->xconfigurerequest.window);
  71. } else if (flags & MAPREQ) {
  72.     TkpPrintWindowId(numStorage, eventPtr->xmaprequest.window);
  73. } else {
  74.     TkpPrintWindowId(numStorage, eventPtr->xany.window);
  75. }
  76. string = numStorage;
  77. goto doString;
  78.     case 'k':
  79. if (flags & KEY) {
  80.     number = eventPtr->xkey.keycode;
  81.     goto doNumber;
  82. }
  83. goto doString;
  84.     case 'm':
  85. if (flags & CROSSING) {
  86.     number = eventPtr->xcrossing.mode;
  87.     string = TkFindStateString(notifyMode, number);
  88. } else if (flags & FOCUS) {
  89.     number = eventPtr->xfocus.mode;
  90.     string = TkFindStateString(notifyMode, number);
  91. }
  92. goto doString;
  93.     case 'o':
  94. if (flags & CREATE) {
  95.     number = eventPtr->xcreatewindow.override_redirect;
  96. } else if (flags & MAP) {
  97.     number = eventPtr->xmap.override_redirect;
  98. } else if (flags & REPARENT) {
  99.     number = eventPtr->xreparent.override_redirect;
  100. } else if (flags & CONFIG) {
  101.     number = eventPtr->xconfigure.override_redirect;
  102. } else {
  103.     goto doString;
  104. }
  105. goto doNumber;
  106.     case 'p':
  107. if (flags & CIRC) {
  108.     string = TkFindStateString(circPlace, eventPtr->xcirculate.place);
  109. } else if (flags & CIRCREQ) {
  110.     string = TkFindStateString(circPlace, eventPtr->xcirculaterequest.place);
  111. }
  112. goto doString;
  113.     case 's':
  114. if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) {
  115.     number = eventPtr->xkey.state;
  116. } else if (flags & CROSSING) {
  117.     number = eventPtr->xcrossing.state;
  118. } else if (flags & PROP) {
  119.     string = TkFindStateString(propNotify,
  120.     eventPtr->xproperty.state);
  121.     goto doString;
  122. } else if (flags & VISIBILITY) {
  123.     string = TkFindStateString(visNotify,
  124.     eventPtr->xvisibility.state);
  125.     goto doString;
  126. } else {
  127.     goto doString;
  128. }
  129. goto doNumber;
  130.     case 't':
  131. if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) {
  132.     number = (int) eventPtr->xkey.time;
  133. } else if (flags & CROSSING) {
  134.     number = (int) eventPtr->xcrossing.time;
  135. } else if (flags & PROP) {
  136.     number = (int) eventPtr->xproperty.time;
  137. } else {
  138.     goto doString;
  139. }
  140. goto doNumber;
  141.     case 'v':
  142. number = eventPtr->xconfigurerequest.value_mask;
  143. goto doNumber;
  144.     case 'w':
  145. if (flags & EXPOSE) {
  146.     number = eventPtr->xexpose.width;
  147. } else if (flags & CONFIG) {
  148.     number = eventPtr->xconfigure.width;
  149. } else if (flags & CREATE) {
  150.     number = eventPtr->xcreatewindow.width;
  151. } else if (flags & CONFIGREQ) {
  152.     number =  eventPtr->xconfigurerequest.width;
  153. } else if (flags & RESIZEREQ) {
  154.     number =  eventPtr->xresizerequest.width;
  155. } else {
  156.     goto doString;
  157. }
  158. goto doNumber;
  159.     case 'x':
  160. if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) {
  161.     number = eventPtr->xkey.x;
  162. } else if (flags & CROSSING) {
  163.     number = eventPtr->xcrossing.x;
  164. } else if (flags & EXPOSE) {
  165.     number = eventPtr->xexpose.x;
  166. } else if (flags & (CREATE|CONFIG|GRAVITY)) {
  167.     number = eventPtr->xcreatewindow.x;
  168. } else if (flags & REPARENT) {
  169.     number = eventPtr->xreparent.x;
  170. } else if (flags & CREATE) {
  171.     number = eventPtr->xcreatewindow.x;
  172. } else if (flags & CONFIGREQ) {
  173.     number =  eventPtr->xconfigurerequest.x;
  174. } else {
  175.     goto doString;
  176. }
  177. goto doNumber;
  178.     case 'y':
  179. if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) {
  180.     number = eventPtr->xkey.y;
  181. } else if (flags & EXPOSE) {
  182.     number = eventPtr->xexpose.y;
  183. } else if (flags & (CREATE|CONFIG|GRAVITY)) {
  184.     number = eventPtr->xcreatewindow.y;
  185. } else if (flags & REPARENT) {
  186.     number = eventPtr->xreparent.y;
  187. } else if (flags & CROSSING) {
  188.     number = eventPtr->xcrossing.y;
  189. } else if (flags & CREATE) {
  190.     number = eventPtr->xcreatewindow.y;
  191. } else if (flags & CONFIGREQ) {
  192.     number = eventPtr->xconfigurerequest.y;
  193. } else {
  194.     goto doString;
  195. }
  196. goto doNumber;
  197.     case 'A':
  198. if (flags & KEY) {
  199.     Tcl_DStringFree(&buf);
  200.     string = TkpGetString(winPtr, eventPtr, &buf);
  201. }
  202. goto doString;
  203.     case 'B':
  204. if (flags & CREATE) {
  205.     number = eventPtr->xcreatewindow.border_width;
  206. } else if (flags & CONFIGREQ) {
  207.     number = eventPtr->xconfigurerequest.border_width;
  208. } else if (flags & CONFIG) {
  209.     number = eventPtr->xconfigure.border_width;
  210. } else {
  211.     goto doString;
  212. }
  213. goto doNumber;
  214.     case 'D':
  215. /*
  216.  * This is used only by the MouseWheel event.
  217.  */
  218. if (flags & KEY) {
  219.     number = eventPtr->xkey.keycode;
  220.     goto doNumber;
  221. }
  222. goto doString;
  223.     case 'E':
  224. number = (int) eventPtr->xany.send_event;
  225. goto doNumber;
  226.     case 'K':
  227. if (flags & KEY) {
  228.     char *name;
  229.     name = TkKeysymToString(keySym);
  230.     if (name != NULL) {
  231. string = name;
  232.     }
  233. }
  234. goto doString;
  235.     case 'N':
  236. if (flags & KEY) {
  237.     number = (int) keySym;
  238.     goto doNumber;
  239. }
  240. goto doString;
  241.     case 'P':
  242. if (flags & PROP) {
  243.     string = Tk_GetAtomName((Tk_Window) winPtr, eventPtr->xproperty.atom);
  244. }
  245. goto doString;
  246.     case 'R':
  247. if (flags & KEY_BUTTON_MOTION_CROSSING) {
  248.     TkpPrintWindowId(numStorage, eventPtr->xkey.root);
  249.     string = numStorage;
  250. }
  251. goto doString;
  252.             case 'S':
  253. if (flags & KEY_BUTTON_MOTION_CROSSING) {
  254.     TkpPrintWindowId(numStorage, eventPtr->xkey.subwindow);
  255.     string = numStorage;
  256. }
  257. goto doString;
  258.     case 'T':
  259. number = eventPtr->type;
  260. goto doNumber;
  261.     case 'W': {
  262. Tk_Window tkwin;
  263. tkwin = Tk_IdToWindow(eventPtr->xany.display,
  264. eventPtr->xany.window);
  265. if (tkwin != NULL) {
  266.     string = Tk_PathName(tkwin);
  267. } else {
  268.     string = "??";
  269. }
  270. goto doString;
  271.     }
  272.     case 'X':
  273. if (flags & KEY_BUTTON_MOTION_CROSSING) {
  274.     Tk_Window tkwin;
  275.     int x, y;
  276.     int width, height;
  277.     number = eventPtr->xkey.x_root;
  278.     tkwin = Tk_IdToWindow(eventPtr->xany.display,
  279.     eventPtr->xany.window);
  280.     if (tkwin != NULL) {
  281. Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height);
  282. number -= x;
  283.     }
  284.     goto doNumber;
  285. }
  286. goto doString;
  287.     case 'Y':
  288. if (flags & KEY_BUTTON_MOTION_CROSSING) {
  289.     Tk_Window tkwin;
  290.     int x, y;
  291.     int width, height;
  292.     number = eventPtr->xkey.y_root;
  293.     tkwin = Tk_IdToWindow(eventPtr->xany.display,
  294.     eventPtr->xany.window);
  295.     if (tkwin != NULL) {
  296. Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height);
  297. number -= y;
  298.     }
  299.     goto doNumber;
  300. }
  301. goto doString;
  302.     default:
  303. numStorage[0] = before[1];
  304. numStorage[1] = '';
  305. string = numStorage;
  306. goto doString;
  307. }
  308. doNumber:
  309. sprintf(numStorage, "%d", number);
  310. string = numStorage;
  311. doString:
  312. spaceNeeded = Tcl_ScanElement(string, &cvtFlags);
  313. length = Tcl_DStringLength(dsPtr);
  314. Tcl_DStringSetLength(dsPtr, length + spaceNeeded);
  315. spaceNeeded = Tcl_ConvertElement(string,
  316. Tcl_DStringValue(dsPtr) + length,
  317. cvtFlags | TCL_DONT_USE_BRACES);
  318. Tcl_DStringSetLength(dsPtr, length + spaceNeeded);
  319. before += 2;
  320.     }
  321.     Tcl_DStringFree(&buf);
  322. }
  323. /*
  324.  *----------------------------------------------------------------------
  325.  *
  326.  * ChangeScreen --
  327.  *
  328.  * This procedure is invoked whenever the current screen changes
  329.  * in an application.  It invokes a Tcl procedure named
  330.  * "tk::ScreenChanged", passing it the screen name as argument.
  331.  * tk::ScreenChanged does things like making the tk::Priv variable
  332.  * point to an array for the current display.
  333.  *
  334.  * Results:
  335.  * None.
  336.  *
  337.  * Side effects:
  338.  * Depends on what tk::ScreenChanged does.  If an error occurs
  339.  * them bgerror will be invoked.
  340.  *
  341.  *----------------------------------------------------------------------
  342.  */
  343. static void
  344. ChangeScreen(interp, dispName, screenIndex)
  345.     Tcl_Interp *interp; /* Interpreter in which to invoke
  346.  * command. */
  347.     char *dispName; /* Name of new display. */
  348.     int screenIndex; /* Index of new screen. */
  349. {
  350.     Tcl_DString cmd;
  351.     int code;
  352.     char screen[TCL_INTEGER_SPACE];
  353.     Tcl_DStringInit(&cmd);
  354.     Tcl_DStringAppend(&cmd, "tk::ScreenChanged ", 18);
  355.     Tcl_DStringAppend(&cmd, dispName, -1);
  356.     sprintf(screen, ".%d", screenIndex);
  357.     Tcl_DStringAppend(&cmd, screen, -1);
  358.     code = Tcl_EvalEx(interp, Tcl_DStringValue(&cmd), Tcl_DStringLength(&cmd),
  359.     TCL_EVAL_GLOBAL);
  360.     if (code != TCL_OK) {
  361. Tcl_AddErrorInfo(interp,
  362. "n    (changing screen in event binding)");
  363. Tcl_BackgroundError(interp);
  364.     }
  365. }
  366. /*
  367.  *----------------------------------------------------------------------
  368.  *
  369.  * Tk_EventCmd --
  370.  *
  371.  * This procedure is invoked to process the "event" Tcl command.
  372.  * It is used to define and generate events.
  373.  *
  374.  * Results:
  375.  * A standard Tcl result.
  376.  *
  377.  * Side effects:
  378.  * See the user documentation.
  379.  *
  380.  *----------------------------------------------------------------------
  381.  */
  382. int
  383. Tk_EventObjCmd(clientData, interp, objc, objv)
  384.     ClientData clientData; /* Main window associated with interpreter. */
  385.     Tcl_Interp *interp; /* Current interpreter. */
  386.     int objc; /* Number of arguments. */
  387.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  388. {
  389.     int index;
  390.     Tk_Window tkwin;
  391.     VirtualEventTable *vetPtr;
  392.     TkBindInfo bindInfo;
  393.     static CONST char *optionStrings[] = {
  394. "add", "delete", "generate", "info",
  395. NULL
  396.     };
  397.     enum options {
  398. EVENT_ADD, EVENT_DELETE, EVENT_GENERATE, EVENT_INFO
  399.     };
  400.     tkwin = (Tk_Window) clientData;
  401.     bindInfo = ((TkWindow *) tkwin)->mainPtr->bindInfo;
  402.     vetPtr = &((BindInfo *) bindInfo)->virtualEventTable;
  403.     if (objc < 2) {
  404. Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?");
  405. return TCL_ERROR;
  406.     }
  407.     if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
  408.     &index) != TCL_OK) {
  409. return TCL_ERROR;
  410.     }
  411.     switch ((enum options) index) {
  412. case EVENT_ADD: {
  413.     int i;
  414.     char *name, *event;
  415.     
  416.     if (objc < 4) {
  417. Tcl_WrongNumArgs(interp, 2, objv,
  418. "virtual sequence ?sequence ...?");
  419. return TCL_ERROR;
  420.     }
  421.     name = Tcl_GetStringFromObj(objv[2], NULL);
  422.     for (i = 3; i < objc; i++) {
  423. event = Tcl_GetStringFromObj(objv[i], NULL);
  424. if (CreateVirtualEvent(interp, vetPtr, name, event) != TCL_OK) {
  425.     return TCL_ERROR;
  426. }
  427.     }
  428.     break;
  429. }
  430. case EVENT_DELETE: {
  431.     int i;
  432.     char *name, *event;
  433.     
  434.     if (objc < 3) {
  435. Tcl_WrongNumArgs(interp, 2, objv,
  436. "virtual ?sequence sequence ...?");
  437. return TCL_ERROR;
  438.     }
  439.     name = Tcl_GetStringFromObj(objv[2], NULL);
  440.     if (objc == 3) {
  441. return DeleteVirtualEvent(interp, vetPtr, name, NULL);
  442.     }
  443.     for (i = 3; i < objc; i++) {
  444. event = Tcl_GetStringFromObj(objv[i], NULL);
  445. if (DeleteVirtualEvent(interp, vetPtr, name, event) != TCL_OK) {
  446.     return TCL_ERROR;
  447. }
  448.     }
  449.     break;
  450. }
  451. case EVENT_GENERATE: {
  452.     if (objc < 4) {
  453. Tcl_WrongNumArgs(interp, 2, objv, "window event ?options?");
  454. return TCL_ERROR;
  455.     }
  456.     return HandleEventGenerate(interp, tkwin, objc - 2, objv + 2);
  457. }
  458. case EVENT_INFO: {
  459.     if (objc == 2) {
  460. GetAllVirtualEvents(interp, vetPtr);
  461. return TCL_OK;
  462.     } else if (objc == 3) {
  463. return GetVirtualEvent(interp, vetPtr,
  464. Tcl_GetStringFromObj(objv[2], NULL));
  465.     } else {
  466. Tcl_WrongNumArgs(interp, 2, objv, "?virtual?");
  467. return TCL_ERROR;
  468.     }
  469. }
  470.     }
  471.     return TCL_OK;
  472. }
  473. /*
  474.  *---------------------------------------------------------------------------
  475.  *
  476.  * InitVirtualEventTable --
  477.  *
  478.  * Given storage for a virtual event table, set up the fields to
  479.  * prepare a new domain in which virtual events may be defined.
  480.  *
  481.  * Results:
  482.  * None.
  483.  *
  484.  * Side effects:
  485.  * *vetPtr is now initialized.
  486.  *
  487.  *---------------------------------------------------------------------------
  488.  */
  489. static void
  490. InitVirtualEventTable(vetPtr)
  491.     VirtualEventTable *vetPtr; /* Pointer to virtual event table.  Memory
  492.  * is supplied by the caller. */
  493. {
  494.     Tcl_InitHashTable(&vetPtr->patternTable,
  495.     sizeof(PatternTableKey) / sizeof(int));
  496.     Tcl_InitHashTable(&vetPtr->nameTable, TCL_ONE_WORD_KEYS);
  497. }
  498. /*
  499.  *---------------------------------------------------------------------------
  500.  *
  501.  * DeleteVirtualEventTable --
  502.  *
  503.  * Delete the contents of a virtual event table.  The caller is
  504.  * responsible for freeing any memory used by the table itself.
  505.  *
  506.  * Results:
  507.  * None.
  508.  *
  509.  * Side effects:
  510.  * Memory is freed.
  511.  *
  512.  *---------------------------------------------------------------------------
  513.  */
  514. static void
  515. DeleteVirtualEventTable(vetPtr)
  516.     VirtualEventTable *vetPtr; /* The virtual event table to delete. */
  517. {
  518.     Tcl_HashEntry *hPtr;
  519.     Tcl_HashSearch search;
  520.     PatSeq *psPtr, *nextPtr;
  521.     hPtr = Tcl_FirstHashEntry(&vetPtr->patternTable, &search);
  522.     for ( ; hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
  523. psPtr = (PatSeq *) Tcl_GetHashValue(hPtr);
  524. for ( ; psPtr != NULL; psPtr = nextPtr) {
  525.     nextPtr = psPtr->nextSeqPtr;
  526.     ckfree((char *) psPtr->voPtr);
  527.     ckfree((char *) psPtr);
  528. }
  529.     }
  530.     Tcl_DeleteHashTable(&vetPtr->patternTable);
  531.     hPtr = Tcl_FirstHashEntry(&vetPtr->nameTable, &search);
  532.     for ( ; hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
  533.         ckfree((char *) Tcl_GetHashValue(hPtr));
  534.     }
  535.     Tcl_DeleteHashTable(&vetPtr->nameTable);
  536. }
  537. /*
  538.  *----------------------------------------------------------------------
  539.  *
  540.  * CreateVirtualEvent --
  541.  *
  542.  * Add a new definition for a virtual event.  If the virtual event
  543.  * is already defined, the new definition augments those that
  544.  * already exist.
  545.  *
  546.  * Results:
  547.  * The return value is TCL_ERROR if an error occured while
  548.  * creating the virtual binding.  In this case, an error message
  549.  * will be left in the interp's result.  If all went well then the
  550.  * return value is TCL_OK.
  551.  *
  552.  * Side effects:
  553.  * The virtual event may cause future calls to Tk_BindEvent to
  554.  * behave differently than they did previously.
  555.  *
  556.  *----------------------------------------------------------------------
  557.  */
  558. static int
  559. CreateVirtualEvent(interp, vetPtr, virtString, eventString)
  560.     Tcl_Interp *interp; /* Used for error reporting. */
  561.     VirtualEventTable *vetPtr;/* Table in which to augment virtual event. */
  562.     char *virtString; /* Name of new virtual event. */
  563.     char *eventString; /* String describing physical event that
  564.  * triggers virtual event. */
  565. {
  566.     PatSeq *psPtr;
  567.     int dummy;
  568.     Tcl_HashEntry *vhPtr;
  569.     unsigned long eventMask;
  570.     PhysicalsOwned *poPtr;
  571.     VirtualOwners *voPtr;
  572.     Tk_Uid virtUid;
  573.     
  574.     virtUid = GetVirtualEventUid(interp, virtString);
  575.     if (virtUid == NULL) {
  576.         return TCL_ERROR;
  577.     }
  578.     /*
  579.      * Find/create physical event
  580.      */
  581.     psPtr = FindSequence(interp, &vetPtr->patternTable, NULL, eventString,
  582.     1, 0, &eventMask);
  583.     if (psPtr == NULL) {
  584.         return TCL_ERROR;
  585.     }
  586.     /*
  587.      * Find/create virtual event.
  588.      */
  589.     vhPtr = Tcl_CreateHashEntry(&vetPtr->nameTable, virtUid, &dummy);
  590.     /*
  591.      * Make virtual event own the physical event.
  592.      */
  593.     poPtr = (PhysicalsOwned *) Tcl_GetHashValue(vhPtr);
  594.     if (poPtr == NULL) {
  595. poPtr = (PhysicalsOwned *) ckalloc(sizeof(PhysicalsOwned));
  596. poPtr->numOwned = 0;
  597.     } else {
  598.         /*
  599.  * See if this virtual event is already defined for this physical
  600.  * event and just return if it is.
  601.  */
  602. int i;
  603. for (i = 0; i < poPtr->numOwned; i++) {
  604.     if (poPtr->patSeqs[i] == psPtr) {
  605.         return TCL_OK;
  606.     }
  607. }
  608. poPtr = (PhysicalsOwned *) ckrealloc((char *) poPtr,
  609. sizeof(PhysicalsOwned) + poPtr->numOwned * sizeof(PatSeq *));
  610.     }
  611.     Tcl_SetHashValue(vhPtr, (ClientData) poPtr);
  612.     poPtr->patSeqs[poPtr->numOwned] = psPtr;
  613.     poPtr->numOwned++;
  614.     /*
  615.      * Make physical event so it can trigger the virtual event.
  616.      */
  617.     voPtr = psPtr->voPtr;
  618.     if (voPtr == NULL) {
  619.         voPtr = (VirtualOwners *) ckalloc(sizeof(VirtualOwners));
  620. voPtr->numOwners = 0;
  621.     } else {
  622.         voPtr = (VirtualOwners *) ckrealloc((char *) voPtr,
  623. sizeof(VirtualOwners)
  624. + voPtr->numOwners * sizeof(Tcl_HashEntry *));
  625.     }
  626.     psPtr->voPtr = voPtr;
  627.     voPtr->owners[voPtr->numOwners] = vhPtr;
  628.     voPtr->numOwners++;
  629.     return TCL_OK;
  630. }
  631. /*
  632.  *--------------------------------------------------------------
  633.  *
  634.  * DeleteVirtualEvent --
  635.  *
  636.  * Remove the definition of a given virtual event.  If the 
  637.  * event string is NULL, all definitions of the virtual event
  638.  * will be removed.  Otherwise, just the specified definition
  639.  * of the virtual event will be removed.
  640.  *
  641.  * Results:
  642.  * The result is a standard Tcl return value.  If an error
  643.  * occurs then the interp's result will contain an error message.
  644.  * It is not an error to attempt to delete a virtual event that
  645.  * does not exist or a definition that does not exist.
  646.  *
  647.  * Side effects:
  648.  * The virtual event given by virtString may be removed from the
  649.  * virtual event table.  
  650.  *
  651.  *--------------------------------------------------------------
  652.  */
  653. static int
  654. DeleteVirtualEvent(interp, vetPtr, virtString, eventString)
  655.     Tcl_Interp *interp; /* Used for error reporting. */
  656.     VirtualEventTable *vetPtr;/* Table in which to delete event. */
  657.     char *virtString; /* String describing event sequence that
  658.  * triggers binding. */
  659.     char *eventString; /* The event sequence that should be deleted,
  660.  * or NULL to delete all event sequences for
  661.  * the entire virtual event. */
  662. {
  663.     int iPhys;
  664.     Tk_Uid virtUid;
  665.     Tcl_HashEntry *vhPtr;
  666.     PhysicalsOwned *poPtr;
  667.     PatSeq *eventPSPtr;
  668.     virtUid = GetVirtualEventUid(interp, virtString);
  669.     if (virtUid == NULL) {
  670.         return TCL_ERROR;
  671.     }
  672.     
  673.     vhPtr = Tcl_FindHashEntry(&vetPtr->nameTable, virtUid);
  674.     if (vhPtr == NULL) {
  675.         return TCL_OK;
  676.     }
  677.     poPtr = (PhysicalsOwned *) Tcl_GetHashValue(vhPtr);
  678.     eventPSPtr = NULL;
  679.     if (eventString != NULL) {
  680. unsigned long eventMask;
  681. /*
  682.  * Delete only the specific physical event associated with the
  683.  * virtual event.  If the physical event doesn't already exist, or
  684.  * the virtual event doesn't own that physical event, return w/o
  685.  * doing anything.
  686.  */
  687. eventPSPtr = FindSequence(interp, &vetPtr->patternTable, NULL,
  688. eventString, 0, 0, &eventMask);
  689. if (eventPSPtr == NULL) {
  690.     CONST char *string;
  691.     string = Tcl_GetStringResult(interp); 
  692.     return (string[0] != '') ? TCL_ERROR : TCL_OK;
  693. }
  694.     }
  695.     for (iPhys = poPtr->numOwned; --iPhys >= 0; ) {
  696. PatSeq *psPtr = poPtr->patSeqs[iPhys];
  697. if ((eventPSPtr == NULL) || (psPtr == eventPSPtr)) {
  698.     int iVirt;
  699.     VirtualOwners *voPtr;
  700.     
  701.     /*
  702.      * Remove association between this physical event and the given
  703.      * virtual event that it triggers.
  704.      */
  705.     voPtr = psPtr->voPtr;
  706.     for (iVirt = 0; iVirt < voPtr->numOwners; iVirt++) {
  707. if (voPtr->owners[iVirt] == vhPtr) {
  708.     break;
  709. }
  710.     }
  711.     if (iVirt == voPtr->numOwners) {
  712. panic("DeleteVirtualEvent: couldn't find owner");
  713.     }
  714.     voPtr->numOwners--;
  715.     if (voPtr->numOwners == 0) {
  716. /*
  717.  * Removed last reference to this physical event, so
  718.  * remove it from physical->virtual map.
  719.  */
  720. PatSeq *prevPtr = (PatSeq *) Tcl_GetHashValue(psPtr->hPtr);
  721. if (prevPtr == psPtr) {
  722.     if (psPtr->nextSeqPtr == NULL) {
  723. Tcl_DeleteHashEntry(psPtr->hPtr);
  724.     } else {
  725. Tcl_SetHashValue(psPtr->hPtr,
  726. psPtr->nextSeqPtr);
  727.     }
  728. } else {
  729.     for ( ; ; prevPtr = prevPtr->nextSeqPtr) {
  730. if (prevPtr == NULL) {
  731.     panic("DeleteVirtualEvent couldn't find on hash chain");
  732. }
  733. if (prevPtr->nextSeqPtr == psPtr) {
  734.     prevPtr->nextSeqPtr = psPtr->nextSeqPtr;
  735.     break;
  736. }
  737.     }
  738. }
  739. ckfree((char *) psPtr->voPtr);
  740. ckfree((char *) psPtr);
  741.     } else {
  742. /*
  743.  * This physical event still triggers some other virtual
  744.  * event(s).  Consolidate the list of virtual owners for
  745.  * this physical event so it no longer triggers the
  746.  * given virtual event.
  747.  */
  748. voPtr->owners[iVirt] = voPtr->owners[voPtr->numOwners];
  749.     }
  750.     /*
  751.      * Now delete the virtual event's reference to the physical
  752.      * event.
  753.      */
  754.     poPtr->numOwned--;
  755.     if (eventPSPtr != NULL && poPtr->numOwned != 0) {
  756.         /*
  757.  * Just deleting this one physical event.  Consolidate list
  758.  * of owned physical events and return.
  759.  */
  760. poPtr->patSeqs[iPhys] = poPtr->patSeqs[poPtr->numOwned];
  761. return TCL_OK;
  762.     }
  763. }
  764.     }
  765.     if (poPtr->numOwned == 0) {
  766. /*
  767.  * All the physical events for this virtual event were deleted,
  768.  * either because there was only one associated physical event or
  769.  * because the caller was deleting the entire virtual event.  Now
  770.  * the virtual event itself should be deleted.
  771.  */
  772. ckfree((char *) poPtr);
  773. Tcl_DeleteHashEntry(vhPtr);
  774.     }
  775.     return TCL_OK;
  776. }
  777. /*
  778.  *---------------------------------------------------------------------------
  779.  *
  780.  * GetVirtualEvent --
  781.  *
  782.  * Return the list of physical events that can invoke the
  783.  * given virtual event.
  784.  *
  785.  * Results:
  786.  * The return value is TCL_OK and the interp's result is filled with the
  787.  * string representation of the physical events associated with the
  788.  * virtual event; if there are no physical events for the given virtual
  789.  * event, the interp's result is filled with and empty string.  If the
  790.  * virtual event string is improperly formed, then TCL_ERROR is
  791.  * returned and an error message is left in the interp's result.
  792.  *
  793.  * Side effects:
  794.  * None.
  795.  *
  796.  *---------------------------------------------------------------------------
  797.  */
  798. static int
  799. GetVirtualEvent(interp, vetPtr, virtString)
  800.     Tcl_Interp *interp; /* Interpreter for reporting. */
  801.     VirtualEventTable *vetPtr;/* Table in which to look for event. */
  802.     char *virtString; /* String describing virtual event. */
  803. {
  804.     Tcl_HashEntry *vhPtr;
  805.     Tcl_DString ds;
  806.     int iPhys;
  807.     PhysicalsOwned *poPtr;
  808.     Tk_Uid virtUid;
  809.     virtUid = GetVirtualEventUid(interp, virtString);
  810.     if (virtUid == NULL) {
  811.         return TCL_ERROR;
  812.     }
  813.     vhPtr = Tcl_FindHashEntry(&vetPtr->nameTable, virtUid);
  814.     if (vhPtr == NULL) {
  815.         return TCL_OK;
  816.     }
  817.     Tcl_DStringInit(&ds);
  818.     poPtr = (PhysicalsOwned *) Tcl_GetHashValue(vhPtr);
  819.     for (iPhys = 0; iPhys < poPtr->numOwned; iPhys++) {
  820. Tcl_DStringSetLength(&ds, 0);
  821. GetPatternString(poPtr->patSeqs[iPhys], &ds);
  822. Tcl_AppendElement(interp, Tcl_DStringValue(&ds));
  823.     }
  824.     Tcl_DStringFree(&ds);
  825.     return TCL_OK;
  826. }
  827. /*
  828.  *--------------------------------------------------------------
  829.  *
  830.  * GetAllVirtualEvents --
  831.  *
  832.  * Return a list that contains the names of all the virtual
  833.  * event defined.
  834.  *
  835.  * Results:
  836.  * There is no return value.  The interp's result is modified to
  837.  * hold a Tcl list with one entry for each virtual event in 
  838.  * nameTable.  
  839.  *
  840.  * Side effects:
  841.  * None.
  842.  *
  843.  *--------------------------------------------------------------
  844.  */
  845. static void
  846. GetAllVirtualEvents(interp, vetPtr)
  847.     Tcl_Interp *interp; /* Interpreter returning result. */
  848.     VirtualEventTable *vetPtr;/* Table containing events. */
  849. {
  850.     Tcl_HashEntry *hPtr;
  851.     Tcl_HashSearch search;
  852.     Tcl_DString ds;
  853.     Tcl_DStringInit(&ds);
  854.     hPtr = Tcl_FirstHashEntry(&vetPtr->nameTable, &search);
  855.     for ( ; hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
  856. Tcl_DStringSetLength(&ds, 0);
  857. Tcl_DStringAppend(&ds, "<<", 2);
  858. Tcl_DStringAppend(&ds, Tcl_GetHashKey(hPtr->tablePtr, hPtr), -1);
  859. Tcl_DStringAppend(&ds, ">>", 2);
  860.         Tcl_AppendElement(interp, Tcl_DStringValue(&ds));
  861.     }
  862.     Tcl_DStringFree(&ds);
  863. }
  864. /*
  865.  *---------------------------------------------------------------------------
  866.  *
  867.  * HandleEventGenerate --
  868.  *
  869.  * Helper function for the "event generate" command.  Generate and
  870.  * process an XEvent, constructed from information parsed from the
  871.  * event description string and its optional arguments.
  872.  *
  873.  * argv[0] contains name of the target window.
  874.  * argv[1] contains pattern string for one event (e.g, <Control-v>).
  875.  * argv[2..argc-1] contains -field/option pairs for specifying
  876.  *         additional detail in the generated event.
  877.  *
  878.  * Either virtual or physical events can be generated this way.
  879.  * The event description string must contain the specification
  880.  * for only one event.
  881.  *
  882.  * Results:
  883.  * None.
  884.  *
  885.  * Side effects:
  886.  * When constructing the event, 
  887.  *  event.xany.serial is filled with the current X serial number.
  888.  *  event.xany.window is filled with the target window.
  889.  *  event.xany.display is filled with the target window's display.
  890.  * Any other fields in eventPtr which are not specified by the pattern
  891.  * string or the optional arguments, are set to 0.
  892.  *
  893.  * The event may be handled sychronously or asynchronously, depending
  894.  * on the value specified by the optional "-when" option.  The
  895.  * default setting is synchronous.
  896.  *
  897.  *---------------------------------------------------------------------------
  898.  */
  899. static int
  900. HandleEventGenerate(interp, mainWin, objc, objv)
  901.     Tcl_Interp *interp; /* Interp for errors return and name lookup. */
  902.     Tk_Window mainWin; /* Main window associated with interp. */
  903.     int objc; /* Number of arguments. */
  904.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  905. {
  906.     XEvent event;    
  907.     CONST char *p;
  908.     char *name, *windowName;
  909.     int count, flags, synch, i, number, warp;
  910.     Tcl_QueuePosition pos;
  911.     Pattern pat;
  912.     Tk_Window tkwin, tkwin2;
  913.     TkWindow *mainPtr;
  914.     unsigned long eventMask;
  915.     static CONST char *fieldStrings[] = {
  916. "-when", "-above", "-borderwidth", "-button",
  917. "-count", "-delta", "-detail", "-focus",
  918. "-height",
  919. "-keycode", "-keysym", "-mode", "-override",
  920. "-place", "-root", "-rootx", "-rooty",
  921. "-sendevent", "-serial", "-state", "-subwindow",
  922. "-time", "-warp", "-width", "-window",
  923. "-x", "-y", NULL
  924.     };
  925.     enum field {
  926. EVENT_WHEN, EVENT_ABOVE, EVENT_BORDER, EVENT_BUTTON,
  927. EVENT_COUNT, EVENT_DELTA, EVENT_DETAIL, EVENT_FOCUS,
  928. EVENT_HEIGHT,
  929. EVENT_KEYCODE, EVENT_KEYSYM, EVENT_MODE, EVENT_OVERRIDE,
  930. EVENT_PLACE, EVENT_ROOT, EVENT_ROOTX, EVENT_ROOTY,
  931. EVENT_SEND, EVENT_SERIAL, EVENT_STATE, EVENT_SUBWINDOW,
  932. EVENT_TIME, EVENT_WARP, EVENT_WIDTH, EVENT_WINDOW,
  933. EVENT_X, EVENT_Y
  934.     };
  935.     windowName = Tcl_GetStringFromObj(objv[0], NULL);
  936.     if (!windowName[0]) {
  937. tkwin = mainWin;
  938.     } else if (NameToWindow(interp, mainWin, objv[0], &tkwin) != TCL_OK) {
  939. return TCL_ERROR;
  940.     }
  941.     mainPtr = (TkWindow *) mainWin;
  942.     if ((tkwin == NULL)
  943.     || (mainPtr->mainPtr != ((TkWindow *) tkwin)->mainPtr)) {
  944. char *name;
  945. name = Tcl_GetStringFromObj(objv[0], NULL);
  946. Tcl_AppendResult(interp, "window id "", name, 
  947. "" doesn't exist in this application", (char *) NULL);
  948. return TCL_ERROR;
  949.     }
  950.     name = Tcl_GetStringFromObj(objv[1], NULL);
  951.     p = name;
  952.     eventMask = 0;
  953.     count = ParseEventDescription(interp, &p, &pat, &eventMask);
  954.     if (count == 0) {
  955. return TCL_ERROR;
  956.     }
  957.     if (count != 1) {
  958. Tcl_SetResult(interp, "Double or Triple modifier not allowed",
  959. TCL_STATIC);
  960. return TCL_ERROR;
  961.     }
  962.     if (*p != '') {
  963. Tcl_SetResult(interp, "only one event specification allowed",
  964. TCL_STATIC);
  965. return TCL_ERROR;
  966.     }
  967.     memset((VOID *) &event, 0, sizeof(event));
  968.     event.xany.type = pat.eventType;
  969.     event.xany.serial = NextRequest(Tk_Display(tkwin));
  970.     event.xany.send_event = False;
  971.     if (windowName[0]) {
  972. event.xany.window = Tk_WindowId(tkwin);
  973.     } else {
  974. event.xany.window = RootWindow(Tk_Display(tkwin), Tk_ScreenNumber(tkwin));
  975.     }
  976.     event.xany.display = Tk_Display(tkwin);
  977.     flags = flagArray[event.xany.type];
  978.     if (flags & DESTROY) {
  979. /*
  980.  * Event DesotryNotify should be generated by destroying 
  981.  * the window.
  982.  */
  983. Tk_DestroyWindow(tkwin);
  984. return TCL_OK;
  985.     }
  986.     if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) {
  987. event.xkey.state = pat.needMods;
  988. if ((flags & KEY) && (event.xany.type != MouseWheelEvent)) {
  989.     TkpSetKeycodeAndState(tkwin, pat.detail.keySym, &event);
  990. } else if (flags & BUTTON) {
  991.     event.xbutton.button = pat.detail.button;
  992. } else if (flags & VIRTUAL) {
  993.     ((XVirtualEvent *) &event)->name = pat.detail.name;
  994. }
  995.     }
  996.     if (flags & (CREATE|UNMAP|MAP|REPARENT|CONFIG|GRAVITY|CIRC)) {
  997. event.xcreatewindow.window = event.xany.window;
  998.     }
  999.     if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) {
  1000. event.xkey.x_root = -1;
  1001. event.xkey.y_root = -1;
  1002.     }
  1003.     /*
  1004.      * Process the remaining arguments to fill in additional fields
  1005.      * of the event.
  1006.      */
  1007.     synch = 1;
  1008.     warp = 0;
  1009.     pos = TCL_QUEUE_TAIL;
  1010.     for (i = 2; i < objc; i += 2) {
  1011. Tcl_Obj *optionPtr, *valuePtr;
  1012. int index;
  1013. optionPtr = objv[i];
  1014. valuePtr = objv[i + 1];
  1015. if (Tcl_GetIndexFromObj(interp, optionPtr, fieldStrings, "option",
  1016. TCL_EXACT, &index) != TCL_OK) {
  1017.     return TCL_ERROR;
  1018. }
  1019. if (objc & 1) {
  1020.     /*
  1021.      * This test occurs after Tcl_GetIndexFromObj() so that
  1022.      * "event generate <Button> -xyz" will return the error message
  1023.      * that "-xyz" is a bad option, rather than that the value
  1024.      * for "-xyz" is missing.
  1025.      */
  1026.     Tcl_AppendResult(interp, "value for "",
  1027.     Tcl_GetStringFromObj(optionPtr, NULL), "" missing",
  1028.     (char *) NULL);
  1029.     return TCL_ERROR;
  1030. }
  1031. switch ((enum field) index) {
  1032.     case EVENT_WARP: {
  1033. if (Tcl_GetBooleanFromObj(interp, valuePtr, &warp) != TCL_OK) {
  1034.     return TCL_ERROR;
  1035. }
  1036. if (!(flags & (KEY_BUTTON_MOTION_VIRTUAL))) {
  1037.     goto badopt;
  1038. }
  1039. break;
  1040.     }
  1041.     case EVENT_WHEN: {
  1042. pos = (Tcl_QueuePosition) TkFindStateNumObj(interp, optionPtr, 
  1043. queuePosition, valuePtr);
  1044. if ((int) pos < -1) {
  1045.     return TCL_ERROR;
  1046. }
  1047. synch = 0;
  1048. if ((int) pos == -1) {
  1049.     synch = 1;
  1050. }
  1051. break;
  1052.     }
  1053.     case EVENT_ABOVE: {
  1054. if (NameToWindow(interp, tkwin, valuePtr, &tkwin2) != TCL_OK) {
  1055.     return TCL_ERROR;
  1056. }
  1057. if (flags & CONFIG) {
  1058.     event.xconfigure.above = Tk_WindowId(tkwin2);
  1059. } else {
  1060.     goto badopt;
  1061. }
  1062. break;
  1063.     }
  1064.     case EVENT_BORDER: {
  1065. if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number) != TCL_OK) {
  1066.     return TCL_ERROR;
  1067. }
  1068. if (flags & (CREATE|CONFIG)) {
  1069.     event.xcreatewindow.border_width = number;
  1070. } else {
  1071.     goto badopt;
  1072. }
  1073. break;
  1074.     }
  1075.     case EVENT_BUTTON: {
  1076. if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) {
  1077.     return TCL_ERROR;
  1078. }
  1079. if (flags & BUTTON) {
  1080.     event.xbutton.button = number;
  1081. } else {
  1082.     goto badopt;
  1083. }
  1084. break;
  1085.     }
  1086.     case EVENT_COUNT: {
  1087. if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) {
  1088.     return TCL_ERROR;
  1089. }
  1090. if (flags & EXPOSE) {
  1091.     event.xexpose.count = number;
  1092. } else {
  1093.     goto badopt;
  1094. }
  1095. break;
  1096.     }
  1097.     case EVENT_DELTA: {
  1098. if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) {
  1099.     return TCL_ERROR;
  1100. }
  1101. if ((flags & KEY) && (event.xkey.type == MouseWheelEvent)) {
  1102.     event.xkey.keycode = number;
  1103. } else {
  1104.     goto badopt;
  1105. }
  1106. break;
  1107.     }
  1108.     case EVENT_DETAIL: {
  1109. number = TkFindStateNumObj(interp, optionPtr, notifyDetail,
  1110. valuePtr);
  1111. if (number < 0) {
  1112.     return TCL_ERROR;
  1113. }
  1114. if (flags & FOCUS) {
  1115.     event.xfocus.detail = number;
  1116. } else if (flags & CROSSING) {
  1117.     event.xcrossing.detail = number;
  1118. } else {
  1119.     goto badopt;
  1120. }
  1121. break;
  1122.     }
  1123.     case EVENT_FOCUS: {
  1124. if (Tcl_GetBooleanFromObj(interp, valuePtr, &number) != TCL_OK) {
  1125.     return TCL_ERROR;
  1126. }
  1127. if (flags & CROSSING) {
  1128.     event.xcrossing.focus = number;
  1129. } else {
  1130.     goto badopt;
  1131. }
  1132. break;
  1133.     }
  1134.     case EVENT_HEIGHT: {
  1135. if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number) != TCL_OK) {
  1136.     return TCL_ERROR;
  1137. }
  1138. if (flags & EXPOSE) {
  1139.      event.xexpose.height = number;
  1140. } else if (flags & CONFIG) {
  1141.     event.xconfigure.height = number;
  1142. } else {
  1143.     goto badopt;
  1144. }
  1145. break;
  1146.     }
  1147.     case EVENT_KEYCODE: {
  1148. if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) {
  1149.     return TCL_ERROR;
  1150. }
  1151. if ((flags & KEY) && (event.xkey.type != MouseWheelEvent)) {
  1152.     event.xkey.keycode = number;
  1153. } else {
  1154.     goto badopt;
  1155. }
  1156. break;
  1157.     }
  1158.     case EVENT_KEYSYM: {
  1159. KeySym keysym;
  1160. char *value;
  1161. value = Tcl_GetStringFromObj(valuePtr, NULL);
  1162. keysym = TkStringToKeysym(value);
  1163. if (keysym == NoSymbol) {
  1164.     Tcl_AppendResult(interp, "unknown keysym "", value, """,
  1165.     (char *) NULL);
  1166.     return TCL_ERROR;
  1167. }
  1168. TkpSetKeycodeAndState(tkwin, keysym, &event);
  1169. if (event.xkey.keycode == 0) {
  1170.     Tcl_AppendResult(interp, "no keycode for keysym "", value,
  1171.     """, (char *) NULL);
  1172.     return TCL_ERROR;
  1173. }
  1174. if (!(flags & KEY) || (event.xkey.type == MouseWheelEvent)) {
  1175.     goto badopt;
  1176. }
  1177. break;
  1178.     }
  1179.     case EVENT_MODE: {
  1180. number = TkFindStateNumObj(interp, optionPtr, notifyMode,
  1181. valuePtr);
  1182. if (number < 0) {
  1183.     return TCL_ERROR;
  1184. }
  1185. if (flags & CROSSING) {
  1186.     event.xcrossing.mode = number;
  1187. } else if (flags & FOCUS) {
  1188.     event.xfocus.mode = number;
  1189. } else {
  1190.     goto badopt;
  1191. }
  1192. break;
  1193.     }
  1194.     case EVENT_OVERRIDE: {
  1195. if (Tcl_GetBooleanFromObj(interp, valuePtr, &number) != TCL_OK) {
  1196.     return TCL_ERROR;
  1197. }
  1198. if (flags & CREATE) {
  1199.     event.xcreatewindow.override_redirect = number;
  1200. } else if (flags & MAP) {
  1201.     event.xmap.override_redirect = number;
  1202. } else if (flags & REPARENT) {
  1203.     event.xreparent.override_redirect = number;
  1204. } else if (flags & CONFIG) {
  1205.     event.xconfigure.override_redirect = number;
  1206. } else {
  1207.     goto badopt;
  1208. }
  1209. break;
  1210.     }
  1211.     case EVENT_PLACE: {
  1212. number = TkFindStateNumObj(interp, optionPtr, circPlace,
  1213. valuePtr);
  1214. if (number < 0) {
  1215.     return TCL_ERROR;
  1216. }
  1217. if (flags & CIRC) {
  1218.     event.xcirculate.place = number;
  1219. } else {
  1220.     goto badopt;
  1221. }
  1222. break;
  1223.     }
  1224.     case EVENT_ROOT: {
  1225. if (NameToWindow(interp, tkwin, valuePtr, &tkwin2) != TCL_OK) {
  1226.     return TCL_ERROR;
  1227. }
  1228. if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) {
  1229.     event.xkey.root = Tk_WindowId(tkwin2);
  1230. } else {
  1231.     goto badopt;
  1232. }
  1233. break;
  1234.     }
  1235.     case EVENT_ROOTX: {
  1236. if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number) != TCL_OK) {
  1237.     return TCL_ERROR;
  1238. }
  1239. if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) {
  1240.     event.xkey.x_root = number;
  1241. } else {
  1242.     goto badopt;
  1243. }
  1244. break;
  1245.     }
  1246.     case EVENT_ROOTY: {
  1247. if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number) != TCL_OK) {
  1248.     return TCL_ERROR;
  1249. }
  1250. if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) {
  1251.     event.xkey.y_root = number;
  1252. } else {
  1253.     goto badopt;
  1254. }
  1255. break;
  1256.     }
  1257.     case EVENT_SEND: {
  1258. CONST char *value;
  1259. value = Tcl_GetStringFromObj(valuePtr, NULL);
  1260. if (isdigit(UCHAR(value[0]))) {
  1261.     /*
  1262.      * Allow arbitrary integer values for the field; they
  1263.      * are needed by a few of the tests in the Tk test suite.
  1264.      */
  1265.     if (Tcl_GetIntFromObj(interp, valuePtr, &number)
  1266.     != TCL_OK) {
  1267. return TCL_ERROR;
  1268.     }
  1269. } else {
  1270.     if (Tcl_GetBooleanFromObj(interp, valuePtr, &number)
  1271.     != TCL_OK) {
  1272. return TCL_ERROR;
  1273.     }
  1274. }
  1275. event.xany.send_event = number;
  1276. break;
  1277.     }
  1278.     case EVENT_SERIAL: {
  1279. if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) {
  1280.     return TCL_ERROR;
  1281. }
  1282. event.xany.serial = number;
  1283. break;
  1284.     }
  1285.     case EVENT_STATE: {
  1286. if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) {
  1287.     if (Tcl_GetIntFromObj(interp, valuePtr, &number)
  1288.     != TCL_OK) {
  1289. return TCL_ERROR;
  1290.     }
  1291.     if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) {
  1292. event.xkey.state = number;
  1293.     } else {
  1294. event.xcrossing.state = number;
  1295.     }
  1296. } else if (flags & VISIBILITY) {
  1297.     number = TkFindStateNumObj(interp, optionPtr, visNotify,
  1298.     valuePtr);
  1299.     if (number < 0) {
  1300. return TCL_ERROR;
  1301.     }
  1302.     event.xvisibility.state = number;
  1303. } else {
  1304.     goto badopt;
  1305. }
  1306. break;
  1307.     }
  1308.     case EVENT_SUBWINDOW: {
  1309. if (NameToWindow(interp, tkwin, valuePtr, &tkwin2) != TCL_OK) {
  1310.     return TCL_ERROR;
  1311. }
  1312. if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) {
  1313.     event.xkey.subwindow = Tk_WindowId(tkwin2);
  1314. } else {
  1315.     goto badopt;
  1316. }
  1317. break;
  1318.     }
  1319.     case EVENT_TIME: {
  1320. if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) {
  1321.     return TCL_ERROR;
  1322. }
  1323. if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) {
  1324.     event.xkey.time = (Time) number;
  1325. } else if (flags & PROP) {
  1326.     event.xproperty.time = (Time) number;
  1327. } else {
  1328.     goto badopt;
  1329. }
  1330. break;
  1331.     }
  1332.     case EVENT_WIDTH: {
  1333. if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number)
  1334. != TCL_OK) {
  1335.     return TCL_ERROR;
  1336. }
  1337. if (flags & EXPOSE) {
  1338.     event.xexpose.width = number;
  1339. } else if (flags & (CREATE|CONFIG)) {
  1340.     event.xcreatewindow.width = number;
  1341. } else {
  1342.     goto badopt;
  1343. }
  1344. break;
  1345.     }
  1346.     case EVENT_WINDOW: {
  1347. if (NameToWindow(interp, tkwin, valuePtr, &tkwin2) != TCL_OK) {
  1348.     return TCL_ERROR;
  1349. }
  1350. if (flags & (CREATE|UNMAP|MAP|REPARENT|CONFIG
  1351. |GRAVITY|CIRC)) {
  1352.     event.xcreatewindow.window = Tk_WindowId(tkwin2);
  1353. } else {
  1354.     goto badopt;
  1355. }
  1356. break;
  1357.     }
  1358.     case EVENT_X: {
  1359. if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number)
  1360. != TCL_OK) {
  1361.     return TCL_ERROR;
  1362. }
  1363. if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) {
  1364.     event.xkey.x = number;
  1365.     /*
  1366.      * Only modify rootx as well if it hasn't been changed.
  1367.      */
  1368.     if (event.xkey.x_root == -1) {
  1369. int rootX, rootY;
  1370. Tk_GetRootCoords(tkwin, &rootX, &rootY);
  1371. event.xkey.x_root = rootX + number;
  1372.     }
  1373. } else if (flags & EXPOSE) {
  1374.     event.xexpose.x = number;
  1375. } else if (flags & (CREATE|CONFIG|GRAVITY)) { 
  1376.     event.xcreatewindow.x = number;
  1377. } else if (flags & REPARENT) {
  1378.     event.xreparent.x = number;
  1379. } else {
  1380.     goto badopt;
  1381. }
  1382. break;
  1383.     }
  1384.     case EVENT_Y: {
  1385. if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number)
  1386. != TCL_OK) {
  1387.     return TCL_ERROR;
  1388. }
  1389. if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) {
  1390.     event.xkey.y = number;
  1391.     /*
  1392.      * Only modify rooty as well if it hasn't been changed.
  1393.      */
  1394.     if (event.xkey.y_root == -1) {
  1395. int rootX, rootY;
  1396. Tk_GetRootCoords(tkwin, &rootX, &rootY);
  1397. event.xkey.y_root = rootY + number;
  1398.     }
  1399. } else if (flags & EXPOSE) {
  1400.     event.xexpose.y = number;
  1401. } else if (flags & (CREATE|CONFIG|GRAVITY)) {
  1402.     event.xcreatewindow.y = number;
  1403. } else if (flags & REPARENT) {
  1404.     event.xreparent.y = number;
  1405. } else {
  1406.     goto badopt;
  1407. }
  1408. break;
  1409.     }
  1410. }
  1411. continue;
  1412. badopt:
  1413. Tcl_AppendResult(interp, name, " event doesn't accept "",
  1414. Tcl_GetStringFromObj(optionPtr, NULL), "" option", NULL);
  1415. return TCL_ERROR;
  1416.     }
  1417.     if (synch != 0) {
  1418. Tk_HandleEvent(&event);
  1419.     } else {
  1420. Tk_QueueWindowEvent(&event, pos);
  1421.     }
  1422.     /*
  1423.      * We only allow warping if the window is mapped
  1424.      */
  1425.     if ((warp != 0) && Tk_IsMapped(tkwin)) {
  1426. TkDisplay *dispPtr;
  1427. dispPtr = TkGetDisplay(event.xmotion.display);
  1428. if (!(dispPtr->flags & TK_DISPLAY_IN_WARP)) {
  1429.     Tcl_DoWhenIdle(DoWarp, (ClientData) dispPtr);
  1430.     dispPtr->flags |= TK_DISPLAY_IN_WARP;
  1431. }
  1432. dispPtr->warpWindow = event.xany.window;
  1433. dispPtr->warpX = event.xkey.x;
  1434. dispPtr->warpY = event.xkey.y;
  1435.     }
  1436.     Tcl_ResetResult(interp);
  1437.     return TCL_OK;
  1438. }
  1439. static int
  1440. NameToWindow(interp, mainWin, objPtr, tkwinPtr)
  1441.     Tcl_Interp *interp; /* Interp for error return and name lookup. */
  1442.     Tk_Window mainWin; /* Main window of application. */
  1443.     Tcl_Obj *objPtr; /* Contains name or id string of window. */
  1444.     Tk_Window *tkwinPtr; /* Filled with token for window. */
  1445. {
  1446.     char *name;
  1447.     Tk_Window tkwin;
  1448.     Window id;
  1449.     name = Tcl_GetStringFromObj(objPtr, NULL);
  1450.     if (name[0] == '.') {
  1451. tkwin = Tk_NameToWindow(interp, name, mainWin);
  1452. if (tkwin == NULL) {
  1453.     return TCL_ERROR;
  1454. }
  1455. *tkwinPtr = tkwin;
  1456.     } else {
  1457. /*
  1458.  * Check for the winPtr being valid, even if it looks ok to
  1459.  * TkpScanWindowId.  [Bug #411307]
  1460.  */
  1461. if ((TkpScanWindowId(NULL, name, &id) != TCL_OK) ||
  1462. ((*tkwinPtr = Tk_IdToWindow(Tk_Display(mainWin), id))
  1463. == NULL)) {
  1464.     Tcl_AppendResult(interp, "bad window name/identifier "",
  1465.     name, """, (char *) NULL);
  1466.     return TCL_ERROR;
  1467. }
  1468.     }
  1469.     return TCL_OK;
  1470. }
  1471. /*
  1472.  *-------------------------------------------------------------------------
  1473.  *
  1474.  * DoWarp --
  1475.  *
  1476.  * Perform Warping of X pointer. Executed as an idle handler only.
  1477.  *
  1478.  * Results:
  1479.  * None
  1480.  *
  1481.  * Side effects:
  1482.  * X Pointer will move to a new location.
  1483.  *
  1484.  *-------------------------------------------------------------------------
  1485.  */
  1486. static void
  1487. DoWarp(clientData)
  1488.     ClientData clientData;
  1489. {
  1490.     TkDisplay *dispPtr = (TkDisplay *) clientData;
  1491.     XWarpPointer(dispPtr->display, (Window) None, (Window) dispPtr->warpWindow,
  1492.                      0, 0, 0, 0, (int) dispPtr->warpX, (int) dispPtr->warpY);
  1493.     XForceScreenSaver(dispPtr->display, ScreenSaverReset);
  1494.     dispPtr->flags &= ~TK_DISPLAY_IN_WARP;
  1495. }
  1496. /*
  1497.  *-------------------------------------------------------------------------
  1498.  *
  1499.  * GetVirtualEventUid --
  1500.  *
  1501.  * Determine if the given string is in the proper format for a
  1502.  * virtual event.
  1503.  *
  1504.  * Results:
  1505.  * The return value is NULL if the virtual event string was
  1506.  * not in the proper format.  In this case, an error message
  1507.  * will be left in the interp's result.  Otherwise the return
  1508.  * value is a Tk_Uid that represents the virtual event.
  1509.  *
  1510.  * Side effects:
  1511.  * None.
  1512.  *
  1513.  *-------------------------------------------------------------------------
  1514.  */
  1515. static Tk_Uid
  1516. GetVirtualEventUid(interp, virtString)
  1517.     Tcl_Interp *interp;
  1518.     char *virtString;
  1519. {
  1520.     Tk_Uid uid;
  1521.     int length;
  1522.     length = strlen(virtString);
  1523.     if (length < 5 || virtString[0] != '<' || virtString[1] != '<' ||
  1524.     virtString[length - 2] != '>' || virtString[length - 1] != '>') {
  1525.         Tcl_AppendResult(interp, "virtual event "", virtString,
  1526. "" is badly formed", (char *) NULL);
  1527.         return NULL;
  1528.     }
  1529.     virtString[length - 2] = '';
  1530.     uid = Tk_GetUid(virtString + 2);
  1531.     virtString[length - 2] = '>';
  1532.     return uid;
  1533. }
  1534. /*
  1535.  *----------------------------------------------------------------------
  1536.  *
  1537.  * FindSequence --
  1538.  *
  1539.  * Find the entry in the pattern table that corresponds to a
  1540.  * particular pattern string, and return a pointer to that
  1541.  * entry.
  1542.  *
  1543.  * Results:
  1544.  * The return value is normally a pointer to the PatSeq
  1545.  * in patternTable that corresponds to eventString.  If an error
  1546.  * was found while parsing eventString, or if "create" is 0 and
  1547.  * no pattern sequence previously existed, then NULL is returned
  1548.  * and the interp's result contains a message describing the problem.
  1549.  * If no pattern sequence previously existed for eventString, then
  1550.  * a new one is created with a NULL command field.  In a successful
  1551.  * return, *maskPtr is filled in with a mask of the event types
  1552.  * on which the pattern sequence depends.
  1553.  *
  1554.  * Side effects:
  1555.  * A new pattern sequence may be allocated.
  1556.  *
  1557.  *----------------------------------------------------------------------
  1558.  */
  1559. static PatSeq *
  1560. FindSequence(interp, patternTablePtr, object, eventString, create,
  1561. allowVirtual, maskPtr)
  1562.     Tcl_Interp *interp; /* Interpreter to use for error
  1563.  * reporting. */
  1564.     Tcl_HashTable *patternTablePtr; /* Table to use for lookup. */
  1565.     ClientData object; /* For binding table, token for object with
  1566.  * which binding is associated.
  1567.  * For virtual event table, NULL. */
  1568.     CONST char *eventString; /* String description of pattern to
  1569.  * match on.  See user documentation
  1570.  * for details. */
  1571.     int create; /* 0 means don't create the entry if
  1572.  * it doesn't already exist.   Non-zero
  1573.  * means create. */
  1574.     int allowVirtual; /* 0 means that virtual events are not
  1575.  * allowed in the sequence.  Non-zero
  1576.  * otherwise. */
  1577.     unsigned long *maskPtr; /* *maskPtr is filled in with the event
  1578.  * types on which this pattern sequence
  1579.  * depends. */
  1580. {
  1581.     Pattern pats[EVENT_BUFFER_SIZE];
  1582.     int numPats, virtualFound;
  1583.     CONST char *p;
  1584.     Pattern *patPtr;
  1585.     PatSeq *psPtr;
  1586.     Tcl_HashEntry *hPtr;
  1587.     int flags, count, new;
  1588.     size_t sequenceSize;
  1589.     unsigned long eventMask;
  1590.     PatternTableKey key;
  1591.     /*
  1592.      *-------------------------------------------------------------
  1593.      * Step 1: parse the pattern string to produce an array
  1594.      * of Patterns.  The array is generated backwards, so
  1595.      * that the lowest-indexed pattern corresponds to the last
  1596.      * event that must occur.
  1597.      *-------------------------------------------------------------
  1598.      */
  1599.     p = eventString;
  1600.     flags = 0;
  1601.     eventMask = 0;
  1602.     virtualFound = 0;
  1603.     patPtr = &pats[EVENT_BUFFER_SIZE-1];
  1604.     for (numPats = 0; numPats < EVENT_BUFFER_SIZE; numPats++, patPtr--) {
  1605. while (isspace(UCHAR(*p))) {
  1606.     p++;
  1607. }
  1608. if (*p == '') {
  1609.     break;
  1610. }
  1611. count = ParseEventDescription(interp, &p, patPtr, &eventMask);
  1612. if (count == 0) {
  1613.     return NULL;
  1614. }
  1615. if (eventMask & VirtualEventMask) {
  1616.     if (allowVirtual == 0) {
  1617. Tcl_SetResult(interp, 
  1618. "virtual event not allowed in definition of another virtual event",
  1619. TCL_STATIC);
  1620. return NULL;
  1621.     }
  1622.     virtualFound = 1;
  1623. }
  1624. /*
  1625.  * Replicate events for DOUBLE, TRIPLE, QUADRUPLE.
  1626.  */
  1627. while ((count-- > 1) && (numPats < EVENT_BUFFER_SIZE-1)) {
  1628.     flags |= PAT_NEARBY;
  1629.     patPtr[-1] = patPtr[0];
  1630.     patPtr--;
  1631.     numPats++;
  1632. }
  1633.     }
  1634.     /*
  1635.      *-------------------------------------------------------------
  1636.      * Step 2: find the sequence in the binding table if it exists,
  1637.      * and add a new sequence to the table if it doesn't.
  1638.      *-------------------------------------------------------------
  1639.      */
  1640.     if (numPats == 0) {
  1641. Tcl_SetResult(interp, "no events specified in binding", TCL_STATIC);
  1642. return NULL;
  1643.     }
  1644.     if ((numPats > 1) && (virtualFound != 0)) {
  1645. Tcl_SetResult(interp, "virtual events may not be composed",
  1646. TCL_STATIC);
  1647. return NULL;
  1648.     }
  1649.     
  1650.     patPtr = &pats[EVENT_BUFFER_SIZE-numPats];
  1651.     memset(&key, 0, sizeof(key));
  1652.     key.object = object;
  1653.     key.type = patPtr->eventType;
  1654.     key.detail = patPtr->detail;
  1655.     hPtr = Tcl_CreateHashEntry(patternTablePtr, (char *) &key, &new);
  1656.     sequenceSize = numPats*sizeof(Pattern);
  1657.     if (!new) {
  1658. for (psPtr = (PatSeq *) Tcl_GetHashValue(hPtr); psPtr != NULL;
  1659. psPtr = psPtr->nextSeqPtr) {
  1660.     if ((numPats == psPtr->numPats)
  1661.     && ((flags & PAT_NEARBY) == (psPtr->flags & PAT_NEARBY))
  1662.     && (memcmp((char *) patPtr, (char *) psPtr->pats,
  1663.     sequenceSize) == 0)) {
  1664. goto done;
  1665.     }
  1666. }
  1667.     }
  1668.     if (!create) {
  1669. if (new) {
  1670.     Tcl_DeleteHashEntry(hPtr);
  1671. }
  1672. /*
  1673.  * No binding exists for the sequence, so return an empty error.
  1674.  * This is a special error that the caller will check for in order
  1675.  * to silently ignore this case.  This is a hack that maintains
  1676.  * backward compatibility for Tk_GetBinding but the various "bind"
  1677.  * commands silently ignore missing bindings.
  1678.  */
  1679. return NULL;
  1680.     }
  1681.     psPtr = (PatSeq *) ckalloc((unsigned) (sizeof(PatSeq)
  1682.     + (numPats-1)*sizeof(Pattern)));
  1683.     psPtr->numPats = numPats;
  1684.     psPtr->eventProc = NULL;
  1685.     psPtr->freeProc = NULL;
  1686.     psPtr->clientData = NULL;
  1687.     psPtr->flags = flags;
  1688.     psPtr->refCount = 0;
  1689.     psPtr->nextSeqPtr = (PatSeq *) Tcl_GetHashValue(hPtr);
  1690.     psPtr->hPtr = hPtr;
  1691.     psPtr->voPtr = NULL;
  1692.     psPtr->nextObjPtr = NULL;
  1693.     Tcl_SetHashValue(hPtr, psPtr);
  1694.     memcpy((VOID *) psPtr->pats, (VOID *) patPtr, sequenceSize);
  1695.     done:
  1696.     *maskPtr = eventMask;
  1697.     return psPtr;
  1698. }
  1699. /*
  1700.  *---------------------------------------------------------------------------
  1701.  *
  1702.  * ParseEventDescription --
  1703.  *
  1704.  * Fill Pattern buffer with information about event from
  1705.  * event string.
  1706.  *
  1707.  * Results:
  1708.  * Leaves error message in interp and returns 0 if there was an
  1709.  * error due to a badly formed event string.  Returns 1 if proper
  1710.  * event was specified, 2 if Double modifier was used in event
  1711.  * string, or 3 if Triple was used.
  1712.  *
  1713.  * Side effects:
  1714.  * On exit, eventStringPtr points to rest of event string (after the
  1715.  * closing '>', so that this procedure can be called repeatedly to
  1716.  * parse all the events in the entire sequence.
  1717.  *
  1718.  *---------------------------------------------------------------------------
  1719.  */
  1720. static int
  1721. ParseEventDescription(interp, eventStringPtr, patPtr,
  1722. eventMaskPtr)
  1723.     Tcl_Interp *interp; /* For error messages. */
  1724.     CONST char **eventStringPtr;/* On input, holds a pointer to start of
  1725.  * event string.  On exit, gets pointer to
  1726.  * rest of string after parsed event. */
  1727.     Pattern *patPtr; /* Filled with the pattern parsed from the
  1728.  * event string. */
  1729.     unsigned long *eventMaskPtr;/* Filled with event mask of matched event. */
  1730.  
  1731. {
  1732.     char *p;
  1733.     unsigned long eventMask;
  1734.     int count, eventFlags;
  1735. #define FIELD_SIZE 48
  1736.     char field[FIELD_SIZE];
  1737.     Tcl_HashEntry *hPtr;
  1738.     Tcl_DString copy;
  1739.     Tcl_DStringInit(&copy);
  1740.     p = Tcl_DStringAppend(&copy, *eventStringPtr, -1);
  1741.     patPtr->eventType = -1;
  1742.     patPtr->needMods = 0;
  1743.     patPtr->detail.clientData = 0;
  1744.     eventMask = 0;
  1745.     count = 1;
  1746.     
  1747.     /*
  1748.      * Handle simple ASCII characters.
  1749.      */
  1750.     if (*p != '<') {
  1751. char string[2];
  1752. patPtr->eventType = KeyPress;
  1753. eventMask = KeyPressMask;
  1754. string[0] = *p;
  1755. string[1] = 0;
  1756. patPtr->detail.keySym = TkStringToKeysym(string);
  1757. if (patPtr->detail.keySym == NoSymbol) {
  1758.     if (isprint(UCHAR(*p))) {
  1759. patPtr->detail.keySym = *p;
  1760.     } else {
  1761. char buf[64];
  1762. sprintf(buf, "bad ASCII character 0x%x", (unsigned char) *p);
  1763. Tcl_SetResult(interp, buf, TCL_VOLATILE);
  1764. count = 0;
  1765. goto done;
  1766.     }
  1767. }
  1768. p++;
  1769. goto end;
  1770.     }
  1771.     /*
  1772.      * A fancier event description.  This can be either a virtual event
  1773.      * or a physical event.
  1774.      *
  1775.      * A virtual event description consists of:
  1776.      *
  1777.      * 1. double open angle brackets.
  1778.      * 2. virtual event name.
  1779.      * 3. double close angle brackets.
  1780.      *
  1781.      * A physical event description consists of:
  1782.      *
  1783.      * 1. open angle bracket.
  1784.      * 2. any number of modifiers, each followed by spaces
  1785.      *    or dashes.
  1786.      * 3. an optional event name.
  1787.      * 4. an option button or keysym name.  Either this or
  1788.      *    item 3 *must* be present;  if both are present
  1789.      *    then they are separated by spaces or dashes.
  1790.      * 5. a close angle bracket.
  1791.      */
  1792.     p++;
  1793.     if (*p == '<') {
  1794. /*
  1795.  * This is a virtual event: soak up all the characters up to
  1796.  * the next '>'.
  1797.  */
  1798. char *field = p + 1;     
  1799. p = strchr(field, '>');
  1800. if (p == field) {
  1801.     Tcl_SetResult(interp, "virtual event "<<>>" is badly formed",
  1802.     TCL_STATIC);
  1803.     count = 0;
  1804.     goto done;
  1805. }     
  1806. if ((p == NULL) || (p[1] != '>')) {
  1807.     Tcl_SetResult(interp, "missing ">" in virtual binding",
  1808.     TCL_STATIC);
  1809.     count = 0;
  1810.     goto done;
  1811. }
  1812. *p = '';
  1813. patPtr->eventType = VirtualEvent;
  1814. eventMask = VirtualEventMask;
  1815. patPtr->detail.name = Tk_GetUid(field);
  1816. *p = '>';
  1817. p += 2;
  1818. goto end;
  1819.     }
  1820.     while (1) {
  1821. ModInfo *modPtr;
  1822. p = GetField(p, field, FIELD_SIZE);
  1823. if (*p == '>') {
  1824.     /*
  1825.      * This solves the problem of, e.g., <Control-M> being
  1826.      * misinterpreted as Control + Meta + missing keysym
  1827.      * instead of Control + KeyPress + M.
  1828.      */
  1829.      break;
  1830. }
  1831. hPtr = Tcl_FindHashEntry(&modTable, field);
  1832. if (hPtr == NULL) {
  1833.     break;
  1834. }
  1835. modPtr = (ModInfo *) Tcl_GetHashValue(hPtr);
  1836. patPtr->needMods |= modPtr->mask;
  1837. if (modPtr->flags & (MULT_CLICKS)) {
  1838.     int i = modPtr->flags & MULT_CLICKS;
  1839.     count = 2;
  1840.     while (i >>= 1) count++;
  1841. }
  1842. while ((*p == '-') || isspace(UCHAR(*p))) {
  1843.     p++;
  1844. }
  1845.     }
  1846.     eventFlags = 0;
  1847.     hPtr = Tcl_FindHashEntry(&eventTable, field);
  1848.     if (hPtr != NULL) {
  1849. EventInfo *eiPtr;
  1850. eiPtr = (EventInfo *) Tcl_GetHashValue(hPtr);
  1851. patPtr->eventType = eiPtr->type;
  1852. eventFlags = flagArray[eiPtr->type];
  1853. eventMask = eiPtr->eventMask;
  1854. while ((*p == '-') || isspace(UCHAR(*p))) {
  1855.     p++;
  1856. }
  1857. p = GetField(p, field, FIELD_SIZE);
  1858.     }
  1859.     if (*field != '') {
  1860. if ((*field >= '1') && (*field <= '5') && (field[1] == '')) {
  1861.     if (eventFlags == 0) {
  1862. patPtr->eventType = ButtonPress;
  1863. eventMask = ButtonPressMask;
  1864.     } else if (eventFlags & KEY) {
  1865. goto getKeysym;
  1866.     } else if ((eventFlags & BUTTON) == 0) {
  1867. Tcl_AppendResult(interp, "specified button "", field,
  1868. "" for non-button event", (char *) NULL);
  1869. count = 0;
  1870. goto done;
  1871.     }
  1872.     patPtr->detail.button = (*field - '0');
  1873. } else {
  1874.     getKeysym:
  1875.     patPtr->detail.keySym = TkStringToKeysym(field);
  1876.     if (patPtr->detail.keySym == NoSymbol) {
  1877. Tcl_AppendResult(interp, "bad event type or keysym "",
  1878. field, """, (char *) NULL);
  1879. count = 0;
  1880. goto done;
  1881.     }
  1882.     if (eventFlags == 0) {
  1883. patPtr->eventType = KeyPress;
  1884. eventMask = KeyPressMask;
  1885.     } else if ((eventFlags & KEY) == 0) {
  1886. Tcl_AppendResult(interp, "specified keysym "", field,
  1887. "" for non-key event", (char *) NULL);
  1888. count = 0;
  1889. goto done;
  1890.     }
  1891. }
  1892.     } else if (eventFlags == 0) {
  1893. Tcl_SetResult(interp, "no event type or button # or keysym",
  1894. TCL_STATIC);
  1895. count = 0;
  1896. goto done;
  1897.     }
  1898.     while ((*p == '-') || isspace(UCHAR(*p))) {
  1899. p++;
  1900.     }
  1901.     if (*p != '>') {
  1902. while (*p != '') {
  1903.     p++;
  1904.     if (*p == '>') {
  1905. Tcl_SetResult(interp,
  1906. "extra characters after detail in binding",
  1907. TCL_STATIC);
  1908. count = 0;
  1909. goto done;
  1910.     }
  1911. }
  1912. Tcl_SetResult(interp, "missing ">" in binding", TCL_STATIC);
  1913. count = 0;
  1914. goto done;
  1915.     }
  1916.     p++;
  1917. end:
  1918.     *eventStringPtr += (p - Tcl_DStringValue(&copy));
  1919.     *eventMaskPtr |= eventMask;
  1920. done:
  1921.     Tcl_DStringFree(&copy);
  1922.     return count;
  1923. }
  1924. /*
  1925.  *----------------------------------------------------------------------
  1926.  *
  1927.  * GetField --
  1928.  *
  1929.  * Used to parse pattern descriptions.  Copies up to
  1930.  * size characters from p to copy, stopping at end of
  1931.  * string, space, "-", ">", or whenever size is
  1932.  * exceeded.
  1933.  *
  1934.  * Results:
  1935.  * The return value is a pointer to the character just
  1936.  * after the last one copied (usually "-" or space or
  1937.  * ">", but could be anything if size was exceeded).
  1938.  * Also places NULL-terminated string (up to size
  1939.  * character, including NULL), at copy.
  1940.  *
  1941.  * Side effects:
  1942.  * None.
  1943.  *
  1944.  *----------------------------------------------------------------------
  1945.  */
  1946. static char *
  1947. GetField(p, copy, size)
  1948.     char *p; /* Pointer to part of pattern. */
  1949.     char *copy; /* Place to copy field. */
  1950.     int size; /* Maximum number of characters to
  1951.  * copy. */
  1952. {
  1953.     while ((*p != '') && !isspace(UCHAR(*p)) && (*p != '>')
  1954.     && (*p != '-') && (size > 1)) {
  1955. *copy = *p;
  1956. p++;
  1957. copy++;
  1958. size--;
  1959.     }
  1960.     *copy = '';
  1961.     return p;
  1962. }
  1963. /*
  1964.  *---------------------------------------------------------------------------
  1965.  *
  1966.  * GetPatternString --
  1967.  *
  1968.  * Produce a string version of the given event, for displaying to
  1969.  * the user.  
  1970.  *
  1971.  * Results:
  1972.  * The string is left in dsPtr.
  1973.  *
  1974.  * Side effects:
  1975.  * It is the caller's responsibility to initialize the DString before
  1976.  * and to free it after calling this procedure.
  1977.  *
  1978.  *---------------------------------------------------------------------------
  1979.  */
  1980. static void
  1981. GetPatternString(psPtr, dsPtr)
  1982.     PatSeq *psPtr;
  1983.     Tcl_DString *dsPtr;
  1984. {
  1985.     Pattern *patPtr;
  1986.     char c, buffer[TCL_INTEGER_SPACE];
  1987.     int patsLeft, needMods;
  1988.     ModInfo *modPtr;
  1989.     EventInfo *eiPtr;
  1990.     /*
  1991.      * The order of the patterns in the sequence is backwards from the order
  1992.      * in which they must be output.
  1993.      */
  1994.     for (patsLeft = psPtr->numPats, patPtr = &psPtr->pats[psPtr->numPats - 1];
  1995.     patsLeft > 0; patsLeft--, patPtr--) {
  1996. /*
  1997.  * Check for simple case of an ASCII character.
  1998.  */
  1999. if ((patPtr->eventType == KeyPress)
  2000. && ((psPtr->flags & PAT_NEARBY) == 0) 
  2001. && (patPtr->needMods == 0)
  2002. && (patPtr->detail.keySym < 128)
  2003. && isprint(UCHAR(patPtr->detail.keySym))
  2004. && (patPtr->detail.keySym != '<')
  2005. && (patPtr->detail.keySym != ' ')) {
  2006.     c = (char) patPtr->detail.keySym;
  2007.     Tcl_DStringAppend(dsPtr, &c, 1);
  2008.     continue;
  2009. }
  2010. /*
  2011.  * Check for virtual event.
  2012.  */
  2013. if (patPtr->eventType == VirtualEvent) {
  2014.     Tcl_DStringAppend(dsPtr, "<<", 2);
  2015.     Tcl_DStringAppend(dsPtr, patPtr->detail.name, -1);
  2016.     Tcl_DStringAppend(dsPtr, ">>", 2);
  2017.     continue;
  2018. }
  2019. /*
  2020.  * It's a more general event specification.  First check
  2021.  * for "Double", "Triple", "Quadruple", then modifiers,
  2022.  * then event type, then keysym or button detail.
  2023.  */
  2024. Tcl_DStringAppend(dsPtr, "<", 1);
  2025. if ((psPtr->flags & PAT_NEARBY) && (patsLeft > 1)
  2026. && (memcmp((char *) patPtr, (char *) (patPtr-1),
  2027. sizeof(Pattern)) == 0)) {
  2028.     patsLeft--;
  2029.     patPtr--;
  2030.     if ((patsLeft > 1) && (memcmp((char *) patPtr,
  2031.     (char *) (patPtr-1), sizeof(Pattern)) == 0)) {
  2032. patsLeft--;
  2033. patPtr--;
  2034.     if ((patsLeft > 1) && (memcmp((char *) patPtr,
  2035.     (char *) (patPtr-1), sizeof(Pattern)) == 0)) {
  2036. patsLeft--;
  2037. patPtr--;
  2038. Tcl_DStringAppend(dsPtr, "Quadruple-", 10);
  2039.     } else {
  2040. Tcl_DStringAppend(dsPtr, "Triple-", 7);
  2041.     }
  2042.     } else {
  2043. Tcl_DStringAppend(dsPtr, "Double-", 7);
  2044.     }
  2045. }
  2046. for (needMods = patPtr->needMods, modPtr = modArray;
  2047. needMods != 0; modPtr++) {
  2048.     if (modPtr->mask & needMods) {
  2049. needMods &= ~modPtr->mask;
  2050. Tcl_DStringAppend(dsPtr, modPtr->name, -1);
  2051. Tcl_DStringAppend(dsPtr, "-", 1);
  2052.     }
  2053. }
  2054. for (eiPtr = eventArray; eiPtr->name != NULL; eiPtr++) {
  2055.     if (eiPtr->type == patPtr->eventType) {
  2056. Tcl_DStringAppend(dsPtr, eiPtr->name, -1);
  2057. if (patPtr->detail.clientData != 0) {
  2058.     Tcl_DStringAppend(dsPtr, "-", 1);
  2059. }
  2060. break;
  2061.     }
  2062. }
  2063. if (patPtr->detail.clientData != 0) {
  2064.     if ((patPtr->eventType == KeyPress)
  2065.     || (patPtr->eventType == KeyRelease)) {
  2066. char *string;
  2067. string = TkKeysymToString(patPtr->detail.keySym);
  2068. if (string != NULL) {
  2069.     Tcl_DStringAppend(dsPtr, string, -1);
  2070. }
  2071.     } else {
  2072. sprintf(buffer, "%d", patPtr->detail.button);
  2073. Tcl_DStringAppend(dsPtr, buffer, -1);
  2074.     }
  2075. }
  2076. Tcl_DStringAppend(dsPtr, ">", 1);
  2077.     }
  2078. }
  2079. /*
  2080.  *---------------------------------------------------------------------------
  2081.  *
  2082.  * EvalTclBinding --
  2083.  *
  2084.  * The procedure that is invoked by Tk_BindEvent when a Tcl binding
  2085.  * is fired.  
  2086.  *
  2087.  * Results:
  2088.  * A standard Tcl result code, the result of globally evaluating the
  2089.  * percent-substitued binding string.
  2090.  *
  2091.  * Side effects:
  2092.  * Normal side effects due to eval.
  2093.  *
  2094.  *---------------------------------------------------------------------------
  2095.  */
  2096. static void
  2097. FreeTclBinding(clientData)
  2098.     ClientData clientData;
  2099. {
  2100.     ckfree((char *) clientData);
  2101. }
  2102. /*
  2103.  *----------------------------------------------------------------------
  2104.  *
  2105.  * TkStringToKeysym --
  2106.  *
  2107.  * This procedure finds the keysym associated with a given keysym
  2108.  * name.
  2109.  *
  2110.  * Results:
  2111.  * The return value is the keysym that corresponds to name, or
  2112.  * NoSymbol if there is no such keysym.
  2113.  *
  2114.  * Side effects:
  2115.  * None.
  2116.  *
  2117.  *----------------------------------------------------------------------
  2118.  */
  2119. KeySym
  2120. TkStringToKeysym(name)
  2121.     char *name; /* Name of a keysym. */
  2122. {
  2123. #ifdef REDO_KEYSYM_LOOKUP
  2124.     Tcl_HashEntry *hPtr;
  2125.     KeySym keysym;
  2126.     hPtr = Tcl_FindHashEntry(&keySymTable, name);
  2127.     if (hPtr != NULL) {
  2128. return (KeySym) Tcl_GetHashValue(hPtr);
  2129.     }
  2130.     if (strlen(name) == 1) {
  2131. keysym = (KeySym) (unsigned char) name[0];
  2132. if (TkKeysymToString(keysym) != NULL) {
  2133.     return keysym;
  2134. }
  2135.     }
  2136. #endif /* REDO_KEYSYM_LOOKUP */
  2137.     return XStringToKeysym(name);
  2138. }
  2139. /*
  2140.  *----------------------------------------------------------------------
  2141.  *
  2142.  * TkKeysymToString --
  2143.  *
  2144.  * This procedure finds the keysym name associated with a given
  2145.  * keysym.
  2146.  *
  2147.  * Results:
  2148.  * The return value is a pointer to a static string containing
  2149.  * the name of the given keysym, or NULL if there is no known name.
  2150.  *
  2151.  * Side effects:
  2152.  * None.
  2153.  *
  2154.  *----------------------------------------------------------------------
  2155.  */
  2156. char *
  2157. TkKeysymToString(keysym)
  2158.     KeySym keysym;
  2159. {
  2160. #ifdef REDO_KEYSYM_LOOKUP
  2161.     Tcl_HashEntry *hPtr;
  2162.     hPtr = Tcl_FindHashEntry(&nameTable, (char *)keysym);
  2163.     if (hPtr != NULL) {
  2164. return (char *) Tcl_GetHashValue(hPtr);
  2165.     }
  2166. #endif /* REDO_KEYSYM_LOOKUP */
  2167.     return XKeysymToString(keysym);
  2168. }
  2169. /*
  2170.  *----------------------------------------------------------------------
  2171.  *
  2172.  * TkCopyAndGlobalEval --
  2173.  *
  2174.  * This procedure makes a copy of a script then passes to Tcl
  2175.  * to evaluate it.  It's used in situations where the execution of
  2176.  * a command may cause the original command string to be reallocated.
  2177.  *
  2178.  * Results:
  2179.  * Returns the result of evaluating script, including both a standard
  2180.  * Tcl completion code and a string in the interp's result.
  2181.  *
  2182.  * Side effects:
  2183.  * None.
  2184.  *
  2185.  *----------------------------------------------------------------------
  2186.  */
  2187. int
  2188. TkCopyAndGlobalEval(interp, script)
  2189.     Tcl_Interp *interp; /* Interpreter in which to evaluate
  2190.  * script. */
  2191.     char *script; /* Script to evaluate. */
  2192. {
  2193.     Tcl_DString buffer;
  2194.     int code;
  2195.     Tcl_DStringInit(&buffer);
  2196.     Tcl_DStringAppend(&buffer, script, -1);
  2197.     code = Tcl_EvalEx(interp, Tcl_DStringValue(&buffer),
  2198.     Tcl_DStringLength(&buffer), TCL_EVAL_GLOBAL);
  2199.     Tcl_DStringFree(&buffer);
  2200.     return code;
  2201. }