X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=hacks%2Fslidescreen.c;h=42d3fefca029a6b10a03d81b640f7f334f942f90;hp=22c7fe28cc7982368ca3f7128006516cce4deef3;hb=07faf451b99879183ed7e909e43a0e065be1ee7f;hpb=3f438031d610c7e15fd33876a879b97e290e05fb diff --git a/hacks/slidescreen.c b/hacks/slidescreen.c index 22c7fe28..42d3fefc 100644 --- a/hacks/slidescreen.c +++ b/hacks/slidescreen.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1992-2005 Jamie Zawinski +/* 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 @@ -14,60 +14,80 @@ enum { DOWN = 0, LEFT, UP, RIGHT }; enum { VERTICAL, HORIZONTAL }; -static int grid_size; -static int pix_inc; -static int hole_x, hole_y; -static int bitmap_w, bitmap_h; -static int xoff, yoff; -static int grid_w, grid_h; -static int delay, delay2; -static GC gc; -static int max_width, max_height; +struct state { + Display *dpy; + Window window; + + int grid_size; + int pix_inc; + int hole_x, hole_y; + int bitmap_w, bitmap_h; + int xoff, yoff; + int grid_w, grid_h; + int delay, delay2; + GC gc; + unsigned long fg, bg; + int max_width, max_height; + int early_i; -static void -init_slide (Display *dpy, Window window) + int draw_rnd, draw_i; + int draw_x, draw_y, draw_ix, draw_iy, draw_dx, draw_dy; + int draw_dir, draw_w, draw_h, draw_size, draw_inc; + int draw_last; + int draw_initted; + + async_load_state *img_loader; +}; + + +static void * +slidescreen_init (Display *dpy, Window window) { - int i; - XGCValues gcv; + struct state *st = (struct state *) calloc (1, sizeof(*st)); XWindowAttributes xgwa; - long gcflags; - int border; - unsigned long fg, bg; - Drawable d; - Colormap cmap; Visual *visual; + XGCValues gcv; + long gcflags; + + st->dpy = dpy; + st->window = window; + XGetWindowAttributes (st->dpy, st->window, &xgwa); + st->img_loader = load_image_async_simple (0, xgwa.screen, st->window, + st->window, 0, 0); - XGetWindowAttributes (dpy, window, &xgwa); - load_random_image (xgwa.screen, window, window, NULL, NULL); - cmap = xgwa.colormap; visual = xgwa.visual; - max_width = xgwa.width; - max_height = xgwa.height; + st->max_width = xgwa.width; + st->max_height = xgwa.height; - delay = get_integer_resource ("delay", "Integer"); - delay2 = get_integer_resource ("delay2", "Integer"); - grid_size = get_integer_resource ("gridSize", "Integer"); - pix_inc = get_integer_resource ("pixelIncrement", "Integer"); - border = get_integer_resource ("internalBorderWidth", "InternalBorderWidth"); + st->delay = get_integer_resource (st->dpy, "delay", "Integer"); + st->delay2 = get_integer_resource (st->dpy, "delay2", "Integer"); + st->grid_size = get_integer_resource (st->dpy, "gridSize", "Integer"); + st->pix_inc = get_integer_resource (st->dpy, "pixelIncrement", "Integer"); + + /* Don't let the grid be smaller than 5x5 */ + while (st->grid_size > xgwa.width / 5) + st->grid_size /= 2; + while (st->grid_size > xgwa.height / 5) + st->grid_size /= 2; + + if (st->delay < 0) st->delay = 0; + if (st->delay2 < 0) st->delay2 = 0; + if (st->pix_inc < 1) st->pix_inc = 1; + if (st->grid_size < 1) st->grid_size = 1; - /* Don't let the grid be smaller than 3x3 */ - if (grid_size > xgwa.width / 3) - grid_size = xgwa.width / 3; - if (grid_size > xgwa.height / 3) - grid_size = xgwa.height / 3; { XColor fgc, bgc; - char *fgs = get_string_resource("background", "Background"); - char *bgs = get_string_resource("foreground", "Foreground"); + char *fgs = get_string_resource(st->dpy, "background", "Background"); + char *bgs = get_string_resource(st->dpy, "foreground", "Foreground"); Bool fg_ok, bg_ok; - if (!XParseColor (dpy, cmap, fgs, &fgc)) - XParseColor (dpy, cmap, "black", &bgc); - if (!XParseColor (dpy, cmap, bgs, &bgc)) - XParseColor (dpy, cmap, "gray", &fgc); + if (!XParseColor (st->dpy, xgwa.colormap, fgs, &fgc)) + XParseColor (st->dpy, xgwa.colormap, "black", &bgc); + if (!XParseColor (st->dpy, xgwa.colormap, bgs, &bgc)) + XParseColor (st->dpy, xgwa.colormap, "gray", &fgc); - fg_ok = XAllocColor (dpy, cmap, &fgc); - bg_ok = XAllocColor (dpy, cmap, &bgc); + fg_ok = XAllocColor (st->dpy, xgwa.colormap, &fgc); + bg_ok = XAllocColor (st->dpy, xgwa.colormap, &bgc); /* If we weren't able to allocate the two colors we want from the colormap (which is likely if the screen has been grabbed on an @@ -76,27 +96,29 @@ init_slide (Display *dpy, Window window) pixels without actually allocating them. */ if (fg_ok) - fg = fgc.pixel; + st->fg = fgc.pixel; else - fg = 0; + st->fg = 0; if (bg_ok) - bg = bgc.pixel; + st->bg = bgc.pixel; else - bg = 1; + st->bg = 1; +#ifndef HAVE_COCOA if (!fg_ok || bg_ok) { + int i; unsigned long fgd = ~0; unsigned long bgd = ~0; - int max = visual_cells (xgwa.screen, visual); + int max = visual_cells (xgwa.screen, xgwa.visual); XColor *all = (XColor *) calloc(sizeof (*all), max); for (i = 0; i < max; i++) { all[i].flags = DoRed|DoGreen|DoBlue; all[i].pixel = i; } - XQueryColors (dpy, cmap, all, max); + XQueryColors (st->dpy, xgwa.colormap, all, max); for(i = 0; i < max; i++) { long rd, gd, bd; @@ -113,7 +135,7 @@ init_slide (Display *dpy, Window window) if (dd < fgd) { fgd = dd; - fg = all[i].pixel; + st->fg = all[i].pixel; if (dd == 0) fg_ok = True; } @@ -131,7 +153,7 @@ init_slide (Display *dpy, Window window) if (dd < bgd) { bgd = dd; - bg = all[i].pixel; + st->bg = all[i].pixel; if (dd == 0) bg_ok = True; } @@ -142,193 +164,270 @@ init_slide (Display *dpy, Window window) } XFree(all); } +#endif /* !HAVE_COCOA */ } - - if (delay < 0) delay = 0; - if (delay2 < 0) delay2 = 0; - if (pix_inc < 1) pix_inc = 1; - if (grid_size < 1) grid_size = 1; - - gcv.foreground = fg; + gcv.foreground = st->fg; gcv.function = GXcopy; gcv.subwindow_mode = IncludeInferiors; gcflags = GCForeground |GCFunction; - if (use_subwindow_mode_p(xgwa.screen, window)) /* see grabscreen.c */ + if (use_subwindow_mode_p(xgwa.screen, st->window)) /* see grabscreen.c */ gcflags |= GCSubwindowMode; - gc = XCreateGC (dpy, window, gcflags, &gcv); + st->gc = XCreateGC (st->dpy, st->window, gcflags, &gcv); - XGetWindowAttributes (dpy, window, &xgwa); - bitmap_w = xgwa.width; - bitmap_h = xgwa.height; + return st; +} - grid_w = bitmap_w / grid_size; - grid_h = bitmap_h / grid_size; - hole_x = random () % grid_w; - hole_y = random () % grid_h; - xoff = (bitmap_w - (grid_w * grid_size)) / 2; - yoff = (bitmap_h - (grid_h * grid_size)) / 2; +static void +draw_grid (struct state *st) +{ + int i; + Drawable d; + int border; + XWindowAttributes xgwa; + + XGetWindowAttributes (st->dpy, st->window, &xgwa); + + border = get_integer_resource (st->dpy, "internalBorderWidth", + "InternalBorderWidth"); + + XGetWindowAttributes (st->dpy, st->window, &xgwa); + st->bitmap_w = xgwa.width; + st->bitmap_h = xgwa.height; + + st->grid_w = st->bitmap_w / st->grid_size; + st->grid_h = st->bitmap_h / st->grid_size; + st->hole_x = random () % st->grid_w; + st->hole_y = random () % st->grid_h; + st->xoff = (st->bitmap_w - (st->grid_w * st->grid_size)) / 2; + st->yoff = (st->bitmap_h - (st->grid_h * st->grid_size)) / 2; - d = window; + d = st->window; + + st->early_i = -10; + st->draw_last = -1; if (border) { int half = border/2; int half2 = (border & 1 ? half+1 : half); - XSetForeground(dpy, gc, bg); - for (i = 0; i < bitmap_w; i += grid_size) + XSetForeground(st->dpy, st->gc, st->bg); + for (i = 0; i < st->bitmap_w; i += st->grid_size) { int j; - for (j = 0; j < bitmap_h; j += grid_size) - XDrawRectangle (dpy, d, gc, - xoff+i+half2, yoff+j+half2, - grid_size-border-1, grid_size-border-1); + for (j = 0; j < st->bitmap_h; j += st->grid_size) + XDrawRectangle (st->dpy, d, st->gc, + st->xoff+i+half2, st->yoff+j+half2, + st->grid_size-border-1, st->grid_size-border-1); } - XSetForeground(dpy, gc, fg); - for (i = 0; i <= bitmap_w; i += grid_size) - XFillRectangle (dpy, d, gc, xoff+i-half, yoff, border, bitmap_h); - for (i = 0; i <= bitmap_h; i += grid_size) - XFillRectangle (dpy, d, gc, xoff, yoff+i-half, bitmap_w, border); + XSetForeground(st->dpy, st->gc, st->fg); + for (i = 0; i <= st->bitmap_w; i += st->grid_size) + XFillRectangle (st->dpy, d, st->gc, st->xoff+i-half, st->yoff, border, st->bitmap_h); + for (i = 0; i <= st->bitmap_h; i += st->grid_size) + XFillRectangle (st->dpy, d, st->gc, st->xoff, st->yoff+i-half, st->bitmap_w, border); } - if (xoff) + if (st->xoff) { - XFillRectangle (dpy, d, gc, 0, 0, xoff, bitmap_h); - XFillRectangle (dpy, d, gc, bitmap_w - xoff, 0, xoff, bitmap_h); + XFillRectangle (st->dpy, d, st->gc, 0, 0, st->xoff, st->bitmap_h); + XFillRectangle (st->dpy, d, st->gc, st->bitmap_w - st->xoff, 0, st->xoff, st->bitmap_h); } - if (yoff) + if (st->yoff) { - XFillRectangle (dpy, d, gc, 0, 0, bitmap_w, yoff); - XFillRectangle (dpy, d, gc, 0, bitmap_h - yoff, bitmap_w, yoff); + XFillRectangle (st->dpy, d, st->gc, 0, 0, st->bitmap_w, st->yoff); + XFillRectangle (st->dpy, d, st->gc, 0, st->bitmap_h - st->yoff, st->bitmap_w, st->yoff); } +} + - XSync (dpy, False); - if (delay2) usleep (delay2); - for (i = 0; i < grid_size; i += pix_inc) +static int +slidescreen_draw_early (struct state *st) +{ + while (st->early_i < 0) + { + st->early_i++; + return 1; + } + + /* for (early_i = 0; early_i < grid_size; early_i += pix_inc) */ { XPoint points [3]; - points[0].x = xoff + grid_size * hole_x; - points[0].y = yoff + grid_size * hole_y; - points[1].x = points[0].x + grid_size; + points[0].x = st->xoff + st->grid_size * st->hole_x; + points[0].y = st->yoff + st->grid_size * st->hole_y; + points[1].x = points[0].x + st->grid_size; points[1].y = points[0].y; points[2].x = points[0].x; - points[2].y = points[0].y + i; - XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin); + points[2].y = points[0].y + st->early_i; + XFillPolygon (st->dpy, st->window, st->gc, points, 3, Convex, CoordModeOrigin); points[1].x = points[0].x; - points[1].y = points[0].y + grid_size; - points[2].x = points[0].x + i; - points[2].y = points[0].y + grid_size; - XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin); + points[1].y = points[0].y + st->grid_size; + points[2].x = points[0].x + st->early_i; + points[2].y = points[0].y + st->grid_size; + XFillPolygon (st->dpy, st->window, st->gc, points, 3, Convex, CoordModeOrigin); - points[0].x = points[1].x + grid_size; + points[0].x = points[1].x + st->grid_size; points[0].y = points[1].y; points[2].x = points[0].x; - points[2].y = points[0].y - i; - XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin); + points[2].y = points[0].y - st->early_i; + XFillPolygon (st->dpy, st->window, st->gc, points, 3, Convex, CoordModeOrigin); points[1].x = points[0].x; - points[1].y = points[0].y - grid_size; - points[2].x = points[1].x - i; + points[1].y = points[0].y - st->grid_size; + points[2].x = points[1].x - st->early_i; points[2].y = points[1].y; - XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin); - - XSync (dpy, False); - if (delay) usleep (delay); + XFillPolygon (st->dpy, st->window, st->gc, points, 3, Convex, CoordModeOrigin); } - XFillRectangle (dpy, window, gc, - xoff + grid_size * hole_x, - yoff + grid_size * hole_y, - grid_size, grid_size); + st->early_i += st->pix_inc; + if (st->early_i < st->grid_size) + return 1; - XSync (dpy, False); - if (delay2) usleep (delay2); + XFillRectangle (st->dpy, st->window, st->gc, + st->xoff + st->grid_size * st->hole_x, + st->yoff + st->grid_size * st->hole_y, + st->grid_size, st->grid_size); + return 0; } -static void -slide1 (Display *dpy, Window window) + +static unsigned long +slidescreen_draw (Display *dpy, Window window, void *closure) { + struct state *st = (struct state *) closure; + int this_delay = st->delay; + /* this code is a total kludge, but who cares, it works... */ - int rnd, i, x, y, ix, iy, dx, dy, dir, w, h, size, inc; - static int last = -1; - - if (last == -1) last = random () % 2; - -/* alternate between horizontal and vertical slides */ -/* note that dir specifies the direction the _hole_ moves, not the tiles */ - if (last == VERTICAL) { - if ((rnd = random () % (grid_w - 1)) < hole_x) { - dx = -1; dir = LEFT; hole_x -= rnd; - } else { - dx = 1; dir = RIGHT; rnd -= hole_x; - } - dy = 0; w = size = rnd + 1; h = 1; - last = HORIZONTAL; - } else { - if ((rnd = random () % (grid_h - 1)) < hole_y) { - dy = -1; dir = UP; hole_y -= rnd; - } else { - dy = 1; dir = DOWN; rnd -= hole_y; - } - dx = 0; h = size = rnd + 1; w = 1; - last = VERTICAL; - } + + if (st->img_loader) /* still loading */ + { + st->img_loader = load_image_async_simple (st->img_loader, 0, 0, 0, 0, 0); + if (! st->img_loader) /* just finished */ + draw_grid (st); + return st->delay; + } + + if (! st->draw_initted) + { + if (!slidescreen_draw_early (st)) + { + st->draw_initted = 1; + return st->delay2; + } + else + return st->delay; + } + + if (st->draw_i == 0) + { + if (st->draw_last == -1) st->draw_last = random () % 2; + + /* alternate between horizontal and vertical slides */ + /* note that draw_dir specifies the direction the _hole_ moves, not the tiles */ + if (st->draw_last == VERTICAL) { + if (((st->grid_w > 1) ? st->draw_rnd = random () % (st->grid_w - 1) : 0) + < st->hole_x) { + st->draw_dx = -1; st->draw_dir = LEFT; st->hole_x -= st->draw_rnd; + } else { + st->draw_dx = 1; st->draw_dir = RIGHT; st->draw_rnd -= st->hole_x; + } + st->draw_dy = 0; st->draw_w = st->draw_size = st->draw_rnd + 1; st->draw_h = 1; + st->draw_last = HORIZONTAL; + } else { + if (((st->grid_h > 1) ? st->draw_rnd = random () % (st->grid_h - 1) : 0) + < st->hole_y) { + st->draw_dy = -1; st->draw_dir = UP; st->hole_y -= st->draw_rnd; + } else { + st->draw_dy = 1; st->draw_dir = DOWN; st->draw_rnd -= st->hole_y; + } + st->draw_dx = 0; st->draw_h = st->draw_size = st->draw_rnd + 1; st->draw_w = 1; + st->draw_last = VERTICAL; + } - ix = x = xoff + (hole_x + dx) * grid_size; - iy = y = yoff + (hole_y + dy) * grid_size; - inc = pix_inc; - for (i = 0; i < grid_size; i += inc) + st->draw_ix = st->draw_x = st->xoff + (st->hole_x + st->draw_dx) * st->grid_size; + st->draw_iy = st->draw_y = st->yoff + (st->hole_y + st->draw_dy) * st->grid_size; + st->draw_inc = st->pix_inc; + + } + + /* for (draw_i = 0; draw_i < grid_size; draw_i += draw_inc) */ { int fx, fy, tox, toy; - if (inc + i > grid_size) - inc = grid_size - i; - tox = x - dx * inc; - toy = y - dy * inc; + if (st->draw_inc + st->draw_i > st->grid_size) + st->draw_inc = st->grid_size - st->draw_i; + tox = st->draw_x - st->draw_dx * st->draw_inc; + toy = st->draw_y - st->draw_dy * st->draw_inc; - fx = (x < 0 ? 0 : x > max_width ? max_width : x); - fy = (y < 0 ? 0 : y > max_height ? max_height : y); - tox = (tox < 0 ? 0 : tox > max_width ? max_width : tox); - toy = (toy < 0 ? 0 : toy > max_height ? max_height : toy); + fx = (st->draw_x < 0 ? 0 : st->draw_x > st->max_width ? st->max_width : st->draw_x); + fy = (st->draw_y < 0 ? 0 : st->draw_y > st->max_height ? st->max_height : st->draw_y); + tox = (tox < 0 ? 0 : tox > st->max_width ? st->max_width : tox); + toy = (toy < 0 ? 0 : toy > st->max_height ? st->max_height : toy); - XCopyArea (dpy, window, window, gc, + XCopyArea (st->dpy, st->window, st->window, st->gc, fx, fy, - grid_size * w, grid_size * h, + st->grid_size * st->draw_w, st->grid_size * st->draw_h, tox, toy); - x -= dx * inc; - y -= dy * inc; - switch (dir) + st->draw_x -= st->draw_dx * st->draw_inc; + st->draw_y -= st->draw_dy * st->draw_inc; + switch (st->draw_dir) { - case DOWN: XFillRectangle (dpy, window, gc, - ix, y + grid_size * h, grid_size * w, iy - y); + case DOWN: XFillRectangle (st->dpy, st->window, st->gc, + st->draw_ix, st->draw_y + st->grid_size * st->draw_h, st->grid_size * st->draw_w, st->draw_iy - st->draw_y); break; - case LEFT: XFillRectangle (dpy, window, gc, ix, iy, x - ix, grid_size * h); + case LEFT: XFillRectangle (st->dpy, st->window, st->gc, st->draw_ix, st->draw_iy, st->draw_x - st->draw_ix, st->grid_size * st->draw_h); break; - case UP: XFillRectangle (dpy, window, gc, ix, iy, grid_size * w, y - iy); + case UP: XFillRectangle (st->dpy, st->window, st->gc, st->draw_ix, st->draw_iy, st->grid_size * st->draw_w, st->draw_y - st->draw_iy); break; - case RIGHT: XFillRectangle (dpy, window, gc, - x + grid_size * w, iy, ix - x, grid_size * h); + case RIGHT: XFillRectangle (st->dpy, st->window, st->gc, + st->draw_x + st->grid_size * st->draw_w, st->draw_iy, st->draw_ix - st->draw_x, st->grid_size * st->draw_h); break; } - - XSync (dpy, False); - if (delay) usleep (delay); - } - switch (dir) - { - case DOWN: hole_y += size; break; - case LEFT: hole_x--; break; - case UP: hole_y--; break; - case RIGHT: hole_x += size; break; } + + st->draw_i += st->draw_inc; + if (st->draw_i >= st->grid_size) + { + st->draw_i = 0; + + switch (st->draw_dir) + { + case DOWN: st->hole_y += st->draw_size; break; + case LEFT: st->hole_x--; break; + case UP: st->hole_y--; break; + case RIGHT: st->hole_x += st->draw_size; break; + } + + this_delay = st->delay2; + } + + return this_delay; +} + +static void +slidescreen_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +static Bool +slidescreen_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + return False; +} + +static void +slidescreen_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + XFreeGC (dpy, st->gc); + free (st); } -char *progclass = "SlidePuzzle"; -char *defaults [] = { +static const char *slidescreen_defaults [] = { "*dontClearRoot: True", #ifdef __sgi /* really, HAVE_READ_DISPLAY_EXTENSION */ @@ -336,7 +435,7 @@ char *defaults [] = { #endif ".background: Black", - ".foreground: Gray", + ".foreground: #BEBEBE", "*gridSize: 70", "*pixelIncrement: 10", "*internalBorderWidth: 4", @@ -345,7 +444,7 @@ char *defaults [] = { 0 }; -XrmOptionDescRec options [] = { +static XrmOptionDescRec slidescreen_options [] = { { "-grid-size", ".gridSize", XrmoptionSepArg, 0 }, { "-ibw", ".internalBorderWidth", XrmoptionSepArg, 0 }, { "-increment", ".pixelIncrement", XrmoptionSepArg, 0 }, @@ -354,14 +453,4 @@ XrmOptionDescRec options [] = { { 0, 0, 0, 0 } }; -void -screenhack (Display *dpy, Window window) -{ - init_slide (dpy, window); - while (1) - { - slide1 (dpy, window); - screenhack_handle_events (dpy); - if (delay2) usleep (delay2); - } -} +XSCREENSAVER_MODULE ("Slidescreen", slidescreen)