diff --git a/CMakeLists.txt b/CMakeLists.txt index 5dc485f51..b0fa7bdbb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,163 +1,164 @@ ########### configure tests ############### # KWIN_HAVE_COMPOSITING - whether any compositing support is available if( X11_Xcomposite_FOUND AND X11_Xdamage_FOUND ) set( KWIN_HAVE_COMPOSITING 1 ) endif( X11_Xcomposite_FOUND AND X11_Xdamage_FOUND ) # KWIN_HAVE_OPENGL_COMPOSITING - whether OpenGL-based compositing support is available if( KWIN_HAVE_COMPOSITING AND OPENGL_FOUND ) set( KWIN_HAVE_OPENGL_COMPOSITING 1 ) endif( KWIN_HAVE_COMPOSITING AND OPENGL_FOUND ) # KWIN_HAVE_XRENDER_COMPOSITING - whether XRender-based compositing support is available if( KWIN_HAVE_COMPOSITING AND X11_Xrender_FOUND AND X11_Xfixes_FOUND ) set( KWIN_HAVE_XRENDER_COMPOSITING 1 ) endif( KWIN_HAVE_COMPOSITING AND X11_Xrender_FOUND AND X11_Xfixes_FOUND ) # safety if( KWIN_HAVE_OPENGL_COMPOSITING OR KWIN_HAVE_XRENDER_COMPOSITING ) # ok else( KWIN_HAVE_OPENGL_COMPOSITING OR KWIN_HAVE_XRENDER_COMPOSITING ) set( KWIN_HAVE_COMPOSITING ) # unset endif( KWIN_HAVE_OPENGL_COMPOSITING OR KWIN_HAVE_XRENDER_COMPOSITING ) macro_log_feature(KWIN_HAVE_COMPOSITING "Compositing support" "X11 Compositing support" "http://www.x.org/" FALSE "" "XComposite and XDamage extensions and OpenGL or XRender with XFixes are required for KWin compositing support") macro_bool_to_01( OPENGL_FOUND KWIN_HAVE_OPENGL ) # for things that are also used by kwin libraries configure_file(lib/kwinconfig.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/lib/kwinconfig.h ) # for kwin internal things configure_file(config-kwin.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kwin.h ) ########### global ############### include_directories( ${CMAKE_CURRENT_BINARY_DIR}/lib ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/lib ${CMAKE_CURRENT_SOURCE_DIR}/effects ${CMAKE_CURRENT_SOURCE_DIR}/tabbox ${KDEBASE_WORKSPACE_SOURCE_DIR}/libs/kephal ) add_subdirectory( lib ) add_subdirectory( killer ) add_subdirectory( kcmkwin ) add_subdirectory( clients ) add_subdirectory( data ) if( KWIN_HAVE_COMPOSITING ) add_subdirectory( effects ) endif( KWIN_HAVE_COMPOSITING ) ########### next target ############### set(kwin_KDEINIT_SRCS workspace.cpp client.cpp clientgroup.cpp placement.cpp atoms.cpp utils.cpp layers.cpp main.cpp tabbox.cpp tabbox/clientitemdelegate.cpp tabbox/clientmodel.cpp tabbox/desktopitemdelegate.cpp tabbox/desktopmodel.cpp tabbox/itemlayoutconfig.cpp tabbox/tabboxconfig.cpp tabbox/tabboxhandler.cpp tabbox/tabboxview.cpp desktopchangeosd.cpp options.cpp plugins.cpp events.cpp killwindow.cpp geometrytip.cpp sm.cpp group.cpp bridge.cpp manage.cpp notifications.cpp activation.cpp useractions.cpp geometry.cpp rules.cpp composite.cpp toplevel.cpp unmanaged.cpp scene.cpp scene_basic.cpp scene_xrender.cpp scene_opengl.cpp deleted.cpp effects.cpp compositingprefs.cpp desktoplayout.cpp paintredirector.cpp ) qt4_add_dbus_adaptor( kwin_KDEINIT_SRCS org.kde.KWin.xml workspace.h KWin::Workspace ) kde4_add_kdeinit_executable( kwin ${kwin_KDEINIT_SRCS}) target_link_libraries(kdeinit_kwin ${KDE4_KDEUI_LIBS} ${KDE4_PLASMA_LIBS} ${QT_QTXML_LIBRARY} kephal kdecorations kwineffects ${X11_LIBRARIES}) if(OPENGL_FOUND) + add_subdirectory(opengltest) target_link_libraries(kdeinit_kwin ${OPENGL_gl_LIBRARY}) # -ldl used by OpenGL code find_library(DL_LIBRARY dl) if (DL_LIBRARY) target_link_libraries(kdeinit_kwin ${DL_LIBRARY}) endif(DL_LIBRARY) # must be after opengl, to be initialized first by the linker target_link_libraries(kdeinit_kwin kwinnvidiahack) endif(OPENGL_FOUND) if (X11_Xrandr_FOUND) target_link_libraries(kdeinit_kwin ${X11_Xrandr_LIB}) endif (X11_Xrandr_FOUND) if (X11_Xcomposite_FOUND) target_link_libraries(kdeinit_kwin ${X11_Xcomposite_LIB}) endif (X11_Xcomposite_FOUND) if (X11_Xdamage_FOUND) target_link_libraries(kdeinit_kwin ${X11_Xdamage_LIB}) endif (X11_Xdamage_FOUND) if (X11_Xrender_FOUND) target_link_libraries(kdeinit_kwin ${X11_Xrender_LIB}) endif (X11_Xrender_FOUND) if (X11_Xfixes_FOUND) target_link_libraries(kdeinit_kwin ${X11_Xfixes_LIB}) endif (X11_Xfixes_FOUND) install(TARGETS kdeinit_kwin ${INSTALL_TARGETS_DEFAULT_ARGS} ) install(TARGETS kwin ${INSTALL_TARGETS_DEFAULT_ARGS} ) ########### next target ############### set( kwinnvidiahack_LIB_SRCS nvidiahack.cpp ) kde4_add_library(kwinnvidiahack SHARED ${kwinnvidiahack_LIB_SRCS}) set_target_properties(kwinnvidiahack PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION} ) install(TARGETS kwinnvidiahack ${INSTALL_TARGETS_DEFAULT_ARGS} ) ########### install files ############### install( FILES kwin.kcfg DESTINATION ${KCFG_INSTALL_DIR} ) install( FILES kwin.notifyrc DESTINATION ${DATA_INSTALL_DIR}/kwin ) install( FILES org.kde.KWin.xml DESTINATION ${DBUS_INTERFACES_INSTALL_DIR} ) install( FILES tabbox/DefaultTabBoxLayouts.xml DESTINATION ${DATA_INSTALL_DIR}/kwin ) kde4_install_icons( ${ICON_INSTALL_DIR} ) diff --git a/compositingprefs.cpp b/compositingprefs.cpp index f38185db7..2aac0e999 100644 --- a/compositingprefs.cpp +++ b/compositingprefs.cpp @@ -1,358 +1,375 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2007 Rivo Laks 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 the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ #include "compositingprefs.h" #include "kwinglobals.h" #include #include #include #include +#include + +#include namespace KWin { CompositingPrefs::CompositingPrefs() : mXgl( false ) , mRecommendCompositing( false ) , mEnableVSync( true ) , mEnableDirectRendering( true ) , mStrictBinding( true ) { } CompositingPrefs::~CompositingPrefs() { } bool CompositingPrefs::recommendCompositing() const { return mRecommendCompositing; } bool CompositingPrefs::compositingPossible() { #ifdef KWIN_HAVE_COMPOSITING Extensions::init(); if( !Extensions::compositeAvailable()) { kDebug( 1212 ) << "No composite extension available"; return false; } if( !Extensions::damageAvailable()) { kDebug( 1212 ) << "No damage extension available"; return false; } #ifdef KWIN_HAVE_OPENGL_COMPOSITING if( Extensions::glxAvailable()) return true; #endif #ifdef KWIN_HAVE_XRENDER_COMPOSITING if( Extensions::renderAvailable() && Extensions::fixesAvailable()) return true; #endif kDebug( 1212 ) << "No OpenGL or XRender/XFixes support"; return false; #else return false; #endif } QString CompositingPrefs::compositingNotPossibleReason() { #ifdef KWIN_HAVE_COMPOSITING Extensions::init(); if( !Extensions::compositeAvailable() || !Extensions::damageAvailable()) { return i18n("Required X extensions (XComposite and XDamage) are not available."); } #if defined( KWIN_HAVE_OPENGL_COMPOSITING ) && !defined( KWIN_HAVE_XRENDER_COMPOSITING ) if( !Extensions::glxAvailable()) return i18n( "GLX/OpenGL are not available and only OpenGL support is compiled." ); #elif !defined( KWIN_HAVE_OPENGL_COMPOSITING ) && defined( KWIN_HAVE_XRENDER_COMPOSITING ) if( !( Extensions::renderAvailable() && Extensions::fixesAvailable())) return i18n( "XRender/XFixes extensions are not available and only XRender support" " is compiled." ); #else if( !( Extensions::glxAvailable() || ( Extensions::renderAvailable() && Extensions::fixesAvailable()))) { return i18n( "GLX/OpenGL and XRender/XFixes are not available." ); } #endif return QString(); #else return i18n("Compositing was disabled at compile time.\n" "It is likely Xorg development headers were not installed."); #endif } void CompositingPrefs::detect() { if( !compositingPossible()) { return; } #ifdef KWIN_HAVE_OPENGL_COMPOSITING + // HACK: This is needed for AIGLX + if( qstrcmp( qgetenv( "KWIN_DIRECT_GL" ), "1" ) != 0 ) + { + // Start an external helper program that initializes GLX and returns + // 0 if we can use direct rendering, and 1 otherwise. + // The reason we have to use an external program is that after GLX + // has been initialized, it's too late to set the LIBGL_ALWAYS_INDIRECT + // environment variable. + // Direct rendering is preferred, since not all OpenGL extensions are + // available with indirect rendering. + const QString opengl_test = KStandardDirs::findExe( "kwin_opengl_test" ); + if ( QProcess::execute( opengl_test ) != 0 ) + setenv( "LIBGL_ALWAYS_INDIRECT", "1", true ); + } if( !Extensions::glxAvailable()) { kDebug( 1212 ) << "No GLX available"; return; } int glxmajor, glxminor; glXQueryVersion( display(), &glxmajor, &glxminor ); kDebug( 1212 ) << "glx version is " << glxmajor << "." << glxminor; bool hasglx13 = ( glxmajor > 1 || ( glxmajor == 1 && glxminor >= 3 )); // remember and later restore active context GLXContext oldcontext = glXGetCurrentContext(); GLXDrawable olddrawable = glXGetCurrentDrawable(); GLXDrawable oldreaddrawable = None; if( hasglx13 ) oldreaddrawable = glXGetCurrentReadDrawable(); if( initGLXContext() ) { detectDriverAndVersion(); applyDriverSpecificOptions(); } if( hasglx13 ) glXMakeContextCurrent( display(), olddrawable, oldreaddrawable, oldcontext ); else glXMakeCurrent( display(), olddrawable, oldcontext ); deleteGLXContext(); #endif } bool CompositingPrefs::initGLXContext() { #ifdef KWIN_HAVE_OPENGL_COMPOSITING mGLContext = NULL; KXErrorHandler handler; // Most of this code has been taken from glxinfo.c QVector attribs; attribs << GLX_RGBA; attribs << GLX_RED_SIZE << 1; attribs << GLX_GREEN_SIZE << 1; attribs << GLX_BLUE_SIZE << 1; attribs << None; XVisualInfo* visinfo = glXChooseVisual( display(), DefaultScreen( display()), attribs.data() ); if( !visinfo ) { attribs.last() = GLX_DOUBLEBUFFER; attribs << None; visinfo = glXChooseVisual( display(), DefaultScreen( display()), attribs.data() ); if (!visinfo) { kDebug( 1212 ) << "Error: couldn't find RGB GLX visual"; return false; } } mGLContext = glXCreateContext( display(), visinfo, NULL, True ); if ( !mGLContext ) { kDebug( 1212 ) << "glXCreateContext failed"; XDestroyWindow( display(), mGLWindow ); return false; } XSetWindowAttributes attr; attr.background_pixel = 0; attr.border_pixel = 0; attr.colormap = XCreateColormap( display(), rootWindow(), visinfo->visual, AllocNone ); attr.event_mask = StructureNotifyMask | ExposureMask; unsigned long mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; int width = 100, height = 100; mGLWindow = XCreateWindow( display(), rootWindow(), 0, 0, width, height, 0, visinfo->depth, InputOutput, visinfo->visual, mask, &attr ); return glXMakeCurrent( display(), mGLWindow, mGLContext ) && !handler.error( true ); #else return false; #endif } void CompositingPrefs::deleteGLXContext() { #ifdef KWIN_HAVE_OPENGL_COMPOSITING if( mGLContext == NULL ) return; glXDestroyContext( display(), mGLContext ); XDestroyWindow( display(), mGLWindow ); #endif } void CompositingPrefs::detectDriverAndVersion() { #ifdef KWIN_HAVE_OPENGL_COMPOSITING mGLVendor = QString((const char*)glGetString( GL_VENDOR )); mGLRenderer = QString((const char*)glGetString( GL_RENDERER )); mGLVersion = QString((const char*)glGetString( GL_VERSION )); mXgl = detectXgl(); if( mGLRenderer.startsWith( "Mesa DRI Intel" ) || mGLRenderer.startsWith( "Mesa DRI Mobile Intel" )) // krazy:exclude=strings { mDriver = "intel"; QStringList words = mGLRenderer.split(' '); mVersion = Version( words[ words.count() - 2 ] ); } else if( mGLVendor == "NVIDIA Corporation" ) { mDriver = "nvidia"; QStringList words = mGLVersion.split(' '); mVersion = Version( words[ words.count() - 1 ] ); } else if( mGLVendor == "ATI Technologies Inc." ) { mDriver = "fglrx"; // Ati changed the version string. // The GL version is either in the first or second part QStringList versionParts = mGLVersion.split(' '); if( versionParts.first().count(".") == 2 || versionParts.count() == 1 ) mVersion = Version( versionParts.first() ); else { // version in second part is encapsulated in () mVersion = Version( versionParts[1].mid( 1, versionParts[1].length() -2 ) ); } } else if( mGLRenderer.startsWith( "Mesa DRI R" )) // krazy:exclude=strings { mDriver = "radeon"; mVersion = Version( mGLRenderer.split(' ')[ 3 ] ); // Check that the version string is changed, and try the fifth element if it does if (!mVersion.startsWith("20")) mVersion = Version( mGLRenderer.split(' ')[ 5 ] ); } else if( mGLRenderer == "Software Rasterizer" ) { mDriver = "software"; QStringList words = mGLVersion.split(' '); mVersion = Version( words[ words.count() - 1 ] ); } else { mDriver = "unknown"; } // Always output as it's VERY useful kWarning( 1212 ) << "GL vendor is" << mGLVendor; kWarning( 1212 ) << "GL renderer is" << mGLRenderer; kWarning( 1212 ) << "GL version is" << mGLVersion; if( mXgl ) kWarning( 1212 ) << "Using XGL"; kWarning( 1212 ) << "Detected driver" << mDriver << ", version" << mVersion.join("."); #endif } // See http://techbase.kde.org/Projects/KWin/HW for a list of some cards that are known to work. void CompositingPrefs::applyDriverSpecificOptions() { // Always recommend mRecommendCompositing = true; // Known driver specific options if( mXgl ) { mStrictBinding = false; } else if( mDriver == "intel" ) { mEnableVSync = false; } else if( mDriver == "nvidia" ) { mStrictBinding = false; } //else if( mDriver == "fglrx" ) // { // } //else if( mDriver == "radeon" ) // { // } //else if( mDriver == "software" ) // { // } } bool CompositingPrefs::detectXgl() { // Xgl apparently uses only this specific X version return VendorRelease(display()) == 70000001; } CompositingPrefs::Version::Version( const QString& str ) : QStringList() { QRegExp numrx( "(\\d+)|(\\D+)" ); int pos = 0; while(( pos = numrx.indexIn( str, pos )) != -1 ) { pos += numrx.matchedLength(); QString part = numrx.cap(); if( part == "." ) continue; append( part ); } } int CompositingPrefs::Version::compare( const Version& v ) const { for( int i = 0; i < qMin( count(), v.count() ); i++ ) { if( at( i )[ 0 ].isDigit() ) { // This part of version string is numeric - compare numbers int num = at( i ).toInt(); int vnum = v.at( i ).toInt(); if( num > vnum ) return 1; else if( num < vnum ) return -1; } else { // This part is string if( at( i ) > v.at( i )) return 1; else if( at( i ) < v.at( i )) return -1; } } if( count() > v.count() ) return 1; else if( count() < v.count() ) return -1; else return 0; } } // namespace diff --git a/main.cpp b/main.cpp index c5346a951..d97dbcf7e 100644 --- a/main.cpp +++ b/main.cpp @@ -1,529 +1,525 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 1999, 2000 Matthias Ettrich Copyright (C) 2003 Lubos Lunak 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 the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ #include "main.h" //#define QT_CLEAN_NAMESPACE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "atoms.h" #include "options.h" #include "sm.h" #include "utils.h" #include "effects.h" #define INT8 _X11INT8 #define INT32 _X11INT32 #include #undef INT8 #undef INT32 namespace KWin { Options* options; Atoms* atoms; int screen_number = -1; bool initting = false; /** * Whether to run Xlib in synchronous mode and print backtraces for X errors. * Note that you most probably need to configure cmake with "-D__KDE_HAVE_GCC_VISIBILITY=0" * and -rdynamic in CXXFLAGS for kBacktrace() to work. */ static bool kwin_sync = false; // errorMessage is only used ifndef NDEBUG, and only in one place. // it might be worth reevaluating why this is used? I don't know. #ifndef NDEBUG /** * Outputs: "Error: (), Request: (), Resource: " */ // This is copied from KXErrorHandler and modified to explicitly use known extensions static QByteArray errorMessage( const XErrorEvent& event, Display* dpy ) { QByteArray ret; char tmp[256]; char num[256]; if( event.request_code < 128 ) { // Core request XGetErrorText( dpy, event.error_code, tmp, 255 ); // The explanation in parentheses just makes // it more verbose and is not really useful if( char* paren = strchr( tmp, '(' )) *paren = '\0'; // The various casts are to get overloads non-ambiguous :-/ ret = QByteArray( "error: " ) + (const char*)( tmp ) + '[' + QByteArray::number( event.error_code ) + ']'; sprintf( num, "%d", event.request_code ); XGetErrorDatabaseText( dpy, "XRequest", num, "", tmp, 256 ); ret += QByteArray( ", request: " ) + (const char*)( tmp ) + '[' + QByteArray::number( event.request_code ) + ']'; if( event.resourceid != 0 ) ret += QByteArray( ", resource: 0x" ) + QByteArray::number( qlonglong( event.resourceid ), 16 ); } else // Extensions { // XGetErrorText() currently has a bug that makes it fail to find text // for some errors (when error==error_base), also XGetErrorDatabaseText() // requires the right extension name, so it is needed to get info about // all extensions. However that is almost impossible: // - Xlib itself has it, but in internal data. // - Opening another X connection now can cause deadlock with server grabs. // - Fetching it at startup means a bunch of roundtrips. // KWin here explicitly uses known extensions. int nextensions; const char** extensions; int* majors; int* error_bases; Extensions::fillExtensionsData( extensions, nextensions, majors, error_bases ); XGetErrorText( dpy, event.error_code, tmp, 255 ); int index = -1; int base = 0; for( int i = 0; i < nextensions; ++i ) if( error_bases[i] != 0 && event.error_code >= error_bases[i] && ( index == -1 || error_bases[i] > base )) { index = i; base = error_bases[i]; } if( tmp == QString::number( event.error_code )) { // XGetErrorText() failed or it has a bug that causes not finding all errors, check ourselves if( index != -1 ) { snprintf( num, 255, "%s.%d", extensions[index], event.error_code - base ); XGetErrorDatabaseText( dpy, "XProtoError", num, "", tmp, 255 ); } else strcpy( tmp, "" ); } if( char* paren = strchr( tmp, '(' )) *paren = '\0'; if( index != -1 ) ret = QByteArray( "error: " ) + (const char*)( tmp ) + '[' + (const char*)( extensions[index] ) + '+' + QByteArray::number( event.error_code - base ) + ']'; else ret = QByteArray( "error: " ) + (const char*)( tmp ) + '[' + QByteArray::number( event.error_code ) + ']'; tmp[0] = '\0'; for( int i = 0; i < nextensions; ++i ) if( majors[i] == event.request_code ) { snprintf( num, 255, "%s.%d", extensions[i], event.minor_code ); XGetErrorDatabaseText( dpy, "XRequest", num, "", tmp, 255 ); ret += QByteArray( ", request: " ) + (const char*)( tmp ) + '[' + (const char*)( extensions[i] ) + '+' + QByteArray::number( event.minor_code ) + ']'; } if( tmp[0] == '\0' ) // Not found? ret += QByteArray( ", request [" ) + QByteArray::number( event.request_code ) + ':' + QByteArray::number( event.minor_code ) + ']'; if( event.resourceid != 0 ) ret += QByteArray( ", resource: 0x" ) + QByteArray::number( qlonglong( event.resourceid ), 16 ); } return ret; } #endif static int x11ErrorHandler( Display* d, XErrorEvent* e ) { Q_UNUSED( d ); bool ignore_badwindow = true; // Might be temporary if( initting && ( e->request_code == X_ChangeWindowAttributes || e->request_code == X_GrabKey ) && e->error_code == BadAccess ) { fputs( i18n( "kwin: it looks like there's already a window manager running. kwin not started.\n" ).toLocal8Bit(), stderr ); exit(1); } if( ignore_badwindow && ( e->error_code == BadWindow || e->error_code == BadColor )) return 0; #ifndef NDEBUG //fprintf( stderr, "kwin: X Error (%s)\n", KXErrorHandler::errorMessage( *e, d ).data()); kWarning( 1212 ) << "kwin: X Error (" << errorMessage( *e, d ) << ")"; #endif if( kwin_sync ) fprintf( stderr, "%s\n", kBacktrace().toLocal8Bit().data() ); return 0; } class AlternativeWMDialog : public KDialog { public: AlternativeWMDialog() : KDialog() { setButtons( KDialog::Ok | KDialog::Cancel ); QWidget* mainWidget = new QWidget( this ); QVBoxLayout* layout = new QVBoxLayout( mainWidget ); QString text = i18n( "KWin is unstable.\n" "It seems to have crashed several times in a row.\n" "You can select another window manager to run:" ); QLabel* textLabel = new QLabel( text, mainWidget ); layout->addWidget( textLabel ); wmList = new KComboBox( mainWidget ); wmList->setEditable( true ); layout->addWidget( wmList ); addWM( "metacity" ); addWM( "openbox" ); addWM( "fvwm2" ); addWM( "kwin" ); setMainWidget( mainWidget ); raise(); centerOnScreen( this ); } void addWM( const QString& wm ) { // TODO: Check if WM is installed if( !KStandardDirs::findExe( wm ).isEmpty() ) wmList->addItem( wm ); } QString selectedWM() const { return wmList->currentText(); } private: KComboBox* wmList; }; int Application::crashes = 0; Application::Application() : KApplication() , owner( screen_number ) { if( KCmdLineArgs::parsedArgs( "qt" )->isSet( "sync" )) { kwin_sync = true; XSynchronize( display(), True ); kDebug( 1212 ) << "Running KWin in sync mode"; } setQuitOnLastWindowClosed( false ); KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); KSharedConfig::Ptr config = KGlobal::config(); if( !config->isImmutable() && args->isSet( "lock" )) { // TODO: This shouldn't be necessary //config->setReadOnly( true ); config->reparseConfiguration(); } if( screen_number == -1 ) screen_number = DefaultScreen( display() ); if( !owner.claim( args->isSet( "replace" ), true )) { fputs( i18n( "kwin: unable to claim manager selection, another wm running? (try using --replace)\n" ).toLocal8Bit(), stderr ); ::exit( 1 ); } connect( &owner, SIGNAL( lostOwnership() ), SLOT( lostSelection() )); KCrash::setEmergencySaveFunction( Application::crashHandler ); crashes = args->getOption( "crashes" ).toInt(); if( crashes >= 4 ) { // Something has gone seriously wrong AlternativeWMDialog dialog; QString cmd = "kwin"; if( dialog.exec() == QDialog::Accepted ) cmd = dialog.selectedWM(); else ::exit( 1 ); if( cmd.length() > 500 ) { kDebug( 1212 ) << "Command is too long, truncating"; cmd = cmd.left( 500 ); } kDebug( 1212 ) << "Starting" << cmd << "and exiting"; char buf[1024]; sprintf( buf, "%s &", cmd.toAscii().data() ); system( buf ); ::exit( 1 ); } if( crashes >= 2 ) { // Disable compositing if we have had too many crashes kDebug( 1212 ) << "Too many crashes recently, disabling compositing"; KConfigGroup compgroup( config, "Compositing" ); compgroup.writeEntry( "Enabled", false ); } // Reset crashes count if we stay up for more that 15 seconds QTimer::singleShot( 15*1000, this, SLOT( resetCrashesCount() )); // If KWin was already running it saved its configuration after loosing the selection -> Reread config->reparseConfiguration(); initting = true; // Startup... // Install X11 error handler XSetErrorHandler( x11ErrorHandler ); // Check whether another windowmanager is running XSelectInput( display(), rootWindow(), SubstructureRedirectMask ); syncX(); // Trigger error now atoms = new Atoms; // initting = false; // TODO // This tries to detect compositing options and can use GLX. GLX problems // (X errors) shouldn't cause kwin to abort, so this is out of the // critical startup section where x errors cause kwin to abort. options = new Options; // create workspace. (void) new Workspace( isSessionRestored() ); syncX(); // Trigger possible errors, there's still a chance to abort initting = false; // Startup done, we are up and running now. XEvent e; e.xclient.type = ClientMessage; e.xclient.message_type = XInternAtom( display(), "_KDE_SPLASH_PROGRESS", False ); e.xclient.display = display(); e.xclient.window = rootWindow(); e.xclient.format = 8; strcpy( e.xclient.data.b, "wm" ); XSendEvent( display(), rootWindow(), False, SubstructureNotifyMask, &e ); } Application::~Application() { delete Workspace::self(); if( owner.ownerWindow() != None ) // If there was no --replace (no new WM) XSetInputFocus( display(), PointerRoot, RevertToPointerRoot, xTime() ); delete options; delete effects; delete atoms; } void Application::lostSelection() { sendPostedEvents(); delete Workspace::self(); // Remove windowmanager privileges XSelectInput( display(), rootWindow(), PropertyChangeMask ); quit(); } bool Application::x11EventFilter( XEvent* e ) { if( Workspace::self() && Workspace::self()->workspaceEvent( e )) return true; return KApplication::x11EventFilter( e ); } bool Application::notify( QObject* o, QEvent* e ) { if( Workspace::self()->workspaceEvent( e )) return true; return KApplication::notify( o, e ); } static void sighandler( int ) { QApplication::exit(); } void Application::crashHandler( int signal ) { crashes++; fprintf( stderr, "Application::crashHandler() called with signal %d; recent crashes: %d\n", signal, crashes ); char cmd[1024]; sprintf( cmd, "%s --crashes %d &", QFile::encodeName(QCoreApplication::applicationFilePath()).constData(), crashes ); sleep( 1 ); system( cmd ); } void Application::resetCrashesCount() { crashes = 0; } } // namespace static const char version[] = KDE_VERSION_STRING; static const char description[] = I18N_NOOP( "KDE window manager" ); extern "C" KDE_EXPORT int kdemain( int argc, char * argv[] ) { bool restored = false; for( int arg = 1; arg < argc; arg++ ) { if( !qstrcmp( argv[arg], "-session" )) { restored = true; break; } } // KWin only works properly with Qt's native X11 backend; override any compile-time // or command line settings to raster or OpenGL. QApplication::setGraphicsSystem("native"); if( !restored ) { // We only do the multihead fork if we are not restored by the session // manager, since the session manager will register multiple kwins, // one for each screen... QByteArray multiHead = qgetenv( "KDE_MULTIHEAD" ); if( multiHead.toLower() == "true" ) { Display* dpy = XOpenDisplay( NULL ); if( !dpy ) { fprintf( stderr, "%s: FATAL ERROR while trying to open display %s\n", argv[0], XDisplayName( NULL )); exit( 1 ); } int number_of_screens = ScreenCount( dpy ); KWin::screen_number = DefaultScreen( dpy ); int pos; // Temporarily needed to reconstruct DISPLAY var if multi-head QByteArray display_name = XDisplayString( dpy ); XCloseDisplay( dpy ); dpy = 0; if(( pos = display_name.lastIndexOf( '.' )) != -1 ) display_name.remove( pos, 10 ); // 10 is enough to be sure we removed ".s" QString envir; if( number_of_screens != 1 ) { for( int i = 0; i < number_of_screens; i++ ) { // If execution doesn't pass by here, then kwin // acts exactly as previously if( i != KWin::screen_number && fork() == 0 ) { KWin::screen_number = i; // Break here because we are the child process, we don't // want to fork() anymore break; } } // In the next statement, display_name shouldn't contain a screen // number. If it had it, it was removed at the "pos" check envir.sprintf( "DISPLAY=%s.%d", display_name.data(), KWin::screen_number ); if( putenv( strdup( envir.toAscii() ))) { fprintf( stderr, "%s: WARNING: unable to set DISPLAY environment variable\n", argv[0] ); perror("putenv()"); } } } } KAboutData aboutData( "kwin", // The program name used internally 0, // The message catalog name. If null, program name is used instead ki18n( "KWin" ), // A displayable program name string version, // The program version string ki18n( description ), // Short description of what the app does KAboutData::License_GPL, // The license this code is released under ki18n( "(c) 1999-2008, The KDE Developers" )); // Copyright Statement aboutData.addAuthor( ki18n( "Matthias Ettrich" ),KLocalizedString(), "ettrich@kde.org" ); aboutData.addAuthor( ki18n( "Cristian Tibirna" ),KLocalizedString(), "tibirna@kde.org" ); aboutData.addAuthor( ki18n( "Daniel M. Duley" ),KLocalizedString(), "mosfet@kde.org" ); aboutData.addAuthor( ki18n( "Luboš Luňák" ), ki18n( "Maintainer" ), "l.lunak@kde.org" ); KCmdLineArgs::init( argc, argv, &aboutData ); KCmdLineOptions args; args.add( "lock", ki18n( "Disable configuration options" )); args.add( "replace", ki18n( "Replace already-running ICCCM2.0-compliant window manager" )); args.add( "crashes ", ki18n( "Indicate that KWin has recently crashed n times" )); KCmdLineArgs::addCmdLineOptions( args ); if( KDE_signal( SIGTERM, KWin::sighandler ) == SIG_IGN ) KDE_signal( SIGTERM, SIG_IGN ); if( KDE_signal( SIGINT, KWin::sighandler ) == SIG_IGN ) KDE_signal( SIGINT, SIG_IGN ); if( KDE_signal( SIGHUP, KWin::sighandler ) == SIG_IGN ) KDE_signal( SIGHUP, SIG_IGN ); - // HACK: This is needed for AIGLX - if( qstrcmp( qgetenv( "KWIN_DIRECT_GL" ), "1" ) != 0 ) - setenv( "LIBGL_ALWAYS_INDIRECT","1", true ); - // HACK: this is needed to work around a Qt4.4.0RC1 bug (#157659) setenv( "QT_SLOW_TOPLEVEL_RESIZE", "1", true ); KWin::Application a; KWin::SessionManager weAreIndeed; KWin::SessionSaveDoneHelper helper; KGlobal::locale()->insertCatalog( "kwin_effects" ); // Announce when KWIN_DIRECT_GL is set for above HACK if( qstrcmp( qgetenv( "KWIN_DIRECT_GL" ), "1" ) == 0 ) kDebug( 1212 ) << "KWIN_DIRECT_GL set, not forcing LIBGL_ALWAYS_INDIRECT=1"; fcntl( XConnectionNumber( KWin::display() ), F_SETFD, 1 ); QString appname; if( KWin::screen_number == 0 ) appname = "org.kde.kwin"; else appname.sprintf( "org.kde.kwin-screen-%d", KWin::screen_number ); QDBusConnection::sessionBus().interface()->registerService( appname, QDBusConnectionInterface::DontQueueService ); return a.exec(); } #include "main.moc" diff --git a/opengltest/CMakeLists.txt b/opengltest/CMakeLists.txt new file mode 100644 index 000000000..49607c821 --- /dev/null +++ b/opengltest/CMakeLists.txt @@ -0,0 +1,10 @@ +########### next target ############### + +set(kwin_opengl_test_SRCS opengltest.cpp ) + +kde4_add_executable(kwin_opengl_test ${kwin_opengl_test_SRCS}) + +target_link_libraries(kwin_opengl_test ${X11_LIBRARIES} ${OPENGL_gl_LIBRARY}) + +install(TARGETS kwin_opengl_test ${INSTALL_TARGETS_DEFAULT_ARGS} ) + diff --git a/opengltest/opengltest.cpp b/opengltest/opengltest.cpp new file mode 100644 index 000000000..dd2273b9d --- /dev/null +++ b/opengltest/opengltest.cpp @@ -0,0 +1,89 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2010 Fredrik Höglund + +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 +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ + +#include +#include +#include +#include + + +// Return 0 if we can use a direct context, 1 otherwise +int main(int argc, char *argv[]) +{ + Display *dpy = XOpenDisplay(0); + + int error_base, event_base; + if (!glXQueryExtension(dpy, &error_base, &event_base)) + return 1; + + int major, minor; + if (!glXQueryVersion(dpy, &major, &minor)) + return 1; + + // glXCreatePixmap() is a GLX 1.3+ function. + // It is also provided by EXT_texture_from_pixmap, but only for indirect contexts. + if (major == 1 && minor < 3) + return 1; + + int attribs[] = { + GLX_RGBA, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + None, + None + }; + + // Try to find an RGBA visual + XVisualInfo *xvi = glXChooseVisual(dpy, DefaultScreen(dpy), attribs); + if (!xvi) { + // Try again for a doubled buffered visual + attribs[sizeof(attribs) / sizeof(int) - 2] = GLX_DOUBLEBUFFER; + xvi = glXChooseVisual(dpy, DefaultScreen(dpy), attribs); + } + + if (!xvi) + return 1; + + GLXContext ctx = glXCreateContext(dpy, xvi, NULL, True); + + // Create a window using the visual. + // We only need it to make the context current + XSetWindowAttributes attr; + attr.background_pixel = 0; + attr.border_pixel = 0; + attr.colormap = XCreateColormap(dpy, DefaultRootWindow(dpy), xvi->visual, AllocNone); + Window win = XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, 1, 1, 0, + xvi->depth, InputOutput, xvi->visual, + CWBackPixel | CWBorderPixel | CWColormap, &attr); + glXMakeCurrent(dpy, win, ctx); + + // Assume that glXCreatePixmap() works with DRI2 drivers, and the NVidia driver + const GLubyte *renderer = glGetString(GL_RENDERER); + if (strstr((const char *)renderer, "DRI2")) + return 0; + + const GLubyte *vendor = glGetString(GL_VENDOR); + if (strstr((const char *)vendor, "NVIDIA")) + return 0; + + return 1; +} +