1 | /* |
2 | Copyright (c) 1999 Matthias Hoelzer-Kluepfel <hoelzer@kde.org> |
3 | Copyright (c) 2000 Matthias Elter <elter@kde.org> |
4 | Copyright (c) 2004 Frans Englich <frans.englich@telia.com> |
5 | |
6 | This program is free software; you can redistribute it and/or modify |
7 | it under the terms of the GNU General Public License as published by |
8 | the Free Software Foundation; either version 2 of the License, or |
9 | (at your option) any later version. |
10 | |
11 | This program is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | GNU General Public License for more details. |
15 | |
16 | You should have received a copy of the GNU General Public License |
17 | along with this program; if not, write to the Free Software |
18 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
19 | |
20 | */ |
21 | |
22 | #include "main.h" |
23 | |
24 | #include <iostream> |
25 | |
26 | #include <QtDBus/QtDBus> |
27 | |
28 | #include <KAboutData> |
29 | #include <KApplication> |
30 | #include <KAuthorized> |
31 | #include <KCmdLineArgs> |
32 | #include <KCModuleInfo> |
33 | #include <KCMultiDialog> |
34 | #include <KDebug> |
35 | #include <KLocale> |
36 | #include <KServiceTypeTrader> |
37 | #include <KStartupInfo> |
38 | #include <KGlobal> |
39 | #include <KIcon> |
40 | #include <kdeversion.h> |
41 | |
42 | #include "main.moc" |
43 | |
44 | using namespace std; |
45 | |
46 | KService::List m_modules; |
47 | |
48 | static int debugArea() { |
49 | static int s_area = KDebug::registerArea("kcmshell" ); |
50 | return s_area; |
51 | } |
52 | |
53 | static bool caseInsensitiveLessThan(const KService::Ptr s1, const KService::Ptr s2) |
54 | { |
55 | const int compare = QString::compare(s1->desktopEntryName(), |
56 | s2->desktopEntryName(), |
57 | Qt::CaseInsensitive); |
58 | return (compare < 0); |
59 | } |
60 | |
61 | static void listModules() |
62 | { |
63 | const KService::List services = KServiceTypeTrader::self()->query( "KCModule" , "[X-KDE-ParentApp] == 'kcontrol' or [X-KDE-ParentApp] == 'kinfocenter'" ); |
64 | for( KService::List::const_iterator it = services.begin(); |
65 | it != services.end(); ++it) |
66 | { |
67 | const KService::Ptr s = (*it); |
68 | if (!KAuthorized::authorizeControlModule(s->menuId())) |
69 | continue; |
70 | m_modules.append(s); |
71 | } |
72 | |
73 | qStableSort(m_modules.begin(), m_modules.end(), caseInsensitiveLessThan); |
74 | } |
75 | |
76 | static KService::Ptr locateModule(const QString& module) |
77 | { |
78 | QString path = module; |
79 | |
80 | if (!path.endsWith(QLatin1String(".desktop" ))) |
81 | path += ".desktop" ; |
82 | |
83 | KService::Ptr service = KService::serviceByStorageId( path ); |
84 | if (!service) { |
85 | return KService::Ptr(); |
86 | } |
87 | |
88 | if (!service->hasServiceType("KCModule" )) { |
89 | // Not a KCModule. E.g. "kcmshell4 akonadi" finds services/kresources/kabc/akonadi.desktop, unrelated. |
90 | return KService::Ptr(); |
91 | } |
92 | |
93 | if ( service->noDisplay() ) { |
94 | kDebug(debugArea()) << module << " should not be loaded." ; |
95 | return KService::Ptr(); |
96 | } |
97 | |
98 | return service; |
99 | } |
100 | |
101 | bool KCMShell::isRunning() |
102 | { |
103 | QString owner = QDBusConnection::sessionBus().interface()->serviceOwner(m_serviceName); |
104 | if( owner == QDBusConnection::sessionBus().baseService() ) |
105 | return false; // We are the one and only. |
106 | |
107 | kDebug(debugArea()) << "kcmshell4 with modules '" << |
108 | m_serviceName << "' is already running." << endl; |
109 | |
110 | QDBusInterface iface(m_serviceName, "/KCModule/dialog" , "org.kde.KCMShellMultiDialog" ); |
111 | QDBusReply<void> reply = iface.call("activate" , kapp->startupId()); |
112 | if (!reply.isValid()) |
113 | { |
114 | kDebug(debugArea()) << "Calling D-Bus function dialog::activate() failed." ; |
115 | return false; // Error, we have to do it ourselves. |
116 | } |
117 | |
118 | return true; |
119 | } |
120 | |
121 | KCMShellMultiDialog::KCMShellMultiDialog(KPageDialog::FaceType dialogFace, QWidget *parent) |
122 | : KCMultiDialog(parent) |
123 | { |
124 | setFaceType(dialogFace); |
125 | setModal(true); |
126 | |
127 | QDBusConnection::sessionBus().registerObject("/KCModule/dialog" , this, QDBusConnection::ExportScriptableSlots); |
128 | } |
129 | |
130 | void KCMShellMultiDialog::activate( const QByteArray& asn_id ) |
131 | { |
132 | kDebug(debugArea()) ; |
133 | |
134 | #ifdef Q_WS_X11 |
135 | KStartupInfo::setNewStartupId( this, asn_id ); |
136 | #endif |
137 | } |
138 | |
139 | void KCMShell::setServiceName(const QString &dbusName ) |
140 | { |
141 | m_serviceName = QLatin1String( "org.kde.kcmshell_" ) + dbusName; |
142 | QDBusConnection::sessionBus().registerService(m_serviceName); |
143 | } |
144 | |
145 | void KCMShell::waitForExit() |
146 | { |
147 | kDebug(debugArea()); |
148 | |
149 | QDBusServiceWatcher *watcher = new QDBusServiceWatcher(this); |
150 | watcher->setConnection(QDBusConnection::sessionBus()); |
151 | watcher->setWatchMode(QDBusServiceWatcher::WatchForOwnerChange); |
152 | watcher->addWatchedService(m_serviceName); |
153 | connect(watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)), |
154 | SLOT(appExit(QString,QString,QString))); |
155 | exec(); |
156 | } |
157 | |
158 | void KCMShell::appExit(const QString &appId, const QString &oldName, const QString &newName) |
159 | { |
160 | Q_UNUSED(appId); |
161 | Q_UNUSED(newName); |
162 | kDebug(debugArea()); |
163 | |
164 | if (!oldName.isEmpty()) |
165 | { |
166 | kDebug(debugArea()) << "'" << appId << "' closed, dereferencing." ; |
167 | KGlobal::deref(); |
168 | } |
169 | } |
170 | |
171 | extern "C" KDE_EXPORT int kdemain(int _argc, char *_argv[]) |
172 | { |
173 | KAboutData aboutData( "kcmshell" , 0, ki18n("KDE Control Module" ), |
174 | KDE_VERSION_STRING, |
175 | ki18n("A tool to start single KDE control modules" ), |
176 | KAboutData::License_GPL, |
177 | ki18n("(c) 1999-2004, The KDE Developers" ) ); |
178 | |
179 | aboutData.addAuthor(ki18n("Frans Englich" ), ki18n("Maintainer" ), "frans.englich@kde.org" ); |
180 | aboutData.addAuthor(ki18n("Daniel Molkentin" ), KLocalizedString(), "molkentin@kde.org" ); |
181 | aboutData.addAuthor(ki18n("Matthias Hoelzer-Kluepfel" ),KLocalizedString(), "hoelzer@kde.org" ); |
182 | aboutData.addAuthor(ki18n("Matthias Elter" ),KLocalizedString(), "elter@kde.org" ); |
183 | aboutData.addAuthor(ki18n("Matthias Ettrich" ),KLocalizedString(), "ettrich@kde.org" ); |
184 | aboutData.addAuthor(ki18n("Waldo Bastian" ),KLocalizedString(), "bastian@kde.org" ); |
185 | |
186 | KCmdLineArgs::init(_argc, _argv, &aboutData); |
187 | |
188 | KCmdLineOptions options; |
189 | options.add("list" , ki18n("List all possible modules" )); |
190 | options.add("+module" , ki18n("Configuration module to open" )); |
191 | options.add("lang <language>" , ki18n("Specify a particular language" )); |
192 | options.add("silent" , ki18n("Do not display main window" )); |
193 | options.add("args <arguments>" , ki18n("Arguments for the module" )); |
194 | KCmdLineArgs::addCmdLineOptions( options ); // Add our own options. |
195 | KCMShell app; |
196 | |
197 | const KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); |
198 | |
199 | const QString lang = args->getOption("lang" ); |
200 | if( !lang.isEmpty() ) { |
201 | KGlobal::setLocale(new KLocale(aboutData.catalogName(), lang)); |
202 | } |
203 | |
204 | if (args->isSet("list" )) |
205 | { |
206 | cout << i18n("The following modules are available:" ).toLocal8Bit().data() << endl; |
207 | |
208 | listModules(); |
209 | |
210 | int maxLen=0; |
211 | |
212 | for( KService::List::ConstIterator it = m_modules.constBegin(); it != m_modules.constEnd(); ++it) |
213 | { |
214 | int len = (*it)->desktopEntryName().length(); |
215 | if (len > maxLen) |
216 | maxLen = len; |
217 | } |
218 | |
219 | for( KService::List::ConstIterator it = m_modules.constBegin(); it != m_modules.constEnd(); ++it) |
220 | { |
221 | QString entry("%1 - %2" ); |
222 | |
223 | entry = entry.arg((*it)->desktopEntryName().leftJustified(maxLen, ' ')) |
224 | .arg(!(*it)->comment().isEmpty() ? (*it)->comment() |
225 | : i18n("No description available" )); |
226 | |
227 | cout << entry.toLocal8Bit().data() << endl; |
228 | } |
229 | return 0; |
230 | } |
231 | |
232 | if (args->count() < 1) |
233 | { |
234 | args->usage(); |
235 | return -1; |
236 | } |
237 | |
238 | QString serviceName; |
239 | KService::List modules; |
240 | for (int i = 0; i < args->count(); i++) |
241 | { |
242 | const QString arg = args->arg(i); |
243 | KService::Ptr service = locateModule(arg); |
244 | if (!service) { |
245 | service = locateModule("kcm_" + arg); |
246 | } |
247 | if (!service) { |
248 | service = locateModule("kcm" + arg); |
249 | } |
250 | |
251 | if (service) { |
252 | modules.append(service); |
253 | if( !serviceName.isEmpty() ) |
254 | serviceName += '_'; |
255 | serviceName += args->arg(i); |
256 | } else { |
257 | fprintf(stderr, "%s\n" , i18n("Could not find module '%1'. See kcmshell4 --list for the full list of modules." , arg).toLocal8Bit().constData()); |
258 | } |
259 | } |
260 | |
261 | /* Check if this particular module combination is already running */ |
262 | app.setServiceName(serviceName); |
263 | if( app.isRunning() ) { |
264 | app.waitForExit(); |
265 | return 0; |
266 | } |
267 | |
268 | KPageDialog::FaceType ftype = KPageDialog::Plain; |
269 | |
270 | if (modules.count() < 1) { |
271 | return 0; |
272 | } else if (modules.count() > 1) { |
273 | ftype = KPageDialog::List; |
274 | } |
275 | |
276 | QStringList moduleArgs; |
277 | QString x = args->getOption("args" ); |
278 | moduleArgs << x.split(QRegExp(" +" )); |
279 | |
280 | KCMShellMultiDialog *dlg = new KCMShellMultiDialog(ftype); |
281 | KCmdLineArgs *kdeargs = KCmdLineArgs::parsedArgs("kde" ); |
282 | if (kdeargs && kdeargs->isSet("caption" )) { |
283 | dlg->setCaption(QString()); |
284 | kdeargs->clear(); |
285 | } else if (modules.count() == 1) { |
286 | dlg->setCaption(modules.first()->name()); |
287 | } |
288 | |
289 | for (KService::List::ConstIterator it = modules.constBegin(); it != modules.constEnd(); ++it) |
290 | dlg->addModule(*it, 0, moduleArgs); |
291 | |
292 | if ( !args->isSet( "icon" ) && modules.count() == 1) |
293 | { |
294 | QString iconName = KCModuleInfo(modules.first()).icon(); |
295 | dlg->setWindowIcon( KIcon(iconName) ); |
296 | } |
297 | dlg->exec(); |
298 | delete dlg; |
299 | |
300 | return 0; |
301 | } |
302 | // vim: sw=4 et sts=4 |
303 | |