mirror of
https://github.com/yshui/picom.git
synced 2025-04-14 17:53:25 -04:00
tentative fix for #1345
This commit is contained in:
parent
6e485a050a
commit
6eb45ad2cf
3 changed files with 57 additions and 30 deletions
65
src/picom.c
65
src/picom.c
|
@ -1451,31 +1451,48 @@ static void unredirect(session_t *ps) {
|
|||
static void handle_x_events(struct session *ps) {
|
||||
bool wm_was_consistent = wm_is_consistent(ps->wm);
|
||||
|
||||
if (ps->vblank_scheduler) {
|
||||
vblank_handle_x_events(ps->vblank_scheduler);
|
||||
while (true) {
|
||||
// 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 time. Use XFlush here too, we might still use some
|
||||
// Xlib functions because OpenGL.
|
||||
//
|
||||
// Also note, `xcb_flush`/`XFlush` may _read_ more events from the server
|
||||
// (yes, this is ridiculous, I know). But since we are polling for events
|
||||
// in a loop, this should be fine - if we read events here, they will be
|
||||
// handled below; and if some requests is sent later in this loop, which
|
||||
// means some events must have been received, we will loop once more and
|
||||
// get here to flush them.
|
||||
XFlush(ps->c.dpy);
|
||||
xcb_flush(ps->c.c);
|
||||
|
||||
// We have to check for vblank events (i.e. special xcb events) and normal
|
||||
// events in a loop. This is because both `xcb_poll_for_event` and
|
||||
// `xcb_poll_for_special_event` will read data from the X connection and
|
||||
// put it in a buffer. So whichever one we call last, say
|
||||
// `xcb_poll_for_special_event`, will read data into the buffer that might
|
||||
// contain events that `xcb_poll_for_event` should handle, and vice versa.
|
||||
// This causes us to go into sleep with events in the buffer.
|
||||
//
|
||||
// We have to keep calling both of them until neither of them return any
|
||||
// events.
|
||||
bool has_events = false;
|
||||
if (ps->vblank_scheduler) {
|
||||
has_events = vblank_handle_x_events(ps->vblank_scheduler) ==
|
||||
VBLANK_HANDLE_X_EVENTS_OK;
|
||||
}
|
||||
|
||||
xcb_generic_event_t *ev;
|
||||
while ((ev = x_poll_for_event(&ps->c))) {
|
||||
has_events = true;
|
||||
ev_handle(ps, (xcb_generic_event_t *)ev);
|
||||
free(ev);
|
||||
};
|
||||
|
||||
if (!has_events) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
// time. Use XFlush here too, we might still use some Xlib functions
|
||||
// because OpenGL.
|
||||
//
|
||||
// Also note, after we have flushed here, we won't flush again in this
|
||||
// function before going into sleep. This is because `xcb_flush`/`XFlush`
|
||||
// may _read_ more events from the server (yes, this is ridiculous, I
|
||||
// know). And we can't have that, see the comments above this function.
|
||||
//
|
||||
// This means if functions called ev_handle need to send some events,
|
||||
// they need to carefully make sure those events are flushed, one way or
|
||||
// another.
|
||||
XFlush(ps->c.dpy);
|
||||
xcb_flush(ps->c.c);
|
||||
|
||||
xcb_generic_event_t *ev;
|
||||
while ((ev = x_poll_for_event(&ps->c))) {
|
||||
ev_handle(ps, (xcb_generic_event_t *)ev);
|
||||
free(ev);
|
||||
};
|
||||
int err = xcb_connection_has_error(ps->c.c);
|
||||
if (err) {
|
||||
log_fatal("X11 server connection broke (error %d)", err);
|
||||
|
|
14
src/vblank.c
14
src/vblank.c
|
@ -69,7 +69,7 @@ struct vblank_scheduler_ops {
|
|||
bool (*init)(struct vblank_scheduler *self);
|
||||
void (*deinit)(struct vblank_scheduler *self);
|
||||
bool (*schedule)(struct vblank_scheduler *self);
|
||||
bool (*handle_x_events)(struct vblank_scheduler *self);
|
||||
enum vblank_handle_x_events_result (*handle_x_events)(struct vblank_scheduler *self);
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -446,10 +446,14 @@ static void handle_present_complete_notify(struct present_vblank_scheduler *self
|
|||
ev_timer_start(self->base.loop, &self->callback_timer);
|
||||
}
|
||||
|
||||
static bool handle_present_events(struct vblank_scheduler *base) {
|
||||
static enum vblank_handle_x_events_result
|
||||
handle_present_events(struct vblank_scheduler *base) {
|
||||
auto self = (struct present_vblank_scheduler *)base;
|
||||
xcb_present_generic_event_t *ev;
|
||||
enum vblank_handle_x_events_result result = VBLANK_HANDLE_X_EVENTS_NO_EVENTS;
|
||||
while ((ev = (void *)xcb_poll_for_special_event(base->c->c, self->event))) {
|
||||
result = VBLANK_HANDLE_X_EVENTS_OK;
|
||||
|
||||
if (ev->event != self->event_id) {
|
||||
// This event doesn't have the right event context, it's not meant
|
||||
// for us.
|
||||
|
@ -462,7 +466,7 @@ static bool handle_present_events(struct vblank_scheduler *base) {
|
|||
next:
|
||||
free(ev);
|
||||
}
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
static const struct vblank_scheduler_ops vblank_scheduler_ops[LAST_VBLANK_SCHEDULER] = {
|
||||
|
@ -573,11 +577,11 @@ vblank_scheduler_new(struct ev_loop *loop, struct x_connection *c, xcb_window_t
|
|||
return self;
|
||||
}
|
||||
|
||||
bool vblank_handle_x_events(struct vblank_scheduler *self) {
|
||||
enum vblank_handle_x_events_result vblank_handle_x_events(struct vblank_scheduler *self) {
|
||||
assert(self->type < LAST_VBLANK_SCHEDULER);
|
||||
auto fn = vblank_scheduler_ops[self->type].handle_x_events;
|
||||
if (fn != NULL) {
|
||||
return fn(self);
|
||||
}
|
||||
return true;
|
||||
return VBLANK_HANDLE_X_EVENTS_NO_EVENTS;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,12 @@ enum vblank_callback_action {
|
|||
VBLANK_CALLBACK_DONE,
|
||||
};
|
||||
|
||||
enum vblank_handle_x_events_result {
|
||||
VBLANK_HANDLE_X_EVENTS_OK,
|
||||
VBLANK_HANDLE_X_EVENTS_ERROR,
|
||||
VBLANK_HANDLE_X_EVENTS_NO_EVENTS,
|
||||
};
|
||||
|
||||
typedef enum vblank_callback_action (*vblank_callback_t)(struct vblank_event *event,
|
||||
void *user_data);
|
||||
|
||||
|
@ -47,4 +53,4 @@ vblank_scheduler_new(struct ev_loop *loop, struct x_connection *c, xcb_window_t
|
|||
enum vblank_scheduler_type type, bool use_realtime_scheduling);
|
||||
void vblank_scheduler_free(struct vblank_scheduler *);
|
||||
|
||||
bool vblank_handle_x_events(struct vblank_scheduler *self);
|
||||
enum vblank_handle_x_events_result vblank_handle_x_events(struct vblank_scheduler *self);
|
||||
|
|
Loading…
Add table
Reference in a new issue