summaryrefslogtreecommitdiffstats
path: root/kdesktop/lock/lockprocess.cc
diff options
context:
space:
mode:
Diffstat (limited to 'kdesktop/lock/lockprocess.cc')
-rw-r--r--kdesktop/lock/lockprocess.cc244
1 files changed, 239 insertions, 5 deletions
diff --git a/kdesktop/lock/lockprocess.cc b/kdesktop/lock/lockprocess.cc
index d589232a1..cdd5581e7 100644
--- a/kdesktop/lock/lockprocess.cc
+++ b/kdesktop/lock/lockprocess.cc
@@ -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"