mirror of
https://github.com/yshui/picom.git
synced 2024-11-18 13:55:36 -05:00
core: reading from X server is fine
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
23563c1ac8
commit
5b92f0bc1e
1 changed files with 18 additions and 40 deletions
58
src/picom.c
58
src/picom.c
|
@ -1535,8 +1535,7 @@ static void unredirect(session_t *ps) {
|
||||||
/// And if we don't get new ones, we won't render, i.e. we would freeze. libxcb
|
/// And if we don't get new ones, we won't render, i.e. we would freeze. libxcb
|
||||||
/// keeps an internal queue of events, so we have to be 100% sure no events are
|
/// keeps an internal queue of events, so we have to be 100% sure no events are
|
||||||
/// left in that queue before we go to sleep.
|
/// left in that queue before we go to sleep.
|
||||||
static void handle_queued_x_events(EV_P attr_unused, ev_prepare *w, int revents attr_unused) {
|
static void handle_x_events(struct session *ps) {
|
||||||
session_t *ps = session_ptr(w, event_check);
|
|
||||||
// Flush because if we go into sleep when there is still requests in the
|
// Flush because if we go into sleep when there is still requests in the
|
||||||
// outgoing buffer, they will not be sent for an indefinite amount of
|
// outgoing buffer, they will not be sent for an indefinite amount of
|
||||||
// time. Use XFlush here too, we might still use some Xlib functions
|
// time. Use XFlush here too, we might still use some Xlib functions
|
||||||
|
@ -1557,41 +1556,6 @@ static void handle_queued_x_events(EV_P attr_unused, ev_prepare *w, int revents
|
||||||
vblank_handle_x_events(ps->vblank_scheduler);
|
vblank_handle_x_events(ps->vblank_scheduler);
|
||||||
}
|
}
|
||||||
|
|
||||||
xcb_generic_event_t *ev;
|
|
||||||
while ((ev = xcb_poll_for_queued_event(ps->c.c))) {
|
|
||||||
ev_handle(ps, ev);
|
|
||||||
free(ev);
|
|
||||||
};
|
|
||||||
int err = xcb_connection_has_error(ps->c.c);
|
|
||||||
if (err) {
|
|
||||||
log_fatal("X11 server connection broke (error %d)", err);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Handle all events X server has sent us so far, so that our internal state will catch
|
|
||||||
/// up with the X server's state. It only makes sense to call this function in the X
|
|
||||||
/// critical section, otherwise we will be chasing a moving goal post.
|
|
||||||
///
|
|
||||||
/// (Disappointingly, grabbing the X server doesn't actually prevent the X server state
|
|
||||||
/// from changing. It should, but in practice we have observed window still being
|
|
||||||
/// destroyed while we have the server grabbed. This is very disappointing and forces us
|
|
||||||
/// to use some hacky code to recover when we discover we are out-of-sync.)
|
|
||||||
///
|
|
||||||
/// This function is different from `handle_queued_x_events` in that this will keep
|
|
||||||
/// reading from the X server until there is nothing left. Whereas
|
|
||||||
/// `handle_queued_x_events` is only concerned with emptying the internal buffer of
|
|
||||||
/// libxcb, so we don't go to sleep with unprocessed data.
|
|
||||||
static void handle_all_x_events(struct session *ps) {
|
|
||||||
assert(ps->server_grabbed);
|
|
||||||
|
|
||||||
XFlush(ps->c.dpy);
|
|
||||||
xcb_flush(ps->c.c);
|
|
||||||
|
|
||||||
if (ps->vblank_scheduler) {
|
|
||||||
vblank_handle_x_events(ps->vblank_scheduler);
|
|
||||||
}
|
|
||||||
|
|
||||||
xcb_generic_event_t *ev;
|
xcb_generic_event_t *ev;
|
||||||
while ((ev = xcb_poll_for_event(ps->c.c))) {
|
while ((ev = xcb_poll_for_event(ps->c.c))) {
|
||||||
ev_handle(ps, ev);
|
ev_handle(ps, ev);
|
||||||
|
@ -1604,9 +1568,14 @@ static void handle_all_x_events(struct session *ps) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_x_events_ev(EV_P attr_unused, ev_prepare *w, int revents attr_unused) {
|
||||||
|
session_t *ps = session_ptr(w, event_check);
|
||||||
|
handle_x_events(ps);
|
||||||
|
}
|
||||||
|
|
||||||
static void handle_new_windows(session_t *ps) {
|
static void handle_new_windows(session_t *ps) {
|
||||||
while (!wm_complete_import(ps->wm, &ps->c, ps->atoms)) {
|
while (!wm_complete_import(ps->wm, &ps->c, ps->atoms)) {
|
||||||
handle_all_x_events(ps);
|
handle_x_events(ps);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check tree changes first, because later property updates need accurate
|
// Check tree changes first, because later property updates need accurate
|
||||||
|
@ -1696,7 +1665,16 @@ static void handle_pending_updates(struct session *ps, double delta_t) {
|
||||||
ps->server_grabbed = true;
|
ps->server_grabbed = true;
|
||||||
|
|
||||||
// Catching up with X server
|
// Catching up with X server
|
||||||
handle_all_x_events(ps);
|
/// Handle all events X server has sent us so far, so that our internal state will
|
||||||
|
/// catch up with the X server's state. It only makes sense to call this function
|
||||||
|
/// in the X critical section, otherwise we will be chasing a moving goal post.
|
||||||
|
///
|
||||||
|
/// (Disappointingly, grabbing the X server doesn't actually prevent the X server
|
||||||
|
/// state from changing. It should, but in practice we have observed window still
|
||||||
|
/// being destroyed while we have the server grabbed. This is very disappointing
|
||||||
|
/// and forces us to use some hacky code to recover when we discover we are
|
||||||
|
/// out-of-sync.)
|
||||||
|
handle_x_events(ps);
|
||||||
if (ps->pending_updates || wm_has_incomplete_imports(ps->wm) ||
|
if (ps->pending_updates || wm_has_incomplete_imports(ps->wm) ||
|
||||||
wm_has_tree_changes(ps->wm)) {
|
wm_has_tree_changes(ps->wm)) {
|
||||||
log_debug("Delayed handling of events, entering critical section");
|
log_debug("Delayed handling of events, entering critical section");
|
||||||
|
@ -2515,7 +2493,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
|
||||||
//
|
//
|
||||||
// So we make use of a ev_prepare handle, which is called right before libev
|
// So we make use of a ev_prepare handle, which is called right before libev
|
||||||
// goes into sleep, to handle all the queued X events.
|
// goes into sleep, to handle all the queued X events.
|
||||||
ev_prepare_init(&ps->event_check, handle_queued_x_events);
|
ev_prepare_init(&ps->event_check, handle_x_events_ev);
|
||||||
// Make sure nothing can cause xcb to read from the X socket after events are
|
// Make sure nothing can cause xcb to read from the X socket after events are
|
||||||
// handled and before we going to sleep.
|
// handled and before we going to sleep.
|
||||||
ev_set_priority(&ps->event_check, EV_MINPRI);
|
ev_set_priority(&ps->event_check, EV_MINPRI);
|
||||||
|
|
Loading…
Reference in a new issue