-/* xscreensaver, Copyright (c) 1999-2014 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 */
-#ifndef HAVE_COCOA
+#ifndef HAVE_JWXYZ
# include <X11/Intrinsic.h>
#endif
#include "screenhack.h"
#include "textclient.h"
+#include "utf8wc.h"
#define FUZZY_BORDER
int scale;
int ticks;
int mode;
+
int escstate;
int csiparam[NPAR];
int curparam;
+ int unicruds; unsigned char unicrud[7];
+
p_char **chars;
p_cell *cells;
XGCValues gcv;
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;
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 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];
CRLF line endings instead of bare LF, so that's no good.
*/
{
- int i, start, end;
+ 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
{
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++;