-/* xscreensaver, Copyright (c) 2005 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 2005-2013 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 "screenhack.h"
#include <stdio.h>
-#include <X11/Xutil.h>
+#include "xpm-pixmap.h"
#define ALIVE 1
#define CHANGED 2
+#define UNDEAD 4
typedef struct {
unsigned long fill_color;
Window window;
XWindowAttributes xgwa;
GC gc;
- unsigned long bg_color;
+ unsigned long fg_color, bg_color;
int border_size;
int spacing;
int inc;
+ int mode;
Bool circles_p;
Bool growing_p;
Bool color_horiz_p;
int nboxes;
box *boxes;
+ XImage *image;
int ncolors;
XColor *colors;
+ int delay;
+ int countdown;
+
+ Bool done_once;
+ async_load_state *img_loader;
+ Pixmap loading_pixmap;
+
} state;
static void
reset_boxes (state *st)
{
- static Bool once = False;
- int mode = -1;
-
st->nboxes = 0;
st->growing_p = True;
st->color_horiz_p = random() & 1;
- if (once)
- free_colors (st->dpy, st->xgwa.colormap, st->colors, st->ncolors);
+ if (st->done_once && st->colors)
+ free_colors (st->xgwa.screen, st->xgwa.colormap, st->colors, st->ncolors);
- if (!once)
+ if (!st->done_once)
{
- char *s = get_string_resource ("mode", "Mode");
+ char *s = get_string_resource (st->dpy, "mode", "Mode");
if (!s || !*s || !strcasecmp (s, "random"))
- mode = -1;
+ st->mode = -1;
else if (!strcasecmp (s, "squares") || !strcasecmp (s, "square"))
- mode = 0;
+ st->mode = 0;
else if (!strcasecmp (s, "circles") || !strcasecmp (s, "circle"))
- mode = 1;
+ st->mode = 1;
else
{
fprintf (stderr,
}
}
- if (mode == -1)
+ if (st->mode == -1)
st->circles_p = random() & 1;
else
- st->circles_p = (mode == 1);
+ st->circles_p = (st->mode == 1);
- once = True;
+ st->done_once = True;
- st->ncolors = get_integer_resource ("colors", "Colors"); /* re-get this */
- make_smooth_colormap (st->dpy, st->xgwa.visual, st->xgwa.colormap,
- st->colors, &st->ncolors, True, 0, False);
- XClearWindow (st->dpy, st->window);
+ if (st->image || get_boolean_resource (st->dpy, "grab", "Boolean"))
+ {
+ if (st->image) XDestroyImage (st->image);
+ st->image = 0;
+
+ if (st->loading_pixmap) abort();
+ if (st->img_loader) abort();
+ if (!get_boolean_resource (st->dpy, "peek", "Boolean"))
+ st->loading_pixmap = XCreatePixmap (st->dpy, st->window,
+ st->xgwa.width, st->xgwa.height,
+ st->xgwa.depth);
+
+ XClearWindow (st->dpy, st->window);
+ st->img_loader = load_image_async_simple (0, st->xgwa.screen,
+ st->window,
+ (st->loading_pixmap
+ ? st->loading_pixmap
+ : st->window),
+ 0, 0);
+ }
+ else
+ {
+ st->ncolors = get_integer_resource (st->dpy, "colors", "Colors"); /* re-get */
+ if (st->ncolors < 1) st->ncolors = 1;
+ make_smooth_colormap (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap,
+ st->colors, &st->ncolors, True, 0, False);
+ if (st->ncolors < 1) abort();
+ XClearWindow (st->dpy, st->window);
+ }
}
-state *
-init_boxes (Display *dpy, Window window)
+static void
+reshape_boxes (state *st)
+{
+ int i;
+ XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
+ for (i = 0; i < st->nboxes; i++)
+ {
+ box *b = &st->boxes[i];
+ b->flags |= CHANGED;
+ }
+}
+
+static void *
+boxfit_init (Display *dpy, Window window)
{
XGCValues gcv;
state *st = (state *) calloc (1, sizeof (*st));
st->dpy = dpy;
st->window = window;
+ st->delay = get_integer_resource (dpy, "delay", "Integer");
XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
- XSelectInput (dpy, window, st->xgwa.your_event_mask | ExposureMask);
+/* XSelectInput (dpy, window, st->xgwa.your_event_mask | ExposureMask);*/
- st->ncolors = get_integer_resource ("colors", "Colors");
- if (st->ncolors < 1) st->ncolors = 1;
- st->colors = (XColor *) malloc (sizeof(XColor) * st->ncolors);
+ if (! get_boolean_resource (dpy, "grab", "Boolean"))
+ {
+ st->ncolors = get_integer_resource (dpy, "colors", "Colors");
+ if (st->ncolors < 1) st->ncolors = 1;
+ st->colors = (XColor *) malloc (sizeof(XColor) * st->ncolors);
+ }
- st->inc = get_integer_resource ("growBy", "GrowBy");
- st->spacing = get_integer_resource ("spacing", "Spacing");
- st->border_size = get_integer_resource ("borderSize", "BorderSize");
- st->bg_color = get_pixel_resource ("background", "Background",
- st->dpy, st->xgwa.colormap);
+ st->inc = get_integer_resource (dpy, "growBy", "GrowBy");
+ st->spacing = get_integer_resource (dpy, "spacing", "Spacing");
+ st->border_size = get_integer_resource (dpy, "borderSize", "BorderSize");
+ st->fg_color = get_pixel_resource (st->dpy, st->xgwa.colormap,
+ "foreground", "Foreground");
+ st->bg_color = get_pixel_resource (st->dpy, st->xgwa.colormap,
+ "background", "Background");
if (st->inc < 1) st->inc = 1;
if (st->border_size < 0) st->border_size = 0;
gcv.background = st->bg_color;
st->gc = XCreateGC (st->dpy, st->window, GCBackground|GCLineWidth, &gcv);
- st->box_count = get_integer_resource ("boxCount", "BoxCount");
+ st->box_count = get_integer_resource (dpy, "boxCount", "BoxCount");
if (st->box_count < 1) st->box_count = 1;
st->nboxes = 0;
reset_boxes (st);
+ reshape_boxes (st);
return st;
}
-static void
-reshape_boxes (state *st)
-{
- int i;
- XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
- for (i = 0; i < st->nboxes; i++)
- {
- box *b = &st->boxes[i];
- b->flags |= CHANGED;
- }
-}
static Bool
}
-static void
+static unsigned int
grow_boxes (state *st)
{
int inc2 = st->inc + st->spacing + st->border_size;
}
a = &st->boxes[st->nboxes-1];
- a->flags |= CHANGED;
+ a->flags = CHANGED;
- for (i = 0; i < 10000; i++)
+ for (i = 0; i < 100; i++)
{
a->x = inc2 + (random() % (st->xgwa.width - inc2));
a->y = inc2 + (random() % (st->xgwa.height - inc2));
{
st->nboxes--; /* go into "fade out" mode now. */
st->growing_p = False;
-
- XSync (st->dpy, False);
- sleep (1);
-
- break;
+ return 2000000; /* make customizable... */
}
/* Pick colors for this box */
- {
- int n = (st->color_horiz_p
- ? (a->x * st->ncolors / st->xgwa.width)
- : (a->y * st->ncolors / st->xgwa.height));
- a->fill_color = st->colors [n % st->ncolors].pixel;
- }
+ if (st->image)
+ {
+ int w = st->image->width;
+ int h = st->image->height;
+ a->fill_color = XGetPixel (st->image, a->x % w, a->y % h);
+ }
+ else
+ {
+ int n = (st->color_horiz_p
+ ? (a->x * st->ncolors / st->xgwa.width)
+ : (a->y * st->ncolors / st->xgwa.height));
+ a->fill_color = st->colors [n % st->ncolors].pixel;
+ }
}
+
+ return st->delay;
}
-static void
+static unsigned int
shrink_boxes (state *st)
{
int i;
remaining++;
}
- if (remaining == 0)
+ if (remaining == 0) {
reset_boxes (st);
+ return 1000000;
+ } else {
+ return st->delay;
+ }
}
{
box *b = &st->boxes[i];
+ if (b->flags & UNDEAD) continue;
+ if (! (b->flags & CHANGED)) continue;
+ b->flags &= ~CHANGED;
+
if (!st->growing_p)
{
/* When shrinking, black out an area outside of the border
before re-drawing the box.
*/
- XSetForeground (st->dpy, st->gc, st->bg_color);
- XSetLineAttributes (st->dpy, st->gc,
- (st->inc + st->border_size) * 2,
- LineSolid, CapButt, JoinMiter);
+ int margin = st->inc + st->border_size;
+ XSetForeground (st->dpy, st->gc, st->bg_color);
if (st->circles_p)
- XDrawArc (st->dpy, st->window, st->gc,
- b->x, b->y,
- (b->w > 0 ? b->w : 1),
- (b->h > 0 ? b->h : 1),
+ XFillArc (st->dpy, st->window, st->gc,
+ b->x - margin, b->y - margin,
+ b->w + (margin*2), b->h + (margin*2),
0, 360*64);
else
- XDrawRectangle (st->dpy, st->window, st->gc,
- b->x, b->y,
- (b->w > 0 ? b->w : 1),
- (b->h > 0 ? b->h : 1));
- XSetLineAttributes (st->dpy, st->gc, st->border_size,
- LineSolid, CapButt, JoinMiter);
+ XFillRectangle (st->dpy, st->window, st->gc,
+ b->x - margin, b->y - margin,
+ b->w + (margin*2), b->h + (margin*2));
+
+ if (b->w <= 0 || b->h <= 0)
+ b->flags |= UNDEAD; /* really very dead now */
}
if (b->w <= 0 || b->h <= 0) continue;
- if (! (b->flags & CHANGED)) continue;
- b->flags &= ~CHANGED;
XSetForeground (st->dpy, st->gc, b->fill_color);
if (st->border_size > 0)
{
- unsigned long bd = st->colors [(b->fill_color + st->ncolors/2)
- % st->ncolors].pixel;
+ unsigned int bd = (st->image
+ ? st->fg_color
+ : st->colors [(b->fill_color + st->ncolors/2)
+ % st->ncolors].pixel);
XSetForeground (st->dpy, st->gc, bd);
if (st->circles_p)
XDrawArc (st->dpy, st->window, st->gc, b->x, b->y, b->w, b->h,
}
}
-static void
-handle_events (state *st)
+
+static unsigned long
+boxfit_draw (Display *dpy, Window window, void *closure)
{
- XSync (st->dpy, False);
- while (XPending (st->dpy))
+ state *st = (state *) closure;
+ int delay;
+
+ if (st->img_loader) /* still loading */
{
- XEvent event;
- XNextEvent (st->dpy, &event);
- if (event.xany.type == ConfigureNotify ||
- event.xany.type == Expose)
- reshape_boxes (st);
- else if (event.xany.type == ButtonPress)
- st->growing_p = !st->growing_p;
-
- screenhack_handle_event (st->dpy, &event);
+ st->img_loader = load_image_async_simple (st->img_loader, 0, 0, 0, 0, 0);
+ if (! st->img_loader) /* just finished */
+ {
+ st->image = XGetImage (st->dpy,
+ (st->loading_pixmap ? st->loading_pixmap :
+ st->window),
+ 0, 0,
+ st->xgwa.width, st->xgwa.height, ~0L,
+ ZPixmap);
+ if (st->loading_pixmap) XFreePixmap (st->dpy, st->loading_pixmap);
+ XSetWindowBackground (st->dpy, st->window, st->bg_color);
+ if (st->loading_pixmap)
+ XClearWindow (st->dpy, st->window);
+ else
+ st->countdown = 2000000;
+ st->loading_pixmap = 0;
+ }
+ return st->delay;
}
+
+ if (st->countdown > 0)
+ {
+ st->countdown -= st->delay;
+ if (st->countdown <= 0)
+ {
+ st->countdown = 0;
+ XClearWindow (st->dpy, st->window);
+ }
+ return st->delay;
+ }
+
+ if (st->growing_p) {
+ draw_boxes (st);
+ delay = grow_boxes (st);
+ } else {
+ delay = shrink_boxes (st);
+ draw_boxes (st);
+ }
+ return delay;
}
+static void
+boxfit_reshape (Display *dpy, Window window, void *closure,
+ unsigned int w, unsigned int h)
+{
+ state *st = (state *) closure;
+ reshape_boxes (st);
+}
-\f
-char *progclass = "BoxFit";
+static Bool
+boxfit_event (Display *dpy, Window window, void *closure, XEvent *event)
+{
+ state *st = (state *) closure;
+ if (event->xany.type == ButtonPress) {
+ st->growing_p = !st->growing_p;
+ return True;
+ }
+ return False;
+}
-char *defaults [] = {
+static void
+boxfit_free (Display *dpy, Window window, void *closure)
+{
+}
+
+
+static const char *boxfit_defaults [] = {
".background: black",
+ ".foreground: #444444",
+ "*fpsSolid: true",
"*delay: 20000",
"*mode: random",
"*colors: 64",
"*growBy: 1",
"*spacing: 1",
"*borderSize: 1",
+ "*grab: False",
+ "*peek: False",
+ "*grabDesktopImages: False", /* HAVE_COCOA */
+ "*chooseRandomImages: True", /* HAVE_COCOA */
+#ifdef USE_IPHONE
+ "*ignoreRotation: True",
+#endif
0
};
-XrmOptionDescRec options [] = {
+static XrmOptionDescRec boxfit_options [] = {
{ "-delay", ".delay", XrmoptionSepArg, 0 },
{ "-colors", ".colors", XrmoptionSepArg, 0 },
{ "-count", ".boxCount", XrmoptionSepArg, 0 },
{ "-growby", ".growBy", XrmoptionSepArg, 0 },
{ "-spacing", ".spacing", XrmoptionSepArg, 0 },
{ "-border", ".borderSize", XrmoptionSepArg, 0 },
+ { "-mode", ".mode", XrmoptionSepArg, 0 },
{ "-circles", ".mode", XrmoptionNoArg, "circles" },
{ "-squares", ".mode", XrmoptionNoArg, "squares" },
{ "-random", ".mode", XrmoptionNoArg, "random" },
+ { "-grab", ".grab", XrmoptionNoArg, "True" },
+ { "-no-grab", ".grab", XrmoptionNoArg, "False" },
+ { "-peek", ".peek", XrmoptionNoArg, "True" },
+ { "-no-peek", ".peek", XrmoptionNoArg, "False" },
{ 0, 0, 0, 0 }
};
-void
-screenhack (Display *dpy, Window window)
-{
- state *st = init_boxes (dpy, window);
- int delay = get_integer_resource ("delay", "Integer");
- reshape_boxes (st);
- while (1)
- {
- if (st->growing_p)
- grow_boxes (st);
- else
- shrink_boxes (st);
-
- draw_boxes (st);
- handle_events (st);
- if (delay) usleep (delay);
- }
-}
+XSCREENSAVER_MODULE ("BoxFit", boxfit)