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