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"
42 #ifdef _POSIX_PRIORITY_SCHEDULING
46 # include <X11/Xlib.h>
47 #if defined(HAVE_XTEST) || defined(HAVE_XKB)
48 # include <X11/keysym.h>
52 # include <X11/extensions/XTest.h>
56 #include <X11/XKBlib.h>
59 extern void logOutOfMem( void );
62 Realloc( void *ptr
, size_t size
)
66 if (!(ret
= realloc( ptr
, size
)) && size
)
73 #define LOG_NAME "kdm_greet"
74 #define LOG_DEBUG_MASK DEBUG_GREET
75 #define LOG_PANIC_EXIT 1
80 gDebug( const char *fmt
, ... )
84 if (debugLevel
& DEBUG_HLPCON
) {
85 va_start( args
, fmt
);
86 logger( DM_DEBUG
, fmt
, args
);
94 int rfd
, mrfd
, mwfd
, srfd
, swfd
;
96 static const char *who
;
102 rfd
= mrfd
, wfd
= mwfd
, who
= "core (master)";
104 rfd
= srfd
, wfd
= swfd
, who
= "core";
109 reader( void *buf
, int count
)
113 for (rlen
= 0; rlen
< count
; ) {
115 ret
= read( rfd
, (void *)((char *)buf
+ rlen
), count
- rlen
);
131 gRead( void *buf
, int count
)
133 if (reader( buf
, count
) != count
)
134 logPanic( "Cannot read from %s\n", who
);
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
))
151 gDebug( "Sending int %d (%#x) to %s\n", val
, val
, who
);
152 gWrite( &val
, sizeof(val
) );
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
) );
166 gSendNStr( const char *buf, int len )
169 gDebug( "Sending string %'.*s to %s\n", len, buf, who );
170 gWrite( &tlen, sizeof(tlen) );
177 gSendArr( int len
, const char *buf
)
179 gDebug( "Sending array %02[:*hhx to %s\n", len
, buf
, who
);
180 gWrite( &len
, sizeof(len
) );
189 gDebug( "Receiving int from %s ...\n", who
);
190 gRead( &val
, sizeof(val
) );
191 gDebug( " -> %d (%#x)\n", val
, val
);
196 igRecvArr( int *rlen
)
201 gRead( &len
, sizeof(len
) );
203 gDebug( " -> %d bytes\n", len
);
206 if (!(buf
= malloc( len
)))
207 logPanic( "No memory for read buffer\n" );
218 gDebug( "Receiving string from %s ...\n", who
);
219 buf
= igRecvArr( &len
);
220 gDebug( " -> %'.*s\n", len
, buf
);
225 gRecvStrArr( int *rnum
)
228 char **argv
, **cargv
;
230 gDebug( "Receiving string array from %s ...\n", who
);
231 gRead( &num
, sizeof(num
) );
232 gDebug( " -> %d strings\n", num
);
237 if (!(argv
= malloc( num
* sizeof(char *) )))
238 logPanic( "No memory for read buffer\n" );
239 for (cargv
= argv
; --num
>= 0; cargv
++)
249 gDebug( "Receiving array from %s ...\n", who
);
250 gRead( num
, sizeof(*num
) );
251 gDebug( " -> %d bytes\n", *num
);
254 if (!(arr
= malloc( *num
)))
255 logPanic( "No memory for read buffer\n" );
257 gDebug( " -> %02[*hhx\n", *num
, arr
);
264 gSendInt( G_GetCfg
);
266 switch (gRecvInt()) {
268 logPanic( "Config value %#x not available\n", id
);
270 logPanic( "Core does not know type of config value %#x\n", id
);
289 getCfgStrArr( int id
, int *len
)
292 return gRecvStrArr( len
);
296 freeStrArr( char **arr
)
301 for (tarr
= arr
; *tarr
; tarr
++)
309 ignoreErrors( Display
*dpy ATTR_UNUSED
, XErrorEvent
*event ATTR_UNUSED
)
311 debug( "ignoring X error\n" );
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.
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
)
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
;
341 abortReset( int n ATTR_UNUSED
)
343 longjmp (resetJmp
, 1);
347 * this display connection better not have any windows...
351 pseudoReset( Display
*dpy
)
355 if (setjmp( resetJmp
)) {
356 logError( "pseudoReset timeout\n" );
358 (void)signal( SIGALRM
, abortReset
);
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" );
369 signal( SIGALRM
, SIG_DFL
);
370 XSetErrorHandler( (XErrorHandler
)0 );
371 debug( "pseudoReset done\n" );
375 static jmp_buf syncJump
;
378 syncTimeout( int n ATTR_UNUSED
)
380 longjmp( syncJump
, 1 );
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
);
392 exit( EX_RESERVER_DPY
);
394 debug( "Before XGrabServer %s\n", dname
);
396 debug( "XGrabServer succeeded %s\n", dname
);
398 (void)signal( SIGALRM
, SIG_DFL
);
402 XUngrabServer( dpy
);
405 debug( "secureDisplay %s done\n", dname
);
409 unsecureDisplay( Display
*dpy
)
411 debug( "Unsecure display %s\n", dname
);
413 XUngrabServer( dpy
);
419 ButtonPressMask | ButtonReleaseMask | PointerMotionMask | \
420 EnterWindowMask | LeaveWindowMask
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
)
433 (void)signal( SIGALRM
, SIG_DFL
);
434 logError( "Keyboard on display %s could not be secured\n", dname
);
435 exit( EX_RESERVER_DPY
);
438 (void)signal( SIGALRM
, SIG_DFL
);
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
)
452 (void)signal( SIGALRM
, SIG_DFL
);
453 logError( "Pointer on display %s could not be secured\n", dname
);
454 exit( EX_RESERVER_DPY
);
457 (void)signal( SIGALRM
, SIG_DFL
);
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
);
471 unsecureInputs( Display
*dpy
)
473 debug( "unsecureInputs %s\n", dname
);
474 XSetInputFocus( dpy
, PointerRoot
, PointerRoot
, CurrentTime
);
475 XUngrabKeyboard( dpy
, CurrentTime
);
476 XUngrabPointer( dpy
, CurrentTime
);
480 static jmp_buf pingTime
;
483 pingLostIOErr( Display
*dpy ATTR_UNUSED
)
485 longjmp( pingTime
, 1 );
489 pingLostSig( int n ATTR_UNUSED
)
491 longjmp( pingTime
, 1 );
495 pingServer( Display
*dpy
)
497 int (*oldError
)( Display
* );
498 void (*oldSig
)( int );
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" );
509 debug( "Server dead\n" );
511 (void)signal( SIGALRM
, SIG_DFL
);
512 XSetIOErrorHandler( oldError
);
516 (void)signal( SIGALRM
, oldSig
);
517 (void)alarm( oldAlarm
);
518 debug( "Server alive\n" );
519 XSetIOErrorHandler( oldError
);
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>
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
);
544 xkbModifierMaskWorker( XkbDescPtr xkb
, const char *name
)
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) {
554 XkbVirtualModsToReal( xkb
, 1 << i
, &mask
);
562 xkbModifierMask( Display
*dpy
, const char *name
)
566 if ((xkb
= XkbGetKeyboard( dpy
, XkbAllComponentsMask
, XkbUseCoreKbd
))) {
567 unsigned int mask
= xkbModifierMaskWorker( xkb
, name
);
568 XkbFreeKeyboard( xkb
, 0, True
);
575 xkbGetModifierState( Display
*dpy
, const char *name
)
580 if (!(mask
= xkbModifierMask( dpy
, name
)))
582 XkbGetState( dpy
, XkbUseCoreKbd
, &state
);
583 return (mask
& state
.locked_mods
) != 0;
587 xkbSetModifier( Display
*dpy
, const char *name
, int sts
)
591 if (!(mask
= xkbModifierMask( dpy
, name
)))
593 XkbLockModifiers( dpy
, XkbUseCoreKbd
, mask
, sts
? mask
: 0 );
596 #endif /* HAVE_XKB */
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
)
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
,
617 return (mask
& (1 << i
)) != 0;
619 XFreeModifiermap( map
);
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 */
634 static int nummodified
, oldnumstate
, newnumstate
;
638 setupModifiers( Display
*mdpy
, int numlock
)
642 newnumstate
= numlock
;
646 if (xkbInit( mdpy
)) {
648 oldnumstate
= xkbGetModifierState( mdpy
, "NumLock" );
649 xkbSetModifier( mdpy
, "NumLock", numlock
);
654 oldnumstate
= xtestGetModifierState( mdpy
, XK_Num_Lock
);
655 if (oldnumstate
!= numlock
)
656 xtestFakeKeypress( mdpy
, XK_Num_Lock
);
661 restoreModifiers( void )
671 if (xkbGetModifierState( dpy
, "NumLock" ) == newnumstate
)
672 xkbSetModifier( dpy
, "NumLock", oldnumstate
);
677 numstat
= xtestGetModifierState( dpy
, XK_Num_Lock
);
678 if (numstat
== newnumstate
&& newnumstate
!= oldnumstate
)
679 xtestFakeKeypress( dpy
, XK_Num_Lock
);
684 setCursor( Display
*mdpy
, int window
, int shape
)
688 if ((xcursor
= XCreateFontCursor( mdpy
, shape
))) {
689 XDefineCursor( mdpy
, window
, xcursor
);
690 XFreeCursor( mdpy
, xcursor
);