~lbrulet-8/compiz-plugins-main/fix-876591

« back to all changes in this revision

Viewing changes to animation/src/extensionplugin.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2011-02-24 17:34:18 UTC
  • Revision ID: james.westby@ubuntu.com-20110224173418-b81hfllshqpciq6n
Tags: upstream-0.9.4
ImportĀ upstreamĀ versionĀ 0.9.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 * Particle system added by : (C) 2006 Dennis Kasprzyk
 
14
 * E-mail                   : onestone@beryl-project.org
 
15
 *
 
16
 * Beam-Up added by : Florencio Guimaraes
 
17
 * E-mail           : florencio@nexcorp.com.br
 
18
 *
 
19
 * Hexagon tessellator added by : Mike Slegeir
 
20
 * E-mail                       : mikeslegeir@mail.utexas.edu>
 
21
 *
 
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.
 
26
 *
 
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.
 
31
 *
 
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.
 
35
 */
 
36
 
 
37
#include "private.h"
 
38
 
 
39
 
 
40
ExtensionPluginAnimation::ExtensionPluginAnimation
 
41
    (const CompString &name,
 
42
     unsigned int nEffects,
 
43
     AnimEffect *effects,
 
44
     CompOption::Vector *effectOptions,
 
45
     unsigned int firstEffectOptionIndex) :
 
46
    ExtensionPluginInfo (name, nEffects, effects, effectOptions,
 
47
                         firstEffectOptionIndex),
 
48
    mAWinWasRestackedJustNow (false),
 
49
    mRestackAnimCount (0)
 
50
{
 
51
}
 
52
 
 
53
ExtensionPluginAnimation::~ExtensionPluginAnimation ()
 
54
{
 
55
}
 
56
 
 
57
void
 
58
ExtensionPluginAnimation::postPreparePaintGeneral ()
 
59
{
 
60
    if (mAWinWasRestackedJustNow)
 
61
        mAWinWasRestackedJustNow = false;
 
62
}
 
63
 
 
64
void
 
65
ExtensionPluginAnimation::cleanUpParentChildChainItem (AnimWindow *aw)
 
66
{
 
67
    PersistentDataMap::iterator itData =
 
68
        aw->persistentData.find ("restack");
 
69
    if (itData != aw->persistentData.end ()) // if found
 
70
    {
 
71
        RestackPersistentData *restackData =
 
72
            static_cast<RestackPersistentData *> (itData->second);
 
73
 
 
74
        if (restackData->mWinThisIsPaintedBefore &&
 
75
            !restackData->mWinThisIsPaintedBefore->destroyed ())
 
76
        {
 
77
            RestackPersistentData *dataOther = static_cast<RestackPersistentData *>
 
78
                (AnimWindow::get (restackData->mWinThisIsPaintedBefore)->
 
79
                 persistentData["restack"]);
 
80
            if (dataOther)
 
81
                dataOther->mWinToBePaintedBeforeThis = 0;
 
82
        }
 
83
        restackData->mWinThisIsPaintedBefore = 0;
 
84
        restackData->mMoreToBePaintedPrev = 0;
 
85
        restackData->mMoreToBePaintedNext = 0;
 
86
    }
 
87
 
 
88
    itData = aw->persistentData.find ("dodge");
 
89
    if (itData != aw->persistentData.end ()) // if found
 
90
    {
 
91
        DodgePersistentData *dodgeData =
 
92
            static_cast<DodgePersistentData *> (itData->second);
 
93
 
 
94
        dodgeData->isDodgeSubject = false;
 
95
        dodgeData->skipPostPrepareScreen = false;
 
96
    }
 
97
}
 
98
 
 
99
bool
 
100
ExtensionPluginAnimation::paintShouldSkipWindow (CompWindow *w)
 
101
{
 
102
    AnimWindow *aw = AnimWindow::get (w);
 
103
    PersistentDataMap::iterator itData = aw->persistentData.find ("restack");
 
104
    if (itData != aw->persistentData.end ()) // if found
 
105
    {
 
106
        RestackPersistentData *data =
 
107
            static_cast<RestackPersistentData *> (itData->second);
 
108
 
 
109
        // Increment (glPaint) visit count
 
110
        data->mVisitCount++;
 
111
 
 
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 ())
 
116
            return true;
 
117
    }
 
118
    return false;
 
119
}
 
120
 
 
121
/// Returns whether this window is relevant for fade focus.
 
122
bool
 
123
ExtensionPluginAnimation::relevantForRestackAnim (CompWindow *w)
 
124
{
 
125
    unsigned int wmType = w->wmType ();
 
126
    if (!((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))
 
135
    {
 
136
        return false;
 
137
    }
 
138
    return !w->destroyed ();
 
139
}
 
140
 
 
141
void
 
142
ExtensionPluginAnimation::prePreparePaintGeneral ()
 
143
{
 
144
    if (!mAWinWasRestackedJustNow)
 
145
        return;
 
146
 
 
147
    bool focusAnimInitiated = false;
 
148
    AnimScreen *as = AnimScreen::get (::screen);
 
149
 
 
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++)
 
153
    {
 
154
        CompWindow *w = (*rit);
 
155
        AnimWindow *aw = AnimWindow::get (w);
 
156
        RestackPersistentData *data = static_cast<RestackPersistentData *>
 
157
            (aw->persistentData["restack"]);
 
158
        if (!data)
 
159
            continue;
 
160
        RestackInfo *restackInfo = data->restackInfo ();
 
161
        if (!restackInfo)
 
162
            continue;
 
163
 
 
164
        data->mIsSecondary = false;
 
165
 
 
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))
 
173
        {
 
174
            data->resetRestackInfo (true);
 
175
            continue;
 
176
        }
 
177
 
 
178
        // Find the first window at a higher stacking order than w
 
179
        CompWindow *nw;
 
180
        for (nw = w->next; nw; nw = nw->next)
 
181
        {
 
182
            if (relevantForRestackAnim (nw))
 
183
                break;
 
184
        }
 
185
 
 
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)
 
192
        {
 
193
            // Free unnecessary restackInfo
 
194
            data->resetRestackInfo (true);
 
195
            continue;
 
196
        }
 
197
 
 
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
 
201
        // (link to it)
 
202
        if (nw)
 
203
        {
 
204
            RestackPersistentData *dataNext =
 
205
                static_cast<RestackPersistentData *>
 
206
                (AnimWindow::get (nw)->persistentData["restack"]);
 
207
 
 
208
            if (dataNext && dataNext->restackInfo () &&
 
209
                wontCreateCircularChain (w, nw))
 
210
            {
 
211
                // Link the two
 
212
                dataNext->mMoreToBePaintedPrev = w;
 
213
                data->mMoreToBePaintedNext = nw;
 
214
 
 
215
                // so far, bottommost on chain
 
216
                data->mMoreToBePaintedPrev = 0;
 
217
            }
 
218
        }
 
219
        else
 
220
        {
 
221
            // Reset chain connections as this is not (yet) on a chain
 
222
            data->mMoreToBePaintedNext = 0;
 
223
            data->mMoreToBePaintedPrev = 0;
 
224
        }
 
225
    }
 
226
 
 
227
    // Now initiate focus animations (after the restack chains are formed
 
228
    // right above)
 
229
    for (CompWindowVector::reverse_iterator rit = mLastClientList.rbegin ();
 
230
         rit != mLastClientList.rend (); rit++)
 
231
    {
 
232
        CompWindow *w = (*rit);
 
233
        AnimWindow *aw = AnimWindow::get (w);
 
234
        RestackPersistentData *data = static_cast<RestackPersistentData *>
 
235
            (aw->persistentData["restack"]);
 
236
        if (!data)
 
237
            continue;
 
238
 
 
239
        RestackInfo *restackInfo = data->restackInfo ();
 
240
        if (restackInfo)
 
241
        {
 
242
            if (as->initiateFocusAnim (aw))
 
243
                focusAnimInitiated = true;
 
244
            else
 
245
                data->resetRestackInfo (true);
 
246
        }
 
247
    }
 
248
 
 
249
    if (!focusAnimInitiated)
 
250
        resetStackingInfo ();
 
251
 
 
252
    if (!focusAnimInitiated ||
 
253
        as->otherPluginsActive () ||
 
254
        !as->isAnimEffectPossible (AnimEffectDodge)) // Only dodge stuff below
 
255
        return;
 
256
 
 
257
    // Calculate dodge amounts
 
258
    foreach (CompWindow *w, mLastClientList)
 
259
    {
 
260
        AnimWindow *aw = AnimWindow::get (w);
 
261
        Animation *curAnim = aw->curAnimation ();
 
262
        if (!curAnim || curAnim->info () != AnimEffectDodge)
 
263
            continue;
 
264
 
 
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)
 
270
            continue;
 
271
 
 
272
        dynamic_cast<DodgeAnim *> (curAnim)->calculateDodgeAmounts ();
 
273
    }
 
274
 
 
275
    // TODO consider removing this loop and skipPostPrepareScreen
 
276
    for (CompWindowVector::reverse_iterator rit = mLastClientList.rbegin ();
 
277
         rit != mLastClientList.rend (); rit++)
 
278
    {
 
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
 
283
            continue;
 
284
 
 
285
        DodgePersistentData *data = static_cast<DodgePersistentData *>
 
286
            (itData->second);
 
287
        if (!data->isDodgeSubject)
 
288
            continue;
 
289
 
 
290
        bool dodgersAreOnlySubjects = true;
 
291
        CompWindow *dw;
 
292
        DodgePersistentData *dataDodger;
 
293
        for (dw = data->dodgeChainStart; dw;
 
294
             dw = dataDodger->dodgeChainNext)
 
295
        {
 
296
            dataDodger = static_cast<DodgePersistentData *>
 
297
                (AnimWindow::get (dw)->persistentData["dodge"]);
 
298
            if (!dataDodger)
 
299
                break;
 
300
            if (!dataDodger->isDodgeSubject)
 
301
                dodgersAreOnlySubjects = false;
 
302
        }
 
303
        if (dodgersAreOnlySubjects)
 
304
            data->skipPostPrepareScreen = true;
 
305
    }
 
306
}
 
307
 
 
308
void
 
309
ExtensionPluginAnimation::handleRestackNotify (AnimWindow *aw)
 
310
{
 
311
    const CompWindowVector &clients = ::screen->clientList ();
 
312
 
 
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) ==
 
316
            clients.end () &&
 
317
        find (mLastClientList.begin (), mLastClientList.end (), aw->mWindow) ==
 
318
            mLastClientList.end ())
 
319
        return;
 
320
 
 
321
    bool winOpenedClosed = false;
 
322
    unsigned int n = clients.size ();
 
323
 
 
324
    if (n != mLastClientList.size ())
 
325
    {
 
326
        winOpenedClosed = true;
 
327
    }
 
328
    // if restacking occurred and not window open/close
 
329
    if (!winOpenedClosed)
 
