-/* xscreensaver, Copyright (c) 2012 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 2012-2016 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* usePty: bool Whether to run the command interactively.
* metaSendsESC: bool Whether to send Alt-x as ESC x in pty-mode.
* swapBSDEL: bool Swap Backspace and Delete in pty-mode.
+ *
+ * On iOS and Android, textclient-mobile.c is used instead.
*/
#include "utils.h"
-#ifndef USE_IPHONE /* whole file -- see OSX/iostextclient.m */
+#if !defined(USE_IPHONE) && !defined(HAVE_ANDROID) /* whole file */
#include "textclient.h"
#include "resources.h"
# ifdef HAVE_UTIL_H
# include <util.h>
# endif
+# ifdef HAVE_SYS_TERMIOS_H
+# include <sys/termios.h>
+# endif
#endif /* HAVE_FORKPTY */
-/*#define DEBUG*/
+#undef DEBUG
extern const char *progname;
Display *dpy;
char *program;
int pix_w, pix_h, char_w, char_h;
+ int max_lines;
Bool pty_p;
XtIntervalId pipe_timer;
}
+# 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
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
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 */
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);
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),
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),
}
else
{
- sprintf (buf, "%.100s: %.100s", progname, program);
+ sprintf (buf, "%.100s: %.100s", progname, cmd);
perror (buf);
}
}
- free (program);
+ free (cmd);
}
}
+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)
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,
*/
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);
}
}
}
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");
}
# endif
- launch_text_generator (d);
+ start_timer (d);
return 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);
}
ret = s[0];
else /* EOF */
{
- if (d->pipe_id)
- XtRemoveInput (d->pipe_id);
- d->pipe_id = 0;
-
if (d->pid)
{
# ifdef DEBUG
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)
{
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;
}