main.c (12946B)
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" 18 19 char *version[] = 20 { 21 "rio version 1.0, Copyright (c) 1994-1996 David Hogan, (c) 2004 Russ Cox", 0 22 }; 23 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 scrolling; 40 int num_screens; 41 int solidsweep = 0; 42 int numvirtuals = 0; 43 int ffm = 0; 44 45 Atom exit_rio; 46 Atom restart_rio; 47 Atom wm_state; 48 Atom wm_change_state; 49 Atom wm_protocols; 50 Atom wm_delete; 51 Atom wm_take_focus; 52 Atom wm_lose_focus; 53 Atom wm_colormaps; 54 Atom _rio_running; 55 Atom _rio_hold_mode; 56 Atom wm_state_fullscreen; 57 Atom wm_state; 58 59 char *fontlist[] = { 60 "lucm.latin1.9", 61 "blit", 62 "*-lucidatypewriter-bold-*-14-*-75-*", 63 "*-lucidatypewriter-medium-*-12-*-75-*", 64 "9x15bold", 65 "fixed", 66 "*", 67 0 68 }; 69 70 void 71 usage(void) 72 { 73 fprintf(stderr, "usage: rio [-grey] [-font fname] [-s] [-term prog] [-version] [-virtuals num] [exit|restart]\n"); 74 exit(1); 75 } 76 77 int 78 main(int argc, char *argv[]) 79 { 80 int i, background, do_exit, do_restart; 81 char *fname; 82 int shape_event; 83 #ifdef SHAPE 84 int dummy; 85 #endif 86 87 shape_event = 0; 88 myargv = argv; /* for restart */ 89 90 do_exit = do_restart = 0; 91 background = 0; 92 font = 0; 93 fname = 0; 94 for(i = 1; i < argc; i++) 95 if(strcmp(argv[i], "-nostalgia") == 0) 96 nostalgia++; 97 else if(strcmp(argv[i], "-grey") == 0) 98 background = 1; 99 else if(strcmp(argv[i], "-debug") == 0) 100 debug++; 101 /* 102 else if(strcmp(argv[i], "-ffm") == 0) 103 ffm++; 104 */ 105 else if(strcmp(argv[i], "-font") == 0 && i+1<argc){ 106 i++; 107 fname = argv[i]; 108 } 109 else if(strcmp(argv[i], "-term") == 0 && i+1<argc) 110 termprog = argv[++i]; 111 else if(strcmp(argv[i], "-virtuals") == 0 && i+1<argc){ 112 numvirtuals = atoi(argv[++i]); 113 if(numvirtuals < 0 || numvirtuals > 12){ 114 fprintf(stderr, "rio: wrong number of virtual displays, defaulting to 4\n"); 115 numvirtuals = 4; 116 } 117 } else if(strcmp(argv[i], "-version") == 0){ 118 fprintf(stderr, "%s", version[0]); 119 if(PATCHLEVEL > 0) 120 fprintf(stderr, "; patch level %d", PATCHLEVEL); 121 fprintf(stderr, "\n"); 122 exit(0); 123 } 124 else if(strcmp(argv[i], "-s") == 0){ 125 scrolling = 1; 126 } 127 else if(argv[i][0] == '-') 128 usage(); 129 else 130 break; 131 for(; i < argc; i++) 132 if(strcmp(argv[i], "exit") == 0) 133 do_exit++; 134 else if(strcmp(argv[i], "restart") == 0) 135 do_restart++; 136 else 137 usage(); 138 139 if(do_exit && do_restart) 140 usage(); 141 142 shell = (char *)getenv("SHELL"); 143 if(shell == NULL) 144 shell = DEFSHELL; 145 146 dpy = XOpenDisplay(""); 147 if(dpy == 0) 148 fatal("can't open display"); 149 150 initting = 1; 151 XSetErrorHandler(handler); 152 if(signal(SIGTERM, sighandler) == SIG_IGN) 153 signal(SIGTERM, SIG_IGN); 154 if(signal(SIGINT, sighandler) == SIG_IGN) 155 signal(SIGINT, SIG_IGN); 156 if(signal(SIGHUP, sighandler) == SIG_IGN) 157 signal(SIGHUP, SIG_IGN); 158 159 exit_rio = XInternAtom(dpy, "9WM_EXIT", False); 160 restart_rio = XInternAtom(dpy, "9WM_RESTART", False); 161 162 curtime = -1; /* don't care */ 163 if(do_exit){ 164 sendcmessage(DefaultRootWindow(dpy), exit_rio, 0L, 1, 1); 165 XSync(dpy, False); 166 exit(0); 167 } 168 if(do_restart){ 169 sendcmessage(DefaultRootWindow(dpy), restart_rio, 0L, 1, 1); 170 XSync(dpy, False); 171 exit(0); 172 } 173 174 if(0) XSynchronize(dpy, True); 175 176 wm_state = XInternAtom(dpy, "WM_STATE", False); 177 wm_change_state = XInternAtom(dpy, "WM_CHANGE_STATE", False); 178 wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False); 179 wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False); 180 wm_take_focus = XInternAtom(dpy, "WM_TAKE_FOCUS", False); 181 wm_lose_focus = XInternAtom(dpy, "_9WM_LOSE_FOCUS", False); 182 wm_colormaps = XInternAtom(dpy, "WM_COLORMAP_WINDOWS", False); 183 _rio_running = XInternAtom(dpy, "_9WM_RUNNING", False); 184 _rio_hold_mode = XInternAtom(dpy, "_9WM_HOLD_MODE", False); 185 wm_state = XInternAtom(dpy, "_NET_WM_STATE", False); 186 wm_state_fullscreen = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); 187 188 if(fname != 0) 189 if((font = XLoadQueryFont(dpy, fname)) == 0) 190 fprintf(stderr, "rio: warning: can't load font %s\n", fname); 191 192 if(font == 0){ 193 i = 0; 194 for(;;){ 195 fname = fontlist[i++]; 196 if(fname == 0){ 197 fprintf(stderr, "rio: warning: can't find a font\n"); 198 break; 199 } 200 font = XLoadQueryFont(dpy, fname); 201 if(font != 0) 202 break; 203 } 204 } 205 if(nostalgia){ 206 _border--; 207 _inset--; 208 } 209 210 #ifdef SHAPE 211 shape = XShapeQueryExtension(dpy, &shape_event, &dummy); 212 #endif 213 214 num_screens = ScreenCount(dpy); 215 screens = (ScreenInfo *)malloc(sizeof(ScreenInfo) * num_screens); 216 if (!screens){ 217 fprintf(stderr, "rio: Failed to allocate memory\n"); 218 return 1; 219 } 220 221 for(i = 0; i < num_screens; i++) 222 initscreen(&screens[i], i, background); 223 224 initb2menu(numvirtuals); 225 226 /* set selection so that 9term knows we're running */ 227 curtime = CurrentTime; 228 XSetSelectionOwner(dpy, _rio_running, screens[0].menuwin, timestamp()); 229 230 XSync(dpy, False); 231 initting = 0; 232 233 nofocus(); 234 235 for(i = 0; i < num_screens; i++) 236 scanwins(&screens[i]); 237 238 keysetup(); 239 mainloop(shape_event); 240 return 0; 241 } 242 243 void 244 initscreen(ScreenInfo *s, int i, int background) 245 { 246 char *ds, *colon, *dot1; 247 unsigned long mask; 248 unsigned long gmask; 249 XGCValues gv; 250 XSetWindowAttributes attr; 251 XVisualInfo xvi; 252 XSetWindowAttributes attrs; 253 254 s->num = i; 255 s->root = RootWindow(dpy, i); 256 s->def_cmap = DefaultColormap(dpy, i); 257 s->min_cmaps = MinCmapsOfScreen(ScreenOfDisplay(dpy, i)); 258 s->depth = DefaultDepth(dpy, i); 259 260 /* 261 * Figure out underlying screen format. 262 */ 263 if(XMatchVisualInfo(dpy, i, 16, TrueColor, &xvi) 264 || XMatchVisualInfo(dpy, i, 16, DirectColor, &xvi)){ 265 s->vis = xvi.visual; 266 s->depth = 16; 267 } 268 else 269 if(XMatchVisualInfo(dpy, i, 15, TrueColor, &xvi) 270 || XMatchVisualInfo(dpy, i, 15, DirectColor, &xvi)){ 271 s->vis = xvi.visual; 272 s->depth = 15; 273 } 274 else 275 if(XMatchVisualInfo(dpy, i, 24, TrueColor, &xvi) 276 || XMatchVisualInfo(dpy, i, 24, DirectColor, &xvi)){ 277 s->vis = xvi.visual; 278 s->depth = 24; 279 } 280 else 281 if(XMatchVisualInfo(dpy, i, 8, PseudoColor, &xvi) 282 || XMatchVisualInfo(dpy, i, 8, StaticColor, &xvi)){ 283 s->vis = xvi.visual; 284 s->depth = 8; 285 } 286 else{ 287 s->depth = DefaultDepth(dpy, i); 288 if(s->depth != 8){ 289 fprintf(stderr, "can't understand depth %d screen", s->depth); 290 exit(1); 291 } 292 s->vis = DefaultVisual(dpy, i); 293 } 294 if(DefaultDepth(dpy, i) != s->depth){ 295 s->def_cmap = XCreateColormap(dpy, s->root, s->vis, AllocNone); 296 } 297 298 ds = DisplayString(dpy); 299 colon = rindex(ds, ':'); 300 if(colon && num_screens > 1){ 301 strcpy(s->display, "DISPLAY="); 302 strcat(s->display, ds); 303 colon = s->display + 8 + (colon - ds); /* use version in buf */ 304 dot1 = index(colon, '.'); /* first period after colon */ 305 if(!dot1) 306 dot1 = colon + strlen(colon); /* if not there, append */ 307 sprintf(dot1, ".%d", i); 308 } 309 else 310 s->display[0] = '\0'; 311 312 s->black = BlackPixel(dpy, i); 313 s->white = WhitePixel(dpy, i); 314 s->activeholdborder = colorpixel(dpy, s, s->depth, 0x000099, s->white); 315 s->inactiveholdborder = colorpixel(dpy, s, s->depth, 0x005DBB, s->black); 316 s->activeborder = colorpixel(dpy, s, s->depth, 0x55AAAA, s->black); 317 s->inactiveborder = colorpixel(dpy, s, s->depth, 0x9EEEEE, s->white); 318 s->red = colorpixel(dpy, s, s->depth, 0xDD0000, s->white); 319 s->width = WidthOfScreen(ScreenOfDisplay(dpy, i)); 320 s->height = HeightOfScreen(ScreenOfDisplay(dpy, i)); 321 s->bkup[0] = XCreatePixmap(dpy, s->root, 2*s->width, BORDER, DefaultDepth(dpy, i)); 322 s->bkup[1] = XCreatePixmap(dpy, s->root, BORDER, 2*s->height, DefaultDepth(dpy, i)); 323 324 gv.foreground = s->black^s->white; 325 gv.background = s->white; 326 gv.function = GXxor; 327 gv.line_width = 0; 328 gv.subwindow_mode = IncludeInferiors; 329 gmask = GCForeground | GCBackground | GCFunction | GCLineWidth 330 | GCSubwindowMode; 331 if(font != 0){ 332 gv.font = font->fid; 333 gmask |= GCFont; 334 } 335 s->gc = XCreateGC(dpy, s->root, gmask, &gv); 336 337 gv.function = GXcopy; 338 s->gccopy = XCreateGC(dpy, s->root, gmask, &gv); 339 340 gv.foreground = s->red; 341 s->gcred = XCreateGC(dpy, s->root, gmask, &gv); 342 343 gv.foreground = colorpixel(dpy, s, s->depth, 0xEEEEEE, s->black); 344 s->gcsweep = XCreateGC(dpy, s->root, gmask, &gv); 345 346 initcurs(s); 347 348 attr.cursor = s->arrow; 349 attr.event_mask = SubstructureRedirectMask 350 | SubstructureNotifyMask | ColormapChangeMask 351 | ButtonPressMask | ButtonReleaseMask | PropertyChangeMask 352 | KeyPressMask | EnterWindowMask; 353 mask = CWCursor|CWEventMask; 354 XChangeWindowAttributes(dpy, s->root, mask, &attr); 355 XSync(dpy, False); 356 357 if(background){ 358 XSetWindowBackgroundPixmap(dpy, s->root, s->root_pixmap); 359 XClearWindow(dpy, s->root); 360 } else 361 system("xsetroot -solid grey30"); 362 363 attrs.border_pixel = colorpixel(dpy, s, s->depth, 0x88CC88, s->black); 364 attrs.background_pixel = colorpixel(dpy, s, s->depth, 0xE9FFE9, s->white); 365 attrs.colormap = s->def_cmap; 366 367 s->menuwin = XCreateWindow(dpy, s->root, 0, 0, 1, 1, 2, 368 s->depth, 369 CopyFromParent, 370 s->vis, 371 CWBackPixel | CWBorderPixel | CWColormap, 372 &attrs 373 ); 374 375 376 gv.foreground = colorpixel(dpy, s, s->depth, 0xE9FFE9, s->white); 377 s->gcmenubg = XCreateGC(dpy, s->menuwin, gmask, &gv); 378 379 gv.foreground = colorpixel(dpy, s, s->depth, 0x448844, s->black); 380 s->gcmenubgs = XCreateGC(dpy, s->menuwin, gmask, &gv); 381 382 gv.foreground = s->black; 383 gv.background = colorpixel(dpy, s, s->depth, 0xE9FFE9, s->white); 384 s->gcmenufg = XCreateGC(dpy, s->menuwin, gmask, &gv); 385 386 gv.foreground = colorpixel(dpy, s, s->depth, 0xE9FFE9, s->white); 387 gv.background = colorpixel(dpy, s, s->depth, 0x448844, s->black); 388 s->gcmenufgs = XCreateGC(dpy, s->menuwin, gmask, &gv); 389 390 attrs.border_pixel = s->red; 391 attrs.background_pixel = colorpixel(dpy, s, s->depth, 0xEEEEEE, s->black); 392 attrs.colormap = s->def_cmap; 393 s->sweepwin = XCreateWindow(dpy, s->root, 0, 0, 1, 1, 4, 394 s->depth, 395 CopyFromParent, 396 s->vis, 397 CWBackPixel | CWBorderPixel | CWColormap, 398 &attrs 399 ); 400 } 401 402 ScreenInfo* 403 getscreen(Window w) 404 { 405 int i; 406 407 for(i = 0; i < num_screens; i++) 408 if(screens[i].root == w) 409 return &screens[i]; 410 411 return 0; 412 } 413 414 Time 415 timestamp(void) 416 { 417 XEvent ev; 418 419 if(curtime == CurrentTime){ 420 XChangeProperty(dpy, screens[0].root, _rio_running, _rio_running, 8, 421 PropModeAppend, (unsigned char *)"", 0); 422 XMaskEvent(dpy, PropertyChangeMask, &ev); 423 curtime = ev.xproperty.time; 424 } 425 return curtime; 426 } 427 428 void 429 sendcmessage(Window w, Atom a, long x, int isroot, int usemask) 430 { 431 XEvent ev; 432 int status; 433 long mask; 434 435 memset(&ev, 0, sizeof(ev)); 436 ev.xclient.type = ClientMessage; 437 ev.xclient.window = w; 438 ev.xclient.message_type = a; 439 ev.xclient.format = 32; 440 ev.xclient.data.l[0] = x; 441 ev.xclient.data.l[1] = timestamp(); 442 mask = 0; 443 if(usemask){ 444 mask |= KeyPressMask; /* seems to be necessary */ 445 if(isroot) 446 mask |= SubstructureRedirectMask; /* magic! */ 447 else 448 mask |= ExposureMask; /* not really correct but so be it */ 449 } 450 status = XSendEvent(dpy, w, False, mask, &ev); 451 if(status == 0) 452 fprintf(stderr, "rio: sendcmessage failed\n"); 453 } 454 455 void 456 sendconfig(Client *c) 457 { 458 XConfigureEvent ce; 459 460 ce.type = ConfigureNotify; 461 ce.event = c->window; 462 ce.window = c->window; 463 ce.x = c->x; 464 ce.y = c->y; 465 ce.width = c->dx; 466 ce.height = c->dy; 467 ce.border_width = c->border; 468 ce.above = None; 469 ce.override_redirect = 0; 470 XSendEvent(dpy, c->window, False, StructureNotifyMask, (XEvent*)&ce); 471 } 472 473 void 474 sighandler(void) 475 { 476 signalled = 1; 477 } 478 479 void 480 getevent(XEvent *e) 481 { 482 int fd; 483 fd_set rfds; 484 struct timeval t; 485 486 if(!signalled){ 487 if(QLength(dpy) > 0){ 488 XNextEvent(dpy, e); 489 return; 490 } 491 fd = ConnectionNumber(dpy); 492 FD_ZERO(&rfds); 493 FD_SET(fd, &rfds); 494 t.tv_sec = t.tv_usec = 0; 495 if(select(fd+1, &rfds, NULL, NULL, &t) == 1){ 496 XNextEvent(dpy, e); 497 return; 498 } 499 XFlush(dpy); 500 FD_SET(fd, &rfds); 501 if(select(fd+1, &rfds, NULL, NULL, NULL) == 1){ 502 XNextEvent(dpy, e); 503 return; 504 } 505 if(errno != EINTR || !signalled){ 506 perror("rio: select failed"); 507 exit(1); 508 } 509 } 510 fprintf(stderr, "rio: exiting on signal\n"); 511 cleanup(); 512 exit(1); 513 } 514 515 void 516 cleanup(void) 517 { 518 Client *c, *cc[2], *next; 519 XWindowChanges wc; 520 int i; 521 522 /* order of un-reparenting determines final stacking order... */ 523 cc[0] = cc[1] = 0; 524 for(c = clients; c; c = next){ 525 next = c->next; 526 i = normal(c); 527 c->next = cc[i]; 528 cc[i] = c; 529 } 530 531 for(i = 0; i < 2; i++){ 532 for(c = cc[i]; c; c = c->next){ 533 if(!withdrawn(c)){ 534 XReparentWindow(dpy, c->window, c->screen->root, 535 c->x, c->y); 536 } 537 wc.border_width = c->border; 538 XConfigureWindow(dpy, c->window, CWBorderWidth, &wc); 539 } 540 } 541 542 XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, timestamp()); 543 for(i = 0; i < num_screens; i++) 544 cmapnofocus(&screens[i]); 545 XCloseDisplay(dpy); 546 }