ephyr: Process queued X events before blocking [v2]

If we end up reading all pending X events in the course of other server
execution, then our notify FD callback won't get invoked and we won't
process them. Fix this by noting that there are queued events in the
block handler, setting the poll timeout to zero and queuing a work
proc to clear the event queue.

v2: use a work proc to clear the event queue rather than doing it in
    the block handler directly.

Signed-off-by: Keith Packard <keithp@keithp.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
This commit is contained in:
Keith Packard 2016-06-04 19:55:07 -07:00
parent f3248eba6e
commit c17a417945
3 changed files with 65 additions and 19 deletions

View File

@ -336,6 +336,16 @@ ephyrInternalDamageRedisplay(ScreenPtr pScreen)
}
}
static void
ephyrXcbProcessEvents(Bool queued_only);
static Bool
ephyrEventWorkProc(ClientPtr client, void *closure)
{
ephyrXcbProcessEvents(TRUE);
return TRUE;
}
static void
ephyrScreenBlockHandler(ScreenPtr pScreen, void *timeout, void *pRead)
{
@ -345,20 +355,16 @@ ephyrScreenBlockHandler(ScreenPtr pScreen, void *timeout, void *pRead)
pScreen->BlockHandler = scrpriv->BlockHandler;
(*pScreen->BlockHandler)(pScreen, timeout, pRead);
scrpriv->BlockHandler = pScreen->BlockHandler;
pScreen->BlockHandler = ephyrScreenBlockHandler;
if (scrpriv->pDamage) {
/* Re-wrap if we're still tracking damage
*/
scrpriv->BlockHandler = pScreen->BlockHandler;
pScreen->BlockHandler = ephyrScreenBlockHandler;
if (scrpriv->pDamage)
ephyrInternalDamageRedisplay(pScreen);
} else {
/* Done tracking damage, note that we've left
* the block handler unwrapped
*/
scrpriv->BlockHandler = NULL;
if (hostx_has_queued_event()) {
if (!QueueWorkProc(ephyrEventWorkProc, NULL, NULL))
FatalError("cannot queue event processing in ephyr block handler");
AdjustWaitForDelay(timeout, 0);
}
}
@ -374,12 +380,6 @@ ephyrSetInternalDamage(ScreenPtr pScreen)
(DamageDestroyFunc) 0,
DamageReportNone, TRUE, pScreen, pScreen);
/* Wrap only once */
if (scrpriv->BlockHandler == NULL) {
scrpriv->BlockHandler = pScreen->BlockHandler;
pScreen->BlockHandler = ephyrScreenBlockHandler;
}
pPixmap = (*pScreen->GetScreenPixmap) (pScreen);
DamageRegister(&pPixmap->drawable, scrpriv->pDamage);
@ -682,6 +682,10 @@ ephyrInitScreen(ScreenPtr pScreen)
Bool
ephyrFinishInitScreen(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
EphyrScrPriv *scrpriv = screen->driver;
/* FIXME: Calling this even if not using shadow.
* Seems harmless enough. But may be safer elsewhere.
*/
@ -693,6 +697,9 @@ ephyrFinishInitScreen(ScreenPtr pScreen)
return FALSE;
#endif
scrpriv->BlockHandler = pScreen->BlockHandler;
pScreen->BlockHandler = ephyrScreenBlockHandler;
return TRUE;
}
@ -1131,12 +1138,13 @@ ephyrProcessConfigureNotify(xcb_generic_event_t *xev)
}
static void
ephyrXcbNotify(int fd, int ready, void *data)
ephyrXcbProcessEvents(Bool queued_only)
{
xcb_connection_t *conn = hostx_get_xcbconn();
while (TRUE) {
xcb_generic_event_t *xev = xcb_poll_for_event(conn);
xcb_generic_event_t *xev = hostx_get_event(queued_only);
if (!xev) {
/* If our XCB connection has died (for example, our window was
* closed), exit now.
@ -1191,6 +1199,12 @@ ephyrXcbNotify(int fd, int ready, void *data)
}
}
static void
ephyrXcbNotify(int fd, int ready, void *data)
{
ephyrXcbProcessEvents(FALSE);
}
void
ephyrCardFini(KdCardInfo * card)
{

View File

@ -70,6 +70,7 @@ struct EphyrHostXVars {
xcb_gcontext_t gc;
xcb_render_pictformat_t argb_format;
xcb_cursor_t empty_cursor;
xcb_generic_event_t *saved_event;
int depth;
Bool use_sw_cursor;
Bool use_fullscreen;
@ -1227,6 +1228,31 @@ hostx_get_xcbconn(void)
return HostX.conn;
}
xcb_generic_event_t *
hostx_get_event(Bool queued_only)
{
xcb_generic_event_t *xev;
if (HostX.saved_event) {
xev = HostX.saved_event;
HostX.saved_event = NULL;
} else {
if (queued_only)
xev = xcb_poll_for_queued_event(HostX.conn);
else
xev = xcb_poll_for_event(HostX.conn);
}
return xev;
}
Bool
hostx_has_queued_event(void)
{
if (!HostX.saved_event)
HostX.saved_event = xcb_poll_for_queued_event(HostX.conn);
return HostX.saved_event != NULL;
}
int
hostx_get_screen(void)
{

View File

@ -157,6 +157,12 @@ hostx_size_set_from_configure(Bool);
xcb_connection_t *
hostx_get_xcbconn(void);
xcb_generic_event_t *
hostx_get_event(Bool queued_only);
Bool
hostx_has_queued_event(void);
int
hostx_get_screen(void);