X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fphosphor.c;h=c01f5a5a17b7e37aaac8b749483f1c49720ef078;hb=3f438031d610c7e15fd33876a879b97e290e05fb;hp=4aced864ab85865c7964a5c858d9e8d724030886;hpb=278c59e14c53fd412b734e699bd4f314f766f804;p=xscreensaver diff --git a/hacks/phosphor.c b/hacks/phosphor.c index 4aced864..c01f5a5a 100644 --- a/hacks/phosphor.c +++ b/hacks/phosphor.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1999 Jamie Zawinski +/* xscreensaver, Copyright (c) 1999-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 @@ -9,14 +9,33 @@ * implied warranty. * * Phosphor -- simulate a glass tty with long-sustain phosphor. + * Written by Jamie Zawinski + * Pty and vt100 emulation by Fredrik Tolf */ #include "screenhack.h" + #include +#include +#include + #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 */ + extern XtAppContext app; #define FUZZY_BORDER @@ -28,9 +47,12 @@ extern XtAppContext app; #define FLARE 1 #define NORMAL 2 #define FADE 3 +#define STATE_MAX FADE #define CURSOR_INDEX 128 +#define NPAR 16 + typedef struct { unsigned char name; int width, height; @@ -54,8 +76,14 @@ typedef struct { XFontStruct *font; int grid_width, grid_height; int char_width, char_height; + int saved_x, saved_y; int scale; int ticks; + int mode; + pid_t pid; + int escstate; + int csiparam[NPAR]; + int curparam; p_char **chars; p_cell *cells; XGCValues gcv; @@ -75,6 +103,9 @@ typedef struct { XtInputId pipe_id; Bool input_available_p; Time subproc_relaunch_delay; + XComposeStatus compose; + Bool meta_sends_esc_p; + Bool swap_bs_del_p; } p_state; @@ -128,6 +159,10 @@ init_phosphor (Display *dpy, Window window) state->window = window; XGetWindowAttributes (dpy, window, &state->xgwa); + XSelectInput (dpy, window, state->xgwa.your_event_mask | ExposureMask); + + state->meta_sends_esc_p = get_boolean_resource ("metaSendsESC", "Boolean"); + state->swap_bs_del_p = get_boolean_resource ("swapBSDEL", "Boolean"); state->font = XLoadQueryFont (dpy, fontname); @@ -144,7 +179,26 @@ init_phosphor (Display *dpy, Window window) font = state->font; state->scale = get_integer_resource ("scale", "Integer"); - state->ticks = 3 + get_integer_resource ("ticks", "Integer"); + state->ticks = STATE_MAX + get_integer_resource ("ticks", "Integer"); + state->escstate = 0; + + { + char *s = get_string_resource ("mode", "Integer"); + state->mode = 0; + if (!s || !*s || !strcasecmp (s, "pipe")) + state->mode = 0; + else if (!strcasecmp (s, "pty")) + state->mode = 1; + else + fprintf (stderr, "%s: mode must be either `pipe' or `pty', not `%s'\n", + progname, s); + +#ifndef HAVE_FORKPTY + fprintf (stderr, "%s: no pty support on this system; using -pipe mode.\n", + progname); + state->mode = 0; +#endif /* HAVE_FORKPTY */ + } #if 0 for (i = 0; i < font->n_properties; i++) @@ -199,6 +253,9 @@ init_phosphor (Display *dpy, Window window) colors, &ncolors, False, True, False); + /* Adjust to the number of colors we actually got. */ + state->ticks = ncolors + STATE_MAX; + /* Now, GCs all around. */ state->gcv.font = font->fid; @@ -233,8 +290,8 @@ init_phosphor (Display *dpy, Window window) for (i = 0; i < ncolors; i++) { state->gcv.foreground = colors[i].pixel; - state->gcs[FADE + i] = XCreateGC (state->dpy, state->window, - flags, &state->gcv); + state->gcs[STATE_MAX + i] = XCreateGC (state->dpy, state->window, + flags, &state->gcv); } } @@ -246,6 +303,48 @@ init_phosphor (Display *dpy, Window window) } +/* Re-query the window size and update the internal character grid if changed. + */ +static void +resize_grid (p_state *state) +{ + int ow = state->grid_width; + int oh = state->grid_height; + p_cell *ocells = state->cells; + int x, y; + + XGetWindowAttributes (state->dpy, state->window, &state->xgwa); + + state->grid_width = state->xgwa.width /(state->char_width * state->scale); + state->grid_height = state->xgwa.height /(state->char_height * state->scale); + + if (ow == state->grid_width && + oh == state->grid_height) + return; + + state->cells = (p_cell *) calloc (sizeof(p_cell), + state->grid_width * state->grid_height); + + for (y = 0; y < state->grid_height; y++) + { + for (x = 0; x < state->grid_width; x++) + { + p_cell *ncell = &state->cells [state->grid_width * y + x]; + if (x < ow && y < oh) + *ncell = ocells [ow * y + x]; + ncell->changed = True; + } + } + + if (state->cursor_x >= state->grid_width) + state->cursor_x = state->grid_width-1; + if (state->cursor_y >= state->grid_height) + state->cursor_y = state->grid_height-1; + + free (ocells); +} + + static void capture_font_bits (p_state *state) { @@ -296,7 +395,7 @@ capture_font_bits (p_state *state) continue; XDrawString (state->dpy, p, state->gc1, i * safe_width, font->ascent, - string + i, 1); + (char *) (string + i), 1); } /* Draw the cursor. */ @@ -446,7 +545,6 @@ static void set_cursor (p_state *state, Bool on) { if (set_cursor_1 (state, on)) -; { if (state->cursor_timer) XtRemoveTimeOut (state->cursor_timer); @@ -525,9 +623,10 @@ static void scroll (p_state *state) { int x, y; + for (x = 0; x < state->grid_width; x++) { - p_cell *from, *to; + p_cell *from = 0, *to = 0; for (y = 1; y < state->grid_height; y++) { from = &state->cells[state->grid_width * y + x]; @@ -549,7 +648,7 @@ scroll (p_state *state) } to = from; - if (to->state == FLARE || to->state == NORMAL) + if (to && (to->state == FLARE || to->state == NORMAL)) { to->state = FADE; to->changed = True; @@ -562,8 +661,12 @@ scroll (p_state *state) static void print_char (p_state *state, int c) { + static char last_c = 0; + static int bk; + p_cell *cell = &state->cells[state->grid_width * state->cursor_y - + state->cursor_x]; + + state->cursor_x]; + int i, start, end; /* Start the cursor fading (in case we don't end up overwriting it.) */ if (cell->state == FLARE || cell->state == NORMAL) @@ -571,41 +674,388 @@ print_char (p_state *state, int c) cell->state = FADE; cell->changed = True; } - - if (c == '\t') c = ' '; /* blah. */ - - if (c == '\r' || c == '\n') - { - state->cursor_x = 0; - if (state->cursor_y == state->grid_height - 1) - scroll (state); - else - state->cursor_y++; - } - else if (c == '\014') + + if (state->pid) /* Only interpret VT100 sequences if running in pty-mode. + It would be nice if we could just interpret them all + the time, but that would require subprocesses to send + CRLF line endings instead of bare LF, so that's no good. + */ { - clear (state); + 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 < state->grid_width - 8) + { + state->cursor_x = (state->cursor_x & ~7) + 8; + } + else + { + state->cursor_x = 0; + if (state->cursor_y < state->grid_height - 1) + state->cursor_y++; + else + scroll (state); + } + break; + case 10: /* LF */ + case 11: /* VT */ + case 12: /* FF */ + if(last_c == 13) + { + cell->state = NORMAL; + cell->p_char = state->chars[bk]; + cell->changed = True; + } + if (state->cursor_y < state->grid_height - 1) + state->cursor_y++; + else + scroll (state); + break; + case 13: /* CR */ + state->cursor_x = 0; + cell = &state->cells[state->grid_width * state->cursor_y]; + if((cell->p_char == NULL) || (cell->p_char->name == CURSOR_INDEX)) + bk = ' '; + else + bk = cell->p_char->name; + break; + case 14: /* SO */ + case 15: /* SI */ + /* Dummy case - I don't want to load several fonts for + the maybe two programs world-wide that use that */ + 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: + cell->state = FLARE; + cell->p_char = state->chars[c]; + cell->changed = True; + state->cursor_x++; + + if (c != ' ' && cell->p_char->blank_p) + cell->p_char = state->chars[CURSOR_INDEX]; + + if (state->cursor_x >= state->grid_width - 1) + { + state->cursor_x = 0; + if (state->cursor_y >= state->grid_height - 1) + scroll (state); + else + state->cursor_y++; + } + break; + } + break; + case 1: + switch (c) + { + case 24: /* CAN */ + case 26: /* SUB */ + state->escstate = 0; + break; + case 'c': /* Reset */ + clear (state); + state->escstate = 0; + break; + case 'D': /* Linefeed */ + if (state->cursor_y < state->grid_height - 1) + state->cursor_y++; + else + scroll (state); + 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 phosphor 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 > state->grid_width) + { + state->cursor_x = 0; + if (state->cursor_y < state->grid_height - 1) + state->cursor_y++; + else + scroll (state); + } + cell = &state->cells[state->grid_width * state->cursor_y + state->cursor_x]; + if (cell->state == FLARE || cell->state == NORMAL) + { + cell->state = FADE; + cell->changed = True; + } + } + 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]) >= state->grid_height - 1) + state->cursor_y = state->grid_height - 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]) >= state->grid_width - 1) + state->cursor_x = state->grid_width - 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)) >= state->grid_height - 1) + state->cursor_y = state->grid_height - 1; + state->escstate = 0; + break; + case '`': + case 'G': + if ((state->cursor_x = (state->csiparam[0] - 1)) >= state->grid_width - 1) + state->cursor_x = state->grid_width - 1; + state->escstate = 0; + break; + case 'f': + case 'H': + if ((state->cursor_y = (state->csiparam[0] - 1)) >= state->grid_height - 1) + state->cursor_y = state->grid_height - 1; + if ((state->cursor_x = (state->csiparam[1] - 1)) >= state->grid_width - 1) + state->cursor_x = state->grid_width - 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 = state->grid_height * state->grid_width; + if (state->csiparam[0] == 0) + start = state->grid_width * state->cursor_y + state->cursor_x; + if (state->csiparam[0] == 1) + end = state->grid_width * state->cursor_y + state->cursor_x; + for (i = start; i < end; i++) + { + cell = &state->cells[i]; + if (cell->state == FLARE || cell->state == NORMAL) + { + cell->state = FADE; + cell->changed = True; + } + } + set_cursor (state, True); + state->escstate = 0; + break; + case 'K': + start = 0; + end = state->grid_width; + if (state->csiparam[0] == 0) + start = state->cursor_x; + if (state->csiparam[1] == 1) + end = state->cursor_x; + for (i = start; i < end; i++) + { + if (cell->state == FLARE || cell->state == NORMAL) + { + cell->state = FADE; + cell->changed = True; + } + cell++; + } + 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; + } + set_cursor (state, True); } else { - cell->state = FLARE; - cell->p_char = state->chars[c]; - cell->changed = True; - state->cursor_x++; - - if (c != ' ' && cell->p_char->blank_p) - cell->p_char = state->chars[CURSOR_INDEX]; - - if (state->cursor_x >= state->grid_width - 1) - { - state->cursor_x = 0; - if (state->cursor_y >= state->grid_height - 1) - scroll (state); - else - state->cursor_y++; - } + if (c == '\t') c = ' '; /* blah. */ + + if (c == '\r' || c == '\n') /* handle CR, LF, or CRLF as "new line". */ + { + if (c == '\n' && last_c == '\r') + ; /* CRLF -- do nothing */ + else + { + state->cursor_x = 0; + if (state->cursor_y == state->grid_height - 1) + scroll (state); + else + state->cursor_y++; + } + } + else if (c == '\014') + { + clear (state); + } + else + { + cell->state = FLARE; + cell->p_char = state->chars[c]; + cell->changed = True; + state->cursor_x++; + + if (c != ' ' && cell->p_char->blank_p) + cell->p_char = state->chars[CURSOR_INDEX]; + + if (state->cursor_x >= state->grid_width - 1) + { + state->cursor_x = 0; + if (state->cursor_y >= state->grid_height - 1) + scroll (state); + else + state->cursor_y++; + } + } + set_cursor (state, True); } - set_cursor (state, True); + + last_c = c; } @@ -640,9 +1090,10 @@ update_display (p_state *state, Bool changed_only) GC gc2 = ((cell->state + 2) < state->ticks ? state->gcs[cell->state + 2] : 0); - XCopyPlane (state->dpy, cell->p_char->pixmap, state->window, - (gc2 ? gc2 : gc1), - 0, 0, width, height, tx, ty, 1L); + GC gc3 = (gc2 ? gc2 : gc1); + if (gc3) + XCopyPlane (state->dpy, cell->p_char->pixmap, state->window, gc3, + 0, 0, width, height, tx, ty, 1L); if (gc2) { XSetClipMask (state->dpy, gc1, cell->p_char->pixmap2); @@ -689,24 +1140,82 @@ subproc_cb (XtPointer closure, int *source, XtInputId *id) static void launch_text_generator (p_state *state) { + char buf[255]; char *oprogram = get_string_resource ("program", "Program"); - char *program = (char *) malloc (strlen (oprogram) + 10); + char *program = (char *) malloc (strlen (oprogram) + 50); + /* oprogram contains a "%d" where the current number of columns goes + */ strcpy (program, "( "); - strcat (program, oprogram); + sprintf (program + strlen(program), oprogram, state->grid_width-1); strcat (program, " ) 2>&1"); - if ((state->pipe = popen (program, "r"))) +#ifdef HAVE_FORKPTY + if(state->mode == 1) { - state->pipe_id = - XtAppAddInput (app, fileno (state->pipe), - (XtPointer) (XtInputReadMask | XtInputExceptMask), - subproc_cb, (XtPointer) state); + int fd; + struct winsize ws; + + ws.ws_row = state->grid_height - 1; + ws.ws_col = state->grid_width - 2; + ws.ws_xpixel = state->xgwa.width; + ws.ws_ypixel = state->xgwa.height; + + state->pipe = NULL; + if((state->pid = forkpty(&fd, NULL, NULL, &ws)) < 0) + { + /* Unable to fork */ + sprintf (buf, "%.100s: forkpty", progname); + perror(buf); + } + else if(!state->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++] = program; + av[i] = 0; + execvp (av[0], av); + sprintf (buf, "%.100s: %.100s", progname, oprogram); + perror(buf); + exit(1); + } + else + { + /* This is the parent fork. */ + state->pipe = fdopen(fd, "r+"); + state->pipe_id = + XtAppAddInput (app, fileno (state->pipe), + (XtPointer) (XtInputReadMask | XtInputExceptMask), + subproc_cb, (XtPointer) state); + } } else +#endif /* HAVE_FORKPTY */ { - perror (program); + /* don't mess up controlling terminal if someone dumbly does + "-pipe -program tcsh". */ + fclose (stdin); + + if ((state->pipe = popen (program, "r"))) + { + state->pipe_id = + XtAppAddInput (app, fileno (state->pipe), + (XtPointer) (XtInputReadMask | XtInputExceptMask), + subproc_cb, (XtPointer) state); + } + else + { + sprintf (buf, "%.100s: %.100s", progname, program); + perror (buf); + } } + + free (program); } @@ -723,7 +1232,7 @@ drain_input (p_state *state) { if (state->input_available_p) { - char s[2]; + unsigned char s[2]; int n = read (fileno (state->pipe), (void *) s, 1); if (n == 1) { @@ -733,7 +1242,15 @@ drain_input (p_state *state) { XtRemoveInput (state->pipe_id); state->pipe_id = 0; - pclose (state->pipe); + if (state->pid) + { + waitpid(state->pid, NULL, 0); + fclose (state->pipe); + } + else + { + pclose (state->pipe); + } state->pipe = 0; if (state->cursor_x != 0) /* break line if unbroken */ @@ -751,6 +1268,120 @@ drain_input (p_state *state) } +/* 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 void +handle_events (p_state *state) +{ + XSync (state->dpy, False); + while (XPending (state->dpy)) + { + XEvent event; + XNextEvent (state->dpy, &event); + + if (event.xany.type == ConfigureNotify) + { + resize_grid (state); + +# if defined(HAVE_FORKPTY) && defined(TIOCSWINSZ) + if (state->pid) + { + /* Tell the sub-process that the screen size has changed. */ + struct winsize ws; + ws.ws_row = state->grid_height - 1; + ws.ws_col = state->grid_width - 2; + ws.ws_xpixel = state->xgwa.width; + ws.ws_ypixel = state->xgwa.height; + ioctl (fileno (state->pipe), TIOCSWINSZ, &ws); + kill (state->pid, SIGWINCH); + } +# endif /* HAVE_FORKPTY && TIOCSWINSZ */ + } + else if (event.xany.type == Expose) + { + update_display (state, False); + } + else if (event.xany.type == KeyPress) + { + KeySym keysym; + unsigned char c = 0; + XLookupString (&event.xkey, (char *) &c, 1, &keysym, + &state->compose); + if (c != 0 && state->pipe) + { + if (!state->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 (state->dpy)) + { + if (state->meta_sends_esc_p) + fputc ('\033', state->pipe); + else + c |= 0x80; + } + + fputc (c, state->pipe); + fflush (state->pipe); + event.xany.type = 0; /* don't interpret this event defaultly. */ + } + } + + screenhack_handle_event (state->dpy, &event); + } + + if (XtAppPending (app) & (XtIMTimer|XtIMAlternateInput)) + XtAppProcessEvent (app, XtIMTimer|XtIMAlternateInput); +} + + char *progclass = "Phosphor"; @@ -764,8 +1395,15 @@ char *defaults [] = { "*ticks: 20", "*delay: 50000", "*cursor: 333", - "*program: " ZIPPY_PROGRAM, + "*program: xscreensaver-text --cols %d", "*relaunch: 5", + "*metaSendsESC: True", + "*swapBSDEL: True", +#ifdef HAVE_FORKPTY + "*mode: pty", +#else /* !HAVE_FORKPTY */ + "*mode: pipe", +#endif /* !HAVE_FORKPTY */ 0 }; @@ -775,6 +1413,12 @@ XrmOptionDescRec options [] = { { "-ticks", ".ticks", XrmoptionSepArg, 0 }, { "-delay", ".delay", XrmoptionSepArg, 0 }, { "-program", ".program", XrmoptionSepArg, 0 }, + { "-pty", ".mode", XrmoptionNoArg, "pty" }, + { "-pipe", ".mode", XrmoptionNoArg, "pipe" }, + { "-meta", ".metaSendsESC", XrmoptionNoArg, "False" }, + { "-esc", ".metaSendsESC", XrmoptionNoArg, "True" }, + { "-bs", ".swapBSDEL", XrmoptionNoArg, "False" }, + { "-del", ".swapBSDEL", XrmoptionNoArg, "True" }, { 0, 0, 0, 0 } }; @@ -791,11 +1435,7 @@ screenhack (Display *dpy, Window window) { run_phosphor (state); XSync (dpy, False); - screenhack_handle_events (dpy); - - if (XtAppPending (app) & (XtIMTimer|XtIMAlternateInput)) - XtAppProcessEvent (app, XtIMTimer|XtIMAlternateInput); - + handle_events (state); if (delay) usleep (delay); } }