You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
381 lines
13 KiB
381 lines
13 KiB
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
|