1 /***************************************************************************
2 componentchooserwm.cpp - description
4 copyright : (C) 2002 by Joseph Wenninger
6 ***************************************************************************/
8 /***************************************************************************
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 *
14 ***************************************************************************/
16 #include "componentchooserwm.h"
17 #include "componentchooserwm.moc"
20 #include <kdesktopfile.h>
21 #include <kmessagebox.h>
24 #include <kstandarddirs.h>
25 #include <ktimerdialog.h>
26 #include <qdbusinterface.h>
27 #include <qdbusconnectioninterface.h>
29 #include <qx11info_x11.h>
31 CfgWm::CfgWm(QWidget
*parent
)
35 , wmLaunchingState( WmNone
)
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" );
53 void CfgWm::configChanged()
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"));
72 void CfgWm::save(KConfig
*)
77 bool CfgWm::saveAndConfirm()
79 KConfig
cfg("ksmserverrc", KConfig::NoGlobals
);
80 KConfigGroup
c( &cfg
, "General");
81 c
.writeEntry("windowManager", currentWm());
83 if( oldwm
== currentWm())
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" );
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" );
112 c
.writeEntry("windowManager", oldwm
);
113 if( oldwm
== "kwin" )
115 kwinRB
->setChecked( true );
116 wmCombo
->setEnabled( false );
120 differentRB
->setChecked( true );
121 wmCombo
->setEnabled( true );
122 for( QHash
< QString
, WmData
>::ConstIterator it
= wms
.constBegin();
123 it
!= wms
.constEnd();
126 if( (*it
).internalName
== oldwm
) // make it selected
127 wmCombo
->setCurrentIndex( wmCombo
->findText( it
.key()));
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
)));
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
)
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
;
186 // delete wmProcess; - it is intentionally leaked, since there is no KProcess:detach()
191 void CfgWm::wmLaunchError()
193 if( wmLaunchingState
!= WmLaunching
|| sender() != wmProcess
)
195 wmLaunchingState
= WmFailed
;
200 void CfgWm::wmLaunchFinished( int exitcode
, QProcess::ExitStatus exitstatus
)
202 if( wmLaunchingState
!= WmLaunching
|| sender() != wmProcess
)
204 if( exitstatus
== QProcess::NormalExit
&& exitcode
== 0 )
205 { // assume it's forked into background
206 wmLaunchingState
= WmOk
;
209 // otherwise it's a failure
210 wmLaunchingState
= WmFailed
;
214 void CfgWm::loadWMs( const QString
& current
)
217 kwin
.internalName
= "kwin";
219 kwin
.configureCommand
= "";
220 kwin
.restartArgument
= "--replace";
221 kwin
.parentArgument
= "";
222 wms
[ "KWin" ] = 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())
236 QString testexec
= file
.desktopGroup().readEntry( "X-KDE-WindowManagerTestExec" );
237 if( !testexec
.isEmpty())
240 proc
.setShellCommand( testexec
);
241 if( proc
.execute() != 0 )
244 QString name
= file
.readName();
247 if( !reg
.exactMatch( wmfile
))
249 QString wm
= reg
.cap( 1 );
250 if( wms
.contains( name
))
253 data
.internalName
= wm
;
254 data
.exec
= file
.desktopGroup().readEntry( "Exec" );
255 if( data
.exec
.isEmpty())
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" );
261 wmCombo
->addItem( name
);
262 if( wms
[ name
].internalName
== current
) // make it selected
264 wmCombo
->setCurrentIndex( wmCombo
->count() - 1 );
266 differentRB
->setChecked( true );
267 wmCombo
->setEnabled( true );
270 differentRB
->setEnabled( wmCombo
->count()>0 );
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())
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" ));