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
5 * Created by: Marc Horowitz <marc@athena.mit.edu>
9 * Copyright (c) 1989 by the Massachusetts Institute of Technology.
10 * For copying and distribution information, see the file
16 #if (!defined(lint) && !defined(SABER))
17 static const char rcsid_xshow_c[] = "$Id$";
20 #include <zephyr/mit-copyright.h>
22 #ifndef X_DISPLAY_MISSING
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"
36 #include "xmode_stack.h"
38 #define max(a,b) ((a)>(b)?(a):(b))
40 XContext desc_context;
42 extern int internal_border_width;
43 extern unsigned long default_bgcolor;
44 extern unsigned long default_fgcolor;
49 desc_context = XUniqueContext();
52 struct res_dict_type {
53 pointer_dictionary dict;
54 char * resname_suffix;
59 xres_get_resource(struct res_dict_type *restype,
63 pointer_dictionary_binding *binding;
67 desc=string_Concat("style.", style);
68 desc=string_Concat2(desc, restype->resname_suffix);
71 restype->dict = pointer_dictionary_Create(37);
72 binding = pointer_dictionary_Define(restype->dict, desc, &exists);
76 return((string) binding->value);
78 value=get_string_resource(desc, restype->resclass);
81 pointer_dictionary_Delete(restype->dict, binding);
83 binding->value=(pointer) value;
84 return value; /* If resource returns NULL, return NULL also */
88 static struct res_dict_type geometry_resources = {
89 NULL, ".geometry", "StyleKey.Style1.Style2.Style3.GeometryKey",
92 static struct res_dict_type bgcolor_resources = {
93 NULL, ".background", "StyleKey.Style1.Style2.Style3.BackgroundKey",
96 #define xres_get_geometry(style) xres_get_resource(&geometry_resources,style)
97 #define xres_get_bgcolor(style) xres_get_resource(&bgcolor_resources,style)
99 static struct res_dict_type fgcolor_resources = {
101 "StyleKey.Style1.Style2.Style3.SubstyleKey.Substyle.ForegroundKey",
106 mode_to_colorname (Display *dpy,
112 desc = string_Concat (style, ".substyle.");
113 desc = string_Concat2 (desc, mode->substyle);
114 result = xres_get_resource (&fgcolor_resources, desc);
120 fixup_and_draw(Display *dpy,
122 xauxblock *auxblocks,
131 int gram_xpos, gram_ypos, gram_xsize, gram_ysize;
137 int maxwidth=0, chars=0, maxascent, maxdescent;
138 int ssize, lsize,csize, rsize, width;
139 int i, ascent, descent;
141 int yofs = internal_border_width;
142 int lofs, cofs, rofs;
145 char *bgstr, *geometry, xpos[10], ypos[10], xfrom, yfrom;
147 gram = (x_gram *)malloc(sizeof(x_gram));
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. */
152 for (line=0; line<numlines; line++) {
153 lsize = csize = rsize = 0;
154 maxascent = maxdescent = 0;
156 /* add up sizes for each block, get max ascent and descent */
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)
167 if (descent>maxdescent)
168 maxdescent = descent;
169 switch (auxblocks[block].align) {
184 /* save what we need to do size fixups */
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;
194 /* get width of line and see if it is bigger than the max width */
196 switch ((lsize?1:0)+(csize?2:0)+(rsize?4:0)) {
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
220 width = lsize*2+csize+XTextWidth(auxblocks[0].font," ",1);
228 width = lsize+rsize+XTextWidth(auxblocks[0].font, " ", 1);
232 width = csize+rsize*2+XTextWidth(auxblocks[0].font, " ", 1);
236 width = max(lsize,rsize)*2+csize+
237 XTextWidth(auxblocks[0].font," ",1)*2;
244 /* fixup x,y for each block, create big string and indices into it */
245 /* set x1,y1,x2,y2 of each block also. */
247 gram->text = (char *)malloc(chars);
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;
255 yofs += lines[line].ascent;
256 yend = yofs+lines[line].descent+1; /* +1 because lines look scrunched
259 for (i=0; i<lines[line].numblock; i++,block++) {
260 blocks[block].fid = auxblocks[block].font->fid;
261 switch (auxblocks[block].align) {
263 blocks[block].x = lofs;
264 blocks[block].x1 = lofs;
265 lofs += auxblocks[block].width;
266 blocks[block].x2 = lofs;
270 blocks[block].x = cofs;
271 blocks[block].x1 = cofs;
272 cofs += auxblocks[block].width;
273 blocks[block].x2 = cofs;
277 blocks[block].x = rofs;
278 blocks[block].x1 = rofs;
279 rofs += auxblocks[block].width;
280 blocks[block].x2 = rofs;
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;
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")),
302 sscanf(geometry, "%c%[0123456789c]%c%[0123456789c]", &xfrom, xpos,
309 gram_xpos = atoi(xpos);
317 gram_ypos = atoi(ypos);
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")),
325 gram->bgcolor = default_bgcolor;
326 if (bgstr && bgstr[0])
327 gram->bgcolor = x_string_to_color(bgstr,default_bgcolor);
330 gram_xsize = maxwidth+(internal_border_width<<1);
331 gram_ysize = yofs+internal_border_width;
332 gram->numblocks = num;
333 gram->blocks = blocks;
335 x_gram_create(dpy, gram, gram_xalign, gram_yalign, gram_xpos,
336 gram_ypos, gram_xsize, gram_ysize, beepcount);
339 /* Silly almost-but-not-quite-useless helper function */
341 no_dots_downcase_var(char *str)
343 register char *var, *var2;
345 var = string_Downcase(var_get_variable(str));
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)
363 xmode_stack modes = xmode_stack_create();
367 xauxblock *auxblocks;
369 int line=0,linestart=0;
374 lines = (xlinedesc *)malloc(sizeof(xlinedesc)*(numnl+1));
376 blocks = (xblock *)malloc(sizeof(xblock)*numstr);
377 auxblocks = (xauxblock *)malloc(sizeof(xauxblock)*numstr);
381 curmode.size = MEDIUM_SIZE;
382 curmode.align = LEFTALIGN;
383 curmode.expcolor = 0;
384 curmode.substyle = string_Copy("default");
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);
397 for (; desc->code!=DT_EOF; desc=desc->next) {
398 switch (desc->code) {
400 xmode_stack_push(modes, curmode);
401 curmode.substyle = string_Copy(curmode.substyle);
403 curmode.font = string_Copy(curmode.font);
405 #define envmatch(string,length) ((desc->len==(length)) && (strncasecmp(desc->str,(string),(length))==0))
407 if (envmatch("roman",5)) {
410 } else if (envmatch("bold",4) || envmatch("b",1))
412 else if (envmatch("italic",6)||envmatch("i",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))
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
433 (desc->next->next) &&
434 (desc->next->code == DT_STR) &&
435 (desc->next->next->code==DT_END)) {
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);
444 curmode.size=SPECIAL_SIZE; /* This is an @font() */
445 curmode.font=string_CreateFromData(desc->next->str,
447 /* skip over the rest of the @font */
448 desc=desc->next->next;
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
455 (desc->next->next) &&
456 (desc->next->code == DT_STR) &&
457 (desc->next->next->code==DT_END)) {
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);
467 colorname=string_CreateFromData(desc->next->str,
469 curmode.color = x_string_to_color(colorname,default_fgcolor);
471 curmode.expcolor = 1;
472 /* skip over the rest of the @font */
473 desc=desc->next->next;
475 } else if (desc->len > 0) { /* avoid @{...} */
476 free(curmode.substyle);
481 curmode.substyle = string_CreateFromData(desc->str, desc->len);
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;
493 blocks[nextblock].fgcolor =
494 x_string_to_color(mode_to_colorname(dpy,style,&curmode),
500 free(curmode.substyle);
501 curmode = xmode_stack_top(modes);
502 xmode_stack_pop(modes);
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;
512 linestart = nextblock;
517 /* case DT_EOF: will drop through to here. */
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;
528 free(curmode.substyle);
529 fixup_and_draw(dpy, style, auxblocks, blocks, nextblock, lines, line,
538 xhandleevent(Display *dpy,
544 if (XFindContext(dpy, w, desc_context, (caddr_t *)&gram))
547 if (event->type == Expose)
548 x_gram_expose(dpy, w, gram,&(event->xexpose));
550 xcut(dpy, event, desc_context);
556 x_get_input(Display *dpy)
560 dprintf1("Entering x_get_input(%x).\n",dpy);
563 * Kludge to get around lossage in XPending:
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.)
569 if (XPending(dpy)==0)
570 XNoOp(dpy); /* Ensure server is still with us... */
572 while (XPending(dpy)) {
573 XNextEvent(dpy,&event);
574 xhandleevent(dpy, event.xany.window, &event);
578 #endif /* X_DISPLAY_MISSING */