~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to kwin/effects/cube/cube.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/********************************************************************
 
2
 KWin - the KDE window manager
 
3
 This file is part of the KDE project.
 
4
 
 
5
 Copyright (C) 2008 Martin Gräßlin <ubuntu@martin-graesslin.com>
 
6
 
 
7
This program is free software; you can redistribute it and/or modify
 
8
it under the terms of the GNU General Public License as published by
 
9
the Free Software Foundation; either version 2 of the License, or
 
10
(at your option) any later version.
 
11
 
 
12
This program is distributed in the hope that it will be useful,
 
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
GNU General Public License for more details.
 
16
 
 
17
You should have received a copy of the GNU General Public License
 
18
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
19
*********************************************************************/
 
20
#include "cube.h"
 
21
#include "cube_inside.h"
 
22
 
 
23
#include <kaction.h>
 
24
#include <kactioncollection.h>
 
25
#include <klocale.h>
 
26
#include <kwinconfig.h>
 
27
#include <kconfiggroup.h>
 
28
#include <kcolorscheme.h>
 
29
#include <kglobal.h>
 
30
#include <kstandarddirs.h>
 
31
#include <kdebug.h>
 
32
 
 
33
#include <QColor>
 
34
#include <QRect>
 
35
#include <QEvent>
 
36
#include <QKeyEvent>
 
37
#include <QVector2D>
 
38
 
 
39
#include <math.h>
 
40
 
 
41
#include <kwinglutils.h>
 
42
#include <kwinglplatform.h>
 
43
 
 
44
namespace KWin
 
45
{
 
46
 
 
47
KWIN_EFFECT(cube, CubeEffect)
 
48
KWIN_EFFECT_SUPPORTED(cube, CubeEffect::supported())
 
49
 
 
50
CubeEffect::CubeEffect()
 
51
    : activated(false)
 
52
    , mousePolling(false)
 
53
    , cube_painting(false)
 
54
    , keyboard_grab(false)
 
55
    , schedule_close(false)
 
56
    , painting_desktop(1)
 
57
    , frontDesktop(0)
 
58
    , cubeOpacity(1.0)
 
59
    , opacityDesktopOnly(true)
 
60
    , displayDesktopName(false)
 
61
    , desktopNameFrame(effects->effectFrame(EffectFrameStyled))
 
62
    , reflection(true)
 
63
    , rotating(false)
 
64
    , desktopChangedWhileRotating(false)
 
65
    , paintCaps(true)
 
66
    , rotationDirection(Left)
 
67
    , verticalRotationDirection(Upwards)
 
68
    , verticalPosition(Normal)
 
69
    , wallpaper(NULL)
 
70
    , texturedCaps(true)
 
71
    , capTexture(NULL)
 
72
    , manualAngle(0.0)
 
73
    , manualVerticalAngle(0.0)
 
74
    , currentShape(QTimeLine::EaseInOutCurve)
 
75
    , start(false)
 
76
    , stop(false)
 
77
    , reflectionPainting(false)
 
78
    , activeScreen(0)
 
79
    , bottomCap(false)
 
80
    , closeOnMouseRelease(false)
 
81
    , zoom(0.0)
 
82
    , zPosition(0.0)
 
83
    , useForTabBox(false)
 
84
    , tabBoxMode(false)
 
85
    , shortcutsRegistered(false)
 
86
    , mode(Cube)
 
87
    , useShaders(false)
 
88
    , cylinderShader(0)
 
89
    , sphereShader(0)
 
90
    , zOrderingFactor(0.0f)
 
91
    , mAddedHeightCoeff1(0.0f)
 
92
    , mAddedHeightCoeff2(0.0f)
 
93
    , m_cubeCapBuffer(NULL)
 
94
    , m_proxy(this)
 
95
{
 
96
    desktopNameFont.setBold(true);
 
97
    desktopNameFont.setPointSize(14);
 
98
    desktopNameFrame->setFont(desktopNameFont);
 
99
 
 
100
    const QString fragmentshader = KGlobal::dirs()->findResource("data", "kwin/cube-reflection.glsl");
 
101
    m_reflectionShader = ShaderManager::instance()->loadFragmentShader(ShaderManager::GenericShader, fragmentshader);
 
102
    const QString capshader = KGlobal::dirs()->findResource("data", "kwin/cube-cap.glsl");
 
103
    m_capShader = ShaderManager::instance()->loadFragmentShader(ShaderManager::GenericShader, capshader);
 
104
    m_textureMirrorMatrix.scale(1.0, -1.0, 1.0);
 
105
    m_textureMirrorMatrix.translate(0.0, -1.0, 0.0);
 
106
    connect(effects, SIGNAL(tabBoxAdded(int)), this, SLOT(slotTabBoxAdded(int)));
 
107
    connect(effects, SIGNAL(tabBoxClosed()), this, SLOT(slotTabBoxClosed()));
 
108
    connect(effects, SIGNAL(tabBoxUpdated()), this, SLOT(slotTabBoxUpdated()));
 
109
    connect(effects, SIGNAL(mouseChanged(QPoint,QPoint,Qt::MouseButtons,Qt::MouseButtons,Qt::KeyboardModifiers,Qt::KeyboardModifiers)),
 
110
            this, SLOT(slotMouseChanged(QPoint,QPoint,Qt::MouseButtons,Qt::MouseButtons,Qt::KeyboardModifiers,Qt::KeyboardModifiers)));
 
111
 
 
112
    reconfigure(ReconfigureAll);
 
113
}
 
114
 
 
115
bool CubeEffect::supported()
 
116
{
 
117
    return effects->compositingType() == OpenGLCompositing;
 
118
}
 
119
 
 
120
void CubeEffect::reconfigure(ReconfigureFlags)
 
121
{
 
122
    loadConfig("Cube");
 
123
}
 
124
 
 
125
void CubeEffect::loadConfig(QString config)
 
126
{
 
127
    KConfigGroup conf = effects->effectConfig(config);
 
128
    foreach (ElectricBorder border, borderActivate) {
 
129
        effects->unreserveElectricBorder(border);
 
130
    }
 
131
    foreach (ElectricBorder border, borderActivateCylinder) {
 
132
        effects->unreserveElectricBorder(border);
 
133
    }
 
134
    foreach (ElectricBorder border, borderActivateSphere) {
 
135
        effects->unreserveElectricBorder(border);
 
136
    }
 
137
    borderActivate.clear();
 
138
    borderActivateCylinder.clear();
 
139
    borderActivateSphere.clear();
 
140
    QList<int> borderList = QList<int>();
 
141
    borderList.append(int(ElectricNone));
 
142
    borderList = conf.readEntry("BorderActivate", borderList);
 
143
    foreach (int i, borderList) {
 
144
        borderActivate.append(ElectricBorder(i));
 
145
        effects->reserveElectricBorder(ElectricBorder(i));
 
146
    }
 
147
    borderList.clear();
 
148
    borderList.append(int(ElectricNone));
 
149
    borderList = conf.readEntry("BorderActivateCylinder", borderList);
 
150
    foreach (int i, borderList) {
 
151
        borderActivateCylinder.append(ElectricBorder(i));
 
152
        effects->reserveElectricBorder(ElectricBorder(i));
 
153
    }
 
154
    borderList.clear();
 
155
    borderList.append(int(ElectricNone));
 
156
    borderList = conf.readEntry("BorderActivateSphere", borderList);
 
157
    foreach (int i, borderList) {
 
158
        borderActivateSphere.append(ElectricBorder(i));
 
159
        effects->reserveElectricBorder(ElectricBorder(i));
 
160
    }
 
161
 
 
162
    cubeOpacity = (float)conf.readEntry("Opacity", 80) / 100.0f;
 
163
    opacityDesktopOnly = conf.readEntry("OpacityDesktopOnly", false);
 
164
    displayDesktopName = conf.readEntry("DisplayDesktopName", true);
 
165
    reflection = conf.readEntry("Reflection", true);
 
166
    rotationDuration = animationTime(conf, "RotationDuration", 500);
 
167
    backgroundColor = conf.readEntry("BackgroundColor", QColor(Qt::black));
 
168
    capColor = conf.readEntry("CapColor", KColorScheme(QPalette::Active, KColorScheme::Window).background().color());
 
169
    paintCaps = conf.readEntry("Caps", true);
 
170
    closeOnMouseRelease = conf.readEntry("CloseOnMouseRelease", false);
 
171
    float defaultZPosition = 100.0f;
 
172
    if (config == "Sphere")
 
173
        defaultZPosition = 450.0f;
 
174
    zPosition = conf.readEntry("ZPosition", defaultZPosition);
 
175
    useForTabBox = conf.readEntry("TabBox", false);
 
176
    invertKeys = conf.readEntry("InvertKeys", false);
 
177
    invertMouse = conf.readEntry("InvertMouse", false);
 
178
    capDeformationFactor = conf.readEntry("CapDeformation", 0) / 100.0f;
 
179
    useZOrdering = conf.readEntry("ZOrdering", false);
 
180
    QString file = conf.readEntry("Wallpaper", QString(""));
 
181
    if (wallpaper)
 
182
        wallpaper->discard();
 
183
    delete wallpaper;
 
184
    wallpaper = NULL;
 
185
    if (!file.isEmpty()) {
 
186
        QImage img = QImage(file);
 
187
        if (!img.isNull()) {
 
188
            wallpaper = new GLTexture(img);
 
189
        }
 
190
    }
 
191
    delete capTexture;
 
192
    capTexture = NULL;
 
193
    texturedCaps = conf.readEntry("TexturedCaps", true);
 
194
    if (texturedCaps) {
 
195
        QString capPath = conf.readEntry("CapPath", KGlobal::dirs()->findResource("appdata", "cubecap.png"));
 
196
        QImage img = QImage(capPath);
 
197
        if (!img.isNull()) {
 
198
            capTexture = new GLTexture(img);
 
199
            capTexture->setFilter(GL_LINEAR);
 
200
#ifndef KWIN_HAVE_OPENGLES
 
201
            capTexture->setWrapMode(GL_CLAMP_TO_BORDER);
 
202
#endif
 
203
        }
 
204
    }
 
205
 
 
206
    timeLine.setCurveShape(QTimeLine::EaseInOutCurve);
 
207
    timeLine.setDuration(rotationDuration);
 
208
 
 
209
    verticalTimeLine.setCurveShape(QTimeLine::EaseInOutCurve);
 
210
    verticalTimeLine.setDuration(rotationDuration);
 
211
 
 
212
    // do not connect the shortcut if we use cylinder or sphere
 
213
    if (!shortcutsRegistered) {
 
214
        KActionCollection* actionCollection = new KActionCollection(this);
 
215
        KAction* cubeAction = static_cast< KAction* >(actionCollection->addAction("Cube"));
 
216
        cubeAction->setText(i18n("Desktop Cube"));
 
217
        cubeAction->setGlobalShortcut(KShortcut(Qt::CTRL + Qt::Key_F11));
 
218
        cubeShortcut = cubeAction->globalShortcut();
 
219
        KAction* cylinderAction = static_cast< KAction* >(actionCollection->addAction("Cylinder"));
 
220
        cylinderAction->setText(i18n("Desktop Cylinder"));
 
221
        cylinderAction->setGlobalShortcut(KShortcut(), KAction::ActiveShortcut);
 
222
        cylinderShortcut = cylinderAction->globalShortcut();
 
223
        KAction* sphereAction = static_cast< KAction* >(actionCollection->addAction("Sphere"));
 
224
        sphereAction->setText(i18n("Desktop Sphere"));
 
225
        sphereAction->setGlobalShortcut(KShortcut(), KAction::ActiveShortcut);
 
226
        sphereShortcut = sphereAction->globalShortcut();
 
227
        connect(cubeAction, SIGNAL(triggered(bool)), this, SLOT(toggleCube()));
 
228
        connect(cylinderAction, SIGNAL(triggered(bool)), this, SLOT(toggleCylinder()));
 
229
        connect(sphereAction, SIGNAL(triggered(bool)), this, SLOT(toggleSphere()));
 
230
        connect(cubeAction, SIGNAL(globalShortcutChanged(QKeySequence)), this, SLOT(cubeShortcutChanged(QKeySequence)));
 
231
        connect(cylinderAction, SIGNAL(globalShortcutChanged(QKeySequence)), this, SLOT(cylinderShortcutChanged(QKeySequence)));
 
232
        connect(sphereAction, SIGNAL(globalShortcutChanged(QKeySequence)), this, SLOT(sphereShortcutChanged(QKeySequence)));
 
233
        shortcutsRegistered = true;
 
234
    }
 
235
 
 
236
    // set the cap color on the shader
 
237
    if (ShaderManager::instance()->isValid() && m_capShader->isValid()) {
 
238
        ShaderManager::instance()->pushShader(m_capShader);
 
239
        m_capShader->setUniform("u_capColor", capColor);
 
240
        ShaderManager::instance()->popShader();
 
241
    }
 
242
}
 
243
 
 
244
CubeEffect::~CubeEffect()
 
245
{
 
246
    foreach (ElectricBorder border, borderActivate) {
 
247
        effects->unreserveElectricBorder(border);
 
248
    }
 
249
    foreach (ElectricBorder border, borderActivateCylinder) {
 
250
        effects->unreserveElectricBorder(border);
 
251
    }
 
252
    foreach (ElectricBorder border, borderActivateSphere) {
 
253
        effects->unreserveElectricBorder(border);
 
254
    }
 
255
    delete wallpaper;
 
256
    delete capTexture;
 
257
    delete cylinderShader;
 
258
    delete sphereShader;
 
259
    delete desktopNameFrame;
 
260
    delete m_reflectionShader;
 
261
    delete m_capShader;
 
262
    delete m_cubeCapBuffer;
 
263
}
 
264
 
 
265
bool CubeEffect::loadShader()
 
266
{
 
267
    if (!(GLPlatform::instance()->supports(GLSL) &&
 
268
            (effects->compositingType() == OpenGLCompositing)))
 
269
        return false;
 
270
    QString fragmentshader       =  KGlobal::dirs()->findResource("data", "kwin/cylinder.frag");
 
271
    QString cylinderVertexshader =  KGlobal::dirs()->findResource("data", "kwin/cylinder.vert");
 
272
    QString sphereVertexshader   = KGlobal::dirs()->findResource("data", "kwin/sphere.vert");
 
273
    if (fragmentshader.isEmpty() || cylinderVertexshader.isEmpty() || sphereVertexshader.isEmpty()) {
 
274
        kError(1212) << "Couldn't locate shader files" << endl;
 
275
        return false;
 
276
    }
 
277
 
 
278
    ShaderManager *shaderManager = ShaderManager::instance();
 
279
    // TODO: use generic shader - currently it is failing in alpha/brightness manipulation
 
280
    cylinderShader = new GLShader(cylinderVertexshader, fragmentshader);
 
281
    if (!cylinderShader->isValid()) {
 
282
        kError(1212) << "The cylinder shader failed to load!" << endl;
 
283
        return false;
 
284
    } else {
 
285
        shaderManager->pushShader(cylinderShader);
 
286
        cylinderShader->setUniform("sampler", 0);
 
287
        QMatrix4x4 projection;
 
288
        float fovy = 60.0f;
 
289
        float aspect = 1.0f;
 
290
        float zNear = 0.1f;
 
291
        float zFar = 100.0f;
 
292
        float ymax = zNear * tan(fovy  * M_PI / 360.0f);
 
293
        float ymin = -ymax;
 
294
        float xmin =  ymin * aspect;
 
295
        float xmax = ymax * aspect;
 
296
        projection.frustum(xmin, xmax, ymin, ymax, zNear, zFar);
 
297
        cylinderShader->setUniform("projection", projection);
 
298
        QMatrix4x4 modelview;
 
299
        float scaleFactor = 1.1 * tan(fovy * M_PI / 360.0f) / ymax;
 
300
        modelview.translate(xmin * scaleFactor, ymax * scaleFactor, -1.1);
 
301
        modelview.scale((xmax - xmin)*scaleFactor / displayWidth(), -(ymax - ymin)*scaleFactor / displayHeight(), 0.001);
 
302
        cylinderShader->setUniform("modelview", modelview);
 
303
        const QMatrix4x4 identity;
 
304
        cylinderShader->setUniform("screenTransformation", identity);
 
305
        cylinderShader->setUniform("windowTransformation", identity);
 
306
        QRect rect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop());
 
307
        cylinderShader->setUniform("width", (float)rect.width() * 0.5f);
 
308
        shaderManager->popShader();
 
309
    }
 
310
    // TODO: use generic shader - currently it is failing in alpha/brightness manipulation
 
311
    sphereShader = new GLShader(sphereVertexshader, fragmentshader);
 
312
    if (!sphereShader->isValid()) {
 
313
        kError(1212) << "The sphere shader failed to load!" << endl;
 
314
        return false;
 
315
    } else {
 
316
        shaderManager->pushShader(sphereShader);
 
317
        sphereShader->setUniform("sampler", 0);
 
318
        QMatrix4x4 projection;
 
319
        float fovy = 60.0f;
 
320
        float aspect = 1.0f;
 
321
        float zNear = 0.1f;
 
322
        float zFar = 100.0f;
 
323
        float ymax = zNear * tan(fovy  * M_PI / 360.0f);
 
324
        float ymin = -ymax;
 
325
        float xmin =  ymin * aspect;
 
326
        float xmax = ymax * aspect;
 
327
        projection.frustum(xmin, xmax, ymin, ymax, zNear, zFar);
 
328
        sphereShader->setUniform("projection", projection);
 
329
        QMatrix4x4 modelview;
 
330
        float scaleFactor = 1.1 * tan(fovy * M_PI / 360.0f) / ymax;
 
331
        modelview.translate(xmin * scaleFactor, ymax * scaleFactor, -1.1);
 
332
        modelview.scale((xmax - xmin)*scaleFactor / displayWidth(), -(ymax - ymin)*scaleFactor / displayHeight(), 0.001);
 
333
        sphereShader->setUniform("modelview", modelview);
 
334
        const QMatrix4x4 identity;
 
335
        sphereShader->setUniform("screenTransformation", identity);
 
336
        sphereShader->setUniform("windowTransformation", identity);
 
337
        QRect rect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop());
 
338
        sphereShader->setUniform("width", (float)rect.width() * 0.5f);
 
339
        sphereShader->setUniform("height", (float)rect.height() * 0.5f);
 
340
        sphereShader->setUniform("u_offset", QVector2D(0, 0));
 
341
        shaderManager->popShader();
 
342
        checkGLError("Loading Sphere Shader");
 
343
    }
 
