Make a branch to make krunner Good Enough For Aaron™.
[kdebase/uwolfer.git] / workspace / kwin / kcmkwin / kwindecoration / kwindecoration.cpp
blob35e7d16c13d306070e52bc82ac3c3d55d71b15cb
1 /*
2 This is the new kwindecoration kcontrol module
4 Copyright (c) 2001
5 Karol Szwed <gallium@kde.org>
6 http://gallium.n3.net/
8 Supports new kwin configuration plugins, and titlebar button position
9 modification via dnd interface.
11 Based on original "kwintheme" (Window Borders)
12 Copyright (C) 2001 Rik Hemsley (rikkus) <rik@kde.org>
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
30 #include <assert.h>
31 #include <QDir>
32 #include <QFileInfo>
33 #include <QLayout>
35 #include <QGroupBox>
36 #include <QGridLayout>
37 #include <QCheckBox>
38 #include <QTabWidget>
40 #include <QLabel>
41 #include <QFile>
42 #include <QSlider>
43 //Added by qt3to4:
44 #include <QPixmap>
45 #include <QHBoxLayout>
46 #include <QVBoxLayout>
48 #include <QtDBus/QtDBus>
50 #include <kapplication.h>
51 #include <kcombobox.h>
52 #include <kdebug.h>
53 #include <kdesktopfile.h>
54 #include <kstandarddirs.h>
55 #include <kglobal.h>
56 #include <klocale.h>
57 #include <kdialog.h>
58 #include <kaboutdata.h>
60 #include "kwindecoration.h"
61 #include "preview.h"
62 #include <kdecoration_plugins_p.h>
63 #include <kdecorationfactory.h>
64 #include <kvbox.h>
65 #include <KPluginFactory>
66 #include <KPluginLoader>
68 // KCModule plugin interface
69 // =========================
70 K_PLUGIN_FACTORY(KWinDecoFactory,
71 registerPlugin<KWinDecorationModule>();
73 K_EXPORT_PLUGIN(KWinDecoFactory("kcmkwindecoration"))
75 KWinDecorationModule::KWinDecorationModule(QWidget* parent, const QVariantList &)
76 : KCModule(KWinDecoFactory::componentData(), parent),
77 kwinConfig(KSharedConfig::openConfig("kwinrc")),
78 pluginObject(0)
80 KConfigGroup style( kwinConfig, "Style");
81 plugins = new KDecorationPreviewPlugins(kwinConfig);
83 QVBoxLayout* layout = new QVBoxLayout(this);
84 layout->setMargin(0);
85 layout->setSpacing(KDialog::spacingHint());
87 // Save this for later...
88 // cbUseMiniWindows = new QCheckBox( i18n( "Render mini &titlebars for all windows"), checkGroup );
89 // QWhatsThis::add( cbUseMiniWindows, i18n( "Note that this option is not available on all styles yet" ) );
91 tabWidget = new QTabWidget( this );
92 layout->addWidget( tabWidget );
94 // Page 1 (General Options)
95 QWidget *pluginPage = new QWidget( tabWidget );
97 QVBoxLayout* pluginLayout = new QVBoxLayout(pluginPage);
98 pluginLayout->setMargin(KDialog::marginHint());
99 pluginLayout->setSpacing(KDialog::spacingHint());
101 // decoration chooser
102 decorationList = new KComboBox( pluginPage );
103 QString whatsThis = i18n("Select the window decoration. This is the look and feel of both "
104 "the window borders and the window handle.");
105 decorationList->setWhatsThis( whatsThis);
106 pluginLayout->addWidget(decorationList);
108 pluginSettingsGrp = new QGroupBox( i18n("Decoration Options"), pluginPage );
109 QGridLayout *pluginSettingsLayout = new QGridLayout();
110 pluginSettingsGrp->setFlat( true );
111 pluginSettingsLayout->setMargin( 0 );
112 pluginSettingsLayout->setSpacing( KDialog::spacingHint() );
113 pluginSettingsGrp->setLayout( pluginSettingsLayout );
114 pluginLayout->addWidget( pluginSettingsGrp );
116 pluginLayout->addStretch();
118 // Border size chooser
119 lBorder = new QLabel (i18n("B&order size:"), pluginSettingsGrp);
120 cBorder = new QComboBox(pluginSettingsGrp);
121 lBorder->setBuddy(cBorder);
122 cBorder->setWhatsThis( i18n( "Use this combobox to change the border size of the decoration." ));
123 lBorder->hide();
124 cBorder->hide();
125 QHBoxLayout *borderSizeLayout = new QHBoxLayout();
126 pluginSettingsGrp->layout()->addItem( borderSizeLayout );
127 borderSizeLayout->addWidget(lBorder);
128 borderSizeLayout->addWidget(cBorder);
129 borderSizeLayout->addStretch();
131 pluginConfigWidget = new KVBox(pluginSettingsGrp);
132 pluginSettingsGrp->layout()->addWidget( pluginConfigWidget );
134 // Page 2 (Button Selector)
135 QWidget* buttonPage = new QWidget( tabWidget );
136 QVBoxLayout* buttonLayout = new QVBoxLayout(buttonPage);
137 buttonLayout->setMargin(KDialog::marginHint());
138 buttonLayout->setSpacing(KDialog::spacingHint());
140 cbShowToolTips = new QCheckBox(
141 i18n("&Show window button tooltips"), buttonPage );
142 cbShowToolTips->setWhatsThis(
143 i18n( "Enabling this checkbox will show window button tooltips. "
144 "If this checkbox is off, no window button tooltips will be shown."));
146 cbUseCustomButtonPositions = new QCheckBox(
147 i18n("Use custom titlebar button &positions"), buttonPage );
148 cbUseCustomButtonPositions->setWhatsThis(
149 i18n( "The appropriate settings can be found in the \"Buttons\" Tab; "
150 "please note that this option is not available on all styles yet." ) );
152 buttonLayout->addWidget( cbShowToolTips );
153 buttonLayout->addWidget( cbUseCustomButtonPositions );
155 // Add nifty dnd button modification widgets
156 buttonPositionWidget = new ButtonPositionWidget(buttonPage, "button_position_widget");
157 buttonPositionWidget->setDecorationFactory(plugins->factory() );
158 QHBoxLayout* buttonControlLayout = new QHBoxLayout();
159 buttonLayout->addLayout( buttonControlLayout );
160 buttonControlLayout->addSpacing(20);
161 buttonControlLayout->addWidget(buttonPositionWidget);
162 // buttonLayout->addStretch();
164 // preview
165 QVBoxLayout* previewLayout = new QVBoxLayout();
166 previewLayout->setSpacing( KDialog::spacingHint() );
167 layout->addLayout( previewLayout );
168 previewLayout->setMargin( KDialog::marginHint() );
170 preview = new KDecorationPreview( this );
171 previewLayout->addWidget(preview);
173 preview->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
174 tabWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
176 // Load all installed decorations into memory
177 // Set up the decoration lists and other UI settings
178 findDecorations();
179 createDecorationList();
180 readConfig( style );
182 resetPlugin( style );
184 tabWidget->addTab( pluginPage, i18n("&Window Decoration") );
185 tabWidget->addTab( buttonPage, i18n("&Buttons") );
187 connect( buttonPositionWidget, SIGNAL(changed()), this, SLOT(slotButtonsChanged()) ); // update preview etc.
188 connect( buttonPositionWidget, SIGNAL(changed()), this, SLOT(slotSelectionChanged()) ); // emit changed()...
189 connect( decorationList, SIGNAL(activated(const QString&)), SLOT(slotSelectionChanged()) );
190 connect( decorationList, SIGNAL(activated(const QString&)),
191 SLOT(slotChangeDecoration(const QString&)) );
192 connect( cbUseCustomButtonPositions, SIGNAL(clicked()), SLOT(slotSelectionChanged()) );
193 connect(cbUseCustomButtonPositions, SIGNAL(toggled(bool)), buttonPositionWidget, SLOT(setEnabled(bool)));
194 connect(cbUseCustomButtonPositions, SIGNAL(toggled(bool)), this, SLOT(slotButtonsChanged()) );
195 connect( cbShowToolTips, SIGNAL(clicked()), SLOT(slotSelectionChanged()) );
196 connect( cBorder, SIGNAL( activated( int )), SLOT( slotBorderChanged( int )));
197 // connect( cbUseMiniWindows, SIGNAL(clicked()), SLOT(slotSelectionChanged()) );
199 KAboutData *about =
200 new KAboutData(I18N_NOOP("kcmkwindecoration"), 0,
201 ki18n("Window Decoration Control Module"),
202 0, KLocalizedString(), KAboutData::License_GPL,
203 ki18n("(c) 2001 Karol Szwed"));
204 about->addAuthor(ki18n("Karol Szwed"), KLocalizedString(), "gallium@kde.org");
205 setAboutData(about);
209 KWinDecorationModule::~KWinDecorationModule()
211 delete preview; // needs to be destroyed before plugins
212 delete plugins;
216 // Find all theme desktop files in all 'data' dirs owned by kwin.
217 // And insert these into a DecorationInfo structure
218 void KWinDecorationModule::findDecorations()
220 QStringList dirList = KGlobal::dirs()->findDirs("data", "kwin");
221 QStringList::ConstIterator it;
223 for (it = dirList.begin(); it != dirList.end(); ++it)
225 QDir d(*it);
226 if (d.exists())
227 foreach (const QFileInfo& fi, d.entryInfoList())
229 QString filename(fi.absoluteFilePath());
230 if (KDesktopFile::isDesktopFile(filename))
232 KDesktopFile desktopFile(filename);
233 QString libName = desktopFile.desktopGroup().readEntry("X-KDE-Library");
235 if (!libName.isEmpty() && libName.startsWith( "kwin3_" ))
237 DecorationInfo di;
238 di.name = desktopFile.readName();
239 di.libraryName = libName;
240 decorations.append( di );
248 // Fills the decorationList with a list of available kwin decorations
249 void KWinDecorationModule::createDecorationList()
251 QList<DecorationInfo>::ConstIterator it;
253 // Sync with kwin hardcoded KDE2 style which has no desktop item
254 QStringList decorationNames;
255 // decorationNames.append( i18n("KDE 2") );
256 for (it = decorations.begin(); it != decorations.end(); ++it)
258 decorationNames.append((*it).name);
260 decorationNames.sort();
261 decorationList->addItems(decorationNames);
265 // Reset the decoration plugin to what the user just selected
266 void KWinDecorationModule::slotChangeDecoration( const QString & text)
268 KConfig _kwinConfig( "kwinrc" );
269 KConfigGroup kwinConfig(&_kwinConfig, "Style");
271 // Let the user see config options for the currently selected decoration
272 resetPlugin( kwinConfig, text );
276 // This is the selection handler setting
277 void KWinDecorationModule::slotSelectionChanged()
279 emit KCModule::changed(true);
282 static const char* const border_names[ KDecorationDefines::BordersCount ] =
284 I18N_NOOP( "Tiny" ),
285 I18N_NOOP( "Normal" ),
286 I18N_NOOP( "Large" ),
287 I18N_NOOP( "Very Large" ),
288 I18N_NOOP( "Huge" ),
289 I18N_NOOP( "Very Huge" ),
290 I18N_NOOP( "Oversized" )
293 int KWinDecorationModule::borderSizeToIndex( BorderSize size, QList< BorderSize > sizes )
295 int pos = 0;
296 for( QList< BorderSize >::ConstIterator it = sizes.begin();
297 it != sizes.end();
298 ++it, ++pos )
299 if( size <= *it )
300 break;
301 return pos;
304 KDecorationDefines::BorderSize KWinDecorationModule::indexToBorderSize( int index,
305 QList< BorderSize > sizes )
307 QList< BorderSize >::ConstIterator it = sizes.begin();
308 for(;
309 it != sizes.end();
310 ++it, --index )
311 if( index == 0 )
312 break;
313 return *it;
316 void KWinDecorationModule::slotBorderChanged( int size )
318 if( lBorder->isHidden())
319 return;
320 emit KCModule::changed( true );
321 QList< BorderSize > sizes;
322 if( plugins->factory() != NULL )
323 sizes = plugins->factory()->borderSizes();
324 assert( sizes.count() >= 2 );
325 border_size = indexToBorderSize( size, sizes );
327 // update preview
328 preview->setTempBorderSize(plugins, border_size);
331 void KWinDecorationModule::slotButtonsChanged()
333 // update preview
334 preview->setTempButtons(plugins, cbUseCustomButtonPositions->isChecked(), buttonPositionWidget->buttonsLeft(), buttonPositionWidget->buttonsRight() );
337 QString KWinDecorationModule::decorationName( QString& libName )
339 QString decoName;
341 QList<DecorationInfo>::Iterator it;
342 for( it = decorations.begin(); it != decorations.end(); ++it )
343 if ( (*it).libraryName == libName )
345 decoName = (*it).name;
346 break;
349 return decoName;
353 QString KWinDecorationModule::decorationLibName( const QString& name )
355 QString libName;
357 // Find the corresponding library name to that of
358 // the current plugin name
359 QList<DecorationInfo>::Iterator it;
360 for( it = decorations.begin(); it != decorations.end(); ++it )
361 if ( (*it).name == name )
363 libName = (*it).libraryName;
364 break;
367 // if (libName.isEmpty())
368 // libName = "kwin_default"; // KDE 2
370 return libName;
374 // Loads/unloads and inserts the decoration config plugin into the
375 // pluginConfigWidget, allowing for dynamic configuration of decorations
376 void KWinDecorationModule::resetPlugin( KConfigGroup& conf, const QString& currentDecoName )
378 // Config names are "kwin_icewm_config"
379 // for "kwin3_icewm" kwin client
381 QString oldName = styleToConfigLib( oldLibraryName );
383 QString currentName;
384 if (!currentDecoName.isEmpty())
385 currentName = decorationLibName( currentDecoName ); // Use what the user selected
386 else
387 currentName = currentLibraryName; // Use what was read from readConfig()
389 if( plugins->loadPlugin( currentName )
390 && preview->recreateDecoration( plugins ))
391 preview->enablePreview();
392 else
393 preview->disablePreview();
394 plugins->destroyPreviousPlugin();
396 checkSupportedBorderSizes();
398 // inform buttonPositionWidget about the new factory...
399 buttonPositionWidget->setDecorationFactory(plugins->factory() );
401 currentName = styleToConfigLib( currentName );
403 // Delete old plugin widget if it exists
404 delete pluginObject;
405 pluginObject = 0;
407 // Use klibloader for library manipulation
408 KLibLoader* loader = KLibLoader::self();
410 // Free the old library if possible
411 if (!oldLibraryName.isNull())
412 loader->unloadLibrary( oldName );
414 KLibrary* library = loader->library( currentName );
415 if (library != NULL)
417 KLibrary::void_function_ptr alloc_ptr = library->resolveFunction("allocate_config");
418 if (alloc_ptr != NULL)
420 allocatePlugin = (QObject* (*)(KConfigGroup& conf, QWidget* parent))alloc_ptr;
421 pluginObject = (QObject*)(allocatePlugin( conf, pluginConfigWidget ));
423 // connect required signals and slots together...
424 connect( pluginObject, SIGNAL(changed()), this, SLOT(slotSelectionChanged()) );
425 connect( this, SIGNAL(pluginLoad(const KConfigGroup&)), pluginObject, SLOT(load(const KConfigGroup&)) );
426 connect( this, SIGNAL(pluginSave(KConfigGroup &)), pluginObject, SLOT(save(KConfigGroup &)) );
427 connect( this, SIGNAL(pluginDefaults()), pluginObject, SLOT(defaults()) );
428 pluginSettingsGrp->show();
429 return;
432 if ( cBorder->isHidden() )
433 pluginSettingsGrp->hide();
434 else if (pluginSettingsGrp->isHidden() )
435 pluginSettingsGrp->show();
439 // Reads the kwin config settings, and sets all UI controls to those settings
440 // Updating the config plugin if required
441 void KWinDecorationModule::readConfig( const KConfigGroup & conf )
443 // General tab
444 // ============
445 cbShowToolTips->setChecked( conf.readEntry("ShowToolTips", true));
446 // cbUseMiniWindows->setChecked( conf.readEntry("MiniWindowBorders", false));
448 // Find the corresponding decoration name to that of
449 // the current plugin library name
451 oldLibraryName = currentLibraryName;
452 currentLibraryName = conf.readEntry("PluginLib",
453 ((QPixmap::defaultDepth() > 8) ? "kwin3_oxygen" : "kwin3_plastik"));
454 QString decoName = decorationName( currentLibraryName );
456 // If we are using the "default" kde client, use the "default" entry.
457 // if (decoName.isEmpty())
458 // decoName = i18n("KDE 2");
460 int numDecos = decorationList->count();
461 for (int i = 0; i < numDecos; ++i)
463 if (decorationList->itemText(i) == decoName)
465 decorationList->setCurrentIndex(i);
466 break;
470 // Buttons tab
471 // ============
472 bool customPositions = conf.readEntry("CustomButtonPositions", false);
473 cbUseCustomButtonPositions->setChecked( customPositions );
474 buttonPositionWidget->setEnabled( customPositions );
475 // Menu and onAllDesktops buttons are default on LHS
476 buttonPositionWidget->setButtonsLeft( conf.readEntry("ButtonsOnLeft", KDecorationOptions::defaultTitleButtonsLeft()) );
477 // Help, Minimize, Maximize and Close are default on RHS
478 buttonPositionWidget->setButtonsRight( conf.readEntry("ButtonsOnRight", KDecorationOptions::defaultTitleButtonsRight()) );
480 int bsize = conf.readEntry( "BorderSize", (int)BorderNormal );
481 if( bsize >= BorderTiny && bsize < BordersCount )
482 border_size = static_cast< BorderSize >( bsize );
483 else
484 border_size = BorderNormal;
485 checkSupportedBorderSizes();
487 emit KCModule::changed(false);
491 // Writes the selected user configuration to the kwin config file
492 void KWinDecorationModule::writeConfig( KConfigGroup & conf )
494 QString name = decorationList->currentText();
495 QString libName = decorationLibName( name );
497 KConfig _kwinConfig( "kwinrc" );
498 KConfigGroup kwinConfig(&_kwinConfig, "Style");
500 // General settings
501 conf.writeEntry("PluginLib", libName);
502 conf.writeEntry("CustomButtonPositions", cbUseCustomButtonPositions->isChecked());
503 conf.writeEntry("ShowToolTips", cbShowToolTips->isChecked());
504 // conf.writeEntry("MiniWindowBorders", cbUseMiniWindows->isChecked());
506 // Button settings
507 conf.writeEntry("ButtonsOnLeft", buttonPositionWidget->buttonsLeft() );
508 conf.writeEntry("ButtonsOnRight", buttonPositionWidget->buttonsRight() );
509 conf.writeEntry("BorderSize", static_cast<int>( border_size ) );
511 oldLibraryName = currentLibraryName;
512 currentLibraryName = libName;
514 // We saved, so tell kcmodule that there have been no new user changes made.
515 emit KCModule::changed(false);
519 // Virutal functions required by KCModule
520 void KWinDecorationModule::load()
522 KConfig _kwinConfig( "kwinrc" );
523 KConfigGroup kwinConfig(&_kwinConfig, "Style");
525 // Reset by re-reading the config
526 readConfig( kwinConfig );
527 resetPlugin( kwinConfig );
531 void KWinDecorationModule::save()
533 KConfig _kwinConfig( "kwinrc" );
534 KConfigGroup kwinConfig(&_kwinConfig, "Style");
536 writeConfig( kwinConfig );
537 emit pluginSave( kwinConfig );
539 kwinConfig.sync();
540 // Send signal to all kwin instances
541 QDBusMessage message =
542 QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig");
543 QDBusConnection::sessionBus().send(message);
548 void KWinDecorationModule::defaults()
550 // Set the KDE defaults
551 cbUseCustomButtonPositions->setChecked( false );
552 buttonPositionWidget->setEnabled( false );
553 cbShowToolTips->setChecked( true );
554 // cbUseMiniWindows->setChecked( false);
555 // Don't set default for now
556 // decorationList->setSelected(
557 // decorationList->findItem( i18n("KDE 2") ), true ); // KDE classic client
559 buttonPositionWidget->setButtonsLeft(KDecorationOptions::defaultTitleButtonsLeft());
560 buttonPositionWidget->setButtonsRight(KDecorationOptions::defaultTitleButtonsRight());
562 border_size = BorderNormal;
563 checkSupportedBorderSizes();
565 // Set plugin defaults
566 emit pluginDefaults();
569 void KWinDecorationModule::checkSupportedBorderSizes()
571 QList< BorderSize > sizes;
572 if( plugins->factory() != NULL )
573 sizes = plugins->factory()->borderSizes();
574 if( sizes.count() < 2 ) {
575 lBorder->hide();
576 cBorder->hide();
577 } else {
578 cBorder->clear();
579 for (QList<BorderSize>::const_iterator it = sizes.begin(); it != sizes.end(); ++it) {
580 BorderSize size = *it;
581 cBorder->addItem(i18n(border_names[size]), borderSizeToIndex(size,sizes) );
583 int pos = borderSizeToIndex( border_size, sizes );
584 lBorder->show();
585 cBorder->show();
586 cBorder->setCurrentIndex(pos);
587 slotBorderChanged( pos );
591 QString KWinDecorationModule::styleToConfigLib( QString& styleLib )
593 if( styleLib.startsWith( "kwin3_" ))
594 return "kwin_" + styleLib.mid( 6 ) + "_config";
595 else
596 return styleLib + "_config";
599 QString KWinDecorationModule::quickHelp() const
601 return i18n( "<h1>Window Manager Decoration</h1>"
602 "<p>This module allows you to choose the window border decorations, "
603 "as well as titlebar button positions and custom decoration options.</p>"
604 "To choose a theme for your window decoration click on its name and apply your choice by clicking the \"Apply\" button below."
605 " If you do not want to apply your choice you can click the \"Reset\" button to discard your changes."
606 "<p>You can configure each theme in the \"Configure [...]\" tab. There are different options specific for each theme.</p>"
607 "<p>In \"General Options (if available)\" you can activate the \"Buttons\" tab by checking the \"Use custom titlebar button positions\" box."
608 " In the \"Buttons\" tab you can change the positions of the buttons to your liking.</p>" );
611 #include "kwindecoration.moc"
612 // vim: ts=4
613 // kate: space-indent off; tab-width 4;