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/spotlight.c | 353 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 353 insertions(+) create mode 100644 hacks/spotlight.c (limited to 'hacks/spotlight.c') diff --git a/hacks/spotlight.c b/hacks/spotlight.c new file mode 100644 index 0000000..7385899 --- /dev/null +++ b/hacks/spotlight.c @@ -0,0 +1,353 @@ +/* + * spotlight - an xscreensaver module + * Copyright (c) 1999, 2001 Rick Schultz + * + * loosely based on the BackSpace module "StefView" by Darcy Brockbank + */ + +/* modified from a module from the xscreensaver distribution */ + +/* + * xscreensaver, Copyright (c) 1992-2006 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. + */ + + +/* #define DEBUG */ +#include +#include +#include "screenhack.h" + +#define X_PERIOD 15000.0 +#define Y_PERIOD 12000.0 + +struct state { + Display *dpy; + Window window; + Screen *screen; + + int sizex, sizey; /* screen size */ + int delay; + int duration; + time_t start_time; + int first_time; + GC window_gc; +#ifdef DEBUG + GC white_gc; +#endif + GC buffer_gc; /* draw in buffer, then flush to screen + to avoid flicker */ + int radius; /* radius of spotlight in pixels */ + + Pixmap pm; /* pixmap grabbed from screen */ + Pixmap buffer; /* pixmap for the buffer */ + + int x, y, s; /* x & y coords of buffer (upper left corner) */ + /* s is the width of the buffer */ + + int off; /* random offset from currentTimeInMs(), so that + two concurrent copies of spotlight have different + behavior. */ + + int oldx, oldy, max_x_speed, max_y_speed; + /* used to keep the new buffer position + over the old spotlight image to make sure + the old image is completely erased */ + + Bool first_p; + async_load_state *img_loader; + XRectangle geom; +}; + + +/* The path the spotlight follows around the screen is sinusoidal. + This function is fed to sin() to get the x & y coords */ +static long +currentTimeInMs(struct state *st) +{ + struct timeval curTime; + unsigned long ret_unsigned; +#ifdef GETTIMEOFDAY_TWO_ARGS + struct timezone tz = {0,0}; + gettimeofday(&curTime, &tz); +#else + gettimeofday(&curTime); +#endif + ret_unsigned = curTime.tv_sec *1000U + curTime.tv_usec / 1000; + return (ret_unsigned <= LONG_MAX) ? ret_unsigned : -1 - (long)(ULONG_MAX - ret_unsigned); +} + + +static void * +spotlight_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XGCValues gcv; + XWindowAttributes xgwa; + long gcflags; + Colormap cmap; + unsigned long bg; + GC clip_gc; + Pixmap clip_pm; + + st->dpy = dpy; + st->window = window; + st->first_p = True; + + XGetWindowAttributes (st->dpy, st->window, &xgwa); + st->screen = xgwa.screen; + st->sizex = xgwa.width; + st->sizey = xgwa.height; + cmap = xgwa.colormap; + bg = get_pixel_resource (st->dpy, cmap, "background", "Background"); + + /* read parameters, keep em sane */ + st->delay = get_integer_resource (st->dpy, "delay", "Integer"); + if (st->delay < 1) st->delay = 1; + st->duration = get_integer_resource (st->dpy, "duration", "Seconds"); + if (st->duration < 1) st->duration = 1; + st->radius = get_integer_resource (st->dpy, "radius", "Integer"); + if (st->radius < 0) st->radius = 125; + + if (xgwa.width > 2560) st->radius *= 2; /* Retina displays */ + + /* Don't let the spotlight be bigger than the window */ + while (st->radius > xgwa.width * 0.45) + st->radius /= 2; + while (st->radius > xgwa.height * 0.45) + st->radius /= 2; + + if (st->radius < 4) + st->radius = 4; + + /* do the dance */ + gcv.function = GXcopy; + gcv.subwindow_mode = IncludeInferiors; + gcflags = GCForeground | GCFunction; + gcv.foreground = bg; + +#ifdef NOPE + if (use_subwindow_mode_p(xgwa.screen, st->window)) /* see grabscreen.c */ + gcflags |= GCSubwindowMode; +#endif + st->window_gc = XCreateGC(st->dpy, st->window, gcflags, &gcv); + + st->pm = XCreatePixmap(st->dpy, st->window, st->sizex, st->sizey, xgwa.depth); + XClearWindow(st->dpy, st->window); + + st->first_time = 1; + + /* create buffer to reduce flicker */ +#ifdef HAVE_JWXYZ /* Don't second-guess Quartz's double-buffering */ + st->buffer = 0; +#else + st->buffer = XCreatePixmap(st->dpy, st->window, st->sizex, st->sizey, xgwa.depth); +#endif + + st->buffer_gc = XCreateGC(st->dpy, (st->buffer ? st->buffer : window), gcflags, &gcv); + if (st->buffer) + XFillRectangle(st->dpy, st->buffer, st->buffer_gc, 0, 0, st->sizex, st->sizey); + + /* create clip mask (so it's a circle, not a square) */ + clip_pm = XCreatePixmap(st->dpy, st->window, st->radius*4, st->radius*4, 1); + st->img_loader = load_image_async_simple (0, xgwa.screen, st->window, st->pm, + 0, &st->geom); + st->start_time = time ((time_t *) 0); + + gcv.foreground = 0L; + clip_gc = XCreateGC(st->dpy, clip_pm, gcflags, &gcv); + XFillRectangle(st->dpy, clip_pm, clip_gc, 0, 0, st->radius*4, st->radius*4); + + XSetForeground(st->dpy, clip_gc, 1L); + XFillArc(st->dpy, clip_pm, clip_gc, st->radius , st->radius, + st->radius*2, st->radius*2, 0, 360*64); + + /* set buffer's clip mask to the one we just made */ + XSetClipMask(st->dpy, st->buffer_gc, clip_pm); + + /* free everything */ + XFreeGC(st->dpy, clip_gc); + XFreePixmap(st->dpy, clip_pm); + + /* avoid remants */ + st->max_x_speed = st->max_y_speed = st->radius; + + st->off = random(); + + /* blank out screen */ + XFillRectangle(st->dpy, st->window, st->window_gc, 0, 0, st->sizex, st->sizey); + + return st; +} + + +/* + * perform one iteration + */ +static void +onestep (struct state *st, Bool first_p) +{ + long now; + unsigned long now_unsigned; + + if (st->img_loader) /* still loading */ + { + st->img_loader = load_image_async_simple (st->img_loader, 0, 0, 0, 0, + &st->geom); + if (! st->img_loader) { /* just finished */ + st->start_time = time ((time_t *) 0); + } + return; + } + + if (!st->img_loader && + st->start_time + st->duration < time ((time_t *) 0)) { + st->img_loader = load_image_async_simple (0, st->screen, st->window, + st->pm, 0, &st->geom); + return; + } + +#define nrnd(x) (random() % (x)) + + st->oldx = st->x; + st->oldy = st->y; + + st->s = st->radius *4 ; /* s = width of buffer */ + + now_unsigned = (unsigned long) currentTimeInMs(st) + st->off; + now = (now_unsigned <= LONG_MAX) ? now_unsigned : -1 - (long)(ULONG_MAX - now_unsigned); + + /* find new x,y */ + st->x = st->geom.x + + ((1 + sin(((double)now) / X_PERIOD * 2. * M_PI))/2.0) + * (st->geom.width - st->s/2) -st->s/4; + st->y = st->geom.y + + ((1 + sin(((double)now) / Y_PERIOD * 2. * M_PI))/2.0) + * (st->geom.height - st->s/2) -st->s/4; + + if (!st->first_p) + { + /* limit change in x and y to buffer width */ + if ( st->x < (st->oldx - st->max_x_speed) ) st->x = st->oldx - st->max_x_speed; + if ( st->x > (st->oldx + st->max_x_speed) ) st->x = st->oldx + st->max_x_speed; + if ( st->y < (st->oldy - st->max_y_speed) ) st->y = st->oldy - st->max_y_speed; + if ( st->y > (st->oldy + st->max_y_speed) ) st->y = st->oldy + st->max_y_speed; + } + + if (! st->buffer) + { + XClearWindow (st->dpy, st->window); + XSetClipOrigin(st->dpy, st->buffer_gc, st->x,st->y); + XCopyArea(st->dpy, st->pm, st->window, st->buffer_gc, st->x, st->y, st->s, st->s, st->x, st->y); + } + else + { + /* clear buffer */ + XFillRectangle(st->dpy, st->buffer, st->buffer_gc, st->x, st->y, st->s, st->s); + + /* copy area of screen image (pm) to buffer + Clip to a circle */ + XSetClipOrigin(st->dpy, st->buffer_gc, st->x,st->y); + XCopyArea(st->dpy, st->pm, st->buffer, st->buffer_gc, st->x, st->y, st->s, st->s, st->x, st->y); + + if (st->first_time) { + /* blank out screen */ + XFillRectangle(st->dpy, st->window, st->window_gc, 0, 0, st->sizex, st->sizey); + st->first_time = 0; + } + + /* copy buffer to screen (window) */ + XCopyArea(st->dpy, st->buffer, st->window, st->window_gc, st->x , st->y, st->s, st->s, st->x, st->y); + +# if 0 + XSetForeground (st->dpy, st->window_gc, + WhitePixel (st->dpy, DefaultScreen (st->dpy))); + XDrawRectangle(st->dpy, st->window, st->window_gc, + st->geom.x, st->geom.y, st->geom.width, st->geom.height); +# endif + } + +#ifdef DEBUG + /* draw a box around the buffer */ + XDrawRectangle(st->dpy, st->window, st->white_gc, st->x , st->y, st->s, st->s); +#endif + +} + + +static unsigned long +spotlight_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + onestep(st, st->first_p); + st->first_p = False; + return st->delay; +} + +static void +spotlight_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +static Bool +spotlight_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + struct state *st = (struct state *) closure; + if (screenhack_event_helper (dpy, window, event)) + { + st->start_time = 0; + return True; + } + return False; +} + +static void +spotlight_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + XFreeGC (dpy, st->window_gc); + XFreeGC (dpy, st->buffer_gc); + if (st->pm) XFreePixmap (dpy, st->pm); + if (st->buffer) XFreePixmap (dpy, st->buffer); + free (st); +} + + + + +static const char *spotlight_defaults [] = { + ".background: black", + ".foreground: white", + "*dontClearRoot: True", + "*fpsSolid: true", + +#ifdef __sgi /* really, HAVE_READ_DISPLAY_EXTENSION */ + "*visualID: Best", +#endif + + "*delay: 10000", + "*duration: 120", + "*radius: 125", +#ifdef HAVE_MOBILE + "*ignoreRotation: True", + "*rotateImages: True", +#endif + 0 +}; + +static XrmOptionDescRec spotlight_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-duration", ".duration", XrmoptionSepArg, 0 }, + { "-radius", ".radius", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("Spotlight", spotlight) -- cgit v1.2.3-55-g7522