From 51168e97a4a4417a23bf03247414211eb2e5427a Mon Sep 17 00:00:00 2001 From: Lucas Murray Date: Mon, 1 Feb 2010 07:44:27 +0000 Subject: [PATCH] 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 --- effects.cpp | 97 ++++++++++++------- effects.h | 2 + effects/highlightwindow/highlightwindow.cpp | 2 +- effects/logout/logout.cpp | 50 ++++++++-- effects/logout/logout.h | 9 +- effects/presentwindows/presentwindows.cpp | 2 +- effects/shadow/shadow.cpp | 2 +- effects/slidingpopups/slidingpopups.cpp | 2 +- effects/taskbarthumbnail/taskbarthumbnail.cpp | 2 +- events.cpp | 7 ++ lib/kwineffects.h | 4 +- 11 files changed, 128 insertions(+), 51 deletions(-) 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.