344
    return true;
 
345
}
 
346
 
 
347
void CubeEffect::prePaintScreen(ScreenPrePaintData& data, int time)
 
348
{
 
349
    if (activated) {
 
350
        data.mask |= PAINT_SCREEN_TRANSFORMED | Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS | PAINT_SCREEN_BACKGROUND_FIRST;
 
351
 
 
352
        if (rotating || start || stop) {
 
353
            timeLine.setCurrentTime(timeLine.currentTime() + time);
 
354
            rotateCube();
 
355
        }
 
356
        if (verticalRotating) {
 
357
            verticalTimeLine.setCurrentTime(verticalTimeLine.currentTime() + time);
 
358
            rotateCube();
 
359
        }
 
360
    }
 
361
    effects->prePaintScreen(data, time);
 
362
}
 
363
 
 
364
void CubeEffect::paintScreen(int mask, QRegion region, ScreenPaintData& data)
 
365
{
 
366
    if (activated) {
 
367
        QRect rect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop());
 
368
 
 
369
        // background
 
370
        float clearColor[4];
 
371
        glGetFloatv(GL_COLOR_CLEAR_VALUE, clearColor);
 
372
        glClearColor(backgroundColor.redF(), backgroundColor.greenF(), backgroundColor.blueF(), 1.0);
 
373
        glClear(GL_COLOR_BUFFER_BIT);
 
374
        glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
 
375
 
 
376
        // wallpaper
 
377
        if (wallpaper) {
 
378
            if (ShaderManager::instance()->isValid()) {
 
379
                ShaderManager::instance()->pushShader(ShaderManager::SimpleShader);
 
380
            }
 
381
            wallpaper->bind();
 
382
            wallpaper->render(region, rect);
 
383
            wallpaper->unbind();
 
384
            if (ShaderManager::instance()->isValid()) {
 
385
                ShaderManager::instance()->popShader();
 
386
            }
 
387
        }
 
388
 
 
389
#ifndef KWIN_HAVE_OPENGLES
 
390
        glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT);
 
391
#endif
 
392
        glEnable(GL_BLEND);
 
393
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
394
 
 
395
        // some veriables needed for painting the caps
 
396
        float cubeAngle = (float)((float)(effects->numberOfDesktops() - 2) / (float)effects->numberOfDesktops() * 180.0f);
 
397
        float point = rect.width() / 2 * tan(cubeAngle * 0.5f * M_PI / 180.0f);
 
398
        float zTranslate = zPosition + zoom;
 
399
        if (start)
 
400
            zTranslate *= timeLine.currentValue();
 
401
        if (stop)
 
402
            zTranslate *= (1.0 - timeLine.currentValue());
 
403
        // reflection
 
404
        if (reflection && mode != Sphere) {
 
405
            // restrict painting the reflections to the current screen
 
406
            PaintClipper::push(QRegion(rect));
 
407
            // we can use a huge scale factor (needed to calculate the rearground vertices)
 
408
            // as we restrict with a PaintClipper painting on the current screen
 
409
            float scaleFactor = 1000000 * tan(60.0 * M_PI / 360.0f) / rect.height();
 
410
            m_reflectionMatrix.setToIdentity();
 
411
            m_reflectionMatrix.scale(1.0, -1.0, 1.0);
 
412
 
 
413
            // TODO reflection is not correct when mixing manual (mouse) rotating with rotation by cursor keys
 
414
            // there's also a small bug when zooming
 
415
            float addedHeight1 = -sin(asin(float(rect.height()) / mAddedHeightCoeff1) + fabs(manualVerticalAngle) * M_PI / 180.0f) * mAddedHeightCoeff1;
 
416
            float addedHeight2 = -sin(asin(float(rect.height()) / mAddedHeightCoeff2) + fabs(manualVerticalAngle) * M_PI / 180.0f) * mAddedHeightCoeff2 - addedHeight1;
 
417
            if (manualVerticalAngle > 0.0f && effects->numberOfDesktops() & 1) {
 
418
                m_reflectionMatrix.translate(0.0, cos(fabs(manualAngle) * M_PI / 360.0f * float(effects->numberOfDesktops())) * addedHeight2 + addedHeight1 - float(rect.height()), 0.0);
 
419
            } else {
 
420
                m_reflectionMatrix.translate(0.0, sin(fabs(manualAngle) * M_PI / 360.0f * float(effects->numberOfDesktops())) * addedHeight2 + addedHeight1 - float(rect.height()), 0.0);
 
421
            }
 
422
            pushMatrix(m_reflectionMatrix);
 
423
 
 
424
#ifndef KWIN_HAVE_OPENGLES
 
425
            // TODO: find a solution for GLES
 
426
            glEnable(GL_CLIP_PLANE0);
 
427
#endif
 
428
            reflectionPainting = true;
 
429
            glEnable(GL_CULL_FACE);
 
430
            paintCap(true, -point - zTranslate);
 
431
 
 
432
            // cube
 
433
            glCullFace(GL_BACK);
 
434
            pushMatrix(m_rotationMatrix);
 
435
            paintCube(mask, region, data);
 
436
            popMatrix();
 
437
 
 
438
            // call the inside cube effects
 
439
#ifndef KWIN_HAVE_OPENGLES
 
440
            foreach (CubeInsideEffect * inside, m_cubeInsideEffects) {
 
441
                pushMatrix(m_rotationMatrix);
 
442
                glTranslatef(rect.width() / 2, rect.height() / 2, -point - zTranslate);
 
443
                glRotatef((1 - frontDesktop) * 360.0f / effects->numberOfDesktops(), 0.0, 1.0, 0.0);
 
444
                inside->paint();
 
445
                popMatrix();
 
446
            }
 
447
#endif
 
448
 
 
449
            glCullFace(GL_FRONT);
 
450
            pushMatrix(m_rotationMatrix);
 
451
            paintCube(mask, region, data);
 
452
            popMatrix();
 
453
 
 
454
            paintCap(false, -point - zTranslate);
 
455
            glDisable(GL_CULL_FACE);
 
456
            reflectionPainting = false;
 
457
#ifndef KWIN_HAVE_OPENGLES
 
458
            // TODO: find a solution for GLES
 
459
            glDisable(GL_CLIP_PLANE0);
 
460
#endif
 
461
            popMatrix();
 
462
 
 
463
            float vertices[] = {
 
464
                -rect.width() * 0.5f, rect.height(), 0.0,
 
465
                rect.width() * 0.5f, rect.height(), 0.0,
 
466
                (float)rect.width()*scaleFactor, rect.height(), -5000,
 
467
                -(float)rect.width()*scaleFactor, rect.height(), -5000
 
468
            };
 
469
            // foreground
 
470
            float alpha = 0.7;
 
471
            if (start)
 
472
                alpha = 0.3 + 0.4 * timeLine.currentValue();
 
473
            if (stop)
 
474
                alpha = 0.3 + 0.4 * (1.0 - timeLine.currentValue());
 
475
            glEnable(GL_BLEND);
 
476
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
477
            ShaderManager *shaderManager = ShaderManager::instance();
 
478
            if (shaderManager->isValid() && m_reflectionShader->isValid()) {
 
479
                // ensure blending is enabled - no attribute stack
 
480
                shaderManager->pushShader(m_reflectionShader);
 
481
                QMatrix4x4 windowTransformation;
 
482
                windowTransformation.translate(rect.x() + rect.width() * 0.5f, 0.0, 0.0);
 
483
                m_reflectionShader->setUniform("windowTransformation", windowTransformation);
 
484
                m_reflectionShader->setUniform("u_alpha", alpha);
 
485
                QVector<float> verts;
 
486
                QVector<float> texcoords;
 
487
                verts.reserve(18);
 
488
                texcoords.reserve(12);
 
489
                texcoords << 0.0 << 0.0;
 
490
                verts << vertices[6] << vertices[7] << vertices[8];
 
491
                texcoords << 0.0 << 0.0;
 
492
                verts << vertices[9] << vertices[10] << vertices[11];
 
493
                texcoords << 1.0 << 0.0;
 
494
                verts << vertices[0] << vertices[1] << vertices[2];
 
495
                texcoords << 1.0 << 0.0;
 
496
                verts << vertices[0] << vertices[1] << vertices[2];
 
497
                texcoords << 1.0 << 0.0;
 
498
                verts << vertices[3] << vertices[4] << vertices[5];
 
499
                texcoords << 0.0 << 0.0;
 
500
                verts << vertices[6] << vertices[7] << vertices[8];
 
501
                GLVertexBuffer *vbo = GLVertexBuffer::streamingBuffer();
 
502
                vbo->reset();
 
503
                vbo->setData(6, 3, verts.data(), texcoords.data());
 
504
                vbo->render(GL_TRIANGLES);
 
505
 
 
506
                shaderManager->popShader();
 
507
            } else {
 
508
#ifndef KWIN_HAVE_OPENGLES
 
509
                glColor4f(0.0, 0.0, 0.0, alpha);
 
510
                glPushMatrix();
 
511
                glTranslatef(rect.x() + rect.width() * 0.5f, 0.0, 0.0);
 
512
                glBegin(GL_POLYGON);
 
513
                glVertex3f(vertices[0], vertices[1], vertices[2]);
 
514
                glVertex3f(vertices[3], vertices[4], vertices[5]);
 
515
                // rearground
 
516
                alpha = -1.0;
 
517
                glColor4f(0.0, 0.0, 0.0, alpha);
 
518
                glVertex3f(vertices[6], vertices[7], vertices[8]);
 
519
                glVertex3f(vertices[9], vertices[10], vertices[11]);
 
520
                glEnd();
 
521
                glPopMatrix();
 
522
#endif
 
523
            }
 
524
            glDisable(GL_BLEND);
 
525
            PaintClipper::pop(QRegion(rect));
 
526
        }
 
