summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2013-04-12 20:15:41 -0700
committerKeith Packard <keithp@keithp.com>2013-11-07 13:32:46 -0800
commit568cf48f00441c834ed78375f13e7846c57312e9 (patch)
treecfa97b50f2f004c56b649f65525dc208e3f80e07
parentbbe7f95e070642c87679cdf4e218fd8fa7528cf3 (diff)
Add event queue splitting
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@keithp.com> Reviewed-By: Uli Schlachter <psychon@znc.in>
-rw-r--r--src/xcb.h38
-rw-r--r--src/xcb_in.c80
-rw-r--r--src/xcbint.h1
3 files changed, 107 insertions, 12 deletions
diff --git a/src/xcb.h b/src/xcb.h
index fe64851..3f2663a 100644
--- a/src/xcb.h
+++ b/src/xcb.h
@@ -291,6 +291,39 @@ 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);
+/**
+ * @typedef typedef struct xcb_extension_t xcb_extension_t
+ */
+typedef struct xcb_extension_t xcb_extension_t; /**< Opaque structure used as key for xcb_get_extension_data_t. */
+
+
+/**
+ * @brief Listen for a special event
+ */
+xcb_special_event_t *xcb_register_for_special_xge(xcb_connection_t *c,
+ xcb_extension_t *ext,
+ 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.
@@ -329,11 +362,6 @@ void xcb_discard_reply(xcb_connection_t *c, unsigned int sequence);
/* xcb_ext.c */
/**
- * @typedef typedef struct xcb_extension_t xcb_extension_t
- */
-typedef struct xcb_extension_t xcb_extension_t; /**< Opaque structure used as key for xcb_get_extension_data_t. */
-
-/**
* @brief Caches reply information from QueryExtension requests.
* @param c: The connection.
* @param ext: The extension data.
diff --git a/src/xcb_in.c b/src/xcb_in.c
index b161e93..839f615 100644
--- a/src/xcb_in.c
+++ b/src/xcb_in.c
@@ -60,6 +60,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;
@@ -104,6 +121,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;
@@ -268,9 +325,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... */
}
@@ -661,17 +721,21 @@ xcb_generic_event_t *xcb_wait_for_special_event(xcb_connection_t *c,
xcb_special_event_t *
xcb_register_for_special_xge(xcb_connection_t *c,
- uint8_t extension,
+ xcb_extension_t *ext,
uint32_t eid,
uint32_t *stamp)
{
xcb_special_event_t *se;
+ const xcb_query_extension_reply_t *ext_reply;
if(c->has_error)
return NULL;
+ ext_reply = xcb_get_extension_data(c, ext);
+ if (!ext_reply)
+ return NULL;
pthread_mutex_lock(&c->iolock);
for (se = c->in.special_events; se; se = se->next) {
- if (se->extension == extension &&
+ if (se->extension == ext_reply->major_opcode &&
se->eid == eid) {
pthread_mutex_unlock(&c->iolock);
return NULL;
@@ -683,7 +747,7 @@ xcb_register_for_special_xge(xcb_connection_t *c,
return NULL;
}
- se->extension = extension;
+ se->extension = ext_reply->major_opcode;
se->eid = eid;
se->events = NULL;
@@ -694,7 +758,6 @@ xcb_register_for_special_xge(xcb_connection_t *c,
se->next = c->in.special_events;
c->in.special_events = se;
-
pthread_mutex_unlock(&c->iolock);
return se;
}
@@ -706,6 +769,9 @@ xcb_unregister_for_special_event(xcb_connection_t *c,
xcb_special_event_t *s, **prev;
struct event_list *events, *next;
+ if (!se)
+ return;
+
if (c->has_error)
return;
diff --git a/src/xcbint.h b/src/xcbint.h
index fcf62b8..45dc044 100644
--- a/src/xcbint.h
+++ b/src/xcbint.h
@@ -155,6 +155,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);