http://ftp.ksu.edu.tw/FTP/FreeBSD/distfiles/xscreensaver-4.20.tar.gz
[xscreensaver] / hacks / xteevee.c
1 /*****************************************************************************
2  *                                                                           *
3  * xteevee -- TV good... TV good...                                          *
4  *                                                                           *
5  * Copyright (c) 1999 Greg Knauss (greg@eod.com)                             *
6  *                                                                           *
7  * Permission to use, copy, modify, distribute, and sell this software and   *
8  * its documentation for any purpose is hereby granted without fee, provided *
9  * that the above copyright notice appear in all copies and that both that   *
10  * copyright notice and this permission notice appear in supporting          *
11  * documentation.  No representations are made about the suitability of this *
12  * software for any purpose.  It is provided "as is" without express or      *
13  * implied warranty.                                                         *
14  *                                                                           *
15  *****************************************************************************/
16
17
18 /* Changelog *****************************************************************
19
20         1.0.0   19991119        Initial release
21
22 */
23
24
25 /* Includes ******************************************************************/
26 #include "screenhack.h"
27 #include "colorbars.h"
28 #include <X11/Xutil.h>
29 #include <time.h>
30 #include <sys/time.h>
31
32
33 /* Defines *******************************************************************/
34 #define XTEEVEE_NAME                    "XTeeVee"
35 #define XTEEVEE_MODE_EXCLUDE            0
36 #define XTEEVEE_MODE_INCLUDE_IMPLICIT   1
37 #define XTEEVEE_MODE_INCLUDE_EXPLICIT   2
38 #define XTEEVEE_ARG_STATIC              "static"
39 #define XTEEVEE_ARG_STATIC_SIGNAL       "staticSignal"
40 #define XTEEVEE_ARG_ROLL                "roll"
41 #define XTEEVEE_ARG_BARS                "bars"
42 #define XTEEVEE_ARG_CYCLE               "cycle"
43 #define XTEEVEE_ARG_DELAY_MODE          "delayMode"
44 #define XTEEVEE_ARG_DELAY_BETWEEN       "delayBetween"
45 #define XTEEVEE_STATIC_COLOR_COUNT      6
46 #define XTEEVEE_STATIC_TILE_COUNT       16
47
48
49 /* Globals *******************************************************************/
50 char *progclass  = XTEEVEE_NAME;
51 char *defaults[] =
52 {
53         "*" XTEEVEE_ARG_STATIC        ": true",
54         "*" XTEEVEE_ARG_STATIC_SIGNAL ": 50",
55         "*" XTEEVEE_ARG_ROLL          ": true",
56         "*" XTEEVEE_ARG_BARS          ": true",
57         "*" XTEEVEE_ARG_CYCLE         ": true",
58         "*" XTEEVEE_ARG_DELAY_MODE    ": 30",
59         "*" XTEEVEE_ARG_DELAY_BETWEEN ": 3",
60         NULL
61 };
62 XrmOptionDescRec options[] =
63 {
64  { "-"    XTEEVEE_ARG_STATIC,"._" XTEEVEE_ARG_STATIC,XrmoptionNoArg,"true" },
65  { "-no-" XTEEVEE_ARG_STATIC,"."  XTEEVEE_ARG_STATIC,XrmoptionNoArg,"false" },
66  { "-"    XTEEVEE_ARG_ROLL  ,"._" XTEEVEE_ARG_ROLL  ,XrmoptionNoArg,"true" },
67  { "-no-" XTEEVEE_ARG_ROLL  ,"."  XTEEVEE_ARG_ROLL  ,XrmoptionNoArg,"false" },
68  { "-"    XTEEVEE_ARG_BARS  ,"._" XTEEVEE_ARG_BARS  ,XrmoptionNoArg,"true" },
69  { "-no-" XTEEVEE_ARG_BARS  ,"."  XTEEVEE_ARG_BARS  ,XrmoptionNoArg,"false" },
70  { "-"    XTEEVEE_ARG_CYCLE ,"."  XTEEVEE_ARG_CYCLE ,XrmoptionNoArg,"true" },
71  { "-no-" XTEEVEE_ARG_CYCLE ,"."  XTEEVEE_ARG_CYCLE ,XrmoptionNoArg,"false" },
72  { NULL                     ,NULL                   ,0             ,NULL }
73 };
74
75
76 /* Functions *****************************************************************/
77
78 /* Get the forground pixel ================================================= */
79 void xteevee_FreeColorForeground(Display* x_Disp,XWindowAttributes* x_WinAttr,
80       GC x_Gc)
81 {
82         XGCValues x_GcVal;
83
84         if (XGetGCValues(x_Disp,x_Gc,GCForeground,&x_GcVal) != 0)
85         {
86                 XFreeColors(x_Disp,x_WinAttr->colormap,&x_GcVal.foreground,1,
87                  0);
88         }
89 }
90
91 /* Static ================================================================== */
92 void xteevee_Static(Display* x_Disp,Window x_Win,XWindowAttributes* x_WinAttr,
93       time_t hack_Time,Pixmap hack_Pm)
94 {
95         GC        x_Gc[XTEEVEE_STATIC_COLOR_COUNT];
96         unsigned long pixels[XTEEVEE_STATIC_COLOR_COUNT];
97         XImage   *xim = 0;
98         char     *orig_bits = 0;
99         XGCValues x_GcVal;
100         int       signal_Strength;
101         XColor    color_Color;
102         int       color_Index;
103         int       tile_Index;
104         Pixmap    tile_Tile[XTEEVEE_STATIC_TILE_COUNT];
105         int       tile_X;
106         int       tile_Y;
107         int       tile_Width;
108         int       tile_Height;
109         char      tile_Used[XTEEVEE_STATIC_TILE_COUNT/2+1];
110         int       tile_Selected;
111
112         /* Get any extra arguments */
113         signal_Strength = get_integer_resource(XTEEVEE_ARG_STATIC_SIGNAL,
114          "Integer");
115
116         /* Build the GCs */
117         color_Color.flags = DoRed|DoGreen|DoBlue;
118         for (color_Index = 0;color_Index < XTEEVEE_STATIC_COLOR_COUNT;
119          color_Index++)
120         {
121                 color_Color.red = color_Color.green = color_Color.blue =
122                  (((double)color_Index+1)/XTEEVEE_STATIC_COLOR_COUNT)*65535;
123                 if (!x_WinAttr->colormap ||
124                     !XAllocColor(x_Disp,x_WinAttr->colormap,&color_Color))
125                 {
126                         /* NOTE: I have no idea what to do here.  Why would
127                                  this fail? */
128                 }
129                 pixels[color_Index] = color_Color.pixel;
130                 x_GcVal.foreground = color_Color.pixel;
131                 x_Gc[color_Index] = XCreateGC(x_Disp,x_Win,GCForeground,
132                  &x_GcVal);
133         }
134
135         /* Build the tiles */
136         for (tile_Index = 0;tile_Index < XTEEVEE_STATIC_TILE_COUNT;
137          tile_Index++)
138         {
139                 if (signal_Strength == 0)
140                 {
141                         /* NOTE: Checking XQueryBestTile() returns tiles that
142                                  are too regular -- you can see patterns
143                                  emerge. */
144                         tile_Width = (random()%128)+64;
145                         tile_Height = (random()%128)+64;
146                 }
147                 else
148                 {
149                         tile_Width = x_WinAttr->width;
150                         tile_Height = x_WinAttr->height;
151                 }
152                 tile_Tile[tile_Index] = XCreatePixmap(x_Disp,x_Win,tile_Width,
153                  tile_Height,x_WinAttr->depth);
154                 XCopyArea(x_Disp,hack_Pm,tile_Tile[tile_Index],x_Gc[0],0,0,
155                  x_WinAttr->width,x_WinAttr->height,0,0);
156
157                 if (signal_Strength == 0)
158                   {
159                     if (!xim)
160                       {
161                         xim = XCreateImage (x_Disp, x_WinAttr->visual,
162                                             x_WinAttr->depth,
163                                             (x_WinAttr->depth == 1
164                                              ? XYPixmap : ZPixmap),
165                                             0, 0,
166                                             x_WinAttr->width,
167                                             x_WinAttr->height,
168                                             8, 0);
169                         
170                         xim->data = (char *) malloc (xim->bytes_per_line *
171                                                      xim->height);
172                       }
173                   }
174                 else if (xim)
175                   {
176                     memcpy (xim->data, orig_bits,
177                             xim->bytes_per_line * xim->height);
178                   }
179                 else
180                   {
181                     xim = XGetImage (x_Disp, tile_Tile[tile_Index], 0, 0,
182                                      x_WinAttr->width, x_WinAttr->height, ~0L,
183                                      (x_WinAttr->depth == 1
184                                       ? XYPixmap : ZPixmap));
185                     orig_bits = (char *) malloc (xim->bytes_per_line *
186                                                  xim->height);
187                     memcpy (orig_bits, xim->data,
188                             xim->bytes_per_line * xim->height);
189                   }
190
191                 for (tile_Y = tile_Height-1;tile_Y >= 0;tile_Y--)
192                   for (tile_X = tile_Width-1;tile_X >= 0;tile_X--)
193                     if (random()%100 > signal_Strength)
194                       XPutPixel(xim,tile_X,tile_Y,
195                                 pixels[random()%XTEEVEE_STATIC_COLOR_COUNT]);
196                 XPutImage(x_Disp,tile_Tile[tile_Index],x_Gc[0],xim,
197                           0,0,0,0,x_WinAttr->width,x_WinAttr->height);
198         }
199
200         if (xim) XDestroyImage (xim);
201         if (orig_bits) free (orig_bits);
202
203         /* Go! */
204         memset(tile_Used,-1,sizeof(tile_Used));
205         if (hack_Time > 0)
206         {
207                 hack_Time += time(NULL);
208         }
209         while ((time(NULL) < hack_Time) || (hack_Time == 0))
210         {
211                 /* Pick a tile */
212                 do
213                 {
214                         tile_Selected = random()%XTEEVEE_STATIC_TILE_COUNT;
215                         for (tile_Index = 0;tile_Index < sizeof(tile_Used);
216                          tile_Index++)
217                         {
218                                 if (tile_Used[tile_Index] == tile_Selected)
219                                 {
220                                         tile_Selected = -1;
221                                         break;
222                                 }
223                         }
224                 } while (tile_Selected == -1);
225                 memmove(tile_Used,tile_Used+1,sizeof(tile_Used)-1);
226                 tile_Used[sizeof(tile_Used)-1] = tile_Selected;
227
228                 /* Set it */
229                 XSetWindowBackgroundPixmap(x_Disp,x_Win,
230                  tile_Tile[tile_Selected]);
231                 XClearWindow(x_Disp,x_Win);
232
233                 XSync(x_Disp,0);
234                 screenhack_handle_events(x_Disp);
235                 usleep(25000);
236         }
237
238         /* Free everything */
239         for (color_Index = 0;color_Index < XTEEVEE_STATIC_COLOR_COUNT;
240          color_Index++)
241         {
242                 xteevee_FreeColorForeground(x_Disp,x_WinAttr,
243                  x_Gc[color_Index]);
244                 XFreeGC(x_Disp,x_Gc[color_Index]);
245         }
246
247         for (tile_Index = 0;tile_Index < XTEEVEE_STATIC_TILE_COUNT;
248          tile_Index++)
249         {
250                 XFreePixmap(x_Disp, tile_Tile[tile_Index]);
251         }
252 }
253
254 /* Vertical Roll =========================================================== */
255 void xteevee_Roll(Display* x_Disp,Window x_Win,XWindowAttributes* x_WinAttr,
256       time_t hack_Time,Pixmap hack_Pm)
257 {
258         GC        x_Gc;
259         XGCValues x_GcVal;
260         int       roll_Y = 0;
261         int       roll_Speed = 0;
262         int       blank_Height = x_WinAttr->height/10;
263
264         /* Build the GC */
265         x_GcVal.foreground = BlackPixel(x_Disp,0);
266         x_GcVal.subwindow_mode = IncludeInferiors;
267         x_Gc = XCreateGC(x_Disp,x_Win,GCForeground|GCSubwindowMode,&x_GcVal);
268
269         /* Go! */
270         if (hack_Time > 0)
271         {
272                 hack_Time += time(NULL);
273         }
274         while ((roll_Y > 0) || ((time(NULL) < hack_Time) || (hack_Time == 0)))
275         {
276                 if (roll_Y > blank_Height)
277                 {
278                         XCopyArea(x_Disp,hack_Pm,x_Win,x_Gc,
279                          0,x_WinAttr->height-(roll_Y-blank_Height)-1,
280                          x_WinAttr->width,roll_Y-blank_Height,
281                          0,0);
282                 }
283                 XFillRectangle(x_Disp,x_Win,x_Gc,
284                  0,roll_Y-blank_Height,
285                  x_WinAttr->width,blank_Height);
286                 if (roll_Y < x_WinAttr->height)
287                 {
288                         XCopyArea(x_Disp,hack_Pm,x_Win,x_Gc,
289                          0,0,
290                          x_WinAttr->width,x_WinAttr->height-roll_Y,
291                          0,roll_Y);
292                 }
293
294                 roll_Y += roll_Speed/2;
295                 if (roll_Speed < 50)
296                 {
297                         roll_Speed++;
298                 }
299                 if (roll_Y > x_WinAttr->height+blank_Height)
300                 {
301                         roll_Y = 0;
302                         roll_Speed = 0;
303                 }
304
305                 XSync(x_Disp,0);
306                 usleep(50000);
307                 screenhack_handle_events(x_Disp);
308         }
309
310         /* Free everything */
311         XFreeGC(x_Disp,x_Gc);
312 }
313
314 /* Color-Bars Test Pattern ================================================= */
315 void xteevee_Bars(Display* x_Disp,Window x_Win,XWindowAttributes* x_WinAttr,
316       time_t hack_Time,Pixmap hack_Pm)
317 {
318   draw_colorbars (x_WinAttr->screen, x_WinAttr->visual, x_Win,
319                   x_WinAttr->colormap,
320                   0, 0, x_WinAttr->width, x_WinAttr->height);
321
322   /* Go! */
323   if (hack_Time > 0)
324     {
325       hack_Time += time(NULL);
326     }
327   while ((time(NULL) < hack_Time) || (hack_Time == 0))
328     {
329       screenhack_handle_events(x_Disp);
330       usleep(100000);
331     }
332 }
333
334
335 /* Standard XScreenSaver entry point ======================================= */
336 void screenhack(Display* x_Disp,Window x_Win)
337 {
338         XWindowAttributes x_WinAttr;
339         GC                x_Gc;
340         XGCValues         x_GcVal;
341         Pixmap            screen_Pm;
342         time_t            delay_Time;
343         int               delay_Mode;
344         int               delay_Between;
345         int               mode_Index;
346         int               mode_Count = 0;
347         int               mode_Total = 0;
348         char              mode_Arg[64+1];
349         int               mode_Min = XTEEVEE_MODE_INCLUDE_IMPLICIT;
350         struct
351         {
352                 char* mode_Arg;
353                 void  (*mode_Func)(Display* x_Disp,Window x_Win,
354                       XWindowAttributes* x_WinAttr,time_t hack_Time,
355                       Pixmap hack_Pm);
356                 int   mode_Flag;
357         } mode_Mode[] =
358         {
359                 { XTEEVEE_ARG_STATIC,xteevee_Static,XTEEVEE_MODE_EXCLUDE },
360                 { XTEEVEE_ARG_ROLL,  xteevee_Roll,  XTEEVEE_MODE_EXCLUDE },
361                 { XTEEVEE_ARG_BARS,  xteevee_Bars,  XTEEVEE_MODE_EXCLUDE },
362                 { NULL,              NULL,          -1 }
363         };
364
365         /* Grab the screen to give us time to do whatever we want */
366         XGetWindowAttributes(x_Disp,x_Win,&x_WinAttr);
367         load_random_image (x_WinAttr.screen, x_Win, x_Win, NULL, NULL);
368
369         x_GcVal.subwindow_mode = IncludeInferiors;
370         x_Gc = XCreateGC(x_Disp,x_Win,GCSubwindowMode,&x_GcVal);
371         screen_Pm = XCreatePixmap(x_Disp,x_Win,x_WinAttr.width,
372          x_WinAttr.height,x_WinAttr.depth);
373         XCopyArea(x_Disp,x_Win,screen_Pm,x_Gc,0,0,x_WinAttr.width,
374          x_WinAttr.height,0,0);
375
376         /* Read the arguments */
377         delay_Mode = get_integer_resource(XTEEVEE_ARG_DELAY_MODE,"Integer");
378         delay_Between = get_integer_resource(XTEEVEE_ARG_DELAY_BETWEEN,
379          "Integer");
380         if (!get_boolean_resource(XTEEVEE_ARG_CYCLE,"Boolean"))
381         {
382                 delay_Mode = 0;
383         }
384         for (mode_Index = 0;mode_Mode[mode_Index].mode_Arg != NULL;
385          mode_Index++)
386         {
387                 if (get_boolean_resource(mode_Mode[mode_Index].mode_Arg,
388                  "Boolean") != 0)
389                 {
390                         mode_Mode[mode_Index].mode_Flag =
391                          XTEEVEE_MODE_INCLUDE_IMPLICIT;
392                         mode_Count++;
393                 }
394                 sprintf(mode_Arg,"_%s",mode_Mode[mode_Index].mode_Arg);
395                 if (get_boolean_resource(mode_Arg,"Boolean") != 0)
396                 {
397                         mode_Mode[mode_Index].mode_Flag =
398                          XTEEVEE_MODE_INCLUDE_EXPLICIT;
399                         mode_Min = XTEEVEE_MODE_INCLUDE_EXPLICIT;
400                         mode_Count++;
401                 }
402                 mode_Total++;
403         }
404         if (mode_Count == 0)
405         {
406                 fprintf(stderr,"%s: No modes selected!\n",XTEEVEE_NAME);
407                 return;
408         }
409
410         /* Cycle through various modes */
411         for (;;)
412         {
413                 /* Find a mode */
414                 do
415                 {
416                         mode_Index = random()%mode_Total;
417                 } while (mode_Mode[mode_Index].mode_Flag < mode_Min);
418
419                 /* Run the hack */
420                 mode_Mode[mode_Index].mode_Func(x_Disp,x_Win,&x_WinAttr,
421                  delay_Mode,screen_Pm);
422
423                 /* Restore the screen and wait */
424                 XCopyArea(x_Disp,screen_Pm,x_Win,x_Gc,0,0,x_WinAttr.width,
425                  x_WinAttr.height,0,0);
426                 delay_Time = time(NULL)+delay_Between;
427                 while (time(NULL) < delay_Time)
428                 {
429                         screenhack_handle_events(x_Disp);
430                         usleep(100000);
431                 }
432         }
433 }