2
* Animation plugin for compiz/beryl
6
* Copyright : (C) 2006 Erkin Bahceci
7
* E-mail : erkinbah@gmail.com
9
* Based on Wobbly and Minimize plugins by
11
* E-mail : davidr@novell.com>
13
* Particle system added by : (C) 2006 Dennis Kasprzyk
14
* E-mail : onestone@beryl-project.org
16
* Beam-Up added by : Florencio Guimaraes
17
* E-mail : florencio@nexcorp.com.br
19
* Hexagon tessellator added by : Mike Slegeir
20
* E-mail : mikeslegeir@mail.utexas.edu>
22
* This program is free software; you can redistribute it and/or
23
* modify it under the terms of the GNU General Public License
24
* as published by the Free Software Foundation; either version 2
25
* of the License, or (at your option) any later version.
27
* This program is distributed in the hope that it will be useful,
28
* but WITHOUT ANY WARRANTY; without even the implied warranty of
29
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30
* GNU General Public License for more details.
32
* You should have received a copy of the GNU General Public License
33
* along with this program; if not, write to the Free Software
34
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
40
ExtensionPluginAnimation::ExtensionPluginAnimation
41
(const CompString &name,
42
unsigned int nEffects,
44
CompOption::Vector *effectOptions,
45
unsigned int firstEffectOptionIndex) :
46
ExtensionPluginInfo (name, nEffects, effects, effectOptions,
47
firstEffectOptionIndex),
48
mAWinWasRestackedJustNow (false),
53
ExtensionPluginAnimation::~ExtensionPluginAnimation ()
58
ExtensionPluginAnimation::postPreparePaintGeneral ()
60
if (mAWinWasRestackedJustNow)
61
mAWinWasRestackedJustNow = false;
65
ExtensionPluginAnimation::cleanUpParentChildChainItem (AnimWindow *aw)
67
PersistentDataMap::iterator itData =
68
aw->persistentData.find ("restack");
69
if (itData != aw->persistentData.end ()) // if found
71
RestackPersistentData *restackData =
72
static_cast<RestackPersistentData *> (itData->second);
74
if (restackData->mWinThisIsPaintedBefore &&
75
!restackData->mWinThisIsPaintedBefore->destroyed ())
77
RestackPersistentData *dataOther = static_cast<RestackPersistentData *>
78
(AnimWindow::get (restackData->mWinThisIsPaintedBefore)->
79
persistentData["restack"]);
81
dataOther->mWinToBePaintedBeforeThis = 0;
83
restackData->mWinThisIsPaintedBefore = 0;
84
restackData->mMoreToBePaintedPrev = 0;
85
restackData->mMoreToBePaintedNext = 0;
88
itData = aw->persistentData.find ("dodge");
89
if (itData != aw->persistentData.end ()) // if found
91
DodgePersistentData *dodgeData =
92
static_cast<DodgePersistentData *> (itData->second);
94
dodgeData->isDodgeSubject = false;
95
dodgeData->skipPostPrepareScreen = false;
100
ExtensionPluginAnimation::paintShouldSkipWindow (CompWindow *w)
102
AnimWindow *aw = AnimWindow::get (w);
103
PersistentDataMap::iterator itData = aw->persistentData.find ("restack");
104
if (itData != aw->persistentData.end ()) // if found
106
RestackPersistentData *data =
107
static_cast<RestackPersistentData *> (itData->second);
109
// Increment (glPaint) visit count
112
// If the window is (to be) painted somewhere other than in its
113
// original stacking order, we don't need to paint it now.
114
if (aw->curAnimation ()->info ()->isRestackAnim &&
115
dynamic_cast<RestackAnim *> (aw->curAnimation ())->paintedElsewhere ())
121
/// Returns whether this window is relevant for fade focus.
123
ExtensionPluginAnimation::relevantForRestackAnim (CompWindow *w)
125
unsigned int wmType = w->wmType ();
127
// these two are to be used as "host" windows
128
// to host the painting of windows being focused
129
// at a stacking order lower than them
130
(CompWindowTypeDockMask | CompWindowTypeSplashMask)) ||
131
wmType == CompWindowTypeNormalMask ||
132
wmType == CompWindowTypeDialogMask ||
133
wmType == CompWindowTypeUtilMask ||
134
wmType == CompWindowTypeUnknownMask))
138
return !w->destroyed ();
142
ExtensionPluginAnimation::prePreparePaintGeneral ()
144
if (!mAWinWasRestackedJustNow)
147
bool focusAnimInitiated = false;
148
AnimScreen *as = AnimScreen::get (::screen);
150
// Go in reverse order so that restack chains are handled properly
151
for (CompWindowVector::reverse_iterator rit = mLastClientList.rbegin ();
152
rit != mLastClientList.rend (); rit++)
154
CompWindow *w = (*rit);
155
AnimWindow *aw = AnimWindow::get (w);
156
RestackPersistentData *data = static_cast<RestackPersistentData *>
157
(aw->persistentData["restack"]);
160
RestackInfo *restackInfo = data->restackInfo ();
164
data->mIsSecondary = false;
166
if (as->otherPluginsActive () ||
167
// Don't initiate focus anim for current dodgers
168
aw->curAnimation () ||
169
// Don't initiate focus anim for windows being passed thru
170
data->mWinPassingThrough ||
171
// Don't animate with stale restack info
172
!restackInfoStillGood (restackInfo))
174
data->resetRestackInfo (true);
178
// Find the first window at a higher stacking order than w
180
for (nw = w->next; nw; nw = nw->next)
182
if (relevantForRestackAnim (nw))
186
// If w is being lowered, there has to be a window
187
// at a higher stacking position than w (like a panel)
188
// which this w's copy can be painted before.
189
// Otherwise the animation will only show w fading in
190
// rather than 2 copies of it cross-fading.
191
if (!restackInfo->raised && !nw)
193
// Free unnecessary restackInfo
194
data->resetRestackInfo (true);
198
// Check if above window is focus-fading/dodging too.
199
// (like a dialog of an app. window)
200
// If so, focus-fade/dodge this together with the one above
204
RestackPersistentData *dataNext =
205
static_cast<RestackPersistentData *>
206
(AnimWindow::get (nw)->persistentData["restack"]);
208
if (dataNext && dataNext->restackInfo () &&
209
wontCreateCircularChain (w, nw))
212
dataNext->mMoreToBePaintedPrev = w;
213
data->mMoreToBePaintedNext = nw;
215
// so far, bottommost on chain
216
data->mMoreToBePaintedPrev = 0;
221
// Reset chain connections as this is not (yet) on a chain
222
data->mMoreToBePaintedNext = 0;
223
data->mMoreToBePaintedPrev = 0;
227
// Now initiate focus animations (after the restack chains are formed
229
for (CompWindowVector::reverse_iterator rit = mLastClientList.rbegin ();
230
rit != mLastClientList.rend (); rit++)
232
CompWindow *w = (*rit);
233
AnimWindow *aw = AnimWindow::get (w);
234
RestackPersistentData *data = static_cast<RestackPersistentData *>
235
(aw->persistentData["restack"]);
239
RestackInfo *restackInfo = data->restackInfo ();
242
if (as->initiateFocusAnim (aw))
243
focusAnimInitiated = true;
245
data->resetRestackInfo (true);
249
if (!focusAnimInitiated)
250
resetStackingInfo ();
252
if (!focusAnimInitiated ||
253
as->otherPluginsActive () ||
254
!as->isAnimEffectPossible (AnimEffectDodge)) // Only dodge stuff below
257
// Calculate dodge amounts
258
foreach (CompWindow *w, mLastClientList)
260
AnimWindow *aw = AnimWindow::get (w);
261
Animation *curAnim = aw->curAnimation ();
262
if (!curAnim || curAnim->info () != AnimEffectDodge)
265
// Only process subjects with a dodge chain
266
DodgePersistentData *dodgeData = static_cast<DodgePersistentData *>
267
(aw->persistentData["dodge"]);
268
if (!dodgeData || !dodgeData->dodgeChainStart ||
269
!dodgeData->isDodgeSubject)
272
dynamic_cast<DodgeAnim *> (curAnim)->calculateDodgeAmounts ();
275
// TODO consider removing this loop and skipPostPrepareScreen
276
for (CompWindowVector::reverse_iterator rit = mLastClientList.rbegin ();
277
rit != mLastClientList.rend (); rit++)
279
CompWindow *w = (*rit);
280
AnimWindow *aw = AnimWindow::get (w);
281
PersistentDataMap::iterator itData = aw->persistentData.find ("dodge");
282
if (itData == aw->persistentData.end ()) // if not found
285
DodgePersistentData *data = static_cast<DodgePersistentData *>
287
if (!data->isDodgeSubject)
290
bool dodgersAreOnlySubjects = true;
292
DodgePersistentData *dataDodger;
293
for (dw = data->dodgeChainStart; dw;
294
dw = dataDodger->dodgeChainNext)
296
dataDodger = static_cast<DodgePersistentData *>
297
(AnimWindow::get (dw)->persistentData["dodge"]);
300
if (!dataDodger->isDodgeSubject)
301
dodgersAreOnlySubjects = false;
303
if (dodgersAreOnlySubjects)
304
data->skipPostPrepareScreen = true;
309
ExtensionPluginAnimation::handleRestackNotify (AnimWindow *aw)
311
const CompWindowVector &clients = ::screen->clientList ();
313
// Only handle restack notifies when the window is (or was) on the client
314
// list (i.e. not for menus, combos, etc.).
315
if (find (clients.begin (), clients.end (), aw->mWindow) ==
317
find (mLastClientList.begin (), mLastClientList.end (), aw->mWindow) ==
318
mLastClientList.end ())
321
bool winOpenedClosed = false;
322
unsigned int n = clients.size ();
324
if (n != mLastClientList.size ())
326
winOpenedClosed = true;
328
// if restacking occurred and not window open/close
329
if (!winOpenedClosed)
331
RestackPersistentData *data = static_cast<RestackPersistentData *>
332
(aw->persistentData["restack"]);
333
data->mConfigureNotified = true;
335
// Find which window is restacked
336
// e.g. here 8507730 was raised:
337
// 54526074 8507730 48234499 14680072 6291497
338
// 54526074 48234499 14680072 8507730 6291497
339
// compare first changed win. of row 1 with last
340
// changed win. of row 2, and vica versa
341
// the matching one is the restacked one
342
CompWindow *wRestacked = 0;
343
CompWindow *wStart = 0;
344
CompWindow *wEnd = 0;
345
CompWindow *wOldAbove = 0;
346
CompWindow *wChangeStart = 0;
347
CompWindow *wChangeEnd = 0;
350
int changeStart = -1;
353
for (unsigned int i = 0; i < n; i++)
355
CompWindow *wi = clients[i];
357
// skip if minimized (prevents flashing problem)
358
if (!wi || wi->destroyed ())
361
// TODO find another filter criteria for Group plugin
362
// because some apps like gedit sets its open dialog
363
// to skip taskbar too, which shouldn't be ignored here.
365
// skip if (tabbed and) hidden by Group plugin
366
// unless it's a dock/panel
367
if (!(wi->wmType () & CompWindowTypeDockMask) &&
368
(wi->state () & (CompWindowStateSkipPagerMask |
369
CompWindowStateSkipTaskbarMask)))
372
if (wi != mLastClientList[i])
376
changeStart = (int)i;
377
wChangeStart = wi; // make use of already found w
385
else if (changeStart >= 0) // found some change earlier
389
// if restacking occurred
390
if (changeStart >= 0 && changeEnd >= 0)
392
// if we have only 2 windows changed,
393
// choose the one clicked on
394
bool preferRaised = false;
395
bool onlyTwo = false;
398
clients[(unsigned)changeEnd] ==
399
mLastClientList[(unsigned)changeStart] &&
400
clients[(unsigned)changeStart] ==
401
mLastClientList[(unsigned)changeEnd])
403
// Check if the window coming on top was
404
// mConfigureNotified (clicked on)
405
RestackPersistentData *data =
406
static_cast<RestackPersistentData *>
407
(AnimWindow::get (wChangeEnd)->
408
persistentData["restack"]);
409
if (data->mConfigureNotified)
414
// Clear all mConfigureNotified's
415
foreach (CompWindow *w2, ::screen->windows ())
417
RestackPersistentData *data =
418
static_cast<RestackPersistentData *>
419
(AnimWindow::get (w2)->persistentData["restack"]);
420
data->mConfigureNotified = false;
425
clients[(unsigned)changeEnd] ==
426
mLastClientList[(unsigned)changeStart]))
430
wRestacked = wChangeEnd;
431
wStart = wChangeStart;
435
else if (clients[(unsigned)changeStart] ==
436
mLastClientList[(unsigned)changeEnd] && // lowered
437
// We don't animate lowering if there is no
438
// window above this window, since this window needs
439
// to be drawn on such a "host" in animPaintWindow
440
// (at least for now).
441
(unsigned int)changeEnd < n - 1)
443
wRestacked = wChangeStart;
446
wOldAbove = mLastClientList[(unsigned)(changeEnd + 1)];
448
for (; wOldAbove; wOldAbove = wOldAbove->next)
450
if (!wOldAbove->destroyed ())
455
if (wRestacked && wStart && wEnd && wOldAbove)
457
AnimWindow *awRestacked = AnimWindow::get (wRestacked);
458
RestackPersistentData *data = static_cast<RestackPersistentData *>
459
(awRestacked->persistentData["restack"]);
461
data->setRestackInfo (wRestacked, wStart, wEnd, wOldAbove,
463
mAWinWasRestackedJustNow = true;
468
updateLastClientList ();
472
ExtensionPluginAnimation::updateLastClientList ()
474
mLastClientList = ::screen->clientList ();
477
/// Returns true if linking wCur to wNext would not result
478
/// in a circular chain being formed.
480
ExtensionPluginAnimation::wontCreateCircularChain (CompWindow *wCur,
483
RestackPersistentData *dataNext = 0;
487
if (wNext == wCur) // would form circular chain
490
dataNext = static_cast<RestackPersistentData *>
491
(AnimWindow::get (wNext)->persistentData["restack"]);
496
wNext = dataNext->mMoreToBePaintedNext;
502
ExtensionPluginAnimation::postUpdateEventEffects (AnimEvent e,
505
AnimScreen *as = AnimScreen::get (::screen);
507
// If a restacking anim. is (now) possible
508
if (e == AnimEventFocus)
510
if (as->isRestackAnimPossible ())
512
// Update the stored window list so that we have an up-to-date list,
513
// since that list wasn't updated while a restacking animation
515
updateLastClientList ();
517
foreach (CompWindow *w, ::screen->windows ())
519
AnimWindow *aw = AnimWindow::get (w);
520
// Allocate persistent restack data if it doesn't already exist
521
if (aw->persistentData.find ("restack") !=
522
aw->persistentData.end ())
524
aw->persistentData["restack"] = new RestackPersistentData ();
527
if (as->isAnimEffectPossible (AnimEffectDodge))
529
foreach (CompWindow *w, ::screen->windows ())
531
AnimWindow *aw = AnimWindow::get (w);
532
// Allocate persistent dodge data if it doesn't already exist
533
if (aw->persistentData.find ("dodge") !=
534
aw->persistentData.end ())
536
aw->persistentData["dodge"] = new DodgePersistentData ();
543
ExtensionPluginAnimation::initPersistentData (AnimWindow *aw)
545
AnimScreen *as = AnimScreen::get (::screen);
547
// TODO: Optimize (via caching isRestackAnimPossible, isAnimEffectPossible)
549
// Only allocate restack data when restack animation is possible
550
if (as->isRestackAnimPossible () &&
552
aw->persistentData.find ("restack") == aw->persistentData.end ())
554
aw->persistentData["restack"] = new RestackPersistentData ();
556
if (as->isAnimEffectPossible (AnimEffectDodge) &&
558
aw->persistentData.find ("dodge") == aw->persistentData.end ())
560
aw->persistentData["dodge"] = new DodgePersistentData ();
562
if (aw->persistentData.find ("multi") == aw->persistentData.end ())
564
aw->persistentData["multi"] = new MultiPersistentData ();
569
ExtensionPluginAnimation::destroyPersistentData (AnimWindow *aw)
571
aw->deletePersistentData ("restack");
572
aw->deletePersistentData ("dodge");
576
ExtensionPluginAnimation::incrementCurRestackAnimCount ()
580
// Enable custom paint list when there is now a restack anim happening
581
if (mRestackAnimCount == 1)
582
AnimScreen::get (::screen)->enableCustomPaintList (true);
586
ExtensionPluginAnimation::decrementCurRestackAnimCount ()
590
// Disable custom paint list when there is no more a restack anim happening
591
if (mRestackAnimCount == 0)
592
AnimScreen::get (::screen)->enableCustomPaintList (false);
596
ExtensionPluginAnimation::restackInfoStillGood (RestackInfo *restackInfo)
598
bool wStartGood = false;
599
bool wEndGood = false;
600
bool wOldAboveGood = false;
601
bool wRestackedGood = false;
603
foreach (CompWindow *w, ::screen->windows ())
605
AnimWindow *aw = AnimWindow::get (w);
607
if (aw->mWindow->destroyed ())
610
if (restackInfo->wStart == w)
612
if (restackInfo->wEnd == w)
614
if (restackInfo->wRestacked == w)
615
wRestackedGood = true;
616
if (restackInfo->wOldAbove == w)
617
wOldAboveGood = true;
619
return (wStartGood && wEndGood && wOldAboveGood && wRestackedGood);
622
/// Resets stacking related info.
624
ExtensionPluginAnimation::resetStackingInfo ()
626
foreach (CompWindow *w, ::screen->windows ())
628
AnimWindow *aw = AnimWindow::get (w);
629
PersistentDataMap::iterator itData =
630
aw->persistentData.find ("restack");
631
if (itData != aw->persistentData.end ()) // if found
633
RestackPersistentData *data =
634
static_cast<RestackPersistentData *> (itData->second);
635
data->mConfigureNotified = false;
636
if (data->restackInfo ())
637
data->resetRestackInfo ();
643
ExtensionPluginAnimation::postStartupCountdown ()
645
updateLastClientList ();
649
ExtensionPluginAnimation::preInitiateOpenAnim (AnimWindow *aw)
651
// Only do when the window is on the client list
652
// (i.e. not for menus, combos, etc.).
653
if (find (::screen->clientList ().begin (),
654
::screen->clientList ().end (), aw->mWindow) !=
655
::screen->clientList ().end ())
657
resetStackingInfo ();
658
updateLastClientList ();
663
ExtensionPluginAnimation::preInitiateCloseAnim (AnimWindow *aw)
665
preInitiateOpenAnim (aw);
669
ExtensionPluginAnimation::preInitiateMinimizeAnim (AnimWindow *aw)
671
preInitiateOpenAnim (aw);
675
ExtensionPluginAnimation::preInitiateUnminimizeAnim (AnimWindow *aw)
677
preInitiateOpenAnim (aw);
681
ExtensionPluginAnimation::cleanUpAnimation (bool closing,
684
if (closing || destructing)
685
updateLastClientList ();
688
/// Go to the bottommost window in this "focus chain"
689
/// This chain is used to handle some cases: e.g when Find dialog
690
/// of an app is open, both windows should be faded when the Find
691
/// dialog is raised.
693
ExtensionPluginAnimation::getBottommostInExtendedFocusChain (CompWindow *wStartPoint)
698
RestackPersistentData *data = static_cast<RestackPersistentData *>
699
(AnimWindow::get (wStartPoint)->persistentData["restack"]);
700
CompWindow *wBottommost = data->mWinToBePaintedBeforeThis;
702
if (!wBottommost || wBottommost->destroyed ())
705
RestackPersistentData *dataBottommost = static_cast<RestackPersistentData *>
706
(AnimWindow::get (wBottommost)->persistentData["restack"]);
707
CompWindow *wPrev = dataBottommost->mMoreToBePaintedPrev;
711
RestackPersistentData *dataPrev = static_cast<RestackPersistentData *>
712
(AnimWindow::get (wPrev)->persistentData["restack"]);
713
wPrev = dataPrev->mMoreToBePaintedPrev;
718
/// Finds the bottommost subject in restack chain,
719
/// simpler version of getBottommostInExtendedFocusChain.
721
ExtensionPluginAnimation::getBottommostInRestackChain (CompWindow *wStartPoint)
723
CompWindow *wBottommost = wStartPoint;
724
RestackPersistentData *dataCur;
725
for (CompWindow *wCur = wStartPoint; wCur;
726
wCur = dataCur->mMoreToBePaintedPrev)
729
dataCur = static_cast<RestackPersistentData *>
730
(AnimWindow::get (wCur)->persistentData["restack"]);
738
ExtensionPluginAnimation::resetMarks ()
740
foreach (CompWindow *w, ::screen->windows ())
742
RestackPersistentData *data = static_cast<RestackPersistentData *>
743
(AnimWindow::get (w)->persistentData["restack"]);
744
data->mWalkerOverNewCopy = false;
745
data->mVisitCount = 0;
750
ExtensionPluginAnimation::prePaintWindowsBackToFront ()
756
ExtensionPluginAnimation::walkFirst ()
761
getBottommostInExtendedFocusChain (*::screen->windows ().begin ());
764
RestackPersistentData *data = static_cast<RestackPersistentData *>
765
(AnimWindow::get (w)->persistentData["restack"]);
772
ExtensionPluginAnimation::markNewCopy (CompWindow *w)
774
RestackPersistentData *data = static_cast<RestackPersistentData *>
775
(AnimWindow::get (w)->persistentData["restack"]);
777
// if window is in a focus chain
778
if (data->mWinThisIsPaintedBefore ||
779
data->mMoreToBePaintedPrev)
781
data->mWalkerOverNewCopy = true;
788
ExtensionPluginAnimation::walkNext (CompWindow *w)
790
RestackPersistentData *data = static_cast<RestackPersistentData *>
791
(AnimWindow::get (w)->persistentData["restack"]);
793
CompWindow *wRet = 0;
795
if (!data->mWalkerOverNewCopy)
797
// Within a chain? (not the 1st or 2nd window)
798
if (data->mMoreToBePaintedNext)
800
wRet = data->mMoreToBePaintedNext;
802
else if (data->mWinThisIsPaintedBefore) // 2nd one in chain?
804
wRet = data->mWinThisIsPaintedBefore;
808
data->mWalkerOverNewCopy = false;
810
if (!wRet && w->next && markNewCopy (w->next))
816
wRet = getBottommostInExtendedFocusChain (w->next);
821
RestackPersistentData *dataRet = static_cast<RestackPersistentData *>
822
(AnimWindow::get (wRet)->persistentData["restack"]);
824
// Prevent cycles, which cause freezes
825
if (dataRet->mVisitCount > 1) // each window is visited at most twice
827
dataRet->mVisitCount++;
832
const CompWindowList &
833
ExtensionPluginAnimation::getWindowPaintList ()
835
mWindowList.clear ();
836
for (CompWindow *w = walkFirst (); w; w = walkNext (w))
837
mWindowList.push_back (w);