527
        glEnable(GL_CULL_FACE);
 
528
        // caps
 
529
        paintCap(false, -point - zTranslate);
 
530
 
 
531
        // cube
 
532
        glCullFace(GL_FRONT);
 
533
        pushMatrix(m_rotationMatrix);
 
534
        paintCube(mask, region, data);
 
535
        popMatrix();
 
536
 
 
537
 
 
538
        // call the inside cube effects
 
539
#ifndef KWIN_HAVE_OPENGLES
 
540
        foreach (CubeInsideEffect * inside, m_cubeInsideEffects) {
 
541
            pushMatrix(m_rotationMatrix);
 
542
            glTranslatef(rect.width() / 2, rect.height() / 2, -point - zTranslate);
 
543
            glRotatef((1 - frontDesktop) * 360.0f / effects->numberOfDesktops(), 0.0, 1.0, 0.0);
 
544
            inside->paint();
 
545
            popMatrix();
 
546
        }
 
547
#endif
 
548
 
 
549
        glCullFace(GL_BACK);
 
550
        pushMatrix(m_rotationMatrix);
 
551
        paintCube(mask, region, data);
 
552
        popMatrix();
 
553
 
 
554
        // cap
 
555
        paintCap(true, -point - zTranslate);
 
556
        glDisable(GL_CULL_FACE);
 
557
 
 
558
        glDisable(GL_BLEND);
 
559
#ifndef KWIN_HAVE_OPENGLES
 
560
        glPopAttrib();
 
561
#endif
 
562
 
 
563
        // desktop name box - inspired from coverswitch
 
564
        if (displayDesktopName) {
 
565
            double opacity = 1.0;
 
566
            if (start)
 
567
                opacity = timeLine.currentValue();
 
568
            if (stop)
 
569
                opacity = 1.0 - timeLine.currentValue();
 
570
            QRect screenRect = effects->clientArea(ScreenArea, activeScreen, frontDesktop);
 
571
            QRect frameRect = QRect(screenRect.width() * 0.33f + screenRect.x(), screenRect.height() * 0.95f + screenRect.y(),
 
572
                                    screenRect.width() * 0.34f, QFontMetrics(desktopNameFont).height());
 
573
            desktopNameFrame->setGeometry(frameRect);
 
574
            desktopNameFrame->setText(effects->desktopName(frontDesktop));
 
575
            desktopNameFrame->render(region, opacity);
 
576
        }
 
577
    } else {
 
578
        effects->paintScreen(mask, region, data);
 
579
    }
 
580
}
 
581
 
 
582
void CubeEffect::rotateCube()
 
583
{
 
584
    QRect rect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop());
 
585
 
 
586
    m_rotationMatrix.setToIdentity();
 
587
    float internalCubeAngle = 360.0f / effects->numberOfDesktops();
 
588
    float zTranslate = zPosition + zoom;
 
589
    if (start)
 
590
        zTranslate *= timeLine.currentValue();
 
591
    if (stop)
 
592
        zTranslate *= (1.0 - timeLine.currentValue());
 
593
    // Rotation of the cube
 
594
    float cubeAngle = (float)((float)(effects->numberOfDesktops() - 2) / (float)effects->numberOfDesktops() * 180.0f);
 
595
    float point = rect.width() / 2 * tan(cubeAngle * 0.5f * M_PI / 180.0f);
 
596
    if (verticalRotating || verticalPosition != Normal || manualVerticalAngle != 0.0) {
 
597
        // change the verticalPosition if manualVerticalAngle > 90 or < -90 degrees
 
598
        if (manualVerticalAngle <= -90.0) {
 
599
            manualVerticalAngle += 90.0;
 
600
            if (verticalPosition == Normal)
 
601
                verticalPosition = Down;
 
602
            if (verticalPosition == Up)
 
603
                verticalPosition = Normal;
 
604
        }
 
605
        if (manualVerticalAngle >= 90.0) {
 
606
            manualVerticalAngle -= 90.0;
 
607
            if (verticalPosition == Normal)
 
608
                verticalPosition = Up;
 
609
            if (verticalPosition == Down)
 
610
                verticalPosition = Normal;
 
611
        }
 
612
        float angle = 0.0;
 
613
        if (verticalPosition == Up) {
 
614
            angle = 90.0;
 
615
            if (!verticalRotating) {
 
616
                if (manualVerticalAngle < 0.0)
 
617
                    angle += manualVerticalAngle;
 
618
                else
 
619
                    manualVerticalAngle = 0.0;
 
620
            }
 
621
        } else if (verticalPosition == Down) {
 
622
            angle = -90.0;
 
623
            if (!verticalRotating) {
 
624
                if (manualVerticalAngle > 0.0)
 
625
                    angle += manualVerticalAngle;
 
626
                else
 
627
                    manualVerticalAngle = 0.0;
 
628
            }
 
629
        } else {
 
630
            angle = manualVerticalAngle;
 
631
        }
 
632
        if (verticalRotating) {
 
633
            angle *= verticalTimeLine.currentValue();
 
634
            if (verticalPosition == Normal && verticalRotationDirection == Upwards)
 
635
                angle = -90.0 + 90 * verticalTimeLine.currentValue();
 
636
            if (verticalPosition == Normal && verticalRotationDirection == Downwards)
 
637
                angle = 90.0 - 90 * verticalTimeLine.currentValue();
 
638
            angle += manualVerticalAngle * (1.0 - verticalTimeLine.currentValue());
 
639
        }
 
640
        if (stop)
 
641
            angle *= (1.0 - timeLine.currentValue());
 
642
        m_rotationMatrix.translate(rect.width() / 2, rect.height() / 2, -point - zTranslate);
 
643
        m_rotationMatrix.rotate(angle, 1.0, 0.0, 0.0);
 
644
        m_rotationMatrix.translate(-rect.width() / 2, -rect.height() / 2, point + zTranslate);
 
645
    }
 
646
    if (rotating || (manualAngle != 0.0)) {
 
647
        int tempFrontDesktop = frontDesktop;
 
648
        if (manualAngle > internalCubeAngle * 0.5f) {
 
649
            manualAngle -= internalCubeAngle;
 
650
            tempFrontDesktop--;
 
651
            if (tempFrontDesktop == 0)
 
652
                tempFrontDesktop = effects->numberOfDesktops();
 
653
        }
 
654
        if (manualAngle < -internalCubeAngle * 0.5f) {
 
655
            manualAngle += internalCubeAngle;
 
656
            tempFrontDesktop++;
 
657
            if (tempFrontDesktop > effects->numberOfDesktops())
 
658
                tempFrontDesktop = 1;
 
659
        }
 
660
        float rotationAngle = internalCubeAngle * timeLine.currentValue();
 
661
        if (rotationAngle > internalCubeAngle * 0.5f) {
 
662
            rotationAngle -= internalCubeAngle;
 
663
            if (!desktopChangedWhileRotating) {
 
664
                desktopChangedWhileRotating = true;
 
665
                if (rotationDirection == Left) {
 
666
                    tempFrontDesktop++;
 
667
                } else if (rotationDirection == Right) {
 
668
                    tempFrontDesktop--;
 
669
                }
 
670
                if (tempFrontDesktop > effects->numberOfDesktops())
 
671
                    tempFrontDesktop = 1;
 
672
                else if (tempFrontDesktop == 0)
 
673
                    tempFrontDesktop = effects->numberOfDesktops();
 
674
            }
 
675
        }
 
676
        // don't change front desktop during stop animation as this would break some logic
 
677
        if (!stop)
 
678
            frontDesktop = tempFrontDesktop;
 
679
        if (rotationDirection == Left) {
 
680
            rotationAngle *= -1;
 
681
        }
 
682
        if (stop)
 
683
            rotationAngle = manualAngle * (1.0 - timeLine.currentValue());
 
684
        else
 
685
            rotationAngle += manualAngle * (1.0 - timeLine.currentValue());
 
686
        m_rotationMatrix.translate(rect.width() / 2, rect.height() / 2, -point - zTranslate);
 
687
        m_rotationMatrix.rotate(rotationAngle, 0.0, 1.0, 0.0);
 
688
        m_rotationMatrix.translate(-rect.width() / 2, -rect.height() / 2, point + zTranslate);
 
689
    }
 
690
}
 
691
 
 
692
void CubeEffect::paintCube(int mask, QRegion region, ScreenPaintData& data)
 
693
{
 
694
    QRect rect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop());
 
695
    float internalCubeAngle = 360.0f / effects->numberOfDesktops();
 
696
    cube_painting = true;
 
697
    float zTranslate = zPosition + zoom;
 
698
    if (start)
 
699
        zTranslate *= timeLine.currentValue();
 
700
    if (stop)
 
701
        zTranslate *= (1.0 - timeLine.currentValue());
 
702
 
 
703
    // Rotation of the cube
 
704
    float cubeAngle = (float)((float)(effects->numberOfDesktops() - 2) / (float)effects->numberOfDesktops() * 180.0f);
 
705
    float point = rect.width() / 2 * tan(cubeAngle * 0.5f * M_PI / 180.0f);
 
706
 
 
707
    for (int i = 0; i < effects->numberOfDesktops(); i++) {
 
708
        // start painting the cube
 
709
        painting_desktop = (i + frontDesktop) % effects->numberOfDesktops();
 
710
        if (painting_desktop == 0) {
 
711
            painting_desktop = effects->numberOfDesktops();
 
712
        }
 
713
        ScreenPaintData newData = data;
 
714
        RotationData rot = RotationData();
 
715
        rot.axis = RotationData::YAxis;
 
716
        rot.angle = internalCubeAngle * i;
 
717
        rot.xRotationPoint = rect.width() / 2;
 
718
        rot.zRotationPoint = -point;
 
719
        newData.rotation = &rot;
 
720
        newData.zTranslate = -zTranslate;
 
721
        effects->paintScreen(mask, region, newData);
 
722
    }
 
723
    cube_painting = false;
 
724
    painting_desktop = effects->currentDesktop();
 
725
}
 
726
 
 
727
void CubeEffect::paintCap(bool frontFirst, float zOffset)
 
728
{
 
729
    if ((!paintCaps) || effects->numberOfDesktops() <= 2)
 
730
        return;
 
731
    GLenum firstCull = frontFirst ? GL_FRONT : GL_BACK;
 
732
    GLenum secondCull = frontFirst ? GL_BACK : GL_FRONT;
 
733
    const QRect rect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop());
 
734
 
 
735
    // create the VBO if not yet created
 
736
    if (!m_cubeCapBuffer) {
 
737
        switch(mode) {
 
738
        case Cube:
 
739
            paintCubeCap();
 
740
            break;
 
741
        case Cylinder:
 
742
            paintCylinderCap();
 
743
            break;
 
744
        case Sphere:
 
745
            paintSphereCap();
 
746
            break;
 
747
        default:
 
748
            // impossible
 
749
            break;
 
750
        }
 
751
    }
 
752
 
 
753
    QMatrix4x4 capMatrix;
 
754
    capMatrix.translate(rect.width() / 2, 0.0, zOffset);
 
755
    capMatrix.rotate((1 - frontDesktop) * 360.0f / effects->numberOfDesktops(), 0.0, 1.0, 0.0);
 
