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 , xTranslate( 0 )
00068 , yTranslate( 0 )
00069 , saturation( 1 )
00070 , brightness( 1 )
00071 , shader( NULL )
00072 {
00073 quads = w->buildQuads();
00074 }
00075
00076 ScreenPaintData::ScreenPaintData()
00077 : xScale( 1 )
00078 , yScale( 1 )
00079 , xTranslate( 0 )
00080 , yTranslate( 0 )
00081 {
00082 }
00083
00084
00085
00086
00087
00088 Effect::Effect()
00089 {
00090 }
00091
00092 Effect::~Effect()
00093 {
00094 }
00095
00096 void Effect::windowUserMovedResized( EffectWindow* , bool, bool )
00097 {
00098 }
00099
00100 void Effect::windowOpacityChanged( EffectWindow*, double )
00101 {
00102 }
00103
00104 void Effect::windowAdded( EffectWindow* )
00105 {
00106 }
00107
00108 void Effect::windowClosed( EffectWindow* )
00109 {
00110 }
00111
00112 void Effect::windowDeleted( EffectWindow* )
00113 {
00114 }
00115
00116 void Effect::windowActivated( EffectWindow* )
00117 {
00118 }
00119
00120 void Effect::windowMinimized( EffectWindow* )
00121 {
00122 }
00123
00124 void Effect::windowUnminimized( EffectWindow* )
00125 {
00126 }
00127
00128 void Effect::windowInputMouseEvent( Window, QEvent* )
00129 {
00130 }
00131
00132 void Effect::grabbedKeyboardEvent( QKeyEvent* )
00133 {
00134 }
00135
00136 void Effect::propertyNotify( EffectWindow* , long )
00137 {
00138 }
00139
00140 void Effect::desktopChanged( int )
00141 {
00142 }
00143
00144 void Effect::windowDamaged( EffectWindow*, const QRect& )
00145 {
00146 }
00147
00148 void Effect::windowGeometryShapeChanged( EffectWindow*, const QRect& )
00149 {
00150 }
00151
00152 void Effect::tabBoxAdded( int )
00153 {
00154 }
00155
00156 void Effect::tabBoxClosed()
00157 {
00158 }
00159
00160 void Effect::tabBoxUpdated()
00161 {
00162 }
00163 bool Effect::borderActivated( ElectricBorder )
00164 {
00165 return false;
00166 }
00167
00168 void Effect::mouseChanged( const QPoint&, const QPoint&, Qt::MouseButtons,
00169 Qt::MouseButtons, Qt::KeyboardModifiers, Qt::KeyboardModifiers )
00170 {
00171 }
00172
00173 void Effect::prePaintScreen( ScreenPrePaintData& data, int time )
00174 {
00175 effects->prePaintScreen( data, time );
00176 }
00177
00178 void Effect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
00179 {
00180 effects->paintScreen( mask, region, data );
00181 }
00182
00183 void Effect::postPaintScreen()
00184 {
00185 effects->postPaintScreen();
00186 }
00187
00188 void Effect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time )
00189 {
00190 effects->prePaintWindow( w, data, time );
00191 }
00192
00193 void Effect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
00194 {
00195 effects->paintWindow( w, mask, region, data );
00196 }
00197
00198 void Effect::postPaintWindow( EffectWindow* w )
00199 {
00200 effects->postPaintWindow( w );
00201 }
00202
00203 void Effect::drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
00204 {
00205 effects->drawWindow( w, mask, region, data );
00206 }
00207
00208 QRect Effect::transformWindowDamage( EffectWindow* w, const QRect& r )
00209 {
00210 return effects->transformWindowDamage( w, r );
00211 }
00212
00213 void Effect::setPositionTransformations( WindowPaintData& data, QRect& region, EffectWindow* w,
00214 const QRect& r, Qt::AspectRatioMode aspect )
00215 {
00216 QSize size = w->size();
00217 size.scale( r.size(), aspect );
00218 data.xScale = size.width() / double( w->width());
00219 data.yScale = size.height() / double( w->height());
00220 int width = int( w->width() * data.xScale );
00221 int height = int( w->height() * data.yScale );
00222 int x = r.x() + ( r.width() - width ) / 2;
00223 int y = r.y() + ( r.height() - height ) / 2;
00224 region = QRect( x, y, width, height );
00225 data.xTranslate = x - w->x();
00226 data.yTranslate = y - w->y();
00227 }
00228
00229 int Effect::displayWidth()
00230 {
00231 return KWin::displayWidth();
00232 }
00233
00234 int Effect::displayHeight()
00235 {
00236 return KWin::displayHeight();
00237 }
00238
00239 QPoint Effect::cursorPos()
00240 {
00241 return effects->cursorPos();
00242 }
00243
00244
00245
00246
00247
00248 EffectsHandler::EffectsHandler(CompositingType type)
00249 : current_paint_screen( 0 )
00250 , current_paint_window( 0 )
00251 , current_draw_window( 0 )
00252 , current_transform( 0 )
00253 , compositing_type( type )
00254 {
00255 if( compositing_type == NoCompositing )
00256 return;
00257 KWin::effects = this;
00258 }
00259
00260 EffectsHandler::~EffectsHandler()
00261 {
00262
00263 assert( loaded_effects.count() == 0 );
00264 }
00265
00266 QRect EffectsHandler::transformWindowDamage( EffectWindow* w, const QRect& r )
00267 {
00268 if( current_transform < loaded_effects.size())
00269 {
00270 QRect rr = loaded_effects[current_transform++].second->transformWindowDamage( w, r );
00271 --current_transform;
00272 return rr;
00273 }
00274 else
00275 return r;
00276 }
00277
00278 Window EffectsHandler::createInputWindow( Effect* e, const QRect& r, const QCursor& cursor )
00279 {
00280 return createInputWindow( e, r.x(), r.y(), r.width(), r.height(), cursor );
00281 }
00282
00283 Window EffectsHandler::createFullScreenInputWindow( Effect* e, const QCursor& cursor )
00284 {
00285 return createInputWindow( e, 0, 0, displayWidth(), displayHeight(), cursor );
00286 }
00287
00288 CompositingType EffectsHandler::compositingType() const
00289 {
00290 return compositing_type;
00291 }
00292
00293 bool EffectsHandler::saturationSupported() const
00294 {
00295 switch( compositing_type )
00296 {
00297 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00298 case OpenGLCompositing:
00299 return GLTexture::saturationSupported();
00300 #endif
00301 case XRenderCompositing:
00302 return false;
00303 default:
00304 abort();
00305 }
00306 }
00307
00308 void EffectsHandler::sendReloadMessage( const QString& effectname )
00309 {
00310 QDBusMessage message = QDBusMessage::createMethodCall("org.kde.kwin", "/KWin", "org.kde.KWin", "reloadEffect");
00311 message << QString("kwin4_effect_" + effectname);
00312 QDBusConnection::sessionBus().send(message);
00313 }
00314
00315 KConfigGroup EffectsHandler::effectConfig( const QString& effectname )
00316 {
00317 KSharedConfig::Ptr kwinconfig = KSharedConfig::openConfig( "kwinrc", KConfig::NoGlobals );
00318 return kwinconfig->group( "Effect-" + effectname );
00319 }
00320
00321 bool EffectsHandler::paintText( const QString& text, const QPoint& center, int maxwidth,
00322 const QColor& color, const QFont& font )
00323 {
00324 QPainter p;
00325
00326 QFontMetrics fm( font );
00327 QString painttext = fm.elidedText( text, Qt::ElideRight, maxwidth );
00328 QRect textrect = fm.boundingRect( painttext );
00329
00330
00331 QPixmap textPixmap( textrect.width(), textrect.height());
00332 textPixmap.fill( Qt::transparent );
00333
00334
00335 p.begin( &textPixmap );
00336 p.setFont( font );
00337 p.setRenderHint( QPainter::TextAntialiasing );
00338 p.setPen( color );
00339 p.drawText( -textrect.topLeft(), painttext );
00340 p.end();
00341
00342
00343 QRect area( center.x() - textrect.width() / 2, center.y() - textrect.height() / 2,
00344 textrect.width(), textrect.height() );
00345
00346 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00347 if( effects->compositingType() == OpenGLCompositing )
00348 {
00349 GLTexture textTexture( textPixmap, GL_TEXTURE_RECTANGLE_ARB );
00350 glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT );
00351 glEnable( GL_BLEND );
00352 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
00353 textTexture.bind();
00354 const float verts[ 4 * 2 ] =
00355 {
00356 area.x(), area.y(),
00357 area.x(), area.y() + area.height(),
00358 area.x() + area.width(), area.y() + area.height(),
00359 area.x() + area.width(), area.y()
00360 };
00361 const float texcoords[ 4 * 2 ] =
00362 {
00363 0, textPixmap.height(),
00364 0, 0,
00365 textPixmap.width(), 0,
00366 textPixmap.width(), textPixmap.height()
00367 };
00368 renderGLGeometry( 4, verts, texcoords );
00369 textTexture.unbind();
00370 glPopAttrib();
00371 return true;
00372 }
00373 #endif
00374 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
00375 if( effects->compositingType() == XRenderCompositing )
00376 {
00377 XRenderPicture textPicture( textPixmap );
00378 XRenderComposite( display(), textPixmap.depth() == 32 ? PictOpOver : PictOpSrc,
00379 textPicture, None, effects->xrenderBufferPicture(),
00380 0, 0, 0, 0, area.x(), area.y(), area.width(), area.height());
00381 return true;
00382 }
00383 #endif
00384 return false;
00385 }
00386
00387 bool EffectsHandler::paintTextWithBackground( const QString& text, const QPoint& center, int maxwidth,
00388 const QColor& color, const QColor& bgcolor, const QFont& font )
00389 {
00390
00391 QFontMetrics fm( font );
00392 QString painttext = fm.elidedText( text, Qt::ElideRight, maxwidth );
00393 QRect textrect = fm.boundingRect( painttext );
00394
00395
00396 QRect area( center.x() - textrect.width() / 2, center.y() - textrect.height() / 2,
00397 textrect.width(), textrect.height() );
00398
00399 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00400 if( effects->compositingType() == OpenGLCompositing )
00401 {
00402 glColor4f( bgcolor.redF(), bgcolor.greenF(), bgcolor.blueF(), bgcolor.alphaF() );
00403 renderRoundBox( area.adjusted( -8, -3, 8, 3 ), 5 );
00404
00405 return paintText( text, center, maxwidth, color, font );
00406 }
00407 #endif
00408 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
00409 if( effects->compositingType() == XRenderCompositing )
00410 {
00411 xRenderRoundBox( effects->xrenderBufferPicture(), area.adjusted( -8, -3, 8, 3 ), 5, bgcolor );
00412 return paintText( text, center, maxwidth, color, font );
00413 }
00414 #endif
00415 return false;
00416 }
00417
00418
00419 EffectsHandler* effects = 0;
00420
00421
00422
00423
00424
00425
00426 EffectWindow::EffectWindow()
00427 {
00428 }
00429
00430 EffectWindow::~EffectWindow()
00431 {
00432 }
00433
00434 bool EffectWindow::isOnCurrentDesktop() const
00435 {
00436 return isOnDesktop( effects->currentDesktop());
00437 }
00438
00439 bool EffectWindow::isOnDesktop( int d ) const
00440 {
00441 return desktop() == d || isOnAllDesktops();
00442 }
00443
00444 bool EffectWindow::hasDecoration() const
00445 {
00446 return contentsRect() != QRect( 0, 0, width(), height());
00447 }
00448
00449
00450
00451
00452
00453
00454 EffectWindowGroup::~EffectWindowGroup()
00455 {
00456 }
00457
00458
00459
00460
00461
00462 GlobalShortcutsEditor::GlobalShortcutsEditor( QWidget *parent ) :
00463 KShortcutsEditor( parent, GlobalAction )
00464 {
00465 }
00466
00467
00468
00469
00470
00471 WindowQuad WindowQuad::makeSubQuad( double x1, double y1, double x2, double y2 ) const
00472 {
00473 assert( x1 < x2 && y1 < y2 && x1 >= left() && x2 <= right() && y1 >= top() && y2 <= bottom());
00474 #ifndef NDEBUG
00475 if( isTransformed())
00476 kFatal( 1212 ) << "Splitting quads is allowed only in pre-paint calls!" ;
00477 #endif
00478 WindowQuad ret( *this );
00479
00480 ret.verts[ 0 ].px = x1;
00481 ret.verts[ 3 ].px = x1;
00482 ret.verts[ 1 ].px = x2;
00483 ret.verts[ 2 ].px = x2;
00484 ret.verts[ 0 ].py = y1;
00485 ret.verts[ 1 ].py = y1;
00486 ret.verts[ 2 ].py = y2;
00487 ret.verts[ 3 ].py = y2;
00488
00489 ret.verts[ 0 ].ox = x1;
00490 ret.verts[ 3 ].ox = x1;
00491 ret.verts[ 1 ].ox = x2;
00492 ret.verts[ 2 ].ox = x2;
00493 ret.verts[ 0 ].oy = y1;
00494 ret.verts[ 1 ].oy = y1;
00495 ret.verts[ 2 ].oy = y2;
00496 ret.verts[ 3 ].oy = y2;
00497 double my_tleft = verts[ 0 ].tx;
00498 double my_tright = verts[ 2 ].tx;
00499 double my_ttop = verts[ 0 ].ty;
00500 double my_tbottom = verts[ 2 ].ty;
00501 double tleft = ( x1 - left()) / ( right() - left()) * ( my_tright - my_tleft ) + my_tleft;
00502 double tright = ( x2 - left()) / ( right() - left()) * ( my_tright - my_tleft ) + my_tleft;
00503 double ttop = ( y1 - top()) / ( bottom() - top()) * ( my_tbottom - my_ttop ) + my_ttop;
00504 double tbottom = ( y2 - top()) / ( bottom() - top()) * ( my_tbottom - my_ttop ) + my_ttop;
00505 ret.verts[ 0 ].tx = tleft;
00506 ret.verts[ 3 ].tx = tleft;
00507 ret.verts[ 1 ].tx = tright;
00508 ret.verts[ 2 ].tx = tright;
00509 ret.verts[ 0 ].ty = ttop;
00510 ret.verts[ 1 ].ty = ttop;
00511 ret.verts[ 2 ].ty = tbottom;
00512 ret.verts[ 3 ].ty = tbottom;
00513 return ret;
00514 }
00515
00516 bool WindowQuad::smoothNeeded() const
00517 {
00518
00519 double width = verts[ 1 ].ox - verts[ 0 ].ox;
00520 double height = verts[ 2 ].oy - verts[ 1 ].oy;
00521 return( verts[ 1 ].px - verts[ 0 ].px != width || verts[ 2 ].px - verts[ 3 ].px != width
00522 || verts[ 2 ].py - verts[ 1 ].py != height || verts[ 3 ].py - verts[ 0 ].py != height );
00523 }
00524
00525
00526
00527
00528
00529 WindowQuadList WindowQuadList::splitAtX( double x ) const
00530 {
00531 WindowQuadList ret;
00532 foreach( WindowQuad quad, *this )
00533 {
00534 #ifndef NDEBUG
00535 if( quad.isTransformed())
00536 kFatal( 1212 ) << "Splitting quads is allowed only in pre-paint calls!" ;
00537 #endif
00538 bool wholeleft = true;
00539 bool wholeright = true;
00540 for( int i = 0;
00541 i < 4;
00542 ++i )
00543 {
00544 if( quad[ i ].x() < x )
00545 wholeright = false;
00546 if( quad[ i ].x() >= x )
00547 wholeleft = false;
00548 }
00549 if( wholeleft || wholeright )
00550 {
00551 ret.append( quad );
00552 continue;
00553 }
00554 ret.append( quad.makeSubQuad( quad.left(), quad.top(), x, quad.bottom()));
00555 ret.append( quad.makeSubQuad( x, quad.top(), quad.right(), quad.bottom()));
00556 }
00557 return ret;
00558 }
00559
00560 WindowQuadList WindowQuadList::splitAtY( double y ) const
00561 {
00562 WindowQuadList ret;
00563 foreach( WindowQuad quad, *this )
00564 {
00565 #ifndef NDEBUG
00566 if( quad.isTransformed())
00567 kFatal( 1212 ) << "Splitting quads is allowed only in pre-paint calls!" ;
00568 #endif
00569 bool wholetop = true;
00570 bool wholebottom = true;
00571 for( int i = 0;
00572 i < 4;
00573 ++i )
00574 {
00575 if( quad[ i ].y() < y )
00576 wholebottom = false;
00577 if( quad[ i ].y() >= y )
00578 wholetop = false;
00579 }
00580 if( wholetop || wholebottom )
00581 {
00582 ret.append( quad );
00583 continue;
00584 }
00585 ret.append( quad.makeSubQuad( quad.left(), quad.top(), quad.right(), y ));
00586 ret.append( quad.makeSubQuad( quad.left(), y, quad.right(), quad.bottom()));
00587 }
00588 return ret;
00589 }
00590
00591 WindowQuadList WindowQuadList::makeGrid( int maxquadsize ) const
00592 {
00593 if( empty())
00594 return *this;
00595
00596 double left = first().left();
00597 double right = first().right();
00598 double top = first().top();
00599 double bottom = first().bottom();
00600 foreach( WindowQuad quad, *this )
00601 {
00602 #ifndef NDEBUG
00603 if( quad.isTransformed())
00604 kFatal( 1212 ) << "Splitting quads is allowed only in pre-paint calls!" ;
00605 #endif
00606 left = qMin( left, quad.left());
00607 right = qMax( right, quad.right());
00608 top = qMin( top, quad.top());
00609 bottom = qMax( bottom, quad.bottom());
00610 }
00611 WindowQuadList ret;
00612 for( double x = left;
00613 x < right;
00614 x += maxquadsize )
00615 {
00616 for( double y = top;
00617 y < bottom;
00618 y += maxquadsize )
00619 {
00620 foreach( WindowQuad quad, *this )
00621 {
00622 if( QRectF( QPointF( quad.left(), quad.top()), QPointF( quad.right(), quad.bottom()))
00623 .intersects( QRectF( x, y, maxquadsize, maxquadsize )))
00624 {
00625 ret.append( quad.makeSubQuad( qMax( x, quad.left()), qMax( y, quad.top()),
00626 qMin( quad.right(), x + maxquadsize ), qMin( quad.bottom(), y + maxquadsize )));
00627 }
00628 }
00629 }
00630 }
00631 return ret;
00632 }
00633
00634 WindowQuadList WindowQuadList::makeRegularGrid( int xSubdivisions, int ySubdivisions ) const
00635 {
00636 if( empty())
00637 return *this;
00638
00639 double left = first().left();
00640 double right = first().right();
00641 double top = first().top();
00642 double bottom = first().bottom();
00643 foreach( WindowQuad quad, *this )
00644 {
00645 #ifndef NDEBUG
00646 if( quad.isTransformed())
00647 kFatal( 1212 ) << "Splitting quads is allowed only in pre-paint calls!" ;
00648 #endif
00649 left = qMin( left, quad.left());
00650 right = qMax( right, quad.right());
00651 top = qMin( top, quad.top());
00652 bottom = qMax( bottom, quad.bottom());
00653 }
00654
00655 double xincrement = (right - left) / xSubdivisions;
00656 double yincrement = (bottom - top) / ySubdivisions;
00657 WindowQuadList ret;
00658 for( double y = top;
00659 y < bottom;
00660 y += yincrement )
00661 {
00662 for( double x = left;
00663 x < right;
00664 x += xincrement)
00665 {
00666 foreach( WindowQuad quad, *this )
00667 {
00668 if( QRectF( QPointF( quad.left(), quad.top()), QPointF( quad.right(), quad.bottom()))
00669 .intersects( QRectF( x, y, xincrement, yincrement )))
00670 {
00671 ret.append( quad.makeSubQuad( qMax( x, quad.left()), qMax( y, quad.top()),
00672 qMin( quad.right(), x + xincrement ), qMin( quad.bottom(), y + yincrement )));
00673 }
00674 }
00675 }
00676 }
00677 return ret;
00678 }
00679
00680 void WindowQuadList::makeArrays( float** vertices, float** texcoords ) const
00681 {
00682 *vertices = new float[ count() * 4 * 2 ];
00683 *texcoords = new float[ count() * 4 * 2 ];
00684 float* vpos = *vertices;
00685 float* tpos = *texcoords;
00686 for( int i = 0;
00687 i < count();
00688 ++i )
00689 for( int j = 0;
00690 j < 4;
00691 ++j )
00692 {
00693 *vpos++ = at( i )[ j ].x();
00694 *vpos++ = at( i )[ j ].y();
00695 *tpos++ = at( i )[ j ].tx;
00696 *tpos++ = at( i )[ j ].ty;
00697 }
00698 }
00699
00700 WindowQuadList WindowQuadList::select( WindowQuadType type ) const
00701 {
00702 foreach( WindowQuad q, *this )
00703 {
00704 if( q.type != type )
00705 {
00706 WindowQuadList ret;
00707 foreach( WindowQuad q, *this )
00708 {
00709 if( q.type == type )
00710 ret.append( q );
00711 }
00712 return ret;
00713 }
00714 }
00715 return *this;
00716 }
00717
00718 WindowQuadList WindowQuadList::filterOut( WindowQuadType type ) const
00719 {
00720 foreach( WindowQuad q, *this )
00721 {
00722 if( q.type == type )
00723 {
00724 WindowQuadList ret;
00725 foreach( WindowQuad q, *this )
00726 {
00727 if( q.type != type )
00728 ret.append( q );
00729 }
00730 return ret;
00731 }
00732 }
00733 return *this;
00734 }
00735
00736 bool WindowQuadList::smoothNeeded() const
00737 {
00738 foreach( WindowQuad q, *this )
00739 if( q.smoothNeeded())
00740 return true;
00741 return false;
00742 }
00743
00744
00745
00746
00747
00748 QStack< QRegion >* PaintClipper::areas = NULL;
00749
00750 PaintClipper::PaintClipper( const QRegion& allowed_area )
00751 : area( allowed_area )
00752 {
00753 push( area );
00754 }
00755
00756 PaintClipper::~PaintClipper()
00757 {
00758 pop( area );
00759 }
00760
00761 void PaintClipper::push( const QRegion& allowed_area )
00762 {
00763 if( allowed_area == infiniteRegion())
00764 return;
00765 if( areas == NULL )
00766 areas = new QStack< QRegion >;
00767 areas->push( allowed_area );
00768 }
00769
00770 void PaintClipper::pop( const QRegion& allowed_area )
00771 {
00772 if( allowed_area == infiniteRegion())
00773 return;
00774 Q_ASSERT( areas != NULL );
00775 Q_ASSERT( areas->top() == allowed_area );
00776 areas->pop();
00777 if( areas->isEmpty())
00778 {
00779 delete areas;
00780 areas = NULL;
00781 }
00782 }
00783
00784 bool PaintClipper::clip()
00785 {
00786 return areas != NULL;
00787 }
00788
00789 QRegion PaintClipper::paintArea()
00790 {
00791 assert( areas != NULL );
00792 QRegion ret = QRegion( 0, 0, displayWidth(), displayHeight());
00793 foreach( QRegion r, *areas )
00794 ret &= r;
00795 return ret;
00796 }
00797
00798 struct PaintClipper::Iterator::Data
00799 {
00800 Data() : index( 0 ) {}
00801 int index;
00802 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00803 QVector< QRect > rects;
00804 #endif
00805 };
00806
00807 PaintClipper::Iterator::Iterator()
00808 : data( new Data )
00809 {
00810 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00811 if( clip() && effects->compositingType() == OpenGLCompositing )
00812 {
00813 glPushAttrib( GL_SCISSOR_BIT );
00814 glEnable( GL_SCISSOR_TEST );
00815 data->rects = paintArea().rects();
00816 data->index = -1;
00817 next();
00818 }
00819 #endif
00820 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
00821 if( clip() && effects->compositingType() == XRenderCompositing )
00822 {
00823 XserverRegion region = toXserverRegion( paintArea());
00824 XFixesSetPictureClipRegion( display(), effects->xrenderBufferPicture(), 0, 0, region );
00825 XFixesDestroyRegion( display(), region );
00826 }
00827 #endif
00828 }
00829
00830 PaintClipper::Iterator::~Iterator()
00831 {
00832 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00833 if( clip() && effects->compositingType() == OpenGLCompositing )
00834 glPopAttrib();
00835 #endif
00836 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
00837 if( clip() && effects->compositingType() == XRenderCompositing )
00838 XFixesSetPictureClipRegion( display(), effects->xrenderBufferPicture(), 0, 0, None );
00839 #endif
00840 delete data;
00841 }
00842
00843 bool PaintClipper::Iterator::isDone()
00844 {
00845 if( !clip())
00846 return data->index == 1;
00847 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00848 if( effects->compositingType() == OpenGLCompositing )
00849 return data->index >= data->rects.count();
00850 #endif
00851 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
00852 if( effects->compositingType() == XRenderCompositing )
00853 return data->index == 1;
00854 #endif
00855 abort();
00856 }
00857
00858 void PaintClipper::Iterator::next()
00859 {
00860 data->index++;
00861 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00862 if( clip() && effects->compositingType() == OpenGLCompositing && data->index < data->rects.count())
00863 {
00864 const QRect& r = data->rects[ data->index ];
00865
00866 glScissor( r.x(), displayHeight() - r.y() - r.height(), r.width(), r.height());
00867 }
00868 #endif
00869 }
00870
00871 QRect PaintClipper::Iterator::boundingRect() const
00872 {
00873 if( !clip())
00874 return infiniteRegion();
00875 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00876 if( effects->compositingType() == OpenGLCompositing )
00877 return data->rects[ data->index ];
00878 #endif
00879 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
00880 if( effects->compositingType() == XRenderCompositing )
00881 return paintArea().boundingRect();
00882 #endif
00883 abort();
00884 return infiniteRegion();
00885 }
00886
00887
00888
00889
00890
00891
00892 TimeLine::TimeLine(const int duration)
00893 {
00894 m_Time = 0;
00895 m_CurveShape = TimeLine::EaseInCurve;
00896 m_Duration = duration;
00897 m_TimeLine = new QTimeLine(m_Duration);
00898 m_TimeLine->setFrameRange(0, m_Duration);
00899 m_TimeLine->setCurveShape(QTimeLine::EaseInCurve);
00900 }
00901
00902 TimeLine::TimeLine(const TimeLine &other)
00903 {
00904 m_Time = other.m_Time;
00905 m_CurveShape = other.m_CurveShape;
00906 m_Duration = other.m_Duration;
00907 m_TimeLine = new QTimeLine(m_Duration);
00908 m_TimeLine->setFrameRange(0, m_Duration);
00909 setProgress(m_Progress);
00910 setCurveShape(m_CurveShape);
00911 }
00912
00913 TimeLine::~TimeLine()
00914 {
00915 delete m_TimeLine;
00916 }
00917
00918 int TimeLine::duration() const
00919 {
00920 return m_Duration;
00921 }
00922
00923 void TimeLine::setDuration(const int msec)
00924 {
00925 m_Duration = msec;
00926 m_TimeLine->setDuration(msec);
00927 }
00928
00929 double TimeLine::value() const
00930 {
00931 return valueForTime(m_Time);
00932 }
00933
00934 double TimeLine::valueForTime(const int msec) const
00935 {
00936
00937
00938
00939
00940 return m_TimeLine->valueForTime(msec);
00941 }
00942
00943 void TimeLine::addTime(const int msec)
00944 {
00945 m_Time = qMin(m_Duration, m_Time + msec);
00946 m_Progress = (double)m_Time / m_Duration;
00947 }
00948
00949 void TimeLine::removeTime(const int msec)
00950 {
00951 m_Time = qMax(0, m_Time - msec);
00952 m_Progress = (double)m_Time / m_Duration;
00953 }
00954
00955 void TimeLine::setProgress(const double progress)
00956 {
00957 m_Progress = progress;
00958 m_Time = qRound(m_Duration * progress);
00959 }
00960
00961 double TimeLine::progress() const
00962 {
00963 return m_Progress;
00964 }
00965
00966 int TimeLine::time() const
00967 {
00968 return m_Time;
00969 }
00970
00971 void TimeLine::addProgress(const double progress)
00972 {
00973 m_Progress += progress;
00974 m_Time = (int)(m_Duration * m_Progress);
00975 }
00976
00977 void TimeLine::setCurveShape(CurveShape curveShape)
00978 {
00979 switch (curveShape)
00980 {
00981 case EaseInCurve:
00982 m_TimeLine->setCurveShape(QTimeLine::EaseInCurve);
00983 break;
00984 case EaseOutCurve:
00985 m_TimeLine->setCurveShape(QTimeLine::EaseOutCurve);
00986 break;
00987 case EaseInOutCurve:
00988 m_TimeLine->setCurveShape(QTimeLine::EaseInOutCurve);
00989 break;
00990 case LinearCurve:
00991 m_TimeLine->setCurveShape(QTimeLine::LinearCurve);
00992 break;
00993 case SineCurve:
00994 m_TimeLine->setCurveShape(QTimeLine::SineCurve);
00995 break;
00996 }
00997 m_CurveShape = curveShape;
00998 }
00999
01000 }