X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fphosphor.c;h=2e57b8617603eed56d83876354175f89fe411590;hb=78add6e627ee5f10e1fa6f3852602ea5066eee5a;hp=47f58dcc7db36ea1de3bc9798921eabbffff49b7;hpb=6afd6db0ae9396cd7ff897ade597cd5483f49b0e;p=xscreensaver diff --git a/hacks/phosphor.c b/hacks/phosphor.c index 47f58dcc..2e57b861 100644 --- a/hacks/phosphor.c +++ b/hacks/phosphor.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1999-2014 Jamie Zawinski +/* xscreensaver, Copyright (c) 1999-2018 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,12 +17,14 @@ # include "config.h" #endif /* HAVE_CONFIG_H */ -#ifndef HAVE_COCOA +#ifndef HAVE_JWXYZ # include #endif #include "screenhack.h" #include "textclient.h" +#include "ximage-loader.h" +#include "utf8wc.h" #define FUZZY_BORDER @@ -42,7 +44,7 @@ #define BUILTIN_FONT #ifdef BUILTIN_FONT -# include "images/6x10font.xbm" +# include "images/gen/6x10font_png.h" #endif /* BUILTIN_FONT */ typedef struct { @@ -69,13 +71,17 @@ typedef struct { const char *program; int grid_width, grid_height; int char_width, char_height; + int xmargin, ymargin; int saved_x, saved_y; 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; @@ -144,6 +150,9 @@ static unsigned short scale_color_channel (unsigned short ch1, unsigned short ch return (ch1 * 100 + ch2 * 156) >> 8; } +#define FONT6x10_WIDTH (256*7) +#define FONT6x10_HEIGHT 10 + static void * phosphor_init (Display *dpy, Window window) { @@ -167,23 +176,13 @@ phosphor_init (Display *dpy, Window window) { #ifndef BUILTIN_FONT fprintf (stderr, "%s: no builtin font\n", progname); - state->font = XLoadQueryFont (dpy, "fixed"); + state->font = load_font_retry (dpy, "fixed"); #endif /* !BUILTIN_FONT */ } else { - state->font = XLoadQueryFont (dpy, fontname); - - if (!state->font) - { - fprintf(stderr, "couldn't load font \"%s\"\n", fontname); - state->font = XLoadQueryFont (dpy, "fixed"); - } - if (!state->font) - { - fprintf(stderr, "couldn't load font \"fixed\""); - exit(1); - } + state->font = load_font_retry (dpy, fontname); + if (!state->font) abort(); } font = state->font; @@ -191,14 +190,15 @@ phosphor_init (Display *dpy, Window window) state->ticks = STATE_MAX + get_integer_resource (dpy, "ticks", "Integer"); state->escstate = 0; + if (state->xgwa.width > 2560) state->scale *= 2; /* Retina displays */ state->cursor_blink = get_integer_resource (dpy, "cursor", "Time"); # ifdef BUILTIN_FONT if (! font) { - state->char_width = (font6x10_width / 256) - 1; - state->char_height = font6x10_height; + state->char_width = (FONT6x10_WIDTH / 256) - 1; + state->char_height = FONT6x10_HEIGHT; } else # endif /* BUILTIN_FONT */ @@ -207,8 +207,20 @@ phosphor_init (Display *dpy, Window window) state->char_height = font->max_bounds.ascent + font->max_bounds.descent; } - state->grid_width = state->xgwa.width / (state->char_width * state->scale); - state->grid_height = state->xgwa.height /(state->char_height * state->scale); +# ifdef USE_IPHONE + /* Stupid iPhone X bezel. + #### This is the worst of all possible ways to do this! But how else? + */ + if (state->xgwa.width == 2436 || state->xgwa.height == 2436) { + state->xmargin = 96; + state->ymargin = state->xmargin; + } +# endif + + state->grid_width = ((state->xgwa.width - state->xmargin * 2) / + (state->char_width * state->scale)); + state->grid_height = ((state->xgwa.height - state->ymargin * 2) / + (state->char_height * state->scale)); state->cells = (p_cell *) calloc (sizeof(p_cell), state->grid_width * state->grid_height); state->chars = (p_char **) calloc (sizeof(p_char *), 256); @@ -216,7 +228,7 @@ phosphor_init (Display *dpy, Window window) 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; @@ -320,8 +332,8 @@ phosphor_init (Display *dpy, Window window) state->tc = textclient_open (dpy); textclient_reshape (state->tc, - state->xgwa.width, - state->xgwa.height, + state->xgwa.width - state->xmargin * 2, + state->xgwa.height - state->ymargin * 2, state->grid_width - 1, state->grid_height - 1, 0); @@ -342,8 +354,17 @@ resize_grid (p_state *state) XGetWindowAttributes (state->dpy, state->window, &state->xgwa); - state->grid_width = state->xgwa.width /(state->char_width * state->scale); - state->grid_height = state->xgwa.height /(state->char_height * state->scale); + /* Would like to ensure here that + state->char_height * state->scale <= state->xgwa.height + but changing scale requires regenerating the bitmaps. */ + + state->grid_width = ((state->xgwa.width - state->xmargin * 2) / + (state->char_width * state->scale)); + state->grid_height = ((state->xgwa.height - state->ymargin * 2) / + (state->char_height * state->scale)); + + if (state->grid_width < 2) state->grid_width = 2; + if (state->grid_height < 2) state->grid_height = 2; if (ow == state->grid_width && oh == state->grid_height) @@ -389,11 +410,54 @@ capture_font_bits (p_state *state) { safe_width = state->char_width + 1; height = state->char_height; - p2 = XCreatePixmapFromBitmapData (state->dpy, state->window, - (char *) font6x10_bits, - font6x10_width, - font6x10_height, - 1, 0, 1); + + int pix_w, pix_h; + XWindowAttributes xgwa; + Pixmap m = 0; + Pixmap p = image_data_to_pixmap (state->dpy, state->window, + _6x10font_png, sizeof(_6x10font_png), + &pix_w, &pix_h, &m); + XImage *im = XGetImage (state->dpy, p, 0, 0, pix_w, pix_h, ~0L, ZPixmap); + XImage *mm = XGetImage (state->dpy, m, 0, 0, pix_w, pix_h, 1, XYPixmap); + XImage *im2; + int x, y; + XGCValues gcv; + GC gc; + unsigned long black = + BlackPixelOfScreen (DefaultScreenOfDisplay (state->dpy)); + + XFreePixmap (state->dpy, p); + XFreePixmap (state->dpy, m); + if (pix_w != 256*7) abort(); + if (pix_h != 10) abort(); + if (pix_w != FONT6x10_WIDTH) abort(); + if (pix_h != FONT6x10_HEIGHT) abort(); + + XGetWindowAttributes (state->dpy, state->window, &xgwa); + im2 = XCreateImage (state->dpy, xgwa.visual, 1, XYBitmap, 0, 0, + pix_w, pix_h, 8, 0); + im2->data = malloc (im2->bytes_per_line * im2->height); + + /* Convert deep image to 1 bit */ + for (y = 0; y < pix_h; y++) + for (x = 0; x < pix_w; x++) + XPutPixel (im2, x, y, + (XGetPixel (mm, x, y) + ? (XGetPixel (im, x, y) == black) + : 0)); + + XDestroyImage (im); + XDestroyImage (mm); + im = 0; + + p2 = XCreatePixmap (state->dpy, state->window, + im2->width, im2->height, im2->depth); + gcv.foreground = 1; + gcv.background = 0; + gc = XCreateGC (state->dpy, p2, GCForeground|GCBackground, &gcv); + XPutImage (state->dpy, p2, gc, im2, 0, 0, 0, 0, im2->width, im2->height); + XFreeGC (state->dpy, gc); + XDestroyImage (im2); } else # endif /* BUILTIN_FONT */ @@ -422,7 +486,7 @@ capture_font_bits (p_state *state) 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 @@ -448,7 +512,7 @@ capture_font_bits (p_state *state) if (p2) { XCopyPlane (state->dpy, p2, p, state->gc1, - 0, 0, font6x10_width, font6x10_height, + 0, 0, FONT6x10_WIDTH, FONT6x10_HEIGHT, 0, 0, 1); XFreePixmap (state->dpy, p2); } @@ -725,9 +789,61 @@ scroll (p_state *state) } +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]; @@ -745,7 +861,11 @@ print_char (p_state *state, int c) 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: @@ -760,20 +880,23 @@ print_char (p_state *state, int c) 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) @@ -782,14 +905,14 @@ print_char (p_state *state, int c) 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 @@ -797,8 +920,7 @@ print_char (p_state *state, int c) 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 */ @@ -818,6 +940,23 @@ print_char (p_state *state, int c) 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; @@ -826,10 +965,10 @@ print_char (p_state *state, int c) 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++; @@ -849,7 +988,7 @@ print_char (p_state *state, int c) 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); @@ -880,10 +1019,14 @@ print_char (p_state *state, int c) 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 @@ -924,15 +1067,15 @@ print_char (p_state *state, int c) 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; @@ -956,16 +1099,16 @@ print_char (p_state *state, int c) 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': @@ -976,22 +1119,22 @@ print_char (p_state *state, int c) 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) @@ -1000,11 +1143,11 @@ print_char (p_state *state, int c) 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]; @@ -1019,7 +1162,7 @@ print_char (p_state *state, int c) 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) @@ -1035,6 +1178,9 @@ print_char (p_state *state, int c) } 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; @@ -1074,6 +1220,16 @@ print_char (p_state *state, int c) 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); } @@ -1089,7 +1245,7 @@ print_char (p_state *state, int c) 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++; @@ -1101,6 +1257,9 @@ print_char (p_state *state, int c) } else { + c = process_unicrud (state, c); + if (!c) return; + cell->state = FLARE; cell->p_char = state->chars[c]; cell->changed = True; @@ -1109,10 +1268,10 @@ print_char (p_state *state, int c) 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++; @@ -1139,10 +1298,10 @@ update_display (p_state *state, Bool changed_only) if (changed_only && !cell->changed) continue; - width = state->char_width * state->scale; + width = state->char_width * state->scale; height = state->char_height * state->scale; - tx = x * width; - ty = y * height; + tx = x * width + state->xmargin; + ty = y * height + state->ymargin; if (cell->state == BLANK || cell->p_char->blank_p) { @@ -1208,7 +1367,9 @@ phosphor_reshape (Display *dpy, Window window, void *closure, if (! changed_p) return; - textclient_reshape (state->tc, w, h, + textclient_reshape (state->tc, + w - state->xmargin * 2, + h - state->ymargin * 2, state->grid_width - 1, state->grid_height - 1, 0); @@ -1244,6 +1405,7 @@ phosphor_free (Display *dpy, Window window, void *closure) static const char *phosphor_defaults [] = { +/* ".lowrez: true",*/ ".background: Black", ".foreground: #00FF00", "*fpsSolid: true",