From 164dbbb0648de2e91d05fafd81fda2bc458eb829 Mon Sep 17 00:00:00 2001 From: "Enrico Weigelt, metux IT consult" Date: Tue, 20 Aug 2024 17:23:21 +0200 Subject: [PATCH] (!1654) 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 --- hw/xnest/Args.c | 6 -- hw/xnest/Args.h | 1 - hw/xnest/Display.c | 3 - hw/xnest/Events.c | 160 +++++++++++++++++++++++++------------------ hw/xnest/Events.h | 3 - hw/xnest/GCOps.c | 53 ++++++++------ hw/xnest/Handlers.c | 3 +- hw/xnest/xcb.c | 2 + hw/xnest/xnest-xcb.h | 8 +++ 9 files changed, 135 insertions(+), 104 deletions(-) diff --git a/hw/xnest/Args.c b/hw/xnest/Args.c index cbf0f7950..a2285acb3 100644 --- a/hw/xnest/Args.c +++ b/hw/xnest/Args.c @@ -34,7 +34,6 @@ is" without express or implied warranty. #include "Args.h" char *xnestDisplayName = NULL; -Bool xnestSynchronize = FALSE; Bool xnestFullGeneration = FALSE; int xnestDefaultClass; Bool xnestUserDefaultClass = FALSE; @@ -60,10 +59,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; @@ -177,7 +172,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"); diff --git a/hw/xnest/Args.h b/hw/xnest/Args.h index fae8fbf2d..7ee70c56b 100644 --- a/hw/xnest/Args.h +++ b/hw/xnest/Args.h @@ -19,7 +19,6 @@ is" without express or implied warranty. #include extern char *xnestDisplayName; -extern Bool xnestSynchronize; extern Bool xnestFullGeneration; extern int xnestDefaultClass; extern Bool xnestUserDefaultClass; diff --git a/hw/xnest/Display.c b/hw/xnest/Display.c index 71be6df38..e6184ad8b 100644 --- a/hw/xnest/Display.c +++ b/hw/xnest/Display.c @@ -74,9 +74,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) diff --git a/hw/xnest/Events.c b/hw/xnest/Events.c index 337f62a55..5b273bd7c 100644 --- a/hw/xnest/Events.c +++ b/hw/xnest/Events.c @@ -32,6 +32,7 @@ is" without express or implied warranty. #include "mi.h" #include "Xnest.h" +#include "xnest-xcb.h" #include "Args.h" #include "Color.h" @@ -65,42 +66,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) { @@ -108,52 +73,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, @@ -163,8 +138,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); } @@ -173,8 +149,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); } @@ -186,15 +163,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, @@ -207,8 +185,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); } @@ -218,8 +197,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; } @@ -230,11 +210,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; } } @@ -242,9 +246,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); } diff --git a/hw/xnest/Events.h b/hw/xnest/Events.h index 1c1b8cd46..3211ccac5 100644 --- a/hw/xnest/Events.h +++ b/hw/xnest/Events.h @@ -17,12 +17,9 @@ is" without express or implied warranty. #include -#define ProcessedExpose (LASTEvent + 1) - extern CARD32 lastEventTime; void SetTimeSinceLastInputEvent(void); -void xnestCollectExposures(void); void xnestCollectEvents(void); void xnestQueueKeyEvent(int type, unsigned int keycode); diff --git a/hw/xnest/GCOps.c b/hw/xnest/GCOps.c index e5bc1cad4..2549840cf 100644 --- a/hw/xnest/GCOps.c +++ b/hw/xnest/GCOps.c @@ -145,21 +145,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); @@ -167,24 +159,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); + } } } diff --git a/hw/xnest/Handlers.c b/hw/xnest/Handlers.c index 27ea30a83..535860338 100644 --- a/hw/xnest/Handlers.c +++ b/hw/xnest/Handlers.c @@ -34,8 +34,7 @@ is" without express or implied warranty. void xnestBlockHandler(void *blockData, void *timeout) { - xnestCollectExposures(); - XFlush(xnestDisplay); + xnestCollectEvents(); } void diff --git a/hw/xnest/xcb.c b/hw/xnest/xcb.c index f298bab61..e6beefca0 100644 --- a/hw/xnest/xcb.c +++ b/hw/xnest/xcb.c @@ -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 */ diff --git a/hw/xnest/xnest-xcb.h b/hw/xnest/xnest-xcb.h index b3df9b2ef..87ccc7fb8 100644 --- a/hw/xnest/xnest-xcb.h +++ b/hw/xnest/xnest-xcb.h @@ -7,11 +7,19 @@ #include +#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;