You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2272 lines
84 KiB
2272 lines
84 KiB
/******************************************************************** |
|
KWin - the KDE window manager |
|
This file is part of the KDE project. |
|
|
|
Copyright (C) 2008 Martin Gräßlin <ubuntu@martin-graesslin.com> |
|
|
|
This program is free software; you can redistribute it and/or modify |
|
it under the terms of the GNU General Public License as published by |
|
the Free Software Foundation; either version 2 of the License, or |
|
(at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
*********************************************************************/ |
|
#include "cube.h" |
|
#include "cube_inside.h" |
|
|
|
#include <kaction.h> |
|
#include <kactioncollection.h> |
|
#include <klocale.h> |
|
#include <kwinconfig.h> |
|
#include <kconfiggroup.h> |
|
#include <kcolorscheme.h> |
|
#include <kglobal.h> |
|
#include <kstandarddirs.h> |
|
#include <kdebug.h> |
|
|
|
#include <QColor> |
|
#include <QRect> |
|
#include <QEvent> |
|
#include <QKeyEvent> |
|
|
|
#include <math.h> |
|
|
|
#include <GL/gl.h> |
|
|
|
namespace KWin |
|
{ |
|
|
|
KWIN_EFFECT( cube, CubeEffect ) |
|
KWIN_EFFECT_SUPPORTED( cube, CubeEffect::supported() ) |
|
|
|
CubeEffect::CubeEffect() |
|
: activated( false ) |
|
, mousePolling( false ) |
|
, cube_painting( false ) |
|
, keyboard_grab( false ) |
|
, schedule_close( false ) |
|
, painting_desktop( 1 ) |
|
, frontDesktop( 0 ) |
|
, cubeOpacity( 1.0 ) |
|
, opacityDesktopOnly( true ) |
|
, displayDesktopName( false ) |
|
, desktopNameFrame( EffectFrame::Styled ) |
|
, reflection( true ) |
|
, rotating( false ) |
|
, desktopChangedWhileRotating( false ) |
|
, paintCaps( true ) |
|
, rotationDirection( Left ) |
|
, verticalRotationDirection( Upwards ) |
|
, verticalPosition( Normal ) |
|
, wallpaper( NULL ) |
|
, texturedCaps( true ) |
|
, capTexture( NULL ) |
|
, manualAngle( 0.0 ) |
|
, manualVerticalAngle( 0.0 ) |
|
, currentShape( TimeLine::EaseInOutCurve ) |
|
, start( false ) |
|
, stop( false ) |
|
, reflectionPainting( false ) |
|
, activeScreen( 0 ) |
|
, bottomCap( false ) |
|
, closeOnMouseRelease( false ) |
|
, zoom( 0.0 ) |
|
, zPosition( 0.0 ) |
|
, useForTabBox( false ) |
|
, tabBoxMode( false ) |
|
, shortcutsRegistered( false ) |
|
, mode( Cube ) |
|
, useShaders( false ) |
|
, cylinderShader( 0 ) |
|
, sphereShader( 0 ) |
|
, zOrderingFactor( 0.0f ) |
|
, mAddedHeightCoeff1( 0.0f ) |
|
, mAddedHeightCoeff2( 0.0f ) |
|
, capListCreated( false ) |
|
, recompileList( true ) |
|
, glList( 0 ) |
|
, m_proxy( this ) |
|
{ |
|
desktopNameFont.setBold( true ); |
|
desktopNameFont.setPointSize( 14 ); |
|
desktopNameFrame.setFont( desktopNameFont ); |
|
|
|
reconfigure( ReconfigureAll ); |
|
} |
|
|
|
bool CubeEffect::supported() |
|
{ |
|
return effects->compositingType() == OpenGLCompositing; |
|
} |
|
|
|
void CubeEffect::reconfigure( ReconfigureFlags ) |
|
{ |
|
loadConfig( "Cube" ); |
|
} |
|
|
|
void CubeEffect::loadConfig( QString config ) |
|
{ |
|
KConfigGroup conf = effects->effectConfig( config ); |
|
foreach( ElectricBorder border, borderActivate ) |
|
{ |
|
effects->unreserveElectricBorder( border ); |
|
} |
|
foreach( ElectricBorder border, borderActivateCylinder ) |
|
{ |
|
effects->unreserveElectricBorder( border ); |
|
} |
|
foreach( ElectricBorder border, borderActivateSphere ) |
|
{ |
|
effects->unreserveElectricBorder( border ); |
|
} |
|
borderActivate.clear(); |
|
borderActivateCylinder.clear(); |
|
borderActivateSphere.clear(); |
|
QList<int> borderList = QList<int>(); |
|
borderList.append( int( ElectricNone ) ); |
|
borderList = conf.readEntry( "BorderActivate", borderList ); |
|
foreach( int i, borderList ) |
|
{ |
|
borderActivate.append( ElectricBorder( i ) ); |
|
effects->reserveElectricBorder( ElectricBorder( i ) ); |
|
} |
|
borderList.clear(); |
|
borderList.append( int( ElectricNone ) ); |
|
borderList = conf.readEntry( "BorderActivateCylinder", borderList ); |
|
foreach( int i, borderList ) |
|
{ |
|
borderActivateCylinder.append( ElectricBorder( i ) ); |
|
effects->reserveElectricBorder( ElectricBorder( i ) ); |
|
} |
|
borderList.clear(); |
|
borderList.append( int( ElectricNone ) ); |
|
borderList = conf.readEntry( "BorderActivateSphere", borderList ); |
|
foreach( int i, borderList ) |
|
{ |
|
borderActivateSphere.append( ElectricBorder( i ) ); |
|
effects->reserveElectricBorder( ElectricBorder( i ) ); |
|
} |
|
|
|
cubeOpacity = (float)conf.readEntry( "Opacity", 80 )/100.0f; |
|
opacityDesktopOnly = conf.readEntry( "OpacityDesktopOnly", false ); |
|
displayDesktopName = conf.readEntry( "DisplayDesktopName", true ); |
|
reflection = conf.readEntry( "Reflection", true ); |
|
rotationDuration = animationTime( conf, "RotationDuration", 500 ); |
|
backgroundColor = conf.readEntry( "BackgroundColor", QColor( Qt::black ) ); |
|
capColor = conf.readEntry( "CapColor", KColorScheme( QPalette::Active, KColorScheme::Window ).background().color() ); |
|
paintCaps = conf.readEntry( "Caps", true ); |
|
closeOnMouseRelease = conf.readEntry( "CloseOnMouseRelease", false ); |
|
float defaultZPosition = 100.0f; |
|
if( config == "Sphere" ) |
|
defaultZPosition = 450.0f; |
|
zPosition = conf.readEntry( "ZPosition", defaultZPosition ); |
|
useForTabBox = conf.readEntry( "TabBox", false ); |
|
invertKeys = conf.readEntry( "InvertKeys", false ); |
|
invertMouse = conf.readEntry( "InvertMouse", false ); |
|
capDeformationFactor = conf.readEntry( "CapDeformation", 0 )/100.0f; |
|
useZOrdering = conf.readEntry( "ZOrdering", false ); |
|
QString file = conf.readEntry( "Wallpaper", QString("") ); |
|
if( wallpaper ) |
|
wallpaper->discard(); |
|
delete wallpaper; |
|
wallpaper = NULL; |
|
if( !file.isEmpty() ) |
|
{ |
|
QImage img = QImage( file ); |
|
if( !img.isNull() ) |
|
{ |
|
wallpaper = new GLTexture( img ); |
|
} |
|
} |
|
delete capTexture; |
|
capTexture = NULL; |
|
texturedCaps = conf.readEntry( "TexturedCaps", true ); |
|
if( texturedCaps ) |
|
{ |
|
QString capPath = conf.readEntry( "CapPath", KGlobal::dirs()->findResource( "appdata", "cubecap.png" ) ); |
|
QImage img = QImage( capPath ); |
|
if( !img.isNull() ) |
|
{ |
|
capTexture = new GLTexture( img ); |
|
capTexture->setFilter( GL_LINEAR ); |
|
capTexture->setWrapMode( GL_CLAMP_TO_BORDER ); |
|
} |
|
} |
|
|
|
timeLine.setCurveShape( TimeLine::EaseInOutCurve ); |
|
timeLine.setDuration( rotationDuration ); |
|
|
|
verticalTimeLine.setCurveShape( TimeLine::EaseInOutCurve ); |
|
verticalTimeLine.setDuration( rotationDuration ); |
|
|
|
// do not connect the shortcut if we use cylinder or sphere |
|
if( !shortcutsRegistered ) |
|
{ |
|
KActionCollection* actionCollection = new KActionCollection( this ); |
|
KAction* cubeAction = static_cast< KAction* >( actionCollection->addAction( "Cube" )); |
|
cubeAction->setText( i18n("Desktop Cube" )); |
|
cubeAction->setGlobalShortcut( KShortcut( Qt::CTRL + Qt::Key_F11 )); |
|
cubeShortcut = cubeAction->globalShortcut(); |
|
KAction* cylinderAction = static_cast< KAction* >( actionCollection->addAction( "Cylinder" )); |
|
cylinderAction->setText( i18n("Desktop Cylinder" )); |
|
cylinderAction->setGlobalShortcut( KShortcut(), KAction::ActiveShortcut); |
|
cylinderShortcut = cylinderAction->globalShortcut(); |
|
KAction* sphereAction = static_cast< KAction* >( actionCollection->addAction( "Sphere" )); |
|
sphereAction->setText( i18n("Desktop Sphere" )); |
|
sphereAction->setGlobalShortcut( KShortcut(), KAction::ActiveShortcut); |
|
sphereShortcut = sphereAction->globalShortcut(); |
|
connect( cubeAction, SIGNAL( triggered( bool )), this, SLOT( toggleCube())); |
|
connect( cylinderAction, SIGNAL( triggered( bool )), this, SLOT( toggleCylinder())); |
|
connect( sphereAction, SIGNAL( triggered( bool )), this, SLOT( toggleSphere())); |
|
connect( cubeAction, SIGNAL( globalShortcutChanged( QKeySequence )), this, SLOT( cubeShortcutChanged(QKeySequence))); |
|
connect( cylinderAction, SIGNAL( globalShortcutChanged( QKeySequence )), this, SLOT( cylinderShortcutChanged(QKeySequence))); |
|
connect( sphereAction, SIGNAL( globalShortcutChanged( QKeySequence )), this, SLOT( sphereShortcutChanged(QKeySequence))); |
|
shortcutsRegistered = true; |
|
} |
|
} |
|
|
|
CubeEffect::~CubeEffect() |
|
{ |
|
foreach( ElectricBorder border, borderActivate ) |
|
{ |
|
effects->unreserveElectricBorder( border ); |
|
} |
|
foreach( ElectricBorder border, borderActivateCylinder ) |
|
{ |
|
effects->unreserveElectricBorder( border ); |
|
} |
|
foreach( ElectricBorder border, borderActivateSphere ) |
|
{ |
|
effects->unreserveElectricBorder( border ); |
|
} |
|
delete wallpaper; |
|
delete capTexture; |
|
delete cylinderShader; |
|
delete sphereShader; |
|
} |
|
|
|
bool CubeEffect::loadShader() |
|
{ |
|
if( !(GLShader::fragmentShaderSupported() && |
|
(effects->compositingType() == OpenGLCompositing))) |
|
return false; |
|
QString fragmentshader = KGlobal::dirs()->findResource( "data", "kwin/cylinder.frag" ); |
|
QString cylinderVertexshader = KGlobal::dirs()->findResource( "data", "kwin/cylinder.vert" ); |
|
QString sphereVertexshader = KGlobal::dirs()->findResource( "data", "kwin/sphere.vert" ); |
|
if( fragmentshader.isEmpty() || cylinderVertexshader.isEmpty() || sphereVertexshader.isEmpty() ) |
|
{ |
|
kError(1212) << "Couldn't locate shader files" << endl; |
|
return false; |
|
} |
|
|
|
cylinderShader = new GLShader(cylinderVertexshader, fragmentshader); |
|
if( !cylinderShader->isValid() ) |
|
{ |
|
kError(1212) << "The cylinder shader failed to load!" << endl; |
|
return false; |
|
} |
|
else |
|
{ |
|
cylinderShader->bind(); |
|
cylinderShader->setUniform( "winTexture", 0 ); |
|
QRect rect = effects->clientArea( FullArea, activeScreen, effects->currentDesktop() ); |
|
cylinderShader->setUniform( "width", (float)rect.width() ); |
|
cylinderShader->unbind(); |
|
} |
|
sphereShader = new GLShader( sphereVertexshader, fragmentshader ); |
|
if( !sphereShader->isValid() ) |
|
{ |
|
kError(1212) << "The sphere shader failed to load!" << endl; |
|
return false; |
|
} |
|
else |
|
{ |
|
sphereShader->bind(); |
|
sphereShader->setUniform( "winTexture", 0 ); |
|
QRect rect = effects->clientArea( FullArea, activeScreen, effects->currentDesktop() ); |
|
sphereShader->setUniform( "width", (float)rect.width() ); |
|
sphereShader->setUniform( "height", (float)rect.height() ); |
|
sphereShader->unbind(); |
|
} |
|
return true; |
|
} |
|
|
|
void CubeEffect::prePaintScreen( ScreenPrePaintData& data, int time ) |
|
{ |
|
if( activated ) |
|
{ |
|
data.mask |= PAINT_SCREEN_TRANSFORMED | Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS | PAINT_SCREEN_BACKGROUND_FIRST; |
|
|
|
if( rotating || start || stop ) |
|
{ |
|
timeLine.addTime( time ); |
|
recompileList = true; |
|
} |
|
if( verticalRotating ) |
|
{ |
|
verticalTimeLine.addTime( time ); |
|
recompileList = true; |
|
} |
|
} |
|
effects->prePaintScreen( data, time ); |
|
} |
|
|
|
void CubeEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data ) |
|
{ |
|
if( activated ) |
|
{ |
|
if( recompileList ) |
|
{ |
|
recompileList = false; |
|
glPushMatrix(); |
|
glNewList( glList, GL_COMPILE ); |
|
rotateCube(); |
|
glEndList(); |
|
glPopMatrix(); |
|
} |
|
|
|
// compile List for cube |
|
if( useList ) |
|
{ |
|
glNewList( glList + 1, GL_COMPILE ); |
|
glPushMatrix(); |
|
paintCube( mask, region, data ); |
|
glPopMatrix(); |
|
glEndList(); |
|
} |
|
|
|
QRect rect = effects->clientArea( FullArea, activeScreen, effects->currentDesktop() ); |
|
|
|
// background |
|
float clearColor[4]; |
|
glGetFloatv( GL_COLOR_CLEAR_VALUE, clearColor ); |
|
glClearColor( backgroundColor.redF(), backgroundColor.greenF(), backgroundColor.blueF(), 1.0 ); |
|
glClear( GL_COLOR_BUFFER_BIT ); |
|
glClearColor( clearColor[0], clearColor[1], clearColor[2], clearColor[3] ); |
|
|
|
// wallpaper |
|
if( wallpaper ) |
|
{ |
|
wallpaper->bind(); |
|
wallpaper->render( region, rect ); |
|
wallpaper->unbind(); |
|
} |
|
|
|
glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT ); |
|
glEnable( GL_BLEND ); |
|
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); |
|
|
|
// some veriables needed for painting the caps |
|
float cubeAngle = (float)((float)(effects->numberOfDesktops() - 2 )/(float)effects->numberOfDesktops() * 180.0f); |
|
float point = rect.width()/2*tan(cubeAngle*0.5f*M_PI/180.0f); |
|
float zTranslate = zPosition + zoom; |
|
if( start ) |
|
zTranslate *= timeLine.value(); |
|
if( stop ) |
|
zTranslate *= ( 1.0 - timeLine.value() ); |
|
// reflection |
|
if( reflection && mode != Sphere ) |
|
{ |
|
// restrict painting the reflections to the current screen |
|
PaintClipper::push( QRegion( rect )); |
|
glPushMatrix(); |
|
// we can use a huge scale factor (needed to calculate the rearground vertices) |
|
// as we restrict with a PaintClipper painting on the current screen |
|
float scaleFactor = 1000000 * tan( 60.0 * M_PI / 360.0f )/rect.height(); |
|
glScalef( 1.0, -1.0, 1.0 ); |
|
|
|
// TODO reflection is not correct when mixing manual (mouse) rotating with rotation by cursor keys |
|
// there's also a small bug when zooming |
|
float addedHeight1 = -sin( asin( float( rect.height() ) / mAddedHeightCoeff1 ) + fabs( manualVerticalAngle ) * M_PI / 180.0f ) * mAddedHeightCoeff1; |
|
float addedHeight2 = -sin( asin( float( rect.height() ) / mAddedHeightCoeff2 ) + fabs( manualVerticalAngle ) * M_PI / 180.0f ) * mAddedHeightCoeff2 - addedHeight1; |
|
if( manualVerticalAngle > 0.0f && effects->numberOfDesktops() & 1 ) |
|
glTranslatef( 0.0, cos( fabs( manualAngle ) * M_PI / 360.0f * float( effects->numberOfDesktops() ) ) * addedHeight2 + addedHeight1 - float( rect.height() ), 0.0 ); |
|
else |
|
glTranslatef( 0.0, sin( fabs( manualAngle ) * M_PI / 360.0f * float( effects->numberOfDesktops() ) ) * addedHeight2 + addedHeight1 - float( rect.height() ), 0.0 ); |
|
|
|
|
|
glEnable( GL_CLIP_PLANE0 ); |
|
reflectionPainting = true; |
|
glEnable( GL_CULL_FACE ); |
|
// caps |
|
if( paintCaps && ( effects->numberOfDesktops() >= 2 ) ) |
|
{ |
|
glPushMatrix(); |
|
glCallList( glList ); |
|
glTranslatef( rect.width()/2, 0.0, -point-zTranslate ); |
|
glRotatef( (1-frontDesktop)*360.0f / effects->numberOfDesktops(), 0.0, 1.0, 0.0 ); |
|
glTranslatef( 0.0, rect.height(), 0.0 ); |
|
glCullFace( GL_FRONT ); |
|
|
|
// bottom texture has to be mirrored |
|
glMatrixMode( GL_TEXTURE ); |
|
glPushMatrix(); |
|
glLoadIdentity(); |
|
glScalef( 1.0f, -1.0f, 1.0f ); |
|
glTranslatef( 0.0f, -1.0f, 0.0f ); |
|
glMatrixMode( GL_MODELVIEW ); |
|
|
|
glCallList( glList + 2 ); |
|
|
|
glMatrixMode( GL_TEXTURE ); |
|
glPopMatrix(); |
|
glMatrixMode( GL_MODELVIEW ); |
|
|
|
glTranslatef( 0.0, -rect.height(), 0.0 ); |
|
glCullFace( GL_BACK ); |
|
glCallList( glList + 2 ); |
|
glPopMatrix(); |
|
} |
|
|
|
// cube |
|
glCullFace( GL_FRONT ); |
|
if( mode == Cylinder ) |
|
{ |
|
cylinderShader->bind(); |
|
cylinderShader->setUniform( "front", 1.0f ); |
|
cylinderShader->unbind(); |
|
} |
|
glPushMatrix(); |
|
glCallList( glList ); |
|
if( useList ) |
|
glCallList( glList + 1 ); |
|
else |
|
{ |
|
glPushMatrix(); |
|
paintCube( mask, region, data ); |
|
glPopMatrix(); |
|
} |
|
glPopMatrix(); |
|
|
|
// call the inside cube effects |
|
foreach( CubeInsideEffect* inside, m_cubeInsideEffects ) |
|
{ |
|
glPushMatrix(); |
|
glCallList( glList ); |
|
glTranslatef( rect.width()/2, rect.height()/2, -point-zTranslate ); |
|
glRotatef( (1-frontDesktop)*360.0f / effects->numberOfDesktops(), 0.0, 1.0, 0.0 ); |
|
inside->paint(); |
|
glPopMatrix(); |
|
} |
|
|
|
glCullFace( GL_BACK ); |
|
if( mode == Cylinder ) |
|
{ |
|
cylinderShader->bind(); |
|
cylinderShader->setUniform( "front", -1.0f ); |
|
cylinderShader->unbind(); |
|
} |
|
glPushMatrix(); |
|
glCallList( glList ); |
|
if( useList ) |
|
glCallList( glList + 1 ); |
|
else |
|
{ |
|
glPushMatrix(); |
|
paintCube( mask, region, data ); |
|
glPopMatrix(); |
|
} |
|
glPopMatrix(); |
|
|
|
// cap |
|
if( paintCaps && ( effects->numberOfDesktops() >= 2 ) ) |
|
{ |
|
glPushMatrix(); |
|
glCallList( glList ); |
|
glTranslatef( rect.width()/2, 0.0, -point-zTranslate ); |
|
glRotatef( (1-frontDesktop)*360.0f / effects->numberOfDesktops(), 0.0, 1.0, 0.0 ); |
|
glTranslatef( 0.0, rect.height(), 0.0 ); |
|
glCullFace( GL_BACK ); |
|
|
|
// bottom texture has to be mirrored |
|
glMatrixMode( GL_TEXTURE ); |
|
glPushMatrix(); |
|
glLoadIdentity(); |
|
glScalef( 1.0f, -1.0f, 1.0f ); |
|
glTranslatef( 0.0f, -1.0f, 0.0f ); |
|
glMatrixMode( GL_MODELVIEW ); |
|
glCallList( glList + 2 ); |
|
|
|
glMatrixMode( GL_TEXTURE ); |
|
glPopMatrix(); |
|
glMatrixMode( GL_MODELVIEW ); |
|
|
|
glTranslatef( 0.0, -rect.height(), 0.0 ); |
|
glCullFace( GL_FRONT ); |
|
glCallList( glList + 2 ); |
|
glPopMatrix(); |
|
} |
|
glDisable( GL_CULL_FACE ); |
|
reflectionPainting = false; |
|
glDisable( GL_CLIP_PLANE0 ); |
|
|
|
glPopMatrix(); |
|
glPushMatrix(); |
|
glTranslatef( rect.x() + rect.width()*0.5f, 0.0, 0.0 ); |
|
float vertices[] = { |
|
-rect.width()*0.5f, rect.height(), 0.0, |
|
rect.width()*0.5f, rect.height(), 0.0, |
|
(float)rect.width()*scaleFactor, rect.height(), -5000, |
|
-(float)rect.width()*scaleFactor, rect.height(), -5000 }; |
|
// foreground |
|
float alpha = 0.7; |
|
if( start ) |
|
alpha = 0.3 + 0.4 * timeLine.value(); |
|
if( stop ) |
|
alpha = 0.3 + 0.4 * ( 1.0 - timeLine.value() ); |
|
glColor4f( 0.0, 0.0, 0.0, alpha ); |
|
glBegin( GL_POLYGON ); |
|
glVertex3f( vertices[0], vertices[1], vertices[2] ); |
|
glVertex3f( vertices[3], vertices[4], vertices[5] ); |
|
// rearground |
|
alpha = -1.0; |
|
glColor4f( 0.0, 0.0, 0.0, alpha ); |
|
glVertex3f( vertices[6], vertices[7], vertices[8] ); |
|
glVertex3f( vertices[9], vertices[10], vertices[11] ); |
|
glEnd(); |
|
glPopMatrix(); |
|
PaintClipper::pop( QRegion( rect )); |
|
} |
|
glEnable( GL_CULL_FACE ); |
|
// caps |
|
if( paintCaps && ( effects->numberOfDesktops() >= 2 )) |
|
{ |
|
glPushMatrix(); |
|
glCallList( glList ); |
|
glTranslatef( rect.width()/2, 0.0, -point-zTranslate ); |
|
glRotatef( (1-frontDesktop)*360.0f / effects->numberOfDesktops(), 0.0, 1.0, 0.0 ); |
|
glTranslatef( 0.0, rect.height(), 0.0 ); |
|
glCullFace( GL_BACK ); |
|
if( mode == Sphere ) |
|
{ |
|
glPushMatrix(); |
|
glScalef( 1.0, -1.0, 1.0 ); |
|
} |
|
|
|
// bottom texture has to be mirrored |
|
glMatrixMode( GL_TEXTURE ); |
|
glPushMatrix(); |
|
glLoadIdentity(); |
|
glScalef( 1.0f, -1.0f, 1.0f ); |
|
glTranslatef( 0.0f, -1.0f, 0.0f ); |
|
glMatrixMode( GL_MODELVIEW ); |
|
|
|
glCallList( glList + 2 ); |
|
|
|
glMatrixMode( GL_TEXTURE ); |
|
glPopMatrix(); |
|
glMatrixMode( GL_MODELVIEW ); |
|
if( mode == Sphere ) |
|
glPopMatrix(); |
|
glTranslatef( 0.0, -rect.height(), 0.0 ); |
|
glCullFace( GL_FRONT ); |
|
glCallList( glList + 2 ); |
|
glPopMatrix(); |
|
} |
|
|
|
// cube |
|
glCullFace( GL_BACK ); |
|
if( mode == Cylinder ) |
|
{ |
|
cylinderShader->bind(); |
|
cylinderShader->setUniform( "front", -1.0f ); |
|
cylinderShader->unbind(); |
|
} |
|
if( mode == Sphere ) |
|
{ |
|
sphereShader->bind(); |
|
sphereShader->setUniform( "front", -1.0f ); |
|
sphereShader->unbind(); |
|
} |
|
glPushMatrix(); |
|
glCallList( glList ); |
|
if( useList ) |
|
glCallList( glList + 1 ); |
|
else |
|
{ |
|
glPushMatrix(); |
|
paintCube( mask, region, data ); |
|
glPopMatrix(); |
|
} |
|
glPopMatrix(); |
|
|
|
|
|
// call the inside cube effects |
|
foreach( CubeInsideEffect* inside, m_cubeInsideEffects ) |
|
{ |
|
glPushMatrix(); |
|
glCallList( glList ); |
|
glTranslatef( rect.width()/2, rect.height()/2, -point-zTranslate ); |
|
glRotatef( (1-frontDesktop)*360.0f / effects->numberOfDesktops(), 0.0, 1.0, 0.0 ); |
|
inside->paint(); |
|
glPopMatrix(); |
|
} |
|
|
|
glCullFace( GL_FRONT ); |
|
if( mode == Cylinder ) |
|
{ |
|
cylinderShader->bind(); |
|
cylinderShader->setUniform( "front", 1.0f ); |
|
cylinderShader->unbind(); |
|
} |
|
if( mode == Sphere ) |
|
{ |
|
sphereShader->bind(); |
|
sphereShader->setUniform( "front", 1.0f ); |
|
sphereShader->unbind(); |
|
} |
|
glPushMatrix(); |
|
glCallList( glList ); |
|
if( useList ) |
|
glCallList( glList + 1 ); |
|
else |
|
{ |
|
glPushMatrix(); |
|
paintCube( mask, region, data ); |
|
glPopMatrix(); |
|
} |
|
glPopMatrix(); |
|
// we painted once without glList, now it's safe to paint using lists |
|
useList = true; |
|
|
|
// cap |
|
if( paintCaps && ( effects->numberOfDesktops() >= 2 )) |
|
{ |
|
glPushMatrix(); |
|
glCallList( glList ); |
|
glTranslatef( rect.width()/2, 0.0, -point-zTranslate ); |
|
glRotatef( (1-frontDesktop)*360.0f / effects->numberOfDesktops(), 0.0, 1.0, 0.0 ); |
|
glTranslatef( 0.0, rect.height(), 0.0 ); |
|
glCullFace( GL_FRONT ); |
|
if( mode == Sphere ) |
|
{ |
|
glPushMatrix(); |
|
glScalef( 1.0, -1.0, 1.0 ); |
|
} |
|
|
|
// bottom texture has to be mirrored |
|
glMatrixMode( GL_TEXTURE ); |
|
glPushMatrix(); |
|
glLoadIdentity(); |
|
glScalef( 1.0f, -1.0f, 1.0f ); |
|
glTranslatef( 0.0f, -1.0f, 0.0f ); |
|
glMatrixMode( GL_MODELVIEW ); |
|
|
|
glCallList( glList + 2 ); |
|
|
|
glMatrixMode( GL_TEXTURE ); |
|
glPopMatrix(); |
|
glMatrixMode( GL_MODELVIEW ); |
|
|
|
if( mode == Sphere ) |
|
glPopMatrix(); |
|
glTranslatef( 0.0, -rect.height(), 0.0 ); |
|
glCullFace( GL_BACK ); |
|
glCallList( glList + 2 ); |
|
glPopMatrix(); |
|
} |
|
glDisable( GL_CULL_FACE ); |
|
|
|
glDisable( GL_BLEND ); |
|
glPopAttrib(); |
|
|
|
// desktop name box - inspired from coverswitch |
|
if( displayDesktopName ) |
|
{ |
|
double opacity = 1.0; |
|
if( start ) |
|
opacity = timeLine.value(); |
|
if( stop ) |
|
opacity = 1.0 - timeLine.value(); |
|
QRect screenRect = effects->clientArea( ScreenArea, activeScreen, frontDesktop ); |
|
QRect frameRect = QRect( screenRect.width() * 0.33f + screenRect.x(), screenRect.height() * 0.95f + screenRect.y(), |
|
screenRect.width() * 0.34f, QFontMetrics( desktopNameFont ).height() ); |
|
desktopNameFrame.setGeometry( frameRect ); |
|
desktopNameFrame.setText( effects->desktopName( frontDesktop ) ); |
|
desktopNameFrame.render( region, opacity ); |
|
} |
|
} |
|
else |
|
{ |
|
effects->paintScreen( mask, region, data ); |
|
} |
|
} |
|
|
|
void CubeEffect::rotateCube() |
|
{ |
|
QRect rect = effects->clientArea( FullArea, activeScreen, effects->currentDesktop() ); |
|
|
|
float internalCubeAngle = 360.0f / effects->numberOfDesktops(); |
|
float zTranslate = zPosition + zoom; |
|
if( start ) |
|
zTranslate *= timeLine.value(); |
|
if( stop ) |
|
zTranslate *= ( 1.0 - timeLine.value() ); |
|
// Rotation of the cube |
|
float cubeAngle = (float)((float)(effects->numberOfDesktops() - 2 )/(float)effects->numberOfDesktops() * 180.0f); |
|
float point = rect.width()/2*tan(cubeAngle*0.5f*M_PI/180.0f); |
|
if( verticalRotating || verticalPosition != Normal || manualVerticalAngle != 0.0 ) |
|
{ |
|
// change the verticalPosition if manualVerticalAngle > 90 or < -90 degrees |
|
if( manualVerticalAngle <= -90.0 ) |
|
{ |
|
manualVerticalAngle += 90.0; |
|
if( verticalPosition == Normal ) |
|
verticalPosition = Down; |
|
if( verticalPosition == Up ) |
|
verticalPosition = Normal; |
|
} |
|
if( manualVerticalAngle >= 90.0 ) |
|
{ |
|
manualVerticalAngle -= 90.0; |
|
if( verticalPosition == Normal ) |
|
verticalPosition = Up; |
|
if( verticalPosition == Down ) |
|
verticalPosition = Normal; |
|
} |
|
float angle = 0.0; |
|
if( verticalPosition == Up ) |
|
{ |
|
angle = 90.0; |
|
if( !verticalRotating) |
|
{ |
|
if( manualVerticalAngle < 0.0 ) |
|
angle += manualVerticalAngle; |
|
else |
|
manualVerticalAngle = 0.0; |
|
} |
|
} |
|
else if( verticalPosition == Down ) |
|
{ |
|
angle = -90.0; |
|
if( !verticalRotating) |
|
{ |
|
if( manualVerticalAngle > 0.0 ) |
|
angle += manualVerticalAngle; |
|
else |
|
manualVerticalAngle = 0.0; |
|
} |
|
} |
|
else |
|
{ |
|
angle = manualVerticalAngle; |
|
} |
|
if( verticalRotating ) |
|
{ |
|
angle *= verticalTimeLine.value(); |
|
if( verticalPosition == Normal && verticalRotationDirection == Upwards ) |
|
angle = -90.0 + 90*verticalTimeLine.value(); |
|
if( verticalPosition == Normal && verticalRotationDirection == Downwards ) |
|
angle = 90.0 - 90*verticalTimeLine.value(); |
|
angle += manualVerticalAngle * (1.0-verticalTimeLine.value()); |
|
} |
|
if( stop ) |
|
angle *= (1.0 - timeLine.value()); |
|
glTranslatef( rect.width()/2, rect.height()/2, -point-zTranslate ); |
|
glRotatef( angle, 1.0, 0.0, 0.0 ); |
|
glTranslatef( -rect.width()/2, -rect.height()/2, point+zTranslate ); |
|
} |
|
if( rotating || (manualAngle != 0.0) ) |
|
{ |
|
int tempFrontDesktop = frontDesktop; |
|
if( manualAngle > internalCubeAngle * 0.5f ) |
|
{ |
|
manualAngle -= internalCubeAngle; |
|
tempFrontDesktop--; |
|
if( tempFrontDesktop == 0 ) |
|
tempFrontDesktop = effects->numberOfDesktops(); |
|
} |
|
if( manualAngle < -internalCubeAngle * 0.5f ) |
|
{ |
|
manualAngle += internalCubeAngle; |
|
tempFrontDesktop++; |
|
if( tempFrontDesktop > effects->numberOfDesktops() ) |
|
tempFrontDesktop = 1; |
|
} |
|
float rotationAngle = internalCubeAngle * timeLine.value(); |
|
if( rotationAngle > internalCubeAngle * 0.5f ) |
|
{ |
|
rotationAngle -= internalCubeAngle; |
|
if( !desktopChangedWhileRotating ) |
|
{ |
|
desktopChangedWhileRotating = true; |
|
if( rotationDirection == Left ) |
|
{ |
|
tempFrontDesktop++; |
|
} |
|
else if( rotationDirection == Right ) |
|
{ |
|
tempFrontDesktop--; |
|
} |
|
if( tempFrontDesktop > effects->numberOfDesktops() ) |
|
tempFrontDesktop = 1; |
|
else if( tempFrontDesktop == 0 ) |
|
tempFrontDesktop = effects->numberOfDesktops(); |
|
} |
|
} |
|
// don't change front desktop during stop animation as this would break some logic |
|
if( !stop ) |
|
frontDesktop = tempFrontDesktop; |
|
if( rotationDirection == Left ) |
|
{ |
|
rotationAngle *= -1; |
|
} |
|
if( stop ) |
|
rotationAngle = manualAngle * (1.0 - timeLine.value()); |
|
else |
|
rotationAngle += manualAngle * (1.0 - timeLine.value()); |
|
glTranslatef( rect.width()/2, rect.height()/2, -point-zTranslate ); |
|
glRotatef( rotationAngle, 0.0, 1.0, 0.0 ); |
|
glTranslatef( -rect.width()/2, -rect.height()/2, point+zTranslate ); |
|
} |
|
} |
|
|
|
void CubeEffect::paintCube( int mask, QRegion region, ScreenPaintData& data ) |
|
{ |
|
QRect rect = effects->clientArea( FullArea, activeScreen, effects->currentDesktop() ); |
|
float internalCubeAngle = 360.0f / effects->numberOfDesktops(); |
|
cube_painting = true; |
|
float zTranslate = zPosition + zoom; |
|
if( start ) |
|
zTranslate *= timeLine.value(); |
|
if( stop ) |
|
zTranslate *= ( 1.0 - timeLine.value() ); |
|
|
|
// Rotation of the cube |
|
float cubeAngle = (float)((float)(effects->numberOfDesktops() - 2 )/(float)effects->numberOfDesktops() * 180.0f); |
|
float point = rect.width()/2*tan(cubeAngle*0.5f*M_PI/180.0f); |
|
|
|
for( int i=0; i<effects->numberOfDesktops(); i++ ) |
|
{ |
|
// start painting the cube |
|
painting_desktop = (i + frontDesktop )%effects->numberOfDesktops(); |
|
if( painting_desktop == 0 ) |
|
{ |
|
painting_desktop = effects->numberOfDesktops(); |
|
} |
|
ScreenPaintData newData = data; |
|
RotationData rot = RotationData(); |
|
rot.axis = RotationData::YAxis; |
|
rot.angle = internalCubeAngle * i; |
|
rot.xRotationPoint = rect.width()/2; |
|
rot.zRotationPoint = -point; |
|
newData.rotation = &rot; |
|
newData.zTranslate = -zTranslate; |
|
effects->paintScreen( mask, region, newData ); |
|
} |
|
cube_painting = false; |
|
painting_desktop = effects->currentDesktop(); |
|
} |
|
|
|
void CubeEffect::paintCap() |
|
{ |
|
if( ( !paintCaps ) || effects->numberOfDesktops() <= 2 ) |
|
return; |
|
|
|
if( !capListCreated ) |
|
{ |
|
capListCreated = true; |
|
glNewList( glList + 2, GL_COMPILE ); |
|
glColor4f( capColor.redF(), capColor.greenF(), capColor.blueF(), cubeOpacity ); |
|
if( texturedCaps && effects->numberOfDesktops() > 3 && capTexture ) |
|
{ |
|
// modulate the cap texture: cap color should be background for translucent pixels |
|
// cube opacity should be used for all pixels |
|
// blend with cap color |
|
float color[4] = { capColor.redF(), capColor.greenF(), capColor.blueF(), cubeOpacity }; |
|
glActiveTexture( GL_TEXTURE0 ); |
|
capTexture->bind(); |
|
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL ); |
|
glColor4fv( color ); |
|
|
|
// set Opacity to cube opacity |
|
// TODO: change opacity during start/stop animation |
|
glActiveTexture( GL_TEXTURE1 ); |
|
capTexture->bind(); |
|
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE ); |
|
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE ); |
|
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS ); |
|
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE ); |
|
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_CONSTANT ); |
|
glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color ); |
|
glActiveTexture( GL_TEXTURE0 ); |
|
glTexParameterfv( GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color ); |
|
} |
|
glPushMatrix(); |
|
switch( mode ) |
|
{ |
|
case Cube: |
|
paintCubeCap(); |
|
break; |
|
case Cylinder: |
|
paintCylinderCap(); |
|
break; |
|
case Sphere: |
|
paintSphereCap(); |
|
break; |
|
default: |
|
// impossible |
|
break; |
|
} |
|
glPopMatrix(); |
|
if( texturedCaps && effects->numberOfDesktops() > 3 && capTexture ) |
|
{ |
|
glActiveTexture( GL_TEXTURE1 ); |
|
glDisable( capTexture->target() ); |
|
glActiveTexture( GL_TEXTURE0 ); |
|
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE ); |
|
glColor4f( 0.0f, 0.0f, 0.0f, 0.0f ); |
|
capTexture->unbind(); |
|
} |
|
glEndList(); |
|
} |
|
} |
|
|
|
void CubeEffect::paintCubeCap() |
|
{ |
|
QRect rect = effects->clientArea( FullArea, activeScreen, effects->currentDesktop() ); |
|
float cubeAngle = (float)((float)(effects->numberOfDesktops() - 2 )/(float)effects->numberOfDesktops() * 180.0f); |
|
float z = rect.width()/2*tan(cubeAngle*0.5f*M_PI/180.0f); |
|
float zTexture = rect.width()/2*tan(45.0f*M_PI/180.0f); |
|
float angle = 360.0f/effects->numberOfDesktops(); |
|
bool texture = texturedCaps && effects->numberOfDesktops() > 3 && capTexture; |
|
for( int i=0; i<effects->numberOfDesktops(); i++ ) |
|
{ |
|
int triangleRows = effects->numberOfDesktops()*5; |
|
float zTriangleDistance = z/(float)triangleRows; |
|
float widthTriangle = tan( angle*0.5 * M_PI/180.0 ) * zTriangleDistance; |
|
float currentWidth = 0.0; |
|
glBegin( GL_TRIANGLES ); |
|
float cosValue = cos( i*angle * M_PI/180.0 ); |
|
float sinValue = sin( i*angle * M_PI/180.0 ); |
|
for( int j=0; j<triangleRows; j++ ) |
|
{ |
|
float previousWidth = currentWidth; |
|
currentWidth = tan( angle*0.5 * M_PI/180.0 ) * zTriangleDistance * (j+1); |
|
int evenTriangles = 0; |
|
int oddTriangles = 0; |
|
for( int k=0; k<floor(currentWidth/widthTriangle*2-1+0.5f); k++ ) |
|
{ |
|
float x1 = -previousWidth; |
|
float x2 = -currentWidth; |
|
float x3 = 0.0; |
|
float z1 = 0.0; |
|
float z2 = 0.0; |
|
float z3 = 0.0; |
|
if( k%2 == 0 ) |
|
{ |
|
x1 += evenTriangles*widthTriangle*2; |
|
x2 += evenTriangles*widthTriangle*2; |
|
x3 = x2+widthTriangle*2; |
|
z1 = j*zTriangleDistance; |
|
z2 = (j+1)*zTriangleDistance; |
|
z3 = (j+1)*zTriangleDistance; |
|
float xRot = cosValue * x1 - sinValue * z1; |
|
float zRot = sinValue * x1 + cosValue * z1; |
|
x1 = xRot; |
|
z1 = zRot; |
|
xRot = cosValue * x2 - sinValue * z2; |
|
zRot = sinValue * x2 + cosValue * z2; |
|
x2 = xRot; |
|
z2 = zRot; |
|
xRot = cosValue * x3 - sinValue * z3; |
|
zRot = sinValue * x3 + cosValue * z3; |
|
x3 = xRot; |
|
z3 = zRot; |
|
evenTriangles++; |
|
} |
|
else |
|
{ |
|
x1 += oddTriangles*widthTriangle*2; |
|
x2 += (oddTriangles+1)*widthTriangle*2; |
|
x3 = x1+widthTriangle*2; |
|
z1 = j*zTriangleDistance; |
|
z2 = (j+1)*zTriangleDistance; |
|
z3 = j*zTriangleDistance; |
|
float xRot = cosValue * x1 - sinValue * z1; |
|
float zRot = sinValue * x1 + cosValue * z1; |
|
x1 = xRot; |
|
z1 = zRot; |
|
xRot = cosValue * x2 - sinValue * z2; |
|
zRot = sinValue * x2 + cosValue * z2; |
|
x2 = xRot; |
|
z2 = zRot; |
|
xRot = cosValue * x3 - sinValue * z3; |
|
zRot = sinValue * x3 + cosValue * z3; |
|
x3 = xRot; |
|
z3 = zRot; |
|
oddTriangles++; |
|
} |
|
float texX1 = 0.0; |
|
float texX2 = 0.0; |
|
float texX3 = 0.0; |
|
float texY1 = 0.0; |
|
float texY2 = 0.0; |
|
float texY3 = 0.0; |
|
if( texture ) |
|
{ |
|
texX1 = x1/(rect.width())+0.5; |
|
texY1 = 0.5 - z1/zTexture * 0.5; |
|
texX2 = x2/(rect.width())+0.5; |
|
texY2 = 0.5 - z2/zTexture * 0.5; |
|
texX3 = x3/(rect.width())+0.5; |
|
texY3 = 0.5 - z3/zTexture * 0.5; |
|
glTexCoord2f( texX1, texY1 ); |
|
} |
|
glVertex3f( x1, 0.0, z1 ); |
|
if( texture ) |
|
{ |
|
glTexCoord2f( texX2, texY2 ); |
|
} |
|
glVertex3f( x2, 0.0, z2 ); |
|
if( texture ) |
|
{ |
|
glTexCoord2f( texX3, texY3 ); |
|
} |
|
glVertex3f( x3, 0.0, z3 ); |
|
} |
|
} |
|
glEnd(); |
|
} |
|
} |
|
|
|
void CubeEffect::paintCylinderCap() |
|
{ |
|
QRect rect = effects->clientArea( FullArea, activeScreen, effects->currentDesktop() ); |
|
float cubeAngle = (float)((float)(effects->numberOfDesktops() - 2 )/(float)effects->numberOfDesktops() * 180.0f); |
|
|
|
float radian = (cubeAngle*0.5)*M_PI/180; |
|
float radius = (rect.width()*0.5)*tan(radian); |
|
float segment = radius/30.0f; |
|
|
|
bool texture = texturedCaps && effects->numberOfDesktops() > 3 && capTexture; |
|
for( int i=1; i<=30; i++ ) |
|
{ |
|
glBegin( GL_TRIANGLE_STRIP ); |
|
int steps = 72; |
|
for( int j=0; j<=steps; j++ ) |
|
{ |
|
float azimuthAngle = (j*(360.0f/steps))*M_PI/180.0f; |
|
float x1 = segment*(i-1) * sin( azimuthAngle ); |
|
float x2 = segment*i * sin( azimuthAngle ); |
|
float z1 = segment*(i-1) * cos( azimuthAngle ); |
|
float z2 = segment*i * cos( azimuthAngle ); |
|
if( texture ) |
|
glTexCoord2f( (radius+x1)/(radius*2.0f), 1.0f - (z1+radius)/(radius*2.0f) ); |
|
glVertex3f( x1, 0.0, z1 ); |
|
if( texture ) |
|
glTexCoord2f( (radius+x2)/(radius*2.0f), 1.0f - (z2+radius)/(radius*2.0f) ); |
|
glVertex3f( x2, 0.0, z2 ); |
|
} |
|
glEnd(); |
|
} |
|
} |
|
|
|
void CubeEffect::paintSphereCap() |
|
{ |
|
QRect rect = effects->clientArea( FullArea, activeScreen, effects->currentDesktop() ); |
|
float cubeAngle = (float)((float)(effects->numberOfDesktops() - 2 )/(float)effects->numberOfDesktops() * 180.0f); |
|
float zTexture = rect.width()/2*tan(45.0f*M_PI/180.0f); |
|
float radius = (rect.width()*0.5)/cos(cubeAngle*0.5*M_PI/180.0); |
|
float angle = acos( (rect.height()*0.5)/radius )*180.0/M_PI; |
|
angle /= 30; |
|
bool texture = texturedCaps && effects->numberOfDesktops() > 3 && capTexture; |
|
glPushMatrix(); |
|
glTranslatef( 0.0, -rect.height()*0.5, 0.0 ); |
|
glBegin( GL_QUADS ); |
|
for( int i=0; i<30; i++ ) |
|
{ |
|
float topAngle = angle*i*M_PI/180.0; |
|
float bottomAngle = angle*(i+1)*M_PI/180.0; |
|
float yTop = rect.height() - radius * cos( topAngle ); |
|
yTop -= (yTop-rect.height()*0.5)*capDeformationFactor; |
|
float yBottom = rect.height() -radius * cos( bottomAngle ); |
|
yBottom -= (yBottom-rect.height()*0.5)*capDeformationFactor; |
|
for( int j=0; j<36; j++ ) |
|
{ |
|
float x = radius * sin( topAngle ) * sin( (90.0+j*10.0)*M_PI/180.0 ); |
|
float z = radius * sin( topAngle ) * cos( (90.0+j*10.0)*M_PI/180.0 ); |
|
if( texture ) |
|
glTexCoord2f( x/(rect.width())+0.5, 0.5 - z/zTexture * 0.5 ); |
|
glVertex3f( x, yTop, z ); |
|
x = radius * sin( bottomAngle ) * sin( (90.0+j*10.0)*M_PI/180.00 ); |
|
z = radius * sin( bottomAngle ) * cos( (90.0+j*10.0)*M_PI/180.0 ); |
|
if( texture ) |
|
glTexCoord2f( x/(rect.width())+0.5, 0.5 - z/zTexture * 0.5 ); |
|
glVertex3f( x, yBottom, z ); |
|
x = radius * sin( bottomAngle ) * sin( (90.0+(j+1)*10.0)*M_PI/180.0 ); |
|
z = radius * sin( bottomAngle ) * cos( (90.0+(j+1)*10.0)*M_PI/180.0 ); |
|
if( texture ) |
|
glTexCoord2f( x/(rect.width())+0.5, 0.5 - z/zTexture * 0.5 ); |
|
glVertex3f( x, yBottom, z ); |
|
x = radius * sin( topAngle ) * sin( (90.0+(j+1)*10.0)*M_PI/180.0 ); |
|
z = radius * sin( topAngle ) * cos( (90.0+(j+1)*10.0)*M_PI/180.0 ); |
|
if( texture ) |
|
glTexCoord2f( x/(rect.width())+0.5, 0.5 - z/zTexture * 0.5 ); |
|
glVertex3f( x, yTop, z ); |
|
} |
|
} |
|
glEnd(); |
|
glPopMatrix(); |
|
} |
|
|
|
void CubeEffect::postPaintScreen() |
|
{ |
|
effects->postPaintScreen(); |
|
if( activated ) |
|
{ |
|
if( start ) |
|
{ |
|
if( timeLine.value() == 1.0 ) |
|
{ |
|
start = false; |
|
timeLine.setProgress(0.0); |
|
// more rotations? |
|
if( !rotations.empty() ) |
|
{ |
|
rotationDirection = rotations.dequeue(); |
|
rotating = true; |
|
// change the curve shape if current shape is not easeInOut |
|
if( currentShape != TimeLine::EaseInOutCurve ) |
|
{ |
|
// more rotations follow -> linear curve |
|
if( !rotations.empty() ) |
|
{ |
|
currentShape = TimeLine::LinearCurve; |
|
} |
|
// last rotation step -> easeOut curve |
|
else |
|
{ |
|
currentShape = TimeLine::EaseOutCurve; |
|
} |
|
timeLine.setCurveShape( currentShape ); |
|
} |
|
else |
|
{ |
|
// if there is at least one more rotation, we can change to easeIn |
|
if( !rotations.empty() ) |
|
{ |
|
currentShape = TimeLine::EaseInCurve; |
|
timeLine.setCurveShape( currentShape ); |
|
} |
|
} |
|
} |
|
} |
|
effects->addRepaintFull(); |
|
return; // schedule_close could have been called, start has to finish first |
|
} |
|
if( stop ) |
|
{ |
|
if( timeLine.value() == 1.0 ) |
|
{ |
|
effects->setCurrentDesktop( frontDesktop ); |
|
stop = false; |
|
timeLine.setProgress(0.0); |
|
activated = false; |
|
// set the new desktop |
|
if( keyboard_grab ) |
|
effects->ungrabKeyboard(); |
|
keyboard_grab = false; |
|
effects->destroyInputWindow( input ); |
|
|
|
effects->setActiveFullScreenEffect( 0 ); |
|
|
|
// delete the GL lists |
|
glDeleteLists( glList, 3 ); |
|
desktopNameFrame.free(); |
|
} |
|
effects->addRepaintFull(); |
|
} |
|
if( rotating || verticalRotating ) |
|
{ |
|
if( rotating && timeLine.value() == 1.0 ) |
|
{ |
|
timeLine.setProgress(0.0); |
|
rotating = false; |
|
desktopChangedWhileRotating = false; |
|
manualAngle = 0.0; |
|
// more rotations? |
|
if( !rotations.empty() ) |
|
{ |
|
rotationDirection = rotations.dequeue(); |
|
rotating = true; |
|
// change the curve shape if current shape is not easeInOut |
|
if( currentShape != TimeLine::EaseInOutCurve ) |
|
{ |
|
// more rotations follow -> linear curve |
|
if( !rotations.empty() ) |
|
{ |
|
currentShape = TimeLine::LinearCurve; |
|
} |
|
// last rotation step -> easeOut curve |
|
else |
|
{ |
|
currentShape = TimeLine::EaseOutCurve; |
|
} |
|
timeLine.setCurveShape( currentShape ); |
|
} |
|
else |
|
{ |
|
// if there is at least one more rotation, we can change to easeIn |
|
if( !rotations.empty() ) |
|
{ |
|
currentShape = TimeLine::EaseInCurve; |
|
timeLine.setCurveShape( currentShape ); |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
// reset curve shape if there are no more rotations |
|
if( currentShape != TimeLine::EaseInOutCurve ) |
|
{ |
|
currentShape = TimeLine::EaseInOutCurve; |
|
timeLine.setCurveShape( currentShape ); |
|
} |
|
} |
|
} |
|
if( verticalRotating && verticalTimeLine.value() == 1.0 ) |
|
{ |
|
verticalTimeLine.setProgress(0.0); |
|
verticalRotating = false; |
|
manualVerticalAngle = 0.0; |
|
// more rotations? |
|
if( !verticalRotations.empty() ) |
|
{ |
|
verticalRotationDirection = verticalRotations.dequeue(); |
|
verticalRotating = true; |
|
if( verticalRotationDirection == Upwards ) |
|
{ |
|
if( verticalPosition == Normal ) |
|
verticalPosition = Up; |
|
if( verticalPosition == Down ) |
|
verticalPosition = Normal; |
|
} |
|
if( verticalRotationDirection == Downwards ) |
|
{ |
|
if( verticalPosition == Normal ) |
|
verticalPosition = Down; |
|
if( verticalPosition == Up ) |
|
verticalPosition = Normal; |
|
} |
|
} |
|
} |
|
effects->addRepaintFull(); |
|
return; // rotation has to end before cube is closed |
|
} |
|
if( schedule_close ) |
|
{ |
|
schedule_close = false; |
|
stop = true; |
|
effects->addRepaintFull(); |
|
} |
|
} |
|
} |
|
|
|
void CubeEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time ) |
|
{ |
|
if( activated ) |
|
{ |
|
if( cube_painting ) |
|
{ |
|
if( mode == Cylinder || mode == Sphere ) |
|
{ |
|
int leftDesktop = frontDesktop -1; |
|
int rightDesktop = frontDesktop + 1; |
|
if( leftDesktop == 0 ) |
|
leftDesktop = effects->numberOfDesktops(); |
|
if( rightDesktop > effects->numberOfDesktops() ) |
|
rightDesktop = 1; |
|
if( painting_desktop == frontDesktop ) |
|
data.quads = data.quads.makeGrid( 40 ); |
|
else if( painting_desktop == leftDesktop || painting_desktop == rightDesktop ) |
|
data.quads = data.quads.makeGrid( 100 ); |
|
else |
|
data.quads = data.quads.makeGrid( 250 ); |
|
} |
|
if( w->isOnDesktop( painting_desktop )) |
|
{ |
|
QRect rect = effects->clientArea( FullArea, activeScreen, painting_desktop ); |
|
if( w->x() < rect.x() ) |
|
{ |
|
data.quads = data.quads.splitAtX( -w->x() ); |
|
} |
|
if( w->x() + w->width() > rect.x() + rect.width() ) |
|
{ |
|
data.quads = data.quads.splitAtX( rect.width() - w->x() ); |
|
} |
|
if( w->y() < rect.y() ) |
|
{ |
|
data.quads = data.quads.splitAtY( -w->y() ); |
|
} |
|
if( w->y() + w->height() > rect.y() + rect.height() ) |
|
{ |
|
data.quads = data.quads.splitAtY( rect.height() - w->y() ); |
|
} |
|
if( useZOrdering && !w->isDesktop() && !w->isDock() ) |
|
data.setTransformed(); |
|
w->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP ); |
|
} |
|
else |
|
{ |
|
// check for windows belonging to the previous desktop |
|
int prev_desktop = painting_desktop -1; |
|
if( prev_desktop == 0 ) |
|
prev_desktop = effects->numberOfDesktops(); |
|
if( w->isOnDesktop( prev_desktop ) && mode == Cube ) |
|
{ |
|
QRect rect = effects->clientArea( FullArea, activeScreen, prev_desktop); |
|
if( w->x()+w->width() > rect.x() + rect.width() ) |
|
{ |
|
w->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP ); |
|
data.quads = data.quads.splitAtX( rect.width() - w->x() ); |
|
if( w->y() < rect.y() ) |
|
{ |
|
data.quads = data.quads.splitAtY( -w->y() ); |
|
} |
|
if( w->y() + w->height() > rect.y() + rect.height() ) |
|
{ |
|
data.quads = data.quads.splitAtY( rect.height() - w->y() ); |
|
} |
|
data.setTransformed(); |
|
effects->prePaintWindow( w, data, time ); |
|
return; |
|
} |
|
} |
|
// check for windows belonging to the next desktop |
|
int next_desktop = painting_desktop +1; |
|
if( next_desktop > effects->numberOfDesktops() ) |
|
next_desktop = 1; |
|
if( w->isOnDesktop( next_desktop ) && mode == Cube ) |
|
{ |
|
QRect rect = effects->clientArea( FullArea, activeScreen, next_desktop); |
|
if( w->x() < rect.x() ) |
|
{ |
|
w->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP ); |
|
data.quads = data.quads.splitAtX( -w->x() ); |
|
if( w->y() < rect.y() ) |
|
{ |
|
data.quads = data.quads.splitAtY( -w->y() ); |
|
} |
|
if( w->y() + w->height() > rect.y() + rect.height() ) |
|
{ |
|
data.quads = data.quads.splitAtY( rect.height() - w->y() ); |
|
} |
|
data.setTransformed(); |
|
effects->prePaintWindow( w, data, time ); |
|
return; |
|
} |
|
} |
|
w->disablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP ); |
|
} |
|
} |
|
} |
|
effects->prePaintWindow( w, data, time ); |
|
} |
|
|
|
void CubeEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) |
|
{ |
|
if( activated && cube_painting ) |
|
{ |
|
if( mode == Cylinder ) |
|
{ |
|
cylinderShader->bind(); |
|
cylinderShader->setUniform( "xCoord", (float)w->x() ); |
|
cylinderShader->setUniform( "cubeAngle", (effects->numberOfDesktops() - 2 )/(float)effects->numberOfDesktops() * 180.0f ); |
|
cylinderShader->setUniform( "useTexture", 1.0f ); |
|
float factor = 0.0f; |
|
if( start ) |
|
factor = 1.0f - timeLine.value(); |
|
if( stop ) |
|
factor = timeLine.value(); |
|
cylinderShader->setUniform( "timeLine", factor ); |
|
data.shader = cylinderShader; |
|
} |
|
if( mode == Sphere ) |
|
{ |
|
sphereShader->bind(); |
|
sphereShader->setUniform( "xCoord", (float)w->x() ); |
|
sphereShader->setUniform( "yCoord", (float)w->y() ); |
|
sphereShader->setUniform( "cubeAngle", (effects->numberOfDesktops() - 2 )/(float)effects->numberOfDesktops() * 180.0f ); |
|
sphereShader->setUniform( "useTexture", 1.0f ); |
|
float factor = 0.0f; |
|
if( start ) |
|
factor = 1.0f - timeLine.value(); |
|
if( stop ) |
|
factor = timeLine.value(); |
|
sphereShader->setUniform( "timeLine", factor ); |
|
data.shader = sphereShader; |
|
} |
|
if( data.shader ) |
|
{ |
|
int texw = w->width(); |
|
int texh = w->height(); |
|
if( !GLTexture::NPOTTextureSupported() ) |
|
{ |
|
kWarning( 1212 ) << "NPOT textures not supported, wasting some memory" ; |
|
texw = nearestPowerOfTwo(texw); |
|
texh = nearestPowerOfTwo(texh); |
|
} |
|
data.shader->setTextureWidth( texw ); |
|
data.shader->setTextureHeight( texh ); |
|
} |
|
//kDebug(1212) << w->caption(); |
|
float opacity = cubeOpacity; |
|
if( start ) |
|
{ |
|
opacity = 1.0 - (1.0 - opacity)*timeLine.value(); |
|
if( reflectionPainting ) |
|
opacity = 0.5 + ( cubeOpacity - 0.5 )*timeLine.value(); |
|
// fade in windows belonging to different desktops |
|
if( painting_desktop == effects->currentDesktop() && (!w->isOnDesktop( painting_desktop )) ) |
|
opacity = timeLine.value() * cubeOpacity; |
|
} |
|
if( stop ) |
|
{ |
|
opacity = 1.0 - (1.0 - opacity)*( 1.0 - timeLine.value() ); |
|
if( reflectionPainting ) |
|
opacity = 0.5 + ( cubeOpacity - 0.5 )*( 1.0 - timeLine.value() ); |
|
// fade out windows belonging to different desktops |
|
if( painting_desktop == effects->currentDesktop() && (!w->isOnDesktop( painting_desktop )) ) |
|
opacity = cubeOpacity * (1.0 - timeLine.value()); |
|
} |
|
// z-Ordering |
|
if( !w->isDesktop() && !w->isDock() && useZOrdering ) |
|
{ |
|
float zOrdering = (effects->stackingOrder().indexOf( w )+1)*zOrderingFactor; |
|
if( start ) |
|
zOrdering *= timeLine.value(); |
|
if( stop ) |
|
zOrdering *= (1.0 - timeLine.value()); |
|
data.zTranslate += zOrdering; |
|
} |
|
// check for windows belonging to the previous desktop |
|
int prev_desktop = painting_desktop -1; |
|
if( prev_desktop == 0 ) |
|
prev_desktop = effects->numberOfDesktops(); |
|
int next_desktop = painting_desktop +1; |
|
if( next_desktop > effects->numberOfDesktops() ) |
|
next_desktop = 1; |
|
glPushMatrix(); |
|
if( w->isOnDesktop( prev_desktop ) && ( mask & PAINT_WINDOW_TRANSFORMED ) ) |
|
{ |
|
QRect rect = effects->clientArea( FullArea, activeScreen, prev_desktop); |
|
WindowQuadList new_quads; |
|
foreach( const WindowQuad &quad, data.quads ) |
|
{ |
|
if( quad.right() > rect.width() - w->x() ) |
|
{ |
|
new_quads.append( quad ); |
|
} |
|
} |
|
data.quads = new_quads; |
|
RotationData rot = RotationData(); |
|
rot.axis = RotationData::YAxis; |
|
rot.xRotationPoint = rect.width() - w->x(); |
|
rot.angle = 360.0f / effects->numberOfDesktops(); |
|
data.rotation = &rot; |
|
float cubeAngle = (float)((float)(effects->numberOfDesktops() - 2 )/(float)effects->numberOfDesktops() * 180.0f); |
|
float point = rect.width()/2*tan(cubeAngle*0.5f*M_PI/180.0f); |
|
glTranslatef( rect.width()/2, 0.0, -point ); |
|
glRotatef( -360.0f / effects->numberOfDesktops(), 0.0, 1.0, 0.0 ); |
|
glTranslatef( -rect.width()/2, 0.0, point ); |
|
} |
|
if( w->isOnDesktop( next_desktop ) && ( mask & PAINT_WINDOW_TRANSFORMED ) ) |
|
{ |
|
QRect rect = effects->clientArea( FullArea, activeScreen, next_desktop); |
|
WindowQuadList new_quads; |
|
foreach( const WindowQuad &quad, data.quads ) |
|
{ |
|
if( w->x() + quad.right() <= rect.x() ) |
|
{ |
|
new_quads.append( quad ); |
|
} |
|
} |
|
data.quads = new_quads; |
|
RotationData rot = RotationData(); |
|
rot.axis = RotationData::YAxis; |
|
rot.xRotationPoint = -w->x(); |
|
rot.angle = -360.0f / effects->numberOfDesktops(); |
|
data.rotation = &rot; |
|
float cubeAngle = (float)((float)(effects->numberOfDesktops() - 2 )/(float)effects->numberOfDesktops() * 180.0f); |
|
float point = rect.width()/2*tan(cubeAngle*0.5f*M_PI/180.0f); |
|
glTranslatef( rect.width()/2, 0.0, -point ); |
|
glRotatef( 360.0f / effects->numberOfDesktops(), 0.0, 1.0, 0.0 ); |
|
glTranslatef( -rect.width()/2, 0.0, point ); |
|
} |
|
QRect rect = effects->clientArea( FullArea, activeScreen, painting_desktop ); |
|
|
|
if( start || stop ) |
|
{ |
|
// we have to change opacity values for fade in/out of windows which are shown on front-desktop |
|
if( prev_desktop == effects->currentDesktop() && w->x() < rect.x() ) |
|
{ |
|
if( start ) |
|
opacity = timeLine.value() * cubeOpacity; |
|
if( stop ) |
|
opacity = cubeOpacity * (1.0 - timeLine.value()); |
|
} |
|
if( next_desktop == effects->currentDesktop() && w->x() + w->width() > rect.x() + rect.width() ) |
|
{ |
|
if( start ) |
|
opacity = timeLine.value() * cubeOpacity; |
|
if( stop ) |
|
opacity = cubeOpacity * (1.0 - timeLine.value()); |
|
} |
|
} |
|
// HACK set opacity to 0.99 in case of fully opaque to ensure that windows are painted in correct sequence |
|
// bug #173214 |
|
if( opacity > 0.99f ) |
|
opacity = 0.99f; |
|
if( opacityDesktopOnly && !w->isDesktop() ) |
|
opacity = 0.99f; |
|
data.opacity *= opacity; |
|
|
|
if( w->isOnDesktop(painting_desktop) && w->x() < rect.x() ) |
|
{ |
|
WindowQuadList new_quads; |
|
foreach( const WindowQuad &quad, data.quads ) |
|
{ |
|
if( quad.right() > -w->x() ) |
|
{ |
|
new_quads.append( quad ); |
|
} |
|
} |
|
data.quads = new_quads; |
|
} |
|
if( w->isOnDesktop(painting_desktop) && w->x() + w->width() > rect.x() + rect.width() ) |
|
{ |
|
WindowQuadList new_quads; |
|
foreach( const WindowQuad &quad, data.quads ) |
|
{ |
|
if( quad.right() <= rect.width() - w->x() ) |
|
{ |
|
new_quads.append( quad ); |
|
} |
|
} |
|
data.quads = new_quads; |
|
} |
|
if( w->y() < rect.y() ) |
|
{ |
|
WindowQuadList new_quads; |
|
foreach( const WindowQuad &quad, data.quads ) |
|
{ |
|
if( quad.bottom() > -w->y() ) |
|
{ |
|
new_quads.append( quad ); |
|
} |
|
} |
|
data.quads = new_quads; |
|
} |
|
if( w->y() + w->height() > rect.y() + rect.height() ) |
|
{ |
|
WindowQuadList new_quads; |
|
foreach( const WindowQuad &quad, data.quads ) |
|
{ |
|
if( quad.bottom() <= rect.height() - w->y() ) |
|
{ |
|
new_quads.append( quad ); |
|
} |
|
} |
|
data.quads = new_quads; |
|
} |
|
} |
|
effects->paintWindow( w, mask, region, data ); |
|
if( activated && cube_painting ) |
|
{ |
|
if( w->isDesktop() && effects->numScreens() > 1 && paintCaps ) |
|
{ |
|
QRect rect = effects->clientArea( FullArea, activeScreen, painting_desktop ); |
|
QRegion paint = QRegion( rect ); |
|
for( int i=0; i<effects->numScreens(); i++ ) |
|
{ |
|
if( i == w->screen() ) |
|
continue; |
|
paint = paint.subtracted( QRegion( effects->clientArea( ScreenArea, i, painting_desktop ))); |
|
} |
|
paint = paint.subtracted( QRegion( w->geometry())); |
|
// in case of free area in multiscreen setup fill it with cap color |
|
if( !paint.isEmpty() ) |
|
{ |
|
if( mode == Cylinder ) |
|
{ |
|
cylinderShader->setUniform( "useTexture", -1.0f ); |
|
cylinderShader->setUniform( "xCoord", 0.0f ); |
|
} |
|
if( mode == Sphere ) |
|
{ |
|
sphereShader->setUniform( "useTexture", -1.0f ); |
|
sphereShader->setUniform( "xCoord", 0.0f ); |
|
sphereShader->setUniform( "yCoord", 0.0f ); |
|
} |
|
glColor4f( capColor.redF(), capColor.greenF(), capColor.blueF(), cubeOpacity ); |
|
glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT ); |
|
glEnable( GL_BLEND ); |
|
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); |
|
glBegin( GL_QUADS ); |
|
float quadSize = 0.0f; |
|
int leftDesktop = frontDesktop -1; |
|
int rightDesktop = frontDesktop + 1; |
|
if( leftDesktop == 0 ) |
|
leftDesktop = effects->numberOfDesktops(); |
|
if( rightDesktop > effects->numberOfDesktops() ) |
|
rightDesktop = 1; |
|
if( painting_desktop == frontDesktop ) |
|
quadSize = 100.0f; |
|
else if( painting_desktop == leftDesktop || painting_desktop == rightDesktop ) |
|
quadSize = 150.0f; |
|
else |
|
quadSize = 250.0f; |
|
foreach( const QRect &paintRect, paint.rects() ) |
|
{ |
|
for( int i=0; i<=(paintRect.height()/quadSize); i++ ) |
|
{ |
|
for( int j=0; j<=(paintRect.width()/quadSize); j++ ) |
|
{ |
|
glVertex2f( paintRect.x()+j*quadSize, paintRect.y()+i*quadSize ); |
|
glVertex2f( qMin( paintRect.x()+(j+1)*quadSize, (float)paintRect.x() + paintRect.width() ), |
|
paintRect.y()+i*quadSize ); |
|
glVertex2f( qMin( paintRect.x()+(j+1)*quadSize, (float)paintRect.x() + paintRect.width() ), |
|
qMin( paintRect.y() + (i+1)*quadSize, (float)paintRect.y() + paintRect.height() ) ); |
|
glVertex2f( paintRect.x()+j*quadSize, |
|
qMin( paintRect.y() + (i+1)*quadSize, (float)paintRect.y() + paintRect.height() ) ); |
|
} |
|
} |
|
} |
|
glEnd(); |
|
glDisable( GL_BLEND ); |
|
glPopAttrib(); |
|
} |
|
} |
|
glPopMatrix(); |
|
if( mode == Cylinder ) |
|
cylinderShader->unbind(); |
|
if( mode == Sphere ) |
|
sphereShader->unbind(); |
|
} |
|
} |
|
|
|
bool CubeEffect::borderActivated( ElectricBorder border ) |
|
{ |
|
if( !borderActivate.contains( border ) && |
|
!borderActivateCylinder.contains( border ) && |
|
!borderActivateSphere.contains( border ) ) |
|
return false; |
|
if( effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this ) |
|
return false; |
|
if( borderActivate.contains( border ) ) |
|
{ |
|
if( !activated || ( activated && mode == Cube ) ) |
|
toggleCube(); |
|
else |
|
return false; |
|
} |
|
if( borderActivateCylinder.contains( border ) ) |
|
{ |
|
if( !activated || ( activated && mode == Cylinder ) ) |
|
toggleCylinder(); |
|
else |
|
return false; |
|
} |
|
if( borderActivateSphere.contains( border ) ) |
|
{ |
|
if( !activated || ( activated && mode == Sphere ) ) |
|
toggleSphere(); |
|
else |
|
return false; |
|
} |
|
return true; |
|
} |
|
|
|
void CubeEffect::toggleCube() |
|
{ |
|
kDebug(1212) << "toggle cube"; |
|
toggle( Cube ); |
|
} |
|
|
|
void CubeEffect::toggleCylinder() |
|
{ |
|
kDebug(1212) << "toggle cylinder"; |
|
if( !useShaders ) |
|
useShaders = loadShader(); |
|
if( useShaders ) |
|
toggle( Cylinder ); |
|
else |
|
kError( 1212 ) << "Sorry shaders are not available - cannot activate Cylinder"; |
|
} |
|
|
|
void CubeEffect::toggleSphere() |
|
{ |
|
kDebug(1212) << "toggle sphere"; |
|
if( !useShaders ) |
|
useShaders = loadShader(); |
|
if( useShaders ) |
|
toggle( Sphere ); |
|
else |
|
kError( 1212 ) << "Sorry shaders are not available - cannot activate Sphere"; |
|
} |
|
|
|
void CubeEffect::toggle( CubeMode newMode ) |
|
{ |
|
if( ( effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this ) || |
|
effects->numberOfDesktops() < 2 ) |
|
return; |
|
if( !activated ) |
|
{ |
|
mode = newMode; |
|
setActive( true ); |
|
} |
|
else |
|
{ |
|
setActive( false ); |
|
} |
|
} |
|
|
|
void CubeEffect::grabbedKeyboardEvent( QKeyEvent* e ) |
|
{ |
|
if( stop ) |
|
return; |
|
// taken from desktopgrid.cpp |
|
if( e->type() == QEvent::KeyPress ) |
|
{ |
|
// check for global shortcuts |
|
// HACK: keyboard grab disables the global shortcuts so we have to check for global shortcut (bug 156155) |
|
if( mode == Cube && cubeShortcut.contains( e->key() + e->modifiers() ) ) |
|
{ |
|
toggleCube(); |
|
return; |
|
} |
|
if( mode == Cylinder && cylinderShortcut.contains( e->key() + e->modifiers() ) ) |
|
{ |
|
toggleCylinder(); |
|
return; |
|
} |
|
if( mode == Sphere && sphereShortcut.contains( e->key() + e->modifiers() ) ) |
|
{ |
|
toggleSphere(); |
|
return; |
|
} |
|
|
|
int desktop = -1; |
|
// switch by F<number> or just <number> |
|
if( e->key() >= Qt::Key_F1 && e->key() <= Qt::Key_F35 ) |
|
desktop = e->key() - Qt::Key_F1 + 1; |
|
else if( e->key() >= Qt::Key_0 && e->key() <= Qt::Key_9 ) |
|
desktop = e->key() == Qt::Key_0 ? 10 : e->key() - Qt::Key_0; |
|
if( desktop != -1 ) |
|
{ |
|
if( desktop <= effects->numberOfDesktops()) |
|
{ |
|
// we have to rotate to chosen desktop |
|
// and end effect when rotation finished |
|
rotateToDesktop( desktop ); |
|
setActive( false ); |
|
} |
|
return; |
|
} |
|
switch( e->key()) |
|
{ // wrap only on autorepeat |
|
case Qt::Key_Left: |
|
// rotate to previous desktop |
|
kDebug(1212) << "left"; |
|
if( !rotating && !start ) |
|
{ |
|
rotating = true; |
|
if( invertKeys ) |
|
rotationDirection = Right; |
|
else |
|
rotationDirection = Left; |
|
} |
|
else |
|
{ |
|
if( rotations.count() < effects->numberOfDesktops() ) |
|
{ |
|
if( invertKeys ) |
|
rotations.enqueue( Right ); |
|
else |
|
rotations.enqueue( Left ); |
|
} |
|
} |
|
break; |
|
case Qt::Key_Right: |
|
// rotate to next desktop |
|
kDebug(1212) << "right"; |
|
if( !rotating && !start ) |
|
{ |
|
rotating = true; |
|
if( invertKeys ) |
|
rotationDirection = Left; |
|
else |
|
rotationDirection = Right; |
|
} |
|
else |
|
{ |
|
if( rotations.count() < effects->numberOfDesktops() ) |
|
{ |
|
if( invertKeys ) |
|
rotations.enqueue( Left ); |
|
else |
|
rotations.enqueue( Right ); |
|
} |
|
} |
|
break; |
|
case Qt::Key_Up: |
|
kDebug(1212) << "up"; |
|
if( invertKeys ) |
|
{ |
|
if( verticalPosition != Down ) |
|
{ |
|
if( !verticalRotating ) |
|
{ |
|
verticalRotating = true; |
|
verticalRotationDirection = Downwards; |
|
if( verticalPosition == Normal ) |
|
verticalPosition = Down; |
|
if( verticalPosition == Up ) |
|
verticalPosition = Normal; |
|
} |
|
else |
|
{ |
|
verticalRotations.enqueue( Downwards ); |
|
} |
|
} |
|
else if( manualVerticalAngle > 0.0 && !verticalRotating ) |
|
{ |
|
// rotate to down position from the manual position |
|
verticalRotating = true; |
|
verticalRotationDirection = Downwards; |
|
verticalPosition = Down; |
|
manualVerticalAngle -= 90.0; |
|
} |
|
} |
|
else |
|
{ |
|
if( verticalPosition != Up ) |
|
{ |
|
if( !verticalRotating ) |
|
{ |
|
verticalRotating = true; |
|
verticalRotationDirection = Upwards; |
|
if( verticalPosition == Normal ) |
|
verticalPosition = Up; |
|
if( verticalPosition == Down ) |
|
verticalPosition = Normal; |
|
} |
|
else |
|
{ |
|
verticalRotations.enqueue( Upwards ); |
|
} |
|
} |
|
else if( manualVerticalAngle < 0.0 && !verticalRotating ) |
|
{ |
|
// rotate to up position from the manual position |
|
verticalRotating = true; |
|
verticalRotationDirection = Upwards; |
|
verticalPosition = Up; |
|
manualVerticalAngle += 90.0; |
|
} |
|
} |
|
break; |
|
case Qt::Key_Down: |
|
kDebug(1212) << "down"; |
|
if( invertKeys ) |
|
{ |
|
if( verticalPosition != Up ) |
|
{ |
|
if( !verticalRotating ) |
|
{ |
|
verticalRotating = true; |
|
verticalRotationDirection = Upwards; |
|
if( verticalPosition == Normal ) |
|
verticalPosition = Up; |
|
if( verticalPosition == Down ) |
|
verticalPosition = Normal; |
|
} |
|
else |
|
{ |
|
verticalRotations.enqueue( Upwards ); |
|
} |
|
} |
|
else if( manualVerticalAngle < 0.0 && !verticalRotating ) |
|
{ |
|
// rotate to up position from the manual position |
|
verticalRotating = true; |
|
verticalRotationDirection = Upwards; |
|
verticalPosition = Up; |
|
manualVerticalAngle += 90.0; |
|
} |
|
} |
|
else |
|
{ |
|
if( verticalPosition != Down ) |
|
{ |
|
if( !verticalRotating ) |
|
{ |
|
verticalRotating = true; |
|
verticalRotationDirection = Downwards; |
|
if( verticalPosition == Normal ) |
|
verticalPosition = Down; |
|
if( verticalPosition == Up ) |
|
verticalPosition = Normal; |
|
} |
|
else |
|
{ |
|
verticalRotations.enqueue( Downwards ); |
|
} |
|
} |
|
else if( manualVerticalAngle > 0.0 && !verticalRotating ) |
|
{ |
|
// rotate to down position from the manual position |
|
verticalRotating = true; |
|
verticalRotationDirection = Downwards; |
|
verticalPosition = Down; |
|
manualVerticalAngle -= 90.0; |
|
} |
|
} |
|
break; |
|
case Qt::Key_Escape: |
|
rotateToDesktop( effects->currentDesktop() ); |
|
setActive( false ); |
|
return; |
|
case Qt::Key_Enter: |
|
case Qt::Key_Return: |
|
case Qt::Key_Space: |
|
setActive( false ); |
|
return; |
|
case Qt::Key_Plus: |
|
zoom -= 10.0; |
|
zoom = qMax( -zPosition, zoom ); |
|
recompileList = true; |
|
break; |
|
case Qt::Key_Minus: |
|
zoom += 10.0f; |
|
recompileList = true; |
|
break; |
|
default: |
|
break; |
|
} |
|
effects->addRepaintFull(); |
|
} |
|
} |
|
|
|
void CubeEffect::rotateToDesktop( int desktop ) |
|
{ |
|
int tempFrontDesktop = frontDesktop; |
|
if( !rotations.empty() ) |
|
{ |
|
// all scheduled rotations will be removed as a speed up |
|
rotations.clear(); |
|
} |
|
if( rotating && !desktopChangedWhileRotating ) |
|
{ |
|
// front desktop will change during the actual rotation - this has to be considered |
|
if( rotationDirection == Left ) |
|
{ |
|
tempFrontDesktop++; |
|
} |
|
else if( rotationDirection == Right ) |
|
{ |
|
tempFrontDesktop--; |
|
} |
|
if( tempFrontDesktop > effects->numberOfDesktops() ) |
|
tempFrontDesktop = 1; |
|
else if( tempFrontDesktop == 0 ) |
|
tempFrontDesktop = effects->numberOfDesktops(); |
|
} |
|
// find the fastest rotation path from tempFrontDesktop to desktop |
|
int rightRotations = tempFrontDesktop - desktop; |
|
if( rightRotations < 0 ) |
|
rightRotations += effects->numberOfDesktops(); |
|
int leftRotations = desktop - tempFrontDesktop; |
|
if( leftRotations < 0 ) |
|
leftRotations += effects->numberOfDesktops(); |
|
if( leftRotations <= rightRotations ) |
|
{ |
|
for( int i=0; i<leftRotations; i++ ) |
|
{ |
|
rotations.enqueue( Left ); |
|
} |
|
} |
|
else |
|
{ |
|
for( int i=0; i<rightRotations; i++ ) |
|
{ |
|
rotations.enqueue( Right ); |
|
} |
|
} |
|
if( !start && !rotating && !rotations.empty() ) |
|
{ |
|
rotating = true; |
|
rotationDirection = rotations.dequeue(); |
|
} |
|
// change timeline curve if more rotations are following |
|
if( !rotations.empty() ) |
|
{ |
|
currentShape = TimeLine::EaseInCurve; |
|
timeLine.setCurveShape( currentShape ); |
|
} |
|
} |
|
|
|
void CubeEffect::setActive( bool active ) |
|
{ |
|
foreach( CubeInsideEffect* inside, m_cubeInsideEffects ) |
|
{ |
|
inside->setActive( true ); |
|
} |
|
if( active ) |
|
{ |
|
if( !mousePolling ) |
|
{ |
|
effects->startMousePolling(); |
|
mousePolling = true; |
|
} |
|
activated = true; |
|
activeScreen = effects->activeScreen(); |
|
keyboard_grab = effects->grabKeyboard( this ); |
|
input = effects->createInputWindow( this, 0, 0, displayWidth(), displayHeight(), |
|
Qt::OpenHandCursor ); |
|
frontDesktop = effects->currentDesktop(); |
|
zoom = 0.0; |
|
zOrderingFactor = zPosition / ( effects->stackingOrder().count() - 1 ); |
|
start = true; |
|
effects->setActiveFullScreenEffect( this ); |
|
kDebug(1212) << "Cube is activated"; |
|
verticalPosition = Normal; |
|
verticalRotating = false; |
|
manualAngle = 0.0; |
|
manualVerticalAngle = 0.0; |
|
if( reflection ) |
|
{ |
|
// clip parts above the reflection area |
|
double eqn[4] = {0.0, 1.0, 0.0, 0.0}; |
|
glPushMatrix(); |
|
QRect rect = effects->clientArea( FullArea, activeScreen, effects->currentDesktop()); |
|
glTranslatef( 0.0, rect.height(), 0.0 ); |
|
glClipPlane( GL_CLIP_PLANE0, eqn ); |
|
glPopMatrix(); |
|
float temporaryCoeff = float( rect.width() ) / tan( M_PI / float( effects->numberOfDesktops() ) ); |
|
mAddedHeightCoeff1 = sqrt( float( rect.height() ) * float( rect.height() ) + temporaryCoeff * temporaryCoeff ); |
|
mAddedHeightCoeff2 = sqrt( float( rect.height() ) * float( rect.height() ) + float( rect.width() ) * float( rect.width() ) + temporaryCoeff * temporaryCoeff ); |
|
} |
|
// create the needed GL lists |
|
glList = glGenLists(3); |
|
capListCreated = false; |
|
recompileList = true; |
|
useList = false; |
|
// create the capList |
|
if( paintCaps ) |
|
paintCap(); |
|
effects->addRepaintFull(); |
|
} |
|
else |
|
{ |
|
if( mousePolling ) |
|
{ |
|
effects->stopMousePolling(); |
|
mousePolling = false; |
|
} |
|
schedule_close = true; |
|
// we have to add a repaint, to start the deactivating |
|
effects->addRepaintFull(); |
|
} |
|
} |
|
|
|
void CubeEffect::mouseChanged( const QPoint& pos, const QPoint& oldpos, Qt::MouseButtons buttons, |
|
Qt::MouseButtons oldbuttons, Qt::KeyboardModifiers, Qt::KeyboardModifiers ) |
|
{ |
|
if( !activated ) |
|
return; |
|
if( tabBoxMode ) |
|
return; |
|
if( stop ) |
|
return; |
|
QRect rect = effects->clientArea( FullArea, activeScreen, effects->currentDesktop() ); |
|
if( buttons.testFlag( Qt::LeftButton ) ) |
|
{ |
|
bool repaint = false; |
|
// vertical movement only if there is not a rotation |
|
if( !verticalRotating ) |
|
{ |
|
// display height corresponds to 180* |
|
int deltaY = pos.y() - oldpos.y(); |
|
float deltaVerticalDegrees = (float)deltaY/rect.height()*180.0f; |
|
if( invertMouse ) |
|
manualVerticalAngle += deltaVerticalDegrees; |
|
else |
|
manualVerticalAngle -= deltaVerticalDegrees; |
|
if( deltaVerticalDegrees != 0.0 ) |
|
repaint = true; |
|
} |
|
// horizontal movement only if there is not a rotation |
|
if( !rotating ) |
|
{ |
|
// display width corresponds to sum of angles of the polyhedron |
|
int deltaX = oldpos.x() - pos.x(); |
|
float deltaDegrees = (float)deltaX/rect.width() * 360.0f; |
|
if( deltaX == 0 ) |
|
{ |
|
if( pos.x() == 0 ) |
|
deltaDegrees = 5.0f; |
|
if( pos.x() == displayWidth() -1 ) |
|
deltaDegrees = -5.0f; |
|
} |
|
if( invertMouse ) |
|
manualAngle += deltaDegrees; |
|
else |
|
manualAngle -= deltaDegrees; |
|
if( deltaDegrees != 0.0 ) |
|
repaint = true; |
|
} |
|
if( repaint ) |
|
{ |
|
recompileList = true; |
|
effects->addRepaintFull(); |
|
} |
|
} |
|
if( !oldbuttons.testFlag( Qt::LeftButton ) && buttons.testFlag( Qt::LeftButton ) ) |
|
{ |
|
XDefineCursor( display(), input, QCursor( Qt::ClosedHandCursor).handle() ); |
|
} |
|
if( oldbuttons.testFlag( Qt::LeftButton) && !buttons.testFlag( Qt::LeftButton ) ) |
|
{ |
|
XDefineCursor( display(), input, QCursor( Qt::OpenHandCursor).handle() ); |
|
if( closeOnMouseRelease ) |
|
setActive( false ); |
|
} |
|
if( oldbuttons.testFlag( Qt::RightButton) && !buttons.testFlag( Qt::RightButton ) ) |
|
{ |
|
// end effect on right mouse button |
|
setActive( false ); |
|
} |
|
} |
|
|
|
void CubeEffect::windowInputMouseEvent( Window w, QEvent* e ) |
|
{ |
|
assert( w == input ); |
|
Q_UNUSED( w ); |
|
QMouseEvent *mouse = dynamic_cast< QMouseEvent* >( e ); |
|
if( mouse && mouse->type() == QEvent::MouseButtonRelease ) |
|
{ |
|
if( mouse->button() == Qt::XButton1 ) |
|
{ |
|
if( !rotating && !start ) |
|
{ |
|
rotating = true; |
|
if( invertMouse ) |
|
rotationDirection = Right; |
|
else |
|
rotationDirection = Left; |
|
} |
|
else |
|
{ |
|
if( rotations.count() < effects->numberOfDesktops() ) |
|
{ |
|
if( invertMouse ) |
|
rotations.enqueue( Right ); |
|
else |
|
rotations.enqueue( Left ); |
|
} |
|
} |
|
effects->addRepaintFull(); |
|
} |
|
if( mouse->button() == Qt::XButton2 ) |
|
{ |
|
if( !rotating && !start ) |
|
{ |
|
rotating = true; |
|
if( invertMouse ) |
|
rotationDirection = Left; |
|
else |
|
rotationDirection = Right; |
|
} |
|
else |
|
{ |
|
if( rotations.count() < effects->numberOfDesktops() ) |
|
{ |
|
if( invertMouse ) |
|
rotations.enqueue( Left ); |
|
else |
|
rotations.enqueue( Right ); |
|
} |
|
} |
|
effects->addRepaintFull(); |
|
} |
|
} |
|
} |
|
|
|
void CubeEffect::tabBoxAdded( int mode ) |
|
{ |
|
if( activated ) |
|
return; |
|
if( effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this ) |
|
return; |
|
if( useForTabBox && mode != TabBoxWindowsMode ) |
|
{ |
|
effects->refTabBox(); |
|
tabBoxMode = true; |
|
setActive( true ); |
|
rotateToDesktop( effects->currentTabBoxDesktop() ); |
|
} |
|
} |
|
|
|
void CubeEffect::tabBoxUpdated() |
|
{ |
|
if( activated ) |
|
rotateToDesktop( effects->currentTabBoxDesktop() ); |
|
} |
|
|
|
void CubeEffect::tabBoxClosed() |
|
{ |
|
if( activated ) |
|
{ |
|
effects->unrefTabBox(); |
|
tabBoxMode = false; |
|
setActive( false ); |
|
} |
|
} |
|
|
|
void CubeEffect::windowAdded( EffectWindow* ) |
|
{ |
|
// when there is a new window we have to paint it once without using GL List |
|
// to prevent that the window is black |
|
if( activated ) |
|
useList = false; |
|
} |
|
|
|
void CubeEffect::cubeShortcutChanged( const QKeySequence& seq ) |
|
{ |
|
cubeShortcut = KShortcut( seq ); |
|
} |
|
|
|
void CubeEffect::cylinderShortcutChanged( const QKeySequence& seq ) |
|
{ |
|
cylinderShortcut = KShortcut( seq ); |
|
} |
|
|
|
void CubeEffect::sphereShortcutChanged( const QKeySequence& seq ) |
|
{ |
|
sphereShortcut = KShortcut( seq ); |
|
} |
|
|
|
void* CubeEffect::proxy() |
|
{ |
|
return &m_proxy; |
|
} |
|
|
|
void CubeEffect::registerCubeInsideEffect(CubeInsideEffect* effect) |
|
{ |
|
m_cubeInsideEffects.append( effect ); |
|
} |
|
|
|
void CubeEffect::unregisterCubeInsideEffect(CubeInsideEffect* effect) |
|
{ |
|
m_cubeInsideEffects.removeAll( effect ); |
|
} |
|
|
|
} // namespace
|
|
|