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;
45 int internal_border_width = 2;
47 unsigned long default_fgcolor;
48 unsigned long default_bgcolor;
49 unsigned long default_bordercolor;
51 static int reset_saver;
52 static int border_width = 1;
53 static int cursor_code = XC_sailboat;
54 static int set_transient;
55 static int enable_delete;
56 static char *title_name,*icon_name;
58 static Window group_leader; /* In order to have transient windows,
59 * I need a top-level window to always exist
61 static XClassHint classhint;
62 static XSetWindowAttributes xattributes;
63 static unsigned long xattributes_mask;
64 static int set_all_desktops = True;
65 static Atom net_wm_desktop = None;
66 static Atom net_wm_window_type = None;
67 static Atom net_wm_window_type_utility = None;
71 * the following properties must be set on all top-level windows:
73 * WM_NAME XStoreName(dpy,w,name);
74 * WM_ICON_NAME XSetIconName(dpy,w,name);
75 * WM_NORMAL_HINTS XSetNormalHints(dpy,w,sizehints);
76 * WM_HINTS XSetWMHints(dpy,w,wmhints);
77 * WM_CLASS XSetClassHint(dpy,w,classhint);
79 * and for individual zgrams:
81 * WM_TRANSIENT_FOR XSetTransientForHint(dpy,w,main_window);
82 * WM_PROTOCOLS XSetWMProtocols(dpy,w,protocols,cnt);
85 /* set all properties defined in ICCCM. If main_window == 0,
86 * per-zgram initialization is not done.
91 x_set_icccm_hints(Display *dpy,
95 XSizeHints *psizehints,
99 XStoreName(dpy,w,name);
100 XSetIconName(dpy,w,icon_name);
101 XSetWMNormalHints(dpy,w,psizehints);
102 XSetWMHints(dpy,w,pwmhints);
103 XSetClassHint(dpy,w,&classhint);
104 /* in order for some wm's to iconify, the window shouldn't be transient.
106 if (main_window != None) {
108 XSetTransientForHint(dpy,w,main_window);
111 XSetWMProtocols(dpy,w,&XA_WM_DELETE_WINDOW,1);
115 x_gram_init(Display *dpy)
118 XSizeHints sizehints;
122 default_fgcolor = BlackPixelOfScreen(DefaultScreenOfDisplay(dpy));
123 default_bgcolor = WhitePixelOfScreen(DefaultScreenOfDisplay(dpy));
124 rv = get_bool_resource("reverseVideo", "ReverseVideo", 0);
126 tc = default_fgcolor;
127 default_fgcolor = default_bgcolor;
128 default_bgcolor = tc;
130 if (temp = get_string_resource("foreground","Foreground"))
131 default_fgcolor = x_string_to_color(temp,default_fgcolor);
132 if (temp = get_string_resource("background","Background"))
133 default_bgcolor = x_string_to_color(temp,default_bgcolor);
134 default_bordercolor = default_fgcolor;
135 if (temp = get_string_resource("borderColor","BorderColor"))
136 default_bordercolor = x_string_to_color(temp,default_bordercolor);
138 temp = get_string_resource("minTimeToLive","MinTimeToLive");
139 if (temp && atoi(temp)>=0)
142 reverse_stack = get_bool_resource("reverseStack", "ReverseStack", 0);
143 reset_saver = get_bool_resource("resetSaver", "ResetSaver", 1);
144 /* The default here should be 1, but mwm sucks */
145 set_transient = get_bool_resource("transient", "Transient", 0);
146 enable_delete = get_bool_resource("enableDelete", "EnableDelete", 1);
148 temp = get_string_resource("borderWidth", "BorderWidth");
150 if (temp && atoi(temp)>=0)
151 border_width = atoi(temp);
153 temp = get_string_resource("internalBorder", "InternalBorder");
155 if (temp && atoi(temp)>=0)
156 internal_border_width = atoi(temp);
158 temp = get_string_resource("cursorCode", "CursorCode");
160 if (temp && atoi(temp))
161 cursor_code = atoi(temp);
163 cursor = XCreateFontCursor(dpy, cursor_code);
165 cursor = XCreateFontCursor(dpy, XC_sailboat);
167 temp = get_string_resource("pointerColor", "Foreground");
170 XColor cursor_fore, cursor_back;
171 /* XXX need to do our own parsing here, since the RecolorCursor
172 routine requires an XColor, not an unsigned long (pixel) */
173 if (!(temp2 = get_string_resource("background","Background"))) {
174 if (default_bgcolor == WhitePixelOfScreen(DefaultScreenOfDisplay(dpy)))
180 DefaultColormapOfScreen(DefaultScreenOfDisplay(dpy)),
181 temp, &cursor_fore) &&
183 DefaultColormapOfScreen(DefaultScreenOfDisplay(dpy)),
184 temp2, &cursor_back)) {
185 XRecolorCursor(dpy, cursor, &cursor_fore, &cursor_back);
188 if (!(title_name=get_string_resource("title","Title")))
189 if (!(title_name=get_string_resource("name","Name")))
190 title_name=app_instance;
192 if (!(icon_name=get_string_resource("iconName","IconName")))
193 if (!(icon_name=get_string_resource("name","Name")))
194 icon_name=app_instance;
196 if (!(temp=get_string_resource("name","Name")))
197 if (!(temp=(char *) getenv("RESOURCE_NAME")))
199 classhint.res_name=string_Copy(temp);
200 classhint.res_class="Zwgc";
203 group_leader=XCreateSimpleWindow(dpy,DefaultRootWindow(dpy),0,0,100,100,
204 0,default_bordercolor,default_bgcolor);
207 sizehints.width = 100;
208 sizehints.height = 100;
209 sizehints.flags = PPosition | PSize;
211 wmhints.input = False;
212 wmhints.initial_state = DontCareState;
213 wmhints.flags = InputHint | StateHint;
215 x_set_icccm_hints(dpy,group_leader,"ZwgcGroup","ZwgcGroup",&sizehints,
218 xattributes.border_pixel = default_bordercolor;
219 xattributes.cursor = cursor;
220 xattributes.event_mask = (ExposureMask|ButtonReleaseMask|ButtonPressMask
221 |LeaveWindowMask|Button1MotionMask
222 |Button3MotionMask|StructureNotifyMask);
223 xattributes_mask = (CWBackPixel|CWBorderPixel|CWEventMask|CWCursor);
225 set_all_desktops = get_bool_resource("allDesktops", "AllDesktops", True);
226 net_wm_desktop = XInternAtom(dpy, "_NET_WM_DESKTOP", False);
227 net_wm_window_type = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
228 net_wm_window_type_utility = XInternAtom(dpy,
229 "_NET_WM_WINDOW_TYPE_UTILITY",
232 temp = get_string_resource ("backingStore", "BackingStore");
235 xattributes_mask |= CWBackingStore;
236 if (!strcasecmp (temp, "notuseful"))
237 xattributes.backing_store = NotUseful;
238 else if (!strcasecmp (temp, "whenmapped"))
239 xattributes.backing_store = WhenMapped;
240 else if (!strcasecmp (temp, "always"))
241 xattributes.backing_store = Always;
242 else if (!strcasecmp (temp, "default"))
243 xattributes_mask &= ~CWBackingStore;
245 switch (get_bool_resource ("backingStore", "BackingStore", -1)) {
247 xattributes.backing_store = NotUseful;
250 xattributes.backing_store = WhenMapped;
254 "zwgc: Cannot interpret backing-store resource value `%s'.\n",
256 xattributes_mask &= ~CWBackingStore;
263 x_calc_gravity(int xalign,
266 if (yalign > 0) { /* North */
267 return (xalign > 0) ? NorthWestGravity
268 : (xalign == 0) ? NorthGravity
270 } else if (yalign == 0) { /* Center */
271 return (xalign > 0) ? WestGravity
272 : (xalign == 0) ? CenterGravity
275 return (xalign > 0) ? SouthWestGravity
276 : (xalign == 0) ? SouthGravity
282 x_gram_create(Display *dpy,
293 XSizeHints sizehints;
295 XSetWindowAttributes attributes;
296 unsigned long all_desktops = 0xFFFFFFFF;
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.
401 x_gram_draw(Display *dpy,
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);
497 x_gram_expose(Display *dpy,
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 */