700de61ec99c36e0ef5a99986dad971ca0d1748d
[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   int count;
28   GC fg, bg;
29   int delay;
30   int spread;
31   int cycles;
32 };
33
34
35 static void *
36 lcdscrub_init (Display *dpy, Window window)
37 {
38   struct state *st = (struct state *) calloc (1, sizeof(*st));
39   XGCValues gcv;
40   st->dpy = dpy;
41   st->window = window;
42   st->delay  = get_integer_resource (st->dpy, "delay",  "Integer");
43   st->spread = get_integer_resource (st->dpy, "spread", "Integer");
44   st->cycles = get_integer_resource (st->dpy, "cycles", "Integer");
45
46   XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
47   gcv.foreground = BlackPixelOfScreen (st->xgwa.screen);
48   gcv.background = WhitePixelOfScreen (st->xgwa.screen);
49   st->bg = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
50   gcv.foreground = WhitePixelOfScreen (st->xgwa.screen);
51   gcv.background = BlackPixelOfScreen (st->xgwa.screen);
52   st->fg = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
53
54 #ifdef HAVE_COCOA
55   jwxyz_XSetAntiAliasing (st->dpy, st->fg, False);
56   jwxyz_XSetAntiAliasing (st->dpy, st->bg, False);
57 #endif
58
59   return st;
60 }
61
62 static unsigned long
63 lcdscrub_draw (Display *dpy, Window window, void *closure)
64 {
65   struct state *st = (struct state *) closure;
66   int count = st->count % st->spread;
67   int i;
68   GC fg = (st->mode & 1 ? st->fg : st->bg);
69   GC bg = (st->mode & 1 ? st->bg : st->fg);
70
71   switch (st->mode) {
72   case HORIZ_W:
73   case HORIZ_B:
74     XFillRectangle (st->dpy, st->window, bg, 0, 0,
75                     st->xgwa.width, st->xgwa.height);
76     for (i = count; i < st->xgwa.height; i += st->spread)
77       XDrawLine (st->dpy, st->window, fg, 0, i, st->xgwa.width, i);
78     break;
79   case VERT_W:
80   case VERT_B:
81     XFillRectangle (st->dpy, st->window, bg, 0, 0,
82                     st->xgwa.width, st->xgwa.height);
83     for (i = count; i < st->xgwa.width; i += st->spread)
84       XDrawLine (st->dpy, st->window, fg, i, 0, i, st->xgwa.height);
85     break;
86   case DIAG_W:
87   case DIAG_B:
88     XFillRectangle (st->dpy, st->window, bg, 0, 0,
89                     st->xgwa.width, st->xgwa.height);
90     for (i = count; i < st->xgwa.width; i += st->spread)
91       XDrawLine (st->dpy, st->window, fg, i, 0, 
92                  i + st->xgwa.width, st->xgwa.width);
93     for (i = -count; i < st->xgwa.height; i += st->spread)
94       XDrawLine (st->dpy, st->window, fg, 0, i,
95                  st->xgwa.height, i + st->xgwa.height);
96     break;
97   case WHITE:
98   case BLACK:
99     XFillRectangle (st->dpy, st->window, fg, 0, 0,
100                     st->xgwa.width, st->xgwa.height);
101     break;
102   default: 
103     abort(); 
104     break;
105   }
106
107   st->count++;
108
109   if (st->count > st->spread * st->cycles)
110     {
111       st->count = 0;
112       if (++st->mode == END)
113         st->mode = 0;
114     }
115
116   return st->delay;
117 }
118
119 static void
120 lcdscrub_reshape (Display *dpy, Window window, void *closure, 
121                  unsigned int w, unsigned int h)
122 {
123 }
124
125 static Bool
126 lcdscrub_event (Display *dpy, Window window, void *closure, XEvent *event)
127 {
128   return False;
129 }
130
131 static void
132 lcdscrub_free (Display *dpy, Window window, void *closure)
133 {
134   struct state *st = (struct state *) closure;
135   XFreeGC (dpy, st->fg);
136   XFreeGC (dpy, st->bg);
137   free (st);
138 }
139
140
141 static const char *lcdscrub_defaults [] = {
142   ".background:         black",
143   ".foreground:         white",
144   "*delay:              100000",
145   "*spread:             8",
146   "*cycles:             60",
147   0
148 };
149
150 static XrmOptionDescRec lcdscrub_options [] = {
151   { "-delay",           ".delay",       XrmoptionSepArg, 0 },
152   { "-spread",          ".spread",      XrmoptionSepArg, 0 },
153   { "-cycles",          ".cycles",      XrmoptionSepArg, 0 },
154   { 0, 0, 0, 0 }
155 };
156
157
158 XSCREENSAVER_MODULE ("LCDscrub", lcdscrub)