-/* xscreensaver, Copyright (c) 1999-2008 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1999-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
# include "config.h"
#endif /* HAVE_CONFIG_H */
-#include <stdio.h>
-#include <signal.h>
-#include <sys/wait.h>
-
-#ifndef HAVE_COCOA
-# define XK_MISCELLANY
-# include <X11/keysymdef.h>
-# include <X11/Xatom.h>
+#ifndef HAVE_JWXYZ
# include <X11/Intrinsic.h>
#endif
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-# include <fcntl.h> /* for O_RDWR */
-#endif
-
-#ifdef HAVE_FORKPTY
-# include <sys/ioctl.h>
-# ifdef HAVE_PTY_H
-# include <pty.h>
-# endif
-# ifdef HAVE_UTIL_H
-# include <util.h>
-# endif
-#endif /* HAVE_FORKPTY */
-
#include "screenhack.h"
+#include "textclient.h"
+#include "utf8wc.h"
#define FUZZY_BORDER
Window window;
XWindowAttributes xgwa;
XFontStruct *font;
+ const char *program;
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;
+ int unicruds; unsigned char unicrud[7];
+
p_char **chars;
p_cell *cells;
XGCValues gcv;
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:
static void clear (p_state *);
static void set_cursor (p_state *, Bool on);
+static unsigned short scale_color_channel (unsigned short ch1, unsigned short ch2)
+{
+ return (ch1 * 100 + ch2 * 156) >> 8;
+}
+
static void *
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)"))
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)
state->gcs = (GC *) calloc (sizeof(GC), state->ticks + 1);
{
- int ncolors = MAX (0, state->ticks - 3);
+ int ncolors = MAX (1, state->ticks - 3);
XColor *colors = (XColor *) calloc (ncolors, sizeof(XColor));
int h1, h2;
double s1, s2, v1, v2;
"foreground", "Foreground");
unsigned long bg = get_pixel_resource (state->dpy, state->xgwa.colormap,
"background", "Background");
- unsigned long flare = get_pixel_resource (state->dpy,state->xgwa.colormap,
- "flareForeground", "Foreground");
- unsigned long fade = get_pixel_resource (state->dpy,state->xgwa.colormap,
- "fadeForeground", "Foreground");
+ unsigned long flare = fg;
- XColor start, end;
+ XColor fg_color, bg_color;
- start.pixel = fade;
- XQueryColor (state->dpy, state->xgwa.colormap, &start);
+ fg_color.pixel = fg;
+ XQueryColor (state->dpy, state->xgwa.colormap, &fg_color);
- end.pixel = bg;
- XQueryColor (state->dpy, state->xgwa.colormap, &end);
+ bg_color.pixel = bg;
+ XQueryColor (state->dpy, state->xgwa.colormap, &bg_color);
/* Now allocate a ramp of colors from the main color to the background. */
- rgb_to_hsv (start.red, start.green, start.blue, &h1, &s1, &v1);
- rgb_to_hsv (end.red, end.green, end.blue, &h2, &s2, &v2);
- make_color_ramp (state->dpy, state->xgwa.colormap,
+ rgb_to_hsv (scale_color_channel(fg_color.red, bg_color.red),
+ scale_color_channel(fg_color.green, bg_color.green),
+ scale_color_channel(fg_color.blue, bg_color.blue),
+ &h1, &s1, &v1);
+ rgb_to_hsv (bg_color.red, bg_color.green, bg_color.blue, &h2, &s2, &v2);
+
+ /* Avoid rainbow effects when fading to black/grey/white. */
+ if (s2 < 0.003)
+ h2 = h1;
+ if (s1 < 0.003)
+ h1 = h2;
+
+ make_color_ramp (state->xgwa.screen, state->xgwa.visual,
+ state->xgwa.colormap,
h1, s1, v1,
h2, s2, v2,
colors, &ncolors,
/* Adjust to the number of colors we actually got. */
state->ticks = ncolors + STATE_MAX;
+ /* If the foreground is brighter than the background, the flare is white.
+ * Otherwise, the flare is left at the foreground color (i.e. no flare). */
+ rgb_to_hsv (fg_color.red, fg_color.green, fg_color.blue, &h1, &s1, &v1);
+ if (v2 <= v1)
+ {
+ XColor white;
+ /* WhitePixel is only for the default visual, which can be overridden
+ * on the command line. */
+ white.red = 0xffff;
+ white.green = 0xffff;
+ white.blue = 0xffff;
+ if (XAllocColor(state->dpy, state->xgwa.colormap, &white))
+ flare = white.pixel;
+ }
+
/* Now, GCs all around.
*/
state->gcv.font = (font ? font->fid : 0);
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,
+ 0);
+
return state;
}
/* Re-query the window size and update the internal character grid if changed.
*/
-static void
+static Bool
resize_grid (p_state *state)
{
int ow = state->grid_width;
if (ow == state->grid_width &&
oh == state->grid_height)
- return;
+ return False;
state->cells = (p_cell *) calloc (sizeof(p_cell),
state->grid_width * state->grid_height);
state->cursor_y = state->grid_height-1;
free (ocells);
+ return True;
}
GCCapStyle | GCLineWidth),
&state->gcv);
-#ifdef HAVE_COCOA
+#ifdef HAVE_JWXYZ
jwxyz_XSetAntiAliasing (state->dpy, state->gc0, False);
jwxyz_XSetAntiAliasing (state->dpy, state->gc1, False);
#endif
}
-
-
static void
cursor_off_timer (XtPointer closure, XtIntervalId *id)
{
}
+static int
+process_unicrud (p_state *state, int c)
+{
+ if ((c & 0xE0) == 0xC0) { /* 110xxxxx: 11 bits, 2 bytes */
+ state->unicruds = 1;
+ state->unicrud[0] = c;
+ state->escstate = 102;
+ } else if ((c & 0xF0) == 0xE0) { /* 1110xxxx: 16 bits, 3 bytes */
+ state->unicruds = 1;
+ state->unicrud[0] = c;
+ state->escstate = 103;
+ } else if ((c & 0xF8) == 0xF0) { /* 11110xxx: 21 bits, 4 bytes */
+ state->unicruds = 1;
+ state->unicrud[0] = c;
+ state->escstate = 104;
+ } else if ((c & 0xFC) == 0xF8) { /* 111110xx: 26 bits, 5 bytes */
+ state->unicruds = 1;
+ state->unicrud[0] = c;
+ state->escstate = 105;
+ } else if ((c & 0xFE) == 0xFC) { /* 1111110x: 31 bits, 6 bytes */
+ state->unicruds = 1;
+ state->unicrud[0] = c;
+ state->escstate = 106;
+ } else if (state->unicruds == 0) {
+ return c;
+ } else {
+ int total = state->escstate - 100; /* see what I did there */
+ if (state->unicruds < total) {
+ /* Buffer more bytes of the UTF-8 sequence */
+ state->unicrud[state->unicruds++] = c;
+ }
+
+ if (state->unicruds >= total) {
+ /* Done! Convert it to Latin1 and print that. */
+ char *s;
+ state->unicrud[state->unicruds] = 0;
+ s = utf8_to_latin1 ((const char *) state->unicrud, False);
+ state->unicruds = 0;
+ state->escstate = 0;
+ if (s) {
+ c = (unsigned char) s[0];
+ free (s);
+ return c;
+ }
+ }
+ }
+ return 0;
+}
+
+
static void
print_char (p_state *state, int c)
{
+ int cols = state->grid_width;
+ int rows = state->grid_height;
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)
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;
+ int start, end;
+
+ /* Mostly duplicated in apple2-main.c */
+
switch (state->escstate)
{
case 0:
state->cursor_x--;
break;
case 9: /* HT */
- if (state->cursor_x < state->grid_width - 8)
+ if (state->cursor_x < cols - 8)
{
state->cursor_x = (state->cursor_x & ~7) + 8;
}
else
{
state->cursor_x = 0;
- if (state->cursor_y < state->grid_height - 1)
+ if (state->cursor_y < rows - 1)
state->cursor_y++;
else
scroll (state);
}
break;
case 10: /* LF */
+# ifndef HAVE_FORKPTY
+ state->cursor_x = 0; /* No ptys on iPhone; assume CRLF. */
+# endif
case 11: /* VT */
case 12: /* FF */
if(state->last_c == 13)
cell->p_char = state->chars[state->bk];
cell->changed = True;
}
- if (state->cursor_y < state->grid_height - 1)
+ if (state->cursor_y < rows - 1)
state->cursor_y++;
else
scroll (state);
break;
case 13: /* CR */
state->cursor_x = 0;
- cell = &state->cells[state->grid_width * state->cursor_y];
+ cell = &state->cells[cols * state->cursor_y];
if((cell->p_char == NULL) || (cell->p_char->name == CURSOR_INDEX))
state->bk = ' ';
else
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 */
+ /* Dummy case - there is one and only one font. */
break;
case 24: /* CAN */
case 26: /* SUB */
state->curparam = 0;
break;
default:
+
+ PRINT: /* Come from states 102-106 */
+ c = process_unicrud (state, c);
+ if (! c)
+ break;
+
+ /* 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.)
+ */
cell->state = FLARE;
cell->p_char = state->chars[c];
cell->changed = True;
if (c != ' ' && cell->p_char->blank_p)
cell->p_char = state->chars[CURSOR_INDEX];
- if (state->cursor_x >= state->grid_width - 1)
+ if (state->cursor_x >= cols - 1 /*####*/)
{
state->cursor_x = 0;
- if (state->cursor_y >= state->grid_height - 1)
+ if (state->cursor_y >= rows - 1)
scroll (state);
else
state->cursor_y++;
state->escstate = 0;
break;
case 'D': /* Linefeed */
- if (state->cursor_y < state->grid_height - 1)
+ if (state->cursor_y < rows - 1)
state->cursor_y++;
else
scroll (state);
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 '%': /* Select charset */
+ /* @: Select default (ISO 646 / ISO 8859-1)
+ G: Select UTF-8
+ 8: Select UTF-8 (obsolete)
+
+ We can just ignore this and always process UTF-8, I think?
+ We must still catch the last byte, though.
+ */
case '(':
case ')':
/* I don't support different fonts either - see above
case '@':
for (i = 0; i < state->csiparam[0]; i++)
{
- if(++state->cursor_x > state->grid_width)
+ if(++state->cursor_x > cols)
{
state->cursor_x = 0;
- if (state->cursor_y < state->grid_height - 1)
+ if (state->cursor_y < rows - 1)
state->cursor_y++;
else
scroll (state);
}
- cell = &state->cells[state->grid_width * state->cursor_y + state->cursor_x];
+ cell = &state->cells[cols * state->cursor_y + state->cursor_x];
if (cell->state == FLARE || cell->state == NORMAL)
{
cell->state = FADE;
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;
+ if ((state->cursor_y += state->csiparam[0]) >= rows - 1 /*####*/)
+ 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]) >= state->grid_width - 1)
- state->cursor_x = state->grid_width - 1;
+ if ((state->cursor_x += state->csiparam[0]) >= cols - 1 /*####*/)
+ state->cursor_x = cols - 1;
state->escstate = 0;
break;
case 'D':
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;
+ if ((state->cursor_y = (state->csiparam[0] - 1)) >= rows - 1 /*####*/)
+ state->cursor_y = rows - 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;
+ if ((state->cursor_x = (state->csiparam[0] - 1)) >= cols - 1 /*####*/)
+ state->cursor_x = cols - 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 = (state->csiparam[0] - 1)) >= rows - 1 /*####*/)
+ state->cursor_y = rows - 1;
+ if ((state->cursor_x = (state->csiparam[1] - 1)) >= cols - 1 /*####*/)
+ state->cursor_x = cols - 1;
if(state->cursor_y < 0)
state->cursor_y = 0;
if(state->cursor_x < 0)
break;
case 'J':
start = 0;
- end = state->grid_height * state->grid_width;
+ end = rows * cols;
if (state->csiparam[0] == 0)
- start = state->grid_width * state->cursor_y + state->cursor_x;
+ start = cols * state->cursor_y + state->cursor_x;
if (state->csiparam[0] == 1)
- end = state->grid_width * state->cursor_y + state->cursor_x;
+ end = cols * state->cursor_y + state->cursor_x;
for (i = start; i < end; i++)
{
cell = &state->cells[i];
break;
case 'K':
start = 0;
- end = state->grid_width;
+ end = cols;
if (state->csiparam[0] == 0)
start = state->cursor_x;
if (state->csiparam[1] == 1)
}
state->escstate = 0;
break;
+ case 'm': /* Set attributes unimplemented (bold, blink, rev) */
+ state->escstate = 0;
+ break;
case 's': /* Save position */
state->saved_x = state->cursor_x;
state->saved_y = state->cursor_y;
case 3:
state->escstate = 0;
break;
+
+ case 102: /* states 102-106 are for UTF-8 decoding */
+ case 103:
+ case 104:
+ case 105:
+ case 106:
+ goto PRINT;
+
+ default:
+ abort();
}
set_cursor (state, True);
}
else
+#endif /* HAVE_FORKPTY */
{
if (c == '\t') c = ' '; /* blah. */
else
{
state->cursor_x = 0;
- if (state->cursor_y == state->grid_height - 1)
+ if (state->cursor_y == rows - 1)
scroll (state);
else
state->cursor_y++;
}
else
{
+ c = process_unicrud (state, c);
+ if (!c) return;
+
cell->state = FLARE;
cell->p_char = state->chars[c];
cell->changed = True;
if (c != ' ' && cell->p_char->blank_p)
cell->p_char = state->chars[CURSOR_INDEX];
- if (state->cursor_x >= state->grid_width - 1)
+ if (state->cursor_x >= cols - 1)
{
state->cursor_x = 0;
- if (state->cursor_y >= state->grid_height - 1)
+ if (state->cursor_y >= rows - 1)
scroll (state);
else
state->cursor_y++;
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;
-}
-
-\f
-/* 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);
- Display *dpy = state->dpy;
- char buf[255];
- char *oprogram = get_string_resource (dpy, "program", "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);
-}
-
-
-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);
- }
- 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;
- }
-}
+ c = textclient_getc (state->tc);
+ if (c > 0)
+ print_char (state, c);
-/* 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;
}
unsigned int w, unsigned int h)
{
p_state *state = (p_state *) closure;
- resize_grid (state);
+ Bool changed_p = 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 */
+ if (! changed_p) return;
+
+ textclient_reshape (state->tc, w, h,
+ state->grid_width - 1,
+ state->grid_height - 1,
+ 0);
}
+
static Bool
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;
}
{
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 */
".background: Black",
".foreground: #00FF00",
"*fpsSolid: true",
- "*fadeForeground: #006400",
- "*flareForeground: #FFFFFF",
#if defined(BUILTIN_FONT)
"*font: (builtin)",
#elif defined(HAVE_COCOA)
"*metaSendsESC: True",
"*swapBSDEL: True",
#ifdef HAVE_FORKPTY
- "*mode: pty",
+ "*usePty: True",
#else /* !HAVE_FORKPTY */
- "*mode: pipe",
+ "*usePty: False",
#endif /* !HAVE_FORKPTY */
0
};
{ "-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" },