~vanvugt/compiz-plugins-main/fix-915236

« back to all changes in this revision

Viewing changes to animation/src/dodge.cpp

  • Committer: Sam Spilsbury
  • Date: 2011-08-12 06:36:10 UTC
  • Revision ID: sam.spilsbury@canonical.com-20110812063610-8mcxo2xohctyp2ak
Sync - Remove Plugins

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
 
// =====================  Effect: Dodge  =========================
40
 
 
41
 
void
42
 
DodgeAnim::applyDodgeTransform ()
43
 
{
44
 
    if (mDodgeData->isDodgeSubject && mDodgeDirection == DodgeDirectionNone)
45
 
        return;
46
 
 
47
 
    float amountX = 0.0f;
48
 
    float amountY = 0.0f;
49
 
 
50
 
    if (mDodgeMaxAmountX != 0)
51
 
        amountX = sin (M_PI * mTransformProgress) * mDodgeMaxAmountX;
52
 
 
53
 
    if (mDodgeMaxAmountY != 0)
54
 
        amountY = sin (M_PI * mTransformProgress) * mDodgeMaxAmountY;
55
 
 
56
 
    mTransform.translate (amountX, amountY, 0.0f);
57
 
}
58
 
 
59
 
bool
60
 
DodgeAnim::moveUpdate ()
61
 
{
62
 
    if (mDodgeData->isDodgeSubject &&
63
 
        mDodgeDirection == DodgeDirectionXY)
64
 
    {
65
 
        mDodgeDirection = DodgeDirectionNone;
66
 
        mDodgeMaxAmountX = 0;
67
 
        mDodgeMaxAmountY = 0;
68
 
    }
69
 
 
70
 
    CompWindow *wBottommost =
71
 
        ExtensionPluginAnimation::getBottommostInRestackChain (mWindow);
72
 
 
73
 
    // Update dodge amount for the dodgers of all subjects
74
 
    // in the restack chain
75
 
    RestackPersistentData *dataCur;
76
 
    for (CompWindow *wCur = wBottommost; wCur;
77
 
         wCur = dataCur->mMoreToBePaintedNext)
78
 
    {
79
 
        AnimWindow *awCur = AnimWindow::get (wCur);
80
 
        dataCur = static_cast<RestackPersistentData *>
81
 
            (awCur->persistentData["restack"]);
82
 
        if (!dataCur)
83
 
            break;
84
 
 
85
 
        Animation *curAnim = awCur->curAnimation ();
86
 
        if (!curAnim || curAnim->info () != AnimEffectDodge)
87
 
            continue;
88
 
 
89
 
        DodgePersistentData *dodgeDataDodger;
90
 
 
91
 
        // Update dodge amount for each dodger
92
 
        for (CompWindow *dw = mDodgeData->dodgeChainStart; dw;
93
 
             dw = dodgeDataDodger->dodgeChainNext)
94
 
        {
95
 
            AnimWindow *adw = AnimWindow::get (dw);
96
 
            dodgeDataDodger =
97
 
                static_cast<DodgePersistentData *>
98
 
                (adw->persistentData["dodge"]);
99
 
 
100
 
            DodgeAnim *animDodger =
101
 
                dynamic_cast<DodgeAnim *> (adw->curAnimation ());
102
 
            if (!animDodger)
103
 
                continue;
104
 
 
105
 
            if (animDodger->mDodgeSubjectWin &&
106
 
                animDodger->mTransformProgress <= 0.5f)
107
 
            {
108
 
                animDodger->updateDodgerDodgeAmount ();
109
 
            }
110
 
        }
111
 
    }
112
 
 
113
 
    return false;
114
 
}
115
 
 
116
 
/// Should only be called for non-subjects.
117
 
void
118
 
DodgeAnim::updateDodgerDodgeAmount ()
119
 
{
120
 
    // Find the box to be dodged, it can contain multiple windows
121
 
    // when there are dialog/utility windows of subject windows
122
 
    // (stacked in the mMoreToBePaintedNext chain).
123
 
    // Then this would be a bounding box of the subject windows
124
 
    // intersecting with dodger.
125
 
    CompRect subjectRect (unionRestackChain (mDodgeSubjectWin).boundingRect ());
126
 
 
127
 
    // Update dodge amount if subject window(s) moved during dodge
128
 
    float newDodgeAmount =
129
 
        getDodgeAmount (subjectRect, mWindow, mDodgeDirection);
130
 
 
131
 
    // Only update if amount got larger
132
 
    if (((mDodgeDirection == DodgeDirectionDown && newDodgeAmount > 0) ||
133
 
         (mDodgeDirection == DodgeDirectionUp && newDodgeAmount < 0)) &&
134
 
        abs (newDodgeAmount) > abs (mDodgeMaxAmountY))
135
 
    {
136
 
        mDodgeMaxAmountY = newDodgeAmount;
137
 
    }
138
 
    else if (((mDodgeDirection == DodgeDirectionRight && newDodgeAmount > 0) ||
139
 
              (mDodgeDirection == DodgeDirectionLeft && newDodgeAmount < 0)) &&
140
 
             abs (newDodgeAmount) > abs (mDodgeMaxAmountX))
141
 
    {
142
 
        mDodgeMaxAmountX = newDodgeAmount;
143
 
    }
144
 
}
145
 
 
146
 
