1 /**
2 * Animation plugin for compiz/beryl
3 *
4 * animation.c
5 *
6 * Copyright : (C) 2006 Erkin Bahceci
7 * E-mail : erkinbah@gmail.com
8 *
9 * Based on Wobbly and Minimize plugins by
10 * : David Reveman
11 * E-mail : davidr@novell.com>
12 *
13 * Airplane added by : Carlo Palma
14 * E-mail : carlopalma@salug.it
15 * Based on code originally written by Mark J. Kilgard
16 *
17 * Beam-Up added by : Florencio Guimaraes
18 * E-mail : florencio@nexcorp.com.br
19 *
20 * Fold and Skewer added by : Tomasz Kolodziejski
21 * E-mail : tkolodziejski@gmail.com
22 *
23 * Hexagon tessellator added by : Mike Slegeir
24 * E-mail : mikeslegeir@mail.utexas.edu>
25 *
26 * Particle system added by : (C) 2006 Dennis Kasprzyk
27 * E-mail : onestone@beryl-project.org
28 *
29 * This program is free software; you can redistribute it and/or
30 * modify it under the terms of the GNU General Public License
31 * as published by the Free Software Foundation; either version 2
32 * of the License, or (at your option) any later version.
33 *
34 * This program is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 * GNU General Public License for more details.
38 *
39 * You should have received a copy of the GNU General Public License
40 * along with this program; if not, write to the Free Software
41 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
42 **/
43
44 /*
45 * TODO:
46 *
47 * - Custom bounding box update function for Airplane
48 *
49 * - Auto direction option: Close in opposite direction of opening
50 * - Proper side surface normals for lighting
51 * - decoration shadows
52 * - shadow quad generation
53 * - shadow texture coords (from clip tex. matrices)
54 * - draw shadows
55 * - fade in shadows
56 *
57 * - Voronoi tessellation
58 * - Brick tessellation
59 * - Triangle tessellation
60 * - Hexagonal tessellation
61 *
62 * Effects:
63 * - Circular action for tornado type fx
64 * - Tornado 3D (especially for minimize)
65 * - Helix 3D (hor. strips descend while they rotate and fade in)
66 * - Glass breaking 3D
67 * - Gaussian distr. points (for gradually increasing polygon size
68 * starting from center or near mouse pointer)
69 * - Drawing cracks
70 * - Gradual cracking
71 *
72 * - fix slowness during transparent cube with <100 opacity
73 * - fix occasional wrong side color in some windows
74 * - fix on top windows and panels
75 * (These two only matter for viewing during Rotate Cube.
76 * All windows should be painted with depth test on
77 * like 3d-plugin does)
78 * - play better with rotate (fix cube face drawn on top of polygons
79 * after 45 deg. rotation)
80 *
81 */
82
83 #include <GL/glu.h>
84 #include "animation-internal.h"
85
86
87 #define EXTENSION_INCREMENT 4
88
89 #define FAKE_ICON_SIZE 4
90
91 int animDisplayPrivateIndex;
92 int animFunctionsPrivateIndex;
93 CompMetadata animMetadata;
94
95 static int switcherPostWait = 0;
96
97
98 char *eventNames[AnimEventNum] =
99 {"Open", "Close", "Minimize", "Shade", "Focus"};
100
101 int chosenEffectOptionIds[AnimEventNum] =
102 {
103 ANIM_SCREEN_OPTION_OPEN_EFFECTS,
104 ANIM_SCREEN_OPTION_CLOSE_EFFECTS,
105 ANIM_SCREEN_OPTION_MINIMIZE_EFFECTS,
106 ANIM_SCREEN_OPTION_SHADE_EFFECTS,
107 ANIM_SCREEN_OPTION_FOCUS_EFFECTS
108 };
109
110 int randomEffectOptionIds[AnimEventNum] =
111 {
112 ANIM_SCREEN_OPTION_OPEN_RANDOM_EFFECTS,
113 ANIM_SCREEN_OPTION_CLOSE_RANDOM_EFFECTS,
114 ANIM_SCREEN_OPTION_MINIMIZE_RANDOM_EFFECTS,
115 ANIM_SCREEN_OPTION_SHADE_RANDOM_EFFECTS,
116 -1
117 };
118
119 int customOptionOptionIds[AnimEventNum] =
120 {
121 ANIM_SCREEN_OPTION_OPEN_OPTIONS,
122 ANIM_SCREEN_OPTION_CLOSE_OPTIONS,
123 ANIM_SCREEN_OPTION_MINIMIZE_OPTIONS,
124 ANIM_SCREEN_OPTION_SHADE_OPTIONS,
125 ANIM_SCREEN_OPTION_FOCUS_OPTIONS
126 };
127
128 int matchOptionIds[AnimEventNum] =
129 {
130 ANIM_SCREEN_OPTION_OPEN_MATCHES,
131 ANIM_SCREEN_OPTION_CLOSE_MATCHES,
132 ANIM_SCREEN_OPTION_MINIMIZE_MATCHES,
133 ANIM_SCREEN_OPTION_SHADE_MATCHES,
134 ANIM_SCREEN_OPTION_FOCUS_MATCHES
135 };
136
137 int durationOptionIds[AnimEventNum] =
138 {
139 ANIM_SCREEN_OPTION_OPEN_DURATIONS,
140 ANIM_SCREEN_OPTION_CLOSE_DURATIONS,
141 ANIM_SCREEN_OPTION_MINIMIZE_DURATIONS,
142 ANIM_SCREEN_OPTION_SHADE_DURATIONS,
143 ANIM_SCREEN_OPTION_FOCUS_DURATIONS
144 };
145
146
147 // Bind each effect in the list of chosen effects for every event, to the
148 // corresponding animation effect (i.e. effect with that name) if it is
149 // provided by a plugin, otherwise set it to None.
150 static void
updateEventEffects(CompScreen * s,AnimEvent e,Bool forRandom)151 updateEventEffects (CompScreen *s,
152 AnimEvent e,
153 Bool forRandom)
154 {
155 ANIM_SCREEN (s);
156
157 CompListValue *listVal;
158 EffectSet *effectSet;
159 if (forRandom)
160 {
161 listVal = &as->opt[randomEffectOptionIds[e]].value.list;
162 effectSet = &as->randomEffects[e];
163 }
164 else
165 {
166 listVal = &as->opt[chosenEffectOptionIds[e]].value.list;
167 effectSet = &as->eventEffects[e];
168 }
169 int n = listVal->nValue;
170
171 if (effectSet->effects)
172 free (effectSet->effects);
173 effectSet->effects = calloc (n, sizeof (AnimEffect));
174 if (!effectSet->effects)
175 {
176 compLogMessage ("animation", CompLogLevelError,
177 "Not enough memory");
178 return;
179 }
180 effectSet->n = n;
181
182 int nEventEffectsAllowed = as->nEventEffectsAllowed[e];
183 const AnimEffect *eventEffectsAllowed = as->eventEffectsAllowed[e];
184
185 int r;
186 for (r = 0; r < n; r++) // for each row
187 {
188 const char *animName = listVal->value[r].s;
189
190 // Find the animation effect with matching name
191 effectSet->effects[r] = AnimEffectNone;
192 int i;
193 for (i = 0; i < nEventEffectsAllowed; i++)
194 {
195 if (0 == strcasecmp (animName, eventEffectsAllowed[i]->name))
196 {
197 effectSet->effects[r] = eventEffectsAllowed[i];
198 break;
199 }
200 }
201 }
202 }
203
204 static void
updateAllEventEffects(CompScreen * s)205 updateAllEventEffects (CompScreen *s)
206 {
207 AnimEvent e;
208 for (e = 0; e < AnimEventNum; e++) // for each anim event
209 updateEventEffects (s, e, FALSE);
210 for (e = 0; e < AnimEventNum - 1; e++) // for each anim event except focus
211 updateEventEffects (s, e, TRUE);
212 }
213
214 // Free everything related to effects
215 static void
freeAllEffects(AnimScreen * as)216 freeAllEffects (AnimScreen *as)
217 {
218 AnimEvent e;
219 for (e = 0; e < AnimEventNum; e++)
220 {
221 if (as->randomEffects[e].effects)
222 free (as->randomEffects[e].effects);
223 if (as->eventEffectsAllowed[e])
224 free (as->eventEffectsAllowed[e]);
225 if (as->eventEffects[e].n > 0 && as->eventEffects[e].effects)
226 free (as->eventEffects[e].effects);
227 }
228 }
229
230 // Extension functions
231
232 static void
animAddExtension(CompScreen * s,ExtensionPluginInfo * extensionPluginInfo)233 animAddExtension (CompScreen *s,
234 ExtensionPluginInfo *extensionPluginInfo)
235 {
236 ANIM_SCREEN (s);
237
238 // Make sure there is enough space for extension plugins
239 if (as->nExtensionPlugins == as->maxExtensionPlugins)
240 {
241 ExtensionPluginInfo **newExtensionPlugins =
242 realloc (as->extensionPlugins,
243 (as->maxExtensionPlugins + EXTENSION_INCREMENT) *
244 sizeof (ExtensionPluginInfo *));
245 if (!newExtensionPlugins)
246 {
247 compLogMessage ("animation", CompLogLevelError,
248 "Not enough memory");
249 return;
250 }
251 as->extensionPlugins = newExtensionPlugins;
252 as->maxExtensionPlugins += EXTENSION_INCREMENT;
253 }
254
255 as->extensionPlugins[as->nExtensionPlugins] = extensionPluginInfo;
256 as->nExtensionPlugins++;
257
258 unsigned int nPluginEffects = extensionPluginInfo->nEffects;
259
260 // Make sure there is enough space for event effects
261 AnimEvent e;
262 for (e = 0; e < AnimEventNum; e++) // for each anim event
263 {
264 if (as->maxEventEffectsAllowed[e] <
265 as->nEventEffectsAllowed[e] + nPluginEffects)
266 {
267 int newNum = as->nEventEffectsAllowed[e] + nPluginEffects;
268 AnimEffect *newEventEfffects =
269 realloc (as->eventEffectsAllowed[e],
270 newNum * sizeof (AnimEffect));
271 if (!newEventEfffects)
272 {
273 compLogMessage ("animation", CompLogLevelError,
274 "Not enough memory");
275 return;
276 }
277 as->eventEffectsAllowed[e] = newEventEfffects;
278 as->maxEventEffectsAllowed[e] = newNum;
279 }
280 }
281
282 Bool eventEffectsNeedUpdate[AnimEventNum] =
283 {FALSE, FALSE, FALSE, FALSE, FALSE};
284
285 // Put this plugin's effects into as->eventEffects and
286 // as->eventEffectsAllowed
287 int j;
288 for (j = 0; j < nPluginEffects; j++)
289 {
290 const AnimEffect effect = extensionPluginInfo->effects[j];
291
292 // Update allowed effects for each event
293 for (e = 0; e < AnimEventNum; e++)
294 {
295 if (effect->usedForEvents[e])
296 {
297 as->eventEffectsAllowed[e][as->nEventEffectsAllowed[e]++] =
298 effect;
299 eventEffectsNeedUpdate[e] = TRUE;
300 }
301 }
302 }
303 for (e = 0; e < AnimEventNum; e++)
304 if (eventEffectsNeedUpdate[e])
305 {
306 updateEventEffects (s, e, FALSE);
307 if (e != AnimEventFocus)
308 updateEventEffects (s, e, TRUE);
309 }
310 }
311
312 static void
animRemoveExtension(CompScreen * s,ExtensionPluginInfo * extensionPluginInfo)313 animRemoveExtension (CompScreen *s,
314 ExtensionPluginInfo *extensionPluginInfo)
315 {
316 ANIM_SCREEN (s);
317 char *pluginName = NULL;
318 int pluginNameLen = 0;
319
320 if (extensionPluginInfo->nEffects > 0)
321 {
322 pluginName = extensionPluginInfo->effects[0]->name;
323 pluginNameLen = strchr (pluginName, ':') - pluginName;
324 }
325
326 // Stop all ongoing animations
327 CompWindow *w;
328 for (w = s->windows; w; w = w->next)
329 {
330 ANIM_WINDOW (w);
331 if (aw->com.curAnimEffect != AnimEffectNone)
332 postAnimationCleanup (w);
333 }
334
335 int p;
336 for (p = 0; p < as->nExtensionPlugins; p++)
337 {
338 // Find the matching one
339 if (as->extensionPlugins[p] == extensionPluginInfo)
340 break;
341 }
342 if (p == as->nExtensionPlugins)
343 return; // couldn't find that extension plugin
344
345 // Remove extensionPlugins[p] (shift following plugins)
346 as->nExtensionPlugins--;
347 if (as->nExtensionPlugins > 0)
348 memmove (&as->extensionPlugins[p],
349 &as->extensionPlugins[p + 1],
350 (as->nExtensionPlugins - p) *
351 sizeof (ExtensionPluginInfo *));
352
353 AnimEvent e;
354 for (e = 0; e < AnimEventNum; e++)
355 {
356 AnimEffect *eventEffectsAllowed = as->eventEffectsAllowed[e];
357 int n = as->nEventEffectsAllowed[e];
358
359 // nUpto: number of event effects upto the removed plugin
360 int nUpto;
361 for (nUpto = 0; nUpto < n; nUpto++)
362 {
363 // if plugin name matches
364 if (0 == strncmp (pluginName, eventEffectsAllowed[nUpto]->name,
365 pluginNameLen))
366 break;
367 }
368 // nUptoNext: number of event effects upto the next plugin
369 int nUptoNext;
370 for (nUptoNext = nUpto; nUptoNext < n; nUptoNext++)
371 {
372 // if plugin name doesn't match
373 if (0 != strncmp (pluginName, eventEffectsAllowed[nUpto]->name,
374 pluginNameLen))
375 break;
376 }
377 if (nUpto < nUptoNext)
378 {
379 // Remove event effects for plugin p (Shift following effects)
380 if (nUptoNext < n)
381 memmove (&eventEffectsAllowed[nUpto],
382 &eventEffectsAllowed[nUptoNext],
383 (nUptoNext - nUpto) * sizeof (AnimEffect));
384 as->nEventEffectsAllowed[e] -= nUptoNext - nUpto;
385
386 // Update event effects to complete removal
387 updateEventEffects (s, e, FALSE);
388 if (e != AnimEventFocus)
389 updateEventEffects (s, e, TRUE);
390 }
391 }
392 }
393
394 // End of extension functions
395
396
397 Bool
defaultAnimInit(CompWindow * w)398 defaultAnimInit (CompWindow * w)
399 {
400 ANIM_SCREEN(w->screen);
401 ANIM_WINDOW(w);
402
403 // store window opacity
404 aw->com.storedOpacity = w->paint.opacity;
405
406 aw->com.timestep =
407 (w->screen->slowAnimations ? 2 : // For smooth slow-mo (refer to display.c)
408 as->opt[ANIM_SCREEN_OPTION_TIME_STEP].value.i);
409
410 return TRUE;
411 }
412
413 Bool
animZoomToIcon(CompWindow * w)414 animZoomToIcon (CompWindow *w)
415 {
416 ANIM_WINDOW(w);
417
418 if (aw->com.curAnimEffect->properties.zoomToIconFunc)
419 return aw->com.curAnimEffect->properties.zoomToIconFunc (w);
420
421 return FALSE;
422 }
423
424 static Bool
defaultMinimizeAnimInit(CompWindow * w)425 defaultMinimizeAnimInit (CompWindow * w)
426 {
427 ANIM_WINDOW(w);
428
429 if (animZoomToIcon (w))
430 {
431 aw->com.animTotalTime /= ZOOM_PERCEIVED_T;
432 aw->com.animRemainingTime = aw->com.animTotalTime;
433 aw->com.usingTransform = TRUE;
434 }
435 return defaultAnimInit (w);
436 }
437
438 static Bool
animWithTransformInit(CompWindow * w)439 animWithTransformInit (CompWindow * w)
440 {
441 ANIM_WINDOW(w);
442
443 aw->com.usingTransform = TRUE;
444
445 return defaultMinimizeAnimInit (w);
446 }
447
448 static inline Bool
returnTrue(CompWindow * w)449 returnTrue (CompWindow *w)
450 {
451 return TRUE;
452 }
453
454 // Assumes events in the metadata are in
455 // [Open, Close, Minimize, Focus, Shade] order
456 // and effects among those are in alphabetical order
457 // but with "(Event) None" first and "(Event) Random" last.
458 static AnimEffect
getMatchingAnimSelection(CompWindow * w,AnimEvent e,int * duration)459 getMatchingAnimSelection (CompWindow *w,
460 AnimEvent e,
461 int *duration)
462 {
463 ANIM_SCREEN(w->screen);
464 ANIM_WINDOW(w);
465
466 EffectSet *eventEffects;
467 CompOptionValue *valMatch;
468 CompOptionValue *valDuration;
469 CompOptionValue *valCustomOptions;
470
471 eventEffects = &as->eventEffects[e];
472 valMatch = &as->opt[matchOptionIds[e]].value;
473 valDuration = &as->opt[durationOptionIds[e]].value;
474 valCustomOptions = &as->opt[customOptionOptionIds[e]].value;
475
476 int nRows = valMatch->list.nValue;
477 if (nRows != eventEffects->n ||
478 nRows != valDuration->list.nValue ||
479 nRows != valCustomOptions->list.nValue)
480 {
481 compLogMessage ("animation", CompLogLevelError,
482 "Animation settings mismatch in \"Animation "
483 "Selection\" list for %s event.", eventNames[e]);
484 return AnimEffectNone;
485 }
486
487 // Find the first row that matches this window for this event
488 int i;
489 for (i = 0; i < nRows; i++)
490 {
491 if (!matchEval (&valMatch->list.value[i].match, w))
492 continue;
493
494 aw->prevAnimSelectionRow = aw->curAnimSelectionRow;
495 aw->curAnimSelectionRow = i;
496
497 if (duration)
498 *duration = valDuration->list.value[i].i;
499
500 return eventEffects->effects[i];
501 }
502
503 return AnimEffectNone;
504 }
505
506 static inline AnimEffect
animGetAnimEffect(AnimScreen * as,AnimEffect effect,AnimEvent animEvent)507 animGetAnimEffect (AnimScreen *as,
508 AnimEffect effect,
509 AnimEvent animEvent)
510 {
511 Bool allRandom = as->opt[ANIM_SCREEN_OPTION_ALL_RANDOM].value.b;
512 AnimEffect *randomEffects = as->randomEffects[animEvent].effects;
513 unsigned int nRandomEffects = as->randomEffects[animEvent].n;
514
515 if ((effect == AnimEffectRandom) || allRandom)
516 {
517 if (nRandomEffects == 0) // no random animation selected, assume "all"
518 {
519 // exclude None and Random
520 randomEffects = as->eventEffectsAllowed[animEvent] + 2;
521 nRandomEffects = as->nEventEffectsAllowed[animEvent] - 2;
522 }
523 unsigned int index;
524 index = (unsigned int)(nRandomEffects * (double)rand() / RAND_MAX);
525 return randomEffects[index];
526 }
527 else
528 return effect;
529 }
530
531 // Converts animation direction string to an integer direction
532 // (up, down, left, or right)
getActualAnimDirection(CompWindow * w,AnimDirection dir,Bool openDir)533 AnimDirection getActualAnimDirection (CompWindow * w,
534 AnimDirection dir,
535 Bool openDir)
536 {
537 ANIM_WINDOW(w);
538
539 if (dir == AnimDirectionRandom)
540 {
541 dir = rand() % 4;
542 }
543 else if (dir == AnimDirectionAuto)
544 {
545 // away from icon
546 int centerX = BORDER_X(w) + BORDER_W(w) / 2;
547 int centerY = BORDER_Y(w) + BORDER_H(w) / 2;
548 float relDiffX = ((float)centerX - aw->com.icon.x) / BORDER_W(w);
549 float relDiffY = ((float)centerY - aw->com.icon.y) / BORDER_H(w);
550
551 if (openDir)
552 {
553 if (aw->com.curWindowEvent == WindowEventMinimize ||
554 aw->com.curWindowEvent == WindowEventUnminimize)
555 // min/unmin. should always result in +/- y direction
556 dir = aw->com.icon.y < w->screen->height - aw->com.icon.y ?
557 AnimDirectionDown : AnimDirectionUp;
558 else if (fabs(relDiffY) > fabs(relDiffX))
559 dir = relDiffY > 0 ? AnimDirectionDown : AnimDirectionUp;
560 else
561 dir = relDiffX > 0 ? AnimDirectionRight : AnimDirectionLeft;
562 }
563 else
564 {
565 if (aw->com.curWindowEvent == WindowEventMinimize ||
566 aw->com.curWindowEvent == WindowEventUnminimize)
567 // min/unmin. should always result in +/- y direction
568 dir = aw->com.icon.y < w->screen->height - aw->com.icon.y ?
569 AnimDirectionUp : AnimDirectionDown;
570 else if (fabs(relDiffY) > fabs(relDiffX))
571 dir = relDiffY > 0 ? AnimDirectionUp : AnimDirectionDown;
572 else
573 dir = relDiffX > 0 ? AnimDirectionLeft : AnimDirectionRight;
574 }
575 }
576 return dir;
577 }
578
579 float
defaultAnimProgress(CompWindow * w)580 defaultAnimProgress (CompWindow *w)
581 {
582 ANIM_WINDOW (w);
583
584 float forwardProgress =
585 1 - aw->com.animRemainingTime / (aw->com.animTotalTime - aw->com.timestep);
586 forwardProgress = MIN(forwardProgress, 1);
587 forwardProgress = MAX(forwardProgress, 0);
588
589 if (aw->com.curWindowEvent == WindowEventOpen ||
590 aw->com.curWindowEvent == WindowEventUnminimize ||
591 aw->com.curWindowEvent == WindowEventUnshade ||
592 aw->com.curWindowEvent == WindowEventFocus)
593 forwardProgress = 1 - forwardProgress;
594
595 return forwardProgress;
596 }
597
598 float
sigmoidAnimProgress(CompWindow * w)599 sigmoidAnimProgress (CompWindow *w)
600 {
601 ANIM_WINDOW (w);
602
603 float forwardProgress =
604 1 - aw->com.animRemainingTime / (aw->com.animTotalTime - aw->com.timestep);
605 forwardProgress = MIN(forwardProgress, 1);
606 forwardProgress = MAX(forwardProgress, 0);
607
608 // Apply sigmoid and normalize
609 forwardProgress =
610 (sigmoid(forwardProgress) - sigmoid(0)) /
611 (sigmoid(1) - sigmoid(0));
612
613 if (aw->com.curWindowEvent == WindowEventOpen ||
614 aw->com.curWindowEvent == WindowEventUnminimize ||
615 aw->com.curWindowEvent == WindowEventUnshade ||
616 aw->com.curWindowEvent == WindowEventFocus)
617 forwardProgress = 1 - forwardProgress;
618
619 return forwardProgress;
620 }
621
622 // Gives some acceleration (when closing a window)
623 // or deceleration (when opening a window)
624 // Applies a sigmoid with slope s,
625 // where minx and maxx are the
626 // starting and ending points on the sigmoid
decelerateProgressCustom(float progress,float minx,float maxx)627 float decelerateProgressCustom(float progress, float minx, float maxx)
628 {
629 float x = 1 - progress;
630 float s = 8;
631
632 return (1 -
633 ((sigmoid2(minx + (x * (maxx - minx)), s) - sigmoid2(minx, s)) /
634 (sigmoid2(maxx, s) - sigmoid2(minx, s))));
635 }
636
decelerateProgress(float progress)637 float decelerateProgress(float progress)
638 {
639 return decelerateProgressCustom(progress, 0.5, 0.75);
640 }
641
642 float
getProgressAndCenter(CompWindow * w,Point * center)643 getProgressAndCenter (CompWindow *w,
644 Point *center)
645 {
646 float forwardProgress = 0;
647
648 ANIM_WINDOW (w);
649
650 if (center)
651 center->x = WIN_X (w) + WIN_W (w) / 2.0;
652
653 if (animZoomToIcon (w))
654 {
655 float dummy;
656 fxZoomAnimProgress (w, &forwardProgress, &dummy, TRUE);
657
658 if (center)
659 getZoomCenterScale (w, center, NULL);
660 }
661 else
662 {
663 forwardProgress = defaultAnimProgress (w);
664
665 if (center)
666 {
667 if (aw->com.curWindowEvent == WindowEventShade ||
668 aw->com.curWindowEvent == WindowEventUnshade)
669 {
670 float origCenterY = WIN_Y (w) + WIN_H (w) / 2.0;
671 center->y =
672 (1 - forwardProgress) * origCenterY +
673 forwardProgress * (WIN_Y (w) + aw->com.model->topHeight);
674 }
675 else // i.e. (un)minimizing without zooming
676 {
677 center->y = WIN_Y (w) + WIN_H (w) / 2.0;
678 }
679 }
680 }
681 return forwardProgress;
682 }
683
684 void
defaultAnimStep(CompWindow * w,float time)685 defaultAnimStep (CompWindow *w, float time)
686 {
687 int steps;
688
689 ANIM_SCREEN (w->screen);
690 ANIM_WINDOW (w);
691
692 float timestep =
693 (w->screen->slowAnimations ? 2 : // For smooth slow-mo (refer to display.c)
694 as->opt[ANIM_SCREEN_OPTION_TIME_STEP].value.i);
695
696 aw->com.timestep = timestep;
697
698 aw->remainderSteps += time / timestep;
699 steps = floor(aw->remainderSteps);
700 aw->remainderSteps -= steps;
701
702 steps = MAX(1, steps);
703
704 aw->com.animRemainingTime -= timestep * steps;
705
706 // avoid sub-zero values
707 aw->com.animRemainingTime = MAX(aw->com.animRemainingTime, 0);
708
709 matrixGetIdentity (&aw->com.transform);
710 if (animZoomToIcon (w))
711 {
712 applyZoomTransform (w);
713 }
714 }
715
716 void
defaultUpdateWindowTransform(CompWindow * w,CompTransform * wTransform)717 defaultUpdateWindowTransform (CompWindow *w,
718 CompTransform *wTransform)
719 {
720 ANIM_WINDOW(w);
721
722 if (aw->com.usingTransform)
723 {
724 if (aw->com.curAnimEffect->properties.modelAnimIs3D)
725 {
726 // center for perspective correction
727 Point center;
728 getProgressAndCenter (w, ¢er);
729
730 ANIM_SCREEN (w->screen);
731 CompTransform skewTransform;
732 matrixGetIdentity (&skewTransform);
733 applyPerspectiveSkew (as->output, &skewTransform, ¢er);
734 applyTransform (wTransform, &aw->com.transform);
735 applyTransform (wTransform, &skewTransform);
736 }
737 else
738 {
739 applyTransform (wTransform, &aw->com.transform);
740 }
741 }
742 }
743
744 // Apply transform to wTransform
745 inline void
applyTransform(CompTransform * wTransform,CompTransform * transform)746 applyTransform (CompTransform *wTransform,
747 CompTransform *transform)
748 {
749 matrixMultiply (wTransform, wTransform, transform);
750 }
751
752 static void
copyResetBB(AnimWindow * aw)753 copyResetBB (AnimWindow *aw)
754 {
755 memcpy (&aw->lastBB, &aw->BB, sizeof (Box));
756 aw->BB.x1 = aw->BB.y1 = MAXSHORT;
757 aw->BB.x2 = aw->BB.y2 = MINSHORT;
758 }
759
760 void
expandBoxWithBox(Box * target,Box * source)761 expandBoxWithBox (Box *target, Box *source)
762 {
763 if (source->x1 < target->x1)
764 target->x1 = source->x1;
765 if (source->x2 > target->x2)
766 target->x2 = source->x2;
767 if (source->y1 < target->y1)
768 target->y1 = source->y1;
769 if (source->y2 > target->y2)
770 target->y2 = source->y2;
771 }
772
773 void
expandBoxWithPoint(Box * target,float fx,float fy)774 expandBoxWithPoint (Box *target, float fx, float fy)
775 {
776 short x = MAX (MIN (fx, MAXSHORT - 1), MINSHORT);
777 short y = MAX (MIN (fy, MAXSHORT - 1), MINSHORT);
778
779 if (target->x1 == MAXSHORT)
780 {
781 target->x1 = x;
782 target->y1 = y;
783 target->x2 = x + 1;
784 target->y2 = y + 1;
785 return;
786 }
787 if (x < target->x1)
788 target->x1 = x;
789 else if (x > target->x2)
790 target->x2 = x;
791
792 if (y < target->y1)
793 target->y1 = y;
794 else if (y > target->y2)
795 target->y2 = y;
796 }
797
798 // This will work for zoom-like 2D transforms,
799 // but not for glide-like 3D transforms.
800 static void
expandBoxWithPoint2DTransform(CompScreen * s,Box * target,CompVector * coords,CompTransform * transformMat)801 expandBoxWithPoint2DTransform (CompScreen *s,
802 Box *target,
803 CompVector *coords,
804 CompTransform *transformMat)
805 {
806 CompVector coordsTransformed;
807
808 matrixMultiplyVector (&coordsTransformed, coords, transformMat);
809 expandBoxWithPoint (target, coordsTransformed.x, coordsTransformed.y);
810 }
811
812 // Either points or objects should be non-NULL.
813 static Bool
expandBoxWithPoints3DTransform(CompOutput * output,CompScreen * s,const CompTransform * transform,Box * targetBox,const float * points,Object * objects,int nPoints)814 expandBoxWithPoints3DTransform (CompOutput *output,
815 CompScreen *s,
816 const CompTransform *transform,
817 Box *targetBox,
818 const float *points,
819 Object *objects,
820 int nPoints)
821 {
822 GLdouble dModel[16];
823 GLdouble dProjection[16];
824 GLdouble x, y, z;
825 int i;
826 for (i = 0; i < 16; i++)
827 {
828 dModel[i] = transform->m[i];
829 dProjection[i] = s->projection[i];
830 }
831 GLint viewport[4] =
832 {output->region.extents.x1,
833 output->region.extents.y1,
834 output->width,
835 output->height};
836
837 if (points) // use points
838 {
839 for (; nPoints; nPoints--, points += 3)
840 {
841 if (!gluProject (points[0], points[1], points[2],
842 dModel, dProjection, viewport,
843 &x, &y, &z))
844 return FALSE;
845
846 expandBoxWithPoint (targetBox, x + 0.5, (s->height - y) + 0.5);
847 }
848 }
849 else // use objects
850 {
851 Object *object = objects;
852 for (; nPoints; nPoints--, object++)
853 {
854 if (!gluProject (object->position.x,
855 object->position.y,
856 object->position.z,
857 dModel, dProjection, viewport,
858 &x, &y, &z))
859 return FALSE;
860
861 expandBoxWithPoint (targetBox, x + 0.5, (s->height - y) + 0.5);
862 }
863 }
864 return TRUE;
865 }
866
867 static void
modelUpdateBB(CompOutput * output,CompWindow * w,Box * BB)868 modelUpdateBB (CompOutput *output,
869 CompWindow * w,
870 Box *BB)
871 {
872 int i;
873
874 ANIM_WINDOW (w);
875
876 Model *model = aw->com.model;
877 if (!model)
878 return;
879
880 Object *object = model->objects;
881
882 if (aw->com.usingTransform)
883 {
884 if (aw->com.curAnimEffect->properties.modelAnimIs3D)
885 {
886 CompTransform wTransform;
887
888 // center for perspective correction
889 Point center;
890 getProgressAndCenter (w, ¢er);
891
892 CompTransform fullTransform;
893 memcpy (fullTransform.m, aw->com.transform.m, sizeof (float) * 16);
894 applyPerspectiveSkew (output, &fullTransform, ¢er);
895
896 prepareTransform (w->screen, output, &wTransform, &fullTransform);
897
898 expandBoxWithPoints3DTransform (output,
899 w->screen,
900 &wTransform,
901 BB,
902 NULL,
903 model->objects,
904 model->numObjects);
905 }
906 else
907 {
908 Object *object = model->objects;
909 for (i = 0; i < model->numObjects; i++, object++)
910 {
911 CompVector coords;
912
913 coords.x = object->position.x;
914 coords.y = object->position.y;
915 coords.z = 0;
916 coords.w = 1;
917
918 expandBoxWithPoint2DTransform (w->screen,
919 BB,
920 &coords,
921 &aw->com.transform);
922 }
923 }
924 }
925 else
926 {
927 for (i = 0; i < model->numObjects; i++, object++)
928 {
929 expandBoxWithPoint (BB,
930 object->position.x + 0.5,
931 object->position.y + 0.5);
932 }
933 }
934 }
935
936 void
updateBBWindow(CompOutput * output,CompWindow * w,Box * BB)937 updateBBWindow (CompOutput *output,
938 CompWindow * w,
939 Box *BB)
940 {
941 Box windowBox = {WIN_X(w), WIN_X(w) + WIN_W(w),
942 WIN_Y(w), WIN_Y(w) + WIN_H(w)};
943 expandBoxWithBox (BB, &windowBox);
944 }
945
946 void
updateBBScreen(CompOutput * output,CompWindow * w,Box * BB)947 updateBBScreen (CompOutput *output,
948 CompWindow * w,
949 Box *BB)
950 {
951 Box screenBox = {0, w->screen->width,
952 0, w->screen->height};
953 expandBoxWithBox (BB, &screenBox);
954 }
955
956 void
prepareTransform(CompScreen * s,CompOutput * output,CompTransform * resultTransform,CompTransform * transform)957 prepareTransform (CompScreen *s,
958 CompOutput *output,
959 CompTransform *resultTransform,
960 CompTransform *transform)
961 {
962 CompTransform sTransform;
963
964 matrixGetIdentity (&sTransform);
965 transformToScreenSpace (s, output,
966 -DEFAULT_Z_CAMERA, &sTransform);
967
968 matrixMultiply (resultTransform, &sTransform, transform);
969 }
970
971 void
compTransformUpdateBB(CompOutput * output,CompWindow * w,Box * BB)972 compTransformUpdateBB (CompOutput *output,
973 CompWindow *w,
974 Box *BB)
975 {
976 ANIM_WINDOW(w);
977 CompScreen *s = w->screen;
978 CompTransform wTransform;
979
980 prepareTransform (s, output, &wTransform, &aw->com.transform);
981
982 float corners[4*3] = {WIN_X(w), WIN_Y(w), 0,
983 WIN_X(w) + WIN_W(w), WIN_Y(w), 0,
984 WIN_X(w), WIN_Y(w) + WIN_H(w), 0,
985 WIN_X(w) + WIN_W(w), WIN_Y(w) + WIN_H(w), 0};
986
987 expandBoxWithPoints3DTransform (output,
988 s,
989 &wTransform,
990 BB,
991 corners,
992 NULL,
993 4);
994 }
995
996 // Damage the union of window's bounding box
997 // before and after animStepFunc does its job
998 static void
damageBoundingBox(CompWindow * w)999 damageBoundingBox (CompWindow * w)
1000 {
1001 ANIM_WINDOW(w);
1002
1003 if (aw->BB.x1 == MAXSHORT) // unintialized BB
1004 return;
1005
1006 // Find union of BB and lastBB
1007 Region regionToDamage = XCreateRegion();
1008 if (!regionToDamage)
1009 return;
1010
1011 XRectangle rect;
1012
1013 BoxPtr BB = &aw->BB;
1014 BoxPtr lastBB = &aw->lastBB;
1015
1016 // Have a 1 pixel margin to prevent occasional 1 pixel line artifact
1017 rect.x = BB->x1 - 1;
1018 rect.y = BB->y1 - 1;
1019 rect.width = BB->x2 - BB->x1 + 2;
1020 rect.height = BB->y2 - BB->y1 + 2;
1021 XUnionRectWithRegion (&rect, &emptyRegion, regionToDamage);
1022
1023 rect.x = lastBB->x1 - 1;
1024 rect.y = lastBB->y1 - 1;
1025 rect.width = lastBB->x2 - lastBB->x1 + 2;
1026 rect.height = lastBB->y2 - lastBB->y1 + 2;
1027 XUnionRectWithRegion (&rect, regionToDamage, regionToDamage);
1028
1029 damageScreenRegion (w->screen, regionToDamage);
1030
1031 XDestroyRegion (regionToDamage);
1032 }
1033
getMousePointerXY(CompScreen * s,short * x,short * y)1034 Bool getMousePointerXY(CompScreen * s, short *x, short *y)
1035 {
1036 Window w1, w2;
1037 int xp, yp, xj, yj;
1038 unsigned int m;
1039
1040 if (XQueryPointer
1041 (s->display->display, s->root, &w1, &w2, &xj, &yj, &xp, &yp, &m))
1042 {
1043 *x = xp;
1044 *y = yp;
1045 return TRUE;
1046 }
1047 return FALSE;
1048 }
1049
animGetWindowState(CompWindow * w)1050 static int animGetWindowState(CompWindow * w)
1051 {
1052 Atom actual;
1053 int result, format;
1054 unsigned long n, left;
1055 unsigned char *data;
1056 int retval = WithdrawnState;
1057
1058 result = XGetWindowProperty(w->screen->display->display, w->id,
1059 w->screen->display->wmStateAtom, 0L,
1060 1L, FALSE,
1061 w->screen->display->wmStateAtom,
1062 &actual, &format, &n, &left, &data);
1063
1064 if (result == Success && data)
1065 {
1066 if (n)
1067 memcpy(&retval, data, sizeof(int));
1068
1069 XFree((void *)data);
1070 }
1071
1072 return retval;
1073 }
1074
1075 static Bool
animSetScreenOptions(CompPlugin * plugin,CompScreen * screen,const char * name,CompOptionValue * value)1076 animSetScreenOptions(CompPlugin *plugin,
1077 CompScreen * screen,
1078 const char *name,
1079 CompOptionValue * value)
1080 {
1081 CompOption *o;
1082 int index;
1083
1084 ANIM_SCREEN(screen);
1085
1086 o = compFindOption(as->opt, NUM_OPTIONS(as), name, &index);
1087 if (!o)
1088 return FALSE;
1089
1090 switch (index)
1091 {
1092 case ANIM_SCREEN_OPTION_OPEN_MATCHES:
1093 case ANIM_SCREEN_OPTION_CLOSE_MATCHES:
1094 case ANIM_SCREEN_OPTION_MINIMIZE_MATCHES:
1095 case ANIM_SCREEN_OPTION_SHADE_MATCHES:
1096 case ANIM_SCREEN_OPTION_FOCUS_MATCHES:
1097 if (compSetOptionList(o, value))
1098 {
1099 int i;
1100 for (i = 0; i < o->value.list.nValue; i++)
1101 matchUpdate (screen->display, &o->value.list.value[i].match);
1102 return TRUE;
1103 }
1104 break;
1105 case ANIM_SCREEN_OPTION_OPEN_OPTIONS:
1106 if (compSetOptionList(o, value))
1107 {
1108 updateOptionSets (screen, AnimEventOpen);
1109 return TRUE;
1110 }
1111 break;
1112 case ANIM_SCREEN_OPTION_CLOSE_OPTIONS:
1113 if (compSetOptionList(o, value))
1114 {
1115 updateOptionSets (screen, AnimEventClose);
1116 return TRUE;
1117 }
1118 break;
1119 case ANIM_SCREEN_OPTION_MINIMIZE_OPTIONS:
1120 if (compSetOptionList(o, value))
1121 {
1122 updateOptionSets (screen, AnimEventMinimize);
1123 return TRUE;
1124 }
1125 break;
1126 case ANIM_SCREEN_OPTION_SHADE_OPTIONS:
1127 if (compSetOptionList(o, value))
1128 {
1129 updateOptionSets (screen, AnimEventShade);
1130 return TRUE;
1131 }
1132 break;
1133 case ANIM_SCREEN_OPTION_FOCUS_OPTIONS:
1134 if (compSetOptionList(o, value))
1135 {
1136 updateOptionSets (screen, AnimEventFocus);
1137 return TRUE;
1138 }
1139 break;
1140 case ANIM_SCREEN_OPTION_OPEN_EFFECTS:
1141 if (compSetOptionList(o, value))
1142 {
1143 updateEventEffects (screen, AnimEventOpen, FALSE);
1144 return TRUE;
1145 }
1146 break;
1147 case ANIM_SCREEN_OPTION_CLOSE_EFFECTS:
1148 if (compSetOptionList(o, value))
1149 {
1150 updateEventEffects (screen, AnimEventClose, FALSE);
1151 return TRUE;
1152 }
1153 break;
1154 case ANIM_SCREEN_OPTION_MINIMIZE_EFFECTS:
1155 if (compSetOptionList(o, value))
1156 {
1157 updateEventEffects (screen, AnimEventMinimize, FALSE);
1158 return TRUE;
1159 }
1160 break;
1161 case ANIM_SCREEN_OPTION_SHADE_EFFECTS:
1162 if (compSetOptionList(o, value))
1163 {
1164 updateEventEffects (screen, AnimEventShade, FALSE);
1165 return TRUE;
1166 }
1167 break;
1168 case ANIM_SCREEN_OPTION_FOCUS_EFFECTS:
1169 if (compSetOptionList(o, value))
1170 {
1171 updateEventEffects (screen, AnimEventFocus, FALSE);
1172 return TRUE;
1173 }
1174 break;
1175 case ANIM_SCREEN_OPTION_OPEN_RANDOM_EFFECTS:
1176 if (compSetOptionList(o, value))
1177 {
1178 updateEventEffects (screen, AnimEventOpen, TRUE);
1179 return TRUE;
1180 }
1181 break;
1182 case ANIM_SCREEN_OPTION_CLOSE_RANDOM_EFFECTS:
1183 if (compSetOptionList(o, value))
1184 {
1185 updateEventEffects (screen, AnimEventClose, TRUE);
1186 return TRUE;
1187 }
1188 break;
1189 case ANIM_SCREEN_OPTION_MINIMIZE_RANDOM_EFFECTS:
1190 if (compSetOptionList(o, value))
1191 {
1192 updateEventEffects (screen, AnimEventMinimize, TRUE);
1193 return TRUE;
1194 }
1195 break;
1196 case ANIM_SCREEN_OPTION_SHADE_RANDOM_EFFECTS:
1197 if (compSetOptionList(o, value))
1198 {
1199 updateEventEffects (screen, AnimEventShade, TRUE);
1200 return TRUE;
1201 }
1202 break;
1203 default:
1204 return compSetScreenOption (screen, o, value);
1205 break;
1206 }
1207
1208 return FALSE;
1209 }
1210
1211 static const CompMetadataOptionInfo animScreenOptionInfo[] = {
1212 // Event settings
1213 { "open_effects", "list", "<type>string</type>", 0, 0 },
1214 { "open_durations", "list", "<type>int</type><min>50</min>", 0, 0 },
1215 { "open_matches", "list", "<type>match</type>", 0, 0 },
1216 { "open_options", "list", "<type>string</type>", 0, 0 },
1217 { "open_random_effects", "list", "<type>string</type>", 0, 0 },
1218 { "close_effects", "list", "<type>string</type>", 0, 0 },
1219 { "close_durations", "list", "<type>int</type><min>50</min>", 0, 0 },
1220 { "close_matches", "list", "<type>match</type>", 0, 0 },
1221 { "close_options", "list", "<type>string</type>", 0, 0 },
1222 { "close_random_effects", "list", "<type>string</type>", 0, 0 },
1223 { "minimize_effects", "list", "<type>string</type>", 0, 0 },
1224 { "minimize_durations", "list", "<type>int</type><min>50</min>", 0, 0 },
1225 { "minimize_matches", "list", "<type>match</type>", 0, 0 },
1226 { "minimize_options", "list", "<type>string</type>", 0, 0 },
1227 { "minimize_random_effects", "list", "<type>string</type>", 0, 0 },
1228 { "shade_effects", "list", "<type>string</type>", 0, 0 },
1229 { "shade_durations", "list", "<type>int</type><min>50</min>", 0, 0 },
1230 { "shade_matches", "list", "<type>match</type>", 0, 0 },
1231 { "shade_options", "list", "<type>string</type>", 0, 0 },
1232 { "shade_random_effects", "list", "<type>string</type>", 0, 0 },
1233 { "focus_effects", "list", "<type>string</type>", 0, 0 },
1234 { "focus_durations", "list", "<type>int</type><min>50</min>", 0, 0 },
1235 { "focus_matches", "list", "<type>match</type>", 0, 0 },
1236 { "focus_options", "list", "<type>string</type>", 0, 0 },
1237 // Misc. settings
1238 { "all_random", "bool", 0, 0, 0 },
1239 { "time_step", "int", "<min>1</min>", 0, 0 },
1240 // Effect settings
1241 { "curved_fold_amp_mult", "float", "<min>-1.5</min><max>2.0</max>", 0, 0 },
1242 { "curved_fold_zoom_to_taskbar", "bool", 0, 0, 0 },
1243 { "dodge_gap_ratio", "float", "<min>0.0</min><max>1.0</max>", 0, 0 },
1244 { "dream_zoom_to_taskbar", "bool", 0, 0, 0 },
1245 { "glide1_away_position", "float", 0, 0, 0 },
1246 { "glide1_away_angle", "float", 0, 0, 0 },
1247 { "glide1_zoom_to_taskbar", "bool", 0, 0, 0 },
1248 { "glide2_away_position", "float", 0, 0, 0 },
1249 { "glide2_away_angle", "float", 0, 0, 0 },
1250 { "glide2_zoom_to_taskbar", "bool", 0, 0, 0 },
1251 { "horizontal_folds_amp_mult", "float", "<min>-1.0</min><max>3.0</max>", 0, 0 },
1252 { "horizontal_folds_num_folds", "int", "<min>1</min>", 0, 0 },
1253 { "horizontal_folds_zoom_to_taskbar", "bool", 0, 0, 0 },
1254 { "magic_lamp_moving_end", "bool", 0, 0, 0 },
1255 { "magic_lamp_grid_res", "int", "<min>4</min>", 0, 0 },
1256 { "magic_lamp_max_waves", "int", "<min>3</min>", 0, 0 },
1257 { "magic_lamp_amp_min", "float", "<min>200</min>", 0, 0 },
1258 { "magic_lamp_amp_max", "float", "<min>200</min>", 0, 0 },
1259 { "magic_lamp_open_start_width", "int", "<min>0</min>", 0, 0 },
1260 { "rollup_fixed_interior", "bool", 0, 0, 0 },
1261 { "sidekick_num_rotations", "float", "<min>0</min>", 0, 0 },
1262 { "sidekick_springiness", "float", "<min>0</min><max>1</max>", 0, 0 },
1263 { "sidekick_zoom_from_center", "int", RESTOSTRING (0, LAST_ZOOM_FROM_CENTER), 0, 0 },
1264 { "vacuum_moving_end", "bool", 0, 0, 0 },
1265 { "vacuum_grid_res", "int", "<min>4</min>", 0, 0 },
1266 { "vacuum_open_start_width", "int", "<min>0</min>", 0, 0 },
1267 { "wave_width", "float", "<min>0</min>", 0, 0 },
1268 { "wave_amp_mult", "float", "<min>-20.0</min><max>20.0</max>", 0, 0 },
1269 { "zoom_from_center", "int", RESTOSTRING (0, LAST_ZOOM_FROM_CENTER), 0, 0 },
1270 { "zoom_springiness", "float", "<min>0</min><max>1</max>", 0, 0 }
1271 };
1272
1273 static CompOption *
animGetScreenOptions(CompPlugin * plugin,CompScreen * screen,int * count)1274 animGetScreenOptions(CompPlugin *plugin, CompScreen * screen, int *count)
1275 {
1276 ANIM_SCREEN(screen);
1277
1278 *count = NUM_OPTIONS(as);
1279 return as->opt;
1280 }
1281
1282 static void
objectInit(Object * object,float positionX,float positionY,float gridPositionX,float gridPositionY)1283 objectInit(Object * object,
1284 float positionX, float positionY,
1285 float gridPositionX, float gridPositionY)
1286 {
1287 object->gridPosition.x = gridPositionX;
1288 object->gridPosition.y = gridPositionY;
1289
1290 object->position.x = positionX;
1291 object->position.y = positionY;
1292
1293 object->offsetTexCoordForQuadBefore.x = 0;
1294 object->offsetTexCoordForQuadBefore.y = 0;
1295 object->offsetTexCoordForQuadAfter.x = 0;
1296 object->offsetTexCoordForQuadAfter.y = 0;
1297 }
1298
1299 void
modelInitObjects(Model * model,int x,int y,int width,int height)1300 modelInitObjects(Model * model, int x, int y, int width, int height)
1301 {
1302 int gridX, gridY;
1303 int nGridCellsX, nGridCellsY;
1304 float x0, y0;
1305
1306 x0 = model->scaleOrigin.x;
1307 y0 = model->scaleOrigin.y;
1308
1309 // number of grid cells in x direction
1310 nGridCellsX = model->gridWidth - 1;
1311
1312 if (model->forWindowEvent == WindowEventShade ||
1313 model->forWindowEvent == WindowEventUnshade)
1314 {
1315 // number of grid cells in y direction
1316 nGridCellsY = model->gridHeight - 3; // One allocated for top, one for bottom
1317
1318 float winContentsHeight =
1319 height - model->topHeight - model->bottomHeight;
1320
1321 //Top
1322 float objectY = y + (0 - y0) * model->scale.y + y0;
1323
1324 for (gridX = 0; gridX < model->gridWidth; gridX++)
1325 {
1326 objectInit(&model->objects[gridX],
1327 x + ((gridX * width / nGridCellsX) - x0) *
1328 model->scale.x + x0, objectY,
1329 (float)gridX / nGridCellsX, 0);
1330 }
1331
1332 // Window contents
1333 for (gridY = 1; gridY < model->gridHeight - 1; gridY++)
1334 {
1335 float inWinY =
1336 (gridY - 1) * winContentsHeight / nGridCellsY +
1337 model->topHeight;
1338 float gridPosY = inWinY / height;
1339
1340 objectY = y + (inWinY - y0) * model->scale.y + y0;
1341
1342 for (gridX = 0; gridX < model->gridWidth; gridX++)
1343 {
1344 objectInit(&model->objects[gridY * model->gridWidth + gridX],
1345 x + ((gridX * width / nGridCellsX) - x0) *
1346 model->scale.x + x0,
1347 objectY, (float)gridX / nGridCellsX, gridPosY);
1348 }
1349 }
1350
1351 // Bottom (gridY is model->gridHeight-1 now)
1352 objectY = y + (height - y0) * model->scale.y + y0;
1353
1354 for (gridX = 0; gridX < model->gridWidth; gridX++)
1355 {
1356 objectInit(&model->objects[gridY * model->gridWidth + gridX],
1357 x + ((gridX * width / nGridCellsX) - x0) *
1358 model->scale.x + x0, objectY,
1359 (float)gridX / nGridCellsX, 1);
1360 }
1361 }
1362 else
1363 {
1364 int objIndex = 0;
1365
1366 // number of grid cells in y direction
1367 nGridCellsY = model->gridHeight - 1;
1368
1369 for (gridY = 0; gridY < model->gridHeight; gridY++)
1370 {
1371 float objectY =
1372 y + ((gridY * height / nGridCellsY) -
1373 y0) * model->scale.y + y0;
1374 for (gridX = 0; gridX < model->gridWidth; gridX++)
1375 {
1376 objectInit(&model->objects[objIndex],
1377 x + ((gridX * width / nGridCellsX) - x0) *
1378 model->scale.x + x0,
1379 objectY,
1380 (float)gridX / nGridCellsX,
1381 (float)gridY / nGridCellsY);
1382 objIndex++;
1383 }
1384 }
1385 }
1386 }
1387
1388 static void
modelMove(Model * model,float tx,float ty)1389 modelMove (Model *model,
1390 float tx,
1391 float ty)
1392 {
1393 Object *object = model->objects;
1394 int i;
1395 for (i = 0; i < model->numObjects; i++, object++)
1396 {
1397 object->position.x += tx;
1398 object->position.y += ty;
1399 }
1400 }
1401
createModel(CompWindow * w,WindowEvent forWindowEvent,AnimEffect forAnimEffect,int gridWidth,int gridHeight)1402 static Model *createModel(CompWindow * w,
1403 WindowEvent forWindowEvent,
1404 AnimEffect forAnimEffect, int gridWidth,
1405 int gridHeight)
1406 {
1407 int x = WIN_X(w);
1408 int y = WIN_Y(w);
1409 int width = WIN_W(w);
1410 int height = WIN_H(w);
1411
1412 Model *model;
1413
1414 model = calloc(1, sizeof(Model));
1415 if (!model)
1416 {
1417 compLogMessage ("animation", CompLogLevelError,
1418 "Not enough memory");
1419 return 0;
1420 }
1421
1422 model->gridWidth = gridWidth;
1423 model->gridHeight = gridHeight;
1424 model->numObjects = gridWidth * gridHeight;
1425 model->objects = calloc(model->numObjects, sizeof(Object));
1426 if (!model->objects)
1427 {
1428 compLogMessage ("animation", CompLogLevelError,
1429 "Not enough memory");
1430 free(model);
1431 return 0;
1432 }
1433
1434 // Store win. size to check later
1435 model->winWidth = width;
1436 model->winHeight = height;
1437
1438 // For shading
1439 model->forWindowEvent = forWindowEvent;
1440 model->topHeight = w->output.top;
1441 model->bottomHeight = w->output.bottom;
1442
1443 model->scale.x = 1.0f;
1444 model->scale.y = 1.0f;
1445
1446 model->scaleOrigin.x = 0.0f;
1447 model->scaleOrigin.y = 0.0f;
1448
1449 modelInitObjects(model, x, y, width, height);
1450
1451 return model;
1452 }
1453
1454 static void
animFreeModel(AnimWindow * aw)1455 animFreeModel(AnimWindow *aw)
1456 {
1457 if (!aw->com.model)
1458 return;
1459
1460 if (aw->com.model->objects)
1461 free(aw->com.model->objects);
1462 free(aw->com.model);
1463 aw->com.model = NULL;
1464 }
1465
1466 static Bool
animEnsureModel(CompWindow * w)1467 animEnsureModel(CompWindow * w)
1468 {
1469 ANIM_WINDOW(w);
1470
1471 WindowEvent forWindowEvent = aw->com.curWindowEvent;
1472 AnimEffect forAnimEffect = aw->com.curAnimEffect;
1473
1474 int gridWidth = 2;
1475 int gridHeight = 2;
1476
1477 if (forAnimEffect->properties.initGridFunc)
1478 forAnimEffect->properties.initGridFunc (w, &gridWidth, &gridHeight);
1479
1480 Bool isShadeUnshadeEvent =
1481 (forWindowEvent == WindowEventShade ||
1482 forWindowEvent == WindowEventUnshade);
1483
1484 Bool wasShadeUnshadeEvent = aw->com.model &&
1485 (aw->com.model->forWindowEvent == WindowEventShade ||
1486 aw->com.model->forWindowEvent == WindowEventUnshade);
1487
1488 if (!aw->com.model ||
1489 gridWidth != aw->com.model->gridWidth ||
1490 gridHeight != aw->com.model->gridHeight ||
1491 (isShadeUnshadeEvent != wasShadeUnshadeEvent) ||
1492 aw->com.model->winWidth != WIN_W(w) || aw->com.model->winHeight != WIN_H(w))
1493 {
1494 animFreeModel(aw);
1495 aw->com.model = createModel(w, forWindowEvent, forAnimEffect,
1496 gridWidth, gridHeight);
1497 if (!aw->com.model)
1498 return FALSE;
1499 }
1500
1501 return TRUE;
1502 }
1503
cleanUpParentChildChainItem(AnimScreen * as,AnimWindow * aw)1504 static void cleanUpParentChildChainItem(AnimScreen *as, AnimWindow *aw)
1505 {
1506 if (aw->winThisIsPaintedBefore && !aw->winThisIsPaintedBefore->destroyed)
1507 {
1508 AnimWindow *aw2 =
1509 GET_ANIM_WINDOW(aw->winThisIsPaintedBefore, as);
1510 if (aw2)
1511 aw2->winToBePaintedBeforeThis = NULL;
1512 }
1513 aw->winThisIsPaintedBefore = NULL;
1514 aw->moreToBePaintedPrev = NULL;
1515 aw->moreToBePaintedNext = NULL;
1516 aw->isDodgeSubject = FALSE;
1517 aw->skipPostPrepareScreen = FALSE;
1518 }
1519
1520 // Update this window's dodgers so that they no longer point
1521 // to this window as their subject
1522 static void
clearDodgersSubject(AnimScreen * as,CompWindow * w)1523 clearDodgersSubject (AnimScreen *as, CompWindow *w)
1524 {
1525 CompWindow *dw;
1526 AnimWindow *adw;
1527
1528 ANIM_WINDOW (w);
1529
1530 for (dw = aw->dodgeChainStart; dw; dw = adw->dodgeChainNext)
1531 {
1532 adw = GET_ANIM_WINDOW(dw, as);
1533 if (!adw)
1534 break;
1535 if (adw->dodgeSubjectWin == w)
1536 adw->dodgeSubjectWin = NULL;
1537 }
1538 }
1539
1540 // Remove this dodger window from the dodge chain
1541 static void
removeFromDodgeChain(AnimScreen * as,CompWindow * dw)1542 removeFromDodgeChain (AnimScreen *as, CompWindow *dw)
1543 {
1544 AnimWindow *adw = GET_ANIM_WINDOW(dw, as);
1545 if (!adw)
1546 return;
1547
1548 if (adw->dodgeSubjectWin)
1549 {
1550 AnimWindow *awSubject = GET_ANIM_WINDOW (adw->dodgeSubjectWin, as);
1551
1552 // if dw is the starting window in the dodge chain
1553 if (awSubject && awSubject->dodgeChainStart == dw)
1554 {
1555 if (adw->dodgeChainNext)
1556 {
1557 // Subject is being raised and there is a next dodger.
1558 awSubject->dodgeChainStart = adw->dodgeChainNext;
1559 }
1560 else
1561 {
1562 // Subject is being lowered or there is no next dodger.
1563 // In either case, we can point chain start to prev. in chain,
1564 // which can be NULL.
1565 awSubject->dodgeChainStart = adw->dodgeChainPrev;
1566 }
1567 }
1568 }
1569
1570 if (adw->dodgeChainNext)
1571 {
1572 AnimWindow *awNext = GET_ANIM_WINDOW (adw->dodgeChainNext, as);
1573
1574 // Point adw->next's prev. to adw->prev.
1575 if (awNext)
1576 awNext->dodgeChainPrev = adw->dodgeChainPrev;
1577 }
1578
1579 if (adw->dodgeChainPrev)
1580 {
1581 AnimWindow *awPrev = GET_ANIM_WINDOW (adw->dodgeChainPrev, as);
1582
1583 // Point adw->prev.'s next to adw->next
1584 if (awPrev)
1585 awPrev->dodgeChainNext = adw->dodgeChainNext;
1586 }
1587 }
1588
postAnimationCleanupCustom(CompWindow * w,Bool closing,Bool finishing,Bool clearMatchingRow)1589 static void postAnimationCleanupCustom (CompWindow * w,
1590 Bool closing,
1591 Bool finishing,
1592 Bool clearMatchingRow)
1593 {
1594 ANIM_WINDOW(w);
1595 ANIM_SCREEN(w->screen);
1596
1597 if (// make sure window shadows (which are not drawn by polygon engine)
1598 // are damaged
1599 (aw->com.curAnimEffect &&
1600 aw->com.curAnimEffect != AnimEffectNone &&
1601 aw->com.curAnimEffect != AnimEffectRandom &&
1602 aw->com.curAnimEffect->properties.addCustomGeometryFunc &&
1603 (aw->com.curWindowEvent == WindowEventOpen ||
1604 aw->com.curWindowEvent == WindowEventUnminimize ||
1605 aw->com.curWindowEvent == WindowEventUnshade ||
1606 aw->com.curWindowEvent == WindowEventFocus)) ||
1607 // make sure the window gets fully damaged with
1608 // effects that possibly have models that don't cover
1609 // the whole window (like in magic lamp with menus)
1610 aw->com.curAnimEffect == AnimEffectMagicLamp ||
1611 aw->com.curAnimEffect == AnimEffectVacuum ||
1612 // make sure dodging windows get one last damage
1613 aw->com.curAnimEffect == AnimEffectDodge ||
1614 // make sure non-animated closing windows get a damage
1615 (aw->com.curWindowEvent == WindowEventClose &&
1616 aw->com.curAnimEffect == AnimEffectNone))
1617 {
1618 updateBBWindow (NULL, w, &aw->BB);
1619 }
1620 // Clear winPassingThrough of each window
1621 // that this one was passing through
1622 // during focus effect
1623 if (aw->com.curAnimEffect == AnimEffectFocusFade)
1624 {
1625 CompWindow *w2;
1626 for (w2 = w->screen->windows; w2; w2 = w2->next)
1627 {
1628 AnimWindow *aw2;
1629
1630 aw2 = GET_ANIM_WINDOW(w2, as);
1631 if (aw2->winPassingThrough == w)
1632 aw2->winPassingThrough = NULL;
1633 }
1634 }
1635
1636 if (aw->com.curAnimEffect == AnimEffectFocusFade ||
1637 aw->com.curAnimEffect == AnimEffectDodge)
1638 {
1639 as->walkerAnimCount--;
1640 }
1641
1642 if (aw->com.curAnimEffect &&
1643 aw->com.curAnimEffect != AnimEffectNone &&
1644 aw->com.curAnimEffect != AnimEffectRandom &&
1645 aw->com.curAnimEffect->properties.cleanupFunc)
1646 aw->com.curAnimEffect->properties.cleanupFunc (w);
1647
1648 if (aw->isDodgeSubject)
1649 clearDodgersSubject (as, w);
1650 else if (aw->com.curAnimEffect == AnimEffectDodge)
1651 removeFromDodgeChain (as, w);
1652
1653 aw->com.curWindowEvent = WindowEventNone;
1654 aw->com.curAnimEffect = AnimEffectNone;
1655 aw->com.animOverrideProgressDir = 0;
1656 aw->com.usingTransform = FALSE;
1657
1658 aw->magicLampWaveCount = 0;
1659
1660 if (aw->magicLampWaves)
1661 {
1662 free (aw->magicLampWaves);
1663 aw->magicLampWaves = 0;
1664 }
1665
1666 if (aw->BB.x1 != MAXSHORT)
1667 {
1668 // damage BB
1669 damageBoundingBox (w);
1670 }
1671 aw->BB.x1 = aw->BB.y1 = MAXSHORT;
1672 aw->BB.x2 = aw->BB.y2 = MINSHORT;
1673
1674 Bool thereIsUnfinishedChainElem = FALSE;
1675
1676 // Look for still playing windows in parent-child chain
1677 CompWindow *wCur = aw->moreToBePaintedNext;
1678 while (wCur)
1679 {
1680 AnimWindow *awCur = GET_ANIM_WINDOW(wCur, as);
1681
1682 if (awCur->com.animRemainingTime > 0)
1683 {
1684 thereIsUnfinishedChainElem = TRUE;
1685 break;
1686 }
1687 wCur = awCur->moreToBePaintedNext;
1688 }
1689 if (!thereIsUnfinishedChainElem)
1690 {
1691 wCur = aw->moreToBePaintedPrev;
1692 while (wCur)
1693 {
1694 AnimWindow *awCur = GET_ANIM_WINDOW(wCur, as);
1695
1696 if (awCur->com.animRemainingTime > 0)
1697 {
1698 thereIsUnfinishedChainElem = TRUE;
1699 break;
1700 }
1701 wCur = awCur->moreToBePaintedPrev;
1702 }
1703 }
1704 if (closing || finishing || !thereIsUnfinishedChainElem)
1705 {
1706 // Finish off all windows in parent-child chain
1707 CompWindow *wCur = aw->moreToBePaintedNext;
1708 while (wCur)
1709 {
1710 AnimWindow *awCur = GET_ANIM_WINDOW(wCur, as);
1711 if (awCur->isDodgeSubject)
1712 clearDodgersSubject (as, wCur);
1713 wCur = awCur->moreToBePaintedNext;
1714 cleanUpParentChildChainItem(as, awCur);
1715 }
1716 wCur = w;
1717 while (wCur)
1718 {
1719 AnimWindow *awCur = GET_ANIM_WINDOW(wCur, as);
1720 if (awCur->isDodgeSubject)
1721 clearDodgersSubject (as, wCur);
1722 wCur = awCur->moreToBePaintedPrev;
1723 cleanUpParentChildChainItem(as, awCur);
1724 }
1725 }
1726
1727 aw->state = aw->newState;
1728
1729 if (clearMatchingRow)
1730 aw->curAnimSelectionRow = -1;
1731
1732 if (aw->com.drawRegion)
1733 XDestroyRegion(aw->com.drawRegion);
1734 aw->com.drawRegion = NULL;
1735 aw->com.useDrawRegion = FALSE;
1736
1737 aw->animInitialized = FALSE;
1738 aw->remainderSteps = 0;
1739 aw->com.animRemainingTime = 0;
1740
1741 // Reset dodge parameters
1742 aw->dodgeMaxAmount = 0;
1743 if (!(aw->moreToBePaintedPrev ||
1744 aw->moreToBePaintedNext))
1745 {
1746 aw->isDodgeSubject = FALSE;
1747 aw->skipPostPrepareScreen = FALSE;
1748 }
1749
1750 if (aw->restackInfo)
1751 {
1752 free(aw->restackInfo);
1753 aw->restackInfo = NULL;
1754 }
1755
1756 if (!finishing)
1757 {
1758 aw->ignoreDamage = TRUE;
1759 while (aw->unmapCnt)
1760 {
1761 unmapWindow(w);
1762 aw->unmapCnt--;
1763 }
1764 aw->ignoreDamage = FALSE;
1765 }
1766 while (aw->destroyCnt)
1767 {
1768 destroyWindow(w);
1769 aw->destroyCnt--;
1770 }
1771 }
1772
postAnimationCleanup(CompWindow * w)1773 void postAnimationCleanup (CompWindow * w)
1774 {
1775 postAnimationCleanupCustom (w, FALSE, FALSE, TRUE);
1776 }
1777
1778 static void
postAnimationCleanupPrev(CompWindow * w,Bool closing,Bool clearMatchingRow)1779 postAnimationCleanupPrev (CompWindow * w,
1780 Bool closing,
1781 Bool clearMatchingRow)
1782 {
1783 ANIM_WINDOW(w);
1784
1785 int curAnimSelectionRow = aw->curAnimSelectionRow;
1786 // Use previous event's anim selection row
1787 aw->curAnimSelectionRow = aw->prevAnimSelectionRow;
1788
1789 postAnimationCleanupCustom (w, closing, FALSE, clearMatchingRow);
1790
1791 // Restore current event's anim selection row
1792 aw->curAnimSelectionRow = curAnimSelectionRow;
1793 }
1794
1795 static void
animActivateEvent(CompScreen * s,Bool activating)1796 animActivateEvent (CompScreen *s,
1797 Bool activating)
1798 {
1799 ANIM_SCREEN(s);
1800
1801 if (activating)
1802 {
1803 if (as->animInProgress)
1804 return;
1805 }
1806 as->animInProgress = activating;
1807
1808 CompOption o[2];
1809
1810 o[0].type = CompOptionTypeInt;
1811 o[0].name = "root";
1812 o[0].value.i = s->root;
1813
1814 o[1].type = CompOptionTypeBool;
1815 o[1].name = "active";
1816 o[1].value.b = activating;
1817
1818 (*s->display->handleCompizEvent) (s->display, "animation", "activate", o, 2);
1819 }
1820
1821 static const PluginEventInfo watchedPlugins[] =
1822 {
1823 {"switcher", "activate"},
1824 {"staticswitcher", "activate"},
1825 {"ring", "activate"},
1826 {"shift", "activate"},
1827 {"stackswitch", "activate"},
1828 {"scale", "activate"},
1829 // the above ones are the switchers
1830 {"group", "tabChangeActivate"},
1831 {"fadedesktop", "activate"},
1832 };
1833
1834 static Bool
otherPluginsActive(AnimScreen * as)1835 otherPluginsActive(AnimScreen *as)
1836 {
1837 int i;
1838 for (i = 0; i < NUM_WATCHED_PLUGINS; i++)
1839 if (as->pluginActive[i])
1840 return TRUE;
1841 return FALSE;
1842 }
1843
1844 static inline Bool
isWinVisible(CompWindow * w)1845 isWinVisible(CompWindow *w)
1846 {
1847 return (!w->destroyed &&
1848 !(!w->shaded &&
1849 (w->attrib.map_state != IsViewable)));
1850 }
1851
1852 static inline void
getHostedOnWin(AnimScreen * as,CompWindow * w,CompWindow * wHost)1853 getHostedOnWin (AnimScreen *as,
1854 CompWindow *w,
1855 CompWindow *wHost)
1856 {
1857 ANIM_WINDOW(w);
1858 AnimWindow *awHost = GET_ANIM_WINDOW(wHost, as);
1859 awHost->winToBePaintedBeforeThis = w;
1860 aw->winThisIsPaintedBefore = wHost;
1861 }
1862
1863 static void
initiateFocusAnimation(CompWindow * w)1864 initiateFocusAnimation(CompWindow *w)
1865 {
1866 CompScreen *s = w->screen;
1867 ANIM_SCREEN(s);
1868 ANIM_WINDOW(w);
1869 int duration = 200;
1870
1871 if (aw->com.curWindowEvent != WindowEventNone || otherPluginsActive(as))
1872 return;
1873
1874 // Check the "switcher post-wait" counter that effectively prevents
1875 // focus animation to be initiated when the zoom option value is low
1876 // in Switcher.
1877 if (switcherPostWait)
1878 return;
1879
1880 AnimEffect chosenEffect =
1881 getMatchingAnimSelection (w, AnimEventFocus, &duration);
1882
1883 if (chosenEffect != AnimEffectNone &&
1884 // On unminimization, focus event is fired first.
1885 // When this happens and minimize is in progress,
1886 // don't prevent rewinding of minimize when unminimize is fired
1887 // right after this focus event.
1888 aw->com.curWindowEvent != WindowEventMinimize)
1889 {
1890 CompWindow *wStart = NULL;
1891 CompWindow *wEnd = NULL;
1892 CompWindow *wOldAbove = NULL;
1893
1894 RestackInfo *restackInfo = aw->restackInfo;
1895 Bool raised = TRUE;
1896
1897 if (restackInfo)
1898 {
1899 wStart = restackInfo->wStart;
1900 wEnd = restackInfo->wEnd;
1901 wOldAbove = restackInfo->wOldAbove;
1902 raised = restackInfo->raised;
1903 }
1904
1905 // FOCUS event!
1906
1907 aw->com.curWindowEvent = WindowEventFocus;
1908 aw->com.curAnimEffect = chosenEffect;
1909
1910 if (chosenEffect == AnimEffectFocusFade ||
1911 chosenEffect == AnimEffectDodge)
1912 {
1913 as->walkerAnimCount++;
1914
1915 // Find union region of all windows that will be
1916 // faded through by w. If the region is empty, don't
1917 // run focus fade effect.
1918
1919 Region fadeRegion = XCreateRegion();
1920 Region thisAndSubjectIntersection = XCreateRegion();
1921 Region thisWinRegion = XCreateRegion();
1922 Region subjectWinRegion = XCreateRegion();
1923 XRectangle rect;
1924
1925 int numDodgingWins = 0;
1926
1927 // Compute subject win. region
1928 rect.x = BORDER_X(w);
1929 rect.y = BORDER_Y(w);
1930 rect.width = BORDER_W(w);
1931 rect.height = BORDER_H(w);
1932 XUnionRectWithRegion(&rect, &emptyRegion, subjectWinRegion);
1933
1934 CompWindow *dw; // Dodge or Focus fade candidate window
1935 for (dw = wStart; dw && dw != wEnd->next; dw = dw->next)
1936 {
1937 if (!isWinVisible(dw) ||
1938 dw->wmType & CompWindowTypeDockMask)
1939 continue;
1940
1941 AnimWindow *adw = GET_ANIM_WINDOW(dw, as);
1942
1943 // Skip windows that have been restacked
1944 if (dw != wEnd && adw->restackInfo)
1945 continue;
1946
1947 // Skip subject window for focus fade
1948 if (w == dw && chosenEffect == AnimEffectFocusFade)
1949 continue;
1950
1951 Bool nonMatching = FALSE;
1952 if (chosenEffect == AnimEffectDodge &&
1953 getMatchingAnimSelection (dw, AnimEventFocus, NULL) !=
1954 chosenEffect)
1955 nonMatching = TRUE;
1956
1957 // Compute intersection of this (dw) with subject
1958 rect.x = BORDER_X(dw);
1959 rect.y = BORDER_Y(dw);
1960 rect.width = BORDER_W(dw);
1961 rect.height = BORDER_H(dw);
1962 XUnionRectWithRegion(&rect, &emptyRegion, thisWinRegion);
1963 XIntersectRegion(subjectWinRegion, thisWinRegion,
1964 thisAndSubjectIntersection);
1965 XUnionRegion(fadeRegion, thisAndSubjectIntersection,
1966 fadeRegion);
1967
1968 if (chosenEffect == AnimEffectFocusFade)
1969 {
1970 adw->winPassingThrough = w;
1971 }
1972 else if (chosenEffect == AnimEffectDodge &&
1973 !XEmptyRegion(thisAndSubjectIntersection) &&
1974 (adw->com.curAnimEffect == AnimEffectNone ||
1975 (adw->com.curAnimEffect == AnimEffectDodge)) &&
1976 dw->id != w->id) // don't let the subject dodge itself
1977 {
1978 // Mark this window for dodge
1979
1980 numDodgingWins++;
1981 adw->dodgeOrder = numDodgingWins;
1982 if (nonMatching) // Use neg. values for non-matching windows
1983 adw->dodgeOrder *= -1;
1984 }
1985 }
1986
1987 if (XEmptyRegion(fadeRegion))
1988 {
1989 // empty intersection -> won't be drawn (will end prematurely)
1990 duration = 0;
1991 }
1992 if ((chosenEffect == AnimEffectFocusFade ||
1993 chosenEffect == AnimEffectDodge) && wOldAbove)
1994 {
1995 // Store this window in the next window
1996 // so that this is drawn before that,
1997 // i.e. in its old place
1998 getHostedOnWin(as, w, wOldAbove);
1999 }
2000
2001 if (chosenEffect == AnimEffectDodge)
2002 {
2003 float maxTransformTotalProgress = 0;
2004 float dodgeMaxStartProgress =
2005 numDodgingWins *
2006 animGetF (w, ANIM_SCREEN_OPTION_DODGE_GAP_RATIO) *
2007 duration / 1000.0f;
2008
2009 CompWindow *wDodgeChainLastVisited = NULL;
2010
2011 animActivateEvent(s, TRUE);
2012
2013 aw->isDodgeSubject = TRUE;
2014 aw->dodgeChainStart = NULL;
2015
2016 for (dw = wStart; dw && dw != wEnd->next; dw = dw->next)
2017 {
2018 AnimWindow *adw = GET_ANIM_WINDOW(dw, as);
2019
2020 // Skip non-dodgers
2021 if (adw->dodgeOrder == 0)
2022 continue;
2023
2024 // Initiate dodge for this window
2025
2026 Bool stationaryDodger = FALSE;
2027 if (adw->dodgeOrder < 0)
2028 {
2029 adw->dodgeOrder *= -1; // Make it positive again
2030 stationaryDodger = TRUE;
2031 }
2032 if (adw->com.curAnimEffect != AnimEffectDodge)
2033 {
2034 adw->com.curAnimEffect = AnimEffectDodge;
2035 as->walkerAnimCount++;
2036 }
2037 adw->dodgeSubjectWin = w;
2038
2039 // Slight change in dodge movement start
2040 // to reflect stacking order of dodgy windows
2041 if (raised)
2042 adw->com.transformStartProgress =
2043 dodgeMaxStartProgress *
2044 (adw->dodgeOrder - 1) / numDodgingWins;
2045 else
2046 adw->com.transformStartProgress =
2047 dodgeMaxStartProgress *
2048 (1 - (float)adw->dodgeOrder / numDodgingWins);
2049
2050 float transformTotalProgress =
2051 1 + adw->com.transformStartProgress;
2052
2053 if (maxTransformTotalProgress < transformTotalProgress)
2054 maxTransformTotalProgress = transformTotalProgress;
2055
2056 // normalize
2057 adw->com.transformStartProgress /=
2058 transformTotalProgress;
2059
2060 if (stationaryDodger)
2061 {
2062 adw->com.transformStartProgress = 0;
2063 transformTotalProgress = 0;
2064 }
2065
2066 adw->com.animTotalTime =
2067 transformTotalProgress * duration;
2068 adw->com.animRemainingTime = adw->com.animTotalTime;
2069
2070 // Put window on dodge chain
2071
2072 // if dodge chain was started before
2073 if (wDodgeChainLastVisited)
2074 {
2075 AnimWindow *awDodgeChainLastVisited =
2076 GET_ANIM_WINDOW(wDodgeChainLastVisited, as);
2077 if (raised)
2078 awDodgeChainLastVisited->dodgeChainNext = dw;
2079 else
2080 awDodgeChainLastVisited->dodgeChainPrev = dw;
2081 }
2082 else if (raised) // mark chain start
2083 {
2084 aw->dodgeChainStart = dw;
2085 }
2086 if (raised)
2087 {
2088 adw->dodgeChainPrev = wDodgeChainLastVisited;
2089 adw->dodgeChainNext = NULL;
2090 }
2091 else
2092 {
2093 adw->dodgeChainPrev = NULL;
2094 adw->dodgeChainNext = wDodgeChainLastVisited;
2095 }
2096
2097 // Find direction (left, right, up, down)
2098 // that minimizes dodge amount
2099
2100 // Dodge amount (dodge shadows as well)
2101
2102 int dodgeAmount[4];
2103
2104 int i;
2105 for (i = 0; i < 4; i++)
2106 dodgeAmount[i] = DODGE_AMOUNT(w, dw, i);
2107
2108 int amountMin = abs(dodgeAmount[0]);
2109 int iMin = 0;
2110 for (i=1; i<4; i++)
2111 {
2112 int absAmount = abs(dodgeAmount[i]);
2113 if (absAmount < amountMin)
2114 {
2115 amountMin = absAmount;
2116 iMin = i;
2117 }
2118 }
2119 adw->dodgeMaxAmount = dodgeAmount[iMin];
2120 adw->dodgeDirection = iMin;
2121
2122 wDodgeChainLastVisited = dw;
2123
2124 // Reset back to 0 for the next dodge calculation
2125 adw->dodgeOrder = 0;
2126 }
2127 if (aw->isDodgeSubject)
2128 aw->dodgeMaxAmount = 0;
2129
2130 // if subject is being lowered,
2131 // point chain-start to the topmost dodging window
2132 if (!raised)
2133 {
2134 aw->dodgeChainStart = wDodgeChainLastVisited;
2135 }
2136
2137 aw->com.animTotalTime =
2138 maxTransformTotalProgress * duration;
2139 }
2140
2141 XDestroyRegion (fadeRegion);
2142 XDestroyRegion (thisAndSubjectIntersection);
2143 XDestroyRegion (thisWinRegion);
2144 XDestroyRegion (subjectWinRegion);
2145 }
2146
2147 if (!animEnsureModel(w))
2148 {
2149 postAnimationCleanup (w);
2150 return;
2151 }
2152
2153 animActivateEvent(s, TRUE);
2154
2155 if (chosenEffect != AnimEffectDodge)
2156 aw->com.animTotalTime = duration;
2157 aw->com.animRemainingTime = aw->com.animTotalTime;
2158
2159 damagePendingOnScreen (s);
2160 }
2161 }
2162
2163 // returns whether this window is relevant for fade focus
2164 static Bool
relevantForFadeFocus(CompWindow * nw)2165 relevantForFadeFocus(CompWindow *nw)
2166 {
2167 if (!((nw->wmType &
2168 // these two are to be used as "host" windows
2169 // to host the painting of windows being focused
2170 // at a stacking order lower than them
2171 (CompWindowTypeDockMask | CompWindowTypeSplashMask)) ||
2172 nw->wmType == CompWindowTypeNormalMask ||
2173 nw->wmType == CompWindowTypeDialogMask ||
2174 nw->wmType == CompWindowTypeUtilMask ||
2175 nw->wmType == CompWindowTypeUnknownMask))
2176 {
2177 return FALSE;
2178 }
2179 return isWinVisible(nw);
2180 }
2181
2182 static Bool
restackInfoStillGood(CompScreen * s,RestackInfo * restackInfo)2183 restackInfoStillGood(CompScreen *s, RestackInfo *restackInfo)
2184 {
2185 Bool wStartGood = FALSE;
2186 Bool wEndGood = FALSE;
2187 Bool wOldAboveGood = FALSE;
2188 Bool wRestackedGood = FALSE;
2189
2190 CompWindow *w;
2191 for (w = s->windows; w; w = w->next)
2192 {
2193 if (restackInfo->wStart == w && isWinVisible(w))
2194 wStartGood = TRUE;
2195 if (restackInfo->wEnd == w && isWinVisible(w))
2196 wEndGood = TRUE;
2197 if (restackInfo->wRestacked == w && isWinVisible(w))
2198 wRestackedGood = TRUE;
2199 if (restackInfo->wOldAbove == w && isWinVisible(w))
2200 wOldAboveGood = TRUE;
2201 }
2202 return (wStartGood && wEndGood && wOldAboveGood && wRestackedGood);
2203 }
2204
2205 // Reset stacking related info
2206 static void
resetStackingInfo(CompScreen * s)2207 resetStackingInfo (CompScreen *s)
2208 {
2209 CompWindow *w;
2210 for (w = s->windows; w; w = w->next)
2211 {
2212 ANIM_WINDOW (w);
2213
2214 aw->configureNotified = FALSE;
2215 if (aw->restackInfo)
2216 {
2217 free (aw->restackInfo);
2218 aw->restackInfo = NULL;
2219 }
2220 }
2221 }
2222
2223 // Returns TRUE if linking wCur to wNext would not result
2224 // in a circular chain being formed.
2225 static Bool
wontCreateCircularChain(CompWindow * wCur,CompWindow * wNext)2226 wontCreateCircularChain (CompWindow *wCur, CompWindow *wNext)
2227 {
2228 ANIM_SCREEN (wCur->screen);
2229 AnimWindow *awNext = NULL;
2230
2231 while (wNext)
2232 {
2233 if (wNext == wCur) // would form circular chain
2234 return FALSE;
2235
2236 awNext = GET_ANIM_WINDOW (wNext, as);
2237 if (!awNext)
2238 return FALSE;
2239
2240 wNext = awNext->moreToBePaintedNext;
2241 }
2242 return TRUE;
2243 }
2244
animPreparePaintScreen(CompScreen * s,int msSinceLastPaint)2245 static void animPreparePaintScreen(CompScreen * s, int msSinceLastPaint)
2246 {
2247 CompWindow *w;
2248
2249 ANIM_SCREEN(s);
2250
2251 // Check and update "switcher post wait" counter
2252 if (switcherPostWait > 0)
2253 {
2254 switcherPostWait++;
2255 if (switcherPostWait > 4) // wait over
2256 {
2257 switcherPostWait = 0;
2258
2259 // Reset stacking related info since it will
2260 // cause problems because of the restacking
2261 // just done by Switcher.
2262 resetStackingInfo (s);
2263 }
2264 }
2265
2266 if (as->aWinWasRestackedJustNow)
2267 {
2268 /*
2269 Handle focusing windows with multiple utility/dialog windows
2270 (like gobby), as in this case where gobby was raised with its
2271 utility windows:
2272
2273 was: C0001B 36000A5 1E0000C 1E0005B 1E00050 3205B63 600003
2274 now: C0001B 36000A5 1E0000C 1E00050 3205B63 1E0005B 600003
2275
2276 was: C0001B 36000A5 1E0000C 1E00050 3205B63 1E0005B 600003
2277 now: C0001B 36000A5 1E0000C 3205B63 1E00050 1E0005B 600003
2278
2279 was: C0001B 36000A5 1E0000C 3205B63 1E00050 1E0005B 600003
2280 now: C0001B 36000A5 3205B63 1E0000C 1E00050 1E0005B 600003
2281 */
2282 CompWindow *wOldAbove = NULL;
2283 for (w = s->windows; w; w = w->next)
2284 {
2285 ANIM_WINDOW(w);
2286 if (aw->restackInfo)
2287 {
2288 if (aw->com.curWindowEvent != WindowEventNone ||
2289 otherPluginsActive(as) ||
2290 // Don't animate with stale restack info
2291 !restackInfoStillGood(s, aw->restackInfo))
2292 {
2293 continue;
2294 }
2295 if (!wOldAbove)
2296 {
2297 // Pick the old above of the bottommost one
2298 wOldAbove = aw->restackInfo->wOldAbove;
2299 }
2300 else
2301 {
2302 // Use as wOldAbove for every focus fading window
2303 // (i.e. the utility/dialog windows of an app.)
2304 if (wOldAbove != w)
2305 aw->restackInfo->wOldAbove = wOldAbove;
2306 }
2307 }
2308 }
2309 // do in reverse order so that focus-fading chains are handled
2310 // properly
2311 for (w = s->reverseWindows; w; w = w->prev)
2312 {
2313 ANIM_WINDOW(w);
2314 if (aw->restackInfo)
2315 {
2316 if (aw->com.curWindowEvent != WindowEventNone ||
2317 // Don't initiate focus anim for current dodgers
2318 aw->com.curAnimEffect != AnimEffectNone ||
2319 // Don't initiate focus anim for windows being passed thru
2320 aw->winPassingThrough ||
2321 otherPluginsActive(as) ||
2322 // Don't animate with stale restack info
2323 !restackInfoStillGood(s, aw->restackInfo))
2324 {
2325 free(aw->restackInfo);
2326 aw->restackInfo = NULL;
2327 continue;
2328 }
2329
2330 // Find the first window at a higher stacking order than w
2331 CompWindow *nw;
2332 for (nw = w->next; nw; nw = nw->next)
2333 {
2334 if (relevantForFadeFocus(nw))
2335 break;
2336 }
2337
2338 // If w is being lowered, there has to be a window
2339 // at a higher stacking position than w (like a panel)
2340 // which this w's copy can be painted before.
2341 // Otherwise the animation will only show w fading in
2342 // rather than 2 copies of it cross-fading.
2343 if (!aw->restackInfo->raised && !nw)
2344 {
2345 // Free unnecessary restackInfo
2346 free(aw->restackInfo);
2347 aw->restackInfo = NULL;
2348 continue;
2349 }
2350
2351 // Check if above window is focus-fading too.
2352 // (like a dialog of an app. window)
2353 // If so, focus-fade this together with the one above
2354 // (link to it)
2355 if (nw)
2356 {
2357 AnimWindow *awNext = GET_ANIM_WINDOW(nw, as);
2358 if (awNext && awNext->winThisIsPaintedBefore &&
2359 wontCreateCircularChain (w, nw))
2360 {
2361 awNext->moreToBePaintedPrev = w;
2362 aw->moreToBePaintedNext = nw;
2363 aw->restackInfo->wOldAbove =
2364 awNext->winThisIsPaintedBefore;
2365 }
2366 }
2367 initiateFocusAnimation(w);
2368 }
2369 }
2370
2371 for (w = s->reverseWindows; w; w = w->prev)
2372 {
2373 ANIM_WINDOW(w);
2374
2375 if (!aw->isDodgeSubject)
2376 continue;
2377 Bool dodgersAreOnlySubjects = TRUE;
2378 CompWindow *dw;
2379 AnimWindow *adw;
2380 for (dw = aw->dodgeChainStart; dw; dw = adw->dodgeChainNext)
2381 {
2382 adw = GET_ANIM_WINDOW(dw, as);
2383 if (!adw)
2384 break;
2385 if (!adw->isDodgeSubject)
2386 dodgersAreOnlySubjects = FALSE;
2387 }
2388 if (dodgersAreOnlySubjects)
2389 aw->skipPostPrepareScreen = TRUE;
2390 }
2391 }
2392
2393 if (as->animInProgress)
2394 {
2395 AnimWindow *aw;
2396 Bool animStillInProgress = FALSE;
2397
2398 for (w = s->windows; w; w = w->next)
2399 {
2400 aw = GET_ANIM_WINDOW(w, as);
2401
2402 if (aw->com.animRemainingTime > 0 &&
2403 (!aw->com.curAnimEffect ||
2404 aw->com.curAnimEffect == AnimEffectNone ||
2405 aw->com.curAnimEffect == AnimEffectRandom))
2406 {
2407 postAnimationCleanup (w);
2408 }
2409 else if (aw->com.animRemainingTime > 0)
2410 {
2411 if (aw->com.curAnimEffect->properties.prePrepPaintScreenFunc &&
2412 aw->com.curAnimEffect->properties.prePrepPaintScreenFunc
2413 (w, msSinceLastPaint))
2414 animStillInProgress = TRUE;
2415
2416 // If just starting, call fx init func.
2417 if (!aw->animInitialized &&
2418 aw->com.curAnimEffect->properties.initFunc)
2419 {
2420 if (!aw->com.curAnimEffect->properties.initFunc (w))
2421 {
2422 // Abort this window's animation
2423 postAnimationCleanup (w);
2424 continue;
2425 }
2426 }
2427
2428 if (aw->com.model &&
2429 (aw->com.model->winWidth != WIN_W(w) ||
2430 aw->com.model->winHeight != WIN_H(w)))
2431 {
2432 // model needs update
2433 // re-create model
2434 if (!animEnsureModel (w))
2435 {
2436 // Abort this window's animation
2437 postAnimationCleanup (w);
2438 continue;
2439 }
2440 }
2441
2442 if (aw->com.curAnimEffect->properties.updateBBFunc)
2443 {
2444 copyResetBB (aw);
2445
2446 if (!aw->animInitialized &&
2447 (aw->com.curWindowEvent == WindowEventClose ||
2448 aw->com.curWindowEvent == WindowEventMinimize ||
2449 aw->com.curWindowEvent == WindowEventShade ||
2450 ((aw->com.curWindowEvent == WindowEventFocus ||
2451 // for dodging windows
2452 aw->com.curAnimEffect == AnimEffectDodge) &&
2453 !aw->isDodgeSubject)))
2454 updateBBWindow (NULL, w, &aw->BB);
2455 }
2456 aw->animInitialized = TRUE;
2457
2458 if (aw->com.curAnimEffect->properties.animStepFunc)
2459 aw->com.curAnimEffect->properties.animStepFunc
2460 (w, msSinceLastPaint);
2461
2462 if (aw->com.curAnimEffect->properties.updateBBFunc)
2463 {
2464 int i;
2465 for (i = 0; i < s->nOutputDev; i++)
2466 aw->com.curAnimEffect->properties.
2467 updateBBFunc (&s->outputDev[i], w, &aw->BB);
2468
2469 if (!(s->damageMask & COMP_SCREEN_DAMAGE_ALL_MASK))
2470 damageBoundingBox (w);
2471 }
2472
2473 if (aw->com.animRemainingTime <= 0)
2474 {
2475 // Animation done
2476 postAnimationCleanup (w);
2477 }
2478 animStillInProgress |= (aw->com.animRemainingTime > 0);
2479 }
2480
2481 if (aw->com.animRemainingTime <= 0)
2482 {
2483 if (aw->com.curAnimEffect != AnimEffectNone ||
2484 aw->unmapCnt > 0 || aw->destroyCnt > 0)
2485 {
2486 postAnimationCleanup (w);
2487 }
2488 aw->com.curWindowEvent = WindowEventNone;
2489 aw->com.curAnimEffect = AnimEffectNone;
2490 }
2491 }
2492
2493 for (w = s->windows; w; w = w->next)
2494 {
2495 aw = GET_ANIM_WINDOW(w, as);
2496 if (aw &&
2497 aw->com.curAnimEffect &&
2498 aw->com.curAnimEffect != AnimEffectNone &&
2499 aw->com.curAnimEffect != AnimEffectRandom &&
2500 aw->com.curAnimEffect->properties.postPrepPaintScreenFunc)
2501 {
2502 aw->com.curAnimEffect->properties.postPrepPaintScreenFunc (w);
2503 }
2504 }
2505
2506 if (!animStillInProgress)
2507 animActivateEvent(s, FALSE);
2508 }
2509
2510 UNWRAP(as, s, preparePaintScreen);
2511 (*s->preparePaintScreen) (s, msSinceLastPaint);
2512 WRAP(as, s, preparePaintScreen, animPreparePaintScreen);
2513 }
2514
animDonePaintScreen(CompScreen * s)2515 static void animDonePaintScreen(CompScreen * s)
2516 {
2517 ANIM_SCREEN(s);
2518
2519 if (as->animInProgress)
2520 damagePendingOnScreen (s);
2521
2522 UNWRAP(as, s, donePaintScreen);
2523 (*s->donePaintScreen) (s);
2524 WRAP(as, s, donePaintScreen, animDonePaintScreen);
2525 }
2526
2527 // Scales z by 0 and does perspective distortion so that it
2528 // looks the same wherever on the screen
2529 void
perspectiveDistortAndResetZ(CompScreen * s,CompTransform * transform)2530 perspectiveDistortAndResetZ (CompScreen *s,
2531 CompTransform *transform)
2532 {
2533 float v = -1.0 / s->width;
2534 /*
2535 This does
2536 transform = M * transform, where M is
2537 1, 0, 0, 0,
2538 0, 1, 0, 0,
2539 0, 0, 0, v,
2540 0, 0, 0, 1
2541 */
2542 float *m = transform->m;
2543 m[8] = v * m[12];
2544 m[9] = v * m[13];
2545 m[10] = v * m[14];
2546 m[11] = v * m[15];
2547 }
2548
2549 void
applyPerspectiveSkew(CompOutput * output,CompTransform * transform,Point * center)2550 applyPerspectiveSkew (CompOutput *output,
2551 CompTransform *transform,
2552 Point *center)
2553 {
2554 GLfloat skewx = -(((center->x - output->region.extents.x1) -
2555 output->width / 2) * 1.15);
2556 GLfloat skewy = -(((center->y - output->region.extents.y1) -
2557 output->height / 2) * 1.15);
2558
2559 /* transform = M * transform, where M is the skew matrix
2560 {1,0,0,0,
2561 0,1,0,0,
2562 skewx,skewy,1,0,
2563 0,0,0,1};
2564 */
2565
2566 float *m = transform->m;
2567 m[8] = skewx * m[0] + skewy * m[4] + m[8];
2568 m[9] = skewx * m[1] + skewy * m[5] + m[9];
2569 m[10] = skewx * m[2] + skewy * m[6] + m[10];
2570 m[11] = skewx * m[3] + skewy * m[7] + m[11];
2571 }
2572
2573 static void
animAddWindowGeometry(CompWindow * w,CompMatrix * matrix,int nMatrix,Region region,Region clip)2574 animAddWindowGeometry(CompWindow * w,
2575 CompMatrix * matrix,
2576 int nMatrix, Region region, Region clip)
2577 {
2578 ANIM_WINDOW(w);
2579 ANIM_SCREEN(w->screen);
2580
2581 // if window is being animated
2582 if (aw->com.animRemainingTime > 0 && aw->com.model &&
2583 !(aw->com.curAnimEffect->properties.letOthersDrawGeomsFunc &&
2584 aw->com.curAnimEffect->properties.letOthersDrawGeomsFunc (w)))
2585 {
2586 BoxPtr pClip;
2587 int nClip;
2588 int nVertices, nIndices;
2589 GLushort *i;
2590 GLfloat *v;
2591 int x1, y1, x2, y2;
2592 float width, height;
2593 float winContentsY, winContentsHeight;
2594 float deformedX, deformedY;
2595 float deformedZ = 0;
2596 int nVertX, nVertY, wx, wy;
2597 int vSize, it;
2598 float gridW, gridH, x, y;
2599 Bool rect = TRUE;
2600 Bool useTextureQ = FALSE;
2601 Model *model = aw->com.model;
2602 Region awRegion = NULL;
2603
2604 Bool notUsing3dCoords =
2605 !aw->com.curAnimEffect->properties.modelAnimIs3D;
2606
2607 // Use Q texture coordinate to avoid jagged-looking quads
2608 // http://www.r3.nu/~cass/qcoord/
2609 if (aw->com.curAnimEffect->properties.useQTexCoord)
2610 useTextureQ = TRUE;
2611
2612 if (aw->com.useDrawRegion)
2613 {
2614 awRegion = XCreateRegion();
2615 XIntersectRegion (region, aw->com.drawRegion, awRegion);
2616 nClip = awRegion->numRects;
2617 pClip = awRegion->rects;
2618 }
2619 else
2620 {
2621 nClip = region->numRects;
2622 pClip = region->rects;
2623 }
2624
2625 if (nClip == 0) // nothing to do
2626 {
2627 if (awRegion)
2628 XDestroyRegion(awRegion);
2629 return;
2630 }
2631
2632 for (it = 0; it < nMatrix; it++)
2633 {
2634 if (matrix[it].xy != 0.0f || matrix[it].yx != 0.0f)
2635 {
2636 rect = FALSE;
2637 break;
2638 }
2639 }
2640
2641 w->drawWindowGeometry = animDrawWindowGeometry;
2642
2643 if (aw->com.curAnimEffect->properties.addCustomGeometryFunc)
2644 {
2645 if (nMatrix == 0)
2646 return;
2647 aw->com.curAnimEffect->properties.
2648 addCustomGeometryFunc (w, nClip, pClip,
2649 nMatrix, matrix);
2650
2651 // If addGeometryFunc exists, it is expected to do everthing
2652 // to add geometries (instead of the rest of this function).
2653
2654 if (w->vCount == 0) // if there is no vertex
2655 {
2656 // put a dummy quad in vertices and indices
2657
2658 w->texUnits = 1;
2659 w->texCoordSize = 4;
2660 vSize = 3 + w->texUnits * w->texCoordSize;
2661
2662 if (4 > w->indexSize)
2663 {
2664 if (!moreWindowIndices(w, 4))
2665 return;
2666 }
2667 if (4 * vSize > w->vertexSize)
2668 {
2669 if (!moreWindowVertices(w, 4 * vSize))
2670 return;
2671 }
2672 w->vCount = 4;
2673 w->indexCount = 4;
2674 w->vertexStride = vSize;
2675
2676 // Clear dummy quad coordinates/indices
2677 memset(w->vertices, 0, sizeof(GLfloat) * 4 * vSize);
2678 memset(w->indices, 0, sizeof(GLushort) * 4);
2679 }
2680 return; // We're done here.
2681 }
2682
2683 // window coordinates and size
2684 wx = WIN_X(w);
2685 wy = WIN_Y(w);
2686 width = WIN_W(w);
2687 height = WIN_H(w);
2688
2689 // to be used if event is shade/unshade
2690 winContentsY = w->attrib.y;
2691 winContentsHeight = w->height;
2692
2693 w->texUnits = nMatrix;
2694
2695 if (w->vCount == 0)
2696 {
2697 // reset
2698 w->indexCount = 0;
2699 w->texCoordSize = 4;
2700 }
2701 w->vertexStride = 3 + w->texUnits * w->texCoordSize;
2702 vSize = w->vertexStride;
2703
2704 nVertices = w->vCount;
2705 nIndices = w->indexCount;
2706
2707 v = w->vertices + (nVertices * vSize);
2708 i = w->indices + nIndices;
2709
2710 // For each clip passed to this function
2711 for (; nClip--; pClip++)
2712 {
2713 x1 = pClip->x1;
2714 y1 = pClip->y1;
2715 x2 = pClip->x2;
2716 y2 = pClip->y2;
2717
2718 gridW = (float)width / (model->gridWidth - 1);
2719
2720 if (aw->com.curWindowEvent == WindowEventShade ||
2721 aw->com.curWindowEvent == WindowEventUnshade)
2722 {
2723 if (y1 < w->attrib.y) // if at top part
2724 {
2725 gridH = model->topHeight;
2726 }
2727 else if (y2 > w->attrib.y + w->height) // if at bottom
2728 {
2729 gridH = model->bottomHeight;
2730 }
2731 else // in window contents (only in Y coords)
2732 {
2733 float winContentsHeight =
2734 height - model->topHeight - model->bottomHeight;
2735 gridH = winContentsHeight / (model->gridHeight - 3);
2736 }
2737 }
2738 else
2739 gridH = (float)height / (model->gridHeight - 1);
2740
2741 // nVertX, nVertY: number of vertices for this clip in x and y dimensions
2742 // + 2 to avoid running short of vertices in some cases
2743 nVertX = ceil((x2 - x1) / gridW) + 2;
2744 nVertY = (gridH ? ceil((y2 - y1) / gridH) : 0) + 2;
2745
2746 // Allocate 4 indices for each quad
2747 int newIndexSize = nIndices + ((nVertX - 1) * (nVertY - 1) * 4);
2748
2749 if (newIndexSize > w->indexSize)
2750 {
2751 if (!moreWindowIndices(w, newIndexSize))
2752 return;
2753
2754 i = w->indices + nIndices;
2755 }
2756 // Assign quad vertices to indices
2757 int jx, jy;
2758 for (jy = 0; jy < nVertY - 1; jy++)
2759 {
2760 for (jx = 0; jx < nVertX - 1; jx++)
2761 {
2762 *i++ = nVertices + nVertX * (2 * jy + 1) + jx;
2763 *i++ = nVertices + nVertX * (2 * jy + 1) + jx + 1;
2764 *i++ = nVertices + nVertX * 2 * jy + jx + 1;
2765 *i++ = nVertices + nVertX * 2 * jy + jx;
2766
2767 nIndices += 4;
2768 }
2769 }
2770
2771 // Allocate vertices
2772 int newVertexSize =
2773 (nVertices + nVertX * (2 * nVertY - 2)) * vSize;
2774 if (newVertexSize > w->vertexSize)
2775 {
2776 if (!moreWindowVertices(w, newVertexSize))
2777 return;
2778
2779 v = w->vertices + (nVertices * vSize);
2780 }
2781
2782 float rowTexCoordQ = 1;
2783 float prevRowCellWidth = 0; // this initial value won't be used
2784 float rowCellWidth = 0;
2785
2786 // For each vertex
2787 for (jy = 0, y = y1; jy < nVertY; jy++)
2788 {
2789 float topiyFloat;
2790 Bool applyOffsets = TRUE;
2791
2792 if (y > y2)
2793 y = y2;
2794
2795 // Do calculations for y here to avoid repeating
2796 // them unnecessarily in the x loop
2797
2798 if (aw->com.curWindowEvent == WindowEventShade
2799 || aw->com.curWindowEvent == WindowEventUnshade)
2800 {
2801 if (y1 < w->attrib.y) // if at top part
2802 {
2803 topiyFloat = (y - WIN_Y(w)) / model->topHeight;
2804 topiyFloat = MIN(topiyFloat, 0.999); // avoid 1.0
2805 applyOffsets = FALSE;
2806 }
2807 else if (y2 > w->attrib.y + w->height) // if at bottom
2808 {
2809 topiyFloat = (model->gridHeight - 2) +
2810 (model->bottomHeight ? (y - winContentsY -
2811 winContentsHeight) /
2812 model->bottomHeight : 0);
2813 applyOffsets = FALSE;
2814 }
2815 else // in window contents (only in Y coords)
2816 {
2817 topiyFloat = (model->gridHeight - 3) *
2818 (y - winContentsY) / winContentsHeight + 1;
2819 }
2820 }
2821 else
2822 {
2823 topiyFloat = (model->gridHeight - 1) * (y - wy) / height;
2824 }
2825 // topiy should be at most (model->gridHeight - 2)
2826 int topiy = (int)(topiyFloat + 1e-4);
2827
2828 if (topiy == model->gridHeight - 1)
2829 topiy--;
2830 int bottomiy = topiy + 1;
2831 float iny = topiyFloat - topiy;
2832
2833 // End of calculations for y
2834
2835 for (jx = 0, x = x1; jx < nVertX; jx++)
2836 {
2837 if (x > x2)
2838 x = x2;
2839
2840 // find containing grid cell (leftix rightix) x (topiy bottomiy)
2841 float leftixFloat =
2842 (model->gridWidth - 1) * (x - wx) / width;
2843 int leftix = (int)(leftixFloat + 1e-4);
2844
2845 if (leftix == model->gridWidth - 1)
2846 leftix--;
2847 int rightix = leftix + 1;
2848
2849 // Objects that are at top, bottom, left, right corners of quad
2850 Object *objToTopLeft =
2851 &(model->objects[topiy * model->gridWidth + leftix]);
2852 Object *objToTopRight =
2853 &(model->objects[topiy * model->gridWidth + rightix]);
2854 Object *objToBottomLeft =
2855 &(model->objects[bottomiy * model->gridWidth + leftix]);
2856 Object *objToBottomRight =
2857 &(model->objects[bottomiy * model->gridWidth + rightix]);
2858
2859 // find position in cell by taking remainder of flooring
2860 float inx = leftixFloat - leftix;
2861
2862 // Interpolate to find deformed coordinates
2863
2864 float hor1x = (1 - inx) *
2865 objToTopLeft->position.x +
2866 inx * objToTopRight->position.x;
2867 float hor1y = (1 - inx) *
2868 objToTopLeft->position.y +
2869 inx * objToTopRight->position.y;
2870 float hor1z = notUsing3dCoords ? 0 :
2871 (1 - inx) *
2872 objToTopLeft->position.z +
2873 inx * objToTopRight->position.z;
2874 float hor2x = (1 - inx) *
2875 objToBottomLeft->position.x +
2876 inx * objToBottomRight->position.x;
2877 float hor2y = (1 - inx) *
2878 objToBottomLeft->position.y +
2879 inx * objToBottomRight->position.y;
2880 float hor2z = notUsing3dCoords ? 0 :
2881 (1 - inx) *
2882 objToBottomLeft->position.z +
2883 inx * objToBottomRight->position.z;
2884
2885 deformedX = (1 - iny) * hor1x + iny * hor2x;
2886 deformedY = (1 - iny) * hor1y + iny * hor2y;
2887 deformedZ = (1 - iny) * hor1z + iny * hor2z;
2888
2889 // Texture coordinates (s, t, r, q)
2890
2891 if (useTextureQ)
2892 {
2893 if (jx == 1)
2894 rowCellWidth = deformedX - v[-3];
2895
2896 // do only once per row for all rows except row 0
2897 if (jy > 0 && jx == 1)
2898 {
2899 rowTexCoordQ = (rowCellWidth / prevRowCellWidth);
2900
2901 for (it = 0; it < nMatrix; it++, v += 4)
2902 {
2903 // update first column
2904 // (since we didn't know rowTexCoordQ before)
2905 v[-vSize] *= rowTexCoordQ; // multiply s & t by q
2906 v[-vSize + 1] *= rowTexCoordQ;
2907 v[-vSize + 3] = rowTexCoordQ; // copy q
2908 }
2909 v -= nMatrix * 4;
2910 }
2911 }
2912
2913 // Loop for each texture element
2914 // (4 texture coordinates for each one)
2915 for (it = 0; it < nMatrix; it++, v += 4)
2916 {
2917 float offsetY = 0;
2918
2919 if (rect)
2920 {
2921 if (applyOffsets && y < y2)
2922 offsetY = objToTopLeft->offsetTexCoordForQuadAfter.y;
2923 v[0] = COMP_TEX_COORD_X (&matrix[it], x); // s
2924 v[1] = COMP_TEX_COORD_Y (&matrix[it], y + offsetY); // t
2925 }
2926 else
2927 {
2928 if (applyOffsets && y < y2)
2929 // FIXME:
2930 // The correct y offset below produces wrong
2931 // texture coordinates for some reason.
2932 offsetY = 0;
2933 // offsetY = objToTopLeft->offsetTexCoordForQuadAfter.y;
2934 v[0] = COMP_TEX_COORD_XY (&matrix[it], x, y + offsetY); // s
2935 v[1] = COMP_TEX_COORD_YX (&matrix[it], x, y + offsetY); // t
2936 }
2937 v[2] = 0; // r
2938
2939 if (0 < jy && jy < nVertY - 1)
2940 {
2941 // copy s, t, r to duplicate row
2942 memcpy(v + nVertX * vSize, v,
2943 3 * sizeof(GLfloat));
2944 v[3 + nVertX * vSize] = 1; // q
2945 }
2946
2947 if (applyOffsets &&
2948 objToTopLeft->offsetTexCoordForQuadBefore.y != 0)
2949 {
2950 // After copying to next row, update texture y coord
2951 // by following object's offset
2952 offsetY = objToTopLeft->offsetTexCoordForQuadBefore.y;
2953 if (rect)
2954 {
2955 v[1] = COMP_TEX_COORD_Y (&matrix[it], y + offsetY);
2956 }
2957 else
2958 {
2959 v[0] = COMP_TEX_COORD_XY (&matrix[it],
2960 x, y + offsetY);
2961 v[1] = COMP_TEX_COORD_YX (&matrix[it],
2962 x, y + offsetY);
2963 }
2964 }
2965 if (useTextureQ)
2966 {
2967 v[3] = rowTexCoordQ; // q
2968
2969 if (jx > 0) // since column 0 is updated when jx == 1
2970 {
2971 // multiply s & t by q
2972 v[0] *= rowTexCoordQ;
2973 v[1] *= rowTexCoordQ;
2974 }
2975 }
2976 else
2977 {
2978 v[3] = 1; // q
2979 }
2980 }
2981
2982 v[0] = deformedX;
2983 v[1] = deformedY;
2984 v[2] = deformedZ;
2985
2986 // Copy vertex coordinates to duplicate row
2987 if (0 < jy && jy < nVertY - 1)
2988 memcpy(v + nVertX * vSize, v, 3 * sizeof(GLfloat));
2989
2990 nVertices++;
2991
2992 // increment x properly (so that coordinates fall on grid intersections)
2993 x = rightix * gridW + wx;
2994
2995 v += 3; // move on to next vertex
2996 }
2997 if (useTextureQ)
2998 prevRowCellWidth = rowCellWidth;
2999
3000 if (0 < jy && jy < nVertY - 1)
3001 {
3002 v += nVertX * vSize; // skip the duplicate row
3003 nVertices += nVertX;
3004 }
3005 // increment y properly (so that coordinates fall on grid intersections)
3006 if (aw->com.curWindowEvent == WindowEventShade
3007 || aw->com.curWindowEvent == WindowEventUnshade)
3008 {
3009 y += gridH;
3010 }
3011 else
3012 {
3013 y = bottomiy * gridH + wy;
3014 }
3015 }
3016 }
3017 w->vCount = nVertices;
3018 w->indexCount = nIndices;
3019 if (awRegion)
3020 {
3021 XDestroyRegion(awRegion);
3022 awRegion = NULL;
3023 }
3024 }
3025 else
3026 {
3027 UNWRAP(as, w->screen, addWindowGeometry);
3028 (*w->screen->addWindowGeometry) (w, matrix, nMatrix, region, clip);
3029 WRAP(as, w->screen, addWindowGeometry, animAddWindowGeometry);
3030 }
3031 }
3032
3033 static void
animDrawWindowTexture(CompWindow * w,CompTexture * texture,const FragmentAttrib * attrib,unsigned int mask)3034 animDrawWindowTexture(CompWindow * w, CompTexture * texture,
3035 const FragmentAttrib *attrib,
3036 unsigned int mask)
3037 {
3038 ANIM_WINDOW(w);
3039 ANIM_SCREEN(w->screen);
3040
3041 if (aw->com.animRemainingTime > 0) // if animation in progress, store texture
3042 {
3043 aw->com.curPaintAttrib = *attrib;
3044 }
3045
3046 UNWRAP(as, w->screen, drawWindowTexture);
3047 (*w->screen->drawWindowTexture) (w, texture, attrib, mask);
3048 WRAP(as, w->screen, drawWindowTexture, animDrawWindowTexture);
3049 }
3050
3051 void
animDrawWindowGeometry(CompWindow * w)3052 animDrawWindowGeometry(CompWindow * w)
3053 {
3054 ANIM_WINDOW (w);
3055
3056 if (aw->com.curAnimEffect->properties.drawCustomGeometryFunc)
3057 {
3058 aw->com.curAnimEffect->properties.drawCustomGeometryFunc (w);
3059 return;
3060 }
3061 int texUnit = w->texUnits;
3062 int currentTexUnit = 0;
3063 int stride = 3 + texUnit * w->texCoordSize;
3064 GLfloat *vertices = w->vertices + (stride - 3);
3065
3066 stride *= sizeof(GLfloat);
3067
3068 glVertexPointer(3, GL_FLOAT, stride, vertices);
3069
3070 while (texUnit--)
3071 {
3072 if (texUnit != currentTexUnit)
3073 {
3074 w->screen->clientActiveTexture(GL_TEXTURE0_ARB + texUnit);
3075 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
3076 currentTexUnit = texUnit;
3077 }
3078 vertices -= w->texCoordSize;
3079 glTexCoordPointer(w->texCoordSize, GL_FLOAT, stride, vertices);
3080 }
3081
3082 glDrawElements(GL_QUADS, w->indexCount, GL_UNSIGNED_SHORT,
3083 w->indices);
3084
3085 // disable all texture coordinate arrays except 0
3086 texUnit = w->texUnits;
3087 if (texUnit > 1)
3088 {
3089 while (--texUnit)
3090 {
3091 (*w->screen->clientActiveTexture) (GL_TEXTURE0_ARB + texUnit);
3092 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
3093 }
3094
3095 (*w->screen->clientActiveTexture) (GL_TEXTURE0_ARB);
3096 }
3097 }
3098
3099 static Bool
animPaintWindow(CompWindow * w,const WindowPaintAttrib * attrib,const CompTransform * transform,Region region,unsigned int mask)3100 animPaintWindow(CompWindow * w,
3101 const WindowPaintAttrib * attrib,
3102 const CompTransform *transform,
3103 Region region, unsigned int mask)
3104 {
3105 Bool status;
3106
3107 ANIM_SCREEN(w->screen);
3108 ANIM_WINDOW(w);
3109
3110 if (aw->com.animRemainingTime > 0)
3111 {
3112 if (!as->animInProgress)
3113 {
3114 // This window shouldn't really be undergoing animation,
3115 // because it won't make progress with false as->animInProgress.
3116 postAnimationCleanup (w);
3117
3118 UNWRAP(as, w->screen, paintWindow);
3119 status = (*w->screen->paintWindow) (w, attrib, transform, region,
3120 mask);
3121 WRAP(as, w->screen, paintWindow, animPaintWindow);
3122
3123 return status;
3124 }
3125 if (aw->com.curAnimEffect == AnimEffectDodge &&
3126 aw->isDodgeSubject &&
3127 aw->walkerOverNewCopy)
3128 {
3129 // if aw is to be painted somewhere other than in its
3130 // original stacking order, we don't
3131 // need to paint it now
3132 return FALSE;
3133 }
3134 if (aw->com.curWindowEvent == WindowEventFocus && otherPluginsActive(as))
3135 postAnimationCleanup (w);
3136
3137 WindowPaintAttrib wAttrib = *attrib;
3138 CompTransform wTransform = *transform;
3139
3140 if (aw->com.curAnimEffect->properties.addCustomGeometryFunc)
3141 {
3142 // Use slightly smaller brightness to force core
3143 // to handle <max saturation case with <max brightness.
3144 // Otherwise polygon effects show fully unsaturated colors
3145 // in that case.
3146 wAttrib.brightness = MAX (0, wAttrib.brightness - 1);
3147 }
3148 w->indexCount = 0;
3149
3150 // TODO: should only happen for distorting effects
3151 mask |= PAINT_WINDOW_TRANSFORMED_MASK;
3152
3153 wAttrib.xScale = 1.0f;
3154 wAttrib.yScale = 1.0f;
3155
3156 if (aw->com.curAnimEffect->properties.updateWindowAttribFunc)
3157 aw->com.curAnimEffect->properties.
3158 updateWindowAttribFunc (w, &wAttrib);
3159
3160 if (aw->com.curAnimEffect->properties.updateWinTransformFunc)
3161 aw->com.curAnimEffect->properties.
3162 updateWinTransformFunc (w, &wTransform);
3163
3164 if (aw->com.curAnimEffect->properties.prePaintWindowFunc)
3165 aw->com.curAnimEffect->properties.prePaintWindowFunc (w);
3166
3167 UNWRAP(as, w->screen, paintWindow);
3168 status = (*w->screen->paintWindow) (w, &wAttrib, &wTransform, region, mask);
3169 WRAP(as, w->screen, paintWindow, animPaintWindow);
3170
3171 if (aw->com.curAnimEffect->properties.postPaintWindowFunc)
3172 {
3173 // Transform to make post-paint coincide with the window
3174 glPushMatrix ();
3175 glLoadMatrixf (wTransform.m);
3176
3177 aw->com.curAnimEffect->properties.postPaintWindowFunc (w);
3178
3179 glPopMatrix ();
3180 }
3181 }
3182 else
3183 {
3184 UNWRAP(as, w->screen, paintWindow);
3185 status = (*w->screen->paintWindow) (w, attrib, transform, region, mask);
3186 WRAP(as, w->screen, paintWindow, animPaintWindow);
3187 }
3188
3189 return status;
3190 }
3191
3192 // Go to the bottommost window in this "focus chain"
3193 // This chain is used to handle some cases: e.g when Find dialog
3194 // of an app is open, both windows should be faded when the Find
3195 // dialog is raised.
3196 static CompWindow*
getBottommostInFocusChain(CompWindow * w)3197 getBottommostInFocusChain (CompWindow *w)
3198 {
3199 if (!w)
3200 return w;
3201
3202 ANIM_WINDOW (w);
3203 ANIM_SCREEN (w->screen);
3204
3205 CompWindow *bottommost = aw->winToBePaintedBeforeThis;
3206
3207 if (!bottommost || bottommost->destroyed)
3208 return w;
3209
3210 AnimWindow *awBottommost = GET_ANIM_WINDOW (bottommost, as);
3211 CompWindow *wPrev = NULL;
3212
3213 if (awBottommost)
3214 wPrev = awBottommost->moreToBePaintedPrev;
3215 while (wPrev)
3216 {
3217 bottommost = wPrev;
3218 wPrev = GET_ANIM_WINDOW(wPrev, as)->moreToBePaintedPrev;
3219 }
3220 return bottommost;
3221 }
3222
3223 static void
resetWalkerMarks(CompScreen * s)3224 resetWalkerMarks (CompScreen *s)
3225 {
3226 CompWindow *w;
3227 for (w = s->windows; w; w = w->next)
3228 {
3229 ANIM_WINDOW(w);
3230 aw->walkerOverNewCopy = FALSE;
3231 aw->walkerVisitCount = 0;
3232 }
3233 }
3234
3235 static CompWindow*
animWalkFirst(CompScreen * s)3236 animWalkFirst (CompScreen *s)
3237 {
3238 ANIM_SCREEN (s);
3239
3240 resetWalkerMarks (s);
3241
3242 CompWindow *w = getBottommostInFocusChain(s->windows);
3243 if (w)
3244 {
3245 AnimWindow *aw = GET_ANIM_WINDOW (w, as);
3246 aw->walkerVisitCount++;
3247 }
3248 return w;
3249 }
3250
3251 static CompWindow*
animWalkLast(CompScreen * s)3252 animWalkLast (CompScreen *s)
3253 {
3254 ANIM_SCREEN (s);
3255
3256 resetWalkerMarks (s);
3257
3258 CompWindow *w = s->reverseWindows;
3259 if (w)
3260 {
3261 AnimWindow *aw = GET_ANIM_WINDOW (w, as);
3262 aw->walkerVisitCount++;
3263 }
3264 return w;
3265 }
3266
3267 static Bool
markNewCopy(CompWindow * w)3268 markNewCopy (CompWindow *w)
3269 {
3270 ANIM_WINDOW (w);
3271
3272 // if window is in a focus chain
3273 if (aw->winThisIsPaintedBefore ||
3274 aw->moreToBePaintedPrev)
3275 {
3276 aw->walkerOverNewCopy = TRUE;
3277 return TRUE;
3278 }
3279 return FALSE;
3280 }
3281
3282 static CompWindow*
animWalkNext(CompWindow * w)3283 animWalkNext (CompWindow *w)
3284 {
3285 ANIM_WINDOW (w);
3286 CompWindow *wRet = NULL;
3287
3288 if (!aw->walkerOverNewCopy)
3289 {
3290 // Within a chain? (not the 1st or 2nd window)
3291 if (aw->moreToBePaintedNext)
3292 wRet = aw->moreToBePaintedNext;
3293 else if (aw->winThisIsPaintedBefore) // 2nd one in chain?
3294 wRet = aw->winThisIsPaintedBefore;
3295 }
3296 else
3297 aw->walkerOverNewCopy = FALSE;
3298
3299 if (!wRet && w->next && markNewCopy (w->next))
3300 wRet = w->next;
3301 else if (!wRet)
3302 wRet = getBottommostInFocusChain(w->next);
3303
3304 if (wRet)
3305 {
3306 ANIM_SCREEN (w->screen);
3307
3308 AnimWindow *awRet = GET_ANIM_WINDOW (wRet, as);
3309 // Prevent cycles, which cause freezes
3310 if (awRet->walkerVisitCount > 1) // each window is visited at most twice
3311 return NULL;
3312 awRet->walkerVisitCount++;
3313 }
3314 return wRet;
3315 }
3316
3317 static CompWindow*
animWalkPrev(CompWindow * w)3318 animWalkPrev (CompWindow *w)
3319 {
3320 ANIM_WINDOW (w);
3321 CompWindow *wRet = NULL;
3322
3323 // Focus chain start?
3324 CompWindow *w2 = aw->winToBePaintedBeforeThis;
3325 if (w2)
3326 wRet = w2;
3327 else if (!aw->walkerOverNewCopy)
3328 {
3329 // Within a focus chain? (not the last window)
3330 CompWindow *wPrev = aw->moreToBePaintedPrev;
3331 if (wPrev)
3332 wRet = wPrev;
3333 else if (aw->winThisIsPaintedBefore) // Focus chain end?
3334 // go to the chain beginning and get the
3335 // prev. in X stacking order
3336 {
3337 if (aw->winThisIsPaintedBefore->prev)
3338 markNewCopy (aw->winThisIsPaintedBefore->prev);
3339
3340 wRet = aw->winThisIsPaintedBefore->prev;
3341 }
3342 }
3343 else
3344 aw->walkerOverNewCopy = FALSE;
3345
3346 if (!wRet && w->prev)
3347 markNewCopy (w->prev);
3348
3349 wRet = w->prev;
3350 if (wRet)
3351 {
3352 ANIM_SCREEN (w->screen);
3353
3354 AnimWindow *awRet = GET_ANIM_WINDOW (wRet, as);
3355 // Prevent cycles, which cause freezes
3356 if (awRet->walkerVisitCount > 1) // each window is visited at most twice
3357 return NULL;
3358 awRet->walkerVisitCount++;
3359 }
3360 return wRet;
3361 }
3362
3363 static void
animInitWindowWalker(CompScreen * s,CompWalker * walker)3364 animInitWindowWalker (CompScreen *s,
3365 CompWalker *walker)
3366 {
3367 ANIM_SCREEN (s);
3368
3369 UNWRAP (as, s, initWindowWalker);
3370 (*s->initWindowWalker) (s, walker);
3371 WRAP (as, s, initWindowWalker, animInitWindowWalker);
3372
3373 if (as->walkerAnimCount > 0) // only walk if necessary
3374 {
3375 if (!as->animInProgress) // just in case
3376 {
3377 as->walkerAnimCount = 0;
3378 return;
3379 }
3380 walker->first = animWalkFirst;
3381 walker->last = animWalkLast;
3382 walker->next = animWalkNext;
3383 walker->prev = animWalkPrev;
3384 }
3385 }
3386
animHandleCompizEvent(CompDisplay * d,const char * pluginName,const char * eventName,CompOption * option,int nOption)3387 static void animHandleCompizEvent(CompDisplay * d, const char *pluginName,
3388 const char *eventName, CompOption * option,
3389 int nOption)
3390 {
3391 ANIM_DISPLAY(d);
3392
3393 UNWRAP (ad, d, handleCompizEvent);
3394 (*d->handleCompizEvent) (d, pluginName, eventName, option, nOption);
3395 WRAP (ad, d, handleCompizEvent, animHandleCompizEvent);
3396
3397 int i;
3398 for (i = 0; i < NUM_WATCHED_PLUGINS; i++)
3399 if (strcmp(pluginName, watchedPlugins[i].pluginName) == 0)
3400 {
3401 if (strcmp(eventName, watchedPlugins[i].activateEventName) == 0)
3402 {
3403 Window xid = getIntOptionNamed(option, nOption, "root", 0);
3404 CompScreen *s = findScreenAtDisplay(d, xid);
3405
3406 if (s)
3407 {
3408 ANIM_SCREEN(s);
3409 as->pluginActive[i] =
3410 getBoolOptionNamed(option, nOption, "active", FALSE);
3411 if (i < NUM_SWITCHERS) // if it's a switcher plugin
3412 {
3413 if (!as->pluginActive[i])
3414 switcherPostWait = 1;
3415 }
3416 }
3417 }
3418 break;
3419 }
3420 }
3421
3422 static void
updateLastClientListStacking(CompScreen * s)3423 updateLastClientListStacking(CompScreen *s)
3424 {
3425 ANIM_SCREEN(s);
3426 int n = s->nClientList;
3427 Window *clientListStacking = (Window *) (s->clientList + n) + n;
3428
3429 if (as->nLastClientListStacking != n) // the number of windows has changed
3430 {
3431 Window *list;
3432
3433 list = realloc (as->lastClientListStacking, sizeof (Window) * n);
3434 as->lastClientListStacking = list;
3435
3436 if (!list)
3437 {
3438 as->nLastClientListStacking = 0;
3439 return;
3440 }
3441
3442 as->nLastClientListStacking = n;
3443 }
3444
3445 // Store new client stack listing
3446 memcpy(as->lastClientListStacking, clientListStacking,
3447 sizeof (Window) * n);
3448 }
3449
3450 // Returns true for windows that don't have a pixmap or certain properties,
3451 // like the dimming layer of gksudo and x-session-manager
3452 static inline Bool
shouldIgnoreForAnim(CompWindow * w,Bool checkPixmap)3453 shouldIgnoreForAnim (CompWindow *w, Bool checkPixmap)
3454 {
3455 ANIM_DISPLAY (w->screen->display);
3456
3457 return ((checkPixmap && !w->texture->pixmap) ||
3458 matchEval (&ad->neverAnimateMatch, w));
3459 }
3460
animHandleEvent(CompDisplay * d,XEvent * event)3461 static void animHandleEvent(CompDisplay * d, XEvent * event)
3462 {
3463 CompWindow *w;
3464
3465 ANIM_DISPLAY(d);
3466
3467 switch (event->type)
3468 {
3469 case PropertyNotify:
3470 if (event->xproperty.atom == d->clientListStackingAtom)
3471 {
3472 CompScreen *s = findScreenAtDisplay (d, event->xproperty.window);
3473 if (s)
3474 updateLastClientListStacking(s);
3475 }
3476 break;
3477 case MapNotify:
3478 w = findWindowAtDisplay(d, event->xmap.window);
3479 if (w)
3480 {
3481 ANIM_WINDOW(w);
3482
3483 if (aw->com.animRemainingTime > 0)
3484 {
3485 aw->state = aw->newState;
3486 }
3487 aw->ignoreDamage = TRUE;
3488 while (aw->unmapCnt)
3489 {
3490 unmapWindow(w);
3491 aw->unmapCnt--;
3492 }
3493 aw->ignoreDamage = FALSE;
3494 }
3495 break;
3496 case DestroyNotify:
3497 w = findWindowAtDisplay(d, event->xdestroywindow.window);
3498 if (w)
3499 {
3500 ANIM_WINDOW(w);
3501 int duration;
3502
3503 if (shouldIgnoreForAnim (w, TRUE))
3504 break;
3505
3506 if (AnimEffectNone ==
3507 getMatchingAnimSelection (w, AnimEventClose, &duration))
3508 break;
3509
3510 aw->destroyCnt++;
3511 w->destroyRefCnt++;
3512 addWindowDamage(w);
3513 }
3514 break;
3515 case UnmapNotify:
3516 w = findWindowAtDisplay(d, event->xunmap.window);
3517 if (w)
3518 {
3519 ANIM_SCREEN(w->screen);
3520
3521 if (w->pendingUnmaps && onCurrentDesktop(w)) // Normal -> Iconic
3522 {
3523 ANIM_WINDOW(w);
3524 int duration = 200;
3525 AnimEffect chosenEffect =
3526 getMatchingAnimSelection (w, AnimEventShade, &duration);
3527
3528 if (w->shaded)
3529 {
3530 // SHADE event!
3531
3532 aw->nowShaded = TRUE;
3533
3534 if (chosenEffect != AnimEffectNone)
3535 {
3536 Bool startingNew = TRUE;
3537
3538 if (aw->com.curWindowEvent != WindowEventNone)
3539 {
3540 if (aw->com.curWindowEvent != WindowEventUnshade)
3541 {
3542 postAnimationCleanupPrev (w, FALSE, FALSE);
3543 }
3544 else
3545 {
3546 // Play the unshade effect backwards from where it left
3547 aw->com.animRemainingTime =
3548 aw->com.animTotalTime -
3549 aw->com.animRemainingTime;
3550
3551 // avoid window remains
3552 if (aw->com.animRemainingTime <= 0)
3553 aw->com.animRemainingTime = 1;
3554
3555 startingNew = FALSE;
3556 if (aw->com.animOverrideProgressDir == 0)
3557 aw->com.animOverrideProgressDir = 2;
3558 else if (aw->com.animOverrideProgressDir == 1)
3559 aw->com.animOverrideProgressDir = 0;
3560 }
3561 }
3562
3563 if (startingNew)
3564 {
3565 AnimEffect effectToBePlayed;
3566 effectToBePlayed =
3567 animGetAnimEffect (as,
3568 chosenEffect,
3569 AnimEventShade);
3570
3571 // handle empty random effect list
3572 if (effectToBePlayed == AnimEffectNone)
3573 break;
3574
3575 aw->com.curAnimEffect = effectToBePlayed;
3576 aw->com.animTotalTime = duration;
3577 aw->com.animRemainingTime = aw->com.animTotalTime;
3578 }
3579
3580 animActivateEvent(w->screen, TRUE);
3581 aw->com.curWindowEvent = WindowEventShade;
3582
3583 if (!animEnsureModel(w))
3584 {
3585 postAnimationCleanup (w);
3586 }
3587
3588 aw->unmapCnt++;
3589 w->unmapRefCnt++;
3590
3591 damagePendingOnScreen (w->screen);
3592 }
3593 }
3594 else if (!w->invisible && !w->hidden)
3595 {
3596 // MINIMIZE event!
3597
3598 // Always reset stacking related info when a window is
3599 // minimized.
3600 resetStackingInfo (w->screen);
3601
3602 aw->newState = IconicState;
3603
3604 if (w->iconGeometrySet)
3605 {
3606 aw->com.icon = w->iconGeometry;
3607 }
3608 else
3609 {
3610 // Minimize to mouse pointer if there is no
3611 // window list or if the window skips taskbar
3612 if (!getMousePointerXY (w->screen,
3613 &aw->com.icon.x,
3614 &aw->com.icon.y))
3615 {
3616 // Use screen center if can't get mouse coords
3617 aw->com.icon.x = w->screen->width / 2;
3618 aw->com.icon.y = w->screen->height / 2;
3619 }
3620 aw->com.icon.width = FAKE_ICON_SIZE;
3621 aw->com.icon.height = FAKE_ICON_SIZE;
3622 }
3623
3624 chosenEffect =
3625 getMatchingAnimSelection (w, AnimEventMinimize, &duration);
3626
3627 if (chosenEffect != AnimEffectNone)
3628 {
3629 Bool startingNew = TRUE;
3630
3631 if (aw->com.curWindowEvent != WindowEventNone)
3632 {
3633 if (aw->com.curWindowEvent != WindowEventUnminimize)
3634 {
3635 postAnimationCleanupPrev (w, FALSE, FALSE);
3636 }
3637 else
3638 {
3639 // Play the unminimize effect backwards from where it left
3640 aw->com.animRemainingTime =
3641 aw->com.animTotalTime - aw->com.animRemainingTime;
3642
3643 // avoid window remains
3644 if (aw->com.animRemainingTime == 0)
3645 aw->com.animRemainingTime = 1;
3646
3647 startingNew = FALSE;
3648 if (aw->com.animOverrideProgressDir == 0)
3649 aw->com.animOverrideProgressDir = 2;
3650 else if (aw->com.animOverrideProgressDir == 1)
3651 aw->com.animOverrideProgressDir = 0;
3652 }
3653 }
3654
3655 if (startingNew)
3656 {
3657 AnimEffect effectToBePlayed;
3658 effectToBePlayed =
3659 animGetAnimEffect (as,
3660 chosenEffect,
3661 AnimEventMinimize);
3662
3663 // handle empty random effect list
3664 if (effectToBePlayed == AnimEffectNone)
3665 {
3666 aw->state = aw->newState;
3667 break;
3668 }
3669 aw->com.curAnimEffect = effectToBePlayed;
3670 aw->com.animTotalTime = duration;
3671 aw->com.animRemainingTime = aw->com.animTotalTime;
3672 }
3673
3674 animActivateEvent(w->screen, TRUE);
3675 aw->com.curWindowEvent = WindowEventMinimize;
3676
3677 if (!animEnsureModel(w))
3678 {
3679 postAnimationCleanup (w);
3680 }
3681 else
3682 {
3683 aw->unmapCnt++;
3684 w->unmapRefCnt++;
3685
3686 damagePendingOnScreen (w->screen);
3687 }
3688 }
3689 else
3690 aw->state = aw->newState;
3691 }
3692 }
3693 else // X -> Withdrawn
3694 {
3695 ANIM_WINDOW(w);
3696 int duration = 200;
3697
3698 // Always reset stacking related info when a window is closed.
3699 resetStackingInfo (w->screen);
3700
3701 if (shouldIgnoreForAnim (w, TRUE) ||
3702 otherPluginsActive (as))
3703 break;
3704
3705 AnimEffect chosenEffect =
3706 getMatchingAnimSelection (w, AnimEventClose, &duration);
3707
3708 // CLOSE event!
3709
3710 aw->state = NormalState;
3711 aw->newState = WithdrawnState;
3712
3713 if (chosenEffect != AnimEffectNone)
3714 {
3715 int tmpSteps = 0;
3716 Bool startingNew = TRUE;
3717
3718 if (aw->com.animRemainingTime > 0 &&
3719 aw->com.curWindowEvent != WindowEventOpen)
3720 {
3721 tmpSteps = aw->com.animRemainingTime;
3722 aw->com.animRemainingTime = 0;
3723 }
3724 if (aw->com.curWindowEvent != WindowEventNone)
3725 {
3726 if (aw->com.curWindowEvent == WindowEventOpen)
3727 {
3728 // Play the create effect backward from where it left
3729 aw->com.animRemainingTime =
3730 aw->com.animTotalTime - aw->com.animRemainingTime;
3731
3732 // avoid window remains
3733 if (aw->com.animRemainingTime <= 0)
3734 aw->com.animRemainingTime = 1;
3735
3736 startingNew = FALSE;
3737 if (aw->com.animOverrideProgressDir == 0)
3738 aw->com.animOverrideProgressDir = 2;
3739 else if (aw->com.animOverrideProgressDir == 1)
3740 aw->com.animOverrideProgressDir = 0;
3741 }
3742 else if (aw->com.curWindowEvent == WindowEventClose)
3743 {
3744 if (aw->com.animOverrideProgressDir == 2)
3745 {
3746 aw->com.animRemainingTime = tmpSteps;
3747 startingNew = FALSE;
3748 }
3749 }
3750 else
3751 {
3752 postAnimationCleanupPrev (w, TRUE, FALSE);
3753 }
3754 }
3755
3756 if (startingNew)
3757 {
3758 AnimEffect effectToBePlayed;
3759 effectToBePlayed = animGetAnimEffect (as,
3760 chosenEffect,
3761 AnimEventClose);
3762
3763 // handle empty random effect list
3764 if (effectToBePlayed == AnimEffectNone)
3765 {
3766 aw->state = aw->newState;
3767 break;
3768 }
3769 aw->com.curAnimEffect = effectToBePlayed;
3770 aw->com.animTotalTime = duration;
3771 aw->com.animRemainingTime = aw->com.animTotalTime;
3772 }
3773 animActivateEvent(w->screen, TRUE);
3774 aw->com.curWindowEvent = WindowEventClose;
3775
3776 if (!animEnsureModel(w))
3777 {
3778 postAnimationCleanupCustom (w, TRUE, FALSE, TRUE);
3779 }
3780 else if (getMousePointerXY
3781 (w->screen, &aw->com.icon.x, &aw->com.icon.y))
3782 {
3783 aw->com.icon.width = FAKE_ICON_SIZE;
3784 aw->com.icon.height = FAKE_ICON_SIZE;
3785
3786 if (aw->com.curAnimEffect == AnimEffectMagicLamp)
3787 aw->com.icon.width =
3788 MAX(aw->com.icon.width,
3789 animGetI (w, ANIM_SCREEN_OPTION_MAGIC_LAMP_OPEN_START_WIDTH));
3790 else if (aw->com.curAnimEffect == AnimEffectVacuum)
3791 aw->com.icon.width =
3792 MAX(aw->com.icon.width,
3793 animGetI (w, ANIM_SCREEN_OPTION_VACUUM_OPEN_START_WIDTH));
3794
3795 aw->unmapCnt++;
3796 w->unmapRefCnt++;
3797
3798 damagePendingOnScreen (w->screen);
3799 }
3800 }
3801 else if (AnimEffectNone !=
3802 getMatchingAnimSelection (w, AnimEventOpen, &duration))
3803 {
3804 // stop the current animation and prevent it from rewinding
3805
3806 if (aw->com.animRemainingTime > 0 &&
3807 aw->com.curWindowEvent != WindowEventOpen)
3808 {
3809 aw->com.animRemainingTime = 0;
3810 }
3811 if ((aw->com.curWindowEvent != WindowEventNone) &&
3812 (aw->com.curWindowEvent != WindowEventClose))
3813 {
3814 postAnimationCleanupCustom (w, TRUE, FALSE, TRUE);
3815 }
3816 // set some properties to make sure this window will use the
3817 // correct open effect the next time it's "opened"
3818
3819 animActivateEvent(w->screen, TRUE);
3820 aw->com.curWindowEvent = WindowEventClose;
3821
3822 aw->unmapCnt++;
3823 w->unmapRefCnt++;
3824
3825 damagePendingOnScreen (w->screen);
3826 }
3827 else
3828 aw->state = aw->newState;
3829 }
3830 }
3831 break;
3832 case ConfigureNotify:
3833 {
3834 XConfigureEvent *ce = &event->xconfigure;
3835 w = findWindowAtDisplay (d, ce->window);
3836 if (!w)
3837 break;
3838 if (w->prev)
3839 {
3840 if (ce->above && ce->above == w->prev->id)
3841 break;
3842 }
3843 else if (ce->above == None)
3844 break;
3845 CompScreen *s = findScreenAtDisplay (d, event->xproperty.window);
3846 if (!s)
3847 break;
3848
3849 ANIM_SCREEN(s);
3850 int n = s->nClientList;
3851 Bool winOpenedClosed = FALSE;
3852
3853 Window *clientList = (Window *) (s->clientList + n);
3854 Window *clientListStacking = clientList + n;
3855
3856 if (n != as->nLastClientListStacking)
3857 winOpenedClosed = TRUE;
3858
3859 // if restacking occurred and not window open/close
3860 if (!winOpenedClosed)
3861 {
3862 ANIM_WINDOW(w);
3863 aw->configureNotified = TRUE;
3864
3865 // Find which window is restacked
3866 // e.g. here 8507730 was raised:
3867 // 54526074 8507730 48234499 14680072 6291497
3868 // 54526074 48234499 14680072 8507730 6291497
3869 // compare first changed win. of row 1 with last
3870 // changed win. of row 2, and vica versa
3871 // the matching one is the restacked one
3872 CompWindow *wRestacked = 0;
3873 CompWindow *wStart = 0;
3874 CompWindow *wEnd = 0;
3875 CompWindow *wOldAbove = 0;
3876 CompWindow *wChangeStart = 0;
3877 CompWindow *wChangeEnd = 0;
3878
3879 Bool raised = FALSE;
3880 int changeStart = -1;
3881 int changeEnd = -1;
3882
3883 int i;
3884 for (i = 0; i < n; i++)
3885 {
3886 CompWindow *wi =
3887 findWindowAtScreen (s, clientListStacking[i]);
3888
3889 // skip if minimized (prevents flashing problem)
3890 if (!wi || !isWinVisible(wi))
3891 continue;
3892
3893 // skip if (tabbed and) hidden by Group plugin
3894 if (wi->state & (CompWindowStateSkipPagerMask |
3895 CompWindowStateSkipTaskbarMask))
3896 continue;
3897
3898 if (clientListStacking[i] !=
3899 as->lastClientListStacking[i])
3900 {
3901 if (changeStart < 0)
3902 {
3903 changeStart = i;
3904 wChangeStart = wi; // make use of already found w
3905 }
3906 else
3907 {
3908 changeEnd = i;
3909 wChangeEnd = wi;
3910 }
3911 }
3912 else if (changeStart >= 0) // found some change earlier
3913 break;
3914 }
3915
3916 // if restacking occurred
3917 if (changeStart >= 0 && changeEnd >= 0)
3918 {
3919 CompWindow *w2;
3920
3921 // if we have only 2 windows changed,
3922 // choose the one clicked on
3923 Bool preferRaised = FALSE;
3924 Bool onlyTwo = FALSE;
3925
3926 if (wChangeEnd &&
3927 clientListStacking[changeEnd] ==
3928 as->lastClientListStacking[changeStart] &&
3929 clientListStacking[changeStart] ==
3930 as->lastClientListStacking[changeEnd])
3931 {
3932 // Check if the window coming on top was
3933 // configureNotified (clicked on)
3934 AnimWindow *aw2 = GET_ANIM_WINDOW(wChangeEnd, as);
3935 if (aw2->configureNotified)
3936 {
3937 preferRaised = TRUE;
3938 }
3939 onlyTwo = TRUE;
3940 }
3941 // Clear all configureNotified's
3942 for (w2 = s->windows; w2; w2 = w2->next)
3943 {
3944 AnimWindow *aw2 = GET_ANIM_WINDOW(w2, as);
3945 aw2->configureNotified = FALSE;
3946 }
3947
3948 if (preferRaised ||
3949 (!onlyTwo &&
3950 clientListStacking[changeEnd] ==
3951 as->lastClientListStacking[changeStart]))
3952 {
3953 // raised
3954 raised = TRUE;
3955 wRestacked = wChangeEnd;
3956 wStart = wChangeStart;
3957 wEnd = wRestacked;
3958 wOldAbove = wStart;
3959 }
3960 else if (clientListStacking[changeStart] ==
3961 as->lastClientListStacking[changeEnd] && // lowered
3962 // We don't animate lowering if there is no
3963 // window above this window, since this window needs
3964 // to be drawn on such a "host" in animPaintWindow
3965 // (at least for now).
3966 changeEnd < n - 1)
3967 {
3968 wRestacked = wChangeStart;
3969 wStart = wRestacked;
3970 wEnd = wChangeEnd;
3971 wOldAbove = findWindowAtScreen
3972 (s, as->lastClientListStacking[changeEnd+1]);
3973 }
3974 for (; wOldAbove && !isWinVisible(wOldAbove);
3975 wOldAbove = wOldAbove->next)
3976 ;
3977 }
3978 if (wRestacked && wStart && wEnd && wOldAbove)
3979 {
3980 AnimWindow *awRestacked = GET_ANIM_WINDOW(wRestacked, as);
3981 if (awRestacked->created)
3982 {
3983 RestackInfo *restackInfo = calloc(1, sizeof(RestackInfo));
3984 if (restackInfo)
3985 {
3986 restackInfo->wRestacked = wRestacked;
3987 restackInfo->wStart = wStart;
3988 restackInfo->wEnd = wEnd;
3989 restackInfo->wOldAbove = wOldAbove;
3990 restackInfo->raised = raised;
3991
3992 if (awRestacked->restackInfo)
3993 free(awRestacked->restackInfo);
3994
3995 awRestacked->restackInfo = restackInfo;
3996 as->aWinWasRestackedJustNow = TRUE;
3997 }
3998 }
3999 }
4000 }
4001 updateLastClientListStacking(s);
4002 }
4003 break;
4004 default:
4005 break;
4006 }
4007
4008 UNWRAP(ad, d, handleEvent);
4009 (*d->handleEvent) (d, event);
4010 WRAP(ad, d, handleEvent, animHandleEvent);
4011
4012 switch (event->type)
4013 {
4014 case PropertyNotify:
4015 if (event->xproperty.atom == d->winActiveAtom &&
4016 d->activeWindow != ad->activeWindow)
4017 {
4018 ad->activeWindow = d->activeWindow;
4019 w = findWindowAtDisplay(d, d->activeWindow);
4020
4021 if (w)
4022 {
4023 int duration = 200;
4024 AnimEffect chosenEffect =
4025 getMatchingAnimSelection (w, AnimEventFocus, &duration);
4026
4027 if (!(chosenEffect == AnimEffectFocusFade ||
4028 chosenEffect == AnimEffectDodge))
4029 initiateFocusAnimation(w);
4030 }
4031 }
4032 break;
4033 case MapRequest:
4034 w = findWindowAtDisplay (d, event->xmaprequest.window);
4035 if (w && w->hints && w->hints->initial_state == IconicState)
4036 {
4037 ANIM_WINDOW (w);
4038 aw->state = aw->newState = IconicState;
4039 }
4040 break;
4041 default:
4042 break;
4043 }
4044 }
4045
animDamageWindowRect(CompWindow * w,Bool initial,BoxPtr rect)4046 static Bool animDamageWindowRect(CompWindow * w, Bool initial, BoxPtr rect)
4047 {
4048 Bool status;
4049
4050 ANIM_SCREEN(w->screen);
4051 ANIM_WINDOW(w);
4052
4053 if (aw->ignoreDamage)
4054 return TRUE; // if doing the unmap at animation's end, ignore the damage
4055
4056 if (initial) // Unminimize or Open
4057 {
4058 int duration = 200;
4059 AnimEffect chosenEffect;
4060
4061 if (aw->state == IconicState)
4062 {
4063 chosenEffect =
4064 getMatchingAnimSelection (w, AnimEventMinimize, &duration);
4065
4066 // UNMINIMIZE event!
4067
4068 if (!w->invisible && !w->hidden &&
4069 chosenEffect != AnimEffectNone &&
4070 !as->pluginActive[3]) // fadedesktop
4071 {
4072 Bool startingNew = TRUE;
4073 Bool playEffect = TRUE;
4074
4075 // Always reset stacking related info when a window is
4076 // unminimized.
4077 resetStackingInfo (w->screen);
4078
4079 if (aw->com.curWindowEvent != WindowEventNone)
4080 {
4081 if (aw->com.curWindowEvent != WindowEventMinimize)
4082 {
4083 postAnimationCleanupPrev (w, FALSE, FALSE);
4084 }
4085 else
4086 {
4087 // Play the minimize effect backwards from where it left
4088 aw->com.animRemainingTime =
4089 aw->com.animTotalTime - aw->com.animRemainingTime;
4090
4091 // avoid window remains
4092 if (aw->com.animRemainingTime <= 0)
4093 aw->com.animRemainingTime = 1;
4094
4095 startingNew = FALSE;
4096 if (aw->com.animOverrideProgressDir == 0)
4097 aw->com.animOverrideProgressDir = 1;
4098 else if (aw->com.animOverrideProgressDir == 2)
4099 aw->com.animOverrideProgressDir = 0;
4100 }
4101 }
4102
4103 if (startingNew)
4104 {
4105 AnimEffect effectToBePlayed;
4106 effectToBePlayed = animGetAnimEffect (as,
4107 chosenEffect,
4108 AnimEventMinimize);
4109
4110 // handle empty random effect list
4111 if (effectToBePlayed == AnimEffectNone)
4112 playEffect = FALSE;
4113
4114 if (playEffect)
4115 {
4116 aw->com.curAnimEffect = effectToBePlayed;
4117 aw->com.animTotalTime = duration;
4118 aw->com.animRemainingTime = aw->com.animTotalTime;
4119 }
4120 }
4121
4122 if (playEffect)
4123 {
4124 animActivateEvent(w->screen, TRUE);
4125 aw->com.curWindowEvent = WindowEventUnminimize;
4126
4127 if (animEnsureModel(w))
4128 {
4129 if (w->iconGeometrySet)
4130 {
4131 aw->com.icon = w->iconGeometry;
4132 }
4133 else
4134 {
4135 // Unminimize from mouse pointer if there is no
4136 // window list or if the window skips taskbar
4137 if (!getMousePointerXY (w->screen,
4138 &aw->com.icon.x,
4139 &aw->com.icon.y))
4140 {
4141 // Use screen center if can't get mouse coords
4142 aw->com.icon.x = w->screen->width / 2;
4143 aw->com.icon.y = w->screen->height / 2;
4144 }
4145 aw->com.icon.width = FAKE_ICON_SIZE;
4146 aw->com.icon.height = FAKE_ICON_SIZE;
4147 }
4148
4149 damagePendingOnScreen (w->screen);
4150 }
4151 else
4152 {
4153 postAnimationCleanup (w);
4154 }
4155 }
4156 }
4157 }
4158 else if (aw->nowShaded)
4159 {
4160 chosenEffect =
4161 getMatchingAnimSelection (w, AnimEventShade, &duration);
4162
4163 // UNSHADE event!
4164
4165 aw->nowShaded = FALSE;
4166
4167 if (chosenEffect != AnimEffectNone)
4168 {
4169 Bool startingNew = TRUE;
4170 Bool playEffect = TRUE;
4171
4172 if (aw->com.curWindowEvent != WindowEventNone)
4173 {
4174 if (aw->com.curWindowEvent != WindowEventShade)
4175 {
4176 postAnimationCleanupPrev (w, FALSE, FALSE);
4177 }
4178 else
4179 {
4180 // Play the shade effect backwards from where it left
4181 aw->com.animRemainingTime =
4182 aw->com.animTotalTime - aw->com.animRemainingTime;
4183
4184 // avoid window remains
4185 if (aw->com.animRemainingTime <= 0)
4186 aw->com.animRemainingTime = 1;
4187
4188 startingNew = FALSE;
4189 if (aw->com.animOverrideProgressDir == 0)
4190 aw->com.animOverrideProgressDir = 1;
4191 else if (aw->com.animOverrideProgressDir == 2)
4192 aw->com.animOverrideProgressDir = 0;
4193 }
4194 }
4195
4196 if (startingNew)
4197 {
4198 AnimEffect effectToBePlayed;
4199 effectToBePlayed = animGetAnimEffect (as,
4200 chosenEffect,
4201 AnimEventShade);
4202
4203 // handle empty random effect list
4204 if (effectToBePlayed == AnimEffectNone)
4205 playEffect = FALSE;
4206
4207 if (playEffect)
4208 {
4209 aw->com.curAnimEffect = effectToBePlayed;
4210 aw->com.animTotalTime = duration;
4211 aw->com.animRemainingTime = aw->com.animTotalTime;
4212 }
4213 }
4214
4215 if (playEffect)
4216 {
4217 animActivateEvent(w->screen, TRUE);
4218 aw->com.curWindowEvent = WindowEventUnshade;
4219
4220 if (animEnsureModel(w))
4221 damagePendingOnScreen (w->screen);
4222 else
4223 postAnimationCleanup (w);
4224 }
4225 }
4226 }
4227 else if (!w->invisible && as->startCountdown == 0)
4228 {
4229 AnimEffect chosenEffect;
4230 int duration = 200;
4231
4232 // Always reset stacking related info when a window is opened.
4233 resetStackingInfo (w->screen);
4234
4235 aw->created = TRUE;
4236
4237 // OPEN event!
4238
4239 if (!otherPluginsActive (as) &&
4240 !shouldIgnoreForAnim (w, FALSE) &&
4241 AnimEffectNone !=
4242 (chosenEffect =
4243 getMatchingAnimSelection (w, AnimEventOpen, &duration)) &&
4244 getMousePointerXY(w->screen, &aw->com.icon.x, &aw->com.icon.y))
4245 {
4246 Bool startingNew = TRUE;
4247 Bool playEffect = TRUE;
4248
4249 if (aw->com.curWindowEvent != WindowEventNone)
4250 {
4251 if (aw->com.curWindowEvent != WindowEventClose)
4252 {
4253 postAnimationCleanupPrev (w, FALSE, FALSE);
4254 }
4255 else
4256 {
4257 // Play the close effect backwards from where it left
4258 aw->com.animRemainingTime =
4259 aw->com.animTotalTime - aw->com.animRemainingTime;
4260
4261 // avoid window remains
4262 if (aw->com.animRemainingTime == 0)
4263 aw->com.animRemainingTime = 1;
4264
4265 startingNew = FALSE;
4266 if (aw->com.animOverrideProgressDir == 0)
4267 aw->com.animOverrideProgressDir = 1;
4268 else if (aw->com.animOverrideProgressDir == 2)
4269 aw->com.animOverrideProgressDir = 0;
4270 }
4271 }
4272
4273 if (startingNew)
4274 {
4275 AnimEffect effectToBePlayed;
4276 effectToBePlayed = animGetAnimEffect (as,
4277 chosenEffect,
4278 AnimEventOpen);
4279
4280 // handle empty random effect list
4281 if (effectToBePlayed == AnimEffectNone)
4282 playEffect = FALSE;
4283
4284 if (playEffect)
4285 {
4286 aw->com.curAnimEffect = effectToBePlayed;
4287 aw->com.animTotalTime = duration;
4288 aw->com.animRemainingTime = aw->com.animTotalTime;
4289 }
4290 }
4291
4292 if (playEffect)
4293 {
4294 animActivateEvent(w->screen, TRUE);
4295 aw->com.curWindowEvent = WindowEventOpen;
4296
4297 aw->com.icon.width = FAKE_ICON_SIZE;
4298 aw->com.icon.height = FAKE_ICON_SIZE;
4299
4300 if (aw->com.curAnimEffect == AnimEffectMagicLamp)
4301 aw->com.icon.width =
4302 MAX(aw->com.icon.width,
4303 animGetI (w, ANIM_SCREEN_OPTION_MAGIC_LAMP_OPEN_START_WIDTH));
4304 else if (aw->com.curAnimEffect == AnimEffectVacuum)
4305 aw->com.icon.width =
4306 MAX(aw->com.icon.width,
4307 animGetI (w, ANIM_SCREEN_OPTION_VACUUM_OPEN_START_WIDTH));
4308
4309 aw->com.icon.x -= aw->com.icon.width / 2;
4310 aw->com.icon.y -= aw->com.icon.height / 2;
4311
4312 if (animEnsureModel(w))
4313 damagePendingOnScreen (w->screen);
4314 else
4315 postAnimationCleanup (w);
4316 }
4317 }
4318 }
4319
4320 aw->newState = NormalState;
4321 }
4322
4323 UNWRAP(as, w->screen, damageWindowRect);
4324 status = (*w->screen->damageWindowRect) (w, initial, rect);
4325 WRAP(as, w->screen, damageWindowRect, animDamageWindowRect);
4326
4327 return status;
4328 }
4329
animWindowResizeNotify(CompWindow * w,int dx,int dy,int dwidth,int dheight)4330 static void animWindowResizeNotify(CompWindow * w, int dx, int dy, int dwidth, int dheight)
4331 {
4332 ANIM_SCREEN(w->screen);
4333 ANIM_WINDOW(w);
4334
4335 // Don't let transient window open anim be interrupted with a resize notify
4336 if (!(aw->com.curWindowEvent == WindowEventOpen &&
4337 (w->wmType &
4338 (CompWindowTypeDropdownMenuMask |
4339 CompWindowTypePopupMenuMask |
4340 CompWindowTypeMenuMask |
4341 CompWindowTypeTooltipMask |
4342 CompWindowTypeNotificationMask |
4343 CompWindowTypeComboMask |
4344 CompWindowTypeDndMask))))
4345 {
4346 if (aw->com.curAnimEffect->properties.refreshFunc)
4347 aw->com.curAnimEffect->properties.refreshFunc (w, aw->animInitialized);
4348
4349 if (aw->com.animRemainingTime > 0)
4350 {
4351 aw->com.animRemainingTime = 0;
4352 postAnimationCleanup (w);
4353 }
4354 }
4355
4356 if (aw->com.model)
4357 {
4358 modelInitObjects(aw->com.model,
4359 WIN_X(w), WIN_Y(w),
4360 WIN_W(w), WIN_H(w));
4361 }
4362
4363 UNWRAP(as, w->screen, windowResizeNotify);
4364 (*w->screen->windowResizeNotify) (w, dx, dy, dwidth, dheight);
4365 WRAP(as, w->screen, windowResizeNotify, animWindowResizeNotify);
4366 }
4367
4368 static void
animWindowMoveNotify(CompWindow * w,int dx,int dy,Bool immediate)4369 animWindowMoveNotify(CompWindow * w, int dx, int dy, Bool immediate)
4370 {
4371 ANIM_SCREEN(w->screen);
4372 ANIM_WINDOW(w);
4373
4374 if (!immediate)
4375 {
4376 if (!(aw->com.animRemainingTime > 0 &&
4377 (aw->com.curAnimEffect == AnimEffectFocusFade ||
4378 aw->com.curAnimEffect == AnimEffectDodge)))
4379 {
4380 CompWindow *w2;
4381
4382 if (aw->com.curAnimEffect->properties.refreshFunc)
4383 aw->com.curAnimEffect->properties.refreshFunc
4384 (w, aw->animInitialized);
4385
4386 if (aw->com.animRemainingTime > 0 && aw->grabbed)
4387 {
4388 aw->com.animRemainingTime = 0;
4389 if (as->animInProgress)
4390 {
4391 Bool animStillInProgress = FALSE;
4392 for (w2 = w->screen->windows; w2; w2 = w2->next)
4393 {
4394 AnimWindow *aw2;
4395
4396 aw2 = GET_ANIM_WINDOW(w2, as);
4397 if (aw2->com.animRemainingTime > 0)
4398 {
4399 animStillInProgress = TRUE;
4400 break;
4401 }
4402 }
4403
4404 if (!animStillInProgress)
4405 animActivateEvent(w->screen, FALSE);
4406 }
4407 postAnimationCleanup (w);
4408 }
4409
4410 if (aw->com.model)
4411 {
4412 modelInitObjects(aw->com.model, WIN_X(w), WIN_Y(w), WIN_W(w),
4413 WIN_H(w));
4414 }
4415 }
4416 }
4417 else if (aw->com.model)
4418 modelMove (aw->com.model, dx, dy);
4419
4420 UNWRAP(as, w->screen, windowMoveNotify);
4421 (*w->screen->windowMoveNotify) (w, dx, dy, immediate);
4422 WRAP(as, w->screen, windowMoveNotify, animWindowMoveNotify);
4423 }
4424
4425 static void
animWindowGrabNotify(CompWindow * w,int x,int y,unsigned int state,unsigned int mask)4426 animWindowGrabNotify(CompWindow * w,
4427 int x, int y, unsigned int state, unsigned int mask)
4428 {
4429 ANIM_SCREEN(w->screen);
4430 ANIM_WINDOW(w);
4431
4432 aw->grabbed = TRUE;
4433
4434 UNWRAP(as, w->screen, windowGrabNotify);
4435 (*w->screen->windowGrabNotify) (w, x, y, state, mask);
4436 WRAP(as, w->screen, windowGrabNotify, animWindowGrabNotify);
4437 }
4438
animWindowUngrabNotify(CompWindow * w)4439 static void animWindowUngrabNotify(CompWindow * w)
4440 {
4441 ANIM_SCREEN(w->screen);
4442 ANIM_WINDOW(w);
4443
4444 aw->grabbed = FALSE;
4445
4446 UNWRAP(as, w->screen, windowUngrabNotify);
4447 (*w->screen->windowUngrabNotify) (w);
4448 WRAP(as, w->screen, windowUngrabNotify, animWindowUngrabNotify);
4449 }
4450
4451 static Bool
animPaintOutput(CompScreen * s,const ScreenPaintAttrib * sAttrib,const CompTransform * transform,Region region,CompOutput * output,unsigned int mask)4452 animPaintOutput(CompScreen * s,
4453 const ScreenPaintAttrib * sAttrib,
4454 const CompTransform *transform,
4455 Region region, CompOutput *output,
4456 unsigned int mask)
4457 {
4458 Bool status;
4459
4460 ANIM_SCREEN(s);
4461
4462 if (as->animInProgress)
4463 {
4464 int p;
4465 for (p = 0; p < as->nExtensionPlugins; p++)
4466 {
4467 const ExtensionPluginInfo *extPlugin = as->extensionPlugins[p];
4468 if (extPlugin->prePaintOutputFunc)
4469 extPlugin->prePaintOutputFunc (s, output);
4470 }
4471
4472 mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
4473 }
4474
4475 as->output = output;
4476
4477 UNWRAP(as, s, paintOutput);
4478 status = (*s->paintOutput) (s, sAttrib, transform, region, output, mask);
4479 WRAP(as, s, paintOutput, animPaintOutput);
4480
4481 CompWindow *w;
4482 if (as->aWinWasRestackedJustNow)
4483 {
4484 as->aWinWasRestackedJustNow = FALSE;
4485 }
4486 if (as->startCountdown > 0)
4487 {
4488 as->startCountdown--;
4489 if (as->startCountdown == 0)
4490 {
4491 // Mark all windows as "created"
4492 for (w = s->windows; w; w = w->next)
4493 {
4494 ANIM_WINDOW(w);
4495 aw->created = TRUE;
4496 }
4497 }
4498 }
4499
4500 return status;
4501 }
4502
4503 static const CompMetadataOptionInfo animDisplayOptionInfo[] = {
4504 { "abi", "int", 0, 0, 0 },
4505 { "index", "int", 0, 0, 0 }
4506 };
4507
4508 static CompOption *
animGetDisplayOptions(CompPlugin * plugin,CompDisplay * display,int * count)4509 animGetDisplayOptions (CompPlugin *plugin,
4510 CompDisplay *display,
4511 int *count)
4512 {
4513 ANIM_DISPLAY (display);
4514 *count = NUM_OPTIONS (ad);
4515 return ad->opt;
4516 }
4517
4518 static Bool
animSetDisplayOption(CompPlugin * plugin,CompDisplay * display,const char * name,CompOptionValue * value)4519 animSetDisplayOption (CompPlugin *plugin,
4520 CompDisplay *display,
4521 const char *name,
4522 CompOptionValue *value)
4523 {
4524 CompOption *o;
4525 int index;
4526 ANIM_DISPLAY (display);
4527 o = compFindOption (ad->opt, NUM_OPTIONS (ad), name, &index);
4528 if (!o)
4529 return FALSE;
4530
4531 switch (index) {
4532 case ANIM_DISPLAY_OPTION_ABI:
4533 case ANIM_DISPLAY_OPTION_INDEX:
4534 break;
4535 default:
4536 return compSetDisplayOption (display, o, value);
4537 }
4538
4539 return FALSE;
4540 }
4541
4542 static AnimWindowCommon *
getAnimWindowCommon(CompWindow * w)4543 getAnimWindowCommon (CompWindow *w)
4544 {
4545 ANIM_WINDOW (w);
4546
4547 return &aw->com;
4548 }
4549
4550 AnimBaseFunctions animBaseFunctions =
4551 {
4552 .addExtension = animAddExtension,
4553 .removeExtension = animRemoveExtension,
4554 .getPluginOptVal = animGetPluginOptVal,
4555 .getMousePointerXY = getMousePointerXY,
4556 .defaultAnimInit = defaultAnimInit,
4557 .defaultAnimStep = defaultAnimStep,
4558 .defaultUpdateWindowTransform = defaultUpdateWindowTransform,
4559 .getProgressAndCenter = getProgressAndCenter,
4560 .defaultAnimProgress = defaultAnimProgress,
4561 .sigmoidAnimProgress = sigmoidAnimProgress,
4562 .decelerateProgressCustom = decelerateProgressCustom,
4563 .decelerateProgress = decelerateProgress,
4564 .updateBBScreen = updateBBScreen,
4565 .updateBBWindow = updateBBWindow,
4566 .modelUpdateBB = modelUpdateBB,
4567 .compTransformUpdateBB = compTransformUpdateBB,
4568 .getActualAnimDirection = getActualAnimDirection,
4569 .expandBoxWithBox = expandBoxWithBox,
4570 .expandBoxWithPoint = expandBoxWithPoint,
4571 .prepareTransform = prepareTransform,
4572 .getAnimWindowCommon = getAnimWindowCommon,
4573 .returnTrue = returnTrue,
4574 .postAnimationCleanup = postAnimationCleanup,
4575 .fxZoomUpdateWindowAttrib = fxZoomUpdateWindowAttrib
4576 };
4577
animInitDisplay(CompPlugin * p,CompDisplay * d)4578 static Bool animInitDisplay(CompPlugin * p, CompDisplay * d)
4579 {
4580 AnimDisplay *ad;
4581
4582 if (!checkPluginABI ("core", CORE_ABIVERSION))
4583 return FALSE;
4584
4585 ad = calloc(1, sizeof(AnimDisplay));
4586 if (!ad)
4587 return FALSE;
4588
4589 if (!compInitDisplayOptionsFromMetadata (d,
4590 &animMetadata,
4591 animDisplayOptionInfo,
4592 ad->opt,
4593 ANIM_DISPLAY_OPTION_NUM))
4594 {
4595 free (ad);
4596 return FALSE;
4597 }
4598
4599 ad->screenPrivateIndex = allocateScreenPrivateIndex(d);
4600 if (ad->screenPrivateIndex < 0)
4601 {
4602 free(ad);
4603 return FALSE;
4604 }
4605
4606 // Never animate screen-dimming layer of logout window and gksu.
4607 matchInit (&ad->neverAnimateMatch);
4608 matchAddExp (&ad->neverAnimateMatch, 0, "title=gksu");
4609 matchAddExp (&ad->neverAnimateMatch, 0, "title=x-session-manager");
4610 matchAddExp (&ad->neverAnimateMatch, 0, "title=gnome-session");
4611 matchUpdate (d, &ad->neverAnimateMatch);
4612
4613 WRAP(ad, d, handleEvent, animHandleEvent);
4614 WRAP(ad, d, handleCompizEvent, animHandleCompizEvent);
4615
4616 ad->opt[ANIM_DISPLAY_OPTION_ABI].value.i = ANIMATION_ABIVERSION;
4617 ad->opt[ANIM_DISPLAY_OPTION_INDEX].value.i = animFunctionsPrivateIndex;
4618
4619 d->base.privates[animDisplayPrivateIndex].ptr = ad;
4620 d->base.privates[animFunctionsPrivateIndex].ptr = &animBaseFunctions;
4621
4622 return TRUE;
4623 }
4624
animFiniDisplay(CompPlugin * p,CompDisplay * d)4625 static void animFiniDisplay(CompPlugin * p, CompDisplay * d)
4626 {
4627 ANIM_DISPLAY(d);
4628
4629 freeScreenPrivateIndex(d, ad->screenPrivateIndex);
4630
4631 matchFini (&ad->neverAnimateMatch);
4632
4633 compFiniDisplayOptions (d, ad->opt, ANIM_DISPLAY_OPTION_NUM);
4634
4635 UNWRAP(ad, d, handleCompizEvent);
4636 UNWRAP(ad, d, handleEvent);
4637
4638 free(ad);
4639 }
4640
4641 AnimEffect AnimEffectNone = &(AnimEffectInfo)
4642 {"animation:None",
4643 {TRUE, TRUE, TRUE, TRUE, TRUE}};
4644
4645 AnimEffect AnimEffectRandom = &(AnimEffectInfo)
4646 {"animation:Random",
4647 {TRUE, TRUE, TRUE, TRUE, FALSE}};
4648
4649 AnimEffect AnimEffectCurvedFold = &(AnimEffectInfo)
4650 {"animation:Curved Fold",
4651 {TRUE, TRUE, TRUE, TRUE, FALSE},
4652 {.updateWindowAttribFunc = fxFoldUpdateWindowAttrib,
4653 .animStepFunc = fxCurvedFoldModelStep,
4654 .initFunc = animWithTransformInit,
4655 .initGridFunc = fxMagicLampInitGrid,
4656 .updateWinTransformFunc = defaultUpdateWindowTransform,
4657 .updateBBFunc = modelUpdateBB,
4658 .zoomToIconFunc = fxCurvedFoldZoomToIcon,
4659 .modelAnimIs3D = TRUE}};
4660
4661 AnimEffect AnimEffectDodge = &(AnimEffectInfo)
4662 {"animation:Dodge",
4663 {FALSE, FALSE, FALSE, FALSE, TRUE},
4664 {.animStepFunc = fxDodgeAnimStep,
4665 .initFunc = defaultAnimInit,
4666 .letOthersDrawGeomsFunc = returnTrue,
4667 .updateWinTransformFunc = fxDodgeUpdateWindowTransform,
4668 .postPrepPaintScreenFunc = fxDodgePostPreparePaintScreen,
4669 .updateBBFunc = fxDodgeUpdateBB}};
4670
4671 AnimEffect AnimEffectDream = &(AnimEffectInfo)
4672 {"animation:Dream",
4673 {TRUE, TRUE, TRUE, FALSE, FALSE},
4674 {.updateWindowAttribFunc = fxDreamUpdateWindowAttrib,
4675 .animStepFunc = fxDreamModelStep,
4676 .initFunc = fxDreamAnimInit,
4677 .initGridFunc = fxMagicLampInitGrid,
4678 .updateWinTransformFunc = defaultUpdateWindowTransform,
4679 .updateBBFunc = modelUpdateBB,
4680 .zoomToIconFunc = fxDreamZoomToIcon}};
4681
4682 AnimEffect AnimEffectFade = &(AnimEffectInfo)
4683 {"animation:Fade",
4684 {TRUE, TRUE, TRUE, FALSE, FALSE},
4685 {.updateWindowAttribFunc = fxFadeUpdateWindowAttrib,
4686 .animStepFunc = defaultAnimStep,
4687 .initFunc = defaultAnimInit,
4688 .letOthersDrawGeomsFunc = returnTrue,
4689 .updateBBFunc = updateBBWindow}};
4690
4691 AnimEffect AnimEffectFocusFade = &(AnimEffectInfo)
4692 {"animation:Focus Fade",
4693 {FALSE, FALSE, FALSE, FALSE, TRUE},
4694 {.updateWindowAttribFunc = fxFocusFadeUpdateWindowAttrib,
4695 .animStepFunc = defaultAnimStep,
4696 .initFunc = defaultAnimInit,
4697 .letOthersDrawGeomsFunc = returnTrue,
4698 .updateBBFunc = updateBBWindow}};
4699
4700 AnimEffect AnimEffectGlide1 = &(AnimEffectInfo)
4701 {"animation:Glide 1",
4702 {TRUE, TRUE, TRUE, FALSE, FALSE},
4703 {.updateWindowAttribFunc = fxGlideUpdateWindowAttrib,
4704 .prePaintWindowFunc = fxGlidePrePaintWindow,
4705 .postPaintWindowFunc = fxGlidePostPaintWindow,
4706 .animStepFunc = fxGlideAnimStep,
4707 .initFunc = fxGlideInit,
4708 .letOthersDrawGeomsFunc = returnTrue,
4709 .updateWinTransformFunc = fxGlideUpdateWindowTransform,
4710 .updateBBFunc = compTransformUpdateBB,
4711 .zoomToIconFunc = fxGlideZoomToIcon}};
4712
4713 AnimEffect AnimEffectGlide2 = &(AnimEffectInfo)
4714 {"animation:Glide 2",
4715 {TRUE, TRUE, TRUE, FALSE, FALSE},
4716 {.updateWindowAttribFunc = fxGlideUpdateWindowAttrib,
4717 .prePaintWindowFunc = fxGlidePrePaintWindow,
4718 .postPaintWindowFunc = fxGlidePostPaintWindow,
4719 .animStepFunc = fxGlideAnimStep,
4720 .initFunc = fxGlideInit,
4721 .letOthersDrawGeomsFunc = returnTrue,
4722 .updateWinTransformFunc = fxGlideUpdateWindowTransform,
4723 .updateBBFunc = compTransformUpdateBB,
4724 .zoomToIconFunc = fxGlideZoomToIcon}};
4725
4726 AnimEffect AnimEffectHorizontalFolds = &(AnimEffectInfo)
4727 {"animation:Horizontal Folds",
4728 {TRUE, TRUE, TRUE, TRUE, FALSE},
4729 {.updateWindowAttribFunc = fxFoldUpdateWindowAttrib,
4730 .animStepFunc = fxHorizontalFoldsModelStep,
4731 .initFunc = animWithTransformInit,
4732 .initGridFunc = fxHorizontalFoldsInitGrid,
4733 .updateWinTransformFunc = defaultUpdateWindowTransform,
4734 .updateBBFunc = modelUpdateBB,
4735 .zoomToIconFunc = fxHorizontalFoldsZoomToIcon,
4736 .modelAnimIs3D = TRUE}};
4737
4738 AnimEffect AnimEffectMagicLamp = &(AnimEffectInfo)
4739 {"animation:Magic Lamp",
4740 {TRUE, TRUE, TRUE, FALSE, FALSE},
4741 {.animStepFunc = fxMagicLampModelStep,
4742 .initFunc = fxMagicLampInit,
4743 .initGridFunc = fxMagicLampInitGrid,
4744 .updateBBFunc = modelUpdateBB,
4745 .useQTexCoord = TRUE}};
4746
4747 AnimEffect AnimEffectRollUp = &(AnimEffectInfo)
4748 {"animation:Roll Up",
4749 {TRUE, TRUE, TRUE, TRUE, FALSE},
4750 {.animStepFunc = fxRollUpModelStep,
4751 .initFunc = fxRollUpAnimInit,
4752 .initGridFunc = fxRollUpInitGrid,
4753 .updateBBFunc = modelUpdateBB}};
4754
4755 AnimEffect AnimEffectSidekick = &(AnimEffectInfo)
4756 {"animation:Sidekick",
4757 {TRUE, TRUE, TRUE, FALSE, FALSE},
4758 {.updateWindowAttribFunc = fxZoomUpdateWindowAttrib,
4759 .animStepFunc = defaultAnimStep,
4760 .initFunc = fxSidekickInit,
4761 .letOthersDrawGeomsFunc = returnTrue,
4762 .updateWinTransformFunc = defaultUpdateWindowTransform,
4763 .updateBBFunc = compTransformUpdateBB,
4764 .zoomToIconFunc = returnTrue}};
4765
4766 AnimEffect AnimEffectVacuum = &(AnimEffectInfo)
4767 {"animation:Vacuum",
4768 {TRUE, TRUE, FALSE, FALSE, FALSE},
4769 {.animStepFunc = fxMagicLampModelStep,
4770 .initFunc = fxMagicLampInit,
4771 .initGridFunc = fxVacuumInitGrid,
4772 .updateBBFunc = modelUpdateBB,
4773 .useQTexCoord = TRUE}};
4774
4775 AnimEffect AnimEffectWave = &(AnimEffectInfo)
4776 {"animation:Wave",
4777 {TRUE, TRUE, TRUE, FALSE, TRUE},
4778 {.animStepFunc = fxWaveModelStep,
4779 .initFunc = animWithTransformInit,
4780 .initGridFunc = fxMagicLampInitGrid,
4781 .updateWinTransformFunc = defaultUpdateWindowTransform,
4782 .updateBBFunc = modelUpdateBB,
4783 .modelAnimIs3D = TRUE}};
4784
4785 AnimEffect AnimEffectZoom = &(AnimEffectInfo)
4786 {"animation:Zoom",
4787 {TRUE, TRUE, TRUE, FALSE, FALSE},
4788 {.updateWindowAttribFunc = fxZoomUpdateWindowAttrib,
4789 .animStepFunc = defaultAnimStep,
4790 .initFunc = fxZoomInit,
4791 .letOthersDrawGeomsFunc = returnTrue,
4792 .updateWinTransformFunc = defaultUpdateWindowTransform,
4793 .updateBBFunc = compTransformUpdateBB,
4794 .zoomToIconFunc = returnTrue}};
4795
4796 AnimEffect animEffects[NUM_EFFECTS];
4797
4798 ExtensionPluginInfo animExtensionPluginInfo = {
4799 .nEffects = NUM_EFFECTS,
4800 .effects = animEffects,
4801
4802 .nEffectOptions = ANIM_SCREEN_OPTION_NUM - NUM_NONEFFECT_OPTIONS,
4803 };
4804
animInitScreen(CompPlugin * p,CompScreen * s)4805 static Bool animInitScreen(CompPlugin * p, CompScreen * s)
4806 {
4807 AnimScreen *as;
4808 CompDisplay *d = s->display;
4809
4810 ANIM_DISPLAY(d);
4811
4812 as = calloc(1, sizeof(AnimScreen));
4813 if (!as)
4814 return FALSE;
4815
4816 if (!compInitScreenOptionsFromMetadata (s,
4817 &animMetadata,
4818 animScreenOptionInfo,
4819 as->opt,
4820 ANIM_SCREEN_OPTION_NUM))
4821 {
4822 free (as);
4823 return FALSE;
4824 }
4825
4826 as->windowPrivateIndex = allocateWindowPrivateIndex(s);
4827 if (as->windowPrivateIndex < 0)
4828 {
4829 compFiniScreenOptions (s, as->opt, ANIM_SCREEN_OPTION_NUM);
4830 free(as);
4831 return FALSE;
4832 }
4833
4834 s->base.privates[ad->screenPrivateIndex].ptr = as;
4835
4836 as->animInProgress = FALSE;
4837
4838 AnimEffect animEffectsTmp[NUM_EFFECTS] =
4839 {
4840 AnimEffectNone,
4841 AnimEffectRandom,
4842 AnimEffectCurvedFold,
4843 AnimEffectDodge,
4844 AnimEffectDream,
4845 AnimEffectFade,
4846 AnimEffectFocusFade,
4847 AnimEffectGlide1,
4848 AnimEffectGlide2,
4849 AnimEffectHorizontalFolds,
4850 AnimEffectMagicLamp,
4851 AnimEffectRollUp,
4852 AnimEffectSidekick,
4853 AnimEffectVacuum,
4854 AnimEffectWave,
4855 AnimEffectZoom
4856 };
4857 memcpy (animEffects,
4858 animEffectsTmp,
4859 NUM_EFFECTS * sizeof (AnimEffect));
4860
4861 animExtensionPluginInfo.effectOptions = &as->opt[NUM_NONEFFECT_OPTIONS];
4862
4863 // Extends itself with the basic set of animation effects.
4864 animAddExtension (s, &animExtensionPluginInfo);
4865
4866 AnimEvent e;
4867 for (e = 0; e < AnimEventNum; e++) // for each anim event
4868 updateOptionSets (s, e);
4869
4870 updateAllEventEffects (s);
4871
4872 as->lastClientListStacking = NULL;
4873 as->nLastClientListStacking = 0;
4874
4875 WRAP(as, s, preparePaintScreen, animPreparePaintScreen);
4876 WRAP(as, s, donePaintScreen, animDonePaintScreen);
4877 WRAP(as, s, paintOutput, animPaintOutput);
4878 WRAP(as, s, paintWindow, animPaintWindow);
4879 WRAP(as, s, damageWindowRect, animDamageWindowRect);
4880 WRAP(as, s, addWindowGeometry, animAddWindowGeometry);
4881 WRAP(as, s, drawWindowTexture, animDrawWindowTexture);
4882 WRAP(as, s, windowResizeNotify, animWindowResizeNotify);
4883 WRAP(as, s, windowMoveNotify, animWindowMoveNotify);
4884 WRAP(as, s, windowGrabNotify, animWindowGrabNotify);
4885 WRAP(as, s, windowUngrabNotify, animWindowUngrabNotify);
4886 WRAP(as, s, initWindowWalker, animInitWindowWalker);
4887
4888 as->startCountdown = 20; // start the countdown
4889
4890 return TRUE;
4891 }
4892
animFiniScreen(CompPlugin * p,CompScreen * s)4893 static void animFiniScreen(CompPlugin * p, CompScreen * s)
4894 {
4895 ANIM_SCREEN(s);
4896
4897 if (as->animInProgress)
4898 animActivateEvent(s, FALSE);
4899
4900 freeWindowPrivateIndex(s, as->windowPrivateIndex);
4901
4902 if (as->lastClientListStacking)
4903 free(as->lastClientListStacking);
4904
4905 free (as->extensionPlugins);
4906 freeAllEffects (as);
4907 freeAllOptionSets (as);
4908
4909 UNWRAP(as, s, preparePaintScreen);
4910 UNWRAP(as, s, donePaintScreen);
4911 UNWRAP(as, s, paintOutput);
4912 UNWRAP(as, s, paintWindow);
4913 UNWRAP(as, s, damageWindowRect);
4914 UNWRAP(as, s, addWindowGeometry);
4915 UNWRAP(as, s, drawWindowTexture);
4916 UNWRAP(as, s, windowResizeNotify);
4917 UNWRAP(as, s, windowMoveNotify);
4918 UNWRAP(as, s, windowGrabNotify);
4919 UNWRAP(as, s, windowUngrabNotify);
4920 UNWRAP(as, s, initWindowWalker);
4921
4922 compFiniScreenOptions (s, as->opt, ANIM_SCREEN_OPTION_NUM);
4923
4924 free(as);
4925 }
4926
animInitWindow(CompPlugin * p,CompWindow * w)4927 static Bool animInitWindow(CompPlugin * p, CompWindow * w)
4928 {
4929 AnimWindow *aw;
4930
4931 ANIM_SCREEN(w->screen);
4932
4933 aw = calloc(1, sizeof(AnimWindow));
4934 if (!aw)
4935 return FALSE;
4936
4937 aw->com.model = 0;
4938 aw->com.animRemainingTime = 0;
4939 aw->animInitialized = FALSE;
4940 aw->com.curAnimEffect = AnimEffectNone;
4941 aw->com.curWindowEvent = WindowEventNone;
4942 aw->com.animOverrideProgressDir = 0;
4943 aw->curAnimSelectionRow = -1;
4944
4945 w->indexCount = 0;
4946
4947 aw->unmapCnt = 0;
4948 aw->destroyCnt = 0;
4949
4950 aw->grabbed = FALSE;
4951
4952 aw->com.useDrawRegion = FALSE;
4953 aw->com.drawRegion = NULL;
4954
4955 aw->BB.x1 = aw->BB.y1 = MAXSHORT;
4956 aw->BB.x2 = aw->BB.y2 = MINSHORT;
4957
4958 aw->nowShaded = FALSE;
4959
4960 if (w->minimized)
4961 {
4962 aw->state = aw->newState = IconicState;
4963 }
4964 else if (w->shaded)
4965 {
4966 aw->state = aw->newState = NormalState;
4967 aw->nowShaded = TRUE;
4968 }
4969 else
4970 {
4971 aw->state = aw->newState = animGetWindowState(w);
4972 }
4973
4974 w->base.privates[as->windowPrivateIndex].ptr = aw;
4975
4976 return TRUE;
4977 }
4978
animFiniWindow(CompPlugin * p,CompWindow * w)4979 static void animFiniWindow(CompPlugin * p, CompWindow * w)
4980 {
4981 ANIM_SCREEN(w->screen);
4982 ANIM_WINDOW(w);
4983
4984 postAnimationCleanupCustom (w, FALSE, TRUE, TRUE);
4985
4986 animFreeModel(aw);
4987
4988 free(aw);
4989 w->base.privates[as->windowPrivateIndex].ptr = NULL;
4990 }
4991
4992 static CompBool
animInitObject(CompPlugin * p,CompObject * o)4993 animInitObject (CompPlugin *p,
4994 CompObject *o)
4995 {
4996 static InitPluginObjectProc dispTab[] = {
4997 (InitPluginObjectProc) 0, /* InitCore */
4998 (InitPluginObjectProc) animInitDisplay,
4999 (InitPluginObjectProc) animInitScreen,
5000 (InitPluginObjectProc) animInitWindow
5001 };
5002
5003 RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
5004 }
5005
5006 static void
animFiniObject(CompPlugin * p,CompObject * o)5007 animFiniObject (CompPlugin *p,
5008 CompObject *o)
5009 {
5010 static FiniPluginObjectProc dispTab[] = {
5011 (FiniPluginObjectProc) 0, /* FiniCore */
5012 (FiniPluginObjectProc) animFiniDisplay,
5013 (FiniPluginObjectProc) animFiniScreen,
5014 (FiniPluginObjectProc) animFiniWindow
5015 };
5016
5017 DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
5018 }
5019
5020 static CompOption *
animGetObjectOptions(CompPlugin * plugin,CompObject * object,int * count)5021 animGetObjectOptions (CompPlugin *plugin,
5022 CompObject *object,
5023 int *count)
5024 {
5025 static GetPluginObjectOptionsProc dispTab[] = {
5026 (GetPluginObjectOptionsProc) 0, /* GetCoreOptions */
5027 (GetPluginObjectOptionsProc) animGetDisplayOptions,
5028 (GetPluginObjectOptionsProc) animGetScreenOptions
5029 };
5030
5031 *count = 0;
5032 RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab),
5033 NULL, (plugin, object, count));
5034 }
5035
5036 static CompBool
animSetObjectOption(CompPlugin * plugin,CompObject * object,const char * name,CompOptionValue * value)5037 animSetObjectOption (CompPlugin *plugin,
5038 CompObject *object,
5039 const char *name,
5040 CompOptionValue *value)
5041 {
5042 static SetPluginObjectOptionProc dispTab[] = {
5043 (SetPluginObjectOptionProc) 0, /* SetCoreOption */
5044 (SetPluginObjectOptionProc) animSetDisplayOption,
5045 (SetPluginObjectOptionProc) animSetScreenOptions
5046 };
5047
5048 RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab), FALSE,
5049 (plugin, object, name, value));
5050 }
5051
animInit(CompPlugin * p)5052 static Bool animInit(CompPlugin * p)
5053 {
5054 if (!compInitPluginMetadataFromInfo (&animMetadata,
5055 p->vTable->name,
5056 0, 0,
5057 animScreenOptionInfo,
5058 ANIM_SCREEN_OPTION_NUM))
5059 return FALSE;
5060
5061 animDisplayPrivateIndex = allocateDisplayPrivateIndex();
5062 if (animDisplayPrivateIndex < 0)
5063 {
5064 compFiniMetadata (&animMetadata);
5065 return FALSE;
5066 }
5067
5068 animFunctionsPrivateIndex = allocateDisplayPrivateIndex ();
5069 if (animFunctionsPrivateIndex < 0)
5070 {
5071 freeDisplayPrivateIndex (animDisplayPrivateIndex);
5072 compFiniMetadata (&animMetadata);
5073 return FALSE;
5074 }
5075
5076 compAddMetadataFromFile (&animMetadata, p->vTable->name);
5077
5078 return TRUE;
5079 }
5080
animFini(CompPlugin * p)5081 static void animFini(CompPlugin * p)
5082 {
5083 freeDisplayPrivateIndex(animDisplayPrivateIndex);
5084 freeDisplayPrivateIndex (animFunctionsPrivateIndex);
5085 compFiniMetadata (&animMetadata);
5086 }
5087
5088 static CompMetadata *
animGetMetadata(CompPlugin * plugin)5089 animGetMetadata (CompPlugin *plugin)
5090 {
5091 return &animMetadata;
5092 }
5093
5094 CompPluginVTable animVTable = {
5095 "animation",
5096 animGetMetadata,
5097 animInit,
5098 animFini,
5099 animInitObject,
5100 animFiniObject,
5101 animGetObjectOptions,
5102 animSetObjectOption,
5103 };
5104
5105 CompPluginVTable*
getCompPluginInfo20070830(void)5106 getCompPluginInfo20070830 (void)
5107 {
5108 return &animVTable;
5109 }
5110
5111