Fix segfault after hot-plugging outputs

When new outputs appear, either because they were just created or
because they have been disabled/reenabled, ensure we always set up the
right xdg_output and wlr_output_power listeners.

Signed-off-by: Jim Ramsay <i.am@jimramsay.com>
pull/204/head
Jim Ramsay 2022-12-18 02:11:38 -05:00
parent 2a9e3dac58
commit 3e5d6ea8eb
3 changed files with 70 additions and 62 deletions

View File

@ -20,7 +20,9 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
struct zxdg_output_manager_v1;
struct zxdg_output_v1; struct zxdg_output_v1;
struct zwlr_output_power_manager_v1;
struct zwlr_output_power_v1; struct zwlr_output_power_v1;
enum output_power_state { enum output_power_state {
@ -65,10 +67,7 @@ struct output {
struct output* output_new(struct wl_output* wl_output, uint32_t id); struct output* output_new(struct wl_output* wl_output, uint32_t id);
void output_destroy(struct output* output); void output_destroy(struct output* output);
void output_set_xdg_output(struct output* output, void output_setup_wl_managers(struct wl_list* list);
struct zxdg_output_v1* xdg_output);
void output_set_wlr_output_power(struct output* output,
struct zwlr_output_power_v1* wlr_output_power);
int output_set_power_state(struct output* output, enum output_power_state state); int output_set_power_state(struct output* output, enum output_power_state state);
void output_list_destroy(struct wl_list* list); void output_list_destroy(struct wl_list* list);
struct output* output_find_by_id(struct wl_list* list, uint32_t id); struct output* output_find_by_id(struct wl_list* list, uint32_t id);

View File

@ -78,8 +78,6 @@ struct wayvnc {
struct wl_list seats; struct wl_list seats;
struct cfg cfg; struct cfg cfg;
struct zxdg_output_manager_v1* xdg_output_manager;
struct zwlr_output_power_manager_v1* wlr_output_power_manager;
struct zwp_virtual_keyboard_manager_v1* keyboard_manager; struct zwp_virtual_keyboard_manager_v1* keyboard_manager;
struct zwlr_virtual_pointer_manager_v1* pointer_manager; struct zwlr_virtual_pointer_manager_v1* pointer_manager;
struct zwlr_data_control_manager_v1* data_control_manager; struct zwlr_data_control_manager_v1* data_control_manager;
@ -134,6 +132,8 @@ static void client_init_data_control(struct wayvnc_client* self);
struct wl_shm* wl_shm = NULL; struct wl_shm* wl_shm = NULL;
struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf = NULL; struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf = NULL;
struct gbm_device* gbm_device = NULL; struct gbm_device* gbm_device = NULL;
struct zxdg_output_manager_v1* xdg_output_manager = NULL;
struct zwlr_output_power_manager_v1* wlr_output_power_manager = NULL;
static bool registry_add_input(void* data, struct wl_registry* registry, static bool registry_add_input(void* data, struct wl_registry* registry,
uint32_t id, const char* interface, uint32_t id, const char* interface,
@ -190,6 +190,7 @@ static void registry_add(void* data, struct wl_registry* registry,
struct wayvnc* self = data; struct wayvnc* self = data;
if (strcmp(interface, wl_output_interface.name) == 0) { if (strcmp(interface, wl_output_interface.name) == 0) {
nvnc_trace("Registering new output %u", id);
struct wl_output* wl_output = struct wl_output* wl_output =
wl_registry_bind(registry, id, &wl_output_interface, 3); wl_registry_bind(registry, id, &wl_output_interface, 3);
if (!wl_output) if (!wl_output)
@ -204,16 +205,20 @@ static void registry_add(void* data, struct wl_registry* registry,
} }
if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0) { if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0) {
self->xdg_output_manager = nvnc_trace("Registering new xdg_output_manager");
xdg_output_manager =
wl_registry_bind(registry, id, wl_registry_bind(registry, id,
&zxdg_output_manager_v1_interface, 3); &zxdg_output_manager_v1_interface, 3);
output_setup_wl_managers(&self->outputs);
return; return;
} }
if (strcmp(interface, zwlr_output_power_manager_v1_interface.name) == 0) { if (strcmp(interface, zwlr_output_power_manager_v1_interface.name) == 0) {
self->wlr_output_power_manager = nvnc_trace("Registering new wlr_output_power_manager");
wl_registry_bind(registry, id, wlr_output_power_manager = wl_registry_bind(registry, id,
&zwlr_output_power_manager_v1_interface, 1); &zwlr_output_power_manager_v1_interface, 1);
output_setup_wl_managers(&self->outputs);
return; return;
} }
@ -327,11 +332,11 @@ void wayvnc_destroy(struct wayvnc* self)
output_list_destroy(&self->outputs); output_list_destroy(&self->outputs);
seat_list_destroy(&self->seats); seat_list_destroy(&self->seats);
zxdg_output_manager_v1_destroy(self->xdg_output_manager); if (xdg_output_manager)
zxdg_output_manager_v1_destroy(xdg_output_manager);
if (self->wlr_output_power_manager) if (wlr_output_power_manager)
zwlr_output_power_manager_v1_destroy( zwlr_output_power_manager_v1_destroy(wlr_output_power_manager);
self->wlr_output_power_manager);
wl_shm_destroy(wl_shm); wl_shm_destroy(wl_shm);
@ -357,25 +362,6 @@ void wayvnc_destroy(struct wayvnc* self)
wl_display_disconnect(self->display); wl_display_disconnect(self->display);
} }
static void init_outputs(struct wayvnc* self)
{
struct output* output;
wl_list_for_each(output, &self->outputs, link) {
struct zxdg_output_v1* xdg_output =
zxdg_output_manager_v1_get_xdg_output(
self->xdg_output_manager, output->wl_output);
output_set_xdg_output(output, xdg_output);
if (self->wlr_output_power_manager) {
struct zwlr_output_power_v1* wlr_output_power =
zwlr_output_power_manager_v1_get_output_power(
self->wlr_output_power_manager,
output->wl_output);
output_set_wlr_output_power(output, wlr_output_power);
}
}
}
static int init_wayland(struct wayvnc* self) static int init_wayland(struct wayvnc* self)
{ {
static const struct wl_registry_listener registry_listener = { static const struct wl_registry_listener registry_listener = {
@ -399,8 +385,6 @@ static int init_wayland(struct wayvnc* self)
wl_display_dispatch(self->display); wl_display_dispatch(self->display);
wl_display_roundtrip(self->display); wl_display_roundtrip(self->display);
init_outputs(self);
if (!self->pointer_manager && !self->disable_input) { if (!self->pointer_manager && !self->disable_input) {
nvnc_log(NVNC_LOG_ERROR, "Virtual Pointer protocol not supported by compositor."); nvnc_log(NVNC_LOG_ERROR, "Virtual Pointer protocol not supported by compositor.");
nvnc_log(NVNC_LOG_ERROR, "wayvnc may still work if started with --disable-input."); nvnc_log(NVNC_LOG_ERROR, "wayvnc may still work if started with --disable-input.");
@ -413,9 +397,6 @@ static int init_wayland(struct wayvnc* self)
goto failure; goto failure;
} }
wl_display_dispatch(self->display);
wl_display_roundtrip(self->display);
if (!self->screencopy.manager) { if (!self->screencopy.manager) {
nvnc_log(NVNC_LOG_ERROR, "Screencopy protocol not supported by compositor. Exiting. Refer to FAQ section in man page."); nvnc_log(NVNC_LOG_ERROR, "Screencopy protocol not supported by compositor. Exiting. Refer to FAQ section in man page.");
goto failure; goto failure;

View File

@ -31,6 +31,9 @@
#include "xdg-output-unstable-v1.h" #include "xdg-output-unstable-v1.h"
#include "wlr-output-power-management-unstable-v1.h" #include "wlr-output-power-management-unstable-v1.h"
extern struct zxdg_output_manager_v1* xdg_output_manager;
extern struct zwlr_output_power_manager_v1* wlr_output_power_manager;
#define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b))
@ -181,6 +184,7 @@ static const struct wl_output_listener output_listener = {
void output_destroy(struct output* output) void output_destroy(struct output* output)
{ {
if (output->xdg_output)
zxdg_output_v1_destroy(output->xdg_output); zxdg_output_v1_destroy(output->xdg_output);
if (output->wlr_output_power) if (output->wlr_output_power)
zwlr_output_power_v1_destroy(output->wlr_output_power); zwlr_output_power_v1_destroy(output->wlr_output_power);
@ -199,24 +203,6 @@ void output_list_destroy(struct wl_list* list)
} }
} }
struct output* output_new(struct wl_output* wl_output, uint32_t id)
{
struct output* output = calloc(1, sizeof(*output));
if (!output) {
nvnc_log(NVNC_LOG_ERROR, "OOM");
return NULL;
}
output->wl_output = wl_output;
output->id = id;
output->power = OUTPUT_POWER_UNKNOWN;
wl_output_add_listener(output->wl_output, &output_listener,
output);
return output;
}
void output_logical_position(void* data, struct zxdg_output_v1* xdg_output, void output_logical_position(void* data, struct zxdg_output_v1* xdg_output,
int32_t x, int32_t y) int32_t x, int32_t y)
{ {
@ -233,6 +219,7 @@ void output_name(void* data, struct zxdg_output_v1* xdg_output,
struct output* self = data; struct output* self = data;
strlcpy(self->name, name, sizeof(self->name)); strlcpy(self->name, name, sizeof(self->name));
nvnc_trace("Output %u name: %s", self->id, self->name);
} }
void output_description(void* data, struct zxdg_output_v1* xdg_output, void output_description(void* data, struct zxdg_output_v1* xdg_output,
@ -241,6 +228,7 @@ void output_description(void* data, struct zxdg_output_v1* xdg_output,
struct output* self = data; struct output* self = data;
strlcpy(self->description, description, sizeof(self->description)); strlcpy(self->description, description, sizeof(self->description));
nvnc_trace("Output %u description: %s", self->id, self->description);
} }
static const struct zxdg_output_v1_listener xdg_output_listener = { static const struct zxdg_output_v1_listener xdg_output_listener = {
@ -251,11 +239,15 @@ static const struct zxdg_output_v1_listener xdg_output_listener = {
.description = output_description, .description = output_description,
}; };
void output_set_xdg_output(struct output* self, static void output_setup_xdg_output_manager(struct output* self)
struct zxdg_output_v1* xdg_output)
{ {
self->xdg_output = xdg_output; if (!xdg_output_manager || self->xdg_output)
return;
struct zxdg_output_v1* xdg_output =
zxdg_output_manager_v1_get_xdg_output(
xdg_output_manager, self->wl_output);
self->xdg_output = xdg_output;
zxdg_output_v1_add_listener(self->xdg_output, &xdg_output_listener, zxdg_output_v1_add_listener(self->xdg_output, &xdg_output_listener,
self); self);
} }
@ -310,9 +302,15 @@ static const struct zwlr_output_power_v1_listener wlr_output_power_listener = {
.failed = output_power_failed, .failed = output_power_failed,
}; };
void output_set_wlr_output_power(struct output* self, static void output_setup_wlr_output_power_manager(struct output* self)
struct zwlr_output_power_v1* wlr_output_power)
{ {
if (!wlr_output_power_manager || self->wlr_output_power)
return;
struct zwlr_output_power_v1* wlr_output_power =
zwlr_output_power_manager_v1_get_output_power(
wlr_output_power_manager,
self->wl_output);
self->wlr_output_power = wlr_output_power; self->wlr_output_power = wlr_output_power;
zwlr_output_power_v1_add_listener(self->wlr_output_power, zwlr_output_power_v1_add_listener(self->wlr_output_power,
@ -382,3 +380,33 @@ struct output* output_cycle(const struct wl_list* list,
struct output* output; struct output* output;
return wl_container_of(iter, output, link); return wl_container_of(iter, output, link);
} }
void output_setup_wl_managers(struct wl_list* list)
{
struct output* output;
wl_list_for_each(output, list, link) {
output_setup_xdg_output_manager(output);
output_setup_wlr_output_power_manager(output);
}
}
struct output* output_new(struct wl_output* wl_output, uint32_t id)
{
struct output* output = calloc(1, sizeof(*output));
if (!output) {
nvnc_log(NVNC_LOG_ERROR, "OOM");
return NULL;
}
output->wl_output = wl_output;
output->id = id;
output->power = OUTPUT_POWER_UNKNOWN;
wl_output_add_listener(output->wl_output, &output_listener,
output);
output_setup_xdg_output_manager(output);
output_setup_wlr_output_power_manager(output);
return output;
}