On 07.11.2013 04:45, Keith Packard wrote: > 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 <kei...@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;
For bikeshedding, I would call this xcb_special_event_filter_t, because this is not actually an event. Having said that, feel free to ignore me. > +/** > + * @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; Add this, please: if(c->has_error) return NULL; > + 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; > +} Uhm, this function just updates stamp if it calls for already existing events? I don't like that, because this way the caller doesn't know if it has to call _unregister again or not. Is there any reason why this cannot return NULL on "collisisions"? Oh and: Please check for calloc() failures. > +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; if(c->has_error) return; > + 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); > -- "In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move." _______________________________________________ xorg-devel@lists.x.org: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel