summaryrefslogtreecommitdiffstats
path: root/opensuse/core/tdebase/lock-xvkbd.diff
diff options
context:
space:
mode:
Diffstat (limited to 'opensuse/core/tdebase/lock-xvkbd.diff')
-rw-r--r--opensuse/core/tdebase/lock-xvkbd.diff380
1 files changed, 380 insertions, 0 deletions
diff --git a/opensuse/core/tdebase/lock-xvkbd.diff b/opensuse/core/tdebase/lock-xvkbd.diff
new file mode 100644
index 000000000..9b5faae8a
--- /dev/null
+++ b/opensuse/core/tdebase/lock-xvkbd.diff
@@ -0,0 +1,380 @@
+Index: kdesktop/lock/lockprocess.cc
+===================================================================
+--- kdesktop/lock/lockprocess.cc.orig
++++ kdesktop/lock/lockprocess.cc
+@@ -36,6 +36,8 @@
+ #include <kstdguiitem.h>
+ #include <kpixmapeffect.h>
+ #include <kpixmap.h>
++#include <kwin.h>
++#include <kwinmodule.h>
+
+ #include <qframe.h>
+ #include <qlabel.h>
+@@ -93,6 +95,8 @@ static Window gVRootData = 0;
+ static Atom gXA_VROOT;
+ static Atom gXA_SCREENSAVER_VERSION;
+
++extern Atom qt_wm_state;
++
+ //===========================================================================
+ //
+ // Screen saver handling process. Handles screensaver window,
+@@ -108,7 +112,9 @@ LockProcess::LockProcess(bool child, boo
+ mVisibility(false),
+ mRestoreXF86Lock(false),
+ mForbidden(false),
+- mAutoLogout(false)
++ mAutoLogout(false),
++ mVkbdProcess(NULL),
++ mKWinModule(NULL)
+ {
+ setupSignals();
+
+@@ -909,10 +915,14 @@ bool LockProcess::checkPass()
+ {
+ if (mAutoLogout)
+ killTimer(mAutoLogoutTimerId);
++
++ showVkbd();
+
+ PasswordDlg passDlg( this, &greetPlugin);
+
+ int ret = execDialog( &passDlg );
++
++ hideVkbd();
+
+ XWindowAttributes rootAttr;
+ XGetWindowAttributes(qt_xdisplay(), RootWindow(qt_xdisplay(),
+@@ -992,9 +1002,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;
+@@ -1031,11 +1045,30 @@ bool LockProcess::x11Event(XEvent *event
+ case ConfigureNotify: // from SubstructureNotifyMask on the root window
+ if(event->xconfigure.event == qt_xrootwin())
+ stayOnTop();
++ for( QValueList< VkbdWindow >::Iterator it = mVkbdWindows.begin();
++ it != mVkbdWindows.end();
++ ++it ) {
++ if( (*it).id == event->xconfigure.window ) {
++ (*it).rect = QRect( 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( QValueList< 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.
+@@ -1060,17 +1093,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( QValueList< VkbdWindow >::ConstIterator it = mVkbdWindows.begin();
++ it != mVkbdWindows.end();
++ ++it )
++ stack[ count++ ] = (*it).id;
+ for( QValueList< QWidget* >::ConstIterator it = mDialogs.begin();
+ it != mDialogs.end();
+ ++it )
+@@ -1169,4 +1209,200 @@ void LockProcess::msgBox( QMessageBox::I
+ 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, SIGNAL( windowAdded( WId )), 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 = QRect( x, y, attr_geom.width, attr_geom.height );
++ mVkbdWindows.prepend( data );
++}
++
++bool LockProcess::forwardVkbdEvent( XEvent* event )
++{
++ if( mVkbdProcess == NULL )
++ return false;
++ QPoint pos;
++ Time time;
++ switch( event->type )
++ {
++ case ButtonPress:
++ case ButtonRelease:
++ pos = QPoint( event->xbutton.x, event->xbutton.y );
++ time = event->xbutton.time;
++ break;
++ case MotionNotify:
++ pos = QPoint( 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( QValueList< 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"
+Index: kdesktop/lock/lockprocess.h
+===================================================================
+--- kdesktop/lock/lockprocess.h.orig
++++ kdesktop/lock/lockprocess.h
+@@ -23,6 +23,7 @@
+ #include <X11/Xlib.h>
+
+ class KLibrary;
++class KWinModule;
+
+ struct GreeterPluginHandle {
+ KLibrary *library;
+@@ -53,7 +54,7 @@ public:
+
+ void msgBox( QMessageBox::Icon type, const QString &txt );
+ int execDialog( QDialog* dlg );
+-
++
+ public slots:
+ void quitSaver();
+ void preparePopup();
+@@ -70,6 +71,7 @@ private slots:
+ void suspend();
+ void checkDPMSActive();
+ void slotDeadTimePassed();
++ void windowAdded( WId );
+
+ private:
+ void configure();
+@@ -93,6 +95,11 @@ private:
+ void stayOnTop();
+ void lockXF86();
+ void unlockXF86();
++ void showVkbd();
++ void hideVkbd();
++ bool forwardVkbdEvent( XEvent* event );
++ void sendVkbdFocusInOut( WId window, Time t );
++ void windowAdded( WId window, bool managed );
+ void resume( bool force );
+ static QVariant getConf(void *ctx, const char *key, const QVariant &dflt);
+
+@@ -125,6 +132,15 @@ private:
+ int mAutoLogoutTimerId;
+ int mAutoLogoutTimeout;
+ bool mAutoLogout;
++ KProcess* mVkbdProcess;
++ KWinModule* mKWinModule;
++ struct VkbdWindow
++ {
++ WId id;
++ QRect rect;
++ };
++ QValueList< VkbdWindow > mVkbdWindows;
++ WId mVkbdLastEventWindow;
+ };
+
+ #endif