float
147
 
DodgeAnim::dodgeProgress ()
148
 
{
149
 
    float forwardProgress = progressLinear ();
150
 
 
151
 
    forwardProgress = 1 - forwardProgress;
152
 
    return forwardProgress;
153
 
}
154
 
 
155
 
void
156
 
DodgeAnim::step ()
157
 
{
158
 
    TransformAnim::step ();
159
 
 
160
 
    mTransformProgress = 0;
161
 
 
162
 
    float forwardProgress = dodgeProgress ();
163
 
    if (forwardProgress > mTransformStartProgress)
164
 
    {
165
 
        // Compute transform progress and normalize
166
 
        mTransformProgress =
167
 
            (forwardProgress - mTransformStartProgress) /
168
 
            (1 - mTransformStartProgress);
169
 
    }
170
 
 
171
 
    mTransform.reset ();
172
 
    applyDodgeTransform ();
173
 
}
174
 
 
175
 
void
176
 
DodgeAnim::updateTransform (GLMatrix &wTransform)
177
 
{
178
 
    TransformAnim::updateTransform (wTransform);
179
 
}
180
 
 
181
 
void
182
 
DodgeAnim::postPreparePaint ()
183
 
{
184
 
    // Only dodge subjects (with dodger chains) should be processed here
185
 
    if (!mDodgeData || !mDodgeData->isDodgeSubject ||
186
 
        !mDodgeData->dodgeChainStart)
187
 
        return;
188
 
 
189
 
    if (!mRestackData || !mRestackData->restackInfo ())
190
 
        return;
191
 
 
192
 
    if (mDodgeData->skipPostPrepareScreen)
193
 
        return;
194
 
 
195
 
    // Find the bottommost subject in restack chain
196
 
    CompWindow *wBottommost = mWindow;
197
 
    RestackPersistentData *dataCur;
198
 
    for (CompWindow *wCur = mRestackData->mMoreToBePaintedPrev; wCur;
199
 
         wCur = dataCur->mMoreToBePaintedPrev)
200
 
    {
201
 
        wBottommost = wCur;
202
 
        dataCur = static_cast<RestackPersistentData *>
203
 
            (AnimWindow::get (wCur)->persistentData["restack"]);
204
 
        if (!dataCur)
205
 
            break;
206
 
    }
207
 
    AnimWindow *awBottommost = AnimWindow::get (wBottommost);
208
 
    RestackPersistentData *restackDataBottommost =
209
 
        static_cast<RestackPersistentData *>
210
 
        (awBottommost->persistentData["restack"]);
211
 
 
212
 
    // Find the first dodging window that hasn't yet
213
 
    // reached 50% progress yet. The subject window should be
214
 
    // painted right behind that one (or right in front of it
215
 
    // if subject is being lowered).
216
 
    RestackPersistentData *restackDataDodger;
217
 
    DodgePersistentData *dodgeDataDodger;
218
 
    CompWindow *dw;
219
 
    for (dw = mDodgeData->dodgeChainStart; dw;
220
 
         dw = dodgeDataDodger->dodgeChainNext)
221
 
    {
222
 
        AnimWindow *adw = AnimWindow::get (dw);
223
 
        restackDataDodger = static_cast<RestackPersistentData *>
224
 
            (adw->persistentData["restack"]);
225
 
        dodgeDataDodger = static_cast<DodgePersistentData *>
226
 
            (adw->persistentData["dodge"]);
227
 
 
228
 
        DodgeAnim *animDodger =
229
 
            dynamic_cast<DodgeAnim *> (adw->curAnimation ());
230
 
 
231
 
        if (!(animDodger->mTransformProgress > 0.5f))
232
 
            break;
233
 
    }
234
 
 
235
 
    RestackInfo *bottommostRestackInfo = restackDataBottommost->restackInfo ();
236
 
    if (!bottommostRestackInfo)
237
 
        return;
238
 
 
239
 
    if (bottommostRestackInfo->raised &&
240
 
        // if mWindow's host should change
241
 
        dw != restackDataBottommost->mWinThisIsPaintedBefore)
242
 
    {
243
 
        if (restackDataBottommost->mWinThisIsPaintedBefore)
244
 
        {
245
 
            // Clear old host
246
 
            RestackPersistentData *dataOldHost =
247
 
                static_cast<RestackPersistentData *>
248
 
                (AnimWindow::get (restackDataBottommost->
249
 
                                  mWinThisIsPaintedBefore)->
250
 
                 persistentData["restack"]);
251
 
            dataOldHost->mWinToBePaintedBeforeThis = 0;
252
 
        }
253
 
        // if a dodger win. is still at <0.5 progress
254
 
        if (dw && restackDataDodger)
255
 
        {
256
 
            // Put subject right behind new host
257
 
            restackDataDodger->mWinToBePaintedBeforeThis = wBottommost;
258
 
        }
259
 
        // otherwise all dodger win.s have passed 0.5 progress
260
 
 
261
 
        CompWindow *wCur = wBottommost;
262
 
        while (wCur)
263
 
        {
264
 
            RestackPersistentData *dataCur =
265
 
                static_cast<RestackPersistentData *>
266
 
                (AnimWindow::get (wCur)->persistentData["restack"]);
267
 
            // dw can be null, which is ok
268
 
            dataCur->mWinThisIsPaintedBefore = dw;
269
 
            wCur = dataCur->mMoreToBePaintedNext;
270
 
        }
271
 
    }
272
 
    else if (!bottommostRestackInfo->raised)
273
 
    {
274
 
        // Put the subject right in front of dw.
275
 
        // But we need to find the (dodger) window above dw
276
 
        // (since we need to put the subject *behind* a window).
277
 
 
278
 
        CompWindow *wDodgeChainAbove = 0;
279
 
 
280
 
        // if a dodger win. is still at <0.5 progress
281
 
        if (dw && dodgeDataDodger)
282
 
        {
283
 
            if (dodgeDataDodger->dodgeChainPrev)
284
 
            {
285
 
                wDodgeChainAbove = dodgeDataDodger->dodgeChainPrev;
286
 
            }
287
 
            else
288
 
            {
289
 
                // Use the wOldAbove of topmost subject
290
 
                wDodgeChainAbove = mRestackData->restackInfo ()->wOldAbove;
291
 
            }
292
 
            if (!wDodgeChainAbove)
293
 
                compLogMessage ("animation", CompLogLevelError,
294
 
                                "%s: error at line %d", __FILE__, __LINE__);
295
 
            else if (restackDataBottommost->mWinThisIsPaintedBefore !=
296
 
                     wDodgeChainAbove) // w's host is changing
297
 
            {
298
 
                RestackPersistentData *dataNewHost =
299
 
                    static_cast<RestackPersistentData *>
300
 
                    (AnimWindow::get (wDodgeChainAbove)->
301
 
                     persistentData["restack"]);
302
 
 
303
 
                // Put subject right behind new host
304
 
                dataNewHost->mWinToBePaintedBeforeThis = wBottommost;
305
 
            }
306
 
        }
307
 
        if (restackDataBottommost->mWinThisIsPaintedBefore &&
308
 
            restackDataBottommost->mWinThisIsPaintedBefore != wDodgeChainAbove)
309
 
        {
310
 
            // Clear old host
311
 
            RestackPersistentData *dataOldHost =
312
 
                static_cast<RestackPersistentData *>
313
 
                (AnimWindow::get (restackDataBottommost->
314
 
                                  mWinThisIsPaintedBefore)->
315
 
                 persistentData["restack"]);
316
 
            dataOldHost->mWinToBePaintedBeforeThis = 0;
317
 
        }
318
 
        // otherwise all dodger win.s have passed 0.5 progress
319
 
 
320
 
        CompWindow *wCur = wBottommost;
321
 
        while (wCur)
322
 
        {
323
 
            RestackPersistentData *dataCur =
324
 
                static_cast<RestackPersistentData *>
325
 
                (AnimWindow::get (wCur)->persistentData["restack"]);
326
 
            // wDodgeChainAbove can be null, which is ok
327
 
            dataCur->mWinThisIsPaintedBefore = wDodgeChainAbove;
328
 
            wCur = dataCur->mMoreToBePaintedNext;
329
 
        }
330
 
    }
331
 
}
332
 
 
333
 
