10bbfda8aSnia/*
20bbfda8aSnia * Animation routines
30bbfda8aSnia */
40bbfda8aSnia
50bbfda8aSnia
60bbfda8aSnia#include "ctwm.h"
70bbfda8aSnia
80bbfda8aSnia#include <sys/time.h>
9b18c2d1eSnia#include <assert.h>
100bbfda8aSnia#include <stdio.h>
110bbfda8aSnia#include <string.h>
120bbfda8aSnia
130bbfda8aSnia#include <X11/extensions/shape.h>
140bbfda8aSnia
150bbfda8aSnia#include "ctwm_atoms.h"
160bbfda8aSnia#include "events.h"
170bbfda8aSnia#include "icons.h"
180bbfda8aSnia#include "image.h"
190bbfda8aSnia#include "screen.h"
200bbfda8aSnia#include "util.h"
210bbfda8aSnia#include "vscreen.h"
220bbfda8aSnia#include "win_utils.h"
230bbfda8aSnia
240bbfda8aSnia#include "animate.h"
250bbfda8aSnia
260bbfda8aSnia
270bbfda8aSnia#define MAXANIMATIONSPEED 20
280bbfda8aSnia
290bbfda8aSnia
300bbfda8aSniaint  Animating        = 0;
310bbfda8aSniaint  AnimationSpeed   = 0;
320bbfda8aSniabool AnimationActive  = false;
330bbfda8aSniabool MaybeAnimate     = true;
340bbfda8aSniastruct timeval AnimateTimeout;
350bbfda8aSnia
360bbfda8aSnia
370bbfda8aSniastatic void Animate(void);
380bbfda8aSniastatic void AnimateButton(TBWindow *tbw);
390bbfda8aSniastatic void AnimateHighlight(TwmWindow *t);
400bbfda8aSniastatic void AnimateIcons(ScreenInfo *scr, Icon *icon);
410bbfda8aSniastatic bool AnimateRoot(void);
420bbfda8aSnia
430bbfda8aSnia
440bbfda8aSnia/*
450bbfda8aSnia * XXX We're directly looking at this for hopefully hysterical raisins.
460bbfda8aSnia * Rexamine the whole tracefile subsystem at some point when we look at
470bbfda8aSnia * debugging.
480bbfda8aSnia *
490bbfda8aSnia * Currently get it via pollution from events.h anyway.
500bbfda8aSnia *
510bbfda8aSnia * extern FILE *tracefile;
520bbfda8aSnia */
530bbfda8aSnia
540bbfda8aSniavoid
550bbfda8aSniaTryToAnimate(void)
560bbfda8aSnia{
570bbfda8aSnia	struct timeval  tp;
580bbfda8aSnia	static unsigned long lastsec;
590bbfda8aSnia	static long lastusec;
600bbfda8aSnia	unsigned long gap;
610bbfda8aSnia
620bbfda8aSnia	if(Animating > 1) {
630bbfda8aSnia		return;        /* rate limiting */
640bbfda8aSnia	}
650bbfda8aSnia
660bbfda8aSnia	gettimeofday(&tp, NULL);
670bbfda8aSnia	gap = ((tp.tv_sec - lastsec) * 1000000) + (tp.tv_usec - lastusec);
680bbfda8aSnia	if(tracefile) {
690bbfda8aSnia		fprintf(tracefile, "Time = %lu, %ld, %ld, %ld, %lu\n", lastsec,
700bbfda8aSnia		        lastusec, (long)tp.tv_sec, (long)tp.tv_usec, gap);
710bbfda8aSnia		fflush(tracefile);
720bbfda8aSnia	}
730bbfda8aSnia	gap *= AnimationSpeed;
740bbfda8aSnia	if(gap < 1000000) {
750bbfda8aSnia		return;
760bbfda8aSnia	}
770bbfda8aSnia	if(tracefile) {
780bbfda8aSnia		fprintf(tracefile, "Animate\n");
790bbfda8aSnia		fflush(tracefile);
800bbfda8aSnia	}
810bbfda8aSnia	Animate();
820bbfda8aSnia	lastsec  = tp.tv_sec;
830bbfda8aSnia	lastusec = tp.tv_usec;
840bbfda8aSnia}
850bbfda8aSnia
860bbfda8aSnia
870bbfda8aSnia
880bbfda8aSniavoid
890bbfda8aSniaStartAnimation(void)
900bbfda8aSnia{
910bbfda8aSnia
920bbfda8aSnia	if(AnimationSpeed > MAXANIMATIONSPEED) {
930bbfda8aSnia		AnimationSpeed = MAXANIMATIONSPEED;
940bbfda8aSnia	}
950bbfda8aSnia	if(AnimationSpeed <= 0) {
960bbfda8aSnia		AnimationSpeed = 0;
970bbfda8aSnia	}
980bbfda8aSnia	if(AnimationActive) {
990bbfda8aSnia		return;
1000bbfda8aSnia	}
1010bbfda8aSnia	switch(AnimationSpeed) {
1020bbfda8aSnia		case 0 :
1030bbfda8aSnia			return;
1040bbfda8aSnia		case 1 :
1050bbfda8aSnia			AnimateTimeout.tv_sec  = 1;
1060bbfda8aSnia			AnimateTimeout.tv_usec = 0;
1070bbfda8aSnia			break;
1080bbfda8aSnia		default :
1090bbfda8aSnia			AnimateTimeout.tv_sec  = 0;
1100bbfda8aSnia			AnimateTimeout.tv_usec = 1000000 / AnimationSpeed;
1110bbfda8aSnia	}
1120bbfda8aSnia	AnimationActive = true;
1130bbfda8aSnia}
1140bbfda8aSnia
1150bbfda8aSnia
1160bbfda8aSniavoid
1170bbfda8aSniaStopAnimation(void)
1180bbfda8aSnia{
1190bbfda8aSnia	AnimationActive = false;
1200bbfda8aSnia}
1210bbfda8aSnia
1220bbfda8aSnia
1230bbfda8aSniavoid
1240bbfda8aSniaSetAnimationSpeed(int speed)
1250bbfda8aSnia{
1260bbfda8aSnia	AnimationSpeed = speed;
1270bbfda8aSnia	if(AnimationSpeed > MAXANIMATIONSPEED) {
1280bbfda8aSnia		AnimationSpeed = MAXANIMATIONSPEED;
1290bbfda8aSnia	}
1300bbfda8aSnia}
1310bbfda8aSnia
1320bbfda8aSnia
1330bbfda8aSniavoid
1340bbfda8aSniaModifyAnimationSpeed(int incr)
1350bbfda8aSnia{
1360bbfda8aSnia	if((AnimationSpeed + incr) < 0) {
1370bbfda8aSnia		return;
1380bbfda8aSnia	}
1390bbfda8aSnia	if((AnimationSpeed + incr) == 0) {
1400bbfda8aSnia		if(AnimationActive) {
1410bbfda8aSnia			StopAnimation();
1420bbfda8aSnia		}
1430bbfda8aSnia		AnimationSpeed = 0;
1440bbfda8aSnia		return;
1450bbfda8aSnia	}
1460bbfda8aSnia	AnimationSpeed += incr;
1470bbfda8aSnia	if(AnimationSpeed > MAXANIMATIONSPEED) {
1480bbfda8aSnia		AnimationSpeed = MAXANIMATIONSPEED;
1490bbfda8aSnia	}
1500bbfda8aSnia
1510bbfda8aSnia	if(AnimationSpeed == 1) {
1520bbfda8aSnia		AnimateTimeout.tv_sec  = 1;
1530bbfda8aSnia		AnimateTimeout.tv_usec = 0;
1540bbfda8aSnia	}
1550bbfda8aSnia	else {
1560bbfda8aSnia		AnimateTimeout.tv_sec  = 0;
1570bbfda8aSnia		AnimateTimeout.tv_usec = 1000000 / AnimationSpeed;
1580bbfda8aSnia	}
1590bbfda8aSnia	AnimationActive = true;
1600bbfda8aSnia}
1610bbfda8aSnia
1620bbfda8aSnia
1630bbfda8aSnia
1640bbfda8aSnia/*
1650bbfda8aSnia * Only called from TryToAnimate
1660bbfda8aSnia */
1670bbfda8aSniastatic void
1680bbfda8aSniaAnimate(void)
1690bbfda8aSnia{
1700bbfda8aSnia	TwmWindow   *t;
1710bbfda8aSnia	int         scrnum;
1720bbfda8aSnia	ScreenInfo  *scr;
1730bbfda8aSnia	int         i;
1740bbfda8aSnia	TBWindow    *tbw;
1750bbfda8aSnia	int         nb;
1760bbfda8aSnia
1770bbfda8aSnia	if(AnimationSpeed == 0) {
1780bbfda8aSnia		return;
1790bbfda8aSnia	}
1800bbfda8aSnia	if(Animating > 1) {
1810bbfda8aSnia		return;        /* rate limiting */
1820bbfda8aSnia	}
1830bbfda8aSnia
1840bbfda8aSnia	/* Impossible? */
1850bbfda8aSnia	if(NumScreens < 1) {
1860bbfda8aSnia		return;
1870bbfda8aSnia	}
1880bbfda8aSnia
1890bbfda8aSnia	MaybeAnimate = false;
1900bbfda8aSnia	scr = NULL;
1910bbfda8aSnia	for(scrnum = 0; scrnum < NumScreens; scrnum++) {
1920bbfda8aSnia		if((scr = ScreenList [scrnum]) == NULL) {
1930bbfda8aSnia			continue;
1940bbfda8aSnia		}
1950bbfda8aSnia
1960bbfda8aSnia		for(t = scr->FirstWindow; t != NULL; t = t->next) {
1970bbfda8aSnia			if(! visible(t)) {
1980bbfda8aSnia				continue;
1990bbfda8aSnia			}
2000bbfda8aSnia			if(t->icon_on && t->icon && t->icon->bm_w && t->icon->image &&
2010bbfda8aSnia			                t->icon->image->next) {
2020bbfda8aSnia				AnimateIcons(scr, t->icon);
2030bbfda8aSnia				MaybeAnimate = true;
2040bbfda8aSnia			}
2050bbfda8aSnia			else if(t->mapped && t->titlebuttons) {
2060bbfda8aSnia				nb = scr->TBInfo.nleft + scr->TBInfo.nright;
2070bbfda8aSnia				for(i = 0, tbw = t->titlebuttons; i < nb; i++, tbw++) {
2080bbfda8aSnia					if(tbw->image && tbw->image->next) {
2090bbfda8aSnia						AnimateButton(tbw);
2100bbfda8aSnia						MaybeAnimate = true;
2110bbfda8aSnia					}
2120bbfda8aSnia				}
2130bbfda8aSnia			}
2140bbfda8aSnia		}
2150bbfda8aSnia		if(scr->Focus) {
2160bbfda8aSnia			t = scr->Focus;
2170bbfda8aSnia			if(t->mapped && t->titlehighlight && t->title_height &&
2180bbfda8aSnia			                t->HiliteImage && t->HiliteImage->next) {
2190bbfda8aSnia				AnimateHighlight(t);
2200bbfda8aSnia				MaybeAnimate = true;
2210bbfda8aSnia			}
2220bbfda8aSnia		}
2230bbfda8aSnia	}
2240bbfda8aSnia	MaybeAnimate |= AnimateRoot();
2250bbfda8aSnia	if(MaybeAnimate) {
226b18c2d1eSnia		// Impossible: scr==NULL means we had no valid screens, which
227b18c2d1eSnia		// means we'd'a bomed out WAY earlier than trying to animate
228b18c2d1eSnia		// something...
229b18c2d1eSnia		assert(scr != NULL);
2300bbfda8aSnia		Animating++;
2310bbfda8aSnia		send_clientmessage(scr->currentvs->wsw->w, XA_WM_END_OF_ANIMATION,
2320bbfda8aSnia		                   EventTime);
2330bbfda8aSnia	}
2340bbfda8aSnia	XFlush(dpy);
2350bbfda8aSnia	return;
2360bbfda8aSnia}
2370bbfda8aSnia
2380bbfda8aSnia
2390bbfda8aSnia/* Originally in add_window.c */
2400bbfda8aSniastatic void
2410bbfda8aSniaAnimateButton(TBWindow *tbw)
2420bbfda8aSnia{
2430bbfda8aSnia	Image       *image;
2440bbfda8aSnia	XSetWindowAttributes attr;
2450bbfda8aSnia
2460bbfda8aSnia	image = tbw->image;
2470bbfda8aSnia	attr.background_pixmap = image->pixmap;
2480bbfda8aSnia	XChangeWindowAttributes(dpy, tbw->window, CWBackPixmap, &attr);
2490bbfda8aSnia	XClearWindow(dpy, tbw->window);
2500bbfda8aSnia	tbw->image = image->next;
2510bbfda8aSnia}
2520bbfda8aSnia
2530bbfda8aSnia/* Originally in add_window.c */
2540bbfda8aSniastatic void
2550bbfda8aSniaAnimateHighlight(TwmWindow *t)
2560bbfda8aSnia{
2570bbfda8aSnia	Image       *image;
2580bbfda8aSnia	XSetWindowAttributes attr;
2590bbfda8aSnia
2600bbfda8aSnia	image = t->HiliteImage;
2610bbfda8aSnia	attr.background_pixmap = image->pixmap;
2620bbfda8aSnia	if(t->hilite_wl) {
2630bbfda8aSnia		XChangeWindowAttributes(dpy, t->hilite_wl, CWBackPixmap, &attr);
2640bbfda8aSnia		XClearWindow(dpy, t->hilite_wl);
2650bbfda8aSnia	}
2660bbfda8aSnia	if(t->hilite_wr) {
2670bbfda8aSnia		XChangeWindowAttributes(dpy, t->hilite_wr, CWBackPixmap, &attr);
2680bbfda8aSnia		XClearWindow(dpy, t->hilite_wr);
2690bbfda8aSnia	}
2700bbfda8aSnia	t->HiliteImage = image->next;
2710bbfda8aSnia}
2720bbfda8aSnia
2730bbfda8aSnia
2740bbfda8aSnia/* Originally in icons.c */
2750bbfda8aSniastatic void
2760bbfda8aSniaAnimateIcons(ScreenInfo *scr, Icon *icon)
2770bbfda8aSnia{
2780bbfda8aSnia	Image       *image;
2790bbfda8aSnia	XRectangle  rect;
2800bbfda8aSnia	XSetWindowAttributes attr;
2810bbfda8aSnia	int         x;
2820bbfda8aSnia
2830bbfda8aSnia	image = icon->image;
2840bbfda8aSnia	attr.background_pixmap = image->pixmap;
2850bbfda8aSnia	XChangeWindowAttributes(dpy, icon->bm_w, CWBackPixmap, &attr);
2860bbfda8aSnia
2870bbfda8aSnia	if(image->mask != None) {
2880bbfda8aSnia		x = GetIconOffset(icon);
2890bbfda8aSnia		XShapeCombineMask(dpy, icon->bm_w, ShapeBounding, 0, 0, image->mask, ShapeSet);
2900bbfda8aSnia		if(icon->has_title) {
2910bbfda8aSnia			rect.x      = 0;
2920bbfda8aSnia			rect.y      = icon->height;
2930bbfda8aSnia			rect.width  = icon->w_width;
2940bbfda8aSnia			rect.height = scr->IconFont.height + 6;
2950bbfda8aSnia
2960bbfda8aSnia			XShapeCombineShape(dpy, scr->ShapeWindow, ShapeBounding, x, 0, icon->bm_w,
2970bbfda8aSnia			                   ShapeBounding, ShapeSet);
2980bbfda8aSnia			XShapeCombineRectangles(dpy, scr->ShapeWindow, ShapeBounding, 0, 0, &rect, 1,
2990bbfda8aSnia			                        ShapeUnion, 0);
3000bbfda8aSnia			XShapeCombineShape(dpy, icon->w, ShapeBounding, 0, 0, scr->ShapeWindow,
3010bbfda8aSnia			                   ShapeBounding, ShapeSet);
3020bbfda8aSnia		}
3030bbfda8aSnia		else
3040bbfda8aSnia			XShapeCombineShape(dpy, icon->w, ShapeBounding, x, 0, icon->bm_w,
3050bbfda8aSnia			                   ShapeBounding, ShapeSet);
3060bbfda8aSnia	}
3070bbfda8aSnia	XClearWindow(dpy, icon->bm_w);
3080bbfda8aSnia	icon->image  = image->next;
3090bbfda8aSnia	return;
3100bbfda8aSnia}
3110bbfda8aSnia
3120bbfda8aSnia
3130bbfda8aSnia/* Original in workmgr.c */
3140bbfda8aSniastatic bool
3150bbfda8aSniaAnimateRoot(void)
3160bbfda8aSnia{
3170bbfda8aSnia	VirtualScreen *vs;
3180bbfda8aSnia	ScreenInfo *scr;
3190bbfda8aSnia	int        scrnum;
3200bbfda8aSnia	Image      *image;
3210bbfda8aSnia	WorkSpace  *ws;
3220bbfda8aSnia	bool       maybeanimate;
3230bbfda8aSnia
3240bbfda8aSnia	maybeanimate = false;
3250bbfda8aSnia	for(scrnum = 0; scrnum < NumScreens; scrnum++) {
3260bbfda8aSnia		if((scr = ScreenList [scrnum]) == NULL) {
3270bbfda8aSnia			continue;
3280bbfda8aSnia		}
3290bbfda8aSnia		if(! scr->workSpaceManagerActive) {
3300bbfda8aSnia			continue;
3310bbfda8aSnia		}
3320bbfda8aSnia
3330bbfda8aSnia		for(vs = scr->vScreenList; vs != NULL; vs = vs->next) {
3340bbfda8aSnia			if(! vs->wsw->currentwspc) {
3350bbfda8aSnia				continue;
3360bbfda8aSnia			}
3370bbfda8aSnia			image = vs->wsw->currentwspc->image;
3380bbfda8aSnia			if((image == NULL) || (image->next == NULL)) {
3390bbfda8aSnia				continue;
3400bbfda8aSnia			}
3410bbfda8aSnia			if(scr->DontPaintRootWindow) {
3420bbfda8aSnia				continue;
3430bbfda8aSnia			}
3440bbfda8aSnia
3450bbfda8aSnia			XSetWindowBackgroundPixmap(dpy, vs->window, image->pixmap);
3460bbfda8aSnia			XClearWindow(dpy, scr->Root);
3470bbfda8aSnia			vs->wsw->currentwspc->image = image->next;
3480bbfda8aSnia			maybeanimate = true;
3490bbfda8aSnia		}
3500bbfda8aSnia	}
3510bbfda8aSnia	for(scrnum = 0; scrnum < NumScreens; scrnum++) {
3520bbfda8aSnia		if((scr = ScreenList [scrnum]) == NULL) {
3530bbfda8aSnia			continue;
3540bbfda8aSnia		}
3550bbfda8aSnia
3560bbfda8aSnia		for(vs = scr->vScreenList; vs != NULL; vs = vs->next) {
3570bbfda8aSnia			if(vs->wsw->state == WMS_buttons) {
3580bbfda8aSnia				continue;
3590bbfda8aSnia			}
3600bbfda8aSnia			for(ws = scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
3610bbfda8aSnia				image = ws->image;
3620bbfda8aSnia
3630bbfda8aSnia				if((image == NULL) || (image->next == NULL)) {
3640bbfda8aSnia					continue;
3650bbfda8aSnia				}
3660bbfda8aSnia				if(ws == vs->wsw->currentwspc) {
3670bbfda8aSnia					continue;
3680bbfda8aSnia				}
3690bbfda8aSnia				XSetWindowBackgroundPixmap(dpy, vs->wsw->mswl [ws->number]->w, image->pixmap);
3700bbfda8aSnia				XClearWindow(dpy, vs->wsw->mswl [ws->number]->w);
3710bbfda8aSnia				ws->image = image->next;
3720bbfda8aSnia				maybeanimate = true;
3730bbfda8aSnia			}
3740bbfda8aSnia		}
3750bbfda8aSnia	}
3760bbfda8aSnia	return maybeanimate;
3770bbfda8aSnia}
378