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 2336 2009-03-22 18:59:56Z kcr $
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 2336 2009-03-22 18:59:56Z kcr $";
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;
154 gram = (x_gram *)malloc(sizeof(x_gram));
156 /* Find total lengths of left, center, and right parts. Also find the
157 length of the longest line and the total number of characters. */
159 for (line=0; line<numlines; line++) {
160 lsize = csize = rsize = 0;
161 maxascent = maxdescent = 0;
163 /* add up sizes for each block, get max ascent and descent */
165 for (i=0; i<lines[line].numblock; i++,block++) {
166 chars += auxblocks[block].len;
167 ssize = XTextWidth(auxblocks[block].font, auxblocks[block].str,
168 auxblocks[block].len);
169 auxblocks[block].width = ssize;
170 ascent = auxblocks[block].font->ascent;
171 descent = auxblocks[block].font->descent;
172 if (ascent>maxascent)
174 if (descent>maxdescent)
175 maxdescent = descent;
176 switch (auxblocks[block].align) {
191 /* save what we need to do size fixups */
193 if (maxascent>lines[line].ascent)
194 lines[line].ascent = maxascent;
195 if (maxdescent>lines[line].descent)
196 lines[line].descent = maxdescent;
197 lines[line].lsize = lsize;
198 lines[line].csize = csize;
199 lines[line].rsize = rsize;
201 /* get width of line and see if it is bigger than the max width */
203 switch ((lsize?1:0)+(csize?2:0)+(rsize?4:0)) {
222 /* in all these cases, we just want to add the width of *any*
223 space, so the first font will do just fine. */
224 /* XXX implicit assumption that a line must have at least one
225 block, so that there is indeed a reasonable font in
227 width = lsize*2+csize+XTextWidth(auxblocks[0].font," ",1);
235 width = lsize+rsize+XTextWidth(auxblocks[0].font, " ", 1);
239 width = csize+rsize*2+XTextWidth(auxblocks[0].font, " ", 1);
243 width = max(lsize,rsize)*2+csize+
244 XTextWidth(auxblocks[0].font," ",1)*2;
251 /* fixup x,y for each block, create big string and indices into it */
252 /* set x1,y1,x2,y2 of each block also. */
254 gram->text = (char *)malloc(chars);
257 for (line=0; line<numlines; line++) {
258 lofs = internal_border_width;
259 cofs = ((maxwidth-lines[line].csize)>>1) + internal_border_width;
260 rofs = maxwidth-lines[line].rsize + internal_border_width;
262 yofs += lines[line].ascent;
263 yend = yofs+lines[line].descent+1; /* +1 because lines look scrunched
266 for (i=0; i<lines[line].numblock; i++,block++) {
267 blocks[block].fid = auxblocks[block].font->fid;
268 switch (auxblocks[block].align) {
270 blocks[block].x = lofs;
271 blocks[block].x1 = lofs;
272 lofs += auxblocks[block].width;
273 blocks[block].x2 = lofs;
277 blocks[block].x = cofs;
278 blocks[block].x1 = cofs;
279 cofs += auxblocks[block].width;
280 blocks[block].x2 = cofs;
284 blocks[block].x = rofs;
285 blocks[block].x1 = rofs;
286 rofs += auxblocks[block].width;
287 blocks[block].x2 = rofs;
290 blocks[block].y = yofs;
291 blocks[block].y1 = ystart;
292 blocks[block].y2 = yend;
293 blocks[block].strindex = strindex;
294 blocks[block].strlen = auxblocks[block].len;
295 strncpy(gram->text+strindex, auxblocks[block].str,
296 auxblocks[block].len);
297 strindex += blocks[block].strlen;
304 if ((geometry = var_get_variable("X_geometry")),(geometry[0]=='\0'))
305 if ((geometry = xres_get_geometry(style))==NULL)
306 if ((geometry = var_get_variable("default_X_geometry")),
309 sscanf(geometry, "%c%[0123456789c]%c%[0123456789c]", &xfrom, xpos,
316 gram_xpos = atoi(xpos);
324 gram_ypos = atoi(ypos);
328 if ((bgstr = var_get_variable("X_background")),(bgstr[0]=='\0'))
329 if ((bgstr = xres_get_bgcolor(style))==NULL)
330 if ((bgstr = var_get_variable("default_X_background")),
332 gram->bgcolor = default_bgcolor;
333 if (bgstr && bgstr[0])
334 gram->bgcolor = x_string_to_color(bgstr,default_bgcolor);
337 gram_xsize = maxwidth+(internal_border_width<<1);
338 gram_ysize = yofs+internal_border_width;
339 gram->numblocks = num;
340 gram->blocks = blocks;
342 gram->notice = get_stored_notice();
345 x_gram_create(dpy, gram, gram_xalign, gram_yalign, gram_xpos,
346 gram_ypos, gram_xsize, gram_ysize, beepcount);
349 /* Silly almost-but-not-quite-useless helper function */
351 no_dots_downcase_var(char *str)
353 register char *var, *var2;
355 var = string_Downcase(var_get_variable(str));
363 #define MODE_TO_FONT(dpy,style,mode) \
364 get_font((dpy),(style),(mode)->font?(mode)->font:(mode)->substyle, \
365 (mode)->size, (mode)->bold+(mode)->italic*2)
373 xmode_stack modes = xmode_stack_create();
377 xauxblock *auxblocks;
379 int line=0,linestart=0;
384 lines = (xlinedesc *)malloc(sizeof(xlinedesc)*(numnl+1));
386 blocks = (xblock *)malloc(sizeof(xblock)*numstr);
387 auxblocks = (xauxblock *)malloc(sizeof(xauxblock)*numstr);
391 curmode.size = MEDIUM_SIZE;
392 curmode.align = LEFTALIGN;
393 curmode.expcolor = 0;
394 curmode.substyle = string_Copy("default");
397 style = var_get_variable("style");
398 if (style[0] == '\0') {
399 style = string_Concat(no_dots_downcase_var("class"),".");
400 style = string_Concat2(style,no_dots_downcase_var("instance"));
401 style = string_Concat2(style,".");
402 style = string_Concat2(style,no_dots_downcase_var("sender"));
403 string_Downcase(style);
407 for (; desc->code!=DT_EOF; desc=desc->next) {
408 switch (desc->code) {
410 xmode_stack_push(modes, curmode);
411 curmode.substyle = string_Copy(curmode.substyle);
413 curmode.font = string_Copy(curmode.font);
415 #define envmatch(string,length) ((desc->len==(length)) && (strncasecmp(desc->str,(string),(length))==0))
417 if (envmatch("roman",5)) {
420 } else if (envmatch("bold",4) || envmatch("b",1))
422 else if (envmatch("italic",6)||envmatch("i",1))
424 else if (envmatch("large",5))
425 curmode.size = LARGE_SIZE;
426 else if (envmatch("medium",6))
427 curmode.size = MEDIUM_SIZE;
428 else if (envmatch("small",5))
429 curmode.size = SMALL_SIZE;
430 else if (envmatch("left",4)||envmatch("l",1))
431 curmode.align = LEFTALIGN;
432 else if (envmatch("center",6)||envmatch("c",1))
433 curmode.align = CENTERALIGN;
434 else if (envmatch("right",5)||envmatch("r",1))
435 curmode.align = RIGHTALIGN;
436 else if (envmatch("beep",4))
438 else if (envmatch("font",4)) {
439 /* lookahead needed. desc->next->str should be the
440 font name, and desc->next->next->code should be
443 (desc->next->next) &&
444 (desc->next->code == DT_STR) &&
445 (desc->next->next->code==DT_END)) {
447 /* Since @font mutates the current environment, we have
448 to pop the environment that this case usually pushes */
449 free(curmode.substyle);
450 curmode = xmode_stack_top(modes);
451 xmode_stack_pop(modes);
454 curmode.size=SPECIAL_SIZE; /* This is an @font() */
455 curmode.font=string_CreateFromData(desc->next->str,
457 /* skip over the rest of the @font */
458 desc=desc->next->next;
460 } else if (envmatch("color",5)) {
461 /* lookahead needed. desc->next->str should be the
462 font name, and desc->next->next->code should be
465 (desc->next->next) &&
466 (desc->next->code == DT_STR) &&
467 (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 colorname=string_CreateFromData(desc->next->str,
479 curmode.color = x_string_to_color(colorname,default_fgcolor);
481 curmode.expcolor = 1;
482 /* skip over the rest of the @font */
483 desc=desc->next->next;
485 } else if (desc->len > 0) { /* avoid @{...} */
486 free(curmode.substyle);
491 curmode.substyle = string_CreateFromData(desc->str, desc->len);
496 auxblocks[nextblock].align = curmode.align;
497 auxblocks[nextblock].font = MODE_TO_FONT(dpy,style,&curmode);
498 auxblocks[nextblock].str = desc->str;
499 auxblocks[nextblock].len = desc->len;
500 if (curmode.expcolor)
501 blocks[nextblock].fgcolor = curmode.color;
503 blocks[nextblock].fgcolor =
504 x_string_to_color(mode_to_colorname(dpy,style,&curmode),
510 free(curmode.substyle);
511 curmode = xmode_stack_top(modes);
512 xmode_stack_pop(modes);
516 lines[line].startblock = linestart;
517 lines[line].numblock = nextblock-linestart;
518 font = MODE_TO_FONT(dpy,style,&curmode);
519 lines[line].ascent = font->ascent;
520 lines[line].descent = font->descent;
522 linestart = nextblock;
527 /* case DT_EOF: will drop through to here. */
529 if (linestart != nextblock) {
530 lines[line].startblock = linestart;
531 lines[line].numblock = nextblock-linestart;
532 font = MODE_TO_FONT(dpy,style,&curmode);
533 lines[line].ascent = 0;
534 lines[line].descent = 0;
538 free(curmode.substyle);
539 fixup_and_draw(dpy, style, auxblocks, blocks, nextblock, lines, line,
548 xhandleevent(Display *dpy,
554 if (XFindContext(dpy, w, desc_context, (caddr_t *)&gram))
557 if (event->type == Expose)
558 x_gram_expose(dpy, w, gram,&(event->xexpose));
560 xcut(dpy, event, desc_context);
566 x_get_input(Display *dpy)
570 dprintf1("Entering x_get_input(%x).\n",dpy);
573 * Kludge to get around lossage in XPending:
575 * (the problem: XPending on a partial packet returns 0 without
576 * reading in the packet. This causes a problem when the X server
577 * dies in the middle of sending a packet.)
579 if (XPending(dpy)==0)
580 XNoOp(dpy); /* Ensure server is still with us... */
582 while (XPending(dpy)) {
583 XNextEvent(dpy,&event);
584 xhandleevent(dpy, event.xany.window, &event);
590 plus_window_deletions(ZNotice_t *notice)
595 static char class_nm[NAMESIZE], instance_nm[NAMESIZE], recip_nm[NAMESIZE];
600 val = var_get_variable("delete_window");
602 #ifdef DEBUG_DELETION
603 fprintf(stderr, "delete_window(%s)\n", val);
606 if (!strcmp(val, "this")) {
611 if (tmp->notice == notice) {
614 xdestroygram(dpy, fry->w, desc_context, fry);
622 else if (!strcmp(val, "s")) {
623 /* I cheated. This is really sender, not class */
624 strcpy(class_nm, notice->z_sender);
629 if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_sender, class_nm)) {
632 xdestroygram(dpy, fry->w, desc_context, fry);
640 else if (!strcmp(val, "ns")) {
641 /* I cheated. This is really sender, not class */
642 strcpy(class_nm, notice->z_sender);
647 if (!!strcasecmp(((ZNotice_t *)(tmp->notice))->z_sender, class_nm)) {
650 xdestroygram(dpy, fry->w, desc_context, fry);
658 else if (!strcmp(val, "r")) {
659 strcpy(recip_nm, notice->z_recipient);
664 if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_recipient, recip_nm)) {
667 xdestroygram(dpy, fry->w, desc_context, fry);
675 else if (!strcmp(val, "nr")) {
676 strcpy(recip_nm, notice->z_recipient);
681 if (!!strcasecmp(((ZNotice_t *)(tmp->notice))->z_recipient, recip_nm)) {
684 xdestroygram(dpy, fry->w, desc_context, fry);
692 else if (!strcmp(val, "cir")) {
693 strcpy(class_nm, notice->z_class);
694 strcpy(instance_nm, notice->z_class_inst);
695 strcpy(recip_nm, notice->z_recipient);
700 if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_class_inst, instance_nm)
701 && !strcasecmp(((ZNotice_t *)(tmp->notice))->z_class, class_nm)
702 && !strcasecmp(((ZNotice_t *)(tmp->notice))->z_recipient, recip_nm))
706 xdestroygram(dpy, fry->w, desc_context, fry);
714 else if (!strcmp(val, "ci")) {
715 strcpy(class_nm, notice->z_class);
716 strcpy(instance_nm, notice->z_class_inst);
721 if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_class_inst, instance_nm)
722 && !strcasecmp(((ZNotice_t *)(tmp->notice))->z_class, class_nm))
726 xdestroygram(dpy, fry->w, desc_context, fry);
734 else if (!strcmp(val, "cr")) {
735 strcpy(class_nm, notice->z_class);
736 strcpy(recip_nm, notice->z_recipient);
741 if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_class, class_nm) &&
742 !strcasecmp(((ZNotice_t *)(tmp->notice))->z_recipient, recip_nm))
746 xdestroygram(dpy, fry->w, desc_context, fry);
754 else if (!strcmp(val, "c")) {
755 strcpy(class_nm, notice->z_class);
760 if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_class, class_nm)) {
763 xdestroygram(dpy, fry->w, desc_context, fry);
771 else if (!strcmp(val, "all")) {
772 while (bottom_gram) {
773 xdestroygram(dpy, bottom_gram->w, desc_context, bottom_gram);
779 #endif /* X_DISPLAY_MISSING */