1 /* xscreensaver, Copyright (c) 2002, 2004 Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
11 * Memscroller -- scrolls a dump of its own RAM across the screen.
14 #include "screenhack.h"
16 #include <X11/Xutil.h>
18 #ifdef HAVE_XSHM_EXTENSION
36 XWindowAttributes xgwa;
37 GC draw_gc, erase_gc, text_gc;
41 enum { SEED_RAM, SEED_RANDOM, SEED_FILE } seed_mode;
42 enum { DRAW_COLOR, DRAW_MONO } draw_mode;
50 # ifdef HAVE_XSHM_EXTENSION
52 XShmSegmentInfo shm_info;
59 init_memscroller (Display *dpy, Window window)
63 state *st = (state *) calloc (1, sizeof (*st));
67 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
68 XSelectInput(st->dpy, st->window, ExposureMask);
70 /* Fill up the colormap with random colors.
71 We don't actually use these explicitly, but in 8-bit mode,
72 they will be used implicitly by the random image bits. */
76 make_random_colormap (st->dpy, st->xgwa.visual, st->xgwa.colormap,
77 colors, &ncolors, True, True, 0, False);
80 st->border = get_integer_resource ("borderSize", "BorderSize");
83 char *fontname = get_string_resource ("font", "Font");
84 st->font = XLoadQueryFont (dpy, fontname);
88 static const char *fonts[] = {
89 "-*-courier-medium-r-*-*-*-1400-*-*-p-*-*-*",
90 "-*-courier-medium-r-*-*-*-600-*-*-p-*-*-*",
91 "-*-utopia-*-r-*-*-*-1400-*-*-p-*-*-*",
92 "-*-utopia-*-r-*-*-*-600-*-*-p-*-*-*",
93 "-*-utopia-*-r-*-*-*-240-*-*-p-*-*-*",
94 "-*-helvetica-*-r-*-*-*-240-*-*-p-*-*-*",
95 "-*-*-*-r-*-*-*-240-*-*-m-*-*-*",
100 st->font = XLoadQueryFont (dpy, fonts[i]);
105 fprintf (stderr, "%s: couldn't load font \"%s\", using \"%s\"\n",
106 progname, fontname, fonts[i]);
109 fprintf(stderr, "%s: couldn't load any font\n", progname);
115 gcv.line_width = st->border;
117 gcv.background = get_pixel_resource("background", "Background",
118 st->dpy, st->xgwa.colormap);
119 gcv.foreground = get_pixel_resource("textColor", "Foreground",
120 st->dpy, st->xgwa.colormap);
121 gcv.font = st->font->fid;
122 st->text_gc = XCreateGC (st->dpy, st->window,
123 GCForeground|GCBackground|GCFont, &gcv);
125 gcv.foreground = get_pixel_resource("foreground", "Foreground",
126 st->dpy, st->xgwa.colormap);
127 st->draw_gc = XCreateGC (st->dpy, st->window,
128 GCForeground|GCBackground|GCLineWidth,
130 gcv.foreground = gcv.background;
131 st->erase_gc = XCreateGC (st->dpy, st->window,
132 GCForeground|GCBackground, &gcv);
135 s = get_string_resource ("drawMode", "DrawMode");
136 if (!s || !*s || !strcasecmp (s, "color"))
137 st->draw_mode = DRAW_COLOR;
138 else if (!strcasecmp (s, "mono"))
139 st->draw_mode = DRAW_MONO;
142 fprintf (stderr, "%s: drawMode must be 'mono' or 'color', not '%s'\n",
150 st->filename = get_string_resource ("filename", "Filename");
154 !strcasecmp (st->filename, "(ram)") ||
155 !strcasecmp (st->filename, "(mem)") ||
156 !strcasecmp (st->filename, "(memory)"))
157 st->seed_mode = SEED_RAM;
158 else if (st->filename &&
159 (!strcasecmp (st->filename, "(rand)") ||
160 !strcasecmp (st->filename, "(random)")))
161 st->seed_mode = SEED_RANDOM;
163 st->seed_mode = SEED_FILE;
166 st->scrollers = (scroller *) calloc (st->nscrollers, sizeof(scroller));
168 for (i = 0; i < st->nscrollers; i++)
170 scroller *sc = &st->scrollers[i];
171 int max_height = 4096;
177 # ifdef HAVE_XSHM_EXTENSION
178 st->shm_p = get_boolean_resource ("useSHM", "Boolean");
181 sc->image = create_xshm_image (st->dpy, st->xgwa.visual,
183 ZPixmap, 0, &st->shm_info,
188 # endif /* HAVE_XSHM_EXTENSION */
191 sc->image = XCreateImage (st->dpy, st->xgwa.visual, st->xgwa.depth,
192 ZPixmap, 0, 0, 1, max_height, 8, 0);
194 if (sc->image && !sc->image->data)
195 sc->image->data = (char *)
196 malloc (sc->image->bytes_per_line * sc->image->height + 1);
198 if (!sc->image || !sc->image->data)
200 fprintf (stderr, "%s: out of memory (allocating 1x%d image)\n",
201 progname, sc->image->height);
211 reshape_memscroller (state *st)
215 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
217 for (i = 0; i < st->nscrollers; i++)
219 scroller *sc = &st->scrollers[i];
223 sc->rez = 6; /* #### */
225 sc->rect.width = (((int) (st->xgwa.width * 0.8)
226 / sc->rez) * sc->rez);
227 sc->rect.height = (((int) (st->xgwa.height * 0.3)
228 / sc->rez) * sc->rez);
230 sc->rect.x = (st->xgwa.width - sc->rect.width) / 2;
231 sc->rect.y = (st->xgwa.height - sc->rect.height) / 2;
235 scroller *sc0 = &st->scrollers[i-1];
236 sc->rez = sc0->rez * 1.8;
238 sc->rect.x = sc0->rect.x;
239 sc->rect.y = (sc0->rect.y + sc0->rect.height + st->border
240 + (st->border + 2) * 7);
241 sc->rect.width = sc0->rect.width;
242 sc->rect.height = (((int) (st->xgwa.height * 0.1)
243 / sc->rez) * sc->rez);
246 XDrawRectangle (st->dpy, st->window, st->draw_gc,
247 sc->rect.x - st->border*2,
248 sc->rect.y - st->border*2,
249 sc->rect.width + st->border*4,
250 sc->rect.height + st->border*4);
257 open_file (state *st)
265 st->in = fopen (st->filename, "r");
269 sprintf (buf, "%s: %s", progname, st->filename);
277 more_bits (state *st, scroller *sc)
279 static unsigned char *lomem = 0;
280 static unsigned char *himem = 0;
281 unsigned char r, g, b;
284 /* Pack bytes as RGBR so that we don't have to worry about actually
285 figuring out the color channel order.
288 # define PACK(r,g,b) ((r) | ((g) << 8) | ((b) << 16) | ((r) << 24))
290 switch (st->seed_mode)
295 lomem = (unsigned char *) progname; /* not first malloc, but early */
296 himem = (unsigned char *) /* not last malloc, but late */
297 st->scrollers[st->nscrollers-1].image->data;
300 if (sc->data < lomem)
303 # ifdef HAVE_SBRK /* re-get it each time through */
304 himem = ((unsigned char *) sbrk(0)) - (2 * sizeof(void *));
307 /* I don't understand what's going on there, but on MacOS X,
308 we're getting insane values for lomem and himem. Is there
309 more than one heap? */
310 if ((unsigned long) himem - (unsigned long) lomem > 0x0FFFFFFF)
311 himem = lomem + 0xFFFF;
313 if (lomem >= himem) abort();
316 if (sc->data >= himem)
319 switch (st->draw_mode)
337 /* avoid having many seconds of blackness: truncate zeros at 24K.
343 if (sc->count_zero > 1024 * (st->draw_mode == DRAW_COLOR ? 24 : 8))
350 switch (st->draw_mode)
353 r = (v >> 16) & 0xFF;
372 /* this one returns only bytes from the file */
375 i = fgetc (st->in); \
377 ? (open_file (st), 1) \
381 /* this one returns a null at EOF -- else we hang on zero-length files */
384 i = fgetc (st->in); \
385 if (i == EOF) { i = 0; open_file (st); } \
391 switch (st->draw_mode)
421 draw_string (state *st, unsigned int n)
424 int direction, ascent, descent;
427 int bot = st->scrollers[0].rect.y;
428 const char *fmt = "%08X";
430 sprintf (buf, fmt, 0);
431 XTextExtents (st->font, buf, strlen(buf),
432 &direction, &ascent, &descent, &overall);
433 sprintf (buf, "%08X", n);
436 h = st->font->ascent + st->font->descent + 1;
437 x = (st->xgwa.width - w) / 2;
440 if (y + h + 10 > bot) return;
442 XFillRectangle (st->dpy, st->window, st->erase_gc,
444 XDrawString (st->dpy, st->window, st->text_gc,
445 x, y + st->font->ascent, buf, strlen(buf));
450 draw_memscroller (state *st)
454 draw_string (st, *((unsigned int *) st->scrollers[0].image->data));
456 for (i = 0; i < st->nscrollers; i++)
458 scroller *sc = &st->scrollers[i];
461 XCopyArea (st->dpy, st->window, st->window, st->draw_gc,
462 sc->rect.x + sc->speed, sc->rect.y,
463 sc->rect.width - sc->speed, sc->rect.height,
464 sc->rect.x, sc->rect.y);
466 if (sc->scroll_tick == 0)
468 int top = ((sc->image->bytes_per_line * sc->rect.height) /
470 unsigned int *out = (unsigned int *) sc->image->data;
471 for (j = 0; j < top; j++)
473 unsigned int v = more_bits(st, sc);
475 for (k = 0; k < sc->rez; k++)
481 if (sc->scroll_tick * sc->speed >= sc->rez)
484 for (j = 0; j < sc->speed; j++)
486 # ifdef HAVE_XSHM_EXTENSION
488 XShmPutImage (st->dpy, st->window, st->draw_gc, sc->image,
490 sc->rect.x + sc->rect.width - sc->image->width - j,
492 sc->rect.width, sc->rect.height,
495 # endif /* HAVE_XSHM_EXTENSION */
496 XPutImage (st->dpy, st->window, st->draw_gc, sc->image,
498 sc->rect.x + sc->rect.width - sc->image->width - j,
500 sc->rect.width, sc->rect.height);
506 handle_events (state *st)
508 XSync (st->dpy, False);
509 while (XPending (st->dpy))
512 XNextEvent (st->dpy, &event);
513 if (event.xany.type == ConfigureNotify ||
514 event.xany.type == Expose)
516 XClearWindow (st->dpy, st->window);
517 reshape_memscroller (st);
520 screenhack_handle_event (st->dpy, &event);
526 char *progclass = "MemScroller";
528 char *defaults [] = {
529 ".background: black",
532 ".textColor: #00FF00",
533 ".foreground: #00FF00",
535 ".font: -*-courier-medium-r-*-*-*-1400-*-*-m-*-*-*",
541 XrmOptionDescRec options [] = {
542 { "-delay", ".delay", XrmoptionSepArg, 0 },
543 { "-font", ".font", XrmoptionSepArg, 0 },
544 { "-filename", ".filename", XrmoptionSepArg, 0 },
545 { "-color", ".drawMode", XrmoptionNoArg, "color" },
546 { "-mono", ".drawMode", XrmoptionNoArg, "mono" },
547 { "-ram", ".filename", XrmoptionNoArg, "(RAM)" },
548 { "-random", ".filename", XrmoptionNoArg, "(RANDOM)" },
554 screenhack (Display *dpy, Window window)
556 state *st = init_memscroller (dpy, window);
557 int delay = get_integer_resource ("delay", "Integer");
558 reshape_memscroller (st);
561 draw_memscroller (st);
564 if (delay) usleep (delay);