X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=hacks%2Fphosphor.c;h=b7ec540725121a6f030358500fb799e275f2e6ca;hp=233acb6f3d8398b9d3f074841df198f230344f75;hb=f8cf5ac7b2f53510f80a0eaf286a25298be17bfe;hpb=ec8d2b32b63649e6d32bdfb306eda062769af823 diff --git a/hacks/phosphor.c b/hacks/phosphor.c index 233acb6f..b7ec5407 100644 --- a/hacks/phosphor.c +++ b/hacks/phosphor.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1999-2011 Jamie Zawinski +/* xscreensaver, Copyright (c) 1999-2012 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 @@ -17,33 +17,12 @@ # include "config.h" #endif /* HAVE_CONFIG_H */ -#include -#include -#include - #ifndef HAVE_COCOA -# define XK_MISCELLANY -# include -# include # include #endif -#ifdef HAVE_UNISTD_H -# include -# include /* for O_RDWR */ -#endif - -#ifdef HAVE_FORKPTY -# include -# ifdef HAVE_PTY_H -# include -# endif -# ifdef HAVE_UTIL_H -# include -# endif -#endif /* HAVE_FORKPTY */ - #include "screenhack.h" +#include "textclient.h" #define FUZZY_BORDER @@ -94,7 +73,6 @@ typedef struct { int scale; int ticks; int mode; - pid_t pid; int escstate; int csiparam[NPAR]; int curparam; @@ -111,32 +89,21 @@ typedef struct { int cursor_x, cursor_y; XtIntervalId cursor_timer; - XtIntervalId pipe_timer; Time cursor_blink; - - FILE *pipe; - XtInputId pipe_id; - Bool input_available_p; - Time subproc_relaunch_delay; - XComposeStatus compose; - Bool meta_sends_esc_p; - Bool swap_bs_del_p; int delay; + Bool pty_p; + + text_data *tc; char last_c; int bk; - Bool meta_done_once; - unsigned int meta_mask; - } p_state; static void capture_font_bits (p_state *state); static p_char *make_character (p_state *state, int c); -static void drain_input (p_state *state); static void char_to_pixmap (p_state *state, p_char *pc, int c); -static void launch_text_generator (p_state *state); /* About font metrics: @@ -188,8 +155,7 @@ phosphor_init (Display *dpy, Window window) /* XSelectInput (dpy, window, state->xgwa.your_event_mask | ExposureMask);*/ state->delay = get_integer_resource (dpy, "delay", "Integer"); - state->meta_sends_esc_p = get_boolean_resource (dpy, "metaSendsESC", "Boolean"); - state->swap_bs_del_p = get_boolean_resource (dpy, "swapBSDEL", "Boolean"); + state->pty_p = get_boolean_resource (dpy, "usePty", "UsePty"); if (!strcasecmp (fontname, "builtin") || !strcasecmp (fontname, "(builtin)")) @@ -220,33 +186,8 @@ phosphor_init (Display *dpy, Window window) state->ticks = STATE_MAX + get_integer_resource (dpy, "ticks", "Integer"); state->escstate = 0; - { - char *s = get_string_resource (dpy, "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++) - if (font->properties[i].name == XA_FONT) - printf ("font: %s\n", XGetAtomName(dpy, font->properties[i].card32)); -#endif /* 0 */ state->cursor_blink = get_integer_resource (dpy, "cursor", "Time"); - state->subproc_relaunch_delay = - (1000 * get_integer_resource (dpy, "relaunch", "Time")); # ifdef BUILTIN_FONT if (! font) @@ -261,20 +202,6 @@ phosphor_init (Display *dpy, Window window) state->char_height = font->max_bounds.ascent + font->max_bounds.descent; } - state->program = get_string_resource (dpy, "program", "Program"); - - - /* Kludge for MacOS standalone mode: see OSX/SaverRunner.m. */ - { - const char *s = getenv ("XSCREENSAVER_STANDALONE"); - if (s && *s && strcmp(s, "0")) - { - state->mode = 1; - state->program = getenv ("SHELL"); - } - } - - state->grid_width = state->xgwa.width / (state->char_width * state->scale); state->grid_height = state->xgwa.height /(state->char_height * state->scale); state->cells = (p_cell *) calloc (sizeof(p_cell), @@ -361,9 +288,15 @@ phosphor_init (Display *dpy, Window window) set_cursor (state, True); - launch_text_generator (state); /* clear (state);*/ + state->tc = textclient_open (dpy); + textclient_reshape (state->tc, + state->xgwa.width, + state->xgwa.height, + state->grid_width - 1, + state->grid_height - 1); + return state; } @@ -659,8 +592,6 @@ set_cursor (p_state *state, Bool on) } - - static void cursor_off_timer (XtPointer closure, XtIntervalId *id) { @@ -770,7 +701,6 @@ print_char (p_state *state, int c) { p_cell *cell = &state->cells[state->grid_width * state->cursor_y + 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) @@ -779,12 +709,14 @@ print_char (p_state *state, int c) cell->changed = True; } - 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. - */ +#ifdef HAVE_FORKPTY + if (state->pty_p) /* 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. + */ { + int i, start, end; switch (state->escstate) { case 0: @@ -1117,6 +1049,7 @@ print_char (p_state *state, int c) set_cursor (state, True); } else +#endif /* HAVE_FORKPTY */ { if (c == '\t') c = ' '; /* blah. */ @@ -1225,223 +1158,15 @@ static unsigned long phosphor_draw (Display *dpy, Window window, void *closure) { p_state *state = (p_state *) closure; + int c; update_display (state, True); decay (state); - drain_input (state); - return state->delay; -} - - -/* Subprocess. - */ - -static void -subproc_cb (XtPointer closure, int *source, XtInputId *id) -{ - p_state *state = (p_state *) closure; - state->input_available_p = True; -} - - -static void -launch_text_generator (p_state *state) -{ - XtAppContext app = XtDisplayToApplicationContext (state->dpy); - char buf[255]; - const char *oprogram = state->program; - char *program = (char *) malloc (strlen (oprogram) + 50); - - strcpy (program, "( "); - strcat (program, oprogram); - - /* Kludge! Special-case "xscreensaver-text" to tell it how wide - the screen is. We used to do this by just always feeding - `program' through sprintf() and setting the default value to - "xscreensaver-text --cols %d", but that makes things blow up - if someone ever uses a --program that includes a % anywhere. - */ - if (!strcmp (oprogram, "xscreensaver-text")) - sprintf (program + strlen(program), " --cols %d", state->grid_width-1); - - strcat (program, " ) 2>&1"); - -#ifdef HAVE_FORKPTY - if(state->mode == 1) - { - 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 */ - { - /* don't mess up controlling terminal if someone dumbly does - "-pipe -program tcsh". */ - static int protected_stdin_p = 0; - if (! protected_stdin_p) { - fclose (stdin); - open ("/dev/null", O_RDWR); /* re-allocate fd 0 */ - protected_stdin_p = 1; - } - - 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); -} + c = textclient_getc (state->tc); + if (c > 0) + print_char (state, c); -static void -relaunch_generator_timer (XtPointer closure, XtIntervalId *id) -{ - p_state *state = (p_state *) closure; - /* if (!state->pipe_timer) abort(); */ - state->pipe_timer = 0; - launch_text_generator (state); -} - - -static void -drain_input (p_state *state) -{ - XtAppContext app = XtDisplayToApplicationContext (state->dpy); - if (state->input_available_p && state->pipe) - { - unsigned char s[2]; - int n = read (fileno (state->pipe), (void *) s, 1); - - if (n == 1) - { - print_char (state, s[0]); - } - else - { - XtRemoveInput (state->pipe_id); - state->pipe_id = 0; - if (state->pid) - { - waitpid(state->pid, NULL, 0); - fclose (state->pipe); - state->pid = 0; - } - else - { - pclose (state->pipe); - } - state->pipe = 0; - - if (state->cursor_x != 0) { /* break line if unbroken */ - print_char (state, '\r'); - print_char (state, '\n'); - } - print_char (state, '\r'); /* blank line */ - print_char (state, '\n'); - - /* Set up a timer to re-launch the subproc in a bit. */ - state->pipe_timer = - XtAppAddTimeOut (app, state->subproc_relaunch_delay, - relaunch_generator_timer, - (XtPointer) state); - } - - state->input_available_p = False; - } -} - - -/* 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; -# ifndef HAVE_COCOA - 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); -# endif /* HAVE_COCOA */ - return modbits; -} - -/* Returns a mask of the bit or bits of a KeyPress event that mean "meta". - */ -static unsigned int -meta_modifier (p_state *state) -{ - if (!state->meta_done_once) - { - /* Really, we are supposed to recompute this if a KeymapNotify - event comes in, but fuck it. */ - state->meta_done_once = True; - state->meta_mask = do_icccm_meta_key_stupidity (state->dpy); - } - return state->meta_mask; + return state->delay; } @@ -1454,34 +1179,9 @@ phosphor_reshape (Display *dpy, Window window, void *closure, if (! changed_p) return; -# if defined(HAVE_FORKPTY) && defined(TIOCSWINSZ) - if (state->pid && state->pipe) - { - /* 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 */ - - - /* If we're running xscreensaver-text, then kill and restart it any - time the window is resized so that it gets an updated --cols arg - right away. But if we're running something else, leave it alone. - */ - if (!strcmp (state->program, "xscreensaver-text")) - { - if (state->pid) - kill (state->pid, SIGTERM); - if (state->pipe) - pclose (state->pipe); - state->input_available_p = False; - relaunch_generator_timer (state, 0); - } + textclient_reshape (state->tc, w, h, + state->grid_width - 1, + state->grid_height - 1); } @@ -1493,33 +1193,7 @@ phosphor_event (Display *dpy, Window window, void *closure, XEvent *event) 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)) - { - 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. */ - } - return True; - } - + return textclient_putc (state->tc, &event->xkey); return False; } @@ -1528,14 +1202,9 @@ phosphor_free (Display *dpy, Window window, void *closure) { p_state *state = (p_state *) closure; - if (state->pipe_id) - XtRemoveInput (state->pipe_id); - if (state->pipe) - pclose (state->pipe); + textclient_close (state->tc); if (state->cursor_timer) XtRemoveTimeOut (state->cursor_timer); - if (state->pipe_timer) - XtRemoveTimeOut (state->pipe_timer); /* #### there's more to free here */ @@ -1566,9 +1235,9 @@ static const char *phosphor_defaults [] = { "*metaSendsESC: True", "*swapBSDEL: True", #ifdef HAVE_FORKPTY - "*mode: pty", + "*usePty: True", #else /* !HAVE_FORKPTY */ - "*mode: pipe", + "*usePty: False", #endif /* !HAVE_FORKPTY */ 0 }; @@ -1579,8 +1248,8 @@ static XrmOptionDescRec phosphor_options [] = { { "-ticks", ".ticks", XrmoptionSepArg, 0 }, { "-delay", ".delay", XrmoptionSepArg, 0 }, { "-program", ".program", XrmoptionSepArg, 0 }, - { "-pty", ".mode", XrmoptionNoArg, "pty" }, - { "-pipe", ".mode", XrmoptionNoArg, "pipe" }, + { "-pipe", ".usePty", XrmoptionNoArg, "False" }, + { "-pty", ".usePty", XrmoptionNoArg, "True" }, { "-meta", ".metaSendsESC", XrmoptionNoArg, "False" }, { "-esc", ".metaSendsESC", XrmoptionNoArg, "True" }, { "-bs", ".swapBSDEL", XrmoptionNoArg, "False" },