756
    capMatrix.translate(0.0, rect.height(), 0.0);
 
757
    if (mode == Sphere) {
 
758
        capMatrix.scale(1.0, -1.0, 1.0);
 
759
    }
 
760
 
 
761
    bool capShader = false;
 
762
    if (ShaderManager::instance()->isValid() && m_capShader->isValid()) {
 
763
        capShader = true;
 
764
        ShaderManager::instance()->pushShader(m_capShader);
 
765
        float opacity = cubeOpacity;
 
766
        if (start) {
 
767
            opacity *= timeLine.currentValue();
 
768
        } else if (stop) {
 
769
            opacity *= (1.0 - timeLine.currentValue());
 
770
        }
 
771
        m_capShader->setUniform("u_opacity", opacity);
 
772
        m_capShader->setUniform("u_mirror", 1);
 
773
        if (reflectionPainting) {
 
774
            m_capShader->setUniform("screenTransformation", m_reflectionMatrix * m_rotationMatrix);
 
775
        } else {
 
776
            m_capShader->setUniform("screenTransformation", m_rotationMatrix);
 
777
        }
 
778
        m_capShader->setUniform("windowTransformation", capMatrix);
 
779
        m_capShader->setUniform("u_untextured", texturedCaps ? 0 : 1);
 
780
        if (texturedCaps && effects->numberOfDesktops() > 3 && capTexture) {
 
781
            capTexture->bind();
 
782
        }
 
783
    } else {
 
784
        pushMatrix(m_rotationMatrix * capMatrix);
 
785
 
 
786
#ifndef KWIN_HAVE_OPENGLES
 
787
        glMatrixMode(GL_TEXTURE);
 
788
#endif
 
789
        pushMatrix();
 
790
        loadMatrix(m_textureMirrorMatrix);
 
791
#ifndef KWIN_HAVE_OPENGLES
 
792
        glMatrixMode(GL_MODELVIEW);
 
793
 
 
794
        glColor4f(capColor.redF(), capColor.greenF(), capColor.blueF(), cubeOpacity);
 
795
        if (texturedCaps && effects->numberOfDesktops() > 3 && capTexture) {
 
796
            // modulate the cap texture: cap color should be background for translucent pixels
 
797
            // cube opacity should be used for all pixels
 
798
            // blend with cap color
 
799
            float color[4] = { capColor.redF(), capColor.greenF(), capColor.blueF(), cubeOpacity };
 
800
            glActiveTexture(GL_TEXTURE0);
 
801
            capTexture->bind();
 
802
            glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
 
803
            glColor4fv(color);
 
804
 
 
805
            // set Opacity to cube opacity
 
806
            // TODO: change opacity during start/stop animation
 
807
            glActiveTexture(GL_TEXTURE1);
 
808
            capTexture->bind();
 
809
            glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
 
810
            glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
 
811
            glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
 
812
            glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
 
813
            glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_CONSTANT);
 
814
            glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
 
815
            glActiveTexture(GL_TEXTURE0);
 
816
            glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);
 
817
        }
 
818
#endif
 
819
    }
 
820
 
 
821
    glEnable(GL_BLEND);
 
822
    glCullFace(firstCull);
 
823
    m_cubeCapBuffer->render(GL_TRIANGLES);
 
824
 
 
825
    if (mode == Sphere) {
 
826
        capMatrix.scale(1.0, -1.0, 1.0);
 
827
    }
 
828
    capMatrix.translate(0.0, -rect.height(), 0.0);
 
829
    if (capShader) {
 
830
        m_capShader->setUniform("windowTransformation", capMatrix);
 
831
        m_capShader->setUniform("u_mirror", 0);
 
832
    } else {
 
833
#ifndef KWIN_HAVE_OPENGLES
 
834
        glMatrixMode(GL_TEXTURE);
 
835
        popMatrix();
 
836
        glMatrixMode(GL_MODELVIEW);
 
837
#endif
 
838
        popMatrix();
 
839
        pushMatrix(m_rotationMatrix * capMatrix);
 
840
    }
 
841
    glCullFace(secondCull);
 
842
    m_cubeCapBuffer->render(GL_TRIANGLES);
 
843
    glDisable(GL_BLEND);
 
844
 
 
845
    if (capShader) {
 
846
        ShaderManager::instance()->popShader();
 
847
        if (texturedCaps && effects->numberOfDesktops() > 3 && capTexture) {
 
848
            capTexture->unbind();
 
849
        }
 
850
    } else {
 
851
        popMatrix();
 
852
        if (texturedCaps && effects->numberOfDesktops() > 3 && capTexture) {
 
853
#ifndef KWIN_HAVE_OPENGLES
 
854
            glActiveTexture(GL_TEXTURE1);
 
855
            glDisable(capTexture->target());
 
856
            glActiveTexture(GL_TEXTURE0);
 
857
            glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
 
858
            glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
 
859
            capTexture->unbind();
 
860
#endif
 
861
        }
 
862
    }
 
863
}
 
864
 
 
865
void CubeEffect::paintCubeCap()
 
866
{
 
867
    QRect rect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop());
 
868
    float cubeAngle = (float)((float)(effects->numberOfDesktops() - 2) / (float)effects->numberOfDesktops() * 180.0f);
 
869
    float z = rect.width() / 2 * tan(cubeAngle * 0.5f * M_PI / 180.0f);
 
870
    float zTexture = rect.width() / 2 * tan(45.0f * M_PI / 180.0f);
 
871
    float angle = 360.0f / effects->numberOfDesktops();
 
872
    bool texture = texturedCaps && effects->numberOfDesktops() > 3 && capTexture;
 
873
    QVector<float> verts;
 
874
    QVector<float> texCoords;
 
875
    for (int i = 0; i < effects->numberOfDesktops(); i++) {
 
876
        int triangleRows = effects->numberOfDesktops() * 5;
 
877
        float zTriangleDistance = z / (float)triangleRows;
 
878
        float widthTriangle = tan(angle * 0.5 * M_PI / 180.0) * zTriangleDistance;
 
879
        float currentWidth = 0.0;
 
880
        float cosValue = cos(i * angle  * M_PI / 180.0);
 
881
        float sinValue = sin(i * angle  * M_PI / 180.0);
 
882
        for (int j = 0; j < triangleRows; j++) {
 
883
            float previousWidth = currentWidth;
 
884
            currentWidth = tan(angle * 0.5 * M_PI / 180.0) * zTriangleDistance * (j + 1);
 
885
            int evenTriangles = 0;
 
886
            int oddTriangles = 0;
 
887
            for (int k = 0; k < floor(currentWidth / widthTriangle * 2 - 1 + 0.5f); k++) {
 
888
                float x1 = -previousWidth;
 
889
                float x2 = -currentWidth;
 
890
                float x3 = 0.0;
 
891
                float z1 = 0.0;
 
892
                float z2 = 0.0;
 
893
                float z3 = 0.0;
 
894
                if (k % 2 == 0) {
 
895
                    x1 += evenTriangles * widthTriangle * 2;
 
896
                    x2 += evenTriangles * widthTriangle * 2;
 
897
                    x3 = x2 + widthTriangle * 2;
 
898
                    z1 = j * zTriangleDistance;
 
899
                    z2 = (j + 1) * zTriangleDistance;
 
900
                    z3 = (j + 1) * zTriangleDistance;
 
901
                    float xRot = cosValue * x1 - sinValue * z1;
 
902
                    float zRot = sinValue * x1 + cosValue * z1;
 
903
                    x1 = xRot;
 
904
                    z1 = zRot;
 
905
                    xRot = cosValue * x2 - sinValue * z2;
 
906
                    zRot = sinValue * x2 + cosValue * z2;
 
907
                    x2 = xRot;
 
908
                    z2 = zRot;
 
909
                    xRot = cosValue * x3 - sinValue * z3;
 
910
                    zRot = sinValue * x3 + cosValue * z3;
 
911
                    x3 = xRot;
 
912
                    z3 = zRot;
 
913
                    evenTriangles++;
 
914
                } else {
 
915
                    x1 += oddTriangles * widthTriangle * 2;
 
916
                    x2 += (oddTriangles + 1) * widthTriangle * 2;
 
917
                    x3 = x1 + widthTriangle * 2;
 
918
                    z1 = j * zTriangleDistance;
 
919
                    z2 = (j + 1) * zTriangleDistance;
 
920
                    z3 = j * zTriangleDistance;
 
921
                    float xRot = cosValue * x1 - sinValue * z1;
 
922
                    float zRot = sinValue * x1 + cosValue * z1;
 
923
                    x1 = xRot;
 
924
                    z1 = zRot;
 
925
                    xRot = cosValue * x2 - sinValue * z2;
 
926
                    zRot = sinValue * x2 + cosValue * z2;
 
927
                    x2 = xRot;
 
928
                    z2 = zRot;
 
929
                    xRot = cosValue * x3 - sinValue * z3;
 
930
                    zRot = sinValue * x3 + cosValue * z3;
 
931
                    x3 = xRot;
 
932
                    z3 = zRot;
 
933
                    oddTriangles++;
 
934
                }
 
935
                float texX1 = 0.0;
 
936
                float texX2 = 0.0;
 
937
                float texX3 = 0.0;
 
938
                float texY1 = 0.0;
 
939
                float texY2 = 0.0;
 
940
                float texY3 = 0.0;
 
941
                if (texture) {
 
942
                    texX1 = x1 / (rect.width()) + 0.5;
 
943
                    texY1 = 0.5 - z1 / zTexture * 0.5;
 
944
                    texX2 = x2 / (rect.width()) + 0.5;
 
945
                    texY2 = 0.5 - z2 / zTexture * 0.5;
 
946
                    texX3 = x3 / (rect.width()) + 0.5;
 
947
                    texY3 = 0.5 - z3 / zTexture * 0.5;
 
948
                    texCoords << texX1 << texY1;
 
949
                }
 
950
                verts << x1 << 0.0 << z1;
 
951
                if (texture) {
 
952
                    texCoords << texX2 << texY2;
 
953
                }
 
954
                verts << x2 << 0.0 << z2;
 
955
                if (texture) {
 
956
                    texCoords << texX3 << texY3;
 
957
                }
 
958
                verts << x3 << 0.0 << z3;
 
959
            }
 
960
        }
 
961
    }
 
962
    delete m_cubeCapBuffer;
 
963
    m_cubeCapBuffer = new GLVertexBuffer(GLVertexBuffer::Static);
 
964
    m_cubeCapBuffer->setData(verts.count() / 3, 3, verts.constData(), texture ? texCoords.constData() : NULL);
 
965
}
 
966
 
 
967
void CubeEffect::paintCylinderCap()
 
968
{
 
969
    QRect rect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop());
 
970
    float cubeAngle = (float)((float)(effects->numberOfDesktops() - 2) / (float)effects->numberOfDesktops() * 180.0f);
 
971
 
 
972
    float radian = (cubeAngle * 0.5) * M_PI / 180;
 
973
    float radius = (rect.width() * 0.5) * tan(radian);
 
974
    float segment = radius / 30.0f;
 
975
 
 
976
    bool texture = texturedCaps && effects->numberOfDesktops() > 3 && capTexture;
 
977
    QVector<float> verts;
 
978
    QVector<float> texCoords;
 
979
    for (int i = 1; i <= 30; i++) {
 
980
        int steps =  72;
 
981
        for (int j = 0; j <= steps; j++) {
 
982
            const float azimuthAngle = (j * (360.0f / steps)) * M_PI / 180.0f;
 
983
            const float azimuthAngle2 = ((j + 1) * (360.0f / steps)) * M_PI / 180.0f;
 
984
            const float x1 = segment * (i - 1) * sin(azimuthAngle);
 
985
            const float x2 = segment * i * sin(azimuthAngle);
 
986
            const float x3 = segment * (i - 1) * sin(azimuthAngle2);
 
987
            const float x4 = segment * i * sin(azimuthAngle2);
 
988
            const float z1 = segment * (i - 1) * cos(azimuthAngle);
 
989
            const float z2 = segment * i * cos(azimuthAngle);
 
990
            const float z3 = segment * (i - 1) * cos(azimuthAngle2);
 
991
            const float z4 = segment * i * cos(azimuthAngle2);
 
992
            if (texture) {
 
993
                texCoords << (radius + x1) / (radius * 2.0f) << 1.0f - (z1 + radius) / (radius * 2.0f);
 
994
                texCoords << (radius + x2) / (radius * 2.0f) << 1.0f - (z2 + radius) / (radius * 2.0f);
 
995
                texCoords << (radius + x3) / (radius * 2.0f) << 1.0f - (z3 + radius) / (radius * 2.0f);
 
996
                texCoords << (radius + x4) / (radius * 2.0f) << 1.0f - (z4 + radius) / (radius * 2.0f);
 
997
                texCoords << (radius + x3) / (radius * 2.0f) << 1.0f - (z3 + radius) / (radius * 2.0f);
 
998
                texCoords << (radius + x2) / (radius * 2.0f) << 1.0f - (z2 + radius) / (radius * 2.0f);
 
999
            }
 
1000
            verts << x1 << 0.0 << z1;
 
1001
            verts << x2 << 0.0 << z2;
 
1002
            verts << x3 << 0.0 << z3;
 
1003
            verts << x4 << 0.0 << z4;
 
1004
            verts << x3 << 0.0 << z3;
 
1005
            verts << x2 << 0.0 << z2;
 
1006
        }
 
1007
    }
 
