Move window_pix into Toplevel, allowing the backing pixmap to be kept even after a window is unmapped.

This is needed for effects to make use of unavailable windows, such as when closing a window.

svn path=/branches/work/kwin_composite/; revision=622777
This commit is contained in:
Philip Falkner 2007-01-12 23:21:36 +00:00
parent 33f8a0758c
commit e3cf0dd455
8 changed files with 132 additions and 175 deletions

View file

@ -28,6 +28,7 @@ License. See the file "COPYING" for the exact licensing terms.
#include "atoms.h" #include "atoms.h"
#include "notifications.h" #include "notifications.h"
#include "rules.h" #include "rules.h"
#include "scene.h"
#include <X11/extensions/shape.h> #include <X11/extensions/shape.h>
#include <QX11Info> #include <QX11Info>
@ -63,12 +64,10 @@ namespace KWinInternal
is done in manage(). is done in manage().
*/ */
Client::Client( Workspace *ws ) Client::Client( Workspace *ws )
: QObject( NULL ), : Toplevel( ws ),
client( None ), client( None ),
wrapper( None ), wrapper( None ),
frame( None ),
decoration( NULL ), decoration( NULL ),
wspace( ws ),
bridge( new Bridge( this )), bridge( new Bridge( this )),
move_faked_activity( false ), move_faked_activity( false ),
move_resize_grab_window( None ), move_resize_grab_window( None ),
@ -82,7 +81,7 @@ Client::Client( Workspace *ws )
process_killer( NULL ), process_killer( NULL ),
user_time( CurrentTime ), // not known yet user_time( CurrentTime ), // not known yet
allowed_actions( 0 ), allowed_actions( 0 ),
postpone_geometry_updates( 0 ), block_geometry_updates( 0 ),
pending_geometry_update( false ), pending_geometry_update( false ),
shade_geometry_change( false ), shade_geometry_change( false ),
border_left( 0 ), border_left( 0 ),
@ -111,7 +110,6 @@ Client::Client( Workspace *ws )
deleting = false; deleting = false;
keep_above = false; keep_above = false;
keep_below = false; keep_below = false;
is_shape = false;
motif_noborder = false; motif_noborder = false;
motif_may_move = true; motif_may_move = true;
motif_may_resize = true; motif_may_resize = true;
@ -124,6 +122,7 @@ Client::Client( Workspace *ws )
modal = false; modal = false;
noborder = false; noborder = false;
user_noborder = false; user_noborder = false;
not_obscured = false;
urgency = false; urgency = false;
ignore_focus_stealing = false; ignore_focus_stealing = false;
demands_attention = false; demands_attention = false;
@ -142,7 +141,7 @@ Client::Client( Workspace *ws )
cmap = None; cmap = None;
frame_geometry = QRect( 0, 0, 100, 100 ); // so that decorations don't start with size being (0,0) geom = QRect( 0, 0, 100, 100 ); // so that decorations don't start with size being (0,0)
client_size = QSize( 100, 100 ); client_size = QSize( 100, 100 );
// SELI initialize xsizehints?? // SELI initialize xsizehints??
@ -155,9 +154,10 @@ Client::~Client()
{ {
assert(!moveResizeMode); assert(!moveResizeMode);
assert( client == None ); assert( client == None );
assert( frame == None && wrapper == None ); assert( wrapper == None );
// assert( frameId() == None );
assert( decoration == NULL ); assert( decoration == NULL );
assert( postpone_geometry_updates == 0 ); assert( block_geometry_updates == 0 );
assert( !check_active_modal ); assert( !check_active_modal );
delete info; delete info;
delete bridge; delete bridge;
@ -176,15 +176,15 @@ void Client::releaseWindow( bool on_shutdown )
{ {
assert( !deleting ); assert( !deleting );
deleting = true; deleting = true;
finishCompositing();
workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules
StackingUpdatesBlocker blocker( workspace()); StackingUpdatesBlocker blocker( workspace());
if (moveResizeMode) if (moveResizeMode)
leaveMoveResize(); leaveMoveResize();
finishWindowRules(); finishWindowRules();
++postpone_geometry_updates; ++block_geometry_updates;
// grab X during the release to make removing of properties, setting to withdrawn state if( isNormalState()) // is mapped?
// and repareting to root an atomic operation (http://lists.kde.org/?l=kde-devel&m=116448102901184&w=2) workspace()->addDamage( geometry());
grabXServer();
setMappingState( WithdrawnState ); setMappingState( WithdrawnState );
setModal( false ); // otherwise its mainwindow wouldn't get focus setModal( false ); // otherwise its mainwindow wouldn't get focus
hidden = true; // so that it's not considered visible anymore (can't use hideClient(), it would set flags) hidden = true; // so that it's not considered visible anymore (can't use hideClient(), it would set flags)
@ -222,12 +222,10 @@ void Client::releaseWindow( bool on_shutdown )
client = None; client = None;
XDestroyWindow( display(), wrapper ); XDestroyWindow( display(), wrapper );
wrapper = None; wrapper = None;
XDestroyWindow( display(), frame ); XDestroyWindow( display(), frameId());
frame = None; // frame = None;
--postpone_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry --block_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry
checkNonExistentClients();
deleteClient( this, Allowed ); deleteClient( this, Allowed );
ungrabXServer();
} }
// like releaseWindow(), but this one is called when the window has been already destroyed // like releaseWindow(), but this one is called when the window has been already destroyed
@ -236,12 +234,15 @@ void Client::destroyClient()
{ {
assert( !deleting ); assert( !deleting );
deleting = true; deleting = true;
finishCompositing();
workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules
StackingUpdatesBlocker blocker( workspace()); StackingUpdatesBlocker blocker( workspace());
if (moveResizeMode) if (moveResizeMode)
leaveMoveResize(); leaveMoveResize();
finishWindowRules(); finishWindowRules();
++postpone_geometry_updates; ++block_geometry_updates;
if( isNormalState()) // is mapped?
workspace()->addDamage( geometry());
setModal( false ); setModal( false );
hidden = true; // so that it's not considered visible anymore hidden = true; // so that it's not considered visible anymore
workspace()->clientHidden( this ); workspace()->clientHidden( this );
@ -251,10 +252,9 @@ void Client::destroyClient()
client = None; // invalidate client = None; // invalidate
XDestroyWindow( display(), wrapper ); XDestroyWindow( display(), wrapper );
wrapper = None; wrapper = None;
XDestroyWindow( display(), frame ); XDestroyWindow( display(), frameId());
frame = None; // frame = None;
--postpone_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry --block_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry
checkNonExistentClients();
deleteClient( this, Allowed ); deleteClient( this, Allowed );
} }
@ -264,12 +264,11 @@ void Client::updateDecoration( bool check_workspace_pos, bool force )
|| ( decoration != NULL && !noBorder()))) || ( decoration != NULL && !noBorder())))
return; return;
bool do_show = false; bool do_show = false;
postponeGeometryUpdates( true ); blockGeometryUpdates( true );
if( force ) if( force )
destroyDecoration(); destroyDecoration();
if( !noBorder()) if( !noBorder())
{ {
setMask( QRegion()); // reset shape mask
decoration = workspace()->createDecoration( bridge ); decoration = workspace()->createDecoration( bridge );
// TODO check decoration's minimum size? // TODO check decoration's minimum size?
decoration->init(); decoration->init();
@ -284,15 +283,20 @@ void Client::updateDecoration( bool check_workspace_pos, bool force )
workarea_diff_x = save_workarea_diff_x; workarea_diff_x = save_workarea_diff_x;
workarea_diff_y = save_workarea_diff_y; workarea_diff_y = save_workarea_diff_y;
do_show = true; do_show = true;
if( compositing() )
discardWindowPixmap();
if( scene != NULL )
scene->windowGeometryShapeChanged( this );
} }
else else
destroyDecoration(); destroyDecoration();
if( check_workspace_pos ) if( check_workspace_pos )
checkWorkspacePosition(); checkWorkspacePosition();
postponeGeometryUpdates( false ); blockGeometryUpdates( false );
if( do_show ) if( do_show )
decoration->widget()->show(); decoration->widget()->show();
updateFrameExtents(); updateFrameExtents();
addDamageFull();
} }
void Client::destroyDecoration() void Client::destroyDecoration()
@ -310,6 +314,11 @@ void Client::destroyDecoration()
move( grav ); move( grav );
workarea_diff_x = save_workarea_diff_x; workarea_diff_x = save_workarea_diff_x;
workarea_diff_y = save_workarea_diff_y; workarea_diff_y = save_workarea_diff_y;
if( compositing() )
discardWindowPixmap();
if( scene != NULL )
scene->windowGeometryShapeChanged( this );
addDamageFull();
} }
} }
@ -322,7 +331,7 @@ void Client::checkBorderSizes()
if( new_left == border_left && new_right == border_right if( new_left == border_left && new_right == border_right
&& new_top == border_top && new_bottom == border_bottom ) && new_top == border_top && new_bottom == border_bottom )
return; return;
GeometryUpdatesPostponer blocker( this ); GeometryUpdatesBlocker blocker( this );
move( calculateGravitation( true )); move( calculateGravitation( true ));
border_left = new_left; border_left = new_left;
border_right = new_right; border_right = new_right;
@ -339,7 +348,7 @@ void Client::checkBorderSizes()
void Client::detectNoBorder() void Client::detectNoBorder()
{ {
if( Shape::hasShape( window())) if( shape())
{ {
noborder = true; noborder = true;
return; return;
@ -427,47 +436,24 @@ void Client::setUserNoBorder( bool set )
void Client::updateShape() void Client::updateShape()
{ {
if ( shape() )
XShapeCombineShape(display(), frameId(), ShapeBounding,
clientPos().x(), clientPos().y(),
window(), ShapeBounding, ShapeSet);
else
XShapeCombineMask( display(), frameId(), ShapeBounding, 0, 0,
None, ShapeSet);
if( compositing() )
discardWindowPixmap();
if( scene != NULL )
scene->windowGeometryShapeChanged( this );
addDamageFull();
// workaround for #19644 - shaped windows shouldn't have decoration // workaround for #19644 - shaped windows shouldn't have decoration
if( shape() && !noBorder()) if( shape() && !noBorder())
{ {
noborder = true; noborder = true;
updateDecoration( true ); updateDecoration( true );
} }
if( shape())
{
XShapeCombineShape(display(), frameId(), ShapeBounding,
clientPos().x(), clientPos().y(),
window(), ShapeBounding, ShapeSet);
}
// !shape() mask setting is done in setMask() when the decoration
// calls it or when the decoration is created/destroyed
if( Shape::version() >= 0x11 ) // 1.1, has input shape support
{ // There appears to be no way to find out if a window has input
// shape set or not, so always propagate the input shape
// (it's the same like the bounding shape by default).
// Also, build the shape using a helper window, not directly
// in the frame window, because the sequence set-shape-to-frame,
// remove-shape-of-client, add-input-shape-of-client has the problem
// that after the second step there's a hole in the input shape
// until the real shape of the client is added and that can make
// the window lose focus (which is a problem with mouse focus policies)
static Window helper_window = None;
if( helper_window == None )
helper_window = XCreateSimpleWindow( display(), rootWindow(),
0, 0, 1, 1, 0, 0, 0 );
XResizeWindow( display(), helper_window, width(), height());
XShapeCombineShape( display(), helper_window, ShapeInput, 0, 0,
frameId(), ShapeBounding, ShapeSet );
XShapeCombineShape( display(), helper_window, ShapeInput,
clientPos().x(), clientPos().y(),
window(), ShapeBounding, ShapeSubtract );
XShapeCombineShape( display(), helper_window, ShapeInput,
clientPos().x(), clientPos().y(),
window(), ShapeInput, ShapeUnion );
XShapeCombineShape( display(), frameId(), ShapeInput, 0, 0,
helper_window, ShapeInput, ShapeSet );
}
} }
void Client::setMask( const QRegion& reg, int mode ) void Client::setMask( const QRegion& reg, int mode )
@ -496,7 +482,11 @@ void Client::setMask( const QRegion& reg, int mode )
xrects, rects.count(), ShapeSet, mode ); xrects, rects.count(), ShapeSet, mode );
delete[] xrects; delete[] xrects;
} }
updateShape(); if( compositing() )
discardWindowPixmap();
if( scene != NULL )
scene->windowGeometryShapeChanged( this );
addDamageFull();
} }
QRegion Client::mask() const QRegion Client::mask() const
@ -745,7 +735,7 @@ void Client::setShade( ShadeMode mode )
} }
assert( decoration != NULL ); // noborder windows can't be shaded assert( decoration != NULL ); // noborder windows can't be shaded
GeometryUpdatesPostponer blocker( this ); GeometryUpdatesBlocker blocker( this );
// decorations may turn off some borders when shaded // decorations may turn off some borders when shaded
decoration->borders( border_left, border_right, border_top, border_bottom ); decoration->borders( border_left, border_right, border_top, border_bottom );
@ -792,9 +782,13 @@ void Client::setShade( ShadeMode mode )
// tell xcompmgr shade's done // tell xcompmgr shade's done
_shade = 2; _shade = 2;
XChangeProperty(display(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L); XChangeProperty(display(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);
if( isNormalState()) // is mapped?
workspace()->addDamage( geometry());
} }
else else
{ {
if( isNormalState()) // is mapped?
workspace()->addDamage( geometry());
int h = height(); int h = height();
shade_geometry_change = true; shade_geometry_change = true;
QSize s( sizeForClientSize( clientSize())); QSize s( sizeForClientSize( clientSize()));
@ -929,8 +923,8 @@ void Client::setMappingState(int s)
XChangeProperty(display(), window(), atoms->wm_state, atoms->wm_state, 32, XChangeProperty(display(), window(), atoms->wm_state, atoms->wm_state, 32,
PropModeReplace, (unsigned char *)data, 2); PropModeReplace, (unsigned char *)data, 2);
if( was_unmanaged ) // manage() did postpone_geometry_updates = 1, now it's ok to finally set the geometry if( was_unmanaged ) // manage() did block_geometry_updates = 1, now it's ok to finally set the geometry
postponeGeometryUpdates( false ); blockGeometryUpdates( false );
} }
/*! /*!
@ -941,12 +935,17 @@ void Client::rawShow()
{ {
if( decoration != NULL ) if( decoration != NULL )
decoration->widget()->show(); // not really necessary, but let it know the state decoration->widget()->show(); // not really necessary, but let it know the state
XMapWindow( display(), frame ); XMapWindow( display(), frameId());
if( !isShade()) if( !isShade())
{ {
XMapWindow( display(), wrapper ); XMapWindow( display(), wrapper );
XMapWindow( display(), client ); XMapWindow( display(), client );
} }
// XComposite invalidates backing pixmaps on unmap (minimize, different
// virtual desktop, etc.). We kept the last known good pixmap around
// for use in effects, but now we want to have access to the new pixmap
if( compositing() )
discardWindowPixmap();
} }
/*! /*!
@ -956,6 +955,7 @@ void Client::rawShow()
*/ */
void Client::rawHide() void Client::rawHide()
{ {
workspace()->addDamage( geometry());
// Here it may look like a race condition, as some other client might try to unmap // Here it may look like a race condition, as some other client might try to unmap
// the window between these two XSelectInput() calls. However, they're supposed to // the window between these two XSelectInput() calls. However, they're supposed to
// use XWithdrawWindow(), which also sends a synthetic event to the root window, // use XWithdrawWindow(), which also sends a synthetic event to the root window,
@ -963,7 +963,7 @@ void Client::rawHide()
// will be missed is also very minimal, so I don't think it's needed to grab the server // will be missed is also very minimal, so I don't think it's needed to grab the server
// here. // here.
XSelectInput( display(), wrapper, ClientWinMask ); // avoid getting UnmapNotify XSelectInput( display(), wrapper, ClientWinMask ); // avoid getting UnmapNotify
XUnmapWindow( display(), frame ); XUnmapWindow( display(), frameId());
XUnmapWindow( display(), wrapper ); XUnmapWindow( display(), wrapper );
XUnmapWindow( display(), client ); XUnmapWindow( display(), client );
XSelectInput( display(), wrapper, ClientWinMask | SubstructureNotifyMask ); XSelectInput( display(), wrapper, ClientWinMask | SubstructureNotifyMask );
@ -1308,7 +1308,7 @@ QString Client::readName() const
return KWin::readNameProperty( window(), XA_WM_NAME ); return KWin::readNameProperty( window(), XA_WM_NAME );
} }
KWIN_COMPARE_PREDICATE( FetchNameInternalPredicate, const Client*, (!cl->isSpecialWindow() || cl->isToolbar()) && cl != value && cl->caption() == value->caption()); KWIN_COMPARE_PREDICATE( FetchNameInternalPredicate, Client, const Client*, (!cl->isSpecialWindow() || cl->isToolbar()) && cl != value && cl->caption() == value->caption());
void Client::setCaption( const QString& _s, bool force ) void Client::setCaption( const QString& _s, bool force )
{ {
@ -1625,58 +1625,6 @@ bool Client::wantsInput() const
return rules()->checkAcceptFocus( input || Ptakefocus ); return rules()->checkAcceptFocus( input || Ptakefocus );
} }
bool Client::isDesktop() const
{
return windowType() == NET::Desktop;
}
bool Client::isDock() const
{
return windowType() == NET::Dock;
}
bool Client::isTopMenu() const
{
return windowType() == NET::TopMenu;
}
bool Client::isMenu() const
{
return windowType() == NET::Menu && !isTopMenu(); // because of backwards comp.
}
bool Client::isToolbar() const
{
return windowType() == NET::Toolbar;
}
bool Client::isSplash() const
{
return windowType() == NET::Splash;
}
bool Client::isUtility() const
{
return windowType() == NET::Utility;
}
bool Client::isDialog() const
{
return windowType() == NET::Dialog;
}
bool Client::isNormalWindow() const
{
return windowType() == NET::Normal;
}
bool Client::isSpecialWindow() const
{
return isDesktop() || isDock() || isSplash() || isTopMenu()
|| isToolbar(); // TODO
}
NET::WindowType Client::windowType( bool direct, int supported_types ) const NET::WindowType Client::windowType( bool direct, int supported_types ) const
{ {
NET::WindowType wt = info->windowType( supported_types ); NET::WindowType wt = info->windowType( supported_types );
@ -1708,6 +1656,12 @@ NET::WindowType Client::windowType( bool direct, int supported_types ) const
return wt; return wt;
} }
bool Client::isSpecialWindow() const
{
return isDesktop() || isDock() || isSplash() || isTopMenu()
|| isToolbar(); // TODO
}
/*! /*!
Sets an appropriate cursor shape for the logical mouse position \a m Sets an appropriate cursor shape for the logical mouse position \a m
@ -1804,46 +1758,24 @@ void Client::cancelAutoRaise()
autoRaiseTimer = 0; autoRaiseTimer = 0;
} }
#ifndef NDEBUG double Client::opacity() const
kdbgstream& operator<<( kdbgstream& stream, const Client* cl )
{ {
if( cl == NULL ) if( info->opacity() == 0xffffffff )
return stream << "\'NULL_CLIENT\'"; return 1.0;
return stream << "\'ID:" << cl->window() << ";WMCLASS:" << cl->resourceClass() << ":" << cl->resourceName() << ";Caption:" << cl->caption() << "\'"; return info->opacity() * 1.0 / 0xffffffff;
} }
kdbgstream& operator<<( kdbgstream& stream, const ClientList& list )
void Client::setOpacity( double opacity )
{ {
stream << "LIST:("; opacity = qBound( 0.0, opacity, 1.0 );
bool first = true; info->setOpacity( static_cast< unsigned long >( opacity * 0xffffffff ));
for( ClientList::ConstIterator it = list.begin(); // we'll react on PropertyNotify
it != list.end();
++it )
{
if( !first )
stream << ":";
first = false;
stream << *it;
}
stream << ")";
return stream;
} }
kdbgstream& operator<<( kdbgstream& stream, const ConstClientList& list )
void Client::debug( kdbgstream& stream ) const
{ {
stream << "LIST:("; stream << "\'ID:" << window() << ";WMCLASS:" << resourceClass() << ":" << resourceName() << ";Caption:" << caption() << "\'";
bool first = true;
for( ConstClientList::ConstIterator it = list.begin();
it != list.end();
++it )
{
if( !first )
stream << ":";
first = false;
stream << *it;
}
stream << ")";
return stream;
} }
#endif
QPixmap * kwin_get_menu_pix_hack() QPixmap * kwin_get_menu_pix_hack()
{ {

View file

@ -299,6 +299,14 @@ void Toplevel::finishCompositing()
damage_region = QRegion(); damage_region = QRegion();
} }
void Toplevel::discardWindowPixmap()
{
if( window_pix == None )
return;
XFreePixmap( display(), window_pix );
window_pix = None;
}
Pixmap Toplevel::createWindowPixmap() const Pixmap Toplevel::createWindowPixmap() const
{ {
assert( compositing()); assert( compositing());

View file

@ -1615,6 +1615,8 @@ bool Unmanaged::windowEvent( XEvent* e )
{ {
detectShape( handle()); detectShape( handle());
addDamageFull(); addDamageFull();
if( compositing() )
discardWindowPixmap();
if( scene != NULL ) if( scene != NULL )
scene->windowGeometryShapeChanged( this ); scene->windowGeometryShapeChanged( this );
} }

View file

@ -47,10 +47,9 @@ void SceneBasic::paint( QRegion, ToplevelList windows )
QRect r = (*it)->geometry().intersect( QRect( 0, 0, displayWidth(), displayHeight())); QRect r = (*it)->geometry().intersect( QRect( 0, 0, displayWidth(), displayHeight()));
if( !r.isEmpty()) if( !r.isEmpty())
{ {
Pixmap pix = (*it)->createWindowPixmap(); Pixmap pix = (*it)->windowPixmap();
XCopyArea( display(), pix, composite_pixmap, gc, XCopyArea( display(), pix, composite_pixmap, gc,
qMax( 0, -(*it)->x()), qMax( 0, -(*it)->y()), r.width(), r.height(), r.x(), r.y()); qMax( 0, -(*it)->x()), qMax( 0, -(*it)->y()), r.width(), r.height(), r.x(), r.y());
XFreePixmap( display(), pix );
} }
} }
XCopyArea( display(), composite_pixmap, rootWindow(), gc, 0, 0, displayWidth(), displayHeight(), 0, 0 ); XCopyArea( display(), composite_pixmap, rootWindow(), gc, 0, 0, displayWidth(), displayHeight(), 0, 0 );

View file

@ -622,8 +622,7 @@ void SceneOpenGL::Window::bindTexture()
return; return;
} }
// Get the pixmap with the window contents // Get the pixmap with the window contents
Pixmap window_pix = toplevel->createWindowPixmap(); Pixmap pix = toplevel->windowPixmap();
Pixmap pix = window_pix;
// HACK // HACK
// When a window uses ARGB visual and has a decoration, the decoration // When a window uses ARGB visual and has a decoration, the decoration
// does use ARGB visual. When converting such window to a texture // does use ARGB visual. When converting such window to a texture
@ -698,21 +697,24 @@ void SceneOpenGL::Window::bindTexture()
} }
XFreeGC( display(), gc ); XFreeGC( display(), gc );
} }
// the pixmap is no longer needed, the texture will be updated // if using copy_buffer, the pixmap is no longer needed, the
// only when the window changes anyway, so no need to cache // texture will be updated only when the window changes anyway,
// the pixmap // so no need to cache the pixmap
XFreePixmap( display(), pix ); if( copy_buffer )
XFreePixmap( display(), pix );
texture_y_inverted = true; texture_y_inverted = true;
toplevel->resetDamage( toplevel->rect()); toplevel->resetDamage( toplevel->rect());
} }
else if( tfp_mode ) else if( tfp_mode )
{ // tfp mode, simply bind the pixmap to texture { // tfp mode, simply bind the pixmap to texture
// TODO what should the lifetime of bound_pixmap be?
if( texture == None ) if( texture == None )
glGenTextures( 1, &texture ); glGenTextures( 1, &texture );
if( bound_pixmap != None && !strict_binding ) // release old if needed if( bound_pixmap != None && !strict_binding ) // release old if needed
{ {
glXReleaseTexImageEXT( display(), bound_glxpixmap, GLX_FRONT_LEFT_EXT ); glXReleaseTexImageEXT( display(), bound_glxpixmap, GLX_FRONT_LEFT_EXT );
glXDestroyGLXPixmap( display(), bound_glxpixmap ); glXDestroyGLXPixmap( display(), bound_glxpixmap );
// TODO bound_pixmap shouldn't always be freed
XFreePixmap( display(), bound_pixmap ); XFreePixmap( display(), bound_pixmap );
} }
static const int attrs[] = static const int attrs[] =
@ -765,10 +767,11 @@ void SceneOpenGL::Window::bindTexture()
} }
} }
glXWaitGL(); glXWaitGL();
// the pixmap is no longer needed, the texture will be updated // if using copy_buffer, the pixmap is no longer needed, the
// only when the window changes anyway, so no need to cache // texture will be updated only when the window changes anyway,
// the pixmap // so no need to cache the pixmap
XFreePixmap( display(), pix ); if( copy_buffer )
XFreePixmap( display(), pix );
if( db ) if( db )
glDrawBuffer( GL_BACK ); glDrawBuffer( GL_BACK );
glXMakeContextCurrent( display(), glxbuffer, glxbuffer, ctxbuffer ); glXMakeContextCurrent( display(), glxbuffer, glxbuffer, ctxbuffer );
@ -776,8 +779,6 @@ void SceneOpenGL::Window::bindTexture()
texture_y_inverted = false; texture_y_inverted = false;
toplevel->resetDamage( toplevel->rect()); toplevel->resetDamage( toplevel->rect());
} }
if( copy_buffer )
XFreePixmap( display(), window_pix );
} }
@ -839,7 +840,12 @@ void SceneOpenGL::Window::discardTexture()
if( !strict_binding ) if( !strict_binding )
glXReleaseTexImageEXT( display(), bound_glxpixmap, GLX_FRONT_LEFT_EXT ); glXReleaseTexImageEXT( display(), bound_glxpixmap, GLX_FRONT_LEFT_EXT );
glXDestroyGLXPixmap( display(), bound_glxpixmap ); glXDestroyGLXPixmap( display(), bound_glxpixmap );
XFreePixmap( display(), bound_pixmap ); // TODO this is broken, and may need changing anyway depending on
// how tfp_mode deals with the new windowPixmap()
if( bound_pixmap != toplevel->windowPixmap( false ) )
// if using copy_buffer, bound_pixmap is independent of
// windowPixmap(), so free it now
XFreePixmap( display(), bound_pixmap );
bound_pixmap = None; bound_pixmap = None;
bound_glxpixmap = None; bound_glxpixmap = None;
} }

View file

@ -305,8 +305,7 @@ Picture SceneXrender::Window::picture()
if( _picture == None && format != NULL ) if( _picture == None && format != NULL )
{ {
// Get the pixmap with the window contents. // Get the pixmap with the window contents.
Pixmap window_pix = toplevel->createWindowPixmap(); Pixmap pix = toplevel->windowPixmap();
Pixmap pix = window_pix;
// HACK the same alpha clear hack like with opengl, see there // HACK the same alpha clear hack like with opengl, see there
Client* c = dynamic_cast< Client* >( toplevel ); Client* c = dynamic_cast< Client* >( toplevel );
bool alpha_clear = c != NULL && c->hasAlpha() && !c->noBorder(); bool alpha_clear = c != NULL && c->hasAlpha() && !c->noBorder();
@ -336,10 +335,9 @@ Picture SceneXrender::Window::picture()
XFreeGC( display(), gc ); XFreeGC( display(), gc );
} }
_picture = XRenderCreatePicture( display(), pix, format, 0, 0 ); _picture = XRenderCreatePicture( display(), pix, format, 0, 0 );
XFreePixmap( display(), pix ); // the picture owns the pixmap
#ifdef ALPHA_CLEAR_COPY #ifdef ALPHA_CLEAR_COPY
if( alpha_clear ) if( alpha_clear )
XFreePixmap( display(), window_pix ); XFreePixmap( display(), pix );
#endif #endif
toplevel->resetDamage( toplevel->rect()); toplevel->resetDamage( toplevel->rect());
} }

View file

@ -17,6 +17,7 @@ Toplevel::Toplevel( Workspace* ws )
: vis( None ) : vis( None )
, id( None ) , id( None )
, wspace( ws ) , wspace( ws )
, window_pix( None )
, damage_handle( None ) , damage_handle( None )
, is_shape( false ) , is_shape( false )
{ {
@ -25,6 +26,7 @@ Toplevel::Toplevel( Workspace* ws )
Toplevel::~Toplevel() Toplevel::~Toplevel()
{ {
assert( damage_handle == None ); assert( damage_handle == None );
discardWindowPixmap();
} }
#ifndef NDEBUG #ifndef NDEBUG

View file

@ -53,7 +53,7 @@ class Toplevel
bool isSplash() const; bool isSplash() const;
bool isUtility() const; bool isUtility() const;
Pixmap createWindowPixmap() const; Pixmap windowPixmap( bool allow_create = true ); // for use with compositing
Visual* visual() const; Visual* visual() const;
bool shape() const; bool shape() const;
virtual double opacity() const = 0; virtual double opacity() const = 0;
@ -70,6 +70,8 @@ class Toplevel
void setHandle( Window id ); void setHandle( Window id );
void detectShape( Window id ); void detectShape( Window id );
void damageNotifyEvent( XDamageNotifyEvent* e ); void damageNotifyEvent( XDamageNotifyEvent* e );
Pixmap createWindowPixmap() const;
void discardWindowPixmap();
QRect geom; QRect geom;
Visual* vis; Visual* vis;
int bit_depth; int bit_depth;
@ -78,6 +80,7 @@ class Toplevel
private: private:
Window id; Window id;
Workspace* wspace; Workspace* wspace;
Pixmap window_pix;
Damage damage_handle; Damage damage_handle;
QRegion damage_region; QRegion damage_region;
bool is_shape; bool is_shape;
@ -189,6 +192,13 @@ inline bool Toplevel::isNormalWindow() const
return windowType() == NET::Normal; return windowType() == NET::Normal;
} }
inline Pixmap Toplevel::windowPixmap( bool allow_create )
{
if( window_pix == None && allow_create )
window_pix = createWindowPixmap();
return window_pix;
}
inline QRegion Toplevel::damage() const inline QRegion Toplevel::damage() const
{ {
return damage_region; return damage_region;