From c2d0090ad7b0528b308741e67cdae11d58792d13 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Tue, 20 Jun 2017 18:22:21 -0400 Subject: [PATCH] Support multiple wl backend outputs --- backend/backend.c | 44 ++++++++++++++++++++++++++++------- backend/wayland/backend.c | 23 ++++++++---------- backend/wayland/output.c | 24 ++++++++++++------- include/backend/wayland.h | 22 +++++++----------- include/wlr/backend/wayland.h | 19 +++++++++++++-- 5 files changed, 86 insertions(+), 46 deletions(-) diff --git a/backend/backend.c b/backend/backend.c index 30ced3e8..e0c52a7e 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -39,13 +39,39 @@ void wlr_backend_destroy(struct wlr_backend *backend) { free(backend); } +static struct wlr_backend *attempt_wl_backend(struct wl_display *display) { + struct wlr_backend *backend = wlr_wl_backend_create(display); + if (backend) { + int outputs = 1; + const char *_outputs = getenv("WLR_WL_OUTPUTS"); + if (_outputs) { + char *end; + outputs = (int)strtol(_outputs, &end, 10); + if (*end) { + wlr_log(L_ERROR, "WLR_WL_OUTPUTS specified with invalid integer, ignoring"); + outputs = 1; + } else if (outputs < 0) { + wlr_log(L_ERROR, "WLR_WL_OUTPUTS specified with negative outputs, ignoring"); + outputs = 1; + } + } + while (outputs--) { + wlr_wl_output_create(backend); + } + } + return backend; +} + struct wlr_backend *wlr_backend_autocreate(struct wl_display *display, struct wlr_session *session) { - // TODO: Choose the most appropriate backend for the situation - // Attempt DRM+libinput + struct wlr_backend *backend; if (getenv("WAYLAND_DISPLAY") || getenv("_WAYLAND_DISPLAY")) { - return wlr_wl_backend_create(display, 1); + backend = attempt_wl_backend(display); + if (backend) { + return backend; + } } + // Attempt DRM+libinput struct wlr_udev *udev; if (!(udev = wlr_udev_create(display))) { wlr_log(L_ERROR, "Failed to start udev"); @@ -56,8 +82,8 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display, wlr_log(L_ERROR, "Failed to open DRM device"); goto error_udev; } - struct wlr_backend *multi = wlr_multi_backend_create(); - if (!multi) { + backend = wlr_multi_backend_create(); + if (!backend) { goto error_gpu; } struct wlr_backend *libinput = @@ -70,13 +96,13 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display, if (!drm) { goto error_libinput; } - wlr_multi_backend_add(multi, libinput); - wlr_multi_backend_add(multi, drm); - return multi; + wlr_multi_backend_add(backend, libinput); + wlr_multi_backend_add(backend, drm); + return backend; error_libinput: wlr_backend_destroy(libinput); error_multi: - wlr_backend_destroy(multi); + wlr_backend_destroy(backend); error_gpu: close(gpu); error_udev: diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 344cc35d..d1213ab7 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -34,7 +34,7 @@ static int dispatch_events(int fd, uint32_t mask, void *data) { static bool wlr_wl_backend_init(struct wlr_backend_state* state) { wlr_log(L_INFO, "Initializating wayland backend"); - state->remote_display = wl_display_connect(getenv("_WAYLAND_DISPLAY")); + state->remote_display = wl_display_connect(NULL); if (!state->remote_display) { wlr_log_errno(L_ERROR, "Could not connect to remote display"); return false; @@ -52,11 +52,8 @@ static bool wlr_wl_backend_init(struct wlr_backend_state* state) { } wlr_egl_init(&state->egl, EGL_PLATFORM_WAYLAND_EXT, state->remote_display); - for (size_t i = 0; i < state->num_outputs; ++i) { - if(!(state->outputs[i] = wlr_wl_output_create(state, i))) { - wlr_log_errno(L_ERROR, "Failed to create %zuth output", i); - return false; - } + for (size_t i = 0; i < state->requested_outputs; ++i) { + wlr_wl_output_create(state->backend); } struct wl_event_loop *loop = wl_display_get_event_loop(state->local_display); @@ -75,8 +72,8 @@ static void wlr_wl_backend_destroy(struct wlr_backend_state *state) { return; } - for (size_t i = 0; i < state->num_outputs; ++i) { - wlr_output_destroy(state->outputs[i]); + for (size_t i = 0; i < state->outputs->length; ++i) { + wlr_output_destroy(state->outputs->items[i]); } for (size_t i = 0; state->devices && i < state->devices->length; ++i) { @@ -101,9 +98,11 @@ static struct wlr_backend_impl backend_impl = { .destroy = wlr_wl_backend_destroy }; +bool wlr_backend_is_wl(struct wlr_backend *b) { + return b->impl == &backend_impl; +} -struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, - size_t num_outputs) { +struct wlr_backend *wlr_wl_backend_create(struct wl_display *display) { wlr_log(L_INFO, "Creating wayland backend"); struct wlr_backend_state *state = calloc(1, sizeof(struct wlr_backend_state)); @@ -123,15 +122,13 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, goto error; } - if (!(state->outputs = calloc(sizeof(void*), num_outputs))) { + if (!(state->outputs = list_create())) { wlr_log(L_ERROR, "Could not allocate outputs list"); goto error; } state->local_display = display; state->backend = backend; - state->num_outputs = num_outputs; - return backend; error: diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 4ce6d97f..49b40ffd 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -23,7 +23,8 @@ static void surface_frame_callback(void *data, struct wl_callback *cb, uint32_t return; } - wl_signal_emit(&output->output->events.frame, output->output); + struct wlr_output *wlr_output = output->wlr_output; + wl_signal_emit(&wlr_output->events.frame, wlr_output); output->frame_callback = wl_surface_frame(output->surface); wl_callback_add_listener(output->frame_callback, &frame_listener, output); wl_callback_destroy(cb); @@ -40,7 +41,7 @@ static struct wl_callback_listener frame_listener = { static void wlr_wl_output_transform(struct wlr_output_state *output, enum wl_output_transform transform) { - output->output->transform = transform; + output->wlr_output->transform = transform; } static void wlr_wl_output_destroy(struct wlr_output_state *output) { @@ -67,7 +68,7 @@ void handle_configure(void *data, struct wl_shell_surface *wl_shell_surface, uint32_t edges, int32_t width, int32_t height){ struct wlr_output_state *ostate = data; assert(ostate && ostate->shell_surface == wl_shell_surface); - struct wlr_output *output = ostate->output; + struct wlr_output *output = ostate->wlr_output; wl_egl_window_resize(ostate->egl_window, width, height, 0, 0); output->width = width; output->height = height; @@ -85,8 +86,14 @@ static struct wl_shell_surface_listener shell_surface_listener = { .popup_done = handle_popup_done }; -struct wlr_output *wlr_wl_output_create(struct wlr_backend_state* backend, - size_t id) { +struct wlr_output *wlr_wl_output_create(struct wlr_backend *_backend) { + assert(wlr_backend_is_wl(_backend)); + struct wlr_backend_state *backend = _backend->state; + if (!backend->remote_display) { + ++backend->requested_outputs; + return NULL; + } + struct wlr_output_state *ostate; if (!(ostate = calloc(sizeof(struct wlr_output_state), 1))) { wlr_log(L_ERROR, "Failed to allocate wlr_output_state"); @@ -105,11 +112,11 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend_state* backend, wlr_output->scale = 1; strncpy(wlr_output->make, "wayland", sizeof(wlr_output->make)); strncpy(wlr_output->model, "wayland", sizeof(wlr_output->model)); - snprintf(wlr_output->name, sizeof(wlr_output->name), "WL-%d", 1); + snprintf(wlr_output->name, sizeof(wlr_output->name), "WL-%zd", + backend->outputs->length + 1); - ostate->id = id; ostate->backend = backend; - ostate->output = wlr_output; + ostate->wlr_output = wlr_output; // TODO: error handling ostate->surface = wl_compositor_create_surface(backend->compositor); @@ -144,6 +151,7 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend_state* backend, return false; } + list_add(backend->outputs, wlr_output); wl_signal_emit(&backend->backend->events.output_add, wlr_output); return wlr_output; } diff --git a/include/backend/wayland.h b/include/backend/wayland.h index 03667c9a..f4a0a3b4 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -11,34 +11,30 @@ struct wlr_backend_state { /* local state */ struct wl_display *local_display; + struct wlr_backend *backend; + list_t *devices; + list_t *outputs; + struct wlr_egl egl; + size_t requested_outputs; /* remote state */ struct wl_display *remote_display; + struct wl_event_source *remote_display_src; struct wl_registry *registry; struct wl_compositor *compositor; struct wl_shell *shell; struct wl_shm *shm; struct wl_seat *seat; const char *seatName; - - struct wlr_backend *backend; - list_t *devices; - - struct wl_event_source* remote_display_src; - - size_t num_outputs; - struct wlr_output **outputs; - struct wlr_egl egl; }; struct wlr_output_state { - size_t id; struct wlr_backend_state *backend; - struct wlr_output *output; + struct wlr_output *wlr_output; struct wl_surface *surface; struct wl_shell_surface *shell_surface; struct wl_egl_window* egl_window; struct wl_callback* frame_callback; - void* egl_surface; + void *egl_surface; }; struct wlr_input_device_state { @@ -47,8 +43,6 @@ struct wlr_input_device_state { }; void wlr_wl_registry_poll(struct wlr_backend_state *backend); -struct wlr_output *wlr_wl_output_create(struct wlr_backend_state* backend, - size_t id); extern const struct wl_seat_listener seat_listener; diff --git a/include/wlr/backend/wayland.h b/include/wlr/backend/wayland.h index 83b465c1..43a0b72e 100644 --- a/include/wlr/backend/wayland.h +++ b/include/wlr/backend/wayland.h @@ -4,8 +4,23 @@ #include #include #include +#include -struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, - size_t outputs); +/** + * Creates a new wlr_wl_backend. This backend will be created with no outputs; + * you must use wlr_wl_output_create to add them. + */ +struct wlr_backend *wlr_wl_backend_create(struct wl_display *display); +/** + * Adds a new output to this backend. You may remove outputs by destroying them. + * Note that if called before initializing the backend, this will return NULL + * and your outputs will be created during initialization (and given to you via + * the output_add signal). + */ +struct wlr_output *wlr_wl_output_create(struct wlr_backend *backend); +/** + * True if the given backend is a wlr_wl_backend. + */ +bool wlr_backend_is_wl(struct wlr_backend *backend); #endif