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
{
//---------------------
// 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<EffectWindowImpl*>(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
{

View file

@ -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;

View file

@ -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 );

View file

@ -4,7 +4,7 @@
Copyright (C) 2007 Lubos Lunak <l.lunak@kde.org>
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
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

View file

@ -4,7 +4,7 @@
Copyright (C) 2007 Lubos Lunak <l.lunak@kde.org>
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
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;

View file

@ -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 )

View file

@ -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() );

View file

@ -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 );

View file

@ -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 );

View file

@ -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 ))

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_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.