bool
334
 
DodgeAnim::shouldDamageWindowOnStart ()
335
 
{
336
 
    // for dodging windows only, when subject is fixed
337
 
    return !(mDodgeMode == AnimationOptions::DodgeModeFixedClickedWindow &&
338
 
             mDodgeData->isDodgeSubject);
339
 
}
340
 
 
341
 
void
342
 
DodgeAnim::updateBB (CompOutput &output)
343
 
{
344
 
    TransformAnim::updateBB (output);
345
 
}
346
 
 
347
 
DodgeAnim::DodgeAnim (CompWindow *w,
348
 
                      WindowEvent curWindowEvent,
349
 
                      float duration,
350
 
                      const AnimEffect info,
351
 
                      const CompRect &icon) :
352
 
    Animation::Animation (w, curWindowEvent, duration, info, icon),
353
 
    RestackAnim::RestackAnim (w, curWindowEvent, duration, info, icon),
354
 
    TransformAnim::TransformAnim (w, curWindowEvent, duration, info, icon),
355
 
    mDodgeData (static_cast<DodgePersistentData *>
356
 
                (AnimWindow::get (w)->persistentData["dodge"])),
357
 
    mDodgeSubjectWin (0),
358
 
    mDodgeMaxAmountX (0),
359
 
    mDodgeMaxAmountY (0),
