1 /********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
5 Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *********************************************************************/
22 Code related to compositing (redirecting windows to pixmaps and tracking
27 XComposite (the protocol, but the function calls map to it):
28 http://gitweb.freedesktop.org/?p=xorg/proto/compositeproto.git;a=blob_plain;hb=HEAD;f=compositeproto.txt
30 XDamage (again the protocol):
31 http://gitweb.freedesktop.org/?p=xorg/proto/damageproto.git;a=blob_plain;hb=HEAD;f=damageproto.txt
33 Paper including basics on compositing, XGL vs AIGLX, XRender vs OpenGL, etc.:
34 http://www.vis.uni-stuttgart.de/~hopf/pub/LinuxTag2007_compiz_NextGenerationDesktop_Paper.pdf
36 Composite HOWTO from Fredrik:
37 http://ktown.kde.org/~fredrik/composite_howto.html
41 #include <config-X11.h>
44 #include <QTextStream>
45 #include "workspace.h"
47 #include "unmanaged.h"
51 #include "scene_basic.h"
52 #include "scene_xrender.h"
53 #include "scene_opengl.h"
54 #include "compositingprefs.h"
55 #include "notifications.h"
61 #include <kactioncollection.h>
63 #include <kxerrorhandler.h>
65 #include <X11/extensions/shape.h>
67 #ifdef HAVE_XCOMPOSITE
68 #include <X11/extensions/Xcomposite.h>
69 #if XCOMPOSITE_MAJOR > 0 || XCOMPOSITE_MINOR >= 3
70 #define HAVE_XCOMPOSITE_OVERLAY
74 #include <X11/extensions/Xrandr.h>
80 //****************************************
82 //****************************************
84 void Workspace::setupCompositing()
86 #ifdef KWIN_HAVE_COMPOSITING
89 if( !options
->useCompositing
&& getenv( "KWIN_COMPOSE") == NULL
)
91 kDebug( 1212 ) << "Compositing is turned off in options or disabled";
94 else if( compositingSuspended
)
96 kDebug( 1212 ) << "Compositing is suspended";
99 else if( !CompositingPrefs::compositingPossible() )
101 kError( 1212 ) << "Compositing is not possible";
104 CompositingType type
= options
->compositingMode
;
105 if( getenv( "KWIN_COMPOSE" ))
107 char c
= getenv( "KWIN_COMPOSE" )[ 0 ];
111 type
= OpenGLCompositing
;
114 type
= XRenderCompositing
;
117 kDebug( 1212 ) << "No compositing";
122 char selection_name
[ 100 ];
123 sprintf( selection_name
, "_NET_WM_CM_S%d", DefaultScreen( display()));
124 cm_selection
= new KSelectionOwner( selection_name
);
125 connect( cm_selection
, SIGNAL( lostOwnership()), SLOT( lostCMSelection()));
126 cm_selection
->claim( true ); // force claiming
131 kDebug( 1212 ) << "X compositing";
132 scene = new SceneBasic( this );
133 break; // don't fall through (this is a testing one) */
134 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
135 case OpenGLCompositing
:
136 kDebug( 1212 ) << "OpenGL compositing";
137 scene
= new SceneOpenGL( this );
138 if( !scene
->initFailed())
142 break; // do not fall back to XRender for now, maybe in the future
144 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
145 case XRenderCompositing
:
146 kDebug( 1212 ) << "XRender compositing";
147 scene
= new SceneXrender( this );
151 #ifndef KWIN_HAVE_COMPOSITING
152 kDebug( 1212 ) << "Compositing was not available at compile time";
154 kDebug( 1212 ) << "No compositing";
159 if( scene
== NULL
|| scene
->initFailed())
161 kError( 1212 ) << "Failed to initialize compositing, compositing disabled";
162 kError( 1212 ) << "Consult http://techbase.kde.org/Projects/KWin/4.0-release-notes#Setting_up";
169 if( options
->refreshRate
> 0 )
170 { // use manually configured refresh rate
171 rate
= options
->refreshRate
;
175 { // autoconfigure refresh rate based on XRandR info
176 if( Extensions::randrAvailable() )
178 XRRScreenConfiguration
*config
;
180 config
= XRRGetScreenInfo( display(), rootWindow() );
181 rate
= XRRConfigCurrentRate( config
);
182 XRRFreeScreenConfigInfo( config
);
186 // 0Hz or less is invalid, so we fallback to a default rate
189 // QTimer gives us 1msec (1000Hz) at best, so we ignore anything higher;
190 // however, additional throttling prevents very high rates from taking place anyway
191 else if( rate
> 1000 )
193 kDebug( 1212 ) << "Refresh rate " << rate
<< "Hz";
194 compositeRate
= 1000 / rate
;
195 lastCompositePaint
.start();
196 // fake a previous paint, so that the next starts right now
197 nextPaintReference
= QTime::currentTime().addMSecs( -compositeRate
);
198 compositeTimer
.setSingleShot( true );
199 checkCompositeTimer();
200 composite_paint_times
.clear();
201 XCompositeRedirectSubwindows( display(), rootWindow(), CompositeRedirectManual
);
202 new EffectsHandlerImpl( scene
->compositingType() ); // sets also the 'effects' pointer
204 foreach( Client
* c
, clients
)
205 c
->setupCompositing();
206 foreach( Client
* c
, desktops
)
207 c
->setupCompositing();
208 foreach( Unmanaged
* c
, unmanaged
)
209 c
->setupCompositing();
210 foreach( Client
* c
, clients
)
211 scene
->windowAdded( c
);
212 foreach( Client
* c
, desktops
)
213 scene
->windowAdded( c
);
214 foreach( Unmanaged
* c
, unmanaged
)
215 scene
->windowAdded( c
);
216 discardPopup(); // force re-creation of the Alt+F3 popup (opacity option)
218 kDebug( 1212 ) << "Compositing was not available at compile time";
222 void Workspace::finishCompositing()
224 #ifdef KWIN_HAVE_COMPOSITING
228 foreach( Client
* c
, clients
)
229 scene
->windowClosed( c
, NULL
);
230 foreach( Client
* c
, desktops
)
231 scene
->windowClosed( c
, NULL
);
232 foreach( Unmanaged
* c
, unmanaged
)
233 scene
->windowClosed( c
, NULL
);
234 foreach( Deleted
* c
, deleted
)
235 scene
->windowDeleted( c
);
236 foreach( Client
* c
, clients
)
237 c
->finishCompositing();
238 foreach( Client
* c
, desktops
)
239 c
->finishCompositing();
240 foreach( Unmanaged
* c
, unmanaged
)
241 c
->finishCompositing();
242 foreach( Deleted
* c
, deleted
)
243 c
->finishCompositing();
244 XCompositeUnredirectSubwindows( display(), rootWindow(), CompositeRedirectManual
);
249 compositeTimer
.stop();
250 repaints_region
= QRegion();
251 for( ClientList::ConstIterator it
= clients
.constBegin();
252 it
!= clients
.constEnd();
254 { // forward all opacity values to the frame in case there'll be other CM running
255 if( (*it
)->opacity() != 1.0 )
257 NETWinInfo2
i( display(), (*it
)->frameId(), rootWindow(), 0 );
258 i
.setOpacity( static_cast< unsigned long >((*it
)->opacity() * 0xffffffff ));
261 discardPopup(); // force re-creation of the Alt+F3 popup (opacity option)
262 // discard all Deleted windows (#152914)
263 while( !deleted
.isEmpty())
264 deleted
.first()->discard( Allowed
);
268 void Workspace::lostCMSelection()
270 kDebug( 1212 ) << "Lost compositing manager selection";
275 void Workspace::slotToggleCompositing()
277 suspendCompositing( !compositingSuspended
);
280 void Workspace::suspendCompositing()
282 suspendCompositing( true );
285 void Workspace::suspendCompositing( bool suspend
)
287 compositingSuspended
= suspend
;
289 setupCompositing(); // will do nothing if suspended
292 void Workspace::addRepaint( int x
, int y
, int w
, int h
)
296 repaints_region
+= QRegion( x
, y
, w
, h
);
297 checkCompositeTimer();
300 void Workspace::addRepaint( const QRect
& r
)
304 repaints_region
+= r
;
305 checkCompositeTimer();
308 void Workspace::addRepaint( const QRegion
& r
)
312 repaints_region
+= r
;
313 checkCompositeTimer();
316 void Workspace::addRepaintFull()
320 repaints_region
= QRegion( 0, 0, displayWidth(), displayHeight());
321 checkCompositeTimer();
324 void Workspace::performCompositing()
326 #ifdef KWIN_HAVE_COMPOSITING
327 // The event loop apparently tries to fire a QTimer as often as possible, even
328 // at the expense of not processing many X events. This means that the composite
329 // repaints can seriously impact performance of everything else, therefore throttle
330 // them - leave at least 1msec time after one repaint is finished and next one
332 if( lastCompositePaint
.elapsed() < 1 )
334 compositeTimer
.start( 1 );
337 if( !scene
->waitSyncAvailable())
338 nextPaintReference
= QTime::currentTime();
340 if((( repaints_region
.isEmpty() && !windowRepaintsPending()) // no damage
341 || !overlay_visible
) // nothing is visible anyway
342 // HACK: don't idle during active full screen effect so that mouse events are not dropped (bug #177226)
343 && !static_cast< EffectsHandlerImpl
* >( effects
)->activeFullScreenEffect() )
346 // Note: It would seem here we should undo suspended unredirect, but when scenes need
347 // it for some reason, e.g. transformations or translucency, the next pass that does not
348 // need this anymore and paints normally will also reset the suspended unredirect.
349 // Otherwise the window would not be painted normally anyway.
352 // create a list of all windows in the stacking order
353 ToplevelList windows
= xStackingOrder();
354 foreach( EffectWindow
* c
, static_cast< EffectsHandlerImpl
* >( effects
)->elevatedWindows())
356 Toplevel
* t
= static_cast< EffectWindowImpl
* >( c
)->window();
357 windows
.removeAll( t
);
360 // skip windows that are not yet ready for being painted
361 ToplevelList tmp
= windows
;
364 // There is a bug somewhere that prevents this from working properly (#160393), but additionally
365 // this cannot be used so carelessly - needs protections against broken clients, the window
366 // should not get focus before it's displayed, handle unredirected windows properly and so on.
367 foreach( Toplevel
* c
, tmp
)
368 if( c
->readyForPainting())
371 foreach( Toplevel
* c
, tmp
)
374 foreach( Toplevel
* c
, windows
)
375 { // This could be possibly optimized WRT obscuring, but that'd need being already
376 // past prePaint() phase - probably not worth it.
377 // TODO I think effects->transformWindowDamage() doesn't need to be called here,
378 // pre-paint will extend painted window areas as necessary.
379 repaints_region
|= c
->repaints().translated( c
->pos());
380 c
->resetRepaints( c
->rect());
382 QRegion repaints
= repaints_region
;
383 // clear all repaints, so that post-pass can add repaints for the next repaint
384 repaints_region
= QRegion();
385 QTime t
= QTime::currentTime();
386 scene
->paint( repaints
, windows
);
387 if( scene
->waitSyncAvailable())
389 // If vsync is used, schedule the next repaint slightly in advance of the next sync,
390 // so that there is still time for the drawing to take place. We have just synced, and
391 // nextPaintReference is time from which multiples of compositeRate should be added,
392 // so set it 10ms back (meaning next paint will be in 'compositeRate - 10').
393 // However, make sure the reserve is smaller than the composite rate.
394 int reserve
= compositeRate
<= 10 ? compositeRate
- 1 : 10;
395 nextPaintReference
= QTime::currentTime().addMSecs( -reserve
);
397 // Trigger at least one more pass even if there would be nothing to paint, so that scene->idle()
398 // is called the next time. If there would be nothing pending, it will not restart the timer and
399 // checkCompositeTime() would restart it again somewhen later, called from functions that
400 // would again add something pending.
401 checkCompositeTimer();
402 checkCompositePaintTime( t
.elapsed());
403 lastCompositePaint
.start();
407 bool Workspace::windowRepaintsPending() const
409 foreach( Toplevel
* c
, clients
)
410 if( !c
->repaints().isEmpty())
412 foreach( Toplevel
* c
, desktops
)
413 if( !c
->repaints().isEmpty())
415 foreach( Toplevel
* c
, unmanaged
)
416 if( !c
->repaints().isEmpty())
418 foreach( Toplevel
* c
, deleted
)
419 if( !c
->repaints().isEmpty())
424 void Workspace::setCompositeTimer()
426 if( !compositing()) // should not really happen, but there may be e.g. some damage events still pending
428 // The last paint set nextPaintReference as a reference time to which multiples of compositeRate
429 // should be added for the next paint. qBound() for protection; system time can change without notice.
430 compositeTimer
.start( qBound( 0, nextPaintReference
.msecsTo( QTime::currentTime() ), 250 ) % compositeRate
);
433 bool Workspace::createOverlay()
435 assert( overlay
== None
);
436 if( !Extensions::compositeOverlayAvailable())
438 if( !Extensions::shapeInputAvailable()) // needed in setupOverlay()
440 #ifdef HAVE_XCOMPOSITE_OVERLAY
441 overlay
= XCompositeGetOverlayWindow( display(), rootWindow());
442 if( overlay
== None
)
450 void Workspace::checkCompositePaintTime( int msec
)
452 if( options
->disableCompositingChecks
)
454 composite_paint_times
.prepend( msec
);
455 bool tooslow
= false;
456 // If last 3 paints were way too slow, disable and warn.
457 // 1 second seems reasonable, it's not that difficult to get relatively high times
458 // with high system load.
459 const int MAX_LONG_PAINT
= 1000;
460 if( composite_paint_times
.count() >= 3 && composite_paint_times
[ 0 ] > MAX_LONG_PAINT
461 && composite_paint_times
[ 1 ] > MAX_LONG_PAINT
&& composite_paint_times
[ 2 ] > MAX_LONG_PAINT
)
463 kDebug( 1212 ) << "Too long paint times, suspending";
466 // If last 15 seconds all paints (all of them) were quite slow, disable and warn too. Quite slow being 0,1s
467 // should be reasonable, that's 10fps and having constant 10fps is bad.
468 // This may possibly trigger also when activating an expensive effect, so this may need tweaking.
469 const int MAX_SHORT_PAINT
= 100;
470 const int SHORT_TIME
= 15000; // 15 sec
472 foreach( int t
, composite_paint_times
)
474 if( t
< MAX_SHORT_PAINT
)
477 if( time
> SHORT_TIME
) // all paints in the given time were long
479 kDebug( 1212 ) << "Long paint times for long time, suspending";
484 if( composite_paint_times
.count() > 1000 )
485 composite_paint_times
.removeLast();
488 QTimer::singleShot( 0, this, SLOT( suspendCompositing()));
489 QString shortcut
, message
;
490 if( KAction
* action
= qobject_cast
<KAction
*>( keys
->action("Suspend Compositing")))
491 shortcut
= action
->globalShortcut().primary().toString(QKeySequence::NativeText
);
492 if (shortcut
.isEmpty())
493 message
= i18n( "Compositing was too slow and has been suspended.\n"
494 "You can disable functionality checks in advanced compositing settings." );
496 message
= i18n( "Compositing was too slow and has been suspended.\n"
497 "If this was only a temporary problem, you can resume using the '%1' shortcut.\n"
498 "You can also disable functionality checks in advanced compositing settings.", shortcut
);
499 Notify::raise( Notify::CompositingSlow
, message
);
500 compositeTimer
.start( 1000 ); // so that it doesn't trigger sooner than suspendCompositing()
504 void Workspace::setupOverlay( Window w
)
506 assert( overlay
!= None
);
507 assert( Extensions::shapeInputAvailable());
508 XSetWindowBackgroundPixmap( display(), overlay
, None
);
509 overlay_shape
= QRegion();
510 setOverlayShape( QRect( 0, 0, displayWidth(), displayHeight()));
513 XSetWindowBackgroundPixmap( display(), w
, None
);
514 XShapeCombineRectangles( display(), w
, ShapeInput
, 0, 0, NULL
, 0, ShapeSet
, Unsorted
);
516 XSelectInput( display(), overlay
, VisibilityChangeMask
);
519 void Workspace::showOverlay()
521 assert( overlay
!= None
);
524 XMapSubwindows( display(), overlay
);
525 XMapWindow( display(), overlay
);
526 overlay_shown
= true;
529 void Workspace::hideOverlay()
531 assert( overlay
!= None
);
532 XUnmapWindow( display(), overlay
);
533 overlay_shown
= false;
534 setOverlayShape( QRect( 0, 0, displayWidth(), displayHeight()));
537 void Workspace::setOverlayShape( const QRegion
& reg
)
539 // Avoid setting the same shape again, it causes flicker (apparently it is not a no-op
540 // and triggers something).
541 if( reg
== overlay_shape
)
543 QVector
< QRect
> rects
= reg
.rects();
544 XRectangle
* xrects
= new XRectangle
[ rects
.count() ];
549 xrects
[ i
].x
= rects
[ i
].x();
550 xrects
[ i
].y
= rects
[ i
].y();
551 xrects
[ i
].width
= rects
[ i
].width();
552 xrects
[ i
].height
= rects
[ i
].height();
554 XShapeCombineRectangles( display(), overlay
, ShapeBounding
, 0, 0,
555 xrects
, rects
.count(), ShapeSet
, Unsorted
);
557 XShapeCombineRectangles( display(), overlay
, ShapeInput
, 0, 0, NULL
, 0, ShapeSet
, Unsorted
);
561 void Workspace::destroyOverlay()
563 if( overlay
== None
)
565 // reset the overlay shape
566 XRectangle rec
= { 0, 0, displayWidth(), displayHeight() };
567 XShapeCombineRectangles( display(), overlay
, ShapeBounding
, 0, 0, &rec
, 1, ShapeSet
, Unsorted
);
568 XShapeCombineRectangles( display(), overlay
, ShapeInput
, 0, 0, &rec
, 1, ShapeSet
, Unsorted
);
569 #ifdef HAVE_XCOMPOSITE_OVERLAY
570 XCompositeReleaseOverlayWindow( display(), overlay
);
573 overlay_shown
= false;
576 bool Workspace::compositingActive()
578 return compositing();
581 // force is needed when the list of windows changes (e.g. a window goes away)
582 void Workspace::checkUnredirect( bool force
)
584 if( !compositing() || overlay
== None
|| !options
->unredirectFullscreen
)
587 forceUnredirectCheck
= true;
588 if( !unredirectTimer
.isActive())
589 unredirectTimer
.start( 0 );
592 void Workspace::delayedCheckUnredirect()
594 if( !compositing() || overlay
== None
|| !options
->unredirectFullscreen
)
597 bool changed
= forceUnredirectCheck
;
598 foreach( Client
* c
, clients
)
600 foreach( Unmanaged
* c
, unmanaged
)
602 foreach( Toplevel
* c
, list
)
604 if( c
->updateUnredirectedState())
607 // no desktops, no Deleted ones
610 forceUnredirectCheck
= false;
611 // Cut out parts from the overlay window where unredirected windows are,
612 // so that they are actually visible.
613 QRegion
reg( 0, 0, displayWidth(), displayHeight());
614 foreach( Toplevel
* c
, list
)
616 if( c
->unredirected())
617 reg
-= c
->geometry();
619 setOverlayShape( reg
);
622 //****************************************
624 //****************************************
626 void Toplevel::setupCompositing()
628 #ifdef KWIN_HAVE_COMPOSITING
631 if( damage_handle
!= None
)
633 damage_handle
= XDamageCreate( display(), frameId(), XDamageReportRawRectangles
);
634 damage_region
= QRegion( 0, 0, width(), height());
635 effect_window
= new EffectWindowImpl();
636 effect_window
->setWindow( this );
638 workspace()->checkUnredirect( true );
642 void Toplevel::finishCompositing()
644 #ifdef KWIN_HAVE_COMPOSITING
645 if( damage_handle
== None
)
647 workspace()->checkUnredirect( true );
648 if( effect_window
->window() == this ) // otherwise it's already passed to Deleted, don't free data
650 discardWindowPixmap();
651 delete effect_window
;
653 XDamageDestroy( display(), damage_handle
);
654 damage_handle
= None
;
655 damage_region
= QRegion();
656 repaints_region
= QRegion();
657 effect_window
= NULL
;
661 void Toplevel::discardWindowPixmap()
664 if( window_pix
== None
)
666 XFreePixmap( display(), window_pix
);
668 if( effectWindow() != NULL
&& effectWindow()->sceneWindow() != NULL
)
669 effectWindow()->sceneWindow()->pixmapDiscarded();
672 Pixmap
Toplevel::createWindowPixmap()
674 #ifdef KWIN_HAVE_COMPOSITING
675 assert( compositing());
680 Pixmap pix
= XCompositeNameWindowPixmap( display(), frameId());
681 // check that the received pixmap is valid and actually matches what we
682 // know about the window (i.e. size)
683 XWindowAttributes attrs
;
684 if( !XGetWindowAttributes( display(), frameId(), &attrs
)
685 || err
.error( false )
686 || attrs
.width
!= width() || attrs
.height
!= height() || attrs
.map_state
!= IsViewable
)
688 kDebug( 1212 ) << "Creating window pixmap failed: " << this;
689 XFreePixmap( display(), pix
);
700 void Toplevel::damageNotifyEvent( XDamageNotifyEvent
* e
)
702 QRegion
damage( e
->area
.x
, e
->area
.y
, e
->area
.width
, e
->area
.height
);
705 while( XPending( display()))
708 if( XPeekEvent( display(), &e2
) && e2
.type
== Extensions::damageNotifyEvent()
709 && e2
.xany
.window
== frameId())
711 XNextEvent( display(), &e2
);
714 // If there are way too many damage events in the queue, just discard them
715 // and damage the whole window. Otherwise the X server can just overload
716 // us with a flood of damage events. Should be probably optimized
717 // in the X server, as this is rather lame.
721 XDamageNotifyEvent
* e
= reinterpret_cast< XDamageNotifyEvent
* >( &e2
);
722 QRect
r( e
->area
.x
, e
->area
.y
, e
->area
.width
, e
->area
.height
);
724 // If there are too many damaged rectangles, increase them
725 // to be multiples of 100x100 px grid, since QRegion get quite
726 // slow with many rectangles, and there is little to gain by using
727 // many small rectangles (rather the opposite, several large should
731 r
.setLeft( r
.left() / 100 * 100 );
732 r
.setRight(( r
.right() + 99 ) / 100 * 100 );
733 r
.setTop( r
.top() / 100 * 100 );
734 r
.setBottom(( r
.bottom() + 99 ) / 100 * 100 );
741 foreach( const QRect
& r
, damage
.rects())
745 void Client::damageNotifyEvent( XDamageNotifyEvent
* e
)
747 Toplevel::damageNotifyEvent( e
);
749 if( sync_counter
== None
) // cannot detect complete redraw, consider done now
750 ready_for_painting
= true;
752 ready_for_painting
= true; // no sync at all, consider done now
757 void Toplevel::addDamage( const QRect
& r
)
759 addDamage( r
.x(), r
.y(), r
.width(), r
.height());
762 void Toplevel::addDamage( int x
, int y
, int w
, int h
)
766 QRect
r( x
, y
, w
, h
);
767 // resizing the decoration may lag behind a bit and when shrinking there
768 // may be a damage event coming with size larger than the current window size
771 repaints_region
+= r
;
772 static_cast<EffectsHandlerImpl
*>(effects
)->windowDamaged( effectWindow(), r
);
773 workspace()->checkCompositeTimer();
776 void Toplevel::addDamageFull()
780 damage_region
= rect();
781 repaints_region
= rect();
782 static_cast<EffectsHandlerImpl
*>(effects
)->windowDamaged( effectWindow(), rect());
783 workspace()->checkCompositeTimer();
786 void Toplevel::resetDamage( const QRect
& r
)
791 void Toplevel::addRepaint( const QRect
& r
)
793 addRepaint( r
.x(), r
.y(), r
.width(), r
.height());
796 void Toplevel::addRepaint( int x
, int y
, int w
, int h
)
800 QRect
r( x
, y
, w
, h
);
802 repaints_region
+= r
;
803 workspace()->checkCompositeTimer();
806 void Toplevel::addRepaintFull()
808 repaints_region
= rect();
809 workspace()->checkCompositeTimer();
812 void Toplevel::resetRepaints( const QRect
& r
)
814 repaints_region
-= r
;
817 void Toplevel::addWorkspaceRepaint( int x
, int y
, int w
, int h
)
819 addWorkspaceRepaint( QRect( x
, y
, w
, h
));
822 void Toplevel::addWorkspaceRepaint( const QRect
& r2
)
826 if( effectWindow() == NULL
) // TODO - this can happen during window destruction
827 return workspace()->addRepaint( r2
);
828 QRect r
= effects
->transformWindowDamage( effectWindow(), r2
);
829 workspace()->addRepaint( r
);
832 bool Toplevel::updateUnredirectedState()
834 assert( compositing());
835 bool should
= shouldUnredirect() && !unredirectSuspend
&& !shape() && !hasAlpha() && opacity() == 1.0 &&
836 !static_cast<EffectsHandlerImpl
*>( effects
)->activeFullScreenEffect();
837 if( should
&& !unredirect
)
840 kDebug( 1212 ) << "Unredirecting:" << this;
841 #ifdef HAVE_XCOMPOSITE
842 XCompositeUnredirectWindow( display(), frameId(), CompositeRedirectManual
);
846 else if( !should
&& unredirect
)
849 kDebug( 1212 ) << "Redirecting:" << this;
850 #ifdef HAVE_XCOMPOSITE
851 XCompositeRedirectWindow( display(), frameId(), CompositeRedirectManual
);
853 discardWindowPixmap();
859 void Toplevel::suspendUnredirect( bool suspend
)
861 if( unredirectSuspend
== suspend
)
863 unredirectSuspend
= suspend
;
864 workspace()->checkUnredirect();
867 //****************************************
869 //****************************************
871 void Client::setupCompositing()
873 Toplevel::setupCompositing();
874 updateVisibility(); // for internalKeep()
877 void Client::finishCompositing()
879 Toplevel::finishCompositing();
883 bool Client::shouldUnredirect() const
885 if( isActiveFullScreen())
887 ToplevelList stacking
= workspace()->xStackingOrder();
888 for( int pos
= stacking
.count() - 1;
892 Toplevel
* c
= stacking
.at( pos
);
893 if( c
== this ) // is not covered by any other window, ok to unredirect
895 if( c
->geometry().intersects( geometry()))
903 //****************************************
905 //****************************************
907 bool Unmanaged::shouldUnredirect() const
909 // the pixmap is needed for the login effect, a nicer solution would be the login effect increasing
910 // refcount for the window pixmap (which would prevent unredirect), avoiding this hack
911 if( resourceClass() == "ksplashx" || resourceClass() == "ksplashsimple" )
913 // it must cover whole display or one xinerama screen, and be the topmost there
914 if( geometry() == workspace()->clientArea( FullArea
, geometry().center(), workspace()->currentDesktop())
915 || geometry() == workspace()->clientArea( ScreenArea
, geometry().center(), workspace()->currentDesktop()))
917 ToplevelList stacking
= workspace()->xStackingOrder();
918 for( int pos
= stacking
.count() - 1;
922 Toplevel
* c
= stacking
.at( pos
);
923 if( c
== this ) // is not covered by any other window, ok to unredirect
925 if( c
->geometry().intersects( geometry()))
933 //****************************************
935 //****************************************
937 bool Deleted::shouldUnredirect() const