Skip to content

Commit 3847a81

Browse files
committed
wayland: handle all outputs disappearing without segfaulting
If you switch TTYs while mpv is playing, wlroots compositors will remove all outputs from the registry. This segfaults when you switch back since we try to access cleared memory. Rework this so wl->current_output is given null when appropriate and properly guarded. You still need at least one output to initially place the surface, but in general they can all disappear during runtime and it should work. Change the log to verbose because that becomes just noise in this case (switching TTYs). The surface entrance event happens later and should get all the proper parameters.
1 parent f0f9322 commit 3847a81

2 files changed

Lines changed: 25 additions & 20 deletions

File tree

video/out/wayland_common.c

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,7 @@ static void rescale_geometry(struct vo_wayland_state *wl, double old_scale);
328328
static void set_geometry(struct vo_wayland_state *wl, bool resize);
329329
static void set_surface_scaling(struct vo_wayland_state *wl);
330330
static void update_output_scaling(struct vo_wayland_state *wl);
331-
static void update_output_geometry(struct vo_wayland_state *wl, struct mp_rect old_geometry,
332-
struct mp_rect old_output_geometry);
331+
static void update_output_geometry(struct vo_wayland_state *wl);
333332
static void destroy_offer(struct vo_wayland_data_offer *o);
334333

335334
/* Wayland listener boilerplate */
@@ -1670,13 +1669,13 @@ static void surface_handle_enter(void *data, struct wl_surface *wl_surface,
16701669
struct wl_output *output)
16711670
{
16721671
struct vo_wayland_state *wl = data;
1673-
if (!wl->current_output)
1674-
return;
16751672

1676-
struct mp_rect old_output_geometry = wl->current_output->geometry;
1677-
struct mp_rect old_geometry = wl->geometry;
1678-
wl->current_output = NULL;
1673+
if (wl->current_output) {
1674+
wl->old_output_geometry = wl->current_output->geometry;
1675+
wl->old_geometry = wl->geometry;
1676+
}
16791677

1678+
wl->current_output = NULL;
16801679
int outputs = 0;
16811680
struct vo_wayland_output *o;
16821681
wl_list_for_each(o, &wl->output_list, link) {
@@ -1689,7 +1688,7 @@ static void surface_handle_enter(void *data, struct wl_surface *wl_surface,
16891688
}
16901689

16911690
if (outputs == 1)
1692-
update_output_geometry(wl, old_geometry, old_output_geometry);
1691+
update_output_geometry(wl);
16931692

16941693
MP_VERBOSE(wl, "Surface entered output %s %s (%s) (0x%x), scale = %f, refresh rate = %f Hz\n",
16951694
wl->current_output->make, wl->current_output->model, wl->current_output->name,
@@ -1702,11 +1701,11 @@ static void surface_handle_leave(void *data, struct wl_surface *wl_surface,
17021701
struct wl_output *output)
17031702
{
17041703
struct vo_wayland_state *wl = data;
1705-
if (!wl->current_output)
1706-
return;
17071704

1708-
struct mp_rect old_output_geometry = wl->current_output->geometry;
1709-
struct mp_rect old_geometry = wl->geometry;
1705+
if (wl->current_output) {
1706+
wl->old_output_geometry = wl->current_output->geometry;
1707+
wl->old_geometry = wl->geometry;
1708+
}
17101709

17111710
int outputs = 0;
17121711
struct vo_wayland_output *o;
@@ -1719,8 +1718,11 @@ static void surface_handle_leave(void *data, struct wl_surface *wl_surface,
17191718
wl->current_output = o;
17201719
}
17211720

1721+
if (!outputs)
1722+
wl->current_output = NULL;
1723+
17221724
if (outputs == 1)
1723-
update_output_geometry(wl, old_geometry, old_output_geometry);
1725+
update_output_geometry(wl);
17241726

17251727
wl->pending_vo_events |= VO_EVENT_WIN_STATE;
17261728
}
@@ -2828,6 +2830,8 @@ static void registry_handle_remove(void *data, struct wl_registry *reg, uint32_t
28282830
wl_list_for_each_safe(output, output_tmp, &wl->output_list, link) {
28292831
if (output->id == id) {
28302832
remove_output(output);
2833+
if (wl_list_length(&wl->output_list) == 0)
2834+
wl->current_output = NULL;
28312835
return;
28322836
}
28332837
}
@@ -3183,7 +3187,7 @@ static struct vo_wayland_output *find_output(struct vo_wayland_state *wl)
31833187
return output;
31843188
}
31853189
if (!fallback_output) {
3186-
MP_ERR(wl, "No screens could be found!\n");
3190+
MP_VERBOSE(wl, "No screens could be found!\n");
31873191
return NULL;
31883192
} else if (screen_id >= 0) {
31893193
MP_WARN(wl, "Screen index %i not found/unavailable! Falling back to screen 0!\n", screen_id);
@@ -3885,8 +3889,7 @@ static void update_output_scaling(struct vo_wayland_state *wl)
38853889
wl->pending_vo_events |= VO_EVENT_DPI | VO_EVENT_RESIZE;
38863890
}
38873891

3888-
static void update_output_geometry(struct vo_wayland_state *wl, struct mp_rect old_geometry,
3889-
struct mp_rect old_output_geometry)
3892+
static void update_output_geometry(struct vo_wayland_state *wl)
38903893
{
38913894
if (wl->need_rescale) {
38923895
update_output_scaling(wl);
@@ -3895,20 +3898,20 @@ static void update_output_geometry(struct vo_wayland_state *wl, struct mp_rect o
38953898

38963899
bool force_resize = false;
38973900
bool use_output_scale = wl_surface_get_version(wl->surface) < 6 &&
3898-
!wl->fractional_scale_manager &&
3901+
!wl->fractional_scale_manager && wl->current_output &&
38993902
wl->scaling != wl->current_output->scale;
39003903

39013904
if (use_output_scale) {
39023905
set_surface_scaling(wl);
39033906
force_resize = true;
39043907
}
39053908

3906-
if (!mp_rect_equals(&old_output_geometry, &wl->current_output->geometry)) {
3909+
if (!mp_rect_equals(&wl->old_output_geometry, &wl->current_output->geometry)) {
39073910
set_geometry(wl, false);
39083911
force_resize = true;
39093912
}
39103913

3911-
if (!mp_rect_equals(&old_geometry, &wl->geometry) || force_resize)
3914+
if (!mp_rect_equals(&wl->old_geometry, &wl->geometry) || force_resize)
39123915
wl->pending_vo_events |= VO_EVENT_RESIZE;
39133916
}
39143917

@@ -4704,7 +4707,7 @@ void vo_wayland_wait_frame(struct vo_wayland_state *wl)
47044707
if (vblank_time <= 0 && wl->refresh_interval > 0)
47054708
vblank_time = wl->refresh_interval;
47064709

4707-
if (vblank_time <= 0 && wl->current_output->refresh_rate > 0)
4710+
if (vblank_time <= 0 && wl->current_output && wl->current_output->refresh_rate > 0)
47084711
vblank_time = 1e9 / wl->current_output->refresh_rate;
47094712

47104713
// Ideally you should never reach this point.

video/out/wayland_common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ struct vo_wayland_state {
5858
struct mp_rect window_size;
5959
struct wl_list output_list;
6060
struct vo_wayland_output *current_output;
61+
struct mp_rect old_geometry;
62+
struct mp_rect old_output_geometry;
6163
int bounded_height;
6264
int bounded_width;
6365
int reduced_height;

0 commit comments

Comments
 (0)