2006-07-05 12:30:03 +00:00
|
|
|
/*****************************************************************
|
|
|
|
KWin - the KDE window manager
|
|
|
|
This file is part of the KDE project.
|
|
|
|
|
|
|
|
Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>
|
|
|
|
|
|
|
|
You can Freely distribute this program under the GNU General Public
|
|
|
|
License. See the file "COPYING" for the exact licensing terms.
|
|
|
|
******************************************************************/
|
|
|
|
|
2006-10-24 19:17:48 +00:00
|
|
|
#include "scene.h"
|
2006-10-15 08:58:38 +00:00
|
|
|
|
|
|
|
#include <X11/extensions/shape.h>
|
2006-07-05 12:30:03 +00:00
|
|
|
|
2006-10-24 19:17:48 +00:00
|
|
|
#include "client.h"
|
2006-10-16 21:06:34 +00:00
|
|
|
#include "effects.h"
|
|
|
|
|
2006-07-05 12:30:03 +00:00
|
|
|
namespace KWinInternal
|
|
|
|
{
|
|
|
|
|
2006-10-16 21:06:34 +00:00
|
|
|
//****************************************
|
|
|
|
// Scene::WrapperEffect
|
|
|
|
//****************************************
|
|
|
|
|
|
|
|
Scene::WrapperEffect::~WrapperEffect()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-07-05 12:30:03 +00:00
|
|
|
//****************************************
|
|
|
|
// Scene
|
|
|
|
//****************************************
|
|
|
|
|
2006-10-15 08:58:38 +00:00
|
|
|
Scene* scene;
|
|
|
|
|
2006-07-05 12:30:03 +00:00
|
|
|
Scene::Scene( Workspace* ws )
|
|
|
|
: wspace( ws )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Scene::~Scene()
|
|
|
|
{
|
|
|
|
}
|
2006-10-16 21:06:34 +00:00
|
|
|
|
2006-10-24 13:38:31 +00:00
|
|
|
// returns mask and possibly modified region
|
|
|
|
void Scene::paintScreen( int* mask, QRegion* region )
|
|
|
|
{
|
|
|
|
*mask = ( *region == QRegion( 0, 0, displayWidth(), displayHeight()))
|
|
|
|
? 0 : PAINT_SCREEN_REGION;
|
|
|
|
WrapperEffect wrapper;
|
2006-10-24 19:17:48 +00:00
|
|
|
updateTimeDiff();
|
2006-10-24 13:38:31 +00:00
|
|
|
// preparation step
|
2006-10-24 19:17:48 +00:00
|
|
|
effects->prePaintScreen( mask, region, time_diff, &wrapper );
|
2006-10-24 13:38:31 +00:00
|
|
|
if( *mask & ( PAINT_SCREEN_TRANSFORMED | PAINT_WINDOW_TRANSFORMED ))
|
|
|
|
*mask &= ~PAINT_SCREEN_REGION;
|
|
|
|
// TODO call also prePaintWindow() for all windows
|
|
|
|
ScreenPaintData data;
|
|
|
|
effects->paintScreen( *mask, *region, data, &wrapper );
|
|
|
|
}
|
|
|
|
|
2006-10-24 19:17:48 +00:00
|
|
|
void Scene::updateTimeDiff()
|
|
|
|
{
|
|
|
|
if( last_time.isNull())
|
|
|
|
{
|
|
|
|
// has been idle for some time, time_diff would be huge
|
|
|
|
time_diff = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
time_diff = last_time.elapsed();
|
|
|
|
if( time_diff < 0 )
|
|
|
|
time_diff = 0;
|
|
|
|
last_time.start();;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Scene::idle()
|
|
|
|
{
|
|
|
|
last_time = QTime();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Scene::WrapperEffect::prePaintScreen( int*, QRegion*, int )
|
2006-10-16 21:06:34 +00:00
|
|
|
{
|
|
|
|
// 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 )
|
2006-10-21 18:07:00 +00:00
|
|
|
scene->paintSimpleScreen( mask, region );
|
2006-10-16 21:06:34 +00:00
|
|
|
else
|
2006-10-21 18:07:00 +00:00
|
|
|
scene->paintGenericScreen( mask, data );
|
2006-10-16 21:06:34 +00:00
|
|
|
}
|
2006-10-21 18:07:00 +00:00
|
|
|
|
2006-10-16 21:06:34 +00:00
|
|
|
// the generic painting code that should eventually handle even
|
|
|
|
// transformations
|
2006-10-22 10:15:19 +00:00
|
|
|
void Scene::paintGenericScreen( int orig_mask, ScreenPaintData )
|
2006-10-16 21:06:34 +00:00
|
|
|
{
|
|
|
|
paintBackground( infiniteRegion());
|
|
|
|
foreach( Window* w, stacking_order ) // bottom to top
|
|
|
|
{
|
|
|
|
if( !w->isVisible())
|
|
|
|
continue;
|
2006-10-22 10:15:19 +00:00
|
|
|
int mask = orig_mask | ( w->isOpaque() ? PAINT_WINDOW_OPAQUE : PAINT_WINDOW_TRANSLUCENT );
|
|
|
|
QRegion damage = infiniteRegion();
|
|
|
|
WrapperEffect wrapper;
|
|
|
|
// preparation step
|
2006-10-24 19:17:48 +00:00
|
|
|
effects->prePaintWindow( w, &mask, &damage, time_diff, &wrapper );
|
2006-10-22 10:15:19 +00:00
|
|
|
paintWindow( w, mask, damage );
|
2006-10-16 21:06:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// the optimized case without any transformations at all
|
2006-10-22 10:15:19 +00:00
|
|
|
void Scene::paintSimpleScreen( int orig_mask, QRegion region )
|
2006-10-16 21:06:34 +00:00
|
|
|
{
|
2006-10-22 10:15:19 +00:00
|
|
|
assert(( orig_mask & ( PAINT_WINDOW_TRANSFORMED | PAINT_SCREEN_TRANSFORMED
|
2006-10-21 18:07:00 +00:00
|
|
|
| PAINT_WINDOW_TRANSLUCENT | PAINT_WINDOW_OPAQUE )) == 0 );
|
2006-10-16 21:06:34 +00:00
|
|
|
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;
|
2006-10-22 10:15:19 +00:00
|
|
|
int mask = orig_mask | ( w->isOpaque() ? PAINT_WINDOW_OPAQUE : PAINT_WINDOW_TRANSLUCENT );
|
|
|
|
QRegion damage = region;
|
|
|
|
WrapperEffect wrapper;
|
|
|
|
// preparation step
|
2006-10-24 19:17:48 +00:00
|
|
|
effects->prePaintWindow( w, &mask, &damage, time_diff, &wrapper );
|
2006-10-22 10:15:19 +00:00
|
|
|
if( mask & PAINT_WINDOW_TRANSLUCENT )
|
|
|
|
phase2.prepend( Phase2Data( w, region, mask ));
|
|
|
|
if( mask & PAINT_WINDOW_OPAQUE )
|
2006-10-16 21:06:34 +00:00
|
|
|
{
|
2006-10-22 10:15:19 +00:00
|
|
|
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());
|
2006-10-16 21:06:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// 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;
|
2006-10-22 10:15:19 +00:00
|
|
|
paintWindow( w, d.mask, d.region );
|
2006-10-16 21:06:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-10-24 19:17:48 +00:00
|
|
|
void Scene::WrapperEffect::prePaintWindow( Scene::Window* , int*, QRegion*, int )
|
2006-10-16 21:06:34 +00:00
|
|
|
{
|
|
|
|
// nothing, no changes
|
|
|
|
}
|
|
|
|
|
|
|
|
void Scene::paintWindow( Window* w, int mask, QRegion region )
|
|
|
|
{
|
|
|
|
WindowPaintData data;
|
2006-10-22 10:15:19 +00:00
|
|
|
data.opacity = w->window()->opacity();
|
2006-10-16 21:06:34 +00:00
|
|
|
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 )
|
|
|
|
{
|
2006-10-22 10:15:19 +00:00
|
|
|
w->performPaint( mask, region, data );
|
2006-10-16 21:06:34 +00:00
|
|
|
}
|
|
|
|
|
2006-07-05 20:52:57 +00:00
|
|
|
void Scene::windowGeometryShapeChanged( Toplevel* )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void Scene::windowOpacityChanged( Toplevel* )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-09-29 19:05:36 +00:00
|
|
|
void Scene::windowAdded( Toplevel* )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-07-05 20:52:57 +00:00
|
|
|
void Scene::windowDeleted( Toplevel* )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-10-16 10:12:48 +00:00
|
|
|
//****************************************
|
|
|
|
// Scene::Window
|
|
|
|
//****************************************
|
|
|
|
|
2006-10-15 08:58:38 +00:00
|
|
|
Scene::Window::Window( Toplevel * c )
|
|
|
|
: toplevel( c )
|
|
|
|
, shape_valid( false )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-10-16 10:12:48 +00:00
|
|
|
Scene::Window::~Window()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-10-16 21:06:34 +00:00
|
|
|
void Scene::Window::free()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-10-15 08:58:38 +00:00
|
|
|
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
|
|
|
|
{
|
2006-10-22 10:15:19 +00:00
|
|
|
return true; // TODO there may be transformations, so always true for now
|
2006-10-15 08:58:38 +00:00
|
|
|
// 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();
|
|
|
|
}
|
2006-07-05 12:30:03 +00:00
|
|
|
|
|
|
|
} // namespace
|