• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KWinLibraries

kwineffects.cpp

Go to the documentation of this file.
00001 /********************************************************************
00002  KWin - the KDE window manager
00003  This file is part of the KDE project.
00004 
00005 Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>
00006 
00007 This program is free software; you can redistribute it and/or modify
00008 it under the terms of the GNU General Public License as published by
00009 the Free Software Foundation; either version 2 of the License, or
00010 (at your option) any later version.
00011 
00012 This program is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with this program.  If not, see <http://www.gnu.org/licenses/>.
00019 *********************************************************************/
00020 
00021 #include "kwineffects.h"
00022 
00023 #include "kwinglutils.h"
00024 #include "kwinxrenderutils.h"
00025 
00026 #include <QtDBus/QtDBus>
00027 #include <QVariant>
00028 #include <QList>
00029 #include <QtCore/QTimeLine>
00030 #include <QtGui/QFontMetrics>
00031 #include <QtGui/QPainter>
00032 #include <QtGui/QPixmap>
00033 
00034 #include <kdebug.h>
00035 #include <ksharedconfig.h>
00036 #include <kconfiggroup.h>
00037 
00038 #include <assert.h>
00039 
00040 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
00041 #include <X11/extensions/Xrender.h>
00042 #include <X11/extensions/Xfixes.h>
00043 #endif
00044 
00045 namespace KWin
00046 {
00047 
00048 void WindowPrePaintData::setTranslucent()
00049     {
00050     mask |= Effect::PAINT_WINDOW_TRANSLUCENT;
00051     mask &= ~Effect::PAINT_WINDOW_OPAQUE;
00052     clip = QRegion(); // cannot clip, will be transparent
00053     }
00054 
00055 void WindowPrePaintData::setTransformed()
00056     {
00057     mask |= Effect::PAINT_WINDOW_TRANSFORMED;
00058     }
00059 
00060 
00061 WindowPaintData::WindowPaintData( EffectWindow* w )
00062     : opacity( w->opacity())
00063     , contents_opacity( 1.0 )
00064     , decoration_opacity( 1.0 )
00065     , xScale( 1 )
00066     , yScale( 1 )
00067     , zScale( 1 )
00068     , xTranslate( 0 )
00069     , yTranslate( 0 )
00070     , zTranslate( 0 )
00071     , saturation( 1 )
00072     , brightness( 1 )
00073     , shader( NULL )
00074     , rotation( NULL )
00075     {
00076     quads = w->buildQuads();
00077     }
00078 
00079 ScreenPaintData::ScreenPaintData()
00080     : xScale( 1 )
00081     , yScale( 1 )
00082     , zScale( 1 )
00083     , xTranslate( 0 )
00084     , yTranslate( 0 )
00085     , zTranslate( 0 )
00086     , rotation( NULL )
00087     {
00088     }
00089 
00090 RotationData::RotationData()
00091     : axis( ZAxis )
00092     , angle( 0.0 )
00093     , xRotationPoint( 0.0 )
00094     , yRotationPoint( 0.0 )
00095     , zRotationPoint( 0.0 )
00096     {
00097     }
00098 
00099 //****************************************
00100 // Effect
00101 //****************************************
00102 
00103 Effect::Effect()
00104     {
00105     }
00106 
00107 Effect::~Effect()
00108     {
00109     }
00110 
00111 void Effect::reconfigure( ReconfigureFlags )
00112     {
00113     }
00114 
00115 void Effect::windowUserMovedResized( EffectWindow* , bool, bool )
00116     {
00117     }
00118 
00119 void Effect::windowOpacityChanged( EffectWindow*, double )
00120     {
00121     }
00122 
00123 void Effect::windowAdded( EffectWindow* )
00124     {
00125     }
00126 
00127 void Effect::windowClosed( EffectWindow* )
00128     {
00129     }
00130 
00131 void Effect::windowDeleted( EffectWindow* )
00132     {
00133     }
00134 
00135 void Effect::windowActivated( EffectWindow* )
00136     {
00137     }
00138 
00139 void Effect::windowMinimized( EffectWindow* )
00140     {
00141     }
00142 
00143 void Effect::windowUnminimized( EffectWindow* )
00144     {
00145     }
00146 
00147 void Effect::windowInputMouseEvent( Window, QEvent* )
00148     {
00149     }
00150 
00151 void Effect::grabbedKeyboardEvent( QKeyEvent* )
00152     {
00153     }
00154 
00155 void Effect::propertyNotify( EffectWindow* , long )
00156     {
00157     }
00158 
00159 void Effect::desktopChanged( int )
00160     {
00161     }
00162 
00163 void Effect::windowDamaged( EffectWindow*, const QRect& )
00164     {
00165     }
00166 
00167 void Effect::windowGeometryShapeChanged( EffectWindow*, const QRect& )
00168     {
00169     }
00170 
00171 void Effect::tabBoxAdded( int )
00172     {
00173     }
00174 
00175 void Effect::tabBoxClosed()
00176     {
00177     }
00178 
00179 void Effect::tabBoxUpdated()
00180     {
00181     }
00182 bool Effect::borderActivated( ElectricBorder )
00183     {
00184     return false;
00185     }
00186 
00187 void Effect::mouseChanged( const QPoint&, const QPoint&, Qt::MouseButtons,
00188     Qt::MouseButtons, Qt::KeyboardModifiers, Qt::KeyboardModifiers )
00189     {
00190     }
00191 
00192 void Effect::prePaintScreen( ScreenPrePaintData& data, int time )
00193     {
00194     effects->prePaintScreen( data, time );
00195     }
00196 
00197 void Effect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
00198     {
00199     effects->paintScreen( mask, region, data );
00200     }
00201     
00202 void Effect::postPaintScreen()
00203     {
00204     effects->postPaintScreen();
00205     }
00206 
00207 void Effect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time )
00208     {
00209     effects->prePaintWindow( w, data, time );
00210     }
00211 
00212 void Effect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
00213     {
00214     effects->paintWindow( w, mask, region, data );
00215     }
00216 
00217 void Effect::postPaintWindow( EffectWindow* w )
00218     {
00219     effects->postPaintWindow( w );
00220     }
00221 
00222 void Effect::drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
00223     {
00224     effects->drawWindow( w, mask, region, data );
00225     }
00226 
00227 void Effect::buildQuads( EffectWindow* w, WindowQuadList& quadList )
00228     {
00229     effects->buildQuads( w, quadList );
00230     }
00231 
00232 QRect Effect::transformWindowDamage( EffectWindow* w, const QRect& r )
00233     {
00234     return effects->transformWindowDamage( w, r );
00235     }
00236 
00237 void Effect::setPositionTransformations( WindowPaintData& data, QRect& region, EffectWindow* w,
00238     const QRect& r, Qt::AspectRatioMode aspect )
00239     {
00240     QSize size = w->size();
00241     size.scale( r.size(), aspect );
00242     data.xScale = size.width() / double( w->width());
00243     data.yScale = size.height() / double( w->height());
00244     int width = int( w->width() * data.xScale );
00245     int height = int( w->height() * data.yScale );
00246     int x = r.x() + ( r.width() - width ) / 2;
00247     int y = r.y() + ( r.height() - height ) / 2;
00248     region = QRect( x, y, width, height );
00249     data.xTranslate = x - w->x();
00250     data.yTranslate = y - w->y();
00251     }
00252 
00253 int Effect::displayWidth()
00254     {
00255     return KWin::displayWidth();
00256     }
00257 
00258 int Effect::displayHeight()
00259     {
00260     return KWin::displayHeight();
00261     }
00262 
00263 QPoint Effect::cursorPos()
00264     {
00265     return effects->cursorPos();
00266     }
00267 
00268 double Effect::animationTime( const KConfigGroup& cfg, const QString& key, int defaultTime )
00269     {
00270     int time = cfg.readEntry( key, 0 );
00271     return time != 0 ? time : qMax( defaultTime * effects->animationTimeFactor(), 1. );
00272     }
00273 
00274 double Effect::animationTime( int defaultTime )
00275     { // at least 1ms, otherwise 0ms times can break some things
00276     return qMax( defaultTime * effects->animationTimeFactor(), 1. );
00277     }
00278 
00279 //****************************************
00280 // EffectsHandler
00281 //****************************************
00282 
00283 EffectsHandler::EffectsHandler(CompositingType type)
00284     : current_paint_screen( 0 )
00285     , current_paint_window( 0 )
00286     , current_draw_window( 0 )
00287     , current_build_quads( 0 )
00288     , current_transform( 0 )
00289     , compositing_type( type )
00290     {
00291     if( compositing_type == NoCompositing )
00292         return;
00293     KWin::effects = this;
00294     }
00295 
00296 EffectsHandler::~EffectsHandler()
00297     {
00298     // All effects should already be unloaded by Impl dtor
00299     assert( loaded_effects.count() == 0 );
00300     }
00301 
00302 QRect EffectsHandler::transformWindowDamage( EffectWindow* w, const QRect& r )
00303     {
00304     if( current_transform < loaded_effects.size())
00305         {
00306         QRect rr = loaded_effects[current_transform++].second->transformWindowDamage( w, r );
00307         --current_transform;
00308         return rr;
00309         }
00310     else
00311         return r;
00312     }
00313 
00314 Window EffectsHandler::createInputWindow( Effect* e, const QRect& r, const QCursor& cursor )
00315     {
00316     return createInputWindow( e, r.x(), r.y(), r.width(), r.height(), cursor );
00317     }
00318 
00319 Window EffectsHandler::createFullScreenInputWindow( Effect* e, const QCursor& cursor )
00320     {
00321     return createInputWindow( e, 0, 0, displayWidth(), displayHeight(), cursor );
00322     }
00323 
00324 CompositingType EffectsHandler::compositingType() const
00325     {
00326     return compositing_type;
00327     }
00328 
00329 bool EffectsHandler::saturationSupported() const
00330     {
00331     switch( compositing_type )
00332         {
00333 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00334         case OpenGLCompositing:
00335             return GLTexture::saturationSupported();
00336 #endif
00337         case XRenderCompositing:
00338             return false; // never
00339         default:
00340             abort();
00341         }
00342     }
00343 
00344 void EffectsHandler::sendReloadMessage( const QString& effectname )
00345     {
00346     QDBusMessage message = QDBusMessage::createMethodCall("org.kde.kwin", "/KWin", "org.kde.KWin", "reconfigureEffect");
00347     message << QString("kwin4_effect_" + effectname);
00348     QDBusConnection::sessionBus().send(message);
00349     }
00350 
00351 KConfigGroup EffectsHandler::effectConfig( const QString& effectname )
00352     {
00353     KSharedConfig::Ptr kwinconfig = KSharedConfig::openConfig( "kwinrc", KConfig::NoGlobals );
00354     return kwinconfig->group( "Effect-" + effectname );
00355     }
00356 
00357 bool EffectsHandler::paintText( const QString& text, const QRect& rect, const QColor& color,
00358         const QFont& font, const Qt::Alignment& alignment )
00359 {
00360     QPainter p;
00361     // Calculate size of the text
00362     QFontMetrics fm( font );
00363     QString painttext = fm.elidedText( text, Qt::ElideRight, rect.width() );
00364     QRect textrect = fm.boundingRect( painttext );
00365 
00366     // Create temporary QImage where the text will be drawn onto
00367     QImage textImage( textrect.width(), textrect.height(), QImage::Format_ARGB32 );
00368     textImage.fill( Qt::transparent );
00369 
00370     // Draw the text
00371     p.begin( &textImage );
00372     p.setFont( font );
00373     p.setRenderHint( QPainter::TextAntialiasing );
00374     p.setPen( color );
00375     p.drawText( -textrect.topLeft(), painttext );
00376     p.end();
00377 
00378     // Area covered by text
00379     int rectX, rectY;
00380     if( alignment & Qt::AlignLeft )
00381         rectX = rect.x();
00382     else if( alignment & Qt::AlignRight )
00383         rectX = rect.right() - textrect.width();
00384     else
00385         rectX = rect.center().x() - textrect.width() / 2;
00386     if( alignment & Qt::AlignTop )
00387         rectY = rect.y();
00388     else if( alignment & Qt::AlignBottom )
00389         rectY = rect.bottom() - textrect.height();
00390     else
00391         rectY = rect.center().y() - textrect.height() / 2;
00392     QRect area( rectX, rectY, textrect.width(), textrect.height() );
00393 
00394 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00395     if( effects->compositingType() == OpenGLCompositing )
00396         {
00397         GLTexture textTexture( textImage, GL_TEXTURE_RECTANGLE_ARB );
00398         glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT );
00399         glEnable( GL_BLEND );
00400         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
00401         textTexture.bind();
00402         textTexture.render( infiniteRegion(), area );
00403         textTexture.unbind();
00404         glPopAttrib();
00405         return true;
00406         }
00407 #endif
00408 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
00409     if( effects->compositingType() == XRenderCompositing )
00410         {
00411         XRenderPicture textPicture( QPixmap::fromImage( textImage ));
00412         XRenderComposite( display(), textImage.depth() == 32 ? PictOpOver : PictOpSrc,
00413             textPicture, None, effects->xrenderBufferPicture(),
00414             0, 0, 0, 0, area.x(), area.y(), area.width(), area.height());
00415         return true;
00416         }
00417 #endif
00418     return false;
00419 }
00420 
00421 bool EffectsHandler::paintTextWithBackground( const QString& text, const QRect& rect, const QColor& color,
00422         const QColor& bgcolor, const QFont& font, const Qt::Alignment& alignment )
00423 {
00424     // Calculate size of the text
00425     QFontMetrics fm( font );
00426     QString painttext = fm.elidedText( text, Qt::ElideRight, rect.width() );
00427     QRect textrect = fm.boundingRect( painttext );
00428 
00429     // Area covered by text
00430     int rectX, rectY;
00431     if( alignment & Qt::AlignLeft )
00432         rectX = rect.x();
00433     else if( alignment & Qt::AlignRight )
00434         rectX = rect.right() - textrect.width();
00435     else
00436         rectX = rect.center().x() - textrect.width() / 2;
00437     if( alignment & Qt::AlignTop )
00438         rectY = rect.y();
00439     else if( alignment & Qt::AlignBottom )
00440         rectY = rect.bottom() - textrect.height();
00441     else
00442         rectY = rect.center().y() - textrect.height() / 2;
00443     QRect area( rectX, rectY, textrect.width(), textrect.height() );
00444 
00445 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00446     if( effects->compositingType() == OpenGLCompositing )
00447     {
00448         glColor4f( bgcolor.redF(), bgcolor.greenF(), bgcolor.blueF(), bgcolor.alphaF() );
00449         renderRoundBox( area.adjusted( -8, -3, 8, 3 ), 5 );
00450 
00451         return paintText( text, rect, color, font, alignment );
00452     }
00453 #endif
00454 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
00455     if( effects->compositingType() == XRenderCompositing )
00456     {
00457         xRenderRoundBox( effects->xrenderBufferPicture(), area.adjusted( -8, -3, 8, 3 ), 5, bgcolor );
00458         return paintText( text, rect, color, font, alignment );
00459     }
00460 #endif
00461     return false;
00462 }
00463 
00464 
00465 EffectsHandler* effects = 0;
00466 
00467 
00468 //****************************************
00469 // EffectWindow
00470 //****************************************
00471 
00472 EffectWindow::EffectWindow()
00473     {
00474     }
00475 
00476 EffectWindow::~EffectWindow()
00477     {
00478     }
00479 
00480 bool EffectWindow::isOnCurrentDesktop() const
00481     {
00482     return isOnDesktop( effects->currentDesktop());
00483     }
00484 
00485 bool EffectWindow::isOnDesktop( int d ) const
00486     {
00487     return desktop() == d || isOnAllDesktops();
00488     }
00489 
00490 bool EffectWindow::hasDecoration() const
00491     {
00492     return contentsRect() != QRect( 0, 0, width(), height());
00493     }
00494 
00495 
00496 //****************************************
00497 // EffectWindowGroup
00498 //****************************************
00499 
00500 EffectWindowGroup::~EffectWindowGroup()
00501     {
00502     }
00503 
00504 //****************************************
00505 // GlobalShortcutsEditor
00506 //****************************************
00507 
00508 GlobalShortcutsEditor::GlobalShortcutsEditor( QWidget *parent ) :
00509         KShortcutsEditor( parent, GlobalAction )
00510     {
00511     }
00512 
00513 /***************************************************************
00514  WindowQuad
00515 ***************************************************************/
00516 
00517 WindowQuad WindowQuad::makeSubQuad( double x1, double y1, double x2, double y2 ) const
00518     {
00519     assert( x1 < x2 && y1 < y2 && x1 >= left() && x2 <= right() && y1 >= top() && y2 <= bottom());
00520 #ifndef NDEBUG
00521     if( isTransformed())
00522         kFatal( 1212 ) << "Splitting quads is allowed only in pre-paint calls!" ;
00523 #endif
00524     WindowQuad ret( *this );
00525     // vertices are clockwise starting from topleft
00526     ret.verts[ 0 ].px = x1;
00527     ret.verts[ 3 ].px = x1;
00528     ret.verts[ 1 ].px = x2;
00529     ret.verts[ 2 ].px = x2;
00530     ret.verts[ 0 ].py = y1;
00531     ret.verts[ 1 ].py = y1;
00532     ret.verts[ 2 ].py = y2;
00533     ret.verts[ 3 ].py = y2;
00534     // original x/y are supposed to be the same, no transforming is done here
00535     ret.verts[ 0 ].ox = x1;
00536     ret.verts[ 3 ].ox = x1;
00537     ret.verts[ 1 ].ox = x2;
00538     ret.verts[ 2 ].ox = x2;
00539     ret.verts[ 0 ].oy = y1;
00540     ret.verts[ 1 ].oy = y1;
00541     ret.verts[ 2 ].oy = y2;
00542     ret.verts[ 3 ].oy = y2;
00543     double my_tleft = verts[ 0 ].tx;
00544     double my_tright = verts[ 2 ].tx;
00545     double my_ttop = verts[ 0 ].ty;
00546     double my_tbottom = verts[ 2 ].ty;
00547     double tleft = ( x1 - left()) / ( right() - left()) * ( my_tright - my_tleft ) + my_tleft;
00548     double tright = ( x2 - left()) / ( right() - left()) * ( my_tright - my_tleft ) + my_tleft;
00549     double ttop = ( y1 - top()) / ( bottom() - top()) * ( my_tbottom - my_ttop ) + my_ttop;
00550     double tbottom = ( y2 - top()) / ( bottom() - top()) * ( my_tbottom - my_ttop ) + my_ttop;
00551     ret.verts[ 0 ].tx = tleft;
00552     ret.verts[ 3 ].tx = tleft;
00553     ret.verts[ 1 ].tx = tright;
00554     ret.verts[ 2 ].tx = tright;
00555     ret.verts[ 0 ].ty = ttop;
00556     ret.verts[ 1 ].ty = ttop;
00557     ret.verts[ 2 ].ty = tbottom;
00558     ret.verts[ 3 ].ty = tbottom;
00559     return ret;
00560     }
00561 
00562 bool WindowQuad::smoothNeeded() const
00563     {
00564     // smoothing is needed if the width or height of the quad does not match the original size
00565     double width = verts[ 1 ].ox - verts[ 0 ].ox;
00566     double height = verts[ 2 ].oy - verts[ 1 ].oy;
00567     return( verts[ 1 ].px - verts[ 0 ].px != width || verts[ 2 ].px - verts[ 3 ].px != width
00568         || verts[ 2 ].py - verts[ 1 ].py != height || verts[ 3 ].py - verts[ 0 ].py != height );
00569     }
00570 
00571 /***************************************************************
00572  WindowQuadList
00573 ***************************************************************/
00574 
00575 WindowQuadList WindowQuadList::splitAtX( double x ) const
00576     {
00577     WindowQuadList ret;
00578     foreach( const WindowQuad &quad, *this )
00579         {
00580 #ifndef NDEBUG
00581         if( quad.isTransformed())
00582             kFatal( 1212 ) << "Splitting quads is allowed only in pre-paint calls!" ;
00583 #endif
00584         bool wholeleft = true;
00585         bool wholeright = true;
00586         for( int i = 0;
00587              i < 4;
00588              ++i )
00589             {
00590             if( quad[ i ].x() < x )
00591                 wholeright = false;
00592             if( quad[ i ].x() > x )
00593                 wholeleft = false;
00594             }
00595         if( wholeleft || wholeright ) // is whole in one split part
00596             {
00597             ret.append( quad );
00598             continue;
00599             }
00600         if( quad.left() == quad.right() ) // quad has no size
00601             {
00602             ret.append( quad );
00603             continue;
00604             }
00605         ret.append( quad.makeSubQuad( quad.left(), quad.top(), x, quad.bottom()));
00606         ret.append( quad.makeSubQuad( x, quad.top(), quad.right(), quad.bottom()));
00607         }
00608     return ret;
00609     }
00610 
00611 WindowQuadList WindowQuadList::splitAtY( double y ) const
00612     {
00613     WindowQuadList ret;
00614     foreach( const WindowQuad &quad, *this )
00615         {
00616 #ifndef NDEBUG
00617         if( quad.isTransformed())
00618             kFatal( 1212 ) << "Splitting quads is allowed only in pre-paint calls!" ;
00619 #endif
00620         bool wholetop = true;
00621         bool wholebottom = true;
00622         for( int i = 0;
00623              i < 4;
00624              ++i )
00625             {
00626             if( quad[ i ].y() < y )
00627                 wholebottom = false;
00628             if( quad[ i ].y() > y )
00629                 wholetop = false;
00630             }
00631         if( wholetop || wholebottom ) // is whole in one split part
00632             {
00633             ret.append( quad );
00634             continue;
00635             }
00636         if( quad.top() == quad.bottom() ) // quad has no size
00637             {
00638             ret.append( quad );
00639             continue;
00640             }
00641         ret.append( quad.makeSubQuad( quad.left(), quad.top(), quad.right(), y ));
00642         ret.append( quad.makeSubQuad( quad.left(), y, quad.right(), quad.bottom()));
00643         }
00644     return ret;
00645     }
00646 
00647 WindowQuadList WindowQuadList::makeGrid( int maxquadsize ) const
00648     {
00649     if( empty())
00650         return *this;
00651     // find the bounding rectangle
00652     double left = first().left();
00653     double right = first().right();
00654     double top = first().top();
00655     double bottom = first().bottom();
00656     foreach( const WindowQuad &quad, *this )
00657         {
00658 #ifndef NDEBUG
00659         if( quad.isTransformed())
00660             kFatal( 1212 ) << "Splitting quads is allowed only in pre-paint calls!" ;
00661 #endif
00662         left = qMin( left, quad.left());
00663         right = qMax( right, quad.right());
00664         top = qMin( top, quad.top());
00665         bottom = qMax( bottom, quad.bottom());
00666         }
00667     WindowQuadList ret;
00668     for( double x = left;
00669          x < right;
00670          x += maxquadsize )
00671         {
00672         for( double y = top;
00673              y < bottom;
00674              y += maxquadsize )
00675             {
00676             foreach( const WindowQuad &quad, *this )
00677                 {
00678                 if( QRectF( QPointF( quad.left(), quad.top()), QPointF( quad.right(), quad.bottom()))
00679                     .intersects( QRectF( x, y, maxquadsize, maxquadsize )))
00680                     {
00681                     ret.append( quad.makeSubQuad( qMax( x, quad.left()), qMax( y, quad.top()),
00682                         qMin( quad.right(), x + maxquadsize ), qMin( quad.bottom(), y + maxquadsize )));
00683                     }
00684                 }
00685             }
00686         }
00687     return ret;
00688     }
00689 
00690 WindowQuadList WindowQuadList::makeRegularGrid( int xSubdivisions, int ySubdivisions ) const
00691     {
00692     if( empty())
00693         return *this;
00694     // find the bounding rectangle
00695     double left = first().left();
00696     double right = first().right();
00697     double top = first().top();
00698     double bottom = first().bottom();
00699     foreach( const WindowQuad &quad, *this )
00700         {
00701 #ifndef NDEBUG
00702         if( quad.isTransformed())
00703             kFatal( 1212 ) << "Splitting quads is allowed only in pre-paint calls!" ;
00704 #endif
00705         left = qMin( left, quad.left());
00706         right = qMax( right, quad.right());
00707         top = qMin( top, quad.top());
00708         bottom = qMax( bottom, quad.bottom());
00709         }
00710 
00711     double xincrement = (right - left) / xSubdivisions;
00712     double yincrement = (bottom - top) / ySubdivisions;
00713     WindowQuadList ret;
00714     for( double y = top;
00715          y < bottom;
00716          y += yincrement )
00717         {
00718         for( double x = left;
00719              x < right;
00720              x +=  xincrement)
00721             {
00722             foreach( const WindowQuad &quad, *this )
00723                 {
00724                 if( QRectF( QPointF( quad.left(), quad.top()), QPointF( quad.right(), quad.bottom()))
00725                     .intersects( QRectF( x, y, xincrement, yincrement )))
00726                     {
00727                     ret.append( quad.makeSubQuad( qMax( x, quad.left()), qMax( y, quad.top()),
00728                         qMin( quad.right(), x + xincrement ), qMin( quad.bottom(), y + yincrement )));
00729                     }
00730                 }
00731             }
00732         }
00733     return ret;
00734     }
00735 
00736 void WindowQuadList::makeArrays( float** vertices, float** texcoords ) const
00737     {
00738     *vertices = new float[ count() * 4 * 2 ];
00739     *texcoords = new float[ count() * 4 * 2 ];
00740     float* vpos = *vertices;
00741     float* tpos = *texcoords;
00742     for( int i = 0;
00743          i < count();
00744          ++i )
00745         for( int j = 0;
00746              j < 4;
00747              ++j )
00748             {
00749             *vpos++ = at( i )[ j ].x();
00750             *vpos++ = at( i )[ j ].y();
00751             *tpos++ = at( i )[ j ].tx;
00752             *tpos++ = at( i )[ j ].ty;
00753             }
00754     }
00755 
00756 WindowQuadList WindowQuadList::select( WindowQuadType type ) const
00757     {
00758     foreach( const WindowQuad &q, *this )
00759         {
00760         if( q.type() != type ) // something else than ones to select, make a copy and filter
00761             {
00762             WindowQuadList ret;
00763             foreach( const WindowQuad &q, *this )
00764                 {
00765                 if( q.type() == type )
00766                     ret.append( q );
00767                 }
00768             return ret;
00769             }
00770         }
00771     return *this; // nothing to filter out
00772     }
00773 
00774 WindowQuadList WindowQuadList::filterOut( WindowQuadType type ) const
00775     {
00776     foreach( const WindowQuad &q, *this )
00777         {
00778         if( q.type() == type ) // something to filter out, make a copy and filter
00779             {
00780             WindowQuadList ret;
00781             foreach( const WindowQuad &q, *this )
00782                 {
00783                 if( q.type() != type )
00784                     ret.append( q );
00785                 }
00786             return ret;
00787             }
00788         }
00789     return *this; // nothing to filter out
00790     }
00791 
00792 bool WindowQuadList::smoothNeeded() const
00793     {
00794     foreach( const WindowQuad &q, *this )
00795         if( q.smoothNeeded())
00796             return true;
00797     return false;
00798     }
00799 
00800 bool WindowQuadList::isTransformed() const
00801     {
00802     foreach( const WindowQuad &q, *this )
00803         if( q.isTransformed())
00804             return true;
00805     return false;
00806     }
00807 
00808 /***************************************************************
00809  PaintClipper
00810 ***************************************************************/
00811 
00812 QStack< QRegion >* PaintClipper::areas = NULL;
00813 
00814 PaintClipper::PaintClipper( const QRegion& allowed_area )
00815     : area( allowed_area )
00816     {
00817     push( area );
00818     }
00819 
00820 PaintClipper::~PaintClipper()
00821     {
00822     pop( area );
00823     }
00824 
00825 void PaintClipper::push( const QRegion& allowed_area )
00826     {
00827     if( allowed_area == infiniteRegion()) // don't push these
00828         return;
00829     if( areas == NULL )
00830         areas = new QStack< QRegion >;
00831     areas->push( allowed_area );
00832     }
00833 
00834 void PaintClipper::pop( const QRegion& allowed_area )
00835     {
00836     if( allowed_area == infiniteRegion())
00837         return;
00838     Q_ASSERT( areas != NULL );
00839     Q_ASSERT( areas->top() == allowed_area );
00840     areas->pop();
00841     if( areas->isEmpty())
00842         {
00843         delete areas;
00844         areas = NULL;
00845         }
00846     }
00847 
00848 bool PaintClipper::clip()
00849     {
00850     return areas != NULL;
00851     }
00852 
00853 QRegion PaintClipper::paintArea()
00854     {
00855     assert( areas != NULL ); // can be called only with clip() == true
00856     QRegion ret = QRegion( 0, 0, displayWidth(), displayHeight());
00857     foreach( const QRegion &r, *areas )
00858         ret &= r;
00859     return ret;
00860     }
00861 
00862 struct PaintClipper::Iterator::Data
00863     {
00864     Data() : index( 0 ) {}
00865     int index;
00866 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00867     QVector< QRect > rects;
00868 #endif
00869     };
00870 
00871 PaintClipper::Iterator::Iterator()
00872     : data( new Data )
00873     {
00874 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00875     if( clip() && effects->compositingType() == OpenGLCompositing )
00876         {
00877         glPushAttrib( GL_SCISSOR_BIT );
00878         glEnable( GL_SCISSOR_TEST );
00879         data->rects = paintArea().rects();
00880         data->index = -1;
00881         next(); // move to the first one
00882         }
00883 #endif
00884 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
00885     if( clip() && effects->compositingType() == XRenderCompositing )
00886         {
00887         XserverRegion region = toXserverRegion( paintArea());
00888         XFixesSetPictureClipRegion( display(), effects->xrenderBufferPicture(), 0, 0, region );
00889         XFixesDestroyRegion( display(), region ); // it's ref-counted
00890         }
00891 #endif
00892     }
00893 
00894 PaintClipper::Iterator::~Iterator()
00895     {
00896 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00897     if( clip() && effects->compositingType() == OpenGLCompositing )
00898         glPopAttrib();
00899 #endif
00900 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
00901     if( clip() && effects->compositingType() == XRenderCompositing )
00902         XFixesSetPictureClipRegion( display(), effects->xrenderBufferPicture(), 0, 0, None );
00903 #endif
00904     delete data;
00905     }
00906 
00907 bool PaintClipper::Iterator::isDone()
00908     {
00909     if( !clip())
00910         return data->index == 1; // run once
00911 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00912     if( effects->compositingType() == OpenGLCompositing )
00913         return data->index >= data->rects.count(); // run once per each area
00914 #endif
00915 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
00916     if( effects->compositingType() == XRenderCompositing )
00917         return data->index == 1; // run once
00918 #endif
00919     abort();
00920     }
00921 
00922 void PaintClipper::Iterator::next()
00923     {
00924     data->index++;
00925 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00926     if( clip() && effects->compositingType() == OpenGLCompositing && data->index < data->rects.count())
00927         {
00928         const QRect& r = data->rects[ data->index ];
00929         // Scissor rect has to be given in OpenGL coords
00930         glScissor( r.x(), displayHeight() - r.y() - r.height(), r.width(), r.height());
00931         }
00932 #endif
00933     }
00934 
00935 QRect PaintClipper::Iterator::boundingRect() const
00936     {
00937     if( !clip())
00938         return infiniteRegion();
00939 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00940     if( effects->compositingType() == OpenGLCompositing )
00941         return data->rects[ data->index ];
00942 #endif
00943 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
00944     if( effects->compositingType() == XRenderCompositing )
00945         return paintArea().boundingRect();
00946 #endif
00947     abort();
00948     return infiniteRegion();
00949     }
00950 
00951 
00952 /***************************************************************
00953  TimeLine
00954 ***************************************************************/
00955 
00956 TimeLine::TimeLine(const int duration)
00957     {
00958     m_Time = 0;
00959     m_Duration = duration;
00960     m_TimeLine = new QTimeLine(m_Duration ? m_Duration : 1); // (avoid QTimeLine warning)
00961     m_TimeLine->setFrameRange(0, m_Duration);
00962     m_TimeLine->setCurveShape(QTimeLine::EaseInCurve);
00963     }
00964 
00965 TimeLine::TimeLine(const TimeLine &other)
00966     {
00967     m_Time = other.m_Time;
00968     m_Duration = other.m_Duration;
00969     m_TimeLine = new QTimeLine(m_Duration ? m_Duration : 1);
00970     m_TimeLine->setFrameRange(0, m_Duration);
00971     setCurveShape(m_CurveShape);
00972     if( m_Duration != 0 )
00973         setProgress(m_Progress);
00974     }
00975 
00976 TimeLine::~TimeLine()
00977     {
00978     delete m_TimeLine;
00979     }
00980 
00981 int TimeLine::duration() const
00982     {
00983     return m_Duration;
00984     }
00985 
00986 void TimeLine::setDuration(const int msec)
00987     {
00988     m_Duration = msec;
00989     m_TimeLine->setDuration(m_Duration);
00990     m_TimeLine->setFrameRange(0, m_Duration);
00991     }
00992 
00993 double TimeLine::value() const
00994     {
00995     Q_ASSERT( m_Duration != 0 );
00996     return valueForTime(m_Time);
00997     }
00998 
00999 double TimeLine::valueForTime(const int msec) const
01000     {
01001     Q_ASSERT( m_Duration != 0 );
01002     // Catch non QTimeLine CurveShapes here, (but there are none right now)
01003 
01004 
01005     // else use QTimeLine ...
01006     return m_TimeLine->valueForTime(msec);
01007     }
01008 
01009 void TimeLine::addTime(const int msec)
01010     {
01011     Q_ASSERT( m_Duration != 0 );
01012     m_Time = qMin(m_Duration, m_Time + msec);
01013     m_Progress = (double)m_Time / m_Duration;
01014     }
01015 
01016 void TimeLine::removeTime(const int msec)
01017     {
01018     Q_ASSERT( m_Duration != 0 );
01019     m_Time = qMax(0, m_Time - msec);
01020     m_Progress = (double)m_Time / m_Duration;
01021     }
01022 
01023 void TimeLine::setProgress(const double progress)
01024     {
01025     Q_ASSERT( m_Duration != 0 );
01026     m_Progress = progress;
01027     m_Time = qRound(m_Duration * progress);
01028     }
01029 
01030 double TimeLine::progress() const
01031     {
01032     Q_ASSERT( m_Duration != 0 );
01033     return m_Progress;
01034     }
01035 
01036 int TimeLine::time() const
01037     {
01038     Q_ASSERT( m_Duration != 0 );
01039     return m_Time;
01040     }
01041 
01042 void TimeLine::addProgress(const double progress)
01043     {
01044     Q_ASSERT( m_Duration != 0 );
01045     m_Progress += progress;
01046     m_Time = (int)(m_Duration * m_Progress);
01047     }
01048 
01049 void TimeLine::setCurveShape(CurveShape curveShape)
01050     {
01051     switch (curveShape)
01052         {
01053         case EaseInCurve:
01054             m_TimeLine->setCurveShape(QTimeLine::EaseInCurve);
01055             break;
01056         case EaseOutCurve:
01057             m_TimeLine->setCurveShape(QTimeLine::EaseOutCurve);
01058             break;
01059         case EaseInOutCurve:
01060             m_TimeLine->setCurveShape(QTimeLine::EaseInOutCurve);
01061             break;
01062         case LinearCurve:
01063             m_TimeLine->setCurveShape(QTimeLine::LinearCurve);
01064             break;
01065         case SineCurve:
01066             m_TimeLine->setCurveShape(QTimeLine::SineCurve);
01067             break;
01068         }
01069         m_CurveShape = curveShape;
01070     }
01071 
01072 /***************************************************************
01073  WindowMotionManager
01074 ***************************************************************/
01075 
01076 WindowMotionManager::WindowMotionManager( bool useGlobalAnimationModifier )
01077     :   m_useGlobalAnimationModifier( useGlobalAnimationModifier )
01078     ,   m_movingWindows( 0 )
01079     { // TODO: Allow developer to modify motion attributes
01080     } // TODO: What happens when the window moves by an external force?
01081 
01082 WindowMotionManager::~WindowMotionManager()
01083     {
01084     }
01085 
01086 void WindowMotionManager::manage( EffectWindow *w )
01087     {
01088     if( m_managedWindows.contains( w ))
01089         return;
01090 
01091     double strength = 0.9;
01092     double decay = 0.75;
01093     if( m_useGlobalAnimationModifier )
01094         {
01095         if( effects->animationTimeFactor() ) // If == 0 we just skip the calculation
01096             strength = 0.9 / effects->animationTimeFactor();
01097         decay = effects->animationTimeFactor() / ( effects->animationTimeFactor() + 0.3333333 );
01098         }
01099 
01100     m_managedWindows[ w ] = WindowMotion();
01101     m_managedWindows[ w ].translation.setStrengthDecay( strength, decay );
01102     m_managedWindows[ w ].scale.setStrengthDecay( strength, decay / 2.0 );
01103 
01104     m_managedWindows[ w ].translation.setValue( w->pos() );
01105     m_managedWindows[ w ].scale.setValue( QPointF( 1.0, 1.0 ));
01106     }
01107 
01108 void WindowMotionManager::unmanage( EffectWindow *w )
01109     {
01110     if( !m_managedWindows.contains( w ))
01111         return;
01112 
01113     QPointF diffT = m_managedWindows[ w ].translation.distance();
01114     QPointF diffS = m_managedWindows[ w ].scale.distance();
01115     if( diffT.x() != 0.0 || diffT.y() != 0.0 || diffS.x() != 0.0 || diffS.y() != 0.0 )
01116         m_movingWindows--; // Window was moving
01117 
01118     m_managedWindows.remove( w );
01119     }
01120 
01121 void WindowMotionManager::unmanageAll()
01122     {
01123     m_managedWindows.clear();
01124     m_movingWindows = 0;
01125     }
01126 
01127 void WindowMotionManager::calculate( int time )
01128     {
01129     if( !effects->animationTimeFactor() )
01130         { // Just skip it completely if the user wants no animation
01131         m_movingWindows = 0;
01132         QHash<EffectWindow*, WindowMotion>::iterator it = m_managedWindows.begin();
01133         for(; it != m_managedWindows.end(); it++ )
01134             {
01135             WindowMotion *motion = &it.value();
01136             motion->translation.finish();
01137             motion->scale.finish();
01138             }
01139         }
01140 
01141     QHash<EffectWindow*, WindowMotion>::iterator it = m_managedWindows.begin();
01142     for(; it != m_managedWindows.end(); it++ )
01143         {
01144         WindowMotion *motion = &it.value();
01145         bool stopped = false;
01146 
01147         // TODO: What happens when distance() == 0 but we are still moving fast?
01148         // TODO: Motion needs to be calculated from the window's center
01149 
01150         QPointF diffT = motion->translation.distance();
01151         if( diffT != QPoint( 0.0, 0.0 ))
01152             { // Still moving
01153             motion->translation.calculate( time );
01154             diffT = motion->translation.distance();
01155             if( qAbs( diffT.x() ) < 0.5 && qAbs( motion->translation.velocity().x() ) < 0.2 &&
01156                 qAbs( diffT.y() ) < 0.5 && qAbs( motion->translation.velocity().y() ) < 0.2 )
01157                 { // Hide tiny oscillations
01158                 motion->translation.finish();
01159                 diffT = QPoint( 0.0, 0.0 );
01160                 stopped = true;
01161                 }
01162             }
01163 
01164         QPointF diffS = motion->scale.distance();
01165         if( diffS != QPoint( 0.0, 0.0 ))
01166             { // Still scaling
01167             motion->scale.calculate( time );
01168             diffS = motion->scale.distance();
01169             if( qAbs( diffS.x() ) < 0.002 && qAbs( motion->scale.velocity().x() ) < 0.05 &&
01170                 qAbs( diffS.y() ) < 0.002 && qAbs( motion->scale.velocity().y() ) < 0.05 )
01171                 { // Hide tiny oscillations
01172                 motion->scale.finish();
01173                 diffS = QPoint( 0.0, 0.0 );
01174                 stopped = true;
01175                 }
01176             }
01177 
01178         // We just finished this window's motion
01179         if( stopped && diffT == QPoint( 0.0, 0.0 ) && diffS == QPoint( 0.0, 0.0 ))
01180             m_movingWindows--;
01181         }
01182     }
01183 
01184 void WindowMotionManager::reset()
01185     {
01186     if( !m_managedWindows.count() )
01187         return;
01188 
01189     EffectWindowList windows = m_managedWindows.keys();
01190 
01191     for( int i = 0; i < windows.size(); i++ )
01192         {
01193         EffectWindow *w = windows.at( i );
01194         m_managedWindows[ w ].translation.setTarget( w->pos() );
01195         m_managedWindows[ w ].translation.finish();
01196         m_managedWindows[ w ].scale.setTarget( QPointF( 1.0, 1.0 ));
01197         m_managedWindows[ w ].scale.finish();
01198         }
01199     }
01200 
01201 void WindowMotionManager::reset( EffectWindow *w )
01202     {
01203     if( !m_managedWindows.contains( w ))
01204         return;
01205 
01206     m_managedWindows[ w ].translation.setTarget( w->pos() );
01207     m_managedWindows[ w ].translation.finish();
01208     m_managedWindows[ w ].scale.setTarget( QPointF( 1.0, 1.0 ));
01209     m_managedWindows[ w ].scale.finish();
01210     }
01211 
01212 void WindowMotionManager::apply( EffectWindow *w, WindowPaintData &data )
01213     {
01214     if( !m_managedWindows.contains( w ))
01215         return;
01216 
01217     // TODO: Take into account existing scale so that we can work with multiple managers (E.g. Present windows + grid)
01218     data.xTranslate += m_managedWindows[ w ].translation.value().x() - w->x();
01219     data.yTranslate += m_managedWindows[ w ].translation.value().y() - w->y();
01220     data.xScale *= m_managedWindows[ w ].scale.value().x();
01221     data.yScale *= m_managedWindows[ w ].scale.value().y();
01222     }
01223 
01224 void WindowMotionManager::moveWindow( EffectWindow *w, QPoint target, double scale, double yScale )
01225     {
01226     if( !m_managedWindows.contains( w ))
01227         abort(); // Notify the effect author that they did something wrong
01228 
01229     if( yScale == 0.0 )
01230         yScale = scale;
01231     QPointF scalePoint( scale, yScale );
01232 
01233     if( m_managedWindows[ w ].translation.value() == target &&
01234         m_managedWindows[ w ].scale.value() == scalePoint )
01235         return; // Window already at that position
01236 
01237     m_managedWindows[ w ].translation.setTarget( target );
01238     m_managedWindows[ w ].scale.setTarget( scalePoint );
01239 
01240     if( m_managedWindows[ w ].translation.velocity() == QPointF( 0.0, 0.0 ) &&
01241         m_managedWindows[ w ].scale.velocity() == QPointF( 0.0, 0.0 ))
01242         m_movingWindows++;
01243     }
01244 
01245 QRectF WindowMotionManager::transformedGeometry( EffectWindow *w ) const
01246     {
01247     QRectF geometry( w->geometry() );
01248 
01249     // TODO: Take into account existing scale so that we can work with multiple managers (E.g. Present windows + grid)
01250     geometry.moveTo( m_managedWindows[ w ].translation.value() );
01251     geometry.setWidth( geometry.width() * m_managedWindows[ w ].scale.value().x() );
01252     geometry.setHeight( geometry.height() * m_managedWindows[ w ].scale.value().y() );
01253 
01254     return geometry;
01255     }
01256 
01257 EffectWindow* WindowMotionManager::windowAtPoint( QPoint point, bool useStackingOrder ) const
01258     {
01259     // TODO: Stacking order uses EffectsHandler::stackingOrder() then filters by m_managedWindows
01260     EffectWindowList windows = m_managedWindows.keys();
01261 
01262     for( int i = 0; i < windows.size(); i++ )
01263         if( transformedGeometry( windows.at( i )).contains( point ))
01264             return windows.at( i );
01265 
01266     return NULL;
01267     }
01268 
01269 } // namespace

KWinLibraries

Skip menu "KWinLibraries"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal