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:
parent
f3248eba6e
commit
c17a417945
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue