1 /*
2  * wmslib/src/but/i_general.c, part of wmslib (Library functions)
3  * Copyright (C) 1994,1997 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 #include <but/net.h>
28 #include <but/timer.h>
29 #include <but/canvas.h>
30 
31 
32 /**********************************************************************
33  * Forward Declarations
34  **********************************************************************/
35 static void  mousein(ButWin *win, int x, int y, ButSet *butset);
36 
37 
38 /**********************************************************************
39  * Globals
40  **********************************************************************/
41 bool  but_inEvent = FALSE;
42 
43 
44 /**********************************************************************
45  * Functions
46  **********************************************************************/
but_init(But * but)47 void  but_init(But *but)  {
48   ButWin  *win = but->win;
49   ButEnv  *env = win->env;
50   int  nfl;
51 
52   assert(MAGIC(win));
53   MAGIC_SET(but);
54   if (!(but->flags & BUT_DRAWABLE))
55     return;
56   if (win->maxLayer < win->minLayer)
57     win->maxLayer = win->minLayer = but->layer;
58   else  {
59     if (but->layer < win->minLayer)
60       win->minLayer = but->layer;
61     if (but->layer > win->maxLayer)
62       win->maxLayer = but->layer;
63   }
64   butSet_addBut(&win->butsNoDraw, but);
65   if (but->w > 0)
66     but_addToTable(but);
67   if (but->flags & BUT_KEYED)  {
68     if (win->keyBut != NULL)  {
69       nfl = win->keyBut->flags & ~BUT_KEYED;
70       if (env->last_mwin == win)
71 	nfl &= ~BUT_KEYACTIVE;
72       but_newFlags(win->keyBut, nfl);
73     }
74     win->keyBut = but;
75     if (env->last_mwin == win)
76       but->flags |= BUT_KEYACTIVE;
77   }
78   nfl = but->flags;
79   but->flags = BUT_DRAWABLE;  /* Force a new flags type redraw. */
80   but_newFlags(but, nfl);
81   butWin_mMove(env->last_mwin, env->last_mx, env->last_my);
82 }
83 
84 
but_resize(But * but,int x,int y,int w,int h)85 void  but_resize(But *but, int x, int y, int w, int h)  {
86   int  oldx = but->x, oldy = but->y, oldw = but->w, oldh = but->h;
87 
88   assert(MAGIC(but));
89   if ((oldx == x) && (oldy == y) && (oldw == w) && (oldh == h))
90     return;
91   if ((w <= 0) || (h <= 0))
92     w = h = 0;
93   if ((oldw > 0) && (but->flags & BUT_DRAWABLE))
94     but_delFromTable(but);
95   but->x = x;
96   but->y = y;
97   but->w = w;
98   but->h = h;
99   if ((w > 0) && (but->flags & BUT_DRAWABLE))
100     but_addToTable(but);
101   if (but->action->resize)  {
102     if (but->action->resize(but, oldx, oldy, oldw, oldh) &&
103 	(but->flags & BUT_DRAWABLE))  {
104       butWin_redraw(but->win, oldx,oldy, oldw,oldh);
105       butWin_redraw(but->win, x,y, w,h);
106     }
107   } else if (but->flags & BUT_DRAWABLE)  {
108     if ((oldw > 0) && (oldh > 0))
109       butWin_redraw(but->win, oldx,oldy, oldw,oldh);
110     butWin_redraw(but->win, x,y, w,h);
111   }
112   if (but->flags & BUT_DRAWABLE)
113     butWin_mMove(but->win->env->last_mwin,
114 		 but->win->env->last_mx, but->win->env->last_my);
115 }
116 
117 
but_destroy(But * but)118 void  but_destroy(But *but)  {
119   ButTimer  *timer;
120 
121   if (but != NULL)  {
122     assert(MAGIC(but));
123     but_newFlags(but, 0);
124     for (timer = but_timerList;  timer != NULL;  timer = timer->next)  {
125       if (timer->but == but)  {
126 	butTimer_destroy(timer);
127 	break;
128       }
129     }
130   }
131   if (but_inEvent)
132     but_dList(but);
133   else
134     but_delete(but);
135 }
136 
137 
but_create(ButWin * win,void * iPacket,const ButAction * action)138 But  *but_create(ButWin *win, void *iPacket, const ButAction *action)  {
139   But  *but;
140 
141   but = (But *)wms_malloc(sizeof(But));
142   MAGIC_SET(but);
143   assert(win->parent || (win->win != None));
144   but->uPacket = NULL;
145   but->iPacket = iPacket;
146   but->win = win;
147   but->layer = 0;
148   but->x = 0;
149   but->y = 0;
150   but->w = 0;
151   but->h = 0;
152   but->id = -2;
153   but->flags = 0;
154   but->keys = NULL;
155   but->action = action;
156   but->destroyCallback = NULL;
157   return(but);
158 }
159 
160 
but_delete(But * but)161 ButOut  but_delete(But *but)  {
162   ButOut  result = 0;
163   ButWin  *win = but->win;
164   int  x = but->x, y = but->y, w = but->w, h = but->h;
165 
166   assert(but != NULL);
167   assert(MAGIC(win));
168   assert(MAGIC(but));
169   if (but->flags)
170     but_newFlags(but, 0);
171   if (but->destroyCallback)
172     but->destroyCallback(but);
173   if (but->action->destroy != NULL)
174     result = but->action->destroy(but);
175   MAGIC_UNSET(but);
176   wms_free(but);
177   butWin_redraw(win, x,y,w,h);
178   return(result);
179 }
180 
181 
but_setFlags(But * but,uint fch)182 void  but_setFlags(But *but, uint fch)  {
183   uint  fl;
184 
185   assert(MAGIC(but));
186   fl = but->flags | fch;
187   fl &= ~(fch >> BUT_MAXBITS);
188   but_newFlags(but, fl);
189 }
190 
191 
but_setKeys(But * but,const ButKey * keys)192 void  but_setKeys(But *but, const ButKey *keys)  {
193   assert(MAGIC(but));
194   assert((but->action->kPress) || (but->action->kRelease));
195   but->keys = keys;
196 }
197 
198 
but_newFlags(But * but,uint nfl)199 void  but_newFlags(But *but, uint nfl)  {
200   static bool  inNewFlags = FALSE;
201   ButWin  *win = but->win, *tmpWin, *ancestor;
202   ButEnv  *env = win->env;
203   uint  oldflags = but->flags;
204 
205   assert(MAGIC(win));
206   assert(MAGIC(but));
207   for (ancestor = win;  ancestor->parent;  ancestor = ancestor->parent)
208     assert(MAGIC(ancestor));
209   if (!(nfl & BUT_PRESSABLE))  {
210     nfl &= ~(BUT_PRESSED|BUT_TWITCHED|BUT_LOCKED);
211     if (env->curhold == but)
212       butEnv_setCursor(env, but, butCur_idle);
213   }
214   if (!(oldflags & BUT_DRAWABLE) && (nfl & BUT_DRAWABLE))  {
215     but->flags = nfl;
216     but_init(but);
217     return;
218   }
219   if (!(nfl & BUT_DRAWABLE) && (env->butIn == but))  {
220     env->butIn = NULL;
221     for (tmpWin = win;  tmpWin;  tmpWin = tmpWin->parent)  {
222       assert(MAGIC(tmpWin));
223       tmpWin->butIn = NULL;
224     }
225   }
226   if ((oldflags & BUT_KEYED) && !(nfl & BUT_KEYED))  {
227     nfl &= ~BUT_KEYACTIVE;
228     ancestor->keyBut = NULL;
229   }
230   if (!(oldflags & BUT_KEYED) && (nfl & BUT_KEYED))  {
231     if (ancestor->keyBut != NULL)  {
232       but_newFlags(ancestor->keyBut, ancestor->keyBut->flags & ~BUT_KEYED);
233     }
234     ancestor->keyBut = but;
235     if (env->last_mwin == but->win)  {
236       nfl |= BUT_KEYACTIVE;
237     }
238   }
239   if ((but->id != -2) && !inNewFlags &&
240       ((nfl & BUT_NETMASK) != (but->flags & BUT_NETMASK)))  {
241     inNewFlags = TRUE;
242     butRnet_newFlags(env, but->id, nfl);
243     inNewFlags = FALSE;
244   }
245   if (!(oldflags & BUT_LOCKED) && (nfl & BUT_LOCKED))  {
246     if (env->lockBut != NULL)
247       but_newFlags(env->lockBut, env->lockBut->flags & ~BUT_LOCKED);
248     env->lockBut = but;
249     win->lock = but;
250     for (tmpWin = env->lockBut->win;  tmpWin->parent;
251 	 tmpWin = tmpWin->parent)  {
252       assert(MAGIC(tmpWin));
253       tmpWin->parent->lock = tmpWin->parentBut;
254     }
255   } else if ((oldflags & BUT_LOCKED) && !(nfl & BUT_LOCKED))  {
256     for (tmpWin = but->win;  tmpWin;  tmpWin = tmpWin->parent)  {
257       assert(MAGIC(tmpWin));
258       tmpWin->lock = NULL;
259     }
260     env->lockBut = NULL;
261   }
262   if (nfl != oldflags)  {
263     assert(but->action->newFlags);
264     but->action->newFlags(but, nfl);
265   }
266   if ((oldflags & BUT_DRAWABLE) && !(nfl & BUT_DRAWABLE))  {
267     if (but->w > 0)  {
268       but_delFromTable(but);
269     }
270   }
271   butWin_mMove(env->last_mwin, env->last_mx, env->last_my);
272 }
273 
274 
but_draw(But * but)275 void  but_draw(But *but)  {
276   assert(MAGIC(but));
277   if ((but->flags & (BUT_DRAWABLE|BUT_DEAD)) == BUT_DRAWABLE)
278     butWin_redraw(but->win, but->x,but->y, but->w,but->h);
279 }
280 
281 
butWin_mMove(ButWin * win,int x,int y)282 ButOut  butWin_mMove(ButWin *win, int x, int y)  {
283   ButEnv  *env;
284   ButOut  result = 0;
285   int  i;
286   But  *but, *oldbut;
287   ButSet  butset;
288   ButWin  *tmpWin;
289 
290   assert(MAGICNULL(win));
291   if (win == NULL)
292     return(0);
293   env = win->env;
294   if ((env->last_mwin != win) &&
295       (!env->last_mwin || (env->last_mwin->physWin != win->physWin)))  {
296     env->curwin = win->physWin;
297     env->curlast = butCur_bogus;
298   }
299   if (win->parent == NULL)  {
300     /* Only do this if you're on a real window, that is, not in a canvas. */
301     env->last_mwin = win;
302     env->last_mx = x;
303     env->last_my = y;
304   }
305   mousein(win, x, y, &butset);
306   for (i = butset.numButs - 1;  i >= 0;  --i)  {
307     but = butset.buts[i];
308     assert(MAGIC(but));
309     if ((but->flags & BUT_DRAWABLE) && !(but->flags & BUT_PRESSTHRU))  {
310       if (but->action->mMove == NULL)
311 	result |= BUTOUT_CAUGHT;
312       else
313 	result |= but->action->mMove(but, x,y);
314       if (result & BUTOUT_CAUGHT)  {
315 	if (result & BUTOUT_IGNORE)
316 	  return(result);
317 	if (env->butIn != but)  {
318 	  if (env->butIn != NULL)  {
319 	    for (tmpWin = env->butIn->win;  tmpWin;
320 		 tmpWin = tmpWin->parent)  {
321 	      tmpWin->butIn = NULL;
322 	    }
323 	    if ((env->butIn->flags & BUT_PRESSABLE) &&
324 		(env->butIn->action->mLeave != NULL))
325 	      result |= env->butIn->action->mLeave(env->butIn);
326 	  }
327 	  env->butIn = but;
328 	  but->win->butIn = but;
329 	  for (tmpWin = but->win;  tmpWin->parent;  tmpWin = tmpWin->parent)  {
330 	    tmpWin->parent->butIn = tmpWin->parentBut;
331 	  }
332 	}
333 	return(result);
334       }
335     }
336   }
337   if (env->butIn != NULL)  {
338     oldbut = env->butIn;
339     for (tmpWin = env->butIn->win;  tmpWin;  tmpWin = tmpWin->parent)  {
340       tmpWin->butIn = NULL;
341     }
342     env->butIn = NULL;
343     if ((oldbut->flags & BUT_PRESSABLE) && (oldbut->action->mLeave != NULL))
344       result |= oldbut->action->mLeave(oldbut);
345   }
346   return(result);
347 }
348 
349 
butWin_mPress(ButWin * win,int x,int y,int butnum)350 ButOut  butWin_mPress(ButWin *win, int x, int y, int butnum)  {
351   ButOut  result;
352   But  *but;
353 
354   assert(MAGIC(win));
355   result = butWin_mMove(win, x, y);
356   but = win->butIn;
357   if (but != NULL)  {
358     assert(MAGIC(but));
359     if ((but->flags & BUT_PRESSABLE) && (but->action->mPress != NULL))  {
360       return(result | but->action->mPress(but, butnum, x, y));
361     }
362   }
363   return(result | BUTOUT_ERR);
364 }
365 
366 
butWin_mRelease(ButWin * win,int x,int y,int butnum)367 ButOut  butWin_mRelease(ButWin *win, int x, int y, int butnum)  {
368   ButOut  result;
369   But  *but;
370 
371   assert(MAGIC(win));
372   result = butWin_mMove(win, x, y);
373   but = win->butIn;
374   if (but != NULL)  {
375     assert(MAGIC(but));
376     if ((but->flags & BUT_PRESSABLE) && (but->action->mRelease != NULL))
377     return(result | but->action->mRelease(but, butnum, x, y));
378   }
379   return(result);
380 }
381 
382 
keycheck(But * but,void * packet)383 static int  keycheck(But *but, void *packet)  {
384   int  keycount;
385   KeySym  sym = *(KeySym *)packet;
386 
387   assert(MAGIC(but));
388   if (but->keys != NULL)  {
389     for (keycount = 0;  but->keys[keycount].key != 0;  ++keycount)  {
390       if ((but->keys[keycount].key == sym) &&
391 	  ((but->win->env->keyModifiers & but->keys[keycount].modMask) ==
392 	   but->keys[keycount].modifiers))
393 	return(1);
394     }
395   }
396   return(0);
397 }
398 
399 
butWin_kPress(ButWin * win,const char * keystr,KeySym sym)400 ButOut  butWin_kPress(ButWin *win, const char *keystr, KeySym sym)  {
401   ButOut  retVal = 0;
402   But  *but;
403 
404   assert(MAGIC(win));
405   /*
406    * The keybut _always_ get a shot at the key when it is pressed.
407    */
408   if (win->keyBut)  {
409     assert(win->keyBut->flags & BUT_PRESSABLE);
410     retVal |= win->keyBut->action->kPress(win->keyBut, keystr, sym);
411   }
412   if (!(retVal & BUTOUT_CAUGHT))  {
413     but = butWin_findButsInRegion(win, 0,0, win->w,win->h, keycheck, &sym);
414     if ((but != NULL) && (but->flags & BUT_PRESSABLE) &&
415 	(but->action->kPress != NULL))  {
416       assert(MAGIC(but));
417       retVal |= but->action->kPress(but, keystr, sym);
418     } else  {
419       /*
420        * A key was pressed that nobody wanted.
421        * But only signal an error if it was a "real" key...don't beep when
422        *   some poor guy presses shift!
423        */
424       if (!IsModifierKey(sym))
425 	retVal |= BUTOUT_ERR;
426     }
427   }
428   return(retVal);
429 }
430 
431 
butWin_kRelease(ButWin * win,const char * keystr,KeySym sym)432 ButOut  butWin_kRelease(ButWin *win, const char *keystr, KeySym sym)  {
433   ButOut  retval = 0;
434   But  *but;
435 
436   assert(MAGIC(win));
437   but = butWin_findButsInRegion(win, 0,0, win->w,win->h, keycheck, &sym);
438   if (but != NULL)  {
439     assert(MAGIC(but));
440     if ((but->flags & BUT_PRESSABLE) && (but->action->kRelease != NULL))
441       retval |= but->action->kRelease(but, keystr, sym);
442   }
443   return(retval);
444 }
445 
446 
447 /* mousein(win, x, y, reason) will return the button number that the mouse is
448  *   presently inside of.  If the mouse is not in any button NULL will
449  *   be returned.
450  * The checkfunc will be called only if the mouse is already inside the
451  *   (x,y,w,h) boundaries of the button.  "reason" is one of BUT_RE_PRESS,
452  *   BUT_RE_RELEASE, or BUT_RE_MOVE, depending on the reason for the button
453  *   to be checked.
454  * Non-pressable buttons will never be returned.
455  *
456  * NOTE: This does a linear search through the buttons.  YUCK!  SLOW!  I'd
457  *   like to recode this to do a three-dimensional binary search (the
458  *   dimensions being window, x, and y) but that would take some seriously
459  *   heavy-duty coding and I have a million other things to do first.
460  *
461  * NOTE to note: I finally did the 3d binary search.  Works great!
462  */
mousein(ButWin * win,int x,int y,ButSet * butset)463 static void  mousein(ButWin *win, int x, int y, ButSet *butset)  {
464   static But  *but;
465 
466   assert(MAGIC(win));
467   if (win->lock)  {
468     butset->dynamic = FALSE;
469     butset->numButs = 1;
470     butset->buts = &but;
471     but = win->lock;
472   } else
473     butWin_findButSet(win, x, y, butset);
474 }
475 
476 
but_compare(const void * a,const void * b)477 static int  but_compare(const void *a, const void *b)  {
478   But **but_a = (But **)a, **but_b = (But **)b;
479 
480   assert(MAGIC(*but_a));
481   assert(MAGIC(*but_b));
482   return((*but_a)->layer - (*but_b)->layer);
483 }
484 
485 
butWin_redraw(ButWin * win,int x,int y,int w,int h)486 void  butWin_redraw(ButWin *win, int x, int y, int w, int h)  {
487   ButWinArea  *newAreas;
488   int  newMaxRedraws, i;
489   bool  change;
490 
491   assert((x > -1000) && (y > -1000));
492   if (!w || !h)
493     return;
494   assert(w > 0);
495   assert(h > 0);
496   if (win->numRedraws + 1 >= win->maxRedraws)  {
497     newMaxRedraws = (win->maxRedraws + 1) * 2;
498     newAreas = wms_malloc(newMaxRedraws * sizeof(ButWinArea));
499     for (i = 0;  i < win->numRedraws;  ++i)  {
500       newAreas[i] = win->redraws[i];
501     }
502     if (win->redraws)
503       wms_free(win->redraws);
504     win->redraws = newAreas;
505     win->maxRedraws = newMaxRedraws;
506   }
507   assert(win->numRedraws < win->maxRedraws);
508   do  {
509     assert(w > 0);
510     assert(h > 0);
511     change = FALSE;
512     for (i = 0;  i < win->numRedraws;  ++i)  {
513       if ((x <= win->redraws[i].x + win->redraws[i].w) &&
514 	  (y <= win->redraws[i].y + win->redraws[i].h) &&
515 	  (x + w >= win->redraws[i].x) &&
516 	  (y + h >= win->redraws[i].y))  {
517 	change = TRUE;
518 	if (win->redraws[i].x < x)  {
519 	  w += x - win->redraws[i].x;
520 	  x = win->redraws[i].x;
521 	}
522 	if (win->redraws[i].y < y)  {
523 	  h += y - win->redraws[i].y;
524 	  y = win->redraws[i].y;
525 	}
526 	if (x + w < win->redraws[i].x + win->redraws[i].w)
527 	  w = win->redraws[i].x + win->redraws[i].w - x;
528 	if (y + h < win->redraws[i].y + win->redraws[i].h)
529 	  h = win->redraws[i].y + win->redraws[i].h - y;
530 	win->redraws[i] = win->redraws[--win->numRedraws];
531       }
532     }
533   } while (change);
534   win->redraws[win->numRedraws].x = x;
535   win->redraws[win->numRedraws].y = y;
536   win->redraws[win->numRedraws].w = w;
537   win->redraws[win->numRedraws].h = h;
538   assert(w > 0);
539   assert(h > 0);
540   ++win->numRedraws;
541   assert(win->numRedraws < win->maxRedraws);
542 }
543 
544 
butWin_performDraws(ButWin * win)545 void  butWin_performDraws(ButWin *win)  {
546   int  drawNum;
547   int  i, drx,dry, drw,drh, x, y, w, h;
548   ButEnv  *env = win->env;
549   XRectangle  cliprect;
550   ButSet  butset;
551   But  *but;
552 
553   assert(MAGIC(win));
554   if (!win->mapped)  {
555     win->numRedraws = 0;
556     return;
557   }
558   for (drawNum = 0;  drawNum < win->numRedraws;  ++drawNum)  {
559     x = win->redraws[drawNum].x;
560     y = win->redraws[drawNum].y;
561     w = win->redraws[drawNum].w;
562     h = win->redraws[drawNum].h;
563     assert(w > 0);
564     assert(h > 0);
565     if (x < win->xOff)  {
566       w -= win->xOff - x;
567       x = win->xOff;
568     }
569     if (x + w > win->xOff + win->w)
570       w = win->xOff + win->w - x;
571     if (y < win->yOff)  {
572       h -= win->yOff - y;
573       y = win->yOff;
574     }
575     if (y + h > win->yOff + win->h)
576       h = win->yOff + win->h - y;
577     if ((w <= 0) || (h <= 0))
578       continue;
579     if (win->id != -2)
580       butRcur_redraw(env, win->id, x,y,w,h);
581     butWin_findButSetInRegion(win, x,y, w,h, &butset);
582     if (butset.numButs > 0)  {
583       cliprect.x = x - win->xOff;
584       cliprect.y = y - win->yOff;
585       cliprect.width = w;
586       cliprect.height = h;
587       XSetClipRectangles(env->dpy, env->gc, 0,0, &cliprect, 1, YXSorted);
588       qsort(butset.buts, butset.numButs, sizeof(But *), but_compare);
589       assert(MAGIC(win));
590       for (i = butset.numButs - 1;  i > 0;  --i)  {
591 	but = butset.buts[i];
592 	assert(MAGIC(but));
593 	if ((but->flags & BUT_OPAQUE) && (but->x <= x) && (but->y <= y) &&
594 	    (but->x + but->w >= x + w) && (but->y + but->h >= y + h))
595 	  break;
596       }
597       for (;  i < butset.numButs;  ++i)  {
598 	but = butset.buts[i];
599 	assert(MAGIC(but));
600 	if (!(but->flags & BUT_DEAD))  {
601 	  if (but->x < x)
602 	    drx = x;
603 	  else
604 	    drx = but->x;
605 	  if (but->y < y)
606 	    dry = y;
607 	  else
608 	    dry = but->y;
609 	  if (but->x + but->w < x+w)
610 	    drw = but->x + but->w - drx;
611 	  else
612 	    drw = x + w - drx;
613 	  if (but->y + but->h < y+h)
614 	    drh = but->y + but->h - dry;
615 	  else
616 	    drh = y+h - dry;
617 	  but->action->draw(but, x,y, w,h);
618 	}
619       }
620       XSetClipMask(env->dpy, env->gc, None);
621       butSet_destroy(&butset);
622       if (win->parent)  {
623 	/*
624 	 * It's a canvas.  Fire off a redraw request so that the changes to
625 	 *   the canvas pixmap will be seen on the screen.
626 	 */
627 	butCan_redrawn(win, x, y, w, h);
628       }
629     }
630   }
631   win->numRedraws = 0;
632 }
633 
634 
butSet_destroy(ButSet * butset)635 void  butSet_destroy(ButSet *butset)  {
636   if (butset->dynamic && (butset->buts != NULL))
637     wms_free(butset->buts);
638 }
639 
640 
641 /* If win is NULL it will execute all destroy commands built up. */
butWin_dList(ButWin * win)642 ButOut  butWin_dList(ButWin *win)  {
643   static ButWin  **dlist = NULL;
644   static int  dlist_len = 0, max_dlist_len = 0;
645   ButWin  **new_dlist;
646   int  i;
647   ButOut  result = 0;
648 
649   assert(MAGICNULL(win));
650   if (win == NULL)  {
651     /*
652      * It is really important that we start at the end here.  Since our
653      *   child windows are added to the _end_ of the dlist, and they _must_
654      *   be destroyed first, we have to go backwards.
655      */
656     while (dlist_len)  {
657       i = dlist_len - 1;
658       if (dlist[i] != NULL)  {
659 	assert(MAGIC(dlist[i]));
660 	result |= butWin_delete(dlist[i]) | BUTOUT_CAUGHT;
661 	if (result & BUTOUT_STILLBUTS)  {
662 	  /* Window still has buttons...can't kill it yet! */
663 	  return(result & ~BUTOUT_STILLBUTS);
664 	}
665 	dlist[i] = NULL;
666       }
667       --dlist_len;
668     }
669   } else  {
670     if (win->iconWin != NULL)  {
671       butWin_dList(win->iconWin);
672       win->iconWin = NULL;
673     }
674     if (dlist_len+1 > max_dlist_len)  {
675       new_dlist = wms_malloc(sizeof(ButWin *) * (dlist_len * 2 + 2));
676       for (i = 0;  i < dlist_len;  ++i)
677 	new_dlist[i] = dlist[i];
678       if (dlist != NULL)
679 	wms_free(dlist);
680       dlist = new_dlist;
681       max_dlist_len = (dlist_len * 2 + 2);
682     }
683     for (i = 0;  i < dlist_len;  ++i)
684       if (dlist[i] == win)
685 	return(result);
686     dlist[dlist_len++] = win;
687   }
688   return(result);
689 }
690 
691 
692 /* If but is NULL it will execute all destroy commands built up. */
but_dList(But * but)693 ButOut  but_dList(But *but)  {
694   static But  **dlist = NULL;
695   static int  dlist_len = 0, max_dlist_len = 0;
696   But  **new_dlist;
697   int  i;
698   ButOut  result = 0;
699 
700   if (but == NULL)  {
701     if (dlist_len == 0)
702       return(0);
703     for (i = 0;  i < dlist_len;  ++i)  {
704       result |= but_delete(dlist[i]) | BUTOUT_CAUGHT;
705     }
706     dlist_len = 0;
707   } else  {
708     if (dlist_len+1 > max_dlist_len)  {
709       new_dlist = wms_malloc(sizeof(But *) * (dlist_len * 2 + 2));
710       for (i = 0;  i < dlist_len;  ++i)
711 	new_dlist[i] = dlist[i];
712       if (dlist != NULL)
713 	wms_free(dlist);
714       dlist = new_dlist;
715       max_dlist_len = (dlist_len * 2 + 2);
716     }
717     for (i = 0;  i < dlist_len;  ++i)
718       if (dlist[i] == but)
719 	return(result);
720     but_newFlags(but, 0);
721     dlist[dlist_len++] = but;
722     but->flags |= BUT_DEAD;
723   }
724   return(result);
725 }
726 
727 
but_flags(But * but,uint flags)728 void  but_flags(But *but, uint flags)  {
729   but->flags = flags;
730   but_draw(but);
731 }
732 
733 
734 #endif  /* X11_DISP */
735