]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/zwgc/xshow.c
eace3f86d83d6d76617f777c23df05e90ddc14ac
[1ts-debian.git] / zephyr / zwgc / xshow.c
1 /* This file is part of the Project Athena Zephyr Notification System.
2  * It is one of the source files comprising zwgc, the Zephyr WindowGram
3  * client.
4  *
5  *      Created by:     Marc Horowitz <marc@athena.mit.edu>
6  *
7  *      $Id: xshow.c 2336 2009-03-22 18:59:56Z kcr $
8  *
9  *      Copyright (c) 1989 by the Massachusetts Institute of Technology.
10  *      For copying and distribution information, see the file
11  *      "mit-copyright.h".
12  */
13
14 #include <sysdep.h>
15
16 #if (!defined(lint) && !defined(SABER))
17 static const char rcsid_xshow_c[] = "$Id: xshow.c 2336 2009-03-22 18:59:56Z kcr $";
18 #endif
19
20 #include <zephyr/mit-copyright.h>
21
22 #ifndef X_DISPLAY_MISSING
23
24 #include <X11/Xlib.h>
25 #include <X11/Xutil.h>
26 #include <X11/Xresource.h>
27 #include <zephyr/zephyr.h>
28 #include "pointer_dictionary.h"
29 #include "new_memory.h"
30 #include "new_string.h"
31 #include "formatter.h"
32 #include "variables.h"
33 #include "zwgc.h"
34 #include "X_driver.h"
35 #include "X_fonts.h"
36 #include "X_gram.h"
37 #include "xmode_stack.h"
38 #ifdef CMU_ZWGCPLUS
39 #include <zephyr/zephyr.h>
40 #include "xrevstack.h"
41 #include "plus.h"
42 #include "xcut.h"
43 #endif
44
45 #define max(a,b)   ((a)>(b)?(a):(b))
46
47 XContext desc_context;
48
49 extern int internal_border_width;
50 extern unsigned long default_bgcolor;
51 extern unsigned long default_fgcolor;
52
53 void
54 xshowinit(void)
55 {
56     desc_context = XUniqueContext();
57 }
58
59 struct res_dict_type {
60     pointer_dictionary  dict;
61     char *              resname_suffix;
62     char *              resclass;
63 };
64
65 static char *
66 xres_get_resource(struct res_dict_type *restype,
67                   char *style)
68 {
69    char *desc;
70    pointer_dictionary_binding *binding;
71    int exists;
72    char *value;
73
74    desc=string_Concat("style.", style);
75    desc=string_Concat2(desc, restype->resname_suffix);
76
77    if (!restype->dict)
78       restype->dict = pointer_dictionary_Create(37);
79    binding = pointer_dictionary_Define(restype->dict, desc, &exists);
80
81    if (exists) {
82       free(desc);
83       return((string) binding->value);
84    } else {
85       value=get_string_resource(desc, restype->resclass);
86       free(desc);
87       if (value==NULL)
88          pointer_dictionary_Delete(restype->dict, binding);
89       else
90          binding->value=(pointer) value;
91       return value;  /* If resource returns NULL, return NULL also */
92    }
93 }
94
95 static struct res_dict_type geometry_resources = {
96     NULL, ".geometry", "StyleKey.Style1.Style2.Style3.GeometryKey",
97 };
98
99 static struct res_dict_type bgcolor_resources = {
100     NULL, ".background", "StyleKey.Style1.Style2.Style3.BackgroundKey",
101 };
102
103 #define xres_get_geometry(style) xres_get_resource(&geometry_resources,style)
104 #define xres_get_bgcolor(style)  xres_get_resource(&bgcolor_resources,style)
105
106 static struct res_dict_type fgcolor_resources = {
107     NULL, ".foreground",
108     "StyleKey.Style1.Style2.Style3.SubstyleKey.Substyle.ForegroundKey",
109 };
110
111 /*ARGSUSED*/
112 char *
113 mode_to_colorname (Display *dpy,
114                    char *style,
115                    xmode *mode)
116 {
117     char *desc, *result;
118
119     desc = string_Concat (style, ".substyle.");
120     desc = string_Concat2 (desc, mode->substyle);
121     result = xres_get_resource (&fgcolor_resources, desc);
122     free (desc);
123     return result;
124 }
125
126 void
127 fixup_and_draw(Display *dpy,
128                char *style,
129                xauxblock *auxblocks,
130                xblock *blocks,
131                int num,
132                xlinedesc *lines,
133                int numlines,
134                int beepcount)
135 {
136     int gram_xalign = 1;
137     int gram_yalign = 1;
138     int gram_xpos, gram_ypos, gram_xsize, gram_ysize;
139
140     x_gram *gram;
141     int strindex = 0;
142
143     int line, block=0;
144     int maxwidth=0, chars=0, maxascent, maxdescent;
145     int ssize,  lsize,csize, rsize, width = 0;
146     int i, ascent, descent;
147
148     int yofs = internal_border_width;
149     int lofs, cofs, rofs;
150     int ystart,yend;
151
152     char *bgstr, *geometry, xpos[10], ypos[10], xfrom, yfrom;
153
154     gram = (x_gram *)malloc(sizeof(x_gram));
155
156     /* Find total lengths of left, center, and right parts.  Also find the
157        length of the longest line and the total number of characters. */
158
159     for (line=0; line<numlines; line++) {
160         lsize = csize = rsize = 0;
161         maxascent = maxdescent = 0;
162         
163         /* add up sizes for each block, get max ascent and descent */
164         
165         for (i=0; i<lines[line].numblock; i++,block++) {
166             chars += auxblocks[block].len;
167             ssize = XTextWidth(auxblocks[block].font, auxblocks[block].str,
168                                auxblocks[block].len);
169             auxblocks[block].width = ssize;
170             ascent = auxblocks[block].font->ascent;
171             descent = auxblocks[block].font->descent;
172             if (ascent>maxascent)
173               maxascent = ascent;
174             if (descent>maxdescent)
175               maxdescent = descent;
176             switch (auxblocks[block].align) {
177               case LEFTALIGN:
178                 lsize += ssize;
179                 break;
180                 
181               case CENTERALIGN:
182                 csize += ssize;
183                 break;
184                 
185               case RIGHTALIGN:
186                 rsize += ssize;
187                 break;
188             }
189         }
190         
191         /* save what we need to do size fixups */
192         
193         if (maxascent>lines[line].ascent)
194           lines[line].ascent = maxascent;
195         if (maxdescent>lines[line].descent)
196           lines[line].descent = maxdescent;
197         lines[line].lsize = lsize;
198         lines[line].csize = csize;
199         lines[line].rsize = rsize;
200         
201         /* get width of line and see if it is bigger than the max width */
202
203         switch ((lsize?1:0)+(csize?2:0)+(rsize?4:0)) {
204 #ifdef DEBUG
205           default:
206             abort();
207 #endif
208             
209           case 0:
210             width = 0;
211             break;
212             
213           case 1:
214             width = lsize;
215             break;
216             
217           case 2:
218             width = csize;
219             break;
220             
221           case 3:
222             /* in all these cases, we just want to add the width of *any*
223                space, so the first font will do just fine. */
224             /* XXX implicit assumption that a line must have at least one
225                block, so that there is indeed a reasonable font in
226                auxblocks[0].font */
227             width = lsize*2+csize+XTextWidth(auxblocks[0].font," ",1);
228             break;
229             
230           case 4:
231             width = rsize;
232             break;
233             
234           case 5:
235             width = lsize+rsize+XTextWidth(auxblocks[0].font, " ", 1);
236             break;
237             
238           case 6:
239             width = csize+rsize*2+XTextWidth(auxblocks[0].font, " ", 1);
240             break;
241             
242           case 7:
243             width = max(lsize,rsize)*2+csize+
244               XTextWidth(auxblocks[0].font," ",1)*2;
245             break;
246         }
247         if (width>maxwidth)
248           maxwidth = width;
249     }
250
251     /* fixup x,y for each block, create big string and indices into it */
252     /* set x1,y1,x2,y2 of each block also. */
253
254     gram->text = (char *)malloc(chars);
255     block = 0;
256
257     for (line=0; line<numlines; line++) {
258         lofs = internal_border_width;
259         cofs = ((maxwidth-lines[line].csize)>>1) + internal_border_width;
260         rofs = maxwidth-lines[line].rsize + internal_border_width;
261         ystart = yofs;
262         yofs += lines[line].ascent;
263         yend = yofs+lines[line].descent+1;   /* +1 because lines look scrunched
264                                                 without it. */
265
266         for (i=0; i<lines[line].numblock; i++,block++) {
267             blocks[block].fid = auxblocks[block].font->fid;
268             switch (auxblocks[block].align) {
269               case LEFTALIGN:
270                 blocks[block].x = lofs;
271                 blocks[block].x1 = lofs;
272                 lofs += auxblocks[block].width;
273                 blocks[block].x2 = lofs;
274                 break;
275                 
276               case CENTERALIGN:
277                 blocks[block].x = cofs;
278                 blocks[block].x1 = cofs;
279                 cofs += auxblocks[block].width;
280                 blocks[block].x2 = cofs;
281                 break;
282
283               case RIGHTALIGN:
284                 blocks[block].x = rofs;
285                 blocks[block].x1 = rofs;
286                 rofs += auxblocks[block].width;
287                 blocks[block].x2 = rofs;
288                 break;
289             }
290             blocks[block].y = yofs;
291             blocks[block].y1 = ystart;
292             blocks[block].y2 = yend;
293             blocks[block].strindex = strindex;
294             blocks[block].strlen = auxblocks[block].len;
295             strncpy(gram->text+strindex, auxblocks[block].str,
296                     auxblocks[block].len);
297             strindex += blocks[block].strlen;
298         }
299
300         yofs = yend;
301
302     }
303
304     if ((geometry = var_get_variable("X_geometry")),(geometry[0]=='\0')) 
305       if ((geometry = xres_get_geometry(style))==NULL)
306         if ((geometry = var_get_variable("default_X_geometry")),
307             (geometry[0]=='\0'))
308           geometry = "+0+0";
309     sscanf(geometry, "%c%[0123456789c]%c%[0123456789c]", &xfrom, xpos,
310            &yfrom, ypos);
311
312     if (xpos[0]=='c') {
313       gram_xalign = 0;
314       gram_xpos = 0;
315     } else
316       gram_xpos = atoi(xpos);
317     if (xfrom=='-')
318       gram_xalign *= -1;
319
320     if (ypos[0]=='c') {
321       gram_yalign = 0;
322       gram_ypos = 0;
323     } else
324       gram_ypos = atoi(ypos);
325     if (yfrom=='-')
326       gram_yalign *= -1;
327
328     if ((bgstr = var_get_variable("X_background")),(bgstr[0]=='\0'))
329       if ((bgstr = xres_get_bgcolor(style))==NULL)
330         if ((bgstr = var_get_variable("default_X_background")),
331             (bgstr[0]=='\0'))
332           gram->bgcolor = default_bgcolor;
333     if (bgstr && bgstr[0])
334       gram->bgcolor = x_string_to_color(bgstr,default_bgcolor);
335
336     
337     gram_xsize = maxwidth+(internal_border_width<<1);
338     gram_ysize = yofs+internal_border_width;
339     gram->numblocks = num;
340     gram->blocks = blocks;
341 #ifdef CMU_ZWGCPLUS
342     gram->notice = get_stored_notice();
343 #endif
344     
345     x_gram_create(dpy, gram, gram_xalign, gram_yalign, gram_xpos,
346                   gram_ypos, gram_xsize, gram_ysize, beepcount);
347 }
348
349 /* Silly almost-but-not-quite-useless helper function */
350 char *
351 no_dots_downcase_var(char *str)
352 {
353    register char *var, *var2;
354
355    var = string_Downcase(var_get_variable(str));
356    var2 = var;
357    while (*var++)
358       if (*var == '.')
359          *var = '_';
360    return(var2);
361 }
362
363 #define MODE_TO_FONT(dpy,style,mode) \
364   get_font((dpy),(style),(mode)->font?(mode)->font:(mode)->substyle, \
365            (mode)->size, (mode)->bold+(mode)->italic*2)
366 void
367 xshow(Display *dpy,
368       desctype *desc,
369       int numstr,
370       int numnl)
371 {
372     XFontStruct *font;
373     xmode_stack modes = xmode_stack_create();
374     xmode curmode;
375     xlinedesc *lines;
376     xblock *blocks;
377     xauxblock *auxblocks;
378     int nextblock=0;
379     int line=0,linestart=0;
380     char *style;
381     int free_style = 0;
382     int beepcount = 0;
383
384     lines = (xlinedesc *)malloc(sizeof(xlinedesc)*(numnl+1));
385
386     blocks = (xblock *)malloc(sizeof(xblock)*numstr);
387     auxblocks = (xauxblock *)malloc(sizeof(xauxblock)*numstr);
388
389     curmode.bold = 0;
390     curmode.italic = 0;
391     curmode.size = MEDIUM_SIZE;
392     curmode.align = LEFTALIGN;
393     curmode.expcolor = 0;
394     curmode.substyle = string_Copy("default");
395     curmode.font = NULL;
396
397     style = var_get_variable("style");
398     if (style[0] == '\0') {
399        style = string_Concat(no_dots_downcase_var("class"),".");
400        style = string_Concat2(style,no_dots_downcase_var("instance"));
401        style = string_Concat2(style,".");
402        style = string_Concat2(style,no_dots_downcase_var("sender"));
403        string_Downcase(style);
404        free_style = 1;
405     }
406
407     for (; desc->code!=DT_EOF; desc=desc->next) {
408         switch (desc->code) {
409           case DT_ENV:
410             xmode_stack_push(modes, curmode);
411             curmode.substyle = string_Copy(curmode.substyle);
412             if (curmode.font)
413               curmode.font = string_Copy(curmode.font);
414             
415 #define envmatch(string,length) ((desc->len==(length)) && (strncasecmp(desc->str,(string),(length))==0))
416
417             if (envmatch("roman",5)) {
418                 curmode.bold = 0;
419                 curmode.italic = 0;
420             } else if (envmatch("bold",4) || envmatch("b",1))
421               curmode.bold = 1;
422             else if (envmatch("italic",6)||envmatch("i",1))
423               curmode.italic = 1;
424             else if (envmatch("large",5))
425               curmode.size = LARGE_SIZE;
426             else if (envmatch("medium",6))
427               curmode.size = MEDIUM_SIZE;
428             else if (envmatch("small",5))
429               curmode.size = SMALL_SIZE;
430             else if (envmatch("left",4)||envmatch("l",1))
431               curmode.align = LEFTALIGN;
432             else if (envmatch("center",6)||envmatch("c",1))
433               curmode.align = CENTERALIGN;
434             else if (envmatch("right",5)||envmatch("r",1))
435               curmode.align = RIGHTALIGN;
436             else if (envmatch("beep",4))
437               beepcount++;
438             else if (envmatch("font",4)) {
439                /* lookahead needed.  desc->next->str should be the
440                   font name, and desc->next->next->code should be
441                   a DT_END*/
442                if ((desc->next) &&
443                    (desc->next->next) &&
444                    (desc->next->code == DT_STR) &&
445                    (desc->next->next->code==DT_END)) {
446
447                   /* Since @font mutates the current environment, we have
448                      to pop the environment that this case usually pushes */
449                   free(curmode.substyle);
450                   curmode = xmode_stack_top(modes);
451                   xmode_stack_pop(modes);
452
453                   /* mutating... */
454                   curmode.size=SPECIAL_SIZE; /* This is an @font() */
455                   curmode.font=string_CreateFromData(desc->next->str,
456                                                      desc->next->len);
457                   /* skip over the rest of the @font */
458                   desc=desc->next->next;
459                }
460             } else if (envmatch("color",5)) {
461                /* lookahead needed.  desc->next->str should be the
462                   font name, and desc->next->next->code should be
463                   a DT_END*/
464                if ((desc->next) &&
465                    (desc->next->next) &&
466                    (desc->next->code == DT_STR) &&
467                    (desc->next->next->code==DT_END)) {
468                   char *colorname;
469
470                   /* Since @font mutates the current environment, we have
471                      to pop the environment that this case usually pushes */
472                   free(curmode.substyle);
473                   curmode = xmode_stack_top(modes);
474                   xmode_stack_pop(modes);
475
476                   /* mutating... */
477                   colorname=string_CreateFromData(desc->next->str,
478                                                   desc->next->len);
479                   curmode.color = x_string_to_color(colorname,default_fgcolor);
480                   free(colorname);
481                   curmode.expcolor = 1;
482                   /* skip over the rest of the @font */
483                   desc=desc->next->next;
484                }
485             } else if (desc->len > 0) { /* avoid @{...} */
486                free(curmode.substyle);
487                if (curmode.font) {
488                   free(curmode.font);
489                   curmode.font = NULL;
490                }
491                curmode.substyle = string_CreateFromData(desc->str, desc->len);
492             }
493             break;
494
495           case DT_STR:
496             auxblocks[nextblock].align = curmode.align;
497             auxblocks[nextblock].font = MODE_TO_FONT(dpy,style,&curmode);
498             auxblocks[nextblock].str = desc->str;
499             auxblocks[nextblock].len = desc->len;
500             if (curmode.expcolor)
501                blocks[nextblock].fgcolor = curmode.color;
502             else
503                blocks[nextblock].fgcolor =
504                  x_string_to_color(mode_to_colorname(dpy,style,&curmode),
505                                    default_fgcolor);
506             nextblock++;
507             break;
508
509           case DT_END:
510             free(curmode.substyle);
511             curmode = xmode_stack_top(modes);
512             xmode_stack_pop(modes);
513             break;
514
515           case DT_NL:
516             lines[line].startblock = linestart;
517             lines[line].numblock = nextblock-linestart;
518             font = MODE_TO_FONT(dpy,style,&curmode);
519             lines[line].ascent = font->ascent;
520             lines[line].descent = font->descent;
521             line++;
522             linestart = nextblock;
523             break;
524         }
525     }
526
527     /* case DT_EOF:    will drop through to here. */
528
529     if (linestart != nextblock) {
530        lines[line].startblock = linestart;
531        lines[line].numblock = nextblock-linestart;
532        font = MODE_TO_FONT(dpy,style,&curmode);
533        lines[line].ascent = 0;
534        lines[line].descent = 0;
535        line++;
536     }
537     
538     free(curmode.substyle);
539     fixup_and_draw(dpy, style, auxblocks, blocks, nextblock, lines, line,
540                    beepcount);
541     free(lines);
542     free(auxblocks);
543     if (free_style)
544       free(style);
545 }
546
547 static void
548 xhandleevent(Display *dpy,
549              Window w,
550              XEvent *event)
551 {
552     x_gram *gram;
553     
554     if (XFindContext(dpy, w, desc_context, (caddr_t *)&gram))
555       return;
556
557     if (event->type == Expose)
558       x_gram_expose(dpy, w, gram,&(event->xexpose));
559     else
560       xcut(dpy, event, desc_context);
561
562     XFlush(dpy);
563 }
564
565 void
566 x_get_input(Display *dpy)
567 {
568     XEvent event;
569     
570     dprintf1("Entering x_get_input(%x).\n",dpy);
571
572     /*
573      * Kludge to get around lossage in XPending:
574      *
575      * (the problem: XPending on a partial packet returns 0 without
576      *  reading in the packet.  This causes a problem when the X server
577      *  dies in the middle of sending a packet.)
578      */
579     if (XPending(dpy)==0)
580       XNoOp(dpy);  /* Ensure server is still with us... */
581     
582     while (XPending(dpy)) {
583         XNextEvent(dpy,&event);
584         xhandleevent(dpy, event.xany.window, &event);
585     }
586 }
587
588 #ifdef CMU_ZWGCPLUS
589 void 
590 plus_window_deletions(ZNotice_t *notice)
591 {
592   x_gram *tmp, *fry;
593   char *val;
594   int done;
595   static char class_nm[NAMESIZE], instance_nm[NAMESIZE], recip_nm[NAMESIZE];
596   
597   if (!dpy)
598     return;
599
600   val = var_get_variable("delete_window");
601   
602 #ifdef DEBUG_DELETION
603   fprintf(stderr, "delete_window(%s)\n", val);
604 #endif
605   if (val) {
606     if (!strcmp(val, "this")) {
607       do {
608         done = 1;
609         tmp = bottom_gram;
610         while (tmp) {
611           if (tmp->notice == notice) {
612             fry = tmp;
613             tmp = tmp->above;
614             xdestroygram(dpy, fry->w, desc_context, fry);
615             done = 0;
616           } else {
617             tmp = tmp->above;
618           }
619         }
620       } while (!done);
621     }
622     else if (!strcmp(val, "s")) {
623       /* I cheated. This is really sender, not class */
624       strcpy(class_nm, notice->z_sender);
625       do {
626         done = 1;
627         tmp = bottom_gram;
628         while (tmp) {
629           if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_sender, class_nm)) {
630             fry = tmp;
631             tmp = tmp->above;
632             xdestroygram(dpy, fry->w, desc_context, fry);
633             done = 0;
634           } else {
635             tmp = tmp->above;
636           }
637         }
638       } while (!done);
639     }
640     else if (!strcmp(val, "ns")) {
641       /* I cheated. This is really sender, not class */
642       strcpy(class_nm, notice->z_sender);
643       do {
644         done = 1;
645         tmp = bottom_gram;
646         while (tmp) {
647           if (!!strcasecmp(((ZNotice_t *)(tmp->notice))->z_sender, class_nm)) {
648             fry = tmp;
649             tmp = tmp->above;
650             xdestroygram(dpy, fry->w, desc_context, fry);
651             done = 0;
652           } else {
653             tmp = tmp->above;
654           }
655         }
656       } while (!done);
657     }
658     else if (!strcmp(val, "r")) {
659       strcpy(recip_nm, notice->z_recipient);
660       do {
661         done = 1;
662         tmp = bottom_gram;
663         while (tmp) {
664           if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_recipient, recip_nm)) {
665             fry = tmp;
666             tmp = tmp->above;
667             xdestroygram(dpy, fry->w, desc_context, fry);
668             done = 0;
669           } else {
670             tmp = tmp->above;
671           }
672         }
673       } while (!done);
674     }
675     else if (!strcmp(val, "nr")) {
676       strcpy(recip_nm, notice->z_recipient);
677       do {
678         done = 1;
679         tmp = bottom_gram;
680         while (tmp) {
681           if (!!strcasecmp(((ZNotice_t *)(tmp->notice))->z_recipient, recip_nm)) {
682             fry = tmp;
683             tmp = tmp->above;
684             xdestroygram(dpy, fry->w, desc_context, fry);
685             done = 0;
686           } else {
687             tmp = tmp->above;
688           }
689         }
690       } while (!done);
691     }
692     else if (!strcmp(val, "cir")) {
693       strcpy(class_nm, notice->z_class);
694       strcpy(instance_nm, notice->z_class_inst);
695       strcpy(recip_nm, notice->z_recipient);
696       do {
697         done = 1;
698         tmp = bottom_gram;
699         while (tmp) {
700           if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_class_inst, instance_nm)
701               && !strcasecmp(((ZNotice_t *)(tmp->notice))->z_class, class_nm)
702               && !strcasecmp(((ZNotice_t *)(tmp->notice))->z_recipient, recip_nm))
703             {
704               fry = tmp;
705               tmp = tmp->above;
706               xdestroygram(dpy, fry->w, desc_context, fry);
707               done = 0;
708             } else {
709               tmp = tmp->above;
710             }
711         }
712       } while (!done);
713     }
714     else if (!strcmp(val, "ci")) {
715       strcpy(class_nm, notice->z_class);
716       strcpy(instance_nm, notice->z_class_inst);
717       do {
718         done = 1;
719         tmp = bottom_gram;
720         while (tmp) {
721           if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_class_inst, instance_nm)
722               && !strcasecmp(((ZNotice_t *)(tmp->notice))->z_class, class_nm)) 
723             {
724               fry = tmp;
725               tmp = tmp->above;
726               xdestroygram(dpy, fry->w, desc_context, fry);
727               done = 0;
728             } else {
729               tmp = tmp->above;
730             }
731         }
732       } while (!done);
733     }
734     else if (!strcmp(val, "cr")) {
735       strcpy(class_nm, notice->z_class);
736       strcpy(recip_nm, notice->z_recipient);
737       do {
738         done = 1;
739         tmp = bottom_gram;
740         while (tmp) {
741           if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_class, class_nm) &&
742               !strcasecmp(((ZNotice_t *)(tmp->notice))->z_recipient, recip_nm)) 
743             {
744               fry = tmp;
745               tmp = tmp->above;
746               xdestroygram(dpy, fry->w, desc_context, fry);
747               done = 0;
748             } else {
749               tmp = tmp->above;
750             }
751         }
752       } while (!done);
753     }
754     else if (!strcmp(val, "c")) {
755       strcpy(class_nm, notice->z_class);
756       do {
757         done = 1;
758         tmp = bottom_gram;
759         while (tmp) {
760           if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_class, class_nm)) {
761             fry = tmp;
762             tmp = tmp->above;
763             xdestroygram(dpy, fry->w, desc_context, fry);
764             done = 0;
765           } else {
766             tmp = tmp->above;
767           }
768         }
769       } while (!done);
770     }
771     else if (!strcmp(val, "all")) {
772       while (bottom_gram) {
773         xdestroygram(dpy, bottom_gram->w, desc_context, bottom_gram);
774       }
775     }
776   }
777 }
778 #endif
779 #endif /* X_DISPLAY_MISSING */
780