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