[PATCH 6/8] Add event queue splitting
Keith Packard
keithp at keithp.com
Wed Nov 6 19:45:43 PST 2013
This allows apps to peel off certain XGE events into separate queues
for custom handling. Designed to support the Present extension
Signed-off-by: Keith Packard <keithp at keithp.com>
---
src/xcb.h | 28 ++++++++++
src/xcb_in.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
src/xcbint.h | 1 +
3 files changed, 193 insertions(+), 3 deletions(-)
diff --git a/src/xcb.h b/src/xcb.h
index c251330..cde820d 100644
--- a/src/xcb.h
+++ b/src/xcb.h
@@ -287,6 +287,34 @@ xcb_generic_event_t *xcb_poll_for_event(xcb_connection_t *c);
*/
xcb_generic_event_t *xcb_poll_for_queued_event(xcb_connection_t *c);
+typedef struct xcb_special_event xcb_special_event_t;
+
+/**
+ * @brief Returns the next event from a special queue
+ */
+xcb_generic_event_t *xcb_poll_for_special_event(xcb_connection_t *c,
+ xcb_special_event_t *se);
+
+/**
+ * @brief Returns the next event from a special queue, blocking until one arrives
+ */
+xcb_generic_event_t *xcb_wait_for_special_event(xcb_connection_t *c,
+ xcb_special_event_t *se);
+
+/**
+ * @brief Listen for a special event
+ */
+xcb_special_event_t *xcb_register_for_special_xge(xcb_connection_t *c,
+ uint8_t extension,
+ uint32_t eid,
+ uint32_t *stamp);
+
+/**
+ * @brief Stop listening for a special event
+ */
+void xcb_unregister_for_special_event(xcb_connection_t *c,
+ xcb_special_event_t *se);
+
/**
* @brief Return the error for a request, or NULL if none can ever arrive.
* @param c: The connection to the X server.
diff --git a/src/xcb_in.c b/src/xcb_in.c
index 0a78ae6..9239c93 100644
--- a/src/xcb_in.c
+++ b/src/xcb_in.c
@@ -61,6 +61,23 @@ struct event_list {
struct event_list *next;
};
+struct xcb_special_event {
+
+ struct xcb_special_event *next;
+
+ /* Match XGE events for the specific extension and event ID (the
+ * first 32 bit word after evtype)
+ */
+ uint8_t extension;
+ uint32_t eid;
+ uint32_t *stamp;
+
+ struct event_list *events;
+ struct event_list **events_tail;
+
+ pthread_cond_t special_event_cond;
+};
+
struct reply_list {
void *reply;
struct reply_list *next;
@@ -105,6 +122,46 @@ static int read_fds(xcb_connection_t *c, int *fds, int nfd)
}
#endif
+typedef struct xcb_ge_special_event_t {
+ uint8_t response_type; /**< */
+ uint8_t extension; /**< */
+ uint16_t sequence; /**< */
+ uint32_t length; /**< */
+ uint16_t evtype; /**< */
+ uint8_t pad0[2]; /**< */
+ uint32_t eid; /**< */
+ uint8_t pad1[16]; /**< */
+} xcb_ge_special_event_t;
+
+static int event_special(xcb_connection_t *c,
+ struct event_list *event)
+{
+ struct xcb_special_event *special_event;
+ struct xcb_ge_special_event_t *ges = (void *) event->event;
+
+ /* Special events are always XGE events */
+ if ((ges->response_type & 0x7f) != XCB_XGE_EVENT)
+ return 0;
+
+ for (special_event = c->in.special_events;
+ special_event;
+ special_event = special_event->next)
+ {
+ if (ges->extension == special_event->extension &&
+ ges->eid == special_event->eid)
+ {
+ *special_event->events_tail = event;
+ special_event->events_tail = &event->next;
+ if (special_event->stamp)
+ ++(*special_event->stamp);
+ pthread_cond_signal(&special_event->special_event_cond);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
static int read_packet(xcb_connection_t *c)
{
xcb_generic_reply_t genrep;
@@ -269,9 +326,12 @@ static int read_packet(xcb_connection_t *c)
}
event->event = buf;
event->next = 0;
- *c->in.events_tail = event;
- c->in.events_tail = &event->next;
- pthread_cond_signal(&c->in.event_cond);
+
+ if (!event_special(c, event)) {
+ *c->in.events_tail = event;
+ c->in.events_tail = &event->next;
+ pthread_cond_signal(&c->in.event_cond);
+ }
return 1; /* I have something for you... */
}
@@ -614,6 +674,107 @@ xcb_generic_error_t *xcb_request_check(xcb_connection_t *c, xcb_void_cookie_t co
return ret;
}
+static xcb_generic_event_t *get_special_event(xcb_connection_t *c,
+ xcb_special_event_t *se)
+{
+ xcb_generic_event_t *event = NULL;
+ struct event_list *events;
+
+ if ((events = se->events) != NULL) {
+ event = events->event;
+ if (!(se->events = events->next))
+ se->events_tail = &se->events;
+ free (events);
+ }
+ return event;
+}
+
+xcb_generic_event_t *xcb_poll_for_special_event(xcb_connection_t *c,
+ xcb_special_event_t *se)
+{
+ xcb_generic_event_t *event;
+
+ if(c->has_error)
+ return 0;
+ pthread_mutex_lock(&c->iolock);
+ event = get_special_event(c, se);
+ pthread_mutex_unlock(&c->iolock);
+ return event;
+}
+
+xcb_generic_event_t *xcb_wait_for_special_event(xcb_connection_t *c,
+ xcb_special_event_t *se)
+{
+ xcb_generic_event_t *event;
+
+ if(c->has_error)
+ return 0;
+ pthread_mutex_lock(&c->iolock);
+
+ /* get_special_event returns 0 on empty list. */
+ while(!(event = get_special_event(c, se)))
+ if(!_xcb_conn_wait(c, &se->special_event_cond, 0, 0))
+ break;
+
+ pthread_mutex_unlock(&c->iolock);
+ return event;
+}
+
+xcb_special_event_t *
+xcb_register_for_special_xge(xcb_connection_t *c,
+ uint8_t extension,
+ uint32_t eid,
+ uint32_t *stamp)
+{
+ xcb_special_event_t *se;
+ pthread_mutex_lock(&c->iolock);
+ for (se = c->in.special_events; se; se = se->next) {
+ if (se->extension == extension &&
+ se->eid == eid)
+ break;
+ }
+ if (!se) {
+ se = calloc(1, sizeof(xcb_special_event_t));
+ se->extension = extension;
+ se->eid = eid;
+
+ se->events = NULL;
+ se->events_tail = &se->events;
+
+ pthread_cond_init(&se->special_event_cond, 0);
+
+ se->next = c->in.special_events;
+ c->in.special_events = se;
+ }
+ se->stamp = stamp;
+ pthread_mutex_unlock(&c->iolock);
+ return se;
+}
+
+void
+xcb_unregister_for_special_event(xcb_connection_t *c,
+ xcb_special_event_t *se)
+{
+ xcb_special_event_t *s, **prev;
+ struct event_list *events, *next;
+ pthread_mutex_lock(&c->iolock);
+
+ for (prev = &c->in.special_events; (s = *prev) != NULL; prev = &(s->next)) {
+ if (s == se) {
+ *prev = se->next;
+ for (events = se->events; events; events = next) {
+ next = events->next;
+ free (events->event);
+ free (events);
+ }
+ pthread_cond_destroy(&se->special_event_cond);
+ free (se);
+ break;
+ }
+ }
+ pthread_mutex_unlock(&c->iolock);
+}
+
/* Private interface */
int _xcb_in_init(_xcb_in *in)
diff --git a/src/xcbint.h b/src/xcbint.h
index bbc5398..364dc59 100644
--- a/src/xcbint.h
+++ b/src/xcbint.h
@@ -150,6 +150,7 @@ typedef struct _xcb_in {
#if HAVE_SENDMSG
_xcb_fd in_fd;
#endif
+ struct xcb_special_event *special_events;
} _xcb_in;
int _xcb_in_init(_xcb_in *in);
--
1.8.4.2
More information about the xorg-devel
mailing list