#if HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
# include <X11/X.h>
# include <X11/Xmd.h>
# include <X11/Xproto.h>
# include "misc.h"
# include "windowstr.h"
# include "pixmapstr.h"
# include "inputstr.h"
# include "mi.h"
# include "mipointer.h"
# include "scrnintstr.h"
# include <X11/extensions/XI.h>
# include <X11/extensions/XIproto.h>
# include <X11/extensions/geproto.h>
# include "extinit.h"
# include "exglobals.h"
# include "eventstr.h"
#ifdef DPMSExtension
# include "dpmsproc.h"
# include <X11/extensions/dpmsconst.h>
#endif
#define QUEUE_SIZE 512
#define EnqueueScreen(dev) dev->spriteInfo->sprite->pEnqueueScreen
#define DequeueScreen(dev) dev->spriteInfo->sprite->pDequeueScreen
typedef struct _Event {
EventListPtr events;
ScreenPtr pScreen;
DeviceIntPtr pDev;
} EventRec, *EventPtr;
typedef struct _EventQueue {
HWEventQueueType head, tail;
CARD32 lastEventTime;
int lastMotion;
EventRec events[QUEUE_SIZE];
mieqHandler handlers[128];
} EventQueueRec, *EventQueuePtr;
static EventQueueRec miEventQueue;
#ifdef XQUARTZ
#include <pthread.h>
static pthread_mutex_t miEventQueueMutex = PTHREAD_MUTEX_INITIALIZER;
extern BOOL serverRunning;
extern pthread_mutex_t serverRunningMutex;
extern pthread_cond_t serverRunningCond;
static inline void wait_for_server_init(void) {
if(!serverRunning) {
pthread_mutex_lock(&serverRunningMutex);
while(!serverRunning)
pthread_cond_wait(&serverRunningCond, &serverRunningMutex);
pthread_mutex_unlock(&serverRunningMutex);
}
}
#endif
Bool
mieqInit(void)
{
int i;
miEventQueue.head = miEventQueue.tail = 0;
miEventQueue.lastEventTime = GetTimeInMillis ();
miEventQueue.lastMotion = FALSE;
for (i = 0; i < 128; i++)
miEventQueue.handlers[i] = NULL;
for (i = 0; i < QUEUE_SIZE; i++)
{
if (miEventQueue.events[i].events == NULL) {
EventListPtr evlist = InitEventList(1);
if (!evlist)
FatalError("Could not allocate event queue.\n");
miEventQueue.events[i].events = evlist;
}
}
SetInputCheck(&miEventQueue.head, &miEventQueue.tail);
return TRUE;
}
void
mieqFini(void)
{
int i;
for (i = 0; i < QUEUE_SIZE; i++)
{
if (miEventQueue.events[i].events != NULL) {
FreeEventList(miEventQueue.events[i].events, 1);
miEventQueue.events[i].events = NULL;
}
}
}
void
mieqEnqueue(DeviceIntPtr pDev, InternalEvent *e)
{
unsigned int oldtail = miEventQueue.tail;
EventListPtr evt;
int isMotion = 0;
int evlen;
Time time;
#ifdef XQUARTZ
wait_for_server_init();
pthread_mutex_lock(&miEventQueueMutex);
#endif
CHECKEVENT(e);
if (e->any.type == ET_Motion)
isMotion = pDev->id;
if (isMotion && isMotion == miEventQueue.lastMotion &&
oldtail != miEventQueue.head) {
oldtail = (oldtail - 1) % QUEUE_SIZE;
}
else {
static int stuck = 0;
if (((oldtail + 1) % QUEUE_SIZE) == miEventQueue.head) {
if (!stuck) {
ErrorF("[mi] EQ overflowing. The server is probably stuck "
"in an infinite loop.\n");
xorg_backtrace();
stuck = 1;
}
#ifdef XQUARTZ
pthread_mutex_unlock(&miEventQueueMutex);
#endif
return;
}
stuck = 0;
}
evlen = e->any.length;
evt = miEventQueue.events[oldtail].events;
if (evt->evlen < evlen)
{
evt->evlen = evlen;
evt->event = realloc(evt->event, evt->evlen);
if (!evt->event)
{
ErrorF("[mi] Running out of memory. Tossing event.\n");
#ifdef XQUARTZ
pthread_mutex_unlock(&miEventQueueMutex);
#endif
return;
}
}
memcpy(evt->event, e, evlen);
time = e->any.time;
if (time < miEventQueue.lastEventTime &&
miEventQueue.lastEventTime - time < 10000)
e->any.time = miEventQueue.lastEventTime;
miEventQueue.lastEventTime = ((InternalEvent*)evt->event)->any.time;
miEventQueue.events[oldtail].pScreen = pDev ? EnqueueScreen(pDev) : NULL;
miEventQueue.events[oldtail].pDev = pDev;
miEventQueue.lastMotion = isMotion;
miEventQueue.tail = (oldtail + 1) % QUEUE_SIZE;
#ifdef XQUARTZ
pthread_mutex_unlock(&miEventQueueMutex);
#endif
}
void
mieqSwitchScreen(DeviceIntPtr pDev, ScreenPtr pScreen, Bool fromDIX)
{
#ifdef XQUARTZ
pthread_mutex_lock(&miEventQueueMutex);
#endif
EnqueueScreen(pDev) = pScreen;
if (fromDIX)
DequeueScreen(pDev) = pScreen;
#ifdef XQUARTZ
pthread_mutex_unlock(&miEventQueueMutex);
#endif
}
void
mieqSetHandler(int event, mieqHandler handler)
{
#ifdef XQUARTZ
pthread_mutex_lock(&miEventQueueMutex);
#endif
if (handler && miEventQueue.handlers[event])
ErrorF("[mi] mieq: warning: overriding existing handler %p with %p for "
"event %d\n", miEventQueue.handlers[event], handler, event);
miEventQueue.handlers[event] = handler;
#ifdef XQUARTZ
pthread_mutex_unlock(&miEventQueueMutex);
#endif
}
static void
ChangeDeviceID(DeviceIntPtr dev, InternalEvent* event)
{
switch(event->any.type)
{
case ET_Motion:
case ET_KeyPress:
case ET_KeyRelease:
case ET_ButtonPress:
case ET_ButtonRelease:
case ET_ProximityIn:
case ET_ProximityOut:
case ET_Hierarchy:
case ET_DeviceChanged:
event->device_event.deviceid = dev->id;
break;
#if XFreeXDGA
case ET_DGAEvent:
break;
#endif
case ET_RawKeyPress:
case ET_RawKeyRelease:
case ET_RawButtonPress:
case ET_RawButtonRelease:
case ET_RawMotion:
event->raw_event.deviceid = dev->id;
break;
default:
ErrorF("[mi] Unknown event type (%d), cannot change id.\n",
event->any.type);
}
}
static void
FixUpEventForMaster(DeviceIntPtr mdev, DeviceIntPtr sdev,
InternalEvent* original, InternalEvent *master)
{
CHECKEVENT(original);
CHECKEVENT(master);
if (original->any.type == ET_ButtonPress ||
original->any.type == ET_ButtonRelease)
{
int btn = original->device_event.detail.button;
if (!sdev->button)
return;
master->device_event.detail.button = sdev->button->map[btn];
}
}
DeviceIntPtr
CopyGetMasterEvent(DeviceIntPtr sdev,
InternalEvent* original, InternalEvent *copy)
{
DeviceIntPtr mdev;
int len = original->any.length;
int type = original->any.type;
CHECKEVENT(original);
if (!sdev || !sdev->u.master)
return NULL;
#if XFreeXDGA
if (type == ET_DGAEvent)
type = original->dga_event.subtype;
#endif
switch(type)
{
case ET_KeyPress:
case ET_KeyRelease:
mdev = GetMaster(sdev, MASTER_KEYBOARD);
break;
case ET_ButtonPress:
case ET_ButtonRelease:
case ET_Motion:
case ET_ProximityIn:
case ET_ProximityOut:
mdev = GetMaster(sdev, MASTER_POINTER);
break;
default:
mdev = sdev->u.master;
break;
}
memcpy(copy, original, len);
ChangeDeviceID(mdev, copy);
FixUpEventForMaster(mdev, sdev, original, copy);
return mdev;
}
void
mieqProcessDeviceEvent(DeviceIntPtr dev,
InternalEvent *event,
ScreenPtr screen)
{
mieqHandler handler;
int x = 0, y = 0;
DeviceIntPtr master;
InternalEvent mevent;
CHECKEVENT(event);
handler = miEventQueue.handlers[event->any.type];
switch (event->any.type) {
case ET_Motion:
case ET_KeyPress:
case ET_KeyRelease:
case ET_ButtonPress:
case ET_ButtonRelease:
if (dev && screen && screen != DequeueScreen(dev) && !handler) {
DequeueScreen(dev) = screen;
x = event->device_event.root_x;
y = event->device_event.root_y;
NewCurrentScreen (dev, DequeueScreen(dev), x, y);
}
break;
default:
break;
}
master = CopyGetMasterEvent(dev, event, &mevent);
if (master)
master->u.lastSlave = dev;
if (handler)
{
int screenNum = dev && DequeueScreen(dev) ? DequeueScreen(dev)->myNum : (screen ? screen->myNum : 0);
handler(screenNum, event, dev);
if (master && dev->u.master)
handler(screenNum, &mevent, master);
} else
{
dev->public.processInputProc(event, dev);
if (master && dev->u.master)
master->public.processInputProc(&mevent, master);
}
}
void
mieqProcessInputEvents(void)
{
EventRec *e = NULL;
int evlen;
ScreenPtr screen;
static InternalEvent *event = NULL;
static size_t event_size = 0;
DeviceIntPtr dev = NULL,
master = NULL;
#ifdef XQUARTZ
pthread_mutex_lock(&miEventQueueMutex);
#endif
while (miEventQueue.head != miEventQueue.tail) {
e = &miEventQueue.events[miEventQueue.head];
evlen = e->events->evlen;
if(evlen > event_size)
{
event = realloc(event, evlen);
event_size = evlen;
}
if (!event)
FatalError("[mi] No memory left for event processing.\n");
memcpy(event, e->events->event, evlen);
dev = e->pDev;
screen = e->pScreen;
miEventQueue.head = (miEventQueue.head + 1) % QUEUE_SIZE;
#ifdef XQUARTZ
pthread_mutex_unlock(&miEventQueueMutex);
#endif
master = (dev && !IsMaster(dev) && dev->u.master) ? dev->u.master : NULL;
if (screenIsSaved == SCREEN_SAVER_ON)
dixSaveScreens (serverClient, SCREEN_SAVER_OFF, ScreenSaverReset);
#ifdef DPMSExtension
else if (DPMSPowerLevel != DPMSModeOn)
SetScreenSaverTimer();
if (DPMSPowerLevel != DPMSModeOn)
DPMSSet(serverClient, DPMSModeOn);
#endif
mieqProcessDeviceEvent(dev, event, screen);
if (event->any.type == ET_Motion && master)
miPointerUpdateSprite(dev);
#ifdef XQUARTZ
pthread_mutex_lock(&miEventQueueMutex);
#endif
}
#ifdef XQUARTZ
pthread_mutex_unlock(&miEventQueueMutex);
#endif
}