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

KWin

scene.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 /*
00022  (NOTE: The compositing code is work in progress. As such this design
00023  documentation may get outdated in some areas.)
00024 
00025  The base class for compositing, implementing shared functionality
00026  between the OpenGL and XRender backends.
00027  
00028  Design:
00029  
00030  When compositing is turned on, XComposite extension is used to redirect
00031  drawing of windows to pixmaps and XDamage extension is used to get informed
00032  about damage (changes) to window contents. This code is mostly in composite.cpp .
00033  
00034  Workspace::performCompositing() starts one painting pass. Painting is done
00035  by painting the screen, which in turn paints every window. Painting can be affected
00036  using effects, which are chained. E.g. painting a screen means that actually
00037  paintScreen() of the first effect is called, which possibly does modifications
00038  and calls next effect's paintScreen() and so on, until Scene::finalPaintScreen()
00039  is called.
00040  
00041  There are 3 phases of every paint (not necessarily done together):
00042  The pre-paint phase, the paint phase and the post-paint phase.
00043  
00044  The pre-paint phase is used to find out about how the painting will be actually
00045  done (i.e. what the effects will do). For example when only a part of the screen
00046  needs to be updated and no effect will do any transformation it is possible to use
00047  an optimized paint function. How the painting will be done is controlled
00048  by the mask argument, see PAINT_WINDOW_* and PAINT_SCREEN_* flags in scene.h .
00049  For example an effect that decides to paint a normal windows as translucent
00050  will need to modify the mask in its prePaintWindow() to include
00051  the PAINT_WINDOW_TRANSLUCENT flag. The paintWindow() function will then get
00052  the mask with this flag turned on and will also paint using transparency.
00053  
00054  The paint pass does the actual painting, based on the information collected
00055  using the pre-paint pass. After running through the effects' paintScreen()
00056  either paintGenericScreen() or optimized paintSimpleScreen() are called.
00057  Those call paintWindow() on windows (not necessarily all), possibly using
00058  clipping to optimize performance and calling paintWindow() first with only
00059  PAINT_WINDOW_OPAQUE to paint the opaque parts and then later
00060  with PAINT_WINDOW_TRANSLUCENT to paint the transparent parts. Function
00061  paintWindow() again goes through effects' paintWindow() until
00062  finalPaintWindow() is called, which calls the window's performPaint() to
00063  do the actual painting.
00064  
00065  The post-paint can be used for cleanups and is also used for scheduling
00066  repaints during the next painting pass for animations. Effects wanting to
00067  repaint certain parts can manually damage them during post-paint and repaint
00068  of these parts will be done during the next paint pass.
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 // Scene
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 // returns mask and possibly modified region
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     // preparation step
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         { // Region painting is not possible with transformations,
00115           // because screen damage doesn't match transformed positions.
00116         *mask &= ~PAINT_SCREEN_REGION;
00117         *region = infiniteRegion();
00118         }
00119     else if(  *mask & PAINT_SCREEN_REGION )
00120         { // make sure not to go outside visible screen
00121         *region &= QRegion( 0, 0, displayWidth(), displayHeight());
00122         }
00123     else
00124         { // whole screen, not transformed, force region to be full
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     // make sure not to go outside of the screen area
00137     *region &= QRegion( 0, 0, displayWidth(), displayHeight());
00138     // make sure all clipping is restored
00139     Q_ASSERT( !PaintClipper::clip());
00140     }
00141 
00142 // Compute time since the last painting pass.
00143 void Scene::updateTimeDiff()
00144     {
00145     if( last_time.isNull())
00146         {
00147         // Painting has been idle (optimized out) for some time,
00148         // which means time_diff would be huge and would break animations.
00149         // Simply set it to one (zero would mean no change at all and could
00150         // cause problems).
00151         time_diff = 1;
00152         }
00153     else
00154         time_diff = last_time.elapsed();
00155     if( time_diff < 0 ) // check time rollback
00156         time_diff = 1;
00157     last_time.start();;
00158     }
00159 
00160 // Painting pass is optimized away.
00161 void Scene::idle()
00162     {
00163     // Don't break time since last paint for the next pass.
00164     last_time = QTime();
00165     }
00166 
00167 // the function that'll be eventually called by paintScreen() above
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 // The generic painting code that can handle even transformations.
00177 // It simply paints bottom-to-top.
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 ) // bottom to top
00184         {
00185         WindowPrePaintData data;
00186         data.mask = orig_mask | ( w->isOpaque() ? PAINT_WINDOW_OPAQUE : PAINT_WINDOW_TRANSLUCENT );
00187         w->resetPaintingEnabled();
00188         data.paint = infiniteRegion(); // no clipping, so doesn't really matter
00189         data.clip = QRegion();
00190         data.quads = w->buildQuads();
00191         // preparation step
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 // The optimized case without any transformations at all.
00208 // It can paint only the requested region and can use clipping
00209 // to reduce painting and improve performance.
00210 void Scene::paintSimpleScreen( int orig_mask, QRegion region )
00211     {
00212     // TODO PAINT_WINDOW_* flags don't belong here, that's why it's in the assert,
00213     // perhaps the two enums should be separated
00214     assert(( orig_mask & ( PAINT_WINDOW_TRANSFORMED | PAINT_SCREEN_TRANSFORMED
00215         | PAINT_WINDOW_TRANSLUCENT | PAINT_WINDOW_OPAQUE )) == 0 );
00216     QHash< Window*, Phase2Data > phase2data;
00217     // Draw each opaque window top to bottom, subtracting the bounding rect of
00218     // each window from the clip region after it's been drawn.
00219     for( int i = stacking_order.count() - 1; // top to bottom
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         // preparation step
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 ) // prepaint added area to draw
00240             painted_region |= data.paint; // make sure it makes it to the screen
00241         // Schedule the window for painting
00242         phase2data[w] = Phase2Data( w, data.paint, data.clip, data.mask, data.quads );
00243         }
00244     // Do the actual painting
00245     // First opaque windows, top to bottom
00246     // This also calculates correct paint regions for windows, also taking
00247     //  care of clipping
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         // Calculate correct paint region and take the clip region into account
00256         d.region = painted_region - allclips;
00257         allclips |= d.clip;
00258         if( d.mask & PAINT_WINDOW_TRANSLUCENT )
00259             {
00260             // For translucent windows, the paint region must contain the
00261             //  entire painted area, except areas clipped by opaque windows
00262             //  above the translucent window
00263             phase2data[w].region = d.region;
00264             }
00265         else
00266             {
00267             // Paint the opaque window
00268             paintWindow( d.window, d.mask, d.region, d.quads );
00269             }
00270         }
00271     // Fill any areas of the root window not covered by windows
00272     if( !( orig_mask & PAINT_SCREEN_BACKGROUND_FIRST ))
00273         paintBackground( painted_region - allclips );
00274     // Now walk the list bottom to top, drawing translucent windows.
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     // no painting outside visible screen (and no transformations)
00289     region &= QRect( 0, 0, displayWidth(), displayHeight());
00290     if( region.isEmpty()) // completely clipped
00291         return;
00292 
00293     WindowPaintData data( w->window()->effectWindow());
00294     data.quads = quads;
00295     effects->paintWindow( effectWindow( w ), mask, region, data );
00296     }
00297 
00298 // the function that'll be eventually called by paintWindow() above
00299 void Scene::finalPaintWindow( EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data )
00300     {
00301     effects->drawWindow( w, mask, region, data );
00302     }
00303 
00304 // will be eventually called from drawWindow()
00305 void Scene::finalDrawWindow( EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data )
00306     {
00307     w->sceneWindow()->performPaint( mask, region, data );
00308     }
00309 
00310 //****************************************
00311 // Scene::Window
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     // it is created on-demand and cached, simply
00331     // reset the flag
00332     shape_valid = false;
00333     delete cached_quad_list;
00334     cached_quad_list = NULL;
00335     }
00336 
00337 // Find out the shape of the window using the XShape extension
00338 // or if shape is not set then simply it's the window geometry.
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; // Unmanaged is always visible
00378     // TODO there may be transformations, so ignore this for now
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()); // has no decoration
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         // TODO asi mam spatne pravy dolni roh - bud tady, nebo v jinych castech
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 } // namespace

KWin

Skip menu "KWin"
  • Main Page
  • 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
  •   libplasma
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.4
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