2 This is the new kwindecoration kcontrol module
5 Karol Szwed <gallium@kde.org>
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.
36 #include <QGridLayout>
45 #include <QHBoxLayout>
46 #include <QVBoxLayout>
48 #include <QtDBus/QtDBus>
50 #include <kapplication.h>
51 #include <kcombobox.h>
53 #include <kdesktopfile.h>
54 #include <kstandarddirs.h>
58 #include <kaboutdata.h>
60 #include "kwindecoration.h"
62 #include <kdecoration_plugins_p.h>
63 #include <kdecorationfactory.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")),
80 KConfigGroup
style( kwinConfig
, "Style");
81 plugins
= new KDecorationPreviewPlugins(kwinConfig
);
83 QVBoxLayout
* layout
= new QVBoxLayout(this);
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." ));
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();
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
179 createDecorationList();
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()) );
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");
209 KWinDecorationModule::~KWinDecorationModule()
211 delete preview
; // needs to be destroyed before 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 const QStringList dirList
= KGlobal::dirs()->findDirs("data", "kwin");
221 QStringList::ConstIterator it
;
223 for (it
= dirList
.constBegin(); it
!= dirList
.constEnd(); ++it
)
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_" ))
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
.constBegin(); it
!= decorations
.constEnd(); ++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
] =
285 I18N_NOOP( "Normal" ),
286 I18N_NOOP( "Large" ),
287 I18N_NOOP( "Very Large" ),
289 I18N_NOOP( "Very Huge" ),
290 I18N_NOOP( "Oversized" )
293 int KWinDecorationModule::borderSizeToIndex( BorderSize size
, QList
< BorderSize
> sizes
)
296 for( QList
< BorderSize
>::ConstIterator it
= sizes
.constBegin();
297 it
!= sizes
.constEnd();
304 KDecorationDefines::BorderSize
KWinDecorationModule::indexToBorderSize( int index
,
305 QList
< BorderSize
> sizes
)
307 QList
< BorderSize
>::ConstIterator it
= sizes
.constBegin();
309 it
!= sizes
.constEnd();
316 void KWinDecorationModule::slotBorderChanged( int size
)
318 if( lBorder
->isHidden())
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
);
328 preview
->setTempBorderSize(plugins
, border_size
);
331 void KWinDecorationModule::slotButtonsChanged()
334 preview
->setTempButtons(plugins
, cbUseCustomButtonPositions
->isChecked(), buttonPositionWidget
->buttonsLeft(), buttonPositionWidget
->buttonsRight() );
337 QString
KWinDecorationModule::decorationName( QString
& libName
)
341 QList
<DecorationInfo
>::Iterator it
;
342 for( it
= decorations
.begin(); it
!= decorations
.end(); ++it
)
343 if ( (*it
).libraryName
== libName
)
345 decoName
= (*it
).name
;
353 QString
KWinDecorationModule::decorationLibName( const QString
& name
)
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
;
367 // if (libName.isEmpty())
368 // libName = "kwin_default"; // KDE 2
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
);
384 if (!currentDecoName
.isEmpty())
385 currentName
= decorationLibName( currentDecoName
); // Use what the user selected
387 currentName
= currentLibraryName
; // Use what was read from readConfig()
389 if( plugins
->loadPlugin( currentName
)
390 && preview
->recreateDecoration( plugins
))
391 preview
->enablePreview();
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
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
);
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();
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
)
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_ozone" : "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
);
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
);
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");
501 conf
.writeEntry("PluginLib", libName
);
502 conf
.writeEntry("CustomButtonPositions", cbUseCustomButtonPositions
->isChecked());
503 conf
.writeEntry("ShowToolTips", cbShowToolTips
->isChecked());
504 // conf.writeEntry("MiniWindowBorders", cbUseMiniWindows->isChecked());
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
);
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
558 decorationList
->setCurrentItem( i18n("Ozone"), true ); // KDE classic client
559 slotChangeDecoration(i18n("Ozone"));
561 buttonPositionWidget
->setButtonsLeft(KDecorationOptions::defaultTitleButtonsLeft());
562 buttonPositionWidget
->setButtonsRight(KDecorationOptions::defaultTitleButtonsRight());
564 border_size
= BorderNormal
;
565 checkSupportedBorderSizes();
567 // Set plugin defaults
568 emit
pluginDefaults();
571 void KWinDecorationModule::checkSupportedBorderSizes()
573 QList
< BorderSize
> sizes
;
574 if( plugins
->factory() != NULL
)
575 sizes
= plugins
->factory()->borderSizes();
576 if( sizes
.count() < 2 ) {
581 for (QList
<BorderSize
>::const_iterator it
= sizes
.constBegin(); it
!= sizes
.constEnd(); ++it
) {
582 BorderSize size
= *it
;
583 cBorder
->addItem(i18n(border_names
[size
]), borderSizeToIndex(size
,sizes
) );
585 int pos
= borderSizeToIndex( border_size
, sizes
);
588 cBorder
->setCurrentIndex(pos
);
589 slotBorderChanged( pos
);
593 QString
KWinDecorationModule::styleToConfigLib( QString
& styleLib
)
595 if( styleLib
.startsWith( "kwin3_" ))
596 return "kwin_" + styleLib
.mid( 6 ) + "_config";
598 return styleLib
+ "_config";
601 QString
KWinDecorationModule::quickHelp() const
603 return i18n( "<h1>Window Manager Decoration</h1>"
604 "<p>This module allows you to choose the window border decorations, "
605 "as well as titlebar button positions and custom decoration options.</p>"
606 "To choose a theme for your window decoration click on its name and apply your choice by clicking the \"Apply\" button below."
607 " If you do not want to apply your choice you can click the \"Reset\" button to discard your changes."
608 "<p>You can configure each theme in the \"Configure [...]\" tab. There are different options specific for each theme.</p>"
609 "<p>In \"General Options (if available)\" you can activate the \"Buttons\" tab by checking the \"Use custom titlebar button positions\" box."
610 " In the \"Buttons\" tab you can change the positions of the buttons to your liking.</p>" );
613 #include "kwindecoration.moc"
615 // kate: space-indent off; tab-width 4;