X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=utils%2Ftextclient.c;h=abb6f1191267a51089d857ea58e93af73752a2a3;hb=d5186197bc394e10a4402f7f6d23fbb14103bc50;hp=ed2997e0b0a0a63dc8510c97fdf56cd012e1324f;hpb=f8cf5ac7b2f53510f80a0eaf286a25298be17bfe;p=xscreensaver diff --git a/utils/textclient.c b/utils/textclient.c index ed2997e0..abb6f119 100644 --- a/utils/textclient.c +++ b/utils/textclient.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 2012 Jamie Zawinski +/* xscreensaver, Copyright (c) 2012-2014 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 @@ -52,7 +52,7 @@ # endif #endif /* HAVE_FORKPTY */ -/*#define DEBUG*/ +#undef DEBUG extern const char *progname; @@ -60,6 +60,7 @@ struct text_data { Display *dpy; char *program; int pix_w, pix_h, char_w, char_h; + int max_lines; Bool pty_p; XtIntervalId pipe_timer; @@ -92,16 +93,40 @@ subproc_cb (XtPointer closure, int *source, XtInputId *id) } +# define BACKSLASH(c) \ + (! ((c >= 'a' && c <= 'z') || \ + (c >= 'A' && c <= 'Z') || \ + (c >= '0' && c <= '9') || \ + c == '.' || c == '_' || c == '-' || c == '+' || c == '/')) + static void launch_text_generator (text_data *d) { XtAppContext app = XtDisplayToApplicationContext (d->dpy); char buf[255]; const char *oprogram = d->program; - char *program = (char *) malloc (strlen (oprogram) + 50); + char *s; + +# ifdef HAVE_COCOA + /* /bin/sh on OS X 10.10 wipes out the PATH. */ + const char *path = getenv("PATH"); + char *cmd = s = malloc ((strlen(oprogram) + strlen(path)) * 2 + 100); + strcpy (s, "export PATH="); + s += strlen (s); + while (*path) { + char c = *path++; + if (BACKSLASH(c)) *s++ = '\\'; + *s++ = c; + } + strcpy (s, "; "); + s += strlen (s); +# else + char *cmd = s = malloc ((strlen(oprogram)) * 2 + 100); +# endif - strcpy (program, "( "); - strcat (program, oprogram); + strcpy (s, "( "); + strcat (s, oprogram); + s += strlen (s); /* Kludge! Special-case "xscreensaver-text" to tell it how wide the screen is. We used to do this by just always feeding @@ -110,12 +135,18 @@ launch_text_generator (text_data *d) if someone ever uses a --program that includes a % anywhere. */ if (!strcmp (oprogram, "xscreensaver-text")) - sprintf (program + strlen(program), " --cols %d", d->char_w); + { + if (d->char_w) + sprintf (s, " --cols %d", d->char_w); + if (d->max_lines) + sprintf (s, " --lines %d", d->max_lines); + s += strlen(s); + } - strcat (program, " ) 2>&1"); + strcpy (s, " ) 2>&1"); # ifdef DEBUG - fprintf (stderr, "%s: textclient: launch %s: %s\n", progname, + fprintf (stderr, "%s: textclient: launch %s: %s\n", cmd, (d->pty_p ? "pty" : "pipe"), program); # endif @@ -130,7 +161,7 @@ launch_text_generator (text_data *d) ws.ws_xpixel = d->pix_w; ws.ws_ypixel = d->pix_h; - d->pipe = NULL; + d->pipe = 0; if ((d->pid = forkpty(&fd, NULL, NULL, &ws)) < 0) { /* Unable to fork */ @@ -146,7 +177,7 @@ launch_text_generator (text_data *d) abort(); av[i++] = "/bin/sh"; av[i++] = "-c"; - av[i++] = program; + av[i++] = cmd; av[i] = 0; execvp (av[0], av); sprintf (buf, "%.100s: %.100s", progname, oprogram); @@ -156,7 +187,9 @@ launch_text_generator (text_data *d) else { /* This is the parent fork. */ + if (d->pipe) abort(); d->pipe = fdopen (fd, "r+"); + if (d->pipe_id) abort(); d->pipe_id = XtAppAddInput (app, fileno (d->pipe), (XtPointer) (XtInputReadMask | XtInputExceptMask), @@ -177,8 +210,10 @@ launch_text_generator (text_data *d) protected_stdin_p = 1; } - if ((d->pipe = popen (program, "r"))) + if (d->pipe) abort(); + if ((d->pipe = popen (cmd, "r"))) { + if (d->pipe_id) abort(); d->pipe_id = XtAppAddInput (app, fileno (d->pipe), (XtPointer) (XtInputReadMask | XtInputExceptMask), @@ -189,12 +224,12 @@ launch_text_generator (text_data *d) } else { - sprintf (buf, "%.100s: %.100s", progname, program); + sprintf (buf, "%.100s: %.100s", progname, cmd); perror (buf); } } - free (program); + free (cmd); } @@ -211,10 +246,58 @@ relaunch_generator_timer (XtPointer closure, XtIntervalId *id) } +static void +start_timer (text_data *d) +{ + XtAppContext app = XtDisplayToApplicationContext (d->dpy); + +# ifdef DEBUG + fprintf (stderr, "%s: textclient: relaunching in %d\n", progname, + (int) d->subproc_relaunch_delay); +# endif + if (d->pipe_timer) + XtRemoveTimeOut (d->pipe_timer); + d->pipe_timer = + XtAppAddTimeOut (app, d->subproc_relaunch_delay, + relaunch_generator_timer, + (XtPointer) d); +} + + +static void +close_pipe (text_data *d) +{ + if (d->pid) + { +# ifdef DEBUG + fprintf (stderr, "%s: textclient: kill %d\n", progname, d->pid); +# endif + kill (d->pid, SIGTERM); + } + d->pid = 0; + + if (d->pipe_id) + XtRemoveInput (d->pipe_id); + d->pipe_id = 0; + + if (d->pipe) + { +# ifdef DEBUG + fprintf (stderr, "%s: textclient: pclose\n", progname); +# endif + pclose (d->pipe); + } + d->pipe = 0; + + +} + + void textclient_reshape (text_data *d, int pix_w, int pix_h, - int char_w, int char_h) + int char_w, int char_h, + int max_lines) { # if defined(HAVE_FORKPTY) && defined(TIOCSWINSZ) @@ -222,6 +305,7 @@ textclient_reshape (text_data *d, d->pix_h = pix_h; d->char_w = char_w; d->char_h = char_h; + d->max_lines = max_lines; # ifdef DEBUG fprintf (stderr, "%s: textclient: reshape: %dx%d, %dx%d\n", progname, @@ -248,14 +332,9 @@ textclient_reshape (text_data *d, */ if (!strcmp (d->program, "xscreensaver-text")) { - if (d->pid) - kill (d->pid, SIGTERM); - if (d->pipe_id) - XtRemoveInput (d->pipe_id); - if (d->pipe) - pclose (d->pipe); + close_pipe (d); d->input_available_p = False; - relaunch_generator_timer (d, 0); + start_timer (d); } } @@ -283,7 +362,11 @@ textclient_open (Display *dpy) } d->subproc_relaunch_delay = - (1000 * get_integer_resource (dpy, "relaunchDelay", "Time")); + get_integer_resource (dpy, "relaunchDelay", "Time"); + if (d->subproc_relaunch_delay < 1) + d->subproc_relaunch_delay = 1; + d->subproc_relaunch_delay *= 1000; + d->meta_sends_esc_p = get_boolean_resource (dpy, "metaSendsESC", "Boolean"); d->swap_bs_del_p = get_boolean_resource (dpy, "swapBSDEL", "Boolean"); @@ -303,7 +386,7 @@ textclient_open (Display *dpy) } # endif - launch_text_generator (d); + start_timer (d); return d; } @@ -316,14 +399,12 @@ textclient_close (text_data *d) fprintf (stderr, "%s: textclient: free\n", progname); # endif + close_pipe (d); if (d->program) free (d->program); - if (d->pipe_id) - XtRemoveInput (d->pipe_id); - if (d->pipe) - pclose (d->pipe); if (d->pipe_timer) XtRemoveTimeOut (d->pipe_timer); + d->pipe_timer = 0; memset (d, 0, sizeof (*d)); free (d); } @@ -350,10 +431,6 @@ textclient_getc (text_data *d) ret = s[0]; else /* EOF */ { - if (d->pipe_id) - XtRemoveInput (d->pipe_id); - d->pipe_id = 0; - if (d->pid) { # ifdef DEBUG @@ -361,17 +438,10 @@ textclient_getc (text_data *d) progname, d->pid); # endif waitpid (d->pid, NULL, 0); - fclose (d->pipe); d->pid = 0; } - else - { -# ifdef DEBUG - fprintf (stderr, "%s: textclient: pclose\n", progname); -# endif - pclose (d->pipe); - } - d->pipe = 0; + + close_pipe (d); if (d->out_column > 0) { @@ -382,14 +452,7 @@ textclient_getc (text_data *d) d->out_buffer = "\r\n\r\n"; } -# ifdef DEBUG - fprintf (stderr, "%s: textclient: relaunching in %d\n", progname, - (int) d->subproc_relaunch_delay); -# endif - d->pipe_timer = - XtAppAddTimeOut (app, d->subproc_relaunch_delay, - relaunch_generator_timer, - (XtPointer) d); + start_timer (d); } d->input_available_p = False; }