shod

mouse-based window manager that can tile windows inside floating containers
Log | Files | Refs | README | LICENSE

shodc.c (14588B)


      1 #include <err.h>
      2 #include <stdio.h>
      3 #include <unistd.h>
      4 
      5 #include "xutil.h"
      6 
      7 #define NAMEMAXLEN                      128
      8 #define DIRECT_ACTION                   2
      9 #define _SHOD_MOVERESIZE_RELATIVE       ((long)(1 << 16))
     10 
     11 /* state action */
     12 enum {
     13 	REMOVE = 0,
     14 	ADD    = 1,
     15 	TOGGLE = 2
     16 };
     17 
     18 /* long list char positions */
     19 enum {
     20 	LIST_STICKY,
     21 	LIST_MAXIMIZED,
     22 	LIST_MINIMIZED,
     23 	LIST_FULLSCREEN,
     24 	LIST_SHADED,
     25 	LIST_LAYER,
     26 	LIST_URGENCY,
     27 	LIST_ACTIVE,
     28 	LIST_LAST
     29 };
     30 
     31 /* focus relative direction */
     32 enum Direction {
     33 	_SHOD_FOCUS_ABSOLUTE            = 0,
     34 	_SHOD_FOCUS_LEFT_CONTAINER      = 1,
     35 	_SHOD_FOCUS_RIGHT_CONTAINER     = 2,
     36 	_SHOD_FOCUS_TOP_CONTAINER       = 3,
     37 	_SHOD_FOCUS_BOTTOM_CONTAINER    = 4,
     38 	_SHOD_FOCUS_PREVIOUS_CONTAINER  = 5,
     39 	_SHOD_FOCUS_NEXT_CONTAINER      = 6,
     40 	_SHOD_FOCUS_LEFT_WINDOW         = 7,
     41 	_SHOD_FOCUS_RIGHT_WINDOW        = 8,
     42 	_SHOD_FOCUS_TOP_WINDOW          = 9,
     43 	_SHOD_FOCUS_BOTTOM_WINDOW       = 10,
     44 	_SHOD_FOCUS_PREVIOUS_WINDOW     = 11,
     45 	_SHOD_FOCUS_NEXT_WINDOW         = 12,
     46 };
     47 
     48 /* global variables */
     49 static Window active;
     50 
     51 /* show usage and exit */
     52 static void
     53 usage(void)
     54 {
     55 	(void)fprintf(stderr, "usage: shodc close [WIN_ID]\n");
     56 	(void)fprintf(stderr, "       shodc cycle [-s]\n");
     57 	(void)fprintf(stderr, "       shodc desks\n");
     58 	(void)fprintf(stderr, "       shodc exit\n");
     59 	(void)fprintf(stderr, "       shodc focus [-clrtbpnLRTBPN] [WIN_ID]\n");
     60 	(void)fprintf(stderr, "       shodc geom [-X|-x N] [-Y|-y N] [-W|-w N] [-H|-h N] [WIN_ID]\n");
     61 	(void)fprintf(stderr, "       shodc goto [-m MON_ID] DESK_ID\n");
     62 	(void)fprintf(stderr, "       shodc list [-ls] [WIN_ID]\n");
     63 	(void)fprintf(stderr, "       shodc sendto [-m MON_ID] DESK_ID [WIN_ID]\n");
     64 	(void)fprintf(stderr, "       shodc state [-ATR] [-abfMms] [WIN_ID]\n");
     65 	exit(1);
     66 }
     67 
     68 /* send client message to root window */
     69 static void
     70 clientmsg(Window win, Atom atom, unsigned long d0, unsigned long d1, unsigned long d2, unsigned long d3, unsigned long d4)
     71 {
     72 	XEvent ev;
     73 	long mask = SubstructureRedirectMask | SubstructureNotifyMask;
     74 
     75 	ev.xclient.type = ClientMessage;
     76 	ev.xclient.serial = 0;
     77 	ev.xclient.send_event = True;
     78 	ev.xclient.message_type = atom;
     79 	ev.xclient.window = win;
     80 	ev.xclient.format = 32;
     81 	ev.xclient.data.l[0] = d0;
     82 	ev.xclient.data.l[1] = d1;
     83 	ev.xclient.data.l[2] = d2;
     84 	ev.xclient.data.l[3] = d3;
     85 	ev.xclient.data.l[4] = d4;
     86 	if (!XSendEvent(dpy, root, False, mask, &ev)) {
     87 		errx(1, "could not send event");
     88 	}
     89 }
     90 
     91 /* get active window */
     92 static Window
     93 getactivewin(void)
     94 {
     95 	Window win;
     96 	unsigned char *list;
     97 	unsigned long len;
     98 	unsigned long dl;   /* dummy variable */
     99 	int di;             /* dummy variable */
    100 	Atom da;            /* dummy variable */
    101 
    102 	list = NULL;
    103 	if (XGetWindowProperty(dpy, root, atoms[_NET_ACTIVE_WINDOW], 0L, 1024, False, XA_WINDOW,
    104 		               &da, &di, &len, &dl, &list) != Success || list == NULL)
    105 		return None;
    106 	win = *(Window *)list;
    107 	XFree(list);
    108 	return win;
    109 }
    110 
    111 /* get window from string */
    112 static Window
    113 getwin(const char *s)
    114 {
    115 	return (Window)strtol(s, NULL, 0);
    116 }
    117 
    118 /* get array of windows */
    119 static unsigned long
    120 getwins(Window **wins, int sflag)
    121 {
    122 	if (sflag)
    123 		return getwinsprop(root, atoms[_NET_CLIENT_LIST_STACKING], wins);
    124 	else
    125 		return getwinsprop(root, atoms[_NET_CLIENT_LIST], wins);
    126 }
    127 
    128 /* get array of desktop names, return size of array */
    129 static unsigned long
    130 getdesknames(char **desknames)
    131 {
    132 	unsigned char *str;
    133 	unsigned long len;
    134 	unsigned long dl;   /* dummy variable */
    135 	int di;             /* dummy variable */
    136 	Atom da;            /* dummy variable */
    137 
    138 
    139 	if (XGetWindowProperty(dpy, root, atoms[_NET_DESKTOP_NAMES], 0, ~0, False,
    140 	                       UTF8_STRING, &da, &di, &len, &dl, &str) ==
    141 	                       Success && str) {
    142 		*desknames = (char *)str;
    143 	} else {
    144 		*desknames = NULL;
    145 		len = 0;
    146 	}
    147 
    148 	return len;
    149 }
    150 
    151 /* get window name */
    152 char *
    153 getwinname(Window win)
    154 {
    155 	XTextProperty tprop;
    156 	char **list = NULL;
    157 	char *name = NULL;
    158 	unsigned char *p = NULL;
    159 	unsigned long size, dl;
    160 	int di;
    161 	Atom da;
    162 
    163 	if (XGetWindowProperty(dpy, win, atoms[_NET_WM_NAME], 0L, 8L, False, UTF8_STRING,
    164 	                       &da, &di, &size, &dl, &p) == Success && p) {
    165 		name = estrndup((char *)p, NAMEMAXLEN);
    166 		XFree(p);
    167 	} else if (XGetWMName(dpy, win, &tprop) &&
    168 		   XmbTextPropertyToTextList(dpy, &tprop, &list, &di) == Success &&
    169 		   di > 0 && list && *list) {
    170 		name = estrndup(*list, NAMEMAXLEN);
    171 		XFreeStringList(list);
    172 		XFree(tprop.value);
    173 	}
    174 	return name;
    175 }
    176 
    177 /* close window */
    178 static void
    179 closewin(int argc, char *argv[])
    180 {
    181 	Window win;
    182 
    183 	win = None;
    184 	if (argc == 1)
    185 		win = active;
    186 	else if (argc == 2 && argv[1][0] != '-')
    187 		win = getwin(argv[1]);
    188 	else
    189 		usage();
    190 	clientmsg(win, atoms[_NET_CLOSE_WINDOW], CurrentTime, DIRECT_ACTION, 0, 0, 0);
    191 }
    192 
    193 /* focus window */
    194 static void
    195 focuswin(int argc, char *argv[])
    196 {
    197 	Window win;
    198 	enum Direction d;
    199 	int cycle, c;
    200 
    201 	cycle = 0;
    202 	d = _SHOD_FOCUS_ABSOLUTE;
    203 	win = None;
    204 	while ((c = getopt(argc, argv, "clrtbpnLRTBPN")) != -1) {
    205 		switch (c) {
    206 		case 'c':
    207 			cycle = 1;
    208 			break;
    209 		case 'L':
    210 			d = _SHOD_FOCUS_LEFT_WINDOW;
    211 			break;
    212 		case 'R':
    213 			d = _SHOD_FOCUS_RIGHT_WINDOW;
    214 			break;
    215 		case 'T':
    216 			d = _SHOD_FOCUS_TOP_WINDOW;
    217 			break;
    218 		case 'B':
    219 			d = _SHOD_FOCUS_BOTTOM_WINDOW;
    220 			break;
    221 		case 'P':
    222 			d = _SHOD_FOCUS_PREVIOUS_WINDOW;
    223 			break;
    224 		case 'N':
    225 			d = _SHOD_FOCUS_NEXT_WINDOW;
    226 			break;
    227 		case 'l':
    228 			d = _SHOD_FOCUS_LEFT_CONTAINER;
    229 			break;
    230 		case 'r':
    231 			d = _SHOD_FOCUS_RIGHT_CONTAINER;
    232 			break;
    233 		case 't':
    234 			d = _SHOD_FOCUS_TOP_CONTAINER;
    235 			break;
    236 		case 'b':
    237 			d = _SHOD_FOCUS_BOTTOM_CONTAINER;
    238 			break;
    239 		case 'p':
    240 			d = _SHOD_FOCUS_PREVIOUS_CONTAINER;
    241 			break;
    242 		case 'n':
    243 			d = _SHOD_FOCUS_NEXT_CONTAINER;
    244 			break;
    245 		default:
    246 			usage();
    247 			break;
    248 		}
    249 	}
    250 	argc -= optind;
    251 	argv += optind;
    252 	if (argc > 1)
    253 		usage();
    254 	if (argc == 1)
    255 		win = getwin(argv[0]);
    256 	clientmsg(win, atoms[_NET_ACTIVE_WINDOW], DIRECT_ACTION, CurrentTime, 0, d, cycle);
    257 }
    258 
    259 /* set container geometry */
    260 static void
    261 setgeom(int argc, char *argv[])
    262 {
    263 	Window win;
    264 	long x, y, w, h;
    265 	int rel;
    266 	int c;
    267 
    268 	rel = 0;
    269 	x = y = w = h = 0;
    270 	while ((c = getopt(argc, argv, "rx:y:w:h:")) != -1) {
    271 		switch (c) {
    272 		case 'r':
    273 			rel |= _SHOD_MOVERESIZE_RELATIVE;
    274 			break;
    275 		case 'x':
    276 			x = strtol(optarg, NULL, 10);
    277 			break;
    278 		case 'y':
    279 			y = strtol(optarg, NULL, 10);
    280 			break;
    281 		case 'w':
    282 			w = strtol(optarg, NULL, 10);
    283 			break;
    284 		case 'h':
    285 			h = strtol(optarg, NULL, 10);
    286 			break;
    287 		default:
    288 			usage();
    289 			break;
    290 		}
    291 	}
    292 	argc -= optind;
    293 	argv += optind;
    294 	if (argc > 1)
    295 		usage();
    296 	win = (argc == 1) ? getwin(argv[0]) : active;
    297 	clientmsg(win, atoms[_NET_MOVERESIZE_WINDOW], rel, x, y, w, h);
    298 }
    299 
    300 /* go to desktop */
    301 static void
    302 gotodesk(int argc, char *argv[])
    303 {
    304 	long mon, desk;
    305 	int c;
    306 
    307 	mon = 0;
    308 	while ((c = getopt(argc, argv, "m")) != -1) {
    309 		switch (c) {
    310 		case 'm':
    311 			mon = strtol(optarg, NULL, 0);
    312 			break;
    313 		default:
    314 			usage();
    315 			break;
    316 		}
    317 	}
    318 	argc -= optind;
    319 	argv += optind;
    320 	if (argc != 1)
    321 		usage();
    322 	desk = strtol(argv[0], NULL, 0) - 1;
    323 	clientmsg(None, atoms[_NET_CURRENT_DESKTOP], desk, CurrentTime, mon, 0, 0);
    324 }
    325 
    326 /* list window type, states, properties, etc */
    327 static void
    328 longlist(Window win)
    329 {
    330 	Atom *as;
    331 	int x, y;
    332 	unsigned int w, h, b, du;
    333 	long desk;
    334 	unsigned long i, natoms, l;
    335 	char state[] = "--------";
    336 	char *name;
    337 	XWMHints *wmhints = NULL;
    338 	Window *list = NULL;
    339 	Window dw;
    340 	XID container, tab;
    341 
    342 	container = tab = 0x0;
    343 	if ((wmhints = XGetWMHints(dpy, win)) != NULL) {
    344 		if (wmhints->flags & XUrgencyHint)
    345 			state[LIST_URGENCY] = 'u';
    346 		XFree(wmhints);
    347 	}
    348 	if (getwinsprop(win, atoms[_SHOD_GROUP_CONTAINER], &list) > 0) {
    349 		if (*list != None) {
    350 			container = *list;
    351 		}
    352 		XFree(list);
    353 	}
    354 	if (getwinsprop(win, atoms[_SHOD_GROUP_TAB], &list) > 0) {
    355 		if (*list != None) {
    356 			tab = *list;
    357 		}
    358 		XFree(list);
    359 	}
    360 	if (win == active)
    361 		state[LIST_ACTIVE] = 'a';
    362 	if ((natoms = getatomsprop(win, atoms[_NET_WM_STATE], &as)) > 0) {
    363 		for (i = 0; i < natoms; i++) {
    364 			if (as[i] == atoms[_NET_WM_STATE_STICKY]) {
    365 				state[LIST_STICKY] = 'y';
    366 			} else if (as[i] == atoms[_NET_WM_STATE_MAXIMIZED_VERT]) {
    367 				if (state[LIST_MAXIMIZED] == 'h') {
    368 					state[LIST_MAXIMIZED] = 'M';
    369 				} else {
    370 					state[LIST_MAXIMIZED] = 'v';
    371 				}
    372 			} else if (as[i] == atoms[_NET_WM_STATE_MAXIMIZED_HORZ]) {
    373 				if (state[LIST_MAXIMIZED] == 'v') {
    374 					state[LIST_MAXIMIZED] = 'M';
    375 				} else {
    376 					state[LIST_MAXIMIZED] = 'h';
    377 				}
    378 			} else if (as[i] == atoms[_NET_WM_STATE_HIDDEN]) {
    379 				state[LIST_MINIMIZED] = 'm';
    380 			} else if (as[i] == atoms[_NET_WM_STATE_SHADED]) {
    381 				state[LIST_SHADED] = 's';
    382 			} else if (as[i] == atoms[_NET_WM_STATE_FULLSCREEN]) {
    383 				state[LIST_FULLSCREEN] = 'F';
    384 			} else if (as[i] == atoms[_NET_WM_STATE_ABOVE]) {
    385 				state[LIST_LAYER] = 'a';
    386 			} else if (as[i] == atoms[_NET_WM_STATE_BELOW]) {
    387 				state[LIST_LAYER] = 'b';
    388 			} else if (as[i] == atoms[_NET_WM_STATE_DEMANDS_ATTENTION]) {
    389 				if (state[LIST_URGENCY] == 'u') {
    390 					state[LIST_URGENCY] = 'U';
    391 				} else {
    392 					state[LIST_URGENCY] = 'a';
    393 				}
    394 			} else if (as[i] == atoms[_NET_WM_STATE_FOCUSED]) {
    395 				if (state[LIST_ACTIVE] == 'a') {
    396 					state[LIST_ACTIVE] = 'A';
    397 				} else {
    398 					state[LIST_ACTIVE] = 'f';
    399 				}
    400 			}
    401 		}
    402 		XFree(as);
    403 	}
    404 	l = getcardprop(win, atoms[_NET_WM_DESKTOP]);
    405 	desk = (l ==  0xFFFFFFFF) ? -1 : (long)l;
    406 
    407 	name = getwinname(win);
    408 	XGetGeometry(dpy, win, &dw, &x, &y, &w, &h, &b, &du);
    409 	XTranslateCoordinates(dpy, win, root, x, y, &x, &y, &dw);
    410 
    411 	printf("%s\t%ld\t%dx%d%+d%+d\t0x%08lx\t0x%08lx\t0x%08lx\t%s\n", state, desk, w, h, x, y, container, tab, win, name);
    412 	free(name);
    413 }
    414 
    415 /* list desktops */
    416 static void
    417 listdesks(int argc, char *argv[])
    418 {
    419 	unsigned long i, nwins, desk, ndesks, curdesk, len, nameslen;
    420 	unsigned long *wdesk;
    421 	int *urgdesks;
    422 	Window *wins;
    423 	XWMHints *hints;
    424 	char *desknames;
    425 
    426 	(void)argv;
    427 	if (argc != 1)
    428 		usage();
    429 	
    430 	/* get variables */
    431 	ndesks = getcardprop(root, atoms[_NET_NUMBER_OF_DESKTOPS]);
    432 	curdesk = getcardprop(root, atoms[_NET_CURRENT_DESKTOP]);
    433 	nameslen = getdesknames(&desknames);
    434 	wdesk = ecalloc(ndesks, sizeof *wdesk);
    435 	urgdesks = ecalloc(ndesks, sizeof *urgdesks);
    436 	nwins = getwinsprop(root, atoms[_NET_CLIENT_LIST], &wins);
    437 	for (i = 0; i < nwins; i++) {
    438 		desk = getcardprop(wins[i], atoms[_NET_WM_DESKTOP]);
    439 		hints = XGetWMHints(dpy, wins[i]);
    440 		if (desk < ndesks) {
    441 			wdesk[desk]++;
    442 			if (hints && hints->flags & XUrgencyHint) {
    443 				urgdesks[desk] = 1;
    444 			}
    445 		}
    446 		XFree(hints);
    447 	}
    448 	XFree(wins);
    449 
    450 	/* list desktops */
    451 	for (len = i = 0; i < ndesks; i++) {
    452 		printf("%c%lu:%s\n",
    453 		       (i == curdesk ? '*' : (urgdesks[i] ? '-' : ' ')),
    454 		       wdesk[i],
    455 		       (desknames && len < nameslen ? desknames+len : ""));
    456 		if (desknames && len < nameslen)
    457 			len += strlen(desknames + len) + 1;
    458 	}
    459 	XFree(desknames);
    460 	free(wdesk);
    461 }
    462 
    463 /* list windows */
    464 static void
    465 list(int argc, char *argv[])
    466 {
    467 	Window *wins;
    468 	unsigned long nwins, i;
    469 	int lflag, sflag;
    470 	int c;
    471 
    472 	lflag = sflag = 0;
    473 	while ((c = getopt(argc, argv, "dls")) != -1) {
    474 		switch (c) {
    475 		case 'l':
    476 			lflag = 1;
    477 			break;
    478 		case 's':
    479 			sflag = 1;
    480 			break;
    481 		default:
    482 			usage();
    483 			break;
    484 		}
    485 	}
    486 	if (argc - optind > 1)
    487 		usage();
    488 	nwins = getwins(&wins, sflag);
    489 	for (i = 0; i < nwins; i++) {
    490 		if (lflag) {
    491 			longlist(wins[i]);
    492 		} else {
    493 			printf("0x%08lx\n", wins[i]);
    494 		}
    495 	}
    496 	XFree(wins);
    497 }
    498 
    499 /* send container to desktop */
    500 static void
    501 sendto(int argc, char *argv[])
    502 {
    503 	Window win;
    504 	long mon, desk;
    505 	int c;
    506 
    507 	mon = 0;
    508 	while ((c = getopt(argc, argv, "m")) != -1) {
    509 		switch (c) {
    510 		case 'm':
    511 			mon = strtol(optarg, NULL, 0);
    512 			break;
    513 		default:
    514 			usage();
    515 			break;
    516 		}
    517 	}
    518 	argc -= optind;
    519 	argv += optind;
    520 	if (argc > 2)
    521 		usage();
    522 	desk = strtol(argv[0], NULL, 0) - 1;
    523 	win = (argc == 2) ? getwin(argv[1]) : active;
    524 	clientmsg(win, atoms[_NET_WM_DESKTOP], desk, DIRECT_ACTION, mon, 0, 0);
    525 }
    526 
    527 /* set container state */
    528 static void
    529 state(int argc, char *argv[])
    530 {
    531 	Window win;
    532 	Atom state1, state2;
    533 	int action;
    534 	int c;
    535 
    536 	action = TOGGLE;
    537 	state1 = state2 = None;
    538 	while ((c = getopt(argc, argv, "ATRabfMmsSy")) != -1) {
    539 		switch (c) {
    540 		case 'A':
    541 			action = ADD;
    542 			break;
    543 		case 'T':
    544 			action = TOGGLE;
    545 			break;
    546 		case 'R':
    547 			action = REMOVE;
    548 			break;
    549 		case 'a':
    550 			state1 = atoms[_NET_WM_STATE_ABOVE];
    551 			state2 = None;
    552 			break;
    553 		case 'b':
    554 			state1 = atoms[_NET_WM_STATE_BELOW];
    555 			state2 = None;
    556 			break;
    557 		case 'f':
    558 			state1 = atoms[_NET_WM_STATE_FULLSCREEN];
    559 			state2 = None;
    560 			break;
    561 		case 'M':
    562 			state1 = atoms[_NET_WM_STATE_MAXIMIZED_VERT];
    563 			state2 = atoms[_NET_WM_STATE_MAXIMIZED_HORZ];
    564 			break;
    565 		case 'm':
    566 			state1 = atoms[_NET_WM_STATE_HIDDEN];
    567 			state2 = None;
    568 			break;
    569 		case 'S':
    570 			state1 = atoms[_SHOD_WM_STATE_STRETCHED];
    571 			state2 = None;
    572 			break;
    573 		case 's':
    574 			state1 = atoms[_NET_WM_STATE_SHADED];
    575 			state2 = None;
    576 			break;
    577 		case 'y':
    578 			state1 = atoms[_NET_WM_STATE_STICKY];
    579 			state2 = None;
    580 			break;
    581 		default:
    582 			usage();
    583 			break;
    584 		}
    585 	}
    586 	argc -= optind;
    587 	argv += optind;
    588 	if (argc > 1)
    589 		usage();
    590 	if (state1 == None)
    591 		return;
    592 	win = (argc == 1) ? getwin(argv[0]) : active;
    593 	clientmsg(win, atoms[_NET_WM_STATE], action, state1, state2, DIRECT_ACTION, 0);
    594 }
    595 
    596 /* cycle containers */
    597 static void
    598 cycle(int argc, char *argv[])
    599 {
    600 	int c, shift;
    601 
    602 	shift = 0;
    603 	while ((c = getopt(argc, argv, "s")) != -1) {
    604 		switch (c) {
    605 		case 's':
    606 			shift = 1;
    607 			break;
    608 		default:
    609 			usage();
    610 			break;
    611 		}
    612 	}
    613 	clientmsg(None, atoms[_SHOD_CYCLE], shift, 0, 0, 0, 0);
    614 }
    615 
    616 /* exit shod */
    617 static void
    618 exitshod(int argc, char *argv[])
    619 {
    620 	Window checkwin;
    621 
    622 	(void)argc;
    623 	(void)argv;
    624 	checkwin = getwinprop(root, atoms[_NET_SUPPORTING_WM_CHECK]);
    625 	if (checkwin != None) {
    626 		XDestroyWindow(dpy, checkwin);
    627 	}
    628 }
    629 
    630 /* shodc: remote controller for shod */
    631 int
    632 main(int argc, char *argv[])
    633 {
    634 	if (argc < 2)
    635 		usage();
    636 
    637 	xinit();
    638 	initatoms();
    639 	active = getactivewin();
    640 	if (strcmp(argv[1], "close") == 0)
    641 		closewin(argc - 1, argv + 1);
    642 	else if (strcmp(argv[1], "desks") == 0)
    643 		listdesks(argc - 1, argv + 1);
    644 	else if (strcmp(argv[1], "focus") == 0)
    645 		focuswin(argc - 1, argv + 1);
    646 	else if (strcmp(argv[1], "geom") == 0)
    647 		setgeom(argc - 1, argv + 1);
    648 	else if (strcmp(argv[1], "goto") == 0)
    649 		gotodesk(argc - 1, argv + 1);
    650 	else if (strcmp(argv[1], "list") == 0)
    651 		list(argc - 1, argv + 1);
    652 	else if (strcmp(argv[1], "sendto") == 0)
    653 		sendto(argc - 1, argv + 1);
    654 	else if (strcmp(argv[1], "state") == 0)
    655 		state(argc - 1, argv + 1);
    656 	else if (strcmp(argv[1], "cycle") == 0)
    657 		cycle(argc - 1, argv + 1);
    658 	else if (strcmp(argv[1], "exit") == 0)
    659 		exitshod(argc - 1, argv + 1);
    660 	else
    661 		usage();
    662 	XCloseDisplay(dpy);
    663 	return 0;
    664 }