]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/zwgc/X_gram.c
pull up to latest athena current
[1ts-debian.git] / zephyr / zwgc / X_gram.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: X_gram.c,v 1.23 2001/07/18 14:06:32 ghudson Exp $
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_X_gram_c[] = "$Id: X_gram.c,v 1.23 2001/07/18 14:06:32 ghudson Exp $";
18 #endif
19
20 #include <zephyr/mit-copyright.h>
21
22 #ifndef X_DISPLAY_MISSING
23
24 #include "X_gram.h"
25 #include "xmark.h"
26 #include <X11/Xutil.h>
27 #include <X11/cursorfont.h>
28 #include "zwgc.h"
29 #include "X_driver.h"
30 #include "X_fonts.h"
31 #include "error.h"
32 #include "new_string.h"
33 #include "xrevstack.h"
34 #include "xerror.h"
35 #include "xselect.h"
36
37 extern XContext desc_context;
38 extern char *app_instance;
39 extern unsigned long x_string_to_color();
40 extern char *getenv();
41
42 /*
43  *
44  */
45
46 int internal_border_width = 2;
47
48 unsigned long default_fgcolor;
49 unsigned long default_bgcolor;
50 unsigned long default_bordercolor;
51 long ttl = 500;
52 static int reset_saver;
53 static int border_width = 1;
54 static int cursor_code = XC_sailboat;
55 static int set_transient;
56 static int enable_delete;
57 static char *title_name,*icon_name;
58 static Cursor cursor;
59 static Window group_leader; /* In order to have transient windows,
60                              * I need a top-level window to always exist
61                              */
62 static XClassHint classhint;
63 static XSetWindowAttributes xattributes;
64 static unsigned long xattributes_mask;
65
66 /* ICCCM note:
67  *
68  * the following properties must be set on all top-level windows:
69  *
70  * WM_NAME                  XStoreName(dpy,w,name);
71  * WM_ICON_NAME             XSetIconName(dpy,w,name);
72  * WM_NORMAL_HINTS          XSetNormalHints(dpy,w,sizehints);
73  * WM_HINTS                 XSetWMHints(dpy,w,wmhints);
74  * WM_CLASS                 XSetClassHint(dpy,w,classhint);
75  *
76  * and for individual zgrams:
77  *
78  * WM_TRANSIENT_FOR         XSetTransientForHint(dpy,w,main_window);
79  * WM_PROTOCOLS             XSetWMProtocols(dpy,w,protocols,cnt);
80  */
81
82 /* set all properties defined in ICCCM.  If main_window == 0,
83  * per-zgram initialization is not done.
84  */
85
86 /*ARGSUSED*/
87 void x_set_icccm_hints(dpy,w,name,icon_name,psizehints,pwmhints,main_window)
88      Display *dpy;
89      Window w;
90      char *name;
91      char *icon_name;
92      XSizeHints *psizehints;
93      XWMHints *pwmhints;
94      Window main_window;
95 {
96    XStoreName(dpy,w,name);
97    XSetIconName(dpy,w,icon_name);
98    XSetNormalHints(dpy,w,psizehints);
99    XSetWMHints(dpy,w,pwmhints);
100    XSetClassHint(dpy,w,&classhint);
101    /* in order for some wm's to iconify, the window shouldn't be transient.
102       e.g. Motif wm */
103    if (main_window != None) {
104       if (set_transient)
105           XSetTransientForHint(dpy,w,main_window);
106    }
107    if (enable_delete)
108       XSetWMProtocols(dpy,w,&XA_WM_DELETE_WINDOW,1);
109 }
110
111 void x_gram_init(dpy)
112      Display *dpy;
113 {
114     char *temp;
115     XSizeHints sizehints;
116     XWMHints wmhints;
117     unsigned long rv,tc;
118
119     default_fgcolor = BlackPixelOfScreen(DefaultScreenOfDisplay(dpy));
120     default_bgcolor = WhitePixelOfScreen(DefaultScreenOfDisplay(dpy));
121     rv = get_bool_resource("reverseVideo", "ReverseVideo", 0);
122     if (rv) {
123        tc = default_fgcolor;
124        default_fgcolor = default_bgcolor;
125        default_bgcolor = tc;
126     }
127     if (temp = get_string_resource("foreground","Foreground"))
128       default_fgcolor = x_string_to_color(temp,default_fgcolor);
129     if (temp = get_string_resource("background","Background"))
130       default_bgcolor = x_string_to_color(temp,default_bgcolor);
131     default_bordercolor = default_fgcolor;
132     if (temp = get_string_resource("borderColor","BorderColor"))
133       default_bordercolor = x_string_to_color(temp,default_bordercolor);
134
135     temp = get_string_resource("minTimeToLive","MinTimeToLive");
136     if (temp && atoi(temp)>=0)
137        ttl = atoi(temp);
138
139     reverse_stack = get_bool_resource("reverseStack", "ReverseStack", 0);
140     reset_saver =  get_bool_resource("resetSaver", "ResetSaver", 1);
141     /* The default here should be 1, but mwm sucks */
142     set_transient = get_bool_resource("transient", "Transient", 0);
143     enable_delete = get_bool_resource("enableDelete", "EnableDelete", 1);
144
145     temp = get_string_resource("borderWidth", "BorderWidth");
146     /* <<<>>> */
147     if (temp && atoi(temp)>=0)
148       border_width = atoi(temp);
149
150     temp = get_string_resource("internalBorder", "InternalBorder");
151     /* <<<>>> */
152     if (temp && atoi(temp)>=0)
153       internal_border_width = atoi(temp);
154
155     temp = get_string_resource("cursorCode", "CursorCode");
156     /* <<<>>> */
157     if (temp && atoi(temp))
158       cursor_code = atoi(temp);
159
160     cursor = XCreateFontCursor(dpy, cursor_code);
161     if (!cursor)
162       cursor = XCreateFontCursor(dpy, XC_sailboat);
163
164     temp = get_string_resource("pointerColor", "Foreground");
165     if (temp) {
166         char *temp2;
167         XColor cursor_fore, cursor_back;
168         /* XXX need to do our own parsing here, since the RecolorCursor
169            routine requires an XColor, not an unsigned long (pixel) */
170         if (!(temp2 = get_string_resource("background","Background"))) {
171             if (default_bgcolor == WhitePixelOfScreen(DefaultScreenOfDisplay(dpy)))
172                 temp2 = "white";
173             else
174                 temp2 = "black";
175         }
176         if (XParseColor(dpy,
177                         DefaultColormapOfScreen(DefaultScreenOfDisplay(dpy)),
178                         temp, &cursor_fore) &&
179             XParseColor(dpy,
180                         DefaultColormapOfScreen(DefaultScreenOfDisplay(dpy)),
181                         temp2, &cursor_back)) {
182               XRecolorCursor(dpy, cursor, &cursor_fore, &cursor_back);
183           }
184     }
185     if (!(title_name=get_string_resource("title","Title")))
186       if (!(title_name=get_string_resource("name","Name")))
187         title_name=app_instance;
188
189     if (!(icon_name=get_string_resource("iconName","IconName")))
190       if (!(icon_name=get_string_resource("name","Name")))
191         icon_name=app_instance;
192
193     if (!(temp=get_string_resource("name","Name")))
194       if (!(temp=(char *) getenv("RESOURCE_NAME")))
195         temp=app_instance;
196     classhint.res_name=string_Copy(temp);
197     classhint.res_class="Zwgc";
198
199     if (set_transient) {
200        group_leader=XCreateSimpleWindow(dpy,DefaultRootWindow(dpy),0,0,100,100,
201                                         0,default_bordercolor,default_bgcolor);
202        sizehints.x = 0;
203        sizehints.y = 0;
204        sizehints.width = 100;
205        sizehints.height = 100;
206        sizehints.flags = PPosition | PSize;
207
208        wmhints.input = False;
209        wmhints.initial_state = DontCareState;
210        wmhints.flags = InputHint | StateHint;
211
212        x_set_icccm_hints(dpy,group_leader,"ZwgcGroup","ZwgcGroup",&sizehints,
213                          &wmhints,0);
214     }
215     xattributes.border_pixel = default_bordercolor;
216     xattributes.cursor = cursor;
217     xattributes.event_mask = (ExposureMask|ButtonReleaseMask|ButtonPressMask
218                               |LeaveWindowMask|Button1MotionMask
219                               |Button3MotionMask|StructureNotifyMask);
220     xattributes_mask = (CWBackPixel|CWBorderPixel|CWEventMask|CWCursor);
221     temp = get_string_resource ("backingStore", "BackingStore");
222     if (!temp)
223         return;
224     xattributes_mask |= CWBackingStore;
225     if (!strcasecmp (temp, "notuseful"))
226         xattributes.backing_store = NotUseful;
227     else if (!strcasecmp (temp, "whenmapped"))
228         xattributes.backing_store = WhenMapped;
229     else if (!strcasecmp (temp, "always"))
230         xattributes.backing_store = Always;
231     else if (!strcasecmp (temp, "default"))
232         xattributes_mask &= ~CWBackingStore;
233     else {
234         switch (get_bool_resource ("backingStore", "BackingStore", -1)) {
235         case 0:
236             xattributes.backing_store = NotUseful;
237             break;
238         case 1:
239             xattributes.backing_store = WhenMapped;
240             break;
241         case -1:
242             fprintf (stderr,
243                  "zwgc: Cannot interpret backing-store resource value `%s'.\n",
244                      temp);
245             xattributes_mask &= ~CWBackingStore;
246             break;
247         }
248     }
249 }
250
251 void x_gram_create(dpy, gram, xalign, yalign, xpos, ypos, xsize, ysize,
252                    beepcount)
253      Display *dpy;
254      x_gram *gram;
255      int xalign, yalign;
256      int xpos, ypos;
257      int xsize, ysize;
258      int beepcount;
259 {
260     Window w;
261     XSizeHints sizehints;
262     XWMHints wmhints;
263     XSetWindowAttributes attributes;
264     extern void x_get_input();
265
266     /*
267      * Adjust xpos, ypos based on the alignments xalign, yalign and the sizes:
268      */
269     if (xalign<0)
270       xpos = WidthOfScreen(DefaultScreenOfDisplay(dpy)) - xpos - xsize
271         - 2*border_width;
272     else if (xalign == 0)
273       xpos = (WidthOfScreen(DefaultScreenOfDisplay(dpy)) - xsize
274               - 2*border_width)>>1 + xpos;
275
276     if (yalign<0)
277       ypos = HeightOfScreen(DefaultScreenOfDisplay(dpy)) - ypos - ysize
278         - 2*border_width;
279     else if (yalign == 0)
280       ypos = (HeightOfScreen(DefaultScreenOfDisplay(dpy)) - ysize
281               - 2*border_width)>>1 + ypos;
282
283     /*
284      * Create the window:
285      */
286     attributes = xattributes;
287     attributes.background_pixel = gram->bgcolor;
288     
289     gram->w = w = XCreateWindow (dpy, DefaultRootWindow (dpy), xpos, ypos,
290                                  xsize, ysize, border_width, 0,
291                                  CopyFromParent, CopyFromParent,
292                                  xattributes_mask, &attributes);
293     
294     sizehints.x = xpos;
295     sizehints.y = ypos;
296     sizehints.width = xsize;
297     sizehints.height = ysize;
298     sizehints.flags = USPosition|USSize;
299
300     wmhints.input = True;
301     wmhints.initial_state = NormalState;
302     if (set_transient) {
303        wmhints.window_group = group_leader;
304        wmhints.flags = InputHint | StateHint | WindowGroupHint;
305
306        x_set_icccm_hints(dpy,w,title_name,icon_name,&sizehints,&wmhints,
307                          group_leader);
308     } else {
309        wmhints.flags = InputHint | StateHint;
310
311        x_set_icccm_hints(dpy,w,title_name,icon_name,&sizehints,&wmhints,0);
312     }
313        
314
315     XSaveContext(dpy, w, desc_context, (caddr_t)gram);
316
317     gram->can_die.tv_sec = 0;
318
319     XMapWindow(dpy, w);
320
321     if (beepcount)
322         XBell(dpy, 0);
323
324     xerror_happened = 0;
325     if (reverse_stack && bottom_gram) {
326        XWindowChanges winchanges;
327        
328        winchanges.sibling=bottom_gram->w;
329        winchanges.stack_mode=Below;
330        begin_xerror_trap (dpy);
331        XReconfigureWMWindow (dpy, w, DefaultScreen (dpy),
332                              CWSibling|CWStackMode, &winchanges);
333        end_xerror_trap (dpy);
334        if (xerror_happened) {
335            /* The event didn't go.  Print an error message, and continue.  */
336            ERROR ("Error configuring window to the bottom of the stack.\n");
337        }
338     }
339     /* we always need to keep a linked list of windows */
340     add_to_bottom(gram);
341     if (xerror_happened)
342        pull_to_top(gram);
343
344     if (reset_saver)
345         XResetScreenSaver(dpy);
346
347     XFlush(dpy);
348     /* Because the flushing/syncing/etc with the error trapping can cause
349        events to be read into the Xlib queue, we need to go through the queue
350        here before exiting so that any pending events get processed.
351        */
352     x_get_input(dpy);
353 }
354
355 void x_gram_draw(dpy, w, gram, region)
356      Display *dpy;
357      Window w;
358      x_gram *gram;
359      Region region;
360 {
361    int i;
362    GC gc;
363    XGCValues gcvals;
364    xblock *xb;
365    XTextItem text;
366    int startblock,endblock,startpixel,endpixel;
367    
368 #define SetFG(fg) \
369    gcvals.foreground=fg; \
370    XChangeGC(dpy,gc,GCForeground,&gcvals)
371
372    gc = XCreateGC(dpy, w, 0, &gcvals);
373    XSetRegion(dpy,gc,region);
374  
375    if ((markgram == gram) && (STARTBLOCK != -1) && (ENDBLOCK != -1)) {
376       if (xmarkSecond() == XMARK_END_BOUND) {
377          startblock=STARTBLOCK;
378          endblock=ENDBLOCK;
379          startpixel=STARTPIXEL;
380          endpixel=ENDPIXEL;
381       } else {
382          startblock=ENDBLOCK;
383          endblock=STARTBLOCK;
384          startpixel=ENDPIXEL;
385          endpixel=STARTPIXEL;
386       }
387    } else {
388       startblock = -1;
389       endblock = -1;
390    }
391
392    for (i=0,xb=gram->blocks ; i<gram->numblocks ; i++,xb++) {
393       if (XRectInRegion(region,xb->x1,xb->y1,xb->x2-xb->x1,
394                         xb->y2-xb->y1) != RectangleOut) {
395          if (i==startblock) {
396             if (i==endblock) {
397                SetFG(gram->bgcolor);
398                XFillRectangle(dpy,w,gc,xb->x1,xb->y1,startpixel,
399                               (xb->y2-xb->y1));
400                SetFG(xb->fgcolor);
401                XFillRectangle(dpy,w,gc,xb->x1+startpixel,xb->y1,
402                               (endpixel-startpixel),(xb->y2-xb->y1));
403                SetFG(gram->bgcolor);
404                XFillRectangle(dpy,w,gc,xb->x1+endpixel,xb->y1,
405                               (xb->x2-xb->x1-endpixel),(xb->y2-xb->y1));
406             } else {
407                SetFG(gram->bgcolor);
408                XFillRectangle(dpy,w,gc,xb->x1,xb->y1,startpixel,
409                               (xb->y2-xb->y1));
410                SetFG(xb->fgcolor);
411                XFillRectangle(dpy,w,gc,xb->x1+startpixel,xb->y1,
412                               (xb->x2-xb->x1-startpixel),(xb->y2-xb->y1));
413             }
414          } else if (i==endblock) {
415             SetFG(xb->fgcolor);
416             XFillRectangle(dpy,w,gc,xb->x1,xb->y1,endpixel,
417                            (xb->y2-xb->y1));
418             SetFG(gram->bgcolor);
419             XFillRectangle(dpy,w,gc,xb->x1+endpixel,xb->y1,
420                            (xb->x2-xb->x1-endpixel),(xb->y2-xb->y1));
421          } else {
422             if ((startblock < i) && (i < endblock)) {
423                SetFG(xb->fgcolor);
424             } else {
425                SetFG(gram->bgcolor);
426             }
427             XFillRectangle(dpy,w,gc,xb->x1,xb->y1,(xb->x2-xb->x1),
428                            (xb->y2-xb->y1));
429          }
430       }
431    }
432
433    gcvals.function=GXxor;
434    XChangeGC(dpy,gc,GCFunction,&gcvals);
435
436    for (i=0,xb=gram->blocks ; i<gram->numblocks ; i++,xb++) {
437       if (XRectInRegion(region,xb->x1,xb->y1,xb->x2-xb->x1,
438                         xb->y2-xb->y1) != RectangleOut) {
439          SetFG(gram->bgcolor^xb->fgcolor);
440          text.chars=gram->text+xb->strindex;
441          text.nchars=xb->strlen;
442          text.delta=0;
443          text.font=xb->fid;
444          XDrawText(dpy,w,gc,xb->x,xb->y,&text,1);
445      }
446    }
447
448    XFreeGC(dpy,gc);
449 }
450
451 void x_gram_expose(dpy,w,gram,event)
452      Display *dpy;
453      Window w;
454      x_gram *gram;
455      XExposeEvent *event;
456 {
457    static Region region;
458    static int partregion;
459    XRectangle rect;
460
461    rect.x = (short) event->x;
462    rect.y = (short) event->y;
463    rect.width = (unsigned short) event->width;
464    rect.height = (unsigned short) event->height;
465
466 #ifdef MARK_DEBUG
467    printf("----- xeventExpose:\nx=%d y=%d w=%d h=%d\n-----",
468           event->x,event->y,event->width,event->height);
469 #endif
470
471    if (! partregion) {
472       region=XCreateRegion();
473       partregion = 1;
474    }
475
476    if (rect.width && rect.height) XUnionRectWithRegion(&rect,region,region);
477
478    if (event->count == 0) {
479       x_gram_draw(dpy,w,gram,region);
480       partregion = 0;
481       XDestroyRegion(region);
482    }
483 }
484
485 #endif /* X_DISPLAY_MISSING */
486