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>
7 * $Id: xshow.c,v 1.15 1999/08/13 00:19:52 danw Exp $
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: xshow.c,v 1.15 1999/08/13 00:19:52 danw Exp $";
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 "formatter.h"
30 #include "variables.h"
34 #include "xmode_stack.h"
36 #define max(a,b) ((a)>(b)?(a):(b))
38 XContext desc_context;
39 static pointer_dictionary colorname_dict = NULL;
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();
49 desc_context = XUniqueContext();
52 struct res_dict_type {
53 pointer_dictionary dict;
54 char * resname_suffix;
58 static char *xres_get_resource (restype, style)
59 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",
105 char *mode_to_colorname (dpy, style, mode)
112 desc = string_Concat (style, ".substyle.");
113 desc = string_Concat2 (desc, mode->substyle);
114 result = xres_get_resource (&fgcolor_resources, desc);
119 void fixup_and_draw(dpy, style, auxblocks, blocks, num, lines, numlines,
124 xauxblock *auxblocks;
132 int gram_xpos, gram_ypos, gram_xsize, gram_ysize;
138 int maxwidth=0, chars=0, maxascent, maxdescent;
139 int ssize, lsize,csize, rsize, width;
140 int i, ascent, descent;
142 int yofs = internal_border_width;
143 int lofs, cofs, rofs;
146 char *bgstr, *geometry, xpos[10], ypos[10], xfrom, yfrom;
148 gram = (x_gram *)malloc(sizeof(x_gram));
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. */
153 for (line=0; line<numlines; line++) {
154 lsize = csize = rsize = 0;
155 maxascent = maxdescent = 0;
157 /* add up sizes for each block, get max ascent and descent */
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)
168 if (descent>maxdescent)
169 maxdescent = descent;
170 switch (auxblocks[block].align) {
185 /* save what we need to do size fixups */
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;
195 /* get width of line and see if it is bigger than the max width */
197 switch ((lsize?1:0)+(csize?2:0)+(rsize?4:0)) {
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
221 width = lsize*2+csize+XTextWidth(auxblocks[0].font," ",1);
229 width = lsize+rsize+XTextWidth(auxblocks[0].font, " ", 1);
233 width = csize+rsize*2+XTextWidth(auxblocks[0].font, " ", 1);
237 width = max(lsize,rsize)*2+csize+
238 XTextWidth(auxblocks[0].font," ",1)*2;
245 /* fixup x,y for each block, create big string and indices into it */
246 /* set x1,y1,x2,y2 of each block also. */
248 gram->text = (char *)malloc(chars);
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;
256 yofs += lines[line].ascent;
257 yend = yofs+lines[line].descent+1; /* +1 because lines look scrunched
260 for (i=0; i<lines[line].numblock; i++,block++) {
261 blocks[block].fid = auxblocks[block].font->fid;
262 switch (auxblocks[block].align) {
264 blocks[block].x = lofs;
265 blocks[block].x1 = lofs;
266 lofs += auxblocks[block].width;
267 blocks[block].x2 = lofs;
271 blocks[block].x = cofs;
272 blocks[block].x1 = cofs;
273 cofs += auxblocks[block].width;
274 blocks[block].x2 = cofs;
278 blocks[block].x = rofs;
279 blocks[block].x1 = rofs;
280 rofs += auxblocks[block].width;
281 blocks[block].x2 = rofs;
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;
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")),
303 sscanf(geometry, "%c%[0123456789c]%c%[0123456789c]", &xfrom, xpos,
310 gram_xpos = atoi(xpos);
318 gram_ypos = atoi(ypos);
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")),
326 gram->bgcolor = default_bgcolor;
327 if (bgstr && bgstr[0])
328 gram->bgcolor = x_string_to_color(bgstr,default_bgcolor);
331 gram_xsize = maxwidth+(internal_border_width<<1);
332 gram_ysize = yofs+internal_border_width;
333 gram->numblocks = num;
334 gram->blocks = blocks;
336 x_gram_create(dpy, gram, gram_xalign, gram_yalign, gram_xpos,
337 gram_ypos, gram_xsize, gram_ysize, beepcount);
340 /* Silly almost-but-not-quite-useless helper function */
341 char *no_dots_downcase_var(str)
344 register char *var, *var2;
346 var = string_Downcase(var_get_variable(str));
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)
364 xmode_stack modes = xmode_stack_create();
368 xauxblock *auxblocks;
370 int line=0,linestart=0;
375 lines = (xlinedesc *)malloc(sizeof(xlinedesc)*(numnl+1));
377 blocks = (xblock *)malloc(sizeof(xblock)*numstr);
378 auxblocks = (xauxblock *)malloc(sizeof(xauxblock)*numstr);
382 curmode.size = MEDIUM_SIZE;
383 curmode.align = LEFTALIGN;
384 curmode.expcolor = 0;
385 curmode.substyle = string_Copy("default");
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);
398 for (; desc->code!=DT_EOF; desc=desc->next) {
399 switch (desc->code) {
401 xmode_stack_push(modes, curmode);
402 curmode.substyle = string_Copy(curmode.substyle);
404 curmode.font = string_Copy(curmode.font);
406 #define envmatch(string,length) ((desc->len==(length)) && (strncasecmp(desc->str,(string),(length))==0))
408 if (envmatch("roman",5)) {
411 } else if (envmatch("bold",4) || envmatch("b",1))
413 else if (envmatch("italic",6)||envmatch("i",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))
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
434 (desc->next->next) &&
435 (desc->next->code == DT_STR) &&
436 (desc->next->next->code==DT_END)) {
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);
445 curmode.size=SPECIAL_SIZE; /* This is an @font() */
446 curmode.font=string_CreateFromData(desc->next->str,
448 /* skip over the rest of the @font */
449 desc=desc->next->next;
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
456 (desc->next->next) &&
457 (desc->next->code == DT_STR) &&
458 (desc->next->next->code==DT_END)) {
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);
468 colorname=string_CreateFromData(desc->next->str,
470 curmode.color = x_string_to_color(colorname,default_fgcolor);
472 curmode.expcolor = 1;
473 /* skip over the rest of the @font */
474 desc=desc->next->next;
476 } else if (desc->len > 0) { /* avoid @{...} */
477 free(curmode.substyle);
482 curmode.substyle = string_CreateFromData(desc->str, desc->len);
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;
494 blocks[nextblock].fgcolor =
495 x_string_to_color(mode_to_colorname(dpy,style,&curmode),
501 free(curmode.substyle);
502 curmode = xmode_stack_top(modes);
503 xmode_stack_pop(modes);
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;
513 linestart = nextblock;
518 /* case DT_EOF: will drop through to here. */
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;
529 free(curmode.substyle);
530 fixup_and_draw(dpy, style, auxblocks, blocks, nextblock, lines, line,
538 static void xhandleevent(dpy, w, event)
545 if (XFindContext(dpy, w, desc_context, (caddr_t *)&gram))
548 if (event->type == Expose)
549 x_gram_expose(dpy, w, gram,&(event->xexpose));
551 xcut(dpy, event, desc_context);
556 void x_get_input(dpy)
561 dprintf1("Entering x_get_input(%x).\n",dpy);
564 * Kludge to get around lossage in XPending:
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.)
570 if (XPending(dpy)==0)
571 XNoOp(dpy); /* Ensure server is still with us... */
573 while (XPending(dpy)) {
574 XNextEvent(dpy,&event);
575 xhandleevent(dpy, event.xany.window, &event);
579 #endif /* X_DISPLAY_MISSING */