/***************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2006 Lubos Lunak You can Freely distribute this program under the GNU General Public License. See the file "COPYING" for the exact licensing terms. ******************************************************************/ #include "scene_basic.h" #include "client.h" #include #include "effects.h" namespace KWinInternal { //**************************************** // Scene::WrapperEffect //**************************************** Scene::WrapperEffect::~WrapperEffect() { } //**************************************** // Scene //**************************************** Scene* scene; Scene::Scene( Workspace* ws ) : wspace( ws ) { } Scene::~Scene() { } void Scene::WrapperEffect::prePaintScreen( int*, QRegion* ) { // nothing, no changes } // the function that'll be eventually called by paintScreen() above void Scene::WrapperEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data ) { if( mask & PAINT_SCREEN_REGION ) scene->paintSimpleScreen( mask, region ); else scene->paintGenericScreen( mask, data ); } // the generic painting code that should eventually handle even // transformations void Scene::paintGenericScreen( int orig_mask, ScreenPaintData ) { paintBackground( infiniteRegion()); foreach( Window* w, stacking_order ) // bottom to top { if( !w->isVisible()) continue; int mask = orig_mask | ( w->isOpaque() ? PAINT_WINDOW_OPAQUE : PAINT_WINDOW_TRANSLUCENT ); QRegion damage = infiniteRegion(); WrapperEffect wrapper; // preparation step effects->prePaintWindow( w, &mask, &damage, &wrapper ); paintWindow( w, mask, damage ); } } // the optimized case without any transformations at all void Scene::paintSimpleScreen( int orig_mask, QRegion region ) { assert(( orig_mask & ( PAINT_WINDOW_TRANSFORMED | PAINT_SCREEN_TRANSFORMED | PAINT_WINDOW_TRANSLUCENT | PAINT_WINDOW_OPAQUE )) == 0 ); QList< Phase2Data > phase2; // Draw each opaque window top to bottom, subtracting the bounding rect of // each window from the clip region after it's been drawn. for( int i = stacking_order.count() - 1; // top to bottom i >= 0; --i ) { Window* w = stacking_order[ i ]; if( !w->isVisible()) continue; if( region.isEmpty()) // completely clipped continue; int mask = orig_mask | ( w->isOpaque() ? PAINT_WINDOW_OPAQUE : PAINT_WINDOW_TRANSLUCENT ); QRegion damage = region; WrapperEffect wrapper; // preparation step effects->prePaintWindow( w, &mask, &damage, &wrapper ); if( mask & PAINT_WINDOW_TRANSLUCENT ) phase2.prepend( Phase2Data( w, region, mask )); if( mask & PAINT_WINDOW_OPAQUE ) { paintWindow( w, mask, region ); if( ( mask & PAINT_WINDOW_TRANSLUCENT ) == 0 ) // window is not transparent, can clip windows below region -= w->shape().translated( w->x(), w->y()); } } // Fill any areas of the root window not covered by windows paintBackground( region ); // Now walk the list bottom to top, drawing translucent windows. // That we draw bottom to top is important now since we're drawing translucent objects // and also are clipping only by opaque windows. foreach( Phase2Data d, phase2 ) { Window* w = d.window; paintWindow( w, d.mask, d.region ); } } void Scene::WrapperEffect::prePaintWindow( Scene::Window* , int*, QRegion* ) { // nothing, no changes } void Scene::paintWindow( Window* w, int mask, QRegion region ) { WindowPaintData data; data.opacity = w->window()->opacity(); WrapperEffect wrapper; effects->paintWindow( w, mask, region, data, &wrapper ); } // the function that'll be eventually called by paintWindow() above void Scene::WrapperEffect::paintWindow( Scene::Window* w, int mask, QRegion region, WindowPaintData& data ) { w->performPaint( mask, region, data ); } void Scene::windowGeometryShapeChanged( Toplevel* ) { } void Scene::windowOpacityChanged( Toplevel* ) { } void Scene::windowAdded( Toplevel* ) { } void Scene::windowDeleted( Toplevel* ) { } //**************************************** // Scene::Window //**************************************** Scene::Window::Window( Toplevel * c ) : toplevel( c ) , shape_valid( false ) { } Scene::Window::~Window() { } void Scene::Window::free() { } void Scene::Window::discardShape() { shape_valid = false; } QRegion Scene::Window::shape() const { if( !shape_valid ) { Client* c = dynamic_cast< Client* >( toplevel ); if( toplevel->shape() || ( c != NULL && !c->mask().isEmpty())) { int count, order; XRectangle* rects = XShapeGetRectangles( display(), toplevel->handle(), ShapeBounding, &count, &order ); if(rects) { shape_region = QRegion(); for( int i = 0; i < count; ++i ) shape_region += QRegion( rects[ i ].x, rects[ i ].y, rects[ i ].width, rects[ i ].height ); XFree(rects); } else shape_region = QRegion( 0, 0, width(), height()); } else shape_region = QRegion( 0, 0, width(), height()); shape_valid = true; } return shape_region; } bool Scene::Window::isVisible() const { return true; // TODO there may be transformations, so always true for now // TODO mapping state? return !toplevel->geometry() .intersect( QRect( 0, 0, displayWidth(), displayHeight())) .isEmpty(); } bool Scene::Window::isOpaque() const { return toplevel->opacity() == 1.0 && !toplevel->hasAlpha(); } } // namespace