360
 
    mDodgeDirection (DodgeDirectionNone),
361
 
    mDodgeMode (optValI (AnimationOptions::DodgeMode))
362
 
{
363
 
}
364
 
 
365
 
void
366
 
DodgeAnim::cleanUp (bool closing,
367
 
                    bool destructing)
368
 
{
369
 
    // Remove this window from its subject's dodger chain
370
 
    if (mDodgeSubjectWin)
371
 
    {
372
 
        CompWindow *w = mDodgeSubjectWin;
373
 
        AnimWindow *aw = AnimWindow::get (w);
374
 
        Animation *curAnim = aw->curAnimation ();
375
 
        DodgePersistentData *dodgeData = static_cast<DodgePersistentData *>
376
 
                (aw->persistentData["dodge"]);
377
 
 
378
 
        if (curAnim && curAnim->info () == AnimEffectDodge &&
379
 
            // Only process subjects with a dodge chain
380
 
            dodgeData && dodgeData->dodgeChainStart &&
381
 
            dodgeData->isDodgeSubject)
382
 
        {
383
 
            // Go through each dodger, checking if this is that one
384
 
            // dw: Dodger window
385
 
            DodgePersistentData *dodgeDataDodger;
386
 
            for (CompWindow *dw = dodgeData->dodgeChainStart; dw;
387
 
                 dw = dodgeDataDodger->dodgeChainNext)
388
 
            {
389
 
                AnimWindow *adw = AnimWindow::get (dw);
390
 
                dodgeDataDodger = static_cast<DodgePersistentData *>
391
 
                    (adw->persistentData["dodge"]);
392
 
                if (dw == mWindow)
393
 
                {
394
 
                    // Remove mWindow from the chain
395
 
                    CompWindow *dwNext = dodgeDataDodger->dodgeChainNext;
396
 
                    if (dwNext)
397
 
                    {
398
 
                        AnimWindow *adwNext = AnimWindow::get (dwNext);
399
 
                        DodgePersistentData *dodgeDataDodgerNext =
400
 
                            static_cast<DodgePersistentData *>
401
 
                            (adwNext->persistentData["dodge"]);
402
 
                        dodgeDataDodgerNext->dodgeChainPrev =
403
 
                            dodgeDataDodger->dodgeChainPrev;
404
 
                    }
405
 
                    CompWindow *dwPrev = dodgeDataDodger->dodgeChainPrev;
406
 
                    if (dwPrev)
407
 
                    {
408
 
                        AnimWindow *adwPrev = AnimWindow::get (dwPrev);
409
 
                        DodgePersistentData *dodgeDataDodgerPrev =
410
 
                            static_cast<DodgePersistentData *>
411
 
                            (adwPrev->persistentData["dodge"]);
412
 
                        dodgeDataDodgerPrev->dodgeChainNext =
413
 
                            dodgeDataDodger->dodgeChainNext;
414
 
                    }
415
 
                    if (dodgeData->dodgeChainStart == mWindow)
416
 
                        dodgeData->dodgeChainStart =
417
 
                            dodgeDataDodger->dodgeChainNext;
418
 
                    dodgeDataDodger->dodgeChainPrev = 0;
419
 
                    dodgeDataDodger->dodgeChainNext = 0;
420
 
                }
421
 
            }
422
 
        }
423
 
    }
424
 
    else
425
 
    {
426
 
        DodgePersistentData *dodgeData = static_cast<DodgePersistentData *>
427
 
                (mAWindow->persistentData["dodge"]);
428
 
 
429
 
        if (dodgeData && dodgeData->isDodgeSubject)
430
 
        {
431
 
            // Update this window's dodgers so that they no longer point
432
 
            // to this window as their subject
433
 
            DodgePersistentData *dodgeDataDodger;
434
 
            for (CompWindow *dw = dodgeData->dodgeChainStart; dw;
435
 
                 dw = dodgeDataDodger->dodgeChainNext)
436
 
            {
437
 
                AnimWindow *adw = AnimWindow::get (dw);
438
 
                if (!adw)
439
 
                    break;
440
 
                dodgeDataDodger = static_cast<DodgePersistentData *>
441
 
                    (adw->persistentData["dodge"]);
442
 
 
443
 
                Animation *curAnim = adw->curAnimation ();
444
 
 
445
 
                if (curAnim && curAnim->info () == AnimEffectDodge)
446
 
                {
447
 
                    DodgeAnim *animDodger = dynamic_cast<DodgeAnim *> (curAnim);
448
 
                    if (animDodger->mDodgeSubjectWin == mWindow)
449
 
                        animDodger->mDodgeSubjectWin = NULL;
450
 
                }
451
 
            }
452
 
        }
453
 
    }
454
 
 
455
 
    // Reset dodge parameters
456
 
    //if (!(restackData->mMoreToBePaintedPrev ||
457
 
        //  restackData->mMoreToBePaintedNext))
458
 
    //{
459
 
        mDodgeData->isDodgeSubject = false;
460
 
        mDodgeData->skipPostPrepareScreen = false;
461
 
    //}
462
 
    RestackAnim::cleanUp (closing, destructing);
463
 
}
464
 
 
465
 
int
466
 
DodgeAnim::getDodgeAmount (CompRect &rect,
467
 
                           CompWindow *dw,
468
 
                           DodgeDirection dir)
469
 
{
470
 
    CompRect dRect (dw->borderRect ().x () +
471
 
                    (dw->outputRect ().x () - dw->borderRect ().x ()) / 2,
472
 
                    dw->borderRect ().y () +
473
 
                    (dw->outputRect ().y () - dw->borderRect ().y ()) / 2,
474
 
                    (dw->borderRect ().width () +
475
 
                     dw->outputRect ().width ()) / 2,
476
 
                    (dw->borderRect ().height () +
477
 
                     dw->outputRect ().height ()) / 2);
478
 
 
479
 
    int amount = 0;
480
 
    switch (dir)
481
 
    {
482
 
        case DodgeDirectionUp:
483
 
            amount = (rect.y () - (dRect.y () + dRect.height ()));
484
 
            break;
485
 
        case DodgeDirectionDown:
486
 
            amount = (rect.y () + rect.height () - dRect.y ());
487
 
            break;
488
 
        case DodgeDirectionLeft:
489
 
            amount = (rect.x () - (dRect.x () + dRect.width ()));
490
 
            break;
491
 
        case DodgeDirectionRight:
492
 
            amount = (rect.x () + rect.width () - dRect.x ());
493
 
            break;
494
 
        default:
495
 
            break;
496
 
    }
497
 
    return amount;
498
 
}
499
 
 
500
 
void
501
 
DodgeAnim::processCandidate (CompWindow *candidateWin,
502
 
                             CompWindow *subjectWin,
503
 
                             CompRegion &candidateAndSubjectIntersection,
504
 
                             int &numSelectedCandidates)
505
 
{
506
 
    AnimWindow *aCandidateWin = AnimWindow::get (candidateWin);
507
 
    AnimScreen *as = AnimScreen::get (::screen);
508
 
 
509
 
    if ((!aCandidateWin->curAnimation () ||
510
 
         aCandidateWin->curAnimation ()->info () == AnimEffectDodge) &&
511
 
        candidateWin != subjectWin) // don't let the subject dodge itself
512
 
    {
513
 
        // Mark this window for dodge
514
 
 
515
 
        bool nonMatching = false;
516
 
        if (as->getMatchingAnimSelection (candidateWin, AnimEventFocus, 0) !=
517
 
            AnimEffectDodge)
518
 
            nonMatching = true;
519
 
 
520
 
        numSelectedCandidates++;
521
 
        DodgePersistentData *data = static_cast<DodgePersistentData *>
522
 
            (aCandidateWin->persistentData["dodge"]);
523
 
        data->dodgeOrder = numSelectedCandidates;
524
 
        if (nonMatching) // Use neg. values for non-matching windows
525
 
            data->dodgeOrder *= -1;
526
 
    }
527
 
}
528
 
 
529
 
void
530
 
DodgeAnim::postInitiateRestackAnim (int numSelectedCandidates,
531
 
                                    int duration,
532
 
                                    CompWindow *wStart,
533
 
                                    CompWindow *wEnd,
534
 
                                    bool raised)
535
 
{
536
 
    DodgePersistentData *dataSubject = mDodgeData;
537
 
    if (!dataSubject)
538
 
        return;
539
 
 
540
 
    dataSubject->isDodgeSubject = true;
541
 
    dataSubject->dodgeChainStart = 0;
542
 
 
543
 
    if (mRestackData && mRestackData->mIsSecondary)
544
 
        return; // We're done here
545
 
 
546
 
    float maxTransformTotalProgress = 0;
547
 
    float dodgeMaxStartProgress =
548
 
        numSelectedCandidates * optValF (AnimationOptions::DodgeGapRatio) *
549
 
        duration / 1000.0f;
550
 
 
551
 
    CompWindow *wDodgeChainLastVisited = 0;
552
 
 
553
 
    // dw: Dodger window(s)
554
 
    for (CompWindow *dw = wStart; dw && dw != wEnd->next; dw = dw->next)
555
 
    {
556
 
        AnimWindow *adw = AnimWindow::get (dw);
557
 
        DodgePersistentData *dataDodger = static_cast<DodgePersistentData *>
558
 
            (adw->persistentData["dodge"]);
559
 
 
560
 
        // Skip non-dodgers
561
 
        if (dataDodger->dodgeOrder == 0)
562
 
            continue;
563
 
 
564
 
        // Initiate dodge for this window
565
 
 
566
 
        bool stationaryDodger = false;
567
 
        if (dataDodger->dodgeOrder < 0)
568
 
        {
569
 
            dataDodger->dodgeOrder *= -1; // Make it positive again
570
 
            stationaryDodger = true;
571
 
        }
572
 
        if (!adw->curAnimation ())
573
 
        {
574
 
            // Create dodge animation for dodger
575
 
            adw->createFocusAnimation (AnimEffectDodge);
576
 
            ExtensionPluginAnimation *extPlugin =
577
 
                static_cast<ExtensionPluginAnimation *>
578
 
                (getExtensionPluginInfo ());
579
 
            extPlugin->incrementCurRestackAnimCount ();
580
 
        }
581
 
 
582
 
        DodgeAnim *animDodger =
583
 
            dynamic_cast<DodgeAnim *> (adw->curAnimation ());
584
 
 
585
 
        animDodger->mDodgeSubjectWin = mWindow;
586
 
 
587
 
        if (mDodgeMode == AnimationOptions::DodgeModeFixedClickedWindow)
588
 
        {
589
 
            // Slight change in dodge movement start
590
 
            // to reflect stacking order of dodger windows
591
 
            if (raised)
592
 
                animDodger->mTransformStartProgress =
593
 
                    dodgeMaxStartProgress *
594
 
                    (dataDodger->dodgeOrder - 1) / numSelectedCandidates;
595
 
            else
596
 
                animDodger->mTransformStartProgress =
597
 
                    dodgeMaxStartProgress *
598
 
                    (1 - (float)dataDodger->dodgeOrder / numSelectedCandidates);
599
 
        }
600
 
 
601
 
        float transformTotalProgress =
602
 
            1 + animDodger->mTransformStartProgress;
603
 
 
604
 
        if (maxTransformTotalProgress < transformTotalProgress)
605
 
            maxTransformTotalProgress = transformTotalProgress;
606
 
 
607
 
        // normalize
608
 
        animDodger->mTransformStartProgress /= transformTotalProgress;
609
 
 
610
 
        if (stationaryDodger)
611
 
        {
612
 
            animDodger->mTransformStartProgress = 0;
613
 
            transformTotalProgress = 0;
614
 
        }
615
 
 
616
 
        animDodger->mTotalTime = transformTotalProgress * duration;
617
 
        animDodger->mRemainingTime = animDodger->mTotalTime;
618
 
 
619
 
        // Put window on dodge chain
620
 
 
621
 
        // if dodge chain was started before
622
 
        if (wDodgeChainLastVisited)
623
 
        {
624
 
            DodgePersistentData *dataDodgeChainLastVisited =
625
 
                static_cast<DodgePersistentData *>
626
 
                (AnimWindow::get (wDodgeChainLastVisited)->
627
 
                 persistentData["dodge"]);
628
 
            if (raised)
629
 
            {
630
 
                dataDodgeChainLastVisited->dodgeChainNext = dw;
631
 
            }
632
 
            else
633
 
                dataDodgeChainLastVisited->dodgeChainPrev = dw;
634
 
        }
635
 
        else if (raised) // mark chain start
636
 
        {
637
 
            dataSubject->dodgeChainStart = dw;
638
 
        }
639
 
        if (raised)
640
 
        {
641
 
            dataDodger->dodgeChainPrev = wDodgeChainLastVisited;
642
 
            dataDodger->dodgeChainNext = 0;
643
 
        }
644
 
        else
645
 
        {
646
 
            dataDodger->dodgeChainPrev = 0;
647
 
            dataDodger->dodgeChainNext = wDodgeChainLastVisited;
648
 
        }
649
 
 
650
 
        wDodgeChainLastVisited = dw;
651
 
 
652
 
        // Reset back to 0 for the next dodge calculation
653
 
        dataDodger->dodgeOrder = 0;
654
 
    }
655
 
 
656
 
    // if subject is being lowered,
657
 
    // point chain-start to the topmost doding window
658
 
    if (!raised)
659
 
        dataSubject->dodgeChainStart = wDodgeChainLastVisited;
660
 
 
661
 
    mTotalTime = maxTransformTotalProgress * duration;
662
 
    mRemainingTime = mTotalTime;
663
 
}
664
 
 
665
 
void
666
 
DodgeAnim::calculateDodgeAmounts ()
667
 
