Add support for showing effects for windows which have already been deleted.

Add a fade-out effect.


svn path=/branches/work/kwin_composite/; revision=623872
icc-effect-5.14.5
Luboš Luňák 2007-01-15 18:03:04 +00:00
parent 921d8d4f22
commit ff6f889ffc
16 changed files with 374 additions and 182 deletions

View File

@ -52,6 +52,7 @@ set(kwin_KDEINIT_SRCS
glutils.cpp
effects.cpp
effects/fadein.cpp
effects/fadeout.cpp
effects/maketransparent.cpp
effects/scalein.cpp
effects/shakymove.cpp

View File

@ -45,9 +45,6 @@ General TODO
- maybe posted paint events need to be processed immediatelly, or maybe the compositing
code should not update the window until the decoration is finished painting
/ handle XRandr changes
- output buffers and similar probably need recreating when the screen size changes
! compile even without OpenGL or XRender
- kwin_composite currently requires both OpenGL and XRender to build
- compiling without either results in compile errors, needs to be fixed
@ -66,6 +63,10 @@ General TODO
+ make effects configurable without having to recompile
- possibly also add something like KWIN_COMPOSE for debugging purposes
* handle properly stacking order of deleted windows for showing in effects
* handle properly deleted windows that reappear (windowReadded() function?)
OpenGL TODO
=================================
@ -147,10 +148,7 @@ XRender TODO
Effects framework TODO
==============================
/ design framework for graphical effects
- modelling it after compiz seems to make a lot of sense
* solve somehow disappearing windows
/ solve somehow disappearing windows
- i.e. when a window is e.g. closed, the Client/Unmanaged object is destroyed, but animations
should be going on
? - maybe animations could be done actually before the state change, it makes sense to destroy
@ -185,6 +183,14 @@ Effects framework TODO
which means that if an effect sets PAINT_WINDOW_TRANSFORMED it needs to set it
also in prePaintScreen()
* PAINT_WINDOW_DISABLED turning off from effects needs some utility functions
- a window may have painting disabled for various reasons and their numbers may increase
over time
- so e.g. an effect showing minimized windows cannot simply turn off DISABLED
for minimized windows, because it may be disabled also for other reasons
- there should be some utility function that will be called by the effect
with arguments saying which disabled windows it wants enabled
Effects TODO
===============================
@ -219,10 +225,8 @@ Effects TODO
- Client::animateMinimizeOrUnminimize()
- Client::setShade()
+ zoom effect
/ zoom effect
- enlarge a portion of the screen
! - would require adding xScale/yScale to ScreenPaintData
- should be doable even for XRender
+ logout effect
* - should be triggered by ksmserver somehow

View File

@ -108,7 +108,6 @@ Client::Client( Workspace *ws )
shade_mode = ShadeNone;
active = false;
deleting = false;
keep_above = false;
keep_below = false;
motif_noborder = false;
@ -175,9 +174,11 @@ void Client::deleteClient( Client* c, allowed_t )
*/
void Client::releaseWindow( bool on_shutdown )
{
assert( !deleting );
deleting = true;
finishCompositing();
assert( !deleting());
delete_refcount = 1;
if( effects )
effects->windowClosed( this );
finishCompositing( false ); // don't discard pixmap
workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules
StackingUpdatesBlocker blocker( workspace());
if (moveResizeMode)
@ -192,7 +193,9 @@ void Client::releaseWindow( bool on_shutdown )
if( !on_shutdown )
workspace()->clientHidden( this );
XUnmapWindow( display(), frameId()); // destroying decoration would cause ugly visual effect
destroyDecoration();
// destroyDecoration();
delete decoration;
decoration = NULL;
cleanGrouping();
if( !on_shutdown )
{
@ -200,9 +203,11 @@ void Client::releaseWindow( bool on_shutdown )
// only when the window is being unmapped, not when closing down KWin
// (NETWM sections 5.5,5.7)
info->setDesktop( 0 );
desk = 0;
// desk = 0; - do not reset internal state, it may still be used by effects
info->setState( 0, info->state()); // reset all state flags
}
else
workspace()->addDeleted( this, Allowed );
XDeleteProperty( display(), client, atoms->kde_net_wm_user_creation_time);
XDeleteProperty( display(), client, atoms->net_frame_extents );
XDeleteProperty( display(), client, atoms->kde_net_wm_frame_strut );
@ -220,22 +225,25 @@ void Client::releaseWindow( bool on_shutdown )
// may do map+unmap before we initially map the window by calling rawShow() from manage().
XUnmapWindow( display(), client );
}
cleanUp();
client = None;
XDestroyWindow( display(), wrapper );
wrapper = None;
XDestroyWindow( display(), frameId());
// frame = None;
--block_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry
deleteClient( this, Allowed );
unrefWindow(); // will delete if recount is == 0
}
// like releaseWindow(), but this one is called when the window has been already destroyed
// (e.g. the application closed it)
void Client::destroyClient()
{
assert( !deleting );
deleting = true;
finishCompositing();
assert( !deleting());
delete_refcount = 1;
if( effects )
effects->windowClosed( this );
finishCompositing( false ); // don't discard pixmap
workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules
StackingUpdatesBlocker blocker( workspace());
if (moveResizeMode)
@ -247,15 +255,50 @@ void Client::destroyClient()
setModal( false );
hidden = true; // so that it's not considered visible anymore
workspace()->clientHidden( this );
destroyDecoration();
// destroyDecoration();
delete decoration;
decoration = NULL;
cleanGrouping();
workspace()->removeClient( this, Allowed );
cleanUp();
client = None; // invalidate
XDestroyWindow( display(), wrapper );
wrapper = None;
XDestroyWindow( display(), frameId());
// frame = None;
--block_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry
unrefWindow(); // will delete if recount is == 0
}
// All clean-up code shared between releaseWindow() and destroyClient().
// Clean up everything that should not affect a deleted Client until it's
// really deleted by unrefWindow(). I.e. stop watching events, turn off timers
// and so on.
void Client::cleanUp()
{
if( Extensions::shapeAvailable())
XShapeSelectInput( display(), client, NoEventMask );
XSelectInput( display(), client, NoEventMask );
delete autoRaiseTimer;
autoRaiseTimer = NULL;
delete shadeHoverTimer;
shadeHoverTimer = NULL;
delete ping_timer;
ping_timer = NULL;
delete process_killer;
process_killer = NULL;
delete demandAttentionKNotifyTimer;
demandAttentionKNotifyTimer = NULL;
}
void Client::unrefWindow()
{
if( --delete_refcount > 0 )
return;
workspace()->removeDeleted( this );
workspace()->addDamage( geometry());
destroyDecoration( true ); // only now gravitate etc., otherwise window pixmap would be wrong
discardWindowPixmap();
deleteClient( this, Allowed );
}
@ -300,9 +343,9 @@ void Client::updateDecoration( bool check_workspace_pos, bool force )
addDamageFull();
}
void Client::destroyDecoration()
void Client::destroyDecoration( bool force )
{
if( decoration != NULL )
if( decoration != NULL || force )
{
delete decoration;
decoration = NULL;
@ -317,7 +360,7 @@ void Client::destroyDecoration()
workarea_diff_y = save_workarea_diff_y;
if( compositing() )
discardWindowPixmap();
if( scene != NULL )
if( scene != NULL && !deleting())
scene->windowGeometryShapeChanged( this );
addDamageFull();
}
@ -852,7 +895,7 @@ void Client::toggleShade()
void Client::updateVisibility()
{
if( deleting )
if( deleting())
return;
bool show = true;
if( hidden )
@ -910,7 +953,7 @@ void Client::updateVisibility()
void Client::setMappingState(int s)
{
assert( client != None );
assert( !deleting || s == WithdrawnState );
assert( !deleting() || s == WithdrawnState );
if( mapping_state == s )
return;
bool was_unmanaged = ( mapping_state == WithdrawnState );

175
client.h
View File

@ -28,6 +28,7 @@ License. See the file "COPYING" for the exact licensing terms.
#include "workspace.h"
#include "kdecoration.h"
#include "rules.h"
#include "toplevel.h"
class QTimer;
class KProcess;
@ -42,7 +43,8 @@ class WinInfo;
class SessionInfo;
class Bridge;
class Client : public QObject, public KDecorationDefines
class Client
: public Toplevel
{
Q_OBJECT
public:
@ -52,7 +54,6 @@ class Client : public QObject, public KDecorationDefines
Window wrapperId() const;
Window decorationId() const;
Workspace* workspace() const;
const Client* transientFor() const;
Client* transientFor();
bool isTransient() const;
@ -66,24 +67,20 @@ class Client : public QObject, public KDecorationDefines
const Group* group() const;
Group* group();
void checkGroup( Group* gr = NULL, bool force = false );
void changeClientLeaderGroup( Group* gr );
// prefer isXXX() instead
NET::WindowType windowType( bool direct = false, int supported_types = SUPPORTED_WINDOW_TYPES_MASK ) const;
const WindowRules* rules() const;
void removeRule( Rules* r );
void setupWindowRules( bool ignore_temporary );
void applyWindowRules();
virtual NET::WindowType windowType( bool direct = false, int supported_types = SUPPORTED_WINDOW_TYPES_MASK ) const;
// returns true for "special" windows and false for windows which are "normal"
// (normal=window which has a border, can be moved by the user, can be closed, etc.)
// true for Desktop, Dock, Splash, Override and TopMenu (and Toolbar??? - for now)
// false for Normal, Dialog, Utility and Menu (and Toolbar??? - not yet) TODO
bool isSpecialWindow() const;
bool hasNETSupport() const;
QRect geometry() const;
QSize size() const;
QSize minSize() const;
QSize maxSize() const;
QPoint pos() const;
QRect rect() const;
int x() const;
int y() const;
int width() const;
int height() const;
QPoint clientPos() const; // inside of geometry()
QSize clientSize() const;
@ -93,6 +90,8 @@ class Client : public QObject, public KDecorationDefines
bool manage( Window w, bool isMapped );
void releaseWindow( bool on_shutdown = false );
void destroyClient();
virtual void unrefWindow();
enum Sizemode // how to resize the window in order to obey constains (mainly aspect ratios)
{
@ -166,24 +165,9 @@ class Client : public QObject, public KDecorationDefines
// auxiliary functions, depend on the windowType
bool wantsTabFocus() const;
bool wantsInput() const;
bool hasNETSupport() const;
bool isMovable() const;
bool isDesktop() const;
bool isDock() const;
bool isToolbar() const;
bool isTopMenu() const;
bool isMenu() const;
bool isNormalWindow() const; // normal as in 'NET::Normal or NET::Unknown non-transient'
bool isDialog() const;
bool isSplash() const;
bool isUtility() const;
// returns true for "special" windows and false for windows which are "normal"
// (normal=window which has a border, can be moved by the user, can be closed, etc.)
// true for Desktop, Dock, Splash, Override and TopMenu (and Toolbar??? - for now)
// false for Normal, Dialog, Utility and Menu (and Toolbar??? - not yet) TODO
bool isSpecialWindow() const;
bool isResizable() const;
bool isMovable() const;
bool isCloseable() const; // may be closed by the user (may have a close button)
void takeActivity( int flags, bool handled, allowed_t ); // takes ActivityFlags as arg (in utils.h)
@ -196,9 +180,10 @@ class Client : public QObject, public KDecorationDefines
void updateDecoration( bool check_workspace_pos, bool force = false );
void checkBorderSizes();
// shape extensions
bool shape() const;
void updateShape();
virtual double opacity() const;
void setOpacity( double opacity );
void setGeometry( int x, int y, int w, int h, ForceGeometry_t force = NormalGeometrySet );
void setGeometry( const QRect& r, ForceGeometry_t force = NormalGeometrySet );
@ -284,10 +269,18 @@ class Client : public QObject, public KDecorationDefines
void showContextHelp();
void cancelShadeHover();
void cancelAutoRaise();
void destroyClient();
void checkActiveModal();
bool hasStrut() const;
bool isMove() const
{
return moveResizeMode && mode == PositionCenter;
}
bool isResize() const
{
return moveResizeMode && mode != PositionCenter;
}
private slots:
void autoRaise();
void shadeHover();
@ -321,6 +314,7 @@ class Client : public QObject, public KDecorationDefines
void clientMessageEvent( XClientMessageEvent* e );
void enterNotifyEvent( XCrossingEvent* e );
void leaveNotifyEvent( XCrossingEvent* e );
void visibilityNotifyEvent( XVisibilityEvent* e );
void focusInEvent( XFocusInEvent* e );
void focusOutEvent( XFocusOutEvent* e );
@ -330,6 +324,9 @@ class Client : public QObject, public KDecorationDefines
void processDecorationButtonPress( int button, int state, int x, int y, int x_root, int y_root );
protected:
virtual void debug( kdbgstream& stream ) const;
private slots:
void pingTimeout();
void processKillerExited();
@ -361,6 +358,7 @@ class Client : public QObject, public KDecorationDefines
void updateWindowRules();
void finishWindowRules();
void setShortcutInternal( const KShortcut& cut );
void cleanUp();
void updateWorkareaDiffs();
void checkDirection( int new_diff, int old_diff, QRect& rect, const QRect& area );
@ -368,7 +366,7 @@ class Client : public QObject, public KDecorationDefines
void configureRequest( int value_mask, int rx, int ry, int rw, int rh, int gravity, bool from_tool );
NETExtendedStrut strut() const;
int checkShadeGeometry( int w, int h );
void postponeGeometryUpdates( bool postpone );
void blockGeometryUpdates( bool block );
bool startMoveResize();
void finishMoveResize( bool cancel );
@ -389,7 +387,7 @@ class Client : public QObject, public KDecorationDefines
void embedClient( Window w, const XWindowAttributes &attr );
void detectNoBorder();
void destroyDecoration();
void destroyDecoration( bool force = false );
void updateFrameExtents();
void rawShow(); // just shows it
@ -400,12 +398,10 @@ class Client : public QObject, public KDecorationDefines
Time readUserCreationTime() const;
static bool sameAppWindowRoleMatch( const Client* c1, const Client* c2, bool active_hack );
void startupIdChanged();
Window client;
Window wrapper;
Window frame;
KDecoration* decoration;
Workspace* wspace;
Bridge* bridge;
int desk;
bool buttonDown;
@ -413,14 +409,6 @@ class Client : public QObject, public KDecorationDefines
bool move_faked_activity;
Window move_resize_grab_window;
bool unrestrictedMoveResize;
bool isMove() const
{
return moveResizeMode && mode == PositionCenter;
}
bool isResize() const
{
return moveResizeMode && mode != PositionCenter;
}
Position mode;
QPoint moveOffset;
@ -444,9 +432,7 @@ class Client : public QObject, public KDecorationDefines
ClientList transients_list; // SELI make this ordered in stacking order?
ShadeMode shade_mode;
uint active :1;
uint deleting : 1; // true when doing cleanup and destroying the client
uint keep_above : 1; // NET::KeepAbove (was stays_on_top)
uint is_shape :1;
uint skip_taskbar :1;
uint original_skip_taskbar :1; // unaffected by KWin
uint Pdeletewindow :1; // does the window understand the DeleteWindow protocol?
@ -466,6 +452,7 @@ class Client : public QObject, public KDecorationDefines
uint modal : 1; // NET::Modal
uint noborder : 1;
uint user_noborder : 1;
uint not_obscured : 1;
uint urgency : 1; // XWMHints, UrgencyHint
uint ignore_focus_stealing : 1; // don't apply focus stealing prevention to this client
uint demands_attention : 1;
@ -503,10 +490,10 @@ class Client : public QObject, public KDecorationDefines
Time ping_timestamp;
Time user_time;
unsigned long allowed_actions;
QRect frame_geometry;
QSize client_size;
int postpone_geometry_updates; // >0 - new geometry is remembered, but not actually set
int block_geometry_updates; // >0 - new geometry is remembered, but not actually set
bool pending_geometry_update;
QRect geom_before_block;
bool shade_geometry_change;
int border_left, border_right, border_top, border_bottom;
QRegion _mask;
@ -516,22 +503,20 @@ class Client : public QObject, public KDecorationDefines
friend struct FetchNameInternalPredicate;
friend struct CheckIgnoreFocusStealingProcedure;
friend struct ResetupRulesProcedure;
friend class GeometryUpdatesPostponer;
friend class GeometryUpdatesBlocker;
void show() { assert( false ); } // SELI remove after Client is no longer QWidget
void hide() { assert( false ); }
QTimer* demandAttentionKNotifyTimer;
friend bool performTransiencyCheck();
};
// helper for Client::postponeGeometryUpdates() being called in pairs (true/false)
class GeometryUpdatesPostponer
// helper for Client::blockGeometryUpdates() being called in pairs (true/false)
class GeometryUpdatesBlocker
{
public:
GeometryUpdatesPostponer( Client* c )
: cl( c ) { cl->postponeGeometryUpdates( true ); }
~GeometryUpdatesPostponer()
{ cl->postponeGeometryUpdates( false ); }
GeometryUpdatesBlocker( Client* c )
: cl( c ) { cl->blockGeometryUpdates( true ); }
~GeometryUpdatesBlocker()
{ cl->blockGeometryUpdates( false ); }
private:
Client* cl;
};
@ -558,7 +543,7 @@ inline Window Client::window() const
inline Window Client::frameId() const
{
return frame;
return handle();
}
inline Window Client::wrapperId() const
@ -571,11 +556,6 @@ inline Window Client::decorationId() const
return decoration != NULL ? decoration->widget()->winId() : None;
}
inline Workspace* Client::workspace() const
{
return wspace;
}
inline const Client* Client::transientFor() const
{
return transient_for;
@ -731,12 +711,6 @@ inline bool Client::keepBelow() const
return keep_below;
}
inline bool Client::shape() const
{
return is_shape;
}
inline bool Client::isFullScreen() const
{
return fullscreen_mode != FullScreenNone;
@ -792,46 +766,6 @@ inline QByteArray Client::windowRole() const
return window_role;
}
inline QRect Client::geometry() const
{
return frame_geometry;
}
inline QSize Client::size() const
{
return frame_geometry.size();
}
inline QPoint Client::pos() const
{
return frame_geometry.topLeft();
}
inline int Client::x() const
{
return frame_geometry.x();
}
inline int Client::y() const
{
return frame_geometry.y();
}
inline int Client::width() const
{
return frame_geometry.width();
}
inline int Client::height() const
{
return frame_geometry.height();
}
inline QRect Client::rect() const
{
return QRect( 0, 0, width(), height());
}
inline QPoint Client::clientPos() const
{
return QPoint( border_left, border_top );
@ -877,7 +811,7 @@ inline const WindowRules* Client::rules() const
return &client_rules;
}
KWIN_PROCEDURE( CheckIgnoreFocusStealingProcedure, cl->ignore_focus_stealing = options->checkIgnoreFocusStealing( cl ));
KWIN_PROCEDURE( CheckIgnoreFocusStealingProcedure, Client, cl->ignore_focus_stealing = options->checkIgnoreFocusStealing( cl ));
inline Window Client::moveResizeGrabWindow() const
{
@ -894,22 +828,9 @@ inline void Client::removeRule( Rules* rule )
client_rules.remove( rule );
}
#ifdef NDEBUG
inline
kndbgstream& operator<<( kndbgstream& stream, const Client* ) { return stream; }
inline
kndbgstream& operator<<( kndbgstream& stream, const ClientList& ) { return stream; }
inline
kndbgstream& operator<<( kndbgstream& stream, const ConstClientList& ) { return stream; }
#else
kdbgstream& operator<<( kdbgstream& stream, const Client* );
kdbgstream& operator<<( kdbgstream& stream, const ClientList& );
kdbgstream& operator<<( kdbgstream& stream, const ConstClientList& );
#endif
KWIN_COMPARE_PREDICATE( WindowMatchPredicate, Window, cl->window() == value );
KWIN_COMPARE_PREDICATE( FrameIdMatchPredicate, Window, cl->frameId() == value );
KWIN_COMPARE_PREDICATE( WrapperIdMatchPredicate, Window, cl->wrapperId() == value );
KWIN_COMPARE_PREDICATE( WindowMatchPredicate, Client, Window, cl->window() == value );
KWIN_COMPARE_PREDICATE( FrameIdMatchPredicate, Client, Window, cl->frameId() == value );
KWIN_COMPARE_PREDICATE( WrapperIdMatchPredicate, Client, Window, cl->wrapperId() == value );
} // namespace

View File

@ -222,6 +222,8 @@ void Workspace::performCompositing()
else if( Unmanaged* c = findUnmanaged( HandleMatchPredicate( children[ i ] )))
windows.append( c );
}
foreach( Toplevel* c, pending_deleted ) // TODO remember stacking order somehow
windows.append( c );
QRegion damage = damage_region;
// clear all damage, so that post-pass can add damage for the next repaint
damage_region = QRegion();
@ -290,12 +292,13 @@ void Toplevel::setupCompositing()
damage_region = QRegion( 0, 0, width(), height());
}
void Toplevel::finishCompositing()
void Toplevel::finishCompositing( bool discard_pixmap )
{
if( damage_handle == None )
return;
XDamageDestroy( display(), damage_handle );
discardWindowPixmap();
if( discard_pixmap )
discardWindowPixmap();
damage_handle = None;
damage_region = QRegion();
}

