not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / kdm / kfrontend / kgapp.cpp
blob93dfec34853d639ff76647e1c7fd13b2c766550d
1 /*
3 Greeter module for xdm
5 Copyright (C) 1997, 1998 Steffen Hansen <hansen@kde.org>
6 Copyright (C) 2000-2003 Oswald Buddenhagen <ossi@kde.org>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 #include "kgapp.h"
27 #include "kdm_greet.h"
28 #include "kdmshutdown.h"
29 #include "kdmconfig.h"
30 #include "kgreeter.h"
31 #ifdef XDMCP
32 # include "kchooser.h"
33 #endif
34 #include "themer/kdmthemer.h"
35 #include "utils.h"
37 #include <kcrash.h>
38 #include <kglobalsettings.h>
39 #include <kcomponentdata.h>
40 #include <kprocess.h>
41 #include <kconfig.h>
42 #include <kstandarddirs.h>
44 #include <QDesktopWidget>
45 #include <QX11Info>
47 #include <stdio.h>
48 #include <stdlib.h> // free(), exit()
49 #include <unistd.h> // alarm()
50 #include <signal.h>
51 #include <locale.h>
52 #include <fcntl.h>
53 #include <sys/stat.h>
54 #ifdef USE_SYSLOG
55 # include <syslog.h>
56 #endif
58 #include <X11/Xlib.h>
59 #include <X11/Xutil.h>
60 #include <X11/keysym.h>
61 #include <X11/cursorfont.h>
63 extern "C" {
65 static void
66 sigAlarm( int )
68 exit( EX_RESERVER_DPY );
73 GreeterApp::GreeterApp( int argc, char **argv ) :
74 inherited( argc, argv ),
75 regrabPtr( false ), regrabKbd( false ),
76 dragWidget( 0 )
78 pingInterval = _isLocal ? 0 : _pingInterval;
79 if (pingInterval) {
80 struct sigaction sa;
81 sigemptyset( &sa.sa_mask );
82 sa.sa_flags = 0;
83 sa.sa_handler = sigAlarm;
84 sigaction( SIGALRM, &sa, 0 );
85 alarm( pingInterval * 70 ); // sic! give the "proper" pinger enough time
86 pingTimerId = startTimer( pingInterval * 60000 );
87 } else
88 pingTimerId = 0;
91 void
92 GreeterApp::timerEvent( QTimerEvent *ev )
94 if (ev->timerId() == pingTimerId) {
95 alarm( 0 );
96 if (!pingServer( QX11Info::display() ))
97 ::exit( EX_RESERVER_DPY );
98 alarm( pingInterval * 70 ); // sic! give the "proper" pinger enough time
102 bool
103 GreeterApp::x11EventFilter( XEvent * ev )
105 KeySym sym;
107 switch (ev->type) {
108 case FocusIn:
109 case FocusOut:
110 if (ev->xfocus.mode == NotifyUngrab) {
111 if (!regrabKbd) {
112 secureKeyboard( QX11Info::display() );
113 regrabKbd = true;
115 } else
116 regrabKbd = false;
117 break;
118 case EnterNotify:
119 case LeaveNotify:
120 if (ev->xcrossing.mode == NotifyUngrab) {
121 if (!regrabPtr) {
122 securePointer( QX11Info::display() );
123 regrabPtr = true;
125 } else
126 regrabPtr = false;
127 break;
128 case KeyPress:
129 sym = XLookupKeysym( &ev->xkey, 0 );
130 if (sym != XK_Return && !IsModifierKey( sym ))
131 emit activity();
132 break;
133 case ButtonPress:
134 emit activity();
135 /* fall through */
136 case ButtonRelease:
137 // Hack to let the RMB work as LMB
138 if (ev->xbutton.button == 3)
139 ev->xbutton.button = 1;
140 /* fall through */
141 case MotionNotify:
142 if (ev->xbutton.state & Button3Mask)
143 ev->xbutton.state = (ev->xbutton.state & ~Button3Mask) | Button1Mask;
144 switch (ev->type) {
145 case ButtonPress:
146 if (((ev->xbutton.state & Mod1Mask) && ev->xbutton.button == 1) ||
147 dragWidget)
149 if (!dragWidget &&
150 ev->xbutton.window != QX11Info::appRootWindow( _greeterScreen ) &&
151 (dragWidget = QWidget::find( ev->xbutton.window )))
153 dragWidget = dragWidget->window();
154 dialogStartPos = dragWidget->geometry().center();
155 mouseStartPos = QPoint( ev->xbutton.x_root, ev->xbutton.y_root );
156 setOverrideCursor( QCursor( Qt::SizeAllCursor ) );
158 return true;
160 break;
161 case ButtonRelease:
162 if (dragWidget) {
163 restoreOverrideCursor();
164 dragWidget = 0;
165 return true;
167 break;
168 case MotionNotify:
169 if (dragWidget) {
170 QRect grt( dragWidget->rect() );
171 grt.moveCenter( dialogStartPos +
172 QPoint( ev->xbutton.x_root, ev->xbutton.y_root ) -
173 mouseStartPos );
174 FDialog::fitInto( qApp->desktop()->screenGeometry( _greeterScreen ), grt );
175 dragWidget->setGeometry( grt );
176 return true;
178 break;
180 break;
182 return false;
185 extern "C" {
187 static int
188 xIOErr( Display * )
190 exit( EX_RESERVER_DPY );
191 // Bogus return value, notreached
192 return 0;
195 static void
196 sigterm( int n ATTR_UNUSED )
198 exit( EX_NORMAL );
201 static char *savhome;
203 static void
204 cleanup( void )
206 char buf[128];
208 if (strcmp( savhome, getenv( "HOME" ) ) || memcmp( savhome, "/tmp/", 5 ))
209 logError( "Internal error: memory corruption detected\n" ); /* no panic: recursion */
210 else {
211 sprintf( buf, "rm -rf %s", savhome );
212 system( buf );
216 static int
217 goodLocale( const char *var )
219 char *l = getenv( var );
220 if (!l)
221 return False;
222 if (*l && strcmp( l, "C" ) && strcmp( l, "POSIX" ))
223 return True;
224 unsetenv( l );
225 return False;
229 main( int argc ATTR_UNUSED, char **argv )
231 char *ci;
232 int i;
233 char qtrc[40];
235 if (!(ci = getenv( "CONINFO" ))) {
236 fprintf( stderr, "This program is part of kdm and should not be run manually.\n" );
237 return 1;
239 if (sscanf( ci, "%d %d %d %d", &srfd, &swfd, &mrfd, &mwfd ) != 4)
240 return 1;
241 fcntl( srfd, F_SETFD, FD_CLOEXEC );
242 fcntl( swfd, F_SETFD, FD_CLOEXEC );
243 fcntl( mrfd, F_SETFD, FD_CLOEXEC );
244 fcntl( mwfd, F_SETFD, FD_CLOEXEC );
245 gSet( 0 );
247 #ifdef USE_SYSLOG
248 openlog( "kdm_greet", LOG_PID, LOG_DAEMON );
249 #endif
251 if ((debugLevel = gRecvInt()) & DEBUG_WGREET)
252 sleep( 100 );
254 signal( SIGTERM, sigterm );
256 dname = getenv( "DISPLAY" );
258 initConfig();
260 /* for QSettings */
261 srand( time( 0 ) );
262 for (i = 0; i < 10000; i++) {
263 sprintf( qtrc, "/tmp/%010d", rand() );
264 if (!mkdir( qtrc, 0700 ))
265 goto okay;
267 logPanic( "Cannot create $HOME\n" );
268 okay:
269 if (setenv( "HOME", qtrc, 1 ))
270 logPanic( "Cannot set $HOME\n" );
271 if (!(savhome = strdup( qtrc )))
272 logPanic( "Cannot save $HOME\n" );
273 atexit( cleanup );
275 if (*_language) {
277 * Make reasonably sure the locale is not POSIX. This will still fail
278 * if all of the following apply:
279 * - LANG, LC_MESSAGES & LC_ALL resolve to POSIX
280 * - an abbreviated locale is configured (the kcm does this)
281 * - the en_US locale is not installed
283 if (!goodLocale( "LC_ALL" ) &&
284 !goodLocale( "LC_MESSAGES" ) &&
285 !goodLocale( "LANG" ))
287 if (strchr( _language, '_' ) && setlocale( LC_ALL, _language ))
288 setenv( "LANG", _language, 1 );
289 else if (setlocale( LC_ALL, "en_US" ))
290 setenv( "LANG", "en_US", 1 );
291 else
292 logError( "Cannot set locale. Translations will not work.\n" );
295 setenv( "LANGUAGE", _language, 1 );
298 static char *fakeArgv[] = { (char *)"kdmgreet", 0 };
300 KCrash::setFlags( KCrash::KeepFDs | KCrash::SaferDialog | KCrash::AlwaysDirectly );
301 KCrash::setApplicationName( QLatin1String( fakeArgv[0] ) );
302 KCrash::setCrashHandler( KCrash::defaultCrashHandler );
303 XSetIOErrorHandler( xIOErr );
304 KComponentData inst( fakeArgv[0] );
305 GreeterApp app( as(fakeArgv) - 1, fakeArgv );
306 foreach (const QString &dir, KGlobal::dirs()->resourceDirs( "qtplugins" ))
307 app.addLibraryPath( dir );
308 initQAppConfig();
309 KGlobalSettings::self();
311 Display *dpy = QX11Info::display();
312 QDesktopWidget *dw = app.desktop();
314 if (_greeterScreen < 0)
315 _greeterScreen = _greeterScreen == -2 ?
316 dw->screenNumber( QPoint( dw->width() - 1, 0 ) ) :
317 dw->screenNumber( QPoint( 0, 0 ) );
319 _colorScheme = KStandardDirs::locate( "data", "color-schemes/" + _colorScheme + ".colors" );
320 if (!_colorScheme.isEmpty()) {
321 KSharedConfigPtr config = KSharedConfig::openConfig( _colorScheme, KConfig::SimpleConfig );
322 app.setPalette( KGlobalSettings::createApplicationPalette( config ) );
325 KdmThemer *themer;
326 if (_useTheme && !_theme.isEmpty()) {
327 QMap<QString, bool> showTypes;
328 // "config" not implemented
329 #ifdef XDMCP
330 if (_loginMode != LOGIN_LOCAL_ONLY)
331 showTypes["chooser"] = true;
332 #endif
333 showTypes["system"] = true;
334 if (_allowShutdown != SHUT_NONE) {
335 showTypes["halt"] = true;
336 showTypes["reboot"] = true;
337 // "suspend" not implemented
340 themer = new KdmThemer( _theme, showTypes, app.desktop()->screen() );
341 if (!themer->isOK()) {
342 delete themer;
343 themer = 0;
345 } else
346 themer = 0;
348 setupModifiers( dpy, _numLockStatus );
349 secureDisplay( dpy );
350 KProcess *proc = 0;
351 if (!_grabServer) {
352 if (_useBackground && !themer) {
353 proc = new KProcess;
354 *proc << QByteArray( argv[0], strrchr( argv[0], '/' ) - argv[0] + 1 ) + "krootimage";
355 *proc << _backgroundCfg;
356 proc->start();
358 gSendInt( G_SetupDpy );
359 gRecvInt();
362 gSendInt( G_Ready );
364 if (themer) {
365 QPixmap pm( dw->size() );
366 for (int i = 0; i < dw->numScreens(); i++)
367 themer->paintBackground( &pm, dw->screenGeometry( i ), i == _greeterScreen );
368 QPalette palette;
369 palette.setBrush( dw->backgroundRole(), QBrush( pm ) );
370 dw->setPalette( palette );
371 dw->setAutoFillBackground( true );
372 dw->setAttribute( Qt::WA_PaintOnScreen );
373 dw->show();
374 dw->repaint();
377 setCursor( dpy, app.desktop()->winId(), XC_left_ptr );
379 int rslt = ex_exit;
380 for (;;) {
381 int cmd = gRecvInt();
383 if (cmd == G_ConfShutdown) {
384 gSet( 1 );
385 gSendInt( G_QryDpyShutdown );
386 int how = gRecvInt(), uid = gRecvInt();
387 QString os = qString( gRecvStr() );
388 gSet( 0 );
389 KDMSlimShutdown::externShutdown( how, os, uid );
390 gSendInt( G_Ready );
391 break;
394 if (cmd == G_ErrorGreet) {
395 if (KGVerify::handleFailVerify( qApp->desktop()->screen( _greeterScreen ), true ))
396 break;
397 _autoLoginDelay = 0;
398 cmd = G_Greet;
401 KProcess *proc2 = 0;
402 app.setOverrideCursor( Qt::WaitCursor );
403 FDialog *dialog;
404 #ifdef XDMCP
405 if (cmd == G_Choose) {
406 dialog = new ChooserDlg;
407 gSendInt( G_Ready ); /* tell chooser to go into async mode */
408 gRecvInt(); /* ack */
409 } else
410 #endif
412 if ((cmd != G_GreetTimed && !_autoLoginAgain) ||
413 _autoLoginUser.isEmpty())
414 _autoLoginDelay = 0;
415 if (themer)
416 dialog = new KThemedGreeter( themer );
417 else
418 dialog = new KStdGreeter;
419 if (*_preloader) {
420 proc2 = new KProcess;
421 *proc2 << _preloader;
422 proc2->start();
425 app.restoreOverrideCursor();
426 debug( "entering event loop\n" );
427 rslt = dialog->exec();
428 debug( "left event loop\n" );
429 delete dialog;
430 delete proc2;
431 #ifdef XDMCP
432 switch (rslt) {
433 case ex_greet:
434 gSendInt( G_DGreet );
435 continue;
436 case ex_choose:
437 gSendInt( G_DChoose );
438 continue;
439 default:
440 break;
442 #endif
443 break;
446 KGVerify::done();
448 delete proc;
449 delete themer;
451 unsecureDisplay( dpy );
452 restoreModifiers();
454 if (rslt == ex_login) {
455 gSendInt( G_Ready );
456 KGVerify::handleFailVerify( qApp->desktop()->screen( _greeterScreen ), false );
459 return EX_NORMAL;
462 } // extern "C"
464 #include "kgapp.moc"