summaryrefslogtreecommitdiff
path: root/Xext/xtest.c
diff options
context:
space:
mode:
Diffstat (limited to 'Xext/xtest.c')
-rw-r--r--Xext/xtest.c199
1 files changed, 178 insertions, 21 deletions
diff --git a/Xext/xtest.c b/Xext/xtest.c
index 32abe2a81..0400062d8 100644
--- a/Xext/xtest.c
+++ b/Xext/xtest.c
@@ -32,6 +32,7 @@
#include <X11/X.h>
#include <X11/Xproto.h>
+#include <X11/Xatom.h>
#include "misc.h"
#include "os.h"
#include "dixstruct.h"
@@ -44,19 +45,38 @@
#include "mi.h"
#include "xkbsrv.h"
#include "xkbstr.h"
-#define _XTEST_SERVER_
-#include <X11/extensions/XTest.h>
-#include <X11/extensions/xteststr.h>
+#include <X11/extensions/xtestproto.h>
#include <X11/extensions/XI.h>
#include <X11/extensions/XIproto.h>
#include "exglobals.h"
#include "mipointer.h"
+#include "xserver-properties.h"
+#include "exevents.h"
#include "modinit.h"
extern int DeviceValuator;
-extern int DeviceMotionNotify;
-extern DevPrivateKey XTstDevicePrivateKey;
+
+/* XTest events are sent during request processing and may be interruped by
+ * a SIGIO. We need a separate event list to avoid events overwriting each
+ * other's memory */
+static EventListPtr xtest_evlist;
+
+/* Used to store if a device is an XTest Virtual device */
+static int XTestDevicePrivateKeyIndex;
+DevPrivateKey XTestDevicePrivateKey = &XTestDevicePrivateKeyIndex;
+
+/**
+ * xtestpointer
+ * is the virtual pointer for XTest. It is the first slave
+ * device of the VCP.
+ * xtestkeyboard
+ * is the virtual keyboard for XTest. It is the first slave
+ * device of the VCK
+ *
+ * Neither of these devices can be deleted.
+ */
+DeviceIntPtr xtestpointer, xtestkeyboard;
#ifdef PANORAMIX
#include "panoramiX.h"
@@ -85,6 +105,8 @@ XTestExtensionInit(INITARGS)
AddExtension(XTestExtensionName, 0, 0,
ProcXTestDispatch, SProcXTestDispatch,
NULL, StandardMinorOpcode);
+
+ xtest_evlist = InitEventList(GetMaximumEventsNum());
}
static int
@@ -158,7 +180,6 @@ ProcXTestFakeInput(ClientPtr client)
int valuators[MAX_VALUATORS] = {0};
int numValuators = 0;
int firstValuator = 0;
- EventListPtr events;
int nevents = 0;
int i;
int base = 0;
@@ -190,11 +211,34 @@ ProcXTestFakeInput(ClientPtr client)
switch (type) {
case XI_DeviceKeyPress:
case XI_DeviceKeyRelease:
+ if (!dev->key)
+ {
+ client->errorValue = ev->u.u.type;
+ return BadValue;
+ }
+ break;
case XI_DeviceButtonPress:
case XI_DeviceButtonRelease:
+ if (!dev->button)
+ {
+ client->errorValue = ev->u.u.type;
+ return BadValue;
+ }
+ break;
case XI_DeviceMotionNotify:
+ if (!dev->valuator)
+ {
+ client->errorValue = ev->u.u.type;
+ return BadValue;
+ }
+ break;
case XI_ProximityIn:
case XI_ProximityOut:
+ if (!dev->proximity)
+ {
+ client->errorValue = ev->u.u.type;
+ return BadValue;
+ }
break;
default:
client->errorValue = ev->u.u.type;
@@ -271,8 +315,6 @@ ProcXTestFakeInput(ClientPtr client)
} else
{
- DeviceIntPtr it;
-
if (nev != 1)
return BadLength;
switch (type)
@@ -299,14 +341,7 @@ ProcXTestFakeInput(ClientPtr client)
return BadValue;
}
- /* When faking core events through XTest, we always fake through the
- * virtual test device.
- */
- for(it = inputInfo.devices; it ; it = it->next )
- if( !IsMaster(it) && it->u.master == dev &&
- dixLookupPrivate(&it->devPrivates, XTstDevicePrivateKey ))
- break;
- dev= it;
+ dev = GetXTestDevice(dev);
}
/* If the event has a time set, wait for it to pass */
@@ -396,26 +431,25 @@ ProcXTestFakeInput(ClientPtr client)
if (screenIsSaved == SCREEN_SAVER_ON)
dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset);
- GetEventList(&events);
switch(type) {
case MotionNotify:
- nevents = GetPointerEvents(events, dev, type, 0, flags,
+ nevents = GetPointerEvents(xtest_evlist, dev, type, 0, flags,
firstValuator, numValuators, valuators);
break;
case ButtonPress:
case ButtonRelease:
- nevents = GetPointerEvents(events, dev, type, ev->u.u.detail,
+ nevents = GetPointerEvents(xtest_evlist, dev, type, ev->u.u.detail,
flags, firstValuator,
numValuators, valuators);
break;
case KeyPress:
case KeyRelease:
- nevents = GetKeyboardEvents(events, dev, type, ev->u.u.detail);
+ nevents = GetKeyboardEvents(xtest_evlist, dev, type, ev->u.u.detail);
break;
}
for (i = 0; i < nevents; i++)
- mieqProcessDeviceEvent(dev, (InternalEvent*)(events+i)->event, NULL);
+ mieqProcessDeviceEvent(dev, (InternalEvent*)(xtest_evlist+i)->event, NULL);
miPointerUpdateSprite(dev);
return client->noClientException;
@@ -549,3 +583,126 @@ SProcXTestDispatch (ClientPtr client)
return BadRequest;
}
}
+
+/**
+ * Allocate an virtual slave device for xtest events, this
+ * is a slave device to inputInfo master devices
+ */
+void InitXTestDevices(void)
+{
+ if(AllocXTestDevice(serverClient, "Virtual core",
+ &xtestpointer, &xtestkeyboard,
+ inputInfo.pointer, inputInfo.keyboard) != Success)
+ FatalError("Failed to allocate XTest devices");
+
+ if (ActivateDevice(xtestpointer, TRUE) != Success ||
+ ActivateDevice(xtestkeyboard, TRUE) != Success)
+ FatalError("Failed to activate XTest core devices.");
+ if (!EnableDevice(xtestpointer, TRUE) ||
+ !EnableDevice(xtestkeyboard, TRUE))
+ FatalError("Failed to enable XTest core devices.");
+
+ AttachDevice(NULL, xtestpointer, inputInfo.pointer);
+ AttachDevice(NULL, xtestkeyboard, inputInfo.keyboard);
+}
+
+/**
+ * Don't allow changing the XTest property.
+ */
+static int
+DeviceSetXTestProperty(DeviceIntPtr dev, Atom property,
+ XIPropertyValuePtr prop, BOOL checkonly)
+{
+ if (property == XIGetKnownProperty(XI_PROP_XTEST_DEVICE))
+ return BadAccess;
+
+ return Success;
+}
+
+/**
+ * Allocate a device pair that is initialised as a slave
+ * device with properties that identify the devices as belonging
+ * to XTest subsystem.
+ * This only creates the pair, Activate/Enable Device
+ * still need to be called.
+ */
+int AllocXTestDevice (ClientPtr client, char* name,
+ DeviceIntPtr* ptr, DeviceIntPtr* keybd,
+ DeviceIntPtr master_ptr, DeviceIntPtr master_keybd)
+{
+ int retval;
+ int len = strlen(name);
+ char *xtestname = xcalloc(len + 7, 1 );
+ char dummy = 1;
+
+ strncpy( xtestname, name, len);
+ strncat( xtestname, " XTEST", 6 );
+
+ retval = AllocDevicePair( client, xtestname, ptr, keybd, CorePointerProc, CoreKeyboardProc, FALSE);
+ if ( retval == Success ){
+ dixSetPrivate(&((*ptr)->devPrivates), XTestDevicePrivateKey, (void *)master_ptr->id);
+ dixSetPrivate(&((*keybd)->devPrivates), XTestDevicePrivateKey, (void *)master_keybd->id);
+ }
+
+ xfree( xtestname );
+
+ XIChangeDeviceProperty(*ptr, XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
+ XA_INTEGER, 8, PropModeReplace, 1, &dummy,
+ FALSE);
+ XISetDevicePropertyDeletable(*ptr, XIGetKnownProperty(XI_PROP_XTEST_DEVICE), FALSE);
+ XIRegisterPropertyHandler(*ptr, DeviceSetXTestProperty, NULL, NULL);
+ XIChangeDeviceProperty(*keybd, XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
+ XA_INTEGER, 8, PropModeReplace, 1, &dummy,
+ FALSE);
+ XISetDevicePropertyDeletable(*keybd, XIGetKnownProperty(XI_PROP_XTEST_DEVICE), FALSE);
+ XIRegisterPropertyHandler(*keybd, DeviceSetXTestProperty, NULL, NULL);
+
+ return retval;
+}
+
+/**
+ * If master is NULL, return TRUE if the given device is an xtest device or
+ * FALSE otherwise.
+ * If master is not NULL, return TRUE if the given device is this master's
+ * xtest device.
+ */
+BOOL
+IsXTestDevice(DeviceIntPtr dev, DeviceIntPtr master)
+{
+ int is_XTest = FALSE;
+ int mid;
+ void *tmp; /* shut up, gcc! */
+
+ if (IsMaster(dev))
+ return is_XTest;
+
+ tmp = dixLookupPrivate(&dev->devPrivates, XTestDevicePrivateKey);
+ mid = (int)tmp;
+
+ /* deviceid 0 is reserved for XIAllDevices, non-zero mid means XTest
+ * device */
+ if ((!master && mid) ||
+ (master && mid == master->id))
+ is_XTest = TRUE;
+
+ return is_XTest;
+}
+
+/**
+ * @return The X Test virtual device for the given master.
+ */
+DeviceIntPtr
+GetXTestDevice(DeviceIntPtr master)
+{
+ DeviceIntPtr it;
+
+ for (it = inputInfo.devices; it; it = it->next)
+ {
+ if (IsXTestDevice(it, master))
+ return it;
+ }
+
+ /* This only happens if master is a slave device. don't do that */
+ return NULL;
+}
+