1 /*
2 * Animate! Animation module for AfterStep
3 *
4 * Copyright (c) 1996 Alfredo Kengi Kojima (kojima@inf.ufrgs.br)
5 *
6 * Copyright (c) 1996 Kaj Groner <kajg@mindspring.com>
7 * Added .steprc parsing and twisty iconify.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23 /*
24 * changes needed in afterstep
25 * broadcast(M_DEICONIFY) must include the icon position>
26 */
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <X11/Xlib.h>
31 #include <signal.h>
32 #include <math.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <ctype.h>
36 #include "../../configure.h"
37 #include "../../afterstep/module.h"
38 #include "../../lib/aftersteplib.h"
39 #include "Animate.h"
40
41 #define AS_PI 3.14159265358979323846
42
43 Display *dpy;
44 int scr;
45 Window root;
46 GC DrawGC;
47 char *ProgName;
48 int Channel[2];
49 void Loop();
50 void ParseOptions(char *);
51
52 struct ASAnimate Animate = { NULL, ANIM_ITERATIONS, ANIM_DELAY,
53 ANIM_TWIST, ANIM_WIDTH, AnimateResizeTwist };
54
55 /*
56 * This makes a twisty iconify/deiconify animation for a window, similar to
57 * MacOS. Parameters specify the position and the size of the initial
58 * window and the final window
59 */
AnimateResizeTwist(int x,int y,int w,int h,int fx,int fy,int fw,int fh)60 void AnimateResizeTwist(int x, int y, int w, int h, int fx, int fy, int fw, int fh)
61 {
62 float cx, cy, cw, ch;
63 float xstep, ystep, wstep, hstep;
64 XPoint points[5];
65 float angle, angle_finite, a, d;
66
67 x += w/2;
68 y += h/2;
69 fx += fw/2;
70 fy += fh/2;
71
72 xstep = (float)(fx-x)/Animate.iterations;
73 ystep = (float)(fy-y)/Animate.iterations;
74 wstep = (float)(fw-w)/Animate.iterations;
75 hstep = (float)(fh-h)/Animate.iterations;
76
77 cx = (float)x;
78 cy = (float)y;
79 cw = (float)w;
80 ch = (float)h;
81 a = atan(ch/cw);
82 d = sqrt((cw/2)*(cw/2)+(ch/2)*(ch/2));
83
84 angle_finite = 2*AS_PI*Animate.twist;
85 for (angle=0;; angle+=(float)(2*AS_PI*Animate.twist/Animate.iterations)) {
86 if (angle > angle_finite)
87 angle = angle_finite;
88 points[0].x = cx+cos(angle-a)*d;
89 points[0].y = cy+sin(angle-a)*d;
90 points[1].x = cx+cos(angle+a)*d;
91 points[1].y = cy+sin(angle+a)*d;
92 points[2].x = cx+cos(angle-a+AS_PI)*d;
93 points[2].y = cy+sin(angle-a+AS_PI)*d;
94 points[3].x = cx+cos(angle+a+AS_PI)*d;
95 points[3].y = cy+sin(angle+a+AS_PI)*d;
96 points[4].x = cx+cos(angle-a)*d;
97 points[4].y = cy+sin(angle-a)*d;
98 XGrabServer(dpy);
99 XDrawLines(dpy, root, DrawGC, points, 5, CoordModeOrigin);
100 XFlush(dpy);
101 sleep_a_little(Animate.delay*1000);
102 XDrawLines(dpy, root, DrawGC, points, 5, CoordModeOrigin);
103 XUngrabServer(dpy);
104 cx+=xstep;
105 cy+=ystep;
106 cw+=wstep;
107 ch+=hstep;
108 a = atan(ch/cw);
109 d = sqrt((cw/2)*(cw/2)+(ch/2)*(ch/2));
110 if (angle >= angle_finite)
111 break;
112 }
113 XFlush(dpy);
114 }
115
116 /*
117 * This makes a zooming iconify/deiconify animation for a window, like most
118 * any other icon animation out there. Parameters specify the position and
119 * the size of the initial window and the final window
120 */
AnimateResizeZoom(int x,int y,int w,int h,int fx,int fy,int fw,int fh)121 void AnimateResizeZoom(int x, int y, int w, int h, int fx, int fy, int fw, int fh)
122 {
123 float cx, cy, cw, ch;
124 float xstep, ystep, wstep, hstep;
125 int i;
126
127 xstep = (float)(fx-x)/Animate.iterations;
128 ystep = (float)(fy-y)/Animate.iterations;
129 wstep = (float)(fw-w)/Animate.iterations;
130 hstep = (float)(fh-h)/Animate.iterations;
131
132 cx = (float)x;
133 cy = (float)y;
134 cw = (float)w;
135 ch = (float)h;
136 for (i=0; i<Animate.iterations; i++) {
137 XGrabServer(dpy);
138 XDrawRectangle(dpy, root, DrawGC, (int)cx, (int)cy, (int)cw, (int)ch);
139 XFlush(dpy);
140 sleep_a_little(Animate.delay);
141 XDrawRectangle(dpy, root, DrawGC, (int)cx, (int)cy, (int)cw, (int)ch);
142 XUngrabServer(dpy);
143 cx+=xstep;
144 cy+=ystep;
145 cw+=wstep;
146 ch+=hstep;
147 }
148 XFlush(dpy);
149 }
150
151 #if 0
152 /*
153 * This makes a animation that looks like that light effect
154 * when you turn off an old TV.
155 * Used for window destruction
156 */
157 void AnimateClose(int x, int y, int w, int h)
158 {
159 int i, step;
160
161 if (h>4) {
162 step = h*4/Animate.iterations;
163 if (step==0) {
164 step = 2;
165 }
166 for (i=h; i>=2; i-=step) {
167 XDrawRectangle(dpy, root, DrawGC, x, y, w, i);
168 XFlush(dpy);
169 sleep_a_little(ANIM_DELAY2*600);
170 XDrawRectangle(dpy, root, DrawGC, x, y, w, i);
171 y+=step/2;
172 }
173 }
174 if (w<2) return;
175 step = w*4/Animate.iterations;
176 if (step==0) {
177 step = 2;
178 }
179 for (i=w; i>=0; i-=step) {
180 XDrawRectangle(dpy, root, DrawGC, x, y, i, 2);
181 XFlush(dpy);
182 sleep_a_little(ANIM_DELAY2*1000);
183 XDrawRectangle(dpy, root, DrawGC, x, y, i, 2);
184 x+=step/2;
185 }
186 sleep_a_little(100000);
187 XFlush(dpy);
188 }
189 #endif
190
DeadPipe(int foo)191 void DeadPipe(int foo)
192 {
193 exit(0);
194 }
195
main(int argc,char ** argv)196 int main(int argc, char **argv)
197 {
198 char *temp;
199 XGCValues gcv;
200 unsigned long color;
201 char mask_mesg[20];
202
203 ProgName = rindex(argv[0], '/')?rindex(argv[0], '/')+1:argv[0];
204 if (argc != 6) {
205 fprintf(stderr,"%s should only be executed by afterstep!\n",ProgName);
206 exit(1);
207 }
208
209 /* Dead pipe == AS died */
210 signal (SIGPIPE, DeadPipe);
211
212 Channel[0] = atoi(argv[1]);
213 Channel[1] = atoi(argv[2]);
214
215 dpy = XOpenDisplay("");
216 if (dpy==NULL) {
217 fprintf(stderr,"%s: could not open display\n",ProgName);
218 exit(1);
219 }
220 root = DefaultRootWindow(dpy);
221 scr = DefaultScreen(dpy);
222
223 sprintf(mask_mesg,"SET_MASK %lu\n",(unsigned long)(M_CONFIGURE_WINDOW|
224 M_ICONIFY|
225 M_DEICONIFY|
226 M_LOCKONSEND));
227
228 SendInfo(Channel, mask_mesg, 0);
229
230 ParseOptions(argv[3]);
231 color = WhitePixel(dpy,scr);
232 if (Animate.color) {
233 XColor xcol;
234 if (XParseColor(dpy,DefaultColormap(dpy,scr),Animate.color, &xcol)) {
235 if (XAllocColor(dpy, DefaultColormap(dpy,scr), &xcol)) {
236 color = xcol.pixel;
237 } else {
238 fprintf(stderr,"%s: could not allocate color '%s'\n",
239 ProgName,Animate.color);
240 }
241 } else {
242 fprintf(stderr,"%s: could not parse color '%s'\n",
243 ProgName,Animate.color);
244 }
245 }
246 gcv.line_width = Animate.width;
247 gcv.function = GXequiv;
248 gcv.foreground = color;
249 gcv.background = color;
250 gcv.subwindow_mode = IncludeInferiors;
251 DrawGC=XCreateGC(dpy, root, GCFunction|GCForeground|GCLineWidth|GCBackground
252 |GCSubwindowMode, &gcv);
253 SendText(Channel,"Nop",0);
254 Loop();
255 }
256
GetWindowSize(Window win,int * x,int * y,int * w,int * h)257 void GetWindowSize(Window win, int *x, int *y, int *w, int *h)
258 {
259 Window root_r;
260 unsigned int bw_r, d_r;
261
262 XGetGeometry(dpy, win, &root_r, x, y, (unsigned int*) w, (unsigned int*) h,
263 &bw_r, &d_r);
264 }
265
266 /*
267 * Wait for some event like iconify, deiconify and stuff.
268 *
269 */
Loop()270 void Loop()
271 {
272 unsigned long header[3], *body;
273 int c, x0, y0, w0, h0, xf, yf, wf, hf;
274 int iconify;
275 Window win;
276
277 while (1) {
278 c=ReadASPacket(Channel[1], header, &body);
279 if (c>0) {
280 switch (header[1]) {
281 case M_DEICONIFY:
282 win = body[1];
283 x0 = body[3];
284 y0 = body[4];
285
286 GetWindowSize(win, &xf, &yf, &wf, &hf);
287 Animate.resize(x0, y0, 64, 64, xf, yf, wf, hf);
288 break;
289
290 case M_ICONIFY:
291 xf = body[3];
292 yf = body[4];
293 if (xf<=-10000) break;
294 wf = 64;
295 hf = 64;
296 free(body);
297
298 SendInfo(Channel, "UNLOCK 1\n", 0);
299 c=ReadASPacket(Channel[1], header, &body);
300 if (c<=0) break;
301 if (header[1]!=M_CONFIGURE_WINDOW) break;
302 x0 = body[3];
303 y0 = body[4];
304 w0 = body[5];
305 h0 = body[6];
306 Animate.resize(x0, y0, w0, h0, xf, yf, wf, hf);
307 break;
308 }
309 free(body);
310 }
311 SendInfo(Channel, "UNLOCK 1\n", 0);
312 }
313 }
314
315 /*****************************************************************************
316 *
317 * This routine is responsible for reading and parsing the config file
318 * Ripped from the Pager.
319 *
320 ****************************************************************************/
ParseOptions(char * filename)321 void ParseOptions(char *filename)
322 {
323 FILE *fd = (FILE *)0;
324 char *line, *t;
325 int Clength;
326
327 line = safemalloc(256);
328
329 fd = fopen(filename,"r");
330 if(fd == (FILE *)0)
331 {
332 fprintf(stderr,"%s: can't open config file %s",ProgName,filename);
333 exit(1);
334 }
335
336 Clength = strlen(ProgName);
337
338 while (fgets(line, 256-1, fd) != (char *)0)
339 {
340 line[strlen(line)-1] = 0;
341
342 if (*line == '*' && mystrncasecmp(line+1, ProgName, Clength)==0)
343 {
344 t = line + Clength + 1;
345 if (mystrncasecmp(t, "Color", 5)==0)
346 {
347 for (t+=5; isspace(*t)&&*t != '\n'&&*t != 0; t++);
348
349 if (Animate.color)
350 free(Animate.color);
351 Animate.color = strdup(t);
352 }
353
354 else if (mystrncasecmp(t, "Delay", 5)==0)
355 {
356 for (t+=5; isspace(*t)&&*t != '\n'&&*t != 0; t++);
357
358 Animate.delay = atoi(t);
359 }
360
361 else if (mystrncasecmp(t, "Width", 5)==0)
362 {
363 for (t+=5; isspace(*t)&&*t != '\n'&&*t != 0; t++);
364
365 Animate.width = atoi(t);
366 }
367
368 else if (mystrncasecmp(t, "Twist", 5)==0)
369 {
370 for (t+=5; isspace(*t)&&*t != '\n'&&*t != 0; t++);
371
372 Animate.twist = atof(t);
373 }
374
375 else if (mystrncasecmp(t, "Iterations", 5)==0)
376 {
377 for (t+=10; isspace(*t)&&*t != '\n'&&*t != 0; t++);
378
379 Animate.iterations = atoi(t);
380 }
381
382 else if (mystrncasecmp(t, "Resize", 6)==0)
383 {
384 for (t+=6; isspace(*t)&&*t != '\n'&&*t != 0; t++);
385
386 if (mystrncasecmp(t, "Twist", 5)==0)
387 Animate.resize = AnimateResizeTwist;
388 else if (mystrncasecmp(t, "Zoom", 4)==0)
389 Animate.resize = AnimateResizeZoom;
390 else
391 fprintf(stderr, "%s: Bad Resize method '%s'\n", ProgName, t);
392 }
393
394 }
395 }
396
397 free(line);
398 fclose(fd);
399 }
400
401