1/* 2 * Animation routines 3 */ 4 5 6#include "ctwm.h" 7 8#include <sys/time.h> 9#include <assert.h> 10#include <stdio.h> 11#include <string.h> 12 13#include <X11/extensions/shape.h> 14 15#include "ctwm_atoms.h" 16#include "events.h" 17#include "icons.h" 18#include "image.h" 19#include "screen.h" 20#include "util.h" 21#include "vscreen.h" 22#include "win_utils.h" 23 24#include "animate.h" 25 26 27#define MAXANIMATIONSPEED 20 28 29 30int Animating = 0; 31int AnimationSpeed = 0; 32bool AnimationActive = false; 33bool MaybeAnimate = true; 34struct timeval AnimateTimeout; 35 36 37static void Animate(void); 38static void AnimateButton(TBWindow *tbw); 39static void AnimateHighlight(TwmWindow *t); 40static void AnimateIcons(ScreenInfo *scr, Icon *icon); 41static bool AnimateRoot(void); 42 43 44/* 45 * XXX We're directly looking at this for hopefully hysterical raisins. 46 * Rexamine the whole tracefile subsystem at some point when we look at 47 * debugging. 48 * 49 * Currently get it via pollution from events.h anyway. 50 * 51 * extern FILE *tracefile; 52 */ 53 54void 55TryToAnimate(void) 56{ 57 struct timeval tp; 58 static unsigned long lastsec; 59 static long lastusec; 60 unsigned long gap; 61 62 if(Animating > 1) { 63 return; /* rate limiting */ 64 } 65 66 gettimeofday(&tp, NULL); 67 gap = ((tp.tv_sec - lastsec) * 1000000) + (tp.tv_usec - lastusec); 68 if(tracefile) { 69 fprintf(tracefile, "Time = %lu, %ld, %ld, %ld, %lu\n", lastsec, 70 lastusec, (long)tp.tv_sec, (long)tp.tv_usec, gap); 71 fflush(tracefile); 72 } 73 gap *= AnimationSpeed; 74 if(gap < 1000000) { 75 return; 76 } 77 if(tracefile) { 78 fprintf(tracefile, "Animate\n"); 79 fflush(tracefile); 80 } 81 Animate(); 82 lastsec = tp.tv_sec; 83 lastusec = tp.tv_usec; 84} 85 86 87 88void 89StartAnimation(void) 90{ 91 92 if(AnimationSpeed > MAXANIMATIONSPEED) { 93 AnimationSpeed = MAXANIMATIONSPEED; 94 } 95 if(AnimationSpeed <= 0) { 96 AnimationSpeed = 0; 97 } 98 if(AnimationActive) { 99 return; 100 } 101 switch(AnimationSpeed) { 102 case 0 : 103 return; 104 case 1 : 105 AnimateTimeout.tv_sec = 1; 106 AnimateTimeout.tv_usec = 0; 107 break; 108 default : 109 AnimateTimeout.tv_sec = 0; 110 AnimateTimeout.tv_usec = 1000000 / AnimationSpeed; 111 } 112 AnimationActive = true; 113} 114 115 116void 117StopAnimation(void) 118{ 119 AnimationActive = false; 120} 121 122 123void 124SetAnimationSpeed(int speed) 125{ 126 AnimationSpeed = speed; 127 if(AnimationSpeed > MAXANIMATIONSPEED) { 128 AnimationSpeed = MAXANIMATIONSPEED; 129 } 130} 131 132 133void 134ModifyAnimationSpeed(int incr) 135{ 136 if((AnimationSpeed + incr) < 0) { 137 return; 138 } 139 if((AnimationSpeed + incr) == 0) { 140 if(AnimationActive) { 141 StopAnimation(); 142 } 143 AnimationSpeed = 0; 144 return; 145 } 146 AnimationSpeed += incr; 147 if(AnimationSpeed > MAXANIMATIONSPEED) { 148 AnimationSpeed = MAXANIMATIONSPEED; 149 } 150 151 if(AnimationSpeed == 1) { 152 AnimateTimeout.tv_sec = 1; 153 AnimateTimeout.tv_usec = 0; 154 } 155 else { 156 AnimateTimeout.tv_sec = 0; 157 AnimateTimeout.tv_usec = 1000000 / AnimationSpeed; 158 } 159 AnimationActive = true; 160} 161 162 163 164/* 165 * Only called from TryToAnimate 166 */ 167static void 168Animate(void) 169{ 170 TwmWindow *t; 171 int scrnum; 172 ScreenInfo *scr; 173 int i; 174 TBWindow *tbw; 175 int nb; 176 177 if(AnimationSpeed == 0) { 178 return; 179 } 180 if(Animating > 1) { 181 return; /* rate limiting */ 182 } 183 184 /* Impossible? */ 185 if(NumScreens < 1) { 186 return; 187 } 188 189 MaybeAnimate = false; 190 scr = NULL; 191 for(scrnum = 0; scrnum < NumScreens; scrnum++) { 192 if((scr = ScreenList [scrnum]) == NULL) { 193 continue; 194 } 195 196 for(t = scr->FirstWindow; t != NULL; t = t->next) { 197 if(! visible(t)) { 198 continue; 199 } 200 if(t->icon_on && t->icon && t->icon->bm_w && t->icon->image && 201 t->icon->image->next) { 202 AnimateIcons(scr, t->icon); 203 MaybeAnimate = true; 204 } 205 else if(t->mapped && t->titlebuttons) { 206 nb = scr->TBInfo.nleft + scr->TBInfo.nright; 207 for(i = 0, tbw = t->titlebuttons; i < nb; i++, tbw++) { 208 if(tbw->image && tbw->image->next) { 209 AnimateButton(tbw); 210 MaybeAnimate = true; 211 } 212 } 213 } 214 } 215 if(scr->Focus) { 216 t = scr->Focus; 217 if(t->mapped && t->titlehighlight && t->title_height && 218 t->HiliteImage && t->HiliteImage->next) { 219 AnimateHighlight(t); 220 MaybeAnimate = true; 221 } 222 } 223 } 224 MaybeAnimate |= AnimateRoot(); 225 if(MaybeAnimate) { 226 // Impossible: scr==NULL means we had no valid screens, which 227 // means we'd'a bomed out WAY earlier than trying to animate 228 // something... 229 assert(scr != NULL); 230 Animating++; 231 send_clientmessage(scr->currentvs->wsw->w, XA_WM_END_OF_ANIMATION, 232 EventTime); 233 } 234 XFlush(dpy); 235 return; 236} 237 238 239/* Originally in add_window.c */ 240static void 241AnimateButton(TBWindow *tbw) 242{ 243 Image *image; 244 XSetWindowAttributes attr; 245 246 image = tbw->image; 247 attr.background_pixmap = image->pixmap; 248 XChangeWindowAttributes(dpy, tbw->window, CWBackPixmap, &attr); 249 XClearWindow(dpy, tbw->window); 250 tbw->image = image->next; 251} 252 253/* Originally in add_window.c */ 254static void 255AnimateHighlight(TwmWindow *t) 256{ 257 Image *image; 258 XSetWindowAttributes attr; 259 260 image = t->HiliteImage; 261 attr.background_pixmap = image->pixmap; 262 if(t->hilite_wl) { 263 XChangeWindowAttributes(dpy, t->hilite_wl, CWBackPixmap, &attr); 264 XClearWindow(dpy, t->hilite_wl); 265 } 266 if(t->hilite_wr) { 267 XChangeWindowAttributes(dpy, t->hilite_wr, CWBackPixmap, &attr); 268 XClearWindow(dpy, t->hilite_wr); 269 } 270 t->HiliteImage = image->next; 271} 272 273 274/* Originally in icons.c */ 275static void 276AnimateIcons(ScreenInfo *scr, Icon *icon) 277{ 278 Image *image; 279 XRectangle rect; 280 XSetWindowAttributes attr; 281 int x; 282 283 image = icon->image; 284 attr.background_pixmap = image->pixmap; 285 XChangeWindowAttributes(dpy, icon->bm_w, CWBackPixmap, &attr); 286 287 if(image->mask != None) { 288 x = GetIconOffset(icon); 289 XShapeCombineMask(dpy, icon->bm_w, ShapeBounding, 0, 0, image->mask, ShapeSet); 290 if(icon->has_title) { 291 rect.x = 0; 292 rect.y = icon->height; 293 rect.width = icon->w_width; 294 rect.height = scr->IconFont.height + 6; 295 296 XShapeCombineShape(dpy, scr->ShapeWindow, ShapeBounding, x, 0, icon->bm_w, 297 ShapeBounding, ShapeSet); 298 XShapeCombineRectangles(dpy, scr->ShapeWindow, ShapeBounding, 0, 0, &rect, 1, 299 ShapeUnion, 0); 300 XShapeCombineShape(dpy, icon->w, ShapeBounding, 0, 0, scr->ShapeWindow, 301 ShapeBounding, ShapeSet); 302 } 303 else 304 XShapeCombineShape(dpy, icon->w, ShapeBounding, x, 0, icon->bm_w, 305 ShapeBounding, ShapeSet); 306 } 307 XClearWindow(dpy, icon->bm_w); 308 icon->image = image->next; 309 return; 310} 311 312 313/* Original in workmgr.c */ 314static bool 315AnimateRoot(void) 316{ 317 VirtualScreen *vs; 318 ScreenInfo *scr; 319 int scrnum; 320 Image *image; 321 WorkSpace *ws; 322 bool maybeanimate; 323 324 maybeanimate = false; 325 for(scrnum = 0; scrnum < NumScreens; scrnum++) { 326 if((scr = ScreenList [scrnum]) == NULL) { 327 continue; 328 } 329 if(! scr->workSpaceManagerActive) { 330 continue; 331 } 332 333 for(vs = scr->vScreenList; vs != NULL; vs = vs->next) { 334 if(! vs->wsw->currentwspc) { 335 continue; 336 } 337 image = vs->wsw->currentwspc->image; 338 if((image == NULL) || (image->next == NULL)) { 339 continue; 340 } 341 if(scr->DontPaintRootWindow) { 342 continue; 343 } 344 345 XSetWindowBackgroundPixmap(dpy, vs->window, image->pixmap); 346 XClearWindow(dpy, scr->Root); 347 vs->wsw->currentwspc->image = image->next; 348 maybeanimate = true; 349 } 350 } 351 for(scrnum = 0; scrnum < NumScreens; scrnum++) { 352 if((scr = ScreenList [scrnum]) == NULL) { 353 continue; 354 } 355 356 for(vs = scr->vScreenList; vs != NULL; vs = vs->next) { 357 if(vs->wsw->state == WMS_buttons) { 358 continue; 359 } 360 for(ws = scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 361 image = ws->image; 362 363 if((image == NULL) || (image->next == NULL)) { 364 continue; 365 } 366 if(ws == vs->wsw->currentwspc) { 367 continue; 368 } 369 XSetWindowBackgroundPixmap(dpy, vs->wsw->mswl [ws->number]->w, image->pixmap); 370 XClearWindow(dpy, vs->wsw->mswl [ws->number]->w); 371 ws->image = image->next; 372 maybeanimate = true; 373 } 374 } 375 } 376 return maybeanimate; 377} 378