Opengl support for shaped windows.

svn path=/branches/work/kwin_composite/; revision=590728
icc-effect-5.14.5
Luboš Luňák 2006-09-30 17:28:27 +00:00
parent fba72ecdfe
commit ace6b4ad8a
11 changed files with 203 additions and 251 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 ),
@ -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;
@ -143,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??
@ -156,7 +154,8 @@ 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( postpone_geometry_updates == 0 );
assert( !check_active_modal ); assert( !check_active_modal );
@ -177,6 +176,7 @@ 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)
@ -220,8 +220,8 @@ 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 --postpone_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry
deleteClient( this, Allowed ); deleteClient( this, Allowed );
} }
@ -232,6 +232,7 @@ 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)
@ -247,8 +248,8 @@ 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 --postpone_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry
deleteClient( this, Allowed ); deleteClient( this, Allowed );
} }
@ -264,7 +265,6 @@ void Client::updateDecoration( bool check_workspace_pos, bool 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();
@ -279,6 +279,8 @@ 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( scene != NULL )
scene->windowGeometryShapeChanged( this );
} }
else else
destroyDecoration(); destroyDecoration();
@ -288,6 +290,7 @@ void Client::updateDecoration( bool check_workspace_pos, bool force )
if( do_show ) if( do_show )
decoration->widget()->show(); decoration->widget()->show();
updateFrameExtents(); updateFrameExtents();
addDamage( rect());
} }
void Client::destroyDecoration() void Client::destroyDecoration()
@ -305,6 +308,9 @@ 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( scene != NULL )
scene->windowGeometryShapeChanged( this );
addDamage( rect());
} }
} }
@ -334,7 +340,7 @@ void Client::checkBorderSizes()
void Client::detectNoBorder() void Client::detectNoBorder()
{ {
if( Shape::hasShape( window())) if( shape())
{ {
noborder = true; noborder = true;
return; return;
@ -422,34 +428,22 @@ 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( scene != NULL )
scene->windowGeometryShapeChanged( this );
addDamage( rect());
// 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 set propagate the input shape
// (it's the same like the bounding shape by default)
XShapeCombineShape( display(), frameId(), ShapeInput, 0, 0,
frameId(), ShapeBounding, ShapeSet );
XShapeCombineShape( display(), frameId(), ShapeInput,
clientPos().x(), clientPos().y(),
window(), ShapeBounding, ShapeSubtract );
XShapeCombineShape( display(), frameId(), ShapeInput,
clientPos().x(), clientPos().y(),
window(), ShapeInput, ShapeUnion );
}
} }
void Client::setMask( const QRegion& reg, int mode ) void Client::setMask( const QRegion& reg, int mode )
@ -478,7 +472,9 @@ void Client::setMask( const QRegion& reg, int mode )
xrects, rects.count(), ShapeSet, mode ); xrects, rects.count(), ShapeSet, mode );
delete[] xrects; delete[] xrects;
} }
updateShape(); if( scene != NULL )
scene->windowGeometryShapeChanged( this );
addDamage( rect());
} }
QRegion Client::mask() const QRegion Client::mask() const
@ -923,7 +919,7 @@ 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 );
@ -945,7 +941,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 );
@ -1290,7 +1286,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 )
{ {
@ -1607,58 +1603,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 );
@ -1690,6 +1634,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
@ -1786,46 +1736,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()
{ {

144
client.h
View File

@ -28,6 +28,7 @@ License. See the file "COPYING" for the exact licensing terms.
#include "workspace.h" #include "workspace.h"
#include "kdecoration.h" #include "kdecoration.h"
#include "rules.h" #include "rules.h"
#include "toplevel.h"
class QTimer; class QTimer;
class KProcess; class KProcess;
@ -42,7 +43,8 @@ class WinInfo;
class SessionInfo; class SessionInfo;
class Bridge; class Bridge;
class Client : public QObject, public KDecorationDefines class Client
: public Toplevel
{ {
Q_OBJECT Q_OBJECT
public: public:
@ -52,7 +54,6 @@ class Client : public QObject, public KDecorationDefines
Window wrapperId() const; Window wrapperId() const;
Window decorationId() const; Window decorationId() const;
Workspace* workspace() const;
const Client* transientFor() const; const Client* transientFor() const;
Client* transientFor(); Client* transientFor();
bool isTransient() const; bool isTransient() const;
@ -66,23 +67,20 @@ class Client : public QObject, public KDecorationDefines
const Group* group() const; const Group* group() const;
Group* group(); Group* group();
void checkGroup( Group* gr = NULL, bool force = false ); void checkGroup( Group* gr = NULL, bool force = false );
// prefer isXXX() instead
NET::WindowType windowType( bool direct = false, int supported_types = SUPPORTED_WINDOW_TYPES_MASK ) const;
const WindowRules* rules() const; const WindowRules* rules() const;
void removeRule( Rules* r ); void removeRule( Rules* r );
void setupWindowRules( bool ignore_temporary ); void setupWindowRules( bool ignore_temporary );
void applyWindowRules(); void applyWindowRules();
virtual NET::WindowType windowType( bool direct = false, int supported_types = SUPPORTED_WINDOW_TYPES_MASK ) const;
// returns true for "special" windows and false for windows which are "normal"
// (normal=window which has a border, can be moved by the user, can be closed, etc.)
// true for Desktop, Dock, Splash, Override and TopMenu (and Toolbar??? - for now)
// false for Normal, Dialog, Utility and Menu (and Toolbar??? - not yet) TODO
bool isSpecialWindow() const;
bool hasNETSupport() const;
QRect geometry() const;
QSize size() const;
QSize minSize() const; QSize minSize() const;
QSize maxSize() const; QSize maxSize() const;
QPoint pos() const;
QRect rect() const;
int x() const;
int y() const;
int width() const;
int height() const;
QPoint clientPos() const; // inside of geometry() QPoint clientPos() const; // inside of geometry()
QSize clientSize() const; QSize clientSize() const;
@ -165,24 +163,9 @@ class Client : public QObject, public KDecorationDefines
// auxiliary functions, depend on the windowType // auxiliary functions, depend on the windowType
bool wantsTabFocus() const; bool wantsTabFocus() const;
bool wantsInput() const; bool wantsInput() const;
bool hasNETSupport() const;
bool isMovable() const;
bool isDesktop() const;
bool isDock() const;
bool isToolbar() const;
bool isTopMenu() const;
bool isMenu() const;
bool isNormalWindow() const; // normal as in 'NET::Normal or NET::Unknown non-transient'
bool isDialog() const;
bool isSplash() const;
bool isUtility() const;
// returns true for "special" windows and false for windows which are "normal"
// (normal=window which has a border, can be moved by the user, can be closed, etc.)
// true for Desktop, Dock, Splash, Override and TopMenu (and Toolbar??? - for now)
// false for Normal, Dialog, Utility and Menu (and Toolbar??? - not yet) TODO
bool isSpecialWindow() const;
bool isResizable() const; bool isResizable() const;
bool isMovable() const;
bool isCloseable() const; // may be closed by the user (may have a close button) bool isCloseable() const; // may be closed by the user (may have a close button)
void takeActivity( int flags, bool handled, allowed_t ); // takes ActivityFlags as arg (in utils.h) void takeActivity( int flags, bool handled, allowed_t ); // takes ActivityFlags as arg (in utils.h)
@ -195,9 +178,10 @@ class Client : public QObject, public KDecorationDefines
void updateDecoration( bool check_workspace_pos, bool force = false ); void updateDecoration( bool check_workspace_pos, bool force = false );
void checkBorderSizes(); void checkBorderSizes();
// shape extensions
bool shape() const;
void updateShape(); void updateShape();
virtual double opacity() const;
void setOpacity( double opacity );
void setGeometry( int x, int y, int w, int h, ForceGeometry_t force = NormalGeometrySet ); void setGeometry( int x, int y, int w, int h, ForceGeometry_t force = NormalGeometrySet );
void setGeometry( const QRect& r, ForceGeometry_t force = NormalGeometrySet ); void setGeometry( const QRect& r, ForceGeometry_t force = NormalGeometrySet );
@ -287,6 +271,15 @@ class Client : public QObject, public KDecorationDefines
void checkActiveModal(); void checkActiveModal();
bool hasStrut() const; bool hasStrut() const;
bool isMove() const
{
return moveResizeMode && mode == PositionCenter;
}
bool isResize() const
{
return moveResizeMode && mode != PositionCenter;
}
private slots: private slots:
void autoRaise(); void autoRaise();
void shadeHover(); void shadeHover();
@ -330,6 +323,9 @@ class Client : public QObject, public KDecorationDefines
void processDecorationButtonPress( int button, int state, int x, int y, int x_root, int y_root ); void processDecorationButtonPress( int button, int state, int x, int y, int x_root, int y_root );
protected:
virtual void debug( kdbgstream& stream ) const;
private slots: private slots:
void pingTimeout(); void pingTimeout();
void processKillerExited(); void processKillerExited();
@ -400,12 +396,10 @@ class Client : public QObject, public KDecorationDefines
Time readUserCreationTime() const; Time readUserCreationTime() const;
static bool sameAppWindowRoleMatch( const Client* c1, const Client* c2, bool active_hack ); static bool sameAppWindowRoleMatch( const Client* c1, const Client* c2, bool active_hack );
void startupIdChanged(); void startupIdChanged();
Window client; Window client;
Window wrapper; Window wrapper;
Window frame;
KDecoration* decoration; KDecoration* decoration;
Workspace* wspace;
Bridge* bridge; Bridge* bridge;
int desk; int desk;
bool buttonDown; bool buttonDown;
@ -413,14 +407,6 @@ class Client : public QObject, public KDecorationDefines
bool move_faked_activity; bool move_faked_activity;
Window move_resize_grab_window; Window move_resize_grab_window;
bool unrestrictedMoveResize; bool unrestrictedMoveResize;
bool isMove() const
{
return moveResizeMode && mode == PositionCenter;
}
bool isResize() const
{
return moveResizeMode && mode != PositionCenter;
}
Position mode; Position mode;
QPoint moveOffset; QPoint moveOffset;
@ -446,7 +432,6 @@ class Client : public QObject, public KDecorationDefines
uint active :1; uint active :1;
uint deleting : 1; // true when doing cleanup and destroying the client uint deleting : 1; // true when doing cleanup and destroying the client
uint keep_above : 1; // NET::KeepAbove (was stays_on_top) uint keep_above : 1; // NET::KeepAbove (was stays_on_top)
uint is_shape :1;
uint skip_taskbar :1; uint skip_taskbar :1;
uint original_skip_taskbar :1; // unaffected by KWin uint original_skip_taskbar :1; // unaffected by KWin
uint Pdeletewindow :1; // does the window understand the DeleteWindow protocol? uint Pdeletewindow :1; // does the window understand the DeleteWindow protocol?
@ -504,7 +489,6 @@ class Client : public QObject, public KDecorationDefines
Time ping_timestamp; Time ping_timestamp;
Time user_time; Time user_time;
unsigned long allowed_actions; unsigned long allowed_actions;
QRect frame_geometry;
QSize client_size; QSize client_size;
int postpone_geometry_updates; // >0 - new geometry is remembered, but not actually set int postpone_geometry_updates; // >0 - new geometry is remembered, but not actually set
bool pending_geometry_update; bool pending_geometry_update;
@ -557,7 +541,7 @@ inline Window Client::window() const
inline Window Client::frameId() const inline Window Client::frameId() const
{ {
return frame; return handle();
} }
inline Window Client::wrapperId() const inline Window Client::wrapperId() const
@ -570,11 +554,6 @@ inline Window Client::decorationId() const
return decoration != NULL ? decoration->widget()->winId() : None; return decoration != NULL ? decoration->widget()->winId() : None;
} }
inline Workspace* Client::workspace() const
{
return wspace;
}
inline const Client* Client::transientFor() const inline const Client* Client::transientFor() const
{ {
return transient_for; return transient_for;
@ -730,12 +709,6 @@ inline bool Client::keepBelow() const
return keep_below; return keep_below;
} }
inline bool Client::shape() const
{
return is_shape;
}
inline bool Client::isFullScreen() const inline bool Client::isFullScreen() const
{ {
return fullscreen_mode != FullScreenNone; return fullscreen_mode != FullScreenNone;
@ -791,46 +764,6 @@ inline QByteArray Client::windowRole() const
return window_role; return window_role;
} }
inline QRect Client::geometry() const
{
return frame_geometry;
}
inline QSize Client::size() const
{
return frame_geometry.size();
}
inline QPoint Client::pos() const
{
return frame_geometry.topLeft();
}
inline int Client::x() const
{
return frame_geometry.x();
}
inline int Client::y() const
{
return frame_geometry.y();
}
inline int Client::width() const
{
return frame_geometry.width();
}
inline int Client::height() const
{
return frame_geometry.height();
}
inline QRect Client::rect() const
{
return QRect( 0, 0, width(), height());
}
inline QPoint Client::clientPos() const inline QPoint Client::clientPos() const
{ {
return QPoint( border_left, border_top ); return QPoint( border_left, border_top );
@ -876,7 +809,7 @@ inline const WindowRules* Client::rules() const
return &client_rules; return &client_rules;
} }
KWIN_PROCEDURE( CheckIgnoreFocusStealingProcedure, cl->ignore_focus_stealing = options->checkIgnoreFocusStealing( cl )); KWIN_PROCEDURE( CheckIgnoreFocusStealingProcedure, Client, cl->ignore_focus_stealing = options->checkIgnoreFocusStealing( cl ));
inline Window Client::moveResizeGrabWindow() const inline Window Client::moveResizeGrabWindow() const
{ {
@ -893,22 +826,9 @@ inline void Client::removeRule( Rules* rule )
client_rules.remove( rule ); client_rules.remove( rule );
} }
#ifdef NDEBUG KWIN_COMPARE_PREDICATE( WindowMatchPredicate, Client, Window, cl->window() == value );
inline KWIN_COMPARE_PREDICATE( FrameIdMatchPredicate, Client, Window, cl->frameId() == value );
kndbgstream& operator<<( kndbgstream& stream, const Client* ) { return stream; } KWIN_COMPARE_PREDICATE( WrapperIdMatchPredicate, Client, Window, cl->wrapperId() == value );
inline
kndbgstream& operator<<( kndbgstream& stream, const ClientList& ) { return stream; }
inline
kndbgstream& operator<<( kndbgstream& stream, const ConstClientList& ) { return stream; }
#else
kdbgstream& operator<<( kdbgstream& stream, const Client* );
kdbgstream& operator<<( kdbgstream& stream, const ClientList& );
kdbgstream& operator<<( kdbgstream& stream, const ConstClientList& );
#endif
KWIN_COMPARE_PREDICATE( WindowMatchPredicate, Window, cl->window() == value );
KWIN_COMPARE_PREDICATE( FrameIdMatchPredicate, Window, cl->frameId() == value );
KWIN_COMPARE_PREDICATE( WrapperIdMatchPredicate, Window, cl->wrapperId() == value );
} // namespace } // namespace

View File

@ -674,7 +674,7 @@ bool Client::windowEvent( XEvent* e )
{ {
if( e->type == Extensions::shapeNotifyEvent() ) if( e->type == Extensions::shapeNotifyEvent() )
{ {
is_shape = hasShape( window()); // workaround for #19644 detectShape( window()); // workaround for #19644
updateShape(); updateShape();
} }
} }
@ -1627,9 +1627,17 @@ bool Unmanaged::windowEvent( XEvent* e )
configureNotifyEvent( &e->xconfigure ); configureNotifyEvent( &e->xconfigure );
break; break;
default: default:
{
if( e->type == Extensions::shapeNotifyEvent() )
{
detectShape( handle());
if( scene != NULL )
scene->windowGeometryShapeChanged( this );
}
if( e->type == Extensions::damageNotifyEvent()) if( e->type == Extensions::damageNotifyEvent())
damageNotifyEvent( reinterpret_cast< XDamageNotifyEvent* >( e )); damageNotifyEvent( reinterpret_cast< XDamageNotifyEvent* >( e ));
break; break;
}
} }
return true; // eat all events return true; // eat all events
} }