330
    {
 
331
        RestackPersistentData *data = static_cast<RestackPersistentData *>
 
332
            (aw->persistentData["restack"]);
 
333
        data->mConfigureNotified = true;
 
334
 
 
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;
 
348
 
 
349
        bool raised = false;
 
350
        int changeStart = -1;
 
351
        int changeEnd = -1;
 
352
 
 
353
        for (unsigned int i = 0; i < n; i++)
 
354
        {
 
355
            CompWindow *wi = clients[i];
 
356
 
 
357
            // skip if minimized (prevents flashing problem)
 
358
            if (!wi || wi->destroyed ())
 
359
                continue;
 
360
 
 
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.
 
364
            /*
 
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)))
 
370
                continue;
 
371
            */
 
372
            if (wi != mLastClientList[i])
 
373
            {
 
374
                if (changeStart < 0)
 
375
                {
 
376
                    changeStart = (int)i;
 
377
                    wChangeStart = wi; // make use of already found w
 
378
                }
 
379
                else
 
380
                {
 
381
                    changeEnd = (int)i;
 
382
                    wChangeEnd = wi;
 
383
                }
 
384
            }
 
385
            else if (changeStart >= 0) // found some change earlier
 
386
                break;
 
387
        }
 
388
 
 
389
        // if restacking occurred
 
390
        if (changeStart >= 0 && changeEnd >= 0)
 
391
        {
 
392
            // if we have only 2 windows changed,
 
393
            // choose the one clicked on
 
394
            bool preferRaised = false;
 
395
            bool onlyTwo = false;
 
396
 
 
397
            if (wChangeEnd &&
 
398
                clients[(unsigned)changeEnd] ==
 
399
                mLastClientList[(unsigned)changeStart] &&
 
400
                clients[(unsigned)changeStart] ==
 
401
                mLastClientList[(unsigned)changeEnd])
 
402
            {
 
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)
 
410
                    preferRaised = true;
 
411
 
 
412
                onlyTwo = true;
 
413
            }
 
414
            // Clear all mConfigureNotified's
 
415
            foreach (CompWindow *w2, ::screen->windows ())
 
416
            {
 
417
                RestackPersistentData *data =
 
418
                    static_cast<RestackPersistentData *>
 
419
                    (AnimWindow::get (w2)->persistentData["restack"]);
 
420
                data->mConfigureNotified = false;
 
421
            }
 
422
 
 
423
            if (preferRaised ||
 
424
                (!onlyTwo &&
 
425
                 clients[(unsigned)changeEnd] ==
 
426
                 mLastClientList[(unsigned)changeStart]))
 
427
            {
 
428
                // raised
 
429
                raised = true;
 
430
                wRestacked = wChangeEnd;
 
431
                wStart = wChangeStart;
 
432
                wEnd = wRestacked;
 
433
                wOldAbove = wStart;
 
434
            }
 
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)
 
442
            {
 
443
                wRestacked = wChangeStart;
 
444
                wStart = wRestacked;
 
445
                wEnd = wChangeEnd;
 
446
                wOldAbove = mLastClientList[(unsigned)(changeEnd + 1)];
 
447
            }
 
448
            for (; wOldAbove; wOldAbove = wOldAbove->next)
 
449
            {
 
450
                if (!wOldAbove->destroyed ())
 
451
                    break;
 
452
            }
 
453
        }
 
454
 
 
455
        if (wRestacked && wStart && wEnd && wOldAbove)
 
456
        {
 
457
            AnimWindow *awRestacked = AnimWindow::get (wRestacked);
 
458
            RestackPersistentData *data = static_cast<RestackPersistentData *>
 
459
                (awRestacked->persistentData["restack"]);
 
460
            {
 
461
                data->setRestackInfo (wRestacked, wStart, wEnd, wOldAbove,
 
462
                                      raised);
 
463
                mAWinWasRestackedJustNow = true;
 
464
            }
 
465
        }
 
466
    }
 
467
 
 
468
    updateLastClientList ();
 
469
}
 
470
 
 
471
void
 
472
ExtensionPluginAnimation::updateLastClientList ()
 
473
{
 
474
    mLastClientList = ::screen->clientList ();
 
475
}
 
476
 
 
477
/// Returns true if linking wCur to wNext would not result
 
478
/// in a circular chain being formed.
 
479
bool
 
480
ExtensionPluginAnimation::wontCreateCircularChain (CompWindow *wCur,
 
481
                                                   CompWindow *wNext)
 
482
{
 
483
    RestackPersistentData *dataNext = 0;
 
484
 
 
485
    while (wNext)
 
486
    {
 
487
        if (wNext == wCur) // would form circular chain
 
488
            return false;
 
489
 
 
490
        dataNext = static_cast<RestackPersistentData *>
 
491
            (AnimWindow::get (wNext)->persistentData["restack"]);
 
492
 
 
493
        if (!dataNext)
 
494
            return false;
 
495
 
 
496
        wNext = dataNext->mMoreToBePaintedNext;
 
497
    }
 
498
    return true;
 
499
}
 
500
 
 
501
void
 
502
ExtensionPluginAnimation::postUpdateEventEffects (AnimEvent e,
 
503
                                                  bool forRandom)
 
