not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / ksmserver / main.cpp
blobb859af470492743e874df3e206809d3d6cfda514
1 /*****************************************************************
2 ksmserver - the KDE session management server
4 Copyright 2000 Matthias Ettrich <ettrich@kde.org>
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 ******************************************************************/
24 #include <fixx11h.h>
25 #include <config-workspace.h>
26 #include <config-ksmserver.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <fcntl.h>
30 #include <errno.h>
31 #include <string.h>
33 #include <KMessageBox>
34 #include <QtDBus/QtDBus>
36 #include <kapplication.h>
37 #include <kcmdlineargs.h>
38 #include <kconfiggroup.h>
39 #include <kaboutdata.h>
40 #include <kdebug.h>
41 #include <klocale.h>
42 #include <kglobal.h>
43 #include <kconfig.h>
44 #include <kmanagerselection.h>
45 #include <kwindowsystem.h>
46 #include "server.h"
47 #include <QX11Info>
49 #include <X11/extensions/Xrender.h>
51 static const char version[] = "0.4";
52 static const char description[] = I18N_NOOP( "The reliable KDE session manager that talks the standard X11R6 \nsession management protocol (XSMP)." );
54 Display* dpy = 0;
55 Colormap colormap = 0;
56 Visual *visual = 0;
58 extern KSMServer* the_server;
60 void IoErrorHandler ( IceConn iceConn)
62 the_server->ioError( iceConn );
65 bool writeTest(QByteArray path)
67 path += "/XXXXXX";
68 int fd = mkstemp(path.data());
69 if (fd == -1)
70 return false;
71 if (write(fd, "Hello World\n", 12) == -1)
73 int save_errno = errno;
74 close(fd);
75 unlink(path.data());
76 errno = save_errno;
77 return false;
79 close(fd);
80 unlink(path.data());
81 return true;
84 void checkComposite()
86 if( qgetenv( "KDE_SKIP_ARGB_VISUALS" ) == "1" )
87 return;
88 // thanks to zack rusin and frederik for pointing me in the right direction
89 // for the following bits of X11 code
90 dpy = XOpenDisplay(0); // open default display
91 if (!dpy)
93 kError() << "Cannot connect to the X server";
94 return;
97 int screen = DefaultScreen(dpy);
98 int eventBase, errorBase;
100 if (XRenderQueryExtension(dpy, &eventBase, &errorBase))
102 int nvi;
103 XVisualInfo templ;
104 templ.screen = screen;
105 templ.depth = 32;
106 templ.c_class = TrueColor;
107 XVisualInfo *xvi = XGetVisualInfo(dpy, VisualScreenMask |
108 VisualDepthMask |
109 VisualClassMask,
110 &templ, &nvi);
111 for (int i = 0; i < nvi; ++i)
113 XRenderPictFormat *format = XRenderFindVisualFormat(dpy,
114 xvi[i].visual);
115 if (format->type == PictTypeDirect && format->direct.alphaMask)
117 visual = xvi[i].visual;
118 colormap = XCreateColormap(dpy, RootWindow(dpy, screen),
119 visual, AllocNone);
120 return;
125 XCloseDisplay( dpy );
126 dpy = NULL;
129 void sanity_check( int argc, char* argv[], KAboutData* aboutDataPtr )
131 QString msg;
132 QByteArray path = getenv("HOME");
133 QByteArray readOnly = getenv("KDE_HOME_READONLY");
134 if (path.isEmpty())
136 msg = QLatin1String("$HOME not set!");
138 if (msg.isEmpty() && access(path.data(), W_OK))
140 if (errno == ENOENT)
141 msg = QLatin1String("$HOME directory (%1) does not exist.");
142 else if (readOnly.isEmpty())
143 msg = QLatin1String("No write access to $HOME directory (%1).");
145 if (msg.isEmpty() && access(path.data(), R_OK))
147 if (errno == ENOENT)
148 msg = "$HOME directory (%1) does not exist.";
149 else
150 msg = "No read access to $HOME directory (%1).";
152 if (msg.isEmpty() && readOnly.isEmpty() && !writeTest(path))
154 if (errno == ENOSPC)
155 msg = "$HOME directory (%1) is out of disk space.";
156 else
157 msg = QByteArray("Writing to the $HOME directory (%1) failed with\n "
158 "the error '")+QByteArray(strerror(errno))+QByteArray("'");
160 if (msg.isEmpty())
162 path = getenv("ICEAUTHORITY");
163 if (path.isEmpty())
165 path = getenv("HOME");
166 path += "/.ICEauthority";
169 if (access(path.data(), W_OK) && (errno != ENOENT))
170 msg = "No write access to '%1'.";
171 else if (access(path.data(), R_OK) && (errno != ENOENT))
172 msg = "No read access to '%1'.";
174 if (msg.isEmpty())
176 #ifdef __GNUC__
177 #warning Is something like this needed for D-BUS?
178 #endif
179 #if 0
180 path = DCOPClient::dcopServerFile();
181 if (access(path.data(), R_OK) && (errno == ENOENT))
183 // Check iceauth
184 if (DCOPClient::iceauthPath().isEmpty())
185 msg = "Could not find 'iceauth' in path.";
187 #endif
189 if (msg.isEmpty())
191 path = getenv("KDETMP");
192 if (path.isEmpty())
193 path = "/tmp";
194 if (!writeTest(path))
196 if (errno == ENOSPC)
197 msg = "Temp directory (%1) is out of disk space.";
198 else
199 msg = "Writing to the temp directory (%1) failed with\n "
200 "the error '"+QByteArray(strerror(errno))+QByteArray("'");
203 if (msg.isEmpty() && (path != "/tmp"))
205 path = "/tmp";
206 if (!writeTest(path))
208 if (errno == ENOSPC)
209 msg = "Temp directory (%1) is out of disk space.";
210 else
211 msg = "Writing to the temp directory (%1) failed with\n "
212 "the error '"+QByteArray(strerror(errno))+QByteArray("'");
215 if (msg.isEmpty())
217 path += "/.ICE-unix";
218 if (access(path.data(), W_OK) && (errno != ENOENT))
219 msg = "No write access to '%1'.";
220 else if (access(path.data(), R_OK) && (errno != ENOENT))
221 msg = "No read access to '%1'.";
223 if (!msg.isEmpty())
225 const char *msg_pre =
226 "The following installation problem was detected\n"
227 "while trying to start KDE:"
228 "\n\n ";
229 const char *msg_post = "\n\nKDE is unable to start.\n";
230 fputs(msg_pre, stderr);
231 fprintf(stderr, "%s", qPrintable(msg.arg(QFile::decodeName(path))));
232 fputs(msg_post, stderr);
234 QApplication a(argc, argv);
235 KComponentData i(aboutDataPtr);
236 QString qmsg = msg_pre+msg.arg(QFile::decodeName(path))+msg_post;
237 KMessageBox::error(0, qmsg, "KDE Installation Problem!");
238 exit(255);
242 extern "C" KDE_EXPORT int kdemain( int argc, char* argv[] )
244 KAboutData aboutData( "ksmserver", 0, ki18n("The KDE Session Manager"),
245 version, ki18n(description), KAboutData::License_BSD,
246 ki18n("(C) 2000, The KDE Developers"));
247 aboutData.addAuthor(ki18n("Matthias Ettrich"),KLocalizedString(), "ettrich@kde.org");
248 aboutData.addAuthor(ki18n("Luboš Luňák"), ki18n( "Maintainer" ), "l.lunak@kde.org" );
250 sanity_check(argc, argv, &aboutData);
252 KCmdLineArgs::init(argc, argv, &aboutData);
254 KCmdLineOptions options;
255 options.add("r");
256 options.add("restore", ki18n("Restores the saved user session if available"));
257 options.add("w");
258 options.add("windowmanager <wm>", ki18n("Starts 'wm' in case no other window manager is \nparticipating in the session. Default is 'kwin'"));
259 options.add("nolocal", ki18n("Also allow remote connections"));
260 KCmdLineArgs::addCmdLineOptions( options );
262 putenv((char*)"SESSION_MANAGER=");
263 checkComposite();
264 KApplication *a;
266 if( dpy != NULL && DefaultDepth(dpy, DefaultScreen(dpy)) >= 24) // 16bpp breaks the software logout effect for some reason???
267 a = new KApplication(dpy, visual ? Qt::HANDLE(visual) : 0, colormap ? Qt::HANDLE(colormap) : 0);
268 else
269 a = new KApplication(true);
270 fcntl(ConnectionNumber(QX11Info::display()), F_SETFD, 1);
272 a->setQuitOnLastWindowClosed(false); // #169486
274 KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
276 if( !QDBusConnection::sessionBus().interface()->registerService( "org.kde.ksmserver", QDBusConnectionInterface::DontQueueService ) )
278 qWarning("Could not register with D-BUS. Aborting.");
279 return 1;
282 QString wm = args->getOption("windowmanager");
284 bool only_local = args->isSet("local");
285 #ifndef HAVE__ICETRANSNOLISTEN
286 /* this seems strange, but the default is only_local, so if !only_local
287 * the option --nolocal was given, and we warn (the option --nolocal
288 * does nothing on this platform, as here the default is reversed)
290 if (!only_local) {
291 qWarning("--[no]local is not supported on your platform. Sorry.");
293 only_local = false;
294 #endif
296 KSMServer *server = new KSMServer( wm, only_local);
298 // for the KDE-already-running check in startkde
299 KSelectionOwner kde_running( "_KDE_RUNNING", 0 );
300 kde_running.claim( false );
302 IceSetIOErrorHandler( IoErrorHandler );
304 KConfigGroup config(KGlobal::config(), "General");
306 int realScreenCount = ScreenCount( QX11Info::display() );
307 bool screenCountChanged =
308 ( config.readEntry( "screenCount", realScreenCount ) != realScreenCount );
310 QString loginMode = config.readEntry( "loginMode", "restorePreviousLogout" );
312 if ( args->isSet("restore") && ! screenCountChanged )
313 server->restoreSession( SESSION_BY_USER );
314 else if ( loginMode == "default" || screenCountChanged )
315 server->startDefaultSession();
316 else if ( loginMode == "restorePreviousLogout" )
317 server->restoreSession( SESSION_PREVIOUS_LOGOUT );
318 else if ( loginMode == "restoreSavedSession" )
319 server->restoreSession( SESSION_BY_USER );
320 else
321 server->startDefaultSession();
322 int ret = a->exec();
323 kde_running.release(); // needs to be done before QApplication destruction
324 delete a;
325 return ret;