1008
    delete m_cubeCapBuffer;
 
1009
    m_cubeCapBuffer = new GLVertexBuffer(GLVertexBuffer::Static);
 
1010
    m_cubeCapBuffer->setData(verts.count() / 3, 3, verts.constData(), texture ? texCoords.constData() : NULL);
 
1011
}
 
1012
 
 
1013
void CubeEffect::paintSphereCap()
 
1014
{
 
1015
    QRect rect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop());
 
1016
    float cubeAngle = (float)((float)(effects->numberOfDesktops() - 2) / (float)effects->numberOfDesktops() * 180.0f);
 
1017
    float zTexture = rect.width() / 2 * tan(45.0f * M_PI / 180.0f);
 
1018
    float radius = (rect.width() * 0.5) / cos(cubeAngle * 0.5 * M_PI / 180.0);
 
1019
    float angle = acos((rect.height() * 0.5) / radius) * 180.0 / M_PI;
 
1020
    angle /= 30;
 
1021
    bool texture = texturedCaps && effects->numberOfDesktops() > 3 && capTexture;
 
1022
    QVector<float> verts;
 
1023
    QVector<float> texCoords;
 
1024
    for (int i = 0; i < 30; i++) {
 
1025
        float topAngle = angle * i * M_PI / 180.0;
 
1026
        float bottomAngle = angle * (i + 1) * M_PI / 180.0;
 
1027
        float yTop = rect.height() * 0.5 - radius * cos(topAngle);
 
1028
        yTop -= (yTop - rect.height() * 0.5) * capDeformationFactor;
 
1029
        float yBottom = rect.height() * 0.5 - radius * cos(bottomAngle);
 
1030
        yBottom -= (yBottom - rect.height() * 0.5) * capDeformationFactor;
 
1031
        for (int j = 0; j < 36; j++) {
 
1032
            const float x1 = radius * sin(topAngle) * sin((90.0 + j * 10.0) * M_PI / 180.0);
 
1033
            const float z1 = radius * sin(topAngle) * cos((90.0 + j * 10.0) * M_PI / 180.0);
 
1034
            const float x2 = radius * sin(bottomAngle) * sin((90.0 + j * 10.0) * M_PI / 180.00);
 
1035
            const float z2 = radius * sin(bottomAngle) * cos((90.0 + j * 10.0) * M_PI / 180.0);
 
1036
            const float x3 = radius * sin(bottomAngle) * sin((90.0 + (j + 1) * 10.0) * M_PI / 180.0);
 
1037
            const float z3 = radius * sin(bottomAngle) * cos((90.0 + (j + 1) * 10.0) * M_PI / 180.0);
 
1038
            const float x4 = radius * sin(topAngle) * sin((90.0 + (j + 1) * 10.0) * M_PI / 180.0);
 
1039
            const float z4 = radius * sin(topAngle) * cos((90.0 + (j + 1) * 10.0) * M_PI / 180.0);
 
1040
            if (texture) {
 
1041
                texCoords << x4 / (rect.width()) + 0.5 << 0.5 - z4 / zTexture * 0.5;
 
1042
                texCoords << x1 / (rect.width()) + 0.5 << 0.5 - z1 / zTexture * 0.5;
 
1043
                texCoords << x2 / (rect.width()) + 0.5 << 0.5 - z2 / zTexture * 0.5;
 
1044
                texCoords << x2 / (rect.width()) + 0.5 << 0.5 - z2 / zTexture * 0.5;
 
1045
                texCoords << x3 / (rect.width()) + 0.5 << 0.5 - z3 / zTexture * 0.5;
 
1046
                texCoords << x4 / (rect.width()) + 0.5 << 0.5 - z4 / zTexture * 0.5;
 
1047
            }
 
1048
            verts << x4 << yTop    << z4;
 
1049
            verts << x1 << yTop    << z1;
 
1050
            verts << x2 << yBottom << z2;
 
1051
            verts << x2 << yBottom << z2;
 
1052
            verts << x3 << yBottom << z3;
 
1053
            verts << x4 << yTop    << z4;
 
1054
        }
 
1055
    }
 
1056
    delete m_cubeCapBuffer;
 
1057
    m_cubeCapBuffer = new GLVertexBuffer(GLVertexBuffer::Static);
 
1058
    m_cubeCapBuffer->setData(verts.count() / 3, 3, verts.constData(), texture ? texCoords.constData() : NULL);
 
1059
}
 
1060
 
 
1061
void CubeEffect::postPaintScreen()
 
1062
{
 
1063
    effects->postPaintScreen();
 
1064
    if (activated) {
 
1065
        if (start) {
 
1066
            if (timeLine.currentValue() == 1.0) {
 
1067
                start = false;
 
1068
                timeLine.setCurrentTime(0);
 
1069
                // more rotations?
 
1070
                if (!rotations.empty()) {
 
1071
                    rotationDirection = rotations.dequeue();
 
1072
                    rotating = true;
 
1073
                    // change the curve shape if current shape is not easeInOut
 
1074
                    if (currentShape != QTimeLine::EaseInOutCurve) {
 
1075
                        // more rotations follow -> linear curve
 
1076
                        if (!rotations.empty()) {
 
1077
                            currentShape = QTimeLine::LinearCurve;
 
1078
                        }
 
1079
                        // last rotation step -> easeOut curve
 
1080
                        else {
 
1081
                            currentShape = QTimeLine::EaseOutCurve;
 
1082
                        }
 
1083
                        timeLine.setCurveShape(currentShape);
 
1084
                    } else {
 
1085
                        // if there is at least one more rotation, we can change to easeIn
 
1086
                        if (!rotations.empty()) {
 
1087
                            currentShape = QTimeLine::EaseInCurve;
 
1088
                            timeLine.setCurveShape(currentShape);
 
1089
                        }
 
1090
                    }
 
1091
                }
 
1092
            }
 
1093
            effects->addRepaintFull();
 
1094
            return; // schedule_close could have been called, start has to finish first
 
1095
        }
 
1096
        if (stop) {
 
1097
            if (timeLine.currentValue() == 1.0) {
 
1098
                effects->setCurrentDesktop(frontDesktop);
 
1099
                stop = false;
 
1100
                timeLine.setCurrentTime(0);
 
1101
                activated = false;
 
1102
                // set the new desktop
 
1103
                if (keyboard_grab)
 
1104
                    effects->ungrabKeyboard();
 
1105
                keyboard_grab = false;
 
1106
                effects->destroyInputWindow(input);
 
1107
 
 
1108
                effects->setActiveFullScreenEffect(0);
 
1109
 
 
1110
                delete m_cubeCapBuffer;
 
1111
                m_cubeCapBuffer = NULL;
 
1112
                desktopNameFrame->free();
 
1113
            }
 
1114
            effects->addRepaintFull();
 
1115
        }
 
1116
        if (rotating || verticalRotating) {
 
1117
            if (rotating && timeLine.currentValue() == 1.0) {
 
1118
                timeLine.setCurrentTime(0.0);
 
1119
                rotating = false;
 
1120
                desktopChangedWhileRotating = false;
 
1121
                manualAngle = 0.0;
 
1122
                // more rotations?
 
1123
                if (!rotations.empty()) {
 
1124
                    rotationDirection = rotations.dequeue();
 
1125
                    rotating = true;
 
1126
                    // change the curve shape if current shape is not easeInOut
 
1127
                    if (currentShape != QTimeLine::EaseInOutCurve) {
 
1128
                        // more rotations follow -> linear curve
 
1129
                        if (!rotations.empty()) {
 
1130
                            currentShape = QTimeLine::LinearCurve;
 
1131
                        }
 
1132
                        // last rotation step -> easeOut curve
 
1133
                        else {
 
1134
                            currentShape = QTimeLine::EaseOutCurve;
 
1135
                        }
 
1136
                        timeLine.setCurveShape(currentShape);
 
1137
                    } else {
 
1138
                        // if there is at least one more rotation, we can change to easeIn
 
1139
                        if (!rotations.empty()) {
 
1140
                            currentShape = QTimeLine::EaseInCurve;
 
1141
                            timeLine.setCurveShape(currentShape);
 
1142
                        }
 
1143
                    }
 
1144
                } else {
 
1145
                    // reset curve shape if there are no more rotations
 
1146
                    if (currentShape != QTimeLine::EaseInOutCurve) {
 
1147
                        currentShape = QTimeLine::EaseInOutCurve;
 
1148
                        timeLine.setCurveShape(currentShape);
 
1149
                    }
 
1150
                }
 
1151
            }
 
1152
            if (verticalRotating && verticalTimeLine.currentValue() == 1.0) {
 
1153
                verticalTimeLine.setCurrentTime(0);
 
1154
                verticalRotating = false;
 
1155
                manualVerticalAngle = 0.0;
 
1156
                // more rotations?
 
1157
                if (!verticalRotations.empty()) {
 
1158
                    verticalRotationDirection = verticalRotations.dequeue();
 
1159
                    verticalRotating = true;
 
1160
                    if (verticalRotationDirection == Upwards) {
 
1161
                        if (verticalPosition == Normal)
 
1162
                            verticalPosition = Up;
 
1163
                        if (verticalPosition == Down)
 
1164
                            verticalPosition = Normal;
 
1165
                    }
 
1166
                    if (verticalRotationDirection == Downwards) {
 
1167
                        if (verticalPosition == Normal)
 
1168
                            verticalPosition = Down;
 
1169
                        if (verticalPosition == Up)
 
1170
                            verticalPosition = Normal;
 
1171
                    }
 
1172
                }
 
1173
            }
 
1174
            effects->addRepaintFull();
 
1175
            return; // rotation has to end before cube is closed
 
1176
        }
 
1177
        if (schedule_close) {
 
1178
            schedule_close = false;
 
1179
            stop = true;
 
1180
            effects->addRepaintFull();
 
1181
        }
 
1182
    }
 
1183
}
 
1184
 
 
1185
void CubeEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time)
 
1186
{
 
1187
    if (activated) {
 
1188
        if (cube_painting) {
 
1189
            if (mode == Cylinder || mode == Sphere) {
 
1190
                int leftDesktop = frontDesktop - 1;
 
1191
                int rightDesktop = frontDesktop + 1;
 
1192
                if (leftDesktop == 0)
 
1193
                    leftDesktop = effects->numberOfDesktops();
 
1194
                if (rightDesktop > effects->numberOfDesktops())
 
1195
                    rightDesktop = 1;
 
1196
                if (painting_desktop == frontDesktop)
 
1197
                    data.quads = data.quads.makeGrid(40);
 
1198
                else if (painting_desktop == leftDesktop || painting_desktop == rightDesktop)
 
1199
                    data.quads = data.quads.makeGrid(100);
 
1200
                else
 
1201
                    data.quads = data.quads.makeGrid(250);
 
1202
            }
 
1203
            if (w->isOnDesktop(painting_desktop)) {
 
1204
                QRect rect = effects->clientArea(FullArea, activeScreen, painting_desktop);
 
1205
                if (w->x() < rect.x()) {
 
1206
                    data.quads = data.quads.splitAtX(-w->x());
 
1207
                }
 
1208
                if (w->x() + w->width() > rect.x() + rect.width()) {
 
1209
                    data.quads = data.quads.splitAtX(rect.width() - w->x());
 
1210
                }
 
1211
                if (w->y() < rect.y()) {
 
1212
                    data.quads = data.quads.splitAtY(-w->y());
 
1213
                }
 
1214
                if (w->y() + w->height() > rect.y() + rect.height()) {
 
1215
                    data.quads = data.quads.splitAtY(rect.height() - w->y());
 
1216
                }
 
1217
                if (useZOrdering && !w->isDesktop() && !w->isDock() && !w->isOnAllDesktops())
 
1218
                    data.setTransformed();
 
1219
                w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
 
1220
            } else {
 
1221
                // check for windows belonging to the previous desktop
 
1222
                int prev_desktop = painting_desktop - 1;
 
1223
                if (prev_desktop == 0)
 
1224
                    prev_desktop = effects->numberOfDesktops();
 
1225
                if (w->isOnDesktop(prev_desktop) && mode == Cube && !useZOrdering) {
 
1226
                    QRect rect = effects->clientArea(FullArea, activeScreen, prev_desktop);
 
1227
                    if (w->x() + w->width() > rect.x() + rect.width()) {
 
1228
                        w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
 
1229
                        data.quads = data.quads.splitAtX(rect.width() - w->x());
 
1230
                        if (w->y() < rect.y()) {
 
1231
                            data.quads = data.quads.splitAtY(-w->y());
 
1232
                        }
 
1233
                        if (w->y() + w->height() > rect.y() + rect.height()) {
 
1234
                            data.quads = data.quads.splitAtY(rect.height() - w->y());
 
1235
                        }
 
1236
                        data.setTransformed();
 
1237
                        effects->prePaintWindow(w, data, time);
 
1238
                        return;
 
1239
                    }
 
1240
                }
 
1241
                // check for windows belonging to the next desktop
 
1242
                int next_desktop = painting_desktop + 1;
 
1243
                if (next_desktop > effects->numberOfDesktops())
 
1244
                    next_desktop = 1;
 
1245
                if (w->isOnDesktop(next_desktop) && mode == Cube && !useZOrdering) {
 
1246
                    QRect rect = effects->clientArea(FullArea, activeScreen, next_desktop);
 
1247
                    if (w->x() < rect.x()) {
 
1248
                        w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
 
1249
                        data.quads = data.quads.splitAtX(-w->x());
 
1250
                        if (w->y() < rect.y()) {
 
1251
                            data.quads = data.quads.splitAtY(-w->y());
 
1252
                        }
 
1253
                        if (w->y() + w->height() > rect.y() + rect.height()) {
 
1254
                            data.quads = data.quads.splitAtY(rect.height() - w->y());
 
1255
                        }
 
1256
                        data.setTransformed();
 
1257
                        effects->prePaintWindow(w, data, time);
 
1258
                        return;
 
1259
                    }
 
1260
                }
 
1261
                w->disablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
 
1262
            }
 
1263
        }
 
1264
    }
 
1265
    effects->prePaintWindow(w, data, time);
 
1266
}
 
