/* xscreensaver, Copyright (c) 1997-2013 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. */ #include "screenhack.h" #ifdef HAVE_DOUBLE_BUFFER_EXTENSION # include "xdbe.h" #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ struct state { Display *dpy; Window window; int ncolors; XColor *colors; int fg_pixel, bg_pixel; Pixmap p0, p1, p2, p3; GC copy_gc, erase_gc, window_gc; int width, height, size; int x1, x2, y1, y2, x3, y3; int dx1, dx2, dx3, dy1, dy2, dy3; int othickness, thickness; Bool do_three; #ifdef HAVE_DOUBLE_BUFFER_EXTENSION XdbeBackBuffer back_buf; #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ Bool flip_a, flip_b; int pix; int delay, color_shift; int reset; int iterations, iteration; }; static void moire2_init_1 (struct state *st) { XWindowAttributes xgwa; XGetWindowAttributes (st->dpy, st->window, &xgwa); st->othickness = get_integer_resource(st->dpy, "thickness", "Thickness"); if (mono_p) st->ncolors = 2; else st->ncolors = get_integer_resource (st->dpy, "colors", "Colors"); if (st->ncolors < 2) st->ncolors = 2; if (st->ncolors <= 2) mono_p = True; if (mono_p) st->colors = 0; else st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1)); if (mono_p) ; else make_smooth_colormap (xgwa.screen, xgwa.visual, xgwa.colormap, st->colors, &st->ncolors, True, 0, True); st->bg_pixel = get_pixel_resource(st->dpy, xgwa.colormap, "background", "Background"); st->fg_pixel = get_pixel_resource(st->dpy, xgwa.colormap, "foreground", "Foreground"); #ifdef HAVE_DOUBLE_BUFFER_EXTENSION st->back_buf = xdbe_get_backbuffer (st->dpy, st->window, XdbeUndefined); #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ } static void reset_moire2 (struct state *st) { GC gc; XWindowAttributes xgwa; XGCValues gcv; Bool xor; XGetWindowAttributes (st->dpy, st->window, &xgwa); st->do_three = (0 == (random() % 3)); st->width = xgwa.width; st->height = xgwa.height; st->size = st->width > st->height ? st->width : st->height; if (st->p0) XFreePixmap(st->dpy, st->p0); if (st->p1) XFreePixmap(st->dpy, st->p1); if (st->p2) XFreePixmap(st->dpy, st->p2); if (st->p3) XFreePixmap(st->dpy, st->p3); st->p0 = XCreatePixmap(st->dpy, st->window, st->width, st->height, 1); st->p1 = XCreatePixmap(st->dpy, st->window, st->width*2, st->height*2, 1); st->p2 = XCreatePixmap(st->dpy, st->window, st->width*2, st->height*2, 1); if (st->do_three) st->p3 = XCreatePixmap(st->dpy, st->window, st->width*2, st->height*2, 1); else st->p3 = 0; st->thickness = (st->othickness > 0 ? st->othickness : (1 + (random() % 4))); gcv.foreground = 0; gcv.line_width = (st->thickness == 1 ? 0 : st->thickness); gc = XCreateGC (st->dpy, st->p1, GCForeground|GCLineWidth, &gcv); XFillRectangle(st->dpy, st->p1, gc, 0, 0, st->width*2, st->height*2); XFillRectangle(st->dpy, st->p2, gc, 0, 0, st->width*2, st->height*2); if (st->do_three) XFillRectangle(st->dpy, st->p3, gc, 0, 0, st->width*2, st->height*2); XSetForeground(st->dpy, gc, 1); xor = (st->do_three || (st->thickness == 1) || (random() & 1)); { int i, ii, maxx, maxy; #define FROB(P) do { \ maxx = (st->size*4); \ maxy = (st->size*4); \ if (0 == (random() % 5)) { \ float f = 1.0 + frand(0.05); \ if (random() & 1) maxx *= f; \ else maxy *= f; \ } \ ii = (st->thickness + 1 + (xor ? 0 : 1) + (random() % (4 * st->thickness))); \ for (i = 0; i < (st->size*2); i += ii) \ XDrawArc(st->dpy, (P), gc, i-st->size, i-st->size, maxx-i-i, maxy-i-i, 0, 360*64); \ if (0 == (random() % 5)) \ { \ XSetFunction(st->dpy, gc, GXxor); \ XFillRectangle(st->dpy, (P), gc, 0, 0, st->width*2, st->height*2); \ XSetFunction(st->dpy, gc, GXcopy); \ } \ } while(0) FROB(st->p1); FROB(st->p2); if (st->do_three) FROB(st->p3); #undef FROB } XFreeGC(st->dpy, gc); if (st->copy_gc) XFreeGC(st->dpy, st->copy_gc); gcv.function = (xor ? GXxor : GXor); gcv.foreground = 1; gcv.background = 0; st->copy_gc = XCreateGC (st->dpy, st->p0, GCFunction|GCForeground|GCBackground, &gcv); gcv.foreground = 0; if (st->erase_gc) XFreeGC(st->dpy, st->erase_gc); st->erase_gc = XCreateGC (st->dpy, st->p0, GCForeground, &gcv); gcv.foreground = st->fg_pixel; gcv.background = st->bg_pixel; if (st->window_gc) XFreeGC(st->dpy, st->window_gc); st->window_gc = XCreateGC (st->dpy, st->window, GCForeground|GCBackground, &gcv); #define FROB(N,DN,MAX) \ N = (MAX/2) + (random() % MAX); \ DN = ((1 + (random() % (7*st->thickness))) * ((random() & 1) ? 1 : -1)) FROB(st->x1,st->dx1,st->width); FROB(st->x2,st->dx2,st->width); FROB(st->x3,st->dx3,st->width); FROB(st->y1,st->dy1,st->height); FROB(st->y2,st->dy2,st->height); FROB(st->y3,st->dy3,st->height); #undef FROB } static void moire2 (struct state *st) { #define FROB(N,DN,MAX) \ N += DN; \ if (N <= 0) N = 0, DN = -DN; \ else if (N >= MAX) N = MAX, DN = -DN; \ else if (0 == (random() % 100)) DN = -DN; \ else if (0 == (random() % 50)) \ DN += (DN <= -20 ? 1 : (DN >= 20 ? -1 : ((random() & 1) ? 1 : -1))) FROB(st->x1,st->dx1,st->width); FROB(st->x2,st->dx2,st->width); FROB(st->x3,st->dx3,st->width); FROB(st->y1,st->dy1,st->height); FROB(st->y2,st->dy2,st->height); FROB(st->y3,st->dy3,st->height); #undef FROB XFillRectangle(st->dpy, st->p0, st->erase_gc, 0, 0, st->width, st->height); XCopyArea(st->dpy, st->p1, st->p0, st->copy_gc, st->x1, st->y1, st->width, st->height, 0, 0); XCopyArea(st->dpy, st->p2, st->p0, st->copy_gc, st->x2, st->y2, st->width, st->height, 0, 0); if (st->do_three) XCopyArea(st->dpy, st->p3, st->p0, st->copy_gc, st->x3, st->y3, st->width, st->height, 0, 0); #ifdef HAVE_DOUBLE_BUFFER_EXTENSION if (st->back_buf) { XdbeSwapInfo info[1]; info[0].swap_window = st->window; info[0].swap_action = XdbeUndefined; XCopyPlane (st->dpy, st->p0, st->back_buf, st->window_gc, 0, 0, st->width, st->height, 0, 0, 1L); XdbeSwapBuffers (st->dpy, info, 1); } else #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ XCopyPlane (st->dpy, st->p0, st->window, st->window_gc, 0, 0, st->width, st->height, 0, 0, 1L); #if 0 XCopyPlane(st->dpy, st->p1, st->window, st->window_gc, (st->width*2)/3, (st->height*2)/3, st->width/2, st->height/2, 0, st->height/2, 1L); XCopyPlane(st->dpy, st->p2, st->window, st->window_gc, (st->width*2)/3, (st->height*2)/3, st->width/2, st->height/2, st->width/2, st->height/2, 1L); #endif } static void * moire2_init (Display *dpy, Window window) { struct state *st = (struct state *) calloc (1, sizeof(*st)); st->dpy = dpy; st->window = window; st->reset = 1; st->delay = get_integer_resource (st->dpy, "delay", "Integer"); st->color_shift = get_integer_resource (st->dpy, "colorShift", "Integer"); if (st->color_shift <= 0) st->color_shift = 1; moire2_init_1 (st); return st; } static unsigned long moire2_draw (Display *dpy, Window window, void *closure) { struct state *st = (struct state *) closure; if (st->reset) { st->reset = 0; st->iteration = 0; st->iterations = 30 + (random() % 70) + (random() % 70); reset_moire2 (st); st->flip_a = mono_p ? False : (random() & 1); st->flip_b = mono_p ? False : (random() & 1); if (st->flip_b) { XSetForeground(st->dpy, st->window_gc, st->bg_pixel); XSetBackground(st->dpy, st->window_gc, st->fg_pixel); } else { XSetForeground(st->dpy, st->window_gc, st->fg_pixel); XSetBackground(st->dpy, st->window_gc, st->bg_pixel); } } if (!mono_p) { st->pix++; st->pix = st->pix % st->ncolors; if (st->flip_a) XSetBackground(st->dpy, st->window_gc, st->colors[st->pix].pixel); else XSetForeground(st->dpy, st->window_gc, st->colors[st->pix].pixel); } moire2 (st); st->iteration++; if (st->iteration >= st->color_shift) { st->iteration = 0; st->iterations--; if (st->iterations <= 0) st->reset = 1; } return st->delay; } static void moire2_reshape (Display *dpy, Window window, void *closure, unsigned int w, unsigned int h) { struct state *st = (struct state *) closure; st->reset = 1; } static Bool moire2_event (Display *dpy, Window window, void *closure, XEvent *event) { return False; } static void moire2_free (Display *dpy, Window window, void *closure) { struct state *st = (struct state *) closure; XFreeGC (dpy, st->copy_gc); XFreeGC (dpy, st->erase_gc); XFreeGC (dpy, st->window_gc); free (st->colors); free (st); } static const char *moire2_defaults [] = { ".lowrez: true", ".background: black", ".foreground: white", "*delay: 50000", "*thickness: 0", "*colors: 150", "*colorShift: 5", #ifdef HAVE_MOBILE "*ignoreRotation: True", #endif #ifdef HAVE_DOUBLE_BUFFER_EXTENSION /* Off by default, since it slows it down a lot, and the flicker isn't really all that bad without it... Or rather, it flickers just as badly with it. The XFree86 implementation of the XDBE extension totally blows! There is just *no* excuse for the "swap buffers" operation to flicker like it does. */ "*useDBE: False", #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ 0 }; static XrmOptionDescRec moire2_options [] = { { "-delay", ".delay", XrmoptionSepArg, 0 }, { "-ncolors", ".colors", XrmoptionSepArg, 0 }, { "-thickness", ".thickness", XrmoptionSepArg, 0 }, { 0, 0, 0, 0 } }; XSCREENSAVER_MODULE ("Moire2", moire2)