~vanvugt/compiz-animation-plugin/fix-915236

« back to all changes in this revision

Viewing changes to src/dodge.cpp

  • Committer: Erkin Bahceci
  • Date: 2009-07-15 16:05:10 UTC
  • Revision ID: git-v1:6eeaa209932c6039edd4c362c352f242468a118a
Initial C++ port. Dodge and magic lamp changes.

- New dodge mode: all windows moving (made the default).
- Fixed dodge artifacts/weirdness showing up in certain situations.
- Magic Lamp renamed to Magic Lamp Wavy.
- Vacuum renamed to Magic Lamp, allowed for minimize (made the default).
- Separated restack stuff (dodge and focus-fade) from animation core.

Show diffs side-by-side

added added

removed removed

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