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_X_gram_c[] = "$Id$";
20 #include <zephyr/mit-copyright.h>
22 #ifndef X_DISPLAY_MISSING
26 #include <X11/Xutil.h>
27 #include <X11/cursorfont.h>
28 #include <X11/Xatom.h>
33 #include "new_string.h"
34 #include "xrevstack.h"
38 extern XContext desc_context;
39 extern char *app_instance;
40 extern unsigned long x_string_to_color();
41 extern char *getenv();
47 int internal_border_width = 2;
49 unsigned long default_fgcolor;
50 unsigned long default_bgcolor;
51 unsigned long default_bordercolor;
53 static int reset_saver;
54 static int border_width = 1;
55 static int cursor_code = XC_sailboat;
56 static int set_transient;
57 static int enable_delete;
58 static char *title_name,*icon_name;
60 static Window group_leader; /* In order to have transient windows,
61 * I need a top-level window to always exist
63 static XClassHint classhint;
64 static XSetWindowAttributes xattributes;
65 static unsigned long xattributes_mask;
66 static int set_all_desktops = True;
67 static Atom net_wm_desktop = None;
68 static Atom net_wm_window_type = None;
69 static Atom net_wm_window_type_utility = None;
73 * the following properties must be set on all top-level windows:
75 * WM_NAME XStoreName(dpy,w,name);
76 * WM_ICON_NAME XSetIconName(dpy,w,name);
77 * WM_NORMAL_HINTS XSetNormalHints(dpy,w,sizehints);
78 * WM_HINTS XSetWMHints(dpy,w,wmhints);
79 * WM_CLASS XSetClassHint(dpy,w,classhint);
81 * and for individual zgrams:
83 * WM_TRANSIENT_FOR XSetTransientForHint(dpy,w,main_window);
84 * WM_PROTOCOLS XSetWMProtocols(dpy,w,protocols,cnt);
87 /* set all properties defined in ICCCM. If main_window == 0,
88 * per-zgram initialization is not done.
92 void x_set_icccm_hints(dpy,w,name,icon_name,psizehints,pwmhints,main_window)
97 XSizeHints *psizehints;
101 XStoreName(dpy,w,name);
102 XSetIconName(dpy,w,icon_name);
103 XSetWMNormalHints(dpy,w,psizehints);
104 XSetWMHints(dpy,w,pwmhints);
105 XSetClassHint(dpy,w,&classhint);
106 /* in order for some wm's to iconify, the window shouldn't be transient.
108 if (main_window != None) {
110 XSetTransientForHint(dpy,w,main_window);
113 XSetWMProtocols(dpy,w,&XA_WM_DELETE_WINDOW,1);
116 void x_gram_init(dpy)
120 XSizeHints sizehints;
124 default_fgcolor = BlackPixelOfScreen(DefaultScreenOfDisplay(dpy));
125 default_bgcolor = WhitePixelOfScreen(DefaultScreenOfDisplay(dpy));
126 rv = get_bool_resource("reverseVideo", "ReverseVideo", 0);
128 tc = default_fgcolor;
129 default_fgcolor = default_bgcolor;
130 default_bgcolor = tc;
132 if (temp = get_string_resource("foreground","Foreground"))
133 default_fgcolor = x_string_to_color(temp,default_fgcolor);
134 if (temp = get_string_resource("background","Background"))
135 default_bgcolor = x_string_to_color(temp,default_bgcolor);
136 default_bordercolor = default_fgcolor;
137 if (temp = get_string_resource("borderColor","BorderColor"))
138 default_bordercolor = x_string_to_color(temp,default_bordercolor);
140 temp = get_string_resource("minTimeToLive","MinTimeToLive");
141 if (temp && atoi(temp)>=0)
144 reverse_stack = get_bool_resource("reverseStack", "ReverseStack", 0);
145 reset_saver = get_bool_resource("resetSaver", "ResetSaver", 1);
146 /* The default here should be 1, but mwm sucks */
147 set_transient = get_bool_resource("transient", "Transient", 0);
148 enable_delete = get_bool_resource("enableDelete", "EnableDelete", 1);
150 temp = get_string_resource("borderWidth", "BorderWidth");
152 if (temp && atoi(temp)>=0)
153 border_width = atoi(temp);
155 temp = get_string_resource("internalBorder", "InternalBorder");
157 if (temp && atoi(temp)>=0)
158 internal_border_width = atoi(temp);
160 temp = get_string_resource("cursorCode", "CursorCode");
162 if (temp && atoi(temp))
163 cursor_code = atoi(temp);
165 cursor = XCreateFontCursor(dpy, cursor_code);
167 cursor = XCreateFontCursor(dpy, XC_sailboat);
169 temp = get_string_resource("pointerColor", "Foreground");
172 XColor cursor_fore, cursor_back;
173 /* XXX need to do our own parsing here, since the RecolorCursor
174 routine requires an XColor, not an unsigned long (pixel) */
175 if (!(temp2 = get_string_resource("background","Background"))) {
176 if (default_bgcolor == WhitePixelOfScreen(DefaultScreenOfDisplay(dpy)))
182 DefaultColormapOfScreen(DefaultScreenOfDisplay(dpy)),
183 temp, &cursor_fore) &&
185 DefaultColormapOfScreen(DefaultScreenOfDisplay(dpy)),
186 temp2, &cursor_back)) {
187 XRecolorCursor(dpy, cursor, &cursor_fore, &cursor_back);
190 if (!(title_name=get_string_resource("title","Title")))
191 if (!(title_name=get_string_resource("name","Name")))
192 title_name=app_instance;
194 if (!(icon_name=get_string_resource("iconName","IconName")))
195 if (!(icon_name=get_string_resource("name","Name")))
196 icon_name=app_instance;
198 if (!(temp=get_string_resource("name","Name")))
199 if (!(temp=(char *) getenv("RESOURCE_NAME")))
201 classhint.res_name=string_Copy(temp);
202 classhint.res_class="Zwgc";
205 group_leader=XCreateSimpleWindow(dpy,DefaultRootWindow(dpy),0,0,100,100,
206 0,default_bordercolor,default_bgcolor);
209 sizehints.width = 100;
210 sizehints.height = 100;
211 sizehints.flags = PPosition | PSize;
213 wmhints.input = False;
214 wmhints.initial_state = DontCareState;
215 wmhints.flags = InputHint | StateHint;
217 x_set_icccm_hints(dpy,group_leader,"ZwgcGroup","ZwgcGroup",&sizehints,
220 xattributes.border_pixel = default_bordercolor;
221 xattributes.cursor = cursor;
222 xattributes.event_mask = (ExposureMask|ButtonReleaseMask|ButtonPressMask
223 |LeaveWindowMask|Button1MotionMask
224 |Button3MotionMask|StructureNotifyMask);
225 xattributes_mask = (CWBackPixel|CWBorderPixel|CWEventMask|CWCursor);
227 set_all_desktops = get_bool_resource("allDesktops", "AllDesktops", True);
228 net_wm_desktop = XInternAtom(dpy, "_NET_WM_DESKTOP", False);
229 net_wm_window_type = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
230 net_wm_window_type_utility = XInternAtom(dpy,
231 "_NET_WM_WINDOW_TYPE_UTILITY",
234 temp = get_string_resource ("backingStore", "BackingStore");
237 xattributes_mask |= CWBackingStore;
238 if (!strcasecmp (temp, "notuseful"))
239 xattributes.backing_store = NotUseful;
240 else if (!strcasecmp (temp, "whenmapped"))
241 xattributes.backing_store = WhenMapped;
242 else if (!strcasecmp (temp, "always"))
243 xattributes.backing_store = Always;
244 else if (!strcasecmp (temp, "default"))
245 xattributes_mask &= ~CWBackingStore;
247 switch (get_bool_resource ("backingStore", "BackingStore", -1)) {
249 xattributes.backing_store = NotUseful;
252 xattributes.backing_store = WhenMapped;
256 "zwgc: Cannot interpret backing-store resource value `%s'.\n",
258 xattributes_mask &= ~CWBackingStore;
264 int x_calc_gravity(xalign, yalign)
267 if (yalign > 0) { /* North */
268 return (xalign > 0) ? NorthWestGravity
269 : (xalign == 0) ? NorthGravity
271 } else if (yalign == 0) { /* Center */
272 return (xalign > 0) ? WestGravity
273 : (xalign == 0) ? CenterGravity
276 return (xalign > 0) ? SouthWestGravity
277 : (xalign == 0) ? SouthGravity
282 void x_gram_create(dpy, gram, xalign, yalign, xpos, ypos, xsize, ysize,
292 XSizeHints sizehints;
294 XSetWindowAttributes attributes;
295 unsigned long all_desktops = 0xFFFFFFFF;
296 extern void x_get_input();
299 * Adjust xpos, ypos based on the alignments xalign, yalign and the sizes:
302 xpos = WidthOfScreen(DefaultScreenOfDisplay(dpy)) - xpos - xsize
304 else if (xalign == 0)
305 xpos = (WidthOfScreen(DefaultScreenOfDisplay(dpy)) - xsize
306 - 2*border_width)>>1 + xpos;
309 ypos = HeightOfScreen(DefaultScreenOfDisplay(dpy)) - ypos - ysize
311 else if (yalign == 0)
312 ypos = (HeightOfScreen(DefaultScreenOfDisplay(dpy)) - ysize
313 - 2*border_width)>>1 + ypos;
318 attributes = xattributes;
319 attributes.background_pixel = gram->bgcolor;
321 gram->w = w = XCreateWindow (dpy, DefaultRootWindow (dpy), xpos, ypos,
322 xsize, ysize, border_width, 0,
323 CopyFromParent, CopyFromParent,
324 xattributes_mask, &attributes);
328 sizehints.width = xsize;
329 sizehints.height = ysize;
330 sizehints.win_gravity = x_calc_gravity(xalign, yalign);
331 sizehints.flags = USPosition|USSize|PWinGravity;
333 wmhints.input = False;
334 wmhints.initial_state = NormalState;
336 wmhints.window_group = group_leader;
337 wmhints.flags = InputHint | StateHint | WindowGroupHint;
339 x_set_icccm_hints(dpy,w,title_name,icon_name,&sizehints,&wmhints,
342 wmhints.flags = InputHint | StateHint;
344 x_set_icccm_hints(dpy,w,title_name,icon_name,&sizehints,&wmhints,0);
347 if (net_wm_window_type != None && net_wm_window_type_utility != None)
348 XChangeProperty(dpy, w, net_wm_window_type, XA_ATOM, 32,
350 (unsigned char *) &net_wm_window_type_utility, 1);
351 if (set_all_desktops && net_wm_desktop != None)
352 XChangeProperty(dpy, w, net_wm_desktop, XA_CARDINAL, 32,
353 PropModeReplace, (unsigned char *) &all_desktops, 1);
355 XSaveContext(dpy, w, desc_context, (caddr_t)gram);
357 gram->can_die.tv_sec = 0;
365 if (reverse_stack && bottom_gram) {
366 XWindowChanges winchanges;
368 winchanges.sibling=bottom_gram->w;
369 winchanges.stack_mode=Below;
370 /* Metacity may use border_width even if it's not specified in
371 * the value mask, so we must initialize it. See:
372 * http://bugzilla.gnome.org/show_bug.cgi?id=305257 */
373 winchanges.border_width=border_width;
375 begin_xerror_trap (dpy);
376 XReconfigureWMWindow (dpy, w, DefaultScreen (dpy),
377 CWSibling|CWStackMode, &winchanges);
378 end_xerror_trap (dpy);
379 if (xerror_happened) {
380 /* The event didn't go. Print an error message, and continue. */
381 ERROR ("Error configuring window to the bottom of the stack.\n");
384 /* we always need to keep a linked list of windows */
390 XResetScreenSaver(dpy);
393 /* Because the flushing/syncing/etc with the error trapping can cause
394 events to be read into the Xlib queue, we need to go through the queue
395 here before exiting so that any pending events get processed.
400 void x_gram_draw(dpy, w, gram, region)
411 int startblock,endblock,startpixel,endpixel;
414 gcvals.foreground=fg; \
415 XChangeGC(dpy,gc,GCForeground,&gcvals)
417 gc = XCreateGC(dpy, w, 0, &gcvals);
418 XSetRegion(dpy,gc,region);
420 if ((markgram == gram) && (STARTBLOCK != -1) && (ENDBLOCK != -1)) {
421 if (xmarkSecond() == XMARK_END_BOUND) {
422 startblock=STARTBLOCK;
424 startpixel=STARTPIXEL;
437 for (i=0,xb=gram->blocks ; i<gram->numblocks ; i++,xb++) {
438 if (XRectInRegion(region,xb->x1,xb->y1,xb->x2-xb->x1,
439 xb->y2-xb->y1) != RectangleOut) {
442 SetFG(gram->bgcolor);
443 XFillRectangle(dpy,w,gc,xb->x1,xb->y1,startpixel,
446 XFillRectangle(dpy,w,gc,xb->x1+startpixel,xb->y1,
447 (endpixel-startpixel),(xb->y2-xb->y1));
448 SetFG(gram->bgcolor);
449 XFillRectangle(dpy,w,gc,xb->x1+endpixel,xb->y1,
450 (xb->x2-xb->x1-endpixel),(xb->y2-xb->y1));
452 SetFG(gram->bgcolor);
453 XFillRectangle(dpy,w,gc,xb->x1,xb->y1,startpixel,
456 XFillRectangle(dpy,w,gc,xb->x1+startpixel,xb->y1,
457 (xb->x2-xb->x1-startpixel),(xb->y2-xb->y1));
459 } else if (i==endblock) {
461 XFillRectangle(dpy,w,gc,xb->x1,xb->y1,endpixel,
463 SetFG(gram->bgcolor);
464 XFillRectangle(dpy,w,gc,xb->x1+endpixel,xb->y1,
465 (xb->x2-xb->x1-endpixel),(xb->y2-xb->y1));
467 if ((startblock < i) && (i < endblock)) {
470 SetFG(gram->bgcolor);
472 XFillRectangle(dpy,w,gc,xb->x1,xb->y1,(xb->x2-xb->x1),
478 gcvals.function=GXxor;
479 XChangeGC(dpy,gc,GCFunction,&gcvals);
481 for (i=0,xb=gram->blocks ; i<gram->numblocks ; i++,xb++) {
482 if (XRectInRegion(region,xb->x1,xb->y1,xb->x2-xb->x1,
483 xb->y2-xb->y1) != RectangleOut) {
484 SetFG(gram->bgcolor^xb->fgcolor);
485 text.chars=gram->text+xb->strindex;
486 text.nchars=xb->strlen;
489 XDrawText(dpy,w,gc,xb->x,xb->y,&text,1);
496 void x_gram_expose(dpy,w,gram,event)
502 static Region region;
503 static int partregion;
506 rect.x = (short) event->x;
507 rect.y = (short) event->y;
508 rect.width = (unsigned short) event->width;
509 rect.height = (unsigned short) event->height;
512 printf("----- xeventExpose:\nx=%d y=%d w=%d h=%d\n-----",
513 event->x,event->y,event->width,event->height);
517 region=XCreateRegion();
521 if (rect.width && rect.height) XUnionRectWithRegion(&rect,region,region);
523 if (event->count == 0) {
524 x_gram_draw(dpy,w,gram,region);
526 XDestroyRegion(region);
530 #endif /* X_DISPLAY_MISSING */