quake-style console with xterm
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

cleanup, handle respawning properly

we can't do any xlib ops in the sigchld handler

+96 -68
+96 -68
qconsole.c
··· 1 - /* vim:ts=8 2 - * $Id: qconsole.c,v 1.4 2008/11/14 04:26:21 jcs Exp $ 3 - * 4 - * Copyright (c) 2005, 2008 joshua stein <jcs@jcs.org> 1 + /* 2 + * qconsole 3 + * Copyright (c) 2005, 2008, 2015 joshua stein <jcs@jcs.org> 5 4 * 6 5 * Redistribution and use in source and binary forms, with or without 7 6 * modification, are permitted provided that the following conditions 8 7 * are met: 9 - * 8 + * 10 9 * 1. Redistributions of source code must retain the above copyright 11 10 * notice, this list of conditions and the following disclaimer. 12 11 * 2. Redistributions in binary form must reproduce the above copyright ··· 14 13 * documentation and/or other materials provided with the distribution. 15 14 * 3. The name of the author may not be used to endorse or promote products 16 15 * derived from this software without specific prior written permission. 17 - * 16 + * 18 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ··· 47 46 #define DIR_DOWN -1 48 47 49 48 #define MAX_SPEED 10 50 - #define DEF_SPEED 9 49 + #define DEF_SPEED 7 51 50 #define DEF_HEIGHT 157 52 51 53 52 #define BORDER 4 ··· 63 62 int cur_direction; 64 63 } main_win; 65 64 66 - char* win_name = "qconsole"; 65 + char *win_name = "qconsole"; 67 66 68 67 /* args to pass to xterm; requires a trailing blank -into option */ 69 - char *xterm_args[6] = { 70 - "xterm", "-name", "qconsole", "-into", "", 68 + static char *xterm_args[6] = { 69 + "xterm", 70 + "-name", "qconsole", 71 + "-into", "", 71 72 NULL 72 73 }; 73 74 74 - const struct option longopts[] = { 75 - { "display", required_argument, NULL, 'd' }, 76 - { "height", required_argument, NULL, 'h' }, 77 - { "speed", required_argument, NULL, 's' }, 78 - 79 - { NULL, 0, NULL, 0 } 80 - }; 81 - 82 - pid_t xterm_pid = 0; 83 - int shutting_down = 0; 84 - int respawning = 0; 75 + static int debug = 0; 76 + static pid_t xterm_pid = 0; 77 + static int shutting_down = 0; 78 + static int respawning = 0; 85 79 86 - extern char *__progname; 80 + extern char *__progname; 87 81 88 - void draw_window(const char *); 89 - void scroll(int direction, int quick); 90 - void xterm_handler(int sig); 91 - void exit_handler(int sig); 92 - void x_error_handler(Display * d, XErrorEvent * e); 93 - void usage(void); 82 + void draw_window(const char *); 83 + void scroll(int direction, int quick); 84 + void xterm_spawn(void); 85 + void child_handler(int sig); 86 + void exit_handler(int sig); 87 + void x_error_handler(Display * d, XErrorEvent * e); 88 + void usage(void); 94 89 95 90 int 96 91 main(int argc, char* argv[]) 97 92 { 98 93 char *display = NULL, *p; 99 - int c; 94 + int ch; 100 95 101 96 bzero(&main_win, sizeof(struct xinfo)); 102 97 main_win.height = DEF_HEIGHT; 103 98 main_win.speed = DEF_SPEED; 104 99 main_win.cur_direction = DIR_UP; 105 100 106 - while ((c = getopt_long_only(argc, argv, "", longopts, NULL)) != -1) { 107 - switch (c) { 101 + while ((ch = getopt(argc, argv, "dh:s:")) != -1) 102 + switch (ch) { 108 103 case 'd': 109 - display = optarg; 104 + debug = 1; 110 105 break; 111 106 112 107 case 'h': ··· 128 123 default: 129 124 usage(); 130 125 } 131 - } 132 126 133 127 argc -= optind; 134 128 argv += optind; ··· 137 131 signal(SIGINT, exit_handler); 138 132 signal(SIGTERM, exit_handler); 139 133 140 - /* giddy up */ 141 - draw_window(display); 134 + /* handle xterm exiting */ 135 + signal(SIGCHLD, child_handler); 142 136 143 - /* fire up xterm */ 144 - signal(SIGCHLD, xterm_handler); 145 - xterm_handler(0); 137 + /* fire up initial xterm */ 138 + draw_window(display); 139 + xterm_spawn(); 146 140 147 141 /* wait for events */ 148 142 for (;;) { ··· 151 145 XNextEvent(main_win.dpy, &event); 152 146 153 147 switch (event.type) { 154 - case ReparentNotify: 155 - { 156 - /* xterm spawned and reparented to us */ 157 - XReparentEvent *e = (XReparentEvent *) &event; 158 - main_win.xterm = e->window; 148 + case ReparentNotify: { 149 + if (debug) 150 + printf("xterm spawned and reparented to us\n"); 159 151 160 - /* move completely off-screen */ 161 - XMoveWindow(main_win.dpy, main_win.xterm, 162 - -1, -1); 163 - XResizeWindow(main_win.dpy, main_win.xterm, 164 - main_win.width, 165 - main_win.height - BORDER); 152 + XReparentEvent *e = (XReparentEvent *) &event; 153 + main_win.xterm = e->window; 166 154 167 - respawning = 0; 168 - } 155 + /* move completely off-screen */ 156 + XMoveWindow(main_win.dpy, main_win.xterm, 157 + -1, -1); 158 + XResizeWindow(main_win.dpy, main_win.xterm, 159 + main_win.width, 160 + main_win.height - BORDER); 169 161 170 162 break; 163 + } 171 164 172 165 case UnmapNotify: 173 - /* xterm died, respawn it */ 174 - if (!respawning) 175 - xterm_handler(NULL); 166 + if (debug) 167 + printf("xterm unmapped, respawning\n"); 168 + 169 + xterm_spawn(); 176 170 177 171 break; 178 172 ··· 262 256 XGetGeometry(main_win.dpy, main_win.win, &root, 263 257 &cur_x, &cur_y, &width, &height, &bw, &depth); 264 258 259 + if (debug) 260 + printf("scrolling from %d to %d%s\n", cur_y, dest, 261 + (quick ? " quickly" : "")); 262 + 263 + if (direction == DIR_DOWN) 264 + XRaiseWindow(main_win.dpy, main_win.win); 265 + 265 266 /* smoothly scroll to our destination */ 266 267 while (!quick && cur_y != dest) { 267 268 inc = (abs(dest - cur_y) / MAX_SPEED) / (MAX_SPEED + 1 - ··· 277 278 cur_y -= (inc * direction); 278 279 279 280 XMoveWindow(main_win.dpy, main_win.win, 0, cur_y); 280 - 281 - XFlush(main_win.dpy); 282 281 XSync(main_win.dpy, False); 283 282 } 284 283 285 284 XMoveWindow(main_win.dpy, main_win.win, 0, dest); 285 + main_win.cur_direction = direction; 286 286 287 - main_win.cur_direction = direction; 287 + if (direction == DIR_DOWN) 288 + XRaiseWindow(main_win.dpy, main_win.win); 288 289 } 289 290 290 291 void 291 - xterm_handler(int sig) 292 + child_handler(int sig) 293 + { 294 + if (!xterm_pid) 295 + return; 296 + 297 + if (debug && sig) 298 + printf("got SIGCHLD, cleaning up after xterm pid %d\n", 299 + xterm_pid); 300 + 301 + waitpid(-1, NULL, WNOHANG); 302 + xterm_pid = 0; 303 + } 304 + 305 + void 306 + xterm_spawn(void) 292 307 { 293 308 pid_t pid; 294 309 295 - if (shutting_down || respawning) 310 + /* this is called in response to SIGCHLD, but signal handlers can't do 311 + * any x11 operations */ 312 + 313 + if (shutting_down) { 314 + if (debug) 315 + printf("shutting down, not respawning\n"); 316 + 296 317 return; 297 - else if (sig) 298 - respawning = 1; 318 + } 319 + 320 + if (debug) 321 + printf("in xterm_spawn\n"); 299 322 300 323 /* clean up if previous xterm died */ 301 324 if (xterm_pid) { 302 - waitpid(-1, NULL, WNOHANG); 303 - xterm_pid = 0; 325 + child_handler(0); 304 326 305 327 scroll(DIR_UP, 1); 306 - 307 328 XUnmapSubwindows(main_win.dpy, main_win.win); 308 329 } 309 330 310 - if (!xterm_pid) { 331 + if (!xterm_pid && !shutting_down) { 332 + if (debug) 333 + printf("forking new xterm into %d\n", 334 + (int)main_win.win); 335 + 311 336 switch (pid = fork()) { 312 337 case -1: 313 338 errx(1, "unable to fork"); ··· 320 345 321 346 default: 322 347 xterm_pid = pid; 348 + /* we are now able to be killed */ 349 + respawning = 1; 323 350 } 324 351 } 325 352 } ··· 329 356 { 330 357 shutting_down = 1; 331 358 359 + if (debug) 360 + printf("in exit_handler with sig %d, shutting down\n", sig); 361 + 332 362 if (xterm_pid) 333 363 kill(xterm_pid, SIGKILL); 334 - 335 - XCloseDisplay(main_win.dpy); 336 364 337 365 exit(0); 338 366 } ··· 349 377 usage(void) 350 378 { 351 379 fprintf(stderr, "usage: %s %s\n", __progname, 352 - "[-display host:dpy] [-height <pixels>] [-speed <1-10>]"); 380 + "[-d] [-h <height>] [-s <speed 1-10>]"); 353 381 exit(1); 354 382 }