1267
 
 
1268
void CubeEffect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data)
 
1269
{
 
1270
    ShaderManager *shaderManager = ShaderManager::instance();
 
1271
    GLShader *shader = shaderManager->pushShader(ShaderManager::GenericShader);
 
1272
    QMatrix4x4 origMatrix;
 
1273
    if (activated && cube_painting) {
 
1274
        //kDebug(1212) << w->caption();
 
1275
        float opacity = cubeOpacity;
 
1276
        if (start) {
 
1277
            opacity = 1.0 - (1.0 - opacity) * timeLine.currentValue();
 
1278
            if (reflectionPainting)
 
1279
                opacity = 0.5 + (cubeOpacity - 0.5) * timeLine.currentValue();
 
1280
            // fade in windows belonging to different desktops
 
1281
            if (painting_desktop == effects->currentDesktop() && (!w->isOnDesktop(painting_desktop)))
 
1282
                opacity = timeLine.currentValue() * cubeOpacity;
 
1283
        }
 
1284
        if (stop) {
 
1285
            opacity = 1.0 - (1.0 - opacity) * (1.0 - timeLine.currentValue());
 
1286
            if (reflectionPainting)
 
1287
                opacity = 0.5 + (cubeOpacity - 0.5) * (1.0 - timeLine.currentValue());
 
1288
            // fade out windows belonging to different desktops
 
1289
            if (painting_desktop == effects->currentDesktop() && (!w->isOnDesktop(painting_desktop)))
 
1290
                opacity = cubeOpacity * (1.0 - timeLine.currentValue());
 
1291
        }
 
1292
        // z-Ordering
 
1293
        if (!w->isDesktop() && !w->isDock() && useZOrdering && !w->isOnAllDesktops()) {
 
1294
            float zOrdering = (effects->stackingOrder().indexOf(w) + 1) * zOrderingFactor;
 
1295
            if (start)
 
1296
                zOrdering *= timeLine.currentValue();
 
1297
            if (stop)
 
1298
                zOrdering *= (1.0 - timeLine.currentValue());
 
1299
            data.zTranslate += zOrdering;
 
1300
        }
 
1301
        // check for windows belonging to the previous desktop
 
1302
        int prev_desktop = painting_desktop - 1;
 
1303
        if (prev_desktop == 0)
 
1304
            prev_desktop = effects->numberOfDesktops();
 
1305
        int next_desktop = painting_desktop + 1;
 
1306
        if (next_desktop > effects->numberOfDesktops())
 
1307
            next_desktop = 1;
 
1308
        if (!shader) {
 
1309
            pushMatrix();
 
1310
        }
 
1311
        if (w->isOnDesktop(prev_desktop) && (mask & PAINT_WINDOW_TRANSFORMED)) {
 
1312
            QRect rect = effects->clientArea(FullArea, activeScreen, prev_desktop);
 
1313
            WindowQuadList new_quads;
 
1314
            foreach (const WindowQuad & quad, data.quads) {
 
1315
                if (quad.right() > rect.width() - w->x()) {
 
1316
                    new_quads.append(quad);
 
1317
                }
 
1318
            }
 
1319
            data.quads = new_quads;
 
1320
            if (shader) {
 
1321
                data.xTranslate = -rect.width();
 
1322
            } else {
 
1323
                RotationData rot = RotationData();
 
1324
                rot.axis = RotationData::YAxis;
 
1325
                rot.xRotationPoint = rect.width() - w->x();
 
1326
                rot.angle = 360.0f / effects->numberOfDesktops();
 
1327
                data.rotation = &rot;
 
1328
                float cubeAngle = (float)((float)(effects->numberOfDesktops() - 2) / (float)effects->numberOfDesktops() * 180.0f);
 
1329
                float point = rect.width() / 2 * tan(cubeAngle * 0.5f * M_PI / 180.0f);
 
1330
                QMatrix4x4 matrix;
 
1331
                matrix.translate(rect.width() / 2, 0.0, -point);
 
1332
                matrix.rotate(-360.0f / effects->numberOfDesktops(), 0.0, 1.0, 0.0);
 
1333
                matrix.translate(-rect.width() / 2, 0.0, point);
 
1334
                multiplyMatrix(matrix);
 
1335
            }
 
1336
        }
 
1337
        if (w->isOnDesktop(next_desktop) && (mask & PAINT_WINDOW_TRANSFORMED)) {
 
1338
            QRect rect = effects->clientArea(FullArea, activeScreen, next_desktop);
 
1339
            WindowQuadList new_quads;
 
1340
            foreach (const WindowQuad & quad, data.quads) {
 
1341
                if (w->x() + quad.right() <= rect.x()) {
 
1342
                    new_quads.append(quad);
 
1343
                }
 
1344
            }
 
1345
            data.quads = new_quads;
 
1346
            if (shader) {
 
1347
                data.xTranslate = rect.width();
 
1348
            } else {
 
1349
                RotationData rot = RotationData();
 
1350
                rot.axis = RotationData::YAxis;
 
1351
                rot.xRotationPoint = -w->x();
 
1352
                rot.angle = -360.0f / effects->numberOfDesktops();
 
1353
                data.rotation = &rot;
 
1354
                float cubeAngle = (float)((float)(effects->numberOfDesktops() - 2) / (float)effects->numberOfDesktops() * 180.0f);
 
1355
                float point = rect.width() / 2 * tan(cubeAngle * 0.5f * M_PI / 180.0f);
 
1356
                QMatrix4x4 matrix;
 
1357
                matrix.translate(rect.width() / 2, 0.0, -point);
 
1358
                matrix.rotate(360.0f / effects->numberOfDesktops(), 0.0, 1.0, 0.0);
 
1359
                matrix.translate(-rect.width() / 2, 0.0, point);
 
1360
                multiplyMatrix(matrix);
 
1361
            }
 
1362
        }
 
1363
        QRect rect = effects->clientArea(FullArea, activeScreen, painting_desktop);
 
1364
 
 
1365
        if (start || stop) {
 
1366
            // we have to change opacity values for fade in/out of windows which are shown on front-desktop
 
1367
            if (prev_desktop == effects->currentDesktop() && w->x() < rect.x()) {
 
1368
                if (start)
 
1369
                    opacity = timeLine.currentValue() * cubeOpacity;
 
1370
                if (stop)
 
1371
                    opacity = cubeOpacity * (1.0 - timeLine.currentValue());
 
1372
            }
 
1373
            if (next_desktop == effects->currentDesktop() && w->x() + w->width() > rect.x() + rect.width()) {
 
1374
                if (start)
 
1375
                    opacity = timeLine.currentValue() * cubeOpacity;
 
1376
                if (stop)
 
1377
                    opacity = cubeOpacity * (1.0 - timeLine.currentValue());
 
1378
            }
 
1379
        }
 
1380
        // HACK set opacity to 0.99 in case of fully opaque to ensure that windows are painted in correct sequence
 
1381
        // bug #173214
 
1382
        if (opacity > 0.99f)
 
1383
            opacity = 0.99f;
 
1384
        if (opacityDesktopOnly && !w->isDesktop())
 
1385
            opacity = 0.99f;
 
1386
        data.opacity *= opacity;
 
1387
 
 
1388
        if (w->isOnDesktop(painting_desktop) && w->x() < rect.x()) {
 
1389
            WindowQuadList new_quads;
 
1390
            foreach (const WindowQuad & quad, data.quads) {
 
1391
                if (quad.right() > -w->x()) {
 
1392
                    new_quads.append(quad);
 
1393
                }
 
1394
            }
 
1395
            data.quads = new_quads;
 
1396
        }
 
1397
        if (w->isOnDesktop(painting_desktop) && w->x() + w->width() > rect.x() + rect.width()) {
 
1398
            WindowQuadList new_quads;
 
1399
            foreach (const WindowQuad & quad, data.quads) {
 
1400
                if (quad.right() <= rect.width() - w->x()) {
 
1401
                    new_quads.append(quad);
 
1402
                }
 
1403
            }
 
1404
            data.quads = new_quads;
 
1405
        }
 
1406
        if (w->y() < rect.y()) {
 
1407
            WindowQuadList new_quads;
 
1408
            foreach (const WindowQuad & quad, data.quads) {
 
1409
                if (quad.bottom() > -w->y()) {
 
1410
                    new_quads.append(quad);
 
1411
                }
 
1412
            }
 
1413
            data.quads = new_quads;
 
1414
        }
 
1415
        if (w->y() + w->height() > rect.y() + rect.height()) {
 
1416
            WindowQuadList new_quads;
 
1417
            foreach (const WindowQuad & quad, data.quads) {
 
1418
                if (quad.bottom() <= rect.height() - w->y()) {
 
1419
                    new_quads.append(quad);
 
1420
                }
 
1421
            }
 
1422
            data.quads = new_quads;
 
1423
        }
 
1424
        if (shader) {
 
1425
            origMatrix = shader->getUniformMatrix4x4("screenTransformation");
 
1426
            GLShader *currentShader = shader;
 
1427
            if (mode == Cylinder) {
 
1428
                shaderManager->pushShader(cylinderShader);
 
1429
                cylinderShader->setUniform("xCoord", (float)w->x());
 
1430
                cylinderShader->setUniform("cubeAngle", (effects->numberOfDesktops() - 2) / (float)effects->numberOfDesktops() * 90.0f);
 
1431
                float factor = 0.0f;
 
1432
                if (start)
 
1433
                    factor = 1.0f - timeLine.currentValue();
 
1434
                if (stop)
 
1435
                    factor = timeLine.currentValue();
 
1436
                cylinderShader->setUniform("timeLine", factor);
 
1437
                data.shader = cylinderShader;
 
1438
                currentShader = cylinderShader;
 
1439
            }
 
1440
            if (mode == Sphere) {
 
1441
                shaderManager->pushShader(sphereShader);
 
1442
                sphereShader->setUniform("u_offset", QVector2D(w->x(), w->y()));
 
1443
                sphereShader->setUniform("cubeAngle", (effects->numberOfDesktops() - 2) / (float)effects->numberOfDesktops() * 90.0f);
 
1444
                float factor = 0.0f;
 
1445
                if (start)
 
1446
                    factor = 1.0f - timeLine.currentValue();
 
1447
                if (stop)
 
1448
                    factor = timeLine.currentValue();
 
1449
                sphereShader->setUniform("timeLine", factor);
 
1450
                data.shader = sphereShader;
 
1451
                currentShader = sphereShader;
 
1452
            }
 
1453
            if (reflectionPainting) {
 
1454
                currentShader->setUniform("screenTransformation", m_reflectionMatrix * m_rotationMatrix * origMatrix);
 
1455
            } else {
 
1456
                currentShader->setUniform("screenTransformation", m_rotationMatrix*origMatrix);
 
1457
            }
 
1458
        }
 
1459
    }
 
1460
    effects->paintWindow(w, mask, region, data);
 
1461
    if (activated && cube_painting) {
 
1462
        if (shader) {
 
1463
            if (mode == Cylinder || mode == Sphere) {
 
1464
                shaderManager->popShader();
 
1465
            } else {
 
1466
                shader->setUniform("screenTransformation", origMatrix);
 
1467
            }
 
1468
            shaderManager->popShader();
 
1469
        }
 
1470
        if (w->isDesktop() && effects->numScreens() > 1 && paintCaps) {
 
1471
            QRect rect = effects->clientArea(FullArea, activeScreen, painting_desktop);
 
1472
            QRegion paint = QRegion(rect);
 
1473
            for (int i = 0; i < effects->numScreens(); i++) {
 
1474
                if (i == w->screen())
 
1475
                    continue;
 
1476
                paint = paint.subtracted(QRegion(effects->clientArea(ScreenArea, i, painting_desktop)));
 
1477
            }
 
1478
            paint = paint.subtracted(QRegion(w->geometry()));
 
1479
            // in case of free area in multiscreen setup fill it with cap color
 
1480
            if (!paint.isEmpty()) {
 
1481
#ifndef KWIN_HAVE_OPENGLES
 
1482
                glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT);
 
1483
#endif
 
1484
                glEnable(GL_BLEND);
 
1485
                glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
1486
                QVector<float> verts;
 
1487
                float quadSize = 0.0f;
 
1488
                int leftDesktop = frontDesktop - 1;
 
1489
                int rightDesktop = frontDesktop + 1;
 
1490
                if (leftDesktop == 0)
 
1491
                    leftDesktop = effects->numberOfDesktops();
 
1492
                if (rightDesktop > effects->numberOfDesktops())
 
1493
                    rightDesktop = 1;
 
1494
                if (painting_desktop == frontDesktop)
 
1495
                    quadSize = 100.0f;
 
1496
                else if (painting_desktop == leftDesktop || painting_desktop == rightDesktop)
 
1497
                    quadSize = 150.0f;
 
1498
                else
 
1499
                    quadSize = 250.0f;
 
1500
                foreach (const QRect & paintRect, paint.rects()) {
 
1501
                    for (int i = 0; i <= (paintRect.height() / quadSize); i++) {
 
1502
                        for (int j = 0; j <= (paintRect.width() / quadSize); j++) {
 
1503
                            verts << qMin(paintRect.x() + (j + 1)*quadSize, (float)paintRect.x() + paintRect.width()) << paintRect.y() + i*quadSize;
 
1504
                            verts << paintRect.x() + j*quadSize << paintRect.y() + i*quadSize;
 
1505
                            verts << paintRect.x() + j*quadSize << qMin(paintRect.y() + (i + 1)*quadSize, (float)paintRect.y() + paintRect.height());
 
1506
                            verts << paintRect.x() + j*quadSize << qMin(paintRect.y() + (i + 1)*quadSize, (float)paintRect.y() + paintRect.height());
 
1507
                            verts << qMin(paintRect.x() + (j + 1)*quadSize, (float)paintRect.x() + paintRect.width()) << qMin(paintRect.y() + (i + 1)*quadSize, (float)paintRect.y() + paintRect.height());
 
1508
                            verts << qMin(paintRect.x() + (j + 1)*quadSize, (float)paintRect.x() + paintRect.width()) << paintRect.y() + i*quadSize;
 
1509
                        }
 
1510
                    }
 
1511
                }
 
1512
                bool capShader = false;
 
1513
                if (ShaderManager::instance()->isValid() && m_capShader->isValid()) {
 
1514
                    capShader = true;
 
1515
                    ShaderManager::instance()->pushShader(m_capShader);
 
1516
                    m_capShader->setUniform("u_mirror", 0);
 
1517
                    m_capShader->setUniform("u_untextured", 1);
 
1518
                    if (reflectionPainting) {
 
1519
                        m_capShader->setUniform("screenTransformation", m_reflectionMatrix * m_rotationMatrix * origMatrix);
 
1520
                    } else {
 
1521
                        m_capShader->setUniform("screenTransformation", m_rotationMatrix * origMatrix);
 
1522
                    }
 
1523
                    m_capShader->setUniform("windowTransformation", QMatrix4x4());
 
1524
                }
 
1525
                GLVertexBuffer *vbo = GLVertexBuffer::streamingBuffer();
 
1526
                vbo->reset();
 
1527
                QColor color = capColor;
 
1528
                capColor.setAlphaF(cubeOpacity);
 
1529
                vbo->setColor(color);
 
1530
                vbo->setData(verts.size() / 2, 2, verts.constData(), NULL);
 
1531
                if (!capShader || mode == Cube) {
 
1532
                    // TODO: use sphere and cylinder shaders
 
1533
                    vbo->render(GL_TRIANGLES);
 
1534
                }
 
1535
                if (capShader) {
 
1536
                    ShaderManager::instance()->popShader();
 
1537
                }
 
1538
                glDisable(GL_BLEND);
 
1539
#ifndef KWIN_HAVE_OPENGLES
 
1540
                glPopAttrib();
 
1541
#endif
 
1542
            }
 
1543
        }
 
1544
        if (!shader) {
 
1545
            popMatrix();
 
1546
        }
 
1547
    }
 
