]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/zwgc/xshow.c
r4275@bucket (orig r265): kcr | 2008-01-21 02:57:32 -0500
[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$
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$";
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 "pointer_dictionary.h"
28 #include "new_memory.h"
29 #include "new_string.h"
30 #include "formatter.h"
31 #include "variables.h"
32 #include "zwgc.h"
33 #include "X_driver.h"
34 #include "X_fonts.h"
35 #include "X_gram.h"
36 #include "xmode_stack.h"
37
38 #define max(a,b)   ((a)>(b)?(a):(b))
39
40 XContext desc_context;
41
42 extern int internal_border_width;
43 extern unsigned long default_bgcolor;
44 extern unsigned long default_fgcolor;
45
46 void
47 xshowinit(void)
48 {
49     desc_context = XUniqueContext();
50 }
51
52 struct res_dict_type {
53     pointer_dictionary  dict;
54     char *              resname_suffix;
55     char *              resclass;
56 };
57
58 static char *
59 xres_get_resource(struct res_dict_type *restype,
60                   char *style)
61 {
62    char *desc;
63    pointer_dictionary_binding *binding;
64    int exists;
65    char *value;
66
67    desc=string_Concat("style.", style);
68    desc=string_Concat2(desc, restype->resname_suffix);
69
70    if (!restype->dict)
71       restype->dict = pointer_dictionary_Create(37);
72    binding = pointer_dictionary_Define(restype->dict, desc, &exists);
73
74    if (exists) {
75       free(desc);
76       return((string) binding->value);
77    } else {
78       value=get_string_resource(desc, restype->resclass);
79       free(desc);
80       if (value==NULL)
81          pointer_dictionary_Delete(restype->dict, binding);
82       else
83          binding->value=(pointer) value;
84       return value;  /* If resource returns NULL, return NULL also */
85    }
86 }
87
88 static struct res_dict_type geometry_resources = {
89     NULL, ".geometry", "StyleKey.Style1.Style2.Style3.GeometryKey",
90 };
91
92 static struct res_dict_type bgcolor_resources = {
93     NULL, ".background", "StyleKey.Style1.Style2.Style3.BackgroundKey",
94 };
95
96 #define xres_get_geometry(style) xres_get_resource(&geometry_resources,style)
97 #define xres_get_bgcolor(style)  xres_get_resource(&bgcolor_resources,style)
98
99 static struct res_dict_type fgcolor_resources = {
100     NULL, ".foreground",
101     "StyleKey.Style1.Style2.Style3.SubstyleKey.Substyle.ForegroundKey",
102 };
103
104 /*ARGSUSED*/
105 char *
106 mode_to_colorname (Display *dpy,
107                    char *style,
108                    xmode *mode)
109 {
110     char *desc, *result;
111
112     desc = string_Concat (style, ".substyle.");
113     desc = string_Concat2 (desc, mode->substyle);
114     result = xres_get_resource (&fgcolor_resources, desc);
115     free (desc);
116     return result;
117 }
118
119 void
120 fixup_and_draw(Display *dpy,
121                char *style,
122                xauxblock *auxblocks,
123                xblock *blocks,
124                int num,
125                xlinedesc *lines,
126                int numlines,
127                int beepcount)
128 {
129     int gram_xalign = 1;
130     int gram_yalign = 1;
131     int gram_xpos, gram_ypos, gram_xsize, gram_ysize;
132
133     x_gram *gram;
134     int strindex = 0;
135
136     int line, block=0;
137     int maxwidth=0, chars=0, maxascent, maxdescent;
138     int ssize,  lsize,csize, rsize, width;
139     int i, ascent, descent;
140
141     int yofs = internal_border_width;
142     int lofs, cofs, rofs;
143     int ystart,yend;
144
145     char *bgstr, *geometry, xpos[10], ypos[10], xfrom, yfrom;
146
147     gram = (x_gram *)malloc(sizeof(x_gram));
148
149     /* Find total lengths of left, center, and right parts.  Also find the
150        length of the longest line and the total number of characters. */
151
152     for (line=0; line<numlines; line++) {
153         lsize = csize = rsize = 0;
154         maxascent = maxdescent = 0;
155         
156         /* add up sizes for each block, get max ascent and descent */
157         
158         for (i=0; i<lines[line].numblock; i++,block++) {
159             chars += auxblocks[block].len;
160             ssize = XTextWidth(auxblocks[block].font, auxblocks[block].str,
161                                auxblocks[block].len);
162             auxblocks[block].width = ssize;
163             ascent = auxblocks[block].font->ascent;
164             descent = auxblocks[block].font->descent;
165             if (ascent>maxascent)
166               maxascent = ascent;
167             if (descent>maxdescent)
168               maxdescent = descent;
169             switch (auxblocks[block].align) {
170               case LEFTALIGN:
171                 lsize += ssize;
172                 break;
173                 
174               case CENTERALIGN:
175                 csize += ssize;
176                 break;
177                 
178               case RIGHTALIGN:
179                 rsize += ssize;
180                 break;
181             }
182         }
183         
184         /* save what we need to do size fixups */
185         
186         if (maxascent>lines[line].ascent)
187           lines[line].ascent = maxascent;
188         if (maxdescent>lines[line].descent)
189           lines[line].descent = maxdescent;
190         lines[line].lsize = lsize;
191         lines[line].csize = csize;
192         lines[line].rsize = rsize;
193         
194         /* get width of line and see if it is bigger than the max width */
195
196         switch ((lsize?1:0)+(csize?2:0)+(rsize?4:0)) {
197 #ifdef DEBUG
198           default:
199             abort();
200 #endif
201             
202           case 0:
203             width = 0;
204             break;
205             
206           case 1:
207             width = lsize;
208             break;
209             
210           case 2:
211             width = csize;
212             break;
213             
214           case 3:
215             /* in all these cases, we just want to add the width of *any*
216                space, so the first font will do just fine. */
217             /* XXX implicit assumption that a line must have at least one
218                block, so that there is indeed a reasonable font in
219                auxblocks[0].font */
220             width = lsize*2+csize+XTextWidth(auxblocks[0].font," ",1);
221             break;
222             
223           case 4:
224             width = rsize;
225             break;
226             
227           case 5:
228             width = lsize+rsize+XTextWidth(auxblocks[0].font, " ", 1);
229             break;
230             
231           case 6:
232             width = csize+rsize*2+XTextWidth(auxblocks[0].font, " ", 1);
233             break;
234             
235           case 7:
236             width = max(lsize,rsize)*2+csize+
237               XTextWidth(auxblocks[0].font," ",1)*2;
238             break;
239         }
240         if (width>maxwidth)
241           maxwidth = width;
242     }
243
244     /* fixup x,y for each block, create big string and indices into it */
245     /* set x1,y1,x2,y2 of each block also. */
246
247     gram->text = (char *)malloc(chars);
248     block = 0;
249
250     for (line=0; line<numlines; line++) {
251         lofs = internal_border_width;
252         cofs = ((maxwidth-lines[line].csize)>>1) + internal_border_width;
253         rofs = maxwidth-lines[line].rsize + internal_border_width;
254         ystart = yofs;
255         yofs += lines[line].ascent;
256         yend = yofs+lines[line].descent+1;   /* +1 because lines look scrunched
257                                                 without it. */
258
259         for (i=0; i<lines[line].numblock; i++,block++) {
260             blocks[block].fid = auxblocks[block].font->fid;
261             switch (auxblocks[block].align) {
262               case LEFTALIGN:
263                 blocks[block].x = lofs;
264                 blocks[block].x1 = lofs;
265                 lofs += auxblocks[block].width;
266                 blocks[block].x2 = lofs;
267                 break;
268                 
269               case CENTERALIGN:
270                 blocks[block].x = cofs;
271                 blocks[block].x1 = cofs;
272                 cofs += auxblocks[block].width;
273                 blocks[block].x2 = cofs;
274                 break;
275
276               case RIGHTALIGN:
277                 blocks[block].x = rofs;
278                 blocks[block].x1 = rofs;
279                 rofs += auxblocks[block].width;
280                 blocks[block].x2 = rofs;
281                 break;
282             }
283             blocks[block].y = yofs;
284             blocks[block].y1 = ystart;
285             blocks[block].y2 = yend;
286             blocks[block].strindex = strindex;
287             blocks[block].strlen = auxblocks[block].len;
288             strncpy(gram->text+strindex, auxblocks[block].str,
289                     auxblocks[block].len);
290             strindex += blocks[block].strlen;
291         }
292
293         yofs = yend;
294
295     }
296
297     if ((geometry = var_get_variable("X_geometry")),(geometry[0]=='\0')) 
298       if ((geometry = xres_get_geometry(style))==NULL)
299         if ((geometry = var_get_variable("default_X_geometry")),
300             (geometry[0]=='\0'))
301           geometry = "+0+0";
302     sscanf(geometry, "%c%[0123456789c]%c%[0123456789c]", &xfrom, xpos,
303            &yfrom, ypos);
304
305     if (xpos[0]=='c') {
306       gram_xalign = 0;
307       gram_xpos = 0;
308     } else
309       gram_xpos = atoi(xpos);
310     if (xfrom=='-')
311       gram_xalign *= -1;
312
313     if (ypos[0]=='c') {
314       gram_yalign = 0;
315       gram_ypos = 0;
316     } else
317       gram_ypos = atoi(ypos);
318     if (yfrom=='-')
319       gram_yalign *= -1;
320
321     if ((bgstr = var_get_variable("X_background")),(bgstr[0]=='\0'))
322       if ((bgstr = xres_get_bgcolor(style))==NULL)
323         if ((bgstr = var_get_variable("default_X_background")),
324             (bgstr[0]=='\0'))
325           gram->bgcolor = default_bgcolor;
326     if (bgstr && bgstr[0])
327       gram->bgcolor = x_string_to_color(bgstr,default_bgcolor);
328
329     
330     gram_xsize = maxwidth+(internal_border_width<<1);
331     gram_ysize = yofs+internal_border_width;
332     gram->numblocks = num;
333     gram->blocks = blocks;
334     
335     x_gram_create(dpy, gram, gram_xalign, gram_yalign, gram_xpos,
336                   gram_ypos, gram_xsize, gram_ysize, beepcount);
337 }
338
339 /* Silly almost-but-not-quite-useless helper function */
340 char *
341 no_dots_downcase_var(char *str)
342 {
343    register char *var, *var2;
344
345    var = string_Downcase(var_get_variable(str));
346    var2 = var;
347    while (*var++)
348       if (*var == '.')
349          *var = '_';
350    return(var2);
351 }
352
353 #define MODE_TO_FONT(dpy,style,mode) \
354   get_font((dpy),(style),(mode)->font?(mode)->font:(mode)->substyle, \
355            (mode)->size, (mode)->bold+(mode)->italic*2)
356 void
357 xshow(Display *dpy,
358       desctype *desc,
359       int numstr,
360       int numnl)
361 {
362     XFontStruct *font;
363     xmode_stack modes = xmode_stack_create();
364     xmode curmode;
365     xlinedesc *lines;
366     xblock *blocks;
367     xauxblock *auxblocks;
368     int nextblock=0;
369     int line=0,linestart=0;
370     char *style;
371     int free_style = 0;
372     int beepcount = 0;
373
374     lines = (xlinedesc *)malloc(sizeof(xlinedesc)*(numnl+1));
375
376     blocks = (xblock *)malloc(sizeof(xblock)*numstr);
377     auxblocks = (xauxblock *)malloc(sizeof(xauxblock)*numstr);
378
379     curmode.bold = 0;
380     curmode.italic = 0;
381     curmode.size = MEDIUM_SIZE;
382     curmode.align = LEFTALIGN;
383     curmode.expcolor = 0;
384     curmode.substyle = string_Copy("default");
385     curmode.font = NULL;
386
387     style = var_get_variable("style");
388     if (style[0] == '\0') {
389        style = string_Concat(no_dots_downcase_var("class"),".");
390        style = string_Concat2(style,no_dots_downcase_var("instance"));
391        style = string_Concat2(style,".");
392        style = string_Concat2(style,no_dots_downcase_var("sender"));
393        string_Downcase(style);
394        free_style = 1;
395     }
396
397     for (; desc->code!=DT_EOF; desc=desc->next) {
398         switch (desc->code) {
399           case DT_ENV:
400             xmode_stack_push(modes, curmode);
401             curmode.substyle = string_Copy(curmode.substyle);
402             if (curmode.font)
403               curmode.font = string_Copy(curmode.font);
404             
405 #define envmatch(string,length) ((desc->len==(length)) && (strncasecmp(desc->str,(string),(length))==0))
406
407             if (envmatch("roman",5)) {
408                 curmode.bold = 0;
409                 curmode.italic = 0;
410             } else if (envmatch("bold",4) || envmatch("b",1))
411               curmode.bold = 1;
412             else if (envmatch("italic",6)||envmatch("i",1))
413               curmode.italic = 1;
414             else if (envmatch("large",5))
415               curmode.size = LARGE_SIZE;
416             else if (envmatch("medium",6))
417               curmode.size = MEDIUM_SIZE;
418             else if (envmatch("small",5))
419               curmode.size = SMALL_SIZE;
420             else if (envmatch("left",4)||envmatch("l",1))
421               curmode.align = LEFTALIGN;
422             else if (envmatch("center",6)||envmatch("c",1))
423               curmode.align = CENTERALIGN;
424             else if (envmatch("right",5)||envmatch("r",1))
425               curmode.align = RIGHTALIGN;
426             else if (envmatch("beep",4))
427               beepcount++;
428             else if (envmatch("font",4)) {
429                /* lookahead needed.  desc->next->str should be the
430                   font name, and desc->next->next->code should be
431                   a DT_END*/
432                if ((desc->next) &&
433                    (desc->next->next) &&
434                    (desc->next->code == DT_STR) &&
435                    (desc->next->next->code==DT_END)) {
436
437                   /* Since @font mutates the current environment, we have
438                      to pop the environment that this case usually pushes */
439                   free(curmode.substyle);
440                   curmode = xmode_stack_top(modes);
441                   xmode_stack_pop(modes);
442
443                   /* mutating... */
444                   curmode.size=SPECIAL_SIZE; /* This is an @font() */
445                   curmode.font=string_CreateFromData(desc->next->str,
446                                                      desc->next->len);
447                   /* skip over the rest of the @font */
448                   desc=desc->next->next;
449                }
450             } else if (envmatch("color",5)) {
451                /* lookahead needed.  desc->next->str should be the
452                   font name, and desc->next->next->code should be
453                   a DT_END*/
454                if ((desc->next) &&
455                    (desc->next->next) &&
456                    (desc->next->code == DT_STR) &&
457                    (desc->next->next->code==DT_END)) {
458                   char *colorname;
459
460                   /* Since @font mutates the current environment, we have
461                      to pop the environment that this case usually pushes */
462                   free(curmode.substyle);
463                   curmode = xmode_stack_top(modes);
464                   xmode_stack_pop(modes);
465
466                   /* mutating... */
467                   colorname=string_CreateFromData(desc->next->str,
468                                                   desc->next->len);
469                   curmode.color = x_string_to_color(colorname,default_fgcolor);
470                   free(colorname);
471                   curmode.expcolor = 1;
472                   /* skip over the rest of the @font */
473                   desc=desc->next->next;
474                }
475             } else if (desc->len > 0) { /* avoid @{...} */
476                free(curmode.substyle);
477                if (curmode.font) {
478                   free(curmode.font);
479                   curmode.font = NULL;
480                }
481                curmode.substyle = string_CreateFromData(desc->str, desc->len);
482             }
483             break;
484
485           case DT_STR:
486             auxblocks[nextblock].align = curmode.align;
487             auxblocks[nextblock].font = MODE_TO_FONT(dpy,style,&curmode);
488             auxblocks[nextblock].str = desc->str;
489             auxblocks[nextblock].len = desc->len;
490             if (curmode.expcolor)
491                blocks[nextblock].fgcolor = curmode.color;
492             else
493                blocks[nextblock].fgcolor =
494                  x_string_to_color(mode_to_colorname(dpy,style,&curmode),
495                                    default_fgcolor);
496             nextblock++;
497             break;
498
499           case DT_END:
500             free(curmode.substyle);
501             curmode = xmode_stack_top(modes);
502             xmode_stack_pop(modes);
503             break;
504
505           case DT_NL:
506             lines[line].startblock = linestart;
507             lines[line].numblock = nextblock-linestart;
508             font = MODE_TO_FONT(dpy,style,&curmode);
509             lines[line].ascent = font->ascent;
510             lines[line].descent = font->descent;
511             line++;
512             linestart = nextblock;
513             break;
514         }
515     }
516
517     /* case DT_EOF:    will drop through to here. */
518
519     if (linestart != nextblock) {
520        lines[line].startblock = linestart;
521        lines[line].numblock = nextblock-linestart;
522        font = MODE_TO_FONT(dpy,style,&curmode);
523        lines[line].ascent = 0;
524        lines[line].descent = 0;
525        line++;
526     }
527     
528     free(curmode.substyle);
529     fixup_and_draw(dpy, style, auxblocks, blocks, nextblock, lines, line,
530                    beepcount);
531     free(lines);
532     free(auxblocks);
533     if (free_style)
534       free(style);
535 }
536
537 static void
538 xhandleevent(Display *dpy,
539              Window w,
540              XEvent *event)
541 {
542     x_gram *gram;
543     
544     if (XFindContext(dpy, w, desc_context, (caddr_t *)&gram))
545       return;
546
547     if (event->type == Expose)
548       x_gram_expose(dpy, w, gram,&(event->xexpose));
549     else
550       xcut(dpy, event, desc_context);
551
552     XFlush(dpy);
553 }
554
555 void
556 x_get_input(Display *dpy)
557 {
558     XEvent event;
559     
560     dprintf1("Entering x_get_input(%x).\n",dpy);
561
562     /*
563      * Kludge to get around lossage in XPending:
564      *
565      * (the problem: XPending on a partial packet returns 0 without
566      *  reading in the packet.  This causes a problem when the X server
567      *  dies in the middle of sending a packet.)
568      */
569     if (XPending(dpy)==0)
570       XNoOp(dpy);  /* Ensure server is still with us... */
571     
572     while (XPending(dpy)) {
573         XNextEvent(dpy,&event);
574         xhandleevent(dpy, event.xany.window, &event);
575     }
576 }
577
578 #endif /* X_DISPLAY_MISSING */
579