diff options
Diffstat (limited to 'kscreensaver/kxsconfig/kxsconfig.cpp')
-rw-r--r-- | kscreensaver/kxsconfig/kxsconfig.cpp | 388 |
1 files changed, 388 insertions, 0 deletions
diff --git a/kscreensaver/kxsconfig/kxsconfig.cpp b/kscreensaver/kxsconfig/kxsconfig.cpp new file mode 100644 index 00000000..feda1ee8 --- /dev/null +++ b/kscreensaver/kxsconfig/kxsconfig.cpp @@ -0,0 +1,388 @@ +//----------------------------------------------------------------------------- +// +// KDE xscreensaver configuration dialog +// +// Copyright (c) Martin R. Jones <mjones@kde.org> 1999 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation; +// version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; see the file COPYING. If not, write to +// the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +// Boston, MA 02110-1301, USA. + +// This file contains code copied from xscreensaver. The xscreensaver +// copyright notice follows. + +/* + * xscreensaver, Copyright (c) 1993-2002 Jamie Zawinski <jwz@jwz.org> + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + */ + +#include <config.h> + +#include <stdlib.h> +#include <qlayout.h> +#include <qtimer.h> +#include <qvbox.h> +#include <qlabel.h> +#include <qfileinfo.h> + +#include <kdebug.h> +#include <kapplication.h> +#include <kconfig.h> +#include <kdialogbase.h> +#include <kprocess.h> +#include <kstandarddirs.h> +#include <klocale.h> +#include <kcmdlineargs.h> +#include <kmessagebox.h> + +#include "kxsconfig.h" +#include "kxscontrol.h" +#include "kxsxml.h" + +template class QPtrList<KXSConfigItem>; + +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <X11/IntrinsicP.h> +#include <X11/ShellP.h> + +int ignoreXError(Display *, XErrorEvent *); + +//=========================================================================== + +const uint widgetEventMask = // X event mask +(uint)( + ExposureMask | + PropertyChangeMask | + StructureNotifyMask + ); + +KXSConfigDialog::KXSConfigDialog(const QString &filename, const QString &name) + : KDialogBase(Plain, name, Ok| Cancel, Ok, 0, 0, false), + mFilename(filename), mPreviewProc(0), mKilled(true) +{ + int slash = filename.findRev('/'); + if (slash >= 0) + mConfigFile = filename.mid(slash+1); + else + mConfigFile = filename; + + mExeName = mConfigFile; + mConfigFile += "rc"; +} + +bool KXSConfigDialog::create() +{ + QVBoxLayout *topLayout = new QVBoxLayout(plainPage(), spacingHint()); + QHBoxLayout *layout = new QHBoxLayout(topLayout, spacingHint()); + QVBox *controlLayout = new QVBox(plainPage()); + controlLayout->setSpacing(spacingHint()); + layout->addWidget(controlLayout); + ((QBoxLayout*)controlLayout->layout())->addStrut(120); + + KConfig config(mConfigFile); + + QString xmlFile = "/doesntexist"; +#ifdef XSCREENSAVER_CONFIG_DIR + xmlFile = XSCREENSAVER_CONFIG_DIR; +#endif + + xmlFile += "/" + mExeName + ".xml"; + if ( QFile::exists( xmlFile ) ) { + // We can use the xscreensaver xml config files. + KXSXml xmlParser(controlLayout); + xmlParser.parse( xmlFile ); + mConfigItemList = *xmlParser.items(); + QWidget *spacer = new QWidget(controlLayout); + controlLayout->setStretchFactor(spacer, 1 ); + QString descr = xmlParser.description(); + if ( !descr.isEmpty() ) { + descr.replace('\n',' '); + descr = descr.simplifyWhiteSpace(); + QLabel *l = new QLabel( i18n( descr.utf8() ), plainPage() ); + l->setAlignment ( WordBreak ); + topLayout->addWidget( l ); + } + } else { + // fall back to KDE's old config files. + int idx = 0; + while (true) { + QString group = QString("Arg%1").arg(idx); + if (config.hasGroup(group)) { + config.setGroup(group); + QString type = config.readEntry("Type"); + if (type == "Range") { + KXSRangeControl *rc = new KXSRangeControl(controlLayout, group, config); + mConfigItemList.append(rc); + } else if (type == "DoubleRange") { + KXSDoubleRangeControl *rc = + new KXSDoubleRangeControl(controlLayout, group, config); + mConfigItemList.append(rc); + } else if (type == "Check") { + KXSCheckBoxControl *cc = new KXSCheckBoxControl(controlLayout, group, + config); + mConfigItemList.append(cc); + } else if (type == "DropList") { + KXSDropListControl *dl = new KXSDropListControl(controlLayout, group, + config); + mConfigItemList.append(dl); + } + } else { + break; + } + idx++; + } + if ( idx == 0 ) + return false; + } + + QPtrListIterator<KXSConfigItem> it( mConfigItemList ); + KXSConfigItem *item; + while ( (item = it.current()) != 0 ) { + ++it; + item->read( config ); + QWidget *i = dynamic_cast<QWidget*>(item); + if (i) { + connect( i, SIGNAL(changed()), SLOT(slotChanged()) ); + } + } + + mPreviewProc = new KProcess; + connect(mPreviewProc, SIGNAL(processExited(KProcess *)), + SLOT(slotPreviewExited(KProcess *))); + + mPreviewTimer = new QTimer(this); + connect(mPreviewTimer, SIGNAL(timeout()), SLOT(slotNewPreview())); + + mPreview = new QWidget(plainPage()); + mPreview->setFixedSize(250, 200); + // mPreview->setBackgroundMode(QWidget::NoBackground); + mPreview->setBackgroundColor(Qt::black); + + layout->add(mPreview); + show(); + + // So that hacks can XSelectInput ButtonPressMask + XSelectInput(qt_xdisplay(), mPreview->winId(), widgetEventMask ); + + slotPreviewExited(0); + return true; +} + +//--------------------------------------------------------------------------- +KXSConfigDialog::~KXSConfigDialog() +{ + if (mPreviewProc && mPreviewProc->isRunning()) { + int pid = mPreviewProc->pid(); + mPreviewProc->kill(); + waitpid(pid, (int *)0, 0); + delete mPreviewProc; + } +} + +//--------------------------------------------------------------------------- +QString KXSConfigDialog::command() +{ + QString cmd; + KXSConfigItem *item; + + for (item = mConfigItemList.first(); item != 0; item = mConfigItemList.next()) + { + cmd += " " + item->command(); + } + + return cmd; +} + +//--------------------------------------------------------------------------- +void KXSConfigDialog::slotPreviewExited(KProcess *) +{ + if ( mKilled ) { + mKilled = false; + mPreviewProc->clearArguments(); + QString saver; + saver.sprintf( "%s -window-id 0x%lX", mFilename.latin1(), long(mPreview->winId()) ); + saver += command(); + kdDebug() << "Command: " << saver << endl; + + unsigned int i = 0; + QString word; + saver = saver.stripWhiteSpace(); + while ( !saver[i].isSpace() ) word += saver[i++]; + //work around a KStandarDirs::findExe() "feature" where it looks in $KDEDIR/bin first no matter what and sometimes finds the wrong executable + QFileInfo checkExe; + QString saverdir = QString("%1/%2").arg(XSCREENSAVER_HACKS_DIR).arg(word); + QString path; + checkExe.setFile(saverdir); + if (checkExe.exists() && checkExe.isExecutable() && checkExe.isFile()) + { + path = saverdir; + } + if (!path.isEmpty()) { + (*mPreviewProc) << path; + + bool inQuotes = false; + while ( i < saver.length() ) { + word = ""; + while ( saver[i].isSpace() && i < saver.length() ) i++; + while ( (!saver[i].isSpace() || inQuotes) && i < saver.length() ) { + if ( saver[i] == '\"' ) { + inQuotes = !inQuotes; + } else { + word += saver[i]; + } + i++; + } + if (!word.isEmpty()) { + (*mPreviewProc) << word; + } + } + + mPreviewProc->start(); + } + } else { + // stops us from spawning the hack really fast, but still not the best + QString path = KStandardDirs::findExe(mFilename, XSCREENSAVER_HACKS_DIR); + if ( QFile::exists(path) ) { + mKilled = true; + slotChanged(); + } + } +} + +//--------------------------------------------------------------------------- +void KXSConfigDialog::slotNewPreview() +{ + if (mPreviewProc->isRunning()) { + mKilled = true; + mPreviewProc->kill(); // restarted in slotPreviewExited() + } else { + slotPreviewExited(0); + } +} + +//--------------------------------------------------------------------------- +void KXSConfigDialog::slotChanged() +{ + if (mPreviewTimer->isActive()) + mPreviewTimer->changeInterval(1000); + else + mPreviewTimer->start(1000, true); +} + +//--------------------------------------------------------------------------- +void KXSConfigDialog::slotOk() +{ + KXSConfigItem *item; + KConfig config(mConfigFile); + + for (item = mConfigItemList.first(); item != 0; item = mConfigItemList.next()) + { + item->save(config); + } + + kapp->quit(); +} + +//--------------------------------------------------------------------------- +void KXSConfigDialog::slotCancel() +{ + kapp->quit(); +} + + +//=========================================================================== + +static const char appName[] = "kxsconfig"; + +static const char description[] = I18N_NOOP("KDE X Screen Saver Configuration tool"); + +static const char version[] = "3.0.0"; + +static const KCmdLineOptions options[] = +{ + {"+screensaver", I18N_NOOP("Filename of the screen saver to configure"), 0}, + {"+[savername]", I18N_NOOP("Optional screen saver name used in messages"), 0}, + KCmdLineLastOption +}; + +static const char *defaults[] = { +#include "XScreenSaver_ad.h" + 0 +}; + +const char *progname = 0; +const char *progclass = "XScreenSaver"; +XrmDatabase db; + +int main(int argc, char *argv[]) +{ + KCmdLineArgs::init(argc, argv, appName, I18N_NOOP("KXSConfig"), description, version); + + KCmdLineArgs::addCmdLineOptions(options); + + KApplication app; + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + if(args->count()==0) + exit(1); + + /* We must read exactly the same resources as xscreensaver. + That means we must have both the same progclass *and* progname, + at least as far as the resource database is concerned. So, + put "xscreensaver" in argv[0] while initializing Xt. + */ + const char *dummyargs[] = { "xscreensaver" }; + int dummyargc = 1; + progname = dummyargs[0]; + + // Teach Xt to use the Display that Qt has already opened. + XtToolkitInitialize (); + XtAppContext xtApp = XtCreateApplicationContext (); + Display *dpy = qt_xdisplay(); + XtAppSetFallbackResources (xtApp, const_cast<char**>(defaults)); + XtDisplayInitialize (xtApp, dpy, progname, progclass, 0, 0, + &dummyargc, + const_cast<char**>(dummyargs)); + Widget toplevel_shell = XtAppCreateShell (progname, progclass, + applicationShellWidgetClass, + dpy, 0, 0); + dpy = XtDisplay (toplevel_shell); + db = XtDatabase (dpy); + XtGetApplicationNameAndClass (dpy, const_cast<char**>(&progname), + const_cast<char**>(&progclass)); + + QString name = QString::fromLocal8Bit(args->arg(args->count() - 1)); + KXSConfigDialog *dialog=new KXSConfigDialog(args->arg(0), name); + if ( dialog->create() ) { + dialog->show(); + app.setMainWidget(dialog); + app.exec(); + } else { + KMessageBox::sorry(0, + i18n("No configuration available for %1").arg(name), + name ); + } + + delete dialog; +} + +#include "kxsconfig.moc" |