1548
}
 
1549
 
 
1550
bool CubeEffect::borderActivated(ElectricBorder border)
 
1551
{
 
1552
    if (!borderActivate.contains(border) &&
 
1553
            !borderActivateCylinder.contains(border) &&
 
1554
            !borderActivateSphere.contains(border))
 
1555
        return false;
 
1556
    if (effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this)
 
1557
        return false;
 
1558
    if (borderActivate.contains(border)) {
 
1559
        if (!activated || (activated && mode == Cube))
 
1560
            toggleCube();
 
1561
        else
 
1562
            return false;
 
1563
    }
 
1564
    if (borderActivateCylinder.contains(border)) {
 
1565
        if (!activated || (activated && mode == Cylinder))
 
1566
            toggleCylinder();
 
1567
        else
 
1568
            return false;
 
1569
    }
 
1570
    if (borderActivateSphere.contains(border)) {
 
1571
        if (!activated || (activated && mode == Sphere))
 
1572
            toggleSphere();
 
1573
        else
 
1574
            return false;
 
1575
    }
 
1576
    return true;
 
1577
}
 
1578
 
 
1579
void CubeEffect::toggleCube()
 
1580
{
 
1581
    kDebug(1212) << "toggle cube";
 
1582
    toggle(Cube);
 
1583
}
 
1584
 
 
1585
void CubeEffect::toggleCylinder()
 
1586
{
 
1587
    kDebug(1212) << "toggle cylinder";
 
1588
    if (!useShaders)
 
1589
        useShaders = loadShader();
 
1590
    if (useShaders)
 
1591
        toggle(Cylinder);
 
1592
    else
 
1593
        kError(1212) << "Sorry shaders are not available - cannot activate Cylinder";
 
1594
}
 
1595
 
 
1596
void CubeEffect::toggleSphere()
 
1597
{
 
1598
    kDebug(1212) << "toggle sphere";
 
1599
    if (!useShaders)
 
1600
        useShaders = loadShader();
 
1601
    if (useShaders)
 
1602
        toggle(Sphere);
 
1603
    else
 
1604
        kError(1212) << "Sorry shaders are not available - cannot activate Sphere";
 
1605
}
 
1606
 
 
1607
void CubeEffect::toggle(CubeMode newMode)
 
1608
{
 
1609
    if ((effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this) ||
 
1610
            effects->numberOfDesktops() < 2)
 
1611
        return;
 
1612
    if (!activated) {
 
1613
        mode = newMode;
 
1614
        setActive(true);
 
1615
    } else {
 
1616
        setActive(false);
 
1617
    }
 
1618
}
 
1619
 
 
1620
void CubeEffect::grabbedKeyboardEvent(QKeyEvent* e)
 
1621
{
 
1622
    if (stop)
 
1623
        return;
 
1624
    // taken from desktopgrid.cpp
 
1625
    if (e->type() == QEvent::KeyPress) {
 
1626
        // check for global shortcuts
 
1627
        // HACK: keyboard grab disables the global shortcuts so we have to check for global shortcut (bug 156155)
 
1628
        if (mode == Cube && cubeShortcut.contains(e->key() + e->modifiers())) {
 
1629
            toggleCube();
 
1630
            return;
 
1631
        }
 
1632
        if (mode == Cylinder && cylinderShortcut.contains(e->key() + e->modifiers())) {
 
1633
            toggleCylinder();
 
1634
            return;
 
1635
        }
 
1636
        if (mode == Sphere && sphereShortcut.contains(e->key() + e->modifiers())) {
 
1637
            toggleSphere();
 
1638
            return;
 
1639
        }
 
1640
 
 
1641
        int desktop = -1;
 
1642
        // switch by F<number> or just <number>
 
1643
        if (e->key() >= Qt::Key_F1 && e->key() <= Qt::Key_F35)
 
1644
            desktop = e->key() - Qt::Key_F1 + 1;
 
1645
        else if (e->key() >= Qt::Key_0 && e->key() <= Qt::Key_9)
 
1646
            desktop = e->key() == Qt::Key_0 ? 10 : e->key() - Qt::Key_0;
 
1647
        if (desktop != -1) {
 
1648
            if (desktop <= effects->numberOfDesktops()) {
 
1649
                // we have to rotate to chosen desktop
 
1650
                // and end effect when rotation finished
 
1651
                rotateToDesktop(desktop);
 
1652
                setActive(false);
 
1653
            }
 
1654
            return;
 
1655
        }
 
1656
        switch(e->key()) {
 
1657
            // wrap only on autorepeat
 
1658
        case Qt::Key_Left:
 
1659
            // rotate to previous desktop
 
1660
            kDebug(1212) << "left";
 
1661
            if (!rotating && !start) {
 
1662
                rotating = true;
 
1663
                if (invertKeys)
 
1664
                    rotationDirection = Right;
 
1665
                else
 
1666
                    rotationDirection = Left;
 
1667
            } else {
 
1668
                if (rotations.count() < effects->numberOfDesktops()) {
 
1669
                    if (invertKeys)
 
1670
                        rotations.enqueue(Right);
 
1671
                    else
 
1672
                        rotations.enqueue(Left);
 
1673
                }
 
1674
            }
 
1675
            break;
 
1676
        case Qt::Key_Right:
 
1677
            // rotate to next desktop
 
1678
            kDebug(1212) << "right";
 
1679
            if (!rotating && !start) {
 
1680
                rotating = true;
 
1681
                if (invertKeys)
 
1682
                    rotationDirection = Left;
 
1683
                else
 
1684
                    rotationDirection = Right;
 
1685
            } else {
 
1686
                if (rotations.count() < effects->numberOfDesktops()) {
 
1687
                    if (invertKeys)
 
1688
                        rotations.enqueue(Left);
 
1689
                    else
 
1690
                        rotations.enqueue(Right);
 
1691
                }
 
1692
            }
 
1693
            break;
 
1694
        case Qt::Key_Up:
 
1695
            kDebug(1212) << "up";
 
1696
            if (invertKeys) {
 
1697
                if (verticalPosition != Down) {
 
1698
                    if (!verticalRotating) {
 
1699
                        verticalRotating = true;
 
1700
                        verticalRotationDirection = Downwards;
 
1701
                        if (verticalPosition == Normal)
 
1702
                            verticalPosition = Down;
 
1703
                        if (verticalPosition == Up)
 
1704
                            verticalPosition = Normal;
 
1705
                    } else {
 
1706
                        verticalRotations.enqueue(Downwards);
 
1707
                    }
 
1708
                } else if (manualVerticalAngle > 0.0 && !verticalRotating) {
 
1709
                    // rotate to down position from the manual position
 
1710
                    verticalRotating = true;
 
1711
                    verticalRotationDirection = Downwards;
 
1712
                    verticalPosition = Down;
 
1713
                    manualVerticalAngle -= 90.0;
 
1714
                }
 
1715
            } else {
 
1716
                if (verticalPosition != Up) {
 
1717
                    if (!verticalRotating) {
 
1718
                        verticalRotating = true;
 
1719
                        verticalRotationDirection = Upwards;
 
1720
                        if (verticalPosition == Normal)
 
1721
                            verticalPosition = Up;
 
1722
                        if (verticalPosition == Down)
 
1723
                            verticalPosition = Normal;
 
1724
                    } else {
 
1725
                        verticalRotations.enqueue(Upwards);
 
1726
                    }
 
1727
                } else if (manualVerticalAngle < 0.0 && !verticalRotating) {
 
1728
                    // rotate to up position from the manual position
 
1729
                    verticalRotating = true;
 
1730
                    verticalRotationDirection = Upwards;
 
1731
                    verticalPosition = Up;
 
1732
                    manualVerticalAngle += 90.0;
 
1733
                }
 
1734
            }
 
1735
            break;
 
1736
        case Qt::Key_Down:
 
1737
            kDebug(1212) << "down";
 
1738
            if (invertKeys) {
 
1739
                if (verticalPosition != Up) {
 
1740
                    if (!verticalRotating) {
 
1741
                        verticalRotating = true;
 
1742
                        verticalRotationDirection = Upwards;
 
1743
                        if (verticalPosition == Normal)
 
1744
                            verticalPosition = Up;
 
1745
                        if (verticalPosition == Down)
 
1746
                            verticalPosition = Normal;
 
1747
                    } else {
 
1748
                        verticalRotations.enqueue(Upwards);
 
1749
                    }
 
1750
                } else if (manualVerticalAngle < 0.0 && !verticalRotating) {
 
1751
                    // rotate to up position from the manual position
 
1752
                    verticalRotating = true;
 
1753
                    verticalRotationDirection = Upwards;
 
1754
                    verticalPosition = Up;
 
1755
                    manualVerticalAngle += 90.0;
 
1756
                }
 
1757
            } else {
 
1758
                if (verticalPosition != Down) {
 
1759
                    if (!verticalRotating) {
 
1760
                        verticalRotating = true;
 
1761
                        verticalRotationDirection = Downwards;
 
1762
                        if (verticalPosition == Normal)
 
1763
                            verticalPosition = Down;
 
1764
                        if (verticalPosition == Up)
 
1765
                            verticalPosition = Normal;
 
1766
                    } else {
 
1767
                        verticalRotations.enqueue(Downwards);
 
1768
                    }
 
1769
                } else if (manualVerticalAngle > 0.0 && !verticalRotating) {
 
1770
                    // rotate to down position from the manual position
 
1771
                    verticalRotating = true;
 
1772
                    verticalRotationDirection = Downwards;
 
1773
                    verticalPosition = Down;
 
1774
                    manualVerticalAngle -= 90.0;
 
1775
                }
 
1776
            }
 
1777
            break;
 
1778
        case Qt::Key_Escape:
 
1779
            rotateToDesktop(effects->currentDesktop());
 
1780
            setActive(false);
 
1781
            return;
 
1782
        case Qt::Key_Enter:
 
1783
        case Qt::Key_Return:
 
1784
        case Qt::Key_Space:
 
1785
            setActive(false);
 
1786
            return;
 
1787
        case Qt::Key_Plus:
 
1788
            zoom -= 10.0;
 
1789
            zoom = qMax(-zPosition, zoom);
 
1790
            rotateCube();
 
1791
            break;
 
1792
        case Qt::Key_Minus:
 
1793
            zoom += 10.0f;
 
1794
            rotateCube();
 
1795
            break;
 
1796
        default:
 
1797
            break;
 
1798
        }
 
1799
        effects->addRepaintFull();
 
1800
    }
 
1801
}
 
