From 6ef5d18757ef5ae2f38d41d914f7d7df100e3799 Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Mon, 13 Jul 2020 18:45:57 +0000 Subject: [PATCH 01/94] render: egl: Use current display to restore NULL context eglGetCurrentDisplay() returns EGL_NO_DISPLAY when there is no context current and eglMakeCurrent() needs a display argument. Fixes #2327 --- render/egl.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/render/egl.c b/render/egl.c index 797d8f15a..f99b37f90 100644 --- a/render/egl.c +++ b/render/egl.c @@ -459,7 +459,20 @@ void wlr_egl_save_context(struct wlr_egl_context *context) { } bool wlr_egl_restore_context(struct wlr_egl_context *context) { - return eglMakeCurrent(context->display, context->draw_surface, + // If the saved context is a null-context, we must use the current + // display instead of the saved display because eglMakeCurrent() can't + // handle EGL_NO_DISPLAY. + EGLDisplay display = context->display == EGL_NO_DISPLAY ? + eglGetCurrentDisplay() : context->display; + + // If the current display is also EGL_NO_DISPLAY, we assume that there + // is currently no context set and no action needs to be taken to unset + // the context. + if (display == EGL_NO_DISPLAY) { + return true; + } + + return eglMakeCurrent(display, context->draw_surface, context->read_surface, context->context); } From a145430afac6e1d0fbf65250b25573fdf1b2e4fd Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Fri, 3 Jul 2020 00:52:25 -0400 Subject: [PATCH 02/94] input/pointer: add wlr_seat_pointer_wrap It allows a compositor to do things like skip motion events on pointer constraint unlock. References: https://github.com/swaywm/sway/pull/5431 --- include/wlr/types/wlr_seat.h | 6 ++++++ types/seat/wlr_seat_pointer.c | 14 ++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index 7b47da089..332ab0d30 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -409,6 +409,12 @@ void wlr_seat_pointer_notify_enter(struct wlr_seat *wlr_seat, */ void wlr_seat_pointer_notify_clear_focus(struct wlr_seat *wlr_seat); +/** + * Warp the pointer of this seat to the given surface-local coordinates, without + * generating motion events. + */ +void wlr_seat_pointer_warp(struct wlr_seat *wlr_seat, double sx, double sy); + /** * Notify the seat of motion over the given surface. Pass surface-local * coordinates where the pointer motion occurred. Defers to any grab of the diff --git a/types/seat/wlr_seat_pointer.c b/types/seat/wlr_seat_pointer.c index 9ad5f88c6..37c637b53 100644 --- a/types/seat/wlr_seat_pointer.c +++ b/types/seat/wlr_seat_pointer.c @@ -199,11 +199,9 @@ void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat, wlr_seat->pointer_state.focused_client = client; wlr_seat->pointer_state.focused_surface = surface; if (surface != NULL) { - wlr_seat->pointer_state.sx = sx; - wlr_seat->pointer_state.sy = sy; + wlr_seat_pointer_warp(wlr_seat, sx, sy); } else { - wlr_seat->pointer_state.sx = NAN; - wlr_seat->pointer_state.sy = NAN; + wlr_seat_pointer_warp(wlr_seat, NAN, NAN); } struct wlr_seat_pointer_focus_change_event event = { @@ -220,6 +218,11 @@ void wlr_seat_pointer_clear_focus(struct wlr_seat *wlr_seat) { wlr_seat_pointer_enter(wlr_seat, NULL, 0, 0); } +void wlr_seat_pointer_warp(struct wlr_seat *wlr_seat, double sx, double sy) { + wlr_seat->pointer_state.sx = sx; + wlr_seat->pointer_state.sy = sy; +} + void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time, double sx, double sy) { struct wlr_seat_client *client = wlr_seat->pointer_state.focused_client; @@ -241,8 +244,7 @@ void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time, wl_fixed_from_double(sy)); } - wlr_seat->pointer_state.sx = sx; - wlr_seat->pointer_state.sy = sy; + wlr_seat_pointer_warp(wlr_seat, sx, sy); } uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, uint32_t time, From 751a21d94f1b4f0345d040ddfd54b723631d5991 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 16 Jul 2020 00:27:23 +0200 Subject: [PATCH 03/94] Update version to 0.11.0 --- meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index a6dad5d6c..4abe63181 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'wlroots', 'c', - version: '0.10.0', + version: '0.11.0', license: 'MIT', meson_version: '>=0.54.0', default_options: [ @@ -15,7 +15,7 @@ project( # necessary for bugfix releases. Increasing soversion is required because # wlroots never guarantees ABI stability -- only API stability is guaranteed # between minor releases. -soversion = 5 +soversion = 6 add_project_arguments([ '-DWLR_USE_UNSTABLE', From bd387da62d78f25027f1f80d25d85970fd09c235 Mon Sep 17 00:00:00 2001 From: Tobias Langendorf Date: Sat, 18 Jul 2020 21:37:02 +0200 Subject: [PATCH 04/94] xwm: add support for xwayland minimize --- include/wlr/xwayland.h | 10 ++++++ include/xwayland/xwm.h | 2 ++ xwayland/xwm.c | 70 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/include/wlr/xwayland.h b/include/wlr/xwayland.h index 03201718c..26a14aea6 100644 --- a/include/wlr/xwayland.h +++ b/include/wlr/xwayland.h @@ -173,6 +173,7 @@ struct wlr_xwayland_surface { bool modal; bool fullscreen; bool maximized_vert, maximized_horz; + bool minimized; bool has_alpha; @@ -181,6 +182,7 @@ struct wlr_xwayland_surface { struct wl_signal request_configure; struct wl_signal request_move; struct wl_signal request_resize; + struct wl_signal request_minimize; struct wl_signal request_maximize; struct wl_signal request_fullscreen; struct wl_signal request_activate; @@ -221,6 +223,11 @@ struct wlr_xwayland_resize_event { uint32_t edges; }; +struct wlr_xwayland_minimize_event { + struct wlr_xwayland_surface *surface; + bool minimize; +}; + struct wlr_xwayland_server *wlr_xwayland_server_create( struct wl_display *display, struct wlr_xwayland_server_options *options); void wlr_xwayland_server_destroy(struct wlr_xwayland_server *server); @@ -250,6 +257,9 @@ void wlr_xwayland_surface_configure(struct wlr_xwayland_surface *surface, void wlr_xwayland_surface_close(struct wlr_xwayland_surface *surface); +void wlr_xwayland_surface_set_minimized(struct wlr_xwayland_surface *surface, + bool minimized); + void wlr_xwayland_surface_set_maximized(struct wlr_xwayland_surface *surface, bool maximized); diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h index 2569092fa..1085cb14e 100644 --- a/include/xwayland/xwm.h +++ b/include/xwayland/xwm.h @@ -44,7 +44,9 @@ enum atom_name { NET_WM_STATE_FULLSCREEN, NET_WM_STATE_MAXIMIZED_VERT, NET_WM_STATE_MAXIMIZED_HORZ, + NET_WM_STATE_HIDDEN, NET_WM_PING, + WM_CHANGE_STATE, WM_STATE, CLIPBOARD, PRIMARY, diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 28e329f39..a3fb61b42 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -42,7 +42,9 @@ const char *atom_map[ATOM_LAST] = { [NET_WM_STATE_FULLSCREEN] = "_NET_WM_STATE_FULLSCREEN", [NET_WM_STATE_MAXIMIZED_VERT] = "_NET_WM_STATE_MAXIMIZED_VERT", [NET_WM_STATE_MAXIMIZED_HORZ] = "_NET_WM_STATE_MAXIMIZED_HORZ", + [NET_WM_STATE_HIDDEN] = "_NET_WM_STATE_HIDDEN", [NET_WM_PING] = "_NET_WM_PING", + [WM_CHANGE_STATE] = "WM_CHANGE_STATE", [WM_STATE] = "WM_STATE", [CLIPBOARD] = "CLIPBOARD", [PRIMARY] = "PRIMARY", @@ -146,6 +148,7 @@ static struct wlr_xwayland_surface *xwayland_surface_create( wl_signal_init(&surface->events.request_configure); wl_signal_init(&surface->events.request_move); wl_signal_init(&surface->events.request_resize); + wl_signal_init(&surface->events.request_minimize); wl_signal_init(&surface->events.request_maximize); wl_signal_init(&surface->events.request_fullscreen); wl_signal_init(&surface->events.request_activate); @@ -290,7 +293,7 @@ static void xwm_surface_activate(struct wlr_xwm *xwm, static void xsurface_set_net_wm_state(struct wlr_xwayland_surface *xsurface) { struct wlr_xwm *xwm = xsurface->xwm; - uint32_t property[4]; + uint32_t property[5]; int i; i = 0; @@ -306,6 +309,9 @@ static void xsurface_set_net_wm_state(struct wlr_xwayland_surface *xsurface) { if (xsurface->maximized_horz) { property[i++] = xwm->atoms[NET_WM_STATE_MAXIMIZED_HORZ]; } + if (xsurface->minimized) { + property[i++] = xwm->atoms[NET_WM_STATE_HIDDEN]; + } xcb_change_property(xwm->xcb_conn, XCB_PROP_MODE_REPLACE, @@ -664,6 +670,8 @@ static void read_surface_net_wm_state(struct wlr_xwm *xwm, xsurface->maximized_vert = true; } else if (atom[i] == xwm->atoms[NET_WM_STATE_MAXIMIZED_HORZ]) { xsurface->maximized_horz = true; + } else if (atom[i] == xwm->atoms[NET_WM_STATE_HIDDEN]) { + xsurface->minimized = true; } } } @@ -1126,6 +1134,7 @@ static void xwm_handle_net_wm_state_message(struct wlr_xwm *xwm, bool fullscreen = xsurface->fullscreen; bool maximized = xsurface_is_maximized(xsurface); + bool minimized = xsurface->minimized; uint32_t action = client_message->data.data32[0]; for (size_t i = 0; i < 2; ++i) { @@ -1143,6 +1152,9 @@ static void xwm_handle_net_wm_state_message(struct wlr_xwm *xwm, } else if (property == xwm->atoms[NET_WM_STATE_MAXIMIZED_HORZ] && update_state(action, &xsurface->maximized_horz)) { xsurface_set_net_wm_state(xsurface); + } else if (property == xwm->atoms[NET_WM_STATE_HIDDEN] && + update_state(action, &xsurface->minimized)) { + xsurface_set_net_wm_state(xsurface); } } // client_message->data.data32[3] is the source indication @@ -1165,6 +1177,19 @@ static void xwm_handle_net_wm_state_message(struct wlr_xwm *xwm, wlr_signal_emit_safe(&xsurface->events.request_maximize, xsurface); } + + if (minimized != xsurface->minimized) { + if (xsurface->minimized) { + xsurface->saved_width = xsurface->width; + xsurface->saved_height = xsurface->height; + } + + struct wlr_xwayland_minimize_event minimize_event = { + .surface = xsurface, + .minimize = xsurface->minimized, + }; + wlr_signal_emit_safe(&xsurface->events.request_minimize, &minimize_event); + } } static void xwm_handle_wm_protocols_message(struct wlr_xwm *xwm, @@ -1202,6 +1227,32 @@ static void xwm_handle_net_active_window_message(struct wlr_xwm *xwm, wlr_signal_emit_safe(&surface->events.request_activate, surface); } +static void xwm_handle_wm_change_state_message(struct wlr_xwm *xwm, + xcb_client_message_event_t *ev) { + struct wlr_xwayland_surface *xsurface = lookup_surface(xwm, ev->window); + uint32_t detail = ev->data.data32[0]; + + if (xsurface == NULL) { + return; + } + + bool minimize; + if (detail == ICCCM_ICONIC_STATE) { + minimize = true; + } else if (detail == ICCCM_NORMAL_STATE) { + minimize = false; + } else { + wlr_log(WLR_DEBUG, "unhandled wm_change_state event %u", detail); + return; + } + + struct wlr_xwayland_minimize_event minimize_event = { + .surface = xsurface, + .minimize = minimize, + }; + wlr_signal_emit_safe(&xsurface->events.request_minimize, &minimize_event); +} + static void xwm_handle_client_message(struct wlr_xwm *xwm, xcb_client_message_event_t *ev) { wlr_log(WLR_DEBUG, "XCB_CLIENT_MESSAGE (%u)", ev->window); @@ -1216,6 +1267,8 @@ static void xwm_handle_client_message(struct wlr_xwm *xwm, xwm_handle_wm_protocols_message(xwm, ev); } else if (ev->type == xwm->atoms[NET_ACTIVE_WINDOW]) { xwm_handle_net_active_window_message(xwm, ev); + } else if (ev->type == xwm->atoms[WM_CHANGE_STATE]) { + xwm_handle_wm_change_state_message(xwm, ev); } else if (!xwm_handle_selection_client_message(xwm, ev)) { char *type_name = xwm_get_atom_name(xwm, ev->type); wlr_log(WLR_DEBUG, "unhandled x11 client message %u (%s)", ev->type, @@ -1768,6 +1821,7 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) { xwm->atoms[NET_WM_STATE_FULLSCREEN], xwm->atoms[NET_WM_STATE_MAXIMIZED_VERT], xwm->atoms[NET_WM_STATE_MAXIMIZED_HORZ], + xwm->atoms[NET_WM_STATE_HIDDEN], xwm->atoms[NET_CLIENT_LIST], }; xcb_change_property(xwm->xcb_conn, @@ -1799,6 +1853,20 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) { return xwm; } +void wlr_xwayland_surface_set_minimized(struct wlr_xwayland_surface *surface, + bool minimized) { + surface->minimized = minimized; + + if (minimized) { + xsurface_set_wm_state(surface, ICCCM_ICONIC_STATE); + } else { + xsurface_set_wm_state(surface, ICCCM_NORMAL_STATE); + } + + xsurface_set_net_wm_state(surface); + xcb_flush(surface->xwm->xcb_conn); +} + void wlr_xwayland_surface_set_maximized(struct wlr_xwayland_surface *surface, bool maximized) { surface->maximized_horz = maximized; From 9686895b4e6b1e44132389b57b958f8885d97d77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonin=20D=C3=A9cimo?= Date: Tue, 21 Jul 2020 17:46:33 +0200 Subject: [PATCH 05/94] Fix typos --- examples/output-power-management.c | 2 +- include/backend/drm/drm.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/output-power-management.c b/examples/output-power-management.c index 8d91c6c05..43e7c53f6 100644 --- a/examples/output-power-management.c +++ b/examples/output-power-management.c @@ -114,7 +114,7 @@ int main(int argc, char *argv[]) { if (output_power_manager == NULL) { fprintf(stderr, - "compositor doesn't support wlr-output-power-managment-unstable-v1\n"); + "compositor doesn't support wlr-output-power-management-unstable-v1\n"); return EXIT_FAILURE; } diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index c56850791..80bc76698 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -134,7 +134,7 @@ struct wlr_drm_connector { struct wl_list link; /* - * We've asked for a state change in the kernel, and yet to recieve a + * We've asked for a state change in the kernel, and yet to receive a * notification for its completion. Currently, the kernel only has a * queue length of 1, and no way to modify your submissions after * they're sent. From cd4827b3b6f2b8b47562e58c4dc8669a0976c282 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 21 Jul 2020 12:05:04 +0200 Subject: [PATCH 06/94] xwayland/xwm: don't insert surface in list on error In case wl_event_loop_add_timer errors out, don't insert the free'd wlr_xwayland_surface in the list. Closes: https://github.com/swaywm/wlroots/issues/1721 --- xwayland/xwm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xwayland/xwm.c b/xwayland/xwm.c index a3fb61b42..50a859851 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -141,7 +141,6 @@ static struct wlr_xwayland_surface *xwayland_surface_create( surface->width = width; surface->height = height; surface->override_redirect = override_redirect; - wl_list_insert(&xwm->surfaces, &surface->link); wl_list_init(&surface->children); wl_list_init(&surface->parent_link); wl_signal_init(&surface->events.destroy); @@ -182,6 +181,8 @@ static struct wlr_xwayland_surface *xwayland_surface_create( return NULL; } + wl_list_insert(&xwm->surfaces, &surface->link); + wlr_signal_emit_safe(&xwm->xwayland->events.new_surface, surface); return surface; From 13f35139d39f3ec40f1f7a20ae15161ef04f03bd Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 21 Jul 2020 13:15:00 +0200 Subject: [PATCH 07/94] xwayland/xwm: add prop count assert in xsurface_set_net_wm_state This helps mitigate buffer overflows. --- xwayland/xwm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 50a859851..a34d56a27 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -294,10 +294,9 @@ static void xwm_surface_activate(struct wlr_xwm *xwm, static void xsurface_set_net_wm_state(struct wlr_xwayland_surface *xsurface) { struct wlr_xwm *xwm = xsurface->xwm; - uint32_t property[5]; - int i; - i = 0; + uint32_t property[5]; + size_t i = 0; if (xsurface->modal) { property[i++] = xwm->atoms[NET_WM_STATE_MODAL]; } @@ -313,6 +312,7 @@ static void xsurface_set_net_wm_state(struct wlr_xwayland_surface *xsurface) { if (xsurface->minimized) { property[i++] = xwm->atoms[NET_WM_STATE_HIDDEN]; } + assert(i <= sizeof(property) / sizeof(property[0])); xcb_change_property(xwm->xcb_conn, XCB_PROP_MODE_REPLACE, From c72efcd1ce070dc5a55625de1b0ef2c6630ce8dc Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 21 Jul 2020 13:16:28 +0200 Subject: [PATCH 08/94] xwayland/xwm: use initializer for props in xsurface_set_wm_state This avoids uninitialized items and makes it clear where the magic number 2 is coming from. --- xwayland/xwm.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/xwayland/xwm.c b/xwayland/xwm.c index a34d56a27..e10503081 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -913,10 +913,7 @@ static void xwm_handle_configure_notify(struct wlr_xwm *xwm, static void xsurface_set_wm_state(struct wlr_xwayland_surface *xsurface, int32_t state) { struct wlr_xwm *xwm = xsurface->xwm; - uint32_t property[2]; - - property[0] = state; - property[1] = XCB_WINDOW_NONE; + uint32_t property[] = { state, XCB_WINDOW_NONE }; xcb_change_property(xwm->xcb_conn, XCB_PROP_MODE_REPLACE, @@ -924,7 +921,7 @@ static void xsurface_set_wm_state(struct wlr_xwayland_surface *xsurface, xwm->atoms[WM_STATE], xwm->atoms[WM_STATE], 32, // format - 2, property); + sizeof(property) / sizeof(property[0]), property); } static void xwm_handle_map_request(struct wlr_xwm *xwm, From 39fd2335bf47ca33e28f61ec7a194c15a9ecc61e Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Sun, 26 Jul 2020 20:21:53 -0700 Subject: [PATCH 09/94] virtual_pointer: remember current axis for axis events --- types/wlr_virtual_pointer_v1.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/types/wlr_virtual_pointer_v1.c b/types/wlr_virtual_pointer_v1.c index aed3647be..75238447f 100644 --- a/types/wlr_virtual_pointer_v1.c +++ b/types/wlr_virtual_pointer_v1.c @@ -103,7 +103,8 @@ static void virtual_pointer_axis(struct wl_client *client, return; } struct wlr_input_device *wlr_dev = &pointer->input_device; - pointer->axis_valid[axis] = true; + pointer->axis = axis; + pointer->axis_valid[pointer->axis] = true; pointer->axis_event[pointer->axis].device = wlr_dev; pointer->axis_event[pointer->axis].time_msec = time; pointer->axis_event[pointer->axis].orientation = axis; From d9bb792794ce476ac79fdc0971fc01aeb3e5c8a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonin=20D=C3=A9cimo?= Date: Thu, 4 Jun 2020 14:33:32 +0200 Subject: [PATCH 10/94] Fix incorrect format parameters --- backend/drm/drm.c | 2 +- backend/session/logind.c | 2 +- backend/wayland/backend.c | 2 +- types/seat/wlr_seat_keyboard.c | 4 ++-- types/wlr_compositor.c | 6 +++--- types/wlr_layer_shell_v1.c | 8 ++++---- types/wlr_linux_dmabuf_v1.c | 4 ++-- types/wlr_surface.c | 8 ++++---- types/wlr_virtual_pointer_v1.c | 8 ++++---- xcursor/wlr_xcursor.c | 4 ++-- xwayland/selection/dnd.c | 4 ++-- xwayland/selection/outgoing.c | 6 +++--- xwayland/xwm.c | 30 ++++++++++++++++-------------- 13 files changed, 45 insertions(+), 43 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 6978c22c1..7ecc28d39 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -800,7 +800,7 @@ bool drm_connector_set_mode(struct wlr_drm_connector *conn, return false; } - wlr_log(WLR_INFO, "Modesetting '%s' with '%ux%u@%u mHz'", + wlr_log(WLR_INFO, "Modesetting '%s' with '%" PRId32 "x%" PRId32 "@%" PRId32 "mHz'", conn->output.name, wlr_mode->width, wlr_mode->height, wlr_mode->refresh); diff --git a/backend/session/logind.c b/backend/session/logind.c index b5acd4e4d..00babcae0 100644 --- a/backend/session/logind.c +++ b/backend/session/logind.c @@ -142,7 +142,7 @@ static bool logind_change_vt(struct wlr_session *base, unsigned vt) { "/org/freedesktop/login1/seat/seat0", "org.freedesktop.login1.Seat", "SwitchTo", &error, &msg, "u", (uint32_t)vt); if (ret < 0) { - wlr_log(WLR_ERROR, "Failed to change to vt '%d'", vt); + wlr_log(WLR_ERROR, "Failed to change to vt '%u'", vt); } sd_bus_error_free(&error); diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 8de63acf7..972963e0f 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -97,7 +97,7 @@ static void registry_global(void *data, struct wl_registry *registry, uint32_t name, const char *iface, uint32_t version) { struct wlr_wl_backend *wl = data; - wlr_log(WLR_DEBUG, "Remote wayland global: %s v%d", iface, version); + wlr_log(WLR_DEBUG, "Remote wayland global: %s v%" PRIu32, iface, version); if (strcmp(iface, wl_compositor_interface.name) == 0) { wl->compositor = wl_registry_bind(registry, name, diff --git a/types/seat/wlr_seat_keyboard.c b/types/seat/wlr_seat_keyboard.c index 715bd4ba1..5328de82f 100644 --- a/types/seat/wlr_seat_keyboard.c +++ b/types/seat/wlr_seat_keyboard.c @@ -267,7 +267,7 @@ void wlr_seat_keyboard_enter(struct wlr_seat *seat, for (size_t i = 0; i < num_keycodes; ++i) { uint32_t *p = wl_array_add(&keys, sizeof(uint32_t)); if (!p) { - wlr_log(WLR_ERROR, "Cannot allocate memory, skipping keycode: %d\n", + wlr_log(WLR_ERROR, "Cannot allocate memory, skipping keycode: %" PRIu32 "\n", keycodes[i]); continue; } @@ -449,7 +449,7 @@ void seat_client_create_keyboard(struct wlr_seat_client *seat_client, for (size_t i = 0; i < num_keycodes; ++i) { uint32_t *p = wl_array_add(&keys, sizeof(uint32_t)); if (!p) { - wlr_log(WLR_ERROR, "Cannot allocate memory, skipping keycode: %d\n", + wlr_log(WLR_ERROR, "Cannot allocate memory, skipping keycode: %" PRIu32 "\n", keycodes[i]); continue; } diff --git a/types/wlr_compositor.c b/types/wlr_compositor.c index 11f22923e..d49dcc18d 100644 --- a/types/wlr_compositor.c +++ b/types/wlr_compositor.c @@ -39,7 +39,7 @@ static void subcompositor_handle_get_subsurface(struct wl_client *client, if (surface == parent) { wl_resource_post_error(resource, WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, - "%s%d: wl_surface@%d cannot be its own parent", + "%s%" PRIu32 ": wl_surface@%" PRIu32 " cannot be its own parent", msg, id, wl_resource_get_id(surface_resource)); return; } @@ -48,7 +48,7 @@ static void subcompositor_handle_get_subsurface(struct wl_client *client, wlr_subsurface_from_wlr_surface(surface) != NULL) { wl_resource_post_error(resource, WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, - "%s%d: wl_surface@%d is already a sub-surface", + "%s%" PRIu32 ": wl_surface@%" PRIu32 " is already a sub-surface", msg, id, wl_resource_get_id(surface_resource)); return; } @@ -56,7 +56,7 @@ static void subcompositor_handle_get_subsurface(struct wl_client *client, if (wlr_surface_get_root_surface(parent) == surface) { wl_resource_post_error(resource, WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, - "%s%d: wl_surface@%d is an ancestor of parent", + "%s%" PRIu32 ": wl_surface@%" PRIu32 " is an ancestor of parent", msg, id, wl_resource_get_id(surface_resource)); return; } diff --git a/types/wlr_layer_shell_v1.c b/types/wlr_layer_shell_v1.c index 0002f4cbf..db2113e3f 100644 --- a/types/wlr_layer_shell_v1.c +++ b/types/wlr_layer_shell_v1.c @@ -74,7 +74,7 @@ static void layer_surface_handle_ack_configure(struct wl_client *client, if (!found) { wl_resource_post_error(resource, ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SURFACE_STATE, - "wrong configure serial: %u", serial); + "wrong configure serial: %" PRIu32, serial); return; } // Then remove old configures from the list @@ -114,7 +114,7 @@ static void layer_surface_handle_set_anchor(struct wl_client *client, if (anchor > max_anchor) { wl_resource_post_error(resource, ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_ANCHOR, - "invalid anchor %d", anchor); + "invalid anchor %" PRIu32, anchor); } struct wlr_layer_surface_v1 *surface = layer_surface_from_resource(resource); @@ -187,7 +187,7 @@ static void layer_surface_set_layer(struct wl_client *client, if (layer > ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY) { wl_resource_post_error(surface->resource, ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER, - "Invalid layer %d", layer); + "Invalid layer %" PRIu32, layer); return; } surface->client_pending.layer = layer; @@ -403,7 +403,7 @@ static void layer_shell_handle_get_layer_surface(struct wl_client *wl_client, free(surface); wl_resource_post_error(client_resource, ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER, - "Invalid layer %d", layer); + "Invalid layer %" PRIu32, layer); return; } surface->namespace = strdup(namespace); diff --git a/types/wlr_linux_dmabuf_v1.c b/types/wlr_linux_dmabuf_v1.c index 7db99eb6c..acd4cb4c9 100644 --- a/types/wlr_linux_dmabuf_v1.c +++ b/types/wlr_linux_dmabuf_v1.c @@ -210,7 +210,7 @@ static void params_create_common(struct wl_client *client, if (buffer->attributes.offset[i] > size) { wl_resource_post_error(params_resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, - "invalid offset %i for plane %d", + "invalid offset %" PRIu32 " for plane %d", buffer->attributes.offset[i], i); goto err_out; } @@ -219,7 +219,7 @@ static void params_create_common(struct wl_client *client, buffer->attributes.stride[i] == 0) { wl_resource_post_error(params_resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, - "invalid stride %i for plane %d", + "invalid stride %" PRIu32 " for plane %d", buffer->attributes.stride[i], i); goto err_out; } diff --git a/types/wlr_surface.c b/types/wlr_surface.c index f0a0b1fb1..1b623504b 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -712,7 +712,7 @@ bool wlr_surface_set_role(struct wlr_surface *surface, if (surface->role != NULL && surface->role != role) { if (error_resource != NULL) { wl_resource_post_error(error_resource, error_code, - "Cannot assign role %s to wl_surface@%d, already has role %s\n", + "Cannot assign role %s to wl_surface@%" PRIu32 ", already has role %s\n", role->name, wl_resource_get_id(surface->resource), surface->role->name); } @@ -720,7 +720,7 @@ bool wlr_surface_set_role(struct wlr_surface *surface, } if (surface->role_data != NULL && surface->role_data != role_data) { wl_resource_post_error(error_resource, error_code, - "Cannot reassign role %s to wl_surface@%d," + "Cannot reassign role %s to wl_surface@%" PRIu32 "," "role object still exists", role->name, wl_resource_get_id(surface->resource)); return false; @@ -791,7 +791,7 @@ static void subsurface_handle_place_above(struct wl_client *client, if (!sibling) { wl_resource_post_error(subsurface->resource, WL_SUBSURFACE_ERROR_BAD_SURFACE, - "%s: wl_surface@%d is not a parent or sibling", + "%s: wl_surface@%" PRIu32 "is not a parent or sibling", "place_above", wl_resource_get_id(sibling_surface->resource)); return; } @@ -818,7 +818,7 @@ static void subsurface_handle_place_below(struct wl_client *client, if (!sibling) { wl_resource_post_error(subsurface->resource, WL_SUBSURFACE_ERROR_BAD_SURFACE, - "%s: wl_surface@%d is not a parent or sibling", + "%s: wl_surface@%" PRIu32 " is not a parent or sibling", "place_below", wl_resource_get_id(sibling_surface->resource)); return; } diff --git a/types/wlr_virtual_pointer_v1.c b/types/wlr_virtual_pointer_v1.c index 75238447f..a9d1fd7bc 100644 --- a/types/wlr_virtual_pointer_v1.c +++ b/types/wlr_virtual_pointer_v1.c @@ -94,7 +94,7 @@ static void virtual_pointer_axis(struct wl_client *client, if (axis > WL_POINTER_AXIS_HORIZONTAL_SCROLL) { wl_resource_post_error(resource, ZWLR_VIRTUAL_POINTER_V1_ERROR_INVALID_AXIS, - "Invalid enumeration value %d", axis); + "Invalid enumeration value %" PRIu32, axis); return; } struct wlr_virtual_pointer_v1 *pointer = @@ -140,7 +140,7 @@ static void virtual_pointer_axis_source(struct wl_client *client, if (source > WL_POINTER_AXIS_SOURCE_WHEEL_TILT) { wl_resource_post_error(resource, ZWLR_VIRTUAL_POINTER_V1_ERROR_INVALID_AXIS_SOURCE, - "Invalid enumeration value %d", source); + "Invalid enumeration value %" PRIu32, source); return; } struct wlr_virtual_pointer_v1 *pointer = @@ -158,7 +158,7 @@ static void virtual_pointer_axis_stop(struct wl_client *client, if (axis > WL_POINTER_AXIS_HORIZONTAL_SCROLL) { wl_resource_post_error(resource, ZWLR_VIRTUAL_POINTER_V1_ERROR_INVALID_AXIS, - "Invalid enumeration value %d", axis); + "Invalid enumeration value %" PRIu32, axis); return; } struct wlr_virtual_pointer_v1 *pointer = @@ -182,7 +182,7 @@ static void virtual_pointer_axis_discrete(struct wl_client *client, if (axis > WL_POINTER_AXIS_HORIZONTAL_SCROLL) { wl_resource_post_error(resource, ZWLR_VIRTUAL_POINTER_V1_ERROR_INVALID_AXIS, - "Invalid enumeration value %d", axis); + "Invalid enumeration value %" PRIu32, axis); return; } struct wlr_virtual_pointer_v1 *pointer = diff --git a/xcursor/wlr_xcursor.c b/xcursor/wlr_xcursor.c index 4e1d02ecf..85e76a556 100644 --- a/xcursor/wlr_xcursor.c +++ b/xcursor/wlr_xcursor.c @@ -24,7 +24,7 @@ */ #define _POSIX_C_SOURCE 200809L -#include +#include #include #include #include @@ -245,7 +245,7 @@ struct wlr_xcursor_theme *wlr_xcursor_theme_load(const char *name, int size) { for (size_t i = 0; i < theme->cursor_count; ++i) { struct wlr_xcursor *c = theme->cursors[i]; struct wlr_xcursor_image *i = c->images[0]; - wlr_log(WLR_DEBUG, "%s (%u images) %dx%d+%d,%d", + wlr_log(WLR_DEBUG, "%s (%u images) %" PRIu32 "x%" PRIu32 "+%" PRIu32 ",%" PRIu32, c->name, c->image_count, i->width, i->height, i->hotspot_x, i->hotspot_y); } diff --git a/xwayland/selection/dnd.c b/xwayland/selection/dnd.c index ec5f16c7f..16941558a 100644 --- a/xwayland/selection/dnd.c +++ b/xwayland/selection/dnd.c @@ -192,7 +192,7 @@ int xwm_handle_selection_client_message(struct wlr_xwm *xwm, drag->source->accepted = accepted; wlr_data_source_dnd_action(drag->source, action); - wlr_log(WLR_DEBUG, "DND_STATUS window=%d accepted=%d action=%d", + wlr_log(WLR_DEBUG, "DND_STATUS window=%" PRIu32 " accepted=%d action=%d", target_window, accepted, action); return 1; } else if (ev->type == xwm->atoms[DND_FINISHED]) { @@ -226,7 +226,7 @@ int xwm_handle_selection_client_message(struct wlr_xwm *xwm, wlr_data_source_dnd_finish(source); } - wlr_log(WLR_DEBUG, "DND_FINISH window=%d performed=%d action=%d", + wlr_log(WLR_DEBUG, "DND_FINISH window=%" PRIu32 " performed=%d action=%d", target_window, performed, action); return 1; } else { diff --git a/xwayland/selection/outgoing.c b/xwayland/selection/outgoing.c index 169f516e7..002c0143c 100644 --- a/xwayland/selection/outgoing.c +++ b/xwayland/selection/outgoing.c @@ -23,9 +23,9 @@ static void xwm_selection_send_notify(struct wlr_xwm *xwm, .property = success ? req->property : XCB_ATOM_NONE, }; - wlr_log(WLR_DEBUG, "SendEvent destination=%d SelectionNotify(31) time=%d " - "requestor=%d selection=%d target=%d property=%d", req->requestor, - req->time, req->requestor, req->selection, req->target, + wlr_log(WLR_DEBUG, "SendEvent destination=%" PRIu32 " SelectionNotify(31) time=%" PRIu32 + " requestor=%" PRIu32 " selection=%" PRIu32 " target=%" PRIu32 " property=%" PRIu32, + req->requestor, req->time, req->requestor, req->selection, req->target, selection_notify.property); xcb_send_event(xwm->xcb_conn, 0, // propagate diff --git a/xwayland/xwm.c b/xwayland/xwm.c index e10503081..692c0f8bb 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -393,8 +393,9 @@ static void read_surface_class(struct wlr_xwm *xwm, surface->class = NULL; } - wlr_log(WLR_DEBUG, "XCB_ATOM_WM_CLASS: %s %s", surface->instance, - surface->class); + wlr_log(WLR_DEBUG, "XCB_ATOM_WM_CLASS: %s %s", + surface->instance ? surface->instance : "(null)", + surface->class ? surface->class : "(null)"); wlr_signal_emit_safe(&surface->events.set_class, surface); } @@ -416,7 +417,8 @@ static void read_surface_role(struct wlr_xwm *xwm, xsurface->role = NULL; } - wlr_log(WLR_DEBUG, "XCB_ATOM_WM_WINDOW_ROLE: %s", xsurface->role); + wlr_log(WLR_DEBUG, "XCB_ATOM_WM_WINDOW_ROLE: %s", + xsurface->role ? xsurface->role : "(null)"); wlr_signal_emit_safe(&xsurface->events.set_role, xsurface); } @@ -444,7 +446,7 @@ static void read_surface_title(struct wlr_xwm *xwm, } xsurface->has_utf8_title = is_utf8; - wlr_log(WLR_DEBUG, "XCB_ATOM_WM_NAME: %s", xsurface->title); + wlr_log(WLR_DEBUG, "XCB_ATOM_WM_NAME: %s", xsurface->title ? xsurface->title : "(null)"); wlr_signal_emit_safe(&xsurface->events.set_title, xsurface); } @@ -558,7 +560,7 @@ static void read_surface_hints(struct wlr_xwm *xwm, xsurface->hints->input = true; } - wlr_log(WLR_DEBUG, "WM_HINTS (%d)", reply->value_len); + wlr_log(WLR_DEBUG, "WM_HINTS (%" PRIu32 ")", reply->value_len); wlr_signal_emit_safe(&xsurface->events.set_hints, xsurface); } #else @@ -610,7 +612,7 @@ static void read_surface_normal_hints(struct wlr_xwm *xwm, xsurface->size_hints->max_height = -1; } - wlr_log(WLR_DEBUG, "WM_NORMAL_HINTS (%d)", reply->value_len); + wlr_log(WLR_DEBUG, "WM_NORMAL_HINTS (%" PRIu32 ")", reply->value_len); } #else static void read_surface_normal_hints(struct wlr_xwm *xwm, @@ -654,7 +656,7 @@ static void read_surface_motif_hints(struct wlr_xwm *xwm, wlr_signal_emit_safe(&xsurface->events.set_decorations, xsurface); } - wlr_log(WLR_DEBUG, "MOTIF_WM_HINTS (%d)", reply->value_len); + wlr_log(WLR_DEBUG, "MOTIF_WM_HINTS (%" PRIu32 ")", reply->value_len); } static void read_surface_net_wm_state(struct wlr_xwm *xwm, @@ -727,8 +729,8 @@ static void read_surface_property(struct wlr_xwm *xwm, read_surface_role(xwm, xsurface, reply); } else { char *prop_name = xwm_get_atom_name(xwm, property); - wlr_log(WLR_DEBUG, "unhandled X11 property %u (%s) for window %u", - property, prop_name, xsurface->window_id); + wlr_log(WLR_DEBUG, "unhandled X11 property %" PRIu32 " (%s) for window %" PRIu32, + property, prop_name ? prop_name : "(null)", xsurface->window_id); free(prop_name); } @@ -1210,8 +1212,8 @@ static void xwm_handle_wm_protocols_message(struct wlr_xwm *xwm, surface->pinging = false; } else { char *type_name = xwm_get_atom_name(xwm, type); - wlr_log(WLR_DEBUG, "unhandled WM_PROTOCOLS client message %u (%s)", - type, type_name); + wlr_log(WLR_DEBUG, "unhandled WM_PROTOCOLS client message %" PRIu32 " (%s)", + type, type_name ? type_name : "(null)"); free(type_name); } } @@ -1269,8 +1271,8 @@ static void xwm_handle_client_message(struct wlr_xwm *xwm, xwm_handle_wm_change_state_message(xwm, ev); } else if (!xwm_handle_selection_client_message(xwm, ev)) { char *type_name = xwm_get_atom_name(xwm, ev->type); - wlr_log(WLR_DEBUG, "unhandled x11 client message %u (%s)", ev->type, - type_name); + wlr_log(WLR_DEBUG, "unhandled x11 client message %" PRIu32 " (%s)", ev->type, + type_name ? type_name : "(null)"); free(type_name); } } @@ -1596,7 +1598,7 @@ static void xwm_get_resources(struct wlr_xwm *xwm) { xfixes_reply = xcb_xfixes_query_version_reply(xwm->xcb_conn, xfixes_cookie, NULL); - wlr_log(WLR_DEBUG, "xfixes version: %d.%d", + wlr_log(WLR_DEBUG, "xfixes version: %" PRIu32 ".%" PRIu32, xfixes_reply->major_version, xfixes_reply->minor_version); free(xfixes_reply); From 1ae2d976c0798d5aaaaced277e931e7e18187536 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonin=20D=C3=A9cimo?= Date: Thu, 4 Jun 2020 16:23:51 +0200 Subject: [PATCH 11/94] xwayland: free server in error path --- xwayland/xwayland.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xwayland/xwayland.c b/xwayland/xwayland.c index ccec7c670..4cb103af0 100644 --- a/xwayland/xwayland.c +++ b/xwayland/xwayland.c @@ -89,7 +89,7 @@ struct wlr_xwayland *wlr_xwayland_create(struct wl_display *wl_display, }; xwayland->server = wlr_xwayland_server_create(wl_display, &options); if (xwayland->server == NULL) { - free(xwayland->server); + free(xwayland); return NULL; } From 6d0ee53e1a3d270b8b783ffbc50b1da621ef7880 Mon Sep 17 00:00:00 2001 From: Scott Moreau Date: Mon, 27 Jul 2020 05:41:54 -0600 Subject: [PATCH 12/94] xwm: Set _NET_WM_STATE_FOCUSED property for the focused surface Certain clients require this property to be set for expected behavior. Most notably, steam client CSD maximize button no longer worked after unmaximizing once, unless the state was changed by another method. The state is unset whenever another surface gains focus. --- include/xwayland/xwm.h | 1 + xwayland/xwm.c | 33 +++++++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h index 1085cb14e..a3e7132d9 100644 --- a/include/xwayland/xwm.h +++ b/include/xwayland/xwm.h @@ -40,6 +40,7 @@ enum atom_name { NET_ACTIVE_WINDOW, NET_WM_MOVERESIZE, NET_SUPPORTING_WM_CHECK, + NET_WM_STATE_FOCUSED, NET_WM_STATE_MODAL, NET_WM_STATE_FULLSCREEN, NET_WM_STATE_MAXIMIZED_VERT, diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 692c0f8bb..88f4c3c5f 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -38,6 +38,7 @@ const char *atom_map[ATOM_LAST] = { [NET_ACTIVE_WINDOW] = "_NET_ACTIVE_WINDOW", [NET_WM_MOVERESIZE] = "_NET_WM_MOVERESIZE", [NET_SUPPORTING_WM_CHECK] = "_NET_SUPPORTING_WM_CHECK", + [NET_WM_STATE_FOCUSED] = "_NET_WM_STATE_FOCUSED", [NET_WM_STATE_MODAL] = "_NET_WM_STATE_MODAL", [NET_WM_STATE_FULLSCREEN] = "_NET_WM_STATE_FULLSCREEN", [NET_WM_STATE_MAXIMIZED_VERT] = "_NET_WM_STATE_MAXIMIZED_VERT", @@ -238,8 +239,20 @@ static void xwm_set_net_client_list(struct wlr_xwm *xwm) { XCB_ATOM_WINDOW, 32, mapped_surfaces, windows); } -static void xwm_send_focus_window(struct wlr_xwm *xwm, +static void xsurface_set_net_wm_state(struct wlr_xwayland_surface *xsurface); + +static void xwm_set_focus_window(struct wlr_xwm *xwm, struct wlr_xwayland_surface *xsurface) { + struct wlr_xwayland_surface *unfocus_surface = xwm->focus_surface; + + // We handle cases where focus_surface == xsurface because we + // want to be able to deny FocusIn events. + xwm->focus_surface = xsurface; + + if (unfocus_surface) { + xsurface_set_net_wm_state(unfocus_surface); + } + if (!xsurface) { xcb_set_input_focus_checked(xwm->xcb_conn, XCB_INPUT_FOCUS_POINTER_ROOT, @@ -270,6 +283,8 @@ static void xwm_send_focus_window(struct wlr_xwm *xwm, values[0] = XCB_STACK_MODE_ABOVE; xcb_configure_window(xwm->xcb_conn, xsurface->window_id, XCB_CONFIG_WINDOW_STACK_MODE, values); + + xsurface_set_net_wm_state(xsurface); } static void xwm_surface_activate(struct wlr_xwm *xwm, @@ -285,9 +300,7 @@ static void xwm_surface_activate(struct wlr_xwm *xwm, xwm_set_net_active_window(xwm, XCB_WINDOW_NONE); } - xwm_send_focus_window(xwm, xsurface); - - xwm->focus_surface = xsurface; + xwm_set_focus_window(xwm, xsurface); xcb_flush(xwm->xcb_conn); } @@ -295,7 +308,7 @@ static void xwm_surface_activate(struct wlr_xwm *xwm, static void xsurface_set_net_wm_state(struct wlr_xwayland_surface *xsurface) { struct wlr_xwm *xwm = xsurface->xwm; - uint32_t property[5]; + uint32_t property[6]; size_t i = 0; if (xsurface->modal) { property[i++] = xwm->atoms[NET_WM_STATE_MODAL]; @@ -312,6 +325,9 @@ static void xsurface_set_net_wm_state(struct wlr_xwayland_surface *xsurface) { if (xsurface->minimized) { property[i++] = xwm->atoms[NET_WM_STATE_HIDDEN]; } + if (xsurface == xwm->focus_surface) { + property[i++] = xwm->atoms[NET_WM_STATE_FOCUSED]; + } assert(i <= sizeof(property) / sizeof(property[0])); xcb_change_property(xwm->xcb_conn, @@ -1299,10 +1315,10 @@ static void xwm_handle_focus_in(struct wlr_xwm *xwm, struct wlr_xwayland_surface *requested_focus = lookup_surface(xwm, ev->event); if (xwm->focus_surface && requested_focus && requested_focus->pid == xwm->focus_surface->pid) { - xwm->focus_surface = requested_focus; + xwm_set_focus_window(xwm, requested_focus); + } else { + xwm_set_focus_window(xwm, xwm->focus_surface); } - - xwm_send_focus_window(xwm, xwm->focus_surface); } static void xwm_handle_xcb_error(struct wlr_xwm *xwm, xcb_value_error_t *ev) { @@ -1817,6 +1833,7 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) { xwm->atoms[NET_WM_STATE], xwm->atoms[NET_ACTIVE_WINDOW], xwm->atoms[NET_WM_MOVERESIZE], + xwm->atoms[NET_WM_STATE_FOCUSED], xwm->atoms[NET_WM_STATE_MODAL], xwm->atoms[NET_WM_STATE_FULLSCREEN], xwm->atoms[NET_WM_STATE_MAXIMIZED_VERT], From c32d89ee3efbc0a61c75e8120bdc2bf035c8ffd3 Mon Sep 17 00:00:00 2001 From: Rouven Czerwinski Date: Sat, 22 Feb 2020 14:56:40 +0100 Subject: [PATCH 13/94] examples: remove unnecessary gles2.h imports --- examples/multi-pointer.c | 1 - examples/pointer.c | 1 - 2 files changed, 2 deletions(-) diff --git a/examples/multi-pointer.c b/examples/multi-pointer.c index 9f7bd6c8e..eceeb6d68 100644 --- a/examples/multi-pointer.c +++ b/examples/multi-pointer.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/examples/pointer.c b/examples/pointer.c index a60807163..703aa59ea 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include From 26af316b3b3c15c0c2cbc76f2d398e5c3ac70c64 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 28 Jul 2020 13:45:24 +0200 Subject: [PATCH 14/94] render/gles2: make wlr_gles2_texture_from_* private These functions are unused by compositors (see e.g. [1]) and prevent wlr_gles2_texture from accessing wlr_gles2_renderer state. This is an issue for proper teardown [2] and for accessing GLES2 extensions. [1]: https://github.com/swaywm/wlroots/pull/1962#issuecomment-569511830 [2]: https://github.com/swaywm/wlroots/pull/1962 --- include/render/gles2.h | 10 ++++++++++ include/wlr/render/gles2.h | 8 -------- render/gles2/renderer.c | 23 +---------------------- render/gles2/texture.c | 15 ++++++++++++--- 4 files changed, 23 insertions(+), 33 deletions(-) diff --git a/include/render/gles2.h b/include/render/gles2.h index 6d25bea05..2853f5b9e 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -102,9 +102,19 @@ const struct wlr_gles2_pixel_format *get_gles2_format_from_gl( GLint gl_format, GLint gl_type, bool alpha); const enum wl_shm_format *get_gles2_wl_formats(size_t *len); +struct wlr_gles2_renderer *gles2_get_renderer( + struct wlr_renderer *wlr_renderer); struct wlr_gles2_texture *gles2_get_texture( struct wlr_texture *wlr_texture); +struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer, + enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height, + const void *data); +struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, + struct wl_resource *data); +struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer, + struct wlr_dmabuf_attributes *attribs); + void push_gles2_marker(const char *file, const char *func); void pop_gles2_marker(void); #define PUSH_GLES2_DEBUG push_gles2_marker(_WLR_FILENAME, __func__) diff --git a/include/wlr/render/gles2.h b/include/wlr/render/gles2.h index 631b11a2a..5a3e9d5c7 100644 --- a/include/wlr/render/gles2.h +++ b/include/wlr/render/gles2.h @@ -21,14 +21,6 @@ struct wlr_egl *wlr_gles2_renderer_get_egl(struct wlr_renderer *renderer); bool wlr_gles2_renderer_check_ext(struct wlr_renderer *renderer, const char *ext); -struct wlr_texture *wlr_gles2_texture_from_pixels(struct wlr_egl *egl, - enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height, - const void *data); -struct wlr_texture *wlr_gles2_texture_from_wl_drm(struct wlr_egl *egl, - struct wl_resource *data); -struct wlr_texture *wlr_gles2_texture_from_dmabuf(struct wlr_egl *egl, - struct wlr_dmabuf_attributes *attribs); - struct wlr_gles2_texture_attribs { GLenum target; /* either GL_TEXTURE_2D or GL_TEXTURE_EXTERNAL_OES */ GLuint tex; diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 914f5b77f..17a9caccc 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -25,7 +25,7 @@ struct wlr_gles2_procs gles2_procs = {0}; static const struct wlr_renderer_impl renderer_impl; -static struct wlr_gles2_renderer *gles2_get_renderer( +struct wlr_gles2_renderer *gles2_get_renderer( struct wlr_renderer *wlr_renderer) { assert(wlr_renderer->impl == &renderer_impl); return (struct wlr_gles2_renderer *)wlr_renderer; @@ -442,27 +442,6 @@ restore_context_out: return r; } -static struct wlr_texture *gles2_texture_from_pixels( - struct wlr_renderer *wlr_renderer, enum wl_shm_format wl_fmt, - uint32_t stride, uint32_t width, uint32_t height, const void *data) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); - return wlr_gles2_texture_from_pixels(renderer->egl, wl_fmt, stride, width, - height, data); -} - -static struct wlr_texture *gles2_texture_from_wl_drm( - struct wlr_renderer *wlr_renderer, struct wl_resource *data) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); - return wlr_gles2_texture_from_wl_drm(renderer->egl, data); -} - -static struct wlr_texture *gles2_texture_from_dmabuf( - struct wlr_renderer *wlr_renderer, - struct wlr_dmabuf_attributes *attribs) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); - return wlr_gles2_texture_from_dmabuf(renderer->egl, attribs); -} - static bool gles2_init_wl_display(struct wlr_renderer *wlr_renderer, struct wl_display *wl_display) { struct wlr_gles2_renderer *renderer = diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 0187a462f..d92eeac3d 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -134,9 +134,12 @@ static const struct wlr_texture_impl texture_impl = { .destroy = gles2_texture_destroy, }; -struct wlr_texture *wlr_gles2_texture_from_pixels(struct wlr_egl *egl, +struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer, enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height, const void *data) { + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_egl *egl = renderer->egl; + wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL); const struct wlr_gles2_pixel_format *fmt = get_gles2_format_from_wl(wl_fmt); @@ -175,8 +178,11 @@ struct wlr_texture *wlr_gles2_texture_from_pixels(struct wlr_egl *egl, return &texture->wlr_texture; } -struct wlr_texture *wlr_gles2_texture_from_wl_drm(struct wlr_egl *egl, +struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, struct wl_resource *resource) { + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_egl *egl = renderer->egl; + wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL); if (!gles2_procs.glEGLImageTargetTexture2DOES) { @@ -238,8 +244,11 @@ struct wlr_texture *wlr_gles2_texture_from_wl_drm(struct wlr_egl *egl, return &texture->wlr_texture; } -struct wlr_texture *wlr_gles2_texture_from_dmabuf(struct wlr_egl *egl, +struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer, struct wlr_dmabuf_attributes *attribs) { + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_egl *egl = renderer->egl; + wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL); if (!gles2_procs.glEGLImageTargetTexture2DOES) { From e8872d9ed7fce59fde56c3fe33796562ac56a66c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 28 Jul 2020 13:56:29 +0200 Subject: [PATCH 15/94] render/gles2: keep ref to wlr_gles2_renderer in wlr_gles2_texture --- include/render/gles2.h | 2 +- render/gles2/texture.c | 49 ++++++++++++++++++++---------------------- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/include/render/gles2.h b/include/render/gles2.h index 2853f5b9e..e9c49af9f 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -79,7 +79,7 @@ struct wlr_gles2_renderer { struct wlr_gles2_texture { struct wlr_texture wlr_texture; - struct wlr_egl *egl; + struct wlr_gles2_renderer *renderer; // Basically: // GL_TEXTURE_2D == mutable diff --git a/render/gles2/texture.c b/render/gles2/texture.c index d92eeac3d..72b69204d 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -29,7 +29,7 @@ struct wlr_gles2_texture *gles2_get_texture( static struct wlr_gles2_texture *get_gles2_texture_in_context( struct wlr_texture *wlr_texture) { struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); - wlr_egl_make_current(texture->egl, EGL_NO_SURFACE, NULL); + wlr_egl_make_current(texture->renderer->egl, EGL_NO_SURFACE, NULL); return texture; } @@ -47,7 +47,7 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture, if (texture->target != GL_TEXTURE_2D) { wlr_log(WLR_ERROR, "Cannot write pixels to immutable texture"); - wlr_egl_unset_current(texture->egl); + wlr_egl_unset_current(texture->renderer->egl); return false; } @@ -75,7 +75,7 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture, POP_GLES2_DEBUG; - wlr_egl_unset_current(texture->egl); + wlr_egl_unset_current(texture->renderer->egl); return true; } @@ -86,12 +86,12 @@ static bool gles2_texture_to_dmabuf(struct wlr_texture *wlr_texture, if (!texture->image) { assert(texture->target == GL_TEXTURE_2D); - if (!texture->egl->exts.image_base_khr) { + if (!texture->renderer->egl->exts.image_base_khr) { return false; } - texture->image = texture->egl->procs.eglCreateImageKHR( - texture->egl->display, texture->egl->context, EGL_GL_TEXTURE_2D_KHR, + texture->image = texture->renderer->egl->procs.eglCreateImageKHR( + texture->renderer->egl->display, texture->renderer->egl->context, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)(uintptr_t)texture->tex, NULL); if (texture->image == EGL_NO_IMAGE_KHR) { return false; @@ -103,7 +103,7 @@ static bool gles2_texture_to_dmabuf(struct wlr_texture *wlr_texture, flags |= WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT; } - return wlr_egl_export_image_to_dmabuf(texture->egl, texture->image, + return wlr_egl_export_image_to_dmabuf(texture->renderer->egl, texture->image, wlr_texture->width, wlr_texture->height, flags, attribs); } @@ -118,11 +118,11 @@ static void gles2_texture_destroy(struct wlr_texture *wlr_texture) { PUSH_GLES2_DEBUG; glDeleteTextures(1, &texture->tex); - wlr_egl_destroy_image(texture->egl, texture->image); + wlr_egl_destroy_image(texture->renderer->egl, texture->image); POP_GLES2_DEBUG; - wlr_egl_unset_current(texture->egl); + wlr_egl_unset_current(texture->renderer->egl); free(texture); } @@ -138,9 +138,8 @@ struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer, enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height, const void *data) { struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); - struct wlr_egl *egl = renderer->egl; - wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL); + wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL); const struct wlr_gles2_pixel_format *fmt = get_gles2_format_from_wl(wl_fmt); if (fmt == NULL) { @@ -155,7 +154,7 @@ struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer, return NULL; } wlr_texture_init(&texture->wlr_texture, &texture_impl, width, height); - texture->egl = egl; + texture->renderer = renderer; texture->target = GL_TEXTURE_2D; texture->has_alpha = fmt->has_alpha; texture->wl_format = fmt->wl_format; @@ -174,16 +173,15 @@ struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer, POP_GLES2_DEBUG; - wlr_egl_unset_current(egl); + wlr_egl_unset_current(renderer->egl); return &texture->wlr_texture; } struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, struct wl_resource *resource) { struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); - struct wlr_egl *egl = renderer->egl; - wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL); + wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL); if (!gles2_procs.glEGLImageTargetTexture2DOES) { return NULL; @@ -192,7 +190,7 @@ struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, EGLint fmt; int width, height; bool inverted_y; - EGLImageKHR image = wlr_egl_create_image_from_wl_drm(egl, resource, + EGLImageKHR image = wlr_egl_create_image_from_wl_drm(renderer->egl, resource, &fmt, &width, &height, &inverted_y); if (image == EGL_NO_IMAGE_KHR) { wlr_log(WLR_ERROR, "Failed to create EGL image from wl_drm resource"); @@ -203,11 +201,11 @@ struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, calloc(1, sizeof(struct wlr_gles2_texture)); if (texture == NULL) { wlr_log(WLR_ERROR, "Allocation failed"); - wlr_egl_destroy_image(egl, image); + wlr_egl_destroy_image(renderer->egl, image); return NULL; } wlr_texture_init(&texture->wlr_texture, &texture_impl, width, height); - texture->egl = egl; + texture->renderer = renderer; texture->wl_format = 0xFFFFFFFF; // texture can't be written anyways texture->image = image; @@ -223,7 +221,7 @@ struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, break; default: wlr_log(WLR_ERROR, "Invalid or unsupported EGL buffer format"); - wlr_egl_destroy_image(egl, image); + wlr_egl_destroy_image(renderer->egl, image); free(texture); return NULL; } @@ -240,22 +238,21 @@ struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, POP_GLES2_DEBUG; - wlr_egl_unset_current(egl); + wlr_egl_unset_current(renderer->egl); return &texture->wlr_texture; } struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer, struct wlr_dmabuf_attributes *attribs) { struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); - struct wlr_egl *egl = renderer->egl; - wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL); + wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL); if (!gles2_procs.glEGLImageTargetTexture2DOES) { return NULL; } - if (!egl->exts.image_dmabuf_import_ext) { + if (!renderer->egl->exts.image_dmabuf_import_ext) { wlr_log(WLR_ERROR, "Cannot create DMA-BUF texture: EGL extension " "unavailable"); return NULL; @@ -281,7 +278,7 @@ struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer, } wlr_texture_init(&texture->wlr_texture, &texture_impl, attribs->width, attribs->height); - texture->egl = egl; + texture->renderer = renderer; texture->has_alpha = true; texture->wl_format = 0xFFFFFFFF; // texture can't be written anyways texture->inverted_y = @@ -289,7 +286,7 @@ struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer, bool external_only; texture->image = - wlr_egl_create_image_from_dmabuf(egl, attribs, &external_only); + wlr_egl_create_image_from_dmabuf(renderer->egl, attribs, &external_only); if (texture->image == EGL_NO_IMAGE_KHR) { wlr_log(WLR_ERROR, "Failed to create EGL image from DMA-BUF"); free(texture); @@ -307,7 +304,7 @@ struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer, POP_GLES2_DEBUG; - wlr_egl_unset_current(egl); + wlr_egl_unset_current(renderer->egl); return &texture->wlr_texture; } From 62da61716f28754a2d3b7151348e1ea40bc6cf66 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 28 Jul 2020 13:58:07 +0200 Subject: [PATCH 16/94] render/gles2: make push/pop debug functions take a wlr_renderer --- include/render/gles2.h | 8 ++--- render/gles2/renderer.c | 80 +++++++++++++++++++++-------------------- render/gles2/texture.c | 20 +++++------ 3 files changed, 56 insertions(+), 52 deletions(-) diff --git a/include/render/gles2.h b/include/render/gles2.h index e9c49af9f..a68170bcb 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -115,9 +115,9 @@ struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer, struct wlr_dmabuf_attributes *attribs); -void push_gles2_marker(const char *file, const char *func); -void pop_gles2_marker(void); -#define PUSH_GLES2_DEBUG push_gles2_marker(_WLR_FILENAME, __func__) -#define POP_GLES2_DEBUG pop_gles2_marker() +void push_gles2_debug_(struct wlr_gles2_renderer *renderer, + const char *file, const char *func); +#define push_gles2_debug(renderer) push_gles2_debug_(renderer, _WLR_FILENAME, __func__) +void pop_gles2_debug(struct wlr_gles2_renderer *renderer); #endif diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 17a9caccc..395e11bd4 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -43,7 +43,7 @@ static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width, struct wlr_gles2_renderer *renderer = gles2_get_renderer_in_context(wlr_renderer); - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); glViewport(0, 0, width, height); renderer->viewport_width = width; @@ -56,7 +56,7 @@ static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width, // XXX: maybe we should save output projection and remove some of the need // for users to sling matricies themselves - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); } static void gles2_end(struct wlr_renderer *wlr_renderer) { @@ -66,12 +66,13 @@ static void gles2_end(struct wlr_renderer *wlr_renderer) { static void gles2_clear(struct wlr_renderer *wlr_renderer, const float color[static 4]) { - gles2_get_renderer_in_context(wlr_renderer); + struct wlr_gles2_renderer *renderer = + gles2_get_renderer_in_context(wlr_renderer); - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); glClearColor(color[0], color[1], color[2], color[3]); glClear(GL_COLOR_BUFFER_BIT); - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); } static void gles2_scissor(struct wlr_renderer *wlr_renderer, @@ -79,7 +80,7 @@ static void gles2_scissor(struct wlr_renderer *wlr_renderer, struct wlr_gles2_renderer *renderer = gles2_get_renderer_in_context(wlr_renderer); - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); if (box != NULL) { struct wlr_box gl_box; wlr_box_transform(&gl_box, box, WL_OUTPUT_TRANSFORM_FLIPPED_180, @@ -90,7 +91,7 @@ static void gles2_scissor(struct wlr_renderer *wlr_renderer, } else { glDisable(GL_SCISSOR_TEST); } - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); } static bool gles2_render_subtexture_with_matrix( @@ -130,7 +131,7 @@ static bool gles2_render_subtexture_with_matrix( float transposition[9]; wlr_matrix_transpose(transposition, matrix); - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); glActiveTexture(GL_TEXTURE0); glBindTexture(texture->target, texture->tex); @@ -168,7 +169,7 @@ static bool gles2_render_subtexture_with_matrix( glBindTexture(texture->target, 0); - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); return true; } @@ -182,7 +183,7 @@ static void gles2_render_quad_with_matrix(struct wlr_renderer *wlr_renderer, float transposition[9]; wlr_matrix_transpose(transposition, matrix); - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); glUseProgram(renderer->shaders.quad.program); glUniformMatrix3fv(renderer->shaders.quad.proj, 1, GL_FALSE, transposition); @@ -197,7 +198,7 @@ static void gles2_render_quad_with_matrix(struct wlr_renderer *wlr_renderer, glDisableVertexAttribArray(renderer->shaders.quad.pos_attrib); - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); } static void gles2_render_ellipse_with_matrix(struct wlr_renderer *wlr_renderer, @@ -217,7 +218,7 @@ static void gles2_render_ellipse_with_matrix(struct wlr_renderer *wlr_renderer, 0, 1, // bottom left }; - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); glUseProgram(renderer->shaders.ellipse.program); glUniformMatrix3fv(renderer->shaders.ellipse.proj, 1, GL_FALSE, transposition); @@ -235,7 +236,7 @@ static void gles2_render_ellipse_with_matrix(struct wlr_renderer *wlr_renderer, glDisableVertexAttribArray(renderer->shaders.ellipse.pos_attrib); glDisableVertexAttribArray(renderer->shaders.ellipse.tex_attrib); - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); } static const enum wl_shm_format *gles2_renderer_formats( @@ -288,10 +289,10 @@ static enum wl_shm_format gles2_preferred_read_format( gles2_get_renderer_in_context(wlr_renderer); GLint gl_format = -1, gl_type = -1; - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &gl_format); glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &gl_type); - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); EGLint alpha_size = -1; eglGetConfigAttrib(renderer->egl->display, renderer->egl->config, @@ -328,7 +329,7 @@ static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer, return false; } - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); // Make sure any pending drawing is finished before we try to read it glFinish(); @@ -355,7 +356,7 @@ static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer, } } - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); return glGetError() == GL_NO_ERROR; } @@ -478,13 +479,13 @@ static void gles2_destroy(struct wlr_renderer *wlr_renderer) { wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL); - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); glDeleteProgram(renderer->shaders.quad.program); glDeleteProgram(renderer->shaders.ellipse.program); glDeleteProgram(renderer->shaders.tex_rgba.program); glDeleteProgram(renderer->shaders.tex_rgbx.program); glDeleteProgram(renderer->shaders.tex_ext.program); - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); if (renderer->exts.debug_khr) { glDisable(GL_DEBUG_OUTPUT_KHR); @@ -519,7 +520,8 @@ static const struct wlr_renderer_impl renderer_impl = { .blit_dmabuf = gles2_blit_dmabuf, }; -void push_gles2_marker(const char *file, const char *func) { +void push_gles2_debug_(struct wlr_gles2_renderer *renderer, + const char *file, const char *func) { if (!gles2_procs.glPushDebugGroupKHR) { return; } @@ -530,7 +532,7 @@ void push_gles2_marker(const char *file, const char *func) { gles2_procs.glPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, 1, -1, str); } -void pop_gles2_marker(void) { +void pop_gles2_debug(struct wlr_gles2_renderer *renderer) { if (gles2_procs.glPopDebugGroupKHR) { gles2_procs.glPopDebugGroupKHR(); } @@ -556,8 +558,9 @@ static void gles2_log(GLenum src, GLenum type, GLuint id, GLenum severity, _wlr_log(gles2_log_importance_to_wlr(type), "[GLES2] %s", msg); } -static GLuint compile_shader(GLuint type, const GLchar *src) { - PUSH_GLES2_DEBUG; +static GLuint compile_shader(struct wlr_gles2_renderer *renderer, + GLuint type, const GLchar *src) { + push_gles2_debug(renderer); GLuint shader = glCreateShader(type); glShaderSource(shader, 1, &src, NULL); @@ -570,19 +573,20 @@ static GLuint compile_shader(GLuint type, const GLchar *src) { shader = 0; } - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); return shader; } -static GLuint link_program(const GLchar *vert_src, const GLchar *frag_src) { - PUSH_GLES2_DEBUG; +static GLuint link_program(struct wlr_gles2_renderer *renderer, + const GLchar *vert_src, const GLchar *frag_src) { + push_gles2_debug(renderer); - GLuint vert = compile_shader(GL_VERTEX_SHADER, vert_src); + GLuint vert = compile_shader(renderer, GL_VERTEX_SHADER, vert_src); if (!vert) { goto error; } - GLuint frag = compile_shader(GL_FRAGMENT_SHADER, frag_src); + GLuint frag = compile_shader(renderer, GL_FRAGMENT_SHADER, frag_src); if (!frag) { glDeleteShader(vert); goto error; @@ -605,11 +609,11 @@ static GLuint link_program(const GLchar *vert_src, const GLchar *frag_src) { goto error; } - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); return prog; error: - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); return 0; } @@ -715,11 +719,11 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { GL_DEBUG_TYPE_PUSH_GROUP_KHR, GL_DONT_CARE, 0, NULL, GL_FALSE); } - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); GLuint prog; renderer->shaders.quad.program = prog = - link_program(quad_vertex_src, quad_fragment_src); + link_program(renderer, quad_vertex_src, quad_fragment_src); if (!renderer->shaders.quad.program) { goto error; } @@ -728,7 +732,7 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { renderer->shaders.quad.pos_attrib = glGetAttribLocation(prog, "pos"); renderer->shaders.ellipse.program = prog = - link_program(quad_vertex_src, ellipse_fragment_src); + link_program(renderer, quad_vertex_src, ellipse_fragment_src); if (!renderer->shaders.ellipse.program) { goto error; } @@ -738,7 +742,7 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { renderer->shaders.ellipse.tex_attrib = glGetAttribLocation(prog, "texcoord"); renderer->shaders.tex_rgba.program = prog = - link_program(tex_vertex_src, tex_fragment_src_rgba); + link_program(renderer, tex_vertex_src, tex_fragment_src_rgba); if (!renderer->shaders.tex_rgba.program) { goto error; } @@ -750,7 +754,7 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { renderer->shaders.tex_rgba.tex_attrib = glGetAttribLocation(prog, "texcoord"); renderer->shaders.tex_rgbx.program = prog = - link_program(tex_vertex_src, tex_fragment_src_rgbx); + link_program(renderer, tex_vertex_src, tex_fragment_src_rgbx); if (!renderer->shaders.tex_rgbx.program) { goto error; } @@ -763,7 +767,7 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { if (renderer->exts.egl_image_external_oes) { renderer->shaders.tex_ext.program = prog = - link_program(tex_vertex_src, tex_fragment_src_external); + link_program(renderer, tex_vertex_src, tex_fragment_src_external); if (!renderer->shaders.tex_ext.program) { goto error; } @@ -775,7 +779,7 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { renderer->shaders.tex_ext.tex_attrib = glGetAttribLocation(prog, "texcoord"); } - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); wlr_egl_unset_current(renderer->egl); @@ -788,7 +792,7 @@ error: glDeleteProgram(renderer->shaders.tex_rgbx.program); glDeleteProgram(renderer->shaders.tex_ext.program); - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); if (renderer->exts.debug_khr) { glDisable(GL_DEBUG_OUTPUT_KHR); diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 72b69204d..5375e7962 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -56,7 +56,7 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture, assert(fmt); // TODO: what if the unpack subimage extension isn't supported? - PUSH_GLES2_DEBUG; + push_gles2_debug(texture->renderer); glBindTexture(GL_TEXTURE_2D, texture->tex); @@ -73,7 +73,7 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture, glBindTexture(GL_TEXTURE_2D, 0); - POP_GLES2_DEBUG; + pop_gles2_debug(texture->renderer); wlr_egl_unset_current(texture->renderer->egl); return true; @@ -115,12 +115,12 @@ static void gles2_texture_destroy(struct wlr_texture *wlr_texture) { struct wlr_gles2_texture *texture = get_gles2_texture_in_context(wlr_texture); - PUSH_GLES2_DEBUG; + push_gles2_debug(texture->renderer); glDeleteTextures(1, &texture->tex); wlr_egl_destroy_image(texture->renderer->egl, texture->image); - POP_GLES2_DEBUG; + pop_gles2_debug(texture->renderer); wlr_egl_unset_current(texture->renderer->egl); @@ -159,7 +159,7 @@ struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer, texture->has_alpha = fmt->has_alpha; texture->wl_format = fmt->wl_format; - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); glGenTextures(1, &texture->tex); glBindTexture(GL_TEXTURE_2D, texture->tex); @@ -171,7 +171,7 @@ struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer, glBindTexture(GL_TEXTURE_2D, 0); - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); wlr_egl_unset_current(renderer->egl); return &texture->wlr_texture; @@ -228,7 +228,7 @@ struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, texture->target = GL_TEXTURE_EXTERNAL_OES; - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); glGenTextures(1, &texture->tex); glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture->tex); @@ -236,7 +236,7 @@ struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, texture->image); glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0); - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); wlr_egl_unset_current(renderer->egl); return &texture->wlr_texture; @@ -295,14 +295,14 @@ struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer, texture->target = external_only ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D; - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); glGenTextures(1, &texture->tex); glBindTexture(texture->target, texture->tex); gles2_procs.glEGLImageTargetTexture2DOES(texture->target, texture->image); glBindTexture(texture->target, 0); - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); wlr_egl_unset_current(renderer->egl); return &texture->wlr_texture; From 1dbcfdaf81778fcd4635c6ecd62b89477f69f0d8 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 28 Jul 2020 14:02:08 +0200 Subject: [PATCH 17/94] render/gles2: remove gles2_procs Move the global into wlr_gles2_renderer. This removes global state and allows us to have multiple renderers with different GL loaders. --- include/render/gles2.h | 20 +++++++++----------- render/gles2/renderer.c | 40 +++++++++++++++++++--------------------- render/gles2/texture.c | 8 ++++---- 3 files changed, 32 insertions(+), 36 deletions(-) diff --git a/include/render/gles2.h b/include/render/gles2.h index a68170bcb..a64aa77ce 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -14,17 +14,6 @@ #include #include -struct wlr_gles2_procs { - PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES; - PFNGLDEBUGMESSAGECALLBACKKHRPROC glDebugMessageCallbackKHR; - PFNGLDEBUGMESSAGECONTROLKHRPROC glDebugMessageControlKHR; - PFNGLPOPDEBUGGROUPKHRPROC glPopDebugGroupKHR; - PFNGLPUSHDEBUGGROUPKHRPROC glPushDebugGroupKHR; - PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES; -}; - -extern struct wlr_gles2_procs gles2_procs; - struct wlr_gles2_pixel_format { enum wl_shm_format wl_format; GLint gl_format, gl_type; @@ -55,6 +44,15 @@ struct wlr_gles2_renderer { bool egl_image_oes; } exts; + struct { + PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES; + PFNGLDEBUGMESSAGECALLBACKKHRPROC glDebugMessageCallbackKHR; + PFNGLDEBUGMESSAGECONTROLKHRPROC glDebugMessageControlKHR; + PFNGLPOPDEBUGGROUPKHRPROC glPopDebugGroupKHR; + PFNGLPUSHDEBUGGROUPKHRPROC glPushDebugGroupKHR; + PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES; + } procs; + struct { struct { GLuint program; diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 395e11bd4..9ec87293f 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -21,8 +21,6 @@ static const GLfloat verts[] = { 0, 1, // bottom left }; -struct wlr_gles2_procs gles2_procs = {0}; - static const struct wlr_renderer_impl renderer_impl; struct wlr_gles2_renderer *gles2_get_renderer( @@ -364,7 +362,8 @@ static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer, static bool gles2_blit_dmabuf(struct wlr_renderer *wlr_renderer, struct wlr_dmabuf_attributes *dst_attr, struct wlr_dmabuf_attributes *src_attr) { - if (!gles2_procs.glEGLImageTargetRenderbufferStorageOES) { + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + if (!renderer->procs.glEGLImageTargetRenderbufferStorageOES) { return false; } @@ -389,15 +388,14 @@ static bool gles2_blit_dmabuf(struct wlr_renderer *wlr_renderer, // texture. gles2_src_tex->inverted_y = !(src_inverted_y ^ dst_inverted_y); - struct wlr_egl *egl = wlr_gles2_renderer_get_egl(wlr_renderer); - if (!wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL)) { + if (!wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL)) { goto texture_destroy_out; } // TODO: The imported buffer should be checked with // eglQueryDmaBufModifiersEXT to see if it may be modified. bool external_only = false; - EGLImageKHR image = wlr_egl_create_image_from_dmabuf(egl, dst_attr, + EGLImageKHR image = wlr_egl_create_image_from_dmabuf(renderer->egl, dst_attr, &external_only); if (image == EGL_NO_IMAGE_KHR) { goto texture_destroy_out; @@ -406,7 +404,7 @@ static bool gles2_blit_dmabuf(struct wlr_renderer *wlr_renderer, GLuint rbo = 0; glGenRenderbuffers(1, &rbo); glBindRenderbuffer(GL_RENDERBUFFER, rbo); - gles2_procs.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, + renderer->procs.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, image); glBindRenderbuffer(GL_RENDERBUFFER, 0); @@ -435,7 +433,7 @@ out: glBindFramebuffer(GL_FRAMEBUFFER, 0); glDeleteFramebuffers(1, &fbo); glDeleteRenderbuffers(1, &rbo); - wlr_egl_destroy_image(egl, image); + wlr_egl_destroy_image(renderer->egl, image); texture_destroy_out: wlr_texture_destroy(src_tex); restore_context_out: @@ -489,7 +487,7 @@ static void gles2_destroy(struct wlr_renderer *wlr_renderer) { if (renderer->exts.debug_khr) { glDisable(GL_DEBUG_OUTPUT_KHR); - gles2_procs.glDebugMessageCallbackKHR(NULL, NULL); + renderer->procs.glDebugMessageCallbackKHR(NULL, NULL); } wlr_egl_unset_current(renderer->egl); @@ -522,19 +520,19 @@ static const struct wlr_renderer_impl renderer_impl = { void push_gles2_debug_(struct wlr_gles2_renderer *renderer, const char *file, const char *func) { - if (!gles2_procs.glPushDebugGroupKHR) { + if (!renderer->procs.glPushDebugGroupKHR) { return; } int len = snprintf(NULL, 0, "%s:%s", file, func) + 1; char str[len]; snprintf(str, len, "%s:%s", file, func); - gles2_procs.glPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, 1, -1, str); + renderer->procs.glPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, 1, -1, str); } void pop_gles2_debug(struct wlr_gles2_renderer *renderer) { - if (gles2_procs.glPopDebugGroupKHR) { - gles2_procs.glPopDebugGroupKHR(); + if (renderer->procs.glPopDebugGroupKHR) { + renderer->procs.glPopDebugGroupKHR(); } } @@ -689,33 +687,33 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { if (check_gl_ext(exts_str, "GL_KHR_debug")) { renderer->exts.debug_khr = true; - load_gl_proc(&gles2_procs.glDebugMessageCallbackKHR, + load_gl_proc(&renderer->procs.glDebugMessageCallbackKHR, "glDebugMessageCallbackKHR"); - load_gl_proc(&gles2_procs.glDebugMessageControlKHR, + load_gl_proc(&renderer->procs.glDebugMessageControlKHR, "glDebugMessageControlKHR"); } if (check_gl_ext(exts_str, "GL_OES_EGL_image_external")) { renderer->exts.egl_image_external_oes = true; - load_gl_proc(&gles2_procs.glEGLImageTargetTexture2DOES, + load_gl_proc(&renderer->procs.glEGLImageTargetTexture2DOES, "glEGLImageTargetTexture2DOES"); } if (check_gl_ext(exts_str, "GL_OES_EGL_image")) { renderer->exts.egl_image_oes = true; - load_gl_proc(&gles2_procs.glEGLImageTargetRenderbufferStorageOES, + load_gl_proc(&renderer->procs.glEGLImageTargetRenderbufferStorageOES, "glEGLImageTargetRenderbufferStorageOES"); } if (renderer->exts.debug_khr) { glEnable(GL_DEBUG_OUTPUT_KHR); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR); - gles2_procs.glDebugMessageCallbackKHR(gles2_log, NULL); + renderer->procs.glDebugMessageCallbackKHR(gles2_log, NULL); // Silence unwanted message types - gles2_procs.glDebugMessageControlKHR(GL_DONT_CARE, + renderer->procs.glDebugMessageControlKHR(GL_DONT_CARE, GL_DEBUG_TYPE_POP_GROUP_KHR, GL_DONT_CARE, 0, NULL, GL_FALSE); - gles2_procs.glDebugMessageControlKHR(GL_DONT_CARE, + renderer->procs.glDebugMessageControlKHR(GL_DONT_CARE, GL_DEBUG_TYPE_PUSH_GROUP_KHR, GL_DONT_CARE, 0, NULL, GL_FALSE); } @@ -796,7 +794,7 @@ error: if (renderer->exts.debug_khr) { glDisable(GL_DEBUG_OUTPUT_KHR); - gles2_procs.glDebugMessageCallbackKHR(NULL, NULL); + renderer->procs.glDebugMessageCallbackKHR(NULL, NULL); } wlr_egl_unset_current(renderer->egl); diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 5375e7962..179bfd891 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -183,7 +183,7 @@ struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL); - if (!gles2_procs.glEGLImageTargetTexture2DOES) { + if (!renderer->procs.glEGLImageTargetTexture2DOES) { return NULL; } @@ -232,7 +232,7 @@ struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, glGenTextures(1, &texture->tex); glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture->tex); - gles2_procs.glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, + renderer->procs.glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, texture->image); glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0); @@ -248,7 +248,7 @@ struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer, wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL); - if (!gles2_procs.glEGLImageTargetTexture2DOES) { + if (!renderer->procs.glEGLImageTargetTexture2DOES) { return NULL; } @@ -299,7 +299,7 @@ struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer, glGenTextures(1, &texture->tex); glBindTexture(texture->target, texture->tex); - gles2_procs.glEGLImageTargetTexture2DOES(texture->target, texture->image); + renderer->procs.glEGLImageTargetTexture2DOES(texture->target, texture->image); glBindTexture(texture->target, 0); pop_gles2_debug(renderer); From 74f7be728715e164d5b7f174491797ce31206c8d Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Sun, 19 Jul 2020 14:57:10 +0200 Subject: [PATCH 18/94] xwayland: do not allow apps to change focus after wlroots request --- include/xwayland/xwm.h | 1 + xwayland/xwm.c | 22 ++++++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h index a3e7132d9..362b4cef0 100644 --- a/include/xwayland/xwm.h +++ b/include/xwayland/xwm.h @@ -128,6 +128,7 @@ struct wlr_xwm { #if WLR_HAS_XCB_ERRORS xcb_errors_context_t *errors_context; #endif + unsigned int last_focus_seq; struct wl_listener compositor_new_surface; struct wl_listener compositor_destroy; diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 88f4c3c5f..87b9edc13 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -275,8 +275,9 @@ static void xwm_set_focus_window(struct wlr_xwm *xwm, } else { xwm_send_wm_message(xsurface, &message_data, XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT); - xcb_set_input_focus(xwm->xcb_conn, XCB_INPUT_FOCUS_POINTER_ROOT, - xsurface->window_id, XCB_CURRENT_TIME); + xcb_void_cookie_t cookie = xcb_set_input_focus(xwm->xcb_conn, + XCB_INPUT_FOCUS_POINTER_ROOT, xsurface->window_id, XCB_CURRENT_TIME); + xwm->last_focus_seq = cookie.sequence; } uint32_t values[1]; @@ -1293,6 +1294,16 @@ static void xwm_handle_client_message(struct wlr_xwm *xwm, } } +static bool validate_focus_serial(uint16_t last_focus_seq, uint16_t event_seq) { + uint16_t rev_dist = event_seq - last_focus_seq; + if (rev_dist >= UINT16_MAX / 2) { + // Probably overflow or too old + return false; + } + + return true; +} + static void xwm_handle_focus_in(struct wlr_xwm *xwm, xcb_focus_in_event_t *ev) { // Do not interfere with grabs @@ -1311,10 +1322,13 @@ static void xwm_handle_focus_in(struct wlr_xwm *xwm, // Note: Some applications rely on being able to change focus, for ex. Steam: // https://github.com/swaywm/sway/issues/1865 // Because of that, we allow changing focus between surfaces belonging to the - // same application. + // same application. We must be careful to ignore requests that are too old + // though, because otherwise it may lead to race conditions: + // https://github.com/swaywm/wlroots/issues/2324 struct wlr_xwayland_surface *requested_focus = lookup_surface(xwm, ev->event); if (xwm->focus_surface && requested_focus && - requested_focus->pid == xwm->focus_surface->pid) { + requested_focus->pid == xwm->focus_surface->pid && + validate_focus_serial(xwm->last_focus_seq, ev->sequence)) { xwm_set_focus_window(xwm, requested_focus); } else { xwm_set_focus_window(xwm, xwm->focus_surface); From aaf490d794bd077330c306face305f4a87de5809 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Thu, 30 Jul 2020 23:23:18 -0500 Subject: [PATCH 19/94] drm: fix uninitialized read get_drm_prop_blob does not set path_len if it returns NULL. Check the return value before path_len to avoid reading uninitialized memory. (Granted, this doesn't change the logic at all, but it does make Valgrind a bit happier.) --- backend/drm/drm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 7ecc28d39..dafe807b3 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1398,7 +1398,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { bool is_mst = false; char *path = get_drm_prop_blob(drm->fd, wlr_conn->id, wlr_conn->props.path, &path_len); - if (path_len > 4 && path && strncmp(path, "mst:", 4) == 0) { + if (path && path_len > 4 && strncmp(path, "mst:", 4) == 0) { is_mst = true; } free(path); From 0032954c75050276375a151389a25d4717ef1cd5 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Mon, 3 Aug 2020 11:48:27 +0200 Subject: [PATCH 20/94] make sure to fail setting gamma on disabled outputs --- types/wlr_gamma_control_v1.c | 1 + types/wlr_output.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/types/wlr_gamma_control_v1.c b/types/wlr_gamma_control_v1.c index 591c6aa3a..48356ee11 100644 --- a/types/wlr_gamma_control_v1.c +++ b/types/wlr_gamma_control_v1.c @@ -108,6 +108,7 @@ static void gamma_control_handle_set_gamma(struct wl_client *client, wlr_output_set_gamma(gamma_control->output, ramp_size, r, g, b); if (!wlr_output_test(gamma_control->output)) { gamma_control_send_failed(gamma_control); + wlr_output_rollback(gamma_control->output); goto error_table; } free(table); diff --git a/types/wlr_output.c b/types/wlr_output.c index ce05f97b9..9d02ec3c6 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -551,6 +551,10 @@ static bool output_basic_test(struct wlr_output *output) { wlr_log(WLR_DEBUG, "Tried to enable adaptive sync on a disabled output"); return false; } + if (!enabled && output->pending.committed & WLR_OUTPUT_STATE_GAMMA_LUT) { + wlr_log(WLR_DEBUG, "Tried to set the gamma lut on a disabled output"); + return false; + } return true; } From 30226eb1fbf2da0f1d6ff6e0c230541e95dfb46b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 5 Aug 2020 18:00:29 +0200 Subject: [PATCH 21/94] gamma-control-v1: fix use-after-free in gamma_control_handle_set_gamma gamma_control_send_failed destroys gamma_control. --- types/wlr_gamma_control_v1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/wlr_gamma_control_v1.c b/types/wlr_gamma_control_v1.c index 48356ee11..f96c84aaa 100644 --- a/types/wlr_gamma_control_v1.c +++ b/types/wlr_gamma_control_v1.c @@ -107,8 +107,8 @@ static void gamma_control_handle_set_gamma(struct wl_client *client, wlr_output_set_gamma(gamma_control->output, ramp_size, r, g, b); if (!wlr_output_test(gamma_control->output)) { - gamma_control_send_failed(gamma_control); wlr_output_rollback(gamma_control->output); + gamma_control_send_failed(gamma_control); goto error_table; } free(table); From f0d03fb8921b79c776d0fe9abedced78302c3c06 Mon Sep 17 00:00:00 2001 From: Ryan Walklin Date: Thu, 25 Jun 2020 22:56:56 +1200 Subject: [PATCH 22/94] Implement logind session SetType method to change session type to wayland --- backend/session/logind.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/backend/session/logind.c b/backend/session/logind.c index 00babcae0..317b179f9 100644 --- a/backend/session/logind.c +++ b/backend/session/logind.c @@ -241,6 +241,24 @@ static bool take_control(struct logind_session *session) { return ret >= 0; } +static bool set_type(struct logind_session *session) { + int ret; + sd_bus_message *msg = NULL; + sd_bus_error error = SD_BUS_ERROR_NULL; + + ret = sd_bus_call_method(session->bus, "org.freedesktop.login1", + session->path, "org.freedesktop.login1.Session", "SetType", + &error, &msg, "s", "wayland"); + if (ret < 0) { + wlr_log(WLR_ERROR, "Failed to set session type for session: %s", + error.message); + } + + sd_bus_error_free(&error); + sd_bus_message_unref(msg); + return ret >= 0; +} + static void release_control(struct logind_session *session) { int ret; sd_bus_message *msg = NULL; @@ -819,6 +837,11 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) { } } + if (!set_type(session)) { + // Not fatal + wlr_log(WLR_INFO, "Failed to set logind session type to wayland"); + } + wlr_log(WLR_INFO, "Successfully loaded logind session"); session->base.impl = &session_logind; From e81d2086c055c697e2f3138529deaba112281f93 Mon Sep 17 00:00:00 2001 From: Ryan Walklin Date: Thu, 25 Jun 2020 23:43:28 +1200 Subject: [PATCH 23/94] Also set XDG_SESSION_TYPE --- backend/session/logind.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/backend/session/logind.c b/backend/session/logind.c index 317b179f9..4f03e523c 100644 --- a/backend/session/logind.c +++ b/backend/session/logind.c @@ -250,12 +250,18 @@ static bool set_type(struct logind_session *session) { session->path, "org.freedesktop.login1.Session", "SetType", &error, &msg, "s", "wayland"); if (ret < 0) { - wlr_log(WLR_ERROR, "Failed to set session type for session: %s", + wlr_log(WLR_ERROR, "Failed to set logind session type for session: %s", error.message); } sd_bus_error_free(&error); sd_bus_message_unref(msg); + + ret = setenv("XDG_SESSION_TYPE", "wayland", 1); + if (ret < 0) { + wlr_log(WLR_ERROR, "Failed to set XDG_SESSION_TYPE for session"); + } + return ret >= 0; } From 7e990a29918968a6f418f3055fefa1d633b3016f Mon Sep 17 00:00:00 2001 From: Ryan Walklin Date: Fri, 26 Jun 2020 08:55:04 +1200 Subject: [PATCH 24/94] Don't set XDG_SESSION_TYPE unless logind SetType succeeds --- backend/session/logind.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/backend/session/logind.c b/backend/session/logind.c index 4f03e523c..c5d0cb294 100644 --- a/backend/session/logind.c +++ b/backend/session/logind.c @@ -257,12 +257,16 @@ static bool set_type(struct logind_session *session) { sd_bus_error_free(&error); sd_bus_message_unref(msg); + if (ret < 0) { + return false; + } + ret = setenv("XDG_SESSION_TYPE", "wayland", 1); if (ret < 0) { wlr_log(WLR_ERROR, "Failed to set XDG_SESSION_TYPE for session"); + return false; } - - return ret >= 0; + return true; } static void release_control(struct logind_session *session) { From c236f60bb6206020396e608d6032c116fe028106 Mon Sep 17 00:00:00 2001 From: Daniel De Graaf Date: Sun, 9 Aug 2020 13:31:53 -0400 Subject: [PATCH 25/94] wlr_virtual_keyboard: fix fd leak --- types/wlr_virtual_keyboard_v1.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/types/wlr_virtual_keyboard_v1.c b/types/wlr_virtual_keyboard_v1.c index 7ae030eec..25c94545c 100644 --- a/types/wlr_virtual_keyboard_v1.c +++ b/types/wlr_virtual_keyboard_v1.c @@ -1,6 +1,7 @@ #define _POSIX_C_SOURCE 199309L #include #include +#include #include #include #include @@ -72,12 +73,14 @@ static void virtual_keyboard_keymap(struct wl_client *client, keyboard->has_keymap = true; xkb_keymap_unref(keymap); xkb_context_unref(context); + close(fd); return; keymap_fail: fd_fail: xkb_context_unref(context); context_fail: wl_client_post_no_memory(client); + close(fd); } static void virtual_keyboard_key(struct wl_client *client, From 801c7670b765aae8dbd72c87e72d0ff9ff8f6cfb Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 14 Aug 2020 10:31:27 +0200 Subject: [PATCH 26/94] examples/simple: use wlr_output_preferred_mode --- examples/simple.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/simple.c b/examples/simple.c index 8540892d6..965e97be3 100644 --- a/examples/simple.c +++ b/examples/simple.c @@ -80,9 +80,9 @@ static void new_output_notify(struct wl_listener *listener, void *data) { wl_container_of(listener, sample, new_output); struct sample_output *sample_output = calloc(1, sizeof(struct sample_output)); - if (!wl_list_empty(&output->modes)) { - struct wlr_output_mode *mode = - wl_container_of(output->modes.prev, mode, link); + + struct wlr_output_mode *mode = wlr_output_preferred_mode(output); + if (mode != NULL) { wlr_output_set_mode(output, mode); } sample_output->output = output; From 379835c42f182aa2c8fa814dea20a325361f8bdf Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 14 Aug 2020 10:31:44 +0200 Subject: [PATCH 27/94] examples/simple: use wlr_renderer instead of GL --- examples/simple.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/examples/simple.c b/examples/simple.c index 965e97be3..e3af1a118 100644 --- a/examples/simple.c +++ b/examples/simple.c @@ -1,5 +1,4 @@ #define _POSIX_C_SOURCE 200112L -#include #include #include #include @@ -8,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -18,7 +18,7 @@ struct sample_state { struct wl_listener new_output; struct wl_listener new_input; struct timespec last_frame; - float color[3]; + float color[4]; int dec; }; @@ -40,6 +40,8 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { struct sample_output *sample_output = wl_container_of(listener, sample_output, frame); struct sample_state *sample = sample_output->sample; + struct wlr_output *wlr_output = sample_output->output; + struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -56,12 +58,15 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { sample->dec = inc; } - wlr_output_attach_render(sample_output->output, NULL); + wlr_output_attach_render(wlr_output, NULL); - glClearColor(sample->color[0], sample->color[1], sample->color[2], 1.0); - glClear(GL_COLOR_BUFFER_BIT); + struct wlr_renderer *renderer = + wlr_backend_get_renderer(wlr_output->backend); + wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); + wlr_renderer_clear(renderer, sample->color); + wlr_renderer_end(renderer); - wlr_output_commit(sample_output->output); + wlr_output_commit(wlr_output); sample->last_frame = now; } @@ -162,7 +167,7 @@ int main(void) { wlr_log_init(WLR_DEBUG, NULL); struct wl_display *display = wl_display_create(); struct sample_state state = { - .color = { 1.0, 0.0, 0.0 }, + .color = { 1.0, 0.0, 0.0, 1.0 }, .dec = 0, .last_frame = { 0 }, .display = display From 9feeb2738dfc5a2b07a817938cef9d553d0a26ee Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Mon, 17 Aug 2020 11:33:57 +0200 Subject: [PATCH 28/94] backend/wayland: destroy relative pointer when output is disconnected Fixes #2243 Fixes #2106 --- backend/wayland/seat.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index 1fcb93e5f..d19744d82 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -473,6 +473,9 @@ static void pointer_handle_output_destroy(struct wl_listener *listener, void *data) { struct wlr_wl_pointer *pointer = wl_container_of(listener, pointer, output_destroy); + if (pointer->relative_pointer) { + zwp_relative_pointer_v1_destroy(pointer->relative_pointer); + } wlr_input_device_destroy(&pointer->input_device->wlr_input_device); } From bad1e9afa8ea7d8927c8b4df83d3f277379dd54e Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 25 Jul 2020 21:53:06 +0200 Subject: [PATCH 29/94] session: Add libseat backend --- .builds/alpine.yml | 2 +- .builds/archlinux.yml | 1 + .builds/freebsd.yml | 1 + backend/session/direct.c | 3 + backend/session/libseat.c | 190 ++++++++++++++++++++++++++++++ backend/session/logind.c | 5 + backend/session/meson.build | 9 ++ backend/session/noop.c | 3 + backend/session/session.c | 24 +++- include/backend/session/session.h | 8 ++ include/wlr/config.h.in | 2 + meson.build | 2 + meson_options.txt | 1 + 13 files changed, 244 insertions(+), 7 deletions(-) create mode 100644 backend/session/libseat.c create mode 100644 include/backend/session/session.h diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 13221d258..402f72f65 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -16,7 +16,7 @@ sources: tasks: - setup: | cd wlroots - meson build -Dauto_features=enabled -Dlogind=disabled -Dxcb-errors=disabled + meson build -Dauto_features=enabled -Dlogind=disabled -Dlibseat=disabled -Dxcb-errors=disabled - build: | cd wlroots ninja -C build diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index b3b1a3c05..9cf2f84fc 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -12,6 +12,7 @@ packages: - xcb-util-errors - xcb-util-image - xcb-util-wm + - seatd sources: - https://github.com/swaywm/wlroots tasks: diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index a0dfc442e..74553f7b1 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -18,6 +18,7 @@ packages: - x11/pixman - x11/xcb-util-errors - x11/xcb-util-wm +- sysutils/seatd sources: - https://github.com/swaywm/wlroots tasks: diff --git a/backend/session/direct.c b/backend/session/direct.c index 4ffd711d7..f9041070b 100644 --- a/backend/session/direct.c +++ b/backend/session/direct.c @@ -18,6 +18,7 @@ #include #include #include "backend/session/direct-ipc.h" +#include "backend/session/session.h" #include "util/signal.h" enum { DRM_MAJOR = 226 }; @@ -246,6 +247,7 @@ static struct wlr_session *direct_session_create(struct wl_display *disp) { return NULL; } + session_init(&session->base); session->sock = direct_ipc_init(&session->child); if (session->sock == -1) { goto error_session; @@ -267,6 +269,7 @@ static struct wlr_session *direct_session_create(struct wl_display *disp) { snprintf(session->base.seat, sizeof(session->base.seat), "%s", seat); session->base.impl = &session_direct; + session->base.active = true; wlr_log(WLR_INFO, "Successfully loaded direct session"); return &session->base; diff --git a/backend/session/libseat.c b/backend/session/libseat.c new file mode 100644 index 000000000..77226204f --- /dev/null +++ b/backend/session/libseat.c @@ -0,0 +1,190 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "backend/session/session.h" +#include "util/signal.h" + +#include + +const struct session_impl session_libseat; + +struct libseat_device { + struct wl_list link; + int fd; + int device_id; +}; + +struct libseat_session { + struct wlr_session base; + + struct libseat *seat; + struct wl_event_source *event; + struct wl_list devices; +}; + +static void handle_enable_seat(struct libseat *seat, void *data) { + struct libseat_session *session = data; + session->base.active = true; + wlr_signal_emit_safe(&session->base.session_signal, session); +} + +static void handle_disable_seat(struct libseat *seat, void *data) { + struct libseat_session *session = data; + session->base.active = false; + wlr_signal_emit_safe(&session->base.session_signal, session); + libseat_disable_seat(session->seat); +} + +static int libseat_event(int fd, uint32_t mask, void *data) { + struct libseat *seat = data; + libseat_dispatch(seat, 0); + return 1; +} + +static struct libseat_seat_listener seat_listener = { + .enable_seat = handle_enable_seat, + .disable_seat = handle_disable_seat, +}; + +static struct libseat_session *libseat_session_from_session( + struct wlr_session *base) { + assert(base->impl == &session_libseat); + return (struct libseat_session *)base; +} + +static struct wlr_session *libseat_session_create(struct wl_display *disp) { + struct libseat_session *session = calloc(1, sizeof(*session)); + if (!session) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return NULL; + } + + session_init(&session->base); + wl_list_init(&session->devices); + + session->seat = libseat_open_seat(&seat_listener, session); + if (session->seat == NULL) { + wlr_log_errno(WLR_ERROR, "Unable to create seat"); + goto error; + } + + const char *seat_name = libseat_seat_name(session->seat); + if (seat_name == NULL) { + wlr_log_errno(WLR_ERROR, "Unable to get seat info"); + goto error; + } + snprintf(session->base.seat, sizeof(session->base.seat), "%s", seat_name); + + struct wl_event_loop *event_loop = wl_display_get_event_loop(disp); + session->event = wl_event_loop_add_fd(event_loop, libseat_get_fd(session->seat), + WL_EVENT_READABLE, libseat_event, session->seat); + if (session->event == NULL) { + wlr_log(WLR_ERROR, "Failed to create libseat event source"); + goto error; + } + + // We may have received enable_seat immediately after the open_seat result, + // so, dispatch once without timeout to speed up activation. + if (libseat_dispatch(session->seat, 0) == -1) { + wlr_log_errno(WLR_ERROR, "libseat dispatch failed"); + goto error; + } + + wlr_log(WLR_INFO, "Successfully loaded libseat session"); + session->base.impl = &session_libseat; + return &session->base; + +error: + if (session->seat != NULL) { + libseat_close_seat(session->seat); + } + if (session->event != NULL) { + wl_event_source_remove(session->event); + } + free(session); + return NULL; +} + +static void libseat_session_destroy(struct wlr_session *base) { + struct libseat_session *session = libseat_session_from_session(base); + + libseat_close_seat(session->seat); + wl_event_source_remove(session->event); + free(session); +} + +static struct libseat_device *find_device_by_fd(struct libseat_session *session, int fd) { + struct libseat_device *dev; + wl_list_for_each(dev, &session->devices, link) { + if (dev->fd == fd) { + return dev; + } + } + return NULL; +} + +static int libseat_session_open_device(struct wlr_session *base, const char *path) { + struct libseat_session *session = libseat_session_from_session(base); + + int fd; + int device_id = libseat_open_device(session->seat, path, &fd); + if (device_id == -1) { + wlr_log_errno(WLR_ERROR, "Failed to open device '%s'", path); + return -1; + } + + struct libseat_device *dev = calloc(1, sizeof(struct libseat_device)); + if (dev == NULL) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + libseat_close_device(session->seat, device_id); + return -1; + } + + dev->fd = fd; + dev->device_id = device_id; + wl_list_insert(&session->devices, &dev->link); + + return fd; +} + +static void libseat_session_close_device(struct wlr_session *base, int fd) { + struct libseat_session *session = libseat_session_from_session(base); + + struct libseat_device *dev = find_device_by_fd(session, fd); + if (dev == NULL) { + wlr_log(WLR_ERROR, "No device with fd %d found", fd); + close(fd); + return; + } + + if (libseat_close_device(session->seat, dev->device_id) == -1) { + wlr_log_errno(WLR_ERROR, "Failed to close device %d", dev->device_id); + } + + wl_list_remove(&dev->link); + free(dev); + close(fd); +} + +static bool libseat_change_vt(struct wlr_session *base, unsigned vt) { + struct libseat_session *session = libseat_session_from_session(base); + return libseat_switch_session(session->seat, vt); +} + +const struct session_impl session_libseat = { + .create = libseat_session_create, + .destroy = libseat_session_destroy, + .open = libseat_session_open_device, + .close = libseat_session_close_device, + .change_vt = libseat_change_vt, +}; diff --git a/backend/session/logind.c b/backend/session/logind.c index c5d0cb294..a460cbe26 100644 --- a/backend/session/logind.c +++ b/backend/session/logind.c @@ -13,6 +13,7 @@ #include #include #include +#include "backend/session/session.h" #include "util/signal.h" #if WLR_HAS_SYSTEMD @@ -778,6 +779,8 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) { return NULL; } + session_init(&session->base); + if (!get_display_session(&session->id)) { goto error; } @@ -855,6 +858,8 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) { wlr_log(WLR_INFO, "Successfully loaded logind session"); session->base.impl = &session_logind; + session->base.active = true; + return &session->base; error_bus: diff --git a/backend/session/meson.build b/backend/session/meson.build index 81ff6d85c..4c83685e9 100644 --- a/backend/session/meson.build +++ b/backend/session/meson.build @@ -62,3 +62,12 @@ if logind_found wlr_files += files('logind.c') wlr_deps += logind endif + +# libseat + +libseat = dependency('libseat', required: get_option('libseat')) +if libseat.found() + wlr_files += files('libseat.c') + wlr_deps += libseat + conf_data.set10('WLR_HAS_LIBSEAT', true) +endif diff --git a/backend/session/noop.c b/backend/session/noop.c index 0e13a1778..3f293775f 100644 --- a/backend/session/noop.c +++ b/backend/session/noop.c @@ -6,6 +6,7 @@ #include #include #include +#include "backend/session/session.h" #include "util/signal.h" const struct session_impl session_noop; @@ -33,7 +34,9 @@ static struct wlr_session *noop_session_create(struct wl_display *disp) { return NULL; } + session_init(session); session->impl = &session_noop; + session->active = true; wlr_log(WLR_INFO, "Successfully initialized noop session"); return session; diff --git a/backend/session/session.c b/backend/session/session.c index 01eeffd98..d8e9509d8 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -13,13 +13,18 @@ #include #include #include +#include "backend/session/session.h" #include "util/signal.h" +extern const struct session_impl session_libseat; extern const struct session_impl session_logind; extern const struct session_impl session_direct; extern const struct session_impl session_noop; static const struct session_impl *impls[] = { +#if WLR_HAS_LIBSEAT + &session_libseat, +#endif #if WLR_HAS_SYSTEMD || WLR_HAS_ELOGIND &session_logind, #endif @@ -65,12 +70,24 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { wlr_session_destroy(session); } +void session_init(struct wlr_session *session) { + wl_signal_init(&session->session_signal); + wl_signal_init(&session->events.destroy); + wl_list_init(&session->devices); +} + struct wlr_session *wlr_session_create(struct wl_display *disp) { struct wlr_session *session = NULL; const char *env_wlr_session = getenv("WLR_SESSION"); if (env_wlr_session) { - if (strcmp(env_wlr_session, "logind") == 0 || + if (strcmp(env_wlr_session, "libseat") == 0) { +#if WLR_HAS_LIBSEAT + session = session_libseat.create(disp); +#else + wlr_log(WLR_ERROR, "wlroots is not compiled with libseat support"); +#endif + } else if (strcmp(env_wlr_session, "logind") == 0 || strcmp(env_wlr_session, "systemd") == 0) { #if WLR_HAS_SYSTEMD || WLR_HAS_ELOGIND session = session_logind.create(disp); @@ -97,11 +114,6 @@ struct wlr_session *wlr_session_create(struct wl_display *disp) { return NULL; } - session->active = true; - wl_signal_init(&session->session_signal); - wl_signal_init(&session->events.destroy); - wl_list_init(&session->devices); - session->udev = udev_new(); if (!session->udev) { wlr_log_errno(WLR_ERROR, "Failed to create udev context"); diff --git a/include/backend/session/session.h b/include/backend/session/session.h new file mode 100644 index 000000000..626f470a3 --- /dev/null +++ b/include/backend/session/session.h @@ -0,0 +1,8 @@ +#ifndef BACKEND_SESSION_SESSION_H +#define BACKEND_SESSION_SESSION_H + +struct wlr_session; + +void session_init(struct wlr_session *session); + +#endif diff --git a/include/wlr/config.h.in b/include/wlr/config.h.in index a7691ff91..77a155982 100644 --- a/include/wlr/config.h.in +++ b/include/wlr/config.h.in @@ -8,6 +8,8 @@ #mesondefine WLR_HAS_SYSTEMD #mesondefine WLR_HAS_ELOGIND +#mesondefine WLR_HAS_LIBSEAT + #mesondefine WLR_HAS_X11_BACKEND #mesondefine WLR_HAS_XWAYLAND diff --git a/meson.build b/meson.build index 4abe63181..ca26391e7 100644 --- a/meson.build +++ b/meson.build @@ -82,6 +82,7 @@ endif conf_data = configuration_data() conf_data.set10('WLR_HAS_SYSTEMD', false) conf_data.set10('WLR_HAS_ELOGIND', false) +conf_data.set10('WLR_HAS_LIBSEAT', false) conf_data.set10('WLR_HAS_X11_BACKEND', false) conf_data.set10('WLR_HAS_XWAYLAND', false) conf_data.set10('WLR_HAS_XCB_ERRORS', false) @@ -176,6 +177,7 @@ meson.override_dependency('wlroots', wlroots) summary({ 'systemd': conf_data.get('WLR_HAS_SYSTEMD', 0), 'elogind': conf_data.get('WLR_HAS_ELOGIND', 0), + 'libseat': conf_data.get('WLR_HAS_LIBSEAT', 0), 'xwayland': conf_data.get('WLR_HAS_XWAYLAND', 0), 'x11_backend': conf_data.get('WLR_HAS_X11_BACKEND', 0), 'xcb-icccm': conf_data.get('WLR_HAS_XCB_ICCCM', 0), diff --git a/meson_options.txt b/meson_options.txt index 894113e7a..382ef2a66 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,5 +1,6 @@ option('logind', type: 'feature', value: 'auto', description: 'Enable support for rootless session via logind') option('logind-provider', type: 'combo', choices: ['auto', 'systemd', 'elogind'], value: 'auto', description: 'Provider of logind support library') +option('libseat', type: 'feature', value: 'auto', description: 'Enable support for rootless session via libseat') option('xcb-errors', type: 'feature', value: 'auto', description: 'Use xcb-errors util library') option('xcb-icccm', type: 'feature', value: 'auto', description: 'Use xcb-icccm util library') option('xwayland', type: 'feature', value: 'auto', yield: true, description: 'Enable support for X11 applications') From 297354f8477285231826f6441b943188ec7d7399 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 24 Aug 2020 10:27:03 +0200 Subject: [PATCH 30/94] Remove unnecessary wl_display_dispatch calls wl_display_roundtrip already takes care of dispatching the display. --- backend/wayland/backend.c | 1 - examples/dmabuf-capture.c | 1 - examples/foreign-toplevel.c | 1 - examples/gamma-control.c | 1 - examples/idle-inhibit.c | 1 - examples/idle.c | 1 - examples/input-inhibitor.c | 1 - examples/input-method-keyboard-grab.c | 1 - examples/input-method.c | 1 - examples/keyboard-shortcuts-inhibit.c | 1 - examples/output-power-management.c | 1 - examples/pointer-constraints.c | 1 - examples/relative-pointer-unstable-v1.c | 1 - examples/screencopy-dmabuf.c | 1 - examples/screencopy.c | 1 - examples/text-input.c | 1 - examples/toplevel-decoration.c | 1 - examples/virtual-pointer.c | 2 -- 18 files changed, 19 deletions(-) diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 972963e0f..a09126ce2 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -279,7 +279,6 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, } wl_registry_add_listener(wl->registry, ®istry_listener, wl); - wl_display_dispatch(wl->remote_display); wl_display_roundtrip(wl->remote_display); if (!wl->compositor) { diff --git a/examples/dmabuf-capture.c b/examples/dmabuf-capture.c index 203a1ac4a..2a3e195c2 100644 --- a/examples/dmabuf-capture.c +++ b/examples/dmabuf-capture.c @@ -754,7 +754,6 @@ static int init(struct capture_context *ctx) { wl_registry_add_listener(ctx->registry, ®istry_listener, ctx); wl_display_roundtrip(ctx->display); - wl_display_dispatch(ctx->display); if (!ctx->export_manager) { av_log(ctx, AV_LOG_ERROR, "Compositor doesn't support %s!\n", diff --git a/examples/foreign-toplevel.c b/examples/foreign-toplevel.c index 9184e7374..1d41d01af 100644 --- a/examples/foreign-toplevel.c +++ b/examples/foreign-toplevel.c @@ -332,7 +332,6 @@ int main(int argc, char **argv) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); if (toplevel_manager == NULL) { diff --git a/examples/gamma-control.c b/examples/gamma-control.c index a060b8837..9fa00ce36 100644 --- a/examples/gamma-control.c +++ b/examples/gamma-control.c @@ -162,7 +162,6 @@ int main(int argc, char *argv[]) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); if (gamma_control_manager == NULL) { diff --git a/examples/idle-inhibit.c b/examples/idle-inhibit.c index 348892ab3..5de32dbd7 100644 --- a/examples/idle-inhibit.c +++ b/examples/idle-inhibit.c @@ -177,7 +177,6 @@ int main(int argc, char **argv) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); if (compositor == NULL) { diff --git a/examples/idle.c b/examples/idle.c index 6faa1d7d3..254f1c79b 100644 --- a/examples/idle.c +++ b/examples/idle.c @@ -125,7 +125,6 @@ int main(int argc, char *argv[]) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); wl_registry_destroy(registry); diff --git a/examples/input-inhibitor.c b/examples/input-inhibitor.c index 25e46c735..7192b45b2 100644 --- a/examples/input-inhibitor.c +++ b/examples/input-inhibitor.c @@ -150,7 +150,6 @@ int main(int argc, char **argv) { struct wl_registry *registry = wl_display_get_registry(display); assert(registry); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); assert(compositor && seat && wm_base && input_inhibit_manager); diff --git a/examples/input-method-keyboard-grab.c b/examples/input-method-keyboard-grab.c index 881f91a92..055abeab8 100644 --- a/examples/input-method-keyboard-grab.c +++ b/examples/input-method-keyboard-grab.c @@ -191,7 +191,6 @@ int main(int argc, char **argv) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); if (input_method_manager == NULL) { diff --git a/examples/input-method.c b/examples/input-method.c index 9276e1599..479c87613 100644 --- a/examples/input-method.c +++ b/examples/input-method.c @@ -324,7 +324,6 @@ int main(int argc, char **argv) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); if (compositor == NULL) { diff --git a/examples/keyboard-shortcuts-inhibit.c b/examples/keyboard-shortcuts-inhibit.c index 3d066c0e0..e9a837b61 100644 --- a/examples/keyboard-shortcuts-inhibit.c +++ b/examples/keyboard-shortcuts-inhibit.c @@ -209,7 +209,6 @@ int main(int argc, char **argv) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); if (compositor == NULL) { diff --git a/examples/output-power-management.c b/examples/output-power-management.c index 43e7c53f6..00d4122a3 100644 --- a/examples/output-power-management.c +++ b/examples/output-power-management.c @@ -109,7 +109,6 @@ int main(int argc, char *argv[]) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); if (output_power_manager == NULL) { diff --git a/examples/pointer-constraints.c b/examples/pointer-constraints.c index 1df9f6ce0..f67f1edec 100644 --- a/examples/pointer-constraints.c +++ b/examples/pointer-constraints.c @@ -198,7 +198,6 @@ int main(int argc, char **argv) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); struct wl_region *disjoint_region = wl_compositor_create_region(compositor); diff --git a/examples/relative-pointer-unstable-v1.c b/examples/relative-pointer-unstable-v1.c index ce671f995..02f9d1c52 100644 --- a/examples/relative-pointer-unstable-v1.c +++ b/examples/relative-pointer-unstable-v1.c @@ -412,7 +412,6 @@ int main(int argc, char **argv) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); /* Check that all the global interfaces were captured */ diff --git a/examples/screencopy-dmabuf.c b/examples/screencopy-dmabuf.c index 74eb8a75d..2525efc5a 100644 --- a/examples/screencopy-dmabuf.c +++ b/examples/screencopy-dmabuf.c @@ -315,7 +315,6 @@ int main(int argc, char *argv[]) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); if (dmabuf == NULL) { diff --git a/examples/screencopy.c b/examples/screencopy.c index cf4652f49..0e03a2384 100644 --- a/examples/screencopy.c +++ b/examples/screencopy.c @@ -234,7 +234,6 @@ int main(int argc, char *argv[]) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); if (shm == NULL) { diff --git a/examples/text-input.c b/examples/text-input.c index bfdbc07b4..ec75d3078 100644 --- a/examples/text-input.c +++ b/examples/text-input.c @@ -344,7 +344,6 @@ int main(int argc, char **argv) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); if (compositor == NULL) { diff --git a/examples/toplevel-decoration.c b/examples/toplevel-decoration.c index e930c4170..cb8caacec 100644 --- a/examples/toplevel-decoration.c +++ b/examples/toplevel-decoration.c @@ -203,7 +203,6 @@ int main(int argc, char **argv) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); if (compositor == NULL) { diff --git a/examples/virtual-pointer.c b/examples/virtual-pointer.c index 84af7ffdc..8fd148305 100644 --- a/examples/virtual-pointer.c +++ b/examples/virtual-pointer.c @@ -67,7 +67,6 @@ int main(int argc, char *argv[]) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); if (pointer_manager == NULL) { @@ -132,7 +131,6 @@ int main(int argc, char *argv[]) { zwlr_virtual_pointer_v1_frame(pointer); zwlr_virtual_pointer_v1_destroy(pointer); - wl_display_dispatch(display); return EXIT_SUCCESS; } From 330c50b48dfe987d7894f5a92c1b084b2cc8c712 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 26 Aug 2020 21:09:56 +0200 Subject: [PATCH 31/94] session: Add missing init to direct-freebsd bad1e9afa8ea ("session: Add libseat backend") introduced a change to to how session backends initialize, but failed to update the FreeBSD specific version of the direct backend accordingly. Closes: https://github.com/swaywm/wlroots/issues/2376 --- backend/session/direct-freebsd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/session/direct-freebsd.c b/backend/session/direct-freebsd.c index c6e1f7204..e4b6c7929 100644 --- a/backend/session/direct-freebsd.c +++ b/backend/session/direct-freebsd.c @@ -18,6 +18,7 @@ #include #include #include "backend/session/direct-ipc.h" +#include "backend/session/session.h" #include "util/signal.h" const struct session_impl session_direct; @@ -274,6 +275,7 @@ static struct wlr_session *direct_session_create(struct wl_display *disp) { return NULL; } + session_init(&session->base); session->sock = direct_ipc_init(&session->child); if (session->sock == -1) { goto error_session; @@ -297,6 +299,7 @@ static struct wlr_session *direct_session_create(struct wl_display *disp) { snprintf(session->base.seat, sizeof(session->base.seat), "%s", seat); session->base.impl = &session_direct; + session->base.active = true; return &session->base; error_ipc: From 2072d59da54ac772410271ad2219ca107a7fff48 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Mon, 20 Jul 2020 23:43:03 +0200 Subject: [PATCH 32/94] xdg-shell: split last-acked and current state These states are distinct in the time period between the ack_configure and the next commit on the surface. Splitting these states avoids the following race for example: - client starts at 1000x1000 - wlr_xdg_toplevel_set_size 500x500 - size is different -> configure sent - client acks the configure - wlr_xdg_toplevel_set_size 1000x1000 - compare_xdg_toplevel_state returns true since there is no pending configure and the currently committed size is still 1000x1000 - no new configure is sent - client commits at the size it last acked, 500x500 --- include/wlr/types/wlr_xdg_shell.h | 1 + include/wlr/types/wlr_xdg_shell_v6.h | 1 + types/xdg_shell/wlr_xdg_toplevel.c | 47 +++++++++--------------- types/xdg_shell_v6/wlr_xdg_toplevel_v6.c | 43 ++++++++-------------- 4 files changed, 35 insertions(+), 57 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index 4bd286ceb..45c5aee08 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -124,6 +124,7 @@ struct wlr_xdg_toplevel { struct wlr_xdg_toplevel_state client_pending; struct wlr_xdg_toplevel_state server_pending; + struct wlr_xdg_toplevel_state last_acked; struct wlr_xdg_toplevel_state current; char *title; diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 5a6cf72f9..2e870aa5c 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -139,6 +139,7 @@ struct wlr_xdg_toplevel_v6 { struct wlr_xdg_toplevel_v6_state client_pending; struct wlr_xdg_toplevel_v6_state server_pending; + struct wlr_xdg_toplevel_v6_state last_acked; struct wlr_xdg_toplevel_v6_state current; char *title; diff --git a/types/xdg_shell/wlr_xdg_toplevel.c b/types/xdg_shell/wlr_xdg_toplevel.c index 3524bd34c..51d0687b5 100644 --- a/types/xdg_shell/wlr_xdg_toplevel.c +++ b/types/xdg_shell/wlr_xdg_toplevel.c @@ -13,60 +13,44 @@ void handle_xdg_toplevel_ack_configure( assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); assert(configure->toplevel_state != NULL); - surface->toplevel->current.maximized = - configure->toplevel_state->maximized; - surface->toplevel->current.fullscreen = - configure->toplevel_state->fullscreen; - surface->toplevel->current.resizing = - configure->toplevel_state->resizing; - surface->toplevel->current.activated = - configure->toplevel_state->activated; - surface->toplevel->current.tiled = - configure->toplevel_state->tiled; + surface->toplevel->last_acked = *configure->toplevel_state; } bool compare_xdg_surface_toplevel_state(struct wlr_xdg_toplevel *state) { - struct { - struct wlr_xdg_toplevel_state state; - uint32_t width, height; - } configured; - // is pending state different from current state? if (!state->base->configured) { return false; } + struct wlr_xdg_toplevel_state *configured = NULL; if (wl_list_empty(&state->base->configure_list)) { - // last configure is actually the current state, just use it - configured.state = state->current; - configured.width = state->base->surface->current.width; - configured.height = state->base->surface->current.height; + // There are currently no pending configures, so check against the last + // state acked by the client. + configured = &state->last_acked; } else { struct wlr_xdg_surface_configure *configure = wl_container_of(state->base->configure_list.prev, configure, link); - configured.state = *configure->toplevel_state; - configured.width = configure->toplevel_state->width; - configured.height = configure->toplevel_state->height; + configured = configure->toplevel_state; } - if (state->server_pending.activated != configured.state.activated) { + if (state->server_pending.activated != configured->activated) { return false; } - if (state->server_pending.fullscreen != configured.state.fullscreen) { + if (state->server_pending.fullscreen != configured->fullscreen) { return false; } - if (state->server_pending.maximized != configured.state.maximized) { + if (state->server_pending.maximized != configured->maximized) { return false; } - if (state->server_pending.resizing != configured.state.resizing) { + if (state->server_pending.resizing != configured->resizing) { return false; } - if (state->server_pending.tiled != configured.state.tiled) { + if (state->server_pending.tiled != configured->tiled) { return false; } - if (state->server_pending.width == configured.width && - state->server_pending.height == configured.height) { + if (state->server_pending.width == configured->width && + state->server_pending.height == configured->height) { return true; } @@ -187,7 +171,10 @@ void handle_xdg_surface_toplevel_committed(struct wlr_xdg_surface *surface) { return; } - // update state that doesn't need compositor approval + // apply state from the last acked configure now that the client committed + surface->toplevel->current = surface->toplevel->last_acked; + + // update state from the client that doesn't need compositor approval surface->toplevel->current.max_width = surface->toplevel->client_pending.max_width; surface->toplevel->current.min_width = diff --git a/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c b/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c index a7a7d12bc..2c626f83d 100644 --- a/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c +++ b/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c @@ -295,55 +295,41 @@ void handle_xdg_toplevel_v6_ack_configure(struct wlr_xdg_surface_v6 *surface, assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); assert(configure->toplevel_state != NULL); - surface->toplevel->current.maximized = - configure->toplevel_state->maximized; - surface->toplevel->current.fullscreen = - configure->toplevel_state->fullscreen; - surface->toplevel->current.resizing = - configure->toplevel_state->resizing; - surface->toplevel->current.activated = - configure->toplevel_state->activated; + surface->toplevel->last_acked = *configure->toplevel_state; } bool compare_xdg_surface_v6_toplevel_state(struct wlr_xdg_toplevel_v6 *state) { - struct { - struct wlr_xdg_toplevel_v6_state state; - uint32_t width, height; - } configured; - // is pending state different from current state? if (!state->base->configured) { return false; } + struct wlr_xdg_toplevel_v6_state *configured = NULL; if (wl_list_empty(&state->base->configure_list)) { - // last configure is actually the current state, just use it - configured.state = state->current; - configured.width = state->base->surface->current.width; - configured.height = state->base->surface->current.height; + // There are currently no pending configures, so check against the last + // state acked by the client. + configured = &state->last_acked; } else { struct wlr_xdg_surface_v6_configure *configure = wl_container_of(state->base->configure_list.prev, configure, link); - configured.state = *configure->toplevel_state; - configured.width = configure->toplevel_state->width; - configured.height = configure->toplevel_state->height; + configured = configure->toplevel_state; } - if (state->server_pending.activated != configured.state.activated) { + if (state->server_pending.activated != configured->activated) { return false; } - if (state->server_pending.fullscreen != configured.state.fullscreen) { + if (state->server_pending.fullscreen != configured->fullscreen) { return false; } - if (state->server_pending.maximized != configured.state.maximized) { + if (state->server_pending.maximized != configured->maximized) { return false; } - if (state->server_pending.resizing != configured.state.resizing) { + if (state->server_pending.resizing != configured->resizing) { return false; } - if (state->server_pending.width == configured.width && - state->server_pending.height == configured.height) { + if (state->server_pending.width == configured->width && + state->server_pending.height == configured->height) { return true; } @@ -430,7 +416,10 @@ void handle_xdg_surface_v6_toplevel_committed(struct wlr_xdg_surface_v6 *surface return; } - // update state that doesn't need compositor approval + // apply state from the last acked configure now that the client committed + surface->toplevel->current = surface->toplevel->last_acked; + + // update state from the client that doesn't need compositor approval surface->toplevel->current.max_width = surface->toplevel->client_pending.max_width; surface->toplevel->current.min_width = From 6949d0fd381dcb5df61d78b34b325473a113f279 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Thu, 27 Aug 2020 15:40:15 +0200 Subject: [PATCH 33/94] render: Don't crash on 0 dimensions Don't force compositors to check when an empty shape is being renderered. References #2282. This was motivated by dwl crashing when setting window borders to 0 (djpohly/dwl#51). --- render/wlr_renderer.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 593d165f4..8fa11cc97 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -99,6 +99,9 @@ bool wlr_render_subtexture_with_matrix(struct wlr_renderer *r, void wlr_render_rect(struct wlr_renderer *r, const struct wlr_box *box, const float color[static 4], const float projection[static 9]) { + if (box->width == 0 || box->height == 0) { + return; + } assert(box->width > 0 && box->height > 0); float matrix[9]; wlr_matrix_project_box(matrix, box, WL_OUTPUT_TRANSFORM_NORMAL, 0, @@ -115,6 +118,9 @@ void wlr_render_quad_with_matrix(struct wlr_renderer *r, void wlr_render_ellipse(struct wlr_renderer *r, const struct wlr_box *box, const float color[static 4], const float projection[static 9]) { + if (box->width == 0 || box->height == 0) { + return; + } assert(box->width > 0 && box->height > 0); float matrix[9]; wlr_matrix_project_box(matrix, box, WL_OUTPUT_TRANSFORM_NORMAL, 0, From c674241ec0d96a4df42eda00da2894f3e5972710 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 2 Jul 2020 17:22:38 +0200 Subject: [PATCH 34/94] output: introduce wlr_output_event_commit This event contains a `committed` bitfield, which allows callers to know which output fields changed during the commit. This allows users to setup a single atomic commit listener, instead of setting up one listener for each event (mode, scale, transform, and so on). References: https://github.com/swaywm/wlroots/issues/2098 --- include/wlr/types/wlr_output.h | 7 ++++++- types/wlr_output.c | 10 +++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 075d09a1f..41423b582 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -163,7 +163,7 @@ struct wlr_output { // Emitted right before commit struct wl_signal precommit; // wlr_output_event_precommit // Emitted right after commit - struct wl_signal commit; + struct wl_signal commit; // wlr_output_event_commit // Emitted right after the buffer has been presented to the user struct wl_signal present; // wlr_output_event_present struct wl_signal enable; @@ -198,6 +198,11 @@ struct wlr_output_event_precommit { struct timespec *when; }; +struct wlr_output_event_commit { + struct wlr_output *output; + uint32_t committed; // bitmask of enum wlr_output_state_field +}; + enum wlr_output_present_flag { // The presentation was synchronized to the "vertical retrace" by the // display hardware such that tearing does not happen. diff --git a/types/wlr_output.c b/types/wlr_output.c index 9d02ec3c6..1c40a1470 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -581,11 +581,11 @@ bool wlr_output_commit(struct wlr_output *output) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - struct wlr_output_event_precommit event = { + struct wlr_output_event_precommit pre_event = { .output = output, .when = &now, }; - wlr_signal_emit_safe(&output->events.precommit, &event); + wlr_signal_emit_safe(&output->events.precommit, &pre_event); if (!output->impl->commit(output)) { output_state_clear(&output->pending); @@ -604,7 +604,11 @@ bool wlr_output_commit(struct wlr_output *output) { output->commit_seq++; - wlr_signal_emit_safe(&output->events.commit, output); + struct wlr_output_event_commit event = { + .output = output, + .committed = output->pending.committed, + }; + wlr_signal_emit_safe(&output->events.commit, &event); bool scale_updated = output->pending.committed & WLR_OUTPUT_STATE_SCALE; if (scale_updated) { From b0144c7ded2b655085eb8e7e9b64908dc9420d60 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 2 Jul 2020 17:29:16 +0200 Subject: [PATCH 35/94] output-power-management-v1: listen to output commit --- .../types/wlr_output_power_management_v1.h | 2 +- types/wlr_output_power_management_v1.c | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/include/wlr/types/wlr_output_power_management_v1.h b/include/wlr/types/wlr_output_power_management_v1.h index 2ceb86002..23ce814a0 100644 --- a/include/wlr/types/wlr_output_power_management_v1.h +++ b/include/wlr/types/wlr_output_power_management_v1.h @@ -25,7 +25,7 @@ struct wlr_output_power_v1 { struct wl_list link; struct wl_listener output_destroy_listener; - struct wl_listener output_enable_listener; + struct wl_listener output_commit_listener; void *data; }; diff --git a/types/wlr_output_power_management_v1.c b/types/wlr_output_power_management_v1.c index 115c74f74..e607eb161 100644 --- a/types/wlr_output_power_management_v1.c +++ b/types/wlr_output_power_management_v1.c @@ -23,7 +23,7 @@ static void output_power_destroy(struct wlr_output_power_v1 *output_power) { } wl_resource_set_user_data(output_power->resource, NULL); wl_list_remove(&output_power->output_destroy_listener.link); - wl_list_remove(&output_power->output_enable_listener.link); + wl_list_remove(&output_power->output_commit_listener.link); wl_list_remove(&output_power->link); free(output_power); } @@ -58,11 +58,14 @@ static void output_power_v1_send_mode(struct wlr_output_power_v1 *output_power) zwlr_output_power_v1_send_mode(output_power->resource, mode); } -static void output_power_handle_output_enable(struct wl_listener *listener, +static void output_power_handle_output_commit(struct wl_listener *listener, void *data) { struct wlr_output_power_v1 *output_power = - wl_container_of(listener, output_power, output_enable_listener); - output_power_v1_send_mode(output_power); + wl_container_of(listener, output_power, output_commit_listener); + struct wlr_output_event_commit *event = data; + if (event->committed & WLR_OUTPUT_STATE_ENABLED) { + output_power_v1_send_mode(output_power); + } } static void output_power_handle_set_mode(struct wl_client *client, @@ -147,10 +150,10 @@ static void output_power_manager_get_output_power(struct wl_client *client, &output_power->output_destroy_listener); output_power->output_destroy_listener.notify = output_power_handle_output_destroy; - wl_signal_add(&output->events.enable, - &output_power->output_enable_listener); - output_power->output_enable_listener.notify = - output_power_handle_output_enable; + wl_signal_add(&output->events.commit, + &output_power->output_commit_listener); + output_power->output_commit_listener.notify = + output_power_handle_output_commit; struct wlr_output_power_v1 *mgmt; wl_list_for_each(mgmt, &manager->output_powers, link) { From 2b418b4d8857a4eacd719b76dfd36210383db6d6 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 31 Aug 2020 16:38:39 +0200 Subject: [PATCH 36/94] examples/dmabuf-capture: add extra roundtrip for wl_output listener This example was relying on wl_display_dispatch being enough to fetch output information. This worked by chance. Add an explicit wl_display_roundtrip. Other examples don't setup wl_output listeners, so they should be fine. Fixes: 297354f84772 ("Remove unnecessary wl_display_dispatch calls") Closes: https://github.com/swaywm/wlroots/issues/2386 --- examples/dmabuf-capture.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/dmabuf-capture.c b/examples/dmabuf-capture.c index 2a3e195c2..60cdb6577 100644 --- a/examples/dmabuf-capture.c +++ b/examples/dmabuf-capture.c @@ -753,6 +753,10 @@ static int init(struct capture_context *ctx) { ctx->registry = wl_display_get_registry(ctx->display); wl_registry_add_listener(ctx->registry, ®istry_listener, ctx); + // First roundtrip to fetch globals + wl_display_roundtrip(ctx->display); + + // Second roundtrip to fetch wl_output information wl_display_roundtrip(ctx->display); if (!ctx->export_manager) { From 8b744412aab11fe4997367adf1a714ef2cb3946e Mon Sep 17 00:00:00 2001 From: Valentin Date: Sun, 30 Aug 2020 11:08:42 +0200 Subject: [PATCH 37/94] Use fixed size integer type This type is meant to be 4 bytes large as seen in _XcursorReadUInt which always reads 4 bytes. An unsigned int is often 4 bytes large but this isnt' guaranteed so it is cleaner to use the exact type we want. --- include/xcursor/xcursor.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/xcursor/xcursor.h b/include/xcursor/xcursor.h index 62e232202..285f4de66 100644 --- a/include/xcursor/xcursor.h +++ b/include/xcursor/xcursor.h @@ -26,8 +26,10 @@ #ifndef XCURSOR_H #define XCURSOR_H -typedef int XcursorBool; -typedef unsigned int XcursorUInt; +#include + +typedef int XcursorBool; +typedef uint32_t XcursorUInt; typedef XcursorUInt XcursorDim; typedef XcursorUInt XcursorPixel; From 65abd4e92af497bbe1ae1085fa16b1b811a3c652 Mon Sep 17 00:00:00 2001 From: Valentin Date: Sun, 30 Aug 2020 11:13:19 +0200 Subject: [PATCH 38/94] Fix undefined behavior Without the casts the bytes accesses get converted to int. but int is not guaranteed to be 4 bytes large. Even when it is 4 bytes large `bytes[3] << 24` does not fit because int is signed. --- xcursor/xcursor.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/xcursor/xcursor.c b/xcursor/xcursor.c index aabef4837..51ce83237 100644 --- a/xcursor/xcursor.c +++ b/xcursor/xcursor.c @@ -285,11 +285,12 @@ _XcursorReadUInt (XcursorFile *file, XcursorUInt *u) return XcursorFalse; if ((*file->read) (file, bytes, 4) != 4) - return XcursorFalse; - *u = ((bytes[0] << 0) | - (bytes[1] << 8) | - (bytes[2] << 16) | - (bytes[3] << 24)); + return XcursorFalse; + + *u = ((XcursorUInt)(bytes[0]) << 0) | + ((XcursorUInt)(bytes[1]) << 8) | + ((XcursorUInt)(bytes[2]) << 16) | + ((XcursorUInt)(bytes[3]) << 24); return XcursorTrue; } From 971de474f0a423cc8f444c92d2e1a8334db8b55d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 28 Aug 2020 19:19:31 +0200 Subject: [PATCH 39/94] backend/session/libseat: register log handler Route libseat errors through wlroots logging infrastructure. This requires libseat 0.2.0. --- backend/session/libseat.c | 25 +++++++++++++++++++++++++ backend/session/meson.build | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/backend/session/libseat.c b/backend/session/libseat.c index 77226204f..751adcd3e 100644 --- a/backend/session/libseat.c +++ b/backend/session/libseat.c @@ -62,6 +62,28 @@ static struct libseat_session *libseat_session_from_session( return (struct libseat_session *)base; } +static enum wlr_log_importance libseat_log_level_to_wlr( + enum libseat_log_level level) { + switch (level) { + case LIBSEAT_LOG_LEVEL_ERROR: + return WLR_ERROR; + case LIBSEAT_LOG_LEVEL_INFO: + return WLR_INFO; + default: + return WLR_DEBUG; + } +} + +static void log_libseat(enum libseat_log_level level, + const char *fmt, va_list args) { + enum wlr_log_importance importance = libseat_log_level_to_wlr(level); + + static char wlr_fmt[1024]; + snprintf(wlr_fmt, sizeof(wlr_fmt), "[libseat] %s", fmt); + + _wlr_vlog(importance, wlr_fmt, args); +} + static struct wlr_session *libseat_session_create(struct wl_display *disp) { struct libseat_session *session = calloc(1, sizeof(*session)); if (!session) { @@ -72,6 +94,9 @@ static struct wlr_session *libseat_session_create(struct wl_display *disp) { session_init(&session->base); wl_list_init(&session->devices); + libseat_set_log_handler(log_libseat); + libseat_set_log_level(LIBSEAT_LOG_LEVEL_ERROR); + session->seat = libseat_open_seat(&seat_listener, session); if (session->seat == NULL) { wlr_log_errno(WLR_ERROR, "Unable to create seat"); diff --git a/backend/session/meson.build b/backend/session/meson.build index 4c83685e9..140d41059 100644 --- a/backend/session/meson.build +++ b/backend/session/meson.build @@ -65,7 +65,7 @@ endif # libseat -libseat = dependency('libseat', required: get_option('libseat')) +libseat = dependency('libseat', required: get_option('libseat'), version: '>=0.2.0') if libseat.found() wlr_files += files('libseat.c') wlr_deps += libseat From 28cedb56237efdf388fed713ddb401a5d8d07434 Mon Sep 17 00:00:00 2001 From: Ryan Walklin Date: Wed, 2 Sep 2020 21:29:12 +1200 Subject: [PATCH 40/94] Quieten failure to set login session type (almost certainly due to systemd version <246) --- backend/session/logind.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/backend/session/logind.c b/backend/session/logind.c index a460cbe26..b9249eced 100644 --- a/backend/session/logind.c +++ b/backend/session/logind.c @@ -242,7 +242,7 @@ static bool take_control(struct logind_session *session) { return ret >= 0; } -static bool set_type(struct logind_session *session) { +static void set_type(struct logind_session *session) { int ret; sd_bus_message *msg = NULL; sd_bus_error error = SD_BUS_ERROR_NULL; @@ -251,7 +251,7 @@ static bool set_type(struct logind_session *session) { session->path, "org.freedesktop.login1.Session", "SetType", &error, &msg, "s", "wayland"); if (ret < 0) { - wlr_log(WLR_ERROR, "Failed to set logind session type for session: %s", + wlr_log(WLR_DEBUG, "Failed to set logind session type for session: %s", error.message); } @@ -259,15 +259,13 @@ static bool set_type(struct logind_session *session) { sd_bus_message_unref(msg); if (ret < 0) { - return false; + return; } ret = setenv("XDG_SESSION_TYPE", "wayland", 1); if (ret < 0) { wlr_log(WLR_ERROR, "Failed to set XDG_SESSION_TYPE for session"); - return false; } - return true; } static void release_control(struct logind_session *session) { @@ -850,10 +848,7 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) { } } - if (!set_type(session)) { - // Not fatal - wlr_log(WLR_INFO, "Failed to set logind session type to wayland"); - } + set_type(session); wlr_log(WLR_INFO, "Successfully loaded logind session"); From a9cbfd950e83df2053474f50f7d12cf79dd74d74 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Wed, 2 Sep 2020 13:06:31 -0400 Subject: [PATCH 41/94] Remove xdg-shell v6 Ding dong the witch is dead Fixes #2381 --- include/types/wlr_xdg_shell_v6.h | 47 -- include/wlr/types/wlr_xdg_shell_v6.h | 375 ------------- protocol/meson.build | 1 - types/meson.build | 5 - types/xdg_shell_v6/wlr_xdg_popup_v6.c | 585 -------------------- types/xdg_shell_v6/wlr_xdg_positioner_v6.c | 230 -------- types/xdg_shell_v6/wlr_xdg_shell_v6.c | 168 ------ types/xdg_shell_v6/wlr_xdg_surface_v6.c | 606 --------------------- types/xdg_shell_v6/wlr_xdg_toplevel_v6.c | 525 ------------------ 9 files changed, 2542 deletions(-) delete mode 100644 include/types/wlr_xdg_shell_v6.h delete mode 100644 include/wlr/types/wlr_xdg_shell_v6.h delete mode 100644 types/xdg_shell_v6/wlr_xdg_popup_v6.c delete mode 100644 types/xdg_shell_v6/wlr_xdg_positioner_v6.c delete mode 100644 types/xdg_shell_v6/wlr_xdg_shell_v6.c delete mode 100644 types/xdg_shell_v6/wlr_xdg_surface_v6.c delete mode 100644 types/xdg_shell_v6/wlr_xdg_toplevel_v6.c diff --git a/include/types/wlr_xdg_shell_v6.h b/include/types/wlr_xdg_shell_v6.h deleted file mode 100644 index 4c9d1fa0e..000000000 --- a/include/types/wlr_xdg_shell_v6.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef TYPES_WLR_XDG_SHELL_V6_H -#define TYPES_WLR_XDG_SHELL_V6_H - -#include -#include -#include "xdg-shell-unstable-v6-protocol.h" - -struct wlr_xdg_positioner_v6_resource { - struct wl_resource *resource; - struct wlr_xdg_positioner_v6 attrs; -}; - -extern const struct wlr_surface_role xdg_toplevel_v6_surface_role; -extern const struct wlr_surface_role xdg_popup_v6_surface_role; - -uint32_t schedule_xdg_surface_v6_configure(struct wlr_xdg_surface_v6 *surface); -struct wlr_xdg_surface_v6 *create_xdg_surface_v6( - struct wlr_xdg_client_v6 *client, struct wlr_surface *surface, - uint32_t id); -void unmap_xdg_surface_v6(struct wlr_xdg_surface_v6 *surface); -void destroy_xdg_surface_v6(struct wlr_xdg_surface_v6 *surface); -void handle_xdg_surface_v6_commit(struct wlr_surface *wlr_surface); -void handle_xdg_surface_v6_precommit(struct wlr_surface *wlr_surface); - -void create_xdg_positioner_v6(struct wlr_xdg_client_v6 *client, uint32_t id); -struct wlr_xdg_positioner_v6_resource *get_xdg_positioner_v6_from_resource( - struct wl_resource *resource); - -void create_xdg_popup_v6(struct wlr_xdg_surface_v6 *xdg_surface, - struct wlr_xdg_surface_v6 *parent, - struct wlr_xdg_positioner_v6_resource *positioner, int32_t id); -void handle_xdg_surface_v6_popup_committed(struct wlr_xdg_surface_v6 *surface); -struct wlr_xdg_popup_grab_v6 *get_xdg_shell_v6_popup_grab_from_seat( - struct wlr_xdg_shell_v6 *shell, struct wlr_seat *seat); -void destroy_xdg_popup_v6(struct wlr_xdg_surface_v6 *surface); - -void create_xdg_toplevel_v6(struct wlr_xdg_surface_v6 *xdg_surface, - uint32_t id); -void handle_xdg_surface_v6_toplevel_committed(struct wlr_xdg_surface_v6 *surface); -void send_xdg_toplevel_v6_configure(struct wlr_xdg_surface_v6 *surface, - struct wlr_xdg_surface_v6_configure *configure); -void handle_xdg_toplevel_v6_ack_configure(struct wlr_xdg_surface_v6 *surface, - struct wlr_xdg_surface_v6_configure *configure); -bool compare_xdg_surface_v6_toplevel_state(struct wlr_xdg_toplevel_v6 *state); -void destroy_xdg_toplevel_v6(struct wlr_xdg_surface_v6 *surface); - -#endif diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h deleted file mode 100644 index 2e870aa5c..000000000 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ /dev/null @@ -1,375 +0,0 @@ -/* - * This protocol is obsolete and will be removed in a future version. The - * recommended replacement is xdg-shell. - */ - -/* - * This an unstable interface of wlroots. No guarantees are made regarding the - * future consistency of this API. - */ -#ifndef WLR_USE_UNSTABLE -#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" -#endif - -#ifndef WLR_TYPES_WLR_XDG_SHELL_V6_H -#define WLR_TYPES_WLR_XDG_SHELL_V6_H - -#include -#include -#include -#include "xdg-shell-unstable-v6-protocol.h" - -/** - * An interface enabling clients to turn their wl_surfaces into windows in a - * desktop environment. - */ -struct wlr_xdg_shell_v6 { - struct wl_global *global; - struct wl_list clients; - struct wl_list popup_grabs; - uint32_t ping_timeout; - - struct wl_listener display_destroy; - - struct { - /** - * The `new_surface` event signals that a client has requested to - * create a new shell surface. At this point, the surface is ready to - * be configured but is not mapped or ready receive input events. The - * surface will be ready to be managed on the `map` event. - */ - struct wl_signal new_surface; - struct wl_signal destroy; - } events; - - void *data; -}; - -struct wlr_xdg_client_v6 { - struct wlr_xdg_shell_v6 *shell; - struct wl_resource *resource; - struct wl_client *client; - struct wl_list surfaces; - - struct wl_list link; // wlr_xdg_shell_v6::clients - - uint32_t ping_serial; - struct wl_event_source *ping_timer; -}; - -struct wlr_xdg_positioner_v6 { - struct wlr_box anchor_rect; - enum zxdg_positioner_v6_anchor anchor; - enum zxdg_positioner_v6_gravity gravity; - enum zxdg_positioner_v6_constraint_adjustment constraint_adjustment; - - struct { - int32_t width, height; - } size; - - struct { - int32_t x, y; - } offset; -}; - -struct wlr_xdg_popup_v6 { - struct wlr_xdg_surface_v6 *base; - struct wl_list link; - - struct wl_resource *resource; - bool committed; - struct wlr_xdg_surface_v6 *parent; - struct wlr_seat *seat; - - // Position of the popup relative to the upper left corner of the window - // geometry of the parent surface - struct wlr_box geometry; - - struct wlr_xdg_positioner_v6 positioner; - - struct wl_list grab_link; // wlr_xdg_popup_grab_v6::popups -}; - -// each seat gets a popup grab -struct wlr_xdg_popup_grab_v6 { - struct wl_client *client; - struct wlr_seat_pointer_grab pointer_grab; - struct wlr_seat_keyboard_grab keyboard_grab; - struct wlr_seat_touch_grab touch_grab; - struct wlr_seat *seat; - struct wl_list popups; - struct wl_list link; // wlr_xdg_shell_v6::popup_grabs - struct wl_listener seat_destroy; -}; - -enum wlr_xdg_surface_v6_role { - WLR_XDG_SURFACE_V6_ROLE_NONE, - WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL, - WLR_XDG_SURFACE_V6_ROLE_POPUP, -}; - -struct wlr_xdg_toplevel_v6_state { - bool maximized, fullscreen, resizing, activated; - uint32_t width, height; - uint32_t max_width, max_height; - uint32_t min_width, min_height; - - // Since the fullscreen request may be made before the toplevel's surface - // is mapped, this is used to store the requested fullscreen output (if - // any) for wlr_xdg_toplevel_v6::client_pending. - struct wlr_output *fullscreen_output; - struct wl_listener fullscreen_output_destroy; -}; - -/** - * An xdg-surface is a user interface element requiring management by the - * compositor. An xdg-surface alone isn't useful, a role should be assigned to - * it in order to map it. - * - * When a surface has a role and is ready to be displayed, the `map` event is - * emitted. When a surface should no longer be displayed, the `unmap` event is - * emitted. The `unmap` event is guaranteed to be emitted before the `destroy` - * event if the view is destroyed when mapped. - */ -struct wlr_xdg_toplevel_v6 { - struct wl_resource *resource; - struct wlr_xdg_surface_v6 *base; - struct wlr_xdg_surface_v6 *parent; - bool added; - - struct wlr_xdg_toplevel_v6_state client_pending; - struct wlr_xdg_toplevel_v6_state server_pending; - struct wlr_xdg_toplevel_v6_state last_acked; - struct wlr_xdg_toplevel_v6_state current; - - char *title; - char *app_id; - - struct { - struct wl_signal request_maximize; - struct wl_signal request_fullscreen; - struct wl_signal request_minimize; - struct wl_signal request_move; - struct wl_signal request_resize; - struct wl_signal request_show_window_menu; - struct wl_signal set_parent; - struct wl_signal set_title; - struct wl_signal set_app_id; - } events; -}; - -struct wlr_xdg_surface_v6_configure { - struct wl_list link; // wlr_xdg_surface_v6::configure_list - uint32_t serial; - - struct wlr_xdg_toplevel_v6_state *toplevel_state; -}; - -struct wlr_xdg_surface_v6 { - struct wlr_xdg_client_v6 *client; - struct wl_resource *resource; - struct wlr_surface *surface; - struct wl_list link; // wlr_xdg_client_v6::surfaces - enum wlr_xdg_surface_v6_role role; - - union { - struct wlr_xdg_toplevel_v6 *toplevel; - struct wlr_xdg_popup_v6 *popup; - }; - - struct wl_list popups; // wlr_xdg_popup_v6::link - - bool added, configured, mapped; - uint32_t configure_serial; - struct wl_event_source *configure_idle; - uint32_t configure_next_serial; - struct wl_list configure_list; - - bool has_next_geometry; - struct wlr_box next_geometry; - struct wlr_box geometry; - - struct wl_listener surface_destroy; - struct wl_listener surface_commit; - - struct { - struct wl_signal destroy; - struct wl_signal ping_timeout; - struct wl_signal new_popup; - /** - * The `map` event signals that the shell surface is ready to be - * managed by the compositor and rendered on the screen. At this point, - * the surface has configured its properties, has had the opportunity - * to bind to the seat to receive input events, and has a buffer that - * is ready to be rendered. You can now safely add this surface to a - * list of views. - */ - struct wl_signal map; - /** - * The `unmap` event signals that the surface is no longer in a state - * where it should be shown on the screen. This might happen if the - * surface no longer has a displayable buffer because either the - * surface has been hidden or is about to be destroyed. - */ - struct wl_signal unmap; - } events; - - void *data; -}; - -struct wlr_xdg_toplevel_v6_move_event { - struct wlr_xdg_surface_v6 *surface; - struct wlr_seat_client *seat; - uint32_t serial; -}; - -struct wlr_xdg_toplevel_v6_resize_event { - struct wlr_xdg_surface_v6 *surface; - struct wlr_seat_client *seat; - uint32_t serial; - uint32_t edges; -}; - -struct wlr_xdg_toplevel_v6_set_fullscreen_event { - struct wlr_xdg_surface_v6 *surface; - bool fullscreen; - struct wlr_output *output; -}; - -struct wlr_xdg_toplevel_v6_show_window_menu_event { - struct wlr_xdg_surface_v6 *surface; - struct wlr_seat_client *seat; - uint32_t serial; - uint32_t x, y; -}; - -struct wlr_xdg_shell_v6 *wlr_xdg_shell_v6_create(struct wl_display *display); - -/** - * Send a ping to the surface. If the surface does not respond in a reasonable - * amount of time, the ping_timeout event will be emitted. - */ -void wlr_xdg_surface_v6_ping(struct wlr_xdg_surface_v6 *surface); - -/** - * Request that this toplevel surface be the given size. Returns the associated - * configure serial. - */ -uint32_t wlr_xdg_toplevel_v6_set_size(struct wlr_xdg_surface_v6 *surface, - uint32_t width, uint32_t height); - -/** - * Request that this toplevel surface show itself in an activated or deactivated - * state. Returns the associated configure serial. - */ -uint32_t wlr_xdg_toplevel_v6_set_activated(struct wlr_xdg_surface_v6 *surface, - bool activated); - -/** - * Request that this toplevel surface consider itself maximized or not - * maximized. Returns the associated configure serial. - */ -uint32_t wlr_xdg_toplevel_v6_set_maximized(struct wlr_xdg_surface_v6 *surface, - bool maximized); - -/** - * Request that this toplevel surface consider itself fullscreen or not - * fullscreen. Returns the associated configure serial. - */ -uint32_t wlr_xdg_toplevel_v6_set_fullscreen(struct wlr_xdg_surface_v6 *surface, - bool fullscreen); - -/** - * Request that this toplevel surface consider itself to be resizing or not - * resizing. Returns the associated configure serial. - */ -uint32_t wlr_xdg_toplevel_v6_set_resizing(struct wlr_xdg_surface_v6 *surface, - bool resizing); - -/** - * Request that this xdg surface closes. - */ -void wlr_xdg_surface_v6_send_close(struct wlr_xdg_surface_v6 *surface); - -/** - * Find a surface within this xdg-surface tree at the given surface-local - * coordinates. Returns the surface and coordinates in the leaf surface - * coordinate system or NULL if no surface is found at that location. - */ -struct wlr_surface *wlr_xdg_surface_v6_surface_at( - struct wlr_xdg_surface_v6 *surface, double sx, double sy, - double *sub_x, double *sub_y); - -/** - * Get the geometry for this positioner based on the anchor rect, gravity, and - * size of this positioner. - */ -struct wlr_box wlr_xdg_positioner_v6_get_geometry( - struct wlr_xdg_positioner_v6 *positioner); - -/** - * Get the anchor point for this popup in the toplevel parent's coordinate system. - */ -void wlr_xdg_popup_v6_get_anchor_point(struct wlr_xdg_popup_v6 *popup, - int *toplevel_sx, int *toplevel_sy); - -/** - * Convert the given coordinates in the popup coordinate system to the toplevel - * surface coordinate system. - */ -void wlr_xdg_popup_v6_get_toplevel_coords(struct wlr_xdg_popup_v6 *popup, - int popup_sx, int popup_sy, int *toplevel_sx, int *toplevel_sy); - -/** - * Set the geometry of this popup to unconstrain it according to its - * xdg-positioner rules. The box should be in the popup's root toplevel parent - * surface coordinate system. - */ -void wlr_xdg_popup_v6_unconstrain_from_box(struct wlr_xdg_popup_v6 *popup, - struct wlr_box *toplevel_sx_box); - -/** - Invert the right/left anchor and gravity for this positioner. This can be - used to "flip" the positioner around the anchor rect in the x direction. - */ -void wlr_positioner_v6_invert_x( - struct wlr_xdg_positioner_v6 *positioner); - -/** - Invert the top/bottom anchor and gravity for this positioner. This can be - used to "flip" the positioner around the anchor rect in the y direction. - */ -void wlr_positioner_v6_invert_y( - struct wlr_xdg_positioner_v6 *positioner); - -bool wlr_surface_is_xdg_surface_v6(struct wlr_surface *surface); - -struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6_from_wlr_surface( - struct wlr_surface *surface); - -/** - * Get the surface geometry. - * This is either the geometry as set by the client, or defaulted to the bounds - * of the surface + the subsurfaces (as specified by the protocol). - * - * The x and y value can be <0 - */ -void wlr_xdg_surface_v6_get_geometry(struct wlr_xdg_surface_v6 *surface, struct wlr_box *box); - -/** - * Call `iterator` on each surface and popup in the xdg-surface tree, with the - * surface's position relative to the root xdg-surface. The function is called - * from root to leaves (in rendering order). - */ -void wlr_xdg_surface_v6_for_each_surface(struct wlr_xdg_surface_v6 *surface, - wlr_surface_iterator_func_t iterator, void *user_data); - -/** - * Call `iterator` on each popup in the xdg-surface tree, with the popup's - * position relative to the root xdg-surface. The function is called from root - * to leaves (in rendering order). - */ -void wlr_xdg_surface_v6_for_each_popup(struct wlr_xdg_surface_v6 *surface, - wlr_surface_iterator_func_t iterator, void *user_data); - -#endif diff --git a/protocol/meson.build b/protocol/meson.build index 2369b70e3..b9b74ca57 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -28,7 +28,6 @@ protocols = { 'text-input-unstable-v3': wl_protocol_dir / 'unstable/text-input/text-input-unstable-v3.xml', 'xdg-decoration-unstable-v1': wl_protocol_dir / 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml', 'xdg-output-unstable-v1': wl_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml', - 'xdg-shell-unstable-v6': wl_protocol_dir / 'unstable/xdg-shell/xdg-shell-unstable-v6.xml', # Other protocols 'gtk-primary-selection': 'gtk-primary-selection.xml', 'kde-idle': 'idle.xml', diff --git a/types/meson.build b/types/meson.build index 998e6b455..80978176e 100644 --- a/types/meson.build +++ b/types/meson.build @@ -11,11 +11,6 @@ wlr_files += files( 'tablet_v2/wlr_tablet_v2_tablet.c', 'tablet_v2/wlr_tablet_v2_tool.c', 'tablet_v2/wlr_tablet_v2.c', - 'xdg_shell_v6/wlr_xdg_popup_v6.c', - 'xdg_shell_v6/wlr_xdg_positioner_v6.c', - 'xdg_shell_v6/wlr_xdg_shell_v6.c', - 'xdg_shell_v6/wlr_xdg_surface_v6.c', - 'xdg_shell_v6/wlr_xdg_toplevel_v6.c', 'xdg_shell/wlr_xdg_popup.c', 'xdg_shell/wlr_xdg_positioner.c', 'xdg_shell/wlr_xdg_shell.c', diff --git a/types/xdg_shell_v6/wlr_xdg_popup_v6.c b/types/xdg_shell_v6/wlr_xdg_popup_v6.c deleted file mode 100644 index bed7e6d90..000000000 --- a/types/xdg_shell_v6/wlr_xdg_popup_v6.c +++ /dev/null @@ -1,585 +0,0 @@ -#include -#include -#include -#include "types/wlr_xdg_shell_v6.h" -#include "util/signal.h" - -static struct wlr_xdg_surface_v6 *xdg_popup_grab_get_topmost( - struct wlr_xdg_popup_grab_v6 *grab) { - struct wlr_xdg_popup_v6 *popup; - wl_list_for_each(popup, &grab->popups, grab_link) { - return popup->base; - } - - return NULL; -} - -static void xdg_popup_grab_end(struct wlr_xdg_popup_grab_v6 *popup_grab) { - struct wlr_xdg_popup_v6 *popup, *tmp; - wl_list_for_each_safe(popup, tmp, &popup_grab->popups, grab_link) { - zxdg_popup_v6_send_popup_done(popup->resource); - } - - wlr_seat_pointer_end_grab(popup_grab->seat); - wlr_seat_keyboard_end_grab(popup_grab->seat); - wlr_seat_touch_end_grab(popup_grab->seat); -} - -static void xdg_pointer_grab_enter(struct wlr_seat_pointer_grab *grab, - struct wlr_surface *surface, double sx, double sy) { - struct wlr_xdg_popup_grab_v6 *popup_grab = grab->data; - if (wl_resource_get_client(surface->resource) == popup_grab->client) { - wlr_seat_pointer_enter(grab->seat, surface, sx, sy); - } else { - wlr_seat_pointer_clear_focus(grab->seat); - } -} - -static void xdg_pointer_grab_clear_focus(struct wlr_seat_pointer_grab *grab) { - wlr_seat_pointer_clear_focus(grab->seat); -} - -static void xdg_pointer_grab_motion(struct wlr_seat_pointer_grab *grab, - uint32_t time, double sx, double sy) { - wlr_seat_pointer_send_motion(grab->seat, time, sx, sy); -} - -static uint32_t xdg_pointer_grab_button(struct wlr_seat_pointer_grab *grab, - uint32_t time, uint32_t button, uint32_t state) { - uint32_t serial = - wlr_seat_pointer_send_button(grab->seat, time, button, state); - if (serial) { - return serial; - } else { - xdg_popup_grab_end(grab->data); - return 0; - } -} - -static void xdg_pointer_grab_axis(struct wlr_seat_pointer_grab *grab, - uint32_t time, enum wlr_axis_orientation orientation, double value, - int32_t value_discrete, enum wlr_axis_source source) { - wlr_seat_pointer_send_axis(grab->seat, time, orientation, value, - value_discrete, source); -} - -static void xdg_pointer_grab_frame(struct wlr_seat_pointer_grab *grab) { - wlr_seat_pointer_send_frame(grab->seat); -} - -static void xdg_pointer_grab_cancel(struct wlr_seat_pointer_grab *grab) { - xdg_popup_grab_end(grab->data); -} - -static const struct wlr_pointer_grab_interface xdg_pointer_grab_impl = { - .enter = xdg_pointer_grab_enter, - .clear_focus = xdg_pointer_grab_clear_focus, - .motion = xdg_pointer_grab_motion, - .button = xdg_pointer_grab_button, - .cancel = xdg_pointer_grab_cancel, - .axis = xdg_pointer_grab_axis, - .frame = xdg_pointer_grab_frame, -}; - -static void xdg_keyboard_grab_enter(struct wlr_seat_keyboard_grab *grab, - struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes, - struct wlr_keyboard_modifiers *modifiers) { - // keyboard focus should remain on the popup -} - -static void xdg_keyboard_grab_clear_focus(struct wlr_seat_keyboard_grab *grab) { - // keyboard focus should remain on the popup -} - -static void xdg_keyboard_grab_key(struct wlr_seat_keyboard_grab *grab, - uint32_t time, uint32_t key, uint32_t state) { - wlr_seat_keyboard_send_key(grab->seat, time, key, state); -} - -static void xdg_keyboard_grab_modifiers(struct wlr_seat_keyboard_grab *grab, - struct wlr_keyboard_modifiers *modifiers) { - wlr_seat_keyboard_send_modifiers(grab->seat, modifiers); -} - -static void xdg_keyboard_grab_cancel(struct wlr_seat_keyboard_grab *grab) { - wlr_seat_pointer_end_grab(grab->seat); -} - -static const struct wlr_keyboard_grab_interface xdg_keyboard_grab_impl = { - .enter = xdg_keyboard_grab_enter, - .clear_focus = xdg_keyboard_grab_clear_focus, - .key = xdg_keyboard_grab_key, - .modifiers = xdg_keyboard_grab_modifiers, - .cancel = xdg_keyboard_grab_cancel, -}; - -static uint32_t xdg_touch_grab_down(struct wlr_seat_touch_grab *grab, - uint32_t time, struct wlr_touch_point *point) { - struct wlr_xdg_popup_grab_v6 *popup_grab = grab->data; - - if (wl_resource_get_client(point->surface->resource) != popup_grab->client) { - xdg_popup_grab_end(grab->data); - return 0; - } - - return wlr_seat_touch_send_down(grab->seat, point->surface, time, - point->touch_id, point->sx, point->sy); -} - -static void xdg_touch_grab_up(struct wlr_seat_touch_grab *grab, - uint32_t time, struct wlr_touch_point *point) { - wlr_seat_touch_send_up(grab->seat, time, point->touch_id); -} - -static void xdg_touch_grab_motion(struct wlr_seat_touch_grab *grab, - uint32_t time, struct wlr_touch_point *point) { - wlr_seat_touch_send_motion(grab->seat, time, point->touch_id, point->sx, - point->sy); -} - -static void xdg_touch_grab_enter(struct wlr_seat_touch_grab *grab, - uint32_t time, struct wlr_touch_point *point) { -} - -static void xdg_touch_grab_cancel(struct wlr_seat_touch_grab *grab) { - wlr_seat_touch_end_grab(grab->seat); -} - -static const struct wlr_touch_grab_interface xdg_touch_grab_impl = { - .down = xdg_touch_grab_down, - .up = xdg_touch_grab_up, - .motion = xdg_touch_grab_motion, - .enter = xdg_touch_grab_enter, - .cancel = xdg_touch_grab_cancel -}; - -static void xdg_popup_grab_handle_seat_destroy( - struct wl_listener *listener, void *data) { - struct wlr_xdg_popup_grab_v6 *xdg_grab = - wl_container_of(listener, xdg_grab, seat_destroy); - - wl_list_remove(&xdg_grab->seat_destroy.link); - - struct wlr_xdg_popup_v6 *popup, *next; - wl_list_for_each_safe(popup, next, &xdg_grab->popups, grab_link) { - destroy_xdg_surface_v6(popup->base); - } - - wl_list_remove(&xdg_grab->link); - free(xdg_grab); -} - -struct wlr_xdg_popup_grab_v6 *get_xdg_shell_v6_popup_grab_from_seat( - struct wlr_xdg_shell_v6 *shell, struct wlr_seat *seat) { - struct wlr_xdg_popup_grab_v6 *xdg_grab; - wl_list_for_each(xdg_grab, &shell->popup_grabs, link) { - if (xdg_grab->seat == seat) { - return xdg_grab; - } - } - - xdg_grab = calloc(1, sizeof(struct wlr_xdg_popup_grab_v6)); - if (!xdg_grab) { - return NULL; - } - - xdg_grab->pointer_grab.data = xdg_grab; - xdg_grab->pointer_grab.interface = &xdg_pointer_grab_impl; - xdg_grab->keyboard_grab.data = xdg_grab; - xdg_grab->keyboard_grab.interface = &xdg_keyboard_grab_impl; - xdg_grab->touch_grab.data = xdg_grab; - xdg_grab->touch_grab.interface = &xdg_touch_grab_impl; - - wl_list_init(&xdg_grab->popups); - - wl_list_insert(&shell->popup_grabs, &xdg_grab->link); - xdg_grab->seat = seat; - - xdg_grab->seat_destroy.notify = xdg_popup_grab_handle_seat_destroy; - wl_signal_add(&seat->events.destroy, &xdg_grab->seat_destroy); - - return xdg_grab; -} - - -static const struct zxdg_popup_v6_interface zxdg_popup_v6_implementation; - -static struct wlr_xdg_surface_v6 *xdg_surface_from_xdg_popup_resource( - struct wl_resource *resource) { - assert(wl_resource_instance_of(resource, &zxdg_popup_v6_interface, - &zxdg_popup_v6_implementation)); - return wl_resource_get_user_data(resource); -} - -void destroy_xdg_popup_v6(struct wlr_xdg_surface_v6 *surface) { - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP); - unmap_xdg_surface_v6(surface); - - wl_resource_set_user_data(surface->popup->resource, NULL); - wl_list_remove(&surface->popup->link); - free(surface->popup); - surface->popup = NULL; - - surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE; -} - -static void xdg_popup_handle_grab(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *seat_resource, - uint32_t serial) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_popup_resource(resource); - struct wlr_seat_client *seat_client = - wlr_seat_client_from_resource(seat_resource); - if (!surface) { - return; - } - - if (surface->popup->committed) { - wl_resource_post_error(surface->popup->resource, - ZXDG_POPUP_V6_ERROR_INVALID_GRAB, - "xdg_popup is already mapped"); - return; - } - - struct wlr_xdg_popup_grab_v6 *popup_grab = - get_xdg_shell_v6_popup_grab_from_seat(surface->client->shell, - seat_client->seat); - - struct wlr_xdg_surface_v6 *topmost = xdg_popup_grab_get_topmost(popup_grab); - bool parent_is_toplevel = - surface->popup->parent->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL; - - if ((topmost == NULL && !parent_is_toplevel) || - (topmost != NULL && topmost != surface->popup->parent)) { - wl_resource_post_error(surface->client->resource, - ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP, - "xdg_popup was not created on the topmost popup"); - return; - } - - popup_grab->client = surface->client->client; - surface->popup->seat = seat_client->seat; - - wl_list_insert(&popup_grab->popups, &surface->popup->grab_link); - - wlr_seat_pointer_start_grab(seat_client->seat, - &popup_grab->pointer_grab); - wlr_seat_keyboard_start_grab(seat_client->seat, - &popup_grab->keyboard_grab); - wlr_seat_touch_start_grab(seat_client->seat, - &popup_grab->touch_grab); -} - -static void xdg_popup_handle_destroy(struct wl_client *client, - struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_popup_resource(resource); - - if (surface && !wl_list_empty(&surface->popups)) { - wl_resource_post_error(surface->client->resource, - ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP, - "xdg_popup was destroyed while it was not the topmost popup"); - return; - } - - wl_resource_destroy(resource); -} - -static const struct zxdg_popup_v6_interface zxdg_popup_v6_implementation = { - .destroy = xdg_popup_handle_destroy, - .grab = xdg_popup_handle_grab, -}; - -static void xdg_popup_handle_resource_destroy(struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_popup_resource(resource); - if (surface != NULL) { - destroy_xdg_popup_v6(surface); - } -} - -void handle_xdg_surface_v6_popup_committed(struct wlr_xdg_surface_v6 *surface) { - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP); - - if (!surface->popup->committed) { - schedule_xdg_surface_v6_configure(surface); - surface->popup->committed = true; - } -} - -const struct wlr_surface_role xdg_popup_v6_surface_role = { - .name = "xdg_popup_v6", - .commit = handle_xdg_surface_v6_commit, - .precommit = handle_xdg_surface_v6_precommit, -}; - -void create_xdg_popup_v6(struct wlr_xdg_surface_v6 *xdg_surface, - struct wlr_xdg_surface_v6 *parent, - struct wlr_xdg_positioner_v6_resource *positioner, int32_t id) { - if (positioner->attrs.size.width == 0 || - positioner->attrs.anchor_rect.width == 0) { - wl_resource_post_error(xdg_surface->resource, - ZXDG_SHELL_V6_ERROR_INVALID_POSITIONER, - "positioner object is not complete"); - return; - } - - if (!wlr_surface_set_role(xdg_surface->surface, &xdg_popup_v6_surface_role, - xdg_surface, xdg_surface->resource, ZXDG_SHELL_V6_ERROR_ROLE)) { - return; - } - - xdg_surface->popup = calloc(1, sizeof(struct wlr_xdg_popup_v6)); - if (!xdg_surface->popup) { - wl_resource_post_no_memory(xdg_surface->resource); - return; - } - - xdg_surface->popup->resource = - wl_resource_create(xdg_surface->client->client, &zxdg_popup_v6_interface, - wl_resource_get_version(xdg_surface->resource), id); - if (xdg_surface->popup->resource == NULL) { - free(xdg_surface->popup); - wl_resource_post_no_memory(xdg_surface->resource); - return; - } - wl_resource_set_implementation(xdg_surface->popup->resource, - &zxdg_popup_v6_implementation, xdg_surface, - xdg_popup_handle_resource_destroy); - - xdg_surface->role = WLR_XDG_SURFACE_V6_ROLE_POPUP; - xdg_surface->popup->base = xdg_surface; - xdg_surface->popup->parent = parent; - xdg_surface->popup->geometry = - wlr_xdg_positioner_v6_get_geometry(&positioner->attrs); - - // positioner properties - memcpy(&xdg_surface->popup->positioner, &positioner->attrs, - sizeof(struct wlr_xdg_positioner_v6)); - - wl_list_insert(&parent->popups, &xdg_surface->popup->link); - - wlr_signal_emit_safe(&parent->events.new_popup, xdg_surface->popup); -} - -void wlr_xdg_popup_v6_get_anchor_point(struct wlr_xdg_popup_v6 *popup, - int *root_sx, int *root_sy) { - struct wlr_box rect = popup->positioner.anchor_rect; - enum zxdg_positioner_v6_anchor anchor = popup->positioner.anchor; - int sx = 0, sy = 0; - - if (anchor == ZXDG_POSITIONER_V6_ANCHOR_NONE) { - sx = (rect.x + rect.width) / 2; - sy = (rect.y + rect.height) / 2; - } else if (anchor == ZXDG_POSITIONER_V6_ANCHOR_TOP) { - sx = (rect.x + rect.width) / 2; - sy = rect.y; - } else if (anchor == ZXDG_POSITIONER_V6_ANCHOR_BOTTOM) { - sx = (rect.x + rect.width) / 2; - sy = rect.y + rect.height; - } else if (anchor == ZXDG_POSITIONER_V6_ANCHOR_LEFT) { - sx = rect.x; - sy = (rect.y + rect.height) / 2; - } else if (anchor == ZXDG_POSITIONER_V6_ANCHOR_RIGHT) { - sx = rect.x + rect.width; - sy = (rect.y + rect.height) / 2; - } else if (anchor == (ZXDG_POSITIONER_V6_ANCHOR_TOP | - ZXDG_POSITIONER_V6_ANCHOR_LEFT)) { - sx = rect.x; - sy = rect.y; - } else if (anchor == (ZXDG_POSITIONER_V6_ANCHOR_TOP | - ZXDG_POSITIONER_V6_ANCHOR_RIGHT)) { - sx = rect.x + rect.width; - sy = rect.y; - } else if (anchor == (ZXDG_POSITIONER_V6_ANCHOR_BOTTOM | - ZXDG_POSITIONER_V6_ANCHOR_LEFT)) { - sx = rect.x; - sy = rect.y + rect.height; - } else if (anchor == (ZXDG_POSITIONER_V6_ANCHOR_BOTTOM | - ZXDG_POSITIONER_V6_ANCHOR_RIGHT)) { - sx = rect.x + rect.width; - sy = rect.y + rect.height; - } - - *root_sx = sx; - *root_sy = sy; -} - -void wlr_xdg_popup_v6_get_toplevel_coords(struct wlr_xdg_popup_v6 *popup, - int popup_sx, int popup_sy, int *toplevel_sx, int *toplevel_sy) { - struct wlr_xdg_surface_v6 *parent = popup->parent; - while (parent != NULL && parent->role == WLR_XDG_SURFACE_V6_ROLE_POPUP) { - popup_sx += parent->popup->geometry.x; - popup_sy += parent->popup->geometry.y; - parent = parent->popup->parent; - } - assert(parent); - - *toplevel_sx = popup_sx + parent->geometry.x; - *toplevel_sy = popup_sy + parent->geometry.y; -} - -static void xdg_popup_v6_box_constraints(struct wlr_xdg_popup_v6 *popup, - struct wlr_box *toplevel_sx_box, int *offset_x, int *offset_y) { - int popup_width = popup->geometry.width; - int popup_height = popup->geometry.height; - int anchor_sx = 0, anchor_sy = 0; - wlr_xdg_popup_v6_get_anchor_point(popup, &anchor_sx, &anchor_sy); - int popup_sx = 0, popup_sy = 0; - wlr_xdg_popup_v6_get_toplevel_coords(popup, popup->geometry.x, - popup->geometry.y, &popup_sx, &popup_sy); - *offset_x = 0, *offset_y = 0; - - if (popup_sx < toplevel_sx_box->x) { - *offset_x = toplevel_sx_box->x - popup_sx; - } else if (popup_sx + popup_width > - toplevel_sx_box->x + toplevel_sx_box->width) { - *offset_x = toplevel_sx_box->x + toplevel_sx_box->width - - (popup_sx + popup_width); - } - - if (popup_sy < toplevel_sx_box->y) { - *offset_y = toplevel_sx_box->y - popup_sy; - } else if (popup_sy + popup_height > - toplevel_sx_box->y + toplevel_sx_box->height) { - *offset_y = toplevel_sx_box->y + toplevel_sx_box->height - - (popup_sy + popup_height); - } -} - -static bool xdg_popup_v6_unconstrain_flip(struct wlr_xdg_popup_v6 *popup, - struct wlr_box *toplevel_sx_box) { - int offset_x = 0, offset_y = 0; - xdg_popup_v6_box_constraints(popup, toplevel_sx_box, - &offset_x, &offset_y); - - if (!offset_x && !offset_y) { - return true; - } - - bool flip_x = offset_x && - (popup->positioner.constraint_adjustment & - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X); - - bool flip_y = offset_y && - (popup->positioner.constraint_adjustment & - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y); - - if (flip_x) { - wlr_positioner_v6_invert_x(&popup->positioner); - } - if (flip_y) { - wlr_positioner_v6_invert_y(&popup->positioner); - } - - popup->geometry = - wlr_xdg_positioner_v6_get_geometry(&popup->positioner); - - xdg_popup_v6_box_constraints(popup, toplevel_sx_box, - &offset_x, &offset_y); - - if (!offset_x && !offset_y) { - // no longer constrained - return true; - } - - // revert the positioner back if it didn't fix it and go to the next part - if (offset_x && flip_x) { - wlr_positioner_v6_invert_x(&popup->positioner); - } - if (offset_y && flip_y) { - wlr_positioner_v6_invert_y(&popup->positioner); - } - - popup->geometry = - wlr_xdg_positioner_v6_get_geometry(&popup->positioner); - - return false; -} - -static bool xdg_popup_v6_unconstrain_slide(struct wlr_xdg_popup_v6 *popup, - struct wlr_box *toplevel_sx_box) { - int offset_x = 0, offset_y = 0; - xdg_popup_v6_box_constraints(popup, toplevel_sx_box, - &offset_x, &offset_y); - - if (!offset_x && !offset_y) { - return true; - } - - bool slide_x = offset_x && - (popup->positioner.constraint_adjustment & - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X); - - bool slide_y = offset_y && - (popup->positioner.constraint_adjustment & - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y); - - if (slide_x) { - popup->geometry.x += offset_x; - } - - if (slide_y) { - popup->geometry.y += offset_y; - } - - int toplevel_x = 0, toplevel_y = 0; - wlr_xdg_popup_v6_get_toplevel_coords(popup, popup->geometry.x, - popup->geometry.y, &toplevel_x, &toplevel_y); - - if (slide_x && toplevel_x < toplevel_sx_box->x) { - popup->geometry.x += toplevel_sx_box->x - toplevel_x; - } - if (slide_y && toplevel_y < toplevel_sx_box->y) { - popup->geometry.y += toplevel_sx_box->y - toplevel_y; - } - - xdg_popup_v6_box_constraints(popup, toplevel_sx_box, - &offset_x, &offset_y); - - return !offset_x && !offset_y; -} - -static bool xdg_popup_v6_unconstrain_resize(struct wlr_xdg_popup_v6 *popup, - struct wlr_box *toplevel_sx_box) { - int offset_x, offset_y; - xdg_popup_v6_box_constraints(popup, toplevel_sx_box, - &offset_x, &offset_y); - - if (!offset_x && !offset_y) { - return true; - } - - bool resize_x = offset_x && - (popup->positioner.constraint_adjustment & - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_X); - - bool resize_y = offset_y && - (popup->positioner.constraint_adjustment & - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y); - - if (resize_x) { - popup->geometry.width -= offset_x; - } - if (resize_y) { - popup->geometry.height -= offset_y; - } - - xdg_popup_v6_box_constraints(popup, toplevel_sx_box, - &offset_x, &offset_y); - - return !offset_x && !offset_y; -} - -void wlr_xdg_popup_v6_unconstrain_from_box(struct wlr_xdg_popup_v6 *popup, - struct wlr_box *toplevel_sx_box) { - if (xdg_popup_v6_unconstrain_flip(popup, toplevel_sx_box)) { - return; - } - if (xdg_popup_v6_unconstrain_slide(popup, toplevel_sx_box)) { - return; - } - if (xdg_popup_v6_unconstrain_resize(popup, toplevel_sx_box)) { - return; - } -} diff --git a/types/xdg_shell_v6/wlr_xdg_positioner_v6.c b/types/xdg_shell_v6/wlr_xdg_positioner_v6.c deleted file mode 100644 index eda19f30c..000000000 --- a/types/xdg_shell_v6/wlr_xdg_positioner_v6.c +++ /dev/null @@ -1,230 +0,0 @@ -#include -#include -#include "types/wlr_xdg_shell_v6.h" - -static const struct zxdg_positioner_v6_interface - zxdg_positioner_v6_implementation; - -struct wlr_xdg_positioner_v6_resource *get_xdg_positioner_v6_from_resource( - struct wl_resource *resource) { - assert(wl_resource_instance_of(resource, &zxdg_positioner_v6_interface, - &zxdg_positioner_v6_implementation)); - return wl_resource_get_user_data(resource); -} - -static void xdg_positioner_destroy(struct wl_resource *resource) { - struct wlr_xdg_positioner_v6_resource *positioner = - get_xdg_positioner_v6_from_resource(resource); - free(positioner); -} - -static void xdg_positioner_handle_destroy(struct wl_client *client, - struct wl_resource *resource) { - wl_resource_destroy(resource); -} - -static void xdg_positioner_handle_set_size(struct wl_client *client, - struct wl_resource *resource, int32_t width, int32_t height) { - struct wlr_xdg_positioner_v6_resource *positioner = - get_xdg_positioner_v6_from_resource(resource); - - if (width < 1 || height < 1) { - wl_resource_post_error(resource, - ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, - "width and height must be positive and non-zero"); - return; - } - - positioner->attrs.size.width = width; - positioner->attrs.size.height = height; -} - -static void xdg_positioner_handle_set_anchor_rect(struct wl_client *client, - struct wl_resource *resource, int32_t x, int32_t y, int32_t width, - int32_t height) { - struct wlr_xdg_positioner_v6_resource *positioner = - get_xdg_positioner_v6_from_resource(resource); - - if (width < 1 || height < 1) { - wl_resource_post_error(resource, - ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, - "width and height must be positive and non-zero"); - return; - } - - positioner->attrs.anchor_rect.x = x; - positioner->attrs.anchor_rect.y = y; - positioner->attrs.anchor_rect.width = width; - positioner->attrs.anchor_rect.height = height; -} - -static void xdg_positioner_handle_set_anchor(struct wl_client *client, - struct wl_resource *resource, uint32_t anchor) { - struct wlr_xdg_positioner_v6_resource *positioner = - get_xdg_positioner_v6_from_resource(resource); - - if (((anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP ) && - (anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM)) || - ((anchor & ZXDG_POSITIONER_V6_ANCHOR_LEFT) && - (anchor & ZXDG_POSITIONER_V6_ANCHOR_RIGHT))) { - wl_resource_post_error(resource, - ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, - "same-axis values are not allowed"); - return; - } - - positioner->attrs.anchor = anchor; -} - -static void xdg_positioner_handle_set_gravity(struct wl_client *client, - struct wl_resource *resource, uint32_t gravity) { - struct wlr_xdg_positioner_v6_resource *positioner = - get_xdg_positioner_v6_from_resource(resource); - - if (((gravity & ZXDG_POSITIONER_V6_GRAVITY_TOP) && - (gravity & ZXDG_POSITIONER_V6_GRAVITY_BOTTOM)) || - ((gravity & ZXDG_POSITIONER_V6_GRAVITY_LEFT) && - (gravity & ZXDG_POSITIONER_V6_GRAVITY_RIGHT))) { - wl_resource_post_error(resource, - ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, - "same-axis values are not allowed"); - return; - } - - positioner->attrs.gravity = gravity; -} - -static void xdg_positioner_handle_set_constraint_adjustment( - struct wl_client *client, struct wl_resource *resource, - uint32_t constraint_adjustment) { - struct wlr_xdg_positioner_v6_resource *positioner = - get_xdg_positioner_v6_from_resource(resource); - - positioner->attrs.constraint_adjustment = constraint_adjustment; -} - -static void xdg_positioner_handle_set_offset(struct wl_client *client, - struct wl_resource *resource, int32_t x, int32_t y) { - struct wlr_xdg_positioner_v6_resource *positioner = - get_xdg_positioner_v6_from_resource(resource); - - positioner->attrs.offset.x = x; - positioner->attrs.offset.y = y; -} - -static const struct zxdg_positioner_v6_interface - zxdg_positioner_v6_implementation = { - .destroy = xdg_positioner_handle_destroy, - .set_size = xdg_positioner_handle_set_size, - .set_anchor_rect = xdg_positioner_handle_set_anchor_rect, - .set_anchor = xdg_positioner_handle_set_anchor, - .set_gravity = xdg_positioner_handle_set_gravity, - .set_constraint_adjustment = - xdg_positioner_handle_set_constraint_adjustment, - .set_offset = xdg_positioner_handle_set_offset, -}; - -struct wlr_box wlr_xdg_positioner_v6_get_geometry( - struct wlr_xdg_positioner_v6 *positioner) { - struct wlr_box geometry = { - .x = positioner->offset.x, - .y = positioner->offset.y, - .width = positioner->size.width, - .height = positioner->size.height, - }; - - if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP) { - geometry.y += positioner->anchor_rect.y; - } else if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM) { - geometry.y += - positioner->anchor_rect.y + positioner->anchor_rect.height; - } else { - geometry.y += - positioner->anchor_rect.y + positioner->anchor_rect.height / 2; - } - - if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_LEFT) { - geometry.x += positioner->anchor_rect.x; - } else if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_RIGHT) { - geometry.x += positioner->anchor_rect.x + positioner->anchor_rect.width; - } else { - geometry.x += - positioner->anchor_rect.x + positioner->anchor_rect.width / 2; - } - - if (positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_TOP) { - geometry.y -= geometry.height; - } else if (!(positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_BOTTOM)) { - geometry.y -= geometry.height / 2; - } - - if (positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_LEFT) { - geometry.x -= geometry.width; - } else if (!(positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_RIGHT)) { - geometry.x -= geometry.width / 2; - } - - if (positioner->constraint_adjustment == - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_NONE) { - return geometry; - } - - return geometry; -} - -void wlr_positioner_v6_invert_x(struct wlr_xdg_positioner_v6 *positioner) { - if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_LEFT) { - positioner->anchor &= ~ZXDG_POSITIONER_V6_ANCHOR_LEFT; - positioner->anchor |= ZXDG_POSITIONER_V6_ANCHOR_RIGHT; - } else if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_RIGHT) { - positioner->anchor &= ~ZXDG_POSITIONER_V6_ANCHOR_RIGHT; - positioner->anchor |= ZXDG_POSITIONER_V6_ANCHOR_LEFT; - } - - if (positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_RIGHT) { - positioner->gravity &= ~ZXDG_POSITIONER_V6_GRAVITY_RIGHT; - positioner->gravity |= ZXDG_POSITIONER_V6_GRAVITY_LEFT; - } else if (positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_LEFT) { - positioner->gravity &= ~ZXDG_POSITIONER_V6_GRAVITY_LEFT; - positioner->gravity |= ZXDG_POSITIONER_V6_GRAVITY_RIGHT; - } -} - -void wlr_positioner_v6_invert_y( - struct wlr_xdg_positioner_v6 *positioner) { - if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP) { - positioner->anchor &= ~ZXDG_POSITIONER_V6_ANCHOR_TOP; - positioner->anchor |= ZXDG_POSITIONER_V6_ANCHOR_BOTTOM; - } else if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM) { - positioner->anchor &= ~ZXDG_POSITIONER_V6_ANCHOR_BOTTOM; - positioner->anchor |= ZXDG_POSITIONER_V6_ANCHOR_TOP; - } - - if (positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_TOP) { - positioner->gravity &= ~ZXDG_POSITIONER_V6_GRAVITY_TOP; - positioner->gravity |= ZXDG_POSITIONER_V6_GRAVITY_BOTTOM; - } else if (positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_BOTTOM) { - positioner->gravity &= ~ZXDG_POSITIONER_V6_GRAVITY_BOTTOM; - positioner->gravity |= ZXDG_POSITIONER_V6_GRAVITY_TOP; - } -} - -void create_xdg_positioner_v6(struct wlr_xdg_client_v6 *client, uint32_t id) { - struct wlr_xdg_positioner_v6_resource *positioner = - calloc(1, sizeof(struct wlr_xdg_positioner_v6_resource)); - if (positioner == NULL) { - wl_client_post_no_memory(client->client); - return; - } - - positioner->resource = wl_resource_create(client->client, - &zxdg_positioner_v6_interface, - wl_resource_get_version(client->resource), id); - if (positioner->resource == NULL) { - free(positioner); - wl_client_post_no_memory(client->client); - return; - } - wl_resource_set_implementation(positioner->resource, - &zxdg_positioner_v6_implementation, positioner, xdg_positioner_destroy); -} diff --git a/types/xdg_shell_v6/wlr_xdg_shell_v6.c b/types/xdg_shell_v6/wlr_xdg_shell_v6.c deleted file mode 100644 index fcaa41e16..000000000 --- a/types/xdg_shell_v6/wlr_xdg_shell_v6.c +++ /dev/null @@ -1,168 +0,0 @@ -#include -#include -#include "types/wlr_xdg_shell_v6.h" -#include "util/signal.h" - -#define SHELL_VERSION 1 - -static const struct zxdg_shell_v6_interface xdg_shell_impl; - -static struct wlr_xdg_client_v6 *xdg_client_from_resource( - struct wl_resource *resource) { - assert(wl_resource_instance_of(resource, &zxdg_shell_v6_interface, - &xdg_shell_impl)); - return wl_resource_get_user_data(resource); -} - -static void xdg_shell_handle_create_positioner(struct wl_client *wl_client, - struct wl_resource *resource, uint32_t id) { - struct wlr_xdg_client_v6 *client = - xdg_client_from_resource(resource); - create_xdg_positioner_v6(client, id); -} - -static void xdg_shell_handle_get_xdg_surface(struct wl_client *wl_client, - struct wl_resource *client_resource, uint32_t id, - struct wl_resource *surface_resource) { - struct wlr_xdg_client_v6 *client = - xdg_client_from_resource(client_resource); - struct wlr_surface *surface = wlr_surface_from_resource(surface_resource); - create_xdg_surface_v6(client, surface, id); -} - -static void xdg_shell_handle_pong(struct wl_client *wl_client, - struct wl_resource *resource, uint32_t serial) { - struct wlr_xdg_client_v6 *client = xdg_client_from_resource(resource); - - if (client->ping_serial != serial) { - return; - } - - wl_event_source_timer_update(client->ping_timer, 0); - client->ping_serial = 0; -} - -static void xdg_shell_handle_destroy(struct wl_client *wl_client, - struct wl_resource *resource) { - struct wlr_xdg_client_v6 *client = xdg_client_from_resource(resource); - - if (!wl_list_empty(&client->surfaces)) { - wl_resource_post_error(client->resource, - ZXDG_SHELL_V6_ERROR_DEFUNCT_SURFACES, - "xdg_wm_base was destroyed before children"); - return; - } - - wl_resource_destroy(resource); -} - -static const struct zxdg_shell_v6_interface xdg_shell_impl = { - .destroy = xdg_shell_handle_destroy, - .create_positioner = xdg_shell_handle_create_positioner, - .get_xdg_surface = xdg_shell_handle_get_xdg_surface, - .pong = xdg_shell_handle_pong, -}; - -static void xdg_client_v6_handle_resource_destroy( - struct wl_resource *resource) { - struct wlr_xdg_client_v6 *client = xdg_client_from_resource(resource); - - struct wlr_xdg_surface_v6 *surface, *tmp = NULL; - wl_list_for_each_safe(surface, tmp, &client->surfaces, link) { - wl_resource_destroy(surface->resource); - } - - if (client->ping_timer != NULL) { - wl_event_source_remove(client->ping_timer); - } - - wl_list_remove(&client->link); - free(client); -} - -static int xdg_client_v6_ping_timeout(void *user_data) { - struct wlr_xdg_client_v6 *client = user_data; - - struct wlr_xdg_surface_v6 *surface; - wl_list_for_each(surface, &client->surfaces, link) { - wlr_signal_emit_safe(&surface->events.ping_timeout, surface); - } - - client->ping_serial = 0; - return 1; -} - -static void xdg_shell_bind(struct wl_client *wl_client, void *data, - uint32_t version, uint32_t id) { - struct wlr_xdg_shell_v6 *xdg_shell = data; - assert(wl_client && xdg_shell); - - struct wlr_xdg_client_v6 *client = - calloc(1, sizeof(struct wlr_xdg_client_v6)); - if (client == NULL) { - wl_client_post_no_memory(wl_client); - return; - } - - wl_list_init(&client->surfaces); - - client->resource = - wl_resource_create(wl_client, &zxdg_shell_v6_interface, version, id); - if (client->resource == NULL) { - free(client); - wl_client_post_no_memory(wl_client); - return; - } - client->client = wl_client; - client->shell = xdg_shell; - - wl_resource_set_implementation(client->resource, &xdg_shell_impl, client, - xdg_client_v6_handle_resource_destroy); - wl_list_insert(&xdg_shell->clients, &client->link); - - struct wl_display *display = wl_client_get_display(client->client); - struct wl_event_loop *loop = wl_display_get_event_loop(display); - client->ping_timer = wl_event_loop_add_timer(loop, - xdg_client_v6_ping_timeout, client); - if (client->ping_timer == NULL) { - wl_client_post_no_memory(client->client); - } -} - -static void handle_display_destroy(struct wl_listener *listener, void *data) { - struct wlr_xdg_shell_v6 *xdg_shell = - wl_container_of(listener, xdg_shell, display_destroy); - wlr_signal_emit_safe(&xdg_shell->events.destroy, xdg_shell); - wl_list_remove(&xdg_shell->display_destroy.link); - wl_global_destroy(xdg_shell->global); - free(xdg_shell); -} - -struct wlr_xdg_shell_v6 *wlr_xdg_shell_v6_create(struct wl_display *display) { - struct wlr_xdg_shell_v6 *xdg_shell = - calloc(1, sizeof(struct wlr_xdg_shell_v6)); - if (!xdg_shell) { - return NULL; - } - - xdg_shell->ping_timeout = 10000; - - wl_list_init(&xdg_shell->clients); - wl_list_init(&xdg_shell->popup_grabs); - - struct wl_global *global = wl_global_create(display, - &zxdg_shell_v6_interface, SHELL_VERSION, xdg_shell, xdg_shell_bind); - if (!global) { - free(xdg_shell); - return NULL; - } - xdg_shell->global = global; - - wl_signal_init(&xdg_shell->events.new_surface); - wl_signal_init(&xdg_shell->events.destroy); - - xdg_shell->display_destroy.notify = handle_display_destroy; - wl_display_add_destroy_listener(display, &xdg_shell->display_destroy); - - return xdg_shell; -} diff --git a/types/xdg_shell_v6/wlr_xdg_surface_v6.c b/types/xdg_shell_v6/wlr_xdg_surface_v6.c deleted file mode 100644 index d9559b988..000000000 --- a/types/xdg_shell_v6/wlr_xdg_surface_v6.c +++ /dev/null @@ -1,606 +0,0 @@ -#include -#include -#include -#include -#include "types/wlr_xdg_shell_v6.h" -#include "util/signal.h" - -bool wlr_surface_is_xdg_surface_v6(struct wlr_surface *surface) { - return surface->role == &xdg_toplevel_v6_surface_role || - surface->role == &xdg_popup_v6_surface_role; -} - -struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6_from_wlr_surface( - struct wlr_surface *surface) { - assert(wlr_surface_is_xdg_surface_v6(surface)); - return (struct wlr_xdg_surface_v6 *)surface->role_data; -} - -static const struct zxdg_surface_v6_interface zxdg_surface_v6_implementation; - -static struct wlr_xdg_surface_v6 *xdg_surface_from_resource( - struct wl_resource *resource) { - assert(wl_resource_instance_of(resource, &zxdg_surface_v6_interface, - &zxdg_surface_v6_implementation)); - return wl_resource_get_user_data(resource); -} - -static void xdg_surface_configure_destroy( - struct wlr_xdg_surface_v6_configure *configure) { - if (configure == NULL) { - return; - } - wl_list_remove(&configure->link); - free(configure->toplevel_state); - free(configure); -} - -void unmap_xdg_surface_v6(struct wlr_xdg_surface_v6 *surface) { - assert(surface->role != WLR_XDG_SURFACE_V6_ROLE_NONE); - - // TODO: probably need to ungrab before this event - if (surface->mapped) { - wlr_signal_emit_safe(&surface->events.unmap, surface); - } - - switch (surface->role) { - case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL: - free(surface->toplevel->title); - surface->toplevel->title = NULL; - free(surface->toplevel->app_id); - surface->toplevel->app_id = NULL; - break; - case WLR_XDG_SURFACE_V6_ROLE_POPUP: - if (surface->popup->seat != NULL) { - struct wlr_xdg_popup_grab_v6 *grab = - get_xdg_shell_v6_popup_grab_from_seat(surface->client->shell, - surface->popup->seat); - - wl_list_remove(&surface->popup->grab_link); - - if (wl_list_empty(&grab->popups)) { - if (grab->seat->pointer_state.grab == &grab->pointer_grab) { - wlr_seat_pointer_end_grab(grab->seat); - } - if (grab->seat->keyboard_state.grab == &grab->keyboard_grab) { - wlr_seat_keyboard_end_grab(grab->seat); - } - } - - surface->popup->seat = NULL; - } - break; - case WLR_XDG_SURFACE_V6_ROLE_NONE: - assert(false && "not reached"); - } - - struct wlr_xdg_surface_v6_configure *configure, *tmp; - wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { - xdg_surface_configure_destroy(configure); - } - - surface->configured = surface->mapped = false; - surface->configure_serial = 0; - if (surface->configure_idle) { - wl_event_source_remove(surface->configure_idle); - surface->configure_idle = NULL; - } - surface->configure_next_serial = 0; - - surface->has_next_geometry = false; - memset(&surface->geometry, 0, sizeof(struct wlr_box)); - memset(&surface->next_geometry, 0, sizeof(struct wlr_box)); -} - -void destroy_xdg_surface_v6(struct wlr_xdg_surface_v6 *surface) { - if (surface->role != WLR_XDG_SURFACE_V6_ROLE_NONE) { - unmap_xdg_surface_v6(surface); - } - - wlr_signal_emit_safe(&surface->events.destroy, surface); - - struct wlr_xdg_popup_v6 *popup_state, *next; - wl_list_for_each_safe(popup_state, next, &surface->popups, link) { - zxdg_popup_v6_send_popup_done(popup_state->resource); - destroy_xdg_popup_v6(popup_state->base); - } - - switch (surface->role) { - case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL: - destroy_xdg_toplevel_v6(surface); - break; - case WLR_XDG_SURFACE_V6_ROLE_POPUP: - destroy_xdg_popup_v6(surface); - break; - case WLR_XDG_SURFACE_V6_ROLE_NONE: - // This space is intentionally left blank - break; - } - - wl_resource_set_user_data(surface->resource, NULL); - surface->surface->role_data = NULL; - wl_list_remove(&surface->link); - wl_list_remove(&surface->surface_destroy.link); - wl_list_remove(&surface->surface_commit.link); - free(surface); -} - -static void xdg_surface_handle_get_toplevel(struct wl_client *client, - struct wl_resource *resource, uint32_t id) { - struct wlr_xdg_surface_v6 *xdg_surface = xdg_surface_from_resource(resource); - create_xdg_toplevel_v6(xdg_surface, id); -} - -static void xdg_surface_handle_get_popup(struct wl_client *wl_client, - struct wl_resource *resource, uint32_t id, - struct wl_resource *parent_resource, - struct wl_resource *positioner_resource) { - struct wlr_xdg_surface_v6 *xdg_surface = - xdg_surface_from_resource(resource); - struct wlr_xdg_surface_v6 *parent = - xdg_surface_from_resource(parent_resource); - struct wlr_xdg_positioner_v6_resource *positioner = - get_xdg_positioner_v6_from_resource(positioner_resource); - - create_xdg_popup_v6(xdg_surface, parent, positioner, id); -} - -static void xdg_surface_handle_ack_configure(struct wl_client *client, - struct wl_resource *resource, uint32_t serial) { - struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource); - - if (surface->role == WLR_XDG_SURFACE_V6_ROLE_NONE) { - wl_resource_post_error(surface->resource, - ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, - "xdg_surface must have a role"); - return; - } - - // First find the ack'ed configure - bool found = false; - struct wlr_xdg_surface_v6_configure *configure, *tmp; - wl_list_for_each(configure, &surface->configure_list, link) { - if (configure->serial == serial) { - found = true; - break; - } - } - if (!found) { - wl_resource_post_error(surface->client->resource, - ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE, - "wrong configure serial: %u", serial); - return; - } - // Then remove old configures from the list - wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { - if (configure->serial == serial) { - break; - } - xdg_surface_configure_destroy(configure); - } - - switch (surface->role) { - case WLR_XDG_SURFACE_V6_ROLE_NONE: - assert(0 && "not reached"); - break; - case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL: - handle_xdg_toplevel_v6_ack_configure(surface, configure); - break; - case WLR_XDG_SURFACE_V6_ROLE_POPUP: - break; - } - - surface->configured = true; - surface->configure_serial = serial; - - xdg_surface_configure_destroy(configure); -} - -static void xdg_surface_handle_set_window_geometry(struct wl_client *client, - struct wl_resource *resource, int32_t x, int32_t y, int32_t width, - int32_t height) { - struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource); - - if (surface->role == WLR_XDG_SURFACE_V6_ROLE_NONE) { - wl_resource_post_error(surface->resource, - ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, - "xdg_surface must have a role"); - return; - } - - if (width <= 0 || height <= 0) { - wlr_log(WLR_ERROR, "Client tried to set invalid geometry"); - wl_resource_post_error(resource, -1, "Tried to set invalid xdg-surface geometry"); - } - - - surface->has_next_geometry = true; - surface->next_geometry.height = height; - surface->next_geometry.width = width; - surface->next_geometry.x = x; - surface->next_geometry.y = y; -} - -static void xdg_surface_handle_destroy(struct wl_client *client, - struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource); - - if (surface->role != WLR_XDG_SURFACE_V6_ROLE_NONE) { - wlr_log(WLR_ERROR, "Tried to destroy an xdg_surface before its role " - "object"); - return; - } - - wl_resource_destroy(resource); -} - -static const struct zxdg_surface_v6_interface zxdg_surface_v6_implementation = { - .destroy = xdg_surface_handle_destroy, - .get_toplevel = xdg_surface_handle_get_toplevel, - .get_popup = xdg_surface_handle_get_popup, - .ack_configure = xdg_surface_handle_ack_configure, - .set_window_geometry = xdg_surface_handle_set_window_geometry, -}; - -static void xdg_surface_send_configure(void *user_data) { - struct wlr_xdg_surface_v6 *surface = user_data; - - surface->configure_idle = NULL; - - struct wlr_xdg_surface_v6_configure *configure = - calloc(1, sizeof(struct wlr_xdg_surface_v6_configure)); - if (configure == NULL) { - wl_client_post_no_memory(surface->client->client); - return; - } - - wl_list_insert(surface->configure_list.prev, &configure->link); - configure->serial = surface->configure_next_serial; - - switch (surface->role) { - case WLR_XDG_SURFACE_V6_ROLE_NONE: - assert(0 && "not reached"); - break; - case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL: - send_xdg_toplevel_v6_configure(surface, configure); - break; - case WLR_XDG_SURFACE_V6_ROLE_POPUP: - zxdg_popup_v6_send_configure(surface->popup->resource, - surface->popup->geometry.x, - surface->popup->geometry.y, - surface->popup->geometry.width, - surface->popup->geometry.height); - break; - } - - zxdg_surface_v6_send_configure(surface->resource, configure->serial); -} - -uint32_t schedule_xdg_surface_v6_configure(struct wlr_xdg_surface_v6 *surface) { - struct wl_display *display = wl_client_get_display(surface->client->client); - struct wl_event_loop *loop = wl_display_get_event_loop(display); - bool pending_same = false; - - switch (surface->role) { - case WLR_XDG_SURFACE_V6_ROLE_NONE: - assert(0 && "not reached"); - break; - case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL: - pending_same = - compare_xdg_surface_v6_toplevel_state(surface->toplevel); - break; - case WLR_XDG_SURFACE_V6_ROLE_POPUP: - break; - } - - if (surface->configure_idle != NULL) { - if (!pending_same) { - // configure request already scheduled - return surface->configure_next_serial; - } - - // configure request not necessary anymore - wl_event_source_remove(surface->configure_idle); - surface->configure_idle = NULL; - return 0; - } else { - if (pending_same) { - // configure request not necessary - return 0; - } - - surface->configure_next_serial = wl_display_next_serial(display); - surface->configure_idle = wl_event_loop_add_idle(loop, - xdg_surface_send_configure, surface); - return surface->configure_next_serial; - } -} - -void wlr_xdg_surface_v6_ping(struct wlr_xdg_surface_v6 *surface) { - if (surface->client->ping_serial != 0) { - // already pinged - return; - } - - surface->client->ping_serial = - wl_display_next_serial(wl_client_get_display(surface->client->client)); - wl_event_source_timer_update(surface->client->ping_timer, - surface->client->shell->ping_timeout); - zxdg_shell_v6_send_ping(surface->client->resource, - surface->client->ping_serial); -} - -void wlr_xdg_surface_v6_send_close(struct wlr_xdg_surface_v6 *surface) { - switch (surface->role) { - case WLR_XDG_SURFACE_V6_ROLE_NONE: - assert(0 && "not reached"); - break; - case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL: - if (surface->toplevel) { - zxdg_toplevel_v6_send_close(surface->toplevel->resource); - } - break; - case WLR_XDG_SURFACE_V6_ROLE_POPUP: - if (surface->popup) { - zxdg_popup_v6_send_popup_done(surface->popup->resource); - } - break; - } -} - -static void xdg_surface_handle_surface_destroy(struct wl_listener *listener, - void *data) { - struct wlr_xdg_surface_v6 *xdg_surface = - wl_container_of(listener, xdg_surface, surface_destroy); - destroy_xdg_surface_v6(xdg_surface); -} - -static void xdg_surface_handle_surface_commit(struct wl_listener *listener, - void *data) { - struct wlr_xdg_surface_v6 *surface = - wl_container_of(listener, surface, surface_commit); - - if (wlr_surface_has_buffer(surface->surface) && !surface->configured) { - wl_resource_post_error(surface->resource, - ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER, - "xdg_surface has never been configured"); - return; - } - - if (surface->role == WLR_XDG_SURFACE_V6_ROLE_NONE) { - wl_resource_post_error(surface->resource, - ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, - "xdg_surface must have a role"); - return; - } -} - -void handle_xdg_surface_v6_commit(struct wlr_surface *wlr_surface) { - struct wlr_xdg_surface_v6 *surface = - wlr_xdg_surface_v6_from_wlr_surface(wlr_surface); - if (surface == NULL) { - return; - } - - if (surface->has_next_geometry) { - surface->has_next_geometry = false; - surface->geometry.x = surface->next_geometry.x; - surface->geometry.y = surface->next_geometry.y; - surface->geometry.width = surface->next_geometry.width; - surface->geometry.height = surface->next_geometry.height; - } - - switch (surface->role) { - case WLR_XDG_SURFACE_V6_ROLE_NONE: - assert(false); - case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL: - handle_xdg_surface_v6_toplevel_committed(surface); - break; - case WLR_XDG_SURFACE_V6_ROLE_POPUP: - handle_xdg_surface_v6_popup_committed(surface); - break; - } - - if (!surface->added) { - surface->added = true; - wlr_signal_emit_safe(&surface->client->shell->events.new_surface, - surface); - } - if (surface->configured && wlr_surface_has_buffer(surface->surface) && - !surface->mapped) { - surface->mapped = true; - wlr_signal_emit_safe(&surface->events.map, surface); - } -} - -void handle_xdg_surface_v6_precommit(struct wlr_surface *wlr_surface) { - struct wlr_xdg_surface_v6 *surface = - wlr_xdg_surface_v6_from_wlr_surface(wlr_surface); - if (surface == NULL) { - return; - } - - if (wlr_surface->pending.committed & WLR_SURFACE_STATE_BUFFER && - wlr_surface->pending.buffer_resource == NULL) { - // This is a NULL commit - if (surface->configured && surface->mapped) { - unmap_xdg_surface_v6(surface); - } - } -} - -static void xdg_surface_handle_resource_destroy(struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource); - if (surface != NULL) { - destroy_xdg_surface_v6(surface); - } -} - -struct wlr_xdg_surface_v6 *create_xdg_surface_v6( - struct wlr_xdg_client_v6 *client, struct wlr_surface *surface, - uint32_t id) { - if (wlr_surface_has_buffer(surface)) { - wl_resource_post_error(client->resource, - ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER, - "xdg_surface must not have a buffer at creation"); - return NULL; - } - - struct wlr_xdg_surface_v6 *xdg_surface = - calloc(1, sizeof(struct wlr_xdg_surface_v6)); - if (xdg_surface == NULL) { - wl_client_post_no_memory(client->client); - return NULL; - } - - xdg_surface->client = client; - xdg_surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE; - xdg_surface->surface = surface; - xdg_surface->resource = wl_resource_create(client->client, - &zxdg_surface_v6_interface, wl_resource_get_version(client->resource), - id); - if (xdg_surface->resource == NULL) { - free(xdg_surface); - wl_client_post_no_memory(client->client); - return NULL; - } - wl_resource_set_implementation(xdg_surface->resource, - &zxdg_surface_v6_implementation, xdg_surface, - xdg_surface_handle_resource_destroy); - - wl_list_init(&xdg_surface->configure_list); - wl_list_init(&xdg_surface->popups); - - wl_signal_init(&xdg_surface->events.destroy); - wl_signal_init(&xdg_surface->events.ping_timeout); - wl_signal_init(&xdg_surface->events.new_popup); - wl_signal_init(&xdg_surface->events.map); - wl_signal_init(&xdg_surface->events.unmap); - - wl_signal_add(&xdg_surface->surface->events.destroy, - &xdg_surface->surface_destroy); - xdg_surface->surface_destroy.notify = xdg_surface_handle_surface_destroy; - - wl_signal_add(&xdg_surface->surface->events.commit, - &xdg_surface->surface_commit); - xdg_surface->surface_commit.notify = xdg_surface_handle_surface_commit; - - wlr_log(WLR_DEBUG, "new xdg_surface %p (res %p)", xdg_surface, - xdg_surface->resource); - wl_list_insert(&client->surfaces, &xdg_surface->link); - - return xdg_surface; -} - -static void xdg_popup_v6_get_position(struct wlr_xdg_popup_v6 *popup, - double *popup_sx, double *popup_sy) { - struct wlr_xdg_surface_v6 *parent = popup->parent; - struct wlr_box parent_geo; - wlr_xdg_surface_v6_get_geometry(parent, &parent_geo); - *popup_sx = parent_geo.x + popup->geometry.x - - popup->base->geometry.x; - *popup_sy = parent_geo.y + popup->geometry.y - - popup->base->geometry.y; -} - -struct wlr_surface *wlr_xdg_surface_v6_surface_at( - struct wlr_xdg_surface_v6 *surface, double sx, double sy, - double *sub_x, double *sub_y) { - struct wlr_xdg_popup_v6 *popup_state; - wl_list_for_each(popup_state, &surface->popups, link) { - struct wlr_xdg_surface_v6 *popup = popup_state->base; - - double popup_sx, popup_sy; - xdg_popup_v6_get_position(popup_state, &popup_sx, &popup_sy); - - struct wlr_surface *sub = wlr_xdg_surface_v6_surface_at(popup, - sx - popup_sx, - sy - popup_sy, - sub_x, sub_y); - if (sub != NULL) { - return sub; - } - } - - return wlr_surface_surface_at(surface->surface, sx, sy, sub_x, sub_y); -} - -struct xdg_surface_v6_iterator_data { - wlr_surface_iterator_func_t user_iterator; - void *user_data; - int x, y; -}; - -static void xdg_surface_v6_iterator(struct wlr_surface *surface, - int sx, int sy, void *data) { - struct xdg_surface_v6_iterator_data *iter_data = data; - iter_data->user_iterator(surface, iter_data->x + sx, iter_data->y + sy, - iter_data->user_data); -} - -static void xdg_surface_v6_for_each_surface(struct wlr_xdg_surface_v6 *surface, - int x, int y, wlr_surface_iterator_func_t iterator, void *user_data) { - struct xdg_surface_v6_iterator_data data = { - .user_iterator = iterator, - .user_data = user_data, - .x = x, .y = y, - }; - wlr_surface_for_each_surface(surface->surface, xdg_surface_v6_iterator, - &data); - - struct wlr_xdg_popup_v6 *popup_state; - wl_list_for_each(popup_state, &surface->popups, link) { - struct wlr_xdg_surface_v6 *popup = popup_state->base; - if (!popup->configured) { - continue; - } - - double popup_sx, popup_sy; - xdg_popup_v6_get_position(popup_state, &popup_sx, &popup_sy); - - xdg_surface_v6_for_each_surface(popup, - x + popup_sx, - y + popup_sy, - iterator, user_data); - } -} - -static void xdg_surface_v6_for_each_popup(struct wlr_xdg_surface_v6 *surface, - int x, int y, wlr_surface_iterator_func_t iterator, void *user_data) { - struct wlr_xdg_popup_v6 *popup_state; - wl_list_for_each(popup_state, &surface->popups, link) { - struct wlr_xdg_surface_v6 *popup = popup_state->base; - if (!popup->configured) { - continue; - } - - double popup_sx, popup_sy; - xdg_popup_v6_get_position(popup_state, &popup_sx, &popup_sy); - iterator(popup->surface, x + popup_sx, y + popup_sy, user_data); - - xdg_surface_v6_for_each_popup(popup, - x + popup_sx, - y + popup_sy, - iterator, user_data); - } -} - -void wlr_xdg_surface_v6_for_each_surface(struct wlr_xdg_surface_v6 *surface, - wlr_surface_iterator_func_t iterator, void *user_data) { - xdg_surface_v6_for_each_surface(surface, 0, 0, iterator, user_data); -} - -void wlr_xdg_surface_v6_for_each_popup(struct wlr_xdg_surface_v6 *surface, - wlr_surface_iterator_func_t iterator, void *user_data) { - xdg_surface_v6_for_each_popup(surface, 0, 0, iterator, user_data); -} - -void wlr_xdg_surface_v6_get_geometry(struct wlr_xdg_surface_v6 *surface, struct wlr_box *box) { - wlr_surface_get_extends(surface->surface, box); - /* The client never set the geometry */ - if (!surface->geometry.width) { - return; - } - - wlr_box_intersection(box, &surface->geometry, box); -} diff --git a/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c b/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c deleted file mode 100644 index 2c626f83d..000000000 --- a/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c +++ /dev/null @@ -1,525 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include "types/wlr_xdg_shell_v6.h" -#include "util/signal.h" - -static const struct zxdg_toplevel_v6_interface zxdg_toplevel_v6_implementation; - -static struct wlr_xdg_surface_v6 *xdg_surface_from_xdg_toplevel_resource( - struct wl_resource *resource) { - assert(wl_resource_instance_of(resource, &zxdg_toplevel_v6_interface, - &zxdg_toplevel_v6_implementation)); - return wl_resource_get_user_data(resource); -} - -void destroy_xdg_toplevel_v6(struct wlr_xdg_surface_v6 *surface) { - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - unmap_xdg_surface_v6(surface); - - if (surface->toplevel->client_pending.fullscreen_output) { - struct wlr_xdg_toplevel_v6_state *client_pending = - &surface->toplevel->client_pending; - wl_list_remove(&client_pending->fullscreen_output_destroy.link); - } - wl_resource_set_user_data(surface->toplevel->resource, NULL); - free(surface->toplevel); - surface->toplevel = NULL; - - surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE; -} - -static void xdg_toplevel_handle_destroy(struct wl_client *client, - struct wl_resource *resource) { - wl_resource_destroy(resource); -} - -static void xdg_toplevel_handle_set_parent(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *parent_resource) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - - struct wlr_xdg_surface_v6 *parent = NULL; - if (parent_resource != NULL) { - parent = xdg_surface_from_xdg_toplevel_resource(parent_resource); - } - - surface->toplevel->parent = parent; - wlr_signal_emit_safe(&surface->toplevel->events.set_parent, surface); -} - -static void xdg_toplevel_handle_set_title(struct wl_client *client, - struct wl_resource *resource, const char *title) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - - char *tmp = strdup(title); - if (tmp == NULL) { - return; - } - - free(surface->toplevel->title); - surface->toplevel->title = tmp; - wlr_signal_emit_safe(&surface->toplevel->events.set_title, surface); -} - -static void xdg_toplevel_handle_set_app_id(struct wl_client *client, - struct wl_resource *resource, const char *app_id) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - - char *tmp = strdup(app_id); - if (tmp == NULL) { - return; - } - - free(surface->toplevel->app_id); - surface->toplevel->app_id = tmp; - wlr_signal_emit_safe(&surface->toplevel->events.set_app_id, surface); -} - -static void xdg_toplevel_handle_show_window_menu(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *seat_resource, - uint32_t serial, int32_t x, int32_t y) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - struct wlr_seat_client *seat = - wlr_seat_client_from_resource(seat_resource); - - if (!surface->configured) { - wl_resource_post_error(surface->toplevel->resource, - ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, - "surface has not been configured yet"); - return; - } - - if (!wlr_seat_validate_grab_serial(seat->seat, serial)) { - wlr_log(WLR_DEBUG, "invalid serial for grab"); - return; - } - - struct wlr_xdg_toplevel_v6_show_window_menu_event event = { - .surface = surface, - .seat = seat, - .serial = serial, - .x = x, - .y = y, - }; - - wlr_signal_emit_safe(&surface->toplevel->events.request_show_window_menu, - &event); -} - -static void xdg_toplevel_handle_move(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *seat_resource, - uint32_t serial) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - struct wlr_seat_client *seat = - wlr_seat_client_from_resource(seat_resource); - - if (!surface->configured) { - wl_resource_post_error(surface->toplevel->resource, - ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, - "surface has not been configured yet"); - return; - } - - if (!wlr_seat_validate_grab_serial(seat->seat, serial)) { - wlr_log(WLR_DEBUG, "invalid serial for grab"); - return; - } - - struct wlr_xdg_toplevel_v6_move_event event = { - .surface = surface, - .seat = seat, - .serial = serial, - }; - - wlr_signal_emit_safe(&surface->toplevel->events.request_move, &event); -} - -static void xdg_toplevel_handle_resize(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *seat_resource, - uint32_t serial, uint32_t edges) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - struct wlr_seat_client *seat = - wlr_seat_client_from_resource(seat_resource); - - if (!surface->configured) { - wl_resource_post_error(surface->toplevel->resource, - ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, - "surface has not been configured yet"); - return; - } - - if (!wlr_seat_validate_grab_serial(seat->seat, serial)) { - wlr_log(WLR_DEBUG, "invalid serial for grab"); - return; - } - - struct wlr_xdg_toplevel_v6_resize_event event = { - .surface = surface, - .seat = seat, - .serial = serial, - .edges = edges, - }; - - wlr_signal_emit_safe(&surface->toplevel->events.request_resize, &event); -} - -static void xdg_toplevel_handle_set_max_size(struct wl_client *client, - struct wl_resource *resource, int32_t width, int32_t height) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - surface->toplevel->client_pending.max_width = width; - surface->toplevel->client_pending.max_height = height; -} - -static void xdg_toplevel_handle_set_min_size(struct wl_client *client, - struct wl_resource *resource, int32_t width, int32_t height) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - surface->toplevel->client_pending.min_width = width; - surface->toplevel->client_pending.min_height = height; -} - -static void xdg_toplevel_handle_set_maximized(struct wl_client *client, - struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - surface->toplevel->client_pending.maximized = true; - wlr_signal_emit_safe(&surface->toplevel->events.request_maximize, surface); -} - -static void xdg_toplevel_handle_unset_maximized(struct wl_client *client, - struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - surface->toplevel->client_pending.maximized = false; - wlr_signal_emit_safe(&surface->toplevel->events.request_maximize, surface); -} - -static void handle_fullscreen_output_destroy(struct wl_listener *listener, - void *data) { - struct wlr_xdg_toplevel_v6_state *state = - wl_container_of(listener, state, fullscreen_output_destroy); - state->fullscreen_output = NULL; - wl_list_remove(&state->fullscreen_output_destroy.link); -} - -static void store_fullscreen_pending(struct wlr_xdg_surface_v6 *surface, - bool fullscreen, struct wlr_output *output) { - struct wlr_xdg_toplevel_v6_state *state = - &surface->toplevel->client_pending; - state->fullscreen = fullscreen; - if (state->fullscreen_output) { - wl_list_remove(&state->fullscreen_output_destroy.link); - } - state->fullscreen_output = output; - if (state->fullscreen_output) { - state->fullscreen_output_destroy.notify = - handle_fullscreen_output_destroy; - wl_signal_add(&state->fullscreen_output->events.destroy, - &state->fullscreen_output_destroy); - } -} - -static void xdg_toplevel_handle_set_fullscreen(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *output_resource) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - - struct wlr_output *output = NULL; - if (output_resource != NULL) { - output = wlr_output_from_resource(output_resource); - } - - store_fullscreen_pending(surface, true, output); - - struct wlr_xdg_toplevel_v6_set_fullscreen_event event = { - .surface = surface, - .fullscreen = true, - .output = output, - }; - - wlr_signal_emit_safe(&surface->toplevel->events.request_fullscreen, &event); -} - -static void xdg_toplevel_handle_unset_fullscreen(struct wl_client *client, - struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - - store_fullscreen_pending(surface, false, NULL); - - struct wlr_xdg_toplevel_v6_set_fullscreen_event event = { - .surface = surface, - .fullscreen = false, - .output = NULL, - }; - - wlr_signal_emit_safe(&surface->toplevel->events.request_fullscreen, &event); -} - -static void xdg_toplevel_handle_set_minimized(struct wl_client *client, - struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - wlr_signal_emit_safe(&surface->toplevel->events.request_minimize, surface); -} - -static const struct zxdg_toplevel_v6_interface - zxdg_toplevel_v6_implementation = { - .destroy = xdg_toplevel_handle_destroy, - .set_parent = xdg_toplevel_handle_set_parent, - .set_title = xdg_toplevel_handle_set_title, - .set_app_id = xdg_toplevel_handle_set_app_id, - .show_window_menu = xdg_toplevel_handle_show_window_menu, - .move = xdg_toplevel_handle_move, - .resize = xdg_toplevel_handle_resize, - .set_max_size = xdg_toplevel_handle_set_max_size, - .set_min_size = xdg_toplevel_handle_set_min_size, - .set_maximized = xdg_toplevel_handle_set_maximized, - .unset_maximized = xdg_toplevel_handle_unset_maximized, - .set_fullscreen = xdg_toplevel_handle_set_fullscreen, - .unset_fullscreen = xdg_toplevel_handle_unset_fullscreen, - .set_minimized = xdg_toplevel_handle_set_minimized, -}; - -void handle_xdg_toplevel_v6_ack_configure(struct wlr_xdg_surface_v6 *surface, - struct wlr_xdg_surface_v6_configure *configure) { - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - assert(configure->toplevel_state != NULL); - - surface->toplevel->last_acked = *configure->toplevel_state; -} - -bool compare_xdg_surface_v6_toplevel_state(struct wlr_xdg_toplevel_v6 *state) { - // is pending state different from current state? - if (!state->base->configured) { - return false; - } - - struct wlr_xdg_toplevel_v6_state *configured = NULL; - if (wl_list_empty(&state->base->configure_list)) { - // There are currently no pending configures, so check against the last - // state acked by the client. - configured = &state->last_acked; - } else { - struct wlr_xdg_surface_v6_configure *configure = - wl_container_of(state->base->configure_list.prev, configure, link); - configured = configure->toplevel_state; - } - - if (state->server_pending.activated != configured->activated) { - return false; - } - if (state->server_pending.fullscreen != configured->fullscreen) { - return false; - } - if (state->server_pending.maximized != configured->maximized) { - return false; - } - if (state->server_pending.resizing != configured->resizing) { - return false; - } - - if (state->server_pending.width == configured->width && - state->server_pending.height == configured->height) { - return true; - } - - if (state->server_pending.width == 0 && state->server_pending.height == 0) { - return true; - } - - return false; -} - -void send_xdg_toplevel_v6_configure(struct wlr_xdg_surface_v6 *surface, - struct wlr_xdg_surface_v6_configure *configure) { - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - - configure->toplevel_state = malloc(sizeof(*configure->toplevel_state)); - if (configure->toplevel_state == NULL) { - wlr_log(WLR_ERROR, "Allocation failed"); - wl_resource_post_no_memory(surface->toplevel->resource); - return; - } - *configure->toplevel_state = surface->toplevel->server_pending; - - uint32_t *s; - struct wl_array states; - wl_array_init(&states); - if (surface->toplevel->server_pending.maximized) { - s = wl_array_add(&states, sizeof(uint32_t)); - if (!s) { - wlr_log(WLR_ERROR, - "Could not allocate state for maximized xdg_toplevel"); - goto error_out; - } - *s = ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED; - } - if (surface->toplevel->server_pending.fullscreen) { - s = wl_array_add(&states, sizeof(uint32_t)); - if (!s) { - wlr_log(WLR_ERROR, - "Could not allocate state for fullscreen xdg_toplevel"); - goto error_out; - } - *s = ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN; - } - if (surface->toplevel->server_pending.resizing) { - s = wl_array_add(&states, sizeof(uint32_t)); - if (!s) { - wlr_log(WLR_ERROR, - "Could not allocate state for resizing xdg_toplevel"); - goto error_out; - } - *s = ZXDG_TOPLEVEL_V6_STATE_RESIZING; - } - if (surface->toplevel->server_pending.activated) { - s = wl_array_add(&states, sizeof(uint32_t)); - if (!s) { - wlr_log(WLR_ERROR, - "Could not allocate state for activated xdg_toplevel"); - goto error_out; - } - *s = ZXDG_TOPLEVEL_V6_STATE_ACTIVATED; - } - - uint32_t width = surface->toplevel->server_pending.width; - uint32_t height = surface->toplevel->server_pending.height; - zxdg_toplevel_v6_send_configure(surface->toplevel->resource, width, - height, &states); - - wl_array_release(&states); - return; - -error_out: - wl_array_release(&states); - wl_resource_post_no_memory(surface->toplevel->resource); -} - -void handle_xdg_surface_v6_toplevel_committed(struct wlr_xdg_surface_v6 *surface) { - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - - if (!surface->toplevel->added) { - // on the first commit, send a configure request to tell the client it - // is added - schedule_xdg_surface_v6_configure(surface); - surface->toplevel->added = true; - return; - } - - // apply state from the last acked configure now that the client committed - surface->toplevel->current = surface->toplevel->last_acked; - - // update state from the client that doesn't need compositor approval - surface->toplevel->current.max_width = - surface->toplevel->client_pending.max_width; - surface->toplevel->current.min_width = - surface->toplevel->client_pending.min_width; - surface->toplevel->current.max_height = - surface->toplevel->client_pending.max_height; - surface->toplevel->current.min_height = - surface->toplevel->client_pending.min_height; -} - -static void xdg_toplevel_handle_resource_destroy(struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - if (surface != NULL) { - destroy_xdg_toplevel_v6(surface); - } -} - -const struct wlr_surface_role xdg_toplevel_v6_surface_role = { - .name = "xdg_toplevel_v6", - .commit = handle_xdg_surface_v6_commit, - .precommit = handle_xdg_surface_v6_precommit, -}; - -void create_xdg_toplevel_v6(struct wlr_xdg_surface_v6 *xdg_surface, - uint32_t id) { - if (!wlr_surface_set_role(xdg_surface->surface, &xdg_toplevel_v6_surface_role, - xdg_surface, xdg_surface->resource, ZXDG_SHELL_V6_ERROR_ROLE)) { - return; - } - - xdg_surface->toplevel = calloc(1, sizeof(struct wlr_xdg_toplevel_v6)); - if (xdg_surface->toplevel == NULL) { - wl_resource_post_no_memory(xdg_surface->resource); - return; - } - wl_signal_init(&xdg_surface->toplevel->events.request_maximize); - wl_signal_init(&xdg_surface->toplevel->events.request_fullscreen); - wl_signal_init(&xdg_surface->toplevel->events.request_minimize); - wl_signal_init(&xdg_surface->toplevel->events.request_move); - wl_signal_init(&xdg_surface->toplevel->events.request_resize); - wl_signal_init(&xdg_surface->toplevel->events.request_show_window_menu); - wl_signal_init(&xdg_surface->toplevel->events.set_parent); - wl_signal_init(&xdg_surface->toplevel->events.set_title); - wl_signal_init(&xdg_surface->toplevel->events.set_app_id); - - xdg_surface->role = WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL; - xdg_surface->toplevel->base = xdg_surface; - - struct wl_resource *toplevel_resource = wl_resource_create( - xdg_surface->client->client, &zxdg_toplevel_v6_interface, - wl_resource_get_version(xdg_surface->resource), id); - if (toplevel_resource == NULL) { - free(xdg_surface->toplevel); - wl_resource_post_no_memory(xdg_surface->resource); - return; - } - xdg_surface->toplevel->resource = toplevel_resource; - wl_resource_set_implementation(toplevel_resource, - &zxdg_toplevel_v6_implementation, xdg_surface, - xdg_toplevel_handle_resource_destroy); -} - -uint32_t wlr_xdg_toplevel_v6_set_size(struct wlr_xdg_surface_v6 *surface, - uint32_t width, uint32_t height) { - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - surface->toplevel->server_pending.width = width; - surface->toplevel->server_pending.height = height; - - return schedule_xdg_surface_v6_configure(surface); -} - -uint32_t wlr_xdg_toplevel_v6_set_activated(struct wlr_xdg_surface_v6 *surface, - bool activated) { - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - surface->toplevel->server_pending.activated = activated; - - return schedule_xdg_surface_v6_configure(surface); -} - -uint32_t wlr_xdg_toplevel_v6_set_maximized(struct wlr_xdg_surface_v6 *surface, - bool maximized) { - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - surface->toplevel->server_pending.maximized = maximized; - - return schedule_xdg_surface_v6_configure(surface); -} - -uint32_t wlr_xdg_toplevel_v6_set_fullscreen(struct wlr_xdg_surface_v6 *surface, - bool fullscreen) { - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - surface->toplevel->server_pending.fullscreen = fullscreen; - - return schedule_xdg_surface_v6_configure(surface); -} - -uint32_t wlr_xdg_toplevel_v6_set_resizing(struct wlr_xdg_surface_v6 *surface, - bool resizing) { - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - surface->toplevel->server_pending.resizing = resizing; - - return schedule_xdg_surface_v6_configure(surface); -} From efe6414640aa15cfad975dec3db427936c0450a4 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Fri, 4 Sep 2020 00:08:45 +0200 Subject: [PATCH 42/94] wayland: emit relative pointer events only for current pointer --- backend/wayland/seat.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index d19744d82..71e04de6b 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -450,6 +450,9 @@ static void relative_pointer_handle_relative_motion(void *data, wl_fixed_t dy_unaccel) { struct wlr_wl_input_device *input_device = data; struct wlr_input_device *wlr_dev = &input_device->wlr_input_device; + if (pointer_get_wl(wlr_dev->pointer) != input_device->backend->current_pointer) { + return; + } uint64_t time_usec = (uint64_t)utime_hi << 32 | utime_lo; From fa05d3cde68de73df4cac9762f6623c6001651cc Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Thu, 3 Sep 2020 21:25:33 +0200 Subject: [PATCH 43/94] session: Don't refuse unprivileged creation of "direct" backend When starting a compositor that's using the "direct" session backend, wlroots needs to handle calls to `drmSetMaster()` and `drmDropMaster()`. As both calls used to require `CAP_SYS_ADMIN`, wlroots thus simply refused starting in case the process doesn't enjoy evelated privileges. Permission rules have changed since linux.git commit 45bc3d26c95a (drm: rework SET_MASTER and DROP_MASTER perm handling, 2020-03-19). As a result, starting with Linux v5.8, both ioctls will now also succeed if the process is currently or has been the DRM master. And as the first process to open render nodes will become the DRM master automatically, this effectively means that process elevation is not strictly required in all setups anymore. So let's drop the `geteuid() != 0` permission check to allow those new rules to do their magic. --- backend/session/direct-ipc.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/backend/session/direct-ipc.c b/backend/session/direct-ipc.c index 94f34a88d..d98d4e669 100644 --- a/backend/session/direct-ipc.c +++ b/backend/session/direct-ipc.c @@ -24,16 +24,6 @@ enum { DRM_MAJOR = 226 }; -static bool have_permissions(void) { -#ifdef __linux__ - if (geteuid() != 0) { - wlr_log(WLR_ERROR, "Do not have root privileges; cannot become DRM master"); - return false; - } -#endif - return true; -} - static void send_msg(int sock, int fd, void *buf, size_t buf_len) { char control[CMSG_SPACE(sizeof(fd))] = {0}; struct iovec iovec = { .iov_base = buf, .iov_len = buf_len }; @@ -223,10 +213,6 @@ void direct_ipc_finish(int sock, pid_t pid) { } int direct_ipc_init(pid_t *pid_out) { - if (!have_permissions()) { - return -1; - } - int sock[2]; if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sock) < 0) { wlr_log_errno(WLR_ERROR, "Failed to create socket pair"); From e44bed0c2b77c944e389efd026948d8ef1230cec Mon Sep 17 00:00:00 2001 From: nerdopolis Date: Tue, 1 Sep 2020 20:00:33 -0400 Subject: [PATCH 44/94] Accommodate for CONFIG_VT=0, all TTYs are in seat0, but not all seat0s have TTYs --- backend/session/logind.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/session/logind.c b/backend/session/logind.c index b9249eced..9c2515a87 100644 --- a/backend/session/logind.c +++ b/backend/session/logind.c @@ -130,8 +130,8 @@ static void logind_release_device(struct wlr_session *base, int fd) { static bool logind_change_vt(struct wlr_session *base, unsigned vt) { struct logind_session *session = logind_session_from_session(base); - // Only seat0 has VTs associated with it - if (strcmp(session->base.seat, "seat0") != 0) { + // Only if seat has VTs associated with it + if (!sd_seat_can_tty(session->base.seat)) { return true; } @@ -791,7 +791,7 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) { } snprintf(session->base.seat, sizeof(session->base.seat), "%s", seat); - if (strcmp(seat, "seat0") == 0) { + if (sd_seat_can_tty(seat)) { ret = sd_session_get_vt(session->id, &session->base.vtnr); if (ret < 0) { wlr_log(WLR_ERROR, "Session not running in virtual terminal"); From 3e03f786ee50f22175db3b7422085df2fa2751d8 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Fri, 4 Sep 2020 13:03:21 +0200 Subject: [PATCH 45/94] xwayland: disconnect display destroy listener even if xwayland didn't initialize --- xwayland/server.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/xwayland/server.c b/xwayland/server.c index b257f2451..27e9861a4 100644 --- a/xwayland/server.c +++ b/xwayland/server.c @@ -150,7 +150,13 @@ static void server_finish_process(struct wlr_xwayland_server *server) { } static void server_finish_display(struct wlr_xwayland_server *server) { - if (!server || server->display == -1) { + if (!server) { + return; + } + + wl_list_remove(&server->display_destroy.link); + + if (server->display == -1) { return; } @@ -158,8 +164,6 @@ static void server_finish_display(struct wlr_xwayland_server *server) { safe_close(server->x_fd[1]); server->x_fd[0] = server->x_fd[1] = -1; - wl_list_remove(&server->display_destroy.link); - unlink_display_sockets(server->display); server->display = -1; server->display_name[0] = '\0'; From e4a7075a9e197781526839a258fbfadb7d0f1e19 Mon Sep 17 00:00:00 2001 From: Roman Gilg Date: Thu, 3 Sep 2020 14:20:04 +0200 Subject: [PATCH 46/94] output-management-v1: add head identifying events The following information through separate events are added: - make - model - serial_number This should allow clients to identify a display over different sessions and load configuration data back. A note is added that the description should be preferred when representing a display in UI to users but as a short form for example the model could be used in this case of course too. --- .../wlr-output-management-unstable-v1.xml | 81 +++++++++++++++++-- 1 file changed, 76 insertions(+), 5 deletions(-) diff --git a/protocol/wlr-output-management-unstable-v1.xml b/protocol/wlr-output-management-unstable-v1.xml index 35f7ca4e3..cadc45fb2 100644 --- a/protocol/wlr-output-management-unstable-v1.xml +++ b/protocol/wlr-output-management-unstable-v1.xml @@ -39,7 +39,7 @@ interface version number is reset. - + This interface is a manager that allows reading and writing the current output device configuration. @@ -125,7 +125,7 @@ - + A head is an output device. The difference between a wl_output object and a head is that heads are advertised even if they are turned off. A head @@ -257,9 +257,80 @@ resources associated with it. + + + + + This event describes the manufacturer of the head. + + This must report the same make as the wl_output interface does in its + geometry event. + + Together with the model and serial_number events the purpose is to + allow clients to recognize heads from previous sessions and for example + load head-specific configurations back. + + It is not guaranteed this event will be ever sent. A reason for that + can be that the compositor does not have information about the make of + the head or the definition of a make is not sensible in the current + setup, for example in a virtual session. Clients can still try to + identify the head by available information from other events but should + be aware that there is an increased risk of false positives. + + It is not recommended to display the make string in UI to users. For + that the string provided by the description event should be preferred. + + + + + + + This event describes the model of the head. + + This must report the same model as the wl_output interface does in its + geometry event. + + Together with the make and serial_number events the purpose is to + allow clients to recognize heads from previous sessions and for example + load head-specific configurations back. + + It is not guaranteed this event will be ever sent. A reason for that + can be that the compositor does not have information about the model of + the head or the definition of a model is not sensible in the current + setup, for example in a virtual session. Clients can still try to + identify the head by available information from other events but should + be aware that there is an increased risk of false positives. + + It is not recommended to display the model string in UI to users. For + that the string provided by the description event should be preferred. + + + + + + + This event describes the serial number of the head. + + Together with the make and model events the purpose is to allow clients + to recognize heads from previous sessions and for example load head- + specific configurations back. + + It is not guaranteed this event will be ever sent. A reason for that + can be that the compositor does not have information about the serial + number of the head or the definition of a serial number is not sensible + in the current setup. Clients can still try to identify the head by + available information from other events but should be aware that there + is an increased risk of false positives. + + It is not recommended to display the serial_number string in UI to + users. For that the string provided by the description event should be + preferred. + + + - + This object describes an output mode. @@ -305,7 +376,7 @@ - + This object is used by the client to describe a full output configuration. @@ -423,7 +494,7 @@ - + This object is used by the client to update a single head's configuration. From bae8d7593c4ac9d72ddc90bded52e96056330ca2 Mon Sep 17 00:00:00 2001 From: Roman Gilg Date: Thu, 3 Sep 2020 14:42:35 +0200 Subject: [PATCH 47/94] output-management-v1: send head identifying information With version 2 we send make, model and serial number to allow clients the identification of heads. --- types/wlr_output_management_v1.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/types/wlr_output_management_v1.c b/types/wlr_output_management_v1.c index 15a971f60..ae20e0d79 100644 --- a/types/wlr_output_management_v1.c +++ b/types/wlr_output_management_v1.c @@ -6,7 +6,7 @@ #include "util/signal.h" #include "wlr-output-management-unstable-v1-protocol.h" -#define OUTPUT_MANAGER_VERSION 1 +#define OUTPUT_MANAGER_VERSION 2 enum { HEAD_STATE_ENABLED = 1 << 0, @@ -761,6 +761,16 @@ static void manager_send_head(struct wlr_output_manager_v1 *manager, output->phys_width, output->phys_height); } + if (version >= ZWLR_OUTPUT_HEAD_V1_MAKE_SINCE_VERSION && output->make[0] != '\0') { + zwlr_output_head_v1_send_make(head_resource, output->make); + } + if (version >= ZWLR_OUTPUT_HEAD_V1_MODEL_SINCE_VERSION && output->model[0] != '\0') { + zwlr_output_head_v1_send_model(head_resource, output->model); + } + if (version >= ZWLR_OUTPUT_HEAD_V1_SERIAL_NUMBER_SINCE_VERSION && output->serial[0] != '\0') { + zwlr_output_head_v1_send_serial_number(head_resource, output->serial); + } + struct wlr_output_mode *mode; wl_list_for_each(mode, &output->modes, link) { head_send_mode(head, head_resource, mode); From 8ad2cc39eb420c22dde7e49c01bde916b7bc58cc Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Tue, 8 Sep 2020 18:03:33 +0200 Subject: [PATCH 48/94] layer-shell: add for_each_popup This brings the layer-shell api in line with that of xdg-shell and avoids reimplementing this function in every compositor in order to render layer shell popups correctly. --- include/wlr/types/wlr_layer_shell_v1.h | 4 ++++ types/wlr_layer_shell_v1.c | 15 +++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/include/wlr/types/wlr_layer_shell_v1.h b/include/wlr/types/wlr_layer_shell_v1.h index b6a0a1352..f13eadb7f 100644 --- a/include/wlr/types/wlr_layer_shell_v1.h +++ b/include/wlr/types/wlr_layer_shell_v1.h @@ -138,6 +138,10 @@ struct wlr_layer_surface_v1 *wlr_layer_surface_v1_from_wlr_surface( void wlr_layer_surface_v1_for_each_surface(struct wlr_layer_surface_v1 *surface, wlr_surface_iterator_func_t iterator, void *user_data); +/* Calls the iterator function for each popup of this surface */ +void wlr_layer_surface_v1_for_each_popup(struct wlr_layer_surface_v1 *surface, + wlr_surface_iterator_func_t iterator, void *user_data); + /** * Find a surface within this layer-surface tree at the given surface-local * coordinates. Returns the surface and coordinates in the leaf surface diff --git a/types/wlr_layer_shell_v1.c b/types/wlr_layer_shell_v1.c index db2113e3f..d83b22b86 100644 --- a/types/wlr_layer_shell_v1.c +++ b/types/wlr_layer_shell_v1.c @@ -534,16 +534,20 @@ static void xdg_surface_for_each_surface(struct wlr_xdg_surface *surface, } } -static void layer_surface_for_each_surface(struct wlr_layer_surface_v1 *surface, - int x, int y, wlr_surface_iterator_func_t iterator, void *user_data) { +void wlr_layer_surface_v1_for_each_surface(struct wlr_layer_surface_v1 *surface, + wlr_surface_iterator_func_t iterator, void *user_data) { struct layer_surface_iterator_data data = { .user_iterator = iterator, .user_data = user_data, - .x = x, .y = y, + .x = 0, .y = 0, }; wlr_surface_for_each_surface(surface->surface, layer_surface_iterator, &data); + wlr_layer_surface_v1_for_each_popup(surface, iterator, user_data); +} +void wlr_layer_surface_v1_for_each_popup(struct wlr_layer_surface_v1 *surface, + wlr_surface_iterator_func_t iterator, void *user_data){ struct wlr_xdg_popup *popup_state; wl_list_for_each(popup_state, &surface->popups, link) { struct wlr_xdg_surface *popup = popup_state->base; @@ -560,11 +564,6 @@ static void layer_surface_for_each_surface(struct wlr_layer_surface_v1 *surface, } } -void wlr_layer_surface_v1_for_each_surface(struct wlr_layer_surface_v1 *surface, - wlr_surface_iterator_func_t iterator, void *user_data) { - layer_surface_for_each_surface(surface, 0, 0, iterator, user_data); -} - struct wlr_surface *wlr_layer_surface_v1_surface_at( struct wlr_layer_surface_v1 *surface, double sx, double sy, double *sub_x, double *sub_y) { From 87836dcb55e15cd1f19f5549d4fcd666135dba15 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 16 Sep 2020 12:54:40 +0200 Subject: [PATCH 49/94] backend: remove check for _WAYLAND_DISPLAY I'm not sure what this was used for, but it's not used by libwayland. Setting _WAYLAND_DISPLAY would result in the Wayland backend being picked but would ignore the actual value of the env variable. --- backend/backend.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/backend.c b/backend/backend.c index c71b072f7..aa0d9668d 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -254,8 +254,7 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display, return backend; } - if (getenv("WAYLAND_DISPLAY") || getenv("_WAYLAND_DISPLAY") || - getenv("WAYLAND_SOCKET")) { + if (getenv("WAYLAND_DISPLAY") || getenv("WAYLAND_SOCKET")) { struct wlr_backend *wl_backend = attempt_wl_backend(display, create_renderer_func); if (!wl_backend) { From 5012121d331c97bc6af856dd58d68b5be336b573 Mon Sep 17 00:00:00 2001 From: Rouven Czerwinski Date: Sat, 19 Sep 2020 11:36:33 +0200 Subject: [PATCH 50/94] xwm: add loop detection for read_surface_parent Implement a simple loop detection while trying to retrieve the parent for a TRANSIENT_FOR window. Fixes swaywm/sway#4624 --- xwayland/xwm.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 87b9edc13..b3e6c885e 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -467,20 +467,41 @@ static void read_surface_title(struct wlr_xwm *xwm, wlr_signal_emit_safe(&xsurface->events.set_title, xsurface); } +static bool has_parent(struct wlr_xwayland_surface *parent, + struct wlr_xwayland_surface *child) { + while (parent) { + if (child == parent) { + return true; + } + + parent = parent->parent; + } + + return false; +} + static void read_surface_parent(struct wlr_xwm *xwm, struct wlr_xwayland_surface *xsurface, xcb_get_property_reply_t *reply) { + struct wlr_xwayland_surface *found_parent = NULL; if (reply->type != XCB_ATOM_WINDOW) { return; } xcb_window_t *xid = xcb_get_property_value(reply); if (xid != NULL) { - xsurface->parent = lookup_surface(xwm, *xid); + found_parent = lookup_surface(xwm, *xid); + if (!has_parent(found_parent, xsurface)) { + xsurface->parent = found_parent; + } else { + wlr_log(WLR_INFO, "%p with %p would create a loop", xsurface, + found_parent); + } } else { xsurface->parent = NULL; } + wl_list_remove(&xsurface->parent_link); if (xsurface->parent != NULL) { wl_list_insert(&xsurface->parent->children, &xsurface->parent_link); From 8dec751a6d84335fb04288b8efab6dd5c90288d3 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Fri, 9 Oct 2020 15:28:07 +0200 Subject: [PATCH 51/94] layer-shell: error on 0 dimension without anchors The protocol requires clients to set opposing anchors when requesting a width or height of 0. The goal of this patch is not to break clients that rely on this behavior but to improve the consistency of the layer shell ecosystem through adherence to the protocol. --- types/wlr_layer_shell_v1.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/types/wlr_layer_shell_v1.c b/types/wlr_layer_shell_v1.c index d83b22b86..bc6811179 100644 --- a/types/wlr_layer_shell_v1.c +++ b/types/wlr_layer_shell_v1.c @@ -307,6 +307,26 @@ static void layer_surface_role_commit(struct wlr_surface *wlr_surface) { return; } + const uint32_t horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; + if (surface->client_pending.desired_width == 0 && + (surface->client_pending.anchor & horiz) != horiz) { + wl_resource_post_error(surface->resource, + ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SIZE, + "width 0 requested without setting left and right anchors"); + return; + } + + const uint32_t vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; + if (surface->client_pending.desired_height == 0 && + (surface->client_pending.anchor & vert) != vert) { + wl_resource_post_error(surface->resource, + ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SIZE, + "height 0 requested without setting top and bottom anchors"); + return; + } + if (surface->closed) { // Ignore commits after the compositor has closed it return; From 86c0b9986b82a477dea7e6029c0fe565dd7af429 Mon Sep 17 00:00:00 2001 From: Roman Gilg Date: Thu, 1 Oct 2020 14:32:57 +0200 Subject: [PATCH 52/94] output-management-v1: send complete head state on enable change The data of a head is only sent when it is enabled. While the head was disabled data might have been changed. In this case clients were not informed about this change. A later enable change that does not also update the other data must still lead to the propagation of this data. Since we do not know what other data was changed while the head was disabled just send together with an enable change all current data. --- types/wlr_output_management_v1.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/types/wlr_output_management_v1.c b/types/wlr_output_management_v1.c index ae20e0d79..728abee7c 100644 --- a/types/wlr_output_management_v1.c +++ b/types/wlr_output_management_v1.c @@ -680,6 +680,9 @@ static void head_send_state(struct wlr_output_head_v1 *head, if (state & HEAD_STATE_ENABLED) { zwlr_output_head_v1_send_enabled(head_resource, head->state.enabled); + // On enabling we send all current data since clients have not been + // notified about potential data changes while the head was disabled. + state = HEAD_STATE_ALL; } if (!head->state.enabled) { From 45c1a3621cc6874e5b5d9694015241668980df5d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 10 Oct 2020 16:47:29 +0200 Subject: [PATCH 53/94] backend/libinput: improve logger callback - Add a prefix to make it clear log messages come from libinput - Properly convert libinput log priority to wlroots' --- backend/libinput/backend.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/backend/libinput/backend.c b/backend/libinput/backend.c index 87497b11d..3c42d7f8f 100644 --- a/backend/libinput/backend.c +++ b/backend/libinput/backend.c @@ -44,9 +44,24 @@ static int handle_libinput_readable(int fd, uint32_t mask, void *_backend) { return 0; } +static enum wlr_log_importance libinput_log_priority_to_wlr( + enum libinput_log_priority priority) { + switch (priority) { + case LIBINPUT_LOG_PRIORITY_ERROR: + return WLR_ERROR; + case LIBINPUT_LOG_PRIORITY_INFO: + return WLR_INFO; + default: + return WLR_DEBUG; + } +} + static void log_libinput(struct libinput *libinput_context, enum libinput_log_priority priority, const char *fmt, va_list args) { - _wlr_vlog(WLR_ERROR, fmt, args); + enum wlr_log_importance importance = libinput_log_priority_to_wlr(priority); + static char wlr_fmt[1024]; + snprintf(wlr_fmt, sizeof(wlr_fmt), "[libinput] %s", fmt); + _wlr_vlog(importance, wlr_fmt, args); } static bool backend_start(struct wlr_backend *wlr_backend) { From ec3f432bbb4cbcb75adc695753353239e017a8bd Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Sat, 10 Oct 2020 22:57:45 -0400 Subject: [PATCH 54/94] examples: use `perror` instead of `fprintf` GNU %m `printf` extension --- examples/screencopy-dmabuf.c | 6 +++--- examples/screencopy.c | 4 ++-- examples/virtual-pointer.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/screencopy-dmabuf.c b/examples/screencopy-dmabuf.c index 2525efc5a..e7657e1a9 100644 --- a/examples/screencopy-dmabuf.c +++ b/examples/screencopy-dmabuf.c @@ -297,7 +297,7 @@ int main(int argc, char *argv[]) { drm_fd = open(render_node, O_RDWR); if (drm_fd < 0) { - fprintf(stderr, "Failed to open drm render node: %m\n"); + perror("Failed to open drm render node"); return EXIT_FAILURE; } @@ -309,7 +309,7 @@ int main(int argc, char *argv[]) { struct wl_display *display = wl_display_connect(NULL); if (display == NULL) { - fprintf(stderr, "failed to create display: %m\n"); + perror("failed to create display"); return EXIT_FAILURE; } @@ -343,7 +343,7 @@ int main(int argc, char *argv[]) { void *data = gbm_bo_map(buffer.bo, 0, 0, buffer.width, buffer.height, GBM_BO_TRANSFER_READ, &stride, &map_data); if (!data) { - fprintf(stderr, "Failed to map gbm bo: %m\n"); + perror("Failed to map gbm bo"); return EXIT_FAILURE; } diff --git a/examples/screencopy.c b/examples/screencopy.c index 0e03a2384..42123e55e 100644 --- a/examples/screencopy.c +++ b/examples/screencopy.c @@ -90,7 +90,7 @@ static struct wl_buffer *create_shm_buffer(enum wl_shm_format fmt, void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (data == MAP_FAILED) { - fprintf(stderr, "mmap failed: %m\n"); + perror("mmap failed"); close(fd); return NULL; } @@ -228,7 +228,7 @@ static void write_image(char *filename, enum wl_shm_format wl_fmt, int width, int main(int argc, char *argv[]) { struct wl_display * display = wl_display_connect(NULL); if (display == NULL) { - fprintf(stderr, "failed to create display: %m\n"); + perror("failed to create display"); return EXIT_FAILURE; } diff --git a/examples/virtual-pointer.c b/examples/virtual-pointer.c index 8fd148305..b91768a47 100644 --- a/examples/virtual-pointer.c +++ b/examples/virtual-pointer.c @@ -61,7 +61,7 @@ int main(int argc, char *argv[]) { } struct wl_display * display = wl_display_connect(NULL); if (display == NULL) { - fprintf(stderr, "failed to create display: %m\n"); + perror("failed to create display"); return EXIT_FAILURE; } From ab80ad902e5914d8b7fbe08f155ac49917acbad0 Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Sat, 10 Oct 2020 22:58:57 -0400 Subject: [PATCH 55/94] xwayland: using %m in `wlr_log` is broken, use `wlr_log_errno` instead This one was awful to track down, but calls to `wlr_log` with %m have the errno masked by the `isatty` call in `log_stderr`. Switch them to `wlr_log_errno` instead. Cue quality "how can read(2) POSSIBLY be returning ENOTTY?" moments. --- xwayland/selection/outgoing.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xwayland/selection/outgoing.c b/xwayland/selection/outgoing.c index 002c0143c..33aa225b4 100644 --- a/xwayland/selection/outgoing.c +++ b/xwayland/selection/outgoing.c @@ -92,7 +92,7 @@ static int xwm_data_source_read(int fd, uint32_t mask, void *data) { size_t available = transfer->source_data.alloc - current; ssize_t len = read(fd, p, available); if (len == -1) { - wlr_log(WLR_ERROR, "read error from data source: %m"); + wlr_log_errno(WLR_ERROR, "read error from data source"); goto error_out; } @@ -289,7 +289,7 @@ static void xwm_selection_send_data(struct wlr_xwm_selection *selection, int p[2]; if (pipe(p) == -1) { - wlr_log(WLR_ERROR, "pipe() failed: %m"); + wlr_log_errno(WLR_ERROR, "pipe() failed"); xwm_selection_send_notify(selection->xwm, req, false); return; } From feb0e1c74d13c44c4c0b8c8db360039846bc9617 Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Sat, 10 Oct 2020 22:51:50 -0400 Subject: [PATCH 56/94] xwayland: fix use-after-free in selection handling Fixes #2425. wlroots can only handle one outgoing transfer at a time, so it keeps a list of pending selections. The head of the list is the currently-active selection, and when that transfer completes and is destroyed, the next one is started. The trouble is when you have a transfer to some app that is misbehaving. fcitx is one such application. With really large transfers, fcitx will hang and never wake up again. So, you can end up with a transfer list that looks like this: | T1: started | T2: pending | T3: pending | T4: pending | The file descriptor for transfer T1 is registered in libwayland's epoll loop. The rest are waiting in wlroots' list. As a user, you want your clipboard back, so you `pkill fcitx`. Now Xwayland sends `XCB_DESTROY_NOTIFY` to let us know to give up. We clean up T4 first. Due to a bug in wlroots code, we register the (fd, transfer data pointer) pair for T1 with libwayland *again*, despite it already being registered. We do this 2 more times as we remove T3 and T2. Finally, we remove T1 and `free` all the memory associated with it, before `close`-ing its transfer file descriptor. However, we still have 3 copies of T1's file descriptor left in the epoll loop, since we erroneously added them as part of removing T2/3/4. When we `close` the file descriptor as part of T1's teardown, we actually cause the epoll loop to wake up the next time around, saying "this file descriptor has activity!" (it was closed, so `read`-ing would normally return 0 to let us know of EOF). But instead of returning 0, it returns -1 with `EBADF`, because the file descriptor has already been closed. And finally, as part of error-handling this, we access the transfer pointer, which was `free`'d. And we crash. --- xwayland/selection/outgoing.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/xwayland/selection/outgoing.c b/xwayland/selection/outgoing.c index 33aa225b4..943e4d1a4 100644 --- a/xwayland/selection/outgoing.c +++ b/xwayland/selection/outgoing.c @@ -55,16 +55,27 @@ static int xwm_selection_flush_source_data( static void xwm_selection_transfer_start_outgoing( struct wlr_xwm_selection_transfer *transfer); +static struct wlr_xwm_selection_transfer *xwm_selection_transfer_get_first( + struct wlr_xwm_selection *selection) { + struct wlr_xwm_selection_transfer *first = NULL; + if (!wl_list_empty(&selection->outgoing)) { + first = wl_container_of(selection->outgoing.prev, first, + outgoing_link); + } + + return first; +} + static void xwm_selection_transfer_destroy_outgoing( struct wlr_xwm_selection_transfer *transfer) { + struct wlr_xwm_selection *selection = transfer->selection; + bool was_first = transfer == xwm_selection_transfer_get_first(selection); wl_list_remove(&transfer->outgoing_link); - // Start next queued transfer - struct wlr_xwm_selection_transfer *first = NULL; - if (!wl_list_empty(&transfer->selection->outgoing)) { - first = wl_container_of(transfer->selection->outgoing.prev, first, - outgoing_link); - xwm_selection_transfer_start_outgoing(first); + // Start next queued transfer if we just removed the active one. + if (was_first && !wl_list_empty(&selection->outgoing)) { + xwm_selection_transfer_start_outgoing( + xwm_selection_transfer_get_first(selection)); } xwm_selection_transfer_remove_source(transfer); From 1b0e4c7e6e0bf02b3c41962b669c00280ecc7712 Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Sat, 3 Oct 2020 14:16:54 -0400 Subject: [PATCH 57/94] xwayland: introduce WLR_XWAYLAND for specifying which Xwayland to use When debugging Xwayland-related issues, a common first step in debugging has been to ask the reporter to move their real Xwayland to /usr/bin/Xwayland.bin, and create a shell script starting Xwayland with extra arguments under the original /usr/bin/Xwayland location. Introducing a `WLR_XWAYLAND` environment variable makes this less invasive, by allowing the user to swap out Xwayland without resorting to global system changes (or source patches). --- docs/env_vars.md | 2 ++ xwayland/server.c | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/env_vars.md b/docs/env_vars.md index 48f96f7fd..9fca81656 100644 --- a/docs/env_vars.md +++ b/docs/env_vars.md @@ -9,6 +9,8 @@ wlroots reads these environment variables * *WLR_SESSION*: specifies the wlr\_session to be used (available sessions: logind/systemd, direct) * *WLR_DIRECT_TTY*: specifies the tty to be used (instead of using /dev/tty) +* *WLR_XWAYLAND*: specifies the path to an Xwayland binary to be used (instead + of following shell search semantics for "Xwayland") ## DRM backend diff --git a/xwayland/server.c b/xwayland/server.c index 27e9861a4..24b435aa6 100644 --- a/xwayland/server.c +++ b/xwayland/server.c @@ -107,8 +107,16 @@ noreturn static void exec_xwayland(struct wlr_xwayland_server *server) { dup2(devnull, STDERR_FILENO); } + const char *xwayland_path = getenv("WLR_XWAYLAND"); + if (xwayland_path) { + wlr_log(WLR_INFO, "Using Xwayland binary to '%s' due to WLR_XWAYLAND", + xwayland_path); + } else { + xwayland_path = "Xwayland"; + } + // This returns if and only if the call fails - execvp("Xwayland", argv); + execvp(xwayland_path, argv); wlr_log_errno(WLR_ERROR, "failed to exec Xwayland"); close(devnull); From 7bb9d48dd1383b688c8fefbbb08c552c3cc33c18 Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Sun, 11 Oct 2020 21:25:26 -0400 Subject: [PATCH 58/94] xwayland: remove stale transfers from the same requestor It seems that if we ever try to reply to a selection request after another has been sent by the same requestor (we reply in FIFO order), the requestor never reads from it, and we end up stalling forever on a transfer that will never complete. It appears that `XCB_SELECTION_REQUEST` has some sort of singleton semantics, and new requests for the same selection are meant to replace outstanding older ones. I couldn't find a reference for this, but empirically this does seem to be the case. Real (contrived) case where we don't currently do this, and things break: * run fcitx * run Slack * wl-copy < <(base64 /opt/firefox/libxul.so) # or some other large file * focus Slack (no need to paste) fcitx will send in an `XCB_SELECTION_REQUEST`, and we'll start processing it. Immediately after, Slack sends its own. fcitx hangs for a long, long time. In the meantime, Slack retries and sends another selection request. We now have two pending requests from Slack. Eventually fcitx gives up (or it can be `pkill`'d), and we start processing the first request Slack gave us (FIFO). Slack (Electron?) isn't listening on the other end anymore, and this transfer never completes. The X11 clipboard becomes unusable until Slack is killed. After this patch, the clipboard is immediately usable again after fcitx bails. Also added a bunch of debug-level logging that makes diagnosing this sort of issue easier. Refs swaywm/sway#4007. --- xwayland/selection/outgoing.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/xwayland/selection/outgoing.c b/xwayland/selection/outgoing.c index 943e4d1a4..190fb7416 100644 --- a/xwayland/selection/outgoing.c +++ b/xwayland/selection/outgoing.c @@ -71,9 +71,11 @@ static void xwm_selection_transfer_destroy_outgoing( struct wlr_xwm_selection *selection = transfer->selection; bool was_first = transfer == xwm_selection_transfer_get_first(selection); wl_list_remove(&transfer->outgoing_link); + wlr_log(WLR_DEBUG, "Destroying transfer %p", transfer); // Start next queued transfer if we just removed the active one. if (was_first && !wl_list_empty(&selection->outgoing)) { + wlr_log(WLR_DEBUG, "Destroyed transfer was active, starting next"); xwm_selection_transfer_start_outgoing( xwm_selection_transfer_get_first(selection)); } @@ -230,6 +232,8 @@ static void xwm_selection_transfer_start_outgoing( struct wlr_xwm *xwm = transfer->selection->xwm; struct wl_event_loop *loop = wl_display_get_event_loop(xwm->xwayland->wl_display); + wlr_log(WLR_DEBUG, "Starting transfer %p", transfer); + assert(transfer == xwm_selection_transfer_get_first(transfer->selection)); transfer->source = wl_event_loop_add_fd(loop, transfer->source_fd, WL_EVENT_READABLE, xwm_data_source_read, transfer); } @@ -312,14 +316,34 @@ static void xwm_selection_send_data(struct wlr_xwm_selection *selection, transfer->source_fd = p[0]; wlr_log(WLR_DEBUG, "Sending Wayland selection %u to Xwayland window with " - "MIME type %s, target %u", req->target, mime_type, req->target); + "MIME type %s, target %u, transfer %p", req->target, mime_type, + req->target, transfer); xwm_selection_source_send(selection, mime_type, p[1]); + // It seems that if we ever try to reply to a selection request after + // another has been sent by the same requestor, the requestor never reads + // from it. It appears to only ever read from the latest, so purge stale + // transfers to prevent clipboard hangs. + struct wlr_xwm_selection_transfer *outgoing, *tmp; + wl_list_for_each_safe(outgoing, tmp, &selection->outgoing, outgoing_link) { + if (transfer->request.requestor == outgoing->request.requestor) { + wlr_log(WLR_DEBUG, "Destroying stale transfer %p", outgoing); + xwm_selection_send_notify(selection->xwm, &outgoing->request, false); + xwm_selection_transfer_destroy_outgoing(outgoing); + } + } + wl_list_insert(&selection->outgoing, &transfer->outgoing_link); // We can only handle one transfer at a time if (wl_list_length(&selection->outgoing) == 1) { + wlr_log(WLR_DEBUG, "No transfer active, starting %p now", transfer); xwm_selection_transfer_start_outgoing(transfer); + } else { + struct wlr_xwm_selection_transfer *outgoing; + wl_list_for_each(outgoing, &selection->outgoing, outgoing_link) { + wlr_log(WLR_DEBUG, "Transfer %p still queued", outgoing); + } } } From afeb941ca027995530d940b81f28421456c77640 Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Mon, 12 Oct 2020 23:47:29 -0400 Subject: [PATCH 59/94] xwayland: notify requestor when we fail to respond to their request We already mostly did this, but there were a couple of branches (`calloc` failures) where we'd bail without letting the other side know. Refs swaywm/sway#4007. Likely not going to be a real improvement there (if `calloc` fails you're already pretty screwed), but it does address a theoretical possibility. --- xwayland/selection/outgoing.c | 40 ++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/xwayland/selection/outgoing.c b/xwayland/selection/outgoing.c index 190fb7416..a5ce2fd26 100644 --- a/xwayland/selection/outgoing.c +++ b/xwayland/selection/outgoing.c @@ -265,15 +265,14 @@ static struct wl_array *xwm_selection_source_get_mime_types( /** * Read the Wayland selection and send it to an Xwayland client. */ -static void xwm_selection_send_data(struct wlr_xwm_selection *selection, +static bool xwm_selection_send_data(struct wlr_xwm_selection *selection, xcb_selection_request_event_t *req, const char *mime_type) { // Check MIME type struct wl_array *mime_types = xwm_selection_source_get_mime_types(selection); if (mime_types == NULL) { wlr_log(WLR_ERROR, "not sending selection: no MIME type list available"); - xwm_selection_send_notify(selection->xwm, req, false); - return; + return false; } bool found = false; @@ -288,16 +287,16 @@ static void xwm_selection_send_data(struct wlr_xwm_selection *selection, if (!found) { wlr_log(WLR_ERROR, "not sending selection: " "requested an unsupported MIME type %s", mime_type); - xwm_selection_send_notify(selection->xwm, req, false); - return; + return false; } struct wlr_xwm_selection_transfer *transfer = calloc(1, sizeof(struct wlr_xwm_selection_transfer)); if (transfer == NULL) { wlr_log(WLR_ERROR, "Allocation failed"); - return; + return false; } + transfer->selection = selection; transfer->request = *req; wl_array_init(&transfer->source_data); @@ -305,9 +304,9 @@ static void xwm_selection_send_data(struct wlr_xwm_selection *selection, int p[2]; if (pipe(p) == -1) { wlr_log_errno(WLR_ERROR, "pipe() failed"); - xwm_selection_send_notify(selection->xwm, req, false); - return; + return false; } + fcntl(p[0], F_SETFD, FD_CLOEXEC); fcntl(p[0], F_SETFL, O_NONBLOCK); fcntl(p[1], F_SETFD, FD_CLOEXEC); @@ -345,6 +344,8 @@ static void xwm_selection_send_data(struct wlr_xwm_selection *selection, wlr_log(WLR_DEBUG, "Transfer %p still queued", outgoing); } } + + return true; } static void xwm_selection_send_targets(struct wlr_xwm_selection *selection, @@ -416,12 +417,12 @@ void xwm_handle_selection_request(struct wlr_xwm *xwm, xwm_get_selection(xwm, req->selection); if (selection == NULL) { wlr_log(WLR_DEBUG, "received selection request for unknown selection"); - return; + goto fail_notify_requestor; } if (selection->window != req->owner) { wlr_log(WLR_DEBUG, "received selection request with invalid owner"); - return; + goto fail_notify_requestor; } // No xwayland surface focused, deny access to clipboard @@ -430,8 +431,7 @@ void xwm_handle_selection_request(struct wlr_xwm *xwm, wlr_log(WLR_DEBUG, "denying read access to selection %u (%s): " "no xwayland surface focused", selection->atom, selection_name); free(selection_name); - xwm_selection_send_notify(xwm, req, false); - return; + goto fail_notify_requestor; } if (req->target == xwm->atoms[TARGETS]) { @@ -446,12 +446,22 @@ void xwm_handle_selection_request(struct wlr_xwm *xwm, if (mime_type == NULL) { wlr_log(WLR_ERROR, "ignoring selection request: unknown atom %u", req->target); - xwm_selection_send_notify(xwm, req, false); - return; + goto fail_notify_requestor; } - xwm_selection_send_data(selection, req, mime_type); + + bool send_success = xwm_selection_send_data(selection, req, mime_type); free(mime_type); + if (!send_success) { + goto fail_notify_requestor; + } } + + return; + +fail_notify_requestor: + // Something went wrong, and there won't be any data being sent to the + // requestor, so let them know. + xwm_selection_send_notify(xwm, req, false); } void xwm_handle_selection_destroy_notify(struct wlr_xwm *xwm, From 99f3c643bf9407c4e0b3eb901b1e44588ae11357 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Wed, 14 Oct 2020 11:47:23 +0200 Subject: [PATCH 60/94] xwayland: add set_geometry event This is necessary to react to changes in position of override-redirect views. --- include/wlr/xwayland.h | 1 + xwayland/xwm.c | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/include/wlr/xwayland.h b/include/wlr/xwayland.h index 26a14aea6..b801b5dd4 100644 --- a/include/wlr/xwayland.h +++ b/include/wlr/xwayland.h @@ -198,6 +198,7 @@ struct wlr_xwayland_surface { struct wl_signal set_hints; struct wl_signal set_decorations; struct wl_signal set_override_redirect; + struct wl_signal set_geometry; struct wl_signal ping_timeout; } events; diff --git a/xwayland/xwm.c b/xwayland/xwm.c index b3e6c885e..b53759da9 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -164,6 +164,7 @@ static struct wlr_xwayland_surface *xwayland_surface_create( wl_signal_init(&surface->events.set_decorations); wl_signal_init(&surface->events.set_override_redirect); wl_signal_init(&surface->events.ping_timeout); + wl_signal_init(&surface->events.set_geometry); xcb_get_geometry_reply_t *geometry_reply = xcb_get_geometry_reply(xwm->xcb_conn, geometry_cookie, NULL); @@ -935,15 +936,25 @@ static void xwm_handle_configure_notify(struct wlr_xwm *xwm, return; } - xsurface->x = ev->x; - xsurface->y = ev->y; - xsurface->width = ev->width; - xsurface->height = ev->height; + bool geometry_changed = + (xsurface->x != ev->x || xsurface->y != ev->y || + xsurface->width != ev->width || xsurface->height != ev->height); + + if (geometry_changed) { + xsurface->x = ev->x; + xsurface->y = ev->y; + xsurface->width = ev->width; + xsurface->height = ev->height; + } if (xsurface->override_redirect != ev->override_redirect) { xsurface->override_redirect = ev->override_redirect; wlr_signal_emit_safe(&xsurface->events.set_override_redirect, xsurface); } + + if (geometry_changed) { + wlr_signal_emit_safe(&xsurface->events.set_geometry, NULL); + } } #define ICCCM_WITHDRAWN_STATE 0 From 616f06c25c06ec04430c4b8f0ac15a40325cd177 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Fri, 16 Oct 2020 12:41:32 +0200 Subject: [PATCH 61/94] xdg_positioner: remove unused field The resource field of wlr_xdg_positioner is never initialized or accessed within wlroots. The wl_resource for this interface is stored in the wlr_xdg_positioner_resource struct. --- include/wlr/types/wlr_xdg_shell.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index 45c5aee08..0b9167d2c 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -48,8 +48,6 @@ struct wlr_xdg_client { }; struct wlr_xdg_positioner { - struct wl_resource *resource; - struct wlr_box anchor_rect; enum xdg_positioner_anchor anchor; enum xdg_positioner_gravity gravity; From e410ff8dd4e83ffc6419eb0709693afb25892e47 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sun, 18 Oct 2020 15:13:05 +0200 Subject: [PATCH 62/94] wlr_drag: remove unused point_destroy field --- include/wlr/types/wlr_data_device.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index 555eeab01..87c578aed 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -136,7 +136,6 @@ struct wlr_drag { struct wl_signal destroy; } events; - struct wl_listener point_destroy; struct wl_listener source_destroy; struct wl_listener seat_client_destroy; struct wl_listener icon_destroy; From b98522b38fa19c732e0bc420178b76b847460dfe Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Sun, 18 Oct 2020 16:33:03 +0300 Subject: [PATCH 63/94] backend/wayland: add touch support to the wayland backend Goal currently is to get support working for a single output, thus there is only one touch device created. Multi-output support is left for later. --- backend/wayland/seat.c | 133 ++++++++++++++++++++++++++++++++++++++ include/backend/wayland.h | 2 + 2 files changed, 135 insertions(+) diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index 71e04de6b..a23a4c917 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -276,6 +276,95 @@ static struct wl_keyboard_listener keyboard_listener = { .repeat_info = keyboard_handle_repeat_info }; +static void touch_coordinates_to_absolute(struct wlr_wl_input_device *device, + wl_fixed_t x, wl_fixed_t y, double *sx, double *sy) { + // TODO: each output needs its own touch + struct wlr_wl_output *output, *tmp; + wl_list_for_each_safe(output, tmp, &device->backend->outputs, link) { + *sx = wl_fixed_to_double(x) / output->wlr_output.width; + *sy = wl_fixed_to_double(y) / output->wlr_output.height; + return; // Choose the first output in the list + } + + *sx = *sy = 0; +} + +static void touch_handle_down(void *data, struct wl_touch *wl_touch, + uint32_t serial, uint32_t time, struct wl_surface *surface, + int32_t id, wl_fixed_t x, wl_fixed_t y) { + struct wlr_wl_input_device *device = data; + assert(device && device->wlr_input_device.touch); + + double sx, sy; + touch_coordinates_to_absolute(device, x, y, &sx, &sy); + struct wlr_event_touch_down event = { + .device = &device->wlr_input_device, + .time_msec = time, + .touch_id = id, + .x = sx, + .y = sy + }; + wlr_signal_emit_safe(&device->wlr_input_device.touch->events.down, &event); +} + +static void touch_handle_up(void *data, struct wl_touch *wl_touch, + uint32_t serial, uint32_t time, int32_t id) { + struct wlr_wl_input_device *device = data; + assert(device && device->wlr_input_device.touch); + + struct wlr_event_touch_up event = { + .device = &device->wlr_input_device, + .time_msec = time, + .touch_id = id, + }; + wlr_signal_emit_safe(&device->wlr_input_device.touch->events.up, &event); +} + +static void touch_handle_motion(void *data, struct wl_touch *wl_touch, + uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y) { + struct wlr_wl_input_device *device = data; + assert(device && device->wlr_input_device.touch); + + double sx, sy; + touch_coordinates_to_absolute(device, x, y, &sx, &sy); + struct wlr_event_touch_motion event = { + .device = &device->wlr_input_device, + .time_msec = time, + .touch_id = id, + .x = sx, + .y = sy + }; + wlr_signal_emit_safe(&device->wlr_input_device.touch->events.motion, &event); +} + +static void touch_handle_frame(void *data, struct wl_touch *wl_touch) { + // no-op +} + +static void touch_handle_cancel(void *data, struct wl_touch *wl_touch) { + // no-op +} + +static void touch_handle_shape(void *data, struct wl_touch *wl_touch, + int32_t id, wl_fixed_t major, wl_fixed_t minor) { + // no-op +} + +static void touch_handle_orientation(void *data, struct wl_touch *wl_touch, + int32_t id, wl_fixed_t orientation) { + // no-op +} + +static struct wl_touch_listener touch_listener = { + .down = touch_handle_down, + .up = touch_handle_up, + .motion = touch_handle_motion, + .frame = touch_handle_frame, + .cancel = touch_handle_cancel, + .shape = touch_handle_shape, + .orientation = touch_handle_orientation, +}; + static struct wlr_wl_input_device *get_wl_input_device_from_input_device( struct wlr_input_device *wlr_dev) { assert(wlr_input_device_is_wl(wlr_dev)); @@ -563,6 +652,28 @@ void create_wl_keyboard(struct wl_keyboard *wl_keyboard, struct wlr_wl_backend * wlr_signal_emit_safe(&wl->backend.events.new_input, wlr_dev); } +void create_wl_touch(struct wl_touch *wl_touch, struct wlr_wl_backend *wl) { + struct wlr_wl_input_device *dev = + create_wl_input_device(wl, WLR_INPUT_DEVICE_TOUCH); + if (!dev) { + return; + } + + struct wlr_input_device *wlr_dev = &dev->wlr_input_device; + + wlr_dev->touch = calloc(1, sizeof(*wlr_dev->touch)); + if (!wlr_dev->touch) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + free(dev); + return; + } + wlr_touch_init(wlr_dev->touch, NULL); + + wl_touch_add_listener(wl_touch, &touch_listener, dev); + wlr_signal_emit_safe(&wl->backend.events.new_input, wlr_dev); +} + + static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, enum wl_seat_capability caps) { struct wlr_wl_backend *backend = data; @@ -614,6 +725,28 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, } assert(backend->keyboard == NULL); // free'ed by input_device_destroy } + + if ((caps & WL_SEAT_CAPABILITY_TOUCH) && backend->touch == NULL) { + wlr_log(WLR_DEBUG, "seat %p offered touch", (void *)wl_seat); + + backend->touch = wl_seat_get_touch(wl_seat); + if (backend->started) { + create_wl_touch(backend->touch, backend); + } + } + if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && backend->touch != NULL) { + wlr_log(WLR_DEBUG, "seat %p dropped touch", (void *)wl_seat); + + struct wlr_input_device *device, *tmp; + wl_list_for_each_safe(device, tmp, &backend->devices, link) { + if (device->type == WLR_INPUT_DEVICE_TOUCH) { + wlr_input_device_destroy(device); + } + } + + wl_touch_release(backend->touch); + backend->touch = NULL; + } } static void seat_handle_name(void *data, struct wl_seat *wl_seat, diff --git a/include/backend/wayland.h b/include/backend/wayland.h index 9a8a404bb..a053adedd 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -39,6 +39,7 @@ struct wlr_wl_backend { struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1; struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1; struct wl_seat *seat; + struct wl_touch *touch; struct wl_pointer *pointer; struct wl_keyboard *keyboard; struct wlr_wl_pointer *current_pointer; @@ -112,6 +113,7 @@ void update_wl_output_cursor(struct wlr_wl_output *output); struct wlr_wl_pointer *pointer_get_wl(struct wlr_pointer *wlr_pointer); void create_wl_pointer(struct wl_pointer *wl_pointer, struct wlr_wl_output *output); void create_wl_keyboard(struct wl_keyboard *wl_keyboard, struct wlr_wl_backend *wl); +void create_wl_touch(struct wl_touch *wl_touch, struct wlr_wl_backend *wl); struct wlr_wl_input_device *create_wl_input_device( struct wlr_wl_backend *backend, enum wlr_input_device_type type); From df417b7e95fce515f85b20e180742bcc289e35d4 Mon Sep 17 00:00:00 2001 From: Mykola Orliuk Date: Sat, 3 Oct 2020 15:06:05 +0200 Subject: [PATCH 64/94] backend/wayland: manage cursor for current pointer --- backend/wayland/output.c | 5 +++-- backend/wayland/seat.c | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/backend/wayland/output.c b/backend/wayland/output.c index bd17fa208..b234c6a0b 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -419,8 +419,9 @@ static void output_destroy(struct wlr_output *wlr_output) { } void update_wl_output_cursor(struct wlr_wl_output *output) { - if (output->backend->pointer && output->enter_serial) { - wl_pointer_set_cursor(output->backend->pointer, output->enter_serial, + struct wlr_wl_pointer *pointer = output->backend->current_pointer; + if (pointer && pointer->output == output && output->enter_serial) { + wl_pointer_set_cursor(pointer->wl_pointer, output->enter_serial, output->cursor.surface, output->cursor.hotspot_x, output->cursor.hotspot_y); } diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index a23a4c917..cce5c0dce 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -48,6 +48,7 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, struct wlr_wl_output *output = wl_surface_get_user_data(surface); assert(output); struct wlr_wl_pointer *pointer = output_get_pointer(output); + assert(!backend->current_pointer || backend->current_pointer == pointer); output->enter_serial = serial; backend->current_pointer = pointer; From 1ac5257357fdf51b2864149f4896c51afd2eda09 Mon Sep 17 00:00:00 2001 From: Mykola Orliuk Date: Sat, 3 Oct 2020 17:34:32 +0200 Subject: [PATCH 65/94] backend/wayland: factor out wlr_wl_seat --- backend/wayland/backend.c | 28 ++++++------- backend/wayland/output.c | 7 +++- backend/wayland/seat.c | 84 +++++++++++++++++++++++++++------------ include/backend/wayland.h | 17 +++++--- 4 files changed, 88 insertions(+), 48 deletions(-) diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index a09126ce2..2059b7266 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -103,9 +103,9 @@ static void registry_global(void *data, struct wl_registry *registry, wl->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 4); } else if (strcmp(iface, wl_seat_interface.name) == 0) { - wl->seat = wl_registry_bind(registry, name, + struct wl_seat *wl_seat = wl_registry_bind(registry, name, &wl_seat_interface, 5); - wl_seat_add_listener(wl->seat, &seat_listener, wl); + create_wl_seat(wl_seat, wl); } else if (strcmp(iface, xdg_wm_base_interface.name) == 0) { wl->xdg_wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); @@ -155,13 +155,16 @@ static bool backend_start(struct wlr_backend *backend) { wl->started = true; - if (wl->keyboard) { - create_wl_keyboard(wl->keyboard, wl); - } + struct wlr_wl_seat *seat = wl->seat; + if (seat != NULL) { + if (seat->keyboard) { + create_wl_keyboard(seat->keyboard, wl); + } - if (wl->tablet_manager && wl->seat) { - wl_add_tablet_seat(wl->tablet_manager, - wl->seat, wl); + if (wl->tablet_manager) { + wl_add_tablet_seat(wl->tablet_manager, + seat->wl_seat, wl); + } } for (size_t i = 0; i < wl->requested_outputs; ++i) { @@ -192,8 +195,6 @@ static void backend_destroy(struct wlr_backend *backend) { wl_list_remove(&wl->local_display_destroy.link); - free(wl->seat_name); - wl_event_source_remove(wl->remote_display_src); wlr_renderer_destroy(wl->renderer); @@ -201,12 +202,7 @@ static void backend_destroy(struct wlr_backend *backend) { wlr_drm_format_set_finish(&wl->linux_dmabuf_v1_formats); - if (wl->pointer) { - wl_pointer_destroy(wl->pointer); - } - if (wl->seat) { - wl_seat_destroy(wl->seat); - } + destroy_wl_seats(wl); if (wl->zxdg_decoration_manager_v1) { zxdg_decoration_manager_v1_destroy(wl->zxdg_decoration_manager_v1); } diff --git a/backend/wayland/output.c b/backend/wayland/output.c index b234c6a0b..568d90db6 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -586,8 +586,11 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *wlr_backend) { wlr_signal_emit_safe(&backend->backend.events.new_output, wlr_output); - if (backend->pointer != NULL) { - create_wl_pointer(backend->pointer, output); + struct wlr_wl_seat *seat = backend->seat; + if (seat != NULL) { + if (seat->pointer) { + create_wl_pointer(seat->pointer, output); + } } return wlr_output; diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index cce5c0dce..f20619d51 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -372,12 +372,49 @@ static struct wlr_wl_input_device *get_wl_input_device_from_input_device( return (struct wlr_wl_input_device *)wlr_dev; } +void create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl) { + assert(!wl->seat); // only one seat supported at the moment + struct wlr_wl_seat *seat = calloc(1, sizeof(struct wlr_wl_seat)); + seat->wl_seat = wl_seat; + wl->seat = seat; + wl_seat_add_listener(wl_seat, &seat_listener, wl); +} + +void destroy_wl_seats(struct wlr_wl_backend *wl) { + struct wlr_wl_seat *seat = wl->seat; + if (!seat) { + return; + } + + if (seat->pointer) { + wl_pointer_destroy(seat->pointer); + } + free(seat->name); + if (seat->wl_seat) { + wl_seat_destroy(seat->wl_seat); + } + free(seat); +} + +static struct wlr_wl_seat *backend_get_seat(struct wlr_wl_backend *backend, struct wl_seat *wl_seat) { + assert(backend->seat && backend->seat->wl_seat == wl_seat); + return backend->seat; +} + +static struct wlr_wl_seat *input_device_get_seat(struct wlr_input_device *wlr_dev) { + struct wlr_wl_input_device *dev = + get_wl_input_device_from_input_device(wlr_dev); + assert(dev->backend->seat); + return dev->backend->seat; +} + static void input_device_destroy(struct wlr_input_device *wlr_dev) { struct wlr_wl_input_device *dev = get_wl_input_device_from_input_device(wlr_dev); if (dev->wlr_input_device.type == WLR_INPUT_DEVICE_KEYBOARD) { - wl_keyboard_release(dev->backend->keyboard); - dev->backend->keyboard = NULL; + struct wlr_wl_seat *seat = input_device_get_seat(wlr_dev); + wl_keyboard_release(seat->keyboard); + seat->keyboard = NULL; } wl_list_remove(&dev->wlr_input_device.link); free(dev); @@ -678,20 +715,20 @@ void create_wl_touch(struct wl_touch *wl_touch, struct wlr_wl_backend *wl) { static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, enum wl_seat_capability caps) { struct wlr_wl_backend *backend = data; - assert(backend->seat == wl_seat); + struct wlr_wl_seat *seat = backend_get_seat(backend, wl_seat); - if ((caps & WL_SEAT_CAPABILITY_POINTER) && backend->pointer == NULL) { + if ((caps & WL_SEAT_CAPABILITY_POINTER) && seat->pointer == NULL) { wlr_log(WLR_DEBUG, "seat %p offered pointer", (void *)wl_seat); struct wl_pointer *wl_pointer = wl_seat_get_pointer(wl_seat); - backend->pointer = wl_pointer; + seat->pointer = wl_pointer; struct wlr_wl_output *output; wl_list_for_each(output, &backend->outputs, link) { create_wl_pointer(wl_pointer, output); } } - if (!(caps & WL_SEAT_CAPABILITY_POINTER) && backend->pointer != NULL) { + if (!(caps & WL_SEAT_CAPABILITY_POINTER) && seat->pointer != NULL) { wlr_log(WLR_DEBUG, "seat %p dropped pointer", (void *)wl_seat); struct wlr_input_device *device, *tmp; @@ -701,21 +738,21 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, } } - wl_pointer_release(backend->pointer); - backend->pointer = NULL; + wl_pointer_release(seat->pointer); + seat->pointer = NULL; } - if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && backend->keyboard == NULL) { + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->keyboard == NULL) { wlr_log(WLR_DEBUG, "seat %p offered keyboard", (void *)wl_seat); struct wl_keyboard *wl_keyboard = wl_seat_get_keyboard(wl_seat); - backend->keyboard = wl_keyboard; + seat->keyboard = wl_keyboard; if (backend->started) { create_wl_keyboard(wl_keyboard, backend); } } - if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && backend->keyboard != NULL) { + if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->keyboard != NULL) { wlr_log(WLR_DEBUG, "seat %p dropped keyboard", (void *)wl_seat); struct wlr_input_device *device, *tmp; @@ -724,18 +761,18 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, wlr_input_device_destroy(device); } } - assert(backend->keyboard == NULL); // free'ed by input_device_destroy + assert(seat->keyboard == NULL); // free'ed by input_device_destroy } - if ((caps & WL_SEAT_CAPABILITY_TOUCH) && backend->touch == NULL) { + if ((caps & WL_SEAT_CAPABILITY_TOUCH) && seat->touch == NULL) { wlr_log(WLR_DEBUG, "seat %p offered touch", (void *)wl_seat); - backend->touch = wl_seat_get_touch(wl_seat); + seat->touch = wl_seat_get_touch(wl_seat); if (backend->started) { - create_wl_touch(backend->touch, backend); + create_wl_touch(seat->touch, backend); } } - if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && backend->touch != NULL) { + if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && seat->touch != NULL) { wlr_log(WLR_DEBUG, "seat %p dropped touch", (void *)wl_seat); struct wlr_input_device *device, *tmp; @@ -745,18 +782,17 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, } } - wl_touch_release(backend->touch); - backend->touch = NULL; + wl_touch_release(seat->touch); + seat->touch = NULL; } } static void seat_handle_name(void *data, struct wl_seat *wl_seat, const char *name) { struct wlr_wl_backend *backend = data; - assert(backend->seat == wl_seat); - // Do we need to check if seatName was previously set for name change? - free(backend->seat_name); - backend->seat_name = strdup(name); + struct wlr_wl_seat *seat = backend_get_seat(backend, wl_seat); + free(seat->name); + seat->name = strdup(name); } const struct wl_seat_listener seat_listener = { @@ -765,7 +801,5 @@ const struct wl_seat_listener seat_listener = { }; struct wl_seat *wlr_wl_input_device_get_seat(struct wlr_input_device *wlr_dev) { - struct wlr_wl_input_device *dev = - get_wl_input_device_from_input_device(wlr_dev); - return dev->backend->seat; + return input_device_get_seat(wlr_dev)->wl_seat; } diff --git a/include/backend/wayland.h b/include/backend/wayland.h index a053adedd..61b349a5e 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -38,13 +38,9 @@ struct wlr_wl_backend { struct wp_presentation *presentation; struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1; struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1; - struct wl_seat *seat; - struct wl_touch *touch; - struct wl_pointer *pointer; - struct wl_keyboard *keyboard; + struct wlr_wl_seat *seat; struct wlr_wl_pointer *current_pointer; struct zwp_tablet_manager_v2 *tablet_manager; - char *seat_name; struct wlr_drm_format_set linux_dmabuf_v1_formats; }; @@ -108,6 +104,15 @@ struct wlr_wl_pointer { struct wl_listener output_destroy; }; +struct wlr_wl_seat { + struct wl_seat *wl_seat; + + char *name; + struct wl_touch *touch; + struct wl_pointer *pointer; + struct wl_keyboard *keyboard; +}; + struct wlr_wl_backend *get_wl_backend_from_backend(struct wlr_backend *backend); void update_wl_output_cursor(struct wlr_wl_output *output); struct wlr_wl_pointer *pointer_get_wl(struct wlr_pointer *wlr_pointer); @@ -116,6 +121,8 @@ void create_wl_keyboard(struct wl_keyboard *wl_keyboard, struct wlr_wl_backend * void create_wl_touch(struct wl_touch *wl_touch, struct wlr_wl_backend *wl); struct wlr_wl_input_device *create_wl_input_device( struct wlr_wl_backend *backend, enum wlr_input_device_type type); +void create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl); +void destroy_wl_seats(struct wlr_wl_backend *wl); extern const struct wl_seat_listener seat_listener; From 36395e5b1c4107d6945213e0c06eaa58d885f97c Mon Sep 17 00:00:00 2001 From: Daniel Kondor Date: Sun, 18 Oct 2020 23:14:35 +0800 Subject: [PATCH 66/94] foreign-toplevel-management: report parent toplevel Based on the wlr-protocols PR: https://github.com/swaywm/wlr-protocols/pull/52 --- examples/foreign-toplevel.c | 41 +++++++++++-- .../wlr_foreign_toplevel_management_v1.h | 17 ++++++ ...oreign-toplevel-management-unstable-v1.xml | 15 ++++- types/wlr_foreign_toplevel_management_v1.c | 58 ++++++++++++++++++- 4 files changed, 123 insertions(+), 8 deletions(-) diff --git a/examples/foreign-toplevel.c b/examples/foreign-toplevel.c index 1d41d01af..995d4f6cc 100644 --- a/examples/foreign-toplevel.c +++ b/examples/foreign-toplevel.c @@ -7,7 +7,7 @@ #include #include "wlr-foreign-toplevel-management-unstable-v1-client-protocol.h" -#define WLR_FOREIGN_TOPLEVEL_MANAGEMENT_VERSION 2 +#define WLR_FOREIGN_TOPLEVEL_MANAGEMENT_VERSION 3 /** * Usage: @@ -38,11 +38,14 @@ enum toplevel_state_field { TOPLEVEL_STATE_INVALID = (1 << 4), }; +static const uint32_t no_parent = (uint32_t)-1; + struct toplevel_state { char *title; char *app_id; uint32_t state; + uint32_t parent_id; }; static void copy_state(struct toplevel_state *current, @@ -67,6 +70,8 @@ static void copy_state(struct toplevel_state *current, current->state = pending->state; } + current->parent_id = pending->parent_id; + pending->state = TOPLEVEL_STATE_INVALID; } @@ -84,6 +89,12 @@ static void print_toplevel(struct toplevel_v1 *toplevel, bool print_endl) { toplevel->current.title ?: "(nil)", toplevel->current.app_id ?: "(nil)"); + if (toplevel->current.parent_id != no_parent) { + printf(" parent=%u", toplevel->current.parent_id); + } else { + printf(" no parent"); + } + if (print_endl) { printf("\n"); } @@ -172,6 +183,28 @@ static void toplevel_handle_state(void *data, toplevel->pending.state = array_to_state(state); } +static struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager = NULL; +static struct wl_list toplevel_list; + +static void toplevel_handle_parent(void *data, + struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel, + struct zwlr_foreign_toplevel_handle_v1 *zwlr_parent) { + struct toplevel_v1 *toplevel = data; + toplevel->pending.parent_id = no_parent; + if (zwlr_parent) { + struct toplevel_v1 *toplevel_tmp; + wl_list_for_each(toplevel_tmp, &toplevel_list, link) { + if (toplevel_tmp->zwlr_toplevel == zwlr_parent) { + toplevel->pending.parent_id = toplevel_tmp->id; + break; + } + } + if (toplevel->pending.parent_id == no_parent) { + fprintf(stderr, "Cannot find parent toplevel!\n"); + } + } +} + static void toplevel_handle_done(void *data, struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel) { struct toplevel_v1 *toplevel = data; @@ -202,11 +235,9 @@ static const struct zwlr_foreign_toplevel_handle_v1_listener toplevel_impl = { .state = toplevel_handle_state, .done = toplevel_handle_done, .closed = toplevel_handle_closed, + .parent = toplevel_handle_parent }; -static struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager = NULL; -static struct wl_list toplevel_list; - static void toplevel_manager_handle_toplevel(void *data, struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager, struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel) { @@ -218,6 +249,8 @@ static void toplevel_manager_handle_toplevel(void *data, toplevel->id = global_id++; toplevel->zwlr_toplevel = zwlr_toplevel; + toplevel->current.parent_id = no_parent; + toplevel->pending.parent_id = no_parent; wl_list_insert(&toplevel_list, &toplevel->link); zwlr_foreign_toplevel_handle_v1_add_listener(zwlr_toplevel, &toplevel_impl, diff --git a/include/wlr/types/wlr_foreign_toplevel_management_v1.h b/include/wlr/types/wlr_foreign_toplevel_management_v1.h index 90d88637c..6ea9d47fd 100644 --- a/include/wlr/types/wlr_foreign_toplevel_management_v1.h +++ b/include/wlr/types/wlr_foreign_toplevel_management_v1.h @@ -50,6 +50,7 @@ struct wlr_foreign_toplevel_handle_v1 { char *title; char *app_id; + struct wlr_foreign_toplevel_handle_v1 *parent; struct wl_list outputs; // wlr_foreign_toplevel_v1_output uint32_t state; // wlr_foreign_toplevel_v1_state @@ -104,6 +105,12 @@ struct wlr_foreign_toplevel_manager_v1 *wlr_foreign_toplevel_manager_v1_create( struct wlr_foreign_toplevel_handle_v1 *wlr_foreign_toplevel_handle_v1_create( struct wlr_foreign_toplevel_manager_v1 *manager); +/* Destroy the given toplevel handle, sending the closed event to any + * client. Also, if the destroyed toplevel is set as a parent of any + * other valid toplevel, clients still holding a handle to both are + * sent a parent signal with NULL parent. If this is not desired, the + * caller should ensure that any child toplevels are destroyed before + * the parent. */ void wlr_foreign_toplevel_handle_v1_destroy( struct wlr_foreign_toplevel_handle_v1 *toplevel); @@ -126,4 +133,14 @@ void wlr_foreign_toplevel_handle_v1_set_activated( void wlr_foreign_toplevel_handle_v1_set_fullscreen( struct wlr_foreign_toplevel_handle_v1* toplevel, bool fullscreen); +/* Set the parent of a toplevel. If the parent changed from its previous + * value, also sends a parent event to all clients that hold handles to + * both toplevel and parent (no message is sent to clients that have + * previously destroyed their parent handle). NULL is allowed as the + * parent, meaning no parent exists. */ +void wlr_foreign_toplevel_handle_v1_set_parent( + struct wlr_foreign_toplevel_handle_v1 *toplevel, + struct wlr_foreign_toplevel_handle_v1 *parent); + + #endif diff --git a/protocol/wlr-foreign-toplevel-management-unstable-v1.xml b/protocol/wlr-foreign-toplevel-management-unstable-v1.xml index a97738f8a..206143b4d 100644 --- a/protocol/wlr-foreign-toplevel-management-unstable-v1.xml +++ b/protocol/wlr-foreign-toplevel-management-unstable-v1.xml @@ -25,7 +25,7 @@ THIS SOFTWARE. - + The purpose of this protocol is to enable the creation of taskbars and docks by providing them with a list of opened applications and @@ -68,7 +68,7 @@ - + A zwlr_foreign_toplevel_handle_v1 object represents an opened toplevel window. Each app may have multiple opened toplevels. @@ -255,5 +255,16 @@ actually changes, this will be indicated by the state event. + + + + + + This event is emitted whenever the parent of the toplevel changes. + + No event is emitted when the parent handle is destroyed by the client. + + + diff --git a/types/wlr_foreign_toplevel_management_v1.c b/types/wlr_foreign_toplevel_management_v1.c index aed0e203c..5e7b731c6 100644 --- a/types/wlr_foreign_toplevel_management_v1.c +++ b/types/wlr_foreign_toplevel_management_v1.c @@ -9,7 +9,7 @@ #include "util/signal.h" #include "wlr-foreign-toplevel-management-unstable-v1-protocol.h" -#define FOREIGN_TOPLEVEL_MANAGEMENT_V1_VERSION 2 +#define FOREIGN_TOPLEVEL_MANAGEMENT_V1_VERSION 3 static const struct zwlr_foreign_toplevel_handle_v1_interface toplevel_handle_impl; @@ -405,6 +405,37 @@ void wlr_foreign_toplevel_handle_v1_set_fullscreen( toplevel_send_state(toplevel); } +static void toplevel_resource_send_parent( + struct wl_resource *toplevel_resource, + struct wlr_foreign_toplevel_handle_v1 *parent) { + struct wl_client *client = wl_resource_get_client(toplevel_resource); + struct wl_resource *parent_resource = NULL; + if (parent) { + parent_resource = wl_resource_find_for_client(&parent->resources, client); + if (!parent_resource) { + /* don't send an event if this client destroyed the parent handle */ + return; + } + } + zwlr_foreign_toplevel_handle_v1_send_parent(toplevel_resource, + parent_resource); +} + +void wlr_foreign_toplevel_handle_v1_set_parent( + struct wlr_foreign_toplevel_handle_v1 *toplevel, + struct wlr_foreign_toplevel_handle_v1 *parent) { + if (parent == toplevel->parent) { + /* only send parent event to the clients if there was a change */ + return; + } + struct wl_resource *toplevel_resource, *tmp; + wl_resource_for_each_safe(toplevel_resource, tmp, &toplevel->resources) { + toplevel_resource_send_parent(toplevel_resource, parent); + } + toplevel->parent = parent; + toplevel_update_idle_source(toplevel); +} + void wlr_foreign_toplevel_handle_v1_destroy( struct wlr_foreign_toplevel_handle_v1 *toplevel) { if (!toplevel) { @@ -432,6 +463,19 @@ void wlr_foreign_toplevel_handle_v1_destroy( wl_list_remove(&toplevel->link); + /* need to ensure no other toplevels hold a pointer to this one as + * a parent, so that a later call to foreign_toplevel_manager_bind() + * will not result in a segfault */ + struct wlr_foreign_toplevel_handle_v1 *tl, *tmp3; + wl_list_for_each_safe(tl, tmp3, &toplevel->manager->toplevels, link) { + if (tl->parent == toplevel) { + /* Note: we send a parent signal to all clients in this case; + * the caller should first destroy the child handles if it + * wishes to avoid this behavior. */ + wlr_foreign_toplevel_handle_v1_set_parent(tl, NULL); + } + } + free(toplevel->title); free(toplevel->app_id); free(toplevel); @@ -542,6 +586,8 @@ static void toplevel_send_details_to_toplevel_resource( zwlr_foreign_toplevel_handle_v1_send_state(resource, &states); wl_array_release(&states); + toplevel_resource_send_parent(resource, toplevel->parent); + zwlr_foreign_toplevel_handle_v1_send_done(resource); } @@ -560,9 +606,17 @@ static void foreign_toplevel_manager_bind(struct wl_client *client, void *data, wl_list_insert(&manager->resources, wl_resource_get_link(resource)); struct wlr_foreign_toplevel_handle_v1 *toplevel, *tmp; + /* First loop: create a handle for all toplevels for all clients. + * Separation into two loops avoid the case where a child handle + * is created before a parent handle, so the parent relationship + * could not be sent to a client. */ + wl_list_for_each_safe(toplevel, tmp, &manager->toplevels, link) { + create_toplevel_resource_for_resource(toplevel, resource); + } + /* Second loop: send details about each toplevel. */ wl_list_for_each_safe(toplevel, tmp, &manager->toplevels, link) { struct wl_resource *toplevel_resource = - create_toplevel_resource_for_resource(toplevel, resource); + wl_resource_find_for_client(&toplevel->resources, client); toplevel_send_details_to_toplevel_resource(toplevel, toplevel_resource); } From 41bf1c6871a2bf9dc91863b9c5b8369ccaaffc61 Mon Sep 17 00:00:00 2001 From: Mykola Orliuk Date: Sun, 18 Oct 2020 19:12:01 +0200 Subject: [PATCH 67/94] backend/wayland: add error flow in create_wl_seat --- backend/wayland/backend.c | 4 +++- backend/wayland/seat.c | 7 ++++++- include/backend/wayland.h | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 2059b7266..459baaa6d 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -105,7 +105,9 @@ static void registry_global(void *data, struct wl_registry *registry, } else if (strcmp(iface, wl_seat_interface.name) == 0) { struct wl_seat *wl_seat = wl_registry_bind(registry, name, &wl_seat_interface, 5); - create_wl_seat(wl_seat, wl); + if (!create_wl_seat(wl_seat, wl)) { + wl_seat_destroy(wl_seat); + } } else if (strcmp(iface, xdg_wm_base_interface.name) == 0) { wl->xdg_wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index f20619d51..10a224a10 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -372,12 +372,17 @@ static struct wlr_wl_input_device *get_wl_input_device_from_input_device( return (struct wlr_wl_input_device *)wlr_dev; } -void create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl) { +bool create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl) { assert(!wl->seat); // only one seat supported at the moment struct wlr_wl_seat *seat = calloc(1, sizeof(struct wlr_wl_seat)); + if (!seat) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return false; + } seat->wl_seat = wl_seat; wl->seat = seat; wl_seat_add_listener(wl_seat, &seat_listener, wl); + return true; } void destroy_wl_seats(struct wlr_wl_backend *wl) { diff --git a/include/backend/wayland.h b/include/backend/wayland.h index 61b349a5e..d782584f6 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -121,7 +121,7 @@ void create_wl_keyboard(struct wl_keyboard *wl_keyboard, struct wlr_wl_backend * void create_wl_touch(struct wl_touch *wl_touch, struct wlr_wl_backend *wl); struct wlr_wl_input_device *create_wl_input_device( struct wlr_wl_backend *backend, enum wlr_input_device_type type); -void create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl); +bool create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl); void destroy_wl_seats(struct wlr_wl_backend *wl); extern const struct wl_seat_listener seat_listener; From 009cd634a2c4d97edf8bdfabe0141923f9e53285 Mon Sep 17 00:00:00 2001 From: Mykola Orliuk Date: Sun, 18 Oct 2020 19:12:01 +0200 Subject: [PATCH 68/94] backend/wayland: fix input creation error handling --- backend/wayland/seat.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index 10a224a10..133f5403d 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -636,9 +636,6 @@ void create_wl_pointer(struct wl_pointer *wl_pointer, struct wlr_wl_output *outp pointer->wl_pointer = wl_pointer; pointer->output = output; - wl_signal_add(&output->wlr_output.events.destroy, &pointer->output_destroy); - pointer->output_destroy.notify = pointer_handle_output_destroy; - struct wlr_wl_input_device *dev = create_wl_input_device(backend, WLR_INPUT_DEVICE_POINTER); if (dev == NULL) { @@ -648,6 +645,9 @@ void create_wl_pointer(struct wl_pointer *wl_pointer, struct wlr_wl_output *outp } pointer->input_device = dev; + wl_signal_add(&output->wlr_output.events.destroy, &pointer->output_destroy); + pointer->output_destroy.notify = pointer_handle_output_destroy; + wlr_dev = &dev->wlr_input_device; wlr_dev->pointer = &pointer->wlr_pointer; wlr_dev->output_name = strdup(output->wlr_output.name); @@ -686,7 +686,7 @@ void create_wl_keyboard(struct wl_keyboard *wl_keyboard, struct wlr_wl_backend * wlr_dev->keyboard = calloc(1, sizeof(*wlr_dev->keyboard)); if (!wlr_dev->keyboard) { wlr_log_errno(WLR_ERROR, "Allocation failed"); - free(dev); + wlr_input_device_destroy(wlr_dev); return; } wlr_keyboard_init(wlr_dev->keyboard, NULL); @@ -707,7 +707,7 @@ void create_wl_touch(struct wl_touch *wl_touch, struct wlr_wl_backend *wl) { wlr_dev->touch = calloc(1, sizeof(*wlr_dev->touch)); if (!wlr_dev->touch) { wlr_log_errno(WLR_ERROR, "Allocation failed"); - free(dev); + wlr_input_device_destroy(wlr_dev); return; } wlr_touch_init(wlr_dev->touch, NULL); From 31aa7f4c95ccc8260d5202d6f0d8c6b5c3c80061 Mon Sep 17 00:00:00 2001 From: Mykola Orliuk Date: Sun, 18 Oct 2020 19:12:01 +0200 Subject: [PATCH 69/94] backend/wayland: fix some keyboard/touch leaks --- backend/wayland/seat.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index 133f5403d..1697616c5 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -391,9 +391,16 @@ void destroy_wl_seats(struct wlr_wl_backend *wl) { return; } + if (seat->touch) { + wl_touch_destroy(seat->touch); + } if (seat->pointer) { wl_pointer_destroy(seat->pointer); } + if (seat->keyboard && !wl->started) { + // early termination will not be handled by input_device_destroy + wl_keyboard_destroy(seat->keyboard); + } free(seat->name); if (seat->wl_seat) { wl_seat_destroy(seat->wl_seat); From 5217456b50f707780fce047b9d67b72f74475d3f Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Mon, 19 Oct 2020 20:48:41 -0400 Subject: [PATCH 70/94] xwayland: fix minor typo in debug log This accidentally slipped through 1b0e4c7. --- xwayland/server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xwayland/server.c b/xwayland/server.c index 24b435aa6..d0057c66a 100644 --- a/xwayland/server.c +++ b/xwayland/server.c @@ -109,7 +109,7 @@ noreturn static void exec_xwayland(struct wlr_xwayland_server *server) { const char *xwayland_path = getenv("WLR_XWAYLAND"); if (xwayland_path) { - wlr_log(WLR_INFO, "Using Xwayland binary to '%s' due to WLR_XWAYLAND", + wlr_log(WLR_INFO, "Using Xwayland binary '%s' due to WLR_XWAYLAND", xwayland_path); } else { xwayland_path = "Xwayland"; From b4ed8b3d7414ff6280098da811f873e5c5146d27 Mon Sep 17 00:00:00 2001 From: Daniel Kondor Date: Tue, 20 Oct 2020 10:08:24 +0800 Subject: [PATCH 71/94] foreign toplevel: send parent event only to clients that support it --- types/wlr_foreign_toplevel_management_v1.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/types/wlr_foreign_toplevel_management_v1.c b/types/wlr_foreign_toplevel_management_v1.c index 5e7b731c6..154f790c3 100644 --- a/types/wlr_foreign_toplevel_management_v1.c +++ b/types/wlr_foreign_toplevel_management_v1.c @@ -408,6 +408,10 @@ void wlr_foreign_toplevel_handle_v1_set_fullscreen( static void toplevel_resource_send_parent( struct wl_resource *toplevel_resource, struct wlr_foreign_toplevel_handle_v1 *parent) { + if (wl_resource_get_version(toplevel_resource) < + ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_PARENT_SINCE_VERSION) { + return; + } struct wl_client *client = wl_resource_get_client(toplevel_resource); struct wl_resource *parent_resource = NULL; if (parent) { From 79c7591dc196b14dfa857caf2c183276f937ee02 Mon Sep 17 00:00:00 2001 From: Scott Moreau Date: Tue, 20 Oct 2020 10:42:01 -0600 Subject: [PATCH 72/94] foreign toplevel: Fix whitespace error --- protocol/wlr-foreign-toplevel-management-unstable-v1.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/wlr-foreign-toplevel-management-unstable-v1.xml b/protocol/wlr-foreign-toplevel-management-unstable-v1.xml index 206143b4d..108133715 100644 --- a/protocol/wlr-foreign-toplevel-management-unstable-v1.xml +++ b/protocol/wlr-foreign-toplevel-management-unstable-v1.xml @@ -261,7 +261,7 @@ This event is emitted whenever the parent of the toplevel changes. - + No event is emitted when the parent handle is destroyed by the client. From 346188c01511d3a6432f6fdaf43823cf58a8efca Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Tue, 27 Oct 2020 18:28:39 +0100 Subject: [PATCH 73/94] xdg_shell: fix a typo --- types/xdg_shell/wlr_xdg_surface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c index 7cd12040d..d33cbffed 100644 --- a/types/xdg_shell/wlr_xdg_surface.c +++ b/types/xdg_shell/wlr_xdg_surface.c @@ -494,7 +494,7 @@ void reset_xdg_surface(struct wlr_xdg_surface *xdg_surface) { break; case WLR_XDG_SURFACE_ROLE_POPUP: wl_resource_set_user_data(xdg_surface->popup->resource, NULL); - xdg_surface->toplevel->resource = NULL; + xdg_surface->popup->resource = NULL; wl_list_remove(&xdg_surface->popup->link); From 85757665e6e1393773b36282aa244feb10b7a5fe Mon Sep 17 00:00:00 2001 From: Marten Ringwelski Date: Thu, 29 Oct 2020 12:36:13 +0100 Subject: [PATCH 74/94] backend/drm: Check if output is enabled before sending frame event When an output is disabled one last pageflip will happen to disable it. Currently this pageflip causes a frame event. Since the output is disabled we don't want to send this frame event. --- backend/drm/drm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index dafe807b3..03cd93185 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1523,7 +1523,7 @@ static void page_flip_handler(int fd, unsigned seq, }; wlr_output_send_present(&conn->output, &present_event); - if (drm->session->active) { + if (drm->session->active && conn->output.enabled) { wlr_output_send_frame(&conn->output); } } From 7c6e06fd13ad3b96375da606d1483c4d19df38af Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Sat, 31 Oct 2020 18:05:39 -0400 Subject: [PATCH 75/94] types/wlr_keyboard: use bitmasks for wlr_keyboard_led and wlr_keyboard_modifier enums --- include/wlr/types/wlr_keyboard.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/include/wlr/types/wlr_keyboard.h b/include/wlr/types/wlr_keyboard.h index c3e360548..c1a19a8eb 100644 --- a/include/wlr/types/wlr_keyboard.h +++ b/include/wlr/types/wlr_keyboard.h @@ -18,22 +18,22 @@ #define WLR_LED_COUNT 3 enum wlr_keyboard_led { - WLR_LED_NUM_LOCK = 1, - WLR_LED_CAPS_LOCK = 2, - WLR_LED_SCROLL_LOCK = 4, + WLR_LED_NUM_LOCK = 1 << 0, + WLR_LED_CAPS_LOCK = 1 << 1, + WLR_LED_SCROLL_LOCK = 1 << 2, }; #define WLR_MODIFIER_COUNT 8 enum wlr_keyboard_modifier { - WLR_MODIFIER_SHIFT = 1, - WLR_MODIFIER_CAPS = 2, - WLR_MODIFIER_CTRL = 4, - WLR_MODIFIER_ALT = 8, - WLR_MODIFIER_MOD2 = 16, - WLR_MODIFIER_MOD3 = 32, - WLR_MODIFIER_LOGO = 64, - WLR_MODIFIER_MOD5 = 128, + WLR_MODIFIER_SHIFT = 1 << 0, + WLR_MODIFIER_CAPS = 1 << 1, + WLR_MODIFIER_CTRL = 1 << 2, + WLR_MODIFIER_ALT = 1 << 3, + WLR_MODIFIER_MOD2 = 1 << 4, + WLR_MODIFIER_MOD3 = 1 << 5, + WLR_MODIFIER_LOGO = 1 << 6, + WLR_MODIFIER_MOD5 = 1 << 7, }; #define WLR_KEYBOARD_KEYS_CAP 32 From 0fdb41fe7c2efeb29206180f076b6a5a7706fdce Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Sat, 31 Oct 2020 18:06:04 -0400 Subject: [PATCH 76/94] types/wlr_output_layout: use bitmask for wlr_direction --- include/wlr/types/wlr_output_layout.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/wlr/types/wlr_output_layout.h b/include/wlr/types/wlr_output_layout.h index cdbc446f9..51c1e4cab 100644 --- a/include/wlr/types/wlr_output_layout.h +++ b/include/wlr/types/wlr_output_layout.h @@ -124,10 +124,10 @@ struct wlr_output *wlr_output_layout_get_center_output( struct wlr_output_layout *layout); enum wlr_direction { - WLR_DIRECTION_UP = 1, - WLR_DIRECTION_DOWN = 2, - WLR_DIRECTION_LEFT = 4, - WLR_DIRECTION_RIGHT = 8, + WLR_DIRECTION_UP = 1 << 0, + WLR_DIRECTION_DOWN = 1 << 1, + WLR_DIRECTION_LEFT = 1 << 2, + WLR_DIRECTION_RIGHT = 1 << 3, }; /** From 368d0146fbda4281b67a65fea3e6eb148655ef8f Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Sat, 31 Oct 2020 18:06:45 -0400 Subject: [PATCH 77/94] util/edges: use bitmask for wlr_edges --- include/wlr/util/edges.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/wlr/util/edges.h b/include/wlr/util/edges.h index bf1eb1e72..90a1167ab 100644 --- a/include/wlr/util/edges.h +++ b/include/wlr/util/edges.h @@ -19,10 +19,10 @@ enum wlr_edges { WLR_EDGE_NONE = 0, - WLR_EDGE_TOP = 1, - WLR_EDGE_BOTTOM = 2, - WLR_EDGE_LEFT = 4, - WLR_EDGE_RIGHT = 8, + WLR_EDGE_TOP = 1 << 0, + WLR_EDGE_BOTTOM = 1 << 1, + WLR_EDGE_LEFT = 1 << 2, + WLR_EDGE_RIGHT = 1 << 3, }; #endif From 0f9b2bfa64359eaeb25b73ccae08c9059bfc02e7 Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Sat, 31 Oct 2020 18:09:17 -0400 Subject: [PATCH 78/94] render/dmabuf: use bitmask for wlr_dmabuf_attributes_flags --- include/wlr/render/dmabuf.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/wlr/render/dmabuf.h b/include/wlr/render/dmabuf.h index 93e50eb30..b9c548967 100644 --- a/include/wlr/render/dmabuf.h +++ b/include/wlr/render/dmabuf.h @@ -15,9 +15,9 @@ #define WLR_DMABUF_MAX_PLANES 4 enum wlr_dmabuf_attributes_flags { - WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT = 1, - WLR_DMABUF_ATTRIBUTES_FLAGS_INTERLACED = 2, - WLR_DMABUF_ATTRIBUTES_FLAGS_BOTTOM_FIRST = 4, + WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT = 1 << 0, + WLR_DMABUF_ATTRIBUTES_FLAGS_INTERLACED = 1 << 1, + WLR_DMABUF_ATTRIBUTES_FLAGS_BOTTOM_FIRST = 1 << 2, }; struct wlr_dmabuf_attributes { From f0ddcd361ea8b20b0a5da8effc30d8c51540f948 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 2 Nov 2020 10:51:52 +0100 Subject: [PATCH 79/94] render: define EGL_NO_PLATFORM_SPECIFIC_TYPES (#2452) This avoids Xlib.h inclusion via EGL headers. See [1] for discussion. This change is based on a Weston commit [2]. [1]: https://github.com/KhronosGroup/EGL-Registry/pull/111 [2]: https://gitlab.freedesktop.org/wayland/weston/commit/526765ddfdfd --- include/wlr/render/egl.h | 3 +++ include/wlr/render/interface.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index d46d95aff..b23931770 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -15,6 +15,9 @@ #ifndef EGL_NO_X11 #define EGL_NO_X11 #endif +#ifndef EGL_NO_PLATFORM_SPECIFIC_TYPES +#define EGL_NO_PLATFORM_SPECIFIC_TYPES +#endif #include diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index 93c987b7d..998b1cfa7 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -15,6 +15,9 @@ #ifndef EGL_NO_X11 #define EGL_NO_X11 #endif +#ifndef EGL_NO_PLATFORM_SPECIFIC_TYPES +#define EGL_NO_PLATFORM_SPECIFIC_TYPES +#endif #include #include From ee43ef3c9d783c832a9b93fbcb9c1fb8c092f196 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 2 Nov 2020 12:11:51 +0100 Subject: [PATCH 80/94] backend/drm: fix "a page-flip is already pending" errors on modeset When performing a modeset, the DRM backend will request a page-flip event. However frame_pending wasn't set to true, so any subsequent wlr_output_schedule_frame calls would imemdiately trigger a synthetic frame event, asking the compositor to submit a new frame. Committing the new frame fails with "a page-flip is already pending" error in the DRM backend. --- backend/drm/drm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 03cd93185..2644014c7 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -373,6 +373,12 @@ static bool drm_crtc_page_flip(struct wlr_drm_connector *conn) { } conn->pageflip_pending = true; + + // wlr_output's API guarantees that submitting a buffer will schedule a + // frame event. However the DRM backend will also schedule a frame event + // when performing a modeset. Set frame_pending to true so that + // wlr_output_schedule_frame doesn't trigger a synthetic frame event. + conn->output.frame_pending = true; return true; } From 1fdaaf697a040c0ec7be661ea7d8a84321dbefb7 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 3 Nov 2020 15:31:23 +0100 Subject: [PATCH 81/94] xwayland: minor code style fixes --- xwayland/xwm.c | 104 ++++++++++++++++++++++++------------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/xwayland/xwm.c b/xwayland/xwm.c index b53759da9..61d9ad7d9 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -1054,49 +1054,49 @@ static void xwm_handle_surface_id_message(struct wlr_xwm *xwm, } } -#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0 -#define _NET_WM_MOVERESIZE_SIZE_TOP 1 -#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2 -#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3 -#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4 -#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5 -#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6 -#define _NET_WM_MOVERESIZE_SIZE_LEFT 7 -#define _NET_WM_MOVERESIZE_MOVE 8 // movement only -#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 // size via keyboard -#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 // move via keyboard -#define _NET_WM_MOVERESIZE_CANCEL 11 // cancel operation +#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0 +#define _NET_WM_MOVERESIZE_SIZE_TOP 1 +#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2 +#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3 +#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4 +#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5 +#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6 +#define _NET_WM_MOVERESIZE_SIZE_LEFT 7 +#define _NET_WM_MOVERESIZE_MOVE 8 // movement only +#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 // size via keyboard +#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 // move via keyboard +#define _NET_WM_MOVERESIZE_CANCEL 11 // cancel operation static enum wlr_edges net_wm_edges_to_wlr(uint32_t net_wm_edges) { enum wlr_edges edges = WLR_EDGE_NONE; switch(net_wm_edges) { - case _NET_WM_MOVERESIZE_SIZE_TOPLEFT: - edges = WLR_EDGE_TOP | WLR_EDGE_LEFT; - break; - case _NET_WM_MOVERESIZE_SIZE_TOP: - edges = WLR_EDGE_TOP; - break; - case _NET_WM_MOVERESIZE_SIZE_TOPRIGHT: - edges = WLR_EDGE_TOP | WLR_EDGE_RIGHT; - break; - case _NET_WM_MOVERESIZE_SIZE_RIGHT: - edges = WLR_EDGE_RIGHT; - break; - case _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT: - edges = WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT; - break; - case _NET_WM_MOVERESIZE_SIZE_BOTTOM: - edges = WLR_EDGE_BOTTOM; - break; - case _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT: - edges = WLR_EDGE_BOTTOM | WLR_EDGE_LEFT; - break; - case _NET_WM_MOVERESIZE_SIZE_LEFT: - edges = WLR_EDGE_LEFT; - break; - default: - break; + case _NET_WM_MOVERESIZE_SIZE_TOPLEFT: + edges = WLR_EDGE_TOP | WLR_EDGE_LEFT; + break; + case _NET_WM_MOVERESIZE_SIZE_TOP: + edges = WLR_EDGE_TOP; + break; + case _NET_WM_MOVERESIZE_SIZE_TOPRIGHT: + edges = WLR_EDGE_TOP | WLR_EDGE_RIGHT; + break; + case _NET_WM_MOVERESIZE_SIZE_RIGHT: + edges = WLR_EDGE_RIGHT; + break; + case _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT: + edges = WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT; + break; + case _NET_WM_MOVERESIZE_SIZE_BOTTOM: + edges = WLR_EDGE_BOTTOM; + break; + case _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT: + edges = WLR_EDGE_BOTTOM | WLR_EDGE_LEFT; + break; + case _NET_WM_MOVERESIZE_SIZE_LEFT: + edges = WLR_EDGE_LEFT; + break; + default: + break; } return edges; @@ -1138,25 +1138,25 @@ static void xwm_handle_net_wm_moveresize_message(struct wlr_xwm *xwm, } } -#define _NET_WM_STATE_REMOVE 0 -#define _NET_WM_STATE_ADD 1 -#define _NET_WM_STATE_TOGGLE 2 +#define _NET_WM_STATE_REMOVE 0 +#define _NET_WM_STATE_ADD 1 +#define _NET_WM_STATE_TOGGLE 2 static bool update_state(int action, bool *state) { int new_state, changed; switch (action) { - case _NET_WM_STATE_REMOVE: - new_state = false; - break; - case _NET_WM_STATE_ADD: - new_state = true; - break; - case _NET_WM_STATE_TOGGLE: - new_state = !*state; - break; - default: - return false; + case _NET_WM_STATE_REMOVE: + new_state = false; + break; + case _NET_WM_STATE_ADD: + new_state = true; + break; + case _NET_WM_STATE_TOGGLE: + new_state = !*state; + break; + default: + return false; } changed = (*state != new_state); From be1e7647c3250d67041947d77350488ae00bc3e3 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 3 Nov 2020 16:48:01 +0100 Subject: [PATCH 82/94] xwayland: log unhandled NET_WM_STATE property changes --- xwayland/xwm.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 61d9ad7d9..fefba7fcc 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -1187,7 +1187,7 @@ static void xwm_handle_net_wm_state_message(struct wlr_xwm *xwm, uint32_t action = client_message->data.data32[0]; for (size_t i = 0; i < 2; ++i) { - uint32_t property = client_message->data.data32[1 + i]; + xcb_atom_t property = client_message->data.data32[1 + i]; if (property == xwm->atoms[NET_WM_STATE_MODAL] && update_state(action, &xsurface->modal)) { @@ -1204,6 +1204,11 @@ static void xwm_handle_net_wm_state_message(struct wlr_xwm *xwm, } else if (property == xwm->atoms[NET_WM_STATE_HIDDEN] && update_state(action, &xsurface->minimized)) { xsurface_set_net_wm_state(xsurface); + } else if (property != XCB_ATOM_NONE) { + char *prop_name = xwm_get_atom_name(xwm, property); + wlr_log(WLR_DEBUG, "Unhandled NET_WM_STATE property change " + "%"PRIu32" (%s)", property, prop_name ? prop_name : "(null)"); + free(prop_name); } } // client_message->data.data32[3] is the source indication From c2db691cad17a6228cde6bbbe39b8afff5f01908 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 27 Aug 2020 11:42:58 +0200 Subject: [PATCH 83/94] gamma-control-v1: apply gamma LUT when output gets enabled Closes: https://github.com/swaywm/wlroots/issues/2372 --- include/wlr/types/wlr_gamma_control_v1.h | 4 ++ types/wlr_gamma_control_v1.c | 51 ++++++++++++++++++------ 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/include/wlr/types/wlr_gamma_control_v1.h b/include/wlr/types/wlr_gamma_control_v1.h index 290a86e94..b247bae34 100644 --- a/include/wlr/types/wlr_gamma_control_v1.h +++ b/include/wlr/types/wlr_gamma_control_v1.h @@ -21,6 +21,10 @@ struct wlr_gamma_control_v1 { struct wlr_output *output; struct wl_list link; + uint16_t *table; + size_t ramp_size; + + struct wl_listener output_commit_listener; struct wl_listener output_destroy_listener; void *data; diff --git a/types/wlr_gamma_control_v1.c b/types/wlr_gamma_control_v1.c index f96c84aaa..2fdaaaab9 100644 --- a/types/wlr_gamma_control_v1.c +++ b/types/wlr_gamma_control_v1.c @@ -24,7 +24,9 @@ static void gamma_control_destroy(struct wlr_gamma_control_v1 *gamma_control) { wlr_output_set_gamma(gamma_control->output, 0, NULL, NULL, NULL); wl_resource_set_user_data(gamma_control->resource, NULL); wl_list_remove(&gamma_control->output_destroy_listener.link); + wl_list_remove(&gamma_control->output_commit_listener.link); wl_list_remove(&gamma_control->link); + free(gamma_control->table); free(gamma_control); } @@ -34,6 +36,22 @@ static void gamma_control_send_failed( gamma_control_destroy(gamma_control); } +static void gamma_control_apply(struct wlr_gamma_control_v1 *gamma_control) { + uint16_t *r = gamma_control->table; + uint16_t *g = gamma_control->table + gamma_control->ramp_size; + uint16_t *b = gamma_control->table + 2 * gamma_control->ramp_size; + + wlr_output_set_gamma(gamma_control->output, gamma_control->ramp_size, r, g, b); + if (!wlr_output_test(gamma_control->output)) { + wlr_output_rollback(gamma_control->output); + gamma_control_send_failed(gamma_control); + return; + } + + // Gamma LUT will be applied on next output commit + wlr_output_schedule_frame(gamma_control->output); +} + static const struct zwlr_gamma_control_v1_interface gamma_control_impl; static struct wlr_gamma_control_v1 *gamma_control_from_resource( @@ -56,6 +74,17 @@ static void gamma_control_handle_output_destroy(struct wl_listener *listener, gamma_control_destroy(gamma_control); } +static void gamma_control_handle_output_commit(struct wl_listener *listener, + void *data) { + struct wlr_gamma_control_v1 *gamma_control = + wl_container_of(listener, gamma_control, output_commit_listener); + struct wlr_output_event_commit *event = data; + if ((event->committed & WLR_OUTPUT_STATE_ENABLED) && + gamma_control->output->enabled) { + gamma_control_apply(gamma_control); + } +} + static void gamma_control_handle_set_gamma(struct wl_client *client, struct wl_resource *gamma_control_resource, int fd) { struct wlr_gamma_control_v1 *gamma_control = @@ -101,20 +130,13 @@ static void gamma_control_handle_set_gamma(struct wl_client *client, close(fd); fd = -1; - uint16_t *r = table; - uint16_t *g = table + ramp_size; - uint16_t *b = table + 2 * ramp_size; + free(gamma_control->table); + gamma_control->table = table; + gamma_control->ramp_size = ramp_size; - wlr_output_set_gamma(gamma_control->output, ramp_size, r, g, b); - if (!wlr_output_test(gamma_control->output)) { - wlr_output_rollback(gamma_control->output); - gamma_control_send_failed(gamma_control); - goto error_table; + if (gamma_control->output->enabled) { + gamma_control_apply(gamma_control); } - free(table); - - // Gamma LUT will be applied on next output commit - wlr_output_schedule_frame(gamma_control->output); return; @@ -177,6 +199,11 @@ static void gamma_control_manager_get_gamma_control(struct wl_client *client, gamma_control->output_destroy_listener.notify = gamma_control_handle_output_destroy; + wl_signal_add(&output->events.commit, + &gamma_control->output_commit_listener); + gamma_control->output_commit_listener.notify = + gamma_control_handle_output_commit; + wl_list_init(&gamma_control->link); size_t gamma_size = wlr_output_get_gamma_size(output); From 2934a7292083468b3e25b5d9ff7a03398229b17a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 22 Oct 2020 18:19:13 +0200 Subject: [PATCH 84/94] screencopy: stop setting needs_frame flag This is already done by wlr_output_schedule_frame (it calls wlr_output_update_needs_frame). --- types/wlr_screencopy_v1.c | 1 - 1 file changed, 1 deletion(-) diff --git a/types/wlr_screencopy_v1.c b/types/wlr_screencopy_v1.c index 702a62b50..19e08a71b 100644 --- a/types/wlr_screencopy_v1.c +++ b/types/wlr_screencopy_v1.c @@ -374,7 +374,6 @@ static void frame_handle_copy(struct wl_client *wl_client, frame->buffer_destroy.notify = frame_handle_buffer_destroy; // Schedule a buffer commit - output->needs_frame = true; wlr_output_schedule_frame(output); wlr_output_lock_attach_render(output, true); From 1328477a82c50ed4dbed0a42d8624510bf8048f1 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 4 Nov 2020 14:02:15 +0100 Subject: [PATCH 85/94] backend/drm: export pending FB in export_dmabuf, if any This allows callers to grab the current frame right after committing it, without having to incur a full vblank worth of latency. --- backend/drm/drm.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 2644014c7..40b73925a 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -639,13 +639,15 @@ static bool drm_connector_export_dmabuf(struct wlr_output *output, return false; } - struct wlr_drm_plane *plane = crtc->primary; - - if (plane->current_fb.type == WLR_DRM_FB_TYPE_NONE) { + struct wlr_drm_fb *fb = &crtc->primary->queued_fb; + if (fb->type == WLR_DRM_FB_TYPE_NONE) { + fb = &crtc->primary->current_fb; + } + if (fb->type == WLR_DRM_FB_TYPE_NONE) { return false; } - return export_drm_bo(plane->current_fb.bo, attribs); + return export_drm_bo(fb->bo, attribs); } struct wlr_drm_fb *plane_get_next_fb(struct wlr_drm_plane *plane) { From ccd313e01ad58beba261ecae78c94f149093ffbb Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 4 Nov 2020 14:08:08 +0100 Subject: [PATCH 86/94] output: update docs to reflect reality The docs were outdated and weren't matching what the DRM backend does (the only implementor of wlr_output_export_dmabuf). --- include/wlr/types/wlr_output.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 41423b582..972343bc4 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -391,8 +391,7 @@ size_t wlr_output_get_gamma_size(struct wlr_output *output); void wlr_output_set_gamma(struct wlr_output *output, size_t size, const uint16_t *r, const uint16_t *g, const uint16_t *b); /** - * Exports the output's current back-buffer as a DMA-BUF (ie. the buffer that - * will be displayed on next commit). + * Exports the last committed buffer as a DMA-BUF. * * The caller is responsible for cleaning up the DMA-BUF attributes. */ From 8c8164c4a6c926891c5d47f58ad4c3aa6eec8811 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 4 Nov 2020 14:29:49 +0100 Subject: [PATCH 87/94] output: add when field to wlr_output_event_commit Similar to the one already present in wlr_output_event_precommit. --- include/wlr/types/wlr_output.h | 1 + types/wlr_output.c | 1 + 2 files changed, 2 insertions(+) diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 972343bc4..cb7427066 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -201,6 +201,7 @@ struct wlr_output_event_precommit { struct wlr_output_event_commit { struct wlr_output *output; uint32_t committed; // bitmask of enum wlr_output_state_field + struct timespec *when; }; enum wlr_output_present_flag { diff --git a/types/wlr_output.c b/types/wlr_output.c index 1c40a1470..4ce7312f0 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -607,6 +607,7 @@ bool wlr_output_commit(struct wlr_output *output) { struct wlr_output_event_commit event = { .output = output, .committed = output->pending.committed, + .when = &now, }; wlr_signal_emit_safe(&output->events.commit, &event); From f0945e112f3f4e50021f55d59572526ff9fee847 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 4 Nov 2020 14:38:56 +0100 Subject: [PATCH 88/94] export-dmabuf: export DMA-BUF on output commit We were previously exporting DMA-BUFs when receiving the capture_output request, and sending a done event on wlr_output.events.precommit. Instead, export and send done on wlr_output.events.commit. --- include/wlr/types/wlr_export_dmabuf_v1.h | 3 +- types/wlr_export_dmabuf_v1.c | 69 ++++++++++++------------ 2 files changed, 35 insertions(+), 37 deletions(-) diff --git a/include/wlr/types/wlr_export_dmabuf_v1.h b/include/wlr/types/wlr_export_dmabuf_v1.h index 817bb1a05..344e6cbf9 100644 --- a/include/wlr/types/wlr_export_dmabuf_v1.h +++ b/include/wlr/types/wlr_export_dmabuf_v1.h @@ -29,12 +29,11 @@ struct wlr_export_dmabuf_frame_v1 { struct wlr_export_dmabuf_manager_v1 *manager; struct wl_list link; // wlr_export_dmabuf_manager_v1::frames - struct wlr_dmabuf_attributes attribs; struct wlr_output *output; bool cursor_locked; - struct wl_listener output_precommit; + struct wl_listener output_commit; }; struct wlr_export_dmabuf_manager_v1 *wlr_export_dmabuf_manager_v1_create( diff --git a/types/wlr_export_dmabuf_v1.c b/types/wlr_export_dmabuf_v1.c index c2ec34c89..a8e2a4bde 100644 --- a/types/wlr_export_dmabuf_v1.c +++ b/types/wlr_export_dmabuf_v1.c @@ -41,8 +41,7 @@ static void frame_destroy(struct wlr_export_dmabuf_frame_v1 *frame) { } } wl_list_remove(&frame->link); - wl_list_remove(&frame->output_precommit.link); - wlr_dmabuf_attributes_finish(&frame->attribs); + wl_list_remove(&frame->output_commit.link); // Make the frame resource inert wl_resource_set_user_data(frame->resource, NULL); free(frame); @@ -53,18 +52,41 @@ static void frame_handle_resource_destroy(struct wl_resource *resource) { frame_destroy(frame); } -static void frame_output_handle_precommit(struct wl_listener *listener, +static void frame_output_handle_commit(struct wl_listener *listener, void *data) { struct wlr_export_dmabuf_frame_v1 *frame = - wl_container_of(listener, frame, output_precommit); - struct wlr_output_event_precommit *event = data; + wl_container_of(listener, frame, output_commit); + struct wlr_output_event_commit *event = data; - if (!(event->output->pending.committed & WLR_OUTPUT_STATE_BUFFER)) { + if (!(event->committed & WLR_OUTPUT_STATE_BUFFER)) { return; } - wl_list_remove(&frame->output_precommit.link); - wl_list_init(&frame->output_precommit.link); + wl_list_remove(&frame->output_commit.link); + wl_list_init(&frame->output_commit.link); + + struct wlr_dmabuf_attributes attribs = {0}; + if (!wlr_output_export_dmabuf(frame->output, &attribs)) { + zwlr_export_dmabuf_frame_v1_send_cancel(frame->resource, + ZWLR_EXPORT_DMABUF_FRAME_V1_CANCEL_REASON_TEMPORARY); + frame_destroy(frame); + return; + } + + uint32_t frame_flags = ZWLR_EXPORT_DMABUF_FRAME_V1_FLAGS_TRANSIENT; + uint32_t mod_high = attribs.modifier >> 32; + uint32_t mod_low = attribs.modifier & 0xFFFFFFFF; + zwlr_export_dmabuf_frame_v1_send_frame(frame->resource, + attribs.width, attribs.height, 0, 0, attribs.flags, frame_flags, + attribs.format, mod_high, mod_low, attribs.n_planes); + + for (int i = 0; i < attribs.n_planes; ++i) { + off_t size = lseek(attribs.fd[i], 0, SEEK_END); + zwlr_export_dmabuf_frame_v1_send_object(frame->resource, i, + attribs.fd[i], size, attribs.offset[i], attribs.stride[i], i); + } + + wlr_dmabuf_attributes_finish(&attribs); time_t tv_sec = event->when->tv_sec; uint32_t tv_sec_hi = (sizeof(tv_sec) > 4) ? tv_sec >> 32 : 0; @@ -98,7 +120,7 @@ static void manager_handle_capture_output(struct wl_client *client, return; } frame->manager = manager; - wl_list_init(&frame->output_precommit.link); + wl_list_init(&frame->output_commit.link); uint32_t version = wl_resource_get_version(manager_resource); frame->resource = wl_resource_create(client, @@ -120,14 +142,6 @@ static void manager_handle_capture_output(struct wl_client *client, return; } - struct wlr_dmabuf_attributes *attribs = &frame->attribs; - if (!wlr_output_export_dmabuf(output, attribs)) { - zwlr_export_dmabuf_frame_v1_send_cancel(frame->resource, - ZWLR_EXPORT_DMABUF_FRAME_V1_CANCEL_REASON_TEMPORARY); - frame_destroy(frame); - return; - } - frame->output = output; wlr_output_lock_attach_render(frame->output, true); @@ -136,26 +150,11 @@ static void manager_handle_capture_output(struct wl_client *client, frame->cursor_locked = true; } - uint32_t frame_flags = ZWLR_EXPORT_DMABUF_FRAME_V1_FLAGS_TRANSIENT; - uint32_t mod_high = attribs->modifier >> 32; - uint32_t mod_low = attribs->modifier & 0xFFFFFFFF; - - zwlr_export_dmabuf_frame_v1_send_frame(frame->resource, - output->width, output->height, 0, 0, attribs->flags, frame_flags, - attribs->format, mod_high, mod_low, attribs->n_planes); - - for (int i = 0; i < attribs->n_planes; ++i) { - off_t size = lseek(attribs->fd[i], 0, SEEK_END); - - zwlr_export_dmabuf_frame_v1_send_object(frame->resource, i, - attribs->fd[i], size, attribs->offset[i], attribs->stride[i], i); - } + wl_list_remove(&frame->output_commit.link); + wl_signal_add(&output->events.commit, &frame->output_commit); + frame->output_commit.notify = frame_output_handle_commit; wlr_output_schedule_frame(output); - - wl_list_remove(&frame->output_precommit.link); - wl_signal_add(&output->events.precommit, &frame->output_precommit); - frame->output_precommit.notify = frame_output_handle_precommit; } static void manager_handle_destroy(struct wl_client *client, From 51fc7ddb294895ccfad173afc8f3a920f6aede4a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 4 Nov 2020 16:03:54 +0100 Subject: [PATCH 89/94] screencopy: perform DMA-BUF copy on output commit --- include/wlr/types/wlr_screencopy_v1.h | 1 + types/wlr_screencopy_v1.c | 154 ++++++++++++++++++-------- 2 files changed, 106 insertions(+), 49 deletions(-) diff --git a/include/wlr/types/wlr_screencopy_v1.h b/include/wlr/types/wlr_screencopy_v1.h index b778dd414..1c45f9057 100644 --- a/include/wlr/types/wlr_screencopy_v1.h +++ b/include/wlr/types/wlr_screencopy_v1.h @@ -53,6 +53,7 @@ struct wlr_screencopy_frame_v1 { struct wlr_output *output; struct wl_listener output_precommit; + struct wl_listener output_commit; struct wl_listener output_destroy; struct wl_listener output_enable; diff --git a/types/wlr_screencopy_v1.c b/types/wlr_screencopy_v1.c index 19e08a71b..d1e8336ee 100644 --- a/types/wlr_screencopy_v1.c +++ b/types/wlr_screencopy_v1.c @@ -143,6 +143,7 @@ static void frame_destroy(struct wlr_screencopy_frame_v1 *frame) { } wl_list_remove(&frame->link); wl_list_remove(&frame->output_precommit.link); + wl_list_remove(&frame->output_commit.link); wl_list_remove(&frame->output_destroy.link); wl_list_remove(&frame->output_enable.link); wl_list_remove(&frame->buffer_destroy.link); @@ -152,6 +153,41 @@ static void frame_destroy(struct wlr_screencopy_frame_v1 *frame) { free(frame); } +static void frame_send_damage(struct wlr_screencopy_frame_v1 *frame) { + if (!frame->with_damage) { + return; + } + + struct screencopy_damage *damage = + screencopy_damage_get_or_create(frame->client, frame->output); + if (damage == NULL) { + return; + } + + // TODO: send fine-grained damage events + struct pixman_box32 *damage_box = + pixman_region32_extents(&damage->damage); + + int damage_x = damage_box->x1; + int damage_y = damage_box->y1; + int damage_width = damage_box->x2 - damage_box->x1; + int damage_height = damage_box->y2 - damage_box->y1; + + zwlr_screencopy_frame_v1_send_damage(frame->resource, + damage_x, damage_y, damage_width, damage_height); + + pixman_region32_clear(&damage->damage); +} + +static void frame_send_ready(struct wlr_screencopy_frame_v1 *frame, + struct timespec *when) { + time_t tv_sec = when->tv_sec; + uint32_t tv_sec_hi = (sizeof(tv_sec) > 4) ? tv_sec >> 32 : 0; + uint32_t tv_sec_lo = tv_sec & 0xFFFFFFFF; + zwlr_screencopy_frame_v1_send_ready(frame->resource, + tv_sec_hi, tv_sec_lo, when->tv_nsec); +} + static void frame_handle_output_precommit(struct wl_listener *listener, void *_data) { struct wlr_screencopy_frame_v1 *frame = @@ -165,9 +201,14 @@ static void frame_handle_output_precommit(struct wl_listener *listener, return; } - struct screencopy_damage *damage = NULL; + struct wl_shm_buffer *shm_buffer = frame->shm_buffer; + if (shm_buffer == NULL) { + return; + } + if (frame->with_damage) { - damage = screencopy_damage_get_or_create(frame->client, output); + struct screencopy_damage *damage = + screencopy_damage_get_or_create(frame->client, output); if (damage) { screencopy_damage_accumulate(damage); if (!pixman_region32_not_empty(&damage->damage)) { @@ -182,36 +223,19 @@ static void frame_handle_output_precommit(struct wl_listener *listener, int x = frame->box.x; int y = frame->box.y; - bool ok = false; - uint32_t flags = 0; + enum wl_shm_format fmt = wl_shm_buffer_get_format(shm_buffer); + int32_t width = wl_shm_buffer_get_width(shm_buffer); + int32_t height = wl_shm_buffer_get_height(shm_buffer); + int32_t stride = wl_shm_buffer_get_stride(shm_buffer); - struct wl_shm_buffer *shm_buffer = frame->shm_buffer; - struct wlr_dmabuf_v1_buffer *dma_buffer = frame->dma_buffer; - assert(shm_buffer || dma_buffer); - - if (shm_buffer) { - enum wl_shm_format fmt = wl_shm_buffer_get_format(shm_buffer); - int32_t width = wl_shm_buffer_get_width(shm_buffer); - int32_t height = wl_shm_buffer_get_height(shm_buffer); - int32_t stride = wl_shm_buffer_get_stride(shm_buffer); - - wl_shm_buffer_begin_access(shm_buffer); - void *data = wl_shm_buffer_get_data(shm_buffer); - uint32_t renderer_flags = 0; - ok = wlr_renderer_read_pixels(renderer, fmt, &renderer_flags, - stride, width, height, x, y, 0, 0, data); - flags |= renderer_flags & WLR_RENDERER_READ_PIXELS_Y_INVERT ? - ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT : 0; - wl_shm_buffer_end_access(shm_buffer); - } else if (dma_buffer) { - struct wlr_dmabuf_attributes attr = { 0 }; - ok = wlr_output_export_dmabuf(frame->output, &attr); - ok = ok && wlr_renderer_blit_dmabuf(renderer, - &dma_buffer->attributes, &attr); - flags |= dma_buffer->attributes.flags & WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT ? - ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT : 0; - wlr_dmabuf_attributes_finish(&attr); - } + wl_shm_buffer_begin_access(shm_buffer); + void *data = wl_shm_buffer_get_data(shm_buffer); + uint32_t renderer_flags = 0; + bool ok = wlr_renderer_read_pixels(renderer, fmt, &renderer_flags, + stride, width, height, x, y, 0, 0, data); + uint32_t flags = renderer_flags & WLR_RENDERER_READ_PIXELS_Y_INVERT ? + ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT : 0; + wl_shm_buffer_end_access(shm_buffer); if (!ok) { zwlr_screencopy_frame_v1_send_failed(frame->resource); @@ -220,29 +244,57 @@ static void frame_handle_output_precommit(struct wl_listener *listener, } zwlr_screencopy_frame_v1_send_flags(frame->resource, flags); + frame_send_damage(frame); + frame_send_ready(frame, event->when); + frame_destroy(frame); +} - // TODO: send fine-grained damage events - if (damage) { - struct pixman_box32 *damage_box = - pixman_region32_extents(&damage->damage); +static void frame_handle_output_commit(struct wl_listener *listener, + void *data) { + struct wlr_screencopy_frame_v1 *frame = + wl_container_of(listener, frame, output_commit); + struct wlr_output_event_commit *event = data; + struct wlr_output *output = frame->output; + struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + assert(renderer); - int damage_x = damage_box->x1; - int damage_y = damage_box->y1; - int damage_width = damage_box->x2 - damage_box->x1; - int damage_height = damage_box->y2 - damage_box->y1; - - zwlr_screencopy_frame_v1_send_damage(frame->resource, - damage_x, damage_y, damage_width, damage_height); - - pixman_region32_clear(&damage->damage); + if (!(event->committed & WLR_OUTPUT_STATE_BUFFER)) { + return; } - time_t tv_sec = event->when->tv_sec; - uint32_t tv_sec_hi = (sizeof(tv_sec) > 4) ? tv_sec >> 32 : 0; - uint32_t tv_sec_lo = tv_sec & 0xFFFFFFFF; - zwlr_screencopy_frame_v1_send_ready(frame->resource, - tv_sec_hi, tv_sec_lo, event->when->tv_nsec); + struct wlr_dmabuf_v1_buffer *dma_buffer = frame->dma_buffer; + if (dma_buffer == NULL) { + return; + } + if (frame->with_damage) { + struct screencopy_damage *damage = + screencopy_damage_get_or_create(frame->client, output); + if (damage && !pixman_region32_not_empty(&damage->damage)) { + return; + } + } + + wl_list_remove(&frame->output_commit.link); + wl_list_init(&frame->output_commit.link); + + struct wlr_dmabuf_attributes attr = { 0 }; + bool ok = wlr_output_export_dmabuf(output, &attr); + ok = ok && wlr_renderer_blit_dmabuf(renderer, + &dma_buffer->attributes, &attr); + uint32_t flags = dma_buffer->attributes.flags & WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT ? + ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT : 0; + wlr_dmabuf_attributes_finish(&attr); + + if (!ok) { + zwlr_screencopy_frame_v1_send_failed(frame->resource); + frame_destroy(frame); + return; + } + + zwlr_screencopy_frame_v1_send_flags(frame->resource, flags); + frame_send_damage(frame); + frame_send_ready(frame, event->when); frame_destroy(frame); } @@ -364,6 +416,9 @@ static void frame_handle_copy(struct wl_client *wl_client, wl_signal_add(&output->events.precommit, &frame->output_precommit); frame->output_precommit.notify = frame_handle_output_precommit; + wl_signal_add(&output->events.commit, &frame->output_commit); + frame->output_commit.notify = frame_handle_output_commit; + wl_signal_add(&output->events.destroy, &frame->output_enable); frame->output_enable.notify = frame_handle_output_enable; @@ -466,6 +521,7 @@ static void capture_output(struct wl_client *wl_client, wl_list_insert(&client->manager->frames, &frame->link); wl_list_init(&frame->output_precommit.link); + wl_list_init(&frame->output_commit.link); wl_list_init(&frame->output_enable.link); wl_list_init(&frame->output_destroy.link); wl_list_init(&frame->buffer_destroy.link); From 4471a83ed0ce3c717d6d59c0a99fbc63614cb248 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 4 Nov 2020 16:06:45 +0100 Subject: [PATCH 90/94] screencopy: send failed when copying a DMA-BUF with a region We don't support that yet. --- types/wlr_screencopy_v1.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/types/wlr_screencopy_v1.c b/types/wlr_screencopy_v1.c index d1e8336ee..2d81ff7be 100644 --- a/types/wlr_screencopy_v1.c +++ b/types/wlr_screencopy_v1.c @@ -278,6 +278,15 @@ static void frame_handle_output_commit(struct wl_listener *listener, wl_list_remove(&frame->output_commit.link); wl_list_init(&frame->output_commit.link); + // TODO: add support for copying regions with DMA-BUFs + if (frame->box.x != 0 || frame->box.y != 0 || + output->width != frame->box.width || + output->height != frame->box.height) { + zwlr_screencopy_frame_v1_send_failed(frame->resource); + frame_destroy(frame); + return; + } + struct wlr_dmabuf_attributes attr = { 0 }; bool ok = wlr_output_export_dmabuf(output, &attr); ok = ok && wlr_renderer_blit_dmabuf(renderer, From 8348fc3ef8b992fce097bef81111eda3677957f4 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Thu, 5 Nov 2020 13:07:45 +0100 Subject: [PATCH 91/94] xwayland: remove unused listener --- include/wlr/xwayland.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/wlr/xwayland.h b/include/wlr/xwayland.h index b801b5dd4..8de9ed07e 100644 --- a/include/wlr/xwayland.h +++ b/include/wlr/xwayland.h @@ -84,7 +84,6 @@ struct wlr_xwayland { struct wl_listener server_ready; struct wl_listener server_destroy; - struct wl_listener client_destroy; struct wl_listener seat_destroy; void *data; From 372a52ecc08aff003b3024e852e848024b699a15 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 6 Nov 2020 19:14:55 +0100 Subject: [PATCH 92/94] input-method: send modifiers in set_keyboard Otherwise the client might have an outdated modifiers state. The same is done in wlr_seat_keyboard [1]. [1]: https://github.com/swaywm/wlroots/blob/8348fc3ef8b992fce097bef81111eda3677957f4/types/seat/wlr_seat_keyboard.c#L163 --- types/wlr_input_method_v2.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/types/wlr_input_method_v2.c b/types/wlr_input_method_v2.c index cb2482888..29b0d0289 100644 --- a/types/wlr_input_method_v2.c +++ b/types/wlr_input_method_v2.c @@ -259,6 +259,9 @@ void wlr_input_method_keyboard_grab_v2_set_keyboard( handle_keyboard_destroy; wl_signal_add(&keyboard->events.destroy, &keyboard_grab->keyboard_destroy); + + wlr_input_method_keyboard_grab_v2_send_modifiers(keyboard_grab, + &keyboard->modifiers); } keyboard_grab->keyboard = keyboard; From 9595f95452a1d7420bbb190dc29c3806c29ca41e Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Tue, 27 Oct 2020 18:28:39 +0100 Subject: [PATCH 93/94] xdg_shell: handle inert popups xdg_popups can be destroyed by the compositor when closed. When this happens, wlroots makes the xdg_popup surface inert and resets the xdg_surface role to NONE. Currently, wlroots sends a protocol error and asserts that an xdg_surface has a role when committed. This is racy if at the same time the client commits an xdg_popup and the compositor closes it. This patch removes the assertion and ignores commits on xdg_surfaces without a role set. --- types/xdg_shell/wlr_xdg_surface.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c index d33cbffed..b65490d0a 100644 --- a/types/xdg_shell/wlr_xdg_surface.c +++ b/types/xdg_shell/wlr_xdg_surface.c @@ -336,7 +336,9 @@ static void xdg_surface_handle_surface_commit(struct wl_listener *listener, return; } - if (surface->role == WLR_XDG_SURFACE_ROLE_NONE) { + // surface->role might be NONE for inert popups + // So we check surface->surface->role + if (surface->surface->role == NULL) { wl_resource_post_error(surface->resource, XDG_SURFACE_ERROR_NOT_CONSTRUCTED, "xdg_surface must have a role"); @@ -361,7 +363,8 @@ void handle_xdg_surface_commit(struct wlr_surface *wlr_surface) { switch (surface->role) { case WLR_XDG_SURFACE_ROLE_NONE: - assert(false); + // inert toplevel or popup + return; case WLR_XDG_SURFACE_ROLE_TOPLEVEL: handle_xdg_surface_toplevel_committed(surface); break; From 238d1c078fb03338e9f271d98f7bf6b1fc399285 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 8 Nov 2020 15:01:44 +0100 Subject: [PATCH 94/94] Update version to 0.12.0 --- meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index ca26391e7..835e01952 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'wlroots', 'c', - version: '0.11.0', + version: '0.12.0', license: 'MIT', meson_version: '>=0.54.0', default_options: [ @@ -15,7 +15,7 @@ project( # necessary for bugfix releases. Increasing soversion is required because # wlroots never guarantees ABI stability -- only API stability is guaranteed # between minor releases. -soversion = 6 +soversion = 7 add_project_arguments([ '-DWLR_USE_UNSTABLE',