From d3a98cf6cbc3bd0b9efc570f58e8812c03931c18 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 16 Oct 2018 10:08:48 +0200 Subject: Original 5.40 --- hacks/memscroller.c | 636 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 636 insertions(+) create mode 100644 hacks/memscroller.c (limited to 'hacks/memscroller.c') diff --git a/hacks/memscroller.c b/hacks/memscroller.c new file mode 100644 index 0000000..2ccc8ad --- /dev/null +++ b/hacks/memscroller.c @@ -0,0 +1,636 @@ +/* xscreensaver, Copyright (c) 2002-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 + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * Memscroller -- scrolls a dump of its own RAM across the screen. + */ + +#include "screenhack.h" +#include "xshm.h" +#include + +#undef countof +#define countof(x) (sizeof(x)/sizeof(*(x))) + +#ifndef HAVE_MOBILE +# define READ_FILES +#endif + +typedef struct { + int which; + XRectangle rect; + XImage *image; + int rez; + int speed; + int scroll_tick; + unsigned int value; + unsigned char *data; + int count_zero; +} scroller; + +typedef struct { + Display *dpy; + Window window; + XWindowAttributes xgwa; + GC draw_gc, erase_gc, text_gc; + XFontStruct *fonts[6]; + int border; + + enum { SEED_RAM, SEED_RANDOM, SEED_FILE } seed_mode; + enum { DRAW_COLOR, DRAW_MONO } draw_mode; + + char *filename; + FILE *in; + + int nscrollers; + scroller *scrollers; + + XShmSegmentInfo shm_info; + + int delay; + +} state; + + +static void reshape_memscroller (state *st); + + +static void * +memscroller_init (Display *dpy, Window window) +{ + int i; + XGCValues gcv; + state *st = (state *) calloc (1, sizeof (*st)); + char *s; + st->dpy = dpy; + st->window = window; + st->delay = get_integer_resource (dpy, "delay", "Integer"); + + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + + /* Fill up the colormap with random colors. + We don't actually use these explicitly, but in 8-bit mode, + they will be used implicitly by the random image bits. */ + { + int ncolors = 255; + XColor colors[256]; + make_random_colormap (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, + colors, &ncolors, True, True, 0, False); + } + + st->border = get_integer_resource (dpy, "borderSize", "BorderSize"); + if (st->xgwa.width > 2560) st->border *= 2; /* Retina displays */ + + { + int i; + int nfonts = countof (st->fonts); + for (i = nfonts-1; i >= 0; i--) + { + char *fontname; + char res[20]; + sprintf (res, "font%d", i+1); + fontname = get_string_resource (dpy, res, "Font"); + /* Each resource can be a comma-separated list of font names. + We use the first one that exists. */ + if (fontname && *fontname) + { + char *f2 = strdup(fontname); + char *f, *token = f2; + while ((f = strtok(token, ",")) && !st->fonts[i]) + { + token = 0; + while (*f == ' ' || *f == '\t') f++; + st->fonts[i] = load_font_retry (dpy, f); + } + free (f2); + if (!st->fonts[i] && i < nfonts-1) + { + fprintf (stderr, "%s: unable to load font: \"%s\"\n", + progname, fontname); + st->fonts[i] = st->fonts[i+1]; + } + } + } + + if (!st->fonts[0]) + st->fonts[0] = load_font_retry (dpy, "fixed"); + if (!st->fonts[0]) abort(); + } + + gcv.line_width = st->border; + + gcv.background = get_pixel_resource(st->dpy, st->xgwa.colormap, + "background", "Background"); + gcv.foreground = get_pixel_resource(st->dpy, st->xgwa.colormap, + "textColor", "Foreground"); + st->text_gc = XCreateGC (st->dpy, st->window, + GCForeground|GCBackground, &gcv); + + gcv.foreground = get_pixel_resource(st->dpy, st->xgwa.colormap, + "foreground", "Foreground"); + st->draw_gc = XCreateGC (st->dpy, st->window, + GCForeground|GCBackground|GCLineWidth, + &gcv); + gcv.foreground = gcv.background; + st->erase_gc = XCreateGC (st->dpy, st->window, + GCForeground|GCBackground, &gcv); + + + s = get_string_resource (dpy, "drawMode", "DrawMode"); + if (!s || !*s || !strcasecmp (s, "color")) + st->draw_mode = DRAW_COLOR; + else if (!strcasecmp (s, "mono")) + st->draw_mode = DRAW_MONO; + else + { + fprintf (stderr, "%s: drawMode must be 'mono' or 'color', not '%s'\n", + progname, s); + exit (1); + } + if (s) free (s); + s = 0; + + +# ifdef READ_FILES + st->filename = get_string_resource (dpy, "filename", "Filename"); +# endif + + if (!st->filename || + !*st->filename || + !strcasecmp (st->filename, "(ram)") || + !strcasecmp (st->filename, "(mem)") || + !strcasecmp (st->filename, "(memory)")) + st->seed_mode = SEED_RAM; +# ifdef READ_FILES + else if (st->filename && + (!strcasecmp (st->filename, "(rand)") || + !strcasecmp (st->filename, "(random)"))) + st->seed_mode = SEED_RANDOM; + else + st->seed_mode = SEED_FILE; +# else + st->seed_mode = SEED_RANDOM; +# endif + + st->nscrollers = 3; + st->scrollers = (scroller *) calloc (st->nscrollers, sizeof(scroller)); + + for (i = 0; i < st->nscrollers; i++) + { + scroller *sc = &st->scrollers[i]; + int max_height = 4096; + + sc->which = i; + sc->speed = i+1; + + if (st->xgwa.width > 2560) sc->speed *= 2.5; /* Retina displays */ + + sc->image = create_xshm_image (st->dpy, st->xgwa.visual, + st->xgwa.depth, + ZPixmap, &st->shm_info, + 1, max_height); + + if (!sc->image) + { + fprintf (stderr, "%s: out of memory (allocating 1x%d image)\n", + progname, sc->image->height); + exit (1); + } + } + + reshape_memscroller (st); + return st; +} + + +static void +reshape_memscroller (state *st) +{ + int i; + + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + + for (i = 0; i < st->nscrollers; i++) + { + scroller *sc = &st->scrollers[i]; + + if (i == 0) + { + sc->rez = 6; /* #### */ + + if (st->xgwa.width > 2560) sc->rez *= 2.5; /* Retina displays */ + + sc->rect.width = (((int) (st->xgwa.width * 0.8) + / sc->rez) * sc->rez); + sc->rect.height = (((int) (st->xgwa.height * 0.3) + / sc->rez) * sc->rez); + + sc->rect.x = (st->xgwa.width - sc->rect.width) / 2; + sc->rect.y = (st->xgwa.height - sc->rect.height) / 2; + } + else + { + scroller *sc0 = &st->scrollers[i-1]; + sc->rez = sc0->rez * 1.8; + + sc->rect.x = sc0->rect.x; + sc->rect.y = (sc0->rect.y + sc0->rect.height + st->border + + (st->border + 2) * 7); + sc->rect.width = sc0->rect.width; + sc->rect.height = (((int) (st->xgwa.height * 0.1) + / sc->rez) * sc->rez); + } + + XDrawRectangle (st->dpy, st->window, st->draw_gc, + sc->rect.x - st->border*2, + sc->rect.y - st->border*2, + sc->rect.width + st->border*4, + sc->rect.height + st->border*4); + } +} + + + +# ifdef READ_FILES +static void +open_file (state *st) +{ + if (st->in) + { + fclose (st->in); + st->in = 0; + } + + st->in = fopen (st->filename, "r"); + if (!st->in) + { + char buf[1024]; + sprintf (buf, "%s: %s", progname, st->filename); + perror (buf); + exit (1); + } +} +#endif + + +/* "The brk and sbrk functions are historical curiosities left over + from earlier days before the advent of virtual memory management." + -- sbrk(2) man page on BSD systems, as of 1995 or so. + */ +#ifdef HAVE_SBRK +# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)) /* gcc >= 4.2 */ + /* Don't print "warning: 'sbrk' is deprecated". */ +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +# endif +#endif + + +static unsigned int +more_bits (state *st, scroller *sc) +{ + static unsigned char *lomem = 0; + static unsigned char *himem = 0; + unsigned char r, g, b; + + /* vv: Each incoming byte rolls through all 4 bytes of this (it is sc->value) + This is the number displayed at the top. + pv: the pixel color value. incoming bytes land in R,G,B, or maybe just G. + */ + unsigned int vv, pv; + + unsigned int rmsk = st->scrollers[0].image->red_mask; + unsigned int gmsk = st->scrollers[0].image->green_mask; + unsigned int bmsk = st->scrollers[0].image->blue_mask; + unsigned int amsk = ~(rmsk | gmsk | bmsk); + + vv = sc->value; + + /* Pack RGB into a pixel according to the XImage component masks; + set the remaining bits to 1 for the benefit of HAVE_JWXYZ alpha. + */ +# undef PACK +# define PACK() ((((r << 24) | (r << 16) | (r << 8) | r) & rmsk) | \ + (((g << 24) | (g << 16) | (g << 8) | g) & gmsk) | \ + (((b << 24) | (b << 16) | (b << 8) | b) & bmsk) | \ + amsk) + + switch (st->seed_mode) + { + case SEED_RAM: + if (himem == 0) + { + lomem = (unsigned char *) progname; /* not first malloc, but early */ + himem = (unsigned char *) /* not last malloc, but late */ + st->scrollers[st->nscrollers-1].image->data; + } + + if (sc->data < lomem) + sc->data = lomem; + +# ifdef HAVE_SBRK /* re-get it each time through */ + himem = ((unsigned char *) sbrk(0)) - (2 * sizeof(void *)); +# endif + + if (!lomem || !himem) + { + /* bad craziness! give up! */ + st->seed_mode = SEED_RANDOM; + return 0; + } + + /* I don't understand what's going on there, but on MacOS X, we're + getting insane values for lomem and himem (both Xlib and HAVE_JWXYZ). + Does malloc() draw from more than one heap? */ + if ((unsigned long) himem - (unsigned long) lomem > 0x0FFFFFFF) { +# if 0 + fprintf (stderr, "%s: wonky: 0x%08x - 0x%08x = 0x%08x\n", progname, + (unsigned int) himem, (unsigned int) lomem, + (unsigned int) himem - (unsigned int) lomem); +# endif + himem = lomem + 0xFFFF; + } + + if (lomem >= himem) abort(); + + RETRY: + if (sc->data >= himem) + sc->data = lomem; + + switch (st->draw_mode) + { + case DRAW_COLOR: + r = *sc->data++; + g = *sc->data++; + b = *sc->data++; + vv = (vv << 24) | (r << 16) | (g << 8) | b; + break; + case DRAW_MONO: + r = 0; + g = *sc->data++; + b = 0; + vv = (vv << 8) | g; + break; + default: + abort(); + } + + pv = PACK(); + + /* avoid having many seconds of blackness: truncate zeros at 24K. + */ + if (vv == 0) + sc->count_zero++; + else + sc->count_zero = 0; + if (sc->count_zero > 1024 * (st->draw_mode == DRAW_COLOR ? 24 : 8)) + goto RETRY; + + break; + + case SEED_RANDOM: + vv = random(); + switch (st->draw_mode) + { + case DRAW_COLOR: + r = (vv >> 16) & 0xFF; + g = (vv >> 8) & 0xFF; + b = (vv ) & 0xFF; + break; + case DRAW_MONO: + r = 0; + g = vv & 0xFF; + b = 0; + break; + default: + abort(); + } + pv = PACK(); + break; + +# ifdef READ_FILES + case SEED_FILE: + { + int i; + + /* this one returns only bytes from the file */ +# define GETC(V) \ + do { \ + i = fgetc (st->in); \ + } while (i == EOF \ + ? (open_file (st), 1) \ + : 0); \ + V = i + + /* this one returns a null at EOF -- else we hang on zero-length files */ +# undef GETC +# define GETC(V) \ + i = fgetc (st->in); \ + if (i == EOF) { i = 0; open_file (st); } \ + V = i + + if (!st->in) + open_file (st); + + switch (st->draw_mode) + { + case DRAW_COLOR: + GETC(r); + GETC(g); + GETC(b); + vv = (vv << 24) | (r << 16) | (g << 8) | b; + break; + case DRAW_MONO: + r = 0; + GETC(g); + b = 0; + vv = (vv << 8) | g; + break; + default: + abort(); + } +# undef GETC + pv = PACK(); + } + break; +# endif /* READ_FILES */ + + default: + abort(); + } + +# undef PACK + + sc->value = vv; + return pv; +} + + +static void +draw_string (state *st) +{ + char buf[40]; + int direction, ascent, descent; + int bot = st->scrollers[0].rect.y; + const char *fmt = "%08X"; + int i; + + /* Draw the first font that fits. + */ + for (i = 0; i < countof (st->fonts); i++) + { + XCharStruct overall; + int x, y, w, h; + + if (! st->fonts[i]) continue; + + sprintf (buf, fmt, 0); + XTextExtents (st->fonts[i], buf, strlen(buf), + &direction, &ascent, &descent, &overall); + sprintf (buf, "%08X", st->scrollers[0].value); + + w = overall.width; + h = ascent + descent + 1; + x = (st->xgwa.width - w) / 2; + y = (bot - h) / 2; + + if (y + h + 10 <= bot && x > -10) + { + XSetFont (st->dpy, st->text_gc, st->fonts[i]->fid); + XFillRectangle (st->dpy, st->window, st->erase_gc, + x-w-1, y-1, w*3+2, h+2); + XDrawString (st->dpy, st->window, st->text_gc, + x, y + ascent, buf, strlen(buf)); + break; + } + } +} + + +static unsigned long +memscroller_draw (Display *dpy, Window window, void *closure) +{ + state *st = (state *) closure; + int i; + draw_string (st); + + for (i = 0; i < st->nscrollers; i++) + { + scroller *sc = &st->scrollers[i]; + int j; + + XCopyArea (st->dpy, st->window, st->window, st->draw_gc, + sc->rect.x + sc->speed, sc->rect.y, + sc->rect.width - sc->speed, sc->rect.height, + sc->rect.x, sc->rect.y); + + if (sc->scroll_tick == 0) + { + int top = ((sc->image->bytes_per_line * sc->rect.height) / + (4 * sc->rez)); + unsigned int *out = (unsigned int *) sc->image->data; + for (j = 0; j < top; j++) + { + unsigned int v = more_bits(st, sc); + int k; + for (k = 0; k < sc->rez; k++) + *out++ = v; + } + } + + sc->scroll_tick++; + if (sc->scroll_tick * sc->speed >= sc->rez) + sc->scroll_tick = 0; + + for (j = 0; j < sc->speed; j++) + { + put_xshm_image (st->dpy, st->window, st->draw_gc, sc->image, + 0, 0, + sc->rect.x + sc->rect.width - sc->image->width - j, + sc->rect.y, + sc->rect.width, sc->rect.height, + &st->shm_info); + } + } + + return st->delay; +} + + +static void +memscroller_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + state *st = (state *) closure; + XClearWindow (st->dpy, st->window); + reshape_memscroller (st); +} + +static Bool +memscroller_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + return False; +} + + +static void +memscroller_free (Display *dpy, Window window, void *closure) +{ +} + + +static const char *memscroller_defaults [] = { + ".background: black", + "*drawMode: color", + "*fpsSolid: true", + "*fpsTop: true", + "*filename: (RAM)", + ".textColor: #00FF00", + ".foreground: #00FF00", + "*borderSize: 2", + +#if defined(HAVE_COCOA) || defined(HAVE_ANDROID) + ".font1: OCR A Std 192, Lucida Console 192, Monaco 192", + ".font2: OCR A Std 144, Lucida Console 144, Monaco 144", + ".font3: OCR A Std 128, Lucida Console 128, Monaco 128", + ".font4: OCR A Std 96, Lucida Console 96, Monaco 96", + ".font5: OCR A Std 48, Lucida Console 48, Monaco 48", + ".font6: OCR A Std 24, Lucida Console 24, Monaco 24", +#elif 0 /* real X11, XQueryFont() */ + ".font1: -*-courier-bold-r-*-*-*-1440-*-*-m-*-*-*", + ".font2: -*-courier-bold-r-*-*-*-960-*-*-m-*-*-*", + ".font3: -*-courier-bold-r-*-*-*-480-*-*-m-*-*-*", + ".font4: -*-courier-bold-r-*-*-*-320-*-*-m-*-*-*", + ".font5: -*-courier-bold-r-*-*-*-180-*-*-m-*-*-*", + ".font6: fixed", +#else /* real X11, load_font_retry() */ + ".font1: -*-ocr a std-medium-r-*-*-*-1440-*-*-m-*-*-*", + ".font2: -*-ocr a std-medium-r-*-*-*-960-*-*-m-*-*-*", + ".font3: -*-ocr a std-medium-r-*-*-*-480-*-*-m-*-*-*", + ".font4: -*-ocr a std-medium-r-*-*-*-320-*-*-m-*-*-*", + ".font5: -*-ocr a std-medium-r-*-*-*-180-*-*-m-*-*-*", + ".font6: -*-ocr a std-medium-r-*-*-*-120-*-*-m-*-*-*", +#endif /* X11 */ + + "*delay: 10000", + "*offset: 0", + 0 +}; + +static XrmOptionDescRec memscroller_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-font", ".font", XrmoptionSepArg, 0 }, + { "-filename", ".filename", XrmoptionSepArg, 0 }, + { "-color", ".drawMode", XrmoptionNoArg, "color" }, + { "-mono", ".drawMode", XrmoptionNoArg, "mono" }, + { "-ram", ".filename", XrmoptionNoArg, "(RAM)" }, + { "-random", ".filename", XrmoptionNoArg, "(RANDOM)" }, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("MemScroller", memscroller) -- cgit v1.2.3-55-g7522