View File

@ -16,6 +16,7 @@ License. See the file "COPYING" for the exact licensing terms.
#include "effects/dialogparent.h"
#include "effects/fadein.h"
#include "effects/fadeout.h"
#include "effects/howto.h"
#include "effects/maketransparent.h"
#include "effects/presentwindows.h"
@ -46,6 +47,10 @@ void Effect::windowAdded( Toplevel* )
{
}
void Effect::windowClosed( Toplevel* )
{
}
void Effect::windowDeleted( Toplevel* )
{
}
@ -115,6 +120,7 @@ EffectsHandler::EffectsHandler( Workspace* ws )
// effects.append( new ShakyMoveEffect );
// effects.append( new ShiftWorkspaceUpEffect( ws ));
// effects.append( new FadeInEffect );
effects.append( new FadeOutEffect );
// effects.append( new ScaleInEffect );
// effects.append( new DialogParentEffect );
@ -147,6 +153,12 @@ void EffectsHandler::windowDeleted( Toplevel* c )
e->windowDeleted( c );
}
void EffectsHandler::windowClosed( Toplevel* c )
{
foreach( Effect* e, effects )
e->windowClosed( c );
}
void EffectsHandler::windowActivated( Toplevel* c )
{
foreach( Effect* e, effects )

View File

@ -74,6 +74,7 @@ class Effect
virtual void windowUserMovedResized( Toplevel* c, bool first, bool last );
virtual void windowAdded( Toplevel* c );
virtual void windowDeleted( Toplevel* c );
virtual void windowClosed( Toplevel* c );
virtual void windowActivated( Toplevel* c );
virtual void windowMinimized( Toplevel* c );
virtual void windowUnminimized( Toplevel* c );
@ -110,6 +111,7 @@ class EffectsHandler
void startPaint();
void windowUserMovedResized( Toplevel* c, bool first, bool last );
void windowAdded( Toplevel* c );
void windowClosed( Toplevel* c );
void windowDeleted( Toplevel* c );
void windowActivated( Toplevel* c );
void windowMinimized( Toplevel* c );

69
effects/fadeout.cpp Normal file
View File

@ -0,0 +1,69 @@
/*****************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>
You can Freely distribute this program under the GNU General Public
License. See the file "COPYING" for the exact licensing terms.
******************************************************************/
#include "fadeout.h"
#include <client.h>
namespace KWinInternal
{
void FadeOutEffect::prePaintWindow( Scene::Window* w, int* mask, QRegion* region, int time )
{
if( windows.contains( w->window()))
{
windows[ w->window() ] -= time / 1000.; // complete change in 1000ms
if( windows[ w->window() ] > 0 )
{
*mask |= Scene::PAINT_WINDOW_TRANSLUCENT;
*mask &= ~( Scene::PAINT_WINDOW_OPAQUE | Scene::PAINT_WINDOW_DISABLED );
}
else
{
windows.remove( w->window());
w->window()->unrefWindow();
}
}
effects->prePaintWindow( w, mask, region, time );
}
void FadeOutEffect::paintWindow( Scene::Window* w, int mask, QRegion region, WindowPaintData& data )
{
if( windows.contains( w->window()))
{
data.opacity *= windows[ w->window()];
}
effects->paintWindow( w, mask, region, data );
}
void FadeOutEffect::postPaintWindow( Scene::Window* w )
{
if( windows.contains( w->window()))
w->window()->addDamageFull(); // trigger next animation repaint
effects->postPaintWindow( w );
}
void FadeOutEffect::windowClosed( Toplevel* c )
{
Client* cc = dynamic_cast< Client* >( c );
if( cc == NULL || cc->isOnCurrentDesktop())
{
windows[ c ] = 1; // count down to 0
c->addDamageFull();
c->refWindow();
}
}
void FadeOutEffect::windowDeleted( Toplevel* c )
{
windows.remove( c );
}
} // namespace

37
effects/fadeout.h Normal file
View File

@ -0,0 +1,37 @@
/*****************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>
You can Freely distribute this program under the GNU General Public
License. See the file "COPYING" for the exact licensing terms.
******************************************************************/
// TODO MIT or some other licence, perhaps move to some lib
#ifndef KWIN_FADEOUT_H
#define KWIN_FADEOUT_H
#include <effects.h>
namespace KWinInternal
{
class FadeOutEffect
: public Effect
{
public:
virtual void prePaintWindow( Scene::Window* w, int* mask, QRegion* region, int time );
virtual void paintWindow( Scene::Window* w, int mask, QRegion region, WindowPaintData& data );
virtual void postPaintWindow( Scene::Window* w );
// TODO react also on virtual desktop changes
virtual void windowClosed( Toplevel* c );
virtual void windowDeleted( Toplevel* c );
private:
QMap< const Toplevel*, double > windows;
};
} // namespace
#endif

View File

@ -290,6 +290,8 @@ QRegion Scene::Window::shape() const
bool Scene::Window::isVisible() const
{
if( toplevel->deleting())
return false;
if( Client* c = dynamic_cast< Client* >( toplevel ))
return c->isShown( true ) && c->isOnCurrentDesktop();
return true; // Unmanaged is always visible

View File

@ -15,6 +15,7 @@ namespace KWinInternal
Toplevel::Toplevel( Workspace* ws )
: vis( None )
, delete_refcount( -1 )
, id( None )
, wspace( ws )
, window_pix( None )

View File

@ -59,12 +59,18 @@ class Toplevel
int depth() const;
bool hasAlpha() const;
void setupCompositing();
void finishCompositing();
void finishCompositing( bool discard_pixmap = true );
void addDamage( const QRect& r );
void addDamage( int x, int y, int w, int h );
void addDamageFull();
QRegion damage() const;
void resetDamage( const QRect& r );
// used by effects to keep the window around for e.g. fadeout effects when it's destroyed
void refWindow();
virtual void unrefWindow() = 0;
bool deleting() const;
protected:
virtual ~Toplevel();
void setHandle( Window id );
@ -75,6 +81,7 @@ class Toplevel
QRect geom;
Visual* vis;
int bit_depth;
int delete_refcount;
virtual void debug( kdbgstream& stream ) const = 0;
friend kdbgstream& operator<<( kdbgstream& stream, const Toplevel* );
private:
@ -219,6 +226,17 @@ inline bool Toplevel::hasAlpha() const
return depth() == 32;
}
inline void Toplevel::refWindow()
{
assert( delete_refcount >= 0 );
++delete_refcount;
}
inline bool Toplevel::deleting() const
{
return delete_refcount >= 0;
}
#ifdef NDEBUG
inline
kndbgstream& operator<<( kndbgstream& stream, const Toplevel* ) { return stream; }

View File

@ -70,10 +70,26 @@ bool Unmanaged::track( Window w )
void Unmanaged::release()
{
workspace()->addDamage( geometry());
finishCompositing();
assert( !deleting());
delete_refcount = 1;
if( effects )
effects->windowClosed( this );
finishCompositing( false ); // don't discard pixmap
workspace()->removeUnmanaged( this, Allowed );
delete this;
if( Extensions::shapeAvailable())
XShapeSelectInput( display(), handle(), NoEventMask );
XSelectInput( display(), handle(), NoEventMask );
unrefWindow(); // will delete if recount is == 0
}
void Unmanaged::unrefWindow()
{
if( --delete_refcount > 0 )
return;
discardWindowPixmap();
workspace()->removeDeleted( this );
workspace()->addDamage( geometry());
deleteUnmanaged( this, Allowed );
}
void Unmanaged::deleteUnmanaged( Unmanaged* c, allowed_t )

View File

@ -30,6 +30,7 @@ class Unmanaged
virtual NET::WindowType windowType( bool direct = false, int supported_types = SUPPORTED_WINDOW_TYPES_MASK ) const;
static void deleteUnmanaged( Unmanaged* c, allowed_t );
virtual double opacity() const;
virtual void unrefWindow();
protected:
virtual void debug( kdbgstream& stream ) const;
private:

View File

@ -583,10 +583,6 @@ void Workspace::removeClient( Client* c, allowed_t )
Notify::raise( Notify::Delete );
Q_ASSERT( clients.contains( c ) || desktops.contains( c ));
if( scene )
scene->windowDeleted( c );
if( effects )
effects->windowDeleted( c );
clients.removeAll( c );
desktops.removeAll( c );
unconstrained_stacking_order.removeAll( c );
@ -620,16 +616,31 @@ void Workspace::removeClient( Client* c, allowed_t )
tab_box->repaint();
updateClientArea();
addDeleted( c, Allowed );
}
void Workspace::removeUnmanaged( Unmanaged* c, allowed_t )
{
assert( unmanaged.contains( c ));
unmanaged.removeAll( c );
addDeleted( c, Allowed );
}
void Workspace::addDeleted( Toplevel* c, allowed_t )
{
assert( !pending_deleted.contains( c ));
pending_deleted.append( c );
}
void Workspace::removeDeleted( Toplevel* c )
{
assert( pending_deleted.contains( c ));
if( scene )
scene->windowDeleted( c );
if( effects )
effects->windowDeleted( c );
unmanaged.removeAll( c );
pending_deleted.removeAll( c );
}
void Workspace::updateFocusChains( Client* c, FocusChainChange change )

