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 ******************************************************************/
25 #include <config-workspace.h>
26 #include <config-ksmserver.h>
33 #include <KMessageBox>
34 #include <QtDBus/QtDBus>
36 #include <kapplication.h>
37 #include <kcmdlineargs.h>
38 #include <kconfiggroup.h>
39 #include <kaboutdata.h>
44 #include <kmanagerselection.h>
45 #include <kwindowsystem.h>
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)." );
55 Colormap colormap
= 0;
58 extern KSMServer
* the_server
;
60 void IoErrorHandler ( IceConn iceConn
)
62 the_server
->ioError( iceConn
);
65 bool writeTest(QByteArray path
)
68 int fd
= mkstemp(path
.data());
71 if (write(fd
, "Hello World\n", 12) == -1)
73 int save_errno
= errno
;
86 if( qgetenv( "KDE_SKIP_ARGB_VISUALS" ) == "1" )
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
93 kError() << "Cannot connect to the X server";
97 int screen
= DefaultScreen(dpy
);
98 int eventBase
, errorBase
;
100 if (XRenderQueryExtension(dpy
, &eventBase
, &errorBase
))
104 templ
.screen
= screen
;
106 templ
.c_class
= TrueColor
;
107 XVisualInfo
*xvi
= XGetVisualInfo(dpy
, VisualScreenMask
|
111 for (int i
= 0; i
< nvi
; ++i
)
113 XRenderPictFormat
*format
= XRenderFindVisualFormat(dpy
,
115 if (format
->type
== PictTypeDirect
&& format
->direct
.alphaMask
)
117 visual
= xvi
[i
].visual
;
118 colormap
= XCreateColormap(dpy
, RootWindow(dpy
, screen
),
125 XCloseDisplay( dpy
);
129 void sanity_check( int argc
, char* argv
[], KAboutData
* aboutDataPtr
)
132 QByteArray path
= getenv("HOME");
133 QByteArray readOnly
= getenv("KDE_HOME_READONLY");
136 msg
= QLatin1String("$HOME not set!");
138 if (msg
.isEmpty() && access(path
.data(), W_OK
))
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
))
148 msg
= "$HOME directory (%1) does not exist.";
150 msg
= "No read access to $HOME directory (%1).";
152 if (msg
.isEmpty() && readOnly
.isEmpty() && !writeTest(path
))
155 msg
= "$HOME directory (%1) is out of disk space.";
157 msg
= QByteArray("Writing to the $HOME directory (%1) failed with\n "
158 "the error '")+QByteArray(strerror(errno
))+QByteArray("'");
162 path
= getenv("ICEAUTHORITY");
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'.";
177 #warning Is something like this needed for D-BUS?
180 path
= DCOPClient::dcopServerFile();
181 if (access(path
.data(), R_OK
) && (errno
== ENOENT
))
184 if (DCOPClient::iceauthPath().isEmpty())
185 msg
= "Could not find 'iceauth' in path.";
191 path
= getenv("KDETMP");
194 if (!writeTest(path
))
197 msg
= "Temp directory (%1) is out of disk space.";
199 msg
= "Writing to the temp directory (%1) failed with\n "
200 "the error '"+QByteArray(strerror(errno
))+QByteArray("'");
203 if (msg
.isEmpty() && (path
!= "/tmp"))
206 if (!writeTest(path
))
209 msg
= "Temp directory (%1) is out of disk space.";
211 msg
= "Writing to the temp directory (%1) failed with\n "
212 "the error '"+QByteArray(strerror(errno
))+QByteArray("'");
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'.";
225 const char *msg_pre
=
226 "The following installation problem was detected\n"
227 "while trying to start KDE:"
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!");
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
;
256 options
.add("restore", ki18n("Restores the saved user session if available"));
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=");
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);
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.");
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)
291 qWarning("--[no]local is not supported on your platform. Sorry.");
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
);
321 server
->startDefaultSession();
323 kde_running
.release(); // needs to be done before QApplication destruction