plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

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 }