From 21fcfa3348213aa87f0e3aef62ca4720c6d31cb7 Mon Sep 17 00:00:00 2001 From: Robert Xu Date: Thu, 10 Nov 2011 18:04:39 -0500 Subject: initial commit to suse branch: eclipse integration --- opensuse/core/tdebase/lock-xvkbd.diff | 380 ++++++++++++++++++++++++++++++++++ 1 file changed, 380 insertions(+) create mode 100644 opensuse/core/tdebase/lock-xvkbd.diff (limited to 'opensuse/core/tdebase/lock-xvkbd.diff') 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 + #include + #include ++#include ++#include + + #include + #include +@@ -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 + + 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 -- cgit v1.2.3