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 14:02:37 -0800
commit79019541e7c56ddfc3828b7bf96e6e5d3cf81c56 (patch)
tree6c36ee6c42b5abeae27b423644bf57f78b392ff4
parent7983bf0fbdc2725403f9db6154d0f5bc944040e5 (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 1fd1f6c..63864dc 100644
--- a/src/xcb.h
+++ b/src/xcb.h
@@ -290,6 +290,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.
@@ -328,11 +361,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 4a01f6f..e122f2f 100644
--- a/src/xcbint.h
+++ b/src/xcbint.h
@@ -154,6 +154,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);