began for maemo
[xscreensaver] / xscreensaver / hacks / zoom.c
1 /*
2  *  Copyright (C) 2000 James Macnicol
3  *
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 
10  * implied warranty.
11  */
12
13 #include <math.h>
14 #include "screenhack.h"
15
16 #ifndef MIN
17 #define MIN(a, b) (((a) < (b))?(a):(b))
18 #endif
19
20 #ifndef MAX
21 #define MAX(a, b) (((a) > (b))?(a):(b))
22 #endif
23
24 #define MINX 0.0
25 #define MINY 0.0
26 /* This should be *way* slower than the spotlight hack was */
27 #define X_PERIOD 45000.0
28 #define Y_PERIOD 36000.0
29
30 struct state {
31   Display *dpy;
32   Window window;
33
34   int sizex, sizey;
35
36   int delay;
37   int pixwidth, pixheight, pixspacex, pixspacey, lensoffsetx, lensoffsety;
38   Bool lenses;
39
40   GC window_gc;
41
42   XImage *orig_map;
43   Pixmap pm;
44
45   int tlx, tly, s;
46
47   int sinusoid_offset;
48
49   async_load_state *img_loader;
50 };
51
52
53 static long currentTimeInMs(struct state *st)
54
55   struct timeval curTime;
56 #ifdef GETTIMEOFDAY_TWO_ARGS
57   struct timezone tz = {0,0};
58   gettimeofday(&curTime, &tz);
59 #else
60   gettimeofday(&curTime);
61 #endif
62   return curTime.tv_sec*1000 + curTime.tv_usec/1000.0;
63 }
64
65 static void *
66 zoom_init (Display *dpy, Window window)
67 {
68   struct state *st = (struct state *) calloc (1, sizeof(*st));
69   XGCValues gcv;
70   XWindowAttributes xgwa;
71   Colormap cmap;
72   unsigned long fg, bg;
73   long gcflags;
74   int nblocksx, nblocksy;
75
76   st->dpy = dpy;
77   st->window = window;
78   XGetWindowAttributes(st->dpy, st->window, &xgwa);
79   st->sizex = xgwa.width;
80   st->sizey = xgwa.height;
81   cmap = xgwa.colormap;
82   fg = get_pixel_resource(st->dpy, cmap, "foreground", "Foreground");
83   bg = get_pixel_resource(st->dpy, cmap, "background", "Background");
84
85   st->delay = get_integer_resource(st->dpy, "delay", "Integer");
86   if (st->delay < 1)
87     st->delay = 1;
88   st->pixwidth = get_integer_resource(st->dpy, "pixwidth", "Integer");
89   if (st->pixwidth < 1)
90     st->pixwidth = 1;
91   st->pixheight = get_integer_resource(st->dpy, "pixheight", "Integer");
92   if (st->pixheight < 1)
93     st->pixheight = 1;
94   st->pixspacex = get_integer_resource(st->dpy, "pixspacex", "Integer");
95   if (st->pixspacex < 0)
96     st->pixspacex = 0;
97   st->pixspacey = get_integer_resource(st->dpy, "pixspacey", "Integer");
98   if (st->pixspacey < 0)
99     st->pixspacey = 0;
100   st->lenses = get_boolean_resource(st->dpy, "lenses", "Boolean");
101   st->lensoffsetx = get_integer_resource(st->dpy, "lensoffsetx", "Integer");
102   st->lensoffsetx = MAX(0, MIN(st->pixwidth, st->lensoffsetx));
103   st->lensoffsety = get_integer_resource(st->dpy, "lensoffsety", "Integer");
104   st->lensoffsety = MAX(0, MIN(st->pixwidth, st->lensoffsety));
105
106   gcv.function = GXcopy;
107   gcv.subwindow_mode = IncludeInferiors;
108   gcflags = GCForeground|GCFunction;
109   gcv.foreground = bg;
110   if (!st->lenses && use_subwindow_mode_p(xgwa.screen, st->window))       /* see grabscreen.c */
111     gcflags |= GCSubwindowMode;
112   st->window_gc = XCreateGC(st->dpy, st->window, gcflags, &gcv);
113
114
115   st->orig_map = NULL;
116   st->pm = XCreatePixmap(st->dpy, st->window, st->sizex, st->sizey, xgwa.depth);
117
118   XFillRectangle(st->dpy, st->window, st->window_gc, 0, 0, st->sizex, st->sizey);
119   XSetWindowBackground(st->dpy, st->window, bg);
120
121   st->img_loader = load_image_async_simple (0, xgwa.screen, st->window,
122                                             st->pm, 0, 0);
123
124   /* We might have needed this to grab the image, but if we leave this set
125      to GCSubwindowMode, then we'll *draw* right over subwindows too. */
126   XSetSubwindowMode (st->dpy, st->window_gc, ClipByChildren);
127
128
129   nblocksx = (int)ceil((double)st->sizex / (double)(st->pixwidth + st->pixspacex));
130   nblocksy = (int)ceil((double)st->sizey / (double)(st->pixheight + st->pixspacey));
131   if (st->lenses)
132     st->s = MAX((nblocksx - 1) * st->lensoffsetx + st->pixwidth, 
133             (nblocksy - 1) * st->lensoffsety + st->pixheight) * 2;
134   else
135     st->s = MAX(nblocksx, nblocksy) * 2;
136
137   st->sinusoid_offset = random();
138
139   return st;
140 }
141
142 static unsigned long
143 zoom_draw (Display *dpy, Window window, void *closure)
144 {
145   struct state *st = (struct state *) closure;
146   unsigned x, y, i, j;
147
148   long now;
149
150   if (st->img_loader)   /* still loading */
151     {
152       st->img_loader = load_image_async_simple (st->img_loader, 0, 0, 0, 0, 0);
153       if (! st->img_loader) {  /* just finished */
154         XClearWindow (st->dpy, st->window);
155         if (!st->lenses) {
156           st->orig_map = XGetImage(st->dpy, st->pm, 0, 0, st->sizex, st->sizey, ~0L, ZPixmap);
157           XFreePixmap(st->dpy, st->pm);
158           st->pm = 0;
159         }
160       }
161       return st->delay;
162     }
163
164 #define nrnd(x) (random() % (x))
165
166   now = currentTimeInMs(st);
167   now += st->sinusoid_offset;  /* don't run multiple screens in lock-step */
168
169   /* find new x,y */
170   st->tlx = ((1. + sin(((double)now) / X_PERIOD * 2. * M_PI))/2.0)
171     * (st->sizex - st->s/2) /* -s/4 */ + MINX;
172   st->tly = ((1. + sin(((double)now) / Y_PERIOD * 2. * M_PI))/2.0)
173     * (st->sizey - st->s/2) /* -s/4 */ + MINY;
174
175   if (st->lenses) {
176     for (x = i = 0; x < st->sizex; x += (st->pixwidth + st->pixspacex), ++i)
177       for (y = j = 0; y < st->sizey; y += (st->pixheight + st->pixspacey), ++j) {
178         XCopyArea(st->dpy, st->pm /* src */, st->window /* dest */, st->window_gc,
179                   st->tlx + i * st->lensoffsetx /* src_x */, 
180                   st->tly + j * st->lensoffsety /* src_y */,
181                   st->pixwidth, st->pixheight,
182                   x /* dest_x */, y /* dest_y */);
183       }
184   } else {
185     for (x = i = 0; x < st->sizex; x += (st->pixwidth + st->pixspacex), ++i)
186       for (y = j = 0; y < st->sizey; y += (st->pixheight + st->pixspacey), ++j) {
187         XSetForeground(st->dpy, st->window_gc, XGetPixel(st->orig_map, st->tlx+i, st->tly+j));
188         XFillRectangle(st->dpy, st->window, st->window_gc, 
189                        i * (st->pixwidth + st->pixspacex),
190                        j * (st->pixheight + st->pixspacey), st->pixwidth, st->pixheight);
191       }
192   }
193
194   return st->delay;
195 }
196
197 static void
198 zoom_reshape (Display *dpy, Window window, void *closure, 
199                  unsigned int w, unsigned int h)
200 {
201 }
202
203 static Bool
204 zoom_event (Display *dpy, Window window, void *closure, XEvent *event)
205 {
206   return False;
207 }
208
209 static void
210 zoom_free (Display *dpy, Window window, void *closure)
211 {
212   struct state *st = (struct state *) closure;
213   XFreeGC (st->dpy, st->window_gc);
214   if (st->orig_map) XDestroyImage (st->orig_map);
215   if (st->pm) XFreePixmap (st->dpy, st->pm);
216   free (st);
217 }
218
219
220 static const char *zoom_defaults[] = {
221   "*dontClearRoot: True",
222   ".foreground: white",
223   ".background: black",
224 #ifdef __sgi /* really, HAVE_READ_DISPLAY_EXTENSION */
225   "*visualID: Best",
226 #endif
227   "*lenses:      false",
228   "*delay:       10000",
229   "*pixwidth:    10",
230   "*pixheight:   10",
231   "*pixspacex:   2",
232   "*pixspacey:   2",
233   "*lensoffsetx: 5",
234   "*lensoffsety: 5",
235   0
236 };
237
238 static XrmOptionDescRec zoom_options[] = {
239   { "-lenses", ".lenses", XrmoptionNoArg, "true" },
240   { "-delay", ".delay", XrmoptionSepArg, 0 },
241   { "-pixwidth", ".pixwidth", XrmoptionSepArg, 0 },
242   { "-pixheight", ".pixheight", XrmoptionSepArg, 0 },
243   { "-pixspacex", ".pixspacex", XrmoptionSepArg, 0 },
244   { "-pixspacey", ".pixspacey", XrmoptionSepArg, 0 },
245   { "-lensoffsetx", ".lensoffsetx", XrmoptionSepArg, 0 },
246   { "-lensoffsety", ".lensoffsety", XrmoptionSepArg, 0 },
247   { 0, 0, 0, 0 }
248 };
249
250 XSCREENSAVER_MODULE ("Zoom", zoom)