@ -39,6 +39,8 @@
# include <kstdguiitem.h>
# include <kpixmapeffect.h>
# include <kpixmap.h>
# include <kwin.h>
# include <kwinmodule.h>
# include <tqframe.h>
# include <tqlabel.h>
@ -119,6 +121,8 @@ static void segv_handler(int)
sleep ( 1 ) ;
}
extern Atom qt_wm_state ;
//===========================================================================
//
// Screen saver handling process. Handles screensaver window,
@ -135,6 +139,8 @@ LockProcess::LockProcess(bool child, bool useBlankOnly)
mRestoreXF86Lock ( false ) ,
mForbidden ( false ) ,
mAutoLogout ( false ) ,
mVkbdProcess ( NULL ) ,
mKWinModule ( NULL ) ,
mPipeOpen ( false ) ,
mPipeOpen_out ( false ) ,
mInfoMessageDisplayed ( false ) ,
@ -1120,9 +1126,11 @@ bool LockProcess::checkPass()
if ( mAutoLogout )
killTimer ( mAutoLogoutTimerId ) ;
showVkbd ( ) ;
PasswordDlg passDlg ( this , & greetPlugin ) ;
int ret = execDialog ( & passDlg ) ;
hideVkbd ( ) ;
if ( mForceReject = = true ) {
ret = TQDialog : : Rejected ;
}
@ -1251,9 +1259,13 @@ bool LockProcess::x11Event(XEvent *event)
switch ( event - > type )
{
case KeyPress :
case ButtonPress :
case MotionNotify :
case ButtonRelease :
if ( forwardVkbdEvent ( event ) )
return true ; // filter out
// fall through
case KeyPress :
if ( mBusy | | ! mDialogs . isEmpty ( ) )
break ;
mBusy = true ;
@ -1290,11 +1302,30 @@ bool LockProcess::x11Event(XEvent *event)
case ConfigureNotify : // from SubstructureNotifyMask on the root window
if ( event - > xconfigure . event = = qt_xrootwin ( ) )
stayOnTop ( ) ;
for ( TQValueList < VkbdWindow > : : Iterator it = mVkbdWindows . begin ( ) ;
it ! = mVkbdWindows . end ( ) ;
+ + it ) {
if ( ( * it ) . id = = event - > xconfigure . window ) {
( * it ) . rect = TQRect ( event - > xconfigure . x , event - > xconfigure . y ,
event - > xconfigure . width , event - > xconfigure . height ) ;
break ;
}
}
break ;
case MapNotify : // from SubstructureNotifyMask on the root window
windowAdded ( event - > xmap . window , false ) ;
if ( event - > xmap . event = = qt_xrootwin ( ) )
stayOnTop ( ) ;
break ;
case DestroyNotify :
for ( TQValueList < VkbdWindow > : : Iterator it = mVkbdWindows . begin ( ) ;
it ! = mVkbdWindows . end ( ) ;
+ + it )
if ( ( * it ) . id = = event - > xdestroywindow . window ) {
mVkbdWindows . remove ( it ) ;
break ;
}
break ;
}
// We have grab with the grab window being the root window.
@ -1319,17 +1350,24 @@ bool LockProcess::x11Event(XEvent *event)
void LockProcess : : stayOnTop ( )
{
if ( ! mDialogs . isEmpty ( ) )
if ( ! mDialogs . isEmpty ( ) | | ! mVkbdWindows . isEmpty ( ) )
{
// this restacking is written in a way so that
// if the stacking positions actually don't change,
// all restacking operations will be no-op,
// and no ConfigureNotify will be generated,
// thus avoiding possible infinite loops
XRaiseWindow ( qt_xdisplay ( ) , mDialogs . first ( ) - > winId ( ) ) ; // raise topmost
if ( ! mVkbdWindows . isEmpty ( ) )
XRaiseWindow ( qt_xdisplay ( ) , mVkbdWindows . first ( ) . id ) ;
else
XRaiseWindow ( qt_xdisplay ( ) , mDialogs . first ( ) - > winId ( ) ) ; // raise topmost
// and stack others below it
Window * stack = new Window [ mDialogs . count ( ) + 1 ] ;
Window * stack = new Window [ mDialogs . count ( ) + mVkbdWindows . count ( ) + 1 ] ;
int count = 0 ;
for ( TQValueList < VkbdWindow > : : ConstIterator it = mVkbdWindows . begin ( ) ;
it ! = mVkbdWindows . end ( ) ;
+ + it )
stack [ count + + ] = ( * it ) . id ;
for ( TQValueList < TQWidget * > : : ConstIterator it = mDialogs . begin ( ) ;
it ! = mDialogs . end ( ) ;
+ + it )
@ -1428,4 +1466,200 @@ void LockProcess::msgBox( TQMessageBox::Icon type, const TQString &txt )
execDialog ( & box ) ;
}
static int run_vkbd = - 1 ;
void LockProcess : : showVkbd ( )
{
if ( run_vkbd = = - 1 ) {
int status = system ( " hal-find-by-property --key system.formfactor.subtype --string tabletpc " ) ;
// status = 0; // enable for testing
run_vkbd = ( WIFEXITED ( status ) & & WEXITSTATUS ( status ) = = 0
& & ! KStandardDirs : : findExe ( " xvkbd " ) . isEmpty ( ) ) ? 1 : 0 ;
}
if ( run_vkbd ) {
mVkbdWindows . clear ( ) ;
mVkbdLastEventWindow = None ;
mKWinModule = new KWinModule ( NULL , KWinModule : : INFO_WINDOWS ) ;
connect ( mKWinModule , TQT_SIGNAL ( windowAdded ( WId ) ) , TQT_SLOT ( windowAdded ( WId ) ) ) ;
mVkbdProcess = new KProcess ;
* mVkbdProcess < < " xvkbd " < < " -compact " < < " -geometry " < < " -0-0 " < < " -xdm " ;
mVkbdProcess - > start ( ) ;
}
}
void LockProcess : : hideVkbd ( )
{
if ( mVkbdProcess ! = NULL ) {
mVkbdProcess - > kill ( ) ;
delete mVkbdProcess ;
mVkbdProcess = NULL ;
delete mKWinModule ;
mKWinModule = NULL ;
mVkbdWindows . clear ( ) ;
}
}
void LockProcess : : windowAdded ( WId w )
{
windowAdded ( w , true ) ;
}
void LockProcess : : windowAdded ( WId w , bool managed )
{
KWin : : WindowInfo info = KWin : : windowInfo ( w , 0 , NET : : WM2WindowClass ) ;
if ( info . windowClassClass ( ) . lower ( ) ! = " xvkbd " )
return ;
// Unmanaged windows (i.e. popups) don't currently work anyway, since they
// don't have WM_CLASS set anyway. I could perhaps try tricks with X id
// ranges if really needed.
if ( managed ) {
// withdraw the window, wait for it to be withdrawn, reparent it directly
// to root at the right position
XWithdrawWindow ( qt_xdisplay ( ) , w , qt_xscreen ( ) ) ;
for ( ; ; ) {
Atom type ;
int format ;
unsigned long length , after ;
unsigned char * data ;
int r = XGetWindowProperty ( qt_xdisplay ( ) , w , qt_wm_state , 0 , 2 ,
false , AnyPropertyType , & type , & format ,
& length , & after , & data ) ;
bool withdrawn = true ;
if ( r = = Success & & data & & format = = 32 ) {
Q_UINT32 * wstate = ( Q_UINT32 * ) data ;
withdrawn = ( * wstate = = WithdrawnState ) ;
XFree ( ( char * ) data ) ;
}
if ( withdrawn )
break ;
}
}
XSelectInput ( qt_xdisplay ( ) , w , StructureNotifyMask ) ;
XWindowAttributes attr_geom ;
if ( ! XGetWindowAttributes ( qt_xdisplay ( ) , w , & attr_geom ) )
return ;
int x = XDisplayWidth ( qt_xdisplay ( ) , qt_xscreen ( ) ) - attr_geom . width ;
int y = XDisplayHeight ( qt_xdisplay ( ) , qt_xscreen ( ) ) - attr_geom . height ;
if ( managed ) {
XSetWindowAttributes attr ;
attr . override_redirect = True ;
XChangeWindowAttributes ( qt_xdisplay ( ) , w , CWOverrideRedirect , & attr ) ;
XReparentWindow ( qt_xdisplay ( ) , w , qt_xrootwin ( ) , x , y ) ;
XMapWindow ( qt_xdisplay ( ) , w ) ;
}
VkbdWindow data ;
data . id = w ;
data . rect = TQRect ( x , y , attr_geom . width , attr_geom . height ) ;
mVkbdWindows . prepend ( data ) ;
}
bool LockProcess : : forwardVkbdEvent ( XEvent * event )
{
if ( mVkbdProcess = = NULL )
return false ;
TQPoint pos ;
Time time ;
switch ( event - > type )
{
case ButtonPress :
case ButtonRelease :
pos = TQPoint ( event - > xbutton . x , event - > xbutton . y ) ;
time = event - > xbutton . time ;
break ;
case MotionNotify :
pos = TQPoint ( event - > xmotion . x , event - > xmotion . y ) ;
time = event - > xmotion . time ;
break ;
default :
return false ;
}
// vkbd windows are kept topmost, so just find the first one in the position
for ( TQValueList < VkbdWindow > : : ConstIterator it = mVkbdWindows . begin ( ) ;
it ! = mVkbdWindows . end ( ) ;
+ + it ) {
if ( ( * it ) . rect . contains ( pos ) ) {
// Find the subwindow where the event should actually go.
// Not exactly cheap in the number of X roundtrips but oh well.
Window window = ( * it ) . id ;
Window root , child ;
int root_x , root_y , x , y ;
unsigned int mask ;
for ( ; ; ) {
if ( ! XQueryPointer ( qt_xdisplay ( ) , window , & root , & child , & root_x , & root_y , & x , & y , & mask ) )
return false ;
if ( child = = None )
break ;
window = child ;
}
switch ( event - > type )
{
case ButtonPress :
case ButtonRelease :
event - > xbutton . x = x ;
event - > xbutton . y = y ;
event - > xbutton . subwindow = None ;
break ;
case MotionNotify :
event - > xmotion . x = x ;
event - > xmotion . y = y ;
event - > xmotion . subwindow = None ;
break ;
}
event - > xany . window = window ;
sendVkbdFocusInOut ( window , time ) ;
XSendEvent ( qt_xdisplay ( ) , window , False , 0 , event ) ;
return true ;
}
}
sendVkbdFocusInOut ( None , time ) ;
return false ;
}
// Fake EnterNotify/LeaveNotify events as the mouse moves. They're not sent by X
// because of the grab and having them makes xvkbd highlight the buttons (but
// not needed otherwise it seems).
void LockProcess : : sendVkbdFocusInOut ( WId window , Time t )
{
if ( mVkbdLastEventWindow = = window )
return ;
if ( mVkbdLastEventWindow ! = None ) {
XEvent e ;
e . xcrossing . type = LeaveNotify ;
e . xcrossing . display = qt_xdisplay ( ) ;
e . xcrossing . window = mVkbdLastEventWindow ;
e . xcrossing . root = qt_xrootwin ( ) ;
e . xcrossing . subwindow = None ;
e . xcrossing . time = t ;
e . xcrossing . x = 0 ;
e . xcrossing . y = 0 ;
e . xcrossing . x_root = - 1 ;
e . xcrossing . y_root = - 1 ;
e . xcrossing . mode = NotifyNormal ;
e . xcrossing . detail = NotifyAncestor ;
e . xcrossing . same_screen = True ;
e . xcrossing . focus = False ;
e . xcrossing . state = 0 ;
XSendEvent ( qt_xdisplay ( ) , mVkbdLastEventWindow , False , 0 , & e ) ;
}
mVkbdLastEventWindow = window ;
if ( mVkbdLastEventWindow ! = None ) {
XEvent e ;
e . xcrossing . type = EnterNotify ;
e . xcrossing . display = qt_xdisplay ( ) ;
e . xcrossing . window = mVkbdLastEventWindow ;
e . xcrossing . root = qt_xrootwin ( ) ;
e . xcrossing . subwindow = None ;
e . xcrossing . time = t ;
e . xcrossing . x = 0 ;
e . xcrossing . y = 0 ;
e . xcrossing . x_root = 0 ;
e . xcrossing . y_root = 0 ;
e . xcrossing . mode = NotifyNormal ;
e . xcrossing . detail = NotifyAncestor ;
e . xcrossing . same_screen = True ;
e . xcrossing . focus = False ;
e . xcrossing . state = 0 ;
XSendEvent ( qt_xdisplay ( ) , mVkbdLastEventWindow , False , 0 , & e ) ;
}
}
# include "lockprocess.moc"