504
{
 
505
    AnimScreen *as = AnimScreen::get (::screen);
 
506
 
 
507
    // If a restacking anim. is (now) possible
 
508
    if (e == AnimEventFocus)
 
509
    {
 
510
        if (as->isRestackAnimPossible ())
 
511
        {
 
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
 
514
            // was not possible.
 
515
            updateLastClientList ();
 
516
 
 
517
            foreach (CompWindow *w, ::screen->windows ())
 
518
            {
 
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 ())
 
523
                    continue;
 
524
                aw->persistentData["restack"] = new RestackPersistentData ();
 
525
            }
 
526
        }
 
527
        if (as->isAnimEffectPossible (AnimEffectDodge))
 
528
        {
 
529
            foreach (CompWindow *w, ::screen->windows ())
 
530
            {
 
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 ())
 
535
                    continue;
 
536
                aw->persistentData["dodge"] = new DodgePersistentData ();
 
537
            }
 
538
        }
 
539
    }
 
540
}
 
541
 
 
542
void
 
543
ExtensionPluginAnimation::initPersistentData (AnimWindow *aw)
 
544
{
 
545
    AnimScreen *as = AnimScreen::get (::screen);
 
546
 
 
547
    // TODO: Optimize (via caching isRestackAnimPossible, isAnimEffectPossible)
 
548
 
 
549
    // Only allocate restack data when restack animation is possible
 
550
    if (as->isRestackAnimPossible () &&
 
551
        // doesn't exist yet
 
552
        aw->persistentData.find ("restack") == aw->persistentData.end ())
 
553
    {
 
554
        aw->persistentData["restack"] = new RestackPersistentData ();
 
555
    }
 
556
    if (as->isAnimEffectPossible (AnimEffectDodge) &&
 
557
        // doesn't exist yet
 
558
        aw->persistentData.find ("dodge") == aw->persistentData.end ())
 
559
    {
 
560
        aw->persistentData["dodge"] = new DodgePersistentData ();
 
561
    }
 
562
    if (aw->persistentData.find ("multi") == aw->persistentData.end ())
 
563
    {
 
564
        aw->persistentData["multi"] = new MultiPersistentData ();
 
565
    }
 
566
}
 
567
 
 
568
void
 
569
ExtensionPluginAnimation::destroyPersistentData (AnimWindow *aw)
 
570
{
 
571
    aw->deletePersistentData ("restack");
 
572
    aw->deletePersistentData ("dodge");
 
573
}
 
574
 
 
575
void
 
576
ExtensionPluginAnimation::incrementCurRestackAnimCount ()
 
577
{
 
578
    mRestackAnimCount++;
 
579
 
 
580
    // Enable custom paint list when there is now a restack anim happening
 
581
    if (mRestackAnimCount == 1)
 
582
        AnimScreen::get (::screen)->enableCustomPaintList (true);
 
583
}
 
584
 
 
585
void
 
586
ExtensionPluginAnimation::decrementCurRestackAnimCount ()
 
587
{
 
588
    mRestackAnimCount--;
 
589
 
 
590
    // Disable custom paint list when there is no more a restack anim happening
 
591
    if (mRestackAnimCount == 0)
 
592
        AnimScreen::get (::screen)->enableCustomPaintList (false);
 
593
}
 
594
 
 
595
bool
 
596
ExtensionPluginAnimation::restackInfoStillGood (RestackInfo *restackInfo)
 
597
{
 
598
    bool wStartGood = false;
 
599
    bool wEndGood = false;
 
600
    bool wOldAboveGood = false;
 
601
    bool wRestackedGood = false;
 
602
 
 
603
    foreach (CompWindow *w, ::screen->windows ())
 
604
    {
 
605
        AnimWindow *aw = AnimWindow::get (w);
 
606
 
 
607
        if (aw->mWindow->destroyed ())
 
608
            continue;
 
609
 
 
610
        if (restackInfo->wStart == w)
 
611
            wStartGood = true;
 
612
        if (restackInfo->wEnd == w)
 
613
            wEndGood = true;
 
614
        if (restackInfo->wRestacked == w)
 
615
            wRestackedGood = true;
 
616
        if (restackInfo->wOldAbove == w)
 
617
            wOldAboveGood = true;
 
618
    }
 
619
    return (wStartGood && wEndGood && wOldAboveGood && wRestackedGood);
 
620
}
 
621
 
 
622
/// Resets stacking related info.
 
623
void
 
