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 2630 2011-02-02 05:26:26Z kcr@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: xshow.c 2630 2011-02-02 05:26:26Z kcr@ATHENA.MIT.EDU $";
20 #include <zephyr/mit-copyright.h>
22 #ifndef X_DISPLAY_MISSING
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"
37 #include "xmode_stack.h"
39 #include <zephyr/zephyr.h>
40 #include "xrevstack.h"
45 #define max(a,b) ((a)>(b)?(a):(b))
47 XContext desc_context;
49 extern int internal_border_width;
50 extern unsigned long default_bgcolor;
51 extern unsigned long default_fgcolor;
56 desc_context = XUniqueContext();
59 struct res_dict_type {
60 pointer_dictionary dict;
61 char * resname_suffix;
66 xres_get_resource(struct res_dict_type *restype,
70 pointer_dictionary_binding *binding;
74 desc=string_Concat("style.", style);
75 desc=string_Concat2(desc, restype->resname_suffix);
78 restype->dict = pointer_dictionary_Create(37);
79 binding = pointer_dictionary_Define(restype->dict, desc, &exists);
83 return((string) binding->value);
85 value=get_string_resource(desc, restype->resclass);
88 pointer_dictionary_Delete(restype->dict, binding);
90 binding->value=(pointer) value;
91 return value; /* If resource returns NULL, return NULL also */
95 static struct res_dict_type geometry_resources = {
96 NULL, ".geometry", "StyleKey.Style1.Style2.Style3.GeometryKey",
99 static struct res_dict_type bgcolor_resources = {
100 NULL, ".background", "StyleKey.Style1.Style2.Style3.BackgroundKey",
103 #define xres_get_geometry(style) xres_get_resource(&geometry_resources,style)
104 #define xres_get_bgcolor(style) xres_get_resource(&bgcolor_resources,style)
106 static struct res_dict_type fgcolor_resources = {
108 "StyleKey.Style1.Style2.Style3.SubstyleKey.Substyle.ForegroundKey",
113 mode_to_colorname (Display *dpy,
119 desc = string_Concat (style, ".substyle.");
120 desc = string_Concat2 (desc, mode->substyle);
121 result = xres_get_resource (&fgcolor_resources, desc);
127 fixup_and_draw(Display *dpy,
129 xauxblock *auxblocks,
138 int gram_xpos, gram_ypos, gram_xsize, gram_ysize;
144 int maxwidth=0, chars=0, maxascent, maxdescent;
145 int ssize, lsize,csize, rsize, width = 0;
146 int i, ascent, descent;
148 int yofs = internal_border_width;
149 int lofs, cofs, rofs;
152 char *bgstr, *geometry, xpos[10], ypos[10], xfrom, yfrom;
153 XFontSetExtents *fse;
155 gram = (x_gram *)malloc(sizeof(x_gram));
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. */
160 for (line = 0; line < numlines; line++) {
161 lsize = csize = rsize = 0;
162 maxascent = maxdescent = 0;
164 /* add up sizes for each block, get max ascent and descent */
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,
173 ssize = XwcTextEscapement(auxblocks[block].font,
174 (XChar2b *)blocks[block].wstr,
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)
183 if (descent > maxdescent)
184 maxdescent = descent;
185 switch (auxblocks[block].align) {
200 /* save what we need to do size fixups */
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;
210 /* get width of line and see if it is bigger than the max width */
212 switch ((lsize ? 1 : 0) + (csize ?2 : 0) + (rsize ? 4 : 0)) {
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
236 width = lsize * 2 + csize + XmbTextEscapement(auxblocks[0].font, " ", 1);
244 width = lsize + rsize + XmbTextEscapement(auxblocks[0].font, " ", 1);
248 width = csize + rsize * 2 + XmbTextEscapement(auxblocks[0].font, " ", 1);
252 width = max(lsize, rsize) * 2 + csize +
253 XmbTextEscapement(auxblocks[0].font, " ", 1) * 2;
256 if (width > maxwidth)
260 /* fixup x,y for each block, create big string and indices into it */
261 /* set x1,y1,x2,y2 of each block also. */
263 gram->text = (char *)malloc(chars);
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;
271 yofs += lines[line].ascent;
272 yend = yofs + lines[line].descent + 1; /* +1 because lines look scrunched
275 for (i = 0; i < lines[line].numblock; i++, block++) {
276 blocks[block].font = auxblocks[block].font;
277 switch (auxblocks[block].align) {
279 blocks[block].x = lofs;
280 blocks[block].x1 = lofs;
281 lofs += auxblocks[block].width;
282 blocks[block].x2 = lofs;
286 blocks[block].x = cofs;
287 blocks[block].x1 = cofs;
288 cofs += auxblocks[block].width;
289 blocks[block].x2 = cofs;
293 blocks[block].x = rofs;
294 blocks[block].x1 = rofs;
295 rofs += auxblocks[block].width;
296 blocks[block].x2 = rofs;
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;
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')
321 sscanf(geometry, "%c%[0123456789c]%c%[0123456789c]", &xfrom, xpos,
324 if (xpos[0] == 'c') {
328 gram_xpos = atoi(xpos);
332 if (ypos[0] == 'c') {
336 gram_ypos = atoi(ypos);
340 bgstr = var_get_variable("X_background");
341 if (bgstr[0] == '\0')
342 bgstr = xres_get_bgcolor(style);
344 bgstr = var_get_variable("default_X_background");
346 gram->bgcolor = default_bgcolor;
348 if (bgstr && bgstr[0])
349 gram->bgcolor = x_string_to_color(bgstr, default_bgcolor);
351 gram_xsize = maxwidth + (internal_border_width << 1);
352 gram_ysize = yofs + internal_border_width;
353 gram->numblocks = num;
354 gram->blocks = blocks;
356 gram->notice = get_stored_notice();
359 x_gram_create(dpy, gram, gram_xalign, gram_yalign, gram_xpos,
360 gram_ypos, gram_xsize, gram_ysize, beepcount);
363 /* Silly almost-but-not-quite-useless helper function */
365 no_dots_downcase_var(char *str)
367 register char *var, *var2;
369 var = string_Downcase(var_get_variable(str));
377 inline static XFontSet
378 mode_to_font(Display *dpy, char *style, xmode *mode) {
381 mode->font ? mode->font : mode->substyle,
383 mode->bold + mode->italic * 2);
387 envmatch(desctype *desc, char *str) {
388 int len = strlen(str);
389 return desc->len == len && strncasecmp(desc->str, str, len) == 0;
393 xshow(Display *dpy, desctype *desc, int numstr, int numnl)
396 XFontSetExtents *fse;
397 xmode_stack modes = xmode_stack_create();
401 xauxblock *auxblocks;
403 int line=0,linestart=0;
407 char *notice_charset = var_get_variable("notice_charset");
410 lines = (xlinedesc *)malloc(sizeof(xlinedesc) * (numnl + 1));
412 blocks = (xblock *)malloc(sizeof(xblock) * numstr);
413 auxblocks = (xauxblock *)malloc(sizeof(xauxblock) * numstr);
417 curmode.size = MEDIUM_SIZE;
418 curmode.align = LEFTALIGN;
419 curmode.expcolor = 0;
420 curmode.substyle = string_Copy("default");
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);
433 for (; desc->code != DT_EOF; desc = desc->next) {
434 switch (desc->code) {
436 xmode_stack_push(modes, curmode);
437 curmode.substyle = string_Copy(curmode.substyle);
439 curmode.font = string_Copy(curmode.font);
440 if (envmatch(desc, "roman")) {
443 } else if (envmatch(desc, "bold") || envmatch(desc, "b"))
445 else if (envmatch(desc, "italic") || envmatch(desc, "i"))
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"))
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
466 (desc->next->next) &&
467 (desc->next->code == DT_STR) &&
468 (desc->next->next->code == DT_END)) {
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);
477 curmode.size = SPECIAL_SIZE; /* This is an @font() */
478 curmode.font = string_CreateFromData(desc->next->str,
480 /* skip over the rest of the @font */
481 desc = desc->next->next;
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
488 (desc->next->next) &&
489 (desc->next->code == DT_STR) &&
490 (desc->next->next->code == DT_END)) {
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);
500 colorname = string_CreateFromData(desc->next->str,
502 curmode.color = x_string_to_color(colorname, default_fgcolor);
504 curmode.expcolor = 1;
505 /* skip over the rest of the @font */
506 desc = desc->next->next;
508 } else if (desc->len > 0) { /* avoid @{...} */
509 free(curmode.substyle);
514 curmode.substyle = string_CreateFromData(desc->str, desc->len);
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
531 &blocks[nextblock].wstr,
532 &blocks[nextblock].wlen);
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);
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]);
546 #ifndef X_HAVE_UTF8_STRING
547 blocks[nextblock].wlen /= 2;
549 if (curmode.expcolor)
550 blocks[nextblock].fgcolor = curmode.color;
552 blocks[nextblock].fgcolor =
553 x_string_to_color(mode_to_colorname(dpy, style, &curmode),
559 free(curmode.substyle);
560 curmode = xmode_stack_top(modes);
561 xmode_stack_pop(modes);
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;
573 linestart = nextblock;
578 /* case DT_EOF: will drop through to here. */
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;
589 free(curmode.substyle);
590 fixup_and_draw(dpy, style, auxblocks, blocks, nextblock, lines, line,
599 xhandleevent(Display *dpy,
605 if (XFindContext(dpy, w, desc_context, (XPointer *)&gram))
608 if (event->type == Expose)
609 x_gram_expose(dpy, w, gram,&(event->xexpose));
611 xcut(dpy, event, desc_context);
617 x_get_input(Display *dpy)
621 dprintf1("Entering x_get_input(%x).\n",dpy);
624 * Kludge to get around lossage in XPending:
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.)
630 if (XPending(dpy)==0)
631 XNoOp(dpy); /* Ensure server is still with us... */
633 while (XPending(dpy)) {
634 XNextEvent(dpy,&event);
635 xhandleevent(dpy, event.xany.window, &event);
641 plus_window_deletions(ZNotice_t *notice)
646 static char class_nm[NAMESIZE], instance_nm[NAMESIZE], recip_nm[NAMESIZE];
651 val = var_get_variable("delete_window");
653 #ifdef DEBUG_DELETION
654 fprintf(stderr, "delete_window(%s)\n", val);
657 if (!strcmp(val, "this")) {
662 if (tmp->notice == notice) {
665 xdestroygram(dpy, fry->w, desc_context, fry);
673 else if (!strcmp(val, "s")) {
674 /* I cheated. This is really sender, not class */
675 strcpy(class_nm, notice->z_sender);
680 if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_sender, class_nm)) {
683 xdestroygram(dpy, fry->w, desc_context, fry);
691 else if (!strcmp(val, "ns")) {
692 /* I cheated. This is really sender, not class */
693 strcpy(class_nm, notice->z_sender);
698 if (!!strcasecmp(((ZNotice_t *)(tmp->notice))->z_sender, class_nm)) {
701 xdestroygram(dpy, fry->w, desc_context, fry);
709 else if (!strcmp(val, "r")) {
710 strcpy(recip_nm, notice->z_recipient);
715 if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_recipient, recip_nm)) {
718 xdestroygram(dpy, fry->w, desc_context, fry);
726 else if (!strcmp(val, "nr")) {
727 strcpy(recip_nm, notice->z_recipient);
732 if (!!strcasecmp(((ZNotice_t *)(tmp->notice))->z_recipient, recip_nm)) {
735 xdestroygram(dpy, fry->w, desc_context, fry);
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);
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))
757 xdestroygram(dpy, fry->w, desc_context, fry);
765 else if (!strcmp(val, "ci")) {
766 strcpy(class_nm, notice->z_class);
767 strcpy(instance_nm, notice->z_class_inst);
772 if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_class_inst, instance_nm)
773 && !strcasecmp(((ZNotice_t *)(tmp->notice))->z_class, class_nm))
777 xdestroygram(dpy, fry->w, desc_context, fry);
785 else if (!strcmp(val, "cr")) {
786 strcpy(class_nm, notice->z_class);
787 strcpy(recip_nm, notice->z_recipient);
792 if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_class, class_nm) &&
793 !strcasecmp(((ZNotice_t *)(tmp->notice))->z_recipient, recip_nm))
797 xdestroygram(dpy, fry->w, desc_context, fry);
805 else if (!strcmp(val, "c")) {
806 strcpy(class_nm, notice->z_class);
811 if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_class, class_nm)) {
814 xdestroygram(dpy, fry->w, desc_context, fry);
822 else if (!strcmp(val, "all")) {
823 while (bottom_gram) {
824 xdestroygram(dpy, bottom_gram->w, desc_context, bottom_gram);
830 #endif /* X_DISPLAY_MISSING */