]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - xshow.c
0e548fa27c02afe5249103c2654c0ce9e7a15218
[1ts-debian.git] / 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 2630 2011-02-02 05:26:26Z kcr@ATHENA.MIT.EDU $
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 2630 2011-02-02 05:26:26Z kcr@ATHENA.MIT.EDU $";
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     XFontSetExtents *fse;
154
155     gram = (x_gram *)malloc(sizeof(x_gram));
156
157     /* Find total lengths of left, center, and right parts.  Also find the
158        length of the longest line and the total number of characters. */
159
160     for (line = 0; line < numlines; line++) {
161         lsize = csize = rsize = 0;
162         maxascent = maxdescent = 0;
163         
164         /* add up sizes for each block, get max ascent and descent */
165         
166         for (i = 0; i < lines[line].numblock; i++, block++) {
167             chars += auxblocks[block].len;
168 #ifdef X_HAVE_UTF8_STRING
169             ssize = Xutf8TextEscapement(auxblocks[block].font,
170                                         blocks[block].wstr,
171                                         blocks[block].wlen);
172 #else
173             ssize = XwcTextEscapement(auxblocks[block].font,
174                                       (XChar2b *)blocks[block].wstr,
175                                       blocks[block].wlen);
176 #endif
177             auxblocks[block].width = ssize;
178             fse = XExtentsOfFontSet(auxblocks[block].font);
179             ascent = -fse->max_logical_extent.y;
180             descent = fse->max_logical_extent.y + fse->max_logical_extent.height;
181             if (ascent > maxascent)
182               maxascent = ascent;
183             if (descent > maxdescent)
184               maxdescent = descent;
185             switch (auxblocks[block].align) {
186               case LEFTALIGN:
187                 lsize += ssize;
188                 break;
189                 
190               case CENTERALIGN:
191                 csize += ssize;
192                 break;
193                 
194               case RIGHTALIGN:
195                 rsize += ssize;
196                 break;
197             }
198         }
199         
200         /* save what we need to do size fixups */
201         
202         if (maxascent > lines[line].ascent)
203           lines[line].ascent = maxascent;
204         if (maxdescent > lines[line].descent)
205           lines[line].descent = maxdescent;
206         lines[line].lsize = lsize;
207         lines[line].csize = csize;
208         lines[line].rsize = rsize;
209         
210         /* get width of line and see if it is bigger than the max width */
211
212         switch ((lsize ? 1 : 0) + (csize ?2 : 0) + (rsize ? 4 : 0)) {
213 #ifdef DEBUG
214           default:
215             abort();
216 #endif
217             
218           case 0:
219             width = 0;
220             break;
221             
222           case 1:
223             width = lsize;
224             break;
225             
226           case 2:
227             width = csize;
228             break;
229             
230           case 3:
231             /* in all these cases, we just want to add the width of *any*
232                space, so the first font will do just fine. */
233             /* XXX implicit assumption that a line must have at least one
234                block, so that there is indeed a reasonable font in
235                auxblocks[0].font */
236             width = lsize * 2 + csize + XmbTextEscapement(auxblocks[0].font, " ", 1);
237             break;
238             
239           case 4:
240             width = rsize;
241             break;
242             
243           case 5:
244             width = lsize + rsize + XmbTextEscapement(auxblocks[0].font, " ", 1);
245             break;
246             
247           case 6:
248             width = csize + rsize * 2 + XmbTextEscapement(auxblocks[0].font, " ", 1);
249             break;
250             
251           case 7:
252             width = max(lsize, rsize) * 2 + csize +
253                 XmbTextEscapement(auxblocks[0].font, " ", 1) * 2;
254             break;
255         }
256         if (width > maxwidth)
257           maxwidth = width;
258     }
259
260     /* fixup x,y for each block, create big string and indices into it */
261     /* set x1,y1,x2,y2 of each block also. */
262
263     gram->text = (char *)malloc(chars);
264     block = 0;
265
266     for (line = 0; line < numlines; line++) {
267         lofs = internal_border_width;
268         cofs = ((maxwidth - lines[line].csize) >> 1) + internal_border_width;
269         rofs = maxwidth - lines[line].rsize + internal_border_width;
270         ystart = yofs;
271         yofs += lines[line].ascent;
272         yend = yofs + lines[line].descent + 1;   /* +1 because lines look scrunched
273                                                     without it. */
274
275         for (i = 0; i < lines[line].numblock; i++, block++) {
276             blocks[block].font = auxblocks[block].font;
277             switch (auxblocks[block].align) {
278               case LEFTALIGN:
279                 blocks[block].x = lofs;
280                 blocks[block].x1 = lofs;
281                 lofs += auxblocks[block].width;
282                 blocks[block].x2 = lofs;
283                 break;
284                 
285               case CENTERALIGN:
286                 blocks[block].x = cofs;
287                 blocks[block].x1 = cofs;
288                 cofs += auxblocks[block].width;
289                 blocks[block].x2 = cofs;
290                 break;
291
292               case RIGHTALIGN:
293                 blocks[block].x = rofs;
294                 blocks[block].x1 = rofs;
295                 rofs += auxblocks[block].width;
296                 blocks[block].x2 = rofs;
297                 break;
298             }
299             blocks[block].y = yofs;
300             blocks[block].y1 = ystart;
301             blocks[block].y2 = yend;
302             blocks[block].strindex = strindex;
303             blocks[block].strlen = auxblocks[block].len;
304             strncpy(gram->text + strindex, auxblocks[block].str,
305                     auxblocks[block].len);
306             strindex += blocks[block].strlen;
307         }
308
309         yofs = yend;
310
311     }
312
313     geometry = var_get_variable("X_geometry");
314     if (geometry[0] == '\0')
315         geometry = xres_get_geometry(style);
316     if (geometry == NULL)
317         geometry = var_get_variable("default_X_geometry");
318     if (geometry[0] == '\0')
319         geometry = "+0+0";
320
321     sscanf(geometry, "%c%[0123456789c]%c%[0123456789c]", &xfrom, xpos,
322            &yfrom, ypos);
323
324     if (xpos[0] == 'c') {
325       gram_xalign = 0;
326       gram_xpos = 0;
327     } else
328       gram_xpos = atoi(xpos);
329     if (xfrom == '-')
330       gram_xalign *= -1;
331
332     if (ypos[0] == 'c') {
333       gram_yalign = 0;
334       gram_ypos = 0;
335     } else
336       gram_ypos = atoi(ypos);
337     if (yfrom == '-')
338       gram_yalign *= -1;
339
340     bgstr = var_get_variable("X_background");
341     if (bgstr[0] == '\0')
342         bgstr = xres_get_bgcolor(style);
343     if (bgstr == NULL)
344         bgstr = var_get_variable("default_X_background");
345     if (bgstr[0]=='\0')
346         gram->bgcolor = default_bgcolor;
347
348     if (bgstr && bgstr[0])
349       gram->bgcolor = x_string_to_color(bgstr, default_bgcolor);
350     
351     gram_xsize = maxwidth + (internal_border_width << 1);
352     gram_ysize = yofs + internal_border_width;
353     gram->numblocks = num;
354     gram->blocks = blocks;
355 #ifdef CMU_ZWGCPLUS
356     gram->notice = get_stored_notice();
357 #endif
358     
359     x_gram_create(dpy, gram, gram_xalign, gram_yalign, gram_xpos,
360                   gram_ypos, gram_xsize, gram_ysize, beepcount);
361 }
362
363 /* Silly almost-but-not-quite-useless helper function */
364 char *
365 no_dots_downcase_var(char *str)
366 {
367    register char *var, *var2;
368
369    var = string_Downcase(var_get_variable(str));
370    var2 = var;
371    while (*var++)
372       if (*var == '.')
373          *var = '_';
374    return(var2);
375 }
376
377 inline static XFontSet
378 mode_to_font(Display *dpy, char *style, xmode *mode) {
379     return get_font(dpy,
380                     style,
381                     mode->font ? mode->font : mode->substyle,
382                     mode->size,
383                     mode->bold + mode->italic * 2);
384 }
385
386 inline static int
387 envmatch(desctype *desc, char *str) {
388     int len = strlen(str);
389     return desc->len == len && strncasecmp(desc->str, str, len) == 0;
390 }
391
392 void
393 xshow(Display *dpy, desctype *desc, int numstr, int numnl)
394 {
395     XFontSet font;
396     XFontSetExtents *fse;
397     xmode_stack modes = xmode_stack_create();
398     xmode curmode;
399     xlinedesc *lines;
400     xblock *blocks;
401     xauxblock *auxblocks;
402     int nextblock=0;
403     int line=0,linestart=0;
404     char *style;
405     int free_style = 0;
406     int beepcount = 0;
407     char *notice_charset = var_get_variable("notice_charset");
408     int i;
409
410     lines = (xlinedesc *)malloc(sizeof(xlinedesc) * (numnl + 1));
411
412     blocks = (xblock *)malloc(sizeof(xblock) * numstr);
413     auxblocks = (xauxblock *)malloc(sizeof(xauxblock) * numstr);
414
415     curmode.bold = 0;
416     curmode.italic = 0;
417     curmode.size = MEDIUM_SIZE;
418     curmode.align = LEFTALIGN;
419     curmode.expcolor = 0;
420     curmode.substyle = string_Copy("default");
421     curmode.font = NULL;
422
423     style = var_get_variable("style");
424     if (style[0] == '\0') {
425        style = string_Concat(no_dots_downcase_var("class"), ".");
426        style = string_Concat2(style, no_dots_downcase_var("instance"));
427        style = string_Concat2(style, ".");
428        style = string_Concat2(style, no_dots_downcase_var("sender"));
429        string_Downcase(style);
430        free_style = 1;
431     }
432
433     for (; desc->code != DT_EOF; desc = desc->next) {
434         switch (desc->code) {
435           case DT_ENV:
436             xmode_stack_push(modes, curmode);
437             curmode.substyle = string_Copy(curmode.substyle);
438             if (curmode.font)
439               curmode.font = string_Copy(curmode.font);
440             if (envmatch(desc, "roman")) {
441                 curmode.bold = 0;
442                 curmode.italic = 0;
443             } else if (envmatch(desc, "bold") || envmatch(desc, "b"))
444               curmode.bold = 1;
445             else if (envmatch(desc, "italic") || envmatch(desc, "i"))
446               curmode.italic = 1;
447             else if (envmatch(desc, "large"))
448               curmode.size = LARGE_SIZE;
449             else if (envmatch(desc, "medium"))
450               curmode.size = MEDIUM_SIZE;
451             else if (envmatch(desc, "small"))
452               curmode.size = SMALL_SIZE;
453             else if (envmatch(desc, "left") || envmatch(desc, "l"))
454               curmode.align = LEFTALIGN;
455             else if (envmatch(desc, "center") || envmatch(desc, "c"))
456               curmode.align = CENTERALIGN;
457             else if (envmatch(desc, "right") || envmatch(desc, "r"))
458               curmode.align = RIGHTALIGN;
459             else if (envmatch(desc, "beep"))
460               beepcount++;
461             else if (envmatch(desc, "font")) {
462                /* lookahead needed.  desc->next->str should be the
463                   font name, and desc->next->next->code should be
464                   a DT_END*/
465                if ((desc->next) &&
466                    (desc->next->next) &&
467                    (desc->next->code == DT_STR) &&
468                    (desc->next->next->code == DT_END)) {
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                   curmode.size = SPECIAL_SIZE; /* This is an @font() */
478                   curmode.font = string_CreateFromData(desc->next->str,
479                                                        desc->next->len);
480                   /* skip over the rest of the @font */
481                   desc = desc->next->next;
482                }
483             } else if (envmatch(desc, "color")) {
484                /* lookahead needed.  desc->next->str should be the
485                   font name, and desc->next->next->code should be
486                   a DT_END*/
487                if ((desc->next) &&
488                    (desc->next->next) &&
489                    (desc->next->code == DT_STR) &&
490                    (desc->next->next->code == DT_END)) {
491                   char *colorname;
492
493                   /* Since @font mutates the current environment, we have
494                      to pop the environment that this case usually pushes */
495                   free(curmode.substyle);
496                   curmode = xmode_stack_top(modes);
497                   xmode_stack_pop(modes);
498
499                   /* mutating... */
500                   colorname = string_CreateFromData(desc->next->str,
501                                                     desc->next->len);
502                   curmode.color = x_string_to_color(colorname, default_fgcolor);
503                   free(colorname);
504                   curmode.expcolor = 1;
505                   /* skip over the rest of the @font */
506                   desc = desc->next->next;
507                }
508             } else if (desc->len > 0) { /* avoid @{...} */
509                free(curmode.substyle);
510                if (curmode.font) {
511                   free(curmode.font);
512                   curmode.font = NULL;
513                }
514                curmode.substyle = string_CreateFromData(desc->str, desc->len);
515             }
516             break;
517
518           case DT_STR:
519             auxblocks[nextblock].align = curmode.align;
520             auxblocks[nextblock].font = mode_to_font(dpy, style, &curmode);
521             auxblocks[nextblock].str = desc->str;
522             auxblocks[nextblock].len = desc->len;
523             i = ZTransliterate(desc->str, desc->len,
524                                strcmp(notice_charset, "UNKNOWN") ?
525                                 notice_charset : "ISO-8859-1",
526 #ifdef X_HAVE_UTF8_STRING
527                                "UTF-8",
528 #else
529                                "UTF-16BE",
530 #endif
531                                &blocks[nextblock].wstr,
532                                &blocks[nextblock].wlen);
533             if (i) {
534                 var_set_variable("error", strerror(i));
535 #ifdef X_HAVE_UTF8_STRING
536                 blocks[nextblock].wlen = desc->len;
537                 blocks[nextblock].wstr = strdup(desc->str);
538 #else
539                 blocks[nextblock].wlen = desc->len * 2;
540                 blocks[nextblock].wstr = malloc(blocks[nextblock].wlen);
541                 for (i = 0; i < desc->len; i++)
542                     *(short *)&(blocks[nextblock].wstr[i * 2]) = htons((short)(unsigned char)desc->str[i]);
543                 /* XXX */
544 #endif
545             }
546 #ifndef X_HAVE_UTF8_STRING
547             blocks[nextblock].wlen /= 2;
548 #endif
549             if (curmode.expcolor)
550                blocks[nextblock].fgcolor = curmode.color;
551             else
552                blocks[nextblock].fgcolor =
553                  x_string_to_color(mode_to_colorname(dpy, style, &curmode),
554                                    default_fgcolor);
555             nextblock++;
556             break;
557
558           case DT_END:
559             free(curmode.substyle);
560             curmode = xmode_stack_top(modes);
561             xmode_stack_pop(modes);
562             break;
563
564           case DT_NL:
565             lines[line].startblock = linestart;
566             lines[line].numblock = nextblock-linestart;
567             font = mode_to_font(dpy, style, &curmode);
568             fse = XExtentsOfFontSet(font);
569             lines[line].ascent = -fse->max_logical_extent.y;
570             lines[line].descent = fse->max_logical_extent.y +
571                 fse->max_logical_extent.height;
572             line++;
573             linestart = nextblock;
574             break;
575         }
576     }
577
578     /* case DT_EOF:    will drop through to here. */
579
580     if (linestart != nextblock) {
581        lines[line].startblock = linestart;
582        lines[line].numblock = nextblock-linestart;
583        font = mode_to_font(dpy, style, &curmode);
584        lines[line].ascent = 0;
585        lines[line].descent = 0;
586        line++;
587     }
588     
589     free(curmode.substyle);
590     fixup_and_draw(dpy, style, auxblocks, blocks, nextblock, lines, line,
591                    beepcount);
592     free(lines);
593     free(auxblocks);
594     if (free_style)
595       free(style);
596 }
597
598 static void
599 xhandleevent(Display *dpy,
600              Window w,
601              XEvent *event)
602 {
603     x_gram *gram;
604     
605     if (XFindContext(dpy, w, desc_context, (XPointer *)&gram))
606       return;
607
608     if (event->type == Expose)
609       x_gram_expose(dpy, w, gram,&(event->xexpose));
610     else
611       xcut(dpy, event, desc_context);
612
613     XFlush(dpy);
614 }
615
616 void
617 x_get_input(Display *dpy)
618 {
619     XEvent event;
620     
621     dprintf1("Entering x_get_input(%x).\n",dpy);
622
623     /*
624      * Kludge to get around lossage in XPending:
625      *
626      * (the problem: XPending on a partial packet returns 0 without
627      *  reading in the packet.  This causes a problem when the X server
628      *  dies in the middle of sending a packet.)
629      */
630     if (XPending(dpy)==0)
631       XNoOp(dpy);  /* Ensure server is still with us... */
632     
633     while (XPending(dpy)) {
634         XNextEvent(dpy,&event);
635         xhandleevent(dpy, event.xany.window, &event);
636     }
637 }
638
639 #ifdef CMU_ZWGCPLUS
640 void 
641 plus_window_deletions(ZNotice_t *notice)
642 {
643   x_gram *tmp, *fry;
644   char *val;
645   int done;
646   static char class_nm[NAMESIZE], instance_nm[NAMESIZE], recip_nm[NAMESIZE];
647   
648   if (!dpy)
649     return;
650
651   val = var_get_variable("delete_window");
652   
653 #ifdef DEBUG_DELETION
654   fprintf(stderr, "delete_window(%s)\n", val);
655 #endif
656   if (val) {
657     if (!strcmp(val, "this")) {
658       do {
659         done = 1;
660         tmp = bottom_gram;
661         while (tmp) {
662           if (tmp->notice == notice) {
663             fry = tmp;
664             tmp = tmp->above;
665             xdestroygram(dpy, fry->w, desc_context, fry);
666             done = 0;
667           } else {
668             tmp = tmp->above;
669           }
670         }
671       } while (!done);
672     }
673     else if (!strcmp(val, "s")) {
674       /* I cheated. This is really sender, not class */
675       strcpy(class_nm, notice->z_sender);
676       do {
677         done = 1;
678         tmp = bottom_gram;
679         while (tmp) {
680           if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_sender, class_nm)) {
681             fry = tmp;
682             tmp = tmp->above;
683             xdestroygram(dpy, fry->w, desc_context, fry);
684             done = 0;
685           } else {
686             tmp = tmp->above;
687           }
688         }
689       } while (!done);
690     }
691     else if (!strcmp(val, "ns")) {
692       /* I cheated. This is really sender, not class */
693       strcpy(class_nm, notice->z_sender);
694       do {
695         done = 1;
696         tmp = bottom_gram;
697         while (tmp) {
698           if (!!strcasecmp(((ZNotice_t *)(tmp->notice))->z_sender, class_nm)) {
699             fry = tmp;
700             tmp = tmp->above;
701             xdestroygram(dpy, fry->w, desc_context, fry);
702             done = 0;
703           } else {
704             tmp = tmp->above;
705           }
706         }
707       } while (!done);
708     }
709     else if (!strcmp(val, "r")) {
710       strcpy(recip_nm, notice->z_recipient);
711       do {
712         done = 1;
713         tmp = bottom_gram;
714         while (tmp) {
715           if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_recipient, recip_nm)) {
716             fry = tmp;
717             tmp = tmp->above;
718             xdestroygram(dpy, fry->w, desc_context, fry);
719             done = 0;
720           } else {
721             tmp = tmp->above;
722           }
723         }
724       } while (!done);
725     }
726     else if (!strcmp(val, "nr")) {
727       strcpy(recip_nm, notice->z_recipient);
728       do {
729         done = 1;
730         tmp = bottom_gram;
731         while (tmp) {
732           if (!!strcasecmp(((ZNotice_t *)(tmp->notice))->z_recipient, recip_nm)) {
733             fry = tmp;
734             tmp = tmp->above;
735             xdestroygram(dpy, fry->w, desc_context, fry);
736             done = 0;
737           } else {
738             tmp = tmp->above;
739           }
740         }
741       } while (!done);
742     }
743     else if (!strcmp(val, "cir")) {
744       strcpy(class_nm, notice->z_class);
745       strcpy(instance_nm, notice->z_class_inst);
746       strcpy(recip_nm, notice->z_recipient);
747       do {
748         done = 1;
749         tmp = bottom_gram;
750         while (tmp) {
751           if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_class_inst, instance_nm)
752               && !strcasecmp(((ZNotice_t *)(tmp->notice))->z_class, class_nm)
753               && !strcasecmp(((ZNotice_t *)(tmp->notice))->z_recipient, recip_nm))
754             {
755               fry = tmp;
756               tmp = tmp->above;
757               xdestroygram(dpy, fry->w, desc_context, fry);
758               done = 0;
759             } else {
760               tmp = tmp->above;
761             }
762         }
763       } while (!done);
764     }
765     else if (!strcmp(val, "ci")) {
766       strcpy(class_nm, notice->z_class);
767       strcpy(instance_nm, notice->z_class_inst);
768       do {
769         done = 1;
770         tmp = bottom_gram;
771         while (tmp) {
772           if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_class_inst, instance_nm)
773               && !strcasecmp(((ZNotice_t *)(tmp->notice))->z_class, class_nm)) 
774             {
775               fry = tmp;
776               tmp = tmp->above;
777               xdestroygram(dpy, fry->w, desc_context, fry);
778               done = 0;
779             } else {
780               tmp = tmp->above;
781             }
782         }
783       } while (!done);
784     }
785     else if (!strcmp(val, "cr")) {
786       strcpy(class_nm, notice->z_class);
787       strcpy(recip_nm, notice->z_recipient);
788       do {
789         done = 1;
790         tmp = bottom_gram;
791         while (tmp) {
792           if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_class, class_nm) &&
793               !strcasecmp(((ZNotice_t *)(tmp->notice))->z_recipient, recip_nm)) 
794             {
795               fry = tmp;
796               tmp = tmp->above;
797               xdestroygram(dpy, fry->w, desc_context, fry);
798               done = 0;
799             } else {
800               tmp = tmp->above;
801             }
802         }
803       } while (!done);
804     }
805     else if (!strcmp(val, "c")) {
806       strcpy(class_nm, notice->z_class);
807       do {
808         done = 1;
809         tmp = bottom_gram;
810         while (tmp) {
811           if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_class, class_nm)) {
812             fry = tmp;
813             tmp = tmp->above;
814             xdestroygram(dpy, fry->w, desc_context, fry);
815             done = 0;
816           } else {
817             tmp = tmp->above;
818           }
819         }
820       } while (!done);
821     }
822     else if (!strcmp(val, "all")) {
823       while (bottom_gram) {
824         xdestroygram(dpy, bottom_gram->w, desc_context, bottom_gram);
825       }
826     }
827   }
828 }
829 #endif
830 #endif /* X_DISPLAY_MISSING */