1 | /* |
2 | Copyright (c) 1999 Matthias Hoelzer-Kluepfel <hoelzer@kde.org> |
3 | |
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. |
8 | |
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. |
13 | |
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. |
17 | |
18 | */ |
19 | |
20 | #include <config-workspace.h> |
21 | |
22 | #include "main.h" |
23 | |
24 | #include <unistd.h> |
25 | |
26 | #include <QFile> |
27 | #include <QTimer> |
28 | |
29 | #include <kapplication.h> |
30 | #include <kcmdlineargs.h> |
31 | #include <kaboutdata.h> |
32 | #include <kservice.h> |
33 | #include <klibrary.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 |
45 | |
46 | #include <kservicetypetrader.h> |
47 | #include <kdefakes.h> |
48 | |
49 | static int ready[ 2 ]; |
50 | static bool startup = false; |
51 | |
52 | static void sendReady() |
53 | { |
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; |
60 | } |
61 | |
62 | static void waitForReady() |
63 | { |
64 | char c = 1; |
65 | close( ready[ 1 ] ); |
66 | read( ready[ 0 ], &c, 1 ); |
67 | close( ready[ 0 ] ); |
68 | } |
69 | |
70 | bool KCMInit::runModule(const QString &libName, KService::Ptr service) |
71 | { |
72 | KLibrary lib(libName); |
73 | if (lib.load()) { |
74 | QVariant tmp = service->property("X-KDE-Init-Symbol" , QVariant::String); |
75 | QString kcminit; |
76 | if( tmp.isValid() ) |
77 | { |
78 | kcminit = tmp.toString(); |
79 | if( !kcminit.startsWith( QLatin1String( "kcminit_" ) ) ) |
80 | kcminit = "kcminit_" + kcminit; |
81 | } |
82 | else |
83 | kcminit = "kcminit_" + libName; |
84 | |
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; |
90 | |
91 | void (*func)() = (void(*)())init; |
92 | func(); |
93 | return true; |
94 | } else { |
95 | kDebug(1208) << "Module" << libName << "does not actually have a kcminit function" ; |
96 | } |
97 | } |
98 | return false; |
99 | } |
100 | |
101 | void KCMInit::runModules( int phase ) |
102 | { |
103 | for(KService::List::Iterator it = list.begin(); |
104 | it != list.end(); |
105 | ++it) { |
106 | KService::Ptr service = (*it); |
107 | |
108 | QVariant tmp = service->property("X-KDE-Init-Library" , QVariant::String); |
109 | QString library; |
110 | if( tmp.isValid() ) |
111 | { |
112 | library = tmp.toString(); |
113 | if( !library.startsWith( QLatin1String( "kcminit_" ) ) ) |
114 | library = QLatin1String( "kcminit_" ) + library; |
115 | } |
116 | else |
117 | { |
118 | library = service->library(); |
119 | } |
120 | |
121 | if (library.isEmpty()) |
122 | continue; // Skip |
123 | |
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(); |
129 | |
130 | if( phase != -1 && libphase != phase ) |
131 | continue; |
132 | |
133 | // try to load the library |
134 | if (!alreadyInitialized.contains(library)) { |
135 | runModule(library, service); |
136 | alreadyInitialized.append(library); |
137 | } |
138 | } |
139 | } |
140 | |
141 | KCMInit::KCMInit( KCmdLineArgs* args ) |
142 | { |
143 | QDBusConnection::sessionBus().registerObject("/kcminit" , this, |
144 | QDBusConnection::ExportScriptableSlots|QDBusConnection::ExportScriptableSignals); |
145 | QString arg; |
146 | if (args->count() == 1) { |
147 | arg = args->arg(0); |
148 | } |
149 | |
150 | if (args->isSet("list" )) |
151 | { |
152 | list = KServiceTypeTrader::self()->query( "KCModuleInit" ); |
153 | |
154 | for(KService::List::Iterator it = list.begin(); |
155 | it != list.end(); |
156 | ++it) |
157 | { |
158 | KService::Ptr service = (*it); |
159 | if (service->library().isEmpty()) |
160 | continue; // Skip |
161 | printf("%s\n" , QFile::encodeName(service->desktopEntryName()).data()); |
162 | } |
163 | return; |
164 | } |
165 | |
166 | if (!arg.isEmpty()) { |
167 | |
168 | QString module = arg; |
169 | if (!module.endsWith(".desktop" )) |
170 | module += ".desktop" ; |
171 | |
172 | KService::Ptr serv = KService::serviceByStorageId( module ); |
173 | if ( !serv || serv->library().isEmpty() ) { |
174 | kError(1208) << i18n("Module %1 not found" , module) << endl; |
175 | return; |
176 | } else |
177 | list.append(serv); |
178 | |
179 | } else { |
180 | |
181 | // locate the desktop files |
182 | list = KServiceTypeTrader::self()->query( "KCModuleInit" ); |
183 | |
184 | } |
185 | // This key has no GUI apparently |
186 | KConfig _config( "kcmdisplayrc" ); |
187 | KConfigGroup config(&_config, "X11" ); |
188 | #ifdef Q_WS_X11 |
189 | bool multihead = !config.readEntry( "disableMultihead" , false) && |
190 | (ScreenCount(QX11Info::display()) > 1); |
191 | #else |
192 | bool multihead = false; |
193 | #endif |
194 | // Pass env. var to kdeinit. |
195 | QString name = "KDE_MULTIHEAD" ; |
196 | QString value = multihead ? "true" : "false" ; |
197 | KToolInvocation::klauncher()->setLaunchEnv(name, value); |
198 | setenv( name.toLatin1().constData(), value.toLatin1().constData(), 1 ); // apply effect also to itself |
199 | |
200 | if( startup ) |
201 | { |
202 | runModules( 0 ); |
203 | XEvent e; |
204 | e.xclient.type = ClientMessage; |
205 | e.xclient.message_type = XInternAtom( QX11Info::display(), "_KDE_SPLASH_PROGRESS" , False ); |
206 | e.xclient.display = QX11Info::display(); |
207 | e.xclient.window = QX11Info::appRootWindow(); |
208 | e.xclient.format = 8; |
209 | strcpy( e.xclient.data.b, "kcminit" ); |
210 | XSendEvent( QX11Info::display(), QX11Info::appRootWindow(), False, SubstructureNotifyMask, &e ); |
211 | sendReady(); |
212 | QTimer::singleShot( 300 * 1000, qApp, SLOT(quit())); // just in case |
213 | qApp->exec(); // wait for runPhase1() and runPhase2() |
214 | } |
215 | else |
216 | runModules( -1 ); // all phases |
217 | } |
218 | |
219 | KCMInit::~KCMInit() |
220 | { |
221 | sendReady(); |
222 | } |
223 | |
224 | void KCMInit::runPhase1() |
225 | { |
226 | runModules( 1 ); |
227 | emit phase1Done(); |
228 | } |
229 | |
230 | void KCMInit::runPhase2() |
231 | { |
232 | runModules( 2 ); |
233 | emit phase2Done(); |
234 | qApp->exit( 0 ); |
235 | } |
236 | |
237 | extern "C" KDE_EXPORT int kdemain(int argc, char *argv[]) |
238 | { |
239 | // kdeinit waits for kcminit to finish, but during KDE startup |
240 | // only important kcm's are started very early in the login process, |
241 | // the rest is delayed, so fork and make parent return after the initial phase |
242 | pipe( ready ); |
243 | if( fork() != 0 ) |
244 | { |
245 | waitForReady(); |
246 | return 0; |
247 | } |
248 | close( ready[ 0 ] ); |
249 | |
250 | startup = ( strcmp( argv[ 0 ], "kcminit_startup" ) == 0 ); // started from startkde? |
251 | KAboutData aboutData( "kcminit" , "kcminit" , ki18n("KCMInit" ), |
252 | "" , |
253 | ki18n("KCMInit - runs startup initialization for Control Modules." )); |
254 | |
255 | KCmdLineArgs::init(argc, argv, &aboutData); |
256 | |
257 | KCmdLineOptions options; |
258 | options.add("list" , ki18n("List modules that are run at startup" )); |
259 | options.add("+module" , ki18n("Configuration module to run" )); |
260 | KCmdLineArgs::addCmdLineOptions( options ); // Add our own options. |
261 | |
262 | KApplication app; |
263 | QDBusConnection::sessionBus().interface()->registerService( "org.kde.kcminit" , |
264 | QDBusConnectionInterface::DontQueueService ); |
265 | KLocale::setMainCatalog(0); |
266 | KCMInit kcminit( KCmdLineArgs::parsedArgs()); |
267 | return 0; |
268 | } |
269 | |
270 | #include "main.moc" |
271 | |