quake-style console with xterm
0
fork

Configure Feed

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

sync

jcs 220a658c 51d79bc9

+142 -82
+142 -82
qconsole.c
··· 1 1 /* vim:ts=8 2 - * $Id: qconsole.c,v 1.2 2008/10/03 01:33:08 jcs Exp $ 3 - * 4 - * qconsole 2 + * $Id: qconsole.c,v 1.3 2008/11/14 04:24:05 jcs Exp $ 5 3 * 6 4 * Copyright (c) 2005, 2008 joshua stein <jcs@jcs.org> 7 5 * ··· 33 31 #include <getopt.h> 34 32 #include <signal.h> 35 33 #include <stdio.h> 34 + #include <stdarg.h> 36 35 #include <stdlib.h> 37 36 #include <string.h> 38 37 #include <time.h> ··· 42 41 43 42 #include <X11/Xlib.h> 44 43 #include <X11/Xutil.h> 44 + #include <X11/Xproto.h> 45 45 46 46 #define DIR_UP 1 47 47 #define DIR_DOWN -1 48 48 49 49 #define MAX_SPEED 10 50 50 #define DEF_SPEED 8 51 - #define DEF_HEIGHT 150 51 + #define DEF_HEIGHT 157 52 52 53 - /* so our window manager knows us */ 54 - char* win_name = "qconsole"; 53 + #define BORDER 4 55 54 56 55 struct xinfo { 57 56 Display* dpy; ··· 63 62 int width, height; 64 63 int cur_direction; 65 64 } main_win; 65 + 66 + char* win_name = "qconsole"; 66 67 67 68 /* args to pass to xterm; requires a trailing blank -into option */ 68 69 char *xterm_args[6] = { ··· 80 81 81 82 pid_t xterm_pid = 0; 82 83 int shutting_down = 0; 84 + int respawning = 0; 83 85 84 86 extern char *__progname; 85 87 88 + void dprintf(char *fmt, ...); 89 + void draw_window(const char *); 90 + void scroll(int direction, int quick); 86 91 void xterm_handler(int sig); 87 92 void exit_handler(int sig); 88 - void draw_window(const char *); 89 - void scroll(int direction); 93 + void x_error_handler(Display * d, XErrorEvent * e); 90 94 void usage(void); 91 95 96 + void 97 + dprintf(char *fmt, ...) 98 + { 99 + static char buf[1024]; 100 + va_list args; 101 + 102 + char timestr[50]; 103 + struct tm *parts; 104 + time_t now; 105 + 106 + (void)time(&now); 107 + parts = localtime(&now); 108 + strftime(timestr, sizeof timestr, "%H:%M:%S", parts); 109 + 110 + va_start(args, fmt); 111 + (void) vsnprintf(buf, sizeof(buf), fmt, args); 112 + va_end(args); 113 + 114 + printf("%s - %d - %s", timestr, respawning, buf); 115 + } 116 + 92 117 int 93 118 main(int argc, char* argv[]) 94 119 { ··· 97 122 98 123 bzero(&main_win, sizeof(struct xinfo)); 99 124 100 - /* init some defaults */ 101 125 main_win.height = DEF_HEIGHT; 102 126 main_win.speed = DEF_SPEED; 103 - 104 127 main_win.cur_direction = DIR_UP; 105 128 106 129 while ((c = getopt_long_only(argc, argv, "", longopts, NULL)) != -1) { ··· 113 136 main_win.height = strtol(optarg, &p, 10); 114 137 if (*p || main_win.height < 1) 115 138 errx(1, "illegal height value -- %s", optarg); 116 - /* NOTREACHED */ 139 + 117 140 break; 118 141 119 142 case 's': ··· 122 145 main_win.speed > MAX_SPEED) 123 146 errx(1, "speed must be between 1 and %d", 124 147 MAX_SPEED); 125 - /* NOTREACHED */ 148 + 126 149 break; 127 150 128 151 default: 129 152 usage(); 130 - /* NOTREACHED */ 131 153 } 132 154 } 133 155 ··· 150 172 bzero(&event, sizeof(XEvent)); 151 173 XNextEvent(main_win.dpy, &event); 152 174 175 + dprintf("got event %d\n", event.type); 176 + 153 177 switch (event.type) { 154 178 case ReparentNotify: 155 179 { 180 + /* xterm spawned and reparented to us */ 181 + dprintf("got reparentnotify\n"); 182 + 156 183 XReparentEvent *e = (XReparentEvent *) &event; 157 - 158 184 main_win.xterm = e->window; 159 185 160 - XMoveWindow(main_win.dpy, main_win.xterm, 0, 0); 186 + /* move completely off-screen */ 187 + XMoveWindow(main_win.dpy, main_win.xterm, 188 + -1, -1); 161 189 XResizeWindow(main_win.dpy, main_win.xterm, 162 - main_win.width, main_win.height); 190 + main_win.width, 191 + main_win.height - BORDER); 163 192 164 - scroll(DIR_DOWN); 193 + respawning = 0; 165 194 } 166 195 167 196 break; 197 + 198 + case UnmapNotify: 199 + /* xterm died, respawn it */ 200 + if (!respawning) 201 + xterm_handler(NULL); 202 + 203 + break; 204 + 168 205 case KeyRelease: 169 - scroll(-main_win.cur_direction); 206 + scroll(-(main_win.cur_direction), 0); 207 + break; 208 + 209 + case FocusOut: 210 + if (main_win.cur_direction == DIR_DOWN) 211 + XSetInputFocus(main_win.dpy, main_win.xterm, 212 + RevertToParent, CurrentTime); 170 213 171 214 break; 172 - default: 173 - printf("unknown event type 0x%x for win %d\n", 174 - event.type, event.xany.window); 175 215 } 176 216 } 177 217 ··· 187 227 188 228 if (!(main_win.dpy = XOpenDisplay(display))) 189 229 errx(1, "Unable to open display %s", XDisplayName(display)); 190 - /* NOTREACHED */ 191 230 192 - main_win.screen = DefaultScreen(main_win.dpy); 231 + XSetErrorHandler ((XErrorHandler) x_error_handler); 193 232 233 + main_win.screen = DefaultScreen(main_win.dpy); 194 234 main_win.width = main_win.dpy_width = DisplayWidth(main_win.dpy, 195 235 main_win.screen); 196 - 197 236 main_win.dpy_height = DisplayHeight(main_win.dpy, main_win.screen); 198 - 199 237 main_win.win = XCreateSimpleWindow(main_win.dpy, 200 238 RootWindow(main_win.dpy, main_win.screen), 201 239 0, -(main_win.height), ··· 206 244 207 245 if (!(rc = XStringListToTextProperty(&win_name, 1, &win_name_prop))) 208 246 errx(1, "XStringListToTextProperty"); 209 - /* NOTREACHED */ 210 247 211 248 XSetWMName(main_win.dpy, main_win.win, &win_name_prop); 212 249 213 250 /* remove all window manager decorations and force our position/size */ 214 - /* XXX: apparently this is not very nice */ 215 251 attributes.override_redirect = True; 216 252 XChangeWindowAttributes(main_win.dpy, main_win.win, 217 253 CWOverrideRedirect, &attributes); 218 254 219 - XMapWindow(main_win.dpy, main_win.win); 255 + XMapRaised(main_win.dpy, main_win.win); 220 256 221 257 XFlush(main_win.dpy); 222 258 XSync(main_win.dpy, False); 223 259 224 260 /* we need to know when the xterm gets reparented to us */ 225 - XSelectInput(main_win.dpy, main_win.win, SubstructureNotifyMask); 261 + XSelectInput(main_win.dpy, main_win.win, SubstructureNotifyMask | 262 + FocusChangeMask); 226 263 227 - /* bind to control+p */ 228 - XGrabKey(main_win.dpy, XKeysymToKeycode(main_win.dpy, XK_p), 264 + /* bind to control+o */ 265 + /* TODO: allow this key to be configurable */ 266 + XGrabKey(main_win.dpy, XKeysymToKeycode(main_win.dpy, XK_o), 229 267 ControlMask, DefaultRootWindow(main_win.dpy), False, 230 268 GrabModeAsync, GrabModeAsync); 231 269 } 232 270 233 271 void 234 - exit_handler(int sig) 272 + scroll(int direction, int quick) 235 273 { 236 - shutting_down = 1; 274 + int cur_x, cur_y, inc, dest; 275 + unsigned width, height, bw, depth; 276 + Window root; 237 277 238 - if (xterm_pid) 239 - kill(xterm_pid, SIGKILL); 278 + dprintf("scrolling %s %s\n", (direction == DIR_DOWN ? "down" : "up"), 279 + (quick ? "quickly" : "")); 240 280 241 - XCloseDisplay(main_win.dpy); 281 + if (direction == DIR_DOWN) { 282 + XSetInputFocus(main_win.dpy, main_win.xterm, RevertToParent, 283 + CurrentTime); 284 + dest = 0; 285 + } else { 286 + XSetInputFocus(main_win.dpy, PointerRoot, RevertToParent, 287 + CurrentTime); 288 + dest = -(main_win.height); 289 + } 290 + 291 + XGetGeometry(main_win.dpy, main_win.win, &root, 292 + &cur_x, &cur_y, &width, &height, &bw, &depth); 242 293 243 - exit(0); 294 + /* smoothly scroll to our destination */ 295 + while (!quick && cur_y != dest) { 296 + inc = (abs(dest - cur_y) / MAX_SPEED) / (MAX_SPEED + 1 - 297 + main_win.speed); 298 + 299 + if (inc < 1) 300 + inc = 1; 301 + 302 + if ((direction == DIR_DOWN && (cur_y + inc >= dest)) || 303 + (direction == DIR_UP && (cur_y - inc < dest))) 304 + break; 305 + 306 + cur_y -= (inc * direction); 307 + 308 + XMoveWindow(main_win.dpy, main_win.win, 0, cur_y); 309 + 310 + XFlush(main_win.dpy); 311 + XSync(main_win.dpy, False); 312 + } 313 + 314 + XMoveWindow(main_win.dpy, main_win.win, 0, dest); 315 + 316 + main_win.cur_direction = direction; 244 317 } 245 318 246 319 void ··· 248 321 { 249 322 pid_t pid; 250 323 251 - if (shutting_down) 324 + dprintf("in xterm_handler with sig %d\n", sig); 325 + 326 + if (shutting_down || respawning) { 327 + dprintf("returning from xterm_handler\n"); 252 328 return; 329 + } else if (sig) { 330 + dprintf("respawning\n"); 331 + respawning = 1; 332 + } 253 333 254 334 /* clean up if previous xterm died */ 255 335 if (xterm_pid) { 256 - int s; 257 - 258 - scroll(DIR_UP); 259 - XUnmapSubwindows(main_win.dpy, main_win.win); 260 - wait(&s); 336 + if (waitpid(-1, NULL, WNOHANG)) 337 + dprintf("wait returned something\n"); 338 + else 339 + dprintf("no wait\n"); 261 340 262 341 xterm_pid = 0; 342 + 343 + scroll(DIR_UP, 1); 344 + XUnmapSubwindows(main_win.dpy, main_win.win); 263 345 } 264 346 265 347 if (!xterm_pid) { 266 348 switch (pid = fork()) { 267 349 case -1: 268 - errx(1, "Unable to fork"); 350 + errx(1, "unable to fork"); 351 + 269 352 case 0: 270 353 /* fork xterm and pass our window id to -into opt */ 271 - asprintf(&xterm_args[4], "%d", main_win.win); 354 + dprintf("running xterm\n"); 355 + asprintf(&xterm_args[4], "%d", (int)main_win.win); 272 356 execvp("xterm", xterm_args); 273 357 exit(0); 274 358 ··· 279 363 } 280 364 281 365 void 282 - scroll(int direction) 366 + exit_handler(int sig) 283 367 { 284 - int cur_x, cur_y, inc, dest; 285 - unsigned width, height, bw, depth; 286 - Window root; 287 - 288 - if (direction == DIR_DOWN) { 289 - XSetInputFocus(main_win.dpy, main_win.xterm, RevertToParent, 290 - CurrentTime); 291 - dest = 0; 292 - } else 293 - dest = -(main_win.height); 294 - 295 - XGetGeometry(main_win.dpy, main_win.win, &root, 296 - &cur_x, &cur_y, &width, &height, &bw, &depth); 297 - 298 - printf("scrolling from %d to %d\n", cur_y, dest); 299 - 300 - while (cur_y != dest) { 301 - inc = (abs(dest - cur_y) / MAX_SPEED) / (MAX_SPEED + 1 - 302 - main_win.speed); 303 - 304 - if (inc < 1) 305 - inc = 1; 306 - 307 - if ((direction == DIR_DOWN && (cur_y + inc >= dest)) || 308 - (direction == DIR_UP && (cur_y - inc < dest))) 309 - break; 310 - 311 - printf(" moving %d\n", inc); 368 + shutting_down = 1; 312 369 313 - cur_y -= (inc * direction); 314 - 315 - XMoveWindow(main_win.dpy, main_win.win, 0, cur_y); 370 + if (xterm_pid) 371 + kill(xterm_pid, SIGKILL); 316 372 317 - XFlush(main_win.dpy); 318 - XSync(main_win.dpy, False); 319 - } 373 + XCloseDisplay(main_win.dpy); 320 374 321 - XMoveWindow(main_win.dpy, main_win.win, 0, dest); 375 + exit(0); 376 + } 322 377 323 - main_win.cur_direction = direction; 378 + void 379 + x_error_handler(Display * d, XErrorEvent * e) 380 + { 381 + if (e->error_code == BadAccess && e->request_code == X_GrabKey) 382 + errx(1, "could not bind key. possibly another application " 383 + "bound to it?\n"); 324 384 } 325 385 326 386 void