http://www.jwz.org/xscreensaver/xscreensaver-5.10.tar.gz
[xscreensaver] / hacks / lcdscrub.c
1 /* xscreensaver, Copyright (c) 2008 Jamie Zawinski <jwz@jwz.org>
2  *
3  * Permission to use, copy, modify, distribute, and sell this software and its
4  * documentation for any purpose is hereby granted without fee, provided that
5  * the above copyright notice appear in all copies and that both that
6  * copyright notice and this permission notice appear in supporting
7  * documentation.  No representations are made about the suitability of this
8  * software for any purpose.  It is provided "as is" without express or 
9  * implied warranty.
10  *
11  * Draws repetitive patterns that should undo burned in LCD screens.
12  * Concept shamelessly cloned from
13  * http://toastycode.com/blog/2008/02/05/lcd-scrub/
14  */
15
16 #include "screenhack.h"
17
18 struct state {
19   Display *dpy;
20   Window window;
21   XWindowAttributes xgwa;
22   enum { HORIZ_W, HORIZ_B, 
23          VERT_W, VERT_B, 
24          DIAG_W, DIAG_B, 
25          WHITE, BLACK,
26          END } mode;
27   unsigned int enabled_mask;
28   int count;
29   GC fg, bg;
30   int delay;
31   int spread;
32   int cycles;
33 };
34
35
36 static void
37 pick_mode (struct state *st)
38 {
39   st->count = 0;
40   while (1)
41     {
42       if (++st->mode == END)
43         st->mode = 0;
44       if (st->enabled_mask & (1 << st->mode))
45         break;
46     }
47 }
48
49 static void *
50 lcdscrub_init (Display *dpy, Window window)
51 {
52   struct state *st = (struct state *) calloc (1, sizeof(*st));
53   XGCValues gcv;
54   st->dpy = dpy;
55   st->window = window;
56   st->delay  = get_integer_resource (st->dpy, "delay",  "Integer");
57   st->spread = get_integer_resource (st->dpy, "spread", "Integer");
58   st->cycles = get_integer_resource (st->dpy, "cycles", "Integer");
59
60   XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
61   gcv.foreground = BlackPixelOfScreen (st->xgwa.screen);
62   gcv.background = WhitePixelOfScreen (st->xgwa.screen);
63   st->bg = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
64   gcv.foreground = WhitePixelOfScreen (st->xgwa.screen);
65   gcv.background = BlackPixelOfScreen (st->xgwa.screen);
66   st->fg = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
67
68 #ifdef HAVE_COCOA
69   jwxyz_XSetAntiAliasing (st->dpy, st->fg, False);
70   jwxyz_XSetAntiAliasing (st->dpy, st->bg, False);
71 #endif
72
73   st->enabled_mask = 0;
74 # define PREF(R,F) \
75    if (get_boolean_resource (st->dpy, R, "Mode")) st->enabled_mask |= (1 << F)
76   PREF("modeHW", HORIZ_W);
77   PREF("modeHB", HORIZ_B);
78   PREF("modeVW", VERT_W);
79   PREF("modeVB", VERT_B);
80   PREF("modeDW", DIAG_W);
81   PREF("modeDB", DIAG_B);
82   PREF("modeW",  WHITE);
83   PREF("modeB",  BLACK);
84 # undef PREF
85   if (! st->enabled_mask) 
86     {
87       fprintf (stderr, "%s: no modes enabled\n", progname);
88       exit (1);
89     }
90
91   pick_mode (st);
92
93   return st;
94 }
95
96 static unsigned long
97 lcdscrub_draw (Display *dpy, Window window, void *closure)
98 {
99   struct state *st = (struct state *) closure;
100   int count = st->count % st->spread;
101   int i;
102   GC fg = (st->mode & 1 ? st->fg : st->bg);
103   GC bg = (st->mode & 1 ? st->bg : st->fg);
104
105   switch (st->mode) {
106   case HORIZ_W:
107   case HORIZ_B:
108     XFillRectangle (st->dpy, st->window, bg, 0, 0,
109                     st->xgwa.width, st->xgwa.height);
110     for (i = count; i < st->xgwa.height; i += st->spread)
111       XDrawLine (st->dpy, st->window, fg, 0, i, st->xgwa.width, i);
112     break;
113   case VERT_W:
114   case VERT_B:
115     XFillRectangle (st->dpy, st->window, bg, 0, 0,
116                     st->xgwa.width, st->xgwa.height);
117     for (i = count; i < st->xgwa.width; i += st->spread)
118       XDrawLine (st->dpy, st->window, fg, i, 0, i, st->xgwa.height);
119     break;
120   case DIAG_W:
121   case DIAG_B:
122     XFillRectangle (st->dpy, st->window, bg, 0, 0,
123                     st->xgwa.width, st->xgwa.height);
124     for (i = count; i < st->xgwa.width; i += st->spread)
125       XDrawLine (st->dpy, st->window, fg, i, 0, 
126                  i + st->xgwa.width, st->xgwa.width);
127     for (i = -count; i < st->xgwa.height; i += st->spread)
128       XDrawLine (st->dpy, st->window, fg, 0, i,
129                  st->xgwa.height, i + st->xgwa.height);
130     break;
131   case WHITE:
132   case BLACK:
133     XFillRectangle (st->dpy, st->window, bg, 0, 0,
134                     st->xgwa.width, st->xgwa.height);
135     break;
136   default: 
137     abort(); 
138     break;
139   }
140
141   st->count++;
142
143   if (st->count > st->spread * st->cycles)
144     pick_mode (st);
145
146   return st->delay;
147 }
148
149 static void
150 lcdscrub_reshape (Display *dpy, Window window, void *closure, 
151                  unsigned int w, unsigned int h)
152 {
153 }
154
155 static Bool
156 lcdscrub_event (Display *dpy, Window window, void *closure, XEvent *event)
157 {
158   return False;
159 }
160
161 static void
162 lcdscrub_free (Display *dpy, Window window, void *closure)
163 {
164   struct state *st = (struct state *) closure;
165   XFreeGC (dpy, st->fg);
166   XFreeGC (dpy, st->bg);
167   free (st);
168 }
169
170
171 static const char *lcdscrub_defaults [] = {
172   ".background:         black",
173   ".foreground:         white",
174   "*delay:              100000",
175   "*spread:             8",
176   "*cycles:             60",
177   "*modeHW:             True",
178   "*modeHB:             True",
179   "*modeVW:             True",
180   "*modeVB:             True",
181   "*modeDW:             True",
182   "*modeDB:             True",
183   "*modeW:              True",
184   "*modeB:              True",
185   0
186 };
187
188 static XrmOptionDescRec lcdscrub_options [] = {
189   { "-delay",           ".delay",       XrmoptionSepArg, 0 },
190   { "-spread",          ".spread",      XrmoptionSepArg, 0 },
191   { "-cycles",          ".cycles",      XrmoptionSepArg, 0 },
192   { "-no-hw",           ".modeHW",      XrmoptionNoArg, "False" },
193   { "-no-hb",           ".modeHB",      XrmoptionNoArg, "False" },
194   { "-no-vw",           ".modeVW",      XrmoptionNoArg, "False" },
195   { "-no-vb",           ".modeVB",      XrmoptionNoArg, "False" },
196   { "-no-dw",           ".modeDW",      XrmoptionNoArg, "False" },
197   { "-no-db",           ".modeDB",      XrmoptionNoArg, "False" },
198   { "-no-w",            ".modeW",       XrmoptionNoArg, "False" },
199   { "-no-b",            ".modeB",       XrmoptionNoArg, "False" },
200   { 0, 0, 0, 0 }
201 };
202
203
204 XSCREENSAVER_MODULE ("LCDscrub", lcdscrub)