Xnest: use XCB for event loop

Now that no X11 calls are being done via Xlib anymore, we're free to
also move over event receiving, leaving Xlib pretty much unused.

Also need to add a simple event queue mechanism, because we've go a
screen operation (see xnestBitBlitHelper) that needs to collect up
certain events for it's return value.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
This commit is contained in:
Enrico Weigelt, metux IT consult 2024-08-20 17:23:21 +02:00
parent 8c701832ea
commit 4716ee9981
9 changed files with 135 additions and 104 deletions

View File

@ -33,7 +33,6 @@ is" without express or implied warranty.
#include "Args.h"
char *xnestDisplayName = NULL;
Bool xnestSynchronize = FALSE;
Bool xnestFullGeneration = FALSE;
int xnestDefaultClass;
Bool xnestUserDefaultClass = FALSE;
@ -70,10 +69,6 @@ ddxProcessArgument(int argc, char *argv[], int i)
}
return 0;
}
if (!strcmp(argv[i], "-sync")) {
xnestSynchronize = TRUE;
return 1;
}
if (!strcmp(argv[i], "-full")) {
xnestFullGeneration = TRUE;
return 1;
@ -187,7 +182,6 @@ void
ddxUseMsg(void)
{
ErrorF("-display string display name of the real server\n");
ErrorF("-sync sinchronize with the real server\n");
ErrorF("-full utilize full regeneration\n");
ErrorF("-class string default visual class\n");
ErrorF("-depth int default depth\n");

View File

@ -19,7 +19,6 @@ is" without express or implied warranty.
#include <X11/Xdefs.h>
extern char *xnestDisplayName;
extern Bool xnestSynchronize;
extern Bool xnestFullGeneration;
extern int xnestDefaultClass;
extern Bool xnestUserDefaultClass;

View File

@ -72,9 +72,6 @@ xnestOpenDisplay(int argc, char *argv[])
FatalError("Unable to open display \"%s\".\n",
XDisplayName(xnestDisplayName));
if (xnestSynchronize)
XSynchronize(xnestDisplay, TRUE);
xnest_upstream_setup();
if (xnestParentWindow != (Window) 0)

View File

@ -30,6 +30,7 @@ is" without express or implied warranty.
#include "inpututils.h"
#include "Xnest.h"
#include "xnest-xcb.h"
#include "Args.h"
#include "Color.h"
@ -63,42 +64,6 @@ SetTimeSinceLastInputEvent(void)
lastEventTime = GetTimeInMillis();
}
static Bool
xnestExposurePredicate(Display * dpy, XEvent * event, char *args)
{
return event->type == Expose || event->type == ProcessedExpose;
}
static Bool
xnestNotExposurePredicate(Display * dpy, XEvent * event, char *args)
{
return !xnestExposurePredicate(dpy, event, args);
}
void
xnestCollectExposures(void)
{
XEvent X;
WindowPtr pWin;
RegionRec Rgn;
BoxRec Box;
while (XCheckIfEvent(xnestDisplay, &X, xnestExposurePredicate, NULL)) {
pWin = xnestWindowPtr(X.xexpose.window);
if (pWin && X.xexpose.width && X.xexpose.height) {
Box.x1 = pWin->drawable.x + wBorderWidth(pWin) + X.xexpose.x;
Box.y1 = pWin->drawable.y + wBorderWidth(pWin) + X.xexpose.y;
Box.x2 = Box.x1 + X.xexpose.width;
Box.y2 = Box.y1 + X.xexpose.height;
RegionInit(&Rgn, &Box, 1);
miSendExposures(pWin, &Rgn, Box.x1, Box.y1);
}
}
}
void
xnestQueueKeyEvent(int type, unsigned int keycode)
{
@ -106,52 +71,62 @@ xnestQueueKeyEvent(int type, unsigned int keycode)
QueueKeyboardEvents(xnestKeyboardDevice, type, keycode);
}
#define EVTYPE(tname) tname *ev = (tname*)event
static void
xnest_handle_event(XEvent X)
xnest_handle_event(xcb_generic_event_t *event)
{
switch (X.type) {
if (!event)
return;
switch (event->response_type & ~0x80) {
case KeyPress:
{
xnestUpdateModifierState(X.xkey.state);
xnestQueueKeyEvent(KeyPress, X.xkey.keycode);
EVTYPE(xcb_key_press_event_t);
xnestUpdateModifierState(ev->state);
xnestQueueKeyEvent(KeyPress, ev->detail);
break;
}
case KeyRelease:
{
xnestUpdateModifierState(X.xkey.state);
xnestQueueKeyEvent(KeyRelease, X.xkey.keycode);
EVTYPE(xcb_key_release_event_t);
xnestUpdateModifierState(ev->state);
xnestQueueKeyEvent(KeyRelease, ev->detail);
break;
}
case ButtonPress:
{
ValuatorMask mask;
EVTYPE(xcb_button_press_event_t);
valuator_mask_set_range(&mask, 0, 0, NULL);
xnestUpdateModifierState(X.xkey.state);
xnestUpdateModifierState(ev->state);
lastEventTime = GetTimeInMillis();
QueuePointerEvents(xnestPointerDevice, ButtonPress,
X.xbutton.button, POINTER_RELATIVE, &mask);
ev->detail, POINTER_RELATIVE, &mask);
break;
}
case ButtonRelease:
{
ValuatorMask mask;
EVTYPE(xcb_button_release_event_t);
valuator_mask_set_range(&mask, 0, 0, NULL);
xnestUpdateModifierState(X.xkey.state);
xnestUpdateModifierState(ev->state);
lastEventTime = GetTimeInMillis();
QueuePointerEvents(xnestPointerDevice, ButtonRelease,
X.xbutton.button, POINTER_RELATIVE, &mask);
ev->detail, POINTER_RELATIVE, &mask);
break;
}
case MotionNotify:
{
EVTYPE(xcb_motion_notify_event_t);
ValuatorMask mask;
int valuators[2];
valuators[0] = X.xmotion.x;
valuators[1] = X.xmotion.y;
valuators[0] = ev->event_x;
valuators[1] = ev->event_y;
valuator_mask_set_range(&mask, 0, 2, valuators);
lastEventTime = GetTimeInMillis();
QueuePointerEvents(xnestPointerDevice, MotionNotify,
@ -161,8 +136,9 @@ xnest_handle_event(XEvent X)
case FocusIn:
{
if (X.xfocus.detail != NotifyInferior) {
ScreenPtr pScreen = xnestScreen(X.xfocus.window);
EVTYPE(xcb_focus_in_event_t);
if (ev->detail != NotifyInferior) {
ScreenPtr pScreen = xnestScreen(ev->event);
if (pScreen)
xnestDirectInstallColormaps(pScreen);
}
@ -171,8 +147,9 @@ xnest_handle_event(XEvent X)
case FocusOut:
{
if (X.xfocus.detail != NotifyInferior) {
ScreenPtr pScreen = xnestScreen(X.xfocus.window);
EVTYPE(xcb_focus_out_event_t);
if (ev->detail != NotifyInferior) {
ScreenPtr pScreen = xnestScreen(ev->event);
if (pScreen)
xnestDirectUninstallColormaps(pScreen);
}
@ -184,15 +161,16 @@ xnest_handle_event(XEvent X)
case EnterNotify:
{
if (X.xcrossing.detail != NotifyInferior) {
ScreenPtr pScreen = xnestScreen(X.xcrossing.window);
EVTYPE(xcb_enter_notify_event_t);
if (ev->detail != NotifyInferior) {
ScreenPtr pScreen = xnestScreen(ev->event);
if (pScreen) {
ValuatorMask mask;
int valuators[2];
NewCurrentScreen(inputInfo.pointer, pScreen, X.xcrossing.x,
X.xcrossing.y);
valuators[0] = X.xcrossing.x;
valuators[1] = X.xcrossing.y;
NewCurrentScreen(inputInfo.pointer, pScreen,
ev->event_x, ev->event_y);
valuators[0] = ev->event_x;
valuators[1] = ev->event_y;
valuator_mask_set_range(&mask, 0, 2, valuators);
lastEventTime = GetTimeInMillis();
QueuePointerEvents(xnestPointerDevice, MotionNotify,
@ -205,8 +183,9 @@ xnest_handle_event(XEvent X)
case LeaveNotify:
{
if (X.xcrossing.detail != NotifyInferior) {
ScreenPtr pScreen = xnestScreen(X.xcrossing.window);
EVTYPE(xcb_leave_notify_event_t);
if (ev->detail != NotifyInferior) {
ScreenPtr pScreen = xnestScreen(ev->event);
if (pScreen) {
xnestDirectUninstallColormaps(pScreen);
}
@ -216,8 +195,9 @@ xnest_handle_event(XEvent X)
case DestroyNotify:
{
if (xnestParentWindow != (Window) 0 &&
X.xdestroywindow.window == xnestParentWindow)
xcb_destroy_notify_event_t *ev = (xcb_destroy_notify_event_t*)event;
if (xnestParentWindow &&
ev->window == xnestParentWindow)
exit(0);
break;
}
@ -228,11 +208,35 @@ xnest_handle_event(XEvent X)
case MapNotify:
case ReparentNotify:
case UnmapNotify:
case NoExpose:
break;
case Expose:
{
EVTYPE(xcb_expose_event_t);
WindowPtr pWin = xnestWindowPtr(ev->window);
if (pWin && ev->width && ev->height) {
RegionRec Rgn;
BoxRec Box = {
.x1 = pWin->drawable.x + wBorderWidth(pWin) + ev->x,
.y1 = pWin->drawable.y + wBorderWidth(pWin) + ev->y,
.x2 = Box.x1 + ev->width,
.y2 = Box.y1 + ev->height,
};
RegionInit(&Rgn, &Box, 1);
miSendExposures(pWin, &Rgn, Box.x1, Box.y1);
}
}
break;
case NoExpose:
ErrorF("xnest: received stray NoExpose\n");
break;
case GraphicsExpose:
ErrorF("xnest: received stray GraphicsExpose\n");
break;
default:
ErrorF("xnest warning: unhandled event: %d\n", X.type);
ErrorF("xnest warning: unhandled event: %d\n", event->response_type);
break;
}
}
@ -240,9 +244,29 @@ xnest_handle_event(XEvent X)
void
xnestCollectEvents(void)
{
XEvent X;
while (XCheckIfEvent(xnestDisplay, &X, xnestNotExposurePredicate, NULL)) {
xnest_handle_event(X);
/* process queued events */
struct xnest_event_queue *tmp = NULL, *walk = NULL;
xorg_list_for_each_entry_safe(walk, tmp, &xnestUpstreamInfo.eventQueue.entry, entry) {
xnest_handle_event(walk->event);
xorg_list_del(&walk->entry);
free(walk->event);
free(walk);
}
xcb_flush(xnestUpstreamInfo.conn);
int err = xcb_connection_has_error(xnestUpstreamInfo.conn);
if (err) {
ErrorF("Xnest: upsream connection error: %d\n", err);
exit(0);
}
/* fetch new events from xcb */
xcb_generic_event_t *event = NULL;
while ((event = xcb_poll_for_event(xnestUpstreamInfo.conn))) {
xnest_handle_event(event);
free(event);
}
xcb_flush(xnestUpstreamInfo.conn);
}

View File

@ -17,12 +17,9 @@ is" without express or implied warranty.
#include <X11/Xmd.h>
#define ProcessedExpose (LASTEvent + 1)
extern CARD32 lastEventTime;
void SetTimeSinceLastInputEvent(void);
void xnestCollectExposures(void);
void xnestCollectEvents(void);
void xnestQueueKeyEvent(int type, unsigned int keycode);

View File

@ -142,21 +142,13 @@ xnestGetImage(DrawablePtr pDrawable, int x, int y, int w, int h,
free(reply);
}
static Bool
xnestBitBlitPredicate(Display * dpy, XEvent * event, char *args)
{
return event->type == GraphicsExpose || event->type == NoExpose;
}
static RegionPtr
xnestBitBlitHelper(GCPtr pGC)
{
if (!pGC->graphicsExposures)
return NullRegion;
else {
XEvent event;
RegionPtr pReg, pTmpReg;
BoxRec Box;
Bool pending, overlap;
pReg = RegionCreate(NULL, 1);
@ -164,24 +156,43 @@ xnestBitBlitHelper(GCPtr pGC)
if (!pReg || !pTmpReg)
return NullRegion;
xcb_flush(xnestUpstreamInfo.conn);
pending = TRUE;
while (pending) {
XIfEvent(xnestDisplay, &event, xnestBitBlitPredicate, NULL);
switch (event.type) {
case NoExpose:
xcb_generic_event_t *event = xcb_wait_for_event(xnestUpstreamInfo.conn);
if (!event) {
pending = FALSE;
break;
}
case GraphicsExpose:
Box.x1 = event.xgraphicsexpose.x;
Box.y1 = event.xgraphicsexpose.y;
Box.x2 = event.xgraphicsexpose.x + event.xgraphicsexpose.width;
Box.y2 = event.xgraphicsexpose.y + event.xgraphicsexpose.height;
RegionReset(pTmpReg, &Box);
RegionAppend(pReg, pTmpReg);
pending = event.xgraphicsexpose.count;
break;
switch (event->response_type & ~0x80) {
case NoExpose:
pending = FALSE;
free(event);
break;
case GraphicsExpose:
{
xcb_graphics_exposure_event_t* ev = (xcb_graphics_exposure_event_t*)event;
BoxRec Box = {
.x1 = ev->x,
.y1 = ev->y,
.x2 = ev->x + ev->width,
.y2 = ev->y + ev->height,
};
RegionReset(pTmpReg, &Box);
RegionAppend(pReg, pTmpReg);
pending = ev->count;
free(event);
break;
}
default:
{
struct xnest_event_queue *q = malloc(sizeof(struct xnest_event_queue));
q->event = event;
xorg_list_add(&q->entry, &xnestUpstreamInfo.eventQueue.entry);
}
}
}

View File

@ -31,8 +31,7 @@ is" without express or implied warranty.
void
xnestBlockHandler(void *blockData, void *timeout)
{
xnestCollectExposures();
XFlush(xnestDisplay);
xnestCollectEvents();
}
void

View File

@ -37,6 +37,8 @@ void xnest_upstream_setup(void) {
for (int i = 0; i < xnestUpstreamInfo.screenId; ++i)
xcb_screen_next (&iter);
xnestUpstreamInfo.screenInfo = iter.data;
xorg_list_init(&xnestUpstreamInfo.eventQueue.entry);
}
/* retrieve upstream GC XID for our xserver GC */

View File

@ -7,11 +7,19 @@
#include <xcb/xcb.h>
#include "include/list.h"
struct xnest_event_queue {
struct xorg_list entry;
xcb_generic_event_t *event;
};
struct xnest_upstream_info {
xcb_connection_t *conn;
uint32_t screenId;
const xcb_screen_t *screenInfo;
const xcb_setup_t *setup;
struct xnest_event_queue eventQueue;
};
extern struct xnest_upstream_info xnestUpstreamInfo;