/* * Animation plugin for compiz/beryl * * animation.c * * Copyright : (C) 2006 Erkin Bahceci * E-mail : erkinbah@gmail.com * * Based on Wobbly and Minimize plugins by * : David Reveman * E-mail : davidr@novell.com> * * Particle system added by : (C) 2006 Dennis Kasprzyk * E-mail : onestone@beryl-project.org * * Beam-Up added by : Florencio Guimaraes * E-mail : florencio@nexcorp.com.br * * Hexagon tessellator added by : Mike Slegeir * E-mail : mikeslegeir@mail.utexas.edu> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "animation-internal.h" // ===================== Effect: Dodge ========================= static void fxDodgeProcessSubject (CompWindow *wCur, Region wRegion, Region dodgeRegion, Bool alwaysInclude) { XRectangle rect; rect.x = WIN_X(wCur); rect.y = WIN_Y(wCur); rect.width = WIN_W(wCur); rect.height = WIN_H(wCur); Region wCurRegion = XCreateRegion(); XUnionRectWithRegion(&rect, &emptyRegion, wCurRegion); if (!alwaysInclude) { Region intersectionRegion = XCreateRegion(); XIntersectRegion(wRegion, wCurRegion, intersectionRegion); if (!XEmptyRegion(intersectionRegion)) XUnionRegion(dodgeRegion, wCurRegion, dodgeRegion); } else XUnionRegion(dodgeRegion, wCurRegion, dodgeRegion); } static void fxDodgeFindDodgeBox (CompWindow *w, XRectangle *dodgeBox) { ANIM_SCREEN(w->screen); ANIM_WINDOW(w); // Find the box to be dodged, it can contain multiple windows // when there are dialog/utility windows of subject windows // (stacked in the moreToBePaintedNext chain) // Then this would be a bounding box of the subject windows // intersecting with dodger. Region wRegion = XCreateRegion(); Region dodgeRegion = XCreateRegion(); XRectangle rect; rect.x = WIN_X(w); rect.y = WIN_Y(w); rect.width = WIN_W(w); rect.height = WIN_H(w); int dodgeMaxAmount = (int)aw->dodgeMaxAmount; // to compute if subject(s) intersect with dodger w, // enlarge dodger window's box so that it encloses all of the covered // region during dodge movement. This corrects the animation when // there are >1 subjects (a window with its dialog/utility windows). switch (aw->dodgeDirection) { case 0: rect.y += dodgeMaxAmount; rect.height -= dodgeMaxAmount; break; case 1: rect.height += dodgeMaxAmount; break; case 2: rect.x += dodgeMaxAmount; rect.width -= dodgeMaxAmount; break; case 3: rect.width += dodgeMaxAmount; break; } XUnionRectWithRegion(&rect, &emptyRegion, wRegion); AnimWindow *awCur; CompWindow *wCur = aw->dodgeSubjectWin; for (; wCur; wCur = awCur->moreToBePaintedNext) { fxDodgeProcessSubject(wCur, wRegion, dodgeRegion, wCur == aw->dodgeSubjectWin); awCur = GET_ANIM_WINDOW(wCur, as); } AnimWindow *awSubj = GET_ANIM_WINDOW(aw->dodgeSubjectWin, as); wCur = awSubj->moreToBePaintedPrev; for (; wCur; wCur = awCur->moreToBePaintedPrev) { fxDodgeProcessSubject(wCur, wRegion, dodgeRegion, FALSE); awCur = GET_ANIM_WINDOW(wCur, as); } XClipBox(dodgeRegion, dodgeBox); } static void applyDodgeTransform (CompWindow * w, CompTransform *transform) { ANIM_WINDOW(w); if (aw->isDodgeSubject) return; float amount = sin(M_PI * aw->transformProgress) * aw->dodgeMaxAmount; if (aw->dodgeDirection > 1) // if x axis matrixTranslate (transform, amount, 0.0f, 0.0f); else matrixTranslate (transform, 0.0f, amount, 0.0f); } Bool fxDodgeAnimStep (CompScreen * s, CompWindow * w, float time) { if (!defaultAnimStep(s, w, time)) return FALSE; ANIM_WINDOW(w); aw->transformProgress = 0; float forwardProgress = defaultAnimProgress(aw); if (forwardProgress > aw->transformStartProgress) { aw->transformProgress = (forwardProgress - aw->transformStartProgress) / (1 - aw->transformStartProgress); } if (!aw->isDodgeSubject && !aw->dodgeSubjectWin) compLogMessage (w->screen->display, "animation", CompLogLevelError, "%s: %d: Dodge subject missing!", __FILE__, __LINE__); if (!aw->isDodgeSubject && aw->dodgeSubjectWin && aw->transformProgress <= 0.5f) { XRectangle dodgeBox; fxDodgeFindDodgeBox (w, &dodgeBox); // Update dodge amount if subject window is moved during dodge float newDodgeAmount = DODGE_AMOUNT_BOX(dodgeBox, w, aw->dodgeDirection); // Only update if amount got larger if (((newDodgeAmount > 0 && aw->dodgeMaxAmount > 0) || (newDodgeAmount < 0 && aw->dodgeMaxAmount < 0)) && abs(newDodgeAmount) > abs(aw->dodgeMaxAmount)) { aw->dodgeMaxAmount = newDodgeAmount; } } resetToIdentity (&aw->transform); applyDodgeTransform (w, &aw->transform); return TRUE; } void fxDodgeUpdateWindowTransform (CompScreen *s, CompWindow *w, CompTransform *wTransform) { ANIM_WINDOW(w); if (aw->isDodgeSubject) return; // Apply transform to wTransform matmul4 (wTransform->m, wTransform->m, aw->transform.m); } void fxDodgePostPreparePaintScreen(CompScreen *s, CompWindow *w) { ANIM_SCREEN(s); ANIM_WINDOW(w); // Only dodge subjects should be processed here if (!aw->isDodgeSubject) return; if (!aw->restackInfo) return; if (aw->skipPostPrepareScreen) return; // Dodgy window CompWindow *dw; AnimWindow *adw = NULL; for (dw = aw->dodgeChainStart; dw; dw = adw->dodgeChainNext) { adw = GET_ANIM_WINDOW(dw, as); if (!adw) break; // find the first dodging window that hasn't yet // reached 50% progress yet. The subject window should be // painted right behind that one (or right in front of it if // the subject window is being lowered). if (!(adw->transformProgress > 0.5f)) break; } AnimWindow *awOldHost = NULL; if (aw->restackInfo->raised && dw != aw->winThisIsPaintedBefore) // w's host is changing { if (aw->winThisIsPaintedBefore) { // Clear old host awOldHost = GET_ANIM_WINDOW(aw->winThisIsPaintedBefore, as); awOldHost->winToBePaintedBeforeThis = NULL; } if (dw && adw) // if a dodgy win. is still at <0.5 progress { // Put subject right behind adw (new host) adw->winToBePaintedBeforeThis = w; } // otherwise all dodgy win.s have passed 0.5 progress CompWindow *wCur = w; while (wCur) { AnimWindow *awCur = GET_ANIM_WINDOW(wCur, as); awCur->winThisIsPaintedBefore = dw; // dw can be null, which is ok wCur = awCur->moreToBePaintedNext; } } else if (!aw->restackInfo->raised) { // Put subject right in front of dw // But we need to find the dodgy window above dw // (since we need to put subject *behind* another one) CompWindow *wDodgeChainAbove = NULL; if (dw && adw) // if a dodgy win. is still at <0.5 progress { if (adw->dodgeChainPrev) wDodgeChainAbove = adw->dodgeChainPrev; else wDodgeChainAbove = aw->restackInfo->wOldAbove; if (!wDodgeChainAbove) compLogMessage (s->display, "animation", CompLogLevelError, "%s: error at line %d", __FILE__, __LINE__); else if (aw->winThisIsPaintedBefore != wDodgeChainAbove) // w's host is changing { AnimWindow *adw2 = GET_ANIM_WINDOW(wDodgeChainAbove, as); // Put subject right behind adw2 (new host) adw2->winToBePaintedBeforeThis = w; } } if (aw->winThisIsPaintedBefore && aw->winThisIsPaintedBefore != wDodgeChainAbove) { awOldHost = GET_ANIM_WINDOW(aw->winThisIsPaintedBefore, as); // Clear old host awOldHost->winToBePaintedBeforeThis = NULL; } // otherwise all dodgy win.s have passed 0.5 progress // wDodgeChainAbove can be null, which is ok aw->winThisIsPaintedBefore = wDodgeChainAbove; } } void fxDodgeUpdateBB (CompOutput *output, CompWindow * w) { ANIM_WINDOW(w); if (!aw->isDodgeSubject) compTransformUpdateBB (output, w); }