624
ExtensionPluginAnimation::resetStackingInfo ()
 
625
{
 
626
    foreach (CompWindow *w, ::screen->windows ())
 
627
    {
 
628
        AnimWindow *aw = AnimWindow::get (w);
 
629
        PersistentDataMap::iterator itData =
 
630
            aw->persistentData.find ("restack");
 
631
        if (itData != aw->persistentData.end ()) // if found
 
632
        {
 
633
            RestackPersistentData *data =
 
634
                static_cast<RestackPersistentData *> (itData->second);
 
635
            data->mConfigureNotified = false;
 
636
            if (data->restackInfo ())
 
637
                data->resetRestackInfo ();
 
638
        }
 
639
    }
 
640
}
 
641
 
 
642
void
 
643
ExtensionPluginAnimation::postStartupCountdown ()
 
644
{
 
645
    updateLastClientList ();
 
646
}
 
647
 
 
648
void
 
649
ExtensionPluginAnimation::preInitiateOpenAnim (AnimWindow *aw)
 
650
{
 
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 ())
 
656
    {
 
657
        resetStackingInfo ();
 
658
        updateLastClientList ();
 
659
    }
 
660
}
 
661
 
 
662
void
 
663
ExtensionPluginAnimation::preInitiateCloseAnim (AnimWindow *aw)
 
664
{
 
665
    preInitiateOpenAnim (aw);
 
666
}
 
667
 
 
668
void
 
669
ExtensionPluginAnimation::preInitiateMinimizeAnim (AnimWindow *aw)
 
670
{
 
671
    preInitiateOpenAnim (aw);
 
672
}
 
673
 
 
674
void
 
675
ExtensionPluginAnimation::preInitiateUnminimizeAnim (AnimWindow *aw)
 
676
{
 
677
    preInitiateOpenAnim (aw);
 
678
}
 
679
 
 
680
void
 
681
ExtensionPluginAnimation::cleanUpAnimation (bool closing,
 
682
                                            bool destructing)
 
683
{
 
684
    if (closing || destructing)
 
685
        updateLastClientList ();
 
686
}
 
687
 
 
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.
 
692
CompWindow *
 
693
ExtensionPluginAnimation::getBottommostInExtendedFocusChain (CompWindow *wStartPoint)
 
694
{
 
695
    if (!wStartPoint)
 
696
        return 0;
 
697
 
 
698
    RestackPersistentData *data = static_cast<RestackPersistentData *>
 
699
        (AnimWindow::get (wStartPoint)->persistentData["restack"]);
 
700
    CompWindow *wBottommost = data->mWinToBePaintedBeforeThis;
 
701
 
 
702
    if (!wBottommost || wBottommost->destroyed ())
 
703
        return wStartPoint;
 
704
 
 
705
    RestackPersistentData *dataBottommost = static_cast<RestackPersistentData *>
 
706
        (AnimWindow::get (wBottommost)->persistentData["restack"]);
 
707
    CompWindow *wPrev = dataBottommost->mMoreToBePaintedPrev;
 
708
    while (wPrev)
 
709
    {
 
710
        wBottommost = wPrev;
 
711
        RestackPersistentData *dataPrev = static_cast<RestackPersistentData *>
 
712
            (AnimWindow::get (wPrev)->persistentData["restack"]);
 
713
        wPrev = dataPrev->mMoreToBePaintedPrev;
 
714
    }
 
715
    return wBottommost;
 
716
}
 
717
 
 
718
/// Finds the bottommost subject in restack chain,
 
719
/// simpler version of getBottommostInExtendedFocusChain.
 
720
CompWindow *
 
721
ExtensionPluginAnimation::getBottommostInRestackChain (CompWindow *wStartPoint)
 
722
{
 
723
    CompWindow *wBottommost = wStartPoint;
 
724
    RestackPersistentData *dataCur;
 
725
    for (CompWindow *wCur = wStartPoint; wCur;
 
726
         wCur = dataCur->mMoreToBePaintedPrev)
 
727
    {
 
728
        wBottommost = wCur;
 
729
        dataCur = static_cast<RestackPersistentData *>
 
730
            (AnimWindow::get (wCur)->persistentData["restack"]);
 
731
        if (!dataCur)
 
732
            break;
 
733
    }
 
734
    return wBottommost;
 
735
}
 
