1 //-----------------------------------------------------------------------------
3 // KDE xscreensaver configuration dialog
5 // Copyright (c) Martin R. Jones <mjones@kde.org> 1999
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public
9 // License as published by the Free Software Foundation;
10 // version 2 of the License.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; see the file COPYING. If not, write to
19 // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 // Boston, MA 02110-1301, USA.
22 // This file contains code copied from xscreensaver. The xscreensaver
23 // copyright notice follows.
26 * xscreensaver, Copyright (c) 1993-2002 Jamie Zawinski <jwz@jwz.org>
28 * Permission to use, copy, modify, distribute, and sell this software and its
29 * documentation for any purpose is hereby granted without fee, provided that
30 * the above copyright notice appear in all copies and that both that
31 * copyright notice and this permission notice appear in supporting
32 * documentation. No representations are made about the suitability of this
33 * software for any purpose. It is provided "as is" without express or
36 #include <config-kxsconfig.h>
43 #include <qfileinfo.h>
44 #include <QVBoxLayout>
45 #include <QHBoxLayout>
49 #include <kapplication.h>
51 #include <kstandarddirs.h>
53 #include <kcmdlineargs.h>
55 #include <kmessagebox.h>
57 #include "kxsconfig.h"
58 #include "kxscontrol.h"
62 #include <X11/Xatom.h>
63 #include <X11/IntrinsicP.h>
64 #include <X11/ShellP.h>
66 int ignoreXError(Display
*, XErrorEvent
*);
68 //===========================================================================
70 const uint widgetEventMask
= // X event mask
77 KXSConfigDialog::KXSConfigDialog(const QString
&filename
, const QString
&name
)
79 mFilename(filename
), mPreviewProc(0), mKilled(false)
83 setButtons(Ok
| Cancel
);
84 setDefaultButton( Ok
);
86 int slash
= filename
.lastIndexOf('/');
88 mConfigFile
= filename
.mid(slash
+1);
90 mConfigFile
= filename
;
92 mExeName
= mConfigFile
;
94 connect( this,SIGNAL(okClicked()),this,SLOT(slotOk()));
95 connect( this,SIGNAL(cancelClicked()),this,SLOT(slotCancel()));
98 bool KXSConfigDialog::create()
100 QWidget
*main
= new QWidget(this);
102 QVBoxLayout
*topLayout
= new QVBoxLayout(main
);
103 topLayout
->setSpacing(spacingHint());
104 QHBoxLayout
*layout
= new QHBoxLayout();
105 topLayout
->addLayout(layout
);
106 layout
->setSpacing(spacingHint());
107 KVBox
*controlLayout
= new KVBox(main
);
108 controlLayout
->setSpacing(spacingHint());
109 layout
->addWidget(controlLayout
);
110 ((QBoxLayout
*)controlLayout
->layout())->addStrut(120);
112 KConfig
config(mConfigFile
);
114 QString xmlFile
= "/doesntexist";
115 #ifdef XSCREENSAVER_CONFIG_DIR
116 xmlFile
= XSCREENSAVER_CONFIG_DIR
;
119 xmlFile
+= "/" + mExeName
+ ".xml";
120 if ( QFile::exists( xmlFile
) ) {
121 // We can use the xscreensaver xml config files.
122 KXSXml
xmlParser(controlLayout
);
123 xmlParser
.parse( xmlFile
);
124 mConfigItemList
= xmlParser
.items();
125 QWidget
*spacer
= new QWidget(controlLayout
);
126 controlLayout
->setStretchFactor(spacer
, 1 );
127 QString descr
= xmlParser
.description();
128 if ( !descr
.isEmpty() ) {
129 descr
= descr
.replace('\n', ' ').simplified();
130 QLabel
*l
= new QLabel( i18n( descr
.toUtf8() ), main
);
132 topLayout
->addWidget( l
);
135 // fall back to KDE's old config files.
138 QString group
= QString("Arg%1").arg(idx
);
139 if (config
.hasGroup(group
)) {
140 KConfigGroup grp
= config
.group(group
);
141 QString type
= grp
.readEntry("Type");
142 if (type
== "Range") {
143 KXSRangeControl
*rc
= new KXSRangeControl(controlLayout
, group
, config
);
144 mConfigItemList
.append(rc
);
145 } else if (type
== "DoubleRange") {
146 KXSDoubleRangeControl
*rc
=
147 new KXSDoubleRangeControl(controlLayout
, group
, config
);
148 mConfigItemList
.append(rc
);
149 } else if (type
== "Check") {
150 KXSCheckBoxControl
*cc
= new KXSCheckBoxControl(controlLayout
, group
,
152 mConfigItemList
.append(cc
);
153 } else if (type
== "DropList") {
154 KXSDropListControl
*dl
= new KXSDropListControl(controlLayout
, group
,
156 mConfigItemList
.append(dl
);
167 for ( int i
= 0; i
< mConfigItemList
.size(); i
++ ) {
168 KXSConfigItem
*item
= mConfigItemList
[i
];
169 item
->read( config
);
170 QWidget
*widget
= dynamic_cast<QWidget
*>( item
);
172 connect( widget
, SIGNAL(changed()), SLOT(slotChanged()) );
176 mPreviewProc
= new KProcess
;
177 connect(mPreviewProc
, SIGNAL(finished(int,QProcess::ExitStatus
)),
178 SLOT(slotPreviewProcFinished(int,QProcess::ExitStatus
)));
180 mPreviewTimer
= new QTimer(this);
181 mPreviewTimer
->setSingleShot(true);
182 connect(mPreviewTimer
, SIGNAL(timeout()), SLOT(slotNewPreview()));
184 mPreview
= new QWidget(main
);
185 mPreview
->setFixedSize(250, 200);
188 palette
.setColor(mPreview
->backgroundRole(), Qt::black
);
189 mPreview
->setPalette(palette
);
192 layout
->addWidget(mPreview
);
195 // So that hacks can XSelectInput ButtonPressMask
196 XSelectInput(QX11Info::display(), mPreview
->winId(), widgetEventMask
);
202 //---------------------------------------------------------------------------
203 KXSConfigDialog::~KXSConfigDialog()
205 if (mPreviewProc
&& mPreviewProc
->state() == QProcess::Running
) {
206 mPreviewProc
->kill();
207 mPreviewProc
->waitForFinished(5000);
212 //---------------------------------------------------------------------------
213 QString
KXSConfigDialog::command()
217 for (int i
= 0; i
< mConfigItemList
.size(); i
++)
219 if (mConfigItemList
[i
]) {
220 cmd
+= " " + mConfigItemList
[i
]->command();
227 //---------------------------------------------------------------------------
228 void KXSConfigDialog::startProcess()
231 mPreviewProc
->clearProgram();
232 QString saver
= QString( "%1 -window-id 0x%2" )
234 .arg( long(mPreview
->winId()), 0, 16 );
236 saver
= saver
.trimmed();
238 kDebug() << "Command: " << saver
;
242 while ( !saver
[i
].isSpace() ) {
245 // work around a KStandarDirs::findExe() "feature" where it looks in
246 // $KDEDIR/bin first no matter what and sometimes finds the wrong executable
248 QString saverdir
= QString(XSCREENSAVER_HACKS_DIR
"/") + exe
;
250 checkExe
.setFile(saverdir
);
251 if (checkExe
.exists() && checkExe
.isExecutable() && checkExe
.isFile())
255 if (!path
.isEmpty()) {
256 (*mPreviewProc
) << path
;
258 (*mPreviewProc
) << KShell::splitArgs(saver
.mid(i
));
260 mPreviewProc
->start();
264 //---------------------------------------------------------------------------
265 void KXSConfigDialog::slotPreviewProcFinished(int exitCode
, QProcess::ExitStatus exitStatus
)
273 // stops us from spawning the hack really fast, but still not the best
274 QString path
= KStandardDirs::findExe(mFilename
, XSCREENSAVER_HACKS_DIR
);
275 if ( QFile::exists(path
) ) {
282 //---------------------------------------------------------------------------
283 void KXSConfigDialog::slotNewPreview()
285 if (mPreviewProc
->state() == QProcess::Running
) {
287 mPreviewProc
->kill(); // restarted in slotPreviewExited()
293 //---------------------------------------------------------------------------
294 void KXSConfigDialog::slotChanged()
296 mPreviewTimer
->start(1000);
299 //---------------------------------------------------------------------------
300 void KXSConfigDialog::slotOk()
302 KConfig
config(mConfigFile
);
304 for (int i
= 0; i
< mConfigItemList
.size(); i
++)
306 if (mConfigItemList
[i
]) {
307 mConfigItemList
[i
]->save(config
);
314 //---------------------------------------------------------------------------
315 void KXSConfigDialog::slotCancel()
321 //===========================================================================
323 static const char appName
[] = "kxsconfig";
325 static const char description
[] = I18N_NOOP("KDE X Screen Saver Configuration tool");
327 static const char version
[] = "3.0.0";
329 static const char *defaults
[] = {
330 #include "XScreenSaver_ad.h"
334 const char *progname
= 0;
335 const char *progclass
= "XScreenSaver";
338 int main(int argc
, char *argv
[])
340 KCmdLineArgs::init(argc
, argv
, appName
, 0, ki18n("KXSConfig"), version
, ki18n(description
));
343 KCmdLineOptions options
;
345 options
.add("+screensaver", ki18n("Filename of the screen saver to configure"));
347 options
.add("+[savername]", ki18n("Optional screen saver name used in messages"));
349 KCmdLineArgs::addCmdLineOptions(options
);
353 KCmdLineArgs
*args
= KCmdLineArgs::parsedArgs();
357 /* We must read exactly the same resources as xscreensaver.
358 That means we must have both the same progclass *and* progname,
359 at least as far as the resource database is concerned. So,
360 put "xscreensaver" in argv[0] while initializing Xt.
362 const char *dummyargs
[] = { "xscreensaver" };
364 progname
= dummyargs
[0];
366 // Teach Xt to use the Display that Qt has already opened.
367 XtToolkitInitialize ();
368 XtAppContext xtApp
= XtCreateApplicationContext ();
369 Display
*dpy
= QX11Info::display();
370 XtAppSetFallbackResources (xtApp
, const_cast<char**>(defaults
));
371 XtDisplayInitialize (xtApp
, dpy
, progname
, progclass
, 0, 0,
373 const_cast<char**>(dummyargs
));
374 Widget toplevel_shell
= XtAppCreateShell (progname
, progclass
,
375 applicationShellWidgetClass
,
377 dpy
= XtDisplay (toplevel_shell
);
378 db
= XtDatabase (dpy
);
379 XtGetApplicationNameAndClass (dpy
, const_cast<char**>(&progname
),
380 const_cast<char**>(&progclass
));
382 QString name
= args
->arg(args
->count() - 1);
383 KXSConfigDialog
*dialog
=new KXSConfigDialog(args
->arg(0), name
);
384 if ( dialog
->create() ) {
388 KMessageBox::sorry(0,
389 i18n("No configuration available for %1", name
),
396 #include "kxsconfig.moc"