//----------------------------------------------------------------------------- // // KDE xscreensaver configuration dialog // // Copyright (c) Martin R. Jones 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 * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kxsconfig.h" #include "kxscontrol.h" #include "kxsxml.h" #include #include #include #include int ignoreXError(Display *, XErrorEvent *); //=========================================================================== const uint widgetEventMask = // X event mask (uint)( ExposureMask | PropertyChangeMask | StructureNotifyMask ); KXSConfigDialog::KXSConfigDialog(const QString &filename, const QString &name) : KDialog(0), mFilename(filename), mPreviewProc(0), mKilled(false) { Q_UNUSED(name) setButtons(Ok| Cancel); setDefaultButton( Ok); setModal(false); int slash = filename.lastIndexOf(QLatin1Char( '/' )); if (slash >= 0) mConfigFile = filename.mid(slash+1); else mConfigFile = filename; mExeName = mConfigFile; mConfigFile += QLatin1String( "rc" ); connect( this,SIGNAL(okClicked()),this,SLOT(slotOk())); connect( this,SIGNAL(cancelClicked()),this,SLOT(slotCancel())); } bool KXSConfigDialog::create() { QWidget *main = new QWidget(this); setMainWidget(main); QVBoxLayout *topLayout = new QVBoxLayout(main); topLayout->setSpacing(spacingHint()); QHBoxLayout *layout = new QHBoxLayout(); topLayout->addLayout(layout); layout->setSpacing(spacingHint()); KVBox *controlLayout = new KVBox(main); controlLayout->setSpacing(spacingHint()); layout->addWidget(controlLayout); ((QBoxLayout*)controlLayout->layout())->addStrut(120); KConfig config(mConfigFile); QString xmlFile = QLatin1String( "/doesntexist" ); #ifdef XSCREENSAVER_CONFIG_DIR xmlFile =QLatin1String( XSCREENSAVER_CONFIG_DIR ); #endif xmlFile += QLatin1Char( '/' ) + mExeName + QLatin1String( ".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 name = xmlParser.name(); setPlainCaption(i18n("Setup %1", i18nc("@item screen saver name", name.toUtf8()))); QString descr = xmlParser.description(); if ( !descr.isEmpty() ) { // NOTE: Simplification must be same as in PO template creation script. descr = descr.replace(QLatin1Char( '\n' ), QLatin1Char( ' ' )).simplified(); // NOTE: Contexts has to match with that extracted by the PO template creation script. QLabel *l = new QLabel( i18nc( "@info screen saver description", descr.toUtf8() ), main ); l->setWordWrap( 1 ); topLayout->addWidget( l ); } } else { // fall back to KDE's old config files. int idx = 0; while (true) { QString group = QString(QLatin1String( "Arg%1" )).arg(idx); if (config.hasGroup(group)) { KConfigGroup grp = config.group(group); QString type = grp.readEntry("Type"); if (type == QLatin1String( "Range" )) { KXSRangeControl *rc = new KXSRangeControl(controlLayout, group, config); mConfigItemList.append(rc); } else if (type == QLatin1String( "DoubleRange" )) { KXSDoubleRangeControl *rc = new KXSDoubleRangeControl(controlLayout, group, config); mConfigItemList.append(rc); } else if (type == QLatin1String( "Check" )) { KXSCheckBoxControl *cc = new KXSCheckBoxControl(controlLayout, group, config); mConfigItemList.append(cc); } else if (type == QLatin1String( "DropList" )) { KXSDropListControl *dl = new KXSDropListControl(controlLayout, group, config); mConfigItemList.append(dl); } } else { break; } idx++; } if ( idx == 0 ) return false; } for ( int i = 0; i < mConfigItemList.size(); i++ ) { KXSConfigItem *item = mConfigItemList[i]; item->read( config ); QWidget *widget = dynamic_cast( item ); if ( widget ) { connect( widget, SIGNAL(changed()), SLOT(slotChanged()) ); } } mPreviewProc = new KProcess; connect(mPreviewProc, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(slotPreviewProcFinished(int,QProcess::ExitStatus))); mPreviewTimer = new QTimer(this); mPreviewTimer->setSingleShot(true); connect(mPreviewTimer, SIGNAL(timeout()), SLOT(slotNewPreview())); mPreview = new QWidget(main); mPreview->setFixedSize(250, 200); { QPalette palette; palette.setColor(mPreview->backgroundRole(), Qt::black); mPreview->setPalette(palette); mPreview->setAutoFillBackground(true); } layout->addWidget(mPreview); show(); // So that hacks can XSelectInput ButtonPressMask XSelectInput(QX11Info::display(), mPreview->winId(), widgetEventMask ); startProcess(); return true; } //--------------------------------------------------------------------------- KXSConfigDialog::~KXSConfigDialog() { if (mPreviewProc && mPreviewProc->state() == QProcess::Running) { mPreviewProc->kill(); mPreviewProc->waitForFinished(5000); delete mPreviewProc; } } //--------------------------------------------------------------------------- QString KXSConfigDialog::command() { QString cmd; for (int i = 0; i < mConfigItemList.size(); i++) { if (mConfigItemList[i]) { cmd += QLatin1String( " " ) + mConfigItemList[i]->command(); } } return cmd; } //--------------------------------------------------------------------------- void KXSConfigDialog::startProcess() { mKilled = false; mPreviewProc->clearProgram(); QString saver = QString( QLatin1String( "%1 -window-id 0x%2" ) ) .arg( mFilename ) .arg( long(mPreview->winId()), 0, 16 ); saver += command(); saver = saver.trimmed(); kDebug() << "Command: " << saver; int i = 0; QString exe; while ( !saver[i].isSpace() ) { exe += 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 = QLatin1String(XSCREENSAVER_HACKS_DIR "/" ) + exe; QString path; checkExe.setFile(saverdir); if (checkExe.exists() && checkExe.isExecutable() && checkExe.isFile()) { path = saverdir; } if (!path.isEmpty()) { (*mPreviewProc) << path; (*mPreviewProc) << KShell::splitArgs(saver.mid(i)); mPreviewProc->start(); } } //--------------------------------------------------------------------------- void KXSConfigDialog::slotPreviewProcFinished(int exitCode, QProcess::ExitStatus exitStatus) { Q_UNUSED(exitCode) Q_UNUSED(exitStatus) if ( mKilled ) { startProcess(); } else { // stops us from spawning the hack really fast, but still not the best QString path = KStandardDirs::findExe(mFilename,QLatin1String( XSCREENSAVER_HACKS_DIR )); if ( QFile::exists(path) ) { mKilled = true; slotChanged(); } } } //--------------------------------------------------------------------------- void KXSConfigDialog::slotNewPreview() { if (mPreviewProc->state() == QProcess::Running) { mKilled = true; mPreviewProc->kill(); // restarted in slotPreviewExited() } else { startProcess(); } } //--------------------------------------------------------------------------- void KXSConfigDialog::slotChanged() { mPreviewTimer->start(1000); } //--------------------------------------------------------------------------- void KXSConfigDialog::slotOk() { KConfig config(mConfigFile); for (int i = 0; i < mConfigItemList.size(); i++) { if (mConfigItemList[i]) { mConfigItemList[i]->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 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, 0, ki18n("KXSConfig"), version, ki18n(description)); KCmdLineOptions options; options.add("+screensaver", ki18n("Filename of the screen saver to configure")); options.add("+[savername]", ki18n("Optional screen saver name used in messages")); KCmdLineArgs::addCmdLineOptions(options); KApplication app; KGlobal::locale()->insertCatalog(QLatin1String( "kxsconfig" )); 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 = QX11Info::display(); XtAppSetFallbackResources (xtApp, const_cast(defaults)); XtDisplayInitialize (xtApp, dpy, progname, progclass, 0, 0, &dummyargc, const_cast(dummyargs)); Widget toplevel_shell = XtAppCreateShell (progname, progclass, applicationShellWidgetClass, dpy, 0, 0); dpy = XtDisplay (toplevel_shell); db = XtDatabase (dpy); XtGetApplicationNameAndClass (dpy, const_cast(&progname), const_cast(&progclass)); QString name = args->arg(args->count() - 1); KXSConfigDialog *dialog=new KXSConfigDialog(args->arg(0), name); if ( dialog->create() ) { dialog->show(); app.exec(); } else { KMessageBox::sorry(0, i18n("No configuration available for %1", name), name ); } delete dialog; } #include "kxsconfig.moc"