/******************************************************************** 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 "main.h" #include "kwin_interface.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY(KWinCompositingConfigFactory, registerPlugin(); ) K_EXPORT_PLUGIN(KWinCompositingConfigFactory("kcmkwincompositing")) namespace KWin { ConfirmDialog::ConfirmDialog() : KTimerDialog(10000, KTimerDialog::CountDown, 0, i18n("Confirm Desktop Effects Change"), KTimerDialog::Ok|KTimerDialog::Cancel, KTimerDialog::Cancel) { setObjectName( QLatin1String( "mainKTimerDialog" ) ); setButtonGuiItem( KDialog::Ok, KGuiItem( i18n( "&Accept Configuration" ), "dialog-ok" )); setButtonGuiItem( KDialog::Cancel, KGuiItem( i18n( "&Return to Previous Configuration" ), "dialog-cancel" )); QLabel *label = new QLabel( i18n( "Desktop effects settings have changed.\n" "Do you want to keep the new settings?\n" "They will be automatically reverted in 10 seconds." ), this ); label->setWordWrap( true ); setMainWidget( label ); setWindowIcon(KIcon("preferences-desktop-effect")); } KWinCompositingConfig::KWinCompositingConfig(QWidget *parent, const QVariantList &) : KCModule( KWinCompositingConfigFactory::componentData(), parent ) , mKWinConfig(KSharedConfig::openConfig( "kwinrc" )) , m_showConfirmDialog( false ) , kwinInterface( NULL ) { KGlobal::locale()->insertCatalog( "kwin_effects" ); ui.setupUi(this); layout()->setMargin(0); ui.verticalSpacer->changeSize(20, KDialog::groupSpacingHint()); ui.verticalSpacer_2->changeSize(20, KDialog::groupSpacingHint()); ui.tabWidget->setCurrentIndex(0); ui.statusTitleWidget->hide(); // For future use (void) I18N_NOOP( "Use GLSL shaders" ); #define OPENGL_INDEX 0 #define XRENDER_INDEX 1 #ifndef KWIN_HAVE_OPENGL_COMPOSITING ui.compositingType->removeItem( OPENGL_INDEX ); ui.glGroup->setEnabled( false ); #define OPENGL_INDEX -1 #define XRENDER_INDEX 0 #endif #ifndef KWIN_HAVE_XRENDER_COMPOSITING ui.compositingType->removeItem( XRENDER_INDEX ); ui.xrenderGroup->setEnabled( false ); #define XRENDER_INDEX -1 #endif kwinInterface = new OrgKdeKWinInterface( "org.kde.kwin", "/KWin", QDBusConnection::sessionBus() ); connect(ui.useCompositing, SIGNAL(toggled(bool)), this, SLOT(compositingEnabled(bool))); connect(ui.tabWidget, SIGNAL(currentChanged(int)), this, SLOT(currentTabChanged(int))); connect(ui.useCompositing, SIGNAL(toggled(bool)), this, SLOT(changed())); connect(ui.effectWinManagement, SIGNAL(toggled(bool)), this, SLOT(changed())); connect(ui.effectShadows, SIGNAL(toggled(bool)), this, SLOT(changed())); connect(ui.effectAnimations, SIGNAL(toggled(bool)), this, SLOT(changed())); connect(ui.effectSelector, SIGNAL(changed(bool)), this, SLOT(changed())); connect(ui.effectSelector, SIGNAL(configCommitted(const QByteArray&)), this, SLOT(reparseConfiguration(const QByteArray&))); connect(ui.windowSwitchingCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(changed())); connect(ui.desktopSwitchingCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(changed())); connect(ui.animationSpeedCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(changed())); connect(ui.compositingType, SIGNAL(currentIndexChanged(int)), this, SLOT(changed())); connect(ui.compositingType, SIGNAL(currentIndexChanged(int)), this, SLOT(toogleSmoothScaleUi(int))); connect(ui.windowThumbnails, SIGNAL(activated(int)), this, SLOT(changed())); connect(ui.disableChecks, SIGNAL(toggled(bool)), this, SLOT(changed())); connect(ui.unredirectFullscreen , SIGNAL(toggled(bool)), this, SLOT(changed())); connect(ui.glScaleFilter, SIGNAL(currentIndexChanged(int)), this, SLOT(changed())); connect(ui.xrScaleFilter, SIGNAL(currentIndexChanged(int)), this, SLOT(changed())); connect(ui.glMode, SIGNAL(currentIndexChanged(int)), this, SLOT(changed())); connect(ui.glDirect, SIGNAL(toggled(bool)), this, SLOT(changed())); connect(ui.glVSync, SIGNAL(toggled(bool)), this, SLOT(changed())); connect(ui.compositingStateButton, SIGNAL(clicked(bool)), kwinInterface, SLOT(toggleCompositing())); connect(kwinInterface, SIGNAL(compositingToggled(bool)), this, SLOT(setupCompositingState(bool))); // Open the temporary config file // Temporary conf file is used to synchronize effect checkboxes with effect // selector by loading/saving effects from/to temp config when active tab // changes. mTmpConfigFile.open(); mTmpConfig = KSharedConfig::openConfig(mTmpConfigFile.fileName()); // NOTICE: this is intended to workaround broken GL implementations that successfully segfault on glXQuery :-( KConfigGroup unsafeConfig(mKWinConfig, "Compositing"); const bool glUnsafe = unsafeConfig.readEntry( "OpenGLIsUnsafe", false ); if( !glUnsafe && CompositingPrefs::compositingPossible() ) { unsafeConfig.writeEntry( "OpenGLIsUnsafe", true ); unsafeConfig.sync(); // Driver-specific config detection mDefaultPrefs.detect(); initEffectSelector(); // Initialize the user interface with the config loaded from kwinrc. load(); unsafeConfig.writeEntry( "OpenGLIsUnsafe", false ); unsafeConfig.sync(); } else { // TODO: Add a "force recheck" button that removes the "OpenGLInUnsafe" flag ui.useCompositing->setEnabled(false); ui.useCompositing->setChecked(false); compositingEnabled(false); QString text = i18n("Desktop effects are not available on this system due to the following technical issues:"); text += "
"; text += CompositingPrefs::compositingNotPossibleReason(); ui.statusTitleWidget->setText(text); ui.statusTitleWidget->setPixmap(KTitleWidget::InfoMessage, KTitleWidget::ImageLeft); ui.statusTitleWidget->show(); setupCompositingState( false, false ); } KAboutData *about = new KAboutData(I18N_NOOP("kcmkwincompositing"), 0, ki18n("KWin Desktop Effects Configuration Module"), 0, KLocalizedString(), KAboutData::License_GPL, ki18n("(c) 2007 Rivo Laks")); about->addAuthor(ki18n("Rivo Laks"), KLocalizedString(), "rivolaks@hot.ee"); setAboutData(about); // search the effect names KServiceTypeTrader* trader = KServiceTypeTrader::self(); KService::List services; QString boxswitch, presentwindows, coverswitch, flipswitch, slide, cube, fadedesktop; // window switcher services = trader->query("KWin/Effect", "[X-KDE-PluginInfo-Name] == 'kwin4_effect_boxswitch'"); if( !services.isEmpty() ) boxswitch = services.first()->name(); services = trader->query("KWin/Effect", "[X-KDE-PluginInfo-Name] == 'kwin4_effect_presentwindows'"); if( !services.isEmpty() ) presentwindows = services.first()->name(); services = trader->query("KWin/Effect", "[X-KDE-PluginInfo-Name] == 'kwin4_effect_coverswitch'"); if( !services.isEmpty() ) coverswitch = services.first()->name(); services = trader->query("KWin/Effect", "[X-KDE-PluginInfo-Name] == 'kwin4_effect_flipswitch'"); if( !services.isEmpty() ) flipswitch = services.first()->name(); // desktop switcher services = trader->query("KWin/Effect", "[X-KDE-PluginInfo-Name] == 'kwin4_effect_slide'"); if( !services.isEmpty() ) slide = services.first()->name(); services = trader->query("KWin/Effect", "[X-KDE-PluginInfo-Name] == 'kwin4_effect_cubeslide'"); if( !services.isEmpty() ) cube = services.first()->name(); services = trader->query("KWin/Effect", "[X-KDE-PluginInfo-Name] == 'kwin4_effect_fadedesktop'"); if( !services.isEmpty() ) fadedesktop = services.first()->name(); // init the combo boxes ui.windowSwitchingCombo->addItem(i18n("No Effect")); ui.windowSwitchingCombo->addItem(boxswitch); ui.windowSwitchingCombo->addItem(presentwindows); ui.windowSwitchingCombo->addItem(coverswitch); ui.windowSwitchingCombo->addItem(flipswitch); ui.desktopSwitchingCombo->addItem(i18n("No Effect")); ui.desktopSwitchingCombo->addItem(slide); ui.desktopSwitchingCombo->addItem(cube); ui.desktopSwitchingCombo->addItem(fadedesktop); } KWinCompositingConfig::~KWinCompositingConfig() { } void KWinCompositingConfig::reparseConfiguration( const QByteArray& conf ) { KSettings::Dispatcher::reparseConfiguration( conf ); } void KWinCompositingConfig::compositingEnabled( bool enabled ) { // Enable the other configuration tabs only when compositing is enabled. ui.compositingOptionsContainer->setEnabled(enabled); ui.tabWidget->setTabEnabled(1, enabled); ui.tabWidget->setTabEnabled(2, enabled); } void KWinCompositingConfig::showConfirmDialog( bool reinitCompositing ) { bool revert = false; // Feel free to extend this to support several kwin instances (multihead) if you // think it makes sense. OrgKdeKWinInterface kwin("org.kde.kwin", "/KWin", QDBusConnection::sessionBus()); if( reinitCompositing ? !kwin.compositingActive().value() : !kwin.waitForCompositingSetup().value() ) { KMessageBox::sorry( this, i18n( "Failed to activate desktop effects using the given " "configuration options. Settings will be reverted to their previous values.\n\n" "Check your X configuration. You may also consider changing advanced options, " "especially changing the compositing type." )); revert = true; } else { ConfirmDialog confirm; if( !confirm.exec()) revert = true; else { // compositing is enabled now setupCompositingState( kwinInterface->compositingActive() ); checkLoadedEffects(); } } if( revert ) { // Revert settings KConfigGroup config(mKWinConfig, "Compositing"); config.deleteGroup(); QMap::const_iterator it = mPreviousConfig.constBegin(); for(; it != mPreviousConfig.constEnd(); ++it) { if (it.value().isEmpty()) continue; config.writeEntry(it.key(), it.value()); } // Sync with KWin and reload configChanged(reinitCompositing); load(); } } void KWinCompositingConfig::initEffectSelector() { // Find all .desktop files of the effects KService::List offers = KServiceTypeTrader::self()->query("KWin/Effect"); QList effectinfos = KPluginInfo::fromServices(offers); // Add them to the plugin selector ui.effectSelector->addPlugins(effectinfos, KPluginSelector::ReadConfigFile, i18n("Appearance"), "Appearance", mTmpConfig); ui.effectSelector->addPlugins(effectinfos, KPluginSelector::ReadConfigFile, i18n("Accessibility"), "Accessibility", mTmpConfig); ui.effectSelector->addPlugins(effectinfos, KPluginSelector::ReadConfigFile, i18n("Focus"), "Focus", mTmpConfig); ui.effectSelector->addPlugins(effectinfos, KPluginSelector::ReadConfigFile, i18n("Window Management"), "Window Management", mTmpConfig); ui.effectSelector->addPlugins(effectinfos, KPluginSelector::ReadConfigFile, i18n("Candy"), "Candy", mTmpConfig); ui.effectSelector->addPlugins(effectinfos, KPluginSelector::ReadConfigFile, i18n("Demos"), "Demos", mTmpConfig); ui.effectSelector->addPlugins(effectinfos, KPluginSelector::ReadConfigFile, i18n("Tests"), "Tests", mTmpConfig); ui.effectSelector->addPlugins(effectinfos, KPluginSelector::ReadConfigFile, i18n("Tools"), "Tools", mTmpConfig); } void KWinCompositingConfig::currentTabChanged(int tab) { // block signals to don't emit the changed()-signal by just switching the current tab blockSignals(true); // write possible changes done to synchronize effect checkboxes and selector // TODO: This segment is prone to fail when the UI is changed; // you'll most likely not think of the hard coded numbers here when just changing the order of the tabs. if (tab == 0) { // General tab was activated saveEffectsTab(); loadGeneralTab(); } else if ( tab == 1 ) { // Effects tab was activated saveGeneralTab(); loadEffectsTab(); } blockSignals(false); } void KWinCompositingConfig::loadGeneralTab() { KConfigGroup config(mKWinConfig, "Compositing"); bool enabled = config.readEntry("Enabled", mDefaultPrefs.recommendCompositing()); ui.useCompositing->setChecked( enabled ); ui.animationSpeedCombo->setCurrentIndex(config.readEntry("AnimationSpeed", 3 )); // Load effect settings KConfigGroup effectconfig(mTmpConfig, "Plugins"); #define LOAD_EFFECT_CONFIG(effectname) effectconfig.readEntry("kwin4_effect_" effectname "Enabled", true) int winManagementEnabled = LOAD_EFFECT_CONFIG("presentwindows") + LOAD_EFFECT_CONFIG("desktopgrid") + LOAD_EFFECT_CONFIG("dialogparent"); if (winManagementEnabled > 0 && winManagementEnabled < 3) { ui.effectWinManagement->setTristate(true); ui.effectWinManagement->setCheckState(Qt::PartiallyChecked); } else ui.effectWinManagement->setChecked(winManagementEnabled); ui.effectShadows->setChecked(LOAD_EFFECT_CONFIG("shadow")); ui.effectAnimations->setChecked(LOAD_EFFECT_CONFIG("minimizeanimation")); #undef LOAD_EFFECT_CONFIG // window switching // Set current option to "none" if no plugin is activated. ui.windowSwitchingCombo->setCurrentIndex( 0 ); KConfigGroup boxswitchconfig(mKWinConfig, "Effect-BoxSwitch"); if( effectEnabled( "boxswitch", effectconfig ) && boxswitchconfig.readEntry("TabBox", true)) ui.windowSwitchingCombo->setCurrentIndex( 1 ); KConfigGroup coverswitchconfig(mKWinConfig, "Effect-CoverSwitch"); if( effectEnabled( "coverswitch", effectconfig ) && coverswitchconfig.readEntry("TabBox", false)) ui.windowSwitchingCombo->setCurrentIndex( 3 ); KConfigGroup flipswitchconfig(mKWinConfig, "Effect-FlipSwitch"); if( effectEnabled( "flipswitch", effectconfig ) && flipswitchconfig.readEntry("TabBox", false)) ui.windowSwitchingCombo->setCurrentIndex( 4 ); KConfigGroup presentwindowsconfig(mKWinConfig, "Effect-PresentWindows"); if( effectEnabled( "presentwindows", effectconfig ) && presentwindowsconfig.readEntry("TabBox", false) ) ui.windowSwitchingCombo->setCurrentIndex( 2 ); // desktop switching // Set current option to "none" if no plugin is activated. ui.desktopSwitchingCombo->setCurrentIndex( 0 ); if( effectEnabled( "slide", effectconfig )) ui.desktopSwitchingCombo->setCurrentIndex( 1 ); if( effectEnabled( "cubeslide", effectconfig )) ui.desktopSwitchingCombo->setCurrentIndex( 2 ); if( effectEnabled( "fadedesktop", effectconfig )) ui.desktopSwitchingCombo->setCurrentIndex( 3 ); if( enabled ) setupCompositingState( kwinInterface->compositingActive() ); else setupCompositingState( false, false ); } void KWinCompositingConfig::setupCompositingState( bool active, bool enabled ) { if( !qgetenv( "KDE_FAILSAFE" ).isNull() ) enabled = false; // compositing state QString stateIcon; QString stateText; QString stateButtonText; if( enabled ) { // check if compositing is active or suspended if( active ) { stateIcon = QString( "dialog-ok-apply" ); stateText = i18n( "Desktop effects are active" ); stateButtonText = i18n( "Suspend Desktop Effects" ); } else { stateIcon = QString( "dialog-cancel" ); stateText = i18n( "Desktop effects are temporarily disabled" ); stateButtonText = i18n( "Resume Desktop Effects" ); } } else { // compositing is disabled stateIcon = QString( "dialog-cancel" ); stateText = i18n( "Desktop effects are disabled" ); stateButtonText = i18n( "Resume Desktop Effects" ); } const int iconSize = (QApplication::fontMetrics().height() > 24) ? 32 : 22; ui.compositingStateIcon->setPixmap( KIcon( stateIcon ).pixmap( iconSize, iconSize ) ); ui.compositingStateLabel->setText( stateText ); ui.compositingStateButton->setText( stateButtonText ); ui.compositingStateIcon->setEnabled( enabled ); ui.compositingStateLabel->setEnabled( enabled ); ui.compositingStateButton->setEnabled( enabled ); } void KWinCompositingConfig::toogleSmoothScaleUi( int compositingType ) { ui.glScaleFilter->setVisible( compositingType == OPENGL_INDEX ); ui.xrScaleFilter->setVisible( compositingType == XRENDER_INDEX ); ui.scaleMethodLabel->setBuddy( compositingType == XRENDER_INDEX ? ui.xrScaleFilter : ui.glScaleFilter ); } bool KWinCompositingConfig::effectEnabled( const QString& effect, const KConfigGroup& cfg ) const { KService::List services = KServiceTypeTrader::self()->query( "KWin/Effect", "[X-KDE-PluginInfo-Name] == 'kwin4_effect_" + effect + '\''); if( services.isEmpty()) return false; QVariant v = services.first()->property("X-KDE-PluginInfo-EnabledByDefault"); return cfg.readEntry("kwin4_effect_" + effect + "Enabled", v.toBool()); } void KWinCompositingConfig::loadEffectsTab() { ui.effectSelector->load(); } void KWinCompositingConfig::loadAdvancedTab() { KConfigGroup config(mKWinConfig, "Compositing"); QString backend = config.readEntry("Backend", "OpenGL"); ui.compositingType->setCurrentIndex((backend == "XRender") ? XRENDER_INDEX : 0); // 4 - off, 5 - shown, 6 - always, other are old values int hps = config.readEntry("HiddenPreviews", 5); if( hps == 6 ) // always ui.windowThumbnails->setCurrentIndex( 0 ); else if( hps == 4 ) // never ui.windowThumbnails->setCurrentIndex( 2 ); else // shown, or default ui.windowThumbnails->setCurrentIndex( 1 ); ui.disableChecks->setChecked( config.readEntry( "DisableChecks", false )); ui.unredirectFullscreen->setChecked( config.readEntry( "UnredirectFullscreen", true )); ui.xrScaleFilter->setCurrentIndex((int)config.readEntry("XRenderSmoothScale", false)); ui.glScaleFilter->setCurrentIndex(config.readEntry("GLTextureFilter", 2)); QString glMode = config.readEntry("GLMode", "TFP"); ui.glMode->setCurrentIndex((glMode == "TFP") ? 0 : ((glMode == "SHM") ? 1 : 2)); ui.glDirect->setChecked(config.readEntry("GLDirect", mDefaultPrefs.enableDirectRendering())); ui.glVSync->setChecked(config.readEntry("GLVSync", mDefaultPrefs.enableVSync())); toogleSmoothScaleUi( ui.compositingType->currentIndex() ); } void KWinCompositingConfig::load() { mKWinConfig->reparseConfiguration(); // Copy Plugins group to temp config file QMap entries = mKWinConfig->entryMap("Plugins"); QMap::const_iterator it = entries.constBegin(); KConfigGroup tmpconfig(mTmpConfig, "Plugins"); tmpconfig.deleteGroup(); for(; it != entries.constEnd(); ++it) tmpconfig.writeEntry(it.key(), it.value()); loadGeneralTab(); loadEffectsTab(); loadAdvancedTab(); emit changed( false ); } void KWinCompositingConfig::saveGeneralTab() { KConfigGroup config(mKWinConfig, "Compositing"); // Check if any critical settings that need confirmation have changed if(ui.useCompositing->isChecked() && ui.useCompositing->isChecked() != config.readEntry("Enabled", mDefaultPrefs.recommendCompositing())) m_showConfirmDialog = true; config.writeEntry("Enabled", ui.useCompositing->isChecked()); config.writeEntry("AnimationSpeed", ui.animationSpeedCombo->currentIndex()); // disable the compositing state if compositing was turned off if( !ui.useCompositing->isChecked() ) setupCompositingState( false, false ); // Save effects KConfigGroup effectconfig(mTmpConfig, "Plugins"); #define WRITE_EFFECT_CONFIG(effectname, widget) effectconfig.writeEntry("kwin4_effect_" effectname "Enabled", widget->isChecked()) if (ui.effectWinManagement->checkState() != Qt::PartiallyChecked) { WRITE_EFFECT_CONFIG("presentwindows", ui.effectWinManagement); WRITE_EFFECT_CONFIG("desktopgrid", ui.effectWinManagement); WRITE_EFFECT_CONFIG("dialogparent", ui.effectWinManagement); } WRITE_EFFECT_CONFIG("shadow", ui.effectShadows); // TODO: maybe also do some effect-specific configuration here, e.g. // enable/disable desktopgrid's animation according to this setting WRITE_EFFECT_CONFIG("minimizeanimation", ui.effectAnimations); #undef WRITE_EFFECT_CONFIG int windowSwitcher = ui.windowSwitchingCombo->currentIndex(); bool boxSwitch = false; bool presentWindowSwitching = false; bool coverSwitch = false; bool flipSwitch = false; switch( windowSwitcher ) { case 1: boxSwitch = true; break; case 2: presentWindowSwitching = true; break; case 3: coverSwitch = true; break; case 4: flipSwitch = true; break; default: break; // nothing } // activate effects if not active if( boxSwitch ) effectconfig.writeEntry("kwin4_effect_boxswitchEnabled", true); if( presentWindowSwitching ) effectconfig.writeEntry("kwin4_effect_presentwindowsEnabled", true); if( coverSwitch ) effectconfig.writeEntry("kwin4_effect_coverswitchEnabled", true); if( flipSwitch ) effectconfig.writeEntry("kwin4_effect_flipswitchEnabled", true); KConfigGroup boxswitchconfig( mKWinConfig, "Effect-BoxSwitch" ); boxswitchconfig.writeEntry( "TabBox", boxSwitch ); boxswitchconfig.sync(); KConfigGroup presentwindowsconfig( mKWinConfig, "Effect-PresentWindows" ); presentwindowsconfig.writeEntry( "TabBox", presentWindowSwitching ); presentwindowsconfig.sync(); KConfigGroup coverswitchconfig( mKWinConfig, "Effect-CoverSwitch" ); coverswitchconfig.writeEntry( "TabBox", coverSwitch ); coverswitchconfig.sync(); KConfigGroup flipswitchconfig( mKWinConfig, "Effect-FlipSwitch" ); flipswitchconfig.writeEntry( "TabBox", flipSwitch ); flipswitchconfig.sync(); int desktopSwitcher = ui.desktopSwitchingCombo->currentIndex(); switch( desktopSwitcher ) { case 0: // no effect effectconfig.writeEntry("kwin4_effect_slideEnabled", false); effectconfig.writeEntry("kwin4_effect_cubeslideEnabled", false); effectconfig.writeEntry("kwin4_effect_fadedesktopEnabled", false); break; case 1: // slide effectconfig.writeEntry("kwin4_effect_slideEnabled", true); effectconfig.writeEntry("kwin4_effect_cubeslideEnabled", false); effectconfig.writeEntry("kwin4_effect_fadedesktopEnabled", false); break; case 2: // cube effectconfig.writeEntry("kwin4_effect_slideEnabled", false); effectconfig.writeEntry("kwin4_effect_cubeslideEnabled", true); effectconfig.writeEntry("kwin4_effect_fadedesktopEnabled", false); break; case 3: // fadedesktop effectconfig.writeEntry("kwin4_effect_slideEnabled", false); effectconfig.writeEntry("kwin4_effect_cubeslideEnabled", false); effectconfig.writeEntry("kwin4_effect_fadedesktopEnabled", true); break; } } void KWinCompositingConfig::saveEffectsTab() { ui.effectSelector->save(); } bool KWinCompositingConfig::saveAdvancedTab() { bool advancedChanged = false; static const int hps[] = { 6 /*always*/, 5 /*shown*/, 4 /*never*/ }; KConfigGroup config(mKWinConfig, "Compositing"); QString glModes[] = { "TFP", "SHM", "Fallback" }; if( config.readEntry("Backend", "OpenGL") != ((ui.compositingType->currentIndex() == 0) ? "OpenGL" : "XRender") || config.readEntry("GLMode", "TFP") != glModes[ui.glMode->currentIndex()] || config.readEntry("GLDirect", mDefaultPrefs.enableDirectRendering()) != ui.glDirect->isChecked() || config.readEntry("GLVSync", mDefaultPrefs.enableVSync()) != ui.glVSync->isChecked() || config.readEntry("DisableChecks", false ) != ui.disableChecks->isChecked()) { m_showConfirmDialog = true; advancedChanged = true; } else if( config.readEntry("HiddenPreviews", 5) != hps[ ui.windowThumbnails->currentIndex() ] || (int)config.readEntry("XRenderSmoothScale", false ) != ui.xrScaleFilter->currentIndex() || config.readEntry("GLTextureFilter", 2 ) != ui.glScaleFilter->currentIndex()) advancedChanged = true; config.writeEntry("Backend", (ui.compositingType->currentIndex() == OPENGL_INDEX) ? "OpenGL" : "XRender"); config.writeEntry("HiddenPreviews", hps[ ui.windowThumbnails->currentIndex() ] ); config.writeEntry("DisableChecks", ui.disableChecks->isChecked()); config.writeEntry( "UnredirectFullscreen", ui.unredirectFullscreen->isChecked() ); config.writeEntry("XRenderSmoothScale", ui.xrScaleFilter->currentIndex() == 1); config.writeEntry("GLTextureFilter", ui.glScaleFilter->currentIndex()); config.writeEntry("GLMode", glModes[ui.glMode->currentIndex()]); config.writeEntry("GLDirect", ui.glDirect->isChecked()); config.writeEntry("GLVSync", ui.glVSync->isChecked()); return advancedChanged; } void KWinCompositingConfig::save() { // Save current config. We'll use this for restoring in case something goes wrong. KConfigGroup config(mKWinConfig, "Compositing"); mPreviousConfig = config.entryMap(); // bah; tab content being dependent on the other is really bad; and // deprecated in the HIG for a reason. It is confusing! // Make sure we only call save on each tab once; as they are stateful due to the revert concept if ( ui.tabWidget->currentIndex() == 0 ) // "General" tab was active { saveGeneralTab(); loadEffectsTab(); saveEffectsTab(); } else { saveEffectsTab(); loadGeneralTab(); saveGeneralTab(); } bool advancedChanged = saveAdvancedTab(); // Copy Plugins group from temp config to real config QMap entries = mTmpConfig->entryMap("Plugins"); QMap::const_iterator it = entries.constBegin(); KConfigGroup realconfig(mKWinConfig, "Plugins"); realconfig.deleteGroup(); for(; it != entries.constEnd(); ++it) realconfig.writeEntry(it.key(), it.value()); emit changed( false ); configChanged(advancedChanged); // This assumes that this KCM is running with the same environment variables as KWin // TODO: Detect KWIN_COMPOSE=N as well if( !qgetenv( "KDE_FAILSAFE" ).isNull() && ui.useCompositing->isChecked() ) { KMessageBox::sorry( this, i18n( "Your settings have been saved but as KDE is currently running in failsafe " "mode desktop effects cannot be enabled at this time.\n\n" "Please exit failsafe mode to enable desktop effects." )); m_showConfirmDialog = false; // Dangerous but there is no way to test if failsafe mode } if(m_showConfirmDialog) { m_showConfirmDialog = false; showConfirmDialog(advancedChanged); } } void KWinCompositingConfig::checkLoadedEffects() { // check for effects not supported by Backend or hardware // such effects are enabled but not returned by DBus method loadedEffects QDBusMessage message = QDBusMessage::createMethodCall( "org.kde.kwin", "/KWin", "org.kde.KWin", "loadedEffects" ); QDBusMessage reply = QDBusConnection::sessionBus().call( message ); KConfigGroup effectConfig = KConfigGroup( mKWinConfig, "Compositing" ); bool enabledAfter = effectConfig.readEntry( "Enabled", mDefaultPrefs.recommendCompositing() ); if( reply.type() == QDBusMessage::ReplyMessage && enabledAfter && !getenv( "KDE_FAILSAFE" )) { effectConfig = KConfigGroup( mKWinConfig, "Plugins" ); QStringList loadedEffects = reply.arguments()[0].toStringList(); QStringList effects = effectConfig.keyList(); QStringList disabledEffects = QStringList(); foreach( QString effect, effects ) // krazy:exclude=foreach { QString temp = effect.mid( 13, effect.length() - 13 - 7 ); effect.truncate( effect.length() - 7 ); if( effectEnabled( temp, effectConfig ) && !loadedEffects.contains( effect ) ) { disabledEffects << effect; } } if( !disabledEffects.isEmpty() ) { KServiceTypeTrader* trader = KServiceTypeTrader::self(); KService::List services; QString message = i18n( "The following desktop effects could not be activated:" ); message.append( "
    " ); foreach( const QString &effect, disabledEffects ) { services = trader->query("KWin/Effect", "[X-KDE-PluginInfo-Name] == '" + effect + '\''); message.append( "
  • " ); if( !services.isEmpty() ) message.append( services.first()->name() ); else message.append( effect); message.append( "
  • " ); } message.append( "
" ); KNotification::event( "effectsnotsupported", message, QPixmap(), NULL, KNotification::CloseOnTimeout, KComponentData( "kwin" ) ); } } } void KWinCompositingConfig::configChanged(bool reinitCompositing) { // Send signal to kwin mKWinConfig->sync(); // Send signal to all kwin instances QDBusMessage message = QDBusMessage::createSignal("/KWin", "org.kde.KWin", reinitCompositing ? "reinitCompositing" : "reloadConfig"); QDBusConnection::sessionBus().send(message); // HACK: We can't just do this here, due to the asynchronous nature of signals. // We also can't change reinitCompositing into a message (which would allow // callWithCallbac() to do this neater) due to multiple kwin instances. if( !m_showConfirmDialog ) QTimer::singleShot(1000, this, SLOT(checkLoadedEffects())); } void KWinCompositingConfig::defaults() { ui.tabWidget->setCurrentIndex(0); ui.useCompositing->setChecked(mDefaultPrefs.recommendCompositing()); ui.effectWinManagement->setChecked(true); ui.effectShadows->setChecked(true); ui.effectAnimations->setChecked(true); ui.windowSwitchingCombo->setCurrentIndex( 1 ); ui.desktopSwitchingCombo->setCurrentIndex( 1 ); ui.animationSpeedCombo->setCurrentIndex( 3 ); ui.effectSelector->defaults(); ui.compositingType->setCurrentIndex( 0 ); ui.windowThumbnails->setCurrentIndex( 1 ); ui.disableChecks->setChecked( false ); ui.unredirectFullscreen->setChecked( true ); ui.xrScaleFilter->setCurrentIndex( 0 ); ui.glScaleFilter->setCurrentIndex( 2 ); ui.glMode->setCurrentIndex( 0 ); ui.glDirect->setChecked( mDefaultPrefs.enableDirectRendering() ); ui.glVSync->setChecked( mDefaultPrefs.enableVSync() ); } QString KWinCompositingConfig::quickHelp() const { return i18n("

Desktop Effects

"); } } // namespace #include "main.moc"