1 /****************************************************************************
2  * Copyright (c) 2000,2001 Sasha Vasko <sasha at aftercode.net>
3  * Copyright (c) 1999 Ethan Fisher <allanon@crystaltokyo.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  *
19  ****************************************************************************/
20 /***********************************************************************
21  * desktop cover for houskeeping mode
22  ***********************************************************************/
23 #define LOCAL_DEBUG
24 
25 #include "../../configure.h"
26 
27 #include "asinternals.h"
28 
29 #include <stdarg.h>
30 
31 #if TIME_WITH_SYS_TIME
32 # include <sys/time.h>
33 # include <time.h>
34 #else
35 # if HAVE_SYS_TIME_H
36 #  include <sys/time.h>
37 # else
38 #  include <time.h>
39 # endif
40 #endif
41 
42 #include "../../libAfterStep/colorscheme.h"
43 
44 /**************************************************************************
45  * Different Desktop change Animation types
46  **************************************************************************/
47 
48 static CARD32 rnd32_seed = 345824357;
49 
50 #define MAX_MY_RND32        0x00ffffffff
51 #ifdef WORD64
52 #define MY_RND32() \
53 (rnd32_seed = ((1664525L*rnd32_seed)&MAX_MY_RND32)+1013904223L)
54 #else
55 #define MY_RND32() \
56 (rnd32_seed = (1664525L*rnd32_seed)+1013904223L)
57 #endif
58 
59 #define BLOCKS_NUM	10
60 #define LEVELS_NUM 	10
61 
62 struct ASDeskAniBlocks {
63 	Window cover;
64 	int steps, steps_done;
65 	unsigned int open_height;
66 	unsigned char *stripes[LEVELS_NUM];
67 	XRectangle blocks[BLOCKS_NUM];
68 	int off_y[LEVELS_NUM];
69 
70 };
71 
72 void do_anim_shape_blocks (void *vdata);
73 
74 
75 void
desk_anim_shape_blocks(ScreenInfo * scr,Window cover,unsigned int steps)76 desk_anim_shape_blocks (ScreenInfo * scr, Window cover, unsigned int steps)
77 {
78 #ifdef SHAPE
79 	XRectangle main_b = { 0, 0, scr->MyDisplayWidth, scr->MyDisplayHeight };
80 	struct ASDeskAniBlocks *data =
81 			safecalloc (1, sizeof (struct ASDeskAniBlocks));
82 	int y_dim = scr->MyDisplayHeight / steps;
83 	int i;
84 
85 	for (i = 0; i < LEVELS_NUM; i++) {
86 		data->off_y[i] = (i - (LEVELS_NUM - 1)) * y_dim;
87 		data->stripes[i] = safecalloc (BLOCKS_NUM, 1);
88 	}
89 
90 	XShapeCombineRectangles (dpy, cover, ShapeBounding, 0, 0, &main_b, 1,
91 													 ShapeSet, Unsorted);
92 	data->cover = cover;
93 	data->steps = steps;
94 
95 	timer_new (20, do_anim_shape_blocks, data);
96 #endif
97 }
98 
do_anim_shape_blocks(void * vdata)99 void do_anim_shape_blocks (void *vdata)
100 {
101 #ifdef SHAPE
102 	struct ASDeskAniBlocks *data = (struct ASDeskAniBlocks *)vdata;
103 	XRectangle main_b = { 0, 0, Scr.MyDisplayWidth, Scr.MyDisplayHeight };
104 	int ratio = MAX_MY_RND32 / LEVELS_NUM;
105 	int x_dim = Scr.MyDisplayWidth / BLOCKS_NUM;
106 	int y_dim = Scr.MyDisplayHeight / data->steps;
107 	int level, th;
108 	unsigned char *tmp;
109 
110 	if (y_dim < 2)
111 		y_dim = 2;
112 
113 
114 	th = MAX_MY_RND32;
115 
116 	level = LEVELS_NUM;
117 	while (--level >= 0) {
118 		int blocks_used;
119 		int i = 0;
120 
121 		th -= ratio;
122 		if (data->off_y[level] < 0)
123 			continue;
124 		blocks_used = 0;
125 
126 		tmp = data->stripes[level];
127 		for (i = 0; i < BLOCKS_NUM; i++) {
128 			if (tmp[i] == 0 && MY_RND32 () > th) {
129 				data->blocks[blocks_used].y = 0;
130 				data->blocks[blocks_used].x = i * x_dim;
131 				data->blocks[blocks_used].width = x_dim;
132 				data->blocks[blocks_used].height = y_dim;
133 				blocks_used++;
134 				tmp[i] = 1;
135 			}
136 		}
137 		XShapeCombineRectangles (dpy, data->cover, ShapeBounding, 0,
138 														 data->off_y[level], data->blocks, blocks_used,
139 														 ShapeSubtract, Unsorted);
140 		XFlush (dpy);
141 	}
142 	if (data->off_y[0] >= 0)
143 		data->open_height += y_dim;
144 
145 	tmp = data->stripes[0];
146 	for (level = 0; level < LEVELS_NUM - 1; level++) {
147 		data->off_y[level] += y_dim;
148 		data->stripes[level] = data->stripes[level + 1];
149 	}
150 	data->off_y[LEVELS_NUM - 1] += y_dim;
151 	data->stripes[LEVELS_NUM - 1] = tmp;
152 	memset (tmp, 0x00, BLOCKS_NUM);
153 
154 	main_b.height = data->open_height;
155 	if (main_b.height > 0)
156 		XShapeCombineRectangles (dpy, data->cover, ShapeBounding, 0, 0,
157 														 &main_b, 1, ShapeSubtract, Unsorted);
158 
159 	++data->steps_done;
160 	if (data->steps_done >= data->steps) {
161 		for (level = 0; level < LEVELS_NUM; level++)
162 			free (data->stripes[level]);
163 		XDestroyWindow (dpy, data->cover);
164 		free (data);
165 	} else
166 		timer_new (20, do_anim_shape_blocks, vdata);
167 #endif
168 }
169 
170 struct ASDeskAniMove {
171 	Window cover;
172 	int steps, steps_done;
173 	int dirx, diry;
174 	int px, py;
175 };
176 
177 void do_anim_slide (void *vdata);
178 void do_anim_shrink (void *vdata);
179 
180 void
desk_anim_slide(ScreenInfo * scr,Window cover,int dirx,int diry,unsigned int steps)181 desk_anim_slide (ScreenInfo * scr, Window cover, int dirx, int diry,
182 								 unsigned int steps)
183 {
184 	struct ASDeskAniMove *data =
185 			safecalloc (1, sizeof (struct ASDeskAniMove));
186 
187 	data->cover = cover;
188 	data->dirx = dirx;
189 	data->diry = diry;
190 	data->steps = steps;
191 
192 	timer_new (20, do_anim_slide, data);
193 }
194 
do_anim_slide(void * vdata)195 void do_anim_slide (void *vdata)
196 {
197 	struct ASDeskAniMove *data = (struct ASDeskAniMove *)vdata;
198 
199 	int inc = Scr.MyDisplayWidth / data->steps;
200 
201 	if (inc == 0)
202 		inc = 1;
203 	data->px += data->dirx * inc;
204 	data->py += data->diry * inc;
205 	XMoveWindow (dpy, data->cover, data->px, data->py);
206 	XFlush (dpy);
207 	++(data->steps_done);
208 	if (data->steps_done >= data->steps) {
209 		XDestroyWindow (dpy, data->cover);
210 		free (data);
211 	} else
212 		timer_new (20, do_anim_slide, vdata);
213 }
214 
215 
216 void
desk_anim_shrink(ScreenInfo * scr,Window cover,int dirx,int diry,unsigned int steps)217 desk_anim_shrink (ScreenInfo * scr, Window cover, int dirx, int diry,
218 									unsigned int steps)
219 {
220 
221 	struct ASDeskAniMove *data =
222 			safecalloc (1, sizeof (struct ASDeskAniMove));
223 
224 	data->cover = cover;
225 	data->dirx = dirx;
226 	data->diry = diry;
227 	data->steps = steps;
228 	data->px = scr->MyDisplayWidth;
229 	data->py = scr->MyDisplayHeight;
230 
231 	timer_new (20, do_anim_shrink, data);
232 }
233 
do_anim_shrink(void * vdata)234 void do_anim_shrink (void *vdata)
235 {
236 	struct ASDeskAniMove *data = (struct ASDeskAniMove *)vdata;
237 	int inc = Scr.MyDisplayWidth / data->steps;
238 
239 	if (inc == 0)
240 		inc = 1;
241 
242 	data->px += data->dirx * inc;
243 	if (data->px < 1)
244 		data->px = 1;
245 	data->py += data->diry * inc;
246 	if (data->py < 1)
247 		data->py = 1;
248 	XResizeWindow (dpy, data->cover, data->px, data->py);
249 	XSync (dpy, False);
250 
251 	++(data->steps_done);
252 	if (data->steps_done >= data->steps) {
253 		XDestroyWindow (dpy, data->cover);
254 		free (data);
255 	} else
256 		timer_new (10, do_anim_shrink, data);
257 }
258 
desk_anim_slideN(ScreenInfo * scr,Window cover,unsigned int steps)259 void desk_anim_slideN (ScreenInfo * scr, Window cover, unsigned int steps)
260 {
261 	desk_anim_slide (scr, cover, 0, -1, steps);
262 }
263 
desk_anim_slideW(ScreenInfo * scr,Window cover,unsigned int steps)264 void desk_anim_slideW (ScreenInfo * scr, Window cover, unsigned int steps)
265 {
266 	desk_anim_slide (scr, cover, -1, 0, steps);
267 }
268 
desk_anim_slideE(ScreenInfo * scr,Window cover,unsigned int steps)269 void desk_anim_slideE (ScreenInfo * scr, Window cover, unsigned int steps)
270 {
271 	desk_anim_slide (scr, cover, 1, 0, steps);
272 }
273 
desk_anim_slideS(ScreenInfo * scr,Window cover,unsigned int steps)274 void desk_anim_slideS (ScreenInfo * scr, Window cover, unsigned int steps)
275 {
276 	desk_anim_slide (scr, cover, 0, 1, steps);
277 }
278 
desk_anim_slideNW(ScreenInfo * scr,Window cover,unsigned int steps)279 void desk_anim_slideNW (ScreenInfo * scr, Window cover, unsigned int steps)
280 {
281 	desk_anim_slide (scr, cover, -1, -1, steps);
282 }
283 
desk_anim_slideNE(ScreenInfo * scr,Window cover,unsigned int steps)284 void desk_anim_slideNE (ScreenInfo * scr, Window cover, unsigned int steps)
285 {
286 	desk_anim_slide (scr, cover, 1, -1, steps);
287 }
288 
desk_anim_slideSE(ScreenInfo * scr,Window cover,unsigned int steps)289 void desk_anim_slideSE (ScreenInfo * scr, Window cover, unsigned int steps)
290 {
291 	desk_anim_slide (scr, cover, 1, 1, steps);
292 }
293 
desk_anim_slideSW(ScreenInfo * scr,Window cover,unsigned int steps)294 void desk_anim_slideSW (ScreenInfo * scr, Window cover, unsigned int steps)
295 {
296 	desk_anim_slide (scr, cover, -1, 1, steps);
297 }
298 
desk_anim_shrinkN(ScreenInfo * scr,Window cover,unsigned int steps)299 void desk_anim_shrinkN (ScreenInfo * scr, Window cover, unsigned int steps)
300 {
301 	desk_anim_shrink (scr, cover, 0, -1, steps);
302 }
303 
304 void
desk_anim_shrinkNW(ScreenInfo * scr,Window cover,unsigned int steps)305 desk_anim_shrinkNW (ScreenInfo * scr, Window cover, unsigned int steps)
306 {
307 	desk_anim_shrink (scr, cover, -1, -1, steps);
308 }
309 
desk_anim_shrinkW(ScreenInfo * scr,Window cover,unsigned int steps)310 void desk_anim_shrinkW (ScreenInfo * scr, Window cover, unsigned int steps)
311 {
312 	desk_anim_shrink (scr, cover, -1, 0, steps);
313 }
314 
315 
316 /*************************************************************************/
317 /* main interface                                                        */
318 /*************************************************************************/
319 
320 static int _as_desktop_cover_recursion = 0;
321 static Window _as_desktop_cover = None;
322 static GC _as_desktop_cover_gc = NULL;
323 static XFontStruct *_as_desktop_cover_xfs = NULL;
324 static int _as_progress_line = 0;
325 static int _as_progress_cursor = 0;
326 
327 #define ANIMATIONS_NUM	13
328 static void (*DeskAnimations[ANIMATIONS_NUM]) (ScreenInfo *, Window,
329 																							 unsigned int) = {
330 NULL, desk_anim_slideNW, desk_anim_slideN, desk_anim_slideNE,
331 			desk_anim_slideE, desk_anim_slideSE, desk_anim_slideS,
332 			desk_anim_slideSW, desk_anim_slideW, desk_anim_shrinkN,
333 			desk_anim_shrinkNW, desk_anim_shrinkW, desk_anim_shape_blocks};
334 
remove_desktop_cover()335 void remove_desktop_cover ()
336 {
337 
338 	if (_as_desktop_cover) {
339 		--_as_desktop_cover_recursion;
340 		if (_as_desktop_cover_recursion == 0) {
341 			int steps = Scr.Feel.desk_cover_animation_steps;
342 			int type = Scr.Feel.desk_cover_animation_type;
343 
344 			XSync (dpy, False);
345 
346 			if (steps > 0 && type >= 0 && DeskAnimations[type % ANIMATIONS_NUM])
347 				DeskAnimations[type % ANIMATIONS_NUM] (ASDefaultScr,
348 																							 _as_desktop_cover, steps);
349 			else
350 				XDestroyWindow (dpy, _as_desktop_cover);
351 			_as_desktop_cover = None;
352 
353 			_as_progress_line = 0;
354 			_as_progress_cursor = 0;
355 
356 			XSync (dpy, False);
357 		}
358 	}
359 }
360 
get_desktop_cover_window()361 Window get_desktop_cover_window ()
362 {
363 	return _as_desktop_cover;
364 }
365 
restack_desktop_cover()366 void restack_desktop_cover ()
367 {
368 	if (_as_desktop_cover)
369 		XRaiseWindow (dpy, _as_desktop_cover);
370 }
371 
cover_desktop()372 void cover_desktop ()
373 {
374 	XSetWindowAttributes attributes;
375 	unsigned long valuemask;
376 	Window w;
377 	XGCValues gcvalue;
378 
379 	if (get_flags (Scr.Feel.flags, DontCoverDesktop))
380 		return;
381 
382 	++_as_desktop_cover_recursion;
383 
384 	if (_as_desktop_cover != None)
385 		return;
386 
387 	valuemask = (CWBackPixmap | CWBackingStore | CWOverrideRedirect);
388 	attributes.background_pixmap = None;
389 	attributes.backing_store = NotUseful;
390 	attributes.override_redirect = True;
391 
392 	w = create_visual_window (Scr.asv, Scr.Root, 0, 0,
393 														Scr.MyDisplayWidth, Scr.MyDisplayHeight,
394 														0, InputOutput, valuemask, &attributes);
395 
396 	XMapRaised (dpy, w);
397 	XSync (dpy, False);
398 	if (_as_desktop_cover_gc == NULL) {
399 		unsigned long mask =
400 				GCFunction | GCForeground | GCBackground | GCGraphicsExposures;
401 		CARD32 r16, g16, b16;
402 
403 		if (_as_desktop_cover_xfs == NULL)
404 			_as_desktop_cover_xfs = XLoadQueryFont (dpy, "fixed");
405 
406 		if (_as_desktop_cover_xfs) {
407 			gcvalue.font = _as_desktop_cover_xfs->fid;
408 			mask |= GCFont;
409 		}
410 
411 		LOCAL_DEBUG_OUT ("desk_anime_tint = %lX",
412 										 Scr.Look.desktop_animation_tint);
413 		r16 = ARGB32_RED16 (Scr.Look.desktop_animation_tint);
414 		g16 = ARGB32_GREEN16 (Scr.Look.desktop_animation_tint);
415 		b16 = ARGB32_BLUE16 (Scr.Look.desktop_animation_tint);
416 		if (ASCS_BLACK_O_WHITE_CRITERIA16 (r16, g16, b16)) {
417 			gcvalue.foreground = Scr.asv->black_pixel;
418 			gcvalue.background = Scr.asv->white_pixel;
419 		} else {
420 			gcvalue.foreground = Scr.asv->white_pixel;
421 			gcvalue.background = Scr.asv->black_pixel;
422 		}
423 		gcvalue.function = GXcopy;
424 		gcvalue.graphics_exposures = 0;
425 
426 		_as_desktop_cover_gc =
427 				create_visual_gc (Scr.asv, Scr.Root, mask, &gcvalue);
428 	}
429 	if (_as_desktop_cover_gc) {
430 		unsigned long pixel;
431 		ARGB2PIXEL (Scr.asv, Scr.Look.desktop_animation_tint, &pixel);
432 		gcvalue.foreground = pixel;
433 		gcvalue.function = GXand;
434 		XChangeGC (dpy, _as_desktop_cover_gc, GCFunction | GCForeground,
435 							 &gcvalue);
436 		XFillRectangle (dpy, w, _as_desktop_cover_gc, 0, 0, Scr.MyDisplayWidth,
437 										Scr.MyDisplayHeight);
438 		gcvalue.foreground = Scr.asv->white_pixel;
439 		gcvalue.function = GXcopy;
440 		XChangeGC (dpy, _as_desktop_cover_gc, GCFunction | GCForeground,
441 							 &gcvalue);
442 	}
443 	_as_desktop_cover = w;
444 }
445 
desktop_cover_cleanup()446 void desktop_cover_cleanup ()
447 {
448 	if (_as_desktop_cover_gc) {
449 		XFreeGC (dpy, _as_desktop_cover_gc);
450 		_as_desktop_cover_gc = NULL;
451 	}
452 
453 	if (_as_desktop_cover_xfs) {
454 		XFreeFont (dpy, _as_desktop_cover_xfs);
455 		_as_desktop_cover_xfs = NULL;
456 	}
457 
458 	if (_as_desktop_cover) {
459 		XDestroyWindow (dpy, _as_desktop_cover);
460 		_as_desktop_cover = None;
461 	}
462 
463 	_as_desktop_cover_recursion = 0;
464 }
465 
466 static char buffer[8192];
467 
display_progress(Bool new_line,const char * msg_format,...)468 void display_progress (Bool new_line, const char *msg_format, ...)
469 {
470 	if (_as_desktop_cover && _as_desktop_cover_xfs && _as_desktop_cover_gc) {
471 		int x, y;
472 		int height;
473 		int len;
474 
475 		va_list ap;
476 		va_start (ap, msg_format);
477 		vsnprintf (&buffer[0], 256, msg_format, ap);
478 		va_end (ap);
479 
480 		len = strlen (&buffer[0]);
481 		if (_as_progress_cursor > 0 && new_line) {
482 			++_as_progress_line;
483 			_as_progress_cursor = 0;
484 		}
485 		/* and now we need to display the text on the screen */
486 		x = Scr.MyDisplayWidth / 20 + _as_progress_cursor;
487 		height =
488 				_as_desktop_cover_xfs->ascent + _as_desktop_cover_xfs->descent + 5;
489 		y = Scr.MyDisplayHeight / 5 + height * _as_progress_line;
490 		_as_progress_cursor +=
491 				XTextWidth (_as_desktop_cover_xfs, &buffer[0], len) + 10;
492 		XDrawString (dpy, _as_desktop_cover, _as_desktop_cover_gc, x, y,
493 								 &buffer[0], len);
494 		ASSync (False);
495 	}
496 }
497