not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / kcminit / main.cpp
blob97c95cc73dc10ebbac832c050a2cb5f029a3dabe
1 /*
2 Copyright (c) 1999 Matthias Hoelzer-Kluepfel <hoelzer@kde.org>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 #include <config-workspace.h>
22 #include "main.h"
24 #include <unistd.h>
26 #include <QFile>
27 #include <QTimer>
29 #include <kapplication.h>
30 #include <kcmdlineargs.h>
31 #include <kaboutdata.h>
32 #include <kservice.h>
33 #include <klibloader.h>
34 #include <kdebug.h>
35 #include <kconfig.h>
36 #include <kconfiggroup.h>
37 #include <klocale.h>
38 #include <ktoolinvocation.h>
39 #include <klauncher_iface.h>
40 #include <QtDBus/QtDBus>
41 #ifdef Q_WS_X11
42 #include <X11/Xlib.h>
43 #include <QX11Info>
44 #endif
46 #include <kservicetypetrader.h>
47 #include <kdefakes.h>
49 static int ready[ 2 ];
50 static bool startup = false;
52 static void sendReady()
54 if( ready[ 1 ] == -1 )
55 return;
56 char c = 0;
57 write( ready[ 1 ], &c, 1 );
58 close( ready[ 1 ] );
59 ready[ 1 ] = -1;
62 static void waitForReady()
64 char c = 1;
65 close( ready[ 1 ] );
66 read( ready[ 0 ], &c, 1 );
67 close( ready[ 0 ] );
70 bool KCMInit::runModule(const QString &libName, KLibLoader *loader, KService::Ptr service)
72 KLibrary *lib = loader->library(libName);
73 if (lib) {
74 QVariant tmp = service->property("X-KDE-Init-Symbol", QVariant::String);
75 QString kcminit;
76 if( tmp.isValid() )
78 kcminit = tmp.toString();
79 if( !kcminit.startsWith( QLatin1String( "kcminit_" ) ) )
80 kcminit = "kcminit_" + kcminit;
82 else
83 kcminit = "kcminit_" + libName;
85 // get the kcminit_ function
86 KLibrary::void_function_ptr init = lib->resolveFunction(kcminit.toUtf8());
87 if (init) {
88 // initialize the module
89 kDebug(1208) << "Initializing " << libName << ": " << kcminit;
91 void (*func)() = (void(*)())init;
92 func();
93 return true;
95 loader->unloadLibrary(libName);
97 return false;
100 void KCMInit::runModules( int phase )
102 KLibLoader *loader = KLibLoader::self();
103 for(KService::List::Iterator it = list.begin();
104 it != list.end();
105 ++it) {
106 KService::Ptr service = (*it);
108 QVariant tmp = service->property("X-KDE-Init-Library", QVariant::String);
109 QString library;
110 if( tmp.isValid() )
112 library = tmp.toString();
113 if( !library.startsWith( QLatin1String( "kcminit_" ) ) )
114 library = QLatin1String( "kcminit_" ) + library;
116 else
118 library = service->library();
121 if (library.isEmpty())
122 continue; // Skip
124 // see ksmserver's README for the description of the phases
125 QVariant vphase = service->property("X-KDE-Init-Phase", QVariant::Int );
126 int libphase = 1;
127 if( vphase.isValid() )
128 libphase = vphase.toInt();
130 if( phase != -1 && libphase != phase )
131 continue;
133 // try to load the library
134 if (! alreadyInitialized.contains( library.toAscii() )) {
135 if (!runModule(library, loader, service)) {
136 library = QLatin1String( "lib" ) + library;
137 if (! alreadyInitialized.contains( library.toAscii() )) {
138 runModule(library, loader, service);
139 alreadyInitialized.append( library.toAscii() );
141 } else
142 alreadyInitialized.append( library.toAscii() );
147 KCMInit::KCMInit( KCmdLineArgs* args )
149 QDBusConnection::sessionBus().registerObject("/kcminit", this,
150 QDBusConnection::ExportScriptableSlots|QDBusConnection::ExportScriptableSignals);
151 QString arg;
152 if (args->count() == 1) {
153 arg = args->arg(0);
156 if (args->isSet("list"))
158 list = KServiceTypeTrader::self()->query( "KCModuleInit" );
160 for(KService::List::Iterator it = list.begin();
161 it != list.end();
162 ++it)
164 KService::Ptr service = (*it);
165 if (service->library().isEmpty())
166 continue; // Skip
167 printf("%s\n", QFile::encodeName(service->desktopEntryName()).data());
169 return;
172 if (!arg.isEmpty()) {
174 QString module = arg;
175 if (!module.endsWith(".desktop"))
176 module += ".desktop";
178 KService::Ptr serv = KService::serviceByStorageId( module );
179 if ( !serv || serv->library().isEmpty() ) {
180 kError(1208) << i18n("Module %1 not found", module) << endl;
181 return;
182 } else
183 list.append(serv);
185 } else {
187 // locate the desktop files
188 list = KServiceTypeTrader::self()->query( "KCModuleInit" );
191 // This key has no GUI apparently
192 KConfig _config( "kcmdisplayrc" );
193 KConfigGroup config(&_config, "X11");
194 #ifdef Q_WS_X11
195 bool multihead = !config.readEntry( "disableMultihead", false) &&
196 (ScreenCount(QX11Info::display()) > 1);
197 #else
198 bool multihead = false;
199 #endif
200 // Pass env. var to kdeinit.
201 QString name = "KDE_MULTIHEAD";
202 QString value = multihead ? "true" : "false";
203 KToolInvocation::klauncher()->setLaunchEnv(name, value);
204 setenv( name.toLatin1().constData(), value.toLatin1().constData(), 1 ); // apply effect also to itself
206 if( startup )
208 runModules( 0 );
209 XEvent e;
210 e.xclient.type = ClientMessage;
211 e.xclient.message_type = XInternAtom( QX11Info::display(), "_KDE_SPLASH_PROGRESS", False );
212 e.xclient.display = QX11Info::display();
213 e.xclient.window = QX11Info::appRootWindow();
214 e.xclient.format = 8;
215 strcpy( e.xclient.data.b, "kcminit" );
216 XSendEvent( QX11Info::display(), QX11Info::appRootWindow(), False, SubstructureNotifyMask, &e );
217 sendReady();
218 QTimer::singleShot( 300 * 1000, qApp, SLOT( quit())); // just in case
219 qApp->exec(); // wait for runPhase1() and runPhase2()
221 else
222 runModules( -1 ); // all phases
225 KCMInit::~KCMInit()
227 sendReady();
230 void KCMInit::runPhase1()
232 runModules( 1 );
233 emit phase1Done();
236 void KCMInit::runPhase2()
238 runModules( 2 );
239 emit phase2Done();
240 qApp->exit( 0 );
243 extern "C" KDE_EXPORT int kdemain(int argc, char *argv[])
245 // kdeinit waits for kcminit to finish, but during KDE startup
246 // only important kcm's are started very early in the login process,
247 // the rest is delayed, so fork and make parent return after the initial phase
248 pipe( ready );
249 if( fork() != 0 )
251 waitForReady();
252 return 0;
254 close( ready[ 0 ] );
256 startup = ( strcmp( argv[ 0 ], "kcminit_startup" ) == 0 ); // started from startkde?
257 KAboutData aboutData( "kcminit", "kcminit", ki18n("KCMInit"),
259 ki18n("KCMInit - runs startup initialization for Control Modules."));
261 KCmdLineArgs::init(argc, argv, &aboutData);
263 KCmdLineOptions options;
264 options.add("list", ki18n("List modules that are run at startup"));
265 options.add("+module", ki18n("Configuration module to run"));
266 KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
268 KApplication app;
269 QDBusConnection::sessionBus().interface()->registerService( "org.kde.kcminit",
270 QDBusConnectionInterface::DontQueueService );
271 KLocale::setMainCatalog(0);
272 KCMInit kcminit( KCmdLineArgs::parsedArgs());
273 return 0;
276 #include "main.moc"