1 /*
2  * wmslib/src/but/i_finder.c, part of wmslib (Library functions)
3  * Copyright (C) 1994 William Shubert.
4  * See "configure.h.in" for more copyright information.
5  */
6 
7 #include <configure.h>
8 
9 #ifdef  X11_DISP
10 
11 #ifdef  STDC_HEADERS
12 #include <stdlib.h>
13 #include <unistd.h>
14 #endif  /* STDC_HEADERS */
15 #include <stdio.h>
16 #include <X11/Xlib.h>
17 #include <X11/Xutil.h>
18 #include <X11/cursorfont.h>
19 #include <X11/Xatom.h>
20 #include <X11/keysym.h>
21 #include <sys/time.h>
22 #ifdef  HAVE_SYS_SELECT_H
23 #include <sys/select.h>
24 #endif
25 #include <wms.h>
26 #include <but/but.h>
27 
28 static void  addButToCol(ButCol *col, But *but, int y1, int y2);
29 static void  addButToRow(ButRow *row, But *but);
30 static void  copyCol(ButCol *dest, ButCol *src);
31 static void  copyRow(ButRow *dest, ButRow *src);
32 static void  findButSetInCol(ButCol *col, int x, int y, ButSet *butset);
33 static void  butDelFromCol(ButCol *col, But *but);
34 static void  butDelFromRow(ButRow *row, But *but);
35 static bool  colEq(ButCol *c1, ButCol *c2);
36 static bool  rowEq(ButRow *r1, ButRow *r2);
37 static void  colDel(ButWin *win, int col_num);
38 static void  rowDel(ButCol *col, int row_num);
39 static int  markForTable(But *but, void *packet);
40 static int  addToTable(But *but, void *packet);
41 static int  butcomp(const void *a, const void *b);
42 
43 #if  0  /* Useful sometimes for debugging. */
44 void  printf_table(but_win_t *win);
45 void  printf_env(but_env_t *win);
46 #endif
47 
butWin_addToTable(ButWin * win)48 void  butWin_addToTable(ButWin *win)  {
49   ButEnv  *env = win->env;
50   ButWin  **new_winlist;
51   int  i, j, new_pos;
52 
53   assert(MAGIC(win));
54   if (win->win != None)  {
55     /*
56      * If win->win is None, then it is a canvas, which does not have to
57      *   be entered into the window table yet.
58      */
59     if (env->wlmax == env->wllen)  {
60       new_winlist = wms_malloc(sizeof(ButWin *) * (env->wllen + 1) * 2);
61       for (i = 0;  i < env->wllen;  ++i)
62 	new_winlist[i] = env->winlist[i];
63       if (env->winlist != NULL)
64 	wms_free(env->winlist);
65       env->winlist = new_winlist;
66       env->wlmax = (env->wllen + 1) * 2;
67     }
68 
69     for (i = 0;  (i < env->wllen) && (win->win > env->winlist[i]->win);  ++i);
70     new_pos = i;
71     for (i = env->wllen;  i > new_pos;  --i)
72       env->winlist[i] = env->winlist[i-1];
73     env->winlist[new_pos] = win;
74     ++env->wllen;
75   }
76 
77   if (win->numCols == 0)  {
78     /*
79      * A canvas may call this function every time the pixmap changes, so
80      *   we have to make sure that we don't re-allocate all this stuff!
81      */
82     win->numCols = 2;
83     win->maxCols = 2;
84     win->cols = wms_malloc(2 * sizeof(ButCol));
85     win->cols[0].startX = int_min;
86     win->cols[1].startX = int_max;
87     for (i = 0;  i < 2;  ++i)  {
88       MAGIC_SET(&win->cols[i]);
89       win->cols[i].numRows = 2;
90       win->cols[i].maxRows = 2;
91       win->cols[i].rows = wms_malloc(2 * sizeof(ButRow));
92       win->cols[i].rows[0].startY = int_min;
93       win->cols[i].rows[1].startY = int_max;
94       for (j = 0;  j < 2;  ++j)  {
95 	MAGIC_SET(&win->cols[i].rows[j]);
96 	win->cols[i].rows[j].numButs = 0;
97 	win->cols[i].rows[j].maxButs = 0;
98 	win->cols[i].rows[j].buts = NULL;
99       }
100     }
101   }
102 #if  DEBUG
103   for (i = 1;  i < env->wllen;  ++i)  {
104     assert(env->winlist[i]->win > env->winlist[i - 1]->win);
105   }
106 #endif  /* DEBUG */
107 }
108 
109 
butWin_rmFromTable(ButWin * win)110 void  butWin_rmFromTable(ButWin *win)  {
111   ButEnv  *env = win->env;
112   int  i;
113 
114   assert(MAGIC(win));
115   assert(MAGIC(env));
116   for (i = 0;  (env->winlist[i] != win) && (i < env->wllen);  ++i);
117   if (i < env->wllen)  {
118     --env->wllen;
119     while (i < env->wllen)  {
120       env->winlist[i] = env->winlist[i+1];
121       ++i;
122     }
123   }
124 #if  DEBUG
125   for (i = 1;  i < env->wllen;  ++i)  {
126     assert(env->winlist[i]->win > env->winlist[i - 1]->win);
127   }
128 #endif  /* DEBUG */
129 }
130 
131 
but_addToTable(But * but)132 void  but_addToTable(But *but)  {
133   ButWin  *win = but->win;
134   int  x1 = but->x, y1 = but->y, x2 = but->x + but->w, y2 = but->y + but->h;
135   int  i, src, dest;
136   ButCol  *new_cl = win->cols;
137   int  new_cll = win->numCols, new_clmax = win->maxCols;
138   int  x1done = 0, x2done = 0;
139 
140   assert(MAGIC(but));
141   assert(but->flags & BUT_DRAWABLE);
142   butSet_delBut(&win->butsNoDraw, but);
143   for (i = 0;  i < new_cll;  ++i)  {
144     assert(MAGIC(&new_cl[i]));
145     if (new_cl[i].startX == x1)
146       x1done = 1;
147     else if (new_cl[i].startX == x2)
148       x2done = 1;
149   }
150   new_cll += 2 - (x1done + x2done);
151   if (new_cll > win->maxCols)  {
152     new_cl = wms_malloc(sizeof(ButCol) * (new_clmax = new_cll * 2));
153     for (i = 0;  i < new_clmax;  ++i)  {
154       MAGIC_SET(&new_cl[i]);
155       new_cl[i].rows = NULL;
156     }
157   }
158   for (src = win->numCols, dest = new_cll;  src > 0;)  {
159     --src;
160     --dest;
161     assert(MAGIC(&win->cols[src]));
162     if (!x2done && (win->cols[src].startX < x2))  {
163       assert(MAGIC(&new_cl[dest]));
164       copyCol(&new_cl[dest], &win->cols[src]);
165       new_cl[dest--].startX = x2;
166       x2done = 1;
167     }
168     if (!x1done && (win->cols[src].startX < x1))  {
169       assert(MAGIC(&new_cl[dest]));
170       copyCol(&new_cl[dest], &win->cols[src]);
171       new_cl[dest].startX = x1;
172       addButToCol(&new_cl[dest--], but, y1, y2);
173       x1done = 1;
174     }
175     assert(MAGIC(&new_cl[dest]));
176     new_cl[dest] = win->cols[src];
177     if ((new_cl[dest].startX < x2) && (new_cl[dest].startX >= x1))
178       addButToCol(&new_cl[dest], but, y1, y2);
179   }
180   if (win->cols != new_cl)  {
181     for (i = 0;  i < win->maxCols;  ++i)
182       MAGIC_UNSET(&win->cols[i]);
183     wms_free(win->cols);
184     win->cols = new_cl;
185   }
186   win->maxCols = new_clmax;
187   win->numCols = new_cll;
188 }
189 
190 
addButToCol(ButCol * col,But * but,int y1,int y2)191 static void  addButToCol(ButCol *col, But *but, int y1, int y2)  {
192   ButRow  *new_rl = col->rows;
193   int  i, src, dest, new_rll = col->numRows, new_rlmax = col->maxRows;
194   int  y1done=0, y2done=0;
195 
196   assert(MAGIC(col));
197   assert(MAGIC(but));
198   for (i = 0;  i < col->numRows;  ++i)  {
199     assert(MAGIC(&col->rows[i]));
200     if (col->rows[i].startY == y1)
201       y1done = 1;
202     if (col->rows[i].startY == y2)
203       y2done = 1;
204   }
205   new_rll += 2 - (y1done + y2done);
206   if (new_rll > col->maxRows)  {
207     new_rl = wms_malloc(sizeof(ButRow) * (new_rlmax = new_rll * 2));
208     for (i = 0;  i < new_rlmax;  ++i)  {
209       MAGIC_SET(&new_rl[i]);
210       new_rl[i].buts = NULL;
211     }
212   }
213   for (src = col->numRows, dest = new_rll;  src > 0;)  {
214     --src;
215     --dest;
216     assert(MAGIC(&col->rows[src]));
217     if (!y2done && (col->rows[src].startY < y2))  {
218       assert(MAGIC(&new_rl[dest]));
219       copyRow(&new_rl[dest], &col->rows[src]);
220       new_rl[dest--].startY = y2;
221       y2done = 1;
222     }
223     if (!y1done && (col->rows[src].startY < y1))  {
224       assert(MAGIC(&new_rl[dest]));
225       copyRow(&new_rl[dest], &col->rows[src]);
226       new_rl[dest].startY = y1;
227       addButToRow(&new_rl[dest--], but);
228       y1done = 1;
229     }
230     assert(MAGIC(&new_rl[dest]));
231     new_rl[dest] = col->rows[src];
232     if ((new_rl[dest].startY < y2) && (new_rl[dest].startY >= y1))
233       addButToRow(&new_rl[dest], but);
234   }
235   if (col->rows != new_rl)  {
236     if (col->rows != NULL)  {
237       wms_free(col->rows);
238       for (i = 0;  i < col->maxRows;  ++i)
239 	MAGIC_UNSET(&col->rows[i]);
240     }
241     col->rows = new_rl;
242   }
243   col->maxRows = new_rlmax;
244   col->numRows = new_rll;
245 }
246 
247 
addButToRow(ButRow * row,But * but)248 static void  addButToRow(ButRow *row, But *but)  {
249   int  i, new_maxButs = row->maxButs, new_numButs = row->numButs + 1;
250   But  **new_bl = row->buts;
251 
252   assert(MAGIC(row));
253   assert(MAGIC(but));
254   if (new_numButs >= row->maxButs)  {
255     new_bl = wms_malloc(sizeof(But *) * (new_maxButs = new_numButs * 2));
256     for (i = 0;  i < row->numButs;  ++i)
257       new_bl[i] = row->buts[i];
258   }
259   for (i = row->numButs - 1;
260        (i >= 0) && (but->layer < row->buts[i]->layer);  --i)  {
261     assert(MAGIC(new_bl[i]));
262     assert(new_bl[i] != but);
263     new_bl[i+1] = new_bl[i];
264   }
265   new_bl[i+1] = but;
266 #if  DEBUG
267   for (;  i >= 0;  --i)
268     assert(new_bl[i] != but);
269 #endif
270   if ((row->buts != NULL) && (row->buts != new_bl))
271     wms_free(row->buts);
272   row->buts = new_bl;
273   row->numButs = new_numButs;
274   row->maxButs = new_maxButs;
275 }
276 
277 
copyCol(ButCol * dest,ButCol * src)278 static void  copyCol(ButCol *dest, ButCol *src)  {
279   int  i;
280 
281   assert(MAGIC(dest));
282   assert(MAGIC(src));
283   *dest = *src;
284   dest->rows = wms_malloc(dest->maxRows * sizeof(ButRow));
285   for (i = 0;  i < dest->maxRows;  ++i)
286     MAGIC_SET(&dest->rows[i]);
287   for (i = 0;  i < dest->numRows;  ++i)
288     copyRow(&dest->rows[i], &src->rows[i]);
289 }
290 
291 
copyRow(ButRow * dest,ButRow * src)292 static void  copyRow(ButRow *dest, ButRow *src)  {
293   int  i;
294 
295   assert(MAGIC(dest));
296   assert(MAGIC(src));
297   *dest = *src;
298   dest->buts = wms_malloc(dest->maxButs * sizeof(But *));
299   for (i = 0;  i < dest->numButs;  ++i)
300     dest->buts[i] = src->buts[i];
301 }
302 
303 
butWin_findButSet(ButWin * win,int x,int y,ButSet * butset)304 void  butWin_findButSet(ButWin *win, int x, int y, ButSet *butset)  {
305   unsigned  hlen, result = 0, cllen = win->numCols;
306 
307   assert(MAGIC(win));
308   butset->dynamic = FALSE;
309   while ((hlen = (cllen >> 1)))  {
310     assert(MAGIC(&win->cols[result+hlen]));
311     if (win->cols[result+hlen].startX > x)  {
312       cllen = hlen;
313     } else  {
314       cllen -= hlen;
315       result += hlen;
316     }
317   }
318   findButSetInCol(&win->cols[result], x, y, butset);
319 }
320 
321 
findButSetInCol(ButCol * col,int x,int y,ButSet * butset)322 static void  findButSetInCol(ButCol *col, int x, int y, ButSet *butset)  {
323   unsigned  hlen, result = 0, rllen = col->numRows;
324 
325   assert(MAGIC(col));
326   while ((hlen = (rllen >> 1)))  {
327     assert(MAGIC(&col->rows[result+hlen]));
328     if (col->rows[result+hlen].startY > y)  {
329       rllen = hlen;
330     } else  {
331       rllen -= hlen;
332       result += hlen;
333     }
334   }
335   butset->numButs = col->rows[result].numButs;
336   butset->buts = col->rows[result].buts;
337   butset->dynamic = FALSE;
338 }
339 
340 
but_delFromTable(But * but)341 void  but_delFromTable(But *but)  {
342   ButWin  *win = but->win;
343   int  i;
344   ButCol  *cl = win->cols;
345 
346   assert(MAGIC(but));
347   assert(MAGIC(win));
348   for (i = 1;  i < win->numCols - 1;  ++i)  {
349     assert(MAGIC(&cl[i]));
350     if ((cl[i].startX >= but->x) &&
351 	(cl[i].startX < but->x + but->w))  {
352       butDelFromCol(&cl[i], but);
353       if (colEq(&cl[i-1], &cl[i]))  {
354 	colDel(win, i);
355 	--i;
356       }
357       if ((i+1 < win->numCols - 1) && colEq(&cl[i], &cl[i+1]))
358 	colDel(win, i+1);
359     }
360   }
361 }
362 
363 
colEq(ButCol * c1,ButCol * c2)364 static bool  colEq(ButCol *c1, ButCol *c2)  {
365   int  i;
366 
367   assert(MAGIC(c1));
368   assert(MAGIC(c2));
369   if (c1->numRows != c2->numRows)
370     return(FALSE);
371   for (i = 0;  i < c1->numRows;  ++i)  {
372     if (!rowEq(&c1->rows[i], &c2->rows[i]))
373       return(FALSE);
374   }
375   return(TRUE);
376 }
377 
378 
rowEq(ButRow * r1,ButRow * r2)379 static bool  rowEq(ButRow *r1, ButRow *r2)  {
380   int  i;
381 
382   assert(MAGIC(r1));
383   assert(MAGIC(r2));
384   if (r1->numButs != r2->numButs)
385     return(FALSE);
386   for (i = 0;  i < r1->numButs;  ++i)  {
387     if (r1->buts[i] != r2->buts[i])
388       return(FALSE);
389   }
390   return(TRUE);
391 }
392 
393 
butDelFromCol(ButCol * col,But * but)394 static void  butDelFromCol(ButCol *col, But *but)  {
395   int  i;
396   ButRow  *rl = col->rows;
397 
398   assert(MAGIC(col));
399   for (i = 1;  i < col->numRows - 1;  ++i)  {
400     assert(MAGIC(&rl[i]));
401     if ((rl[i].startY >= but->y) &&
402 	(rl[i].startY < but->y + but->h))  {
403       butDelFromRow(&rl[i], but);
404       if (rowEq(&rl[i-1], &rl[i]))  {
405 	rowDel(col, i);
406 	--i;
407       }
408       if ((i+1 < col->numRows - 1) && rowEq(&rl[i], &rl[i+1]))
409 	rowDel(col, i+1);
410     }
411   }
412 }
413 
414 
butDelFromRow(ButRow * row,But * but)415 static void  butDelFromRow(ButRow *row, But *but)  {
416   int  dest, src;
417 
418   assert(MAGIC(row));
419   for (dest = 0, src = 0;  src < row->numButs;  ++src)  {
420     assert(MAGIC(row->buts[src]));
421     row->buts[dest] = row->buts[src];
422     if (row->buts[dest] != but)  {
423       ++dest;
424     } else  {
425       assert(src == dest);
426     }
427   }
428   assert(src == dest + 1);
429   --row->numButs;
430   assert(dest == row->numButs);
431 }
432 
433 
colDel(ButWin * win,int col_num)434 static void  colDel(ButWin *win, int col_num)  {
435   int  i;
436 
437   assert(MAGIC(win));
438   assert(MAGIC(&win->cols[col_num]));
439   for (i = 0;  i < win->cols[col_num].numRows;  ++i)  {
440     assert(MAGIC(&win->cols[col_num].rows[i]));
441     if (win->cols[col_num].rows[i].buts != NULL)
442       wms_free(win->cols[col_num].rows[i].buts);
443   }
444   wms_free(win->cols[col_num].rows);
445   --win->numCols;
446   for (i = col_num;  i < win->numCols;  ++i)
447     win->cols[i] = win->cols[i+1];
448 }
449 
450 
rowDel(ButCol * col,int row_num)451 static void  rowDel(ButCol *col, int row_num)  {
452   int  i;
453 
454   assert(MAGIC(col));
455   assert(MAGIC(&col->rows[row_num]));
456   if (col->rows[row_num].buts != NULL)
457     wms_free(col->rows[row_num].buts);
458   --col->numRows;
459   for (i = row_num;  i < col->numRows;  ++i)
460     col->rows[i] = col->rows[i+1];
461 }
462 
463 
butWin_findButSetInRegion(ButWin * win,int x,int y,int w,int h,ButSet * butset)464 void  butWin_findButSetInRegion(ButWin *win, int x, int y, int w, int h,
465 				ButSet *butset)  {
466   assert(MAGIC(win));
467   butset->numButs = 0;
468   butset->dynamic = TRUE;
469   butWin_findButsInRegion(win, x,y, w,h, markForTable, butset);
470   if (butset->numButs > 0)  {
471     butset->buts = wms_malloc(butset->numButs * sizeof(But *));
472     butset->maxButs = butset->numButs;
473     butset->numButs = 0;
474     butWin_findButsInRegion(win, x,y, w,h, addToTable, butset);
475     qsort(butset->buts, butset->numButs, sizeof(But *), butcomp);
476   } else  {
477     butset->dynamic = FALSE;
478     butset->buts = NULL;
479   }
480 }
481 
482 
markForTable(But * but,void * packet)483 static int markForTable(But *but, void *packet)  {
484   ButSet *butset = packet;
485 
486   if (but == NULL) {
487     return(0);
488   }
489   assert(MAGIC(but));
490   if ((but->flags & (BUT_TABLED|BUT_DEAD|BUT_DRAWABLE)) == BUT_DRAWABLE)  {
491     ++butset->numButs;
492     but->flags |= BUT_TABLED;
493   }
494   return(0);
495 }
496 
497 
addToTable(But * but,void * packet)498 static int  addToTable(But *but, void *packet)  {
499   ButSet  *butset = packet;
500 
501   assert(MAGIC(but));
502   if (but->flags & BUT_TABLED)  {
503     butset->buts[butset->numButs++] = but;
504     assert(butset->numButs <= butset->maxButs);
505     but->flags &= ~BUT_TABLED;
506   }
507   return(0);
508 }
509 
510 
butcomp(const void * a,const void * b)511 static int  butcomp(const void *a, const void *b)  {
512   const But  *but_a = *(But **)a;
513   const But  *but_b = *(But **)b;
514 
515   assert(MAGIC(but_a));
516   assert(MAGIC(but_b));
517   if (but_a->layer != but_b->layer)
518     return(but_a->layer - but_b->layer);
519   else if (but_a > but_b)
520     return(-1);
521   else
522     return(1);
523 }
524 
525 
butEnv_findWin(ButEnv * env,Window win)526 ButWin  *butEnv_findWin(ButEnv *env, Window win)  {
527   int  wmin = 0, wmax = env->wllen, wnum;
528 
529 #if  DEBUG
530   for (wnum = 1;  wnum < env->wllen;  ++wnum)  {
531     assert(env->winlist[wnum]->win > env->winlist[wnum - 1]->win);
532   }
533 #endif  /* DEBUG */
534   while (wmin < wmax)  {
535     wnum = (wmax + wmin) >> 1;
536     assert(MAGIC(env->winlist[wnum]));
537     if (env->winlist[wnum]->win == win)  {
538       return(env->winlist[wnum]);
539     }
540     if (env->winlist[wnum]->win > win)  {
541       wmax = wnum;
542     } else  {
543       wmin = wnum + 1;
544     }
545   }
546   return(NULL);
547 }
548 
549 
butWin_findButsInRegion(ButWin * win,int x,int y,int w,int h,bool (* action)(But * but,void * packet),void * packet)550 But  *butWin_findButsInRegion(ButWin *win, int x,int y, int w,int h,
551 			      bool (*action)(But *but, void *packet),
552 			      void *packet)  {
553   int  r, c, b;
554   ButCol  *col;
555   ButRow  *row;
556   But *but;
557 
558   assert(MAGIC(win));
559   for (c = 1;  c < win->numCols - 1;  ++c)  {
560     col = &win->cols[c];
561     assert(MAGIC(col));
562     if ((col->startX < x+w) && (win->cols[c+1].startX > x))  {
563       for (r = 1;  r < col->numRows - 1;  ++r)  {
564 	row = &col->rows[r];
565 	assert(MAGIC(row));
566 	if ((row->startY < y+h) && (col->rows[r+1].startY > y))  {
567 	  for (b = 0;  b < row->numButs;  ++b)  {
568 	    but = row->buts[b];
569 	    assert(MAGIC(but));
570 	    if (action(but, packet))
571 	      return(but);
572 	  }
573 	}
574       }
575     }
576   }
577   return(NULL);
578 }
579 
580 
581 #if  0  /* Sometimes useful for debugging. */
582 void  printf_env(but_env_t  *env)  {
583   int  i;
584 
585   printf("Env has %d (max %d) windows:\n", env->wllen, env->wlmax);
586   for (i = 0;  i < env->wllen;  ++i)
587     printf("  0x%x (x win %d)\n", (int)env->winlist[i],
588 	   (int)(env->winlist[i]->win));
589 }
590 
591 
592 void  printf_table(but_win_t  *win)  {
593   int  i, j, k;
594 
595   for (i = 0;  i < win->numCols - 1;  ++i)  {
596     printf("Col %d of %d: %d..%d\n", i+1, win->numCols - 1,
597 	   win->cols[i].startX, win->cols[i+1].startX - 1);
598     for (j = 0;  j < win->cols[i].numRows - 1;  ++j)  {
599       printf("  Row %d of %d: %d..%d\n", j+1, win->cols[i].numRows - 1,
600 	     win->cols[i].rows[j].startY, win->cols[i].rows[j+1].startY - 1);
601       if (win->cols[i].rows[j].numButs == 0)
602 	printf("    No buttons.\n");
603       else  {
604 	for (k = 0;  k < win->cols[i].rows[j].numButs;  ++k)
605 	  printf("    But 0x%x\n", (int)win->cols[i].rows[j].buts[k]);
606       }
607     }
608   }
609   printf("---\n");
610 }
611 #endif
612 
613 
butSet_addBut(ButSet * butset,But * but)614 void  butSet_addBut(ButSet *butset, But *but)  {
615   int  i, new_maxButs;
616   But  **newbuts;
617 
618   assert(MAGIC(butset));
619   assert(butset->dynamic);
620   for (i = 0;  i < butset->numButs;  ++i)  {
621     if (butset->buts[i] == but)
622       return;
623   }
624   if (butset->numButs == butset->maxButs)  {
625     new_maxButs = (butset->maxButs + 1) * 2;
626     newbuts = wms_malloc(new_maxButs * sizeof(But *));
627     if (butset->buts != NULL)  {
628       memcpy(newbuts, butset->buts, butset->maxButs * sizeof(But *));
629       wms_free(butset->buts);
630     }
631     butset->buts = newbuts;
632     butset->maxButs = new_maxButs;
633   }
634   butset->buts[butset->numButs++] = but;
635 }
636 
637 
butSet_delBut(ButSet * butset,But * but)638 void  butSet_delBut(ButSet *butset, But *but)  {
639   int  i;
640 
641   assert(MAGIC(butset));
642   for (i = 0;  i < butset->numButs;  ++i)  {
643     if (butset->buts[i] == but)  {
644       butset->buts[i] = butset->buts[--butset->numButs];
645       return;
646     }
647   }
648 }
649 
650 
651 #endif
652