1 /* erase.c: Erase the screen in various more or less interesting ways.
2 * Copyright (c) 1997-2001 Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
12 * Portions (c) 1997 by Johannes Keukelaar <johannes@nada.kth.se>:
13 * Permission to use in any way granted. Provided "as is" without expressed
14 * or implied warranty. NO WARRANTY, NO EXPRESSION OF SUITABILITY FOR ANY
15 * PURPOSE. (I.e.: Use in any way, but at your own risk!)
21 #include "resources.h"
23 extern char *progname;
26 #define countof(x) (sizeof(x)/sizeof(*(x)))
28 #define LITTLE_NAP 5000 /* 1/200th sec */
30 typedef void (*Eraser) (Display *dpy, Window window, GC gc,
31 int width, int height, int total_msecs);
38 # ifdef GETTIMEOFDAY_TWO_ARGS
40 gettimeofday (&tt, &tz);
44 return (tt.tv_sec * 1000) + (tt.tv_usec / 1000);
49 random_lines (Display *dpy, Window window, GC gc,
50 int width, int height, int total_msecs)
54 Bool horiz_p = (random() & 1);
55 int max = (horiz_p ? height : width);
56 int *lines = (int *) calloc(max, sizeof(*lines));
59 unsigned long start_tick = millitime();
60 unsigned long end_tick = start_tick + total_msecs;
61 unsigned long tick = start_tick;
65 for (i = 0; i < max; i++)
68 for (i = 0; i < max; i++)
77 while (tick < end_tick)
79 int i = (max * (tick - start_tick)) / (end_tick - start_tick);
91 for (j = 0; j < granularity; j++)
93 int ii = i * granularity + j;
95 if (ii >= horiz_p ? height : width) /* don't go off array */
99 XDrawLine (dpy, window, gc, 0, lines[ii], width, lines[ii]);
101 XDrawLine (dpy, window, gc, lines[ii], 0, lines[ii], height);
116 venetian (Display *dpy, Window window, GC gc,
117 int width, int height, int total_msecs)
119 Bool horiz_p = (random() & 1);
120 Bool flip_p = (random() & 1);
121 int max = (horiz_p ? height : width);
122 int *lines = (int *) calloc(max, sizeof(*lines));
126 unsigned long start_tick = millitime();
127 unsigned long end_tick = (start_tick +
128 (1.5 * total_msecs)); /* this one needs more */
129 unsigned long tick = start_tick;
134 for (i = 0; i < max*2; i++)
136 int line = ((i / 16) * 16) - ((i % 16) * 15);
137 if (line >= 0 && line < max)
138 lines[j++] = (flip_p ? max - line : line);
141 while (tick < end_tick)
143 int i = (max * (tick - start_tick)) / (end_tick - start_tick);
153 for (k = oi; k <= i; k++)
156 XDrawLine(dpy,window, gc, 0, lines[k], width, lines[k]);
158 XDrawLine(dpy,window, gc, lines[k], 0, lines[k], height);
172 triple_wipe (Display *dpy, Window window, GC gc,
173 int width, int height, int total_msecs)
175 Bool flip_x = random() & 1;
176 Bool flip_y = random() & 1;
177 int max = width + (height / 2);
178 int *lines = (int *)calloc(max, sizeof(int));
182 unsigned long start_tick = millitime();
183 unsigned long end_tick = start_tick + total_msecs;
184 unsigned long tick = start_tick;
188 for(i = 0; i < width/2; i++)
189 lines[i] = i*2+height;
190 for(i = 0; i < height/2; i++)
191 lines[i+width/2] = i*2;
192 for(i = 0; i < width/2; i++)
193 lines[i+width/2+height/2] = width-i*2-(width%2?0:1)+height;
195 while (tick < end_tick)
197 int i = (max * (tick - start_tick)) / (end_tick - start_tick);
208 for (k = oi; k <= i; k++)
210 if (lines[k] < height)
211 x = 0, y = lines[k], x2 = width, y2 = y;
213 x = lines[k]-height, y = 0, x2 = x, y2 = height;
216 x = width-x, x2 = width-x2;
218 y = height-y, y2 = height-y2;
220 XDrawLine (dpy, window, gc, x, y, x2, y2);
234 quad_wipe (Display *dpy, Window window, GC gc,
235 int width, int height, int total_msecs)
237 Bool flip_x = random() & 1;
238 Bool flip_y = random() & 1;
239 int max = width + height;
240 int *lines = (int *)calloc(max, sizeof(int));
244 unsigned long start_tick = millitime();
245 unsigned long end_tick = start_tick + total_msecs;
246 unsigned long tick = start_tick;
250 for (i = 0; i < max/4; i++)
253 lines[i*4+1] = height-i*2-(height%2?0:1);
254 lines[i*4+2] = height+i*2;
255 lines[i*4+3] = height+width-i*2-(width%2?0:1);
258 while (tick < end_tick)
260 int i = (max * (tick - start_tick)) / (end_tick - start_tick);
270 for (k = oi; k <= i; k++)
273 if (lines[k] < height)
274 x = 0, y = lines[k], x2 = width, y2 = y;
276 x = lines[k]-height, y = 0, x2 = x, y2 = height;
279 x = width-x, x2 = width-x2;
281 y = height-y, y2 = height-y2;
283 XDrawLine (dpy, window, gc, x, y, x2, y2);
299 circle_wipe (Display *dpy, Window window, GC gc,
300 int width, int height, int total_msecs)
303 int start = random() % max;
304 int rad = (width > height ? width : height);
305 int flip_p = random() & 1;
308 unsigned long start_tick = millitime();
309 unsigned long end_tick = start_tick + total_msecs;
310 unsigned long tick = start_tick;
315 oth = (flip_p ? max : 0);
316 while (tick < end_tick)
318 int th = (max * (tick - start_tick)) / (end_tick - start_tick);
320 th = (360 * 64) - th;
329 XFillArc(dpy, window, gc,
330 (width/2)-rad, (height/2)-rad, rad*2, rad*2,
331 (start+oth)%(360*64),
344 three_circle_wipe (Display *dpy, Window window, GC gc,
345 int width, int height, int total_msecs)
347 int max = (360 * 64) / 6;
348 int start = random() % max;
349 int rad = (width > height ? width : height);
352 unsigned long start_tick = millitime();
353 unsigned long end_tick = start_tick + total_msecs;
354 unsigned long tick = start_tick;
360 while (tick < end_tick)
362 int th = (max * (tick - start_tick)) / (end_tick - start_tick);
372 XFillArc(dpy, window, gc,
373 (width/2)-rad, (height/2)-rad, rad*2, rad*2,
374 (start+off+oth)%(360*64),
376 XFillArc(dpy, window, gc,
377 (width/2)-rad, (height/2)-rad, rad*2, rad*2,
378 ((start+off-oth))%(360*64),
382 XFillArc(dpy, window, gc,
383 (width/2)-rad, (height/2)-rad, rad*2, rad*2,
384 (start+off+oth)%(360*64),
386 XFillArc(dpy, window, gc,
387 (width/2)-rad, (height/2)-rad, rad*2, rad*2,
388 ((start+off-oth))%(360*64),
392 XFillArc(dpy, window, gc,
393 (width/2)-rad, (height/2)-rad, rad*2, rad*2,
394 (start+off+oth)%(360*64),
396 XFillArc(dpy, window, gc,
397 (width/2)-rad, (height/2)-rad, rad*2, rad*2,
398 ((start+off-oth))%(360*64),
412 squaretate (Display *dpy, Window window, GC gc,
413 int width, int height, int total_msecs)
415 int max = ((width > height ? width : width) * 2);
417 Bool flip = random() & 1;
419 unsigned long start_tick = millitime();
420 unsigned long end_tick = start_tick + total_msecs;
421 unsigned long tick = start_tick;
427 points[0].x = width-points[0].x; \
428 points[1].x = width-points[1].x; \
429 points[2].x = width-points[2].x; } \
430 XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin)
432 while (tick < end_tick)
434 int i = (max * (tick - start_tick)) / (end_tick - start_tick);
449 points[2].y = points[0].y + ((i * height) / max);
455 points[1].y = height;
456 points[2].x = ((i * width) / max);
457 points[2].y = height;
461 points[0].y = height;
463 points[1].y = height;
465 points[2].y = height - ((i * height) / max);
469 points[0].y = height;
472 points[2].x = width - ((i * width) / max);
486 /* from Frederick Roeber <roeber@netscape.com> */
488 fizzle (Display *dpy, Window window, GC gc,
489 int width, int height, int total_msecs)
491 /* These dimensions must be prime numbers. They should be roughly the
492 square root of the width and height. */
495 # define SIZE (BX*BY)
505 unsigned long start_tick = millitime();
506 unsigned long end_tick = (start_tick +
507 (2.5 * total_msecs)); /* this one needs more */
508 unsigned long tick = start_tick;
512 /* Distribute the numbers [0,SIZE) randomly in the array */
516 for( i = 0; i < SIZE; i++ ) {
521 for( i = 0; i < SIZE; i++ ) {
522 j = random()%(SIZE-i);
523 array[indices[j]] = i;
524 indices[j] = indices[SIZE-i-1];
528 /* nx, ny are the number of cells across and down, rounded up */
529 nx = width / BX + (0 == (width %BX) ? 0 : 1);
530 ny = height / BY + (0 == (height%BY) ? 0 : 1);
531 skews = (XPoint *)malloc(sizeof(XPoint) * (nx*ny));
532 if( (XPoint *)0 != skews ) {
533 for( i = 0; i < nx; i++ ) {
534 for( j = 0; j < ny; j++ ) {
535 skews[j * nx + i].x = random()%BX;
536 skews[j * nx + i].y = random()%BY;
541 # define SKEWX(cx, cy) (((XPoint *)0 == skews)?0:skews[cy*nx + cx].x)
542 # define SKEWY(cx, cy) (((XPoint *)0 == skews)?0:skews[cy*nx + cx].y)
544 while (tick < end_tick)
546 int i = (SIZE * (tick - start_tick)) / (end_tick - start_tick);
556 for (j = oi; j < i; j++)
558 int x = array[j] % BX;
559 int y = array[j] / BX;
561 for (iy = 0, cy = 0; iy < height; iy += BY, cy++)
564 for( ix = 0, cx = 0; ix < width; ix += BX, cx++ ) {
565 int xx = ix + (SKEWX(cx, cy) + x*((cx%(BX-1))+1))%BX;
566 int yy = iy + (SKEWY(cx, cy) + y*((cy%(BY-1))+1))%BY;
567 if (xx < width && yy < height)
569 points[npoints].x = xx;
570 points[npoints].y = yy;
571 if (++npoints == countof(points))
573 XDrawPoints(dpy, window, gc, points, npoints,
591 XDrawPoints(dpy, window, gc, points, npoints, CoordModeOrigin);
602 if (skews) free(skews);
606 /* from Rick Campbell <rick@campbellcentral.org> */
608 spiral (Display *dpy, Window window, GC context,
609 int width, int height, int total_msecs)
611 int granularity = 1; /* #### */
613 double pi2 = (M_PI + M_PI);
615 int angle_step = 1000 / 8; /* disc granularity is 8 degrees */
616 int max = pi2 * angle_step;
623 total_msecs *= 2.5; /* this one needs more */
627 arc_max_limit = (ceil (sqrt ((width * width) + (height * height))) / 2.0);
628 length_step = ((arc_max_limit + loop_count - 1) / loop_count);
629 arc_max_limit += length_step;
630 points [0].x = width / 2;
631 points [0].y = height / 2;
632 points [1].x = points [0].x + length_step;
633 points [1].y = points [0].y;
634 points [2].x = points [1].x;
635 points [2].y = points [1].y;
637 for (arc_limit = length_step;
638 arc_limit < arc_max_limit;
639 arc_limit += length_step)
641 int arc_length = length_step;
642 int length_base = arc_limit;
644 unsigned long start_tick = millitime();
645 unsigned long end_tick = start_tick + (total_msecs /
646 (arc_max_limit / length_step));
647 unsigned long tick = start_tick;
654 int max2 = max / granularity;
657 while (tick < end_tick)
660 i = (max * (tick - start_tick)) / (end_tick - start_tick);
661 if (i > max) i = max;
674 for (k = oi; k <= i; k++)
679 for (j = 0; j < granularity; j++)
681 int ii = k * granularity + j;
682 angle = ii / (double) angle_step;
683 arc_length = length_base + ((length_step * angle) / pi2);
684 points [1].x = points [2].x;
685 points [1].y = points [2].y;
686 points [2].x = points [0].x +
687 (int)(cos(angle) * arc_length);
688 points [2].y = points [0].y +
689 (int)(sin(angle) * arc_length);
690 XFillPolygon (dpy, window, context, points, 3, Convex,
707 #define MAX(a,b) ((a)>(b)?(a):(b))
708 #define MIN(a,b) ((a)<(b)?(a):(b))
710 /* from David Bagley <bagleyd@tux.org> */
712 random_squares(Display * dpy, Window window, GC gc,
713 int width, int height, int total_msecs)
715 int granularity = 20;
717 int randsize = MAX(1, MIN(width, height) / (16 + (random() % 32)));
718 int max = (height / randsize + 1) * (width / randsize + 1);
719 int *squares = (int *) calloc(max, sizeof (*squares));
721 int columns = width / randsize + 1; /* Add an extra for roundoff */
724 unsigned long start_tick = millitime();
725 unsigned long end_tick = start_tick + total_msecs;
726 unsigned long tick = start_tick;
730 for (i = 0; i < max; i++)
733 for (i = 0; i < max; i++)
738 squares[i] = squares[r];
742 while (tick < end_tick)
744 int i = (max * (tick - start_tick)) / (end_tick - start_tick);
756 for (j = 0; j < granularity; j++)
758 int ii = i * granularity + j;
760 XFillRectangle(dpy, window, gc,
761 (squares[ii] % columns) * randsize,
762 (squares[ii] / columns) * randsize,
775 /* I first saw something like this, albeit in reverse, in an early Tetris
776 implementation for the Mac.
777 -- Torbjörn Andersson <torbjorn@dev.eurotime.se>
780 slide_lines (Display *dpy, Window window, GC gc,
781 int width, int height, int total_msecs)
784 int dy = MAX (10, height/40);
787 unsigned long start_tick = millitime();
788 unsigned long end_tick = start_tick + total_msecs;
789 unsigned long tick = start_tick;
793 while (tick < end_tick)
795 int i = (max * (tick - start_tick)) / (end_tick - start_tick);
809 int from2 = width - oi - w;
810 int to2 = width - i - w;
812 for (y = 0; y < height; y += dy)
816 XCopyArea (dpy, window, window, gc, from1, y, w, dy, to1, y);
817 XFillRectangle (dpy, window, gc, from1, y, to1-from1, dy);
821 XCopyArea (dpy, window, window, gc, from2, y, w, dy, to2, y);
822 XFillRectangle (dpy, window, gc, from2+w, y, to2-from2, dy);
836 /* from Frederick Roeber <roeber@xigo.com> */
838 losira (Display * dpy, Window window, GC gc,
839 int width, int height, int total_msecs)
842 XWindowAttributes wa;
846 double xx[8], yy[8], dx[8], dy[8];
852 int max_off = MAX(1, max / 12);
854 int msecs1 = (0.55 * total_msecs);
855 int msecs2 = (0.30 * total_msecs);
856 int msecs3 = (0.15 * total_msecs);
858 unsigned long start_tick = millitime();
859 unsigned long end_tick = start_tick + msecs1;
860 unsigned long tick = start_tick;
864 XGetWindowAttributes(dpy, window, &wa);
865 white.flags = DoRed|DoGreen|DoBlue;
866 white.red = white.green = white.blue = 65535;
867 XAllocColor(dpy, wa.colormap, &white);
868 gcv.foreground = white.pixel;
869 white_gc = XCreateGC(dpy, window, GCForeground, &gcv);
871 /* Squeeze in from the sides */
872 while (tick < end_tick)
874 int i = (max * (tick - start_tick)) / (end_tick - start_tick);
883 int off = (max_off * (tick - start_tick)) / (end_tick - start_tick);
887 int w = max - to1 - off/2 + 1;
888 int from2 = max+(to1-from1)+off/2;
894 XCopyArea (dpy, window, window, gc, from1, 0, w, height, to1, 0);
895 XCopyArea (dpy, window, window, gc, from2, 0, w, height, to2, 0);
896 XFillRectangle (dpy, window, gc, from1, 0, (to1-from1), height);
897 XFillRectangle (dpy, window, gc, to2+w, 0, from2+w, height);
898 XFillRectangle (dpy, window, white_gc, max-off/2, 0, off, height);
908 XFillRectangle(dpy, window, white_gc, max-max_off/2, 0, max_off, height);
910 /* Cap the top and bottom of the line */
911 XFillRectangle(dpy, window, gc, max-max_off/2, 0, max_off, max_off/2);
912 XFillRectangle(dpy, window, gc, max-max_off/2, height-max_off/2,
914 XFillArc(dpy, window, white_gc, max-max_off/2-1, 0,
915 max_off-1, max_off-1, 0, 180*64);
916 XFillArc(dpy, window, white_gc, max-max_off/2-1, height-max_off,
917 max_off-1, max_off-1,
920 XFillRectangle(dpy, window, gc, 0, 0, max-max_off/2, height);
921 XFillRectangle(dpy, window, gc, max+max_off/2-1, 0, max-max_off/2, height);
924 /* Collapse vertically */
925 start_tick = millitime();
926 end_tick = start_tick + msecs2;
931 while (tick < end_tick)
933 int i = (max * (tick - start_tick)) / (end_tick - start_tick);
934 int x = (width-max_off)/2;
944 int off = (max_off * (tick - start_tick)) / (end_tick - start_tick);
948 int h = max - to1 - off/2;
949 int from2 = max+(to1-from1)+off/2;
955 XCopyArea (dpy, window, window, gc, x, from1, w, h, x, to1);
956 XCopyArea (dpy, window, window, gc, x, from2, w, h, x, to2);
957 XFillRectangle(dpy, window, gc, x, from1, w, (to1 - from1));
958 XFillRectangle(dpy, window, gc, x, to2+h, w, (to2 - from2));
967 /* "This is Sci-Fi" */
968 for( i = 0; i < 8; i++ ) {
969 arc[0][i].width = arc[0][i].height = max_off;
970 arc[1][i].width = arc[1][i].height = max_off;
971 arc[0][i].x = arc[1][i].x = width/2;
972 arc[0][i].y = arc[1][i].y = height/2;
973 xx[i] = (double)(width/2) - max_off/2;
974 yy[i] = (double)(height/2) - max_off/2;
977 arc[0][0].angle1 = arc[1][0].angle1 = 0*64; arc[0][0].angle2 = arc[1][0].angle2 = 45*64;
978 arc[0][1].angle1 = arc[1][1].angle1 = 45*64; arc[0][1].angle2 = arc[1][1].angle2 = 45*64;
979 arc[0][2].angle1 = arc[1][2].angle1 = 90*64; arc[0][2].angle2 = arc[1][2].angle2 = 45*64;
980 arc[0][3].angle1 = arc[1][3].angle1 = 135*64; arc[0][3].angle2 = arc[1][3].angle2 = 45*64;
981 arc[0][4].angle1 = arc[1][4].angle1 = 180*64; arc[0][4].angle2 = arc[1][4].angle2 = 45*64;
982 arc[0][5].angle1 = arc[1][5].angle1 = 225*64; arc[0][5].angle2 = arc[1][5].angle2 = 45*64;
983 arc[0][6].angle1 = arc[1][6].angle1 = 270*64; arc[0][6].angle2 = arc[1][6].angle2 = 45*64;
984 arc[0][7].angle1 = arc[1][7].angle1 = 315*64; arc[0][7].angle2 = arc[1][7].angle2 = 45*64;
986 for( i = 0; i < 8; i++ ) {
987 dx[i] = cos((i*45 + 22.5)/360 * 2*M_PI);
988 dy[i] = -sin((i*45 + 22.5)/360 * 2*M_PI);
992 XChangeGC(dpy, gc, GCLineWidth, &gcv);
994 XClearWindow (dpy, window);
995 XFillArc(dpy, window, white_gc,
996 width/2-max_off/2-1, height/2-max_off/2-1,
997 max_off-1, max_off-1,
999 XDrawLine(dpy, window, gc, 0, height/2-1, width, height/2-1);
1000 XDrawLine(dpy, window, gc, width/2-1, 0, width/2-1, height);
1001 XDrawLine(dpy, window, gc, width/2-1-max_off, height/2-1-max_off,
1002 width/2+max_off, height/2+max_off);
1003 XDrawLine(dpy, window, gc, width/2+max_off, height/2-1-max_off,
1004 width/2-1-max_off, height/2+max_off);
1010 start_tick = millitime();
1011 end_tick = start_tick + msecs3;
1014 while (tick < end_tick)
1016 int i = (max_off * (tick - start_tick)) / (end_tick - start_tick);
1020 usleep (LITTLE_NAP);
1026 for (j = 0; j < 8; j++)
1030 arc[(i+1)%2][j].x = xx[j];
1031 arc[(i+1)%2][j].y = yy[j];
1034 XFillRectangle (dpy, window, gc,
1035 (width-max_off*5)/2, (height-max_off*5)/2,
1036 max_off*5, max_off*5);
1037 XFillArcs(dpy, window, white_gc, arc[(i+1)%2], 8);
1048 /*XFreeColors(dpy, wa.colormap, &white.pixel, 1, 0);*/
1049 XFreeGC(dpy, white_gc);
1054 static Eraser erasers[] = {
1071 erase_window (Display *dpy, Window window, GC gc,
1072 int width, int height, int mode, int total_msecs)
1074 Bool verbose_p = False;
1075 unsigned long start = millitime();
1077 if (mode < 0 || mode >= countof(erasers))
1078 mode = random() % countof(erasers);
1080 (*(erasers[mode])) (dpy, window, gc, width, height, total_msecs);
1083 fprintf(stderr, "%s: eraser %d time: %4.2f sec\n",
1084 progname, mode, (millitime() - start) / 1000.0);
1086 XClearWindow (dpy, window);
1088 usleep (333333); /* 1/3 sec */
1093 erase_full_window(Display *dpy, Window window)
1095 XWindowAttributes xgwa;
1099 int erase_msecs, erase_mode;
1102 s = get_string_resource("eraseSeconds", "Integer");
1104 erase_msecs = 1000 * get_float_resource("eraseSeconds", "Float");
1108 if (erase_msecs < 10 || erase_msecs > 10000)
1113 s = get_string_resource("eraseMode", "Integer");
1115 erase_mode = get_integer_resource("eraseMode", "Integer");
1120 XGetWindowAttributes (dpy, window, &xgwa);
1121 black.flags = DoRed|DoGreen|DoBlue;
1122 black.red = black.green = black.blue = 0;
1123 XAllocColor(dpy, xgwa.colormap, &black);
1124 gcv.foreground = black.pixel;
1125 erase_gc = XCreateGC (dpy, window, GCForeground, &gcv);
1126 erase_window (dpy, window, erase_gc, xgwa.width, xgwa.height,
1127 erase_mode, erase_msecs);
1128 XFreeColors(dpy, xgwa.colormap, &black.pixel, 1, 0);
1129 XFreeGC(dpy, erase_gc);