00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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();
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
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 {
00276 return qMax( defaultTime * effects->animationTimeFactor(), 1. );
00277 }
00278
00279
00280
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
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;
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
00362 QFontMetrics fm( font );
00363 QString painttext = fm.elidedText( text, Qt::ElideRight, rect.width() );
00364 QRect textrect = fm.boundingRect( painttext );
00365
00366
00367 QImage textImage( textrect.width(), textrect.height(), QImage::Format_ARGB32 );
00368 textImage.fill( Qt::transparent );
00369
00370
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
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
00425 QFontMetrics fm( font );
00426 QString painttext = fm.elidedText( text, Qt::ElideRight, rect.width() );
00427 QRect textrect = fm.boundingRect( painttext );
00428
00429
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
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
00498
00499
00500 EffectWindowGroup::~EffectWindowGroup()
00501 {
00502 }
00503
00504
00505
00506
00507
00508 GlobalShortcutsEditor::GlobalShortcutsEditor( QWidget *parent ) :
00509 KShortcutsEditor( parent, GlobalAction )
00510 {
00511 }
00512
00513
00514
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
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
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
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
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 )
00596 {
00597 ret.append( quad );
00598 continue;
00599 }
00600 if( quad.left() == quad.right() )
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 )
00632 {
00633 ret.append( quad );
00634 continue;
00635 }
00636 if( quad.top() == quad.bottom() )
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
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
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 )
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;
00772 }
00773
00774 WindowQuadList WindowQuadList::filterOut( WindowQuadType type ) const
00775 {
00776 foreach( const WindowQuad &q, *this )
00777 {
00778 if( q.type() == type )
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;
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
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())
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 );
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();
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 );
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;
00911 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00912 if( effects->compositingType() == OpenGLCompositing )
00913 return data->index >= data->rects.count();
00914 #endif
00915 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
00916 if( effects->compositingType() == XRenderCompositing )
00917 return data->index == 1;
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
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
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);
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
01003
01004
01005
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
01074
01075
01076 WindowMotionManager::WindowMotionManager( bool useGlobalAnimationModifier )
01077 : m_useGlobalAnimationModifier( useGlobalAnimationModifier )
01078 , m_movingWindows( 0 )
01079 {
01080 }
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() )
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--;
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 {
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
01148
01149
01150 QPointF diffT = motion->translation.distance();
01151 if( diffT != QPoint( 0.0, 0.0 ))
01152 {
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 {
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 {
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 {
01172 motion->scale.finish();
01173 diffS = QPoint( 0.0, 0.0 );
01174 stopped = true;
01175 }
01176 }
01177
01178
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
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();
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;
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
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
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 }