00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072 #include "scene.h"
00073
00074 #include <X11/extensions/shape.h>
00075
00076 #include "client.h"
00077 #include "deleted.h"
00078 #include "effects.h"
00079
00080 namespace KWin
00081 {
00082
00083
00084
00085
00086
00087 Scene* scene;
00088
00089 Scene::Scene( Workspace* ws )
00090 : wspace( ws ),
00091 has_waitSync( false )
00092 {
00093 }
00094
00095 Scene::~Scene()
00096 {
00097 }
00098
00099
00100 void Scene::paintScreen( int* mask, QRegion* region )
00101 {
00102 *mask = ( *region == QRegion( 0, 0, displayWidth(), displayHeight()))
00103 ? 0 : PAINT_SCREEN_REGION;
00104 updateTimeDiff();
00105
00106 static_cast<EffectsHandlerImpl*>(effects)->startPaint();
00107 ScreenPrePaintData pdata;
00108 pdata.mask = *mask;
00109 pdata.paint = *region;
00110 effects->prePaintScreen( pdata, time_diff );
00111 *mask = pdata.mask;
00112 *region = pdata.paint;
00113 if( *mask & ( PAINT_SCREEN_TRANSFORMED | PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS ))
00114 {
00115
00116 *mask &= ~PAINT_SCREEN_REGION;
00117 *region = infiniteRegion();
00118 }
00119 else if( *mask & PAINT_SCREEN_REGION )
00120 {
00121 *region &= QRegion( 0, 0, displayWidth(), displayHeight());
00122 }
00123 else
00124 {
00125 *region = QRegion( 0, 0, displayWidth(), displayHeight());
00126 }
00127 painted_region = *region;
00128 if( *mask & PAINT_SCREEN_BACKGROUND_FIRST )
00129 paintBackground( *region );
00130 ScreenPaintData data;
00131 effects->paintScreen( *mask, *region, data );
00132 foreach( Window* w, stacking_order )
00133 effects->postPaintWindow( effectWindow( w ));
00134 effects->postPaintScreen();
00135 *region |= painted_region;
00136
00137 *region &= QRegion( 0, 0, displayWidth(), displayHeight());
00138
00139 Q_ASSERT( !PaintClipper::clip());
00140 }
00141
00142
00143 void Scene::updateTimeDiff()
00144 {
00145 if( last_time.isNull())
00146 {
00147
00148
00149
00150
00151 time_diff = 1;
00152 }
00153 else
00154 time_diff = last_time.elapsed();
00155 if( time_diff < 0 )
00156 time_diff = 1;
00157 last_time.start();;
00158 }
00159
00160
00161 void Scene::idle()
00162 {
00163
00164 last_time = QTime();
00165 }
00166
00167
00168 void Scene::finalPaintScreen( int mask, QRegion region, ScreenPaintData& data )
00169 {
00170 if( mask & ( PAINT_SCREEN_TRANSFORMED | PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS ))
00171 paintGenericScreen( mask, data );
00172 else
00173 paintSimpleScreen( mask, region );
00174 }
00175
00176
00177
00178 void Scene::paintGenericScreen( int orig_mask, ScreenPaintData )
00179 {
00180 if( !( orig_mask & PAINT_SCREEN_BACKGROUND_FIRST ))
00181 paintBackground( infiniteRegion());
00182 QList< Phase2Data > phase2;
00183 foreach( Window* w, stacking_order )
00184 {
00185 WindowPrePaintData data;
00186 data.mask = orig_mask | ( w->isOpaque() ? PAINT_WINDOW_OPAQUE : PAINT_WINDOW_TRANSLUCENT );
00187 w->resetPaintingEnabled();
00188 data.paint = infiniteRegion();
00189 data.clip = QRegion();
00190 data.quads = w->buildQuads();
00191
00192 effects->prePaintWindow( effectWindow( w ), data, time_diff );
00193 #ifndef NDEBUG
00194 foreach( const WindowQuad &q, data.quads )
00195 if( q.isTransformed())
00196 kFatal( 1212 ) << "Pre-paint calls are not allowed to transform quads!" ;
00197 #endif
00198 if( !w->isPaintingEnabled())
00199 continue;
00200 phase2.append( Phase2Data( w, infiniteRegion(), data.clip, data.mask, data.quads ));
00201 }
00202
00203 foreach( const Phase2Data &d, phase2 )
00204 paintWindow( d.window, d.mask, d.region, d.quads );
00205 }
00206
00207
00208
00209
00210 void Scene::paintSimpleScreen( int orig_mask, QRegion region )
00211 {
00212
00213
00214 assert(( orig_mask & ( PAINT_WINDOW_TRANSFORMED | PAINT_SCREEN_TRANSFORMED
00215 | PAINT_WINDOW_TRANSLUCENT | PAINT_WINDOW_OPAQUE )) == 0 );
00216 QHash< Window*, Phase2Data > phase2data;
00217
00218
00219 for( int i = stacking_order.count() - 1;
00220 i >= 0;
00221 --i )
00222 {
00223 Window* w = stacking_order[ i ];
00224 WindowPrePaintData data;
00225 data.mask = orig_mask | ( w->isOpaque() ? PAINT_WINDOW_OPAQUE : PAINT_WINDOW_TRANSLUCENT );
00226 w->resetPaintingEnabled();
00227 data.paint = region;
00228 data.clip = w->isOpaque() ? w->shape().translated( w->x(), w->y()) : QRegion();
00229 data.quads = w->buildQuads();
00230
00231 effects->prePaintWindow( effectWindow( w ), data, time_diff );
00232 #ifndef NDEBUG
00233 foreach( const WindowQuad &q, data.quads )
00234 if( q.isTransformed())
00235 kFatal( 1212 ) << "Pre-paint calls are not allowed to transform quads!" ;
00236 #endif
00237 if( !w->isPaintingEnabled())
00238 continue;
00239 if( data.paint != region )
00240 painted_region |= data.paint;
00241
00242 phase2data[w] = Phase2Data( w, data.paint, data.clip, data.mask, data.quads );
00243 }
00244
00245
00246
00247
00248 QRegion allclips;
00249 for( int i = stacking_order.count() - 1; i >= 0; --i )
00250 {
00251 Window* w = stacking_order[ i ];
00252 if( !phase2data.contains( w ))
00253 continue;
00254 Phase2Data d = phase2data[w];
00255
00256 d.region = painted_region - allclips;
00257 allclips |= d.clip;
00258 if( d.mask & PAINT_WINDOW_TRANSLUCENT )
00259 {
00260
00261
00262
00263 phase2data[w].region = d.region;
00264 }
00265 else
00266 {
00267
00268 paintWindow( d.window, d.mask, d.region, d.quads );
00269 }
00270 }
00271
00272 if( !( orig_mask & PAINT_SCREEN_BACKGROUND_FIRST ))
00273 paintBackground( painted_region - allclips );
00274
00275 for( int i = 0; i < stacking_order.count(); i++ )
00276 {
00277 Window* w = stacking_order[ i ];
00278 if( !phase2data.contains( w ))
00279 continue;
00280 Phase2Data d = phase2data[w];
00281 if( d.mask & PAINT_WINDOW_TRANSLUCENT )
00282 paintWindow( d.window, d.mask, d.region, d.quads );
00283 }
00284 }
00285
00286 void Scene::paintWindow( Window* w, int mask, QRegion region, WindowQuadList quads )
00287 {
00288
00289 region &= QRect( 0, 0, displayWidth(), displayHeight());
00290 if( region.isEmpty())
00291 return;
00292
00293 WindowPaintData data( w->window()->effectWindow());
00294 data.quads = quads;
00295 effects->paintWindow( effectWindow( w ), mask, region, data );
00296 }
00297
00298
00299 void Scene::finalPaintWindow( EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data )
00300 {
00301 effects->drawWindow( w, mask, region, data );
00302 }
00303
00304
00305 void Scene::finalDrawWindow( EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data )
00306 {
00307 w->sceneWindow()->performPaint( mask, region, data );
00308 }
00309
00310
00311
00312
00313
00314 Scene::Window::Window( Toplevel * c )
00315 : toplevel( c )
00316 , filter( ImageFilterFast )
00317 , disable_painting( 0 )
00318 , shape_valid( false )
00319 , cached_quad_list( NULL )
00320 {
00321 }
00322
00323 Scene::Window::~Window()
00324 {
00325 delete cached_quad_list;
00326 }
00327
00328 void Scene::Window::discardShape()
00329 {
00330
00331
00332 shape_valid = false;
00333 delete cached_quad_list;
00334 cached_quad_list = NULL;
00335 }
00336
00337
00338
00339 QRegion Scene::Window::shape() const
00340 {
00341 if( !shape_valid )
00342 {
00343 Client* c = dynamic_cast< Client* >( toplevel );
00344 if( toplevel->shape() || ( c != NULL && !c->mask().isEmpty()))
00345 {
00346 int count, order;
00347 XRectangle* rects = XShapeGetRectangles( display(), toplevel->frameId(),
00348 ShapeBounding, &count, &order );
00349 if(rects)
00350 {
00351 shape_region = QRegion();
00352 for( int i = 0;
00353 i < count;
00354 ++i )
00355 shape_region += QRegion( rects[ i ].x, rects[ i ].y,
00356 rects[ i ].width, rects[ i ].height );
00357 XFree(rects);
00358 }
00359 else
00360 shape_region = QRegion();
00361 }
00362 else
00363 shape_region = QRegion( 0, 0, width(), height());
00364 shape_valid = true;
00365 }
00366 return shape_region;
00367 }
00368
00369 bool Scene::Window::isVisible() const
00370 {
00371 if( dynamic_cast< Deleted* >( toplevel ) != NULL )
00372 return false;
00373 if( !toplevel->isOnCurrentDesktop())
00374 return false;
00375 if( Client* c = dynamic_cast< Client* >( toplevel ))
00376 return c->isShown( true );
00377 return true;
00378
00379 return !toplevel->geometry()
00380 .intersected( QRect( 0, 0, displayWidth(), displayHeight()))
00381 .isEmpty();
00382 }
00383
00384 bool Scene::Window::isOpaque() const
00385 {
00386 return toplevel->opacity() == 1.0 && !toplevel->hasAlpha();
00387 }
00388
00389 bool Scene::Window::isPaintingEnabled() const
00390 {
00391 return !disable_painting;
00392 }
00393
00394 void Scene::Window::resetPaintingEnabled()
00395 {
00396 disable_painting = 0;
00397 if( dynamic_cast< Deleted* >( toplevel ) != NULL )
00398 disable_painting |= PAINT_DISABLED_BY_DELETE;
00399 if( !toplevel->isOnCurrentDesktop())
00400 disable_painting |= PAINT_DISABLED_BY_DESKTOP;
00401 if( Client* c = dynamic_cast< Client* >( toplevel ))
00402 {
00403 if( c->isMinimized() )
00404 disable_painting |= PAINT_DISABLED_BY_MINIMIZE;
00405 if( c->isHiddenInternal())
00406 disable_painting |= PAINT_DISABLED;
00407 }
00408 }
00409
00410 void Scene::Window::enablePainting( int reason )
00411 {
00412 disable_painting &= ~reason;
00413 }
00414
00415 void Scene::Window::disablePainting( int reason )
00416 {
00417 disable_painting |= reason;
00418 }
00419
00420 WindowQuadList Scene::Window::buildQuads() const
00421 {
00422 if( cached_quad_list != NULL )
00423 return *cached_quad_list;
00424 WindowQuadList ret;
00425 if( toplevel->clientPos() == QPoint( 0, 0 ) && toplevel->clientSize() == toplevel->size())
00426 ret = makeQuads( WindowQuadContents, shape());
00427 else
00428 {
00429 QRegion contents = shape() & QRect( toplevel->clientPos(), toplevel->clientSize());
00430 QRegion decoration = shape() - contents;
00431 ret = makeQuads( WindowQuadContents, contents );
00432 ret += makeQuads( WindowQuadDecoration, decoration );
00433 }
00434 cached_quad_list = new WindowQuadList( ret );
00435 return ret;
00436 }
00437
00438 WindowQuadList Scene::Window::makeQuads( WindowQuadType type, const QRegion& reg ) const
00439 {
00440 WindowQuadList ret;
00441 foreach( const QRect &r, reg.rects())
00442 {
00443 WindowQuad quad( type );
00444
00445 quad[ 0 ] = WindowVertex( r.x(), r.y(), r.x(), r.y());
00446 quad[ 1 ] = WindowVertex( r.x() + r.width(), r.y(), r.x() + r.width(), r.y());
00447 quad[ 2 ] = WindowVertex( r.x() + r.width(), r.y() + r.height(), r.x() + r.width(), r.y() + r.height());
00448 quad[ 3 ] = WindowVertex( r.x(), r.y() + r.height(), r.x(), r.y() + r.height());
00449 ret.append( quad );
00450 }
00451 return ret;
00452 }
00453
00454 }