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 temp = get_string_resource("foreground", "Foreground");
132 default_fgcolor = x_string_to_color(temp, default_fgcolor);
133 temp = get_string_resource("background", "Background");
135 default_bgcolor = x_string_to_color(temp, default_bgcolor);
136 default_bordercolor = default_fgcolor;
137 temp = get_string_resource("borderColor", "BorderColor");
139 default_bordercolor = x_string_to_color(temp, default_bordercolor);
141 temp = get_string_resource("minTimeToLive", "MinTimeToLive");
142 if (temp && atoi(temp)>=0)
145 reverse_stack = get_bool_resource("reverseStack", "ReverseStack", 0);
146 reset_saver = get_bool_resource("resetSaver", "ResetSaver", 1);
147 /* The default here should be 1, but mwm sucks */
148 set_transient = get_bool_resource("transient", "Transient", 0);
149 enable_delete = get_bool_resource("enableDelete", "EnableDelete", 1);
151 temp = get_string_resource("borderWidth", "BorderWidth");
153 if (temp && atoi(temp)>=0)
154 border_width = atoi(temp);
156 temp = get_string_resource("internalBorder", "InternalBorder");
158 if (temp && atoi(temp)>=0)
159 internal_border_width = atoi(temp);
161 temp = get_string_resource("cursorCode", "CursorCode");
163 if (temp && atoi(temp))
164 cursor_code = atoi(temp);
166 cursor = XCreateFontCursor(dpy, cursor_code);
168 cursor = XCreateFontCursor(dpy, XC_sailboat);
170 temp = get_string_resource("pointerColor", "Foreground");
173 XColor cursor_fore, cursor_back;
174 /* XXX need to do our own parsing here, since the RecolorCursor
175 routine requires an XColor, not an unsigned long (pixel) */
176 if (!(temp2 = get_string_resource("background","Background"))) {
177 if (default_bgcolor == WhitePixelOfScreen(DefaultScreenOfDisplay(dpy)))
183 DefaultColormapOfScreen(DefaultScreenOfDisplay(dpy)),
184 temp, &cursor_fore) &&
186 DefaultColormapOfScreen(DefaultScreenOfDisplay(dpy)),
187 temp2, &cursor_back)) {
188 XRecolorCursor(dpy, cursor, &cursor_fore, &cursor_back);
191 if (!(title_name=get_string_resource("title","Title")))
192 if (!(title_name=get_string_resource("name","Name")))
193 title_name=app_instance;
195 if (!(icon_name=get_string_resource("iconName","IconName")))
196 if (!(icon_name=get_string_resource("name","Name")))
197 icon_name=app_instance;
199 if (!(temp=get_string_resource("name","Name")))
200 if (!(temp=(char *) getenv("RESOURCE_NAME")))
202 classhint.res_name=string_Copy(temp);
203 classhint.res_class="Zwgc";
206 group_leader=XCreateSimpleWindow(dpy,DefaultRootWindow(dpy),0,0,100,100,
207 0,default_bordercolor,default_bgcolor);
210 sizehints.width = 100;
211 sizehints.height = 100;
212 sizehints.flags = PPosition | PSize;
214 wmhints.input = False;
215 wmhints.initial_state = DontCareState;
216 wmhints.flags = InputHint | StateHint;
218 x_set_icccm_hints(dpy,group_leader,"ZwgcGroup","ZwgcGroup",&sizehints,
221 xattributes.border_pixel = default_bordercolor;
222 xattributes.cursor = cursor;
223 xattributes.event_mask = (ExposureMask|ButtonReleaseMask|ButtonPressMask
224 |LeaveWindowMask|Button1MotionMask
225 |Button3MotionMask|StructureNotifyMask);
226 xattributes_mask = (CWBackPixel|CWBorderPixel|CWEventMask|CWCursor);
228 set_all_desktops = get_bool_resource("allDesktops", "AllDesktops", True);
229 net_wm_desktop = XInternAtom(dpy, "_NET_WM_DESKTOP", False);
230 net_wm_window_type = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
231 net_wm_window_type_utility = XInternAtom(dpy,
232 "_NET_WM_WINDOW_TYPE_UTILITY",
235 temp = get_string_resource ("backingStore", "BackingStore");
238 xattributes_mask |= CWBackingStore;
239 if (!strcasecmp (temp, "notuseful"))
240 xattributes.backing_store = NotUseful;
241 else if (!strcasecmp (temp, "whenmapped"))
242 xattributes.backing_store = WhenMapped;
243 else if (!strcasecmp (temp, "always"))
244 xattributes.backing_store = Always;
245 else if (!strcasecmp (temp, "default"))
246 xattributes_mask &= ~CWBackingStore;
248 switch (get_bool_resource ("backingStore", "BackingStore", -1)) {
250 xattributes.backing_store = NotUseful;
253 xattributes.backing_store = WhenMapped;
257 "zwgc: Cannot interpret backing-store resource value `%s'.\n",
259 xattributes_mask &= ~CWBackingStore;
266 x_calc_gravity(int xalign,
269 if (yalign > 0) { /* North */
270 return (xalign > 0) ? NorthWestGravity
271 : (xalign == 0) ? NorthGravity
273 } else if (yalign == 0) { /* Center */
274 return (xalign > 0) ? WestGravity
275 : (xalign == 0) ? CenterGravity
278 return (xalign > 0) ? SouthWestGravity
279 : (xalign == 0) ? SouthGravity
285 x_gram_create(Display *dpy,
296 XSizeHints sizehints;
298 XSetWindowAttributes attributes;
299 unsigned long all_desktops = 0xFFFFFFFF;
302 * Adjust xpos, ypos based on the alignments xalign, yalign and the sizes:
305 xpos = WidthOfScreen(DefaultScreenOfDisplay(dpy)) - xpos - xsize
307 else if (xalign == 0)
308 xpos = ((WidthOfScreen(DefaultScreenOfDisplay(dpy)) - xsize
309 - 2*border_width)>>1) + xpos;
312 ypos = HeightOfScreen(DefaultScreenOfDisplay(dpy)) - ypos - ysize
314 else if (yalign == 0)
315 ypos = ((HeightOfScreen(DefaultScreenOfDisplay(dpy)) - ysize
316 - 2*border_width)>>1) + ypos;
321 attributes = xattributes;
322 attributes.background_pixel = gram->bgcolor;
324 gram->w = w = XCreateWindow (dpy, DefaultRootWindow (dpy), xpos, ypos,
325 xsize, ysize, border_width, 0,
326 CopyFromParent, CopyFromParent,
327 xattributes_mask, &attributes);
331 sizehints.width = xsize;
332 sizehints.height = ysize;
333 sizehints.win_gravity = x_calc_gravity(xalign, yalign);
334 sizehints.flags = USPosition|USSize|PWinGravity;
336 wmhints.input = False;
337 wmhints.initial_state = NormalState;
339 wmhints.window_group = group_leader;
340 wmhints.flags = InputHint | StateHint | WindowGroupHint;
342 x_set_icccm_hints(dpy,w,title_name,icon_name,&sizehints,&wmhints,
345 wmhints.flags = InputHint | StateHint;
347 x_set_icccm_hints(dpy,w,title_name,icon_name,&sizehints,&wmhints,0);
350 if (net_wm_window_type != None && net_wm_window_type_utility != None)
351 XChangeProperty(dpy, w, net_wm_window_type, XA_ATOM, 32,
353 (unsigned char *) &net_wm_window_type_utility, 1);
354 if (set_all_desktops && net_wm_desktop != None)
355 XChangeProperty(dpy, w, net_wm_desktop, XA_CARDINAL, 32,
356 PropModeReplace, (unsigned char *) &all_desktops, 1);
358 XSaveContext(dpy, w, desc_context, (caddr_t)gram);
360 gram->can_die.tv_sec = 0;
368 if (reverse_stack && bottom_gram) {
369 XWindowChanges winchanges;
371 winchanges.sibling=bottom_gram->w;
372 winchanges.stack_mode=Below;
373 /* Metacity may use border_width even if it's not specified in
374 * the value mask, so we must initialize it. See:
375 * http://bugzilla.gnome.org/show_bug.cgi?id=305257 */
376 winchanges.border_width=border_width;
378 begin_xerror_trap (dpy);
379 XReconfigureWMWindow (dpy, w, DefaultScreen (dpy),
380 CWSibling|CWStackMode, &winchanges);
381 end_xerror_trap (dpy);
382 if (xerror_happened) {
383 /* The event didn't go. Print an error message, and continue. */
384 ERROR ("Error configuring window to the bottom of the stack.\n");
387 /* we always need to keep a linked list of windows */
393 XResetScreenSaver(dpy);
396 /* Because the flushing/syncing/etc with the error trapping can cause
397 events to be read into the Xlib queue, we need to go through the queue
398 here before exiting so that any pending events get processed.
404 x_gram_draw(Display *dpy,
414 int startblock,endblock,startpixel,endpixel;
417 gcvals.foreground=fg; \
418 XChangeGC(dpy,gc,GCForeground,&gcvals)
420 gc = XCreateGC(dpy, w, 0, &gcvals);
421 XSetRegion(dpy,gc,region);
423 if ((markgram == gram) && (STARTBLOCK != -1) && (ENDBLOCK != -1)) {
424 if (xmarkSecond() == XMARK_END_BOUND) {
425 startblock=STARTBLOCK;
427 startpixel=STARTPIXEL;
440 for (i=0,xb=gram->blocks ; i<gram->numblocks ; i++,xb++) {
441 if (XRectInRegion(region,xb->x1,xb->y1,xb->x2-xb->x1,
442 xb->y2-xb->y1) != RectangleOut) {
445 SetFG(gram->bgcolor);
446 XFillRectangle(dpy,w,gc,xb->x1,xb->y1,startpixel,
449 XFillRectangle(dpy,w,gc,xb->x1+startpixel,xb->y1,
450 (endpixel-startpixel),(xb->y2-xb->y1));
451 SetFG(gram->bgcolor);
452 XFillRectangle(dpy,w,gc,xb->x1+endpixel,xb->y1,
453 (xb->x2-xb->x1-endpixel),(xb->y2-xb->y1));
455 SetFG(gram->bgcolor);
456 XFillRectangle(dpy,w,gc,xb->x1,xb->y1,startpixel,
459 XFillRectangle(dpy,w,gc,xb->x1+startpixel,xb->y1,
460 (xb->x2-xb->x1-startpixel),(xb->y2-xb->y1));
462 } else if (i==endblock) {
464 XFillRectangle(dpy,w,gc,xb->x1,xb->y1,endpixel,
466 SetFG(gram->bgcolor);
467 XFillRectangle(dpy,w,gc,xb->x1+endpixel,xb->y1,
468 (xb->x2-xb->x1-endpixel),(xb->y2-xb->y1));
470 if ((startblock < i) && (i < endblock)) {
473 SetFG(gram->bgcolor);
475 XFillRectangle(dpy,w,gc,xb->x1,xb->y1,(xb->x2-xb->x1),
481 gcvals.function=GXxor;
482 XChangeGC(dpy,gc,GCFunction,&gcvals);
484 for (i=0,xb=gram->blocks ; i<gram->numblocks ; i++,xb++) {
485 if (XRectInRegion(region,xb->x1,xb->y1,xb->x2-xb->x1,
486 xb->y2-xb->y1) != RectangleOut) {
487 SetFG(gram->bgcolor^xb->fgcolor);
488 text.chars=gram->text+xb->strindex;
489 text.nchars=xb->strlen;
492 XDrawText(dpy,w,gc,xb->x,xb->y,&text,1);
500 x_gram_expose(Display *dpy,
505 static Region region;
506 static int partregion;
509 rect.x = (short) event->x;
510 rect.y = (short) event->y;
511 rect.width = (unsigned short) event->width;
512 rect.height = (unsigned short) event->height;
515 printf("----- xeventExpose:\nx=%d y=%d w=%d h=%d\n-----",
516 event->x,event->y,event->width,event->height);
520 region=XCreateRegion();
524 if (rect.width && rect.height) XUnionRectWithRegion(&rect,region,region);
526 if (event->count == 0) {
527 x_gram_draw(dpy,w,gram,region);
529 XDestroyRegion(region);
533 #endif /* X_DISPLAY_MISSING */