add more spacing
[personal-kdebase.git] / workspace / kdm / kfrontend / kdm_greet.c
blob34a307b11d1ed8731b47f4b510c99cb5cb4b9fa1
1 /*
3 KDE Greeter module for xdm
5 Copyright (C) 2001-2003 Oswald Buddenhagen <ossi@kde.org>
7 This file contains code from the old xdm core,
8 Copyright 1988, 1998 Keith Packard, MIT X Consortium/The Open Group
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26 #include <config-workspace.h>
27 #include <config-kdm.h>
28 #include <config-X11.h>
30 #include "kdm_greet.h"
31 #include "kdmconfig.h"
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <stdarg.h>
36 #include <string.h>
37 #include <signal.h>
38 #include <setjmp.h>
39 #include <ctype.h>
40 #include <time.h>
41 #include <errno.h>
42 #ifdef _POSIX_PRIORITY_SCHEDULING
43 # include <sched.h>
44 #endif
46 # include <X11/Xlib.h>
47 #if defined(HAVE_XTEST) || defined(HAVE_XKB)
48 # include <X11/keysym.h>
49 #endif
51 #ifdef HAVE_XTEST
52 # include <X11/extensions/XTest.h>
53 #endif
55 #ifdef HAVE_XKB
56 #include <X11/XKBlib.h>
57 #endif
59 extern void logOutOfMem( void );
61 static void *
62 Realloc( void *ptr, size_t size )
64 void *ret;
66 if (!(ret = realloc( ptr, size )) && size)
67 logOutOfMem();
68 return ret;
71 #define PRINT_QUOTES
72 #define PRINT_ARRAYS
73 #define LOG_NAME "kdm_greet"
74 #define LOG_DEBUG_MASK DEBUG_GREET
75 #define LOG_PANIC_EXIT 1
76 #define STATIC
77 #include <printf.c>
79 static void
80 gDebug( const char *fmt, ... )
82 va_list args;
84 if (debugLevel & DEBUG_HLPCON) {
85 va_start( args, fmt );
86 logger( DM_DEBUG, fmt, args );
87 va_end( args );
92 char *dname;
94 int rfd, mrfd, mwfd, srfd, swfd;
95 static int wfd;
96 static const char *who;
98 void
99 gSet( int master )
101 if (master)
102 rfd = mrfd, wfd = mwfd, who = "core (master)";
103 else
104 rfd = srfd, wfd = swfd, who = "core";
108 static int
109 reader( void *buf, int count )
111 int ret, rlen;
113 for (rlen = 0; rlen < count; ) {
114 dord:
115 ret = read( rfd, (void *)((char *)buf + rlen), count - rlen );
116 if (ret < 0) {
117 if (errno == EINTR)
118 goto dord;
119 if (errno == EAGAIN)
120 break;
121 return -1;
123 if (!ret)
124 break;
125 rlen += ret;
127 return rlen;
130 static void
131 gRead( void *buf, int count )
133 if (reader( buf, count ) != count)
134 logPanic( "Cannot read from %s\n", who );
137 static void
138 gWrite( const void *buf, int count )
140 if (write( wfd, buf, count ) != count)
141 logPanic( "Cannot write to %s\n", who );
142 #ifdef _POSIX_PRIORITY_SCHEDULING
143 if ((debugLevel & DEBUG_HLPCON))
144 sched_yield();
145 #endif
148 void
149 gSendInt( int val )
151 gDebug( "Sending int %d (%#x) to %s\n", val, val, who );
152 gWrite( &val, sizeof(val) );
155 void
156 gSendStr( const char *buf )
158 int len = buf ? strlen( buf ) + 1 : 0;
159 gDebug( "Sending string %'s to %s\n", buf, who );
160 gWrite( &len, sizeof(len) );
161 gWrite( buf, len );
165 static void
166 gSendNStr( const char *buf, int len )
168 int tlen = len + 1;
169 gDebug( "Sending string %'.*s to %s\n", len, buf, who );
170 gWrite( &tlen, sizeof(tlen) );
171 gWrite( buf, len );
172 gWrite( "", 1 );
176 void
177 gSendArr( int len, const char *buf )
179 gDebug( "Sending array %02[:*hhx to %s\n", len, buf, who );
180 gWrite( &len, sizeof(len) );
181 gWrite( buf, len );
185 gRecvInt()
187 int val;
189 gDebug( "Receiving int from %s ...\n", who );
190 gRead( &val, sizeof(val) );
191 gDebug( " -> %d (%#x)\n", val, val );
192 return val;
195 static char *
196 igRecvArr( int *rlen )
198 int len;
199 char *buf;
201 gRead( &len, sizeof(len) );
202 *rlen = len;
203 gDebug( " -> %d bytes\n", len );
204 if (!len)
205 return (char *)0;
206 if (!(buf = malloc( len )))
207 logPanic( "No memory for read buffer\n" );
208 gRead( buf, len );
209 return buf;
212 char *
213 gRecvStr()
215 int len;
216 char *buf;
218 gDebug( "Receiving string from %s ...\n", who );
219 buf = igRecvArr( &len );
220 gDebug( " -> %'.*s\n", len, buf );
221 return buf;
224 char **
225 gRecvStrArr( int *rnum )
227 int num;
228 char **argv, **cargv;
230 gDebug( "Receiving string array from %s ...\n", who );
231 gRead( &num, sizeof(num) );
232 gDebug( " -> %d strings\n", num );
233 if (rnum)
234 *rnum = num;
235 if (!num)
236 return (char **)0;
237 if (!(argv = malloc( num * sizeof(char *) )))
238 logPanic( "No memory for read buffer\n" );
239 for (cargv = argv; --num >= 0; cargv++)
240 *cargv = gRecvStr();
241 return argv;
244 char *
245 gRecvArr( int *num )
247 char *arr;
249 gDebug( "Receiving array from %s ...\n", who );
250 gRead( num, sizeof(*num) );
251 gDebug( " -> %d bytes\n", *num );
252 if (!*num)
253 return (char *)0;
254 if (!(arr = malloc( *num )))
255 logPanic( "No memory for read buffer\n" );
256 gRead( arr, *num );
257 gDebug( " -> %02[*hhx\n", *num, arr );
258 return arr;
261 static void
262 reqCfg( int id )
264 gSendInt( G_GetCfg );
265 gSendInt( id );
266 switch (gRecvInt()) {
267 case GE_NoEnt:
268 logPanic( "Config value %#x not available\n", id );
269 case GE_BadType:
270 logPanic( "Core does not know type of config value %#x\n", id );
275 getCfgInt( int id )
277 reqCfg( id );
278 return gRecvInt();
281 char *
282 getCfgStr( int id )
284 reqCfg( id );
285 return gRecvStr();
288 char **
289 getCfgStrArr( int id, int *len )
291 reqCfg( id );
292 return gRecvStrArr( len );
295 void
296 freeStrArr( char **arr )
298 char **tarr;
300 if (arr) {
301 for (tarr = arr; *tarr; tarr++)
302 free( *tarr );
303 free( arr );
308 static int
309 ignoreErrors( Display *dpy ATTR_UNUSED, XErrorEvent *event ATTR_UNUSED )
311 debug( "ignoring X error\n" );
312 return 0;
316 * this is mostly bogus -- but quite useful. I wish the protocol
317 * had some way of enumerating and identifying clients, that way
318 * this code wouldn't have to be this kludgy.
321 static void
322 killWindows( Display *dpy, Window window )
324 Window root, parent, *children;
325 unsigned child, nchildren = 0;
327 while (XQueryTree( dpy, window, &root, &parent, &children, &nchildren )
328 && nchildren > 0)
330 for (child = 0; child < nchildren; child++) {
331 debug( "XKillClient 0x%lx\n", (unsigned long)children[child] );
332 XKillClient( dpy, children[child] );
334 XFree( (char *)children );
338 static jmp_buf resetJmp;
340 static void
341 abortReset( int n ATTR_UNUSED )
343 longjmp (resetJmp, 1);
347 * this display connection better not have any windows...
350 static void
351 pseudoReset( Display *dpy )
353 int screen;
355 if (setjmp( resetJmp )) {
356 logError( "pseudoReset timeout\n" );
357 } else {
358 (void)signal( SIGALRM, abortReset );
359 (void)alarm( 30 );
360 XSetErrorHandler( ignoreErrors );
361 for (screen = 0; screen < ScreenCount( dpy ); screen++) {
362 debug( "pseudoReset screen %d\n", screen );
363 killWindows( dpy, RootWindow( dpy, screen ) );
365 debug( "before XSync\n" );
366 XSync( dpy, False );
367 (void)alarm( 0 );
369 signal( SIGALRM, SIG_DFL );
370 XSetErrorHandler( (XErrorHandler)0 );
371 debug( "pseudoReset done\n" );
375 static jmp_buf syncJump;
377 static void
378 syncTimeout( int n ATTR_UNUSED )
380 longjmp( syncJump, 1 );
383 void
384 secureDisplay( Display *dpy )
386 debug( "secureDisplay %s\n", dname );
387 (void)alarm( (unsigned)_grabTimeout );
388 (void)signal( SIGALRM, syncTimeout );
389 if (setjmp( syncJump )) {
390 logError( "Display %s could not be secured\n", dname );
391 sleep( 10 );
392 exit( EX_RESERVER_DPY );
394 debug( "Before XGrabServer %s\n", dname );
395 XGrabServer( dpy );
396 debug( "XGrabServer succeeded %s\n", dname );
397 (void)alarm( 0 );
398 (void)signal( SIGALRM, SIG_DFL );
399 pseudoReset( dpy );
400 if (!_grabServer)
402 XUngrabServer( dpy );
403 XSync( dpy, False );
405 debug( "secureDisplay %s done\n", dname );
408 void
409 unsecureDisplay( Display *dpy )
411 debug( "Unsecure display %s\n", dname );
412 if (_grabServer) {
413 XUngrabServer( dpy );
414 XSync( dpy, False );
418 #define GRABEVENTS \
419 ButtonPressMask | ButtonReleaseMask | PointerMotionMask | \
420 EnterWindowMask | LeaveWindowMask
422 void
423 secureKeyboard( Display *dpy )
425 (void)alarm( (unsigned)_grabTimeout );
426 (void)signal( SIGALRM, syncTimeout );
427 if (setjmp( syncJump ) ||
428 XGrabKeyboard( dpy, DefaultRootWindow( dpy ), True,
429 GrabModeAsync, GrabModeAsync,
430 CurrentTime ) != GrabSuccess)
432 (void)alarm( 0 );
433 (void)signal( SIGALRM, SIG_DFL );
434 logError( "Keyboard on display %s could not be secured\n", dname );
435 exit( EX_RESERVER_DPY );
437 (void)alarm( 0 );
438 (void)signal( SIGALRM, SIG_DFL );
441 void
442 securePointer( Display *dpy )
444 (void)alarm( (unsigned)_grabTimeout );
445 (void)signal( SIGALRM, syncTimeout );
446 if (setjmp( syncJump ) ||
447 XGrabPointer( dpy, DefaultRootWindow( dpy ), True, GRABEVENTS,
448 GrabModeAsync, GrabModeAsync,
449 None, None, CurrentTime ) != GrabSuccess)
451 (void)alarm( 0 );
452 (void)signal( SIGALRM, SIG_DFL );
453 logError( "Pointer on display %s could not be secured\n", dname );
454 exit( EX_RESERVER_DPY );
456 (void)alarm( 0 );
457 (void)signal( SIGALRM, SIG_DFL );
460 void
461 secureInputs( Display *dpy )
463 debug( "secureInputs %s\n", dname );
464 secureKeyboard( dpy );
465 securePointer( dpy );
466 XSetInputFocus( dpy, None, None, CurrentTime );
467 debug( "secureInputs %s done\n", dname );
470 void
471 unsecureInputs( Display *dpy )
473 debug( "unsecureInputs %s\n", dname );
474 XSetInputFocus( dpy, PointerRoot, PointerRoot, CurrentTime );
475 XUngrabKeyboard( dpy, CurrentTime );
476 XUngrabPointer( dpy, CurrentTime );
477 XSync( dpy, False );
480 static jmp_buf pingTime;
482 static int
483 pingLostIOErr( Display *dpy ATTR_UNUSED )
485 longjmp( pingTime, 1 );
488 static void
489 pingLostSig( int n ATTR_UNUSED )
491 longjmp( pingTime, 1 );
495 pingServer( Display *dpy )
497 int (*oldError)( Display * );
498 void (*oldSig)( int );
499 int oldAlarm;
501 oldError = XSetIOErrorHandler( pingLostIOErr );
502 oldAlarm = alarm( 0 );
503 oldSig = signal( SIGALRM, pingLostSig );
504 (void)alarm( _pingTimeout * 60 );
505 if (!setjmp( pingTime )) {
506 debug( "Ping server\n" );
507 XSync( dpy, False );
508 } else {
509 debug( "Server dead\n" );
510 (void)alarm( 0 );
511 (void)signal( SIGALRM, SIG_DFL );
512 XSetIOErrorHandler( oldError );
513 return False;
515 (void)alarm( 0 );
516 (void)signal( SIGALRM, oldSig );
517 (void)alarm( oldAlarm );
518 debug( "Server alive\n" );
519 XSetIOErrorHandler( oldError );
520 return True;
524 * Modifier changing code based on kdebase/kxkb/kcmmisc.cpp
526 * XTest part: Copyright (C) 2000-2001 Lubos Lunak <l.lunak@kde.org>
527 * XKB part: Copyright (C) 2001-2002 Oswald Buddenhagen <ossi@kde.org>
531 #ifdef HAVE_XKB
532 static int
533 xkbInit( Display *dpy )
535 int xkb_opcode, xkb_event, xkb_error;
536 int xkb_lmaj = XkbMajorVersion;
537 int xkb_lmin = XkbMinorVersion;
538 return XkbLibraryVersion( &xkb_lmaj, &xkb_lmin ) &&
539 XkbQueryExtension( dpy, &xkb_opcode, &xkb_event,
540 &xkb_error, &xkb_lmaj, &xkb_lmin );
543 static unsigned int
544 xkbModifierMaskWorker( XkbDescPtr xkb, const char *name )
546 int i;
548 if (!xkb->names)
549 return 0;
550 for (i = 0; i < XkbNumVirtualMods; i++) {
551 char *modStr = XGetAtomName( xkb->dpy, xkb->names->vmods[i] );
552 if (modStr != NULL && strcmp( name, modStr ) == 0) {
553 unsigned int mask;
554 XkbVirtualModsToReal( xkb, 1 << i, &mask );
555 return mask;
558 return 0;
561 static unsigned int
562 xkbModifierMask( Display *dpy, const char *name )
564 XkbDescPtr xkb;
566 if ((xkb = XkbGetKeyboard( dpy, XkbAllComponentsMask, XkbUseCoreKbd ))) {
567 unsigned int mask = xkbModifierMaskWorker( xkb, name );
568 XkbFreeKeyboard( xkb, 0, True );
569 return mask;
571 return 0;
574 static int
575 xkbGetModifierState( Display *dpy, const char *name )
577 unsigned int mask;
578 XkbStateRec state;
580 if (!(mask = xkbModifierMask( dpy, name )))
581 return 0;
582 XkbGetState( dpy, XkbUseCoreKbd, &state );
583 return (mask & state.locked_mods) != 0;
586 static int
587 xkbSetModifier( Display *dpy, const char *name, int sts )
589 unsigned int mask;
591 if (!(mask = xkbModifierMask( dpy, name )))
592 return False;
593 XkbLockModifiers( dpy, XkbUseCoreKbd, mask, sts ? mask : 0 );
594 return True;
596 #endif /* HAVE_XKB */
598 #ifdef HAVE_XTEST
599 static int
600 xtestGetModifierState( Display *dpy, int key )
602 XModifierKeymap *map;
603 KeyCode modifier_keycode;
604 unsigned int i, mask;
605 Window dummy1, dummy2;
606 int dummy3, dummy4, dummy5, dummy6;
608 if ((modifier_keycode = XKeysymToKeycode( dpy, key )) == NoSymbol)
609 return 0;
610 map = XGetModifierMapping( dpy );
611 for (i = 0; i < 8; ++i)
612 if (map->modifiermap[map->max_keypermod * i] == modifier_keycode) {
613 XFreeModifiermap( map );
614 XQueryPointer( dpy, DefaultRootWindow( dpy ),
615 &dummy1, &dummy2, &dummy3, &dummy4, &dummy5, &dummy6,
616 &mask );
617 return (mask & (1 << i)) != 0;
619 XFreeModifiermap( map );
620 return 0;
623 static void
624 xtestFakeKeypress( Display *dpy, int key )
626 XTestFakeKeyEvent( dpy, XKeysymToKeycode( dpy, key ), True, CurrentTime );
627 XTestFakeKeyEvent( dpy, XKeysymToKeycode( dpy, key ), False, CurrentTime );
629 #endif /* HAVE_XTEST */
631 #ifdef HAVE_XKB
632 static int havexkb;
633 #endif
634 static int nummodified, oldnumstate, newnumstate;
635 static Display *dpy;
637 void
638 setupModifiers( Display *mdpy, int numlock )
640 if (numlock == 2)
641 return;
642 newnumstate = numlock;
643 nummodified = True;
644 dpy = mdpy;
645 #ifdef HAVE_XKB
646 if (xkbInit( mdpy )) {
647 havexkb = True;
648 oldnumstate = xkbGetModifierState( mdpy, "NumLock" );
649 xkbSetModifier( mdpy, "NumLock", numlock );
650 return;
652 #endif
653 #ifdef HAVE_XTEST
654 oldnumstate = xtestGetModifierState( mdpy, XK_Num_Lock );
655 if (oldnumstate != numlock)
656 xtestFakeKeypress( mdpy, XK_Num_Lock );
657 #endif
660 void
661 restoreModifiers( void )
663 #ifdef HAVE_XTEST
664 int numstat;
665 #endif
667 if (!nummodified)
668 return;
669 #ifdef HAVE_XKB
670 if (havexkb) {
671 if (xkbGetModifierState( dpy, "NumLock" ) == newnumstate)
672 xkbSetModifier( dpy, "NumLock", oldnumstate );
673 return;
675 #endif
676 #ifdef HAVE_XTEST
677 numstat = xtestGetModifierState( dpy, XK_Num_Lock );
678 if (numstat == newnumstate && newnumstate != oldnumstate)
679 xtestFakeKeypress( dpy, XK_Num_Lock );
680 #endif
683 void
684 setCursor( Display *mdpy, int window, int shape )
686 Cursor xcursor;
688 if ((xcursor = XCreateFontCursor( mdpy, shape ))) {
689 XDefineCursor( mdpy, window, xcursor );
690 XFreeCursor( mdpy, xcursor );
691 XFlush( mdpy );