View File

@ -18,6 +18,8 @@ License. See the file "COPYING" for the exact licensing terms.
#include <QCursor>
#include <netwm.h>
#include <kxmessages.h>
#include <qdatetime.h>
#include <kmanagerselection.h>
#include "utils.h"
#include "kdecoration.h"
@ -77,7 +79,7 @@ class Workspace : public QObject, public KDecorationDefines
virtual ~Workspace();
static Workspace * self() { return _self; }
bool workspaceEvent( XEvent * );
KDecoration* createDecoration( KDecorationBridge* bridge );
@ -87,6 +89,9 @@ class Workspace : public QObject, public KDecorationDefines
template< typename T > Client* findClient( T predicate );
template< typename T1, typename T2 > void forEachClient( T1 procedure, T2 predicate );
template< typename T > void forEachClient( T procedure );
template< typename T > Unmanaged* findUnmanaged( T predicate );
template< typename T1, typename T2 > void forEachUnmanaged( T1 procedure, T2 predicate );
template< typename T > void forEachUnmanaged( T procedure );
QRect clientArea( clientAreaOption, const QPoint& p, int desktop ) const;
QRect clientArea( clientAreaOption, const Client* c ) const;
@ -181,7 +186,7 @@ class Workspace : public QObject, public KDecorationDefines
ClientList ensureStackingOrder( const ClientList& clients ) const;
Client* topClientOnDesktop( int desktop, bool unconstrained = false, bool only_normal = true ) const;
Client* topClientOnDesktop( int desktop, bool unconstrained = false ) const;
Client* findDesktop( bool topmost, int desktop ) const;
void sendClientToDesktop( Client* c, int desktop, bool dont_activate );
void windowToPreviousDesktop( Client* c );
@ -234,14 +239,17 @@ class Workspace : public QObject, public KDecorationDefines
void sendPingToWindow( Window w, Time timestamp ); // called from Client::pingWindow()
void sendTakeActivity( Client* c, Time timestamp, long flags ); // called from Client::takeActivity()
// only called from Client::destroyClient() or Client::releaseWindow()
void removeClient( Client*, allowed_t );
void removeClient( Client*, allowed_t ); // only called from Client::destroyClient() or Client::releaseWindow()
void setActiveClient( Client*, allowed_t );
Group* findGroup( Window leader ) const;
void addGroup( Group* group, allowed_t );
void removeGroup( Group* group, allowed_t );
Group* findClientLeaderGroup( const Client* c ) const;
void removeUnmanaged( Unmanaged*, allowed_t ); // only called from Unmanaged::release()
void removeDeleted( Toplevel* );
void addDeleted( Toplevel*, allowed_t );
bool checkStartupNotification( Window w, KStartupInfoId& id, KStartupInfoData& data );
void focusToNull(); // SELI public?
@ -276,6 +284,17 @@ class Workspace : public QObject, public KDecorationDefines
void requestDelayFocus( Client* );
void toggleTopDockShadows(bool on);
void addDamage( const QRect& r );
void addDamage( int x, int y, int w, int h );
void addDamageFull();
// creates XComposite overlay window, cal initOverlay() afterwards
bool createOverlay();
// init overlay and the destination window in it
void setupOverlay( Window window );
// destroys XComposite overlay window
void destroyOverlay();
Window overlayWindow();
public slots:
void refresh();
@ -406,12 +425,10 @@ class Workspace : public QObject, public KDecorationDefines
void cleanupTemporaryRules();
void writeWindowRules();
void slotBlockShortcuts(int data);
void slotReloadConfig();
// kompmgr
void setPopupClientOpacity(int v);
void resetClientOpacity();
void setTransButtonText(int value);
// end
void setPopupClientOpacity( QAction* action );
void setupCompositing();
void performCompositing();
void lostCMSelection();
protected:
bool keyPressMouseEmulation( XKeyEvent& ev );
@ -459,6 +476,8 @@ class Workspace : public QObject, public KDecorationDefines
// this is the right way to create a new client
Client* createClient( Window w, bool is_mapped );
void addClient( Client* c, allowed_t );
Unmanaged* createUnmanaged( Window w );
void addUnmanaged( Unmanaged* c, allowed_t );
Window findSpecialEventWindow( XEvent* e );
@ -500,6 +519,8 @@ class Workspace : public QObject, public KDecorationDefines
void closeActivePopup();
void updateClientArea( bool force );
void finishCompositing();
SystemTrayWindowList systemTrayWins;
@ -536,10 +557,12 @@ class Workspace : public QObject, public KDecorationDefines
ClientList clients;
ClientList desktops;
UnmanagedList unmanaged;
ToplevelList pending_deleted;
ClientList unconstrained_stacking_order; // topmost last
ClientList stacking_order; // topmost last
QVector< ClientList > focus_chain; // currently ative last
ClientList unconstrained_stacking_order;
ClientList stacking_order;
QVector< ClientList > focus_chain;
ClientList global_focus_chain; // this one is only for things like tabbox's MRU
ClientList should_get_focus; // last is most recent
ClientList attention_chain;
@ -573,6 +596,7 @@ class Workspace : public QObject, public KDecorationDefines
QMenu *popup;
QMenu *advanced_popup;
QMenu *trans_popup;
QMenu *desk_popup;
int desk_popup_index;
@ -656,12 +680,14 @@ class Workspace : public QObject, public KDecorationDefines
bool forced_global_mouse_grab;
friend class StackingUpdatesBlocker;
//kompmgr
KSelectionOwner* cm_selection;
QTimer compositeTimer;
QTime lastCompositePaint;
int compositeRate;
QRegion damage_region;
Window overlay; // XComposite overlay window
QSlider *transSlider;
QPushButton *transButton;
private:
friend bool performTransiencyCheck();
};
// helper for Workspace::blockStackingUpdates() being called in pairs (true/false)
@ -804,6 +830,11 @@ inline bool Workspace::globalShortcutsDisabled() const
return global_shortcuts_disabled || global_shortcuts_disabled_for_client;
}
inline Window Workspace::overlayWindow()
{
return overlay;
}
template< typename T >
inline Client* Workspace::findClient( T predicate )
{
@ -831,7 +862,27 @@ inline void Workspace::forEachClient( T procedure )
return forEachClient( procedure, TruePredicate());
}
KWIN_COMPARE_PREDICATE( ClientMatchPredicate, const Client*, cl == value );
template< typename T >
inline Unmanaged* Workspace::findUnmanaged( T predicate )
{
return findUnmanagedInList( unmanaged, predicate );
}
template< typename T1, typename T2 >
inline void Workspace::forEachUnmanaged( T1 procedure, T2 predicate )
{
for ( UnmanagedList::ConstIterator it = unmanaged.begin(); it != unmanaged.end(); ++it)
if ( predicate( const_cast< const Unmanaged* >( *it)))
procedure( *it );
}
template< typename T >
inline void Workspace::forEachUnmanaged( T procedure )
{
return forEachUnmanaged( procedure, TruePredicate());
}
KWIN_COMPARE_PREDICATE( ClientMatchPredicate, Client, const Client*, cl == value );
inline bool Workspace::hasClient( const Client* c )
{
return findClient( ClientMatchPredicate( c ));