Blob


1 /* Copyright (c) 1994-1996 David Hogan, see README for licence details */
2 #include <stdio.h>
3 #include <signal.h>
4 #include <errno.h>
5 #include <stdlib.h>
6 #include <unistd.h>
7 #include <X11/X.h>
8 #include <X11/Xos.h>
9 #include <X11/Xlib.h>
10 #include <X11/Xutil.h>
11 #include <X11/Xatom.h>
12 #ifdef SHAPE
13 #include <X11/extensions/shape.h>
14 #endif
15 #include "dat.h"
16 #include "fns.h"
17 #include "patchlevel.h"
19 char *version[] =
20 {
21 "rio version 1.0, Copyright (c) 1994-1996 David Hogan, (c) 2004 Russ Cox", 0,
22 };
24 Display *dpy;
25 ScreenInfo *screens;
26 int initting;
27 XFontStruct *font;
28 int nostalgia;
29 char **myargv;
30 char *termprog;
31 char *shell;
32 Bool shape;
33 int _border = 4;
34 int _corner = 25;
35 int _inset = 1;
36 int curtime;
37 int debug;
38 int signalled;
39 int num_screens;
40 int solidsweep = 0;
42 Atom exit_9wm;
43 Atom restart_9wm;
44 Atom wm_state;
45 Atom wm_change_state;
46 Atom wm_protocols;
47 Atom wm_delete;
48 Atom wm_take_focus;
49 Atom wm_lose_focus;
50 Atom wm_colormaps;
51 Atom _9wm_running;
52 Atom _9wm_hold_mode;
54 char *fontlist[] = {
55 "lucm.latin1.9",
56 "blit",
57 "*-lucidatypewriter-bold-*-14-*-75-*",
58 "*-lucidatypewriter-medium-*-12-*-75-*",
59 "9x15bold",
60 "fixed",
61 "*",
62 0,
63 };
65 void
66 usage(void)
67 {
68 fprintf(stderr, "usage: rio [-grey] [-version] [-font fname] [-term prog] [exit|restart]\n");
69 exit(1);
70 }
72 int
73 main(int argc, char *argv[])
74 {
75 int i, background, do_exit, do_restart;
76 char *fname;
77 int shape_event;
78 #ifdef SHAPE
79 int dummy;
80 #endif
82 shape_event = 0;
83 myargv = argv; /* for restart */
85 do_exit = do_restart = 0;
86 background = 0;
87 font = 0;
88 fname = 0;
89 for (i = 1; i < argc; i++)
90 if (strcmp(argv[i], "-nostalgia") == 0)
91 nostalgia++;
92 else if (strcmp(argv[i], "-grey") == 0)
93 background = 1;
94 else if (strcmp(argv[i], "-debug") == 0)
95 debug++;
96 else if (strcmp(argv[i], "-font") == 0 && i+1<argc) {
97 i++;
98 fname = argv[i];
99 }
100 else if (strcmp(argv[i], "-term") == 0 && i+1<argc)
101 termprog = argv[++i];
102 else if (strcmp(argv[i], "-version") == 0) {
103 fprintf(stderr, "%s", version[0]);
104 if (PATCHLEVEL > 0)
105 fprintf(stderr, "; patch level %d", PATCHLEVEL);
106 fprintf(stderr, "\n");
107 exit(0);
109 else if (argv[i][0] == '-')
110 usage();
111 else
112 break;
113 for (; i < argc; i++)
114 if (strcmp(argv[i], "exit") == 0)
115 do_exit++;
116 else if (strcmp(argv[i], "restart") == 0)
117 do_restart++;
118 else
119 usage();
121 if (do_exit && do_restart)
122 usage();
124 shell = (char *)getenv("SHELL");
125 if (shell == NULL)
126 shell = DEFSHELL;
128 dpy = XOpenDisplay("");
129 if (dpy == 0)
130 fatal("can't open display");
132 initting = 1;
133 XSetErrorHandler(handler);
134 if (signal(SIGTERM, sighandler) == SIG_IGN)
135 signal(SIGTERM, SIG_IGN);
136 if (signal(SIGINT, sighandler) == SIG_IGN)
137 signal(SIGINT, SIG_IGN);
138 if (signal(SIGHUP, sighandler) == SIG_IGN)
139 signal(SIGHUP, SIG_IGN);
141 exit_9wm = XInternAtom(dpy, "9WM_EXIT", False);
142 restart_9wm = XInternAtom(dpy, "9WM_RESTART", False);
144 curtime = -1; /* don't care */
145 if (do_exit) {
146 sendcmessage(DefaultRootWindow(dpy), exit_9wm, 0L, 1);
147 XSync(dpy, False);
148 exit(0);
150 if (do_restart) {
151 sendcmessage(DefaultRootWindow(dpy), restart_9wm, 0L, 1);
152 XSync(dpy, False);
153 exit(0);
156 if (0) XSynchronize(dpy, True);
158 wm_state = XInternAtom(dpy, "WM_STATE", False);
159 wm_change_state = XInternAtom(dpy, "WM_CHANGE_STATE", False);
160 wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False);
161 wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
162 wm_take_focus = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
163 wm_lose_focus = XInternAtom(dpy, "_9WM_LOSE_FOCUS", False);
164 wm_colormaps = XInternAtom(dpy, "WM_COLORMAP_WINDOWS", False);
165 _9wm_running = XInternAtom(dpy, "_9WM_RUNNING", False);
166 _9wm_hold_mode = XInternAtom(dpy, "_9WM_HOLD_MODE", False);
168 if (fname != 0)
169 if ((font = XLoadQueryFont(dpy, fname)) == 0)
170 fprintf(stderr, "9wm: warning: can't load font %s\n", fname);
172 if (font == 0) {
173 i = 0;
174 for (;;) {
175 fname = fontlist[i++];
176 if (fname == 0) {
177 fprintf(stderr, "9wm: warning: can't find a font\n");
178 break;
180 font = XLoadQueryFont(dpy, fname);
181 if (font != 0)
182 break;
185 if (nostalgia) {
186 _border--;
187 _inset--;
190 #ifdef SHAPE
191 shape = XShapeQueryExtension(dpy, &shape_event, &dummy);
192 #endif
194 num_screens = ScreenCount(dpy);
195 screens = (ScreenInfo *)malloc(sizeof(ScreenInfo) * num_screens);
197 for (i = 0; i < num_screens; i++)
198 initscreen(&screens[i], i, background);
200 /* set selection so that 9term knows we're running */
201 curtime = CurrentTime;
202 XSetSelectionOwner(dpy, _9wm_running, screens[0].menuwin, timestamp());
204 XSync(dpy, False);
205 initting = 0;
207 nofocus();
209 for (i = 0; i < num_screens; i++)
210 scanwins(&screens[i]);
212 mainloop(shape_event);
213 return 0;
216 void
217 initscreen(ScreenInfo *s, int i, int background)
219 char *ds, *colon, *dot1;
220 unsigned long mask;
221 unsigned long gmask;
222 XGCValues gv;
223 XSetWindowAttributes attr;
224 XVisualInfo xvi;
225 XSetWindowAttributes attrs;
227 s->num = i;
228 s->root = RootWindow(dpy, i);
229 s->def_cmap = DefaultColormap(dpy, i);
230 s->min_cmaps = MinCmapsOfScreen(ScreenOfDisplay(dpy, i));
231 s->depth = DefaultDepth(dpy, i);
233 /*
234 * Figure out underlying screen format.
235 */
236 if(XMatchVisualInfo(dpy, i, 16, TrueColor, &xvi)
237 || XMatchVisualInfo(dpy, i, 16, DirectColor, &xvi)){
238 s->vis = xvi.visual;
239 s->depth = 16;
241 else
242 if(XMatchVisualInfo(dpy, i, 15, TrueColor, &xvi)
243 || XMatchVisualInfo(dpy, i, 15, DirectColor, &xvi)){
244 s->vis = xvi.visual;
245 s->depth = 15;
247 else
248 if(XMatchVisualInfo(dpy, i, 24, TrueColor, &xvi)
249 || XMatchVisualInfo(dpy, i, 24, DirectColor, &xvi)){
250 s->vis = xvi.visual;
251 s->depth = 24;
253 else
254 if(XMatchVisualInfo(dpy, i, 8, PseudoColor, &xvi)
255 || XMatchVisualInfo(dpy, i, 8, StaticColor, &xvi)){
256 s->vis = xvi.visual;
257 s->depth = 8;
259 else{
260 s->depth = DefaultDepth(dpy, i);
261 if(s->depth != 8){
262 fprintf(stderr, "can't understand depth %d screen", s->depth);
263 exit(1);
265 s->vis = DefaultVisual(dpy, i);
267 if(DefaultDepth(dpy, i) != s->depth) {
268 s->def_cmap = XCreateColormap(dpy, s->root, s->vis, AllocNone);
271 ds = DisplayString(dpy);
272 colon = rindex(ds, ':');
273 if (colon && num_screens > 1) {
274 strcpy(s->display, "DISPLAY=");
275 strcat(s->display, ds);
276 colon = s->display + 8 + (colon - ds); /* use version in buf */
277 dot1 = index(colon, '.'); /* first period after colon */
278 if (!dot1)
279 dot1 = colon + strlen(colon); /* if not there, append */
280 sprintf(dot1, ".%d", i);
282 else
283 s->display[0] = '\0';
285 s->black = BlackPixel(dpy, i);
286 s->white = WhitePixel(dpy, i);
287 s->activeholdborder = colorpixel(dpy, s, s->depth, 0x000099, s->white);
288 s->inactiveholdborder = colorpixel(dpy, s, s->depth, 0x005DBB, s->black);
289 s->activeborder = colorpixel(dpy, s, s->depth, 0x55AAAA, s->black);
290 s->inactiveborder = colorpixel(dpy, s, s->depth, 0x9EEEEE, s->white);
291 s->red = colorpixel(dpy, s, s->depth, 0xDD0000, s->white);
292 s->width = WidthOfScreen(ScreenOfDisplay(dpy, i));
293 s->height = HeightOfScreen(ScreenOfDisplay(dpy, i));
294 s->bkup[0] = XCreatePixmap(dpy, s->root, 2*s->width, BORDER, DefaultDepth(dpy, i));
295 s->bkup[1] = XCreatePixmap(dpy, s->root, BORDER, 2*s->height, DefaultDepth(dpy, i));
297 gv.foreground = s->black^s->white;
298 gv.background = s->white;
299 gv.function = GXxor;
300 gv.line_width = 0;
301 gv.subwindow_mode = IncludeInferiors;
302 gmask = GCForeground | GCBackground | GCFunction | GCLineWidth
303 | GCSubwindowMode;
304 if (font != 0) {
305 gv.font = font->fid;
306 gmask |= GCFont;
308 s->gc = XCreateGC(dpy, s->root, gmask, &gv);
310 gv.function = GXcopy;
311 s->gccopy = XCreateGC(dpy, s->root, gmask, &gv);
313 gv.foreground = s->red;
314 s->gcred = XCreateGC(dpy, s->root, gmask, &gv);
316 gv.foreground = colorpixel(dpy, s, s->depth, 0xEEEEEE, s->black);
317 s->gcsweep = XCreateGC(dpy, s->root, gmask, &gv);
319 initcurs(s);
321 attr.cursor = s->arrow;
322 attr.event_mask = SubstructureRedirectMask
323 | SubstructureNotifyMask | ColormapChangeMask
324 | ButtonPressMask | ButtonReleaseMask | PropertyChangeMask;
325 mask = CWCursor|CWEventMask;
326 XChangeWindowAttributes(dpy, s->root, mask, &attr);
327 XSync(dpy, False);
329 if (background) {
330 XSetWindowBackgroundPixmap(dpy, s->root, s->root_pixmap);
331 XClearWindow(dpy, s->root);
332 } else
333 system("xsetroot -solid grey30");
335 attrs.border_pixel = colorpixel(dpy, s, s->depth, 0x88CC88, s->black);
336 attrs.background_pixel = colorpixel(dpy, s, s->depth, 0xE9FFE9, s->white);
337 attrs.colormap = s->def_cmap;
339 s->menuwin = XCreateWindow(dpy, s->root, 0, 0, 1, 1, 2,
340 s->depth,
341 CopyFromParent,
342 s->vis,
343 CWBackPixel | CWBorderPixel | CWColormap,
344 &attrs
345 );
348 gv.foreground = colorpixel(dpy, s, s->depth, 0xE9FFE9, s->white);
349 s->gcmenubg = XCreateGC(dpy, s->menuwin, gmask, &gv);
351 gv.foreground = colorpixel(dpy, s, s->depth, 0x448844, s->black);
352 s->gcmenubgs = XCreateGC(dpy, s->menuwin, gmask, &gv);
354 gv.foreground = s->black;
355 gv.background = colorpixel(dpy, s, s->depth, 0xE9FFE9, s->white);
356 s->gcmenufg = XCreateGC(dpy, s->menuwin, gmask, &gv);
358 gv.foreground = colorpixel(dpy, s, s->depth, 0xE9FFE9, s->white);
359 gv.background = colorpixel(dpy, s, s->depth, 0x448844, s->black);
360 s->gcmenufgs = XCreateGC(dpy, s->menuwin, gmask, &gv);
362 attrs.border_pixel = s->red;
363 attrs.background_pixel = colorpixel(dpy, s, s->depth, 0xEEEEEE, s->black);
364 attrs.colormap = s->def_cmap;
365 s->sweepwin = XCreateWindow(dpy, s->root, 0, 0, 1, 1, 4,
366 s->depth,
367 CopyFromParent,
368 s->vis,
369 CWBackPixel | CWBorderPixel | CWColormap,
370 &attrs
371 );
374 ScreenInfo*
375 getscreen(Window w)
377 int i;
379 for (i = 0; i < num_screens; i++)
380 if (screens[i].root == w)
381 return &screens[i];
383 return 0;
386 Time
387 timestamp(void)
389 XEvent ev;
391 if (curtime == CurrentTime) {
392 XChangeProperty(dpy, screens[0].root, _9wm_running, _9wm_running, 8,
393 PropModeAppend, (unsigned char *)"", 0);
394 XMaskEvent(dpy, PropertyChangeMask, &ev);
395 curtime = ev.xproperty.time;
397 return curtime;
400 void
401 sendcmessage(Window w, Atom a, long x, int isroot)
403 XEvent ev;
404 int status;
405 long mask;
407 memset(&ev, 0, sizeof(ev));
408 ev.xclient.type = ClientMessage;
409 ev.xclient.window = w;
410 ev.xclient.message_type = a;
411 ev.xclient.format = 32;
412 ev.xclient.data.l[0] = x;
413 ev.xclient.data.l[1] = timestamp();
414 mask = 0L;
415 if (isroot)
416 mask = SubstructureRedirectMask; /* magic! */
417 else
418 mask = ExposureMask; /* not really correct but so be it */
419 status = XSendEvent(dpy, w, False, mask, &ev);
420 if (status == 0)
421 fprintf(stderr, "9wm: sendcmessage failed\n");
424 void
425 sendconfig(Client *c)
427 XConfigureEvent ce;
429 ce.type = ConfigureNotify;
430 ce.event = c->window;
431 ce.window = c->window;
432 ce.x = c->x;
433 ce.y = c->y;
434 ce.width = c->dx;
435 ce.height = c->dy;
436 ce.border_width = c->border;
437 ce.above = None;
438 ce.override_redirect = 0;
439 XSendEvent(dpy, c->window, False, StructureNotifyMask, (XEvent*)&ce);
442 void
443 sighandler(void)
445 signalled = 1;
448 void
449 getevent(XEvent *e)
451 int fd;
452 fd_set rfds;
453 struct timeval t;
455 if (!signalled) {
456 if (QLength(dpy) > 0) {
457 XNextEvent(dpy, e);
458 return;
460 fd = ConnectionNumber(dpy);
461 FD_ZERO(&rfds);
462 FD_SET(fd, &rfds);
463 t.tv_sec = t.tv_usec = 0;
464 if (select(fd+1, &rfds, NULL, NULL, &t) == 1) {
465 XNextEvent(dpy, e);
466 return;
468 XFlush(dpy);
469 FD_SET(fd, &rfds);
470 if (select(fd+1, &rfds, NULL, NULL, NULL) == 1) {
471 XNextEvent(dpy, e);
472 return;
474 if (errno != EINTR || !signalled) {
475 perror("9wm: select failed");
476 exit(1);
479 fprintf(stderr, "9wm: exiting on signal\n");
480 cleanup();
481 exit(1);
484 void
485 cleanup(void)
487 Client *c, *cc[2], *next;
488 XWindowChanges wc;
489 int i;
491 /* order of un-reparenting determines final stacking order... */
492 cc[0] = cc[1] = 0;
493 for (c = clients; c; c = next) {
494 next = c->next;
495 i = normal(c);
496 c->next = cc[i];
497 cc[i] = c;
500 for (i = 0; i < 2; i++) {
501 for (c = cc[i]; c; c = c->next) {
502 if (!withdrawn(c)) {
503 gravitate(c, 1);
504 XReparentWindow(dpy, c->window, c->screen->root,
505 c->x, c->y);
507 wc.border_width = c->border;
508 XConfigureWindow(dpy, c->window, CWBorderWidth, &wc);
512 XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, timestamp());
513 for (i = 0; i < num_screens; i++)
514 cmapnofocus(&screens[i]);
515 XCloseDisplay(dpy);