Commit 51168e97 authored by Lucas Murray's avatar Lucas Murray

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
parent b674835c
......@@ -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
{
......
......@@ -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;
......
......@@ -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 );
......
......@@ -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
......@@ -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;
......
......@@ -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 )
......
......@@ -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() );
......
......@@ -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 );
......
......@@ -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 );
......
......@@ -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 ))
......
......@@ -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.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment