add more spacing
[personal-kdebase.git] / runtime / kcontrol / componentchooser / componentchooserwm.cpp
blobab26a231c1b6bd9de7bf289b91d54a92a500a3f9
1 /***************************************************************************
2 componentchooserwm.cpp - description
3 -------------------
4 copyright : (C) 2002 by Joseph Wenninger
5 email : jowenn@kde.org
6 ***************************************************************************/
8 /***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License verstion 2 as *
12 * published by the Free Software Foundation *
13 * *
14 ***************************************************************************/
16 #include "componentchooserwm.h"
17 #include "componentchooserwm.moc"
19 #include <kdebug.h>
20 #include <kdesktopfile.h>
21 #include <kmessagebox.h>
22 #include <kprocess.h>
23 #include <kshell.h>
24 #include <kstandarddirs.h>
25 #include <ktimerdialog.h>
26 #include <qdbusinterface.h>
27 #include <qdbusconnectioninterface.h>
28 #include <netwm.h>
29 #include <qx11info_x11.h>
31 CfgWm::CfgWm(QWidget *parent)
32 : QWidget(parent)
33 , Ui::WmConfig_UI()
34 , CfgPlugin()
35 , wmLaunchingState( WmNone )
36 , wmProcess( NULL )
38 setupUi(this);
39 connect(wmCombo,SIGNAL(activated(int)), this, SLOT(configChanged()));
40 connect(kwinRB,SIGNAL(toggled(bool)),this,SLOT(configChanged()));
41 connect(differentRB,SIGNAL(toggled(bool)),this,SLOT(configChanged()));
42 connect(differentRB,SIGNAL(toggled(bool)),this,SLOT(checkConfigureWm()));
43 connect(wmCombo,SIGNAL(activated(int)),this,SLOT(checkConfigureWm()));
44 connect(configureButton,SIGNAL(clicked()),this,SLOT(configureWm()));
46 KGlobal::dirs()->addResourceType( "windowmanagers", "data", "ksmserver/windowmanagers" );
49 CfgWm::~CfgWm()
53 void CfgWm::configChanged()
55 emit changed(true);
58 void CfgWm::defaults()
60 wmCombo->setCurrentIndex( 0 );
64 void CfgWm::load(KConfig *)
66 KConfig cfg("ksmserverrc", KConfig::NoGlobals);
67 KConfigGroup c( &cfg, "General");
68 loadWMs(c.readEntry("windowManager", "kwin"));
69 emit changed(false);
72 void CfgWm::save(KConfig *)
74 saveAndConfirm();
77 bool CfgWm::saveAndConfirm()
79 KConfig cfg("ksmserverrc", KConfig::NoGlobals);
80 KConfigGroup c( &cfg, "General");
81 c.writeEntry("windowManager", currentWm());
82 emit changed(false);
83 if( oldwm == currentWm())
84 return true;
85 QString restartArgument = currentWmData().restartArgument;
86 if( restartArgument.isEmpty())
88 KMessageBox::information( this,
89 i18n( "The new window manager will be used when KDE is started the next time." ),
90 i18n( "Window Manager Change" ), "windowmanagerchange" );
91 oldwm = currentWm();
92 return true;
94 else
96 if( tryWmLaunch())
98 oldwm = currentWm();
99 cfg.sync();
100 QDBusInterface ksmserver("org.kde.ksmserver", "/KSMServer" );
101 ksmserver.call( QDBus::NoBlock, "wmChanged" );
102 KMessageBox::information( window(),
103 i18n( "A new window manager is running.\n"
104 "It is still recommended to restart this KDE session to make sure "
105 "all running applications adjust for this change." ),
106 i18n( "Window Manager Replaced" ), "restartafterwmchange" );
107 return true;
109 else
110 { // revert config
111 emit changed(true);
112 c.writeEntry("windowManager", oldwm);
113 if( oldwm == "kwin" )
115 kwinRB->setChecked( true );
116 wmCombo->setEnabled( false );
118 else
120 differentRB->setChecked( true );
121 wmCombo->setEnabled( true );
122 for( QHash< QString, WmData >::ConstIterator it = wms.constBegin();
123 it != wms.constEnd();
124 ++it )
126 if( (*it).internalName == oldwm ) // make it selected
127 wmCombo->setCurrentIndex( wmCombo->findText( it.key()));
130 return false;
135 bool CfgWm::tryWmLaunch()
137 if( currentWm() == "kwin"
138 && qstrcmp( NETRootInfo( QX11Info::display(), NET::SupportingWMCheck ).wmName(), "KWin" ) == 0 )
140 return true; // it is already running, don't necessarily restart e.g. after a failure with other WM
142 KMessageBox::information( window(), i18n( "Your running window manager will be now replaced with "
143 "the configured one." ), i18n( "Window Manager Change" ), "windowmanagerchange" );
144 wmLaunchingState = WmLaunching;
145 wmProcess = new KProcess;
146 *wmProcess << KShell::splitArgs( currentWmData().exec ) << currentWmData().restartArgument;
147 connect( wmProcess, SIGNAL( error( QProcess::ProcessError )), this, SLOT( wmLaunchError()));
148 connect( wmProcess, SIGNAL( finished( int, QProcess::ExitStatus )),
149 this, SLOT( wmLaunchFinished( int, QProcess::ExitStatus )));
150 wmProcess->start();
151 wmDialog = new KTimerDialog( 20000, KTimerDialog::CountDown, window(), i18n( "Config Window Manager Change" ),
152 KTimerDialog::Ok | KTimerDialog::Cancel, KTimerDialog::Cancel );
153 wmDialog->setButtonGuiItem( KDialog::Ok, KGuiItem( i18n( "&Accept Change" ), "dialog-ok" ));
154 wmDialog->setButtonGuiItem( KDialog::Cancel, KGuiItem( i18n( "&Revert to Previous" ), "dialog-cancel" ));
155 QLabel *label = new QLabel(
156 i18n( "The configured window manager is being launched.\n"
157 "Please check it has started properly and confirm the change.\n"
158 "The launch will be automatically reverted in 20 seconds." ), wmDialog );
159 label->setWordWrap( true );
160 wmDialog->setMainWidget( label );
161 if( wmDialog->exec() == QDialog::Accepted ) // the user confirmed
162 wmLaunchingState = WmOk;
163 else // cancelled for some reason
165 if( wmLaunchingState == WmLaunching )
166 { // time out
167 wmLaunchingState = WmFailed;
168 KProcess::startDetached( "kwin", QStringList() << "--replace" );
169 // Let's hope KWin never fails.
170 KMessageBox::sorry( window(),
171 i18n( "The running window manager has been reverted to the default KDE window manager KWin." ));
173 else if( wmLaunchingState == WmFailed )
175 KProcess::startDetached( "kwin", QStringList() << "--replace" );
176 // Let's hope KWin never fails.
177 KMessageBox::sorry( window(),
178 i18n( "The new window manager has failed to start.\n"
179 "The running window manager has been reverted to the default KDE window manager KWin." ));
182 bool ret = ( wmLaunchingState == WmOk );
183 wmLaunchingState = WmNone;
184 delete wmDialog;
185 wmDialog = NULL;
186 // delete wmProcess; - it is intentionally leaked, since there is no KProcess:detach()
187 wmProcess = NULL;
188 return ret;
191 void CfgWm::wmLaunchError()
193 if( wmLaunchingState != WmLaunching || sender() != wmProcess )
194 return;
195 wmLaunchingState = WmFailed;
196 wmDialog->reject();
200 void CfgWm::wmLaunchFinished( int exitcode, QProcess::ExitStatus exitstatus )
202 if( wmLaunchingState != WmLaunching || sender() != wmProcess )
203 return;
204 if( exitstatus == QProcess::NormalExit && exitcode == 0 )
205 { // assume it's forked into background
206 wmLaunchingState = WmOk;
207 return;
209 // otherwise it's a failure
210 wmLaunchingState = WmFailed;
211 wmDialog->reject();
214 void CfgWm::loadWMs( const QString& current )
216 WmData kwin;
217 kwin.internalName = "kwin";
218 kwin.exec = "kwin";
219 kwin.configureCommand = "";
220 kwin.restartArgument = "--replace";
221 kwin.parentArgument = "";
222 wms[ "KWin" ] = kwin;
223 oldwm = "kwin";
224 kwinRB->setChecked( true );
225 wmCombo->setEnabled( false );
227 QStringList list = KGlobal::dirs()->findAllResources( "windowmanagers", QString(), KStandardDirs::NoDuplicates );
228 QRegExp reg( ".*/([^/\\.]*)\\.[^/\\.]*" );
229 foreach( const QString& wmfile, list )
231 KDesktopFile file( wmfile );
232 if( file.noDisplay())
233 continue;
234 if( !file.tryExec())
235 continue;
236 QString testexec = file.desktopGroup().readEntry( "X-KDE-WindowManagerTestExec" );
237 if( !testexec.isEmpty())
239 KProcess proc;
240 proc.setShellCommand( testexec );
241 if( proc.execute() != 0 )
242 continue;
244 QString name = file.readName();
245 if( name.isEmpty())
246 continue;
247 if( !reg.exactMatch( wmfile ))
248 continue;
249 QString wm = reg.cap( 1 );
250 if( wms.contains( name ))
251 continue;
252 WmData data;
253 data.internalName = wm;
254 data.exec = file.desktopGroup().readEntry( "Exec" );
255 if( data.exec.isEmpty())
256 continue;
257 data.configureCommand = file.desktopGroup().readEntry( "X-KDE-WindowManagerConfigure" );
258 data.restartArgument = file.desktopGroup().readEntry( "X-KDE-WindowManagerRestartArgument" );
259 data.parentArgument = file.desktopGroup().readEntry( "X-KDE-WindowManagerConfigureParentArgument" );
260 wms[ name ] = data;
261 wmCombo->addItem( name );
262 if( wms[ name ].internalName == current ) // make it selected
264 wmCombo->setCurrentIndex( wmCombo->count() - 1 );
265 oldwm = wm;
266 differentRB->setChecked( true );
267 wmCombo->setEnabled( true );
270 differentRB->setEnabled( wmCombo->count()>0 );
271 checkConfigureWm();
274 CfgWm::WmData CfgWm::currentWmData() const
276 return kwinRB->isChecked() ? wms[ "KWin" ] : wms[ wmCombo->currentText() ];
279 QString CfgWm::currentWm() const
281 return currentWmData().internalName;
284 void CfgWm::checkConfigureWm()
286 configureButton->setEnabled( !currentWmData().configureCommand.isEmpty());
289 void CfgWm::configureWm()
291 if( oldwm != currentWm() // needs switching first
292 && !saveAndConfirm())
294 return;
296 QStringList args;
297 if( !currentWmData().parentArgument.isEmpty())
298 args << currentWmData().parentArgument << QString::number( window()->winId());
299 if( !KProcess::startDetached( currentWmData().configureCommand, args ))
300 KMessageBox::sorry( window(), i18n( "Running the configuration tool failed" ));