Merge branch 'github/fork/imirkin/pause-render' into 'master'

backend/x11: only send frames when the window is visible

Closes #2675

See merge request wlroots/wlroots!2682
This commit is contained in:
Simon Ser 2026-03-08 05:36:43 +00:00
commit 1467218b64
3 changed files with 71 additions and 5 deletions

View file

@ -110,14 +110,70 @@ static void handle_x11_event(struct wlr_x11_backend *x11,
} }
break; break;
} }
case XCB_UNMAP_NOTIFY: {
xcb_unmap_notify_event_t *ev = (xcb_unmap_notify_event_t *)event;
struct wlr_x11_output *output =
get_x11_output_from_window_id(x11, ev->window);
if (output != NULL) {
wlr_log(WLR_DEBUG, "Window unmapped, stopping updates");
output->mapped = false;
}
break;
}
case XCB_MAP_NOTIFY: {
xcb_unmap_notify_event_t *ev = (xcb_unmap_notify_event_t *)event;
struct wlr_x11_output *output =
get_x11_output_from_window_id(x11, ev->window);
if (output != NULL) {
wlr_log(WLR_DEBUG, "Window mapped%s", !output->hidden ? ", resuming updates" : "");
output->mapped = true;
if (!output->hidden) {
wlr_output_send_frame(&output->wlr_output);
}
}
break;
}
case XCB_PROPERTY_NOTIFY: {
xcb_property_notify_event_t *ev = (xcb_property_notify_event_t *)event;
struct wlr_x11_output *output =
get_x11_output_from_window_id(x11, ev->window);
if (output == NULL) {
break;
}
if (ev->atom == x11->atoms.net_wm_state) {
xcb_get_property_cookie_t cookie =
xcb_get_property(x11->xcb, false, ev->window,
ev->atom, XCB_ATOM_ATOM, 0, 32);
xcb_get_property_reply_t *reply =
xcb_get_property_reply(x11->xcb, cookie, NULL);
if (reply->type != XCB_ATOM_ATOM) {
free(reply);
break;
}
xcb_atom_t *atoms = xcb_get_property_value(reply);
bool was_hidden = output->hidden;
output->hidden = false;
for (int i = 0; i < xcb_get_property_value_length(reply); i++) {
if (atoms[i] == x11->atoms.net_wm_state_hidden) {
wlr_log(WLR_DEBUG, "Window hidden, stopping updates");
output->hidden = true;
}
}
free(reply);
if (was_hidden && !output->hidden) {
wlr_log(WLR_DEBUG, "Window no longer hidden%s", output->mapped ? ", resuming updates" : "");
if (output->mapped) {
wlr_output_send_frame(&output->wlr_output);
}
}
}
break;
}
case 0: { case 0: {
xcb_value_error_t *ev = (xcb_value_error_t *)event; xcb_value_error_t *ev = (xcb_value_error_t *)event;
handle_x11_error(x11, ev); handle_x11_error(x11, ev);
break; break;
} }
case XCB_UNMAP_NOTIFY:
case XCB_MAP_NOTIFY:
break;
default: default:
handle_x11_unknown_event(x11, event); handle_x11_unknown_event(x11, event);
break; break;
@ -414,6 +470,8 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_event_loop *loop,
} atom[] = { } atom[] = {
{ .name = "WM_PROTOCOLS", .atom = &x11->atoms.wm_protocols }, { .name = "WM_PROTOCOLS", .atom = &x11->atoms.wm_protocols },
{ .name = "WM_DELETE_WINDOW", .atom = &x11->atoms.wm_delete_window }, { .name = "WM_DELETE_WINDOW", .atom = &x11->atoms.wm_delete_window },
{ .name = "_NET_WM_STATE", .atom = &x11->atoms.net_wm_state },
{ .name = "_NET_WM_STATE_HIDDEN", .atom = &x11->atoms.net_wm_state_hidden },
{ .name = "_NET_WM_NAME", .atom = &x11->atoms.net_wm_name }, { .name = "_NET_WM_NAME", .atom = &x11->atoms.net_wm_name },
{ .name = "UTF8_STRING", .atom = &x11->atoms.utf8_string }, { .name = "UTF8_STRING", .atom = &x11->atoms.utf8_string },
{ .name = "_VARIABLE_REFRESH", .atom = &x11->atoms.variable_refresh }, { .name = "_VARIABLE_REFRESH", .atom = &x11->atoms.variable_refresh },

View file

@ -628,7 +628,8 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) {
XCB_CW_COLORMAP | XCB_CW_CURSOR; XCB_CW_COLORMAP | XCB_CW_CURSOR;
uint32_t values[] = { uint32_t values[] = {
0, 0,
XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY, XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY |
XCB_EVENT_MASK_PROPERTY_CHANGE,
x11->colormap, x11->colormap,
x11->transparent_cursor, x11->transparent_cursor,
}; };
@ -676,6 +677,8 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) {
xcb_flush(x11->xcb); xcb_flush(x11->xcb);
output->mapped = true;
wl_list_insert(&x11->outputs, &output->link); wl_list_insert(&x11->outputs, &output->link);
wlr_pointer_init(&output->pointer, &x11_pointer_impl, "x11-pointer"); wlr_pointer_init(&output->pointer, &x11_pointer_impl, "x11-pointer");
@ -796,7 +799,8 @@ void handle_x11_present_event(struct wlr_x11_backend *x11,
timespec_from_nsec(&present_event.when, complete_notify->ust * 1000); timespec_from_nsec(&present_event.when, complete_notify->ust * 1000);
wlr_output_send_present(&output->wlr_output, &present_event); wlr_output_send_present(&output->wlr_output, &present_event);
wlr_output_send_frame(&output->wlr_output); if (output->mapped && !output->hidden)
wlr_output_send_frame(&output->wlr_output);
break; break;
default: default:
wlr_log(WLR_DEBUG, "Unhandled Present event %"PRIu16, event->event_type); wlr_log(WLR_DEBUG, "Unhandled Present event %"PRIu16, event->event_type);

View file

@ -47,6 +47,8 @@ struct wlr_x11_output {
pixman_region32_t exposed; pixman_region32_t exposed;
uint64_t last_msc; uint64_t last_msc;
bool mapped;
bool hidden;
struct { struct {
struct wlr_swapchain *swapchain; struct wlr_swapchain *swapchain;
@ -94,6 +96,8 @@ struct wlr_x11_backend {
xcb_atom_t wm_protocols; xcb_atom_t wm_protocols;
xcb_atom_t wm_delete_window; xcb_atom_t wm_delete_window;
xcb_atom_t net_wm_name; xcb_atom_t net_wm_name;
xcb_atom_t net_wm_state;
xcb_atom_t net_wm_state_hidden;
xcb_atom_t utf8_string; xcb_atom_t utf8_string;
xcb_atom_t variable_refresh; xcb_atom_t variable_refresh;
} atoms; } atoms;