1 /*****************************************************************************
3 * xteevee -- TV good... TV good... *
5 * Copyright (c) 1999 Greg Knauss (greg@eod.com) *
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 *
15 *****************************************************************************/
18 /* Changelog *****************************************************************
20 1.0.0 19991119 Initial release
25 /* Includes ******************************************************************/
26 #include "screenhack.h"
27 #include <X11/Xutil.h>
30 /* Defines *******************************************************************/
31 #define XTEEVEE_NAME "XTeeVee"
32 #define XTEEVEE_MODE_EXCLUDE 0
33 #define XTEEVEE_MODE_INCLUDE_IMPLICIT 1
34 #define XTEEVEE_MODE_INCLUDE_EXPLICIT 2
35 #define XTEEVEE_ARG_STATIC "static"
36 #define XTEEVEE_ARG_STATIC_SIGNAL "staticSignal"
37 #define XTEEVEE_ARG_ROLL "roll"
38 #define XTEEVEE_ARG_BARS "bars"
39 #define XTEEVEE_ARG_CYCLE "cycle"
40 #define XTEEVEE_ARG_DELAY_MODE "delayMode"
41 #define XTEEVEE_ARG_DELAY_BETWEEN "delayBetween"
42 #define XTEEVEE_STATIC_COLOR_COUNT 6
43 #define XTEEVEE_STATIC_TILE_COUNT 16
44 #define XTEEVEE_BARS_COLOR_TOP_COUNT 7
45 #define XTEEVEE_BARS_COLOR_BOTTOM_COUNT 5
48 /* Globals *******************************************************************/
49 char *progclass = XTEEVEE_NAME;
52 "*" XTEEVEE_ARG_STATIC ": true",
53 "*" XTEEVEE_ARG_STATIC_SIGNAL ": 50",
54 "*" XTEEVEE_ARG_ROLL ": true",
55 "*" XTEEVEE_ARG_BARS ": true",
56 "*" XTEEVEE_ARG_CYCLE ": true",
57 "*" XTEEVEE_ARG_DELAY_MODE ": 30",
58 "*" XTEEVEE_ARG_DELAY_BETWEEN ": 3",
61 XrmOptionDescRec options[] =
63 { "-" XTEEVEE_ARG_STATIC,"._" XTEEVEE_ARG_STATIC,XrmoptionNoArg,"true" },
64 { "-no-" XTEEVEE_ARG_STATIC,"." XTEEVEE_ARG_STATIC,XrmoptionNoArg,"false" },
65 { "-" XTEEVEE_ARG_ROLL ,"._" XTEEVEE_ARG_ROLL ,XrmoptionNoArg,"true" },
66 { "-no-" XTEEVEE_ARG_ROLL ,"." XTEEVEE_ARG_ROLL ,XrmoptionNoArg,"false" },
67 { "-" XTEEVEE_ARG_BARS ,"._" XTEEVEE_ARG_BARS ,XrmoptionNoArg,"true" },
68 { "-no-" XTEEVEE_ARG_BARS ,"." XTEEVEE_ARG_BARS ,XrmoptionNoArg,"false" },
69 { "-" XTEEVEE_ARG_CYCLE ,"." XTEEVEE_ARG_CYCLE ,XrmoptionNoArg,"true" },
70 { "-no-" XTEEVEE_ARG_CYCLE ,"." XTEEVEE_ARG_CYCLE ,XrmoptionNoArg,"false" },
71 { NULL ,NULL ,0 ,NULL }
75 /* Functions *****************************************************************/
77 /* Get the forground pixel ================================================= */
78 void xteevee_FreeColorForeground(Display* x_Disp,XWindowAttributes* x_WinAttr,
83 if (XGetGCValues(x_Disp,x_Gc,GCForeground,&x_GcVal) != 0)
85 XFreeColors(x_Disp,x_WinAttr->colormap,&x_GcVal.foreground,1,
90 /* Static ================================================================== */
91 void xteevee_Static(Display* x_Disp,Window x_Win,XWindowAttributes* x_WinAttr,
92 time_t hack_Time,Pixmap hack_Pm)
94 GC x_Gc[XTEEVEE_STATIC_COLOR_COUNT];
95 unsigned long pixels[XTEEVEE_STATIC_COLOR_COUNT];
103 Pixmap tile_Tile[XTEEVEE_STATIC_TILE_COUNT];
108 char tile_Used[XTEEVEE_STATIC_TILE_COUNT/2+1];
111 /* Get any extra arguments */
112 signal_Strength = get_integer_resource(XTEEVEE_ARG_STATIC_SIGNAL,
116 color_Color.flags = DoRed|DoGreen|DoBlue;
117 for (color_Index = 0;color_Index < XTEEVEE_STATIC_COLOR_COUNT;
120 color_Color.red = color_Color.green = color_Color.blue =
121 (((double)color_Index+1)/XTEEVEE_STATIC_COLOR_COUNT)*65535;
122 if (XAllocColor(x_Disp,x_WinAttr->colormap,&color_Color) == 0)
124 /* NOTE: I have no idea what to do here. Why would
127 pixels[color_Index] = color_Color.pixel;
128 x_GcVal.foreground = color_Color.pixel;
129 x_Gc[color_Index] = XCreateGC(x_Disp,x_Win,GCForeground,
133 /* Build the tiles */
134 for (tile_Index = 0;tile_Index < XTEEVEE_STATIC_TILE_COUNT;
137 if (signal_Strength == 0)
139 /* NOTE: Checking XQueryBestTile() returns tiles that
140 are too regular -- you can see patterns
142 tile_Width = (random()%128)+64;
143 tile_Height = (random()%128)+64;
147 tile_Width = x_WinAttr->width;
148 tile_Height = x_WinAttr->height;
150 tile_Tile[tile_Index] = XCreatePixmap(x_Disp,x_Win,tile_Width,
151 tile_Height,x_WinAttr->depth);
152 XCopyArea(x_Disp,hack_Pm,tile_Tile[tile_Index],x_Gc[0],0,0,
153 x_WinAttr->width,x_WinAttr->height,0,0);
155 if (signal_Strength == 0)
159 xim = XCreateImage (x_Disp, x_WinAttr->visual,
161 (x_WinAttr->depth == 1
162 ? XYPixmap : ZPixmap),
168 xim->data = (char *) malloc (xim->bytes_per_line *
174 memcpy (xim->data, orig_bits,
175 xim->bytes_per_line * xim->height);
179 xim = XGetImage (x_Disp, tile_Tile[tile_Index], 0, 0,
180 x_WinAttr->width, x_WinAttr->height, ~0L,
181 (x_WinAttr->depth == 1
182 ? XYPixmap : ZPixmap));
183 orig_bits = (char *) malloc (xim->bytes_per_line *
185 memcpy (orig_bits, xim->data,
186 xim->bytes_per_line * xim->height);
189 for (tile_Y = tile_Height-1;tile_Y >= 0;tile_Y--)
190 for (tile_X = tile_Width-1;tile_X >= 0;tile_X--)
191 if (random()%100 > signal_Strength)
192 XPutPixel(xim,tile_X,tile_Y,
193 pixels[random()%XTEEVEE_STATIC_COLOR_COUNT]);
194 XPutImage(x_Disp,tile_Tile[tile_Index],x_Gc[0],xim,
195 0,0,0,0,x_WinAttr->width,x_WinAttr->height);
198 if (xim) XDestroyImage (xim);
199 if (orig_bits) free (orig_bits);
202 memset(tile_Used,-1,sizeof(tile_Used));
205 hack_Time += time(NULL);
207 while ((time(NULL) < hack_Time) || (hack_Time == 0))
212 tile_Selected = random()%XTEEVEE_STATIC_TILE_COUNT;
213 for (tile_Index = 0;tile_Index < sizeof(tile_Used);
216 if (tile_Used[tile_Index] == tile_Selected)
222 } while (tile_Selected == -1);
223 memmove(tile_Used,tile_Used+1,sizeof(tile_Used)-1);
224 tile_Used[sizeof(tile_Used)-1] = tile_Selected;
227 XSetWindowBackgroundPixmap(x_Disp,x_Win,
228 tile_Tile[tile_Selected]);
229 XClearWindow(x_Disp,x_Win);
232 screenhack_handle_events(x_Disp);
236 /* Free everything */
237 for (color_Index = 0;color_Index < XTEEVEE_STATIC_COLOR_COUNT;
240 xteevee_FreeColorForeground(x_Disp,x_WinAttr,
242 XFreeGC(x_Disp,x_Gc[color_Index]);
245 for (tile_Index = 0;tile_Index < XTEEVEE_STATIC_TILE_COUNT;
248 XFreePixmap(x_Disp, tile_Tile[tile_Index]);
252 /* Vertical Roll =========================================================== */
253 void xteevee_Roll(Display* x_Disp,Window x_Win,XWindowAttributes* x_WinAttr,
254 time_t hack_Time,Pixmap hack_Pm)
260 int blank_Height = x_WinAttr->height/10;
263 x_GcVal.foreground = BlackPixel(x_Disp,0);
264 x_GcVal.subwindow_mode = IncludeInferiors;
265 x_Gc = XCreateGC(x_Disp,x_Win,GCForeground|GCSubwindowMode,&x_GcVal);
270 hack_Time += time(NULL);
272 while ((roll_Y > 0) || ((time(NULL) < hack_Time) || (hack_Time == 0)))
274 if (roll_Y > blank_Height)
276 XCopyArea(x_Disp,hack_Pm,x_Win,x_Gc,
277 0,x_WinAttr->height-(roll_Y-blank_Height)-1,
278 x_WinAttr->width,roll_Y-blank_Height,
281 XFillRectangle(x_Disp,x_Win,x_Gc,
282 0,roll_Y-blank_Height,
283 x_WinAttr->width,blank_Height);
284 if (roll_Y < x_WinAttr->height)
286 XCopyArea(x_Disp,hack_Pm,x_Win,x_Gc,
288 x_WinAttr->width,x_WinAttr->height-roll_Y,
292 roll_Y += roll_Speed/2;
297 if (roll_Y > x_WinAttr->height+blank_Height)
305 screenhack_handle_events(x_Disp);
308 /* Free everything */
309 XFreeGC(x_Disp,x_Gc);
312 /* Color-Bars Test Pattern ================================================= */
313 void xteevee_Bars(Display* x_Disp,Window x_Win,XWindowAttributes* x_WinAttr,
314 time_t hack_Time,Pixmap hack_Pm)
316 GC x_GcTop[XTEEVEE_BARS_COLOR_TOP_COUNT];
317 GC x_GcBottom[XTEEVEE_BARS_COLOR_BOTTOM_COUNT];
321 char* color_ColorTop[] =
331 char* color_ColorBottom[] =
341 for (color_Index = 0;color_Index < XTEEVEE_BARS_COLOR_TOP_COUNT;
344 if (XParseColor(x_Disp,x_WinAttr->colormap,
345 color_ColorTop[color_Index],&color_Color) == 0)
347 /* NOTE: Um, badness? */
349 if (XAllocColor(x_Disp,x_WinAttr->colormap,&color_Color) == 0)
351 /* NOTE: More badness? */
353 x_GcVal.foreground = color_Color.pixel;
354 x_GcTop[color_Index] =
355 XCreateGC(x_Disp,x_Win,GCForeground,&x_GcVal);
357 for (color_Index = 0;color_Index < XTEEVEE_BARS_COLOR_BOTTOM_COUNT;
360 if (XParseColor(x_Disp,x_WinAttr->colormap,
361 color_ColorBottom[color_Index],&color_Color) == 0)
363 /* NOTE: Um, badness? */
365 if (XAllocColor(x_Disp,x_WinAttr->colormap,&color_Color) == 0)
367 /* NOTE: More badness? */
369 x_GcVal.foreground = color_Color.pixel;
370 x_GcBottom[color_Index] =
371 XCreateGC(x_Disp,x_Win,GCForeground,&x_GcVal);
374 /* Draw color-bar test pattern */
375 XClearWindow(x_Disp,x_Win);
376 for (color_Index = 0;color_Index < XTEEVEE_BARS_COLOR_TOP_COUNT;
379 XFillRectangle(x_Disp,x_Win,x_GcTop[color_Index],
380 ((x_WinAttr->width/XTEEVEE_BARS_COLOR_TOP_COUNT)+1)*
383 (x_WinAttr->width/XTEEVEE_BARS_COLOR_TOP_COUNT)+1,
384 (x_WinAttr->height/5)*4);
386 for (color_Index = 0;color_Index < XTEEVEE_BARS_COLOR_BOTTOM_COUNT;
389 XFillRectangle(x_Disp,x_Win,x_GcBottom[color_Index],
390 ((x_WinAttr->width/XTEEVEE_BARS_COLOR_BOTTOM_COUNT)+1)*
392 (x_WinAttr->height/5)*4,
393 (x_WinAttr->width/XTEEVEE_BARS_COLOR_BOTTOM_COUNT)+1,
394 x_WinAttr->height-(x_WinAttr->height/5)*4);
400 hack_Time += time(NULL);
402 while ((time(NULL) < hack_Time) || (hack_Time == 0))
404 screenhack_handle_events(x_Disp);
408 /* Free everything */
409 for (color_Index = 0;color_Index < XTEEVEE_BARS_COLOR_TOP_COUNT;
412 xteevee_FreeColorForeground(x_Disp,x_WinAttr,
413 x_GcTop[color_Index]);
414 XFreeGC(x_Disp,x_GcTop[color_Index]);
416 for (color_Index = 0;color_Index < XTEEVEE_BARS_COLOR_BOTTOM_COUNT;
419 xteevee_FreeColorForeground(x_Disp,x_WinAttr,
420 x_GcBottom[color_Index]);
421 XFreeGC(x_Disp,x_GcBottom[color_Index]);
425 /* Standard XScreenSaver entry point ======================================= */
426 void screenhack(Display* x_Disp,Window x_Win)
428 XWindowAttributes x_WinAttr;
439 int mode_Min = XTEEVEE_MODE_INCLUDE_IMPLICIT;
443 void (*mode_Func)(Display* x_Disp,Window x_Win,
444 XWindowAttributes* x_WinAttr,time_t hack_Time,
449 { XTEEVEE_ARG_STATIC,xteevee_Static,XTEEVEE_MODE_EXCLUDE },
450 { XTEEVEE_ARG_ROLL, xteevee_Roll, XTEEVEE_MODE_EXCLUDE },
451 { XTEEVEE_ARG_BARS, xteevee_Bars, XTEEVEE_MODE_EXCLUDE },
455 /* Grab the screen to give us time to do whatever we want */
456 XGetWindowAttributes(x_Disp,x_Win,&x_WinAttr);
457 grab_screen_image(x_WinAttr.screen,x_Win);
458 x_GcVal.subwindow_mode = IncludeInferiors;
459 x_Gc = XCreateGC(x_Disp,x_Win,GCSubwindowMode,&x_GcVal);
460 screen_Pm = XCreatePixmap(x_Disp,x_Win,x_WinAttr.width,
461 x_WinAttr.height,x_WinAttr.depth);
462 XCopyArea(x_Disp,x_Win,screen_Pm,x_Gc,0,0,x_WinAttr.width,
463 x_WinAttr.height,0,0);
465 /* Read the arguments */
466 delay_Mode = get_integer_resource(XTEEVEE_ARG_DELAY_MODE,"Integer");
467 delay_Between = get_integer_resource(XTEEVEE_ARG_DELAY_BETWEEN,
469 if (!get_boolean_resource(XTEEVEE_ARG_CYCLE,"Boolean"))
473 for (mode_Index = 0;mode_Mode[mode_Index].mode_Arg != NULL;
476 if (get_boolean_resource(mode_Mode[mode_Index].mode_Arg,
479 mode_Mode[mode_Index].mode_Flag =
480 XTEEVEE_MODE_INCLUDE_IMPLICIT;
483 sprintf(mode_Arg,"_%s",mode_Mode[mode_Index].mode_Arg);
484 if (get_boolean_resource(mode_Arg,"Boolean") != 0)
486 mode_Mode[mode_Index].mode_Flag =
487 XTEEVEE_MODE_INCLUDE_EXPLICIT;
488 mode_Min = XTEEVEE_MODE_INCLUDE_EXPLICIT;
495 fprintf(stderr,"%s: No modes selected!\n",XTEEVEE_NAME);
499 /* Cycle through various modes */
505 mode_Index = random()%mode_Total;
506 } while (mode_Mode[mode_Index].mode_Flag < mode_Min);
509 mode_Mode[mode_Index].mode_Func(x_Disp,x_Win,&x_WinAttr,
510 delay_Mode,screen_Pm);
512 /* Restore the screen and wait */
513 XCopyArea(x_Disp,screen_Pm,x_Win,x_Gc,0,0,x_WinAttr.width,
514 x_WinAttr.height,0,0);
515 delay_Time = time(NULL)+delay_Between;
516 while (time(NULL) < delay_Time)
518 screenhack_handle_events(x_Disp);