{
668
 
    // holds whether each side of the subject is covered by dodgers or not
669
 
    bool coveredSides[4] = {false, false, false, false};
670
 
 
671
 
    // maximum distance between a dodger window and the subject in X and Y axes
672
 
    int maxDistX = 0;
673
 
    int maxDistXActual = 0;
674
 
    int maxDistY = 0;
675
 
    int maxDistYActual = 0;
676
 
 
677
 
    CompRect subjectRect (unionRestackChain (mWindow).boundingRect ());
678
 
 
679
 
    // Go through each dodger, calculating its dodge amount.
680
 
    // dw: Dodger window
681
 
    DodgePersistentData *dodgeDataDodger;
682
 
    for (CompWindow *dw = mDodgeData->dodgeChainStart; dw;
683
 
         dw = dodgeDataDodger->dodgeChainNext)
684
 
    {
685
 
        AnimWindow *adw = AnimWindow::get (dw);
686
 
 
687
 
        dodgeDataDodger = static_cast<DodgePersistentData *>
688
 
            (adw->persistentData["dodge"]);
689
 
 
690
 
        DodgeAnim *animDodger =
691
 
            dynamic_cast<DodgeAnim *> (adw->curAnimation ());
692
 
        if (!animDodger)
693
 
            continue;
694
 
 
695
 
        // Find direction (left, right, up, down) that minimizes dodge amount
696
 
 
697
 
        int dodgeAmount[4];
698
 
 
699
 
        for (int i = 0; i < 4; i++)
700
 
            dodgeAmount[i] =
701
 
                DodgeAnim::getDodgeAmount (subjectRect, dw, (DodgeDirection)i);
702
 
 
703
 
        int amountMinActual = dodgeAmount[0];
704
 
        int amountMinAbs = abs (amountMinActual);
705
 
        int iMin = 0;
706
 
        for (int i=1; i<4; i++)
707
 
        {
708
 
            int absAmount = abs (dodgeAmount[i]);
709
 
            if (amountMinAbs > absAmount)
710
 
            {
711
 
                amountMinAbs = absAmount;
712
 
                amountMinActual = dodgeAmount[i];
713
 
                iMin = i;
714
 
            }
715
 
        }
716
 
        if (iMin == DodgeDirectionUp ||
717
 
            iMin == DodgeDirectionDown)
718
 
        {
719
 
            animDodger->mDodgeMaxAmountX = 0;
720
 
            animDodger->mDodgeMaxAmountY = dodgeAmount[iMin];
721
 
            if (mDodgeMode == AnimationOptions::DodgeModeAllMoving &&
722
 
                maxDistY < amountMinAbs)
723
 
            {
724
 
                maxDistY = amountMinAbs;
725
 
                maxDistYActual = amountMinActual;
726
 
            }
727
 
        }
728
 
        else
729
 
        {
730
 
            animDodger->mDodgeMaxAmountX = dodgeAmount[iMin];
731
 
            animDodger->mDodgeMaxAmountY = 0;
732
 
            if (mDodgeMode == AnimationOptions::DodgeModeAllMoving && maxDistX < amountMinAbs)
733
 
            {
734
 
                maxDistX = amountMinAbs;
735
 
                maxDistXActual = amountMinActual;
736
 
            }
737
 
        }
738
 
        animDodger->mDodgeDirection = (DodgeDirection)iMin;
739
 
 
740
 
        coveredSides[iMin] = true;
741
 
    }
742
 
 
743
 
    if (mDodgeMode == AnimationOptions::DodgeModeFixedClickedWindow)
744
 
    {
745
 
        // Subject doesn't move
746
 
        mDodgeMaxAmountX = 0;
747
 
        mDodgeMaxAmountY = 0;
748
 
        mDodgeDirection = DodgeDirectionNone;
749
 
    }
750
 
    else
751
 
    {
752
 
        // Subject should dodge in an axis if only one side is
753
 
        // covered by a dodger.
754
 
        bool subjectDodgesInX = (coveredSides[DodgeDirectionLeft] ^
755
 
                                 coveredSides[DodgeDirectionRight]);
756
 
        bool subjectDodgesInY = (coveredSides[DodgeDirectionUp] ^
757
 
                                 coveredSides[DodgeDirectionDown]);
758
 
 
759
 
        float dodgeAmountX = subjectDodgesInX ? -maxDistXActual / 2 : 0;
760
 
        float dodgeAmountY = subjectDodgesInY ? -maxDistYActual / 2 : 0;
761
 
        DodgeDirection dodgeDirection;
762
 
 
763
 
        if (!subjectDodgesInX && !subjectDodgesInY)
764
 
            dodgeDirection = DodgeDirectionNone;
765
 
        else
766
 
            dodgeDirection = DodgeDirectionXY;
767
 
 
768
 
        CompWindow *wBottommost =
769
 
            ExtensionPluginAnimation::getBottommostInRestackChain (mWindow);
770
 
 
771
 
        float offsetX = 0;
772
 
        float offsetY = 0;
773
 
        float offsetIncrementX = (dodgeAmountX == 0 ? 0 :
774
 
                                  100 * dodgeAmountX / fabs (dodgeAmountX));
775
 
        float offsetIncrementY = (dodgeAmountY == 0 ? 0 :
776
 
                                  100 * dodgeAmountY / fabs (dodgeAmountY));
777
 
 
778
 
        // Set dodge amount and direction for all subjects
779
 
        // in the restack chain
780
 
        RestackPersistentData *dataCur;
781
 
        for (CompWindow *wCur = wBottommost; wCur;
782
 
             wCur = dataCur->mMoreToBePaintedNext,
783
 
             offsetX += offsetIncrementX,
784
 
             offsetY += offsetIncrementY)
785
 
        {
786
 
            AnimWindow *awCur = AnimWindow::get (wCur);
787
 
 
788
 
            dataCur = static_cast<RestackPersistentData *>
789
 
                (awCur->persistentData["restack"]);
790
 
            if (!dataCur)
791
 
                break;
792
 
 
793
 
            Animation *curAnim = awCur->curAnimation ();
794
 
            if (!curAnim || curAnim->info () != AnimEffectDodge)
795
 
                continue;
796
 
            DodgeAnim *dodgeAnim = dynamic_cast<DodgeAnim *> (curAnim);
797
 
 
798
 
            dodgeAnim->mDodgeMaxAmountX = dodgeAmountX + offsetX;
799
 
            dodgeAnim->mDodgeMaxAmountY = dodgeAmountY + offsetY;
800
 
            dodgeAnim->mDodgeDirection = dodgeDirection;
801
 
 
802
 
            dodgeAnim->mTransformStartProgress = 0;
803
 
        }
804
 
 
805
 
        if (dodgeDirection == DodgeDirectionXY)
806
 
        {
807
 
            // Go through each dodger, adjusting its dodge amount if the
808
 
            // subject(s) is dodging in that axis (X or Y).
809
 
            // dw: Dodger window
810
 
            DodgePersistentData *dodgeDataDodger;
811
 
            for (CompWindow *dw = mDodgeData->dodgeChainStart; dw;
812
 
                 dw = dodgeDataDodger->dodgeChainNext)
813
 
            {
814
 
                AnimWindow *adw = AnimWindow::get (dw);
815
 
 
816
 
                dodgeDataDodger = static_cast<DodgePersistentData *>
817
 
                    (adw->persistentData["dodge"]);
818
 
 
819
 
                DodgeAnim *animDodger =
820
 
                    dynamic_cast<DodgeAnim *> (adw->curAnimation ());
821
 
                if (!animDodger)
822
 
                    continue;
823
 
 
824
 
                // if both dodge in X axis
825
 
                if (subjectDodgesInX && animDodger->mDodgeMaxAmountX != 0)
826
 
                {
827
 
                    if (animDodger->mDodgeMaxAmountX *
828
 
                        (animDodger->mDodgeMaxAmountX + dodgeAmountX) < 0)
829
 
                    {
830
 
                        // If the sign is going to change, just reset instead
831
 
                        animDodger->mDodgeMaxAmountX = 0;
832
 
                    }
833
 
                    else
834
 
                        animDodger->mDodgeMaxAmountX += dodgeAmountX;
835
 
                }
836
 
 
837
 
                // if both dodge in Y axis
838
 
                if (subjectDodgesInY && animDodger->mDodgeMaxAmountY != 0)
839
 
                {
840
 
                    if (animDodger->mDodgeMaxAmountY *
841
 
                        (animDodger->mDodgeMaxAmountY + dodgeAmountY) < 0)
842
 
                    {
843
 
                        // If the sign is going to change, just reset instead
844
 
                        animDodger->mDodgeMaxAmountY = 0;
845
 
                    }
846
 
                    else
847
 
                        animDodger->mDodgeMaxAmountY += dodgeAmountY;
848
 
                }
849
 
            }
850
 
        }
851
 
    }
852
 
}
853
 
 
854
 
bool
855
 
DodgeAnim::paintedElsewhere ()
856
 
{
857
 
    bool elsewhere =
858
 
        mRestackData &&
859
 
        mRestackData->mWinThisIsPaintedBefore && // has to be currently hosted
860
 
        mDodgeData &&
861
 
        mDodgeData->isDodgeSubject &&
862
 
        overNewCopy ();
863
 
 
864
 
    return elsewhere;
865
 
}
866
 
 
867
 
DodgePersistentData::DodgePersistentData () :
868
 
    dodgeOrder (0),
869
 
    isDodgeSubject (false),
870
 
    skipPostPrepareScreen (false),
871
 
    dodgeChainStart (0),
872
 
    dodgeChainPrev (0),
873
 
    dodgeChainNext (0)
874
 
{
875
 
}
876