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 <stdbool.h>
struct zxdg_output_manager_v1;
struct zxdg_output_v1;
struct zwlr_output_power_manager_v1;
struct zwlr_output_power_v1;
enum output_power_state {
@ -65,10 +67,7 @@ struct output {
struct output* output_new(struct wl_output* wl_output, uint32_t id);
void output_destroy(struct output* output);
void output_set_xdg_output(struct output* output,
struct zxdg_output_v1* xdg_output);
void output_set_wlr_output_power(struct output* output,
struct zwlr_output_power_v1* wlr_output_power);
void output_setup_wl_managers(struct wl_list* list);
int output_set_power_state(struct output* output, enum output_power_state state);
void output_list_destroy(struct wl_list* list);
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 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 zwlr_virtual_pointer_manager_v1* pointer_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 zwp_linux_dmabuf_v1* zwp_linux_dmabuf = 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,
uint32_t id, const char* interface,
@ -190,6 +190,7 @@ static void registry_add(void* data, struct wl_registry* registry,
struct wayvnc* self = data;
if (strcmp(interface, wl_output_interface.name) == 0) {
nvnc_trace("Registering new output %u", id);
struct wl_output* wl_output =
wl_registry_bind(registry, id, &wl_output_interface, 3);
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) {
self->xdg_output_manager =
nvnc_trace("Registering new xdg_output_manager");
xdg_output_manager =
wl_registry_bind(registry, id,
&zxdg_output_manager_v1_interface, 3);
output_setup_wl_managers(&self->outputs);
return;
}
if (strcmp(interface, zwlr_output_power_manager_v1_interface.name) == 0) {
self->wlr_output_power_manager =
wl_registry_bind(registry, id,
nvnc_trace("Registering new wlr_output_power_manager");
wlr_output_power_manager = wl_registry_bind(registry, id,
&zwlr_output_power_manager_v1_interface, 1);
output_setup_wl_managers(&self->outputs);
return;
}
@ -327,11 +332,11 @@ void wayvnc_destroy(struct wayvnc* self)
output_list_destroy(&self->outputs);
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)
zwlr_output_power_manager_v1_destroy(
self->wlr_output_power_manager);
if (wlr_output_power_manager)
zwlr_output_power_manager_v1_destroy(wlr_output_power_manager);
wl_shm_destroy(wl_shm);
@ -357,25 +362,6 @@ void wayvnc_destroy(struct wayvnc* self)
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 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_roundtrip(self->display);
init_outputs(self);
if (!self->pointer_manager && !self->disable_input) {
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.");
@ -413,9 +397,6 @@ static int init_wayland(struct wayvnc* self)
goto failure;
}
wl_display_dispatch(self->display);
wl_display_roundtrip(self->display);
if (!self->screencopy.manager) {
nvnc_log(NVNC_LOG_ERROR, "Screencopy protocol not supported by compositor. Exiting. Refer to FAQ section in man page.");
goto failure;

View File

@ -31,6 +31,9 @@
#include "xdg-output-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 MAX(a, b) ((a) > (b) ? (a) : (b))
@ -181,7 +184,8 @@ static const struct wl_output_listener output_listener = {
void output_destroy(struct output* output)
{
zxdg_output_v1_destroy(output->xdg_output);
if (output->xdg_output)
zxdg_output_v1_destroy(output->xdg_output);
if (output->wlr_output_power)
zwlr_output_power_v1_destroy(output->wlr_output_power);
wl_output_destroy(output->wl_output);
@ -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,
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;
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,
@ -241,6 +228,7 @@ void output_description(void* data, struct zxdg_output_v1* xdg_output,
struct output* self = data;
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 = {
@ -251,13 +239,17 @@ static const struct zxdg_output_v1_listener xdg_output_listener = {
.description = output_description,
};
void output_set_xdg_output(struct output* self,
struct zxdg_output_v1* xdg_output)
static void output_setup_xdg_output_manager(struct output* self)
{
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,
self);
self);
}
const char* output_power_state_name(enum output_power_state state)
@ -310,9 +302,15 @@ static const struct zwlr_output_power_v1_listener wlr_output_power_listener = {
.failed = output_power_failed,
};
void output_set_wlr_output_power(struct output* self,
struct zwlr_output_power_v1* wlr_output_power)
static void output_setup_wlr_output_power_manager(struct output* self)
{
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;
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;
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;
}