3 * FvwmAnimate! Animation module for fvwm
5 * Copyright (c) 1997 Frank Scheelen <scheelen@worldonline.nl>
6 * Copyright (c) 1996 Alfredo Kengi Kojima (kojima@inf.ufrgs.br)
7 * Copyright (c) 1996 Kaj Groner <kajg@mindspring.com>
8 * Added .steprc parsing and twisty iconify.
10 * Copyright (c) 1998 Dan Espen <dane@mk.bellcore.com>
11 * Changed to run under fvwm. Lots of changes made.
12 * This used to only animate iconify on M_CONFIGURE_WINDOW.
13 * This module no longer reads M_CONFIGURE_WINDOW.
14 * I added args to M_ICONIFY so iconification takes one message.
15 * The arg parsing is completely redone using library functions.
16 * I also added args to M_DEICONIFY to eliminate the need to read the
18 * Added AnimateResizeLines animation effect.
19 * Changed option "resize" to "effect", (resize still works).
20 * Changed effect "zoom" to "frame", (zoom still works).
21 * Added myfprintf double parens debugging trick.
22 * Changed so that commands can be sent to this module while it is
24 * Changed so that this module creates its own built in menu.
25 * Added Stop, Save commands.
26 * Changed so this this module uses FvwmForm for complete control on all
28 * Anything can request an animation thru "sendtomodule".
30 * This program is free software; you can redistribute it and/or modify
31 * it under the terms of the GNU General Public License as published by
32 * the Free Software Foundation; either version 2 of the License, or
33 * (at your option) any later version.
35 * This program is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 * GNU General Public License for more details.
40 * You should have received a copy of the GNU General Public License
41 * along with this program; if not, write to the Free Software
42 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
52 #include <fcntl.h> /* for O_WRONLY */
53 #include <sys/times.h>
54 #include "libs/ftime.h"
56 #include "libs/fvwmsignal.h"
57 #include "libs/Module.h"
58 #include "libs/fvwmlib.h"
59 #include "libs/Picture.h"
60 #include "libs/PictureGraphics.h"
61 #include "libs/PictureUtils.h"
62 #include "libs/FRenderInit.h"
63 #include "libs/Grab.h"
64 #include "libs/Graphics.h"
65 #include "libs/Parse.h"
66 #include "libs/Strings.h"
67 #include "FvwmAnimate.h"
69 #define AS_PI 3.14159265358979323846
73 static ModuleArgs
* module
;
74 static int Channel
[2];
76 static unsigned long color
; /* color for animation */
77 static Pixmap pixmap
= None
; /* pixmap for weirdness */
79 static int animate_none
= 0; /* count bypassed animations */
80 static Bool stop_recvd
= False
; /* got stop command */
81 static Bool running
= False
; /* whether we are initiialized or not */
82 static Bool custom_recvd
= False
; /* got custom command */
84 #define MAX_SAVED_STATES 25
85 static Bool play_state
= True
; /* current state: pause or play */
86 static unsigned int num_saved_play_states
= 0;
87 static Bool saved_play_states
[MAX_SAVED_STATES
];
100 /* here is the old double parens trick. */
103 #define myfprintf(X) \
112 /* #define DEBUG_ANIMATION */
113 #ifdef DEBUG_ANIMATION
114 #define myaprintf(X) \
121 /* Macros for creating and sending commands:
123 CMD10 - module->name, CatString3("*",module->name,0)
124 CMD11 - module->name,module->name */
125 #define CMD1X(TEXT) \
126 sprintf(cmd,TEXT,module->name);\
127 SendText(Channel,cmd,0);
128 #define CMD10(TEXT) \
129 sprintf(cmd,TEXT,module->name,CatString3("*",module->name,0));\
130 SendText(Channel,cmd,0);
131 #define CMD11(TEXT) \
132 sprintf(cmd,TEXT,module->name,module->name);\
133 SendText(Channel,cmd,0);
135 static void Loop(void);
136 static void ParseOptions(void);
137 static void ParseConfigLine(char *);
138 static void CreateDrawGC(void);
139 static void DefineMe(void);
140 static void SaveConfig(void);
141 static void StopCmd(void);
142 static void AnimateResizeZoom(int, int, int, int, int, int, int, int);
143 static void AnimateResizeLines(int, int, int, int, int, int, int, int);
144 static void AnimateResizeFlip(int, int, int, int, int, int, int, int);
145 static void AnimateResizeTurn(int, int, int, int, int, int, int, int);
146 static void AnimateResizeRandom(int, int, int, int, int, int, int, int);
147 static void AnimateResizeZoom3D(int, int, int, int, int, int, int, int);
148 static void AnimateResizeNone(int, int, int, int, int, int, int, int);
149 static void AnimateResizeTwist(int, int, int, int, int, int, int, int);
150 static void DefineForm(void);
152 static RETSIGTYPE
HandleTerminate(int sig
);
154 struct ASAnimate Animate
= { NULL
, NULL
, ANIM_ITERATIONS
, ANIM_DELAY
,
155 ANIM_TWIST
, ANIM_WIDTH
,
156 AnimateResizeTwist
, ANIM_TIME
};
158 /* We now have so many effects, that I feel the need for a table. */
159 typedef struct AnimateEffects
{
162 void (*function
)(int, int, int, int, int, int, int, int);
163 char *button
; /* used to set custom form */
165 /* Note None and Random must be the first 2 entries. */
166 struct AnimateEffects effects
[] = {
167 {"None", 0, AnimateResizeNone
, NULL
},
168 {"Random", 0, AnimateResizeRandom
, NULL
},
169 {"Flip", 0, AnimateResizeFlip
, NULL
},
170 {"Frame", "Zoom", AnimateResizeZoom
, NULL
},
171 {"Frame3D", "Zoom3D", AnimateResizeZoom3D
, NULL
},
172 {"Lines", 0, AnimateResizeLines
, NULL
},
173 {"Turn", 0, AnimateResizeTurn
, NULL
},
174 {"Twist", 0, AnimateResizeTwist
, NULL
}
176 #define NUM_EFFECTS sizeof(effects) / sizeof(struct AnimateEffects)
178 static Bool
is_animation_visible(
179 int x
, int y
, int w
, int h
, int fx
, int fy
, int fw
, int fh
)
181 Bool is_start_visible
= True
;
182 Bool is_end_visible
= True
;
184 if (x
>= Scr
.MyDisplayWidth
|| x
+ w
< 0 ||
185 y
>= Scr
.MyDisplayWidth
|| y
+ h
< 0)
187 is_start_visible
= False
;
189 if (fx
>= Scr
.MyDisplayWidth
|| fx
+ fw
< 0 ||
190 fy
>= Scr
.MyDisplayWidth
|| fy
+ fh
< 0)
192 is_end_visible
= False
;
194 return (is_start_visible
|| is_end_visible
);
198 * This makes a twisty iconify/deiconify animation for a window, similar to
199 * MacOS. Parameters specify the position and the size of the initial
200 * window and the final window
202 static void AnimateResizeTwist(
203 int x
, int y
, int w
, int h
, int fx
, int fy
, int fw
, int fh
)
205 float cx
, cy
, cw
, ch
;
206 float xstep
, ystep
, wstep
, hstep
;
208 float angle
, angle_finite
, a
, d
;
210 if (!is_animation_visible(x
, y
, w
, h
, fx
, fy
, fw
, fh
))
217 xstep
= (float)(fx
-x
)/Animate
.iterations
;
218 ystep
= (float)(fy
-y
)/Animate
.iterations
;
219 wstep
= (float)(fw
-w
)/Animate
.iterations
;
220 hstep
= (float)(fh
-h
)/Animate
.iterations
;
227 d
= sqrt((cw
/2)*(cw
/2)+(ch
/2)*(ch
/2));
229 angle_finite
= 2*AS_PI
*Animate
.twist
;
231 XInstallColormap(dpy
, Pcmap
);
232 for (angle
=0;; angle
+=(float)(2*AS_PI
*Animate
.twist
/Animate
.iterations
)) {
233 if (angle
> angle_finite
)
234 angle
= angle_finite
;
235 points
[0].x
= cx
+cos(angle
-a
)*d
;
236 points
[0].y
= cy
+sin(angle
-a
)*d
;
237 points
[1].x
= cx
+cos(angle
+a
)*d
;
238 points
[1].y
= cy
+sin(angle
+a
)*d
;
239 points
[2].x
= cx
+cos(angle
-a
+AS_PI
)*d
;
240 points
[2].y
= cy
+sin(angle
-a
+AS_PI
)*d
;
241 points
[3].x
= cx
+cos(angle
+a
+AS_PI
)*d
;
242 points
[3].y
= cy
+sin(angle
+a
+AS_PI
)*d
;
243 points
[4].x
= cx
+cos(angle
-a
)*d
;
244 points
[4].y
= cy
+sin(angle
-a
)*d
;
245 XDrawLines(dpy
, Scr
.root
, gc
, points
, 5, CoordModeOrigin
);
247 usleep(Animate
.delay
*1000);
248 XDrawLines(dpy
, Scr
.root
, gc
, points
, 5, CoordModeOrigin
);
254 d
= sqrt((cw
/2)*(cw
/2)+(ch
/2)*(ch
/2));
255 if (angle
>= angle_finite
)
258 MyXUngrabServer(dpy
);
262 * Add even more 3D feel to AfterStep by doing a flipping iconify.
263 * Parameters specify the position and the size of the initial and the
266 * Idea: how about texture mapped, user definable free 3D movement
267 * during a resize? That should get X on its knees all right! :)
269 void AnimateResizeFlip(
270 int x
, int y
, int w
, int h
, int fx
, int fy
, int fw
, int fh
)
272 float cx
, cy
, cw
, ch
;
273 float xstep
, ystep
, wstep
, hstep
;
280 float angle
, angle_finite
;
282 if (!is_animation_visible(x
, y
, w
, h
, fx
, fy
, fw
, fh
))
285 xstep
= (float) (fx
- x
) / Animate
.iterations
;
286 ystep
= (float) (fy
- y
) / Animate
.iterations
;
287 wstep
= (float) (fw
- w
) / Animate
.iterations
;
288 hstep
= (float) (fh
- h
) / Animate
.iterations
;
295 angle_finite
= 2 * AS_PI
* Animate
.twist
;
297 XInstallColormap(dpy
, Pcmap
);
299 angle
+= (float) (2 * AS_PI
* Animate
.twist
/ Animate
.iterations
)) {
300 if (angle
> angle_finite
)
301 angle
= angle_finite
;
303 distortx
= (cw
/ 10) - ((cw
/ 5) * sin(angle
));
304 distortch
= (ch
/ 2) * cos(angle
);
305 midy
= cy
+ (ch
/ 2);
307 points
[0].x
= cx
+ distortx
;
308 points
[0].y
= midy
- distortch
;
309 points
[1].x
= cx
+ cw
- distortx
;
310 points
[1].y
= points
[0].y
;
311 points
[2].x
= cx
+ cw
+ distortx
;
312 points
[2].y
= midy
+ distortch
;
313 points
[3].x
= cx
- distortx
;
314 points
[3].y
= points
[2].y
;
315 points
[4].x
= points
[0].x
;
316 points
[4].y
= points
[0].y
;
318 XDrawLines(dpy
, Scr
.root
, gc
, points
, 5, CoordModeOrigin
);
320 usleep(Animate
.delay
* 1000);
321 XDrawLines(dpy
, Scr
.root
, gc
, points
, 5, CoordModeOrigin
);
326 if (angle
>= angle_finite
)
329 MyXUngrabServer(dpy
);
334 * And another one, this time around the Y-axis.
336 void AnimateResizeTurn(
337 int x
, int y
, int w
, int h
, int fx
, int fy
, int fw
, int fh
)
339 float cx
, cy
, cw
, ch
;
340 float xstep
, ystep
, wstep
, hstep
;
347 float angle
, angle_finite
;
349 if (!is_animation_visible(x
, y
, w
, h
, fx
, fy
, fw
, fh
))
352 xstep
= (float) (fx
- x
) / Animate
.iterations
;
353 ystep
= (float) (fy
- y
) / Animate
.iterations
;
354 wstep
= (float) (fw
- w
) / Animate
.iterations
;
355 hstep
= (float) (fh
- h
) / Animate
.iterations
;
362 angle_finite
= 2 * AS_PI
* Animate
.twist
;
364 XInstallColormap(dpy
, Pcmap
);
366 angle
+= (float) (2 * AS_PI
* Animate
.twist
/ Animate
.iterations
)) {
367 if (angle
> angle_finite
)
368 angle
= angle_finite
;
370 distorty
= (ch
/ 10) - ((ch
/ 5) * sin(angle
));
371 distortcw
= (cw
/ 2) * cos(angle
);
372 midx
= cx
+ (cw
/ 2);
374 points
[0].x
= midx
- distortcw
;
375 points
[0].y
= cy
+ distorty
;
376 points
[1].x
= midx
+ distortcw
;
377 points
[1].y
= cy
- distorty
;
378 points
[2].x
= points
[1].x
;
379 points
[2].y
= cy
+ ch
+ distorty
;
380 points
[3].x
= points
[0].x
;
381 points
[3].y
= cy
+ ch
- distorty
;
382 points
[4].x
= points
[0].x
;
383 points
[4].y
= points
[0].y
;
385 XDrawLines(dpy
, Scr
.root
, gc
, points
, 5, CoordModeOrigin
);
387 usleep(Animate
.delay
* 1000);
388 XDrawLines(dpy
, Scr
.root
, gc
, points
, 5, CoordModeOrigin
);
393 if (angle
>= angle_finite
)
396 MyXUngrabServer(dpy
);
400 * This makes a zooming iconify/deiconify animation for a window, like most
401 * any other icon animation out there. Parameters specify the position and
402 * the size of the initial window and the final window
404 static void AnimateResizeZoom(int x
, int y
, int w
, int h
,
405 int fx
, int fy
, int fw
, int fh
)
407 float cx
, cy
, cw
, ch
;
408 float xstep
, ystep
, wstep
, hstep
;
411 if (!is_animation_visible(x
, y
, w
, h
, fx
, fy
, fw
, fh
))
414 xstep
= (float)(fx
-x
)/Animate
.iterations
;
415 ystep
= (float)(fy
-y
)/Animate
.iterations
;
416 wstep
= (float)(fw
-w
)/Animate
.iterations
;
417 hstep
= (float)(fh
-h
)/Animate
.iterations
;
424 XInstallColormap(dpy
, Pcmap
);
425 for (i
=0; i
<Animate
.iterations
; i
++) {
426 XDrawRectangle(dpy
, Scr
.root
, gc
, (int)cx
, (int)cy
, (int)cw
, (int)ch
);
428 usleep(Animate
.delay
*1000);
429 XDrawRectangle(dpy
, Scr
.root
, gc
, (int)cx
, (int)cy
, (int)cw
, (int)ch
);
435 MyXUngrabServer(dpy
);
439 * The effect of this is similar to AnimateResizeZoom but this time we
440 * add lines to create a 3D effect. The gotcha is that we have to do
441 * something different depending on the direction we are zooming in.
443 * Andy Parker <parker_andy@hotmail.com>
445 void AnimateResizeZoom3D(
446 int x
, int y
, int w
, int h
, int fx
, int fy
, int fw
, int fh
)
448 float cx
, cy
, cw
, ch
;
449 float xstep
, ystep
, wstep
, hstep
, srca
, dsta
;
452 if (!is_animation_visible(x
, y
, w
, h
, fx
, fy
, fw
, fh
))
455 xstep
= (float) (fx
- x
) / Animate
.iterations
;
456 ystep
= (float) (fy
- y
) / Animate
.iterations
;
457 wstep
= (float) (fw
- w
) / Animate
.iterations
;
458 hstep
= (float) (fh
- h
) / Animate
.iterations
;
459 dsta
= (float) (fw
+ fh
);
460 srca
= (float) (w
+ h
);
468 XInstallColormap(dpy
, Pcmap
);
471 /* We are going from a Window to an Icon */
473 for (i
= 0; i
< Animate
.iterations
; i
++) {
474 XDrawRectangle(dpy
, Scr
.root
, gc
, (int) cx
, (int) cy
, (int) cw
,
476 XDrawRectangle(dpy
, Scr
.root
, gc
, (int) fx
, (int) fy
, (int) fw
,
478 XDrawLine(dpy
, Scr
.root
, gc
, (int) cx
, (int) cy
, fx
, fy
);
479 XDrawLine(dpy
, Scr
.root
, gc
, ((int) cx
+ (int) cw
), (int) cy
,
481 XDrawLine(dpy
, Scr
.root
, gc
, ((int) cx
+ (int) cw
),
482 ((int) cy
+ (int) ch
), (fx
+ fw
), (fy
+ fh
));
483 XDrawLine(dpy
, Scr
.root
, gc
, (int) cx
, ((int) cy
+ (int) ch
), fx
,
486 usleep(Animate
.delay
* 1000);
487 XDrawRectangle(dpy
, Scr
.root
, gc
, (int) cx
, (int) cy
, (int) cw
,
489 XDrawRectangle(dpy
, Scr
.root
, gc
, (int) fx
, (int) fy
, (int) fw
,
491 XDrawLine(dpy
, Scr
.root
, gc
, (int) cx
, (int) cy
, fx
, fy
);
492 XDrawLine(dpy
, Scr
.root
, gc
, ((int) cx
+ (int) cw
), (int) cy
,
494 XDrawLine(dpy
, Scr
.root
, gc
, ((int) cx
+ (int) cw
),
495 ((int) cy
+ (int) ch
), (fx
+ fw
), (fy
+ fh
));
496 XDrawLine(dpy
, Scr
.root
, gc
, (int) cx
, ((int) cy
+ (int) ch
), fx
,
505 /* We are going from an Icon to a Window */
506 for (i
= 0; i
< Animate
.iterations
; i
++) {
507 XDrawRectangle(dpy
, Scr
.root
, gc
, (int) cx
, (int) cy
, (int) cw
,
509 XDrawRectangle(dpy
, Scr
.root
, gc
, x
, y
, w
, h
);
510 XDrawLine(dpy
, Scr
.root
, gc
, (int) cx
, (int) cy
, x
, y
);
511 XDrawLine(dpy
, Scr
.root
, gc
, ((int) cx
+ (int) cw
), (int) cy
,
513 XDrawLine(dpy
, Scr
.root
, gc
, ((int) cx
+ (int) cw
), ((int) cy
+
514 (int) ch
), (x
+ w
), (y
+ h
));
515 XDrawLine(dpy
, Scr
.root
, gc
, (int) cx
, ((int) cy
+ (int) ch
), x
,
518 usleep(Animate
.delay
* 1000);
519 XDrawRectangle(dpy
, Scr
.root
, gc
, (int) cx
, (int) cy
, (int) cw
,
521 XDrawRectangle(dpy
, Scr
.root
, gc
, x
, y
, w
, h
);
522 XDrawLine(dpy
, Scr
.root
, gc
, (int) cx
, (int) cy
, x
, y
);
523 XDrawLine(dpy
, Scr
.root
, gc
, ((int) cx
+ (int) cw
), (int) cy
,
525 XDrawLine(dpy
, Scr
.root
, gc
, ((int) cx
+ (int) cw
),
526 ((int) cy
+ (int) ch
), (x
+ w
), (y
+ h
));
527 XDrawLine(dpy
, Scr
.root
, gc
, (int) cx
, ((int) cy
+ (int) ch
), x
,
535 MyXUngrabServer(dpy
);
539 * This picks one of the animations and calls it.
541 void AnimateResizeRandom(
542 int x
, int y
, int w
, int h
, int fx
, int fy
, int fw
, int fh
)
544 if (!is_animation_visible(x
, y
, w
, h
, fx
, fy
, fw
, fh
))
547 /* Note, first 2 effects "None" and "Random" should never be chosen */
548 effects
[(rand() + (x
* y
+ w
* h
+ fx
)) % (NUM_EFFECTS
- 2) + 2].function
549 (x
, y
, w
, h
, fx
, fy
, fw
, fh
);
553 * This animation creates 4 lines from each corner of the initial window,
554 * to each corner of the final window.
556 * Parameters specify the position and the size of the initial window and
559 * Starting with x/y w/h, need to draw sets of 4 line segs from initial
562 * The variable "ants" controls whether each iteration is drawn and then
563 * erased vs. draw all the segments and then come back and erase them.
565 * Currently I have this hardcoded as the later. The word "ants" is
566 * used, because if "ants" is set to 0 and the number of iterations is
567 * high, it looks a little like ants crawling across the screen.
569 static void AnimateResizeLines(int x
, int y
, int w
, int h
,
570 int fx
, int fy
, int fw
, int fh
) {
572 int ants
= 1, ant_ctr
;
574 XSegment seg
[4]; /* draw 4 unconnected lines */
575 XSegment incr
[4]; /* x/y increments */
579 if (!is_animation_visible(x
, y
, w
, h
, fx
, fy
, fw
, fh
))
582 /* define the array occurances */
590 if (ants
== 1) { /* if draw then erase */
591 MyXGrabServer(dpy
); /* grab for whole animation */
592 XInstallColormap(dpy
, Pcmap
);
594 for (ant_ctr
=0;ant_ctr
<=ants
;ant_ctr
++) {
595 /* Put args into arrays: */
596 BEG
.UR
.x1
= x
; /* upper left */
598 /* Temporarily put width and height in Lower Left slot.
599 Changed to Lower Left x/y later. */
603 /* Use final positions to calc increments. */
609 /* The lines look a little better if they start and end a little in
610 from the edges. Allowing tuning might be overkill. */
611 for (i
=0;i
<2;i
++) { /* for begin and endpoints */
612 if (ends
[i
].LL
.x1
> 40) { /* if width > 40 */
613 ends
[i
].LL
.x1
-=16; /* reduce width a little */
614 ends
[i
].UR
.x1
+= 8; /* move in a little */
616 if (ends
[i
].LL
.y1
> 40) { /* if height > 40 */
617 ends
[i
].LL
.y1
-=16; /* reduce height a little */
618 ends
[i
].UR
.y1
+= 8; /* move down a little */
620 /* Upper Left, Use x from Upper Right + width */
621 ends
[i
].UL
.x1
= ends
[i
].UR
.x1
+ ends
[i
].LL
.x1
;
622 ends
[i
].UL
.y1
= ends
[i
].UR
.y1
; /* copy y */
623 /* Lower Right, Use y from Upper Right + height */
624 ends
[i
].LR
.x1
= ends
[i
].UR
.x1
; /* copy x */
625 ends
[i
].LR
.y1
= ends
[i
].UR
.y1
+ ends
[i
].LL
.y1
;
626 /* Now width and height have been used, change LL to endpoints. */
627 ends
[i
].LL
.x1
+= ends
[i
].UR
.x1
;
628 ends
[i
].LL
.y1
+= ends
[i
].UR
.y1
;
630 /* Now put the increment in the end x/y slots */
631 for (i
=0;i
<4;i
++) { /* for each of 4 line segs */
632 INC
.seg
[i
].x2
= (INC
.seg
[i
].x1
- BEG
.seg
[i
].x1
)/Animate
.iterations
;
633 INC
.seg
[i
].y2
= (INC
.seg
[i
].y1
- BEG
.seg
[i
].y1
)/Animate
.iterations
;
635 for (i
=0; i
<Animate
.iterations
; i
++) {
636 for (j
=0;j
<4;j
++) { /* all 4 line segs */
637 BEG
.seg
[j
].x2
= BEG
.seg
[j
].x1
+ INC
.seg
[j
].x2
; /* calc end points */
638 BEG
.seg
[j
].y2
= BEG
.seg
[j
].y1
+ INC
.seg
[j
].y2
; /* calc end points */
641 "Lines %dx%d-%dx%d, %dx%d-%dx%d, %dx%d-%dx%d, %dx%d-%dx%d,"
643 BEG
.UR
.x1
, BEG
.UR
.y1
, BEG
.UR
.x2
, BEG
.UR
.y2
,
644 BEG
.UL
.x1
, BEG
.UL
.y1
, BEG
.UL
.x2
, BEG
.UL
.y2
,
645 BEG
.LR
.x1
, BEG
.LR
.y1
, BEG
.LR
.x2
, BEG
.LR
.y2
,
646 BEG
.LL
.x1
, BEG
.LL
.y1
, BEG
.LL
.x2
, BEG
.LL
.y2
, ant_ctr
));
649 XInstallColormap(dpy
, Pcmap
);
651 XDrawSegments(dpy
, Scr
.root
, gc
, BEG
.seg
, 4);
653 if (ant_ctr
== 0) { /* only pause on draw cycle */
654 usleep(Animate
.delay
*1000);
657 XDrawSegments(dpy
, Scr
.root
, gc
, BEG
.seg
, 4);
658 MyXUngrabServer(dpy
);
660 for (j
=0;j
<4;j
++) { /* all 4 lines segs */
661 BEG
.seg
[j
].x1
+= INC
.seg
[j
].x2
; /* calc new starting point */
662 BEG
.seg
[j
].y1
+= INC
.seg
[j
].y2
; /* calc new starting point */
663 } /* end 4 lines segs */
664 } /* end iterations */
666 if (ants
== 1) { /* if draw then erase */
667 MyXUngrabServer(dpy
); /* end grab for whole animation */
668 myaprintf((stderr
,"Did ungrab\n"));
671 myaprintf((stderr
,"Done animating\n"));
675 * Animate None is set on during configuration. When set on, it causes
676 * this module to exit after some number of animation events. (If it
677 * just exited immediately, you couldn't use this module to turn it back
680 static void AnimateResizeNone(
681 int x
, int y
, int w
, int h
, int fx
, int fy
, int fw
, int fh
)
692 if (!is_animation_visible(x
, y
, w
, h
, fx
, fy
, fw
, fh
))
700 * This makes a animation that looks like that light effect
701 * when you turn off an old TV.
702 * Used for window destruction
704 * This was commented out in Afterstep, I don't know why yet. dje.
706 static void AnimateClose(int x
, int y
, int w
, int h
)
710 if (!is_animation_visible(x
, y
, w
, h
, fx
, fy
, fw
, fh
)
714 step
= h
*4/Animate
.iterations
;
718 for (i
=h
; i
>=2; i
-=step
) {
719 XDrawRectangle(dpy
, Scr
.root
, gc
, x
, y
, w
, i
);
721 usleep(ANIM_DELAY2
*600);
722 XDrawRectangle(dpy
, Scr
.root
, gc
, x
, y
, w
, i
);
727 step
= w
*4/Animate
.iterations
;
731 for (i
=w
; i
>=0; i
-=step
) {
732 XDrawRectangle(dpy
, Scr
.root
, gc
, x
, y
, i
, 2);
734 usleep(ANIM_DELAY2
*1000);
735 XDrawRectangle(dpy
, Scr
.root
, gc
, x
, y
, i
, 2);
745 myfprintf((stderr
,"Dead Pipe, arg %d\n",arg
));
752 HandleTerminate(int sig
) {
753 fvwmSetTerminate(sig
);
758 int main(int argc
, char **argv
) {
759 char cmd
[200]; /* really big area for a command */
761 /* The new arg parsing function replaces the "manual" parsing */
762 module
= ParseModuleArgs(argc
,argv
,1);
765 fprintf(stderr
,"FvwmAnimate Version "VERSION
" should only be executed by fvwm!\n");
769 #ifdef HAVE_SIGACTION
771 struct sigaction sigact
;
773 sigemptyset(&sigact
.sa_mask
);
774 sigaddset(&sigact
.sa_mask
, SIGTERM
);
775 sigaddset(&sigact
.sa_mask
, SIGINT
);
776 sigaddset(&sigact
.sa_mask
, SIGPIPE
);
778 sigact
.sa_flags
= SA_INTERRUPT
; /* to interrupt ReadFvwmPacket() */
782 sigact
.sa_handler
= HandleTerminate
;
784 sigaction(SIGTERM
, &sigact
, NULL
);
785 sigaction(SIGINT
, &sigact
, NULL
);
786 sigaction(SIGPIPE
, &sigact
, NULL
);
789 #ifdef USE_BSD_SIGNALS
790 fvwmSetSignalMask( sigmask(SIGTERM
) |
794 signal(SIGTERM
, HandleTerminate
);
795 signal(SIGINT
, HandleTerminate
);
796 signal(SIGPIPE
, HandleTerminate
); /* Dead pipe == fvwm died */
797 #ifdef HAVE_SIGINTERRUPT
798 siginterrupt(SIGTERM
, True
);
799 siginterrupt(SIGINT
, True
);
800 siginterrupt(SIGPIPE
, True
);
804 Channel
[0] = module
->to_fvwm
;
805 Channel
[1] = module
->from_fvwm
;
807 dpy
= XOpenDisplay("");
809 fprintf(stderr
,"%s: can not open display\n",module
->name
);
812 /* FvwmAnimate must use the root visuals so do not call
813 * PictureInitCMap but PictureInitCMapRoot. Color Limit is not needed */
814 PictureInitCMapRoot(dpy
, False
, NULL
, False
, False
);
816 Scr
.root
= DefaultRootWindow(dpy
);
817 Scr
.screen
= DefaultScreen(dpy
);
819 sprintf(cmd
,"read .%s Quiet",module
->name
); /* read quiet modules config */
820 SendText(Channel
,cmd
,0);
821 ParseOptions(); /* get cmds fvwm has parsed */
823 SetMessageMask(Channel
, M_ICONIFY
|M_DEICONIFY
|M_STRING
|M_SENDCONFIG
824 |M_CONFIG_INFO
); /* tell fvwm about our mask */
825 CreateDrawGC(); /* create initial GC if necc. */
826 SendText(Channel
,"Nop",0);
828 running
= True
; /* out of initialization phase */
829 SendFinishedStartupNotification(Channel
); /* tell fvwm we're running */
830 SetSyncMask(Channel
,M_ICONIFY
|M_DEICONIFY
|M_STRING
); /* lock on send mask */
831 SetNoGrabMask(Channel
,M_ICONIFY
|M_DEICONIFY
|M_STRING
); /* ignore during recapture */
832 Loop(); /* start running */
837 * Wait for some event like iconify, deiconify and stuff.
839 static void Loop(void) {
841 clock_t time_start
; /* for time() */
842 clock_t time_end
; /* for time() */
844 struct tms time_buffer
; /* for time() */
847 myfprintf((stderr
,"Starting event loop\n"));
848 while ( !isTerminated
) {
849 if ( (packet
= ReadFvwmPacket(Channel
[1])) == NULL
)
850 break; /* fvwm is gone */
852 switch (packet
->type
) {
854 Scr
.Vx
= packet
->body
[0];
855 Scr
.Vy
= packet
->body
[1];
856 Scr
.CurrentDesk
= packet
->body
[2];
859 Scr
.CurrentDesk
= packet
->body
[0];
862 if (play_state
== False
)
866 if (packet
->size
< 15 /* If not all info needed, */
867 || packet
->body
[5] == 0) { /* or a "noicon" icon */
868 break; /* don't animate it */
870 if (Animate
.time
!= 0) {
871 time_start
= times(&time_buffer
);
873 Animate
.resize((int)packet
->body
[3], /* t->icon_x_loc */
874 (int)packet
->body
[4], /* t->icon_y_loc */
875 (int)packet
->body
[5], /* t->icon_p_width */
876 (int)packet
->body
[6], /* t->icon_p_height */
877 (int)packet
->body
[7], /* t->frame_x */
878 (int)packet
->body
[8], /* t->frame_y */
879 (int)packet
->body
[9], /* t->frame_width */
880 (int)packet
->body
[10]); /* t->frame_height */
881 if (Animate
.time
!= 0) {
882 time_end
= times(&time_buffer
);
883 time_accum
= time_end
- time_start
;
886 "DE_Iconify, args %d+%d+%dx%d %d+%d+%dx%d. took %dx%d\n",
887 (int)packet
->body
[3], /* t->icon_x_loc */
888 (int)packet
->body
[4], /* t->icon_y_loc */
889 (int)packet
->body
[5], /* t->icon_p_width */
890 (int)packet
->body
[6], /* t->icon_p_height */
891 (int)packet
->body
[7], /* t->frame_x */
892 (int)packet
->body
[8], /* t->frame_y */
893 (int)packet
->body
[9], /* t->frame_width */
894 (int)packet
->body
[10], /* t->frame_height */
897 /* So far, clk_tck seems to be non-portable...dje */
898 /* (int)time_accum,(int)CLK_TCK)); */
902 if (play_state
== False
)
906 /* In Afterstep, this logic waited for M_CONFIGURE_WINDOW
907 before animating. To this time, I don't know why.
908 (One is sent right after the other.)
910 if (packet
->size
< 15 /* if not enough info */
911 || (int)packet
->body
[3] == -10000 /* or a transient window */
912 || (int)packet
->body
[5] == 0) { /* or a "noicon" icon */
913 break; /* don't animate it */
915 if (Animate
.time
!= 0) {
916 time_start
= times(&time_buffer
);
918 Animate
.resize((int)packet
->body
[7], /* t->frame_x */
919 (int)packet
->body
[8], /* t->frame_y */
920 (int)packet
->body
[9], /* t->frame_width */
921 (int)packet
->body
[10], /* t->frame_height */
922 (int)packet
->body
[3], /* t->icon_x_loc */
923 (int)packet
->body
[4], /* t->icon_y_loc */
924 (int)packet
->body
[5], /* t->icon_p_width */
925 (int)packet
->body
[6]); /* t->icon_p_height */
926 if (Animate
.time
!= 0) {
927 time_end
= times(&time_buffer
);
928 time_accum
= time_end
- time_start
;
931 "Iconify, args %d+%d+%dx%d %d+%d+%dx%d. Took %d\n",
932 (int)packet
->body
[7], /* t->frame_x */
933 (int)packet
->body
[8], /* t->frame_y */
934 (int)packet
->body
[9], /* t->frame_width */
935 (int)packet
->body
[10], /* t->frame_height */
936 (int)packet
->body
[3], /* t->icon_x_loc */
937 (int)packet
->body
[4], /* t->icon_y_loc */
938 (int)packet
->body
[5], /* t->icon_p_width */
939 (int)packet
->body
[6],
945 char *line
= (char *)&packet
->body
[3];
947 line
= GetNextToken(line
, &token
);
953 if (strcasecmp(token
, "animate") == 0)
955 /* This message lets anything create an animation. Eg:
956 SendToModule FvwmAnimate \
957 animate 1 1 10 10 100 100 100 100
962 line
, "%5d %5d %5d %5d %5d %5d %5d %5d",
963 &locs
[0], &locs
[1], &locs
[2], &locs
[3],
964 &locs
[4], &locs
[5], &locs
[6], &locs
[7]);
965 if (matched
== 8 && play_state
== True
)
968 locs
[0], locs
[1], locs
[2], locs
[3],
969 locs
[4], locs
[5], locs
[6], locs
[7]);
971 "animate %d+%d+%dx%d %d+%d+%dx%d\n",
972 locs
[0], locs
[1], locs
[2], locs
[3],
973 locs
[4], locs
[5], locs
[6], locs
[7]));
980 if (strcasecmp(token
, "reset") == 0)
983 num_saved_play_states
= 0;
985 else if (strcasecmp(token
, "play") == 0)
989 else if (strcasecmp(token
, "pause") == 0)
993 else if (strcasecmp(token
, "push") == 0)
995 if (num_saved_play_states
< MAX_SAVED_STATES
)
997 saved_play_states
[num_saved_play_states
]
1003 stderr
, "FvwmAnimate: Too many "
1004 "nested push commands;\n\tthe "
1005 "current state can not be "
1006 "restored later using pop\n");
1008 num_saved_play_states
++;
1010 else if (strcasecmp(token
, "pop") == 0)
1012 num_saved_play_states
--;
1013 if (num_saved_play_states
< 0)
1015 num_saved_play_states
= 0;
1017 stderr
, "FvwmAnimate: Got pop "
1018 "without push, ignored\n");
1020 else if (num_saved_play_states
<
1023 play_state
= saved_play_states
[
1024 num_saved_play_states
];
1028 line
= GetNextToken(line
, &token
);
1033 myfprintf((stderr
,"Got command: %s\n", (char *)&packet
->body
[3]));
1034 ParseConfigLine((char *)&packet
->body
[3]);
1036 } /* end switch header */
1038 myfprintf((stderr
,"Sending unlock\n"));
1039 if (packet
->type
!= M_CONFIG_INFO
)
1040 SendUnlockNotification(Channel
); /* fvwm can continue now! */
1041 if ((Animate
.resize
== AnimateResizeNone
/* If no animation desired */
1042 && animate_none
>= 1) /* and 1 animation(s) */
1043 || stop_recvd
) { /* or stop cmd */
1044 /* This still isn't perfect, if the user turns off animation,
1045 they would expect the menu to change on the spot.
1046 On the otherhand, the menu shouldn't change if the module is
1048 This logic is dependent on fvwm sending iconify messages
1049 to make this module exit. Currently it is sending messages
1050 even when "Style NoIcon" is on for everything.
1052 StopCmd(); /* update menu */
1053 myfprintf((stderr
,"Exiting, animate none count %d, stop recvd %c\n",
1054 animate_none
, stop_recvd
? 'y' : 'n'));
1055 break; /* and stop */
1056 } /* end stopping */
1057 /* The execution of the custom command has to be delayed,
1058 because we first had to send the UNLOCK response.
1061 custom_recvd
= False
;
1063 CMD1X("Module FvwmForm Form%s");
1070 * This routine is responsible for reading and parsing the config file
1071 * Used FvwmEvent as a model.
1075 static const char *table
[]= {
1079 #define Custom_arg 1
1083 #define Effect_arg 3
1085 #define Iterations_arg 4
1087 #define Pixmap_arg 5
1089 #define Resize_arg 6
1097 #define Twist_arg 10
1099 #define Width_arg 11
1100 }; /* Keep list in alphabetic order, using binary search! */
1101 static void ParseOptions(void) {
1104 Scr
.MyDisplayWidth
= DisplayWidth(dpy
, Scr
.screen
);
1105 Scr
.MyDisplayHeight
= DisplayHeight(dpy
, Scr
.screen
);
1108 Scr
.CurrentDesk
= 0;
1110 myfprintf((stderr
,"Reading options\n"));
1111 InitGetConfigLine(Channel
,CatString3("*",module
->name
,0));
1112 while (GetConfigLine(Channel
,&buf
), buf
!= NULL
) {
1113 ParseConfigLine(buf
);
1114 } /* end config lines */
1115 } /* end function */
1118 void ParseConfigLine(char *buf
) {
1124 if (buf
[strlen(buf
)-1] == '\n') { /* if line ends with newline */
1125 buf
[strlen(buf
)-1] = '\0'; /* strip off \n */
1127 /* capture the ImagePath setting, don't worry about ColorLimit */
1128 if (strncasecmp(buf
, "ImagePath",9)==0) {
1129 PictureSetImagePath(&buf
[9]);
1131 /* Search for MyName (normally *FvwmAnimate) */
1132 else if (strncasecmp(buf
, CatString3("*",module
->name
,0), module
->namelen
+1) == 0) {/* If its for me */
1133 myfprintf((stderr
,"Found line for me: %s\n", buf
));
1134 p
= buf
+module
->namelen
+1; /* starting point */
1136 if ((e
= FindToken(p
,table
,char *))) { /* config option ? */
1137 if ((strcasecmp(*e
,"Stop") != 0)
1138 && (strcasecmp(*e
,"Custom") != 0)
1139 && (strcasecmp(*e
,"Save") != 0)) { /* no arg commands */
1140 p
+=strlen(*e
); /* skip matched token */
1141 p
= GetNextSimpleOption( p
, &q
);
1142 if (!q
) { /* If arg not found */
1143 fprintf(stderr
,"%s: %s%s needs a parameter\n",
1144 module
->name
, module
->name
,*e
);
1149 switch (e
- (char**)table
) {
1150 case Stop_arg
: /* Stop command */
1151 if (running
) { /* if not a stored command */
1152 stop_recvd
= True
; /* remember to stop */
1155 case Save_arg
: /* Save command */
1158 case Custom_arg
: /* Custom command */
1159 if (running
) { /* if not a stored command */
1160 custom_recvd
= True
; /* remember someone asked */
1163 case Color_arg
: /* Color */
1164 if (Animate
.color
) {
1165 free(Animate
.color
); /* release storage holding color name */
1166 Animate
.color
= 0; /* show its gone */
1168 if ((strcasecmp(q
,"None") != 0) /* If not color "none" */
1169 && (strcasecmp(q
,"Black^White") != 0)
1170 && (strcasecmp(q
,"White^Black") != 0)) {
1171 Animate
.color
= (char *)safestrdup(q
); /* make copy of name */
1173 /* override the pixmap option */
1174 if (Animate
.pixmap
) {
1175 free(Animate
.pixmap
);
1179 XFreePixmap(dpy
, pixmap
);
1182 CreateDrawGC(); /* update GC */
1185 if (Animate
.pixmap
) {
1186 free(Animate
.pixmap
); /* release storage holding pixmap name */
1187 Animate
.pixmap
= 0; /* show its gone */
1189 if (strcasecmp(q
,"None") != 0) { /* If not pixmap "none" */
1190 Animate
.pixmap
= (char *)safestrdup(q
); /* make copy of name */
1193 XFreePixmap(dpy
, pixmap
);
1196 CreateDrawGC(); /* update GC */
1198 case Delay_arg
: /* Delay */
1199 Animate
.delay
= atoi(q
);
1201 case Iterations_arg
: /* Iterations */
1202 Animate
.iterations
= atoi(q
);
1203 /* Silently fix up iterations less than 1. */
1204 if (Animate
.iterations
<= 0) {
1205 Animate
.iterations
= 1;
1208 case Effect_arg
: /* Effect */
1209 case Resize_arg
: /* -or - Resize */
1210 for (i
=0; i
< NUM_EFFECTS
; i
++) {
1211 if (strcasecmp(q
, effects
[i
].name
)==0
1212 || (effects
[i
].alias
1213 && strcasecmp(q
, effects
[i
].alias
)==0)) {
1214 Animate
.resize
= effects
[i
].function
;
1217 } /* end all effects */
1218 if (i
> NUM_EFFECTS
) { /* If not found */
1219 fprintf(stderr
, "%s: Unknown Effect '%s'\n", module
->name
, q
);
1221 /* Logically, you would only reset these when you got a command
1222 of None, or Random, but it doesn't really matter. */
1224 curtime
= time(NULL
);
1225 seed
= (unsigned) curtime
% INT_MAX
;
1228 case Time_arg
: /* Time in milliseconds */
1229 Animate
.time
= (clock_t)atoi(q
);
1231 case Twist_arg
: /* Twist */
1232 Animate
.twist
= atof(q
);
1234 case Width_arg
: /* Width */
1235 Animate
.width
= atoi(q
);
1236 /* Silently fix up width less than 0. */
1237 if (Animate
.width
< 0) {
1240 CreateDrawGC(); /* update GC */
1243 fprintf(stderr
,"%s: unknown action %s\n",module
->name
,*e
);
1246 } else { /* Match Myname, but a space */
1247 fprintf(stderr
,"%s: unknown command: %s\n",module
->name
,buf
);
1249 if(q
) { /* if parsed an arg */
1250 free(q
); /* free its memory */
1252 } /* config line for me */
1253 } /* end function */
1255 /* create GC for drawing the various animations */
1256 /* Called during start-up, and whenever the color or line width changes. */
1257 static void CreateDrawGC(void) {
1259 myfprintf((stderr
,"Creating GC\n"));
1262 XFreeGC(dpy
,gc
); /* free old GC */
1264 /* From builtins.c: */
1265 color
= (PictureBlackPixel() ^ PictureWhitePixel());
1267 gcv
.function
= GXxor
; /* default is to xor the lines */
1269 { /* if pixmap called for */
1270 FvwmPicture
*picture
;
1271 FvwmPictureAttributes fpa
;
1273 fpa
.mask
= FPAM_NO_COLOR_LIMIT
;
1274 picture
= PGetFvwmPicture(
1275 dpy
, RootWindow(dpy
,Scr
.screen
), 0, Animate
.pixmap
, fpa
);
1277 fprintf(stderr
, "%s: Could not load pixmap '%s'\n",
1278 module
->name
, Animate
.pixmap
);
1280 pixmap
= XCreatePixmap(
1281 dpy
, RootWindow(dpy
, Scr
.screen
), picture
->width
,
1282 picture
->height
, Pdepth
);
1283 PGraphicsCopyPixmaps(
1284 dpy
, picture
->picture
, None
, None
,
1285 picture
->depth
, pixmap
, None
,
1286 0, 0, picture
->width
, picture
->height
, 0, 0);
1287 PDestroyFvwmPicture(dpy
, picture
);
1290 else if (Animate
.color
)
1291 { /* if color called for */
1292 if (XParseColor(dpy
, Pcmap
,Animate
.color
, &xcol
))
1294 if (PictureAllocColor(dpy
, Pcmap
, &xcol
, True
))
1297 /* free it now, only interested in the pixel */
1299 dpy
, Pcmap
, &xcol
.pixel
, 1, 0, True
);
1300 /* gcv.function=GXequiv; Afterstep used this. */
1305 "%s: could not allocate color '%s'\n",
1306 module
->name
,Animate
.color
);
1311 fprintf(stderr
,"%s: could not parse color '%s'\n",
1312 module
->name
,Animate
.color
);
1315 gcv
.line_width
= Animate
.width
;
1316 gcv
.foreground
= color
;
1317 myfprintf((stderr
,"Color is %ld\n",gcv
.foreground
));
1318 gcv
.subwindow_mode
= IncludeInferiors
;
1322 gcv
.fill_style
= FillTiled
;
1324 gc
=fvwmlib_XCreateGC(
1325 dpy
, Scr
.root
, GCFunction
| GCForeground
| GCLineWidth
1326 | GCSubwindowMode
| (pixmap
? GCFillStyle
| GCTile
: 0), &gcv
);
1330 * Send commands to fvwm to define this modules menus.
1332 * When I first wrote this, I thought it might be a good idea to call the
1333 * menu "FvwmAnimate", just like the module name. To my surprise, I
1334 * found that fvwm treats menus just like functions. In fact I could no
1335 * longer start FvwmAnimate because it kept finding the menu instead of
1336 * the function. This probably should be fixed, but for now, the
1337 * generated menu is called "MenuFvwmAnimate", or "Menu<ModuleAlias>".
1340 static void DefineMe(void) {
1341 char cmd
[200]; /* really big area for a command */
1342 myfprintf((stderr
,"defining menu\n"));
1344 CMD1X("DestroyMenu Menu%s");
1345 CMD1X("DestroyMenu MenuIterations%s");
1346 CMD1X("DestroyMenu MenuEffects%s");
1347 CMD1X("DestroyMenu MenuWidth%s");
1348 CMD1X("DestroyMenu MenuTwist%s");
1349 CMD1X("DestroyMenu MenuDelay%s");
1350 CMD1X("DestroyMenu MenuColor%s");
1352 CMD1X("AddToMenu Menu%s \"Animation Main Menu\" Title");
1353 CMD11("AddToMenu Menu%s \"&E. Effects\" Popup MenuEffects%s");
1354 CMD11("AddToMenu Menu%s \"&I. Iterations\" Popup MenuIterations%s");
1355 CMD11("AddToMenu Menu%s \"&T. Twists\" Popup MenuTwist%s");
1356 CMD11("AddToMenu Menu%s \"&L. Line Width\" Popup MenuWidth%s");
1357 CMD11("AddToMenu Menu%s \"&D. Delays\" Popup MenuDelay%s");
1358 CMD11("AddToMenu Menu%s \"&X. Color for XOR\" Popup MenuColor%s");
1359 CMD10("AddToMenu Menu%s \"&C. Custom Settings\" %sCustom");
1360 CMD10("AddToMenu Menu%s \"&S. Save Config\" %sSave");
1361 CMD10("AddToMenu Menu%s \"&Z. Stop Animation\" %sStop");
1362 CMD11("AddToMenu Menu%s \"&R. Restart Animation\" FuncRestart%s");
1364 /* Define function for stopping and restarting Animation. */
1365 CMD1X("DestroyFunc FuncRestart%s");
1366 CMD10("AddToFunc FuncRestart%s \"I\" %sStop");
1367 CMD11("AddToFunc FuncRestart%s \"I\" Module FvwmAnimate %s");
1369 /* Define the sub menus. */
1370 CMD1X("AddToMenu MenuIterations%s \"Iterations\" Title");
1371 CMD10("AddToMenu MenuIterations%s \"&1. Iterations 1\" %sIterations 1");
1372 CMD10("AddToMenu MenuIterations%s \"&2. Iterations 2\" %sIterations 2");
1373 CMD10("AddToMenu MenuIterations%s \"&3. Iterations 4\" %sIterations 4");
1374 CMD10("AddToMenu MenuIterations%s \"&4. Iterations 8\" %sIterations 8");
1375 CMD10("AddToMenu MenuIterations%s \"&5. Iterations 16\" %sIterations 16");
1376 CMD10("AddToMenu MenuIterations%s \"&6. Iterations 32\" %sIterations 32");
1378 CMD1X("AddToMenu MenuWidth%s \"Line Width\" Title");
1379 CMD10("AddToMenu MenuWidth%s \"&1. Line Width 0 (fast)\" %sWidth 0");
1380 CMD10("AddToMenu MenuWidth%s \"&2. Line Width 1\" %sWidth 1");
1381 CMD10("AddToMenu MenuWidth%s \"&3. Line Width 2\" %sWidth 2");
1382 CMD10("AddToMenu MenuWidth%s \"&4. Line Width 4\" %sWidth 4");
1383 CMD10("AddToMenu MenuWidth%s \"&5. Line Width 6\" %sWidth 6");
1384 CMD10("AddToMenu MenuWidth%s \"&6. Line Width 8\" %sWidth 8");
1386 CMD1X("AddToMenu MenuTwist%s \"Twists (Twist, Turn, Flip only)\" Title");
1387 CMD10("AddToMenu MenuTwist%s \"&1. Twist .25\" %sTwist .25");
1388 CMD10("AddToMenu MenuTwist%s \"&2. Twist .50\" %sTwist .50");
1389 CMD10("AddToMenu MenuTwist%s \"&3. Twist 1\" %sTwist 1");
1390 CMD10("AddToMenu MenuTwist%s \"&4. Twist 2\" %sTwist 2");
1392 CMD1X("AddToMenu MenuDelay%s \"Delays\" Title");
1393 CMD10("AddToMenu MenuDelay%s \"&1. Delay 1/1000 sec\" %sDelay 1");
1394 CMD10("AddToMenu MenuDelay%s \"&2. Delay 1/100 sec\" %sDelay 10");
1395 CMD10("AddToMenu MenuDelay%s \"&3. Delay 1/10 sec\" %sDelay 100");
1397 /* Same as the colors at the front of the colorlimiting table */
1398 CMD1X("AddToMenu MenuColor%s \"Colors\" Title");
1399 CMD10("AddToMenu MenuColor%s \"&1. Color Black^White\" %sColor None");
1400 CMD10("AddToMenu MenuColor%s \"&2. Color White\" %sColor white");
1401 CMD10("AddToMenu MenuColor%s \"&3. Color Black\" %sColor black");
1402 CMD10("AddToMenu MenuColor%s \"&4. Color Grey\" %sColor grey");
1403 CMD10("AddToMenu MenuColor%s \"&5. Color Green\" %sColor green");
1404 CMD10("AddToMenu MenuColor%s \"&6. Color Blue\" %sColor blue");
1405 CMD10("AddToMenu MenuColor%s \"&7. Color Red\" %sColor red");
1406 CMD10("AddToMenu MenuColor%s \"&8. Color Cyan\" %sColor cyan");
1407 CMD10("AddToMenu MenuColor%s \"&9. Color Yellow\" %sColor yellow");
1408 CMD10("AddToMenu MenuColor%s \"&A. Color Magenta\" %sColor magenta");
1409 CMD10("AddToMenu MenuColor%s \"&B. Color DodgerBlue\" %sColor DodgerBlue");
1410 CMD10("AddToMenu MenuColor%s \"&C. Color SteelBlue\" %sColor SteelBlue");
1411 CMD10("AddToMenu MenuColor%s \"&D. Color Chartreuse\" %sColor chartreuse");
1412 CMD10("AddToMenu MenuColor%s \"&E. Color Wheat\" %sColor wheat");
1413 CMD10("AddToMenu MenuColor%s \"&F. Color Turquoise\" %sColor turquoise");
1415 CMD1X("AddToMenu MenuEffects%s \"Effects\" Title");
1416 CMD10("AddToMenu MenuEffects%s \"&1. Effect Random\" %sEffect Random");
1417 CMD10("AddToMenu MenuEffects%s \"&2. Effect Flip\" %sEffect Flip");
1418 CMD10("AddToMenu MenuEffects%s \"&3. Effect Frame\" %sEffect Frame");
1419 CMD10("AddToMenu MenuEffects%s \"&4. Effect Frame3D\" %sEffect Frame3D");
1420 CMD10("AddToMenu MenuEffects%s \"&5. Effect Lines\" %sEffect Lines");
1421 CMD10("AddToMenu MenuEffects%s \"&6. Effect Turn\" %sEffect Turn");
1422 CMD10("AddToMenu MenuEffects%s \"&7. Effect Twist\" %sEffect Twist");
1423 CMD10("AddToMenu MenuEffects%s \"&N. Effect None\" %sEffect None");
1425 /* Still to be done:
1426 Use of FvwmForms for Help. (Need to fix line spacing in FvwmForms first).
1430 /* Write the current config into a file. */
1431 static void SaveConfig(void) {
1434 char filename
[100]; /* more than enough room */
1435 char msg
[200]; /* even more room for msg */
1436 /* Need to use logic to create fully qualified file name same as in
1437 read.c, right now, this logic only works well if fvwm is started
1438 from the users home directory.
1440 sprintf(filename
,"%s/.%s",getenv("FVWM_USERDIR"),module
->name
);
1441 config_file
= fopen(filename
,"w");
1442 if (config_file
== NULL
) {
1444 "%s: Open config file <%s> for write failed. \
1445 Save not done! Error\n",
1446 module
->name
, filename
);
1450 fprintf(config_file
,"# This file was created by %s\n\n",module
->name
);
1451 for (i
=0; i
< NUM_EFFECTS
; i
++) {
1452 if (effects
[i
].function
== Animate
.resize
) {
1453 fprintf(config_file
,"*%s: Effect %s\n",module
->name
,effects
[i
].name
);
1456 } /* all possible effects */
1457 fprintf(config_file
,"*%s: Iterations %d\n",module
->name
,Animate
.iterations
);
1458 fprintf(config_file
,"*%s: Width %d\n",module
->name
,Animate
.width
);
1459 fprintf(config_file
,"*%s: Twist %f\n",module
->name
,Animate
.twist
);
1460 fprintf(config_file
,"*%s: Delay %d\n",module
->name
,Animate
.delay
);
1461 if (Animate
.color
) {
1462 fprintf(config_file
,"*%s: Color %s\n",module
->name
,Animate
.color
);
1464 /* Note, add "time" if that ever works. dje. 10/14/98 */
1465 fclose(config_file
);
1468 /* Stop is different than KillModule in that it gives this module a chance to
1469 alter the builtin menu before it exits.
1471 static void StopCmd(void) {
1473 myfprintf((stderr
,"%s: Defining startup menu in preparation for stop\n",
1475 CMD1X("DestroyMenu Menu%s");
1476 CMD11("AddToMenu Menu%s \"%s\" Title");
1477 CMD11("AddToMenu Menu%s \"&0. Start FvwmAnimate\" Module %s");
1480 static void DefineForm(void) {
1483 myfprintf((stderr
,"Defining form Form%s\n", module
->name
));
1484 CMD1X("DestroyModuleConfig Form%s*");
1485 CMD1X("*Form%sWarpPointer");
1486 CMD1X("*Form%sLine center");
1487 CMD11("*Form%sText \"Custom settings for %s\"");
1488 CMD1X("*Form%sLine left");
1489 CMD1X("*Form%sText \"\"");
1490 CMD1X("*Form%sLine left");
1491 CMD1X("*Form%sText \"Effect:\"");
1492 CMD1X("*Form%sSelection meth single");
1493 for (i
=0; i
< NUM_EFFECTS
; i
++) { /* for all effects */
1494 effects
[i
].button
="off"; /* init the button setting */
1495 if (Animate
.resize
== effects
[i
].function
) { /* compare to curr setting */
1496 effects
[i
].button
="on"; /* turn on one button */
1497 } /* end if curr setting */
1498 } /* end all buttons */
1499 /* Macro for a command with one var */
1500 #define CMD1V(TEXT,VAR) \
1501 sprintf(cmd,TEXT,module->name,VAR);\
1502 SendText(Channel,cmd,0);
1504 /* There is a cleaner way (using the array) for this...dje */
1505 CMD1V("*Form%sChoice RANDOM RANDOM %s \"Random\"",effects
[1].button
);
1506 CMD1V("*Form%sChoice FLIP FLIP %s \"Flip\"",effects
[2].button
);
1507 CMD1V("*Form%sChoice FRAME FRAME %s \"Frame\"",effects
[3].button
);
1508 CMD1V("*Form%sChoice FRAME3D FRAME3D %s \"Frame3d\"",effects
[4].button
);
1509 CMD1V("*Form%sChoice LINES LINES %s \"Lines\"",effects
[5].button
);
1510 CMD1V("*Form%sChoice TURN TURN %s \"Turn\"",effects
[6].button
);
1511 CMD1V("*Form%sChoice TWIST TWIST %s \"Twist\"",effects
[7].button
);
1512 CMD1X("*Form%sLine left");
1513 CMD1X("*Form%sText \"\"");
1514 CMD1X("*Form%sLine left");
1515 CMD1X("*Form%sText \"Iterations:\"");
1516 CMD1V("*Form%sInput Iterations 5 \"%d\"",Animate
.iterations
);
1517 CMD1X("*Form%sText \"Twists:\"");
1518 CMD1V("*Form%sInput Twists 10 \"%f\"",Animate
.twist
);
1519 CMD1X("*Form%sText \"Linewidth:\"");
1520 CMD1V("*Form%sInput Linewidth 3 \"%d\"",Animate
.width
);
1521 CMD1X("*Form%sText \"Delays:\"");
1522 CMD1V("*Form%sInput Delays 5 \"%d\"",Animate
.delay
);
1523 CMD1X("*Form%sLine left");
1524 CMD1X("*Form%sText \"\"");
1525 CMD1X("*Form%sLine left");
1526 CMD1X("*Form%sText \"Color:\"");
1527 CMD1V("*Form%sInput Color 20 \"%s\"",
1528 Animate
.color
? Animate
.color
: "Black^White");
1529 CMD1X("*Form%sLine left");
1530 CMD1X("*Form%sText \"\"");
1532 F1 - Apply, F2 - Apply and Save, F3 - Reset, F4 - Dismiss
1535 CMD1X("*Form%sLine expand");
1536 CMD1X("*Form%sButton continue \"F1 - Apply\" F1");
1537 CMD11("*Form%sCommand *%sIterations $(Iterations)");
1538 CMD11("*Form%sCommand *%sTwist $(Twists)");
1539 CMD11("*Form%sCommand *%sWidth $(Linewidth)");
1540 CMD11("*Form%sCommand *%sDelay $(Delays)");
1541 CMD11("*Form%sCommand *%sColor $(Color)");
1542 CMD11("*Form%sCommand *%sEffect $(RANDOM?Random)\
1550 CMD1X("*Form%sButton continue \"F2 - Apply & Save\" F2");
1551 CMD11("*Form%sCommand *%sIterations $(Iterations)");
1552 CMD11("*Form%sCommand *%sTwist $(Twists)");
1553 CMD11("*Form%sCommand *%sWidth $(Linewidth)");
1554 CMD11("*Form%sCommand *%sDelay $(Delays)");
1555 CMD11("*Form%sCommand *%sColor $(Color)");
1556 CMD11("*Form%sCommand *%sEffect $(RANDOM?Random)\
1563 CMD11("*Form%sCommand *%sSave");
1565 CMD1X("*Form%sButton restart \"F3 - Reset\" F3");
1567 CMD1X("*Form%sButton quit \"F4 - Dismiss\" F4");
1568 CMD1X("*Form%sCommand Nop");