Document the compositing framework and the scene backends,
describe the design, add links to external docs. Restructure COMPOSITE_TODO into sections and add sort of priorities. svn path=/branches/work/kwin_composite/; revision=600163
This commit is contained in:
parent
5f03c77514
commit
d92d3a8165
11 changed files with 545 additions and 156 deletions
224
COMPOSITE_TODO
224
COMPOSITE_TODO
|
@ -1,93 +1,99 @@
|
|||
* = not done
|
||||
This file lists TODO items for the compositing code.
|
||||
|
||||
See file HACKING for details on developing KWin.
|
||||
See effects/howto.* for a HOWTO on writting effects.
|
||||
See documentation in source (mainly in scene.cpp) for description
|
||||
of the design of the compositing framework.
|
||||
|
||||
TODO
|
||||
=================================
|
||||
|
||||
* = not done, will be either done by me, or should be at least discussed first with me
|
||||
+ = not done, I don't plan on doing it that soon
|
||||
- in other words, these should be the best ones for you if you want to help
|
||||
! = like +, but they should be relatively simple
|
||||
- in other words, these should be the best if you want to get started with the code
|
||||
/ = work in progress
|
||||
? = should it be done?
|
||||
|
||||
See the HACKING file for KWin details. The composite-related sources are mostly
|
||||
composite.cpp and scene_opengl.cpp (TODO: add comments and general overview).
|
||||
|
||||
Sources:
|
||||
General TODO
|
||||
=================================
|
||||
|
||||
- glcompmgr : http://lists.freedesktop.org/archives/xorg/2006-July/017006.html ,
|
||||
http://www.mail-archive.com/compiz%40lists.freedesktop.org/msg00023.html
|
||||
- simple and easy to understand
|
||||
- works even without texture_from_pixmap extension
|
||||
- claims to support several different gfx cards
|
||||
- compiz : git clone git://anongit.freedesktop.org/git/xorg/app/compiz
|
||||
- the ultimate <whatever>
|
||||
- glxcompmgr : git clone git://anongit.freedesktop.org/git/xorg/app/glxcompgr
|
||||
- a rather old version of compiz, but also simpler and as such simpler
|
||||
to understand
|
||||
- libcm (metacity) : cvs -d :pserver:anonymous@anoncvs.gnome.org:/cvs/gnome co libcm
|
||||
- no idea about it
|
||||
|
||||
- http://opengl.org - documentation - OpenGL Redbook, GLX docs, extensions docs
|
||||
|
||||
TODO:
|
||||
|
||||
* Check/make it work with other gfx cards
|
||||
- I've tested only with nvidia with the 9625 beta drivers and 8776 stable drivers so far
|
||||
- I have absolutely no idea about other gfx cards, needs to be tested
|
||||
* ati
|
||||
* intel
|
||||
* who knows what else
|
||||
|
||||
? Xgl support
|
||||
- Compiz itself doesn't work when compiled with the libGL from nvidia,
|
||||
it ships its own and links against it
|
||||
? might be worth trying to use that libGL as well
|
||||
- it may be just because of the special libGL, but when testing with Xgl
|
||||
it even seemed non-conformant - none of the provided configs had
|
||||
GLX_RENDER_TYPE with GLX_RGBA_BIT even though required by GLX
|
||||
and other funny things. Indeed, it may be just me being still pretty
|
||||
clueless about these things.
|
||||
* is there a good reason to support Xgl? With the 9625 nvidia drivers
|
||||
it seems to work fine without them
|
||||
|
||||
? AIGLX support
|
||||
- no idea about this at all
|
||||
* find out if it works
|
||||
|
||||
* XComposite overlay window
|
||||
! XComposite overlay window
|
||||
- X.Org 7.1 and newer have XComposite extension version 0.3, which allows
|
||||
creating an overlay window to paint to instead of painting to the root window
|
||||
- I still run older X.Org here
|
||||
- the code in glcompmgr for this is in HAVE_OVERLAYS, stealing primarily from
|
||||
here should be better since it's simpler and the code so far has been
|
||||
modelled more after glcompmgr
|
||||
- the code in compiz for this is in USE_COW
|
||||
* use double-buffering with the overlay window - kwin already has code
|
||||
! - use double-buffering with the overlay window - kwin already has code
|
||||
for double-buffered destination drawable, but I haven't been able to test it
|
||||
|
||||
* when relying on extensions, detect that they are available
|
||||
- some of the glcompmgr code probably depends on OpenGL/GLX extensions that may
|
||||
not be always available, probably the same with compiz
|
||||
* find out which code relies on extensions and add checks
|
||||
- should be only needed for OpenGL code, I think this doesn't matter for XRender
|
||||
|
||||
? alpha clear hack
|
||||
* find out if it affects performance
|
||||
* if yes, try to find a better way of solving the problem
|
||||
- since kompmgr has an option to make only the decoration transparent,
|
||||
+ - find out if it affects performance
|
||||
+ - if yes, try to find a better way of solving the problem
|
||||
! - since kompmgr has an option to make only the decoration transparent,
|
||||
it should be possible to do the same here - if the window has alpha and a decoration
|
||||
or if there should be only the decoration transparent, paint first the contents
|
||||
and then the decoration - this should make it possible to paint the decoration
|
||||
without the random alpha that is right now handled by the alpha hack
|
||||
|
||||
/ design framework for graphical effects
|
||||
- modelling it after compiz seems to make a lot of sense
|
||||
* don't add workspace damage in Toplevel::addDamage()
|
||||
- instead add damage of windows to the screen only before doing the painting
|
||||
- this should prevent repaints because of changing obscured windows
|
||||
|
||||
* update only those parts of the screen that have been changed
|
||||
- for paintSimpleScreen() - it currently sets region to the whole screen
|
||||
* instead of using glXSwapBuffers() there should be glCopyPixels() used
|
||||
- compiz has such code in evenLoop() in the if() block for COMP_SCREEN_DAMAGE_REGION_MASK
|
||||
* perhaps syncing to vblank will be needed to avoid flicker
|
||||
* XCopyArea() should not update the whole screen but only the affected areas
|
||||
* wait for decoration repaints
|
||||
- it is sometimes visible that the window contents are painted first and the decoration
|
||||
only afterwards with a small delay
|
||||
- maybe posted paint events need to be processed immediatelly, or maybe the compositing
|
||||
code should not update the window until the decoration is finished painting
|
||||
|
||||
* sync to vblank
|
||||
* handle XRandr changes
|
||||
- output buffers and similar probably need recreating when the screen size changes
|
||||
|
||||
|
||||
OpenGL TODO
|
||||
=================================
|
||||
|
||||
+ Check/make it work with other gfx cards
|
||||
- I've tested only with nvidia with the 9625 beta drivers and 8776 stable drivers so far
|
||||
- I have absolutely no idea about other gfx cards, needs to be tested
|
||||
+ - ati
|
||||
+ - intel
|
||||
+ - who knows what else
|
||||
|
||||
? Xgl support
|
||||
- Compiz itself doesn't work when compiled with the libGL from nvidia,
|
||||
it ships its own and links against it
|
||||
? - might be worth trying to use that libGL as well
|
||||
- it may be just because of the special libGL, but when testing with Xgl
|
||||
it even seemed non-conformant - none of the provided configs had
|
||||
GLX_RENDER_TYPE with GLX_RGBA_BIT even though required by GLX
|
||||
and other funny things. Indeed, it may be just me being still pretty
|
||||
clueless about these things.
|
||||
? - is there a good reason to support Xgl? With the 9625 nvidia drivers
|
||||
it seems to work fine without them and there's AIGLX
|
||||
|
||||
? AIGLX support
|
||||
- no idea about this at all
|
||||
+ - find out if it works
|
||||
|
||||
! when relying on extensions, detect that they are available
|
||||
- some of the glcompmgr code probably depends on OpenGL/GLX extensions that may
|
||||
not be always available, probably the same with compiz
|
||||
! - find out which code relies on extensions and add checks
|
||||
! - it seems that some systems (using older X.org?) will need local versions
|
||||
of some #defines like GLX_TEXTURE_FORMAT_EXT
|
||||
- Beryl has this code in beryl.h
|
||||
|
||||
+ sync to vblank
|
||||
- currently the compositing code is run with 20ms timer, i.e. constant 50fps
|
||||
- the GLX_SGI_video_sync extension should be used
|
||||
- compiz uses this, no idea about it though
|
||||
|
||||
? GL_ARB_texture_rectangle vs GL_ARB_texture_non_power_of_two
|
||||
+ GL_ARB_texture_rectangle vs GL_ARB_texture_non_power_of_two
|
||||
- code currently uses GL_ARB_texture_rectangle (GL_TEXTURE_RECTANGLE_ARB), using
|
||||
normal textures when GL_ARB_texture_non_power_of_two is available should(?) be
|
||||
preferred
|
||||
|
@ -95,26 +101,98 @@ TODO:
|
|||
? in SceneOpenGL::bindTexture() with tfp_mode, with some gfx cards it seems
|
||||
to be faster to not short-circuit the texture binding when there's been
|
||||
no damage
|
||||
* confirm and try to find out when to do it and when not
|
||||
+ - confirm and try to find out when to do it and when not
|
||||
|
||||
* SceneXrender::Window::performPaint() doesn't use xScale/yScale
|
||||
! update only those parts of the screen that have been changed
|
||||
- for paintSimpleScreen() - it currently sets region to the whole screen
|
||||
! - instead of using glXSwapBuffers() there should be glCopyPixels() used
|
||||
- compiz has such code in evenLoop() in the if() block for COMP_SCREEN_DAMAGE_REGION_MASK
|
||||
+ - perhaps syncing to vblank will be needed to avoid flicker
|
||||
! - XCopyArea() should not update the whole screen but only the affected areas
|
||||
|
||||
|
||||
XRender TODO
|
||||
==============================
|
||||
|
||||
+ SceneXrender::Window::performPaint() doesn't use xScale/yScale
|
||||
- XRenderSetPictureTransform() should be capable of doing this
|
||||
- note that the matrix used seems to be weird (it doesn't act like the normal transformation
|
||||
matrix as far as I can tell)
|
||||
|
||||
|
||||
Effects framework TODO
|
||||
==============================
|
||||
|
||||
/ design framework for graphical effects
|
||||
- modelling it after compiz seems to make a lot of sense
|
||||
|
||||
* solve somehow disappearing windows
|
||||
- i.e. when a window is e.g. closed, the Client/Unmanaged object is destroyed, but animations
|
||||
should be going on
|
||||
? maybe animations could be done actually before the state change, it makes sense to destroy
|
||||
? - maybe animations could be done actually before the state change, it makes sense to destroy
|
||||
the window only after it's finished exploding or really minimizing the window only after
|
||||
the animation of minimizing to the taskbar is done, however this looks very hairy
|
||||
and error-prone
|
||||
? maybe the animation effects should keep the necessary info themselves, so that the object
|
||||
? - maybe the animation effects should keep the necessary info themselves, so that the object
|
||||
can be destroyed
|
||||
- the problem here may be what to do when the window again reappears, a new object will
|
||||
be created, but the old animation should be stopped - compare window id's?
|
||||
? maybe just keep the object around in a special list
|
||||
- another problem is that then the window won't exist at all in the scene functions,
|
||||
so e.g. no paintWindow() will be called for it
|
||||
? - maybe just keep the object around in a special list
|
||||
|
||||
* don't add workspace damage in Toplevel::addDamage()
|
||||
- instead add damage of windows to the screen only before doing the painting
|
||||
- this should prevent repaints because of obscured windows
|
||||
* more notification functions for effects are needed
|
||||
- currently there are only very few notification functions (windowAdded, windowActivated,...)
|
||||
! - virtual desktop change
|
||||
! - window state changes
|
||||
? more
|
||||
|
||||
* shadows
|
||||
|
||||
* support for effects involving more virtual desktops
|
||||
- currently effects are limited to only the active virtual desktop
|
||||
|
||||
* support for grabbing input
|
||||
- during some more complicated effects, input (at least mouse) should be disabled,
|
||||
because currently there is no way to do input redirection
|
||||
|
||||
|
||||
Effects TODO
|
||||
===============================
|
||||
|
||||
+ adapt the kcontrol module used by Kompmgr
|
||||
- in kcmkwin/kwinoptions
|
||||
! - uses ~/.xcompmgr, convert to use normal KConfig
|
||||
? - I don't think these effects should be plugins or anything like that,
|
||||
probably simply write to kwinrc and use the Option class in KWin
|
||||
|
||||
+ implements all effects Kompmgr could do
|
||||
+ - all effects from the Opacity tab should be already doable
|
||||
! - applying translucency only to the decoration
|
||||
- use clientSize() and clientPos() from Client
|
||||
- see also the alpha clear hack todo entry
|
||||
! - not usign ARGB visuals
|
||||
- just clear the alpha channel in the alpha clear hack
|
||||
- or do it while painting (see also the alpha clear hack todo entry)
|
||||
! - the rest - should be simple
|
||||
* - shadows
|
||||
- framework is not ready for them yet (see the todo entry)
|
||||
+ - tab Effects
|
||||
! - fade-in should be simple
|
||||
+ - fade between changes
|
||||
- will need notification about opacity changes
|
||||
- not sure if this is doable for other opacity changes then the ones
|
||||
initiated by the user or by the application
|
||||
* - fade-out needs framework for disappearing windows (see the todo entry)
|
||||
|
||||
+ minimize/shade effects
|
||||
- to replace the ones from KWin core
|
||||
- Client::animateMinimizeOrUnminimize()
|
||||
- Client::setShade()
|
||||
|
||||
+ zoom effect
|
||||
- enlarge a portion of the screen
|
||||
! - would require adding xScale/yScale to ScreenPaintData
|
||||
- should be doable even for XRender
|
||||
|
||||
? other effects
|
||||
|
|
|
@ -8,6 +8,23 @@ You can Freely distribute this program under the GNU General Public
|
|||
License. See the file "COPYING" for the exact licensing terms.
|
||||
******************************************************************/
|
||||
|
||||
/*
|
||||
Code related to compositing (redirecting windows to pixmaps and tracking
|
||||
window damage).
|
||||
|
||||
Docs:
|
||||
|
||||
XComposite (the protocol, but the function calls map to it):
|
||||
http://gitweb.freedesktop.org/?p=xorg/proto/compositeproto.git;a=blob;hb=HEAD;f=protocol
|
||||
|
||||
XDamage (again the protocol):
|
||||
http://gitweb.freedesktop.org/?p=xorg/proto/damageproto.git;a=blob;hb=HEAD;f=protocol
|
||||
|
||||
Composite HOWTO from Fredrik:
|
||||
http://ktown.kde.org/~fredrik/composite_howto.html
|
||||
|
||||
*/
|
||||
|
||||
#include "utils.h"
|
||||
#include "workspace.h"
|
||||
#include "client.h"
|
||||
|
@ -125,7 +142,7 @@ void Workspace::addDamageFull()
|
|||
damage_region = QRegion( 0, 0, displayWidth(), displayHeight());
|
||||
}
|
||||
|
||||
void Workspace::compositeTimeout()
|
||||
void Workspace::performCompositing()
|
||||
{
|
||||
// The event loop apparently tries to fire a QTimer as often as possible, even
|
||||
// at the expense of not processing many X events. This means that the composite
|
||||
|
@ -139,6 +156,8 @@ void Workspace::compositeTimeout()
|
|||
scene->idle();
|
||||
return;
|
||||
}
|
||||
// create a list of all windows in the stacking order
|
||||
// TODO keep this list like now a stacking order of Client window is kept
|
||||
ToplevelList windows;
|
||||
Window* children;
|
||||
unsigned int children_count;
|
||||
|
@ -156,11 +175,13 @@ void Workspace::compositeTimeout()
|
|||
else if( Unmanaged* c = findUnmanaged( HandleMatchPredicate( children[ i ] )))
|
||||
windows.append( c );
|
||||
}
|
||||
scene->prePaint();
|
||||
scene->initPaint();
|
||||
scene->paint( damage_region, windows );
|
||||
// clear all damage
|
||||
damage_region = QRegion();
|
||||
foreach( Toplevel* c, windows )
|
||||
c->resetDamage();
|
||||
// run post-pass only after clearing the damage
|
||||
scene->postPaint();
|
||||
lastCompositePaint.start();
|
||||
}
|
||||
|
|
110
scene.cpp
110
scene.cpp
|
@ -8,6 +8,65 @@ You can Freely distribute this program under the GNU General Public
|
|||
License. See the file "COPYING" for the exact licensing terms.
|
||||
******************************************************************/
|
||||
|
||||
/*
|
||||
(NOTE: The compositing code is work in progress. As such this design
|
||||
documentation may get outdated in some areas.)
|
||||
|
||||
The base class for compositing, implementing shared functionality
|
||||
between the OpenGL and XRender backends.
|
||||
|
||||
Design:
|
||||
|
||||
When compositing is turned on, XComposite extension is used to redirect
|
||||
drawing of windows to pixmaps and XDamage extension is used to get informed
|
||||
about damage (changes) to window contents. This code is mostly in composite.cpp .
|
||||
|
||||
Workspace::performCompositing() starts one painting pass. Painting is done
|
||||
by painting the screen, which in turn paints every window. Painting can be affected
|
||||
using effects, which are chained. E.g. painting a screen means that actually
|
||||
paintScreen() of the first effect is called, which possibly does modifications
|
||||
and calls next effect's paintScreen() and so on, until Scene::finalPaintScreen()
|
||||
is called.
|
||||
|
||||
There are 3 phases of every paint (not necessarily done together):
|
||||
The pre-paint phase, the paint phase and the post-paint phase.
|
||||
|
||||
The pre-paint phase is used to find out about how the painting will be actually
|
||||
done (i.e. what the effects will do). For example when only a part of the screen
|
||||
needs to be updated and no effect will do any transformation it is possible to use
|
||||
an optimized paint function. How the painting will be done is controlled
|
||||
by the mask argument, see PAINT_WINDOW_* and PAINT_SCREEN_* flags in scene.h .
|
||||
For example an effect that decides to paint a normal windows as translucent
|
||||
will need to modify the mask in its prePaintWindow() to include
|
||||
the PAINT_WINDOW_TRANSLUCENT flag. The paintWindow() function will then get
|
||||
the mask with this flag turned on and will also paint using transparency.
|
||||
|
||||
The paint pass does the actual painting, based on the information collected
|
||||
using the pre-paint pass. After running through the effects' paintScreen()
|
||||
either paintGenericScreen() or optimized paintSimpleScreen() are called.
|
||||
Those call paintWindow() on windows (not necessarily all), possibly using
|
||||
clipping to optimize performance and calling paintWindow() first with only
|
||||
PAINT_WINDOW_OPAQUE to paint the opaque parts and then later
|
||||
with PAINT_WINDOW_TRANSLUCENT to paint the transparent parts. Function
|
||||
paintWindow() again goes through effects' paintWindow() until
|
||||
finalPaintWindow() is called, which calls the window's performPaint() to
|
||||
do the actual painting.
|
||||
|
||||
The post-paint can be used for cleanups and is also used for scheduling
|
||||
repaints during the next painting pass for animations. Effects wanting to
|
||||
repaint certain parts can manually damage them during post-paint and repaint
|
||||
of these parts will be done during the next paint pass.
|
||||
|
||||
|
||||
Various notes:
|
||||
|
||||
- When the screen or a window are transformed (*_TRANSFORMED flag), clipping
|
||||
and similar optimizations are not done (too complicated), so in such cases
|
||||
infiniteRegion() should be always used. Make sure not to make any transformations
|
||||
of such regions.
|
||||
|
||||
*/
|
||||
|
||||
#include "scene.h"
|
||||
|
||||
#include <X11/extensions/shape.h>
|
||||
|
@ -33,7 +92,7 @@ Scene::~Scene()
|
|||
{
|
||||
}
|
||||
|
||||
void Scene::prePaint()
|
||||
void Scene::initPaint()
|
||||
{
|
||||
effects->startPaint();
|
||||
// do the rest of prepaint pass together with paint pass
|
||||
|
@ -47,43 +106,48 @@ void Scene::paintScreen( int* mask, QRegion* region )
|
|||
updateTimeDiff();
|
||||
// preparation step
|
||||
effects->prePaintScreen( mask, region, time_diff );
|
||||
// optimized painting is not possible with transformations
|
||||
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 );
|
||||
}
|
||||
|
||||
// Compute time since the last painting pass.
|
||||
void Scene::updateTimeDiff()
|
||||
{
|
||||
if( last_time.isNull())
|
||||
{
|
||||
// has been idle for some time, time_diff would be huge
|
||||
// Painting has been idle (optimized out) for some time,
|
||||
// which means time_diff would be huge and would break animations.
|
||||
// Simply set it to zero.
|
||||
time_diff = 0;
|
||||
}
|
||||
else
|
||||
time_diff = last_time.elapsed();
|
||||
if( time_diff < 0 )
|
||||
if( time_diff < 0 ) // check time rollback
|
||||
time_diff = 0;
|
||||
last_time.start();;
|
||||
}
|
||||
|
||||
// Painting pass is optimized away.
|
||||
void Scene::idle()
|
||||
{
|
||||
// Don't break time since last paint for the next pass.
|
||||
last_time = QTime();
|
||||
}
|
||||
|
||||
// the function that'll be eventually called by paintScreen() above
|
||||
void Scene::finalPaintScreen( int mask, QRegion region, ScreenPaintData& data )
|
||||
{
|
||||
if( mask & PAINT_SCREEN_REGION )
|
||||
if( mask & PAINT_SCREEN_REGION ) // can do optimized case?
|
||||
paintSimpleScreen( mask, region );
|
||||
else
|
||||
paintGenericScreen( mask, data );
|
||||
}
|
||||
|
||||
// the generic painting code that should eventually handle even
|
||||
// transformations
|
||||
// The generic painting code that can handle even transformations.
|
||||
// It simply paints bottom-to-top.
|
||||
void Scene::paintGenericScreen( int orig_mask, ScreenPaintData )
|
||||
{
|
||||
paintBackground( infiniteRegion());
|
||||
|
@ -99,9 +163,13 @@ void Scene::paintGenericScreen( int orig_mask, ScreenPaintData )
|
|||
}
|
||||
}
|
||||
|
||||
// the optimized case without any transformations at all
|
||||
// The optimized case without any transformations at all.
|
||||
// It can paint only the requested region and can use clipping
|
||||
// to reduce painting and improve performance.
|
||||
void Scene::paintSimpleScreen( int orig_mask, QRegion region )
|
||||
{
|
||||
// TODO PAINT_WINDOW_* flags don't belong here, that's why it's in the assert,
|
||||
// perhaps the two enums should be separated
|
||||
assert(( orig_mask & ( PAINT_WINDOW_TRANSFORMED | PAINT_SCREEN_TRANSFORMED
|
||||
| PAINT_WINDOW_TRANSLUCENT | PAINT_WINDOW_OPAQUE )) == 0 );
|
||||
QList< Phase2Data > phase2;
|
||||
|
@ -120,12 +188,15 @@ void Scene::paintSimpleScreen( int orig_mask, QRegion region )
|
|||
QRegion damage = region;
|
||||
// preparation step
|
||||
effects->prePaintWindow( w, &mask, &damage, time_diff );
|
||||
// If the window is transparent, the transparent part will be done
|
||||
// in the 2nd pass.
|
||||
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
|
||||
// If the window is not transparent at all, it can clip windows below.
|
||||
if( ( mask & PAINT_WINDOW_TRANSLUCENT ) == 0 )
|
||||
region -= w->shape().translated( w->x(), w->y());
|
||||
}
|
||||
}
|
||||
|
@ -159,25 +230,10 @@ void Scene::postPaint()
|
|||
effects->postPaintScreen();
|
||||
foreach( Window* w, stacking_order )
|
||||
effects->postPaintWindow( w );
|
||||
// do cleanup
|
||||
stacking_order.clear();
|
||||
}
|
||||
|
||||
void Scene::windowGeometryShapeChanged( Toplevel* )
|
||||
{
|
||||
}
|
||||
|
||||
void Scene::windowOpacityChanged( Toplevel* )
|
||||
{
|
||||
}
|
||||
|
||||
void Scene::windowAdded( Toplevel* )
|
||||
{
|
||||
}
|
||||
|
||||
void Scene::windowDeleted( Toplevel* )
|
||||
{
|
||||
}
|
||||
|
||||
//****************************************
|
||||
// Scene::Window
|
||||
//****************************************
|
||||
|
@ -198,9 +254,13 @@ void Scene::Window::free()
|
|||
|
||||
void Scene::Window::discardShape()
|
||||
{
|
||||
// it is created on-demand and cached, simply
|
||||
// reset the flag
|
||||
shape_valid = false;
|
||||
}
|
||||
|
||||
// Find out the shape of the window using the XShape extension
|
||||
// or if not shape is set then simply it's the window geometry.
|
||||
QRegion Scene::Window::shape() const
|
||||
{
|
||||
if( !shape_valid )
|
||||
|
|
54
scene.h
54
scene.h
|
@ -23,45 +23,73 @@ class Workspace;
|
|||
class WindowPaintData;
|
||||
class ScreenPaintData;
|
||||
|
||||
// The base class for compositing backends.
|
||||
class Scene
|
||||
{
|
||||
public:
|
||||
Scene( Workspace* ws );
|
||||
virtual ~Scene() = 0;
|
||||
class Window;
|
||||
virtual void prePaint();
|
||||
// repaints the given screen areas, windows provides the stacking order
|
||||
// Called before calling paint() to perform initialization (does not
|
||||
// do the prepaint pass though)
|
||||
virtual void initPaint();
|
||||
// Repaints the given screen areas, windows provides the stacking order.
|
||||
// The entry point for the main part of the painting pass.
|
||||
virtual void paint( QRegion damage, ToplevelList windows ) = 0;
|
||||
// Called to perform post paint cleanup and for animations to prepare
|
||||
// for next pass.
|
||||
virtual void postPaint();
|
||||
|
||||
// Notification function - KWin core informs about changes.
|
||||
// Used to mainly discard cached data.
|
||||
|
||||
// shape/size of a window changed
|
||||
virtual void windowGeometryShapeChanged( Toplevel* );
|
||||
virtual void windowGeometryShapeChanged( Toplevel* ) = 0;
|
||||
// opacity of a window changed
|
||||
virtual void windowOpacityChanged( Toplevel* );
|
||||
virtual void windowOpacityChanged( Toplevel* ) = 0;
|
||||
// a new window has been created
|
||||
virtual void windowAdded( Toplevel* );
|
||||
virtual void windowAdded( Toplevel* ) = 0;
|
||||
// a window has been destroyed
|
||||
virtual void windowDeleted( Toplevel* );
|
||||
virtual void windowDeleted( Toplevel* ) = 0;
|
||||
// Flags controlling how painting is done.
|
||||
enum
|
||||
{
|
||||
// Window (or at least part of it) will be painted opaque.
|
||||
PAINT_WINDOW_OPAQUE = 1 << 0,
|
||||
// Window (or at least part of it) will be painted translucent.
|
||||
PAINT_WINDOW_TRANSLUCENT = 1 << 1,
|
||||
// Window will be painted with transformed geometry.
|
||||
PAINT_WINDOW_TRANSFORMED = 1 << 2,
|
||||
// Paint only a region of the screen (can be optimized, cannot
|
||||
// be used together with TRANSFORMED flags).
|
||||
PAINT_SCREEN_REGION = 1 << 3,
|
||||
// Whole screen will be painted with transformed geometry.
|
||||
PAINT_SCREEN_TRANSFORMED = 1 << 4
|
||||
};
|
||||
// there's nothing to paint (adjust time_diff later)
|
||||
void idle();
|
||||
protected:
|
||||
// shared implementation, starts painting the screen
|
||||
void paintScreen( int* mask, QRegion* region );
|
||||
friend class EffectsHandler;
|
||||
// called after all effects had their paintScreen() called
|
||||
void finalPaintScreen( int mask, QRegion region, ScreenPaintData& data );
|
||||
// shared implementation of painting the screen in the generic
|
||||
// (unoptimized) way
|
||||
virtual void paintGenericScreen( int mask, ScreenPaintData data );
|
||||
// shared implementation of painting the screen in an optimized way
|
||||
virtual void paintSimpleScreen( int mask, QRegion region );
|
||||
// paint the background (not the desktop background - the whole background)
|
||||
virtual void paintBackground( QRegion region ) = 0;
|
||||
// called after all effects had their paintWindow() called
|
||||
void finalPaintWindow( Window* w, int mask, QRegion region, WindowPaintData& data );
|
||||
// shared implementation, starts painting the window
|
||||
virtual void paintWindow( Window* w, int mask, QRegion region );
|
||||
// infinite region, i.e. everything
|
||||
static QRegion infiniteRegion();
|
||||
// compute time since the last repaint
|
||||
void updateTimeDiff();
|
||||
// saved data for 2nd pass of optimized screen painting
|
||||
struct Phase2Data
|
||||
{
|
||||
Phase2Data( Window* w, QRegion r, int m ) : window( w ), region( r ), mask( m ) {}
|
||||
|
@ -69,26 +97,36 @@ class Scene
|
|||
QRegion region;
|
||||
int mask;
|
||||
};
|
||||
// windows in their stacking order
|
||||
QVector< Window* > stacking_order;
|
||||
// time since last repaint
|
||||
int time_diff;
|
||||
QTime last_time;
|
||||
Workspace* wspace;
|
||||
};
|
||||
|
||||
// The base class for windows representations in composite backends
|
||||
class Scene::Window
|
||||
{
|
||||
public:
|
||||
Window( Toplevel* c );
|
||||
virtual ~Window();
|
||||
virtual void free(); // is often copied by value, use manually instead of dtor
|
||||
// this class is often copied by value, use manually instead of dtor
|
||||
virtual void free();
|
||||
// perform the actual painting of the window
|
||||
virtual void performPaint( int mask, QRegion region, WindowPaintData data ) = 0;
|
||||
int x() const;
|
||||
int y() const;
|
||||
int width() const;
|
||||
int height() const;
|
||||
// access to the internal window class
|
||||
// TODO eventually get rid of this
|
||||
Toplevel* window();
|
||||
// is the window visible at all
|
||||
bool isVisible() const;
|
||||
// is the window fully opaque
|
||||
bool isOpaque() const;
|
||||
// shape of the window
|
||||
QRegion shape() const;
|
||||
void discardShape();
|
||||
Window() {} // QMap sucks even in Qt4
|
||||
|
@ -103,7 +141,7 @@ extern Scene* scene;
|
|||
|
||||
inline
|
||||
QRegion Scene::infiniteRegion()
|
||||
{ // INT_MIN / 2 because it's width/height (INT_MIN+INT_MAX==-1)
|
||||
{ // INT_MIN / 2 because width/height is used (INT_MIN+INT_MAX==-1)
|
||||
return QRegion( INT_MIN / 2, INT_MIN / 2, INT_MAX, INT_MAX );
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,13 @@ You can Freely distribute this program under the GNU General Public
|
|||
License. See the file "COPYING" for the exact licensing terms.
|
||||
******************************************************************/
|
||||
|
||||
/*
|
||||
This is very simple compositing code using only plain X. It doesn't use any effects
|
||||
or anything like that, it merely draws everything as it would be visible without
|
||||
compositing. It was the first compositing code in KWin and is usable only for testing
|
||||
and as the very simple "this is how it works".
|
||||
*/
|
||||
|
||||
#include "scene_basic.h"
|
||||
|
||||
#include "utils.h"
|
||||
|
@ -16,10 +23,6 @@ License. See the file "COPYING" for the exact licensing terms.
|
|||
namespace KWinInternal
|
||||
{
|
||||
|
||||
//****************************************
|
||||
// SceneBasic
|
||||
//****************************************
|
||||
|
||||
SceneBasic::SceneBasic( Workspace* ws )
|
||||
: Scene( ws )
|
||||
{
|
||||
|
@ -56,9 +59,27 @@ void SceneBasic::paint( QRegion, ToplevelList windows )
|
|||
XFlush( display());
|
||||
}
|
||||
|
||||
// These functions are not used at all, SceneBasic
|
||||
// is not using inherited functionality.
|
||||
|
||||
void SceneBasic::paintBackground( QRegion )
|
||||
{
|
||||
// empty, not using inherited functionality
|
||||
}
|
||||
|
||||
void SceneBasic::windowGeometryShapeChanged( Toplevel* )
|
||||
{
|
||||
}
|
||||
|
||||
void SceneBasic::windowOpacityChanged( Toplevel* )
|
||||
{
|
||||
}
|
||||
|
||||
void SceneBasic::windowAdded( Toplevel* )
|
||||
{
|
||||
}
|
||||
|
||||
void SceneBasic::windowDeleted( Toplevel* )
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -25,6 +25,10 @@ class SceneBasic
|
|||
virtual void paint( QRegion damage, ToplevelList windows );
|
||||
protected:
|
||||
virtual void paintBackground( QRegion region );
|
||||
virtual void windowGeometryShapeChanged( Toplevel* );
|
||||
virtual void windowOpacityChanged( Toplevel* );
|
||||
virtual void windowAdded( Toplevel* );
|
||||
virtual void windowDeleted( Toplevel* );
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
121
scene_opengl.cpp
121
scene_opengl.cpp
|
@ -8,8 +8,49 @@ You can Freely distribute this program under the GNU General Public
|
|||
License. See the file "COPYING" for the exact licensing terms.
|
||||
|
||||
Based on glcompmgr code by Felix Bellaby.
|
||||
Using code from Compiz and Beryl.
|
||||
******************************************************************/
|
||||
|
||||
/*
|
||||
This is the OpenGL-based compositing code. It is the primary and most powerful
|
||||
compositing backend.
|
||||
|
||||
Sources and other compositing managers:
|
||||
=======================================
|
||||
|
||||
- http://opengl.org
|
||||
- documentation
|
||||
- OpenGL Redbook
|
||||
- GLX docs
|
||||
- extensions docs
|
||||
|
||||
- glcompmgr
|
||||
- http://lists.freedesktop.org/archives/xorg/2006-July/017006.html ,
|
||||
- http://www.mail-archive.com/compiz%40lists.freedesktop.org/msg00023.html
|
||||
- simple and easy to understand
|
||||
- works even without texture_from_pixmap extension
|
||||
- claims to support several different gfx cards
|
||||
|
||||
- compiz
|
||||
- git clone git://anongit.freedesktop.org/git/xorg/app/compiz
|
||||
- the ultimate <whatever>
|
||||
- glxcompmgr
|
||||
- git clone git://anongit.freedesktop.org/git/xorg/app/glxcompgr
|
||||
- a rather old version of compiz, but also simpler and as such simpler
|
||||
to understand
|
||||
|
||||
- beryl
|
||||
- the community fork of Compiz
|
||||
- http://beryl-project.org
|
||||
- svn co svn://metascape.afraid.org/svnroot/beryl
|
||||
|
||||
- libcm (metacity)
|
||||
- cvs -d :pserver:anonymous@anoncvs.gnome.org:/cvs/gnome co libcm
|
||||
- not much idea about it, the model differs a lot from KWin/Compiz/Beryl
|
||||
- does not seem to be very powerful or with that much development going on
|
||||
|
||||
*/
|
||||
|
||||
#include "scene_opengl.h"
|
||||
|
||||
#include "utils.h"
|
||||
|
@ -25,22 +66,39 @@ namespace KWinInternal
|
|||
// SceneOpenGL
|
||||
//****************************************
|
||||
|
||||
// the config used for windows
|
||||
GLXFBConfig SceneOpenGL::fbcdrawable;
|
||||
// GLX content
|
||||
GLXContext SceneOpenGL::context;
|
||||
GLXPixmap SceneOpenGL::glxroot;
|
||||
// the destination drawable where the compositing is done
|
||||
GLXDrawable SceneOpenGL::glxroot;
|
||||
bool SceneOpenGL::tfp_mode; // using glXBindTexImageEXT (texture_from_pixmap)
|
||||
bool SceneOpenGL::root_db; // destination drawable is double-buffered
|
||||
bool SceneOpenGL::copy_buffer_hack; // workaround for nvidia < 1.0-9xxx drivers
|
||||
|
||||
// finding of OpenGL extensions functions
|
||||
typedef void (*glXFuncPtr)();
|
||||
typedef glXFuncPtr (*glXGetProcAddress_func)( const GLubyte* );
|
||||
|
||||
static glXFuncPtr getProcAddress( const char* name )
|
||||
{
|
||||
glXFuncPtr ret = NULL;
|
||||
if( glXGetProcAddress != NULL )
|
||||
ret = glXGetProcAddress( ( const GLubyte* ) name );
|
||||
if( ret == NULL )
|
||||
ret = ( glXFuncPtr ) dlsym( RTLD_DEFAULT, name );
|
||||
return ret;
|
||||
}
|
||||
|
||||
// texture_from_pixmap extension functions
|
||||
typedef void (*glXBindTexImageEXT_func)( Display* dpy, GLXDrawable drawable,
|
||||
int buffer, const int* attrib_list );
|
||||
typedef void (*glXReleaseTexImageEXT_func)( Display* dpy, GLXDrawable drawable, int buffer );
|
||||
typedef void (*glXFuncPtr)();
|
||||
typedef glXFuncPtr (*glXGetProcAddress_func)( const GLubyte* );
|
||||
glXBindTexImageEXT_func glXBindTexImageEXT;
|
||||
glXReleaseTexImageEXT_func glXReleaseTexImageEXT;
|
||||
glXGetProcAddress_func glXGetProcAddress;
|
||||
glXBindTexImageEXT_func glXBindTexImageEXT;
|
||||
|
||||
// detect OpenGL error (add to various places in code to pinpoint the place)
|
||||
static void checkGLError( const char* txt )
|
||||
{
|
||||
GLenum err = glGetError();
|
||||
|
@ -48,6 +106,7 @@ static void checkGLError( const char* txt )
|
|||
kWarning() << "GL error (" << txt << "): 0x" << QString::number( err, 16 ) << endl;
|
||||
}
|
||||
|
||||
// attributes for finding a double-buffered root window config
|
||||
const int root_db_attrs[] =
|
||||
{
|
||||
GLX_DOUBLEBUFFER, True,
|
||||
|
@ -60,6 +119,7 @@ const int root_db_attrs[] =
|
|||
None
|
||||
};
|
||||
|
||||
// attributes for finding a non-double-buffered root window config
|
||||
static const int root_buffer_attrs[] =
|
||||
{
|
||||
GLX_DOUBLEBUFFER, False,
|
||||
|
@ -72,6 +132,7 @@ static const int root_buffer_attrs[] =
|
|||
None
|
||||
};
|
||||
|
||||
// attributes for finding config for windows
|
||||
const int drawable_attrs[] =
|
||||
{
|
||||
GLX_DOUBLEBUFFER, False,
|
||||
|
@ -85,6 +146,7 @@ const int drawable_attrs[] =
|
|||
None
|
||||
};
|
||||
|
||||
// attributes for finding config for windows when using tfp
|
||||
const int drawable_tfp_attrs[] =
|
||||
{
|
||||
GLX_DOUBLEBUFFER, False,
|
||||
|
@ -99,16 +161,6 @@ const int drawable_tfp_attrs[] =
|
|||
None
|
||||
};
|
||||
|
||||
static glXFuncPtr getProcAddress( const char* name )
|
||||
{
|
||||
glXFuncPtr ret = NULL;
|
||||
if( glXGetProcAddress != NULL )
|
||||
ret = glXGetProcAddress( ( const GLubyte* ) name );
|
||||
if( ret == NULL )
|
||||
ret = ( glXFuncPtr ) dlsym( RTLD_DEFAULT, name );
|
||||
return ret;
|
||||
}
|
||||
|
||||
SceneOpenGL::SceneOpenGL( Workspace* ws )
|
||||
: Scene( ws )
|
||||
{
|
||||
|
@ -116,6 +168,7 @@ SceneOpenGL::SceneOpenGL( Workspace* ws )
|
|||
int dummy;
|
||||
if( !glXQueryExtension( display(), &dummy, &dummy ))
|
||||
return;
|
||||
// handle OpenGL extensions functions
|
||||
glXGetProcAddress = (glXGetProcAddress_func) getProcAddress( "glxGetProcAddress" );
|
||||
if( glXGetProcAddress == NULL )
|
||||
glXGetProcAddress = (glXGetProcAddress_func) getProcAddress( "glxGetProcAddressARB" );
|
||||
|
@ -125,7 +178,7 @@ SceneOpenGL::SceneOpenGL( Workspace* ws )
|
|||
// use copy buffer hack from glcompmgr (called COPY_BUFFER there) - nvidia drivers older than
|
||||
// 1.0-9xxx don't update pixmaps properly, so do a copy first
|
||||
copy_buffer_hack = !tfp_mode; // TODO detect that it's nvidia < 1.0-9xxx driver
|
||||
initBuffer();
|
||||
initBuffer(); // create destination buffer
|
||||
if( tfp_mode )
|
||||
{
|
||||
if( !findConfig( drawable_tfp_attrs, fbcdrawable ))
|
||||
|
@ -140,6 +193,7 @@ SceneOpenGL::SceneOpenGL( Workspace* ws )
|
|||
assert( false );
|
||||
context = glXCreateNewContext( display(), fbcroot, GLX_RGBA_TYPE, NULL, GL_FALSE );
|
||||
glXMakeContextCurrent( display(), glxroot, glxroot, context );
|
||||
// OpenGL scene setup
|
||||
glMatrixMode( GL_PROJECTION );
|
||||
glLoadIdentity();
|
||||
glOrtho( 0, displayWidth(), 0, displayHeight(), 0, 65535 );
|
||||
|
@ -167,6 +221,7 @@ SceneOpenGL::~SceneOpenGL()
|
|||
checkGLError( "Cleanup" );
|
||||
}
|
||||
|
||||
// create destination buffer
|
||||
void SceneOpenGL::initBuffer()
|
||||
{
|
||||
XWindowAttributes attrs;
|
||||
|
@ -182,12 +237,14 @@ void SceneOpenGL::initBuffer()
|
|||
}
|
||||
if( root_db )
|
||||
{
|
||||
// root window is double-buffered, paint directly to it
|
||||
buffer = rootWindow();
|
||||
glxroot = glXCreateWindow( display(), fbcroot, buffer, NULL );
|
||||
glDrawBuffer( GL_BACK );
|
||||
}
|
||||
else
|
||||
{
|
||||
// no double-buffered root, paint to a buffer and copy to root window
|
||||
XGCValues gcattr;
|
||||
gcattr.subwindow_mode = IncludeInferiors;
|
||||
gcroot = XCreateGC( display(), rootWindow(), GCSubwindowMode, &gcattr );
|
||||
|
@ -197,6 +254,7 @@ void SceneOpenGL::initBuffer()
|
|||
}
|
||||
}
|
||||
|
||||
// print info about found configs
|
||||
static void debugFBConfig( GLXFBConfig* fbconfigs, int i, const int* attrs )
|
||||
{
|
||||
int pos = 0;
|
||||
|
@ -214,6 +272,7 @@ static void debugFBConfig( GLXFBConfig* fbconfigs, int i, const int* attrs )
|
|||
}
|
||||
}
|
||||
|
||||
// find config matching the given attributes and possibly the given X visual
|
||||
bool SceneOpenGL::findConfig( const int* attrs, GLXFBConfig& config, VisualID visual )
|
||||
{
|
||||
int cnt;
|
||||
|
@ -263,6 +322,7 @@ bool SceneOpenGL::findConfig( const int* attrs, GLXFBConfig& config, VisualID vi
|
|||
return false;
|
||||
}
|
||||
|
||||
// the entry function for painting
|
||||
void SceneOpenGL::paint( QRegion damage, ToplevelList toplevels )
|
||||
{
|
||||
foreach( Toplevel* c, toplevels )
|
||||
|
@ -275,10 +335,13 @@ void SceneOpenGL::paint( QRegion damage, ToplevelList toplevels )
|
|||
glPushMatrix();
|
||||
glClearColor( 0, 0, 0, 1 );
|
||||
glClear( GL_COLOR_BUFFER_BIT );
|
||||
// OpenGL has (0,0) in the bottom-left corner while X has it in the top-left corner,
|
||||
// which is annoying and confusing. Therefore flip the whole OpenGL scene upside down
|
||||
// and move it up, so that it actually uses the same coordinate system like X.
|
||||
glScalef( 1, -1, 1 );
|
||||
glTranslatef( 0, -displayHeight(), 0 );
|
||||
int mask = 0;
|
||||
paintScreen( &mask, &damage );
|
||||
paintScreen( &mask, &damage ); // call generic implementation
|
||||
glPopMatrix();
|
||||
// TODO only partial repaint for mask & PAINT_SCREEN_REGION
|
||||
if( root_db )
|
||||
|
@ -296,7 +359,7 @@ void SceneOpenGL::paint( QRegion damage, ToplevelList toplevels )
|
|||
void SceneOpenGL::paintGenericScreen( int mask, ScreenPaintData data )
|
||||
{
|
||||
if( mask & PAINT_SCREEN_TRANSFORMED )
|
||||
{
|
||||
{ // apply screen transformations
|
||||
glPushMatrix();
|
||||
glTranslatef( data.xTranslate, data.yTranslate, 0 );
|
||||
}
|
||||
|
@ -309,6 +372,7 @@ void SceneOpenGL::paintGenericScreen( int mask, ScreenPaintData data )
|
|||
void SceneOpenGL::paintSimpleScreen( int mask, QRegion region )
|
||||
{
|
||||
// TODO repaint only damaged areas (means also don't do glXSwapBuffers and similar)
|
||||
// For now always force redrawing of the whole area.
|
||||
region = QRegion( 0, 0, displayWidth(), displayHeight());
|
||||
Scene::paintSimpleScreen( mask, region );
|
||||
}
|
||||
|
@ -376,16 +440,17 @@ void SceneOpenGL::Window::free()
|
|||
discardTexture();
|
||||
}
|
||||
|
||||
// Bind the window pixmap to an OpenGL texture.
|
||||
void SceneOpenGL::Window::bindTexture()
|
||||
{
|
||||
if( texture != 0 && toplevel->damage().isEmpty()
|
||||
&& !tfp_mode ) // interestingly this makes tfp slower
|
||||
&& !tfp_mode ) // TODO interestingly this makes tfp slower with some gfx cards
|
||||
{
|
||||
// texture doesn't need updating, just bind it
|
||||
glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texture );
|
||||
return;
|
||||
}
|
||||
// TODO cache pixmaps here if possible
|
||||
// Get the pixmap with the window contents
|
||||
Pixmap window_pix = toplevel->createWindowPixmap();
|
||||
Pixmap pix = window_pix;
|
||||
// HACK
|
||||
|
@ -425,11 +490,11 @@ void SceneOpenGL::Window::bindTexture()
|
|||
glXWaitX();
|
||||
}
|
||||
if( tfp_mode )
|
||||
{
|
||||
{ // tfp mode, simply bind the pixmap to texture
|
||||
if( texture == None )
|
||||
glGenTextures( 1, &texture );
|
||||
if( bound_pixmap != None )
|
||||
{
|
||||
{ // release old if needed
|
||||
glXReleaseTexImageEXT( display(), bound_glxpixmap, GLX_FRONT_LEFT_EXT );
|
||||
glXDestroyGLXPixmap( display(), bound_glxpixmap );
|
||||
XFreePixmap( display(), bound_pixmap );
|
||||
|
@ -448,7 +513,7 @@ void SceneOpenGL::Window::bindTexture()
|
|||
glXBindTexImageEXT( display(), bound_glxpixmap, GLX_FRONT_LEFT_EXT, NULL );
|
||||
}
|
||||
else
|
||||
{
|
||||
{ // non-tfp case, copy pixmap contents to a texture
|
||||
GLXDrawable pixmap = glXCreatePixmap( display(), fbcdrawable, pix, NULL );
|
||||
glXMakeContextCurrent( display(), pixmap, pixmap, context );
|
||||
glReadBuffer( GL_FRONT );
|
||||
|
@ -509,6 +574,8 @@ void SceneOpenGL::Window::discardTexture()
|
|||
texture = 0;
|
||||
}
|
||||
|
||||
// paint a quad (rectangle), ty1/ty2 are texture coordinates (for handling
|
||||
// swapped y coordinate, see below)
|
||||
static void quadPaint( int x1, int y1, int x2, int y2, int ty1, int ty2 )
|
||||
{
|
||||
glTexCoord2i( x1, ty1 );
|
||||
|
@ -521,8 +588,11 @@ static void quadPaint( int x1, int y1, int x2, int y2, int ty1, int ty2 )
|
|||
glVertex2i( x1, y2 );
|
||||
}
|
||||
|
||||
// paint the window
|
||||
void SceneOpenGL::Window::performPaint( int mask, QRegion region, WindowPaintData data )
|
||||
{
|
||||
// check if there is something to paint (e.g. don't paint if the window
|
||||
// is only opaque and only PAINT_WINDOW_TRANSLUCENT is requested)
|
||||
bool opaque = isOpaque() && data.opacity == 1.0;
|
||||
if( mask & ( PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSLUCENT ))
|
||||
{}
|
||||
|
@ -544,6 +614,7 @@ void SceneOpenGL::Window::performPaint( int mask, QRegion region, WindowPaintDat
|
|||
return;
|
||||
bindTexture();
|
||||
glPushMatrix();
|
||||
// do required transformations
|
||||
int x = toplevel->x();
|
||||
int y = toplevel->y();
|
||||
if( mask & PAINT_WINDOW_TRANSFORMED )
|
||||
|
@ -554,6 +625,7 @@ void SceneOpenGL::Window::performPaint( int mask, QRegion region, WindowPaintDat
|
|||
glTranslatef( x, y, 0 );
|
||||
if(( mask & PAINT_WINDOW_TRANSFORMED ) && ( data.xScale != 1 || data.yScale != 1 ))
|
||||
glScalef( data.xScale, data.yScale, 1 );
|
||||
// setup blending of transparent windows
|
||||
bool was_blend = glIsEnabled( GL_BLEND );
|
||||
if( !opaque )
|
||||
{
|
||||
|
@ -562,6 +634,8 @@ void SceneOpenGL::Window::performPaint( int mask, QRegion region, WindowPaintDat
|
|||
}
|
||||
if( data.opacity != 1.0 )
|
||||
{
|
||||
// the window is additionally configured to have its opacity adjusted,
|
||||
// do it
|
||||
if( toplevel->hasAlpha())
|
||||
{
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
|
||||
|
@ -580,6 +654,7 @@ void SceneOpenGL::Window::performPaint( int mask, QRegion region, WindowPaintDat
|
|||
}
|
||||
}
|
||||
glEnable( GL_TEXTURE_RECTANGLE_ARB );
|
||||
// actually paint the window
|
||||
glBegin( GL_QUADS );
|
||||
foreach( QRect r, region.rects())
|
||||
{
|
||||
|
@ -587,6 +662,8 @@ void SceneOpenGL::Window::performPaint( int mask, QRegion region, WindowPaintDat
|
|||
int y2 = r.y() + r.height();
|
||||
int ty1 = y1;
|
||||
int ty2 = y2;
|
||||
// tfp can result in the texture having y coordinate inverted (because
|
||||
// of the internal format), so do the inversion if needed
|
||||
if( !texture_y_inverted ) // "!" because of converting to OpenGL coords
|
||||
{
|
||||
ty1 = height() - y1;
|
||||
|
|
|
@ -64,9 +64,9 @@ class SceneOpenGL::Window
|
|||
Window() {} // QMap sucks even in Qt4
|
||||
private:
|
||||
Texture texture;
|
||||
bool texture_y_inverted;
|
||||
Pixmap bound_pixmap;
|
||||
GLXPixmap bound_glxpixmap; // only for tfp_mode
|
||||
bool texture_y_inverted; // texture has y inverted
|
||||
Pixmap bound_pixmap; // the pixmap the texture is bound to, only for tfp_mode
|
||||
GLXPixmap bound_glxpixmap; // the glx pixmap the texture is bound to, only for tfp_mode
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -8,6 +8,27 @@ You can Freely distribute this program under the GNU General Public
|
|||
License. See the file "COPYING" for the exact licensing terms.
|
||||
******************************************************************/
|
||||
|
||||
/*
|
||||
This is the XRender-based compositing code. The primary compositing
|
||||
backend is the OpenGL-based one, which should be more powerful
|
||||
and also possibly better documented. This backend is mostly for cases
|
||||
when the OpenGL backend cannot be used for some reason (insufficient
|
||||
performance, no usable OpenGL support at all, etc.)
|
||||
The plan is to keep it around as long as needed/possible, but if it
|
||||
proves to be too much hassle it will be dropped in the future.
|
||||
|
||||
Docs:
|
||||
|
||||
XRender (the protocol, but the function calls map to it):
|
||||
http://webcvs.freedesktop.org/xlibs/Render/protocol
|
||||
(I couldn't find it in the freedesktop git repository, so this one
|
||||
is a bit older, but it shouldn't matter.)
|
||||
|
||||
XFixes (again, the protocol):
|
||||
http://gitweb.freedesktop.org/?p=xorg/proto/fixesproto.git;a=blob;hb=HEAD;f=protocol
|
||||
|
||||
*/
|
||||
|
||||
#include "scene_xrender.h"
|
||||
|
||||
#ifdef HAVE_XRENDER
|
||||
|
@ -23,12 +44,13 @@ namespace KWinInternal
|
|||
// SceneXrender
|
||||
//****************************************
|
||||
|
||||
// kDebug() support for the XserverRegion type
|
||||
struct RegionDebug
|
||||
{
|
||||
RegionDebug( XserverRegion r ) : rr( r ) {}
|
||||
XserverRegion rr;
|
||||
};
|
||||
|
||||
|
||||
#ifdef NDEBUG
|
||||
inline
|
||||
kndbgstream& operator<<( kndbgstream& stream, RegionDebug ) { return stream; }
|
||||
|
@ -55,15 +77,11 @@ ScreenPaintData SceneXrender::screen_paint;
|
|||
SceneXrender::SceneXrender( Workspace* ws )
|
||||
: Scene( ws )
|
||||
{
|
||||
// create XRender picture for the root window
|
||||
format = XRenderFindVisualFormat( display(), DefaultVisual( display(), DefaultScreen( display())));
|
||||
XRenderPictureAttributes pa;
|
||||
pa.subwindow_mode = IncludeInferiors;
|
||||
front = XRenderCreatePicture( display(), rootWindow(), format, CPSubwindowMode, &pa );
|
||||
XRectangle xr;
|
||||
xr.x = SHRT_MIN / 2;
|
||||
xr.y = SHRT_MIN / 2;
|
||||
xr.width = SHRT_MAX;
|
||||
xr.height = SHRT_MAX;
|
||||
createBuffer();
|
||||
}
|
||||
|
||||
|
@ -77,6 +95,7 @@ SceneXrender::~SceneXrender()
|
|||
(*it).free();
|
||||
}
|
||||
|
||||
// the entry point for painting
|
||||
void SceneXrender::paint( QRegion damage, ToplevelList toplevels )
|
||||
{
|
||||
foreach( Toplevel* c, toplevels )
|
||||
|
@ -112,6 +131,7 @@ void SceneXrender::paintGenericScreen( int mask, ScreenPaintData data )
|
|||
Scene::paintGenericScreen( mask, data );
|
||||
}
|
||||
|
||||
// fill the screen background
|
||||
void SceneXrender::paintBackground( QRegion region )
|
||||
{
|
||||
if( region != infiniteRegion())
|
||||
|
@ -156,8 +176,8 @@ void SceneXrender::windowAdded( Toplevel* c )
|
|||
windows[ c ] = Window( c );
|
||||
}
|
||||
|
||||
// TODO handle xrandr changes
|
||||
|
||||
// Create the compositing buffer. The root window is not double-buffered,
|
||||
// so it is done manually using this buffer,
|
||||
void SceneXrender::createBuffer()
|
||||
{
|
||||
if( buffer != None )
|
||||
|
@ -167,6 +187,9 @@ void SceneXrender::createBuffer()
|
|||
XFreePixmap( display(), pixmap ); // The picture owns the pixmap now
|
||||
}
|
||||
|
||||
// Convert QRegion to XserverRegion. This code uses XserverRegion
|
||||
// only when really necessary as the shared implementation uses
|
||||
// QRegion.
|
||||
XserverRegion SceneXrender::toXserverRegion( QRegion region )
|
||||
{
|
||||
QVector< QRect > rects = region.rects();
|
||||
|
@ -204,6 +227,7 @@ void SceneXrender::Window::free()
|
|||
discardShape();
|
||||
}
|
||||
|
||||
// Create XRender picture for the pixmap with the window contents.
|
||||
Picture SceneXrender::Window::picture()
|
||||
{
|
||||
if( !toplevel->damage().isEmpty() && _picture != None )
|
||||
|
@ -213,9 +237,10 @@ Picture SceneXrender::Window::picture()
|
|||
}
|
||||
if( _picture == None && format != NULL )
|
||||
{
|
||||
// Get the pixmap with the window contents.
|
||||
Pixmap window_pix = toplevel->createWindowPixmap();
|
||||
Pixmap pix = window_pix;
|
||||
// HACK the same like with opengl
|
||||
// HACK the same alpha clear hack like with opengl, see there
|
||||
Client* c = dynamic_cast< Client* >( toplevel );
|
||||
bool alpha_clear = c != NULL && c->hasAlpha() && !c->noBorder();
|
||||
#define ALPHA_CLEAR_COPY
|
||||
|
@ -268,6 +293,7 @@ void SceneXrender::Window::discardAlpha()
|
|||
alpha = None;
|
||||
}
|
||||
|
||||
// Create XRender picture for the alpha mask.
|
||||
Picture SceneXrender::Window::alphaMask( double opacity )
|
||||
{
|
||||
if( isOpaque() && opacity == 1.0 )
|
||||
|
@ -285,6 +311,7 @@ Picture SceneXrender::Window::alphaMask( double opacity )
|
|||
alpha_cached_opacity = 1.0;
|
||||
return None;
|
||||
}
|
||||
// Create a 1x1 8bpp pixmap containing the given opacity in the alpha channel.
|
||||
Pixmap pixmap = XCreatePixmap( display(), rootWindow(), 1, 1, 8 );
|
||||
XRenderPictFormat* format = XRenderFindStandardFormat( display(), PictStandardA8 );
|
||||
XRenderPictureAttributes pa;
|
||||
|
@ -298,8 +325,10 @@ Picture SceneXrender::Window::alphaMask( double opacity )
|
|||
return alpha;
|
||||
}
|
||||
|
||||
// paint the window
|
||||
void SceneXrender::Window::performPaint( int mask, QRegion region, WindowPaintData data )
|
||||
{
|
||||
// check if there is something to paint
|
||||
bool opaque = isOpaque() && data.opacity == 1.0;
|
||||
if( mask & ( PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSLUCENT ))
|
||||
{}
|
||||
|
@ -319,9 +348,10 @@ void SceneXrender::Window::performPaint( int mask, QRegion region, WindowPaintDa
|
|||
XFixesSetPictureClipRegion( display(), buffer, 0, 0, clip_region );
|
||||
XFixesDestroyRegion( display(), clip_region );
|
||||
}
|
||||
Picture pic = picture();
|
||||
Picture pic = picture(); // get XRender picture
|
||||
if( pic == None ) // The render format can be null for GL and/or Xv visuals
|
||||
return;
|
||||
// do required transformations
|
||||
int x = toplevel->x();
|
||||
int y = toplevel->y();
|
||||
if( mask & PAINT_SCREEN_TRANSFORMED )
|
||||
|
|
|
@ -42,6 +42,9 @@ License. See the file "COPYING" for the exact licensing terms.
|
|||
#include "group.h"
|
||||
#include "rules.h"
|
||||
#include "kwinadaptor.h"
|
||||
#include "unmanaged.h"
|
||||
#include "scene.h"
|
||||
#include "effects.h"
|
||||
|
||||
#include <X11/extensions/shape.h>
|
||||
#include <X11/keysym.h>
|
||||
|
@ -122,7 +125,8 @@ Workspace::Workspace( bool restore )
|
|||
topmenu_space( NULL ),
|
||||
set_active_client_recursion( 0 ),
|
||||
block_stacking_updates( 0 ),
|
||||
forced_global_mouse_grab( false )
|
||||
forced_global_mouse_grab( false ),
|
||||
damage_region( None )
|
||||
{
|
||||
new KWinAdaptor( "org.kde.kwin", "/KWin", QDBusConnection::sessionBus(), this );
|
||||
|
||||
|
@ -166,10 +170,12 @@ Workspace::Workspace( bool restore )
|
|||
ColormapChangeMask |
|
||||
SubstructureRedirectMask |
|
||||
SubstructureNotifyMask |
|
||||
FocusChangeMask // for NotifyDetailNone
|
||||
FocusChangeMask | // for NotifyDetailNone
|
||||
ExposureMask
|
||||
);
|
||||
|
||||
Shape::init();
|
||||
Extensions::init();
|
||||
setupCompositing();
|
||||
|
||||
// compatibility
|
||||
long data = 1;
|
||||
|
@ -318,6 +324,7 @@ void Workspace::init()
|
|||
connect(&reconfigureTimer, SIGNAL(timeout()), this,
|
||||
SLOT(slotReconfigure()));
|
||||
connect( &updateToolWindowsTimer, SIGNAL( timeout()), this, SLOT( slotUpdateToolWindows()));
|
||||
connect( &compositeTimer, SIGNAL( timeout()), SLOT( performCompositing()));
|
||||
|
||||
connect(KGlobalSettings::self(), SIGNAL(appearanceChanged()), this,
|
||||
SLOT(slotReconfigure()));
|
||||
|
@ -355,7 +362,11 @@ void Workspace::init()
|
|||
XWindowAttributes attr;
|
||||
XGetWindowAttributes(display(), wins[i], &attr);
|
||||
if (attr.override_redirect )
|
||||
{
|
||||
if( attr.map_state != IsUnmapped && attr.c_class != InputOnly && compositing())
|
||||
createUnmanaged( wins[ i ] );
|
||||
continue;
|
||||
}
|
||||
if( topmenu_space && topmenu_space->winId() == wins[ i ] )
|
||||
continue;
|
||||
if (attr.map_state != IsUnmapped)
|
||||
|
@ -418,6 +429,7 @@ void Workspace::init()
|
|||
|
||||
Workspace::~Workspace()
|
||||
{
|
||||
finishCompositing();
|
||||
blockStackingUpdates( true );
|
||||
// TODO grabXServer();
|
||||
// use stacking_order, so that kwin --replace keeps stacking order
|
||||
|
@ -429,6 +441,10 @@ Workspace::~Workspace()
|
|||
(*it)->releaseWindow( true );
|
||||
// no removeClient() is called !
|
||||
}
|
||||
for( UnmanagedList::ConstIterator it = unmanaged.begin();
|
||||
it != unmanaged.end();
|
||||
++it )
|
||||
(*it)->release();
|
||||
delete desktop_widget;
|
||||
delete tab_box;
|
||||
delete popupinfo;
|
||||
|
@ -472,6 +488,26 @@ Client* Workspace::createClient( Window w, bool is_mapped )
|
|||
return NULL;
|
||||
}
|
||||
addClient( c, Allowed );
|
||||
if( scene )
|
||||
scene->windowAdded( c );
|
||||
if( effects )
|
||||
effects->windowAdded( c );
|
||||
return c;
|
||||
}
|
||||
|
||||
Unmanaged* Workspace::createUnmanaged( Window w )
|
||||
{
|
||||
Unmanaged* c = new Unmanaged( this );
|
||||
if( !c->track( w ))
|
||||
{
|
||||
Unmanaged::deleteUnmanaged( c, Allowed );
|
||||
return NULL;
|
||||
}
|
||||
addUnmanaged( c, Allowed );
|
||||
if( scene )
|
||||
scene->windowAdded( c );
|
||||
if( effects )
|
||||
effects->windowAdded( c );
|
||||
return c;
|
||||
}
|
||||
|
||||
|
@ -514,6 +550,11 @@ void Workspace::addClient( Client* c, allowed_t )
|
|||
updateToolWindows( true );
|
||||
}
|
||||
|
||||
void Workspace::addUnmanaged( Unmanaged* c, allowed_t )
|
||||
{
|
||||
unmanaged.append( c );
|
||||
}
|
||||
|
||||
/*
|
||||
Destroys the client \a c
|
||||
*/
|
||||
|
@ -533,6 +574,10 @@ void Workspace::removeClient( Client* c, allowed_t )
|
|||
Notify::raise( Notify::Delete );
|
||||
|
||||
Q_ASSERT( clients.contains( c ) || desktops.contains( c ));
|
||||
if( scene )
|
||||
scene->windowDeleted( c );
|
||||
if( effects )
|
||||
effects->windowDeleted( c );
|
||||
clients.removeAll( c );
|
||||
desktops.removeAll( c );
|
||||
unconstrained_stacking_order.removeAll( c );
|
||||
|
@ -568,6 +613,16 @@ void Workspace::removeClient( Client* c, allowed_t )
|
|||
updateClientArea();
|
||||
}
|
||||
|
||||
void Workspace::removeUnmanaged( Unmanaged* c, allowed_t )
|
||||
{
|
||||
assert( unmanaged.contains( c ));
|
||||
if( scene )
|
||||
scene->windowDeleted( c );
|
||||
if( effects )
|
||||
effects->windowDeleted( c );
|
||||
unmanaged.removeAll( c );
|
||||
}
|
||||
|
||||
void Workspace::updateFocusChains( Client* c, FocusChainChange change )
|
||||
{
|
||||
if( !c->wantsTabFocus()) // doesn't want tab focus, remove
|
||||
|
@ -864,7 +919,7 @@ void Workspace::slotSettingsChanged(int category)
|
|||
/*!
|
||||
Reread settings
|
||||
*/
|
||||
KWIN_PROCEDURE( CheckBorderSizesProcedure, cl->checkBorderSizes() );
|
||||
KWIN_PROCEDURE( CheckBorderSizesProcedure, Client, cl->checkBorderSizes() );
|
||||
|
||||
void Workspace::slotReconfigure()
|
||||
{
|
||||
|
@ -921,6 +976,11 @@ void Workspace::slotReconfigure()
|
|||
updateTopMenuGeometry();
|
||||
updateCurrentTopMenu();
|
||||
}
|
||||
|
||||
if( options->useTranslucency )
|
||||
setupCompositing();
|
||||
else
|
||||
finishCompositing();
|
||||
|
||||
loadWindowRules();
|
||||
for( ClientList::Iterator it = clients.begin();
|
||||
|
@ -1622,7 +1682,7 @@ void Workspace::slotGrabWindow()
|
|||
QPixmap snapshot = QPixmap::grabWindow( active_client->frameId() );
|
||||
|
||||
//No XShape - no work.
|
||||
if( Shape::available())
|
||||
if( Extensions::shapeAvailable())
|
||||
{
|
||||
//As the first step, get the mask from XShape.
|
||||
int count, order;
|
||||
|
@ -2335,7 +2395,7 @@ void Workspace::helperDialog( const QString& message, const Client* c )
|
|||
{
|
||||
KAction* action = keys->action( "Window Operations Menu" );
|
||||
QString shortcut = QString( "%1 (%2)" ).arg( action->text() )
|
||||
.arg( action->globalShortcut().seq( 0 ).toString());
|
||||
.arg( action->shortcut().seq( 0 ).toString());
|
||||
args << "--msgbox" <<
|
||||
i18n( "You have selected to show a window without its border.\n"
|
||||
"Without the border, you will not be able to enable the border "
|
||||
|
@ -2348,7 +2408,7 @@ void Workspace::helperDialog( const QString& message, const Client* c )
|
|||
{
|
||||
KAction* action = keys->action( "Window Operations Menu" );
|
||||
QString shortcut = QString( "%1 (%2)" ).arg( action->text() )
|
||||
.arg( action->globalShortcut().seq( 0 ).toString());
|
||||
.arg( action->shortcut().seq( 0 ).toString());
|
||||
args << "--msgbox" <<
|
||||
i18n( "You have selected to show a window in fullscreen mode.\n"
|
||||
"If the application itself does not have an option to turn the fullscreen "
|
||||
|
|
|
@ -420,7 +420,7 @@ class Workspace : public QObject, public KDecorationDefines
|
|||
void setPopupClientOpacity(int v);
|
||||
void resetClientOpacity();
|
||||
void setTransButtonText(int value);
|
||||
void compositeTimeout();
|
||||
void performCompositing();
|
||||
|
||||
protected:
|
||||
bool keyPressMouseEmulation( XKeyEvent& ev );
|
||||
|
|
Loading…
Reference in a new issue