diff --git a/effects.cpp b/effects.cpp
index 505fb5e173..d02315f332 100644
--- a/effects.cpp
+++ b/effects.cpp
@@ -46,6 +46,52 @@ along with this program. If not, see .
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)
: 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 )
{
if( Client* cl = dynamic_cast< Client* >( static_cast(c)->window()))
@@ -1281,46 +1337,13 @@ QRect EffectWindowImpl::contentsRect() const
QByteArray EffectWindowImpl::readProperty( long atom, long type, int format ) const
{
- int len = 32768;
- 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();
- }
+ return readWindowProperty( window()->window(), atom, type, format );
}
void EffectWindowImpl::deleteProperty(long int atom) const
-{
- XDeleteProperty( QX11Info::display(), window()->window(), atom );
-}
-
+ {
+ deleteWindowProperty( window()->window(), atom );
+ }
bool EffectWindowImpl::isMovable() const
{
diff --git a/effects.h b/effects.h
index 9de14467fe..c58f5b82b3 100644
--- a/effects.h
+++ b/effects.h
@@ -134,6 +134,8 @@ class EffectsHandlerImpl : public EffectsHandler
virtual unsigned long xrenderBufferPicture();
virtual void reconfigure();
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;
diff --git a/effects/highlightwindow/highlightwindow.cpp b/effects/highlightwindow/highlightwindow.cpp
index a57e104b3a..89d7c48fdd 100644
--- a/effects/highlightwindow/highlightwindow.cpp
+++ b/effects/highlightwindow/highlightwindow.cpp
@@ -129,7 +129,7 @@ void HighlightWindowEffect::windowDeleted( EffectWindow* w )
void HighlightWindowEffect::propertyNotify( EffectWindow* w, long a )
{
- if( a != m_atom )
+ if( !w || a != m_atom )
return; // Not our atom
QByteArray byteData = w->readProperty( m_atom, m_atom, 32 );
diff --git a/effects/logout/logout.cpp b/effects/logout/logout.cpp
index d0e41047a2..5c2350a4a1 100644
--- a/effects/logout/logout.cpp
+++ b/effects/logout/logout.cpp
@@ -4,7 +4,7 @@
Copyright (C) 2007 Lubos Lunak
Copyright (C) 2009 Martin Gräßlin
-Copyright (C) 2009 Lucas Murray
+Copyright (C) 2009, 2010 Lucas Murray
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
@@ -35,10 +35,18 @@ KWIN_EFFECT( logout, LogoutEffect )
LogoutEffect::LogoutEffect()
: progress( 0.0 )
+ , displayEffect( false )
, logoutWindow( NULL )
, logoutWindowClosed( true )
, 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 ];
sprintf( net_wm_cm_name, "_NET_WM_CM_S%d", DefaultScreen( display()));
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 );
XChangeProperty( display(), sel, hack, hack, 8, PropModeReplace, (unsigned char*)&hack, 1 );
// the atom is not removed when effect is destroyed, this is temporary anyway
+
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
blurTexture = NULL;
blurTarget = NULL;
@@ -78,7 +87,7 @@ void LogoutEffect::reconfigure( ReconfigureFlags )
void LogoutEffect::prePaintScreen( ScreenPrePaintData& data, int time )
{
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
- if( !logoutWindow && progress == 0.0 )
+ if( !displayEffect && progress == 0.0 )
{
if( blurTexture )
{
@@ -117,7 +126,7 @@ void LogoutEffect::prePaintScreen( ScreenPrePaintData& data, int time )
else
#endif
{
- if( logoutWindow != NULL && !logoutWindowClosed )
+ if( displayEffect )
progress = qMin( 1.0, progress + time / animationTime( 2000.0 ));
else if( progress > 0.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
{
- if( logoutWindowPassed )
+ if( logoutWindowPassed || ignoredWindows.contains( w ))
{ // Window is rendered after the FBO
windows.append( w );
windowsOpacities[ w ] = data.opacity;
@@ -165,7 +174,7 @@ void LogoutEffect::paintWindow( EffectWindow* w, int mask, QRegion region, Windo
if( w == logoutWindow )
// This is the logout window don't alter it but render our vignetting now
renderVignetting();
- else if( !logoutWindowPassed )
+ else if( !logoutWindowPassed && !ignoredWindows.contains( w ))
// Window is in the background, desaturate
data.saturation *= ( 1.0 - progress * 0.2 );
// All other windows are unaltered
@@ -174,13 +183,15 @@ void LogoutEffect::paintWindow( EffectWindow* w, int mask, QRegion region, Windo
#endif
if( effects->compositingType() == KWin::XRenderCompositing )
{ // 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.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
logoutWindowPassed = true;
}
@@ -305,8 +316,13 @@ void LogoutEffect::windowAdded( EffectWindow* w )
logoutWindow = w;
logoutWindowClosed = false; // So we don't blur the window on close
progress = 0.0;
+ displayEffect = true;
+ ignoredWindows.clear();
effects->addRepaintFull();
}
+ else if( canDoPersistent )
+ // TODO: Add parent
+ ignoredWindows.append( w );
}
void LogoutEffect::windowClosed( EffectWindow* w )
@@ -314,12 +330,15 @@ void LogoutEffect::windowClosed( EffectWindow* w )
if( w == logoutWindow )
{
logoutWindowClosed = true;
+ if( !canDoPersistent )
+ displayEffect = false; // Fade back to normal
effects->addRepaintFull();
}
}
void LogoutEffect::windowDeleted( EffectWindow* w )
{
+ ignoredWindows.removeAll( w );
if( w == logoutWindow )
logoutWindow = NULL;
}
@@ -364,4 +383,21 @@ void LogoutEffect::renderVignetting()
}
#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
diff --git a/effects/logout/logout.h b/effects/logout/logout.h
index c155303a3f..0a640c0d0b 100644
--- a/effects/logout/logout.h
+++ b/effects/logout/logout.h
@@ -4,7 +4,7 @@
Copyright (C) 2007 Lubos Lunak
Copyright (C) 2009 Martin Gräßlin
-Copyright (C) 2009 Lucas Murray
+Copyright (C) 2009, 2010 Lucas Murray
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
@@ -46,13 +46,20 @@ class LogoutEffect
virtual void windowAdded( EffectWindow* w );
virtual void windowClosed( EffectWindow* w );
virtual void windowDeleted( EffectWindow* w );
+ virtual void propertyNotify( EffectWindow* w, long a );
private:
bool isLogoutDialog( EffectWindow* w );
double progress; // 0-1
+ bool displayEffect;
EffectWindow* logoutWindow;
bool logoutWindowClosed;
bool logoutWindowPassed;
+ // Persistent effect
+ long logoutAtom;
+ bool canDoPersistent;
+ EffectWindowList ignoredWindows;
+
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
void renderVignetting();
int frameDelay;
diff --git a/effects/presentwindows/presentwindows.cpp b/effects/presentwindows/presentwindows.cpp
index a3f6a585ff..542cfb7a40 100644
--- a/effects/presentwindows/presentwindows.cpp
+++ b/effects/presentwindows/presentwindows.cpp
@@ -732,7 +732,7 @@ void PresentWindowsEffect::tabBoxKeyEvent( QKeyEvent* event )
// Atom handling
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
if( a == m_atomDesktop )
diff --git a/effects/shadow/shadow.cpp b/effects/shadow/shadow.cpp
index f9ed6aeba8..43acd525c8 100644
--- a/effects/shadow/shadow.cpp
+++ b/effects/shadow/shadow.cpp
@@ -373,7 +373,7 @@ QRect ShadowEffect::transformWindowDamage( EffectWindow* w, const QRect& r )
void ShadowEffect::propertyNotify( EffectWindow* w, long atom )
{
- if ( atom != shadowOverride )
+ if( !w || atom != shadowOverride )
return;
const QByteArray value = w->readProperty( atom, atom, 32 );
w->setData( ShadowOverrideRole, !value.isNull() );
diff --git a/effects/slidingpopups/slidingpopups.cpp b/effects/slidingpopups/slidingpopups.cpp
index 587e4d3c3a..8a3ee8a595 100644
--- a/effects/slidingpopups/slidingpopups.cpp
+++ b/effects/slidingpopups/slidingpopups.cpp
@@ -184,7 +184,7 @@ void SlidingPopupsEffect::windowDeleted( EffectWindow* w )
void SlidingPopupsEffect::propertyNotify( EffectWindow* w, long a )
{
- if( a != mAtom )
+ if( !w || a != mAtom )
return;
QByteArray data = w->readProperty( mAtom, mAtom, 32 );
diff --git a/effects/taskbarthumbnail/taskbarthumbnail.cpp b/effects/taskbarthumbnail/taskbarthumbnail.cpp
index c6cf6a4efb..01f0f30f5d 100644
--- a/effects/taskbarthumbnail/taskbarthumbnail.cpp
+++ b/effects/taskbarthumbnail/taskbarthumbnail.cpp
@@ -131,7 +131,7 @@ void TaskbarThumbnailEffect::windowDeleted( EffectWindow* w )
void TaskbarThumbnailEffect::propertyNotify( EffectWindow* w, long a )
{
- if( a != atom )
+ if( !w || a != atom )
return;
thumbnails.remove( w );
QByteArray data = w->readProperty( atom, atom, 32 );
diff --git a/events.cpp b/events.cpp
index 87ca65706b..0c095c80a2 100644
--- a/events.cpp
+++ b/events.cpp
@@ -321,6 +321,13 @@ bool Workspace::workspaceEvent( XEvent * e )
if( c->windowEvent( e ))
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
&& ( e->type == MotionNotify || e->type == ButtonPress || e->type == ButtonRelease ))
diff --git a/lib/kwineffects.h b/lib/kwineffects.h
index 440aab5d19..36743cdb7e 100644
--- a/lib/kwineffects.h
+++ b/lib/kwineffects.h
@@ -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_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( \
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.
*/
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.