View File

@ -38,17 +38,24 @@ bool Client::manage( Window w, bool isMapped )
{ {
StackingUpdatesBlocker stacking_blocker( workspace()); StackingUpdatesBlocker stacking_blocker( workspace());
grabXServer();
XWindowAttributes attr; XWindowAttributes attr;
if( !XGetWindowAttributes(display(), w, &attr)) if( !XGetWindowAttributes(display(), w, &attr))
{
ungrabXServer();
return false; return false;
}
grabXServer();
// from this place on, manage() mustn't return false // from this place on, manage() mustn't return false
postpone_geometry_updates = 1; postpone_geometry_updates = 1;
pending_geometry_update = true; // force update when finishing with geometry changes pending_geometry_update = true; // force update when finishing with geometry changes
embedClient( w, attr ); embedClient( w, attr );
vis = attr.visual;
setupCompositing();
// SELI order all these things in some sane manner // SELI order all these things in some sane manner
@ -77,6 +84,7 @@ bool Client::manage( Window w, bool isMapped )
NET::WM2UserTime | NET::WM2UserTime |
NET::WM2StartupId | NET::WM2StartupId |
NET::WM2ExtendedStrut | NET::WM2ExtendedStrut |
NET::WM2Opacity |
0; 0;
info = new WinInfo( this, display(), client, rootWindow(), properties, 2 ); info = new WinInfo( this, display(), client, rootWindow(), properties, 2 );
@ -105,6 +113,9 @@ bool Client::manage( Window w, bool isMapped )
setupWindowRules( false ); setupWindowRules( false );
setCaption( cap_normal, true ); setCaption( cap_normal, true );
if( Extensions::shapeAvailable())
XShapeSelectInput( display(), window(), ShapeNotifyMask );
detectShape( window());
detectNoBorder(); detectNoBorder();
fetchIconicName(); fetchIconicName();
getWMHints(); // needs to be done before readTransient() because of reading the group getWMHints(); // needs to be done before readTransient() because of reading the group
@ -313,9 +324,8 @@ bool Client::manage( Window w, bool isMapped )
if(( !isSpecialWindow() || isToolbar()) && isMovable()) if(( !isSpecialWindow() || isToolbar()) && isMovable())
keepInArea( area, partial_keep_in_area ); keepInArea( area, partial_keep_in_area );
XShapeSelectInput( display(), window(), ShapeNotifyMask ); if( shape())
is_shape = Shape::hasShape( window()); updateShape();
updateShape();
//CT extra check for stupid jdk 1.3.1. But should make sense in general //CT extra check for stupid jdk 1.3.1. But should make sense in general
// if client has initial state set to Iconic and is transient with a parent // if client has initial state set to Iconic and is transient with a parent
@ -510,7 +520,7 @@ bool Client::manage( Window w, bool isMapped )
// sendSyntheticConfigureNotify(); done when setting mapping state // sendSyntheticConfigureNotify(); done when setting mapping state
delete session; delete session;
ungrabXServer(); ungrabXServer();
client_rules.discardTemporary(); client_rules.discardTemporary();
@ -528,7 +538,7 @@ bool Client::manage( Window w, bool isMapped )
void Client::embedClient( Window w, const XWindowAttributes &attr ) void Client::embedClient( Window w, const XWindowAttributes &attr )
{ {
assert( client == None ); assert( client == None );
assert( frame == None ); assert( frameId() == None );
assert( wrapper == None ); assert( wrapper == None );
client = w; client = w;
// we don't want the window to be destroyed when we are destroyed // we don't want the window to be destroyed when we are destroyed
@ -544,9 +554,10 @@ void Client::embedClient( Window w, const XWindowAttributes &attr )
swa.background_pixmap = None; swa.background_pixmap = None;
swa.border_pixel = 0; swa.border_pixel = 0;
frame = XCreateWindow( display(), rootWindow(), 0, 0, 1, 1, 0, Window frame = XCreateWindow( display(), rootWindow(), 0, 0, 1, 1, 0,
attr.depth, InputOutput, attr.visual, attr.depth, InputOutput, attr.visual,
CWColormap | CWBackPixmap | CWBorderPixel, &swa ); CWColormap | CWBackPixmap | CWBorderPixel, &swa );
setHandle( frame );
wrapper = XCreateWindow( display(), frame, 0, 0, 1, 1, 0, wrapper = XCreateWindow( display(), frame, 0, 0, 1, 1, 0,
attr.depth, InputOutput, attr.visual, attr.depth, InputOutput, attr.visual,
CWColormap | CWBackPixmap | CWBorderPixel, &swa ); CWColormap | CWBackPixmap | CWBorderPixel, &swa );

View File

@ -17,6 +17,8 @@ Based on glcompmgr code by Felix Bellaby.
#include "utils.h" #include "utils.h"
#include "client.h" #include "client.h"
#include <X11/extensions/shape.h>
namespace KWinInternal namespace KWinInternal
{ {
@ -134,11 +136,11 @@ void SceneOpenGL::paint( QRegion, ToplevelList windows )
// TODO for double-buffered root glDrawBuffer( GL_BACK ); // TODO for double-buffered root glDrawBuffer( GL_BACK );
glXMakeContextCurrent( display(), glxroot, glxroot, context ); glXMakeContextCurrent( display(), glxroot, glxroot, context );
glPushMatrix(); glPushMatrix();
// TODO Y axis in opengl grows up apparently
glTranslatef( w.glX(), w.glY(), 0 ); glTranslatef( w.glX(), w.glY(), 0 );
glEnable( GL_TEXTURE_RECTANGLE_ARB ); glEnable( GL_TEXTURE_RECTANGLE_ARB );
glBegin( GL_QUADS ); glBegin( GL_QUADS );
quadDraw( 0, 0, w.width(), w.height()); foreach( QRect r, w.shape().rects())
quadDraw( r.x(), w.height() - r.y() - r.height(), r.width(), r.height());
glEnd(); glEnd();
glPopMatrix(); glPopMatrix();
glDisable( GL_TEXTURE_RECTANGLE_ARB ); glDisable( GL_TEXTURE_RECTANGLE_ARB );
@ -166,10 +168,21 @@ void SceneOpenGL::windowDeleted( Toplevel* c )
windows.remove( c ); windows.remove( c );
} }
void SceneOpenGL::windowGeometryShapeChanged( Toplevel* c )
{
if( !windows.contains( c )) // this is ok, shape is not valid
return; // by default
Window& w = windows[ c ];
w.discardShape();
w.discardPixmap();
w.discardTexture();
}
SceneOpenGL::Window::Window( Toplevel* c ) SceneOpenGL::Window::Window( Toplevel* c )
: toplevel( c ) : toplevel( c )
, glxpixmap( None ) , glxpixmap( None )
, texture( None ) , texture( None )
, shape_valid( false )
{ {
} }
@ -219,4 +232,38 @@ void SceneOpenGL::Window::bindTexture()
} }
} }
void SceneOpenGL::Window::discardShape()
{
shape_valid = false;
}
QRegion SceneOpenGL::Window::shape() const
{
if( !shape_valid )
{
if( toplevel->shape())
{
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;
}
} // namespace } // namespace

View File

@ -27,8 +27,9 @@ class SceneOpenGL
SceneOpenGL( Workspace* ws ); SceneOpenGL( Workspace* ws );
virtual ~SceneOpenGL(); virtual ~SceneOpenGL();
virtual void paint( QRegion damage, ToplevelList windows ); virtual void paint( QRegion damage, ToplevelList windows );
virtual void windowAdded( Toplevel* ); virtual void windowAdded( Toplevel* c );
virtual void windowDeleted( Toplevel* ); virtual void windowDeleted( Toplevel* c );
virtual void windowGeometryShapeChanged( Toplevel* c );
private: private:
typedef GLuint Texture; typedef GLuint Texture;
GC gcroot; GC gcroot;
@ -53,13 +54,17 @@ class SceneOpenGL::Window
int height() const; int height() const;
GLXPixmap glxPixmap() const; GLXPixmap glxPixmap() const;
void bindTexture(); void bindTexture();
Window() {} // QMap sucks even in Qt4 QRegion shape() const;
private:
void discardPixmap(); void discardPixmap();
void discardTexture(); void discardTexture();
void discardShape();
Window() {} // QMap sucks even in Qt4
private:
Toplevel* toplevel; Toplevel* toplevel;
mutable GLXPixmap glxpixmap; mutable GLXPixmap glxpixmap;
Texture texture; Texture texture;
mutable QRegion shape_region;
mutable bool shape_valid;
}; };
inline inline

