00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #include <config-X11.h>
00042
00043 #include "utils.h"
00044 #include <QTextStream>
00045 #include "workspace.h"
00046 #include "client.h"
00047 #include "unmanaged.h"
00048 #include "deleted.h"
00049 #include "effects.h"
00050 #include "scene.h"
00051 #include "scene_basic.h"
00052 #include "scene_xrender.h"
00053 #include "scene_opengl.h"
00054 #include "compositingprefs.h"
00055
00056 #include <stdio.h>
00057
00058 #include <QMenu>
00059 #include <kxerrorhandler.h>
00060
00061 #include <X11/extensions/shape.h>
00062
00063 #ifdef HAVE_XCOMPOSITE
00064 #include <X11/extensions/Xcomposite.h>
00065 #if XCOMPOSITE_MAJOR > 0 || XCOMPOSITE_MINOR >= 3
00066 #define HAVE_XCOMPOSITE_OVERLAY
00067 #endif
00068 #endif
00069 #ifdef HAVE_XRANDR
00070 #include <X11/extensions/Xrandr.h>
00071 #endif
00072
00073 namespace KWin
00074 {
00075
00076
00077
00078
00079
00080 void Workspace::setupCompositing()
00081 {
00082 #ifdef KWIN_HAVE_COMPOSITING
00083 if( scene != NULL )
00084 return;
00085 if( !options->useCompositing && getenv( "KWIN_COMPOSE") == NULL )
00086 {
00087 kDebug( 1212 ) << "Compositing is turned off in options";
00088 return;
00089 }
00090 else if( compositingSuspended )
00091 {
00092 kDebug( 1212 ) << "Compositing is suspended";
00093 return;
00094 }
00095 else if( !CompositingPrefs::compositingPossible() )
00096 {
00097 kError( 1212 ) << "Compositing is not possible";
00098 return;
00099 }
00100 CompositingType type = options->compositingMode;
00101 if( getenv( "KWIN_COMPOSE" ))
00102 {
00103 char c = getenv( "KWIN_COMPOSE" )[ 0 ];
00104 switch( c )
00105 {
00106 case 'O':
00107 type = OpenGLCompositing;
00108 break;
00109 case 'X':
00110 type = XRenderCompositing;
00111 break;
00112 default:
00113 kDebug( 1212 ) << "No compositing";
00114 return;
00115 }
00116 }
00117
00118 char selection_name[ 100 ];
00119 sprintf( selection_name, "_NET_WM_CM_S%d", DefaultScreen( display()));
00120 cm_selection = new KSelectionOwner( selection_name );
00121 connect( cm_selection, SIGNAL( lostOwnership()), SLOT( lostCMSelection()));
00122 cm_selection->claim( true );
00123
00124 switch( type )
00125 {
00126
00127
00128
00129
00130 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00131 case OpenGLCompositing:
00132 kDebug( 1212 ) << "OpenGL compositing";
00133 scene = new SceneOpenGL( this );
00134 if( !scene->initFailed())
00135 break;
00136 delete scene;
00137 scene = NULL;
00138 break;
00139 #endif
00140 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
00141 case XRenderCompositing:
00142 kDebug( 1212 ) << "XRender compositing";
00143 scene = new SceneXrender( this );
00144 break;
00145 #endif
00146 default:
00147 #ifndef KWIN_HAVE_COMPOSITING
00148 kDebug( 1212 ) << "Compositing was not available at compile time";
00149 #else
00150 kDebug( 1212 ) << "No compositing";
00151 #endif
00152 delete cm_selection;
00153 return;
00154 }
00155 if( scene == NULL || scene->initFailed())
00156 {
00157 kError( 1212 ) << "Failed to initialize compositing, compositing disabled";
00158 kError( 1212 ) << "Consult http://techbase.kde.org/Projects/KWin/4.0-release-notes#Setting_up";
00159 delete scene;
00160 scene = NULL;
00161 delete cm_selection;
00162 return;
00163 }
00164 int rate = 0;
00165 if( options->refreshRate > 0 )
00166 {
00167 rate = options->refreshRate;
00168 }
00169 #ifdef HAVE_XRANDR
00170 else
00171 {
00172 if( Extensions::randrAvailable() )
00173 {
00174 XRRScreenConfiguration *config;
00175
00176 config = XRRGetScreenInfo( display(), rootWindow() );
00177 rate = XRRConfigCurrentRate( config );
00178 XRRFreeScreenConfigInfo( config );
00179 }
00180 }
00181 #endif
00182
00183 if( rate <= 0 )
00184 rate = 50;
00185
00186
00187 else if( rate > 1000 )
00188 rate = 1000;
00189 kDebug( 1212 ) << "Refresh rate " << rate << "Hz";
00190 compositeRate = 1000 / rate;
00191 compositeTimer.start( compositeRate );
00192 lastCompositePaint.start();
00193 XCompositeRedirectSubwindows( display(), rootWindow(), CompositeRedirectManual );
00194 new EffectsHandlerImpl( scene->compositingType() );
00195 addRepaintFull();
00196 foreach( Client* c, clients )
00197 c->setupCompositing();
00198 foreach( Client* c, desktops )
00199 c->setupCompositing();
00200 foreach( Unmanaged* c, unmanaged )
00201 c->setupCompositing();
00202 foreach( Client* c, clients )
00203 scene->windowAdded( c );
00204 foreach( Client* c, desktops )
00205 scene->windowAdded( c );
00206 foreach( Unmanaged* c, unmanaged )
00207 scene->windowAdded( c );
00208 delete popup;
00209 popup = NULL;
00210 #else
00211 kDebug( 1212 ) << "Compositing was not available at compile time";
00212 #endif
00213 }
00214
00215 void Workspace::finishCompositing()
00216 {
00217 #ifdef KWIN_HAVE_COMPOSITING
00218 if( scene == NULL )
00219 return;
00220 delete cm_selection;
00221 foreach( Client* c, clients )
00222 scene->windowClosed( c, NULL );
00223 foreach( Client* c, desktops )
00224 scene->windowClosed( c, NULL );
00225 foreach( Unmanaged* c, unmanaged )
00226 scene->windowClosed( c, NULL );
00227 foreach( Deleted* c, deleted )
00228 scene->windowDeleted( c );
00229 foreach( Client* c, clients )
00230 c->finishCompositing();
00231 foreach( Client* c, desktops )
00232 c->finishCompositing();
00233 foreach( Unmanaged* c, unmanaged )
00234 c->finishCompositing();
00235 foreach( Deleted* c, deleted )
00236 c->finishCompositing();
00237 XCompositeUnredirectSubwindows( display(), rootWindow(), CompositeRedirectManual );
00238 compositeTimer.stop();
00239 delete effects;
00240 effects = NULL;
00241 delete scene;
00242 scene = NULL;
00243 repaints_region = QRegion();
00244 for( ClientList::ConstIterator it = clients.begin();
00245 it != clients.end();
00246 ++it )
00247 {
00248 if( (*it)->opacity() != 1.0 )
00249 {
00250 NETWinInfo i( display(), (*it)->frameId(), rootWindow(), 0 );
00251 i.setOpacity( static_cast< unsigned long >((*it)->opacity() * 0xffffffff ));
00252 }
00253 }
00254 delete popup;
00255 popup = NULL;
00256
00257 while( !deleted.isEmpty())
00258 deleted.first()->discard( Allowed );
00259 #endif
00260 }
00261
00262 void Workspace::lostCMSelection()
00263 {
00264 kDebug( 1212 ) << "Lost compositing manager selection";
00265 finishCompositing();
00266 }
00267
00268
00269 void Workspace::slotToggleCompositing()
00270 {
00271 compositingSuspended = !compositingSuspended;
00272 finishCompositing();
00273 setupCompositing();
00274 }
00275
00276 void Workspace::addRepaint( int x, int y, int w, int h )
00277 {
00278 if( !compositing())
00279 return;
00280 repaints_region += QRegion( x, y, w, h );
00281 }
00282
00283 void Workspace::addRepaint( const QRect& r )
00284 {
00285 if( !compositing())
00286 return;
00287 repaints_region += r;
00288 }
00289
00290 void Workspace::addRepaint( const QRegion& r )
00291 {
00292 if( !compositing())
00293 return;
00294 repaints_region += r;
00295 }
00296
00297 void Workspace::addRepaintFull()
00298 {
00299 if( !compositing())
00300 return;
00301 repaints_region = QRegion( 0, 0, displayWidth(), displayHeight());
00302 }
00303
00304 void Workspace::performCompositing()
00305 {
00306 #ifdef KWIN_HAVE_COMPOSITING
00307
00308
00309
00310
00311
00312 if( lastCompositePaint.elapsed() < 1 )
00313 return;
00314 checkCursorPos();
00315 if(( repaints_region.isEmpty() && !windowRepaintsPending())
00316 || !overlay_visible )
00317 {
00318 scene->idle();
00319 return;
00320 }
00321
00322 ToplevelList windows = compositingStackingOrder();
00323 foreach( EffectWindow* c, static_cast< EffectsHandlerImpl* >( effects )->elevatedWindows())
00324 {
00325 Toplevel* t = static_cast< EffectWindowImpl* >( c )->window();
00326 windows.removeAll( t );
00327 windows.append( t );
00328 }
00329
00330 ToplevelList tmp = windows;
00331 windows.clear();
00332 #if 0
00333
00334
00335
00336 foreach( Toplevel* c, tmp )
00337 if( c->readyForPainting())
00338 windows.append( c );
00339 #else
00340 foreach( Toplevel* c, tmp )
00341 windows.append( c );
00342 #endif
00343 foreach( Toplevel* c, windows )
00344 {
00345
00346
00347
00348 repaints_region |= c->repaints().translated( c->pos());
00349 c->resetRepaints( c->rect());
00350 }
00351 QRegion repaints = repaints_region;
00352
00353 repaints_region = QRegion();
00354 scene->paint( repaints, windows );
00355 if( scene->waitSyncAvailable())
00356 {
00357
00358
00359 int untilNextSync = compositeRate - ( lastCompositePaint.elapsed() % compositeRate );
00360 compositeTimer.start( qMax( 1, untilNextSync - 10 ));
00361 }
00362 lastCompositePaint.start();
00363 #endif
00364 }
00365
00366 bool Workspace::windowRepaintsPending() const
00367 {
00368 foreach( Toplevel* c, clients )
00369 if( !c->repaints().isEmpty())
00370 return true;
00371 foreach( Toplevel* c, desktops )
00372 if( !c->repaints().isEmpty())
00373 return true;
00374 foreach( Toplevel* c, unmanaged )
00375 if( !c->repaints().isEmpty())
00376 return true;
00377 foreach( Toplevel* c, deleted )
00378 if( !c->repaints().isEmpty())
00379 return true;
00380 return false;
00381 }
00382
00383 bool Workspace::createOverlay()
00384 {
00385 assert( overlay == None );
00386 if( !Extensions::compositeOverlayAvailable())
00387 return false;
00388 if( !Extensions::shapeInputAvailable())
00389 return false;
00390 #ifdef HAVE_XCOMPOSITE_OVERLAY
00391 overlay = XCompositeGetOverlayWindow( display(), rootWindow());
00392 if( overlay == None )
00393 return false;
00394 return true;
00395 #else
00396 return false;
00397 #endif
00398 }
00399
00400 void Workspace::setupOverlay( Window w )
00401 {
00402 assert( overlay != None );
00403 assert( Extensions::shapeInputAvailable());
00404 XShapeCombineRectangles( display(), overlay, ShapeInput, 0, 0, NULL, 0, ShapeSet, Unsorted );
00405 if( w != None )
00406 XShapeCombineRectangles( display(), w, ShapeInput, 0, 0, NULL, 0, ShapeSet, Unsorted );
00407 XSelectInput( display(), overlay, VisibilityChangeMask );
00408 }
00409
00410 void Workspace::showOverlay()
00411 {
00412 assert( overlay != None );
00413 if( overlay_shown )
00414 return;
00415 XMapSubwindows( display(), overlay );
00416 XMapWindow( display(), overlay );
00417 overlay_shown = true;
00418 }
00419
00420 void Workspace::destroyOverlay()
00421 {
00422 if( overlay == None )
00423 return;
00424 #ifdef HAVE_XCOMPOSITE_OVERLAY
00425 XCompositeReleaseOverlayWindow( display(), overlay );
00426 #endif
00427 overlay = None;
00428 overlay_shown = false;
00429 }
00430
00431
00432
00433
00434
00435 void Toplevel::setupCompositing()
00436 {
00437 #ifdef KWIN_HAVE_COMPOSITING
00438 if( !compositing())
00439 return;
00440 if( damage_handle != None )
00441 return;
00442 damage_handle = XDamageCreate( display(), frameId(), XDamageReportRawRectangles );
00443 damage_region = QRegion( 0, 0, width(), height());
00444 effect_window = new EffectWindowImpl();
00445 effect_window->setWindow( this );
00446 #endif
00447 }
00448
00449 void Toplevel::finishCompositing()
00450 {
00451 #ifdef KWIN_HAVE_COMPOSITING
00452 if( damage_handle == None )
00453 return;
00454 if( effect_window->window() == this )
00455 {
00456 discardWindowPixmap();
00457 delete effect_window;
00458 }
00459 XDamageDestroy( display(), damage_handle );
00460 damage_handle = None;
00461 damage_region = QRegion();
00462 repaints_region = QRegion();
00463 effect_window = NULL;
00464 #endif
00465 }
00466
00467 void Toplevel::discardWindowPixmap()
00468 {
00469 addDamageFull();
00470 if( window_pix == None )
00471 return;
00472 XFreePixmap( display(), window_pix );
00473 window_pix = None;
00474 if( effectWindow() != NULL && effectWindow()->sceneWindow() != NULL )
00475 effectWindow()->sceneWindow()->pixmapDiscarded();
00476 }
00477
00478 Pixmap Toplevel::createWindowPixmap()
00479 {
00480 #ifdef KWIN_HAVE_COMPOSITING
00481 assert( compositing());
00482 grabXServer();
00483 KXErrorHandler err;
00484 window_pix = XCompositeNameWindowPixmap( display(), frameId());
00485
00486
00487 XWindowAttributes attrs;
00488 if( !XGetWindowAttributes( display(), frameId(), &attrs )
00489 || err.error( false )
00490 || attrs.width != width() || attrs.height != height() || attrs.map_state != IsViewable )
00491 {
00492 kDebug( 1212 ) << "Creating window pixmap failed: " << this;
00493 XFreePixmap( display(), window_pix );
00494 window_pix = None;
00495 }
00496 ungrabXServer();
00497 return window_pix;
00498 #else
00499 return None;
00500 #endif
00501 }
00502
00503 #ifdef HAVE_XDAMAGE
00504 void Toplevel::damageNotifyEvent( XDamageNotifyEvent* e )
00505 {
00506 QRegion damage( e->area.x, e->area.y, e->area.width, e->area.height );
00507
00508 int cnt = 1;
00509 while( XPending( display()))
00510 {
00511 XEvent e2;
00512 if( XPeekEvent( display(), &e2 ) && e2.type == Extensions::damageNotifyEvent()
00513 && e2.xany.window == frameId())
00514 {
00515 XNextEvent( display(), &e2 );
00516 if( cnt > 200 )
00517 {
00518
00519
00520
00521
00522 damage = rect();
00523 continue;
00524 }
00525 XDamageNotifyEvent* e = reinterpret_cast< XDamageNotifyEvent* >( &e2 );
00526 QRect r( e->area.x, e->area.y, e->area.width, e->area.height );
00527 ++cnt;
00528
00529
00530
00531
00532
00533 if( cnt > 50 )
00534 {
00535 r.setLeft( r.left() / 100 * 100 );
00536 r.setRight(( r.right() + 99 ) / 100 * 100 );
00537 r.setTop( r.top() / 100 * 100 );
00538 r.setBottom(( r.bottom() + 99 ) / 100 * 100 );
00539 }
00540 damage += r;
00541 continue;
00542 }
00543 break;
00544 }
00545 foreach( QRect r, damage.rects())
00546 addDamage( r );
00547 }
00548
00549 void Client::damageNotifyEvent( XDamageNotifyEvent* e )
00550 {
00551 Toplevel::damageNotifyEvent( e );
00552 #ifdef HAVE_XSYNC
00553 if( sync_counter == None )
00554 ready_for_painting = true;
00555 #else
00556 ready_for_painting = true;
00557 #endif
00558 }
00559 #endif
00560
00561 void Toplevel::addDamage( const QRect& r )
00562 {
00563 addDamage( r.x(), r.y(), r.width(), r.height());
00564 }
00565
00566 void Toplevel::addDamage( int x, int y, int w, int h )
00567 {
00568 if( !compositing())
00569 return;
00570 QRect r( x, y, w, h );
00571
00572
00573 r &= rect();
00574 damage_region += r;
00575 repaints_region += r;
00576 static_cast<EffectsHandlerImpl*>(effects)->windowDamaged( effectWindow(), r );
00577 }
00578
00579 void Toplevel::addDamageFull()
00580 {
00581 if( !compositing())
00582 return;
00583 damage_region = rect();
00584 repaints_region = rect();
00585 static_cast<EffectsHandlerImpl*>(effects)->windowDamaged( effectWindow(), rect());
00586 }
00587
00588 void Toplevel::resetDamage( const QRect& r )
00589 {
00590 damage_region -= r;
00591 }
00592
00593 void Toplevel::addRepaint( const QRect& r )
00594 {
00595 addRepaint( r.x(), r.y(), r.width(), r.height());
00596 }
00597
00598 void Toplevel::addRepaint( int x, int y, int w, int h )
00599 {
00600 if( !compositing())
00601 return;
00602 QRect r( x, y, w, h );
00603 r &= rect();
00604 repaints_region += r;
00605 }
00606
00607 void Toplevel::addRepaintFull()
00608 {
00609 repaints_region = rect();
00610 }
00611
00612 void Toplevel::resetRepaints( const QRect& r )
00613 {
00614 repaints_region -= r;
00615 }
00616
00617 void Toplevel::addWorkspaceRepaint( int x, int y, int w, int h )
00618 {
00619 addWorkspaceRepaint( QRect( x, y, w, h ));
00620 }
00621
00622 void Toplevel::addWorkspaceRepaint( const QRect& r2 )
00623 {
00624 if( !compositing())
00625 return;
00626 if( effectWindow() == NULL )
00627 return workspace()->addRepaint( r2 );
00628 QRect r = effects->transformWindowDamage( effectWindow(), r2 );
00629 workspace()->addRepaint( r );
00630 }
00631
00632 }