1 /* Copyright (c) 1994-1996 David Hogan, see README for licence details */
10 #include <X11/Xutil.h>
11 #include <X11/Xatom.h>
13 #include <X11/extensions/shape.h>
17 #include "patchlevel.h"
21 "rio version 1.0, Copyright (c) 1994-1996 David Hogan, (c) 2004 Russ Cox", 0
60 "*-lucidatypewriter-bold-*-14-*-75-*",
61 "*-lucidatypewriter-medium-*-12-*-75-*",
71 fprintf(stderr, "usage: rio [-grey] [-font fname] [-s] [-term prog] [-version] [-virtuals num] [exit|restart]\n");
76 main(int argc, char *argv[])
78 int i, background, do_exit, do_restart;
86 myargv = argv; /* for restart */
88 do_exit = do_restart = 0;
92 for(i = 1; i < argc; i++)
93 if(strcmp(argv[i], "-nostalgia") == 0)
95 else if(strcmp(argv[i], "-grey") == 0)
97 else if(strcmp(argv[i], "-debug") == 0)
100 else if(strcmp(argv[i], "-ffm") == 0)
103 else if(strcmp(argv[i], "-font") == 0 && i+1<argc){
107 else if(strcmp(argv[i], "-term") == 0 && i+1<argc)
108 termprog = argv[++i];
109 else if(strcmp(argv[i], "-virtuals") == 0 && i+1<argc){
110 numvirtuals = atoi(argv[++i]);
111 if(numvirtuals < 0 || numvirtuals > 12){
112 fprintf(stderr, "rio: wrong number of virtual displays, defaulting to 4\n");
115 } else if(strcmp(argv[i], "-version") == 0){
116 fprintf(stderr, "%s", version[0]);
118 fprintf(stderr, "; patch level %d", PATCHLEVEL);
119 fprintf(stderr, "\n");
122 else if(strcmp(argv[i], "-s") == 0){
125 else if(argv[i][0] == '-')
130 if(strcmp(argv[i], "exit") == 0)
132 else if(strcmp(argv[i], "restart") == 0)
137 if(do_exit && do_restart)
140 shell = (char *)getenv("SHELL");
144 dpy = XOpenDisplay("");
146 fatal("can't open display");
149 XSetErrorHandler(handler);
150 if(signal(SIGTERM, sighandler) == SIG_IGN)
151 signal(SIGTERM, SIG_IGN);
152 if(signal(SIGINT, sighandler) == SIG_IGN)
153 signal(SIGINT, SIG_IGN);
154 if(signal(SIGHUP, sighandler) == SIG_IGN)
155 signal(SIGHUP, SIG_IGN);
157 exit_rio = XInternAtom(dpy, "9WM_EXIT", False);
158 restart_rio = XInternAtom(dpy, "9WM_RESTART", False);
160 curtime = -1; /* don't care */
162 sendcmessage(DefaultRootWindow(dpy), exit_rio, 0L, 1, 1);
167 sendcmessage(DefaultRootWindow(dpy), restart_rio, 0L, 1, 1);
172 if(0) XSynchronize(dpy, True);
174 wm_state = XInternAtom(dpy, "WM_STATE", False);
175 wm_change_state = XInternAtom(dpy, "WM_CHANGE_STATE", False);
176 wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False);
177 wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
178 wm_take_focus = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
179 wm_lose_focus = XInternAtom(dpy, "_9WM_LOSE_FOCUS", False);
180 wm_colormaps = XInternAtom(dpy, "WM_COLORMAP_WINDOWS", False);
181 _rio_running = XInternAtom(dpy, "_9WM_RUNNING", False);
182 _rio_hold_mode = XInternAtom(dpy, "_9WM_HOLD_MODE", False);
185 if((font = XLoadQueryFont(dpy, fname)) == 0)
186 fprintf(stderr, "rio: warning: can't load font %s\n", fname);
191 fname = fontlist[i++];
193 fprintf(stderr, "rio: warning: can't find a font\n");
196 font = XLoadQueryFont(dpy, fname);
207 shape = XShapeQueryExtension(dpy, &shape_event, &dummy);
210 num_screens = ScreenCount(dpy);
211 screens = (ScreenInfo *)malloc(sizeof(ScreenInfo) * num_screens);
213 for(i = 0; i < num_screens; i++)
214 initscreen(&screens[i], i, background);
216 initb2menu(numvirtuals);
218 /* set selection so that 9term knows we're running */
219 curtime = CurrentTime;
220 XSetSelectionOwner(dpy, _rio_running, screens[0].menuwin, timestamp());
227 for(i = 0; i < num_screens; i++)
228 scanwins(&screens[i]);
231 mainloop(shape_event);
236 initscreen(ScreenInfo *s, int i, int background)
238 char *ds, *colon, *dot1;
242 XSetWindowAttributes attr;
244 XSetWindowAttributes attrs;
247 s->root = RootWindow(dpy, i);
248 s->def_cmap = DefaultColormap(dpy, i);
249 s->min_cmaps = MinCmapsOfScreen(ScreenOfDisplay(dpy, i));
250 s->depth = DefaultDepth(dpy, i);
253 * Figure out underlying screen format.
255 if(XMatchVisualInfo(dpy, i, 16, TrueColor, &xvi)
256 || XMatchVisualInfo(dpy, i, 16, DirectColor, &xvi)){
261 if(XMatchVisualInfo(dpy, i, 15, TrueColor, &xvi)
262 || XMatchVisualInfo(dpy, i, 15, DirectColor, &xvi)){
267 if(XMatchVisualInfo(dpy, i, 24, TrueColor, &xvi)
268 || XMatchVisualInfo(dpy, i, 24, DirectColor, &xvi)){
273 if(XMatchVisualInfo(dpy, i, 8, PseudoColor, &xvi)
274 || XMatchVisualInfo(dpy, i, 8, StaticColor, &xvi)){
279 s->depth = DefaultDepth(dpy, i);
281 fprintf(stderr, "can't understand depth %d screen", s->depth);
284 s->vis = DefaultVisual(dpy, i);
286 if(DefaultDepth(dpy, i) != s->depth){
287 s->def_cmap = XCreateColormap(dpy, s->root, s->vis, AllocNone);
290 ds = DisplayString(dpy);
291 colon = rindex(ds, ':');
292 if(colon && num_screens > 1){
293 strcpy(s->display, "DISPLAY=");
294 strcat(s->display, ds);
295 colon = s->display + 8 + (colon - ds); /* use version in buf */
296 dot1 = index(colon, '.'); /* first period after colon */
298 dot1 = colon + strlen(colon); /* if not there, append */
299 sprintf(dot1, ".%d", i);
302 s->display[0] = '\0';
304 s->black = BlackPixel(dpy, i);
305 s->white = WhitePixel(dpy, i);
306 s->activeholdborder = colorpixel(dpy, s, s->depth, 0x000099, s->white);
307 s->inactiveholdborder = colorpixel(dpy, s, s->depth, 0x005DBB, s->black);
308 s->activeborder = colorpixel(dpy, s, s->depth, 0x55AAAA, s->black);
309 s->inactiveborder = colorpixel(dpy, s, s->depth, 0x9EEEEE, s->white);
310 s->red = colorpixel(dpy, s, s->depth, 0xDD0000, s->white);
311 s->width = WidthOfScreen(ScreenOfDisplay(dpy, i));
312 s->height = HeightOfScreen(ScreenOfDisplay(dpy, i));
313 s->bkup[0] = XCreatePixmap(dpy, s->root, 2*s->width, BORDER, DefaultDepth(dpy, i));
314 s->bkup[1] = XCreatePixmap(dpy, s->root, BORDER, 2*s->height, DefaultDepth(dpy, i));
316 gv.foreground = s->black^s->white;
317 gv.background = s->white;
320 gv.subwindow_mode = IncludeInferiors;
321 gmask = GCForeground | GCBackground | GCFunction | GCLineWidth
327 s->gc = XCreateGC(dpy, s->root, gmask, &gv);
329 gv.function = GXcopy;
330 s->gccopy = XCreateGC(dpy, s->root, gmask, &gv);
332 gv.foreground = s->red;
333 s->gcred = XCreateGC(dpy, s->root, gmask, &gv);
335 gv.foreground = colorpixel(dpy, s, s->depth, 0xEEEEEE, s->black);
336 s->gcsweep = XCreateGC(dpy, s->root, gmask, &gv);
340 attr.cursor = s->arrow;
341 attr.event_mask = SubstructureRedirectMask
342 | SubstructureNotifyMask | ColormapChangeMask
343 | ButtonPressMask | ButtonReleaseMask | PropertyChangeMask
344 | KeyPressMask | EnterWindowMask;
345 mask = CWCursor|CWEventMask;
346 XChangeWindowAttributes(dpy, s->root, mask, &attr);
350 XSetWindowBackgroundPixmap(dpy, s->root, s->root_pixmap);
351 XClearWindow(dpy, s->root);
353 system("xsetroot -solid grey30");
355 attrs.border_pixel = colorpixel(dpy, s, s->depth, 0x88CC88, s->black);
356 attrs.background_pixel = colorpixel(dpy, s, s->depth, 0xE9FFE9, s->white);
357 attrs.colormap = s->def_cmap;
359 s->menuwin = XCreateWindow(dpy, s->root, 0, 0, 1, 1, 2,
363 CWBackPixel | CWBorderPixel | CWColormap,
368 gv.foreground = colorpixel(dpy, s, s->depth, 0xE9FFE9, s->white);
369 s->gcmenubg = XCreateGC(dpy, s->menuwin, gmask, &gv);
371 gv.foreground = colorpixel(dpy, s, s->depth, 0x448844, s->black);
372 s->gcmenubgs = XCreateGC(dpy, s->menuwin, gmask, &gv);
374 gv.foreground = s->black;
375 gv.background = colorpixel(dpy, s, s->depth, 0xE9FFE9, s->white);
376 s->gcmenufg = XCreateGC(dpy, s->menuwin, gmask, &gv);
378 gv.foreground = colorpixel(dpy, s, s->depth, 0xE9FFE9, s->white);
379 gv.background = colorpixel(dpy, s, s->depth, 0x448844, s->black);
380 s->gcmenufgs = XCreateGC(dpy, s->menuwin, gmask, &gv);
382 attrs.border_pixel = s->red;
383 attrs.background_pixel = colorpixel(dpy, s, s->depth, 0xEEEEEE, s->black);
384 attrs.colormap = s->def_cmap;
385 s->sweepwin = XCreateWindow(dpy, s->root, 0, 0, 1, 1, 4,
389 CWBackPixel | CWBorderPixel | CWColormap,
399 for(i = 0; i < num_screens; i++)
400 if(screens[i].root == w)
411 if(curtime == CurrentTime){
412 XChangeProperty(dpy, screens[0].root, _rio_running, _rio_running, 8,
413 PropModeAppend, (unsigned char *)"", 0);
414 XMaskEvent(dpy, PropertyChangeMask, &ev);
415 curtime = ev.xproperty.time;
421 sendcmessage(Window w, Atom a, long x, int isroot, int usemask)
427 memset(&ev, 0, sizeof(ev));
428 ev.xclient.type = ClientMessage;
429 ev.xclient.window = w;
430 ev.xclient.message_type = a;
431 ev.xclient.format = 32;
432 ev.xclient.data.l[0] = x;
433 ev.xclient.data.l[1] = timestamp();
436 mask |= KeyPressMask; /* seems to be necessary */
438 mask |= SubstructureRedirectMask; /* magic! */
440 mask |= ExposureMask; /* not really correct but so be it */
442 status = XSendEvent(dpy, w, False, mask, &ev);
444 fprintf(stderr, "rio: sendcmessage failed\n");
448 sendconfig(Client *c)
452 ce.type = ConfigureNotify;
453 ce.event = c->window;
454 ce.window = c->window;
459 ce.border_width = c->border;
461 ce.override_redirect = 0;
462 XSendEvent(dpy, c->window, False, StructureNotifyMask, (XEvent*)&ce);
479 if(QLength(dpy) > 0){
483 fd = ConnectionNumber(dpy);
486 t.tv_sec = t.tv_usec = 0;
487 if(select(fd+1, &rfds, NULL, NULL, &t) == 1){
493 if(select(fd+1, &rfds, NULL, NULL, NULL) == 1){
497 if(errno != EINTR || !signalled){
498 perror("rio: select failed");
502 fprintf(stderr, "rio: exiting on signal\n");
510 Client *c, *cc[2], *next;
514 /* order of un-reparenting determines final stacking order... */
516 for(c = clients; c; c = next){
523 for(i = 0; i < 2; i++){
524 for(c = cc[i]; c; c = c->next){
526 XReparentWindow(dpy, c->window, c->screen->root,
529 wc.border_width = c->border;
530 XConfigureWindow(dpy, c->window, CWBorderWidth, &wc);
534 XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, timestamp());
535 for(i = 0; i < num_screens; i++)
536 cmapnofocus(&screens[i]);