~unity-team/compiz/plugins-main-trunk.fix_wrong_window_move_expo

« back to all changes in this revision

Viewing changes to animation/src/dodge.cpp

  • Committer: David Barth
  • Date: 2011-03-29 16:36:40 UTC
  • Revision ID: david.barth@canonical.com-20110329163640-fpen5qsoo0lbjode
initial import from compiz-plugins-main_0.9.4git20110322.orig.tar.gz

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