ed765a987c0bdeba36373344e09cf2af7445d6c2
[xscreensaver] / hacks / compass.c
1 /* xscreensaver, Copyright (c) 1999 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
12 #include <math.h>
13 #include "screenhack.h"
14
15 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
16 # include "xdbe.h"
17 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
18
19 #define countof(x) (sizeof(x)/sizeof(*(x)))
20 #define ABS(x) ((x)<0?-(x):(x))
21 #define MAX(x,y) ((x)<(y)?(y):(x))
22 #define MIN(x,y) ((x)>(y)?(y):(x))
23 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
24 #define RANDSIGN() ((random() & 1) ? 1 : -1)
25
26 struct disc {
27   int theta;            /* 0 - 360*64 */
28   int velocity;
29   int acceleration;
30   int limit;
31   GC gc;
32   void (*draw) (Display *, Drawable, struct disc *,
33                 int x, int y, int radius);
34 };
35
36
37 static void
38 draw_letters (Display *dpy, Drawable d, struct disc *disc,
39               int x, int y, int radius)
40 {
41   XPoint points[50];
42   double th2 = 2 * M_PI * (disc->theta / ((double) 360*64));
43   double th;
44
45   /* W */
46
47   th = th2;
48
49   points[0].x = x + radius * 0.8 * cos(th - 0.07);
50   points[0].y = y + radius * 0.8 * sin(th - 0.07);
51
52   points[1].x = x + radius * 0.7 * cos(th - 0.05);
53   points[1].y = y + radius * 0.7 * sin(th - 0.05);
54
55   points[2].x = x + radius * 0.78 * cos(th);
56   points[2].y = y + radius * 0.78 * sin(th);
57
58   points[3].x = x + radius * 0.7 * cos(th + 0.05);
59   points[3].y = y + radius * 0.7 * sin(th + 0.05);
60
61   points[4].x = x + radius * 0.8 * cos(th + 0.07);
62   points[4].y = y + radius * 0.8 * sin(th + 0.07);
63
64   XDrawLines (dpy, d, disc->gc, points, 5, CoordModeOrigin);
65
66   /* 30 (1) */
67
68   th = th2 + (2 * M_PI * 0.08333);
69
70   points[0].x = x + radius * 0.78 * cos(th - 0.13);
71   points[0].y = y + radius * 0.78 * sin(th - 0.13);
72
73   points[1].x = x + radius * 0.8  * cos(th - 0.08);
74   points[1].y = y + radius * 0.8  * sin(th - 0.08);
75
76   points[2].x = x + radius * 0.78 * cos(th - 0.03);
77   points[2].y = y + radius * 0.78 * sin(th - 0.03);
78
79   points[3].x = x + radius * 0.76 * cos(th - 0.03);
80   points[3].y = y + radius * 0.76 * sin(th - 0.03);
81
82   points[4].x = x + radius * 0.75 * cos(th - 0.08);
83   points[4].y = y + radius * 0.75 * sin(th - 0.08);
84
85   points[5].x = x + radius * 0.74 * cos(th - 0.03);
86   points[5].y = y + radius * 0.74 * sin(th - 0.03);
87
88   points[6].x = x + radius * 0.72 * cos(th - 0.03);
89   points[6].y = y + radius * 0.72 * sin(th - 0.03);
90
91   points[7].x = x + radius * 0.7  * cos(th - 0.08);
92   points[7].y = y + radius * 0.7  * sin(th - 0.08);
93
94   points[8].x = x + radius * 0.72  * cos(th - 0.13);
95   points[8].y = y + radius * 0.72  * sin(th - 0.13);
96
97   XDrawLines (dpy, d, disc->gc, points, 9, CoordModeOrigin);
98
99   /* 30 (2) */
100
101   points[0].x = x + radius * 0.78 * cos(th + 0.03);
102   points[0].y = y + radius * 0.78 * sin(th + 0.03);
103
104   points[1].x = x + radius * 0.8  * cos(th + 0.08);
105   points[1].y = y + radius * 0.8  * sin(th + 0.08);
106
107   points[2].x = x + radius * 0.78 * cos(th + 0.13);
108   points[2].y = y + radius * 0.78 * sin(th + 0.13);
109
110   points[3].x = x + radius * 0.72 * cos(th + 0.13);
111   points[3].y = y + radius * 0.72 * sin(th + 0.13);
112
113   points[4].x = x + radius * 0.7  * cos(th + 0.08);
114   points[4].y = y + radius * 0.7  * sin(th + 0.08);
115
116   points[5].x = x + radius * 0.72  * cos(th + 0.03);
117   points[5].y = y + radius * 0.72  * sin(th + 0.03);
118
119   points[6] = points[0];
120
121   XDrawLines (dpy, d, disc->gc, points, 7, CoordModeOrigin);
122
123   /* 33 (1) */
124
125   th = th2 + (2 * M_PI * 0.16666);
126
127   points[0].x = x + radius * 0.78 * cos(th - 0.13);
128   points[0].y = y + radius * 0.78 * sin(th - 0.13);
129
130   points[1].x = x + radius * 0.8  * cos(th - 0.08);
131   points[1].y = y + radius * 0.8  * sin(th - 0.08);
132
133   points[2].x = x + radius * 0.78 * cos(th - 0.03);
134   points[2].y = y + radius * 0.78 * sin(th - 0.03);
135
136   points[3].x = x + radius * 0.76 * cos(th - 0.03);
137   points[3].y = y + radius * 0.76 * sin(th - 0.03);
138
139   points[4].x = x + radius * 0.75 * cos(th - 0.08);
140   points[4].y = y + radius * 0.75 * sin(th - 0.08);
141
142   points[5].x = x + radius * 0.74 * cos(th - 0.03);
143   points[5].y = y + radius * 0.74 * sin(th - 0.03);
144
145   points[6].x = x + radius * 0.72 * cos(th - 0.03);
146   points[6].y = y + radius * 0.72 * sin(th - 0.03);
147
148   points[7].x = x + radius * 0.7  * cos(th - 0.08);
149   points[7].y = y + radius * 0.7  * sin(th - 0.08);
150
151   points[8].x = x + radius * 0.72  * cos(th - 0.13);
152   points[8].y = y + radius * 0.72  * sin(th - 0.13);
153
154   XDrawLines (dpy, d, disc->gc, points, 9, CoordModeOrigin);
155
156   /* 33 (2) */
157
158   points[0].x = x + radius * 0.78 * cos(th + 0.03);
159   points[0].y = y + radius * 0.78 * sin(th + 0.03);
160
161   points[1].x = x + radius * 0.8  * cos(th + 0.08);
162   points[1].y = y + radius * 0.8  * sin(th + 0.08);
163
164   points[2].x = x + radius * 0.78 * cos(th + 0.13);
165   points[2].y = y + radius * 0.78 * sin(th + 0.13);
166
167   points[3].x = x + radius * 0.76 * cos(th + 0.13);
168   points[3].y = y + radius * 0.76 * sin(th + 0.13);
169
170   points[4].x = x + radius * 0.75 * cos(th + 0.08);
171   points[4].y = y + radius * 0.75 * sin(th + 0.08);
172
173   points[5].x = x + radius * 0.74 * cos(th + 0.13);
174   points[5].y = y + radius * 0.74 * sin(th + 0.13);
175
176   points[6].x = x + radius * 0.72 * cos(th + 0.13);
177   points[6].y = y + radius * 0.72 * sin(th + 0.13);
178
179   points[7].x = x + radius * 0.7  * cos(th + 0.08);
180   points[7].y = y + radius * 0.7  * sin(th + 0.08);
181
182   points[8].x = x + radius * 0.72  * cos(th + 0.03);
183   points[8].y = y + radius * 0.72  * sin(th + 0.03);
184
185   XDrawLines (dpy, d, disc->gc, points, 9, CoordModeOrigin);
186
187   /* N */
188
189   th = th2 + (2 * M_PI * 0.25);
190
191   points[0].x = x + radius * 0.7 * cos(th - 0.05);
192   points[0].y = y + radius * 0.7 * sin(th - 0.05);
193
194   points[1].x = x + radius * 0.8 * cos(th - 0.05);
195   points[1].y = y + radius * 0.8 * sin(th - 0.05);
196
197   points[2].x = x + radius * 0.7 * cos(th + 0.05);
198   points[2].y = y + radius * 0.7 * sin(th + 0.05);
199
200   points[3].x = x + radius * 0.8 * cos(th + 0.05);
201   points[3].y = y + radius * 0.8 * sin(th + 0.05);
202
203   XDrawLines (dpy, d, disc->gc, points, 4, CoordModeOrigin);
204
205   /* 3 */
206
207   th = th2 + (2 * M_PI * 0.33333);
208
209   points[0].x = x + radius * 0.78 * cos(th - 0.05);
210   points[0].y = y + radius * 0.78 * sin(th - 0.05);
211
212   points[1].x = x + radius * 0.8  * cos(th);
213   points[1].y = y + radius * 0.8  * sin(th);
214
215   points[2].x = x + radius * 0.78 * cos(th + 0.05);
216   points[2].y = y + radius * 0.78 * sin(th + 0.05);
217
218   points[3].x = x + radius * 0.76 * cos(th + 0.05);
219   points[3].y = y + radius * 0.76 * sin(th + 0.05);
220
221   points[4].x = x + radius * 0.75 * cos(th);
222   points[4].y = y + radius * 0.75 * sin(th);
223
224   points[5].x = x + radius * 0.74 * cos(th + 0.05);
225   points[5].y = y + radius * 0.74 * sin(th + 0.05);
226
227   points[6].x = x + radius * 0.72 * cos(th + 0.05);
228   points[6].y = y + radius * 0.72 * sin(th + 0.05);
229
230   points[7].x = x + radius * 0.7  * cos(th);
231   points[7].y = y + radius * 0.7  * sin(th);
232
233   points[8].x = x + radius * 0.72  * cos(th - 0.05);
234   points[8].y = y + radius * 0.72  * sin(th - 0.05);
235
236   XDrawLines (dpy, d, disc->gc, points, 9, CoordModeOrigin);
237
238   /* 6 */
239
240   th = th2 + (2 * M_PI * 0.41666);
241
242   points[0].x = x + radius * 0.78 * cos(th + 0.05);
243   points[0].y = y + radius * 0.78 * sin(th + 0.05);
244
245   points[1].x = x + radius * 0.8  * cos(th);
246   points[1].y = y + radius * 0.8  * sin(th);
247
248   points[2].x = x + radius * 0.78 * cos(th - 0.05);
249   points[2].y = y + radius * 0.78 * sin(th - 0.05);
250
251   points[3].x = x + radius * 0.72 * cos(th - 0.05);
252   points[3].y = y + radius * 0.72 * sin(th - 0.05);
253
254   points[4].x = x + radius * 0.7  * cos(th);
255   points[4].y = y + radius * 0.7  * sin(th);
256
257   points[5].x = x + radius * 0.72 * cos(th + 0.05);
258   points[5].y = y + radius * 0.72 * sin(th + 0.05);
259
260   points[6].x = x + radius * 0.74 * cos(th + 0.05);
261   points[6].y = y + radius * 0.74 * sin(th + 0.05);
262
263   points[7].x = x + radius * 0.76 * cos(th);
264   points[7].y = y + radius * 0.76 * sin(th);
265
266   points[8].x = x + radius * 0.74 * cos(th - 0.05);
267   points[8].y = y + radius * 0.74 * sin(th - 0.05);
268
269   XDrawLines (dpy, d, disc->gc, points, 9, CoordModeOrigin);
270
271
272   /* E */
273
274   th = th2 + (2 * M_PI * 0.5);
275
276   points[0].x = x + radius * 0.8 * cos(th + 0.05);
277   points[0].y = y + radius * 0.8 * sin(th + 0.05);
278
279   points[1].x = x + radius * 0.8 * cos(th - 0.05);
280   points[1].y = y + radius * 0.8 * sin(th - 0.05);
281
282   points[2].x = x + radius * 0.75 * cos(th - 0.05);
283   points[2].y = y + radius * 0.75 * sin(th - 0.05);
284
285   points[3].x = x + radius * 0.75 * cos(th + 0.025);
286   points[3].y = y + radius * 0.75 * sin(th + 0.025);
287
288   points[4].x = x + radius * 0.75 * cos(th - 0.05);
289   points[4].y = y + radius * 0.75 * sin(th - 0.05);
290
291   points[5].x = x + radius * 0.7 * cos(th - 0.05);
292   points[5].y = y + radius * 0.7 * sin(th - 0.05);
293
294   points[6].x = x + radius * 0.7 * cos(th + 0.05);
295   points[6].y = y + radius * 0.7 * sin(th + 0.05);
296
297   XDrawLines (dpy, d, disc->gc, points, 7, CoordModeOrigin);
298
299   /* 12 (1) */
300
301   th = th2 + (2 * M_PI * 0.58333);
302
303   points[0].x = x + radius * 0.77 * cos(th - 0.06);
304   points[0].y = y + radius * 0.77 * sin(th - 0.06);
305
306   points[1].x = x + radius * 0.8  * cos(th - 0.03);
307   points[1].y = y + radius * 0.8  * sin(th - 0.03);
308
309   points[2].x = x + radius * 0.7  * cos(th - 0.03);
310   points[2].y = y + radius * 0.7  * sin(th - 0.03);
311
312   XDrawLines (dpy, d, disc->gc, points, 3, CoordModeOrigin);
313
314   /* 12 (2) */
315
316   points[0].x = x + radius * 0.78 * cos(th + 0.02);
317   points[0].y = y + radius * 0.78 * sin(th + 0.02);
318
319   points[1].x = x + radius * 0.8  * cos(th + 0.07);
320   points[1].y = y + radius * 0.8  * sin(th + 0.07);
321
322   points[2].x = x + radius * 0.78 * cos(th + 0.11);
323   points[2].y = y + radius * 0.78 * sin(th + 0.11);
324
325   points[3].x = x + radius * 0.76 * cos(th + 0.11);
326   points[3].y = y + radius * 0.76 * sin(th + 0.11);
327
328   points[4].x = x + radius * 0.74 * cos(th + 0.02);
329   points[4].y = y + radius * 0.74 * sin(th + 0.02);
330
331   points[5].x = x + radius * 0.71 * cos(th + 0.03);
332   points[5].y = y + radius * 0.71 * sin(th + 0.03);
333
334   points[6].x = x + radius * 0.7  * cos(th + 0.03);
335   points[6].y = y + radius * 0.7  * sin(th + 0.03);
336
337   points[7].x = x + radius * 0.7  * cos(th + 0.13);
338   points[7].y = y + radius * 0.7  * sin(th + 0.13);
339
340   XDrawLines (dpy, d, disc->gc, points, 8, CoordModeOrigin);
341
342   /* 15 (1) */
343
344   th = th2 + (2 * M_PI * 0.66666);
345
346   points[0].x = x + radius * 0.77 * cos(th - 0.06);
347   points[0].y = y + radius * 0.77 * sin(th - 0.06);
348
349   points[1].x = x + radius * 0.8  * cos(th - 0.03);
350   points[1].y = y + radius * 0.8  * sin(th - 0.03);
351
352   points[2].x = x + radius * 0.7  * cos(th - 0.03);
353   points[2].y = y + radius * 0.7  * sin(th - 0.03);
354
355   XDrawLines (dpy, d, disc->gc, points, 3, CoordModeOrigin);
356
357   /* 15 (2) */
358
359   points[0].x = x + radius * 0.8  * cos(th + 0.11);
360   points[0].y = y + radius * 0.8  * sin(th + 0.11);
361
362   points[1].x = x + radius * 0.8  * cos(th + 0.02);
363   points[1].y = y + radius * 0.8  * sin(th + 0.02);
364
365   points[2].x = x + radius * 0.76 * cos(th + 0.02);
366   points[2].y = y + radius * 0.76 * sin(th + 0.02);
367
368   points[3].x = x + radius * 0.77 * cos(th + 0.06);
369   points[3].y = y + radius * 0.77 * sin(th + 0.06);
370
371   points[4].x = x + radius * 0.76 * cos(th + 0.10);
372   points[4].y = y + radius * 0.76 * sin(th + 0.10);
373
374   points[5].x = x + radius * 0.73 * cos(th + 0.11);
375   points[5].y = y + radius * 0.73 * sin(th + 0.11);
376
377   points[6].x = x + radius * 0.72 * cos(th + 0.10);
378   points[6].y = y + radius * 0.72 * sin(th + 0.10);
379
380   points[7].x = x + radius * 0.7  * cos(th + 0.06);
381   points[7].y = y + radius * 0.7  * sin(th + 0.06);
382
383   points[8].x = x + radius * 0.72 * cos(th + 0.02);
384   points[8].y = y + radius * 0.72 * sin(th + 0.02);
385
386   XDrawLines (dpy, d, disc->gc, points, 9, CoordModeOrigin);
387
388   /* S */
389
390   th = th2 + (2 * M_PI * 0.75);
391
392   points[0].x = x + radius * 0.78 * cos(th + 0.05);
393   points[0].y = y + radius * 0.78 * sin(th + 0.05);
394
395   points[1].x = x + radius * 0.8  * cos(th);
396   points[1].y = y + radius * 0.8  * sin(th);
397
398   points[2].x = x + radius * 0.78 * cos(th - 0.05);
399   points[2].y = y + radius * 0.78 * sin(th - 0.05);
400
401   points[3].x = x + radius * 0.76 * cos(th - 0.05);
402   points[3].y = y + radius * 0.76 * sin(th - 0.05);
403
404   points[4].x = x + radius * 0.74 * cos(th + 0.05);
405   points[4].y = y + radius * 0.74 * sin(th + 0.05);
406
407   points[5].x = x + radius * 0.72 * cos(th + 0.05);
408   points[5].y = y + radius * 0.72 * sin(th + 0.05);
409
410   points[6].x = x + radius * 0.7  * cos(th);
411   points[6].y = y + radius * 0.7  * sin(th);
412
413   points[7].x = x + radius * 0.72  * cos(th - 0.05);
414   points[7].y = y + radius * 0.72  * sin(th - 0.05);
415
416   XDrawLines (dpy, d, disc->gc, points, 8, CoordModeOrigin);
417
418   /* 21 (1) */
419
420   th = th2 + (2 * M_PI * 0.83333);
421
422   points[0].x = x + radius * 0.78 * cos(th - 0.13);
423   points[0].y = y + radius * 0.78 * sin(th - 0.13);
424
425   points[1].x = x + radius * 0.8  * cos(th - 0.08);
426   points[1].y = y + radius * 0.8  * sin(th - 0.08);
427
428   points[2].x = x + radius * 0.78 * cos(th - 0.03);
429   points[2].y = y + radius * 0.78 * sin(th - 0.03);
430
431   points[3].x = x + radius * 0.76 * cos(th - 0.03);
432   points[3].y = y + radius * 0.76 * sin(th - 0.03);
433
434   points[4].x = x + radius * 0.74 * cos(th - 0.12);
435   points[4].y = y + radius * 0.74 * sin(th - 0.12);
436
437   points[5].x = x + radius * 0.71 * cos(th - 0.13);
438   points[5].y = y + radius * 0.71 * sin(th - 0.13);
439
440   points[6].x = x + radius * 0.7  * cos(th - 0.13);
441   points[6].y = y + radius * 0.7  * sin(th - 0.13);
442
443   points[7].x = x + radius * 0.7  * cos(th - 0.02);
444   points[7].y = y + radius * 0.7  * sin(th - 0.02);
445
446   XDrawLines (dpy, d, disc->gc, points, 8, CoordModeOrigin);
447
448   /* 21 (2) */
449
450   points[0].x = x + radius * 0.77 * cos(th + 0.03);
451   points[0].y = y + radius * 0.77 * sin(th + 0.03);
452
453   points[1].x = x + radius * 0.8  * cos(th + 0.06);
454   points[1].y = y + radius * 0.8  * sin(th + 0.06);
455
456   points[2].x = x + radius * 0.7  * cos(th + 0.06);
457   points[2].y = y + radius * 0.7  * sin(th + 0.06);
458
459   XDrawLines (dpy, d, disc->gc, points, 3, CoordModeOrigin);
460
461   /* 24 (1) */
462
463   th = th2 + (2 * M_PI * 0.91666);
464
465   points[0].x = x + radius * 0.78 * cos(th - 0.13);
466   points[0].y = y + radius * 0.78 * sin(th - 0.13);
467
468   points[1].x = x + radius * 0.8  * cos(th - 0.08);
469   points[1].y = y + radius * 0.8  * sin(th - 0.08);
470
471   points[2].x = x + radius * 0.78 * cos(th - 0.03);
472   points[2].y = y + radius * 0.78 * sin(th - 0.03);
473
474   points[3].x = x + radius * 0.76 * cos(th - 0.03);
475   points[3].y = y + radius * 0.76 * sin(th - 0.03);
476
477   points[4].x = x + radius * 0.74 * cos(th - 0.12);
478   points[4].y = y + radius * 0.74 * sin(th - 0.12);
479
480   points[5].x = x + radius * 0.71 * cos(th - 0.13);
481   points[5].y = y + radius * 0.71 * sin(th - 0.13);
482
483   points[6].x = x + radius * 0.7  * cos(th - 0.13);
484   points[6].y = y + radius * 0.7  * sin(th - 0.13);
485
486   points[7].x = x + radius * 0.7  * cos(th - 0.02);
487   points[7].y = y + radius * 0.7  * sin(th - 0.02);
488
489   XDrawLines (dpy, d, disc->gc, points, 8, CoordModeOrigin);
490
491   /* 24 (2) */
492
493   points[0].x = x + radius * 0.69 * cos(th + 0.09);
494   points[0].y = y + radius * 0.69 * sin(th + 0.09);
495
496   points[1].x = x + radius * 0.8  * cos(th + 0.09);
497   points[1].y = y + radius * 0.8  * sin(th + 0.09);
498
499   points[2].x = x + radius * 0.72 * cos(th + 0.01);
500   points[2].y = y + radius * 0.72 * sin(th + 0.01);
501
502   points[3].x = x + radius * 0.72 * cos(th + 0.13);
503   points[3].y = y + radius * 0.72 * sin(th + 0.13);
504
505   XDrawLines (dpy, d, disc->gc, points, 4, CoordModeOrigin);
506 }
507
508
509 static void
510 draw_ticks (Display *dpy, Drawable d, struct disc *disc,
511             int x, int y, int radius)
512 {
513   XSegment segs[72];
514   int i;
515   double tick = (M_PI * 2) / 72;
516
517   for (i = 0; i < 72; i++)
518     {
519       int radius2 = radius;
520       double th = (i * tick) + (2 * M_PI * (disc->theta / ((double) 360*64)));
521
522       if (i % 6)
523         radius2 -= radius / 16;
524       else
525         radius2 -= radius / 8;
526
527       segs[i].x1 = x + radius  * cos(th);
528       segs[i].y1 = y + radius  * sin(th);
529       segs[i].x2 = x + radius2 * cos(th);
530       segs[i].y2 = y + radius2 * sin(th);
531     }
532   XDrawSegments (dpy, d, disc->gc, segs, countof(segs));
533
534   draw_letters (dpy, d, disc, x, y, radius);
535 }
536
537
538 static void
539 draw_thin_arrow (Display *dpy, Drawable d, struct disc *disc,
540                  int x, int y, int radius)
541 {
542   XPoint points[3];
543   double th;
544   int radius2;
545   double tick = ((M_PI * 2) / 72) * 2;
546
547   radius *= 0.9;
548   radius2 = radius - (radius / 8) * 3;
549
550   th = 2 * M_PI * (disc->theta / ((double) 360*64));
551
552   points[0].x = x + radius * cos(th);           /* tip */
553   points[0].y = y + radius * sin(th);
554
555   points[1].x = x + radius2 * cos(th - tick);   /* tip left */
556   points[1].y = y + radius2 * sin(th - tick);
557
558   points[2].x = x + radius2 * cos(th + tick);   /* tip right */
559   points[2].y = y + radius2 * sin(th + tick);
560
561   XDrawLine (dpy, d, disc->gc,
562              (int) (x + radius2 * cos(th)),
563              (int) (y + radius2 * sin(th)),
564              (int) (x + -radius * cos(th)),
565              (int) (y + -radius * sin(th)));
566
567   XFillPolygon (dpy, d, disc->gc, points, 3, Convex, CoordModeOrigin);
568 }
569
570
571 static void
572 draw_thick_arrow (Display *dpy, Drawable d, struct disc *disc,
573                   int x, int y, int radius)
574 {
575   XPoint points[10];
576   double th;
577   int radius2, radius3;
578   double tick = ((M_PI * 2) / 72) * 2;
579
580   radius *= 0.9;
581   radius2 = radius - (radius / 8) * 3;
582   radius3 = radius - (radius / 8) * 2;
583   th = 2 * M_PI * (disc->theta / ((double) 360*64));
584
585   points[0].x = x + radius * cos(th);           /* tip */
586   points[0].y = y + radius * sin(th);
587
588   points[1].x = x + radius2 * cos(th - tick);   /* tip left */
589   points[1].y = y + radius2 * sin(th - tick);
590
591   points[2].x = x + radius2 * cos(th + tick);   /* tip right */
592   points[2].y = y + radius2 * sin(th + tick);
593
594   points[3] = points[0];
595
596   XDrawLines (dpy, d, disc->gc, points, 4, CoordModeOrigin);
597
598   points[0].x = x + radius2 * cos(th - tick/2);  /* top left */
599   points[0].y = y + radius2 * sin(th - tick/2);
600
601   points[1].x = x + -radius2 * cos(th + tick/2); /* bottom left */
602   points[1].y = y + -radius2 * sin(th + tick/2);
603
604   points[2].x = x + -radius3 * cos(th);          /* bottom */
605   points[2].y = y + -radius3 * sin(th);
606
607   points[3].x = x + -radius * cos(th);           /* bottom spike */
608   points[3].y = y + -radius * sin(th);
609
610   points[4] = points[2];                         /* return */
611
612   points[5].x = x + -radius2 * cos(th - tick/2); /* bottom right */
613   points[5].y = y + -radius2 * sin(th - tick/2);
614
615   points[6].x = x + radius2 * cos(th + tick/2);  /* top right */
616   points[6].y = y + radius2 * sin(th + tick/2);
617
618   XDrawLines (dpy, d, disc->gc, points, 7, CoordModeOrigin);
619 }
620
621
622
623 static void
624 roll_disc (struct disc *disc)
625 {
626   double th = disc->theta;
627   if (th < 0)
628     th = -(th + disc->velocity);
629   else
630     th = (th + disc->velocity);
631
632   if (th > (360*64))
633     th -= (360*64);
634   else if (th < 0)
635     th += (360*64);
636
637   disc->theta = (disc->theta > 0 ? th : -th);
638
639   disc->velocity += disc->acceleration;
640
641   if (disc->velocity > disc->limit || 
642       disc->velocity < -disc->limit)
643     disc->acceleration = -disc->acceleration;
644
645   /* Alter direction of rotational acceleration randomly. */
646   if (! (random() % 120))
647     disc->acceleration = -disc->acceleration;
648
649   /* Change acceleration very occasionally. */
650   if (! (random() % 200))
651     {
652       if (random() & 1)
653         disc->acceleration *= 1.2;
654       else
655         disc->acceleration *= 0.8;
656     }
657 }
658
659
660 static void
661 init_spin (struct disc *disc)
662 {
663   disc->limit = 5*64;
664   disc->theta = RAND(360*64);
665   disc->velocity = RAND(16) * RANDSIGN();
666   disc->acceleration = RAND(16) * RANDSIGN();
667 }
668
669
670 static void
671 draw_compass (Display *dpy, Drawable d, struct disc **discs,
672               int x, int y, int radius)
673 {
674   int i = 0;
675   while (discs[i])
676     {
677       discs[i]->draw (dpy, d, discs[i], x, y, radius);
678       roll_disc (discs[i]);
679       i++;
680     }
681 }
682
683 static void
684 draw_pointer (Display *dpy, Drawable d, GC ptr_gc, GC dot_gc,
685               int x, int y, int radius)
686 {
687   XPoint points[3];
688   int size = radius * 0.1;
689
690   /* top */
691
692   points[0].x = x - size;
693   points[0].y = y - radius - size;
694
695   points[1].x = x + size;
696   points[1].y = y - radius - size;
697
698   points[2].x = x;
699   points[2].y = y - radius;
700   
701   XFillPolygon (dpy, d, ptr_gc, points, 3, Convex, CoordModeOrigin);
702
703   /* top right */
704
705   points[0].x = x - (radius * 0.85);
706   points[0].y = y - (radius * 0.8);
707
708   points[1].x = x - (radius * 1.1);
709   points[1].y = y - (radius * 0.55);
710
711   points[2].x = x - (radius * 0.6);
712   points[2].y = y - (radius * 0.65);
713   
714   XFillPolygon (dpy, d, ptr_gc, points, 3, Convex, CoordModeOrigin);
715
716   /* left */
717
718   points[0].x = x - (radius * 1.05);
719   points[0].y = y;
720
721   points[1].x = x - (radius * 1.1);
722   points[1].y = y - (radius * 0.025);
723
724   points[2].x = x - (radius * 1.1);
725   points[2].y = y + (radius * 0.025);
726   
727   XFillPolygon (dpy, d, dot_gc, points, 3, Convex, CoordModeOrigin);
728
729   /* right */
730
731   points[0].x = x + (radius * 1.05);
732   points[0].y = y;
733
734   points[1].x = x + (radius * 1.1);
735   points[1].y = y - (radius * 0.025);
736
737   points[2].x = x + (radius * 1.1);
738   points[2].y = y + (radius * 0.025);
739   
740   XFillPolygon (dpy, d, dot_gc, points, 3, Convex, CoordModeOrigin);
741
742   /* bottom */
743
744   points[0].x = x;
745   points[0].y = y + (radius * 1.05);
746
747   points[1].x = x - (radius * 0.025);
748   points[1].y = y + (radius * 1.1);
749
750   points[2].x = x + (radius * 0.025);
751   points[2].y = y + (radius * 1.1);
752   
753   XFillPolygon (dpy, d, dot_gc, points, 3, Convex, CoordModeOrigin);
754
755   /* bottom left */
756
757   points[0].x = x + (radius * 0.74);
758   points[0].y = y + (radius * 0.74);
759
760   points[1].x = x + (radius * 0.78);
761   points[1].y = y + (radius * 0.75);
762
763   points[2].x = x + (radius * 0.75);
764   points[2].y = y + (radius * 0.78);
765   
766   XFillPolygon (dpy, d, dot_gc, points, 3, Convex, CoordModeOrigin);
767
768   /* top left */
769
770   points[0].x = x + (radius * 0.74);
771   points[0].y = y - (radius * 0.74);
772
773   points[1].x = x + (radius * 0.78);
774   points[1].y = y - (radius * 0.75);
775
776   points[2].x = x + (radius * 0.75);
777   points[2].y = y - (radius * 0.78);
778   
779   XFillPolygon (dpy, d, dot_gc, points, 3, Convex, CoordModeOrigin);
780
781   /* bottom right */
782
783   points[0].x = x - (radius * 0.74);
784   points[0].y = y + (radius * 0.74);
785
786   points[1].x = x - (radius * 0.78);
787   points[1].y = y + (radius * 0.75);
788
789   points[2].x = x - (radius * 0.75);
790   points[2].y = y + (radius * 0.78);
791   
792   XFillPolygon (dpy, d, dot_gc, points, 3, Convex, CoordModeOrigin);
793 }
794
795 \f
796 char *progclass = "Compass";
797
798 char *defaults [] = {
799   ".background:         #000000",
800   ".foreground:         #DDFFFF",
801   "*arrow1Foreground:   #FFF66A",
802   "*arrow2Foreground:   #F7D64A",
803   "*pointerForeground:  #FF0000",
804   "*delay:              20000",
805   "*doubleBuffer:       True",
806 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
807   "*useDBE:             True",
808 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
809   0
810 };
811
812 XrmOptionDescRec options [] = {
813   { "-delay",           ".delay",       XrmoptionSepArg, 0 },
814   { "-db",              ".doubleBuffer", XrmoptionNoArg,  "True" },
815   { "-no-db",           ".doubleBuffer", XrmoptionNoArg,  "False" },
816   { 0, 0, 0, 0 }
817 };
818
819 void
820 screenhack (Display *dpy, Window window)
821 {
822   XGCValues gcv;
823   int delay = get_integer_resource ("delay", "Integer");
824   Bool dbuf = get_boolean_resource ("doubleBuffer", "Boolean");
825   struct disc *discs[4];
826   int x, y, size, size2;
827   GC ptr_gc;
828   GC erase_gc = 0;
829   XWindowAttributes xgwa;
830   Pixmap b=0, ba=0, bb=0;       /* double-buffer to reduce flicker */
831 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
832   XdbeBackBuffer backb = 0;
833 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
834
835   XGetWindowAttributes (dpy, window, &xgwa);
836   size2 = MIN(xgwa.width, xgwa.height);
837
838   if (size2 > 600) size2 = 600;
839
840   size = (size2 / 2) * 0.8;
841
842   x = xgwa.width/2;
843   y = xgwa.height/2;
844
845   if (dbuf)
846     {
847 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
848       b = backb = xdbe_get_backbuffer (dpy, window, XdbeUndefined);
849 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
850
851       if (!b)
852         {
853           x = size2/2;
854           y = size2/2;
855           ba = XCreatePixmap (dpy, window, size2, size2, xgwa.depth);
856           bb = XCreatePixmap (dpy, window, size2, size2, xgwa.depth);
857           b = ba;
858         }
859     }
860   else
861     {
862       b = window;
863     }
864
865   discs[0] = (struct disc *) calloc (1, sizeof (struct disc));
866   discs[1] = (struct disc *) calloc (1, sizeof (struct disc));
867   discs[2] = (struct disc *) calloc (1, sizeof (struct disc));
868   discs[3] = 0;
869
870   gcv.foreground = get_pixel_resource ("foreground", "Foreground",
871                                        dpy, xgwa.colormap);
872   gcv.line_width = MAX(2, (size/60));
873   gcv.join_style = JoinBevel;
874   discs[0]->draw = draw_ticks;
875   discs[0]->gc = XCreateGC (dpy, b, GCForeground|GCLineWidth|GCJoinStyle,
876                             &gcv);
877   init_spin (discs[0]);
878
879   gcv.foreground = get_pixel_resource ("arrow2Foreground", "Foreground",
880                                        dpy, xgwa.colormap);
881   gcv.line_width = MAX(4, (size / 30));
882   discs[1]->draw = draw_thick_arrow;
883   discs[1]->gc = XCreateGC (dpy, b, GCForeground|GCLineWidth, &gcv);
884   init_spin (discs[1]);
885
886   gcv.foreground = get_pixel_resource ("arrow1Foreground", "Foreground",
887                                        dpy, xgwa.colormap);
888   gcv.line_width = MAX(4, (size / 30));
889   discs[2]->draw = draw_thin_arrow;
890   discs[2]->gc = XCreateGC (dpy, b, GCForeground|GCLineWidth, &gcv);
891   init_spin (discs[2]);
892
893   gcv.foreground = get_pixel_resource ("pointerForeground", "Foreground",
894                                        dpy, xgwa.colormap);
895   ptr_gc = XCreateGC (dpy, b, GCForeground|GCLineWidth, &gcv);
896
897   gcv.foreground = get_pixel_resource ("background", "Background",
898                                        dpy, xgwa.colormap);
899   erase_gc = XCreateGC (dpy, b, GCForeground, &gcv);
900
901   if (ba) XFillRectangle (dpy, ba, erase_gc, 0, 0, size2, size2);
902   if (bb) XFillRectangle (dpy, bb, erase_gc, 0, 0, size2, size2);
903
904   while (1)
905     {
906       XFillRectangle (dpy, b, erase_gc, 0, 0, xgwa.width, xgwa.height);
907
908       draw_compass (dpy, b, discs, x, y, size);
909       draw_pointer (dpy, b, ptr_gc, discs[0]->gc, x, y, size);
910
911 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
912       if (backb)
913         {
914           XdbeSwapInfo info[1];
915           info[0].swap_window = window;
916           info[0].swap_action = XdbeUndefined;
917           XdbeSwapBuffers (dpy, info, 1);
918         }
919       else
920 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
921       if (dbuf)
922         {
923           XCopyArea (dpy, b, window, erase_gc, 0, 0,
924                      size2, size2,
925                      xgwa.width/2 - x,
926                      xgwa.height/2 - y);
927           b = (b == ba ? bb : ba);
928         }
929
930       XSync (dpy, False);
931       screenhack_handle_events (dpy);
932       if (delay)
933         usleep (delay);
934     }
935 }