/[dtapublic]/projs/dtats/trunk/shared_source/c_tk_base_7_5_w_mods/tktexttag.c
ViewVC logotype

Diff of /projs/dtats/trunk/shared_source/c_tk_base_7_5_w_mods/tktexttag.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 69 by dashley, Sat Nov 5 10:54:17 2016 UTC revision 71 by dashley, Sat Nov 5 11:07:06 2016 UTC
# Line 1  Line 1 
1  /* $Header$ */  /* $Header$ */
2    
3  /*  /*
4   * tkTextTag.c --   * tkTextTag.c --
5   *   *
6   *      This module implements the "tag" subcommand of the widget command   *      This module implements the "tag" subcommand of the widget command
7   *      for text widgets, plus most of the other high-level functions   *      for text widgets, plus most of the other high-level functions
8   *      related to tags.   *      related to tags.
9   *   *
10   * Copyright (c) 1992-1994 The Regents of the University of California.   * Copyright (c) 1992-1994 The Regents of the University of California.
11   * Copyright (c) 1994-1997 Sun Microsystems, Inc.   * Copyright (c) 1994-1997 Sun Microsystems, Inc.
12   *   *
13   * See the file "license.terms" for information on usage and redistribution   * See the file "license.terms" for information on usage and redistribution
14   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15   *   *
16   * RCS: @(#) $Id: tktexttag.c,v 1.1.1.1 2001/06/13 05:10:53 dtashley Exp $   * RCS: @(#) $Id: tktexttag.c,v 1.1.1.1 2001/06/13 05:10:53 dtashley Exp $
17   */   */
18    
19  #include "default.h"  #include "default.h"
20  #include "tkPort.h"  #include "tkPort.h"
21  #include "tkInt.h"  #include "tkInt.h"
22  #include "tkText.h"  #include "tkText.h"
23    
24  static Tk_ConfigSpec tagConfigSpecs[] = {  static Tk_ConfigSpec tagConfigSpecs[] = {
25      {TK_CONFIG_BORDER, "-background", (char *) NULL, (char *) NULL,      {TK_CONFIG_BORDER, "-background", (char *) NULL, (char *) NULL,
26          (char *) NULL, Tk_Offset(TkTextTag, border), TK_CONFIG_NULL_OK},          (char *) NULL, Tk_Offset(TkTextTag, border), TK_CONFIG_NULL_OK},
27      {TK_CONFIG_BITMAP, "-bgstipple", (char *) NULL, (char *) NULL,      {TK_CONFIG_BITMAP, "-bgstipple", (char *) NULL, (char *) NULL,
28          (char *) NULL, Tk_Offset(TkTextTag, bgStipple), TK_CONFIG_NULL_OK},          (char *) NULL, Tk_Offset(TkTextTag, bgStipple), TK_CONFIG_NULL_OK},
29      {TK_CONFIG_STRING, "-borderwidth", (char *) NULL, (char *) NULL,      {TK_CONFIG_STRING, "-borderwidth", (char *) NULL, (char *) NULL,
30          "0", Tk_Offset(TkTextTag, bdString),          "0", Tk_Offset(TkTextTag, bdString),
31          TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK},          TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK},
32      {TK_CONFIG_STRING, "-elide", (char *) NULL, (char *) NULL,      {TK_CONFIG_STRING, "-elide", (char *) NULL, (char *) NULL,
33          "0", Tk_Offset(TkTextTag, elideString),          "0", Tk_Offset(TkTextTag, elideString),
34          TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK},          TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK},
35      {TK_CONFIG_BITMAP, "-fgstipple", (char *) NULL, (char *) NULL,      {TK_CONFIG_BITMAP, "-fgstipple", (char *) NULL, (char *) NULL,
36          (char *) NULL, Tk_Offset(TkTextTag, fgStipple), TK_CONFIG_NULL_OK},          (char *) NULL, Tk_Offset(TkTextTag, fgStipple), TK_CONFIG_NULL_OK},
37      {TK_CONFIG_FONT, "-font", (char *) NULL, (char *) NULL,      {TK_CONFIG_FONT, "-font", (char *) NULL, (char *) NULL,
38          (char *) NULL, Tk_Offset(TkTextTag, tkfont), TK_CONFIG_NULL_OK},          (char *) NULL, Tk_Offset(TkTextTag, tkfont), TK_CONFIG_NULL_OK},
39      {TK_CONFIG_COLOR, "-foreground", (char *) NULL, (char *) NULL,      {TK_CONFIG_COLOR, "-foreground", (char *) NULL, (char *) NULL,
40          (char *) NULL, Tk_Offset(TkTextTag, fgColor), TK_CONFIG_NULL_OK},          (char *) NULL, Tk_Offset(TkTextTag, fgColor), TK_CONFIG_NULL_OK},
41      {TK_CONFIG_STRING, "-justify", (char *) NULL, (char *) NULL,      {TK_CONFIG_STRING, "-justify", (char *) NULL, (char *) NULL,
42          (char *) NULL, Tk_Offset(TkTextTag, justifyString), TK_CONFIG_NULL_OK},          (char *) NULL, Tk_Offset(TkTextTag, justifyString), TK_CONFIG_NULL_OK},
43      {TK_CONFIG_STRING, "-lmargin1", (char *) NULL, (char *) NULL,      {TK_CONFIG_STRING, "-lmargin1", (char *) NULL, (char *) NULL,
44          (char *) NULL, Tk_Offset(TkTextTag, lMargin1String), TK_CONFIG_NULL_OK},          (char *) NULL, Tk_Offset(TkTextTag, lMargin1String), TK_CONFIG_NULL_OK},
45      {TK_CONFIG_STRING, "-lmargin2", (char *) NULL, (char *) NULL,      {TK_CONFIG_STRING, "-lmargin2", (char *) NULL, (char *) NULL,
46          (char *) NULL, Tk_Offset(TkTextTag, lMargin2String), TK_CONFIG_NULL_OK},          (char *) NULL, Tk_Offset(TkTextTag, lMargin2String), TK_CONFIG_NULL_OK},
47      {TK_CONFIG_STRING, "-offset", (char *) NULL, (char *) NULL,      {TK_CONFIG_STRING, "-offset", (char *) NULL, (char *) NULL,
48          (char *) NULL, Tk_Offset(TkTextTag, offsetString), TK_CONFIG_NULL_OK},          (char *) NULL, Tk_Offset(TkTextTag, offsetString), TK_CONFIG_NULL_OK},
49      {TK_CONFIG_STRING, "-overstrike", (char *) NULL, (char *) NULL,      {TK_CONFIG_STRING, "-overstrike", (char *) NULL, (char *) NULL,
50          (char *) NULL, Tk_Offset(TkTextTag, overstrikeString),          (char *) NULL, Tk_Offset(TkTextTag, overstrikeString),
51          TK_CONFIG_NULL_OK},          TK_CONFIG_NULL_OK},
52      {TK_CONFIG_STRING, "-relief", (char *) NULL, (char *) NULL,      {TK_CONFIG_STRING, "-relief", (char *) NULL, (char *) NULL,
53          (char *) NULL, Tk_Offset(TkTextTag, reliefString), TK_CONFIG_NULL_OK},          (char *) NULL, Tk_Offset(TkTextTag, reliefString), TK_CONFIG_NULL_OK},
54      {TK_CONFIG_STRING, "-rmargin", (char *) NULL, (char *) NULL,      {TK_CONFIG_STRING, "-rmargin", (char *) NULL, (char *) NULL,
55          (char *) NULL, Tk_Offset(TkTextTag, rMarginString), TK_CONFIG_NULL_OK},          (char *) NULL, Tk_Offset(TkTextTag, rMarginString), TK_CONFIG_NULL_OK},
56      {TK_CONFIG_STRING, "-spacing1", (char *) NULL, (char *) NULL,      {TK_CONFIG_STRING, "-spacing1", (char *) NULL, (char *) NULL,
57          (char *) NULL, Tk_Offset(TkTextTag, spacing1String), TK_CONFIG_NULL_OK},          (char *) NULL, Tk_Offset(TkTextTag, spacing1String), TK_CONFIG_NULL_OK},
58      {TK_CONFIG_STRING, "-spacing2", (char *) NULL, (char *) NULL,      {TK_CONFIG_STRING, "-spacing2", (char *) NULL, (char *) NULL,
59          (char *) NULL, Tk_Offset(TkTextTag, spacing2String), TK_CONFIG_NULL_OK},          (char *) NULL, Tk_Offset(TkTextTag, spacing2String), TK_CONFIG_NULL_OK},
60      {TK_CONFIG_STRING, "-spacing3", (char *) NULL, (char *) NULL,      {TK_CONFIG_STRING, "-spacing3", (char *) NULL, (char *) NULL,
61          (char *) NULL, Tk_Offset(TkTextTag, spacing3String), TK_CONFIG_NULL_OK},          (char *) NULL, Tk_Offset(TkTextTag, spacing3String), TK_CONFIG_NULL_OK},
62      {TK_CONFIG_STRING, "-tabs", (char *) NULL, (char *) NULL,      {TK_CONFIG_STRING, "-tabs", (char *) NULL, (char *) NULL,
63          (char *) NULL, Tk_Offset(TkTextTag, tabString), TK_CONFIG_NULL_OK},          (char *) NULL, Tk_Offset(TkTextTag, tabString), TK_CONFIG_NULL_OK},
64      {TK_CONFIG_STRING, "-underline", (char *) NULL, (char *) NULL,      {TK_CONFIG_STRING, "-underline", (char *) NULL, (char *) NULL,
65          (char *) NULL, Tk_Offset(TkTextTag, underlineString),          (char *) NULL, Tk_Offset(TkTextTag, underlineString),
66          TK_CONFIG_NULL_OK},          TK_CONFIG_NULL_OK},
67      {TK_CONFIG_CUSTOM, "-wrap", (char *) NULL, (char *) NULL,      {TK_CONFIG_CUSTOM, "-wrap", (char *) NULL, (char *) NULL,
68          (char *) NULL, Tk_Offset(TkTextTag, wrapMode),          (char *) NULL, Tk_Offset(TkTextTag, wrapMode),
69          TK_CONFIG_NULL_OK,          TK_CONFIG_NULL_OK,
70     &textWrapModeOption},     &textWrapModeOption},
71     {TK_CONFIG_END,     {TK_CONFIG_END,
72     (char *) NULL,     (char *) NULL,
73     (char *) NULL,     (char *) NULL,
74     (char *) NULL,     (char *) NULL,
75          (char *) NULL,          (char *) NULL,
76     0,     0,
77     0}     0}
78  };  };
79    
80  /*  /*
81   * Forward declarations for procedures defined later in this file:   * Forward declarations for procedures defined later in this file:
82   */   */
83    
84  static void             ChangeTagPriority _ANSI_ARGS_((TkText *textPtr,  static void             ChangeTagPriority _ANSI_ARGS_((TkText *textPtr,
85                              TkTextTag *tagPtr, int prio));                              TkTextTag *tagPtr, int prio));
86  static TkTextTag *      FindTag _ANSI_ARGS_((Tcl_Interp *interp,  static TkTextTag *      FindTag _ANSI_ARGS_((Tcl_Interp *interp,
87                              TkText *textPtr, char *tagName));                              TkText *textPtr, char *tagName));
88  static void             SortTags _ANSI_ARGS_((int numTags,  static void             SortTags _ANSI_ARGS_((int numTags,
89                              TkTextTag **tagArrayPtr));                              TkTextTag **tagArrayPtr));
90  static int              TagSortProc _ANSI_ARGS_((CONST VOID *first,  static int              TagSortProc _ANSI_ARGS_((CONST VOID *first,
91                              CONST VOID *second));                              CONST VOID *second));
92    
93  /*  /*
94   *--------------------------------------------------------------   *--------------------------------------------------------------
95   *   *
96   * TkTextTagCmd --   * TkTextTagCmd --
97   *   *
98   *      This procedure is invoked to process the "tag" options of   *      This procedure is invoked to process the "tag" options of
99   *      the widget command for text widgets. See the user documentation   *      the widget command for text widgets. See the user documentation
100   *      for details on what it does.   *      for details on what it does.
101   *   *
102   * Results:   * Results:
103   *      A standard Tcl result.   *      A standard Tcl result.
104   *   *
105   * Side effects:   * Side effects:
106   *      See the user documentation.   *      See the user documentation.
107   *   *
108   *--------------------------------------------------------------   *--------------------------------------------------------------
109   */   */
110    
111  int  int
112  TkTextTagCmd(textPtr, interp, argc, argv)  TkTextTagCmd(textPtr, interp, argc, argv)
113      register TkText *textPtr;   /* Information about text widget. */      register TkText *textPtr;   /* Information about text widget. */
114      Tcl_Interp *interp;         /* Current interpreter. */      Tcl_Interp *interp;         /* Current interpreter. */
115      int argc;                   /* Number of arguments. */      int argc;                   /* Number of arguments. */
116      char **argv;                /* Argument strings.  Someone else has already      char **argv;                /* Argument strings.  Someone else has already
117                                   * parsed this command enough to know that                                   * parsed this command enough to know that
118                                   * argv[1] is "tag". */                                   * argv[1] is "tag". */
119  {  {
120      int c, i, addTag;      int c, i, addTag;
121      size_t length;      size_t length;
122      char *fullOption;      char *fullOption;
123      register TkTextTag *tagPtr;      register TkTextTag *tagPtr;
124      TkTextIndex first, last, index1, index2;      TkTextIndex first, last, index1, index2;
125    
126      if (argc < 3) {      if (argc < 3) {
127          Tcl_AppendResult(interp, "wrong # args: should be \"",          Tcl_AppendResult(interp, "wrong # args: should be \"",
128                  argv[0], " tag option ?arg arg ...?\"", (char *) NULL);                  argv[0], " tag option ?arg arg ...?\"", (char *) NULL);
129          return TCL_ERROR;          return TCL_ERROR;
130      }      }
131      c = argv[2][0];      c = argv[2][0];
132      length = strlen(argv[2]);      length = strlen(argv[2]);
133      if ((c == 'a') && (strncmp(argv[2], "add", length) == 0)) {      if ((c == 'a') && (strncmp(argv[2], "add", length) == 0)) {
134          fullOption = "add";          fullOption = "add";
135          addTag = 1;          addTag = 1;
136    
137          addAndRemove:          addAndRemove:
138          if (argc < 5) {          if (argc < 5) {
139              Tcl_AppendResult(interp, "wrong # args: should be \"",              Tcl_AppendResult(interp, "wrong # args: should be \"",
140                      argv[0], " tag ", fullOption,                      argv[0], " tag ", fullOption,
141                      " tagName index1 ?index2 index1 index2 ...?\"",                      " tagName index1 ?index2 index1 index2 ...?\"",
142                      (char *) NULL);                      (char *) NULL);
143              return TCL_ERROR;              return TCL_ERROR;
144          }          }
145          tagPtr = TkTextCreateTag(textPtr, argv[3]);          tagPtr = TkTextCreateTag(textPtr, argv[3]);
146          for (i = 4; i < argc; i += 2) {          for (i = 4; i < argc; i += 2) {
147              if (TkTextGetIndex(interp, textPtr, argv[i], &index1) != TCL_OK) {              if (TkTextGetIndex(interp, textPtr, argv[i], &index1) != TCL_OK) {
148                  return TCL_ERROR;                  return TCL_ERROR;
149              }              }
150              if (argc > (i+1)) {              if (argc > (i+1)) {
151                  if (TkTextGetIndex(interp, textPtr, argv[i+1], &index2)                  if (TkTextGetIndex(interp, textPtr, argv[i+1], &index2)
152                          != TCL_OK) {                          != TCL_OK) {
153                      return TCL_ERROR;                      return TCL_ERROR;
154                  }                  }
155                  if (TkTextIndexCmp(&index1, &index2) >= 0) {                  if (TkTextIndexCmp(&index1, &index2) >= 0) {
156                      return TCL_OK;                      return TCL_OK;
157                  }                  }
158              } else {              } else {
159                  index2 = index1;                  index2 = index1;
160                  TkTextIndexForwChars(&index2, 1, &index2);                  TkTextIndexForwChars(&index2, 1, &index2);
161              }              }
162            
163              if (tagPtr->affectsDisplay) {              if (tagPtr->affectsDisplay) {
164                  TkTextRedrawTag(textPtr, &index1, &index2, tagPtr, !addTag);                  TkTextRedrawTag(textPtr, &index1, &index2, tagPtr, !addTag);
165              } else {              } else {
166                  /*                  /*
167                   * Still need to trigger enter/leave events on tags that                   * Still need to trigger enter/leave events on tags that
168                   * have changed.                   * have changed.
169                   */                   */
170            
171                  TkTextEventuallyRepick(textPtr);                  TkTextEventuallyRepick(textPtr);
172              }              }
173              TkBTreeTag(&index1, &index2, tagPtr, addTag);              TkBTreeTag(&index1, &index2, tagPtr, addTag);
174            
175              /*              /*
176               * If the tag is "sel" then grab the selection if we're supposed               * If the tag is "sel" then grab the selection if we're supposed
177               * to export it and don't already have it.  Also, invalidate               * to export it and don't already have it.  Also, invalidate
178               * partially-completed selection retrievals.               * partially-completed selection retrievals.
179               */               */
180            
181              if (tagPtr == textPtr->selTagPtr) {              if (tagPtr == textPtr->selTagPtr) {
182                  if (addTag && textPtr->exportSelection                  if (addTag && textPtr->exportSelection
183                          && !(textPtr->flags & GOT_SELECTION)) {                          && !(textPtr->flags & GOT_SELECTION)) {
184                      Tk_OwnSelection(textPtr->tkwin, XA_PRIMARY,                      Tk_OwnSelection(textPtr->tkwin, XA_PRIMARY,
185                              TkTextLostSelection, (ClientData) textPtr);                              TkTextLostSelection, (ClientData) textPtr);
186                      textPtr->flags |= GOT_SELECTION;                      textPtr->flags |= GOT_SELECTION;
187                  }                  }
188                  textPtr->abortSelections = 1;                  textPtr->abortSelections = 1;
189              }              }
190          }          }
191      } else if ((c == 'b') && (strncmp(argv[2], "bind", length) == 0)) {      } else if ((c == 'b') && (strncmp(argv[2], "bind", length) == 0)) {
192          if ((argc < 4) || (argc > 6)) {          if ((argc < 4) || (argc > 6)) {
193              Tcl_AppendResult(interp, "wrong # args: should be \"",              Tcl_AppendResult(interp, "wrong # args: should be \"",
194                      argv[0], " tag bind tagName ?sequence? ?command?\"",                      argv[0], " tag bind tagName ?sequence? ?command?\"",
195                      (char *) NULL);                      (char *) NULL);
196              return TCL_ERROR;              return TCL_ERROR;
197          }          }
198          tagPtr = TkTextCreateTag(textPtr, argv[3]);          tagPtr = TkTextCreateTag(textPtr, argv[3]);
199    
200          /*          /*
201           * Make a binding table if the widget doesn't already have           * Make a binding table if the widget doesn't already have
202           * one.           * one.
203           */           */
204    
205          if (textPtr->bindingTable == NULL) {          if (textPtr->bindingTable == NULL) {
206              textPtr->bindingTable = Tk_CreateBindingTable(interp);              textPtr->bindingTable = Tk_CreateBindingTable(interp);
207          }          }
208    
209          if (argc == 6) {          if (argc == 6) {
210              int append = 0;              int append = 0;
211              unsigned long mask;              unsigned long mask;
212    
213              if (argv[5][0] == 0) {              if (argv[5][0] == 0) {
214                  return Tk_DeleteBinding(interp, textPtr->bindingTable,                  return Tk_DeleteBinding(interp, textPtr->bindingTable,
215                          (ClientData) tagPtr, argv[4]);                          (ClientData) tagPtr, argv[4]);
216              }              }
217              if (argv[5][0] == '+') {              if (argv[5][0] == '+') {
218                  argv[5]++;                  argv[5]++;
219                  append = 1;                  append = 1;
220              }              }
221              mask = Tk_CreateBinding(interp, textPtr->bindingTable,              mask = Tk_CreateBinding(interp, textPtr->bindingTable,
222                      (ClientData) tagPtr, argv[4], argv[5], append);                      (ClientData) tagPtr, argv[4], argv[5], append);
223              if (mask == 0) {              if (mask == 0) {
224                  return TCL_ERROR;                  return TCL_ERROR;
225              }              }
226              if (mask & (unsigned) ~(ButtonMotionMask|Button1MotionMask              if (mask & (unsigned) ~(ButtonMotionMask|Button1MotionMask
227                      |Button2MotionMask|Button3MotionMask|Button4MotionMask                      |Button2MotionMask|Button3MotionMask|Button4MotionMask
228                      |Button5MotionMask|ButtonPressMask|ButtonReleaseMask                      |Button5MotionMask|ButtonPressMask|ButtonReleaseMask
229                      |EnterWindowMask|LeaveWindowMask|KeyPressMask                      |EnterWindowMask|LeaveWindowMask|KeyPressMask
230                      |KeyReleaseMask|PointerMotionMask|VirtualEventMask)) {                      |KeyReleaseMask|PointerMotionMask|VirtualEventMask)) {
231                  Tk_DeleteBinding(interp, textPtr->bindingTable,                  Tk_DeleteBinding(interp, textPtr->bindingTable,
232                          (ClientData) tagPtr, argv[4]);                          (ClientData) tagPtr, argv[4]);
233                  Tcl_ResetResult(interp);                  Tcl_ResetResult(interp);
234                  Tcl_AppendResult(interp, "requested illegal events; ",                  Tcl_AppendResult(interp, "requested illegal events; ",
235                          "only key, button, motion, enter, leave, and virtual ",                          "only key, button, motion, enter, leave, and virtual ",
236                          "events may be used", (char *) NULL);                          "events may be used", (char *) NULL);
237                  return TCL_ERROR;                  return TCL_ERROR;
238              }              }
239          } else if (argc == 5) {          } else if (argc == 5) {
240              char *command;              char *command;
241            
242              command = Tk_GetBinding(interp, textPtr->bindingTable,              command = Tk_GetBinding(interp, textPtr->bindingTable,
243                      (ClientData) tagPtr, argv[4]);                      (ClientData) tagPtr, argv[4]);
244              if (command == NULL) {              if (command == NULL) {
245                  char *string = Tcl_GetStringResult(interp);                  char *string = Tcl_GetStringResult(interp);
246    
247                  /*                  /*
248                   * Ignore missing binding errors.  This is a special hack                   * Ignore missing binding errors.  This is a special hack
249                   * that relies on the error message returned by FindSequence                   * that relies on the error message returned by FindSequence
250                   * in tkBind.c.                   * in tkBind.c.
251                   */                   */
252    
253                  if (string[0] != '\0') {                  if (string[0] != '\0') {
254                      return TCL_ERROR;                      return TCL_ERROR;
255                  } else {                  } else {
256                      Tcl_ResetResult(interp);                      Tcl_ResetResult(interp);
257                  }                  }
258              } else {              } else {
259                  Tcl_SetResult(interp, command, TCL_STATIC);                  Tcl_SetResult(interp, command, TCL_STATIC);
260              }              }
261          } else {          } else {
262              Tk_GetAllBindings(interp, textPtr->bindingTable,              Tk_GetAllBindings(interp, textPtr->bindingTable,
263                      (ClientData) tagPtr);                      (ClientData) tagPtr);
264          }          }
265      } else if ((c == 'c') && (strncmp(argv[2], "cget", length) == 0)      } else if ((c == 'c') && (strncmp(argv[2], "cget", length) == 0)
266              && (length >= 2)) {              && (length >= 2)) {
267          if (argc != 5) {          if (argc != 5) {
268              Tcl_AppendResult(interp, "wrong # args: should be \"",              Tcl_AppendResult(interp, "wrong # args: should be \"",
269                      argv[0], " tag cget tagName option\"",                      argv[0], " tag cget tagName option\"",
270                      (char *) NULL);                      (char *) NULL);
271              return TCL_ERROR;              return TCL_ERROR;
272          }          }
273          tagPtr = FindTag(interp, textPtr, argv[3]);          tagPtr = FindTag(interp, textPtr, argv[3]);
274          if (tagPtr == NULL) {          if (tagPtr == NULL) {
275              return TCL_ERROR;              return TCL_ERROR;
276          }          }
277          return Tk_ConfigureValue(interp, textPtr->tkwin, tagConfigSpecs,          return Tk_ConfigureValue(interp, textPtr->tkwin, tagConfigSpecs,
278                  (char *) tagPtr, argv[4], 0);                  (char *) tagPtr, argv[4], 0);
279      } else if ((c == 'c') && (strncmp(argv[2], "configure", length) == 0)      } else if ((c == 'c') && (strncmp(argv[2], "configure", length) == 0)
280              && (length >= 2)) {              && (length >= 2)) {
281          if (argc < 4) {          if (argc < 4) {
282              Tcl_AppendResult(interp, "wrong # args: should be \"",              Tcl_AppendResult(interp, "wrong # args: should be \"",
283                      argv[0], " tag configure tagName ?option? ?value? ",                      argv[0], " tag configure tagName ?option? ?value? ",
284                      "?option value ...?\"", (char *) NULL);                      "?option value ...?\"", (char *) NULL);
285              return TCL_ERROR;              return TCL_ERROR;
286          }          }
287          tagPtr = TkTextCreateTag(textPtr, argv[3]);          tagPtr = TkTextCreateTag(textPtr, argv[3]);
288          if (argc == 4) {          if (argc == 4) {
289              return Tk_ConfigureInfo(interp, textPtr->tkwin, tagConfigSpecs,              return Tk_ConfigureInfo(interp, textPtr->tkwin, tagConfigSpecs,
290                      (char *) tagPtr, (char *) NULL, 0);                      (char *) tagPtr, (char *) NULL, 0);
291          } else if (argc == 5) {          } else if (argc == 5) {
292              return Tk_ConfigureInfo(interp, textPtr->tkwin, tagConfigSpecs,              return Tk_ConfigureInfo(interp, textPtr->tkwin, tagConfigSpecs,
293                      (char *) tagPtr, argv[4], 0);                      (char *) tagPtr, argv[4], 0);
294          } else {          } else {
295              int result;              int result;
296    
297              result = Tk_ConfigureWidget(interp, textPtr->tkwin, tagConfigSpecs,              result = Tk_ConfigureWidget(interp, textPtr->tkwin, tagConfigSpecs,
298                      argc-4, argv+4, (char *) tagPtr, 0);                      argc-4, argv+4, (char *) tagPtr, 0);
299              /*              /*
300               * Some of the configuration options, like -underline               * Some of the configuration options, like -underline
301               * and -justify, require additional translation (this is               * and -justify, require additional translation (this is
302               * needed because we need to distinguish a particular value               * needed because we need to distinguish a particular value
303               * of an option from "unspecified").               * of an option from "unspecified").
304               */               */
305    
306              if (tagPtr->bdString != NULL) {              if (tagPtr->bdString != NULL) {
307                  if (Tk_GetPixels(interp, textPtr->tkwin, tagPtr->bdString,                  if (Tk_GetPixels(interp, textPtr->tkwin, tagPtr->bdString,
308                          &tagPtr->borderWidth) != TCL_OK) {                          &tagPtr->borderWidth) != TCL_OK) {
309                      return TCL_ERROR;                      return TCL_ERROR;
310                  }                  }
311                  if (tagPtr->borderWidth < 0) {                  if (tagPtr->borderWidth < 0) {
312                      tagPtr->borderWidth = 0;                      tagPtr->borderWidth = 0;
313                  }                  }
314              }              }
315              if (tagPtr->reliefString != NULL) {              if (tagPtr->reliefString != NULL) {
316                  if (Tk_GetRelief(interp, tagPtr->reliefString,                  if (Tk_GetRelief(interp, tagPtr->reliefString,
317                          &tagPtr->relief) != TCL_OK) {                          &tagPtr->relief) != TCL_OK) {
318                      return TCL_ERROR;                      return TCL_ERROR;
319                  }                  }
320              }              }
321              if (tagPtr->justifyString != NULL) {              if (tagPtr->justifyString != NULL) {
322                  if (Tk_GetJustify(interp, tagPtr->justifyString,                  if (Tk_GetJustify(interp, tagPtr->justifyString,
323                          &tagPtr->justify) != TCL_OK) {                          &tagPtr->justify) != TCL_OK) {
324                      return TCL_ERROR;                      return TCL_ERROR;
325                  }                  }
326              }              }
327              if (tagPtr->lMargin1String != NULL) {              if (tagPtr->lMargin1String != NULL) {
328                  if (Tk_GetPixels(interp, textPtr->tkwin,                  if (Tk_GetPixels(interp, textPtr->tkwin,
329                          tagPtr->lMargin1String, &tagPtr->lMargin1) != TCL_OK) {                          tagPtr->lMargin1String, &tagPtr->lMargin1) != TCL_OK) {
330                      return TCL_ERROR;                      return TCL_ERROR;
331                  }                  }
332              }              }
333              if (tagPtr->lMargin2String != NULL) {              if (tagPtr->lMargin2String != NULL) {
334                  if (Tk_GetPixels(interp, textPtr->tkwin,                  if (Tk_GetPixels(interp, textPtr->tkwin,
335                          tagPtr->lMargin2String, &tagPtr->lMargin2) != TCL_OK) {                          tagPtr->lMargin2String, &tagPtr->lMargin2) != TCL_OK) {
336                      return TCL_ERROR;                      return TCL_ERROR;
337                  }                  }
338              }              }
339              if (tagPtr->offsetString != NULL) {              if (tagPtr->offsetString != NULL) {
340                  if (Tk_GetPixels(interp, textPtr->tkwin, tagPtr->offsetString,                  if (Tk_GetPixels(interp, textPtr->tkwin, tagPtr->offsetString,
341                          &tagPtr->offset) != TCL_OK) {                          &tagPtr->offset) != TCL_OK) {
342                      return TCL_ERROR;                      return TCL_ERROR;
343                  }                  }
344              }              }
345              if (tagPtr->overstrikeString != NULL) {              if (tagPtr->overstrikeString != NULL) {
346                  if (Tcl_GetBoolean(interp, tagPtr->overstrikeString,                  if (Tcl_GetBoolean(interp, tagPtr->overstrikeString,
347                          &tagPtr->overstrike) != TCL_OK) {                          &tagPtr->overstrike) != TCL_OK) {
348                      return TCL_ERROR;                      return TCL_ERROR;
349                  }                  }
350              }              }
351              if (tagPtr->rMarginString != NULL) {              if (tagPtr->rMarginString != NULL) {
352                  if (Tk_GetPixels(interp, textPtr->tkwin,                  if (Tk_GetPixels(interp, textPtr->tkwin,
353                          tagPtr->rMarginString, &tagPtr->rMargin) != TCL_OK) {                          tagPtr->rMarginString, &tagPtr->rMargin) != TCL_OK) {
354                      return TCL_ERROR;                      return TCL_ERROR;
355                  }                  }
356              }              }
357              if (tagPtr->spacing1String != NULL) {              if (tagPtr->spacing1String != NULL) {
358                  if (Tk_GetPixels(interp, textPtr->tkwin,                  if (Tk_GetPixels(interp, textPtr->tkwin,
359                          tagPtr->spacing1String, &tagPtr->spacing1) != TCL_OK) {                          tagPtr->spacing1String, &tagPtr->spacing1) != TCL_OK) {
360                      return TCL_ERROR;                      return TCL_ERROR;
361                  }                  }
362                  if (tagPtr->spacing1 < 0) {                  if (tagPtr->spacing1 < 0) {
363                      tagPtr->spacing1 = 0;                      tagPtr->spacing1 = 0;
364                  }                  }
365              }              }
366              if (tagPtr->spacing2String != NULL) {              if (tagPtr->spacing2String != NULL) {
367                  if (Tk_GetPixels(interp, textPtr->tkwin,                  if (Tk_GetPixels(interp, textPtr->tkwin,
368                          tagPtr->spacing2String, &tagPtr->spacing2) != TCL_OK) {                          tagPtr->spacing2String, &tagPtr->spacing2) != TCL_OK) {
369                      return TCL_ERROR;                      return TCL_ERROR;
370                  }                  }
371                  if (tagPtr->spacing2 < 0) {                  if (tagPtr->spacing2 < 0) {
372                      tagPtr->spacing2 = 0;                      tagPtr->spacing2 = 0;
373                  }                  }
374              }              }
375              if (tagPtr->spacing3String != NULL) {              if (tagPtr->spacing3String != NULL) {
376                  if (Tk_GetPixels(interp, textPtr->tkwin,                  if (Tk_GetPixels(interp, textPtr->tkwin,
377                          tagPtr->spacing3String, &tagPtr->spacing3) != TCL_OK) {                          tagPtr->spacing3String, &tagPtr->spacing3) != TCL_OK) {
378                      return TCL_ERROR;                      return TCL_ERROR;
379                  }                  }
380                  if (tagPtr->spacing3 < 0) {                  if (tagPtr->spacing3 < 0) {
381                      tagPtr->spacing3 = 0;                      tagPtr->spacing3 = 0;
382                  }                  }
383              }              }
384              if (tagPtr->tabArrayPtr != NULL) {              if (tagPtr->tabArrayPtr != NULL) {
385                  ckfree((char *) tagPtr->tabArrayPtr);                  ckfree((char *) tagPtr->tabArrayPtr);
386                  tagPtr->tabArrayPtr = NULL;                  tagPtr->tabArrayPtr = NULL;
387              }              }
388              if (tagPtr->tabString != NULL) {              if (tagPtr->tabString != NULL) {
389                  tagPtr->tabArrayPtr = TkTextGetTabs(interp, textPtr->tkwin,                  tagPtr->tabArrayPtr = TkTextGetTabs(interp, textPtr->tkwin,
390                          tagPtr->tabString);                          tagPtr->tabString);
391                  if (tagPtr->tabArrayPtr == NULL) {                  if (tagPtr->tabArrayPtr == NULL) {
392                      return TCL_ERROR;                      return TCL_ERROR;
393                  }                  }
394              }              }
395              if (tagPtr->underlineString != NULL) {              if (tagPtr->underlineString != NULL) {
396                  if (Tcl_GetBoolean(interp, tagPtr->underlineString,                  if (Tcl_GetBoolean(interp, tagPtr->underlineString,
397                          &tagPtr->underline) != TCL_OK) {                          &tagPtr->underline) != TCL_OK) {
398                      return TCL_ERROR;                      return TCL_ERROR;
399                  }                  }
400              }              }
401              if (tagPtr->elideString != NULL) {              if (tagPtr->elideString != NULL) {
402                  if (Tcl_GetBoolean(interp, tagPtr->elideString,                  if (Tcl_GetBoolean(interp, tagPtr->elideString,
403                          &tagPtr->elide) != TCL_OK) {                          &tagPtr->elide) != TCL_OK) {
404                      return TCL_ERROR;                      return TCL_ERROR;
405                  }                  }
406              }              }
407    
408              /*              /*
409               * If the "sel" tag was changed, be sure to mirror information               * If the "sel" tag was changed, be sure to mirror information
410               * from the tag back into the text widget record.   NOTE: we               * from the tag back into the text widget record.   NOTE: we
411               * don't have to free up information in the widget record               * don't have to free up information in the widget record
412               * before overwriting it, because it was mirrored in the tag               * before overwriting it, because it was mirrored in the tag
413               * and hence freed when the tag field was overwritten.               * and hence freed when the tag field was overwritten.
414               */               */
415    
416              if (tagPtr == textPtr->selTagPtr) {              if (tagPtr == textPtr->selTagPtr) {
417                  textPtr->selBorder = tagPtr->border;                  textPtr->selBorder = tagPtr->border;
418                  textPtr->selBdString = tagPtr->bdString;                  textPtr->selBdString = tagPtr->bdString;
419                  textPtr->selFgColorPtr = tagPtr->fgColor;                  textPtr->selFgColorPtr = tagPtr->fgColor;
420              }              }
421              tagPtr->affectsDisplay = 0;              tagPtr->affectsDisplay = 0;
422              if ((tagPtr->border != NULL)              if ((tagPtr->border != NULL)
423                      || (tagPtr->bdString != NULL)                      || (tagPtr->bdString != NULL)
424                      || (tagPtr->reliefString != NULL)                      || (tagPtr->reliefString != NULL)
425                      || (tagPtr->bgStipple != None)                      || (tagPtr->bgStipple != None)
426                      || (tagPtr->fgColor != NULL) || (tagPtr->tkfont != None)                      || (tagPtr->fgColor != NULL) || (tagPtr->tkfont != None)
427                      || (tagPtr->fgStipple != None)                      || (tagPtr->fgStipple != None)
428                      || (tagPtr->justifyString != NULL)                      || (tagPtr->justifyString != NULL)
429                      || (tagPtr->lMargin1String != NULL)                      || (tagPtr->lMargin1String != NULL)
430                      || (tagPtr->lMargin2String != NULL)                      || (tagPtr->lMargin2String != NULL)
431                      || (tagPtr->offsetString != NULL)                      || (tagPtr->offsetString != NULL)
432                      || (tagPtr->overstrikeString != NULL)                      || (tagPtr->overstrikeString != NULL)
433                      || (tagPtr->rMarginString != NULL)                      || (tagPtr->rMarginString != NULL)
434                      || (tagPtr->spacing1String != NULL)                      || (tagPtr->spacing1String != NULL)
435                      || (tagPtr->spacing2String != NULL)                      || (tagPtr->spacing2String != NULL)
436                      || (tagPtr->spacing3String != NULL)                      || (tagPtr->spacing3String != NULL)
437                      || (tagPtr->tabString != NULL)                      || (tagPtr->tabString != NULL)
438                      || (tagPtr->underlineString != NULL)                      || (tagPtr->underlineString != NULL)
439                      || (tagPtr->elideString != NULL)                      || (tagPtr->elideString != NULL)
440                      || (tagPtr->wrapMode != TEXT_WRAPMODE_NULL)) {                      || (tagPtr->wrapMode != TEXT_WRAPMODE_NULL)) {
441                  tagPtr->affectsDisplay = 1;                  tagPtr->affectsDisplay = 1;
442              }              }
443              TkTextRedrawTag(textPtr, (TkTextIndex *) NULL,              TkTextRedrawTag(textPtr, (TkTextIndex *) NULL,
444                      (TkTextIndex *) NULL, tagPtr, 1);                      (TkTextIndex *) NULL, tagPtr, 1);
445              return result;              return result;
446          }          }
447      } else if ((c == 'd') && (strncmp(argv[2], "delete", length) == 0)) {      } else if ((c == 'd') && (strncmp(argv[2], "delete", length) == 0)) {
448          Tcl_HashEntry *hPtr;          Tcl_HashEntry *hPtr;
449    
450          if (argc < 4) {          if (argc < 4) {
451              Tcl_AppendResult(interp, "wrong # args: should be \"",              Tcl_AppendResult(interp, "wrong # args: should be \"",
452                      argv[0], " tag delete tagName tagName ...\"",                      argv[0], " tag delete tagName tagName ...\"",
453                      (char *) NULL);                      (char *) NULL);
454              return TCL_ERROR;              return TCL_ERROR;
455          }          }
456          for (i = 3; i < argc; i++) {          for (i = 3; i < argc; i++) {
457              hPtr = Tcl_FindHashEntry(&textPtr->tagTable, argv[i]);              hPtr = Tcl_FindHashEntry(&textPtr->tagTable, argv[i]);
458              if (hPtr == NULL) {              if (hPtr == NULL) {
459                  continue;                  continue;
460              }              }
461              tagPtr = (TkTextTag *) Tcl_GetHashValue(hPtr);              tagPtr = (TkTextTag *) Tcl_GetHashValue(hPtr);
462              if (tagPtr == textPtr->selTagPtr) {              if (tagPtr == textPtr->selTagPtr) {
463                  continue;                  continue;
464              }              }
465              if (tagPtr->affectsDisplay) {              if (tagPtr->affectsDisplay) {
466                  TkTextRedrawTag(textPtr, (TkTextIndex *) NULL,                  TkTextRedrawTag(textPtr, (TkTextIndex *) NULL,
467                          (TkTextIndex *) NULL, tagPtr, 1);                          (TkTextIndex *) NULL, tagPtr, 1);
468              }              }
469              TkTextMakeByteIndex(textPtr->tree, 0, 0, &first);              TkTextMakeByteIndex(textPtr->tree, 0, 0, &first);
470              TkTextMakeByteIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree),              TkTextMakeByteIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree),
471                      0, &last),                      0, &last),
472              TkBTreeTag(&first, &last, tagPtr, 0);              TkBTreeTag(&first, &last, tagPtr, 0);
473              Tcl_DeleteHashEntry(hPtr);              Tcl_DeleteHashEntry(hPtr);
474              if (textPtr->bindingTable != NULL) {              if (textPtr->bindingTable != NULL) {
475                  Tk_DeleteAllBindings(textPtr->bindingTable,                  Tk_DeleteAllBindings(textPtr->bindingTable,
476                          (ClientData) tagPtr);                          (ClientData) tagPtr);
477              }              }
478                    
479              /*              /*
480               * Update the tag priorities to reflect the deletion of this tag.               * Update the tag priorities to reflect the deletion of this tag.
481               */               */
482    
483              ChangeTagPriority(textPtr, tagPtr, textPtr->numTags-1);              ChangeTagPriority(textPtr, tagPtr, textPtr->numTags-1);
484              textPtr->numTags -= 1;              textPtr->numTags -= 1;
485              TkTextFreeTag(textPtr, tagPtr);              TkTextFreeTag(textPtr, tagPtr);
486          }          }
487      } else if ((c == 'l') && (strncmp(argv[2], "lower", length) == 0)) {      } else if ((c == 'l') && (strncmp(argv[2], "lower", length) == 0)) {
488          TkTextTag *tagPtr2;          TkTextTag *tagPtr2;
489          int prio;          int prio;
490    
491          if ((argc != 4) && (argc != 5)) {          if ((argc != 4) && (argc != 5)) {
492              Tcl_AppendResult(interp, "wrong # args: should be \"",              Tcl_AppendResult(interp, "wrong # args: should be \"",
493                      argv[0], " tag lower tagName ?belowThis?\"",                      argv[0], " tag lower tagName ?belowThis?\"",
494                      (char *) NULL);                      (char *) NULL);
495              return TCL_ERROR;              return TCL_ERROR;
496          }          }
497          tagPtr = FindTag(interp, textPtr, argv[3]);          tagPtr = FindTag(interp, textPtr, argv[3]);
498          if (tagPtr == NULL) {          if (tagPtr == NULL) {
499              return TCL_ERROR;              return TCL_ERROR;
500          }          }
501          if (argc == 5) {          if (argc == 5) {
502              tagPtr2 = FindTag(interp, textPtr, argv[4]);              tagPtr2 = FindTag(interp, textPtr, argv[4]);
503              if (tagPtr2 == NULL) {              if (tagPtr2 == NULL) {
504                  return TCL_ERROR;                  return TCL_ERROR;
505              }              }
506              if (tagPtr->priority < tagPtr2->priority) {              if (tagPtr->priority < tagPtr2->priority) {
507                  prio = tagPtr2->priority - 1;                  prio = tagPtr2->priority - 1;
508              } else {              } else {
509                  prio = tagPtr2->priority;                  prio = tagPtr2->priority;
510              }              }
511          } else {          } else {
512              prio = 0;              prio = 0;
513          }          }
514          ChangeTagPriority(textPtr, tagPtr, prio);          ChangeTagPriority(textPtr, tagPtr, prio);
515          TkTextRedrawTag(textPtr, (TkTextIndex *) NULL, (TkTextIndex *) NULL,          TkTextRedrawTag(textPtr, (TkTextIndex *) NULL, (TkTextIndex *) NULL,
516                  tagPtr, 1);                  tagPtr, 1);
517      } else if ((c == 'n') && (strncmp(argv[2], "names", length) == 0)      } else if ((c == 'n') && (strncmp(argv[2], "names", length) == 0)
518              && (length >= 2)) {              && (length >= 2)) {
519          TkTextTag **arrayPtr;          TkTextTag **arrayPtr;
520          int arraySize;          int arraySize;
521    
522          if ((argc != 3) && (argc != 4)) {          if ((argc != 3) && (argc != 4)) {
523              Tcl_AppendResult(interp, "wrong # args: should be \"",              Tcl_AppendResult(interp, "wrong # args: should be \"",
524                      argv[0], " tag names ?index?\"",                      argv[0], " tag names ?index?\"",
525                      (char *) NULL);                      (char *) NULL);
526              return TCL_ERROR;              return TCL_ERROR;
527          }          }
528          if (argc == 3) {          if (argc == 3) {
529              Tcl_HashSearch search;              Tcl_HashSearch search;
530              Tcl_HashEntry *hPtr;              Tcl_HashEntry *hPtr;
531    
532              arrayPtr = (TkTextTag **) ckalloc((unsigned)              arrayPtr = (TkTextTag **) ckalloc((unsigned)
533                      (textPtr->numTags * sizeof(TkTextTag *)));                      (textPtr->numTags * sizeof(TkTextTag *)));
534              for (i = 0, hPtr = Tcl_FirstHashEntry(&textPtr->tagTable, &search);              for (i = 0, hPtr = Tcl_FirstHashEntry(&textPtr->tagTable, &search);
535                      hPtr != NULL; i++, hPtr = Tcl_NextHashEntry(&search)) {                      hPtr != NULL; i++, hPtr = Tcl_NextHashEntry(&search)) {
536                  arrayPtr[i] = (TkTextTag *) Tcl_GetHashValue(hPtr);                  arrayPtr[i] = (TkTextTag *) Tcl_GetHashValue(hPtr);
537              }              }
538              arraySize = textPtr->numTags;              arraySize = textPtr->numTags;
539          } else {          } else {
540              if (TkTextGetIndex(interp, textPtr, argv[3], &index1)              if (TkTextGetIndex(interp, textPtr, argv[3], &index1)
541                      != TCL_OK) {                      != TCL_OK) {
542                  return TCL_ERROR;                  return TCL_ERROR;
543              }              }
544              arrayPtr = TkBTreeGetTags(&index1, &arraySize);              arrayPtr = TkBTreeGetTags(&index1, &arraySize);
545              if (arrayPtr == NULL) {              if (arrayPtr == NULL) {
546                  return TCL_OK;                  return TCL_OK;
547              }              }
548          }          }
549          SortTags(arraySize, arrayPtr);          SortTags(arraySize, arrayPtr);
550          for (i = 0; i < arraySize; i++) {          for (i = 0; i < arraySize; i++) {
551              tagPtr = arrayPtr[i];              tagPtr = arrayPtr[i];
552              Tcl_AppendElement(interp, tagPtr->name);              Tcl_AppendElement(interp, tagPtr->name);
553          }          }
554          ckfree((char *) arrayPtr);          ckfree((char *) arrayPtr);
555      } else if ((c == 'n') && (strncmp(argv[2], "nextrange", length) == 0)      } else if ((c == 'n') && (strncmp(argv[2], "nextrange", length) == 0)
556              && (length >= 2)) {              && (length >= 2)) {
557          TkTextSearch tSearch;          TkTextSearch tSearch;
558          char position[TK_POS_CHARS];          char position[TK_POS_CHARS];
559    
560          if ((argc != 5) && (argc != 6)) {          if ((argc != 5) && (argc != 6)) {
561              Tcl_AppendResult(interp, "wrong # args: should be \"",              Tcl_AppendResult(interp, "wrong # args: should be \"",
562                      argv[0], " tag nextrange tagName index1 ?index2?\"",                      argv[0], " tag nextrange tagName index1 ?index2?\"",
563                      (char *) NULL);                      (char *) NULL);
564              return TCL_ERROR;              return TCL_ERROR;
565          }          }
566          tagPtr = FindTag((Tcl_Interp *) NULL, textPtr, argv[3]);          tagPtr = FindTag((Tcl_Interp *) NULL, textPtr, argv[3]);
567          if (tagPtr == NULL) {          if (tagPtr == NULL) {
568              return TCL_OK;              return TCL_OK;
569          }          }
570          if (TkTextGetIndex(interp, textPtr, argv[4], &index1) != TCL_OK) {          if (TkTextGetIndex(interp, textPtr, argv[4], &index1) != TCL_OK) {
571              return TCL_ERROR;              return TCL_ERROR;
572          }          }
573          TkTextMakeByteIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree),          TkTextMakeByteIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree),
574                  0, &last);                  0, &last);
575          if (argc == 5) {          if (argc == 5) {
576              index2 = last;              index2 = last;
577          } else if (TkTextGetIndex(interp, textPtr, argv[5], &index2)          } else if (TkTextGetIndex(interp, textPtr, argv[5], &index2)
578                  != TCL_OK) {                  != TCL_OK) {
579              return TCL_ERROR;              return TCL_ERROR;
580          }          }
581    
582          /*          /*
583           * The search below is a bit tricky.  Rather than use the B-tree           * The search below is a bit tricky.  Rather than use the B-tree
584           * facilities to stop the search at index2, let it search up           * facilities to stop the search at index2, let it search up
585           * until the end of the file but check for a position past index2           * until the end of the file but check for a position past index2
586           * ourselves.  The reason for doing it this way is that we only           * ourselves.  The reason for doing it this way is that we only
587           * care whether the *start* of the range is before index2;  once           * care whether the *start* of the range is before index2;  once
588           * we find the start, we don't want TkBTreeNextTag to abort the           * we find the start, we don't want TkBTreeNextTag to abort the
589           * search because the end of the range is after index2.           * search because the end of the range is after index2.
590           */           */
591    
592          TkBTreeStartSearch(&index1, &last, tagPtr, &tSearch);          TkBTreeStartSearch(&index1, &last, tagPtr, &tSearch);
593          if (TkBTreeCharTagged(&index1, tagPtr)) {          if (TkBTreeCharTagged(&index1, tagPtr)) {
594              TkTextSegment *segPtr;              TkTextSegment *segPtr;
595              int offset;              int offset;
596    
597              /*              /*
598               * The first character is tagged.  See if there is an               * The first character is tagged.  See if there is an
599               * on-toggle just before the character.  If not, then               * on-toggle just before the character.  If not, then
600               * skip to the end of this tagged range.               * skip to the end of this tagged range.
601               */               */
602    
603              for (segPtr = index1.linePtr->segPtr, offset = index1.byteIndex;              for (segPtr = index1.linePtr->segPtr, offset = index1.byteIndex;
604                      offset >= 0;                      offset >= 0;
605                      offset -= segPtr->size, segPtr = segPtr->nextPtr) {                      offset -= segPtr->size, segPtr = segPtr->nextPtr) {
606                  if ((offset == 0) && (segPtr->typePtr == &tkTextToggleOnType)                  if ((offset == 0) && (segPtr->typePtr == &tkTextToggleOnType)
607                          && (segPtr->body.toggle.tagPtr == tagPtr)) {                          && (segPtr->body.toggle.tagPtr == tagPtr)) {
608                      goto gotStart;                      goto gotStart;
609                  }                  }
610              }              }
611              if (!TkBTreeNextTag(&tSearch)) {              if (!TkBTreeNextTag(&tSearch)) {
612                   return TCL_OK;                   return TCL_OK;
613              }              }
614          }          }
615    
616          /*          /*
617           * Find the start of the tagged range.           * Find the start of the tagged range.
618           */           */
619    
620          if (!TkBTreeNextTag(&tSearch)) {          if (!TkBTreeNextTag(&tSearch)) {
621              return TCL_OK;              return TCL_OK;
622          }          }
623          gotStart:          gotStart:
624          if (TkTextIndexCmp(&tSearch.curIndex, &index2) >= 0) {          if (TkTextIndexCmp(&tSearch.curIndex, &index2) >= 0) {
625              return TCL_OK;              return TCL_OK;
626          }          }
627          TkTextPrintIndex(&tSearch.curIndex, position);          TkTextPrintIndex(&tSearch.curIndex, position);
628          Tcl_AppendElement(interp, position);          Tcl_AppendElement(interp, position);
629          TkBTreeNextTag(&tSearch);          TkBTreeNextTag(&tSearch);
630          TkTextPrintIndex(&tSearch.curIndex, position);          TkTextPrintIndex(&tSearch.curIndex, position);
631          Tcl_AppendElement(interp, position);          Tcl_AppendElement(interp, position);
632      } else if ((c == 'p') && (strncmp(argv[2], "prevrange", length) == 0)      } else if ((c == 'p') && (strncmp(argv[2], "prevrange", length) == 0)
633              && (length >= 2)) {              && (length >= 2)) {
634          TkTextSearch tSearch;          TkTextSearch tSearch;
635          char position1[TK_POS_CHARS];          char position1[TK_POS_CHARS];
636          char position2[TK_POS_CHARS];          char position2[TK_POS_CHARS];
637    
638          if ((argc != 5) && (argc != 6)) {          if ((argc != 5) && (argc != 6)) {
639              Tcl_AppendResult(interp, "wrong # args: should be \"",              Tcl_AppendResult(interp, "wrong # args: should be \"",
640                      argv[0], " tag prevrange tagName index1 ?index2?\"",                      argv[0], " tag prevrange tagName index1 ?index2?\"",
641                      (char *) NULL);                      (char *) NULL);
642              return TCL_ERROR;              return TCL_ERROR;
643          }          }
644          tagPtr = FindTag((Tcl_Interp *) NULL, textPtr, argv[3]);          tagPtr = FindTag((Tcl_Interp *) NULL, textPtr, argv[3]);
645          if (tagPtr == NULL) {          if (tagPtr == NULL) {
646              return TCL_OK;              return TCL_OK;
647          }          }
648          if (TkTextGetIndex(interp, textPtr, argv[4], &index1) != TCL_OK) {          if (TkTextGetIndex(interp, textPtr, argv[4], &index1) != TCL_OK) {
649              return TCL_ERROR;              return TCL_ERROR;
650          }          }
651          if (argc == 5) {          if (argc == 5) {
652              TkTextMakeByteIndex(textPtr->tree, 0, 0, &index2);              TkTextMakeByteIndex(textPtr->tree, 0, 0, &index2);
653          } else if (TkTextGetIndex(interp, textPtr, argv[5], &index2)          } else if (TkTextGetIndex(interp, textPtr, argv[5], &index2)
654                  != TCL_OK) {                  != TCL_OK) {
655              return TCL_ERROR;              return TCL_ERROR;
656          }          }
657    
658          /*          /*
659           * The search below is a bit weird.  The previous toggle can be           * The search below is a bit weird.  The previous toggle can be
660           * either an on or off toggle. If it is an on toggle, then we           * either an on or off toggle. If it is an on toggle, then we
661           * need to turn around and search forward for the end toggle.           * need to turn around and search forward for the end toggle.
662           * Otherwise we keep searching backwards.           * Otherwise we keep searching backwards.
663           */           */
664    
665          TkBTreeStartSearchBack(&index1, &index2, tagPtr, &tSearch);          TkBTreeStartSearchBack(&index1, &index2, tagPtr, &tSearch);
666    
667          if (!TkBTreePrevTag(&tSearch)) {          if (!TkBTreePrevTag(&tSearch)) {
668              return TCL_OK;              return TCL_OK;
669          }          }
670          if (tSearch.segPtr->typePtr == &tkTextToggleOnType) {          if (tSearch.segPtr->typePtr == &tkTextToggleOnType) {
671              TkTextPrintIndex(&tSearch.curIndex, position1);              TkTextPrintIndex(&tSearch.curIndex, position1);
672              TkTextMakeByteIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree),              TkTextMakeByteIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree),
673                      0, &last);                      0, &last);
674              TkBTreeStartSearch(&tSearch.curIndex, &last, tagPtr, &tSearch);              TkBTreeStartSearch(&tSearch.curIndex, &last, tagPtr, &tSearch);
675              TkBTreeNextTag(&tSearch);              TkBTreeNextTag(&tSearch);
676              TkTextPrintIndex(&tSearch.curIndex, position2);              TkTextPrintIndex(&tSearch.curIndex, position2);
677          } else {          } else {
678              TkTextPrintIndex(&tSearch.curIndex, position2);              TkTextPrintIndex(&tSearch.curIndex, position2);
679              TkBTreePrevTag(&tSearch);              TkBTreePrevTag(&tSearch);
680              if (TkTextIndexCmp(&tSearch.curIndex, &index2) < 0) {              if (TkTextIndexCmp(&tSearch.curIndex, &index2) < 0) {
681                  return TCL_OK;                  return TCL_OK;
682              }              }
683              TkTextPrintIndex(&tSearch.curIndex, position1);              TkTextPrintIndex(&tSearch.curIndex, position1);
684          }          }
685          Tcl_AppendElement(interp, position1);          Tcl_AppendElement(interp, position1);
686          Tcl_AppendElement(interp, position2);          Tcl_AppendElement(interp, position2);
687      } else if ((c == 'r') && (strncmp(argv[2], "raise", length) == 0)      } else if ((c == 'r') && (strncmp(argv[2], "raise", length) == 0)
688              && (length >= 3)) {              && (length >= 3)) {
689          TkTextTag *tagPtr2;          TkTextTag *tagPtr2;
690          int prio;          int prio;
691    
692          if ((argc != 4) && (argc != 5)) {          if ((argc != 4) && (argc != 5)) {
693              Tcl_AppendResult(interp, "wrong # args: should be \"",              Tcl_AppendResult(interp, "wrong # args: should be \"",
694                      argv[0], " tag raise tagName ?aboveThis?\"",                      argv[0], " tag raise tagName ?aboveThis?\"",
695                      (char *) NULL);                      (char *) NULL);
696              return TCL_ERROR;              return TCL_ERROR;
697          }          }
698          tagPtr = FindTag(interp, textPtr, argv[3]);          tagPtr = FindTag(interp, textPtr, argv[3]);
699          if (tagPtr == NULL) {          if (tagPtr == NULL) {
700              return TCL_ERROR;              return TCL_ERROR;
701          }          }
702          if (argc == 5) {          if (argc == 5) {
703              tagPtr2 = FindTag(interp, textPtr, argv[4]);              tagPtr2 = FindTag(interp, textPtr, argv[4]);
704              if (tagPtr2 == NULL) {              if (tagPtr2 == NULL) {
705                  return TCL_ERROR;                  return TCL_ERROR;
706              }              }
707              if (tagPtr->priority <= tagPtr2->priority) {              if (tagPtr->priority <= tagPtr2->priority) {
708                  prio = tagPtr2->priority;                  prio = tagPtr2->priority;
709              } else {              } else {
710                  prio = tagPtr2->priority + 1;                  prio = tagPtr2->priority + 1;
711              }              }
712          } else {          } else {
713              prio = textPtr->numTags-1;              prio = textPtr->numTags-1;
714          }          }
715          ChangeTagPriority(textPtr, tagPtr, prio);          ChangeTagPriority(textPtr, tagPtr, prio);
716          TkTextRedrawTag(textPtr, (TkTextIndex *) NULL, (TkTextIndex *) NULL,          TkTextRedrawTag(textPtr, (TkTextIndex *) NULL, (TkTextIndex *) NULL,
717                  tagPtr, 1);                  tagPtr, 1);
718      } else if ((c == 'r') && (strncmp(argv[2], "ranges", length) == 0)      } else if ((c == 'r') && (strncmp(argv[2], "ranges", length) == 0)
719              && (length >= 3)) {              && (length >= 3)) {
720          TkTextSearch tSearch;          TkTextSearch tSearch;
721          char position[TK_POS_CHARS];          char position[TK_POS_CHARS];
722    
723          if (argc != 4) {          if (argc != 4) {
724              Tcl_AppendResult(interp, "wrong # args: should be \"",              Tcl_AppendResult(interp, "wrong # args: should be \"",
725                      argv[0], " tag ranges tagName\"", (char *) NULL);                      argv[0], " tag ranges tagName\"", (char *) NULL);
726              return TCL_ERROR;              return TCL_ERROR;
727          }          }
728          tagPtr = FindTag((Tcl_Interp *) NULL, textPtr, argv[3]);          tagPtr = FindTag((Tcl_Interp *) NULL, textPtr, argv[3]);
729          if (tagPtr == NULL) {          if (tagPtr == NULL) {
730              return TCL_OK;              return TCL_OK;
731          }          }
732          TkTextMakeByteIndex(textPtr->tree, 0, 0, &first);          TkTextMakeByteIndex(textPtr->tree, 0, 0, &first);
733          TkTextMakeByteIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree),          TkTextMakeByteIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree),
734                  0, &last);                  0, &last);
735          TkBTreeStartSearch(&first, &last, tagPtr, &tSearch);          TkBTreeStartSearch(&first, &last, tagPtr, &tSearch);
736          if (TkBTreeCharTagged(&first, tagPtr)) {          if (TkBTreeCharTagged(&first, tagPtr)) {
737              TkTextPrintIndex(&first, position);              TkTextPrintIndex(&first, position);
738              Tcl_AppendElement(interp, position);              Tcl_AppendElement(interp, position);
739          }          }
740          while (TkBTreeNextTag(&tSearch)) {          while (TkBTreeNextTag(&tSearch)) {
741              TkTextPrintIndex(&tSearch.curIndex, position);              TkTextPrintIndex(&tSearch.curIndex, position);
742              Tcl_AppendElement(interp, position);              Tcl_AppendElement(interp, position);
743          }          }
744      } else if ((c == 'r') && (strncmp(argv[2], "remove", length) == 0)      } else if ((c == 'r') && (strncmp(argv[2], "remove", length) == 0)
745              && (length >= 2)) {              && (length >= 2)) {
746          fullOption = "remove";          fullOption = "remove";
747          addTag = 0;          addTag = 0;
748          goto addAndRemove;          goto addAndRemove;
749      } else {      } else {
750          Tcl_AppendResult(interp, "bad tag option \"", argv[2],          Tcl_AppendResult(interp, "bad tag option \"", argv[2],
751                  "\": must be add, bind, cget, configure, delete, lower, ",                  "\": must be add, bind, cget, configure, delete, lower, ",
752                  "names, nextrange, raise, ranges, or remove",                  "names, nextrange, raise, ranges, or remove",
753                  (char *) NULL);                  (char *) NULL);
754          return TCL_ERROR;          return TCL_ERROR;
755      }      }
756      return TCL_OK;      return TCL_OK;
757  }  }
758    
759  /*  /*
760   *----------------------------------------------------------------------   *----------------------------------------------------------------------
761   *   *
762   * TkTextCreateTag --   * TkTextCreateTag --
763   *   *
764   *      Find the record describing a tag within a given text widget,   *      Find the record describing a tag within a given text widget,
765   *      creating a new record if one doesn't already exist.   *      creating a new record if one doesn't already exist.
766   *   *
767   * Results:   * Results:
768   *      The return value is a pointer to the TkTextTag record for tagName.   *      The return value is a pointer to the TkTextTag record for tagName.
769   *   *
770   * Side effects:   * Side effects:
771   *      A new tag record is created if there isn't one already defined   *      A new tag record is created if there isn't one already defined
772   *      for tagName.   *      for tagName.
773   *   *
774   *----------------------------------------------------------------------   *----------------------------------------------------------------------
775   */   */
776    
777  TkTextTag *  TkTextTag *
778  TkTextCreateTag(textPtr, tagName)  TkTextCreateTag(textPtr, tagName)
779      TkText *textPtr;            /* Widget in which tag is being used. */      TkText *textPtr;            /* Widget in which tag is being used. */
780      char *tagName;              /* Name of desired tag. */      char *tagName;              /* Name of desired tag. */
781  {  {
782      register TkTextTag *tagPtr;      register TkTextTag *tagPtr;
783      Tcl_HashEntry *hPtr;      Tcl_HashEntry *hPtr;
784      int new;      int new;
785    
786      hPtr = Tcl_CreateHashEntry(&textPtr->tagTable, tagName, &new);      hPtr = Tcl_CreateHashEntry(&textPtr->tagTable, tagName, &new);
787      if (!new) {      if (!new) {
788          return (TkTextTag *) Tcl_GetHashValue(hPtr);          return (TkTextTag *) Tcl_GetHashValue(hPtr);
789      }      }
790    
791      /*      /*
792       * No existing entry.  Create a new one, initialize it, and add a       * No existing entry.  Create a new one, initialize it, and add a
793       * pointer to it to the hash table entry.       * pointer to it to the hash table entry.
794       */       */
795    
796      tagPtr = (TkTextTag *) ckalloc(sizeof(TkTextTag));      tagPtr = (TkTextTag *) ckalloc(sizeof(TkTextTag));
797      tagPtr->name = Tcl_GetHashKey(&textPtr->tagTable, hPtr);      tagPtr->name = Tcl_GetHashKey(&textPtr->tagTable, hPtr);
798      tagPtr->toggleCount = 0;      tagPtr->toggleCount = 0;
799      tagPtr->tagRootPtr = NULL;      tagPtr->tagRootPtr = NULL;
800      tagPtr->priority = textPtr->numTags;      tagPtr->priority = textPtr->numTags;
801      tagPtr->border = NULL;      tagPtr->border = NULL;
802      tagPtr->bdString = NULL;      tagPtr->bdString = NULL;
803      tagPtr->borderWidth = 0;      tagPtr->borderWidth = 0;
804      tagPtr->reliefString = NULL;      tagPtr->reliefString = NULL;
805      tagPtr->relief = TK_RELIEF_FLAT;      tagPtr->relief = TK_RELIEF_FLAT;
806      tagPtr->bgStipple = None;      tagPtr->bgStipple = None;
807      tagPtr->fgColor = NULL;      tagPtr->fgColor = NULL;
808      tagPtr->tkfont = NULL;      tagPtr->tkfont = NULL;
809      tagPtr->fgStipple = None;      tagPtr->fgStipple = None;
810      tagPtr->justifyString = NULL;      tagPtr->justifyString = NULL;
811      tagPtr->justify = TK_JUSTIFY_LEFT;      tagPtr->justify = TK_JUSTIFY_LEFT;
812      tagPtr->lMargin1String = NULL;      tagPtr->lMargin1String = NULL;
813      tagPtr->lMargin1 = 0;      tagPtr->lMargin1 = 0;
814      tagPtr->lMargin2String = NULL;      tagPtr->lMargin2String = NULL;
815      tagPtr->lMargin2 = 0;      tagPtr->lMargin2 = 0;
816      tagPtr->offsetString = NULL;      tagPtr->offsetString = NULL;
817      tagPtr->offset = 0;      tagPtr->offset = 0;
818      tagPtr->overstrikeString = NULL;      tagPtr->overstrikeString = NULL;
819      tagPtr->overstrike = 0;      tagPtr->overstrike = 0;
820      tagPtr->rMarginString = NULL;      tagPtr->rMarginString = NULL;
821      tagPtr->rMargin = 0;      tagPtr->rMargin = 0;
822      tagPtr->spacing1String = NULL;      tagPtr->spacing1String = NULL;
823      tagPtr->spacing1 = 0;      tagPtr->spacing1 = 0;
824      tagPtr->spacing2String = NULL;      tagPtr->spacing2String = NULL;
825      tagPtr->spacing2 = 0;      tagPtr->spacing2 = 0;
826      tagPtr->spacing3String = NULL;      tagPtr->spacing3String = NULL;
827      tagPtr->spacing3 = 0;      tagPtr->spacing3 = 0;
828      tagPtr->tabString = NULL;      tagPtr->tabString = NULL;
829      tagPtr->tabArrayPtr = NULL;      tagPtr->tabArrayPtr = NULL;
830      tagPtr->underlineString = NULL;      tagPtr->underlineString = NULL;
831      tagPtr->underline = 0;      tagPtr->underline = 0;
832      tagPtr->elideString = NULL;      tagPtr->elideString = NULL;
833      tagPtr->elide = 0;      tagPtr->elide = 0;
834      tagPtr->wrapMode = TEXT_WRAPMODE_NULL;      tagPtr->wrapMode = TEXT_WRAPMODE_NULL;
835      tagPtr->affectsDisplay = 0;      tagPtr->affectsDisplay = 0;
836      textPtr->numTags++;      textPtr->numTags++;
837      Tcl_SetHashValue(hPtr, tagPtr);      Tcl_SetHashValue(hPtr, tagPtr);
838      return tagPtr;      return tagPtr;
839  }  }
840    
841  /*  /*
842   *----------------------------------------------------------------------   *----------------------------------------------------------------------
843   *   *
844   * FindTag --   * FindTag --
845   *   *
846   *      See if tag is defined for a given widget.   *      See if tag is defined for a given widget.
847   *   *
848   * Results:   * Results:
849   *      If tagName is defined in textPtr, a pointer to its TkTextTag   *      If tagName is defined in textPtr, a pointer to its TkTextTag
850   *      structure is returned.  Otherwise NULL is returned and an   *      structure is returned.  Otherwise NULL is returned and an
851   *      error message is recorded in the interp's result unless interp   *      error message is recorded in the interp's result unless interp
852   *      is NULL.   *      is NULL.
853   *   *
854   * Side effects:   * Side effects:
855   *      None.   *      None.
856   *   *
857   *----------------------------------------------------------------------   *----------------------------------------------------------------------
858   */   */
859    
860  static TkTextTag *  static TkTextTag *
861  FindTag(interp, textPtr, tagName)  FindTag(interp, textPtr, tagName)
862      Tcl_Interp *interp;         /* Interpreter to use for error message;      Tcl_Interp *interp;         /* Interpreter to use for error message;
863                                   * if NULL, then don't record an error                                   * if NULL, then don't record an error
864                                   * message. */                                   * message. */
865      TkText *textPtr;            /* Widget in which tag is being used. */      TkText *textPtr;            /* Widget in which tag is being used. */
866      char *tagName;              /* Name of desired tag. */      char *tagName;              /* Name of desired tag. */
867  {  {
868      Tcl_HashEntry *hPtr;      Tcl_HashEntry *hPtr;
869    
870      hPtr = Tcl_FindHashEntry(&textPtr->tagTable, tagName);      hPtr = Tcl_FindHashEntry(&textPtr->tagTable, tagName);
871      if (hPtr != NULL) {      if (hPtr != NULL) {
872          return (TkTextTag *) Tcl_GetHashValue(hPtr);          return (TkTextTag *) Tcl_GetHashValue(hPtr);
873      }      }
874      if (interp != NULL) {      if (interp != NULL) {
875          Tcl_AppendResult(interp, "tag \"", tagName,          Tcl_AppendResult(interp, "tag \"", tagName,
876                  "\" isn't defined in text widget", (char *) NULL);                  "\" isn't defined in text widget", (char *) NULL);
877      }      }
878      return NULL;      return NULL;
879  }  }
880    
881  /*  /*
882   *----------------------------------------------------------------------   *----------------------------------------------------------------------
883   *   *
884   * TkTextFreeTag --   * TkTextFreeTag --
885   *   *
886   *      This procedure is called when a tag is deleted to free up the   *      This procedure is called when a tag is deleted to free up the
887   *      memory and other resources associated with the tag.   *      memory and other resources associated with the tag.
888   *   *
889   * Results:   * Results:
890   *      None.   *      None.
891   *   *
892   * Side effects:   * Side effects:
893   *      Memory and other resources are freed.   *      Memory and other resources are freed.
894   *   *
895   *----------------------------------------------------------------------   *----------------------------------------------------------------------
896   */   */
897    
898  void  void
899  TkTextFreeTag(textPtr, tagPtr)  TkTextFreeTag(textPtr, tagPtr)
900      TkText *textPtr;                    /* Info about overall widget. */      TkText *textPtr;                    /* Info about overall widget. */
901      register TkTextTag *tagPtr;         /* Tag being deleted. */      register TkTextTag *tagPtr;         /* Tag being deleted. */
902  {  {
903      if (tagPtr->border != None) {      if (tagPtr->border != None) {
904          Tk_Free3DBorder(tagPtr->border);          Tk_Free3DBorder(tagPtr->border);
905      }      }
906      if (tagPtr->bdString != NULL) {      if (tagPtr->bdString != NULL) {
907          ckfree(tagPtr->bdString);          ckfree(tagPtr->bdString);
908      }      }
909      if (tagPtr->reliefString != NULL) {      if (tagPtr->reliefString != NULL) {
910          ckfree(tagPtr->reliefString);          ckfree(tagPtr->reliefString);
911      }      }
912      if (tagPtr->bgStipple != None) {      if (tagPtr->bgStipple != None) {
913          Tk_FreeBitmap(textPtr->display, tagPtr->bgStipple);          Tk_FreeBitmap(textPtr->display, tagPtr->bgStipple);
914      }      }
915      if (tagPtr->fgColor != None) {      if (tagPtr->fgColor != None) {
916          Tk_FreeColor(tagPtr->fgColor);          Tk_FreeColor(tagPtr->fgColor);
917      }      }
918      Tk_FreeFont(tagPtr->tkfont);      Tk_FreeFont(tagPtr->tkfont);
919      if (tagPtr->fgStipple != None) {      if (tagPtr->fgStipple != None) {
920          Tk_FreeBitmap(textPtr->display, tagPtr->fgStipple);          Tk_FreeBitmap(textPtr->display, tagPtr->fgStipple);
921      }      }
922      if (tagPtr->justifyString != NULL) {      if (tagPtr->justifyString != NULL) {
923          ckfree(tagPtr->justifyString);          ckfree(tagPtr->justifyString);
924      }      }
925      if (tagPtr->lMargin1String != NULL) {      if (tagPtr->lMargin1String != NULL) {
926          ckfree(tagPtr->lMargin1String);          ckfree(tagPtr->lMargin1String);
927      }      }
928      if (tagPtr->lMargin2String != NULL) {      if (tagPtr->lMargin2String != NULL) {
929          ckfree(tagPtr->lMargin2String);          ckfree(tagPtr->lMargin2String);
930      }      }
931      if (tagPtr->offsetString != NULL) {      if (tagPtr->offsetString != NULL) {
932          ckfree(tagPtr->offsetString);          ckfree(tagPtr->offsetString);
933      }      }
934      if (tagPtr->overstrikeString != NULL) {      if (tagPtr->overstrikeString != NULL) {
935          ckfree(tagPtr->overstrikeString);          ckfree(tagPtr->overstrikeString);
936      }      }
937      if (tagPtr->rMarginString != NULL) {      if (tagPtr->rMarginString != NULL) {
938          ckfree(tagPtr->rMarginString);          ckfree(tagPtr->rMarginString);
939      }      }
940      if (tagPtr->spacing1String != NULL) {      if (tagPtr->spacing1String != NULL) {
941          ckfree(tagPtr->spacing1String);          ckfree(tagPtr->spacing1String);
942      }      }
943      if (tagPtr->spacing2String != NULL) {      if (tagPtr->spacing2String != NULL) {
944          ckfree(tagPtr->spacing2String);          ckfree(tagPtr->spacing2String);
945      }      }
946      if (tagPtr->spacing3String != NULL) {      if (tagPtr->spacing3String != NULL) {
947          ckfree(tagPtr->spacing3String);          ckfree(tagPtr->spacing3String);
948      }      }
949      if (tagPtr->tabString != NULL) {      if (tagPtr->tabString != NULL) {
950          ckfree(tagPtr->tabString);          ckfree(tagPtr->tabString);
951      }      }
952      if (tagPtr->tabArrayPtr != NULL) {      if (tagPtr->tabArrayPtr != NULL) {
953          ckfree((char *) tagPtr->tabArrayPtr);          ckfree((char *) tagPtr->tabArrayPtr);
954      }      }
955      if (tagPtr->underlineString != NULL) {      if (tagPtr->underlineString != NULL) {
956          ckfree(tagPtr->underlineString);          ckfree(tagPtr->underlineString);
957      }      }
958      ckfree((char *) tagPtr);      ckfree((char *) tagPtr);
959  }  }
960    
961  /*  /*
962   *----------------------------------------------------------------------   *----------------------------------------------------------------------
963   *   *
964   * SortTags --   * SortTags --
965   *   *
966   *      This procedure sorts an array of tag pointers in increasing   *      This procedure sorts an array of tag pointers in increasing
967   *      order of priority, optimizing for the common case where the   *      order of priority, optimizing for the common case where the
968   *      array is small.   *      array is small.
969   *   *
970   * Results:   * Results:
971   *      None.   *      None.
972   *   *
973   * Side effects:   * Side effects:
974   *      None.   *      None.
975   *   *
976   *----------------------------------------------------------------------   *----------------------------------------------------------------------
977   */   */
978    
979  static void  static void
980  SortTags(numTags, tagArrayPtr)  SortTags(numTags, tagArrayPtr)
981      int numTags;                /* Number of tag pointers at *tagArrayPtr. */      int numTags;                /* Number of tag pointers at *tagArrayPtr. */
982      TkTextTag **tagArrayPtr;    /* Pointer to array of pointers. */      TkTextTag **tagArrayPtr;    /* Pointer to array of pointers. */
983  {  {
984      int i, j, prio;      int i, j, prio;
985      register TkTextTag **tagPtrPtr;      register TkTextTag **tagPtrPtr;
986      TkTextTag **maxPtrPtr, *tmp;      TkTextTag **maxPtrPtr, *tmp;
987    
988      if (numTags < 2) {      if (numTags < 2) {
989          return;          return;
990      }      }
991      if (numTags < 20) {      if (numTags < 20) {
992          for (i = numTags-1; i > 0; i--, tagArrayPtr++) {          for (i = numTags-1; i > 0; i--, tagArrayPtr++) {
993              maxPtrPtr = tagPtrPtr = tagArrayPtr;              maxPtrPtr = tagPtrPtr = tagArrayPtr;
994              prio = tagPtrPtr[0]->priority;              prio = tagPtrPtr[0]->priority;
995              for (j = i, tagPtrPtr++; j > 0; j--, tagPtrPtr++) {              for (j = i, tagPtrPtr++; j > 0; j--, tagPtrPtr++) {
996                  if (tagPtrPtr[0]->priority < prio) {                  if (tagPtrPtr[0]->priority < prio) {
997                      prio = tagPtrPtr[0]->priority;                      prio = tagPtrPtr[0]->priority;
998                      maxPtrPtr = tagPtrPtr;                      maxPtrPtr = tagPtrPtr;
999                  }                  }
1000              }              }
1001              tmp = *maxPtrPtr;              tmp = *maxPtrPtr;
1002              *maxPtrPtr = *tagArrayPtr;              *maxPtrPtr = *tagArrayPtr;
1003              *tagArrayPtr = tmp;              *tagArrayPtr = tmp;
1004          }          }
1005      } else {      } else {
1006          qsort((VOID *) tagArrayPtr, (unsigned) numTags, sizeof (TkTextTag *),          qsort((VOID *) tagArrayPtr, (unsigned) numTags, sizeof (TkTextTag *),
1007                      TagSortProc);                      TagSortProc);
1008      }      }
1009  }  }
1010    
1011  /*  /*
1012   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1013   *   *
1014   * TagSortProc --   * TagSortProc --
1015   *   *
1016   *      This procedure is called by qsort when sorting an array of   *      This procedure is called by qsort when sorting an array of
1017   *      tags in priority order.   *      tags in priority order.
1018   *   *
1019   * Results:   * Results:
1020   *      The return value is -1 if the first argument should be before   *      The return value is -1 if the first argument should be before
1021   *      the second element (i.e. it has lower priority), 0 if it's   *      the second element (i.e. it has lower priority), 0 if it's
1022   *      equivalent (this should never happen!), and 1 if it should be   *      equivalent (this should never happen!), and 1 if it should be
1023   *      after the second element.   *      after the second element.
1024   *   *
1025   * Side effects:   * Side effects:
1026   *      None.   *      None.
1027   *   *
1028   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1029   */   */
1030    
1031  static int  static int
1032  TagSortProc(first, second)  TagSortProc(first, second)
1033      CONST VOID *first, *second;         /* Elements to be compared. */      CONST VOID *first, *second;         /* Elements to be compared. */
1034  {  {
1035      TkTextTag *tagPtr1, *tagPtr2;      TkTextTag *tagPtr1, *tagPtr2;
1036    
1037      tagPtr1 = * (TkTextTag **) first;      tagPtr1 = * (TkTextTag **) first;
1038      tagPtr2 = * (TkTextTag **) second;      tagPtr2 = * (TkTextTag **) second;
1039      return tagPtr1->priority - tagPtr2->priority;      return tagPtr1->priority - tagPtr2->priority;
1040  }  }
1041    
1042  /*  /*
1043   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1044   *   *
1045   * ChangeTagPriority --   * ChangeTagPriority --
1046   *   *
1047   *      This procedure changes the priority of a tag by modifying   *      This procedure changes the priority of a tag by modifying
1048   *      its priority and the priorities of other tags that are affected   *      its priority and the priorities of other tags that are affected
1049   *      by the change.   *      by the change.
1050   *   *
1051   * Results:   * Results:
1052   *      None.   *      None.
1053   *   *
1054   * Side effects:   * Side effects:
1055   *      Priorities may be changed for some or all of the tags in   *      Priorities may be changed for some or all of the tags in
1056   *      textPtr.  The tags will be arranged so that there is exactly   *      textPtr.  The tags will be arranged so that there is exactly
1057   *      one tag at each priority level between 0 and textPtr->numTags-1,   *      one tag at each priority level between 0 and textPtr->numTags-1,
1058   *      with tagPtr at priority "prio".   *      with tagPtr at priority "prio".
1059   *   *
1060   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1061   */   */
1062    
1063  static void  static void
1064  ChangeTagPriority(textPtr, tagPtr, prio)  ChangeTagPriority(textPtr, tagPtr, prio)
1065      TkText *textPtr;                    /* Information about text widget. */      TkText *textPtr;                    /* Information about text widget. */
1066      TkTextTag *tagPtr;                  /* Tag whose priority is to be      TkTextTag *tagPtr;                  /* Tag whose priority is to be
1067                                           * changed. */                                           * changed. */
1068      int prio;                           /* New priority for tag. */      int prio;                           /* New priority for tag. */
1069  {  {
1070      int low, high, delta;      int low, high, delta;
1071      register TkTextTag *tagPtr2;      register TkTextTag *tagPtr2;
1072      Tcl_HashEntry *hPtr;      Tcl_HashEntry *hPtr;
1073      Tcl_HashSearch search;      Tcl_HashSearch search;
1074    
1075      if (prio < 0) {      if (prio < 0) {
1076          prio = 0;          prio = 0;
1077      }      }
1078      if (prio >= textPtr->numTags) {      if (prio >= textPtr->numTags) {
1079          prio = textPtr->numTags-1;          prio = textPtr->numTags-1;
1080      }      }
1081      if (prio == tagPtr->priority) {      if (prio == tagPtr->priority) {
1082          return;          return;
1083      } else if (prio < tagPtr->priority) {      } else if (prio < tagPtr->priority) {
1084          low = prio;          low = prio;
1085          high = tagPtr->priority-1;          high = tagPtr->priority-1;
1086          delta = 1;          delta = 1;
1087      } else {      } else {
1088          low = tagPtr->priority+1;          low = tagPtr->priority+1;
1089          high = prio;          high = prio;
1090          delta = -1;          delta = -1;
1091      }      }
1092      for (hPtr = Tcl_FirstHashEntry(&textPtr->tagTable, &search);      for (hPtr = Tcl_FirstHashEntry(&textPtr->tagTable, &search);
1093              hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {              hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
1094          tagPtr2 = (TkTextTag *) Tcl_GetHashValue(hPtr);          tagPtr2 = (TkTextTag *) Tcl_GetHashValue(hPtr);
1095          if ((tagPtr2->priority >= low) && (tagPtr2->priority <= high)) {          if ((tagPtr2->priority >= low) && (tagPtr2->priority <= high)) {
1096              tagPtr2->priority += delta;              tagPtr2->priority += delta;
1097          }          }
1098      }      }
1099      tagPtr->priority = prio;      tagPtr->priority = prio;
1100  }  }
1101    
1102  /*  /*
1103   *--------------------------------------------------------------   *--------------------------------------------------------------
1104   *   *
1105   * TkTextBindProc --   * TkTextBindProc --
1106   *   *
1107   *      This procedure is invoked by the Tk dispatcher to handle   *      This procedure is invoked by the Tk dispatcher to handle
1108   *      events associated with bindings on items.   *      events associated with bindings on items.
1109   *   *
1110   * Results:   * Results:
1111   *      None.   *      None.
1112   *   *
1113   * Side effects:   * Side effects:
1114   *      Depends on the command invoked as part of the binding   *      Depends on the command invoked as part of the binding
1115   *      (if there was any).   *      (if there was any).
1116   *   *
1117   *--------------------------------------------------------------   *--------------------------------------------------------------
1118   */   */
1119    
1120  void  void
1121  TkTextBindProc(clientData, eventPtr)  TkTextBindProc(clientData, eventPtr)
1122      ClientData clientData;              /* Pointer to canvas structure. */      ClientData clientData;              /* Pointer to canvas structure. */
1123      XEvent *eventPtr;                   /* Pointer to X event that just      XEvent *eventPtr;                   /* Pointer to X event that just
1124                                           * happened. */                                           * happened. */
1125  {  {
1126      TkText *textPtr = (TkText *) clientData;      TkText *textPtr = (TkText *) clientData;
1127      int repick  = 0;      int repick  = 0;
1128    
1129  # define AnyButtonMask (Button1Mask|Button2Mask|Button3Mask\  # define AnyButtonMask (Button1Mask|Button2Mask|Button3Mask\
1130          |Button4Mask|Button5Mask)          |Button4Mask|Button5Mask)
1131    
1132      Tcl_Preserve((ClientData) textPtr);      Tcl_Preserve((ClientData) textPtr);
1133    
1134      /*      /*
1135       * This code simulates grabs for mouse buttons by keeping track       * This code simulates grabs for mouse buttons by keeping track
1136       * of whether a button is pressed and refusing to pick a new current       * of whether a button is pressed and refusing to pick a new current
1137       * character while a button is pressed.       * character while a button is pressed.
1138       */       */
1139    
1140      if (eventPtr->type == ButtonPress) {      if (eventPtr->type == ButtonPress) {
1141          textPtr->flags |= BUTTON_DOWN;          textPtr->flags |= BUTTON_DOWN;
1142      } else if (eventPtr->type == ButtonRelease) {      } else if (eventPtr->type == ButtonRelease) {
1143          int mask;          int mask;
1144    
1145          switch (eventPtr->xbutton.button) {          switch (eventPtr->xbutton.button) {
1146              case Button1:              case Button1:
1147                  mask = Button1Mask;                  mask = Button1Mask;
1148                  break;                  break;
1149              case Button2:              case Button2:
1150                  mask = Button2Mask;                  mask = Button2Mask;
1151                  break;                  break;
1152              case Button3:              case Button3:
1153                  mask = Button3Mask;                  mask = Button3Mask;
1154                  break;                  break;
1155              case Button4:              case Button4:
1156                  mask = Button4Mask;                  mask = Button4Mask;
1157                  break;                  break;
1158              case Button5:              case Button5:
1159                  mask = Button5Mask;                  mask = Button5Mask;
1160                  break;                  break;
1161              default:              default:
1162                  mask = 0;                  mask = 0;
1163                  break;                  break;
1164          }          }
1165          if ((eventPtr->xbutton.state & AnyButtonMask) == (unsigned) mask) {          if ((eventPtr->xbutton.state & AnyButtonMask) == (unsigned) mask) {
1166              textPtr->flags &= ~BUTTON_DOWN;              textPtr->flags &= ~BUTTON_DOWN;
1167              repick = 1;              repick = 1;
1168          }          }
1169      } else if ((eventPtr->type == EnterNotify)      } else if ((eventPtr->type == EnterNotify)
1170              || (eventPtr->type == LeaveNotify)) {              || (eventPtr->type == LeaveNotify)) {
1171          if (eventPtr->xcrossing.state & AnyButtonMask)  {          if (eventPtr->xcrossing.state & AnyButtonMask)  {
1172              textPtr->flags |= BUTTON_DOWN;              textPtr->flags |= BUTTON_DOWN;
1173          } else {          } else {
1174              textPtr->flags &= ~BUTTON_DOWN;              textPtr->flags &= ~BUTTON_DOWN;
1175          }          }
1176          TkTextPickCurrent(textPtr, eventPtr);          TkTextPickCurrent(textPtr, eventPtr);
1177          goto done;          goto done;
1178      } else if (eventPtr->type == MotionNotify) {      } else if (eventPtr->type == MotionNotify) {
1179          if (eventPtr->xmotion.state & AnyButtonMask)  {          if (eventPtr->xmotion.state & AnyButtonMask)  {
1180              textPtr->flags |= BUTTON_DOWN;              textPtr->flags |= BUTTON_DOWN;
1181          } else {          } else {
1182              textPtr->flags &= ~BUTTON_DOWN;              textPtr->flags &= ~BUTTON_DOWN;
1183          }          }
1184          TkTextPickCurrent(textPtr, eventPtr);          TkTextPickCurrent(textPtr, eventPtr);
1185      }      }
1186      if ((textPtr->numCurTags > 0) && (textPtr->bindingTable != NULL)      if ((textPtr->numCurTags > 0) && (textPtr->bindingTable != NULL)
1187              && (textPtr->tkwin != NULL)) {              && (textPtr->tkwin != NULL)) {
1188          Tk_BindEvent(textPtr->bindingTable, eventPtr, textPtr->tkwin,          Tk_BindEvent(textPtr->bindingTable, eventPtr, textPtr->tkwin,
1189                  textPtr->numCurTags, (ClientData *) textPtr->curTagArrayPtr);                  textPtr->numCurTags, (ClientData *) textPtr->curTagArrayPtr);
1190      }      }
1191      if (repick) {      if (repick) {
1192          unsigned int oldState;          unsigned int oldState;
1193    
1194          oldState = eventPtr->xbutton.state;          oldState = eventPtr->xbutton.state;
1195          eventPtr->xbutton.state &= ~(Button1Mask|Button2Mask          eventPtr->xbutton.state &= ~(Button1Mask|Button2Mask
1196                  |Button3Mask|Button4Mask|Button5Mask);                  |Button3Mask|Button4Mask|Button5Mask);
1197          TkTextPickCurrent(textPtr, eventPtr);          TkTextPickCurrent(textPtr, eventPtr);
1198          eventPtr->xbutton.state = oldState;          eventPtr->xbutton.state = oldState;
1199      }      }
1200    
1201      done:      done:
1202      Tcl_Release((ClientData) textPtr);      Tcl_Release((ClientData) textPtr);
1203  }  }
1204    
1205  /*  /*
1206   *--------------------------------------------------------------   *--------------------------------------------------------------
1207   *   *
1208   * TkTextPickCurrent --   * TkTextPickCurrent --
1209   *   *
1210   *      Find the character containing the coordinates in an event   *      Find the character containing the coordinates in an event
1211   *      and place the "current" mark on that character.  If the   *      and place the "current" mark on that character.  If the
1212   *      "current" mark has moved then generate a fake leave event   *      "current" mark has moved then generate a fake leave event
1213   *      on the old current character and a fake enter event on the new   *      on the old current character and a fake enter event on the new
1214   *      current character.   *      current character.
1215   *   *
1216   * Results:   * Results:
1217   *      None.   *      None.
1218   *   *
1219   * Side effects:   * Side effects:
1220   *      The current mark for textPtr may change.  If it does,   *      The current mark for textPtr may change.  If it does,
1221   *      then the commands associated with character entry and leave   *      then the commands associated with character entry and leave
1222   *      could do just about anything.  For example, the text widget   *      could do just about anything.  For example, the text widget
1223   *      might be deleted.  It is up to the caller to protect itself   *      might be deleted.  It is up to the caller to protect itself
1224   *      with calls to Tcl_Preserve and Tcl_Release.   *      with calls to Tcl_Preserve and Tcl_Release.
1225   *   *
1226   *--------------------------------------------------------------   *--------------------------------------------------------------
1227   */   */
1228    
1229  void  void
1230  TkTextPickCurrent(textPtr, eventPtr)  TkTextPickCurrent(textPtr, eventPtr)
1231      register TkText *textPtr;           /* Text widget in which to select      register TkText *textPtr;           /* Text widget in which to select
1232                                           * current character. */                                           * current character. */
1233      XEvent *eventPtr;                   /* Event describing location of      XEvent *eventPtr;                   /* Event describing location of
1234                                           * mouse cursor.  Must be EnterWindow,                                           * mouse cursor.  Must be EnterWindow,
1235                                           * LeaveWindow, ButtonRelease, or                                           * LeaveWindow, ButtonRelease, or
1236                                           * MotionNotify. */                                           * MotionNotify. */
1237  {  {
1238      TkTextIndex index;      TkTextIndex index;
1239      TkTextTag **oldArrayPtr, **newArrayPtr;      TkTextTag **oldArrayPtr, **newArrayPtr;
1240      TkTextTag **copyArrayPtr = NULL;    /* Initialization needed to prevent      TkTextTag **copyArrayPtr = NULL;    /* Initialization needed to prevent
1241                                           * compiler warning. */                                           * compiler warning. */
1242    
1243      int numOldTags, numNewTags, i, j, size;      int numOldTags, numNewTags, i, j, size;
1244      XEvent event;      XEvent event;
1245    
1246      /*      /*
1247       * If a button is down, then don't do anything at all;  we'll be       * If a button is down, then don't do anything at all;  we'll be
1248       * called again when all buttons are up, and we can repick then.       * called again when all buttons are up, and we can repick then.
1249       * This implements a form of mouse grabbing.       * This implements a form of mouse grabbing.
1250       */       */
1251    
1252      if (textPtr->flags & BUTTON_DOWN) {      if (textPtr->flags & BUTTON_DOWN) {
1253          if (((eventPtr->type == EnterNotify) || (eventPtr->type == LeaveNotify))          if (((eventPtr->type == EnterNotify) || (eventPtr->type == LeaveNotify))
1254                  && ((eventPtr->xcrossing.mode == NotifyGrab)                  && ((eventPtr->xcrossing.mode == NotifyGrab)
1255                  || (eventPtr->xcrossing.mode == NotifyUngrab))) {                  || (eventPtr->xcrossing.mode == NotifyUngrab))) {
1256              /*              /*
1257               * Special case:  the window is being entered or left because               * Special case:  the window is being entered or left because
1258               * of a grab or ungrab.  In this case, repick after all.               * of a grab or ungrab.  In this case, repick after all.
1259               * Furthermore, clear BUTTON_DOWN to release the simulated               * Furthermore, clear BUTTON_DOWN to release the simulated
1260               * grab.               * grab.
1261               */               */
1262    
1263              textPtr->flags &= ~BUTTON_DOWN;              textPtr->flags &= ~BUTTON_DOWN;
1264          } else {          } else {
1265              return;              return;
1266          }          }
1267      }      }
1268    
1269      /*      /*
1270       * Save information about this event in the widget in case we have       * Save information about this event in the widget in case we have
1271       * to synthesize more enter and leave events later (e.g. because a       * to synthesize more enter and leave events later (e.g. because a
1272       * character was deleted, causing a new character to be underneath       * character was deleted, causing a new character to be underneath
1273       * the mouse cursor).  Also translate MotionNotify events into       * the mouse cursor).  Also translate MotionNotify events into
1274       * EnterNotify events, since that's what gets reported to event       * EnterNotify events, since that's what gets reported to event
1275       * handlers when the current character changes.       * handlers when the current character changes.
1276       */       */
1277    
1278      if (eventPtr != &textPtr->pickEvent) {      if (eventPtr != &textPtr->pickEvent) {
1279          if ((eventPtr->type == MotionNotify)          if ((eventPtr->type == MotionNotify)
1280                  || (eventPtr->type == ButtonRelease)) {                  || (eventPtr->type == ButtonRelease)) {
1281              textPtr->pickEvent.xcrossing.type = EnterNotify;              textPtr->pickEvent.xcrossing.type = EnterNotify;
1282              textPtr->pickEvent.xcrossing.serial = eventPtr->xmotion.serial;              textPtr->pickEvent.xcrossing.serial = eventPtr->xmotion.serial;
1283              textPtr->pickEvent.xcrossing.send_event              textPtr->pickEvent.xcrossing.send_event
1284                      = eventPtr->xmotion.send_event;                      = eventPtr->xmotion.send_event;
1285              textPtr->pickEvent.xcrossing.display = eventPtr->xmotion.display;              textPtr->pickEvent.xcrossing.display = eventPtr->xmotion.display;
1286              textPtr->pickEvent.xcrossing.window = eventPtr->xmotion.window;              textPtr->pickEvent.xcrossing.window = eventPtr->xmotion.window;
1287              textPtr->pickEvent.xcrossing.root = eventPtr->xmotion.root;              textPtr->pickEvent.xcrossing.root = eventPtr->xmotion.root;
1288              textPtr->pickEvent.xcrossing.subwindow = None;              textPtr->pickEvent.xcrossing.subwindow = None;
1289              textPtr->pickEvent.xcrossing.time = eventPtr->xmotion.time;              textPtr->pickEvent.xcrossing.time = eventPtr->xmotion.time;
1290              textPtr->pickEvent.xcrossing.x = eventPtr->xmotion.x;              textPtr->pickEvent.xcrossing.x = eventPtr->xmotion.x;
1291              textPtr->pickEvent.xcrossing.y = eventPtr->xmotion.y;              textPtr->pickEvent.xcrossing.y = eventPtr->xmotion.y;
1292              textPtr->pickEvent.xcrossing.x_root = eventPtr->xmotion.x_root;              textPtr->pickEvent.xcrossing.x_root = eventPtr->xmotion.x_root;
1293              textPtr->pickEvent.xcrossing.y_root = eventPtr->xmotion.y_root;              textPtr->pickEvent.xcrossing.y_root = eventPtr->xmotion.y_root;
1294              textPtr->pickEvent.xcrossing.mode = NotifyNormal;              textPtr->pickEvent.xcrossing.mode = NotifyNormal;
1295              textPtr->pickEvent.xcrossing.detail = NotifyNonlinear;              textPtr->pickEvent.xcrossing.detail = NotifyNonlinear;
1296              textPtr->pickEvent.xcrossing.same_screen              textPtr->pickEvent.xcrossing.same_screen
1297                      = eventPtr->xmotion.same_screen;                      = eventPtr->xmotion.same_screen;
1298              textPtr->pickEvent.xcrossing.focus = False;              textPtr->pickEvent.xcrossing.focus = False;
1299              textPtr->pickEvent.xcrossing.state = eventPtr->xmotion.state;              textPtr->pickEvent.xcrossing.state = eventPtr->xmotion.state;
1300          } else  {          } else  {
1301              textPtr->pickEvent = *eventPtr;              textPtr->pickEvent = *eventPtr;
1302          }          }
1303      }      }
1304    
1305      /*      /*
1306       * Find the new current character, then find and sort all of the       * Find the new current character, then find and sort all of the
1307       * tags associated with it.       * tags associated with it.
1308       */       */
1309    
1310      if (textPtr->pickEvent.type != LeaveNotify) {      if (textPtr->pickEvent.type != LeaveNotify) {
1311          TkTextPixelIndex(textPtr, textPtr->pickEvent.xcrossing.x,          TkTextPixelIndex(textPtr, textPtr->pickEvent.xcrossing.x,
1312                  textPtr->pickEvent.xcrossing.y, &index);                  textPtr->pickEvent.xcrossing.y, &index);
1313          newArrayPtr = TkBTreeGetTags(&index, &numNewTags);          newArrayPtr = TkBTreeGetTags(&index, &numNewTags);
1314          SortTags(numNewTags, newArrayPtr);          SortTags(numNewTags, newArrayPtr);
1315      } else {      } else {
1316          newArrayPtr = NULL;          newArrayPtr = NULL;
1317          numNewTags = 0;          numNewTags = 0;
1318      }      }
1319    
1320      /*      /*
1321       * Resort the tags associated with the previous marked character       * Resort the tags associated with the previous marked character
1322       * (the priorities might have changed), then make a copy of the       * (the priorities might have changed), then make a copy of the
1323       * new tags, and compare the old tags to the copy, nullifying       * new tags, and compare the old tags to the copy, nullifying
1324       * any tags that are present in both groups (i.e. the tags that       * any tags that are present in both groups (i.e. the tags that
1325       * haven't changed).       * haven't changed).
1326       */       */
1327    
1328      SortTags(textPtr->numCurTags, textPtr->curTagArrayPtr);      SortTags(textPtr->numCurTags, textPtr->curTagArrayPtr);
1329      if (numNewTags > 0) {      if (numNewTags > 0) {
1330          size = numNewTags * sizeof(TkTextTag *);          size = numNewTags * sizeof(TkTextTag *);
1331          copyArrayPtr = (TkTextTag **) ckalloc((unsigned) size);          copyArrayPtr = (TkTextTag **) ckalloc((unsigned) size);
1332          memcpy((VOID *) copyArrayPtr, (VOID *) newArrayPtr, (size_t) size);          memcpy((VOID *) copyArrayPtr, (VOID *) newArrayPtr, (size_t) size);
1333          for (i = 0; i < textPtr->numCurTags; i++) {          for (i = 0; i < textPtr->numCurTags; i++) {
1334              for (j = 0; j < numNewTags; j++) {              for (j = 0; j < numNewTags; j++) {
1335                  if (textPtr->curTagArrayPtr[i] == copyArrayPtr[j]) {                  if (textPtr->curTagArrayPtr[i] == copyArrayPtr[j]) {
1336                      textPtr->curTagArrayPtr[i] = NULL;                      textPtr->curTagArrayPtr[i] = NULL;
1337                      copyArrayPtr[j] = NULL;                      copyArrayPtr[j] = NULL;
1338                      break;                      break;
1339                  }                  }
1340              }              }
1341          }          }
1342      }      }
1343    
1344      /*      /*
1345       * Invoke the binding system with a LeaveNotify event for all of       * Invoke the binding system with a LeaveNotify event for all of
1346       * the tags that have gone away.  We have to be careful here,       * the tags that have gone away.  We have to be careful here,
1347       * because it's possible that the binding could do something       * because it's possible that the binding could do something
1348       * (like calling tkwait) that eventually modifies       * (like calling tkwait) that eventually modifies
1349       * textPtr->curTagArrayPtr.  To avoid problems in situations like       * textPtr->curTagArrayPtr.  To avoid problems in situations like
1350       * this, update curTagArrayPtr to its new value before invoking       * this, update curTagArrayPtr to its new value before invoking
1351       * any bindings, and don't use it any more here.       * any bindings, and don't use it any more here.
1352       */       */
1353    
1354      numOldTags = textPtr->numCurTags;      numOldTags = textPtr->numCurTags;
1355      textPtr->numCurTags = numNewTags;      textPtr->numCurTags = numNewTags;
1356      oldArrayPtr = textPtr->curTagArrayPtr;      oldArrayPtr = textPtr->curTagArrayPtr;
1357      textPtr->curTagArrayPtr = newArrayPtr;      textPtr->curTagArrayPtr = newArrayPtr;
1358      if (numOldTags != 0) {      if (numOldTags != 0) {
1359          if ((textPtr->bindingTable != NULL) && (textPtr->tkwin != NULL)) {          if ((textPtr->bindingTable != NULL) && (textPtr->tkwin != NULL)) {
1360              event = textPtr->pickEvent;              event = textPtr->pickEvent;
1361              event.type = LeaveNotify;              event.type = LeaveNotify;
1362    
1363              /*              /*
1364               * Always use a detail of NotifyAncestor.  Besides being               * Always use a detail of NotifyAncestor.  Besides being
1365               * consistent, this avoids problems where the binding code               * consistent, this avoids problems where the binding code
1366               * will discard NotifyInferior events.               * will discard NotifyInferior events.
1367               */               */
1368    
1369              event.xcrossing.detail = NotifyAncestor;              event.xcrossing.detail = NotifyAncestor;
1370              Tk_BindEvent(textPtr->bindingTable, &event, textPtr->tkwin,              Tk_BindEvent(textPtr->bindingTable, &event, textPtr->tkwin,
1371                      numOldTags, (ClientData *) oldArrayPtr);                      numOldTags, (ClientData *) oldArrayPtr);
1372          }          }
1373          ckfree((char *) oldArrayPtr);          ckfree((char *) oldArrayPtr);
1374      }      }
1375    
1376      /*      /*
1377       * Reset the "current" mark (be careful to recompute its location,       * Reset the "current" mark (be careful to recompute its location,
1378       * since it might have changed during an event binding).  Then       * since it might have changed during an event binding).  Then
1379       * invoke the binding system with an EnterNotify event for all of       * invoke the binding system with an EnterNotify event for all of
1380       * the tags that have just appeared.       * the tags that have just appeared.
1381       */       */
1382    
1383      TkTextPixelIndex(textPtr, textPtr->pickEvent.xcrossing.x,      TkTextPixelIndex(textPtr, textPtr->pickEvent.xcrossing.x,
1384              textPtr->pickEvent.xcrossing.y, &index);              textPtr->pickEvent.xcrossing.y, &index);
1385      TkTextSetMark(textPtr, "current", &index);      TkTextSetMark(textPtr, "current", &index);
1386      if (numNewTags != 0) {      if (numNewTags != 0) {
1387          if ((textPtr->bindingTable != NULL) && (textPtr->tkwin != NULL)) {          if ((textPtr->bindingTable != NULL) && (textPtr->tkwin != NULL)) {
1388              event = textPtr->pickEvent;              event = textPtr->pickEvent;
1389              event.type = EnterNotify;              event.type = EnterNotify;
1390              event.xcrossing.detail = NotifyAncestor;              event.xcrossing.detail = NotifyAncestor;
1391              Tk_BindEvent(textPtr->bindingTable, &event, textPtr->tkwin,              Tk_BindEvent(textPtr->bindingTable, &event, textPtr->tkwin,
1392                      numNewTags, (ClientData *) copyArrayPtr);                      numNewTags, (ClientData *) copyArrayPtr);
1393          }          }
1394          ckfree((char *) copyArrayPtr);          ckfree((char *) copyArrayPtr);
1395      }      }
1396  }  }
1397    
1398  /* End of tktexttag.c */  /* End of tktexttag.c */

Legend:
Removed from v.69  
changed lines
  Added in v.71

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25