1802
 
 
1803
void CubeEffect::rotateToDesktop(int desktop)
 
1804
{
 
1805
    int tempFrontDesktop = frontDesktop;
 
1806
    if (!rotations.empty()) {
 
1807
        // all scheduled rotations will be removed as a speed up
 
1808
        rotations.clear();
 
1809
    }
 
1810
    if (rotating && !desktopChangedWhileRotating) {
 
1811
        // front desktop will change during the actual rotation - this has to be considered
 
1812
        if (rotationDirection == Left) {
 
1813
            tempFrontDesktop++;
 
1814
        } else if (rotationDirection == Right) {
 
1815
            tempFrontDesktop--;
 
1816
        }
 
1817
        if (tempFrontDesktop > effects->numberOfDesktops())
 
1818
            tempFrontDesktop = 1;
 
1819
        else if (tempFrontDesktop == 0)
 
1820
            tempFrontDesktop = effects->numberOfDesktops();
 
1821
    }
 
1822
    // find the fastest rotation path from tempFrontDesktop to desktop
 
1823
    int rightRotations = tempFrontDesktop - desktop;
 
1824
    if (rightRotations < 0)
 
1825
        rightRotations += effects->numberOfDesktops();
 
1826
    int leftRotations = desktop - tempFrontDesktop;
 
1827
    if (leftRotations < 0)
 
1828
        leftRotations += effects->numberOfDesktops();
 
1829
    if (leftRotations <= rightRotations) {
 
1830
        for (int i = 0; i < leftRotations; i++) {
 
1831
            rotations.enqueue(Left);
 
1832
        }
 
1833
    } else {
 
1834
        for (int i = 0; i < rightRotations; i++) {
 
1835
            rotations.enqueue(Right);
 
1836
        }
 
1837
    }
 
1838
    if (!start && !rotating && !rotations.empty()) {
 
1839
        rotating = true;
 
1840
        rotationDirection = rotations.dequeue();
 
1841
    }
 
1842
    // change timeline curve if more rotations are following
 
1843
    if (!rotations.empty()) {
 
1844
        currentShape = QTimeLine::EaseInCurve;
 
1845
        timeLine.setCurveShape(currentShape);
 
1846
    }
 
1847
}
 
1848
 
 
1849
void CubeEffect::setActive(bool active)
 
1850
{
 
1851
    foreach (CubeInsideEffect * inside, m_cubeInsideEffects) {
 
1852
        inside->setActive(true);
 
1853
    }
 
1854
    if (active) {
 
1855
        if (!mousePolling) {
 
1856
            effects->startMousePolling();
 
1857
            mousePolling = true;
 
1858
        }
 
1859
        activated = true;
 
1860
        activeScreen = effects->activeScreen();
 
1861
        keyboard_grab = effects->grabKeyboard(this);
 
1862
        input = effects->createInputWindow(this, 0, 0, displayWidth(), displayHeight(),
 
1863
                                           Qt::OpenHandCursor);
 
1864
        frontDesktop = effects->currentDesktop();
 
1865
        zoom = 0.0;
 
1866
        zOrderingFactor = zPosition / (effects->stackingOrder().count() - 1);
 
1867
        start = true;
 
1868
        effects->setActiveFullScreenEffect(this);
 
1869
        kDebug(1212) << "Cube is activated";
 
1870
        verticalPosition = Normal;
 
1871
        verticalRotating = false;
 
1872
        manualAngle = 0.0;
 
1873
        manualVerticalAngle = 0.0;
 
1874
        if (reflection) {
 
1875
            QRect rect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop());
 
1876
#ifndef KWIN_HAVE_OPENGLES
 
1877
            // clip parts above the reflection area
 
1878
            double eqn[4] = {0.0, 1.0, 0.0, 0.0};
 
1879
            glPushMatrix();
 
1880
            glTranslatef(0.0, rect.height(), 0.0);
 
1881
            glClipPlane(GL_CLIP_PLANE0, eqn);
 
1882
            glPopMatrix();
 
1883
#endif
 
1884
            float temporaryCoeff = float(rect.width()) / tan(M_PI / float(effects->numberOfDesktops()));
 
1885
            mAddedHeightCoeff1 = sqrt(float(rect.height()) * float(rect.height()) + temporaryCoeff * temporaryCoeff);
 
1886
            mAddedHeightCoeff2 = sqrt(float(rect.height()) * float(rect.height()) + float(rect.width()) * float(rect.width()) + temporaryCoeff * temporaryCoeff);
 
1887
        }
 
1888
        m_rotationMatrix.setToIdentity();
 
1889
        effects->addRepaintFull();
 
1890
    } else {
 
1891
        if (mousePolling) {
 
1892
            effects->stopMousePolling();
 
1893
            mousePolling = false;
 
1894
        }
 
1895
        schedule_close = true;
 
1896
        // we have to add a repaint, to start the deactivating
 
1897
        effects->addRepaintFull();
 
1898
    }
 
1899
}
 
1900
 
 
1901
void CubeEffect::slotMouseChanged(const QPoint& pos, const QPoint& oldpos, Qt::MouseButtons buttons,
 
1902
                              Qt::MouseButtons oldbuttons, Qt::KeyboardModifiers, Qt::KeyboardModifiers)
 
1903
{
 
1904
    if (!activated)
 
1905
        return;
 
1906
    if (tabBoxMode)
 
1907
        return;
 
1908
    if (stop)
 
1909
        return;
 
1910
    QRect rect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop());
 
1911
    if (buttons.testFlag(Qt::LeftButton)) {
 
1912
        bool repaint = false;
 
1913
        // vertical movement only if there is not a rotation
 
1914
        if (!verticalRotating) {
 
1915
            // display height corresponds to 180*
 
1916
            int deltaY = pos.y() - oldpos.y();
 
1917
            float deltaVerticalDegrees = (float)deltaY / rect.height() * 180.0f;
 
1918
            if (invertMouse)
 
1919
                manualVerticalAngle += deltaVerticalDegrees;
 
1920
            else
 
1921
                manualVerticalAngle -= deltaVerticalDegrees;
 
1922
            if (deltaVerticalDegrees != 0.0)
 
1923
                repaint = true;
 
1924
        }
 
1925
        // horizontal movement only if there is not a rotation
 
1926
        if (!rotating) {
 
1927
            // display width corresponds to sum of angles of the polyhedron
 
1928
            int deltaX = oldpos.x() - pos.x();
 
1929
            float deltaDegrees = (float)deltaX / rect.width() * 360.0f;
 
1930
            if (deltaX == 0) {
 
1931
                if (pos.x() == 0)
 
1932
                    deltaDegrees = 5.0f;
 
1933
                if (pos.x() == displayWidth() - 1)
 
1934
                    deltaDegrees = -5.0f;
 
1935
            }
 
1936
            if (invertMouse)
 
1937
                manualAngle += deltaDegrees;
 
1938
            else
 
1939
                manualAngle -= deltaDegrees;
 
1940
            if (deltaDegrees != 0.0)
 
1941
                repaint = true;
 
1942
        }
 
1943
        if (repaint) {
 
1944
            rotateCube();
 
1945
            effects->addRepaintFull();
 
1946
        }
 
1947
    }
 
1948
    if (!oldbuttons.testFlag(Qt::LeftButton) && buttons.testFlag(Qt::LeftButton)) {
 
1949
        XDefineCursor(display(), input, QCursor(Qt::ClosedHandCursor).handle());
 
1950
    }
 
1951
    if (oldbuttons.testFlag(Qt::LeftButton) && !buttons.testFlag(Qt::LeftButton)) {
 
1952
        XDefineCursor(display(), input, QCursor(Qt::OpenHandCursor).handle());
 
1953
        if (closeOnMouseRelease)
 
1954
            setActive(false);
 
1955
    }
 
1956
    if (oldbuttons.testFlag(Qt::RightButton) && !buttons.testFlag(Qt::RightButton)) {
 
1957
        // end effect on right mouse button
 
1958
        setActive(false);
 
1959
    }
 
1960
}
 
1961
 
 
1962
void CubeEffect::windowInputMouseEvent(Window w, QEvent* e)
 
1963
{
 
1964
    assert(w == input);
 
1965
    Q_UNUSED(w);
 
1966
    QMouseEvent *mouse = dynamic_cast< QMouseEvent* >(e);
 
1967
    if (mouse && mouse->type() == QEvent::MouseButtonRelease) {
 
1968
        if (mouse->button() == Qt::XButton1) {
 
1969
            if (!rotating && !start) {
 
1970
                rotating = true;
 
1971
                if (invertMouse)
 
1972
                    rotationDirection = Right;
 
1973
                else
 
1974
                    rotationDirection = Left;
 
1975
            } else {
 
1976
                if (rotations.count() < effects->numberOfDesktops()) {
 
1977
                    if (invertMouse)
 
1978
                        rotations.enqueue(Right);
 
1979
                    else
 
1980
                        rotations.enqueue(Left);
 
1981
                }
 
1982
            }
 
1983
            effects->addRepaintFull();
 
1984
        }
 
1985
        if (mouse->button() == Qt::XButton2) {
 
1986
            if (!rotating && !start) {
 
1987
                rotating = true;
 
1988
                if (invertMouse)
 
1989
                    rotationDirection = Left;
 
1990
                else
 
1991
                    rotationDirection = Right;
 
1992
            } else {
 
1993
                if (rotations.count() < effects->numberOfDesktops()) {
 
1994
                    if (invertMouse)
 
1995
                        rotations.enqueue(Left);
 
1996
                    else
 
1997
                        rotations.enqueue(Right);
 
1998
                }
 
1999
            }
 
2000
            effects->addRepaintFull();
 
2001
        }
 
2002
    }
 
2003
}
 
2004
 
 
2005
void CubeEffect::slotTabBoxAdded(int mode)
 
2006
{
 
2007
    if (activated)
 
2008
        return;
 
2009
    if (effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this)
 
2010
        return;
 
2011
    if (useForTabBox && mode == TabBoxDesktopListMode) {
 
2012
        effects->refTabBox();
 
2013
        tabBoxMode = true;
 
2014
        setActive(true);
 
2015
        rotateToDesktop(effects->currentTabBoxDesktop());
 
2016
    }
 
2017
}
 
2018
 
 
2019
void CubeEffect::slotTabBoxUpdated()
 
2020
{
 
2021
    if (activated) {
 
2022
        rotateToDesktop(effects->currentTabBoxDesktop());
 
2023
        effects->addRepaintFull();
 
2024
    }
 
2025
}
 
2026
 
 
2027
void CubeEffect::slotTabBoxClosed()
 
2028
{
 
2029
    if (activated) {
 
2030
        effects->unrefTabBox();
 
2031
        tabBoxMode = false;
 
2032
        setActive(false);
 
2033
    }
 
2034
}
 
2035
 
 
2036
void CubeEffect::cubeShortcutChanged(const QKeySequence& seq)
 
2037
{
 
2038
    cubeShortcut = KShortcut(seq);
 
2039
}
 
2040
 
 
2041
void CubeEffect::cylinderShortcutChanged(const QKeySequence& seq)
 
2042
{
 
2043
    cylinderShortcut = KShortcut(seq);
 
2044
}
 
2045
 
 
2046
void CubeEffect::sphereShortcutChanged(const QKeySequence& seq)
 
2047
{
 
2048
    sphereShortcut = KShortcut(seq);
 
2049
}
 
2050
 
 
2051
void* CubeEffect::proxy()
 
2052
{
 
2053
    return &m_proxy;
 
2054
}
 
2055
 
 
2056
void CubeEffect::registerCubeInsideEffect(CubeInsideEffect* effect)
 
2057
{
 
2058
    m_cubeInsideEffects.append(effect);
 
2059
}
 
2060
 
 
2061
void CubeEffect::unregisterCubeInsideEffect(CubeInsideEffect* effect)
 
2062
{
 
2063
    m_cubeInsideEffects.removeAll(effect);
 
2064
}
 
2065
 
 
2066
} // namespace