736
 
 
737
void
 
738
ExtensionPluginAnimation::resetMarks ()
 
739
{
 
740
    foreach (CompWindow *w, ::screen->windows ())
 
741
    {
 
742
        RestackPersistentData *data = static_cast<RestackPersistentData *>
 
743
            (AnimWindow::get (w)->persistentData["restack"]);
 
744
        data->mWalkerOverNewCopy = false;
 
745
        data->mVisitCount = 0;
 
746
    }
 
747
}
 
748
 
 
749
void
 
750
ExtensionPluginAnimation::prePaintWindowsBackToFront ()
 
751
{
 
752
    resetMarks ();
 
753
}
 
754
 
 
755
CompWindow *
 
756
ExtensionPluginAnimation::walkFirst ()
 
757
{
 
758
    resetMarks ();
 
759
 
 
760
    CompWindow *w =
 
761
        getBottommostInExtendedFocusChain (*::screen->windows ().begin ());
 
762
    if (w)
 
763
    {
 
764
        RestackPersistentData *data = static_cast<RestackPersistentData *>
 
765
            (AnimWindow::get (w)->persistentData["restack"]);
 
766
        data->mVisitCount++;
 
767
    }
 
768
    return w;
 
769
}
 
770
 
 
771
bool
 
772
ExtensionPluginAnimation::markNewCopy (CompWindow *w)
 
773
{
 
774
    RestackPersistentData *data = static_cast<RestackPersistentData *>
 
775
        (AnimWindow::get (w)->persistentData["restack"]);
 
776
 
 
777
    // if window is in a focus chain
 
778
    if (data->mWinThisIsPaintedBefore ||
 
779
        data->mMoreToBePaintedPrev)
 
780
    {
 
781
        data->mWalkerOverNewCopy = true;
 
782
        return true;
 
783
    }
 
784
    return false;
 
785
}
 
786
 
 
787
CompWindow *
 
788
ExtensionPluginAnimation::walkNext (CompWindow *w)
 
789
{
 
790
    RestackPersistentData *data = static_cast<RestackPersistentData *>
 
791
        (AnimWindow::get (w)->persistentData["restack"]);
 
792
 
 
793
    CompWindow *wRet = 0;
 
794
 
 
795
    if (!data->mWalkerOverNewCopy)
 
796
    {
 
797
        // Within a chain? (not the 1st or 2nd window)
 
798
        if (data->mMoreToBePaintedNext)
 
799
        {
 
800
            wRet = data->mMoreToBePaintedNext;
 
801
        }
 
802
        else if (data->mWinThisIsPaintedBefore) // 2nd one in chain?
 
803
        {
 
804
            wRet = data->mWinThisIsPaintedBefore;
 
805
        }
 
806
    }
 
807
    else
 
808
        data->mWalkerOverNewCopy = false;
 
809
 
 
810
    if (!wRet && w->next && markNewCopy (w->next))
 
811
    {
 
812
        wRet = w->next;
 
813
    }
 
814
    else if (!wRet)
 
815
    {
 
816
        wRet = getBottommostInExtendedFocusChain (w->next);
 
817
    }
 
818
 
 
819
    if (wRet)
 
820
    {
 
821
        RestackPersistentData *dataRet = static_cast<RestackPersistentData *>
 
822
            (AnimWindow::get (wRet)->persistentData["restack"]);
 
823
 
 
824
        // Prevent cycles, which cause freezes
 
825
        if (dataRet->mVisitCount > 1) // each window is visited at most twice
 
826
            return 0;
 
827
        dataRet->mVisitCount++;
 
828
    }
 
829
    return wRet;
 
830
}
 
831
 
 
832
const CompWindowList &
 
833
ExtensionPluginAnimation::getWindowPaintList ()
 
834
{
 
835
    mWindowList.clear ();
 
836
    for (CompWindow *w = walkFirst (); w; w = walkNext (w))
 
837
        mWindowList.push_back (w);
 
838
 
 
839
    return mWindowList;
 
840
}
 
841