/* $Id$ This is the new kwindecoration kcontrol module Copyright (c) 2001 Karol Szwed http://gallium.n3.net/ Supports new kwin configuration plugins, and titlebar button position modification via dnd interface. Based on original "kwintheme" (Window Borders) Copyright (C) 2001 Rik Hemsley (rikkus) */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kwindecoration.h" // KCModule plugin interface // ========================= typedef KGenericFactory KWinDecoFactory; K_EXPORT_COMPONENT_FACTORY( kcm_kwindecoration, KWinDecoFactory("kcmkwindecoration") ); KWinDecorationModule::KWinDecorationModule(QWidget* parent, const char* name, const QStringList &) : KCModule(KWinDecoFactory::instance(), parent, name), DCOPObject("KWinClientDecoration") { KConfig kwinConfig("kwinrc"); kwinConfig.setGroup("Style"); QVBoxLayout* layout = new QVBoxLayout(this); tabWidget = new QTabWidget( this ); layout->addWidget( tabWidget ); // Page 1 (General Options) QVBox* page1 = new QVBox( tabWidget ); page1->setSpacing( KDialog::spacingHint() ); page1->setMargin( KDialog::marginHint() ); QGroupBox* btnGroup = new QGroupBox( 1, Qt::Horizontal, i18n("Window Decoration"), page1 ); QWhatsThis::add( btnGroup, i18n("Select the window decoration. This is the look and feel of both " "the window borders and the window handle.") ); decorationListBox = new QListBox( btnGroup ); QGroupBox* checkGroup = new QGroupBox( 1, Qt::Horizontal, i18n("General Options (if available)"), page1 ); cbUseCustomButtonPositions = new QCheckBox( i18n("Use custom titlebar button &positions"), checkGroup ); QWhatsThis::add( cbUseCustomButtonPositions, i18n( "The appropriate settings can be found in the \"Buttons\" Tab. " "Please note that this option is not available on all styles yet!" ) ); cbShowToolTips = new QCheckBox( i18n("&Show window button tooltips"), checkGroup ); QWhatsThis::add( cbShowToolTips, i18n( "Enabling this checkbox will show window button tooltips. " "If this checkbox is off, no window button tooltips will be shown.")); // Save this for later... // cbUseMiniWindows = new QCheckBox( i18n( "Render mini &titlebars for all windows"), checkGroup ); // QWhatsThis::add( cbUseMiniWindows, i18n( "Note that this option is not available on all styles yet!" ) ); // Page 2 (Button Selector) buttonPage = new QVBox( tabWidget ); buttonPage->setSpacing( KDialog::spacingHint() ); buttonPage->setMargin( KDialog::marginHint() ); QGroupBox* buttonBox = new QGroupBox( 1, Qt::Horizontal, i18n("Titlebar Button Position"), buttonPage ); // Add nifty dnd button modification widgets QLabel* label = new QLabel( buttonBox ); dropSite = new ButtonDropSite( buttonBox ); label->setText( i18n( "To add or remove titlebar buttons, simply drag items " "between the available item list and the titlebar preview. Similarly, " "drag items within the titlebar preview to re-position them.") ); buttonSource = new ButtonSource( buttonBox ); // Page 3 (Configure decoration via client plugin page) pluginPage = new QVBox( tabWidget ); pluginPage->setSpacing( KDialog::spacingHint() ); pluginPage->setMargin( KDialog::marginHint() ); pluginObject = NULL; // Load all installed decorations into memory // Set up the decoration lists and other UI settings findDecorations(); createDecorationList(); readConfig( &kwinConfig ); resetPlugin( &kwinConfig ); tabWidget->insertTab( page1, i18n("&General") ); tabWidget->insertTab( buttonPage, i18n("&Buttons") ); tabWidget->insertTab( pluginPage, i18n("&Configure [") + decorationListBox->currentText() + i18n("]") ); tabWidget->setTabEnabled( buttonPage, cbUseCustomButtonPositions->isChecked() ); tabWidget->setTabEnabled( pluginPage, pluginObject ? true : false ); connect( dropSite, SIGNAL(buttonAdded(char)), buttonSource, SLOT(hideButton(char)) ); connect( dropSite, SIGNAL(buttonRemoved(char)), buttonSource, SLOT(showButton(char)) ); connect( buttonSource, SIGNAL(buttonDropped()), dropSite, SLOT(removeClickedButton()) ); connect( dropSite, SIGNAL(changed()), this, SLOT(slotSelectionChanged()) ); connect( buttonSource, SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged()) ); connect( decorationListBox, SIGNAL(selectionChanged()), SLOT(slotSelectionChanged()) ); connect( decorationListBox, SIGNAL(highlighted(const QString&)), SLOT(slotDecorationHighlighted(const QString&)) ); connect( cbUseCustomButtonPositions, SIGNAL(clicked()), SLOT(slotSelectionChanged()) ); connect( cbUseCustomButtonPositions, SIGNAL(toggled(bool)), SLOT(slotEnableButtonTab(bool)) ); connect( cbShowToolTips, SIGNAL(clicked()), SLOT(slotSelectionChanged()) ); // connect( cbUseMiniWindows, SIGNAL(clicked()), SLOT(slotSelectionChanged()) ); // Allow kwin dcop signal to update our selection list connectDCOPSignal("kwin", 0, "dcopResetAllClients()", "dcopUpdateClientList()", false); } KWinDecorationModule::~KWinDecorationModule() { } // Find all theme desktop files in all 'data' dirs owned by kwin. // And insert these into a DecorationInfo structure void KWinDecorationModule::findDecorations() { QStringList dirList = KGlobal::dirs()->findDirs("data", "kwin"); QStringList::ConstIterator it; for (it = dirList.begin(); it != dirList.end(); it++) { QDir d(*it); if (d.exists()) for (QFileInfoListIterator it(*d.entryInfoList()); it.current(); ++it) { QString filename(it.current()->absFilePath()); if (KDesktopFile::isDesktopFile(filename)) { KDesktopFile desktopFile(filename); QString libName = desktopFile.readEntry("X-KDE-Library"); if (!libName.isEmpty()) { DecorationInfo di; di.name = desktopFile.readName(); di.libraryName = libName; decorations.append( di ); } } } } } // Fills the decorationListBox with a list of available kwin decorations void KWinDecorationModule::createDecorationList() { QValueList::ConstIterator it; // Sync with kwin hardcoded KDE2 style which has no desktop item decorationListBox->insertItem( i18n("KDE 2") ); for (it = decorations.begin(); it != decorations.end(); ++it) { DecorationInfo info = *it; decorationListBox->insertItem( info.name ); } decorationListBox->sort(); } // Reset the decoration plugin to what the user just selected void KWinDecorationModule::slotDecorationHighlighted( const QString& s ) { KConfig kwinConfig("kwinrc"); kwinConfig.setGroup("Style"); // Let the user see config options for the currently selected decoration resetPlugin( &kwinConfig, &s ); tabWidget->setTabEnabled( pluginPage, pluginObject ? true : false ); tabWidget->changeTab( pluginPage, i18n("&Configure [%1]").arg( decorationListBox->currentText() ) ); } // This is the selection handler setting void KWinDecorationModule::slotSelectionChanged() { emit changed(true); } void KWinDecorationModule::slotEnableButtonTab(bool on) { tabWidget->setTabEnabled( buttonPage, on ); } QString KWinDecorationModule::decorationName( QString& libName ) { QString decoName; QValueList::Iterator it; for( it = decorations.begin(); it != decorations.end(); ++it ) if ( (*it).libraryName == libName ) { decoName = (*it).name; break; } return decoName; } QString KWinDecorationModule::decorationLibName( const QString& name ) { QString libName; // Find the corresponding library name to that of // the current plugin name QValueList::Iterator it; for( it = decorations.begin(); it != decorations.end(); ++it ) if ( (*it).name == name ) { libName = (*it).libraryName; break; } if (libName.isEmpty()) libName = "kwin_default"; // KDE 2 return libName; } // Loads/unloads and inserts the decoration config plugin into the // pluginPage, allowing for dynamic configuration of decorations void KWinDecorationModule::resetPlugin( KConfig* conf, const QString* currentDecoName ) { // Config names are "kwin_icewm_config" // for "kwin_icewm" kwin client QString oldName = oldLibraryName; oldName += "_config"; QString currentName; if (currentDecoName) currentName = decorationLibName( *currentDecoName ); // Use what the user selected else currentName = currentLibraryName; // Use what was read from readConfig() currentName += "_config"; // Delete old plugin widget if it exists if (pluginObject) delete pluginObject; // Use klibloader for library manipulation KLibLoader* loader = KLibLoader::self(); // Free the old library if possible if (!oldLibraryName.isNull()) loader->unloadLibrary( QFile::encodeName(oldName) ); KLibrary* library = loader->library( QFile::encodeName(currentName) ); if (library != NULL) { void* alloc_ptr = library->symbol("allocate_config"); if (alloc_ptr != NULL) { allocatePlugin = (QObject* (*)(KConfig* conf, QWidget* parent))alloc_ptr; pluginObject = allocatePlugin( conf, pluginPage ); // connect required signals and slots together... connect( pluginObject, SIGNAL(changed()), this, SLOT(slotSelectionChanged()) ); connect( this, SIGNAL(pluginLoad(KConfig*)), pluginObject, SLOT(load(KConfig*)) ); connect( this, SIGNAL(pluginSave(KConfig*)), pluginObject, SLOT(save(KConfig*)) ); connect( this, SIGNAL(pluginDefaults()), pluginObject, SLOT(defaults()) ); return; } } pluginObject = NULL; } // Reads the kwin config settings, and sets all UI controls to those settings // Updating the config plugin if required void KWinDecorationModule::readConfig( KConfig* conf ) { // General tab // ============ cbUseCustomButtonPositions->setChecked( conf->readBoolEntry("CustomButtonPositions", false)); tabWidget->setTabEnabled( buttonPage, cbUseCustomButtonPositions->isChecked() ); cbShowToolTips->setChecked( conf->readBoolEntry("ShowToolTips", true )); // cbUseMiniWindows->setChecked( conf->readBoolEntry("MiniWindowBorders", false)); // Find the corresponding decoration name to that of // the current plugin library name oldLibraryName = currentLibraryName; currentLibraryName = conf->readEntry("PluginLib", ((QPixmap::defaultDepth() > 8) ? "kwin_keramik" : "kwin_quartz")); QString decoName = decorationName( currentLibraryName ); // If we are using the "default" kde client, use the "default" entry. if (decoName.isEmpty()) decorationListBox->setSelected( decorationListBox->findItem( i18n("KDE 2") ), true ); else // Update the decoration listbox decorationListBox->setSelected( decorationListBox->findItem( decoName ), true); // Buttons tab // ============ // Menu and sticky buttons are default on LHS dropSite->buttonsLeft = conf->readEntry("ButtonsOnLeft", "MS"); // Help, Minimize, Maximize and Close are default on RHS dropSite->buttonsRight = conf->readEntry("ButtonsOnRight", "HIAX"); dropSite->repaint(false); buttonSource->showAllButtons(); // Step through the button lists, and hide the dnd button source items unsigned int i; for(i = 0; i < dropSite->buttonsLeft.length(); i++) buttonSource->hideButton( dropSite->buttonsLeft[i].latin1() ); for(i = 0; i < dropSite->buttonsRight.length(); i++) buttonSource->hideButton( dropSite->buttonsRight[i].latin1() ); emit changed(false); } // Writes the selected user configuration to the kwin config file void KWinDecorationModule::writeConfig( KConfig* conf ) { QString name = decorationListBox->currentText(); QString libName = decorationLibName( name ); KConfig kwinConfig("kwinrc"); kwinConfig.setGroup("Style"); // General settings conf->writeEntry("PluginLib", libName); conf->writeEntry("CustomButtonPositions", cbUseCustomButtonPositions->isChecked()); conf->writeEntry("ShowToolTips", cbShowToolTips->isChecked()); // conf->writeEntry("MiniWindowBorders", cbUseMiniWindows->isChecked()); // Button settings conf->writeEntry("ButtonsOnLeft", dropSite->buttonsLeft ); conf->writeEntry("ButtonsOnRight", dropSite->buttonsRight ); oldLibraryName = currentLibraryName; currentLibraryName = libName; // We saved, so tell kcmodule that there have been no new user changes made. emit changed(false); } void KWinDecorationModule::dcopUpdateClientList() { // Changes the current active ListBox item, and // Loads a new plugin configuration tab if required. KConfig kwinConfig("kwinrc"); kwinConfig.setGroup("Style"); readConfig( &kwinConfig ); resetPlugin( &kwinConfig ); } // Virutal functions required by KCModule void KWinDecorationModule::load() { KConfig kwinConfig("kwinrc"); kwinConfig.setGroup("Style"); // Reset by re-reading the config // The plugin doesn't need changing, as we have not saved readConfig( &kwinConfig ); emit pluginLoad( &kwinConfig ); } void KWinDecorationModule::save() { KConfig kwinConfig("kwinrc"); kwinConfig.setGroup("Style"); writeConfig( &kwinConfig ); emit pluginSave( &kwinConfig ); kwinConfig.sync(); resetKWin(); // resetPlugin() will get called via the above DCOP function } void KWinDecorationModule::defaults() { // Set the KDE defaults cbUseCustomButtonPositions->setChecked( false ); cbShowToolTips->setChecked( true ); // cbUseMiniWindows->setChecked( false); // Don't set default for now // decorationListBox->setSelected( // decorationListBox->findItem( i18n("KDE 2") ), true ); // KDE classic client dropSite->buttonsLeft = "MS"; dropSite->buttonsRight= "HIAX"; dropSite->repaint(false); buttonSource->showAllButtons(); buttonSource->hideButton('M'); buttonSource->hideButton('S'); buttonSource->hideButton('H'); buttonSource->hideButton('I'); buttonSource->hideButton('A'); buttonSource->hideButton('X'); // Set plugin defaults emit pluginDefaults(); } QString KWinDecorationModule::quickHelp() const { return i18n( "

Window Decorations

" "This module allows you to choose the window border decorations, " "as well as titlebar button positions and custom decoration options."); } const KAboutData* KWinDecorationModule::aboutData() const { KAboutData* about = new KAboutData(I18N_NOOP("kcmkwindecoration"), I18N_NOOP("Window Decoration Control Module"), 0, 0, KAboutData::License_GPL, I18N_NOOP("(c) 2001 Karol Szwed")); about->addAuthor("Karol Szwed", 0, "gallium@kde.org"); return about; } void KWinDecorationModule::resetKWin() { bool ok = kapp->dcopClient()->send("kwin", "KWinInterface", "reconfigure()", QByteArray()); if (!ok) kdDebug() << "kcmkwindecoration: Could not reconfigure kwin" << endl; } #include "kwindecoration.moc" // vim: ts=4