chiark / gitweb /
Imported Upstream version 1.0.0
[e16] / src / fx.c
1 /*
2  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies of the Software, its documentation and marketing & publicity
13  * materials, and acknowledgment shall be given in the documentation, materials
14  * and software packages that this Software was used.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 #include "E.h"
24 #include "desktops.h"
25 #include "dialog.h"
26 #include "ecompmgr.h"
27 #include "eimage.h"
28 #include "emodule.h"
29 #include "settings.h"
30 #include "timers.h"
31 #include "xwin.h"
32 #include <math.h>
33
34 #define E_FX_RAINDROPS          0
35 #define E_FX_IMAGESPINNER       0
36
37 /* FIXME - Needs cleaning up */
38
39 #ifndef M_PI_2
40 #define M_PI_2 (3.141592654 / 2)
41 #endif
42
43 #define FX_OP_START  1
44 #define FX_OP_STOP   2
45 #define FX_OP_TOGGLE 3
46
47 typedef struct {
48    const char         *name;
49    void                (*init_func) (const char *name);
50    void                (*desk_func) (void);
51    void                (*quit_func) (void);
52    void                (*pause_func) (void);
53    char                enabled;
54    char                paused;
55 } FXHandler;
56
57 #if USE_COMPOSITE
58 /* As of composite 0.4 we need to set the clip region */
59 #define SET_GC_CLIP(eo, gc) ECompMgrWinClipToGC(eo, gc)
60 #else
61 #define SET_GC_CLIP(eo, gc)
62 #endif
63
64 /****************************** RIPPLES *************************************/
65
66 #define fx_ripple_waterh 64
67 static Pixmap       fx_ripple_above = None;
68 static Win          fx_ripple_win = NULL;
69 static int          fx_ripple_count = 0;
70 static Timer       *fx_ripple_timer = NULL;
71
72 static int
73 FX_ripple_timeout(void *data __UNUSED__)
74 {
75    static double       incv = 0, inch = 0;
76    static GC           gc1 = 0, gc = 0;
77    int                 y;
78    EObj               *bgeo;
79
80    bgeo = DeskGetBackgroundObj(DesksGetCurrent());
81
82    if (fx_ripple_above == None)
83      {
84         XGCValues           gcv;
85
86         fx_ripple_win = EobjGetWin(bgeo);
87
88         fx_ripple_above =
89            ECreatePixmap(fx_ripple_win, WinGetW(VROOT),
90                          fx_ripple_waterh * 2, 0);
91         if (gc)
92            EXFreeGC(gc);
93         if (gc1)
94            EXFreeGC(gc1);
95         gcv.subwindow_mode = IncludeInferiors;
96         gc = EXCreateGC(WinGetXwin(fx_ripple_win), GCSubwindowMode, &gcv);
97         gc1 = EXCreateGC(WinGetXwin(fx_ripple_win), 0L, &gcv);
98      }
99
100    if (fx_ripple_count == 0)
101       XCopyArea(disp, WinGetXwin(fx_ripple_win), fx_ripple_above, gc, 0,
102                 WinGetH(VROOT) - (fx_ripple_waterh * 3), WinGetW(VROOT),
103                 fx_ripple_waterh * 2, 0, 0);
104
105    fx_ripple_count++;
106    if (fx_ripple_count > 32)
107       fx_ripple_count = 0;
108
109    incv += 0.40;
110    if (incv > (M_PI_2 * 4))
111       incv = 0;
112    inch += 0.32;
113    if (inch > (M_PI_2 * 4))
114       inch = 0;
115
116    SET_GC_CLIP(bgeo, gc1);
117
118    for (y = 0; y < fx_ripple_waterh; y++)
119      {
120         double              aa, a, p;
121         int                 yoff, off, yy;
122
123         p = (((double)(fx_ripple_waterh - y)) / ((double)fx_ripple_waterh));
124         a = p * p * 48 + incv;
125         yoff = y + (int)(sin(a) * 7) + 1;
126         yy = (fx_ripple_waterh * 2) - yoff;
127         aa = p * p * 64 + inch;
128         off = (int)(sin(aa) * 10 * (1 - p));
129         XCopyArea(disp, fx_ripple_above, WinGetXwin(fx_ripple_win), gc1, 0, yy,
130                   WinGetW(VROOT), 1, off,
131                   WinGetH(VROOT) - fx_ripple_waterh + y);
132      }
133
134    return 1;
135 }
136
137 static void
138 FX_Ripple_Init(const char *name __UNUSED__)
139 {
140    fx_ripple_count = 0;
141    TIMER_ADD(fx_ripple_timer, 0.066, FX_ripple_timeout, NULL);
142 }
143
144 static void
145 FX_Ripple_Desk(void)
146 {
147    if (fx_ripple_above != None)
148       EFreePixmap(fx_ripple_above);
149    fx_ripple_count = 0;
150    fx_ripple_above = None;
151 }
152
153 static void
154 FX_Ripple_Quit(void)
155 {
156    TIMER_DEL(fx_ripple_timer);
157    EClearArea(fx_ripple_win, 0, WinGetH(VROOT) - fx_ripple_waterh,
158               WinGetW(VROOT), fx_ripple_waterh);
159 }
160
161 static void
162 FX_Ripple_Pause(void)
163 {
164    static char         paused = 0;
165
166    if (!paused)
167      {
168         FX_Ripple_Quit();
169         paused = 1;
170      }
171    else
172      {
173         FX_Ripple_Init(NULL);
174         paused = 0;
175      }
176 }
177
178 #if E_FX_RAINDROPS
179 #include "piximg.h"
180
181 /****************************** RAIN DROPS **********************************/
182
183 #define fx_raindrop_size 96
184 #define fx_raindrop_size2 (fx_raindrop_size / 2)
185 #define fx_raindrop_duration 32
186 #define fx_frequency 4
187 #define fx_amplitude 48
188 static Win          fx_raindrops_win = NULL;
189 static int          fx_raindrops_number = 4;
190 static PixImg      *fx_raindrops_draw = NULL;
191 static Timer       *fx_raindrops_timer = NULL;
192
193 typedef struct {
194    int                 x, y;
195    int                 count;
196    PixImg             *buf;
197 } DropContext;
198
199 static DropContext  fx_raindrops[4];
200
201 static int
202 FX_raindrops_timeout(void *data __UNUSED__)
203 {
204    static GC           gc1 = 0, gc = 0;
205    int                 i, x, y, xx, yy;
206    int                 percent_done;
207    static char         first = 1;
208    static char         sintab[256];
209    static unsigned char disttab[fx_raindrop_size][fx_raindrop_size];
210    EObj               *bgeo;
211
212    bgeo = DeskGetBackgroundObj(DesksGetCurrent());
213
214    if (fx_raindrops_win == None)
215      {
216         XGCValues           gcv;
217
218         if (first)
219           {
220              int                 j;
221
222              first = 0;
223              for (i = 0; i < 256; i++)
224                 sintab[i] =
225                    (char)(sin(((double)i) * M_PI_2 * 4 / 256) * fx_amplitude);
226              for (j = 0; j < fx_raindrop_size; j++)
227                {
228                   for (i = 0; i < fx_raindrop_size; i++)
229                     {
230                        xx = i - fx_raindrop_size2;
231                        yy = j - fx_raindrop_size2;
232                        disttab[i][j] =
233                           (unsigned char)sqrt((double)((xx * xx) + (yy * yy)));
234                     }
235                }
236           }
237
238         fx_raindrops_win = EobjGetWin(bgeo);
239
240         if (gc)
241            EXFreeGC(gc);
242         if (gc1)
243            EXFreeGC(gc1);
244
245         gcv.subwindow_mode = IncludeInferiors;
246         gc = EXCreateGC(WinGetXwin(fx_raindrops_win), GCSubwindowMode, &gcv);
247         gc1 = EXCreateGC(WinGetXwin(fx_raindrops_win), 0L, &gcv);
248
249         fx_raindrops_draw =
250            ECreatePixImg(WinGetXwin(fx_raindrops_win), fx_raindrop_size,
251                          fx_raindrop_size);
252         if (!fx_raindrops_draw)
253            return 0;
254
255         for (i = 0; i < fx_raindrops_number; i++)
256           {
257              fx_raindrops[i].buf =
258                 ECreatePixImg(WinGetXwin(fx_raindrops_win), fx_raindrop_size,
259                               fx_raindrop_size);
260              if (fx_raindrops[i].buf)
261                 XShmGetImage(disp, WinGetXwin(fx_raindrops_win),
262                              fx_raindrops[i].buf->xim, fx_raindrops[i].x,
263                              fx_raindrops[i].y, 0xffffffff);
264              if (!fx_raindrops[i].buf)
265                 return 0;
266           }
267      }
268
269    SET_GC_CLIP(bgeo, gc1);
270
271    for (i = 0; i < fx_raindrops_number; i++)
272      {
273         fx_raindrops[i].count++;
274         if (fx_raindrops[i].count == fx_raindrop_duration)
275           {
276              int                 j, count = 0;
277              char                intersect = 1;
278
279              EClearArea(fx_raindrops_win, fx_raindrops[i].x,
280                         fx_raindrops[i].y, fx_raindrop_size, fx_raindrop_size);
281              fx_raindrops[i].count = 0;
282              while (intersect)
283                {
284                   count++;
285                   if (count > 10240)
286                      break;
287                   intersect = 0;
288                   for (j = 0; j < fx_raindrops_number; j++)
289                     {
290                        fx_raindrops[i].x =
291                           rand() % (WinGetW(VROOT) - fx_raindrop_size);
292                        fx_raindrops[i].y =
293                           rand() % (WinGetH(VROOT) - fx_raindrop_size);
294                        if (fx_raindrops[i].x < 0)
295                           fx_raindrops[i].x = 0;
296                        else if (fx_raindrops[i].x >
297                                 (WinGetW(VROOT) - fx_raindrop_size))
298                           fx_raindrops[i].x = WinGetW(VROOT) - fx_raindrop_size;
299                        if (fx_raindrops[i].y < 0)
300                           fx_raindrops[i].y = 0;
301                        else if (fx_raindrops[i].y >
302                                 (WinGetH(VROOT) - fx_raindrop_size))
303                           fx_raindrops[i].y = WinGetH(VROOT) - fx_raindrop_size;
304                        if (i != j)
305                          {
306                             if (((fx_raindrops[i].x >= fx_raindrops[j].x)
307                                  && (fx_raindrops[i].x <
308                                      fx_raindrops[j].x + fx_raindrop_size)
309                                  && (fx_raindrops[i].y >= fx_raindrops[j].y)
310                                  && (fx_raindrops[i].y <
311                                      fx_raindrops[j].y + fx_raindrop_size))
312                                 ||
313                                 ((fx_raindrops
314                                   [i].x + fx_raindrop_size >= fx_raindrops[j].x)
315                                  && (fx_raindrops[i].x + fx_raindrop_size <
316                                      fx_raindrops[j].x + fx_raindrop_size)
317                                  && (fx_raindrops[i].y >= fx_raindrops[j].y)
318                                  && (fx_raindrops[i].y <
319                                      fx_raindrops[j].y + fx_raindrop_size))
320                                 || ((fx_raindrops[i].x >= fx_raindrops[j].x)
321                                     && (fx_raindrops[i].x <
322                                         fx_raindrops[j].x + fx_raindrop_size)
323                                     && (fx_raindrops[i].y + fx_raindrop_size >=
324                                         fx_raindrops[j].y)
325                                     && (fx_raindrops[i].y + fx_raindrop_size <
326                                         fx_raindrops[j].y + fx_raindrop_size))
327                                 ||
328                                 ((fx_raindrops
329                                   [i].x + fx_raindrop_size >= fx_raindrops[j].x)
330                                  && (fx_raindrops[i].x + fx_raindrop_size <
331                                      fx_raindrops[j].x + fx_raindrop_size)
332                                  && (fx_raindrops[i].y + fx_raindrop_size >=
333                                      fx_raindrops[j].y)
334                                  && (fx_raindrops[i].y + fx_raindrop_size <
335                                      fx_raindrops[j].y + fx_raindrop_size)))
336                                intersect = 1;
337                          }
338                     }
339                }
340              XShmGetImage(disp, WinGetXwin(fx_raindrops_win),
341                           fx_raindrops[i].buf->xim,
342                           fx_raindrops[i].x, fx_raindrops[i].y, 0xffffffff);
343           }
344         percent_done =
345            1 + ((fx_raindrops[i].count << 8) / fx_raindrop_duration);
346         for (y = 0; y < fx_raindrop_size; y++)
347           {
348              for (x = 0; x < fx_raindrop_size; x++)
349                {
350                   int                 dist;
351
352                   dist = disttab[x][y];
353                   if (dist > fx_raindrop_size2)
354                      XPutPixel(fx_raindrops_draw->xim, x, y,
355                                XGetPixel(fx_raindrops[i].buf->xim, x, y));
356                   else
357                     {
358                        int                 percent;
359
360                        percent = 1 + ((dist << 8) / fx_raindrop_size2);
361                        if (percent > percent_done)
362                           XPutPixel(fx_raindrops_draw->xim, x, y,
363                                     XGetPixel(fx_raindrops[i].buf->xim, x, y));
364                        else
365                          {
366                             int                 varx, vary;
367                             int                 phase, divisor, multiplier;
368
369                             phase =
370                                ((percent - percent_done) * fx_frequency) & 0xff;
371                             xx = x - fx_raindrop_size2;
372                             yy = y - fx_raindrop_size2;
373                             divisor = 1 + (dist << 8);
374                             multiplier =
375                                (int)sintab[phase] * (256 - percent_done);
376                             varx = ((-xx) * multiplier) / divisor;
377                             vary = ((-yy) * multiplier) / divisor;
378                             xx = x + varx;
379                             yy = y + vary;
380                             if (xx < 0)
381                                xx = 0;
382                             else if (xx >= fx_raindrop_size)
383                                xx = fx_raindrop_size - 1;
384                             if (yy < 0)
385                                yy = 0;
386                             else if (yy >= fx_raindrop_size)
387                                yy = fx_raindrop_size - 1;
388                             XPutPixel(fx_raindrops_draw->xim, x, y,
389                                       XGetPixel(fx_raindrops[i].buf->xim, xx,
390                                                 yy));
391                          }
392                     }
393                }
394           }
395         XShmPutImage(disp, WinGetXwin(fx_raindrops_win), gc1,
396                      fx_raindrops_draw->xim, 0, 0,
397                      fx_raindrops[i].x, fx_raindrops[i].y, fx_raindrop_size,
398                      fx_raindrop_size, False);
399         ESync(0);
400      }
401
402    return 1;
403 }
404
405 static void
406 FX_Raindrops_Init(const char *name __UNUSED__)
407 {
408    int                 i;
409
410    fx_raindrops_win = None;
411    for (i = 0; i < fx_raindrops_number; i++)
412      {
413         fx_raindrops[i].count = rand() % fx_raindrop_duration;
414         fx_raindrops[i].x = rand() % (WinGetW(VROOT) - fx_raindrop_size);
415         fx_raindrops[i].y = rand() % (WinGetH(VROOT) - fx_raindrop_size);
416      }
417    TIMER_ADD(fx_raindrops_timer, 0.066, FX_raindrops_timeout, NULL);
418 }
419
420 static void
421 FX_Raindrops_Desk(void)
422 {
423    fx_raindrops_win = None;
424 }
425
426 static void
427 FX_Raindrops_Quit(void)
428 {
429    int                 i;
430
431    TIMER_DEL(fx_raindrops_timer);
432    for (i = 0; i < fx_raindrops_number; i++)
433      {
434         EClearArea(fx_raindrops_win, fx_raindrops[i].x, fx_raindrops[i].y,
435                    fx_raindrop_size, fx_raindrop_size);
436         if (fx_raindrops[i].buf)
437            EDestroyPixImg(fx_raindrops[i].buf);
438         fx_raindrops[i].buf = NULL;
439      }
440    if (fx_raindrops_draw)
441       EDestroyPixImg(fx_raindrops_draw);
442    fx_raindrops_draw = NULL;
443    fx_raindrops_win = None;
444 }
445
446 static void
447 FX_Raindrops_Pause(void)
448 {
449    static char         paused = 0;
450
451    if (!paused)
452      {
453         FX_Raindrops_Quit();
454         paused = 1;
455      }
456    else
457      {
458         FX_Raindrops_Init(NULL);
459         paused = 0;
460      }
461 }
462
463 #endif /* E_FX_RAINDROPS */
464
465 /****************************** WAVES ***************************************/
466 /* by tsade :)                                                              */
467 /****************************************************************************/
468
469 #define FX_WAVE_WATERH 64
470 #define FX_WAVE_WATERW 64
471 #define FX_WAVE_DEPTH  10
472 #define FX_WAVE_GRABH  (FX_WAVE_WATERH + FX_WAVE_DEPTH)
473 #define FX_WAVE_CROSSPERIOD 0.42
474 static Pixmap       fx_wave_above = None;
475 static Win          fx_wave_win = NULL;
476 static int          fx_wave_count = 0;
477 static Timer       *fx_wave_timer = NULL;
478
479 static int
480 FX_Wave_timeout(void *data __UNUSED__)
481 {
482    /* Variables */
483    static double       incv = 0, inch = 0;
484    static double       incx = 0;
485    double              incx2;
486    static GC           gc1 = 0, gc = 0;
487    int                 y;
488    EObj               *bgeo;
489
490    bgeo = DeskGetBackgroundObj(DesksGetCurrent());
491
492    /* Check to see if we need to create stuff */
493    if (!fx_wave_above)
494      {
495         XGCValues           gcv;
496
497         fx_wave_win = EobjGetWin(bgeo);
498
499         fx_wave_above =
500            ECreatePixmap(fx_wave_win, WinGetW(VROOT), FX_WAVE_WATERH * 2, 0);
501         if (gc)
502            EXFreeGC(gc);
503         if (gc1)
504            EXFreeGC(gc1);
505         gcv.subwindow_mode = IncludeInferiors;
506         gc = EXCreateGC(WinGetXwin(fx_wave_win), GCSubwindowMode, &gcv);
507         gc1 = EXCreateGC(WinGetXwin(fx_wave_win), 0L, &gcv);
508      }
509
510    /* On the zero, grab the desktop again. */
511    if (fx_wave_count == 0)
512      {
513         XCopyArea(disp, WinGetXwin(fx_wave_win), fx_wave_above, gc, 0,
514                   WinGetH(VROOT) - (FX_WAVE_WATERH * 3), WinGetW(VROOT),
515                   FX_WAVE_WATERH * 2, 0, 0);
516      }
517
518    /* Increment and roll the counter */
519    fx_wave_count++;
520    if (fx_wave_count > 32)
521       fx_wave_count = 0;
522
523    /* Increment and roll some other variables */
524    incv += 0.40;
525    if (incv > (M_PI_2 * 4))
526       incv = 0;
527
528    inch += 0.32;
529    if (inch > (M_PI_2 * 4))
530       inch = 0;
531
532    incx += 0.32;
533    if (incx > (M_PI_2 * 4))
534       incx = 0;
535
536    SET_GC_CLIP(bgeo, gc1);
537
538    /* Copy the area to correct bugs */
539    if (fx_wave_count == 0)
540      {
541         XCopyArea(disp, fx_wave_above, WinGetXwin(fx_wave_win), gc1, 0,
542                   WinGetH(VROOT) - FX_WAVE_GRABH, WinGetW(VROOT),
543                   FX_WAVE_DEPTH * 2, 0, WinGetH(VROOT) - FX_WAVE_GRABH);
544      }
545
546    /* Go through the bottom couple (FX_WAVE_WATERH) lines of the window */
547    for (y = 0; y < FX_WAVE_WATERH; y++)
548      {
549         /* Variables */
550         double              aa, a, p;
551         int                 yoff, off, yy;
552         int                 x;
553
554         /* Figure out the side-to-side movement */
555         p = (((double)(FX_WAVE_WATERH - y)) / ((double)FX_WAVE_WATERH));
556         a = p * p * 48 + incv;
557         yoff = y + (int)(sin(a) * 7) + 1;
558         yy = (FX_WAVE_WATERH * 2) - yoff;
559         aa = p * p * FX_WAVE_WATERH + inch;
560         off = (int)(sin(aa) * 10 * (1 - p));
561
562         /* Set up the next part */
563         incx2 = incx;
564
565         /* Go through the width of the screen, in block sizes */
566         for (x = 0; x < WinGetW(VROOT); x += FX_WAVE_WATERW)
567           {
568              /* Variables */
569              int                 sx;
570
571              /* Add something to incx2 and roll it */
572              incx2 += FX_WAVE_CROSSPERIOD;
573
574              if (incx2 > (M_PI_2 * 4))
575                 incx2 = 0;
576
577              /* Figure it out */
578              sx = (int)(sin(incx2) * FX_WAVE_DEPTH);
579
580              /* Display this block */
581              XCopyArea(disp, fx_wave_above, WinGetXwin(fx_wave_win), gc1, x, yy,        /* x, y */
582                        FX_WAVE_WATERW, 1,       /* w, h */
583                        off + x, WinGetH(VROOT) - FX_WAVE_WATERH + y + sx        /* dx, dy */
584                 );
585           }
586      }
587
588    return 1;
589 }
590
591 static void
592 FX_Waves_Init(const char *name __UNUSED__)
593 {
594    fx_wave_count = 0;
595    TIMER_ADD(fx_wave_timer, 0.066, FX_Wave_timeout, NULL);
596 }
597
598 static void
599 FX_Waves_Desk(void)
600 {
601    EFreePixmap(fx_wave_above);
602    fx_wave_count = 0;
603    fx_wave_above = 0;
604 }
605
606 static void
607 FX_Waves_Quit(void)
608 {
609    TIMER_DEL(fx_wave_timer);
610    EClearArea(fx_wave_win, 0, WinGetH(VROOT) - FX_WAVE_WATERH,
611               WinGetW(VROOT), FX_WAVE_WATERH);
612 }
613
614 static void
615 FX_Waves_Pause(void)
616 {
617    static char         paused = 0;
618
619    if (!paused)
620      {
621         FX_Waves_Quit();
622         paused = 1;
623      }
624    else
625      {
626         FX_Waves_Init(NULL);
627         paused = 0;
628      }
629 }
630
631 #if E_FX_IMAGESPINNER
632
633 /****************************** IMAGESPINNER ********************************/
634
635 static Win          fx_imagespinner_win = NULL;
636 static int          fx_imagespinner_count = 3;
637 static char        *fx_imagespinner_params = NULL;
638 static Timer       *fx_imagespinner_timer = NULL;
639
640 static int
641 FX_imagespinner_timeout(void *data __UNUSED__)
642 {
643    char               *string = NULL;
644    EObj               *bgeo;
645
646    if (fx_imagespinner_win == None)
647      {
648         bgeo = DeskGetBackgroundObj(DesksGetCurrent());
649         fx_imagespinner_win = EobjGetWin(bgeo);
650      }
651
652 #if 0                           /* Don't use getword */
653 /* do stuff here */
654    string = getword(fx_imagespinner_params, fx_imagespinner_count);
655    if (!string)
656      {
657         fx_imagespinner_count = 3;
658         string = getword(fx_imagespinner_params, fx_imagespinner_count);
659      }
660 #endif
661
662    fx_imagespinner_count++;
663    if (string)
664      {
665         EImage             *im;
666
667         im = ThemeImageLoad(string);
668         if (im)
669           {
670              int                 x, y, w, h;
671
672              EImageGetSize(im, &w, &h);
673              sscanf(fx_imagespinner_params, "%*s %i %i ", &x, &y);
674              x = ((WinGetW(VROOT) * x) >> 10) - ((w * x) >> 10);
675              y = ((WinGetH(VROOT) * y) >> 10) - ((h * y) >> 10);
676              EImageRenderOnDrawable(im, fx_imagespinner_win, None, 0,
677                                     x, y, w, h);
678              EImageFree(im);
679           }
680         Efree(string);
681      }
682
683    return 1;
684 }
685
686 static void
687 FX_ImageSpinner_Init(const char *name)
688 {
689    fx_imagespinner_count = 3;
690    TIMER_ADD(fx_imagespinner_timer, 0.066, FX_imagespinner_timeout, NULL);
691    fx_imagespinner_params = Estrdup(name);
692 }
693
694 static void
695 FX_ImageSpinner_Desk(void)
696 {
697    EObj               *bgeo;
698
699    bgeo = DeskGetBackgroundObj(DesksGetCurrent());
700    fx_imagespinner_win = EobjGetWin(bgeo);
701 }
702
703 static void
704 FX_ImageSpinner_Quit(void)
705 {
706    TIMER_DEL(fx_imagespinner_timer);
707    EClearArea(fx_imagespinner_win, 0, 0, WinGetW(VROOT), WinGetH(VROOT));
708    Efree(fx_imagespinner_params);
709    fx_imagespinner_params = NULL;
710    fx_imagespinner_win = None;
711 }
712
713 static void
714 FX_ImageSpinner_Pause(void)
715 {
716    static char         paused = 0;
717
718    if (!paused)
719      {
720         FX_ImageSpinner_Quit();
721         paused = 1;
722      }
723    else
724      {
725         FX_ImageSpinner_Init(NULL);
726         paused = 0;
727      }
728 }
729
730 #endif /* E_FX_IMAGESPINNER */
731
732 /****************************************************************************/
733
734 static FXHandler    fx_handlers[] = {
735    {"ripples",
736     FX_Ripple_Init, FX_Ripple_Desk, FX_Ripple_Quit, FX_Ripple_Pause,
737     0, 0},
738    {"waves",
739     FX_Waves_Init, FX_Waves_Desk, FX_Waves_Quit, FX_Waves_Pause,
740     0, 0},
741 #if E_FX_RAINDROPS              /* FIXME */
742    {"raindrops",
743     FX_Raindrops_Init, FX_Raindrops_Desk, FX_Raindrops_Quit,
744     FX_Raindrops_Pause,
745     0, 0},
746 #endif
747 #if E_FX_IMAGESPINNER
748    {"imagespinner",
749     FX_ImageSpinner_Init, FX_ImageSpinner_Desk, FX_ImageSpinner_Quit,
750     FX_ImageSpinner_Pause,
751     0, 0},
752 #endif
753 };
754 #define N_FX_HANDLERS (sizeof(fx_handlers)/sizeof(FXHandler))
755
756 /****************************** Effect handlers *****************************/
757
758 static FXHandler   *
759 FX_Find(const char *name)
760 {
761    unsigned int        i;
762
763    for (i = 0; i < N_FX_HANDLERS; i++)
764       if (!strcmp(fx_handlers[i].name, name))
765          return &fx_handlers[i];
766
767    return NULL;
768 }
769
770 static void
771 FX_Op(const char *name, int fx_op)
772 {
773    FXHandler          *fxh;
774
775    fxh = FX_Find(name);
776    if (fxh == NULL)
777       return;
778
779    switch (fx_op)
780      {
781      case FX_OP_START:
782         if (fxh->enabled)
783            break;
784       do_start:
785         if (fxh->init_func)
786            fxh->init_func(name);
787         fxh->enabled = 1;
788         break;
789
790      case FX_OP_STOP:
791         if (!fxh->enabled)
792            break;
793       do_stop:
794         if (fxh->quit_func)
795            fxh->quit_func();
796         fxh->enabled = 0;
797         break;
798
799      case FX_OP_TOGGLE:
800         if (fxh->enabled)
801            goto do_stop;
802         else
803            goto do_start;
804      }
805 }
806
807 static void
808 FX_DeskChange(void)
809 {
810    unsigned int        i;
811
812    for (i = 0; i < N_FX_HANDLERS; i++)
813      {
814         if (fx_handlers[i].enabled)
815           {
816              if (fx_handlers[i].desk_func)
817                 fx_handlers[i].desk_func();
818           }
819      }
820 }
821
822 static void
823 FX_Pause(void)
824 {
825    unsigned int        i;
826
827    for (i = 0; i < N_FX_HANDLERS; i++)
828      {
829         if (fx_handlers[i].enabled)
830           {
831              if (fx_handlers[i].paused)
832                {
833                   if (fx_handlers[i].pause_func)
834                      fx_handlers[i].pause_func();
835                   fx_handlers[i].paused = 1;
836                }
837              else
838                {
839                   if (fx_handlers[i].pause_func)
840                      fx_handlers[i].pause_func();
841                   fx_handlers[i].paused = 0;
842                }
843           }
844      }
845 }
846
847 static void
848 FX_StartAll(void)
849 {
850    unsigned int        i;
851    FXHandler          *fxh;
852
853    for (i = 0; i < N_FX_HANDLERS; i++)
854      {
855         fxh = &fx_handlers[i];
856         if (fxh->enabled && fxh->init_func)
857            fxh->init_func(fxh->name);
858      }
859 }
860
861 static int
862 FX_IsOn(const char *effect)
863 {
864    unsigned int        i;
865
866    for (i = 0; i < N_FX_HANDLERS; i++)
867      {
868         if (!strcmp(fx_handlers[i].name, effect))
869           {
870              return fx_handlers[i].enabled;
871           }
872      }
873    return 0;
874 }
875
876 /****************************************************************************/
877
878 /*
879  * Fx Module
880  */
881
882 static void
883 FxSighan(int sig, void *prm __UNUSED__)
884 {
885    switch (sig)
886      {
887      case ESIGNAL_START:
888         FX_StartAll();
889         break;
890      case ESIGNAL_AREA_SWITCH_START:
891      case ESIGNAL_DESK_SWITCH_START:
892         break;
893      case ESIGNAL_AREA_SWITCH_DONE:
894      case ESIGNAL_DESK_SWITCH_DONE:
895         FX_DeskChange();
896         break;
897      case ESIGNAL_ANIMATION_SUSPEND:
898      case ESIGNAL_ANIMATION_RESUME:
899         FX_Pause();
900         break;
901      }
902 }
903
904 #if ENABLE_DIALOGS
905 static char         tmp_effect_raindrops;
906 static char         tmp_effect_ripples;
907 static char         tmp_effect_waves;
908
909 static void
910 CB_ConfigureFX(Dialog * d __UNUSED__, int val, void *data __UNUSED__)
911 {
912    if (val < 2)
913      {
914         FX_Op("raindrops", tmp_effect_raindrops ? FX_OP_START : FX_OP_STOP);
915         FX_Op("ripples", tmp_effect_ripples ? FX_OP_START : FX_OP_STOP);
916         FX_Op("waves", tmp_effect_waves ? FX_OP_START : FX_OP_STOP);
917      }
918    autosave();
919 }
920
921 static void
922 _DlgFillFx(Dialog * d __UNUSED__, DItem * table, void *data __UNUSED__)
923 {
924    DItem              *di;
925
926    tmp_effect_raindrops = FX_IsOn("raindrops");
927    tmp_effect_ripples = FX_IsOn("ripples");
928    tmp_effect_waves = FX_IsOn("waves");
929
930    DialogItemTableSetOptions(table, 1, 0, 0, 0);
931
932    /* Effects */
933    di = DialogAddItem(table, DITEM_TEXT);
934    DialogItemSetText(di, _("Effects"));
935 #if 0                           /* Disabled */
936    di = DialogAddItem(table, DITEM_CHECKBUTTON);
937    DialogItemSetText(di, _("Enable Effect: Raindrops"));
938    DialogItemCheckButtonSetPtr(di, &tmp_effect_raindrops);
939 #endif
940    di = DialogAddItem(table, DITEM_CHECKBUTTON);
941    DialogItemSetText(di, _("Ripples"));
942    DialogItemCheckButtonSetPtr(di, &tmp_effect_ripples);
943
944    di = DialogAddItem(table, DITEM_CHECKBUTTON);
945    DialogItemSetText(di, _("Waves"));
946    DialogItemCheckButtonSetPtr(di, &tmp_effect_waves);
947 }
948
949 const DialogDef     DlgFx = {
950    "CONFIGURE_FX",
951    N_("FX"),
952    N_("Special FX Settings"),
953    SOUND_SETTINGS_FX,
954    "pix/fx.png",
955    N_("Enlightenment Special Effects\n" "Settings Dialog\n"),
956    _DlgFillFx,
957    DLG_OAC, CB_ConfigureFX,
958 };
959 #endif /* ENABLE_DIALOGS */
960
961 static void
962 FxIpc(const char *params)
963 {
964    char                word1[1024];
965    char                word2[1024];
966
967    if (!params)
968       return;
969
970    word1[0] = word2[0] = '\0';
971    sscanf(params, "%1000s %1000s", word1, word2);
972
973    if (!strcmp(word1, "raindrops") || !strcmp(word1, "ripples") ||
974        !strcmp(word1, "waves"))
975      {
976         if (!strcmp(word2, ""))
977            FX_Op(word1, FX_OP_TOGGLE);
978         else if (!strcmp(word2, "on"))
979            FX_Op(word1, FX_OP_START);
980         else if (!strcmp(word2, "off"))
981            FX_Op(word1, FX_OP_STOP);
982         else if (!strcmp(word2, "?"))
983            IpcPrintf("%s: %s", word1, FX_IsOn(word1) ? "on" : "off");
984         else
985            IpcPrintf("Error: unknown mode specified");
986      }
987 }
988
989 static const IpcItem FxIpcArray[] = {
990    {
991     FxIpc,
992     "fx", "fx",
993     "Toggle various effects on/off",
994     "  fx <effect> <mode>   Set the mode of a particular effect\n"
995     "  fx <effect> ?\"      Get the current mode\n"
996     "the following effects are available\n"
997     " ripples <on/off> (ripples that act as a water effect on the screen)\n"
998     " waves <on/off> (waves that act as a water effect on the screen)\n"}
999    ,
1000 };
1001 #define N_IPC_FUNCS (sizeof(FxIpcArray)/sizeof(IpcItem))
1002
1003 static const CfgItem FxCfgItems[] = {
1004    CFR_ITEM_BOOL(fx_handlers[0].enabled, ripples.enabled, 0),
1005    CFR_ITEM_BOOL(fx_handlers[1].enabled, waves.enabled, 0),
1006 #if E_FX_RAINDROPS              /* FIXME */
1007    CFR_ITEM_BOOL(fx_handlers[2].enabled, raindrops.enabled, 0),
1008 #endif
1009 };
1010 #define N_CFG_ITEMS (sizeof(FxCfgItems)/sizeof(CfgItem))
1011
1012 /*
1013  * Module descriptor
1014  */
1015 extern const EModule ModEffects;
1016 const EModule       ModEffects = {
1017    "effects", "efx",
1018    FxSighan,
1019    {N_IPC_FUNCS, FxIpcArray},
1020    {N_CFG_ITEMS, FxCfgItems}
1021 };