Skip to content
Commits on Source (15)
  • Marius Vlad's avatar
    remoting-plugin: Release and detach the head · 0ba5b694
    Marius Vlad authored
    
    
    This re-orders the disable/destroy shutdown sequence such that
    lookup_remoted_output(), in remoting_output_disable(), would find a
    remoting output.
    
    Otherwise, without this, lookup_remoted_output() wouldn't find a
    remoting output available when shutting down the compositor, ultimately
    leading to a crash.
    
    Signed-off-by: default avatarMarius Vlad <marius.vlad@collabora.com>
    (cherry picked from commit c3270e88)
    0ba5b694
  • Marius Vlad's avatar
    remoting-plugin: Check virtual outputs/remoting instance · 17f5a44f
    Marius Vlad authored
    With commit aab722bb, "backend-drm: prepare virtual output API for
    heterogeneous outputs", we now call the virtual destroy function,
    but when shutting the compositor we no longer have a remoting instance
    available.
    
    When searching out for a remoting output verify if the remoting instance is
    still available before attempting to search for a remoting output.
    
    Addresses the following crash at shutdown:
    
    0x00007fd430a1d347 in lookup_remoted_output (output=0x557163d5dad0) at ../remoting/remoting-plugin.c:515
    0x00007fd430a1d746 in remoting_output_destroy (output=0x557163d5dad0) at ../remoting/remoting-plugin.c:635
    0x00007fd439e11ab9 in drm_virtual_output_destroy (base=0x557163d5dad0) at ../libweston/backend-drm/drm-virtual.c:265
    0x00007fd43a8635d0 in weston_compositor_shutdown (ec=0x557163239530) at ../libweston/compositor.c:8271
    0x00007fd439e029d4 in drm_destroy (backend=0x557163240ae0) at ../libweston/backend-drm/drm.c:2713
    0x00007fd43a863e07 in weston_...
    17f5a44f
  • Marius Vlad's avatar
    pipewire: Follow-up with remoting pluging when releasing the head · eaa777b9
    Marius Vlad authored
    
    
    Similarily to what the remoting plug-in does, explicitly call
    weston_release_head() before removing the output list entry.
    
    We do that to avoid lookup_pipewire_output() returning NULL and still
    find out the pipewire_output.
    
    Signed-off-by: default avatarMarius Vlad <marius.vlad@collabora.com>
    (cherry picked from commit 5db6d19e)
    eaa777b9
  • Marius Vlad's avatar
    pipewire: Fix memleak upon compositor shutdown · 597437a0
    Marius Vlad authored
    
    
    This happens when shutting the compositor, and follows-up with the
    remoting plug-in.
    
    Signed-off-by: default avatarMarius Vlad <marius.vlad@collabora.com>
    (cherry picked from commit aa78da24)
    597437a0
  • Marius Vlad's avatar
    pipewire: Destroy the pipewire outputs at shutdown · 0849a9b3
    Marius Vlad authored
    
    
    Seems like we are missing destroying the pipewire outputs on the shutdown
    path; this follow-ups with remoting plug-in as well.
    
    Signed-off-by: default avatarMarius Vlad <marius.vlad@collabora.com>
    (cherry picked from commit 278fe4d7)
    0849a9b3
  • Marius Vlad's avatar
    pipewire-plugin: Check virtual outputs/remoting instance · 70479268
    Marius Vlad authored
    Similarly to remoting plug-in in commit "Check virtual outputs/remoting
    instance" this avoids touching the pipewire instance, and with it, the
    pipewire output.
    
    Includes a note to point up what should be done about by
    checking out #591
    
    .
    
    Signed-off-by: default avatarMarius Vlad <marius.vlad@collabora.com>
    (cherry picked from commit 6617deeb)
    70479268
  • Marius Vlad's avatar
    backend-drm: Do not overwrite plane's index when creating virtual plane · df70b81e
    Marius Vlad authored
    
    
    Starting with commit 4cde507b "backend-drm: fix plane sorting" the
    plane list will have a descending order of the planes rather than ascending.
    
    This reversed order had the side-effect of exposing the fact that we
    don't set-up a plane index when creating the drm_plane using the DRM
    virtual API. Without settting a plane index for that drm_plane we
    effectively overwrite the plane index which has the 0 (zero) entry.
    
    This wasn't an issue before commit 4cde507b "backend-drm: fix
    plane sorting" as it seems we never picked up that plane index as
    being a suitable one due to the fact that those were assigned to primary
    planes, but after that commit, the cursor plane will be one getting
    the 0 (zero) plane index.
    
    Finally, this would trip over because we attempt to place a (cursor)
    view on a primary plane (where it would've normally be a cursor
    plane) and we end up with no framebuffer ref.
    
    This is fixed trivially by assigning a plane index, different than the
    ones already created by create_spirtes().
    
    Signed-off-by: default avatarMarius Vlad <marius.vlad@collabora.com>
    (cherry picked from commit 27ce9dad)
    df70b81e
  • Leandro Ribeiro's avatar
    desktop-shell: do not forget to reset pending config size after resizes · d5a3ec5e
    Leandro Ribeiro authored and Marius Vlad's avatar Marius Vlad committed
    
    
    During interactive resizes, we progressively change the size of the
    client surface and send config events with these sizes to the client.
    After that, the toplevel->pending.size keeps the size of the last config
    event that we've sent, i.e. the surface size after the resize is over.
    
    Later, if the client spontaneously resize (by attaching a buffer with a
    different size or setting the viewport destination, for instance), their
    surface size will change, but toplevel->pending.size continues being
    that old size from after the resize. If something happens and Weston
    decides to send a config event, clients may re-allocate to that old
    size, resulting in a sudden resize.
    
    This does not happen when a client goes from fullscreen/maximized to
    windowed mode because in such cases we are resetting
    toplevel->pending.size to zero. So in the next config event that clients
    receive they are allowed to attach buffers with the size that they
    prefer.
    
    So do the same after a resize: set the pending config size to zero.
    
    Signed-off-by: default avatarLeandro Ribeiro <leandro.ribeiro@collabora.com>
    (cherry picked from commit ba82af93)
    d5a3ec5e
  • Alexandros Frantzis's avatar
    xwayland: Handle shell hint for client to choose dimensions · 2d66d01c
    Alexandros Frantzis authored and Marius Vlad's avatar Marius Vlad committed
    A config event with width == 0 or height == 0 from the shell is a hint
    to the client to choose its own dimensions. Since X11 clients don't
    support such hints we make a best guess by trying to use the last saved
    dimensions or, as a fallback, the current dimensions.
    
    This hint is mainly used by libweston/desktop shells when transitioning
    to a normal state from maximized, fullscreen or after a resize [1].
    Without support for this hint the aforementioned transition causes
    xwayland surfaces to be configured to a 1x1 size.
    
    To be able to use the last saved dimensions with xwayland surface, the
    shell needs to first set the maximized/fullscreen state and only then
    set the new size, which is currently the case for desktop-shell.
    Otherwise, if the new size is set first, then the last saved dimensions
    will be set to the fullscreen/maximized values and won't be useful when
    restoring to a normal window size.
    
    [1] Recently we've introduced ba82af93...
    2d66d01c
  • Michael Olbrich's avatar
    libweston: clear parent_view when the parent view is destroyed · 5ad870f5
    Michael Olbrich authored and Marius Vlad's avatar Marius Vlad committed
    
    
    When a view is destroyed then the views of subsurfaces remain until the view
    list is rebuilt for the next repaint.
    During that time view->parent_view contains an invalid pointer and weston will
    crash when it tries to access the view.
    
    This happens for a surface with subsurfaces with views on two different outputs
    with the ivi-shell:
    
    When the surface is destroyed then the destroy handler of the ivi-shell
    (shell_handle_surface_destroy()) may be called first. It will (indirectly)
    destroy the view of the main surface with weston_view_destroy().
    Next the surface destroy handler of the subsurfaces
    (subsurface_handle_parent_destroy() is called. It will unmap the first view of
    the subsurface. Here weston_surface_assign_output() is called which tries to
    find the output of the second view and accesses the now invalid
    view->parent_view in the process.
    
    There are probably other ways to trigger similar crashes.
    
    To avoid this, clear view->parent_view when the parent view is destroyed.
    
    Fixes 0669d4de ("libweston: Skip views without a layer assignment in
          output_mask calculations")
    
    Signed-off-by: default avatarMichael Olbrich <m.olbrich@pengutronix.de>
    (cherry picked from commit 39796f88)
    5ad870f5
  • Michael Olbrich's avatar
    desktop-shell: avoid crashes when a surface disappears during resize · ff13a90e
    Michael Olbrich authored and Marius Vlad's avatar Marius Vlad committed
    
    
    The desktop_surface object is destroyed first so it can happen that the shsurf
    still exists but desktop_surface is already NULL. So expand the check to make
    sure the desktop_surface is still available in the resize callbacks.
    
    Signed-off-by: default avatarMichael Olbrich <m.olbrich@pengutronix.de>
    (cherry picked from commit 06365e60)
    ff13a90e
  • Sergio Gómez's avatar
    libweston/input: Remove redundant surface destroy listener in constraints · 0bd68d9a
    Sergio Gómez authored and Marius Vlad's avatar Marius Vlad committed
    
    
    Currently, the surface destroy listener in pointer constraints is redundant,
    since surface destruction already handles pointer constraints destruction (see
    libweston/compositor.c:weston_surface_unref()).
    
    Signed-off-by: default avatarSergio Gómez <sergio.g.delreal@gmail.com>
    (cherry picked from commit 64da736d)
    0bd68d9a
  • Sergio Gómez's avatar
    libweston: Add view unmap listener to pointer constraints · 21e46364
    Sergio Gómez authored and Marius Vlad's avatar Marius Vlad committed
    
    
    Since the logic of pointer constraints assumes a valid view throughout, add a
    signal to disable constraints when its current view is unmapped by Weston.
    
    The assumption that a previously unmapped view is valid already leads to the
    constraints code crashing. This can happen when attaching a NULL buffer to the
    surface and commiting, which effectively unmaps the view with the side effect of
    clearing the surface's input region, which is then assumed valid inside
    maybe_warp_confined_pointer().
    
    Fixes: #721
    
    Signed-off-by: default avatarSergio Gómez <sergio.g.delreal@gmail.com>
    (cherry picked from commit e3079393)
    21e46364
  • Sergio Gómez's avatar
    libweston: Add assert for valid confine region in maybe_warp_confined_pointer() · 072c5672
    Sergio Gómez authored and Marius Vlad's avatar Marius Vlad committed
    
    
    Signed-off-by: default avatarSergio Gómez <sergio.g.delreal@gmail.com>
    (cherry picked from commit b6423e59)
    072c5672
  • Sergio Gómez's avatar
    libweston/input: Fix assert for valid confine region · a627a4be
    Sergio Gómez authored and Marius Vlad's avatar Marius Vlad committed
    
    
    We need only check that the region is not empty. If either the input region or
    the constraint region have degenerate extents, the intersection from the
    previous instruction will set confine_region->data to pixman_region_empty_data.
    
    Fixes: b6423e59
    
    Signed-off-by: default avatarSergio Gómez <sergio.g.delreal@gmail.com>
    (cherry picked from commit 1ed88f60)
    a627a4be
......@@ -1153,7 +1153,7 @@ resize_grab_motion(struct weston_pointer_grab *grab,
weston_pointer_move(pointer, event);
if (!shsurf)
if (!shsurf || !shsurf->desktop_surface)
return;
weston_view_from_global_fixed(shsurf->view,
......@@ -1204,11 +1204,12 @@ resize_grab_button(struct weston_pointer_grab *grab,
if (pointer->button_count == 0 &&
state == WL_POINTER_BUTTON_STATE_RELEASED) {
if (resize->base.shsurf != NULL) {
if (resize->base.shsurf && resize->base.shsurf->desktop_surface) {
struct weston_desktop_surface *desktop_surface =
resize->base.shsurf->desktop_surface;
weston_desktop_surface_set_resizing(desktop_surface,
false);
weston_desktop_surface_set_size(desktop_surface, 0, 0);
}
shell_grab_end(&resize->base);
......@@ -1221,10 +1222,11 @@ resize_grab_cancel(struct weston_pointer_grab *grab)
{
struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
if (resize->base.shsurf != NULL) {
if (resize->base.shsurf && resize->base.shsurf->desktop_surface) {
struct weston_desktop_surface *desktop_surface =
resize->base.shsurf->desktop_surface;
weston_desktop_surface_set_resizing(desktop_surface, false);
weston_desktop_surface_set_size(desktop_surface, 0, 0);
}
shell_grab_end(&resize->base);
......
......@@ -1452,6 +1452,7 @@ struct weston_view {
struct weston_surface *surface;
struct wl_list surface_link;
struct wl_signal destroy_signal;
struct wl_signal unmap_signal;
/* struct weston_paint_node::view_link */
struct wl_list paint_node_list;
......@@ -1605,7 +1606,7 @@ struct weston_pointer_constraint {
bool hint_is_pending;
struct wl_listener pointer_destroy_listener;
struct wl_listener surface_destroy_listener;
struct wl_listener view_unmap_listener;
struct wl_listener surface_commit_listener;
struct wl_listener surface_activate_listener;
};
......
......@@ -81,6 +81,20 @@ drm_virtual_crtc_destroy(struct drm_crtc *crtc)
free(crtc);
}
static uint32_t
get_drm_plane_index_maximum(struct drm_device *device)
{
uint32_t max = 0;
struct drm_plane *p;
wl_list_for_each(p, &device->plane_list, link) {
if (p->plane_idx > max)
max = p->plane_idx;
}
return max;
}
/**
* Create a drm_plane for virtual output
*
......@@ -125,6 +139,7 @@ drm_virtual_plane_create(struct drm_device *device, struct drm_output *output)
goto err;
weston_plane_init(&plane->base, b->compositor, 0, 0);
plane->plane_idx = get_drm_plane_index_maximum(device) + 1;
wl_list_insert(&device->plane_list, &plane->link);
return plane;
......
......@@ -396,6 +396,7 @@ weston_view_create(struct weston_surface *surface)
wl_list_insert(&surface->views, &view->surface_link);
wl_signal_init(&view->destroy_signal);
wl_signal_init(&view->unmap_signal);
wl_list_init(&view->link);
wl_list_init(&view->layer_link.link);
wl_list_init(&view->paint_node_list);
......@@ -1827,6 +1828,7 @@ transform_parent_handle_parent_destroy(struct wl_listener *listener,
geometry.parent_destroy_listener);
weston_view_set_transform_parent(view, NULL);
view->parent_view = NULL;
}
WL_EXPORT void
......@@ -2247,22 +2249,22 @@ weston_view_unmap(struct weston_view *view)
view->output_mask = 0;
weston_surface_assign_output(view->surface);
if (weston_surface_is_mapped(view->surface))
return;
wl_list_for_each(seat, &view->surface->compositor->seat_list, link) {
struct weston_touch *touch = weston_seat_get_touch(seat);
struct weston_pointer *pointer = weston_seat_get_pointer(seat);
struct weston_keyboard *keyboard =
weston_seat_get_keyboard(seat);
if (keyboard && keyboard->focus == view->surface)
weston_keyboard_set_focus(keyboard, NULL);
if (pointer && pointer->focus == view)
weston_pointer_clear_focus(pointer);
if (touch && touch->focus == view)
weston_touch_set_focus(touch, NULL);
if (!weston_surface_is_mapped(view->surface)) {
wl_list_for_each(seat, &view->surface->compositor->seat_list, link) {
struct weston_touch *touch = weston_seat_get_touch(seat);
struct weston_pointer *pointer = weston_seat_get_pointer(seat);
struct weston_keyboard *keyboard =
weston_seat_get_keyboard(seat);
if (keyboard && keyboard->focus == view->surface)
weston_keyboard_set_focus(keyboard, NULL);
if (pointer && pointer->focus == view)
weston_pointer_clear_focus(pointer);
if (touch && touch->focus == view)
weston_touch_set_focus(touch, NULL);
}
}
weston_signal_emit_mutable(&view->unmap_signal, view);
}
WL_EXPORT void
......
......@@ -3713,8 +3713,8 @@ enable_pointer_constraint(struct weston_pointer_constraint *constraint,
constraint->view = view;
pointer_constraint_notify_activated(constraint);
weston_pointer_start_grab(constraint->pointer, &constraint->grab);
wl_list_remove(&constraint->surface_destroy_listener.link);
wl_list_init(&constraint->surface_destroy_listener.link);
wl_signal_add(&constraint->view->unmap_signal,
&constraint->view_unmap_listener);
}
static bool
......@@ -3729,6 +3729,8 @@ weston_pointer_constraint_disable(struct weston_pointer_constraint *constraint)
constraint->view = NULL;
pointer_constraint_notify_deactivated(constraint);
weston_pointer_end_grab(constraint->grab.pointer);
wl_list_remove(&constraint->view_unmap_listener.link);
wl_list_init(&constraint->view_unmap_listener.link);
}
void
......@@ -3738,7 +3740,6 @@ weston_pointer_constraint_destroy(struct weston_pointer_constraint *constraint)
weston_pointer_constraint_disable(constraint);
wl_list_remove(&constraint->pointer_destroy_listener.link);
wl_list_remove(&constraint->surface_destroy_listener.link);
wl_list_remove(&constraint->surface_commit_listener.link);
wl_list_remove(&constraint->surface_activate_listener.link);
......@@ -3935,13 +3936,13 @@ pointer_constraint_pointer_destroyed(struct wl_listener *listener, void *data)
}
static void
pointer_constraint_surface_destroyed(struct wl_listener *listener, void *data)
pointer_constraint_view_unmapped(struct wl_listener *listener, void *data)
{
struct weston_pointer_constraint *constraint =
container_of(listener, struct weston_pointer_constraint,
surface_destroy_listener);
struct weston_pointer_constraint *constraint =
container_of(listener, struct weston_pointer_constraint,
view_unmap_listener);
weston_pointer_constraint_destroy(constraint);
disable_pointer_constraint(constraint);
}
static void
......@@ -4005,8 +4006,8 @@ weston_pointer_constraint_create(struct weston_surface *surface,
constraint->surface_activate_listener.notify =
pointer_constraint_surface_activate;
constraint->surface_destroy_listener.notify =
pointer_constraint_surface_destroyed;
constraint->view_unmap_listener.notify =
pointer_constraint_view_unmapped;
constraint->surface_commit_listener.notify =
pointer_constraint_surface_committed;
constraint->pointer_destroy_listener.notify =
......@@ -4016,8 +4017,6 @@ weston_pointer_constraint_create(struct weston_surface *surface,
&constraint->surface_activate_listener);
wl_signal_add(&pointer->destroy_signal,
&constraint->pointer_destroy_listener);
wl_signal_add(&surface->destroy_signal,
&constraint->surface_destroy_listener);
wl_signal_add(&surface->commit_signal,
&constraint->surface_commit_listener);
......@@ -4787,6 +4786,7 @@ maybe_warp_confined_pointer(struct weston_pointer_constraint *constraint)
pixman_region32_intersect(&confine_region,
&constraint->view->surface->input,
&constraint->region);
assert(pixman_region32_not_empty(&confine_region));
region_to_outline(&confine_region, &borders);
pixman_region32_fini(&confine_region);
......
......@@ -149,6 +149,16 @@ lookup_pipewire_output(struct weston_output *base_output)
struct weston_pipewire *pipewire = weston_pipewire_get(c);
struct pipewire_output *output;
/* XXX: This could happen on the compositor shutdown path with our
* destroy listener being removed, and pipewire_output_destroy() being
* called as a virtual destructor.
*
* See https://gitlab.freedesktop.org/wayland/weston/-/issues/591 for
* an alternative to the shutdown sequence.
*/
if (!pipewire)
return NULL;
wl_list_for_each(output, &pipewire->output_list, link) {
if (output->output == base_output)
return output;
......@@ -310,6 +320,11 @@ pipewire_output_destroy(struct weston_output *base_output)
struct pipewire_output *output = lookup_pipewire_output(base_output);
struct weston_mode *mode, *next;
if (!output)
return;
weston_head_release(output->head);
wl_list_for_each_safe(mode, next, &base_output->mode_list, link) {
wl_list_remove(&mode->link);
free(mode);
......@@ -318,7 +333,6 @@ pipewire_output_destroy(struct weston_output *base_output)
pw_stream_destroy(output->stream);
wl_list_remove(&output->link);
weston_head_release(output->head);
free(output->head);
free(output);
}
......@@ -630,13 +644,19 @@ weston_pipewire_destroy(struct wl_listener *l, void *data)
{
struct weston_pipewire *pipewire =
wl_container_of(l, pipewire, destroy_listener);
struct pipewire_output *p_output, *p_output_next;
weston_log_scope_destroy(pipewire->debug);
pipewire->debug = NULL;
wl_list_for_each_safe(p_output, p_output_next, &pipewire->output_list, link)
pipewire_output_destroy(p_output->output);
wl_event_source_remove(pipewire->loop_source);
pw_loop_leave(pipewire->loop);
pw_loop_destroy(pipewire->loop);
free(pipewire);
}
static struct weston_pipewire *
......
......@@ -512,6 +512,16 @@ lookup_remoted_output(struct weston_output *output)
struct weston_remoting *remoting = weston_remoting_get(c);
struct remoted_output *remoted_output;
/* XXX: This could happen on the compositor shutdown path with our
* destroy listener being removed, and remoting_output_destroy() being
* called as a virtual destructor.
*
* See https://gitlab.freedesktop.org/wayland/weston/-/issues/591 for
* an alternative to the shutdown sequence.
*/
if (!remoting)
return NULL;
wl_list_for_each(remoted_output, &remoting->output_list, link) {
if (remoted_output->output == output)
return remoted_output;
......@@ -636,6 +646,11 @@ remoting_output_destroy(struct weston_output *output)
struct remoted_output *remoted_output = lookup_remoted_output(output);
struct weston_mode *mode, *next;
if (!remoted_output)
return;
weston_head_release(remoted_output->head);
wl_list_for_each_safe(mode, next, &output->mode_list, link) {
wl_list_remove(&mode->link);
free(mode);
......@@ -650,7 +665,6 @@ remoting_output_destroy(struct weston_output *output)
free(remoted_output->gst_pipeline);
wl_list_remove(&remoted_output->link);
weston_head_release(remoted_output->head);
free(remoted_output->head);
free(remoted_output);
}
......
......@@ -2795,6 +2795,8 @@ send_configure(struct weston_surface *surface, int32_t width, int32_t height)
struct theme *t;
int new_width, new_height;
int vborder, hborder;
bool use_saved_dimensions = false;
bool use_current_dimensions = false;
if (!window || !window->wm)
return;
......@@ -2809,20 +2811,46 @@ send_configure(struct weston_surface *surface, int32_t width, int32_t height)
vborder = 0;
}
if (width > hborder)
new_width = width - hborder;
else
new_width = 1;
if (height > vborder)
new_height = height - vborder;
else
new_height = 1;
/* A config event with width == 0 or height == 0 is a hint to the client
* to choose its own dimensions. Since X11 clients don't support such
* hints we make a best guess here by trying to use the last saved
* dimensions or, as a fallback, the current dimensions. */
if (width == 0 || height == 0) {
use_saved_dimensions = window->saved_width > 0 &&
window->saved_height > 0;
use_current_dimensions = !use_saved_dimensions &&
window->width > 0 &&
window->height > 0;
}
/* The saved or current dimensions are the plain window content
* dimensions without the borders, so we can use them directly for
* new_width and new_height below. */
if (use_current_dimensions) {
new_width = window->width;
new_height = window->height;
} else if (use_saved_dimensions) {
new_width = window->saved_width;
new_height = window->saved_height;
} else {
new_width = (width > hborder) ? (width - hborder) : 1;
new_height = (height > vborder) ? (height - vborder) : 1;
}
if (window->width != new_width || window->height != new_height) {
window->width = new_width;
window->height = new_height;
/* Save the toplevel size so that we can pick up a reasonable
* value when the compositor tell us to choose a size. We are
* already saving the size before going fullscreen/maximized,
* but this covers the case in which our size is changed but we
* continue on a normal state. */
if (!weston_wm_window_is_maximized(window) && !window->fullscreen) {
window->saved_width = new_width;
window->saved_height = new_height;
}
if (window->frame) {
if (weston_wm_window_is_maximized(window))
frame_set_flag(window->frame, FRAME_FLAG_MAXIMIZED);
......