Keep the logout effect active until KWin is killed or the user cancels

the logout by using new information provided by KSMServer; Allow effects
to read and detect root window property notify events.

svn path=/trunk/KDE/kdebase/workspace/; revision=1083335
This commit is contained in:
Lucas Murray 2010-02-01 07:44:27 +00:00
parent b674835c6c
commit 51168e97a4
11 changed files with 128 additions and 51 deletions

View file

@ -46,6 +46,52 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
namespace KWin namespace KWin
{ {
//---------------------
// Static
static QByteArray readWindowProperty( Window win, long atom, long type, int format )
{
int len = 32768;
for(;;)
{
unsigned char* data;
Atom rtype;
int rformat;
unsigned long nitems, after;
if( XGetWindowProperty( QX11Info::display(), win,
atom, 0, len, False, AnyPropertyType,
&rtype, &rformat, &nitems, &after, &data ) == Success )
{
if( after > 0 )
{
XFree( data );
len *= 2;
continue;
}
if( long( rtype ) == type && rformat == format )
{
int bytelen = format == 8 ? nitems : format == 16 ? nitems * sizeof( short ) : nitems * sizeof( long );
QByteArray ret( reinterpret_cast< const char* >( data ), bytelen );
XFree( data );
return ret;
}
else // wrong format, type or something
{
XFree( data );
return QByteArray();
}
}
else // XGetWindowProperty() failed
return QByteArray();
}
}
static void deleteWindowProperty( Window win, long int atom )
{
XDeleteProperty( QX11Info::display(), win, atom );
}
//---------------------
EffectsHandlerImpl::EffectsHandlerImpl(CompositingType type) EffectsHandlerImpl::EffectsHandlerImpl(CompositingType type)
: EffectsHandler(type) : EffectsHandler(type)
@ -428,6 +474,16 @@ void EffectsHandlerImpl::registerPropertyType( long atom, bool reg )
} }
} }
QByteArray EffectsHandlerImpl::readRootProperty( long atom, long type, int format ) const
{
return readWindowProperty( rootWindow(), atom, type, format );
}
void EffectsHandlerImpl::deleteRootProperty( long atom ) const
{
deleteWindowProperty( rootWindow(), atom );
}
void EffectsHandlerImpl::activateWindow( EffectWindow* c ) void EffectsHandlerImpl::activateWindow( EffectWindow* c )
{ {
if( Client* cl = dynamic_cast< Client* >( static_cast<EffectWindowImpl*>(c)->window())) if( Client* cl = dynamic_cast< Client* >( static_cast<EffectWindowImpl*>(c)->window()))
@ -1281,46 +1337,13 @@ QRect EffectWindowImpl::contentsRect() const
QByteArray EffectWindowImpl::readProperty( long atom, long type, int format ) const QByteArray EffectWindowImpl::readProperty( long atom, long type, int format ) const
{ {
int len = 32768; return readWindowProperty( window()->window(), atom, type, format );
for(;;)
{
unsigned char* data;
Atom rtype;
int rformat;
unsigned long nitems, after;
if( XGetWindowProperty( QX11Info::display(), window()->window(),
atom, 0, len, False, AnyPropertyType,
&rtype, &rformat, &nitems, &after, &data ) == Success )
{
if( after > 0 )
{
XFree( data );
len *= 2;
continue;
}
if( long( rtype ) == type && rformat == format )
{
int bytelen = format == 8 ? nitems : format == 16 ? nitems * sizeof( short ) : nitems * sizeof( long );
QByteArray ret( reinterpret_cast< const char* >( data ), bytelen );
XFree( data );
return ret;
}
else // wrong format, type or something
{
XFree( data );
return QByteArray();
}
}
else // XGetWindowProperty() failed
return QByteArray();
}
} }
void EffectWindowImpl::deleteProperty(long int atom) const void EffectWindowImpl::deleteProperty(long int atom) const
{ {
XDeleteProperty( QX11Info::display(), window()->window(), atom ); deleteWindowProperty( window()->window(), atom );
} }
bool EffectWindowImpl::isMovable() const bool EffectWindowImpl::isMovable() const
{ {

View file

@ -134,6 +134,8 @@ class EffectsHandlerImpl : public EffectsHandler
virtual unsigned long xrenderBufferPicture(); virtual unsigned long xrenderBufferPicture();
virtual void reconfigure(); virtual void reconfigure();
virtual void registerPropertyType( long atom, bool reg ); virtual void registerPropertyType( long atom, bool reg );
virtual QByteArray readRootProperty( long atom, long type, int format ) const;
virtual void deleteRootProperty( long atom ) const;
virtual bool hasDecorationShadows() const; virtual bool hasDecorationShadows() const;

View file

@ -129,7 +129,7 @@ void HighlightWindowEffect::windowDeleted( EffectWindow* w )
void HighlightWindowEffect::propertyNotify( EffectWindow* w, long a ) void HighlightWindowEffect::propertyNotify( EffectWindow* w, long a )
{ {
if( a != m_atom ) if( !w || a != m_atom )
return; // Not our atom return; // Not our atom
QByteArray byteData = w->readProperty( m_atom, m_atom, 32 ); QByteArray byteData = w->readProperty( m_atom, m_atom, 32 );

View file

@ -4,7 +4,7 @@
Copyright (C) 2007 Lubos Lunak <l.lunak@kde.org> Copyright (C) 2007 Lubos Lunak <l.lunak@kde.org>
Copyright (C) 2009 Martin Gräßlin <kde@martin-graesslin.com> Copyright (C) 2009 Martin Gräßlin <kde@martin-graesslin.com>
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com> Copyright (C) 2009, 2010 Lucas Murray <lmurray@undefinedfire.com>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -35,10 +35,18 @@ KWIN_EFFECT( logout, LogoutEffect )
LogoutEffect::LogoutEffect() LogoutEffect::LogoutEffect()
: progress( 0.0 ) : progress( 0.0 )
, displayEffect( false )
, logoutWindow( NULL ) , logoutWindow( NULL )
, logoutWindowClosed( true ) , logoutWindowClosed( true )
, logoutWindowPassed( false ) , logoutWindowPassed( false )
, canDoPersistent( false )
, ignoredWindows()
{ {
// Persistent effect
logoutAtom = XInternAtom( display(), "_KDE_LOGGING_OUT", False );
effects->registerPropertyType( logoutAtom, true );
// Block KSMServer's effect
char net_wm_cm_name[ 100 ]; char net_wm_cm_name[ 100 ];
sprintf( net_wm_cm_name, "_NET_WM_CM_S%d", DefaultScreen( display())); sprintf( net_wm_cm_name, "_NET_WM_CM_S%d", DefaultScreen( display()));
Atom net_wm_cm = XInternAtom( display(), net_wm_cm_name, False ); Atom net_wm_cm = XInternAtom( display(), net_wm_cm_name, False );
@ -46,6 +54,7 @@ LogoutEffect::LogoutEffect()
Atom hack = XInternAtom( display(), "_KWIN_LOGOUT_EFFECT", False ); Atom hack = XInternAtom( display(), "_KWIN_LOGOUT_EFFECT", False );
XChangeProperty( display(), sel, hack, hack, 8, PropModeReplace, (unsigned char*)&hack, 1 ); XChangeProperty( display(), sel, hack, hack, 8, PropModeReplace, (unsigned char*)&hack, 1 );
// the atom is not removed when effect is destroyed, this is temporary anyway // the atom is not removed when effect is destroyed, this is temporary anyway
#ifdef KWIN_HAVE_OPENGL_COMPOSITING #ifdef KWIN_HAVE_OPENGL_COMPOSITING
blurTexture = NULL; blurTexture = NULL;
blurTarget = NULL; blurTarget = NULL;
@ -78,7 +87,7 @@ void LogoutEffect::reconfigure( ReconfigureFlags )
void LogoutEffect::prePaintScreen( ScreenPrePaintData& data, int time ) void LogoutEffect::prePaintScreen( ScreenPrePaintData& data, int time )
{ {
#ifdef KWIN_HAVE_OPENGL_COMPOSITING #ifdef KWIN_HAVE_OPENGL_COMPOSITING
if( !logoutWindow && progress == 0.0 ) if( !displayEffect && progress == 0.0 )
{ {
if( blurTexture ) if( blurTexture )
{ {
@ -117,7 +126,7 @@ void LogoutEffect::prePaintScreen( ScreenPrePaintData& data, int time )
else else
#endif #endif
{ {
if( logoutWindow != NULL && !logoutWindowClosed ) if( displayEffect )
progress = qMin( 1.0, progress + time / animationTime( 2000.0 )); progress = qMin( 1.0, progress + time / animationTime( 2000.0 ));
else if( progress > 0.0 ) else if( progress > 0.0 )
progress = qMax( 0.0, progress - time / animationTime( 500.0 )); progress = qMax( 0.0, progress - time / animationTime( 500.0 ));
@ -150,7 +159,7 @@ void LogoutEffect::paintWindow( EffectWindow* w, int mask, QRegion region, Windo
} }
else else
{ {
if( logoutWindowPassed ) if( logoutWindowPassed || ignoredWindows.contains( w ))
{ // Window is rendered after the FBO { // Window is rendered after the FBO
windows.append( w ); windows.append( w );
windowsOpacities[ w ] = data.opacity; windowsOpacities[ w ] = data.opacity;
@ -165,7 +174,7 @@ void LogoutEffect::paintWindow( EffectWindow* w, int mask, QRegion region, Windo
if( w == logoutWindow ) if( w == logoutWindow )
// This is the logout window don't alter it but render our vignetting now // This is the logout window don't alter it but render our vignetting now
renderVignetting(); renderVignetting();
else if( !logoutWindowPassed ) else if( !logoutWindowPassed && !ignoredWindows.contains( w ))
// Window is in the background, desaturate // Window is in the background, desaturate
data.saturation *= ( 1.0 - progress * 0.2 ); data.saturation *= ( 1.0 - progress * 0.2 );
// All other windows are unaltered // All other windows are unaltered
@ -174,13 +183,15 @@ void LogoutEffect::paintWindow( EffectWindow* w, int mask, QRegion region, Windo
#endif #endif
if( effects->compositingType() == KWin::XRenderCompositing ) if( effects->compositingType() == KWin::XRenderCompositing )
{ // Since we can't do vignetting in XRender just do a stronger desaturation and darken { // Since we can't do vignetting in XRender just do a stronger desaturation and darken
if( w != logoutWindow && !logoutWindowPassed ) if( w != logoutWindow && !logoutWindowPassed && !ignoredWindows.contains( w ))
{ {
data.saturation *= ( 1.0 - progress * 0.8 ); data.saturation *= ( 1.0 - progress * 0.8 );
data.brightness *= ( 1.0 - progress * 0.3 ); data.brightness *= ( 1.0 - progress * 0.3 );
} }
} }
if( w == logoutWindow ) if( w == logoutWindow ||
ignoredWindows.contains( w )) // HACK: All windows past the first ignored one should not be
// blurred as it affects the stacking order.
// All following windows are on top of the logout window and should not be altered either // All following windows are on top of the logout window and should not be altered either
logoutWindowPassed = true; logoutWindowPassed = true;
} }
@ -305,8 +316,13 @@ void LogoutEffect::windowAdded( EffectWindow* w )
logoutWindow = w; logoutWindow = w;
logoutWindowClosed = false; // So we don't blur the window on close logoutWindowClosed = false; // So we don't blur the window on close
progress = 0.0; progress = 0.0;
displayEffect = true;
ignoredWindows.clear();
effects->addRepaintFull(); effects->addRepaintFull();
} }
else if( canDoPersistent )
// TODO: Add parent
ignoredWindows.append( w );
} }
void LogoutEffect::windowClosed( EffectWindow* w ) void LogoutEffect::windowClosed( EffectWindow* w )
@ -314,12 +330,15 @@ void LogoutEffect::windowClosed( EffectWindow* w )
if( w == logoutWindow ) if( w == logoutWindow )
{ {
logoutWindowClosed = true; logoutWindowClosed = true;
if( !canDoPersistent )
displayEffect = false; // Fade back to normal
effects->addRepaintFull(); effects->addRepaintFull();
} }
} }
void LogoutEffect::windowDeleted( EffectWindow* w ) void LogoutEffect::windowDeleted( EffectWindow* w )
{ {
ignoredWindows.removeAll( w );
if( w == logoutWindow ) if( w == logoutWindow )
logoutWindow = NULL; logoutWindow = NULL;
} }
@ -364,4 +383,21 @@ void LogoutEffect::renderVignetting()
} }
#endif #endif
void LogoutEffect::propertyNotify( EffectWindow* w, long a )
{
if( w || a != logoutAtom )
return; // Not our atom
QByteArray byteData = effects->readRootProperty( logoutAtom, logoutAtom, 8 );
if( byteData.length() < 1 )
{ // Property was deleted
displayEffect = false;
return;
}
// We are using a compatible KSMServer therefore only terminate the effect when the
// atom is deleted, not when the dialog is closed.
canDoPersistent = true;
}
} // namespace } // namespace

View file

@ -4,7 +4,7 @@
Copyright (C) 2007 Lubos Lunak <l.lunak@kde.org> Copyright (C) 2007 Lubos Lunak <l.lunak@kde.org>
Copyright (C) 2009 Martin Gräßlin <kde@martin-graesslin.com> Copyright (C) 2009 Martin Gräßlin <kde@martin-graesslin.com>
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com> Copyright (C) 2009, 2010 Lucas Murray <lmurray@undefinedfire.com>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -46,13 +46,20 @@ class LogoutEffect
virtual void windowAdded( EffectWindow* w ); virtual void windowAdded( EffectWindow* w );
virtual void windowClosed( EffectWindow* w ); virtual void windowClosed( EffectWindow* w );
virtual void windowDeleted( EffectWindow* w ); virtual void windowDeleted( EffectWindow* w );
virtual void propertyNotify( EffectWindow* w, long a );
private: private:
bool isLogoutDialog( EffectWindow* w ); bool isLogoutDialog( EffectWindow* w );
double progress; // 0-1 double progress; // 0-1
bool displayEffect;
EffectWindow* logoutWindow; EffectWindow* logoutWindow;
bool logoutWindowClosed; bool logoutWindowClosed;
bool logoutWindowPassed; bool logoutWindowPassed;
// Persistent effect
long logoutAtom;
bool canDoPersistent;
EffectWindowList ignoredWindows;
#ifdef KWIN_HAVE_OPENGL_COMPOSITING #ifdef KWIN_HAVE_OPENGL_COMPOSITING
void renderVignetting(); void renderVignetting();
int frameDelay; int frameDelay;

View file

@ -732,7 +732,7 @@ void PresentWindowsEffect::tabBoxKeyEvent( QKeyEvent* event )
// Atom handling // Atom handling
void PresentWindowsEffect::propertyNotify( EffectWindow* w, long a ) void PresentWindowsEffect::propertyNotify( EffectWindow* w, long a )
{ {
if( a != m_atomDesktop && a != m_atomWindows ) if( !w || ( a != m_atomDesktop && a != m_atomWindows ))
return; // Not our atom return; // Not our atom
if( a == m_atomDesktop ) if( a == m_atomDesktop )

View file

@ -373,7 +373,7 @@ QRect ShadowEffect::transformWindowDamage( EffectWindow* w, const QRect& r )
void ShadowEffect::propertyNotify( EffectWindow* w, long atom ) void ShadowEffect::propertyNotify( EffectWindow* w, long atom )
{ {
if ( atom != shadowOverride ) if( !w || atom != shadowOverride )
return; return;
const QByteArray value = w->readProperty( atom, atom, 32 ); const QByteArray value = w->readProperty( atom, atom, 32 );
w->setData( ShadowOverrideRole, !value.isNull() ); w->setData( ShadowOverrideRole, !value.isNull() );

View file

@ -184,7 +184,7 @@ void SlidingPopupsEffect::windowDeleted( EffectWindow* w )
void SlidingPopupsEffect::propertyNotify( EffectWindow* w, long a ) void SlidingPopupsEffect::propertyNotify( EffectWindow* w, long a )
{ {
if( a != mAtom ) if( !w || a != mAtom )
return; return;
QByteArray data = w->readProperty( mAtom, mAtom, 32 ); QByteArray data = w->readProperty( mAtom, mAtom, 32 );

View file

@ -131,7 +131,7 @@ void TaskbarThumbnailEffect::windowDeleted( EffectWindow* w )
void TaskbarThumbnailEffect::propertyNotify( EffectWindow* w, long a ) void TaskbarThumbnailEffect::propertyNotify( EffectWindow* w, long a )
{ {
if( a != atom ) if( !w || a != atom )
return; return;
thumbnails.remove( w ); thumbnails.remove( w );
QByteArray data = w->readProperty( atom, atom, 32 ); QByteArray data = w->readProperty( atom, atom, 32 );

View file

@ -321,6 +321,13 @@ bool Workspace::workspaceEvent( XEvent * e )
if( c->windowEvent( e )) if( c->windowEvent( e ))
return true; return true;
} }
// We want to pass root window property events to effects
if( e->type == PropertyNotify && e->xany.window == rootWindow() && effects )
{
XPropertyEvent* re = &e->xproperty;
static_cast< EffectsHandlerImpl* >( effects )->propertyNotify( NULL, re->atom );
}
} }
if( movingClient != NULL && movingClient->moveResizeGrabWindow() == e->xany.window if( movingClient != NULL && movingClient->moveResizeGrabWindow() == e->xany.window
&& ( e->type == MotionNotify || e->type == ButtonPress || e->type == ButtonRelease )) && ( e->type == MotionNotify || e->type == ButtonPress || e->type == ButtonRelease ))

View file

@ -170,7 +170,7 @@ X-KDE-Library=kwin4_effect_cooleffect
#define KWIN_EFFECT_API_MAKE_VERSION( major, minor ) (( major ) << 8 | ( minor )) #define KWIN_EFFECT_API_MAKE_VERSION( major, minor ) (( major ) << 8 | ( minor ))
#define KWIN_EFFECT_API_VERSION_MAJOR 0 #define KWIN_EFFECT_API_VERSION_MAJOR 0
#define KWIN_EFFECT_API_VERSION_MINOR 112 #define KWIN_EFFECT_API_VERSION_MINOR 113
#define KWIN_EFFECT_API_VERSION KWIN_EFFECT_API_MAKE_VERSION( \ #define KWIN_EFFECT_API_VERSION KWIN_EFFECT_API_MAKE_VERSION( \
KWIN_EFFECT_API_VERSION_MAJOR, KWIN_EFFECT_API_VERSION_MINOR ) KWIN_EFFECT_API_VERSION_MAJOR, KWIN_EFFECT_API_VERSION_MINOR )
@ -722,6 +722,8 @@ class KWIN_EXPORT EffectsHandler
Note that even events that haven't been registered for can be received. Note that even events that haven't been registered for can be received.
*/ */
virtual void registerPropertyType( long atom, bool reg ) = 0; virtual void registerPropertyType( long atom, bool reg ) = 0;
virtual QByteArray readRootProperty( long atom, long type, int format ) const = 0;
virtual void deleteRootProperty( long atom ) const = 0;
/** /**
* Returns @a true if the active window decoration has shadow API hooks. * Returns @a true if the active window decoration has shadow API hooks.