X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fapple2-main.c;h=3beeeeea62142ea7b9db5f59b755e494540999d6;hb=0d6b320def9180cf907ceaed56b23a972a11b757;hp=ae38787f9856b0912b7b7e6b347595e9dd215333;hpb=96a411663168b0ba5432b407a83be55f3df0c802;p=xscreensaver diff --git a/hacks/apple2-main.c b/hacks/apple2-main.c index ae38787f..3beeeeea 100644 --- a/hacks/apple2-main.c +++ b/hacks/apple2-main.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1998-2003 Jamie Zawinski +/* xscreensaver, Copyright (c) 1998-2005 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -10,18 +10,35 @@ * * Apple ][ CRT simulator, by Trevor Blackwell * with additional work by Jamie Zawinski + * Pty and vt100 emulation by Fredrik Tolf */ #include +#include #include "screenhack.h" #include "apple2.h" #include #include -#include + +#define XK_MISCELLANY +#include + +#ifdef HAVE_FORKPTY +# include +# ifdef HAVE_PTY_H +# include +# endif +# ifdef HAVE_UTIL_H +# include +# endif +#endif /* HAVE_FORKPTY */ #undef countof #define countof(x) (sizeof((x))/sizeof((*x))) +#define SCREEN_COLS 40 +#define SCREEN_ROWS 24 + #define DEBUG extern XtAppContext app; @@ -523,7 +540,7 @@ load_image (Display *dpy, Window window, char **image_filename_r) XGetWindowAttributes (dpy, window, &xgwa); p = XCreatePixmap (dpy, window, xgwa.width, xgwa.height, xgwa.depth); - load_random_image (xgwa.screen, window, p, image_filename_r); + load_random_image (xgwa.screen, window, p, image_filename_r, NULL); image = XGetImage (dpy, p, 0, 0, xgwa.width, xgwa.height, ~0, ZPixmap); XFreePixmap (dpy, p); p = 0; @@ -552,18 +569,37 @@ load_image (Display *dpy, Window window, char **image_filename_r) char *progclass = "Apple2"; char *defaults [] = { + ".background: black", + ".foreground: white", "*mode: random", "*duration: 20", + "*program: xscreensaver-text --cols 40", + "*metaSendsESC: True", + "*swapBSDEL: True", + "*fast: False", +# ifdef HAVE_FORKPTY + "*usePty: True", +#else + "*usePty: False", +# endif /* !HAVE_FORKPTY */ + ANALOGTV_DEFAULTS 0 }; XrmOptionDescRec options [] = { - { "-slideshow", ".mode", XrmoptionNoArg, "slideshow" }, - { "-basic", ".mode", XrmoptionNoArg, "basic" }, - { "-text", ".mode", XrmoptionNoArg, "text" }, + { "-slideshow", ".mode", XrmoptionNoArg, "slideshow" }, + { "-basic", ".mode", XrmoptionNoArg, "basic" }, + { "-text", ".mode", XrmoptionNoArg, "text" }, { "-program", ".program", XrmoptionSepArg, 0 }, { "-duration", ".duration", XrmoptionSepArg, 0 }, + { "-pty", ".usePty", XrmoptionNoArg, "True" }, + { "-pipe", ".usePty", XrmoptionNoArg, "False" }, + { "-meta", ".metaSendsESC", XrmoptionNoArg, "False" }, + { "-esc", ".metaSendsESC", XrmoptionNoArg, "True" }, + { "-bs", ".swapBSDEL", XrmoptionNoArg, "False" }, + { "-del", ".swapBSDEL", XrmoptionNoArg, "True" }, + { "-fast", ".fast", XrmoptionNoArg, "True" }, ANALOGTV_OPTIONS { 0, 0, 0, 0 } }; @@ -644,7 +680,10 @@ void slideshow_controller(apple2_sim_t *sim, int *stepno, if (dot) *dot=0; } if (strlen(basename)>20) basename[20]=0; - for (s=basename; *s; s++) *s = toupper (*s); + for (s=basename; *s; s++) { + *s = toupper (*s); + if (*s <= ' ') *s = '_'; + } sprintf(sim->typing_buf, "BLOAD %s\n", basename); sim->typing = sim->typing_buf; @@ -719,15 +758,37 @@ void slideshow_controller(apple2_sim_t *sim, int *stepno, } } +#define NPAR 16 + struct terminal_controller_data { FILE *pipe; int pipe_id; + pid_t pid; int input_available_p; XtIntervalId timeout_id; char curword[256]; unsigned char lastc; int fake_nl; double last_emit_time; + XComposeStatus compose; + + int escstate; + int csiparam[NPAR]; + int curparam; + int cursor_x, cursor_y; + int saved_x, saved_y; + union { + struct { + unsigned int bold : 1; + unsigned int blink : 1; + unsigned int rev : 1; + } bf; + int w; + } termattrib; + Bool meta_sends_esc_p; + Bool swap_bs_del_p; + Bool fast_p; + }; static void @@ -741,19 +802,63 @@ subproc_cb (XtPointer closure, int *source, XtInputId *id) static void launch_text_generator (struct terminal_controller_data *mine) { + char buf[255]; char *oprogram = get_string_resource ("program", "Program"); - char *program; - - if (!oprogram || !*oprogram) - oprogram = FORTUNE_PROGRAM; - - program = (char *) malloc (strlen (oprogram) + 10); + char *program = (char *) malloc (strlen (oprogram) + 10); strcpy (program, "( "); strcat (program, oprogram); strcat (program, " ) 2>&1"); if (mine->pipe) abort(); + +# ifdef HAVE_FORKPTY + if (get_boolean_resource ("usePty", "Boolean")) + { + int fd; + struct winsize ws; + + ws.ws_col = SCREEN_COLS; + ws.ws_row = SCREEN_ROWS; + ws.ws_xpixel = ws.ws_col * 6; + ws.ws_ypixel = ws.ws_row * 8; + + mine->pipe = NULL; + if((mine->pid = forkpty(&fd, NULL, NULL, &ws)) < 0) + { + /* Unable to fork */ + sprintf (buf, "%.100s: forkpty", progname); + perror(buf); + } + else if(!mine->pid) + { + /* This is the child fork. */ + char *av[10]; + int i = 0; + if (putenv("TERM=vt100")) + abort(); + av[i++] = "/bin/sh"; + av[i++] = "-c"; + av[i++] = oprogram; + av[i] = 0; + execvp (av[0], av); + sprintf (buf, "%.100s: %.100s", progname, oprogram); + perror(buf); + exit(1); + } + else + { + /* This is the parent fork. */ + mine->pipe = fdopen(fd, "r+"); + mine->pipe_id = + XtAppAddInput (app, fileno (mine->pipe), + (XtPointer) (XtInputReadMask | XtInputExceptMask), + subproc_cb, (XtPointer) mine); + } + } + else +# endif /* HAVE_FORKPTY */ + if ((mine->pipe = popen (program, "r"))) { if (mine->pipe_id) abort(); @@ -764,7 +869,8 @@ launch_text_generator (struct terminal_controller_data *mine) } else { - perror (program); + sprintf (buf, "%.100s: %.100s", progname, program); + perror(buf); } } @@ -830,6 +936,480 @@ terminal_read(struct terminal_controller_data *mine, unsigned char *buf, int n) } +/* The interpretation of the ModN modifiers is dependent on what keys + are bound to them: Mod1 does not necessarily mean "meta". It only + means "meta" if Meta_L or Meta_R are bound to it. If Meta_L is on + Mod5, then Mod5 is the one that means Meta. Oh, and Meta and Alt + aren't necessarily the same thing. Icepicks in my forehead! + */ +static unsigned int +do_icccm_meta_key_stupidity (Display *dpy) +{ + unsigned int modbits = 0; + int i, j, k; + XModifierKeymap *modmap = XGetModifierMapping (dpy); + for (i = 3; i < 8; i++) + for (j = 0; j < modmap->max_keypermod; j++) + { + int code = modmap->modifiermap[i * modmap->max_keypermod + j]; + KeySym *syms; + int nsyms = 0; + if (code == 0) continue; + syms = XGetKeyboardMapping (dpy, code, 1, &nsyms); + for (k = 0; k < nsyms; k++) + if (syms[k] == XK_Meta_L || syms[k] == XK_Meta_R || + syms[k] == XK_Alt_L || syms[k] == XK_Alt_R) + modbits |= (1 << i); + XFree (syms); + } + XFreeModifiermap (modmap); + return modbits; +} + +/* Returns a mask of the bit or bits of a KeyPress event that mean "meta". + */ +static unsigned int +meta_modifier (Display *dpy) +{ + static Bool done_once = False; + static unsigned int mask = 0; + if (!done_once) + { + /* Really, we are supposed to recompute this if a KeymapNotify + event comes in, but fuck it. */ + done_once = True; + mask = do_icccm_meta_key_stupidity (dpy); + } + return mask; +} + + +static int +terminal_keypress_handler (Display *dpy, XEvent *event, void *data) +{ + struct terminal_controller_data *mine = + (struct terminal_controller_data *) data; + KeySym keysym; + unsigned char c = 0; + XLookupString (&event->xkey, (char *) &c, 1, &keysym, &mine->compose); + if (c == 0 || !mine->pipe) + return 0; + + if (!mine->swap_bs_del_p) ; + else if (c == 127) c = 8; + else if (c == 8) c = 127; + + /* If meta was held down, send ESC, or turn on the high bit. */ + if (event->xkey.state & meta_modifier (dpy)) + { + if (mine->meta_sends_esc_p) + fputc ('\033', mine->pipe); + else + c |= 0x80; + } + + fputc (c, mine->pipe); + fflush (mine->pipe); + + event->xany.type = 0; /* do not process this event further */ + + return 0; +} + + +static void +a2_ascii_printc (apple2_state_t *st, unsigned char c, + Bool bold_p, Bool blink_p, Bool rev_p, + Bool scroll_p) +{ + if (c >= 'a' && c <= 'z') /* upcase lower-case chars */ + { + c &= 0xDF; + } + else if ((c >= 'A'+128) || /* upcase and blink */ + (c < ' ' && c != 014 && /* high-bit & ctl chrs */ + c != '\r' && c != '\n' && c!='\t')) + { + c = (c & 0x1F) | 0x80; + } + else if (c >= 'A' && c <= 'Z') /* invert upper-case chars */ + { + c |= 0x80; + } + + if (bold_p) c |= 0xc0; + if (blink_p) c = (c & ~0x40) | 0x80; + if (rev_p) c |= 0xc0; + + if (scroll_p) + a2_printc(st, c); + else + a2_printc_noscroll(st, c); +} + + +static void +a2_vt100_printc (apple2_sim_t *sim, struct terminal_controller_data *state, + unsigned char c) +{ + apple2_state_t *st=sim->st; + int cols = SCREEN_COLS; + int rows = SCREEN_ROWS; + + int i; + int start, end; + + switch (state->escstate) + { + case 0: + switch (c) + { + case 7: /* BEL */ + /* Dummy case - we don't want the screensaver to beep */ + /* #### But maybe this should flash the screen? */ + break; + case 8: /* BS */ + if (state->cursor_x > 0) + state->cursor_x--; + break; + case 9: /* HT */ + if (state->cursor_x < cols - 8) + { + state->cursor_x = (state->cursor_x & ~7) + 8; + } + else + { + state->cursor_x = 0; + if (state->cursor_y < rows - 1) + state->cursor_y++; + else + a2_scroll (st); + } + break; + case 10: /* LF */ + case 11: /* VT */ + case 12: /* FF */ + if (state->cursor_y < rows - 1) + state->cursor_y++; + else + a2_scroll (st); + break; + case 13: /* CR */ + state->cursor_x = 0; + break; + case 14: /* SO */ + case 15: /* SI */ + /* Dummy case - there is one and only one font. */ + break; + case 24: /* CAN */ + case 26: /* SUB */ + /* Dummy case - these interrupt escape sequences, so + they don't do anything in this state */ + break; + case 27: /* ESC */ + state->escstate = 1; + break; + case 127: /* DEL */ + /* Dummy case - this is supposed to be ignored */ + break; + case 155: /* CSI */ + state->escstate = 2; + for(i = 0; i < NPAR; i++) + state->csiparam[i] = 0; + state->curparam = 0; + break; + default: + /* If the cursor is in column 39 and we print a character, then + that character shows up in column 39, and the cursor is no longer + visible on the screen (it's in "column 40".) If another character + is printed, then that character shows up in column 0, and the + cursor moves to column 1. + + This is empirically what xterm and gnome-terminal do, so that must + be the right thing. (In xterm, the cursor vanishes, whereas; in + gnome-terminal, the cursor overprints the character in col 39.) + */ + if (state->cursor_x >= cols) + { + state->cursor_x = 0; + if (state->cursor_y >= rows - 1) + a2_scroll (st); + else + state->cursor_y++; + } + + a2_goto(st, state->cursor_y, state->cursor_x); /* clips range */ + a2_ascii_printc (st, c, + state->termattrib.bf.bold, + state->termattrib.bf.blink, + state->termattrib.bf.rev, + False); + state->cursor_x++; + + break; + } + break; + case 1: + switch (c) + { + case 24: /* CAN */ + case 26: /* SUB */ + state->escstate = 0; + break; + case 'c': /* Reset */ + a2_cls(st); + state->escstate = 0; + break; + case 'D': /* Linefeed */ + if (state->cursor_y < rows - 1) + state->cursor_y++; + else + a2_scroll (st); + state->escstate = 0; + break; + case 'E': /* Newline */ + state->cursor_x = 0; + state->escstate = 0; + break; + case 'M': /* Reverse newline */ + if (state->cursor_y > 0) + state->cursor_y--; + state->escstate = 0; + break; + case '7': /* Save state */ + state->saved_x = state->cursor_x; + state->saved_y = state->cursor_y; + state->escstate = 0; + break; + case '8': /* Restore state */ + state->cursor_x = state->saved_x; + state->cursor_y = state->saved_y; + state->escstate = 0; + break; + case '[': /* CSI */ + state->escstate = 2; + for(i = 0; i < NPAR; i++) + state->csiparam[i] = 0; + state->curparam = 0; + break; + case '%': /* Select charset */ + /* No, I don't support UTF-8, since the apple2 font + isn't even Unicode anyway. We must still catch the + last byte, though. */ + case '(': + case ')': + /* I don't support different fonts either - see above + for SO and SI */ + state->escstate = 3; + break; + default: + /* Escape sequences not supported: + * + * H - Set tab stop + * Z - Terminal identification + * > - Keypad change + * = - Other keypad change + * ] - OS command + */ + state->escstate = 0; + break; + } + break; + case 2: + switch (c) + { + case 24: /* CAN */ + case 26: /* SUB */ + state->escstate = 0; + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (state->curparam < NPAR) + state->csiparam[state->curparam] = + (state->csiparam[state->curparam] * 10) + (c - '0'); + break; + case ';': + state->csiparam[++state->curparam] = 0; + break; + case '[': + state->escstate = 3; + break; + case '@': + for (i = 0; i < state->csiparam[0]; i++) + { + if(++state->cursor_x > cols) + { + state->cursor_x = 0; + if (state->cursor_y < rows - 1) + state->cursor_y++; + else + a2_scroll (st); + } + } + state->escstate = 0; + break; + case 'F': + state->cursor_x = 0; + case 'A': + if (state->csiparam[0] == 0) + state->csiparam[0] = 1; + if ((state->cursor_y -= state->csiparam[0]) < 0) + state->cursor_y = 0; + state->escstate = 0; + break; + case 'E': + state->cursor_x = 0; + case 'e': + case 'B': + if (state->csiparam[0] == 0) + state->csiparam[0] = 1; + if ((state->cursor_y += state->csiparam[0]) >= rows) + state->cursor_y = rows - 1; + state->escstate = 0; + break; + case 'a': + case 'C': + if (state->csiparam[0] == 0) + state->csiparam[0] = 1; + if ((state->cursor_x += state->csiparam[0]) >= cols) + state->cursor_x = cols - 1; + state->escstate = 0; + break; + case 'D': + if (state->csiparam[0] == 0) + state->csiparam[0] = 1; + if ((state->cursor_x -= state->csiparam[0]) < 0) + state->cursor_x = 0; + state->escstate = 0; + break; + case 'd': + if ((state->cursor_y = (state->csiparam[0] - 1)) >= rows) + state->cursor_y = rows - 1; + state->escstate = 0; + break; + case '`': + case 'G': + if ((state->cursor_x = (state->csiparam[0] - 1)) >= cols) + state->cursor_x = cols - 1; + state->escstate = 0; + break; + case 'f': + case 'H': + if ((state->cursor_y = (state->csiparam[0] - 1)) >= rows) + state->cursor_y = rows - 1; + if ((state->cursor_x = (state->csiparam[1] - 1)) >= cols) + state->cursor_x = cols - 1; + if(state->cursor_y < 0) + state->cursor_y = 0; + if(state->cursor_x < 0) + state->cursor_x = 0; + state->escstate = 0; + break; + case 'J': + start = 0; + end = rows * cols; + if (state->csiparam[0] == 0) + start = cols * state->cursor_y + state->cursor_x; + if (state->csiparam[0] == 1) + end = cols * state->cursor_y + state->cursor_x; + + a2_goto(st, state->cursor_y, state->cursor_x); + for (i = start; i < end; i++) + { + a2_ascii_printc(st, ' ', False, False, False, False); + } + state->escstate = 0; + break; + case 'K': + start = 0; + end = cols; + if (state->csiparam[0] == 0) + start = state->cursor_x; + if (state->csiparam[1] == 1) + end = state->cursor_x; + + a2_goto(st, state->cursor_y, state->cursor_x); + for (i = start; i < end; i++) + { + a2_ascii_printc(st, ' ', False, False, False, False); + } + state->escstate = 0; + break; + case 'm': /* Set attributes */ + for (i = 0; i <= state->curparam; i++) + { + switch(state->csiparam[i]) + { + case 0: + state->termattrib.w = 0; + break; + case 1: + state->termattrib.bf.bold = 1; + break; + case 5: + state->termattrib.bf.blink = 1; + break; + case 7: + state->termattrib.bf.rev = 1; + break; + case 21: + case 22: + state->termattrib.bf.bold = 0; + break; + case 25: + state->termattrib.bf.blink = 0; + break; + case 27: + state->termattrib.bf.rev = 0; + break; + } + } + state->escstate = 0; + break; + case 's': /* Save position */ + state->saved_x = state->cursor_x; + state->saved_y = state->cursor_y; + state->escstate = 0; + break; + case 'u': /* Restore position */ + state->cursor_x = state->saved_x; + state->cursor_y = state->saved_y; + state->escstate = 0; + break; + case '?': /* DEC Private modes */ + if ((state->curparam != 0) || (state->csiparam[0] != 0)) + state->escstate = 0; + break; + default: + /* Known unsupported CSIs: + * + * L - Insert blank lines + * M - Delete lines (I don't know what this means...) + * P - Delete characters + * X - Erase characters (difference with P being...?) + * c - Terminal identification + * g - Clear tab stop(s) + * h - Set mode (Mainly due to its complexity and lack of good + docs) + * l - Clear mode + * m - Set mode (Phosphor is, per defenition, green on black) + * n - Status report + * q - Set keyboard LEDs + * r - Set scrolling region (too exhausting - noone uses this, + right?) + */ + state->escstate = 0; + break; + } + break; + case 3: + state->escstate = 0; + break; + } + a2_goto(st, state->cursor_y, state->cursor_x); +} + + /* It's fun to put things like "gdb" as the command. For one, it's amusing how the standard mumble (version, no warranty, it's @@ -848,6 +1428,13 @@ terminal_controller(apple2_sim_t *sim, int *stepno, double *next_actiontime) sim->controller_data=calloc(sizeof(struct terminal_controller_data),1); mine=(struct terminal_controller_data *) sim->controller_data; + mine->meta_sends_esc_p = get_boolean_resource ("metaSendsESC", "Boolean"); + mine->swap_bs_del_p = get_boolean_resource ("swapBSDEL", "Boolean"); + mine->fast_p = get_boolean_resource ("fast", "Boolean"); + + sim->dec->key_handler = terminal_keypress_handler; + sim->dec->key_data = mine; + switch(*stepno) { case 0: @@ -858,17 +1445,19 @@ terminal_controller(apple2_sim_t *sim, int *stepno, double *next_actiontime) a2_goto(st,0,16); a2_prints(st, "APPLE ]["); a2_goto(st,2,0); + mine->cursor_y = 2; if (! mine->pipe) launch_text_generator(mine); - *next_actiontime += 4.0; + if (! mine->fast_p) + *next_actiontime += 4.0; *stepno = 10; break; case 10: { - unsigned char buf[5]; + unsigned char buf[1024]; int nr,nwant; double elapsed; @@ -879,28 +1468,17 @@ terminal_controller(apple2_sim_t *sim, int *stepno, double *next_actiontime) if (nwant<1) nwant=1; if (nwant>4) nwant=4; + if (mine->fast_p) + nwant = sizeof(buf)-1; + nr=terminal_read(mine, buf, nwant); for (i=0; i= 'a' && c <= 'z') /* upcase lower-case chars */ - { - a2_printc(st, c&0xDF); - } - else if ((c >= 'A'+128) || /* upcase and blink */ - (c < ' ' && c != 014 && /* high-bit & ctl chrs */ - c != '\r' && c != '\n' && c!='\t')) - { - a2_printc(st, (c & 0x1F) | 0x80); - } - else if (c >= 'A' && c <= 'Z') /* invert upper-case chars */ - { - a2_printc(st, c | 0x80); - } - else { - a2_printc(st, c); - } + + if (mine->pid) + a2_vt100_printc (sim, mine, c); + else + a2_ascii_printc (st, c, False, False, False, True); } } break; @@ -929,17 +1507,17 @@ struct basic_controller_data { */ static char *moire_program[]={ "10 HGR2\n", - "20 FOR Y = 0 TO 191 STEP 2\n", + "20 FOR Y = 0 TO 190 STEP 2\n", "30 HCOLOR=4 : REM BLACK\n", - "40 HLINE 0,191-Y TO 279,Y\n", + "40 HPLOT 0,191-Y TO 279,Y\n", "60 HCOLOR=7 : REM WHITE\n", - "80 HLINE 0,190-Y TO 279,Y+1\n", + "80 HPLOT 0,190-Y TO 279,Y+1\n", "90 NEXT Y\n", - "100 FOR X = 0 TO 279 STEP 3\n", + "100 FOR X = 0 TO 278 STEP 3\n", "110 HCOLOR=4\n", - "120 HLINE 279-X,0 TO X,192\n", + "120 HPLOT 279-X,0 TO X,191\n", "140 HCOLOR=7\n", - "150 HLINE 278-X,0 TO X+1,192\n", + "150 HPLOT 278-X,0 TO X+1,191\n", "160 NEXT X\n", NULL }; @@ -949,9 +1527,9 @@ static char *sinewave_program[] = { "25 K=0\n", "30 FOR X = 0 TO 279\n", "32 HCOLOR= 0\n", - "35 HLINE X,0 TO X,159\n", + "35 HPLOT X,0 TO X,159\n", "38 HCOLOR= 3\n", - "40 Y = 80 + SIN(15*(X-K)/279)\n", + "40 Y = 80 + SIN(15*(X-K)/279) * 40\n", "50 HPLOT X,Y\n", "60 NEXT X\n", "70 K=K+4\n", @@ -973,13 +1551,13 @@ static char *random_lores_program[]={ "100 COLOR= RND(1)*16\n", "110 X=RND(1)*40\n", - "120 Y1=RND(1)*48\n", - "130 Y2=RND(1)*48\n", + "120 Y1=RND(1)*40\n", + "130 Y2=RND(1)*40\n", "140 FOR Y = Y1 TO Y2\n", "150 PLOT X,Y\n", "160 NEXT Y\n", - "210 Y=RND(1)*48\n", + "210 Y=RND(1)*40\n", "220 X1=RND(1)*40\n", "230 X2=RND(1)*40\n", "240 FOR X = X1 TO X2\n", @@ -1288,12 +1866,23 @@ screenhack (Display *dpy, Window window) int duration = get_integer_resource ("duration", "Integer"); char *s; void (*controller)(apple2_sim_t *sim, int *stepno, double *next_actiontime); + Bool random_p = False; + controller = 0; if (duration < 1) duration = 1; + if (!get_boolean_resource ("root", "Boolean")) + { + XWindowAttributes xgwa; + XGetWindowAttributes (dpy, window, &xgwa); + XSelectInput (dpy, window, + xgwa.your_event_mask | + KeyPressMask | ButtonPressMask | ExposureMask); + } + s = get_string_resource ("mode", "Mode"); if (!s || !*s || !strcasecmp(s, "random")) - controller = controllers[random() % (countof(controllers))]; + random_p = True; else if (!strcasecmp(s, "text")) controller = terminal_controller; else if (!strcasecmp(s, "slideshow")) @@ -1306,16 +1895,17 @@ screenhack (Display *dpy, Window window) progname, s); exit (1); } + if (s) free (s); - if (!get_boolean_resource ("root", "Boolean")) + if (controller == terminal_controller) + duration = 999999; /* this one runs "forever" */ + + while (1) { - XWindowAttributes xgwa; - XGetWindowAttributes (dpy, window, &xgwa); - XSelectInput (dpy, window, - xgwa.your_event_mask | - KeyPressMask | ButtonPressMask | ExposureMask); - } + if (random_p) + controller = controllers[random() % (countof(controllers))]; - apple2 (dpy, window, duration, controller); - XSync (dpy, False); + apple2 (dpy, window, duration, controller); + XSync (dpy, False); + } }