View File

@ -19,6 +19,7 @@ Toplevel::Toplevel( Workspace* ws )
, wspace( ws ) , wspace( ws )
, damage_handle( None ) , damage_handle( None )
, window_pixmap( None ) , window_pixmap( None )
, is_shape( false )
{ {
} }
@ -72,6 +73,10 @@ kdbgstream& operator<<( kdbgstream& stream, const ConstToplevelList& list )
} }
#endif #endif
void Toplevel::detectShape( Window id )
{
is_shape = Extensions::hasShape( id );
}
} // namespace } // namespace

View File

@ -55,6 +55,7 @@ class Toplevel
Pixmap windowPixmap() const; Pixmap windowPixmap() const;
Visual* visual() const; Visual* visual() const;
bool shape() const;
virtual double opacity() const = 0; virtual double opacity() const = 0;
void setupCompositing(); void setupCompositing();
void finishCompositing(); void finishCompositing();
@ -64,6 +65,7 @@ class Toplevel
void resetDamage(); void resetDamage();
protected: protected:
void setHandle( Window id ); void setHandle( Window id );
void detectShape( Window id );
void resetWindowPixmap(); void resetWindowPixmap();
void damageNotifyEvent( XDamageNotifyEvent* e ); void damageNotifyEvent( XDamageNotifyEvent* e );
QRect geom; QRect geom;
@ -76,6 +78,7 @@ class Toplevel
Damage damage_handle; Damage damage_handle;
QRegion damage_region; QRegion damage_region;
mutable Pixmap window_pixmap; mutable Pixmap window_pixmap;
bool is_shape;
}; };
inline Window Toplevel::handle() const inline Window Toplevel::handle() const
@ -189,6 +192,11 @@ inline QRegion Toplevel::damage() const
return damage_region; return damage_region;
} }
inline bool Toplevel::shape() const
{
return is_shape;
}
#ifdef NDEBUG #ifdef NDEBUG
inline inline
kndbgstream& operator<<( kndbgstream& stream, const Toplevel* ) { return stream; } kndbgstream& operator<<( kndbgstream& stream, const Toplevel* ) { return stream; }

View File

@ -12,6 +12,8 @@ License. See the file "COPYING" for the exact licensing terms.
#include "workspace.h" #include "workspace.h"
#include <X11/extensions/shape.h>
namespace KWinInternal namespace KWinInternal
{ {
@ -47,6 +49,9 @@ bool Unmanaged::track( Window w )
0; 0;
info = new NETWinInfo( display(), w, rootWindow(), properties, 2 ); info = new NETWinInfo( display(), w, rootWindow(), properties, 2 );
if( Extensions::shapeAvailable())
XShapeSelectInput( display(), w, ShapeNotifyMask );
detectShape( w );
setupCompositing(); setupCompositing();
resetWindowPixmap(); resetWindowPixmap();
return true; return true;

View File

@ -84,6 +84,20 @@ int Extensions::shapeNotifyEvent()
return shape_event_base + ShapeNotify; return shape_event_base + ShapeNotify;
} }
// does the window w need a shape combine mask around it?
bool Extensions::hasShape( Window w )
{
int xws, yws, xbs, ybs;
unsigned int wws, hws, wbs, hbs;
int boundingShaped = 0, clipShaped = 0;
if( !Extensions::shapeAvailable())
return false;
XShapeQueryExtents(display(), w,
&boundingShaped, &xws, &yws, &wws, &hws,
&clipShaped, &xbs, &ybs, &wbs, &hbs);
return boundingShaped != 0;
}
int Extensions::damageNotifyEvent() int Extensions::damageNotifyEvent()
{ {
#ifdef HAVE_XDAMAGE #ifdef HAVE_XDAMAGE

View File

@ -149,6 +149,7 @@ class Extensions
static int damageNotifyEvent(); static int damageNotifyEvent();
static bool compositeAvailable() { return has_composite; } static bool compositeAvailable() { return has_composite; }
static bool fixesAvailable() { return has_fixes; } static bool fixesAvailable() { return has_fixes; }
static bool hasShape( Window w );
private: private:
static bool has_shape; static bool has_shape;
static int shape_event_base; static int shape_event_base;