mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2025-10-29 05:40:12 -04:00
The renderer redesign is going to need the render fd before the backend is fully started, so we have to move the wl registry code to when the backend is created instead of when it is started. We also need to stash the wl_keyboard and emit it to library users later, once they've added their listeners and started the backend.
269 lines
7.2 KiB
C
269 lines
7.2 KiB
C
#include <assert.h>
|
|
#include <EGL/egl.h>
|
|
#include <EGL/eglext.h>
|
|
#include <limits.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <wayland-server.h>
|
|
#include <wlr/backend/interface.h>
|
|
#include <wlr/interfaces/wlr_input_device.h>
|
|
#include <wlr/interfaces/wlr_output.h>
|
|
#include <wlr/render/egl.h>
|
|
#include <wlr/render/gles2.h>
|
|
#include <wlr/util/log.h>
|
|
#include "backend/wayland.h"
|
|
#include "util/signal.h"
|
|
#include "xdg-shell-unstable-v6-client-protocol.h"
|
|
|
|
struct wlr_wl_backend *get_wl_backend_from_backend(struct wlr_backend *backend) {
|
|
assert(wlr_backend_is_wl(backend));
|
|
return (struct wlr_wl_backend *)backend;
|
|
}
|
|
|
|
static int dispatch_events(int fd, uint32_t mask, void *data) {
|
|
struct wlr_wl_backend *wl = data;
|
|
int count = 0;
|
|
|
|
if ((mask & WL_EVENT_HANGUP) || (mask & WL_EVENT_ERROR)) {
|
|
wl_display_terminate(wl->local_display);
|
|
return 0;
|
|
}
|
|
|
|
if (mask & WL_EVENT_READABLE) {
|
|
count = wl_display_dispatch(wl->remote_display);
|
|
}
|
|
if (mask == 0) {
|
|
count = wl_display_dispatch_pending(wl->remote_display);
|
|
wl_display_flush(wl->remote_display);
|
|
}
|
|
return count;
|
|
}
|
|
|
|
static void xdg_shell_handle_ping(void *data, struct zxdg_shell_v6 *shell,
|
|
uint32_t serial) {
|
|
zxdg_shell_v6_pong(shell, serial);
|
|
}
|
|
|
|
static const struct zxdg_shell_v6_listener xdg_shell_listener = {
|
|
xdg_shell_handle_ping,
|
|
};
|
|
|
|
static void registry_global(void *data, struct wl_registry *registry,
|
|
uint32_t name, const char *iface, uint32_t version) {
|
|
struct wlr_wl_backend *wl = data;
|
|
|
|
wlr_log(WLR_DEBUG, "Remote wayland global: %s v%d", iface, version);
|
|
|
|
if (strcmp(iface, wl_compositor_interface.name) == 0) {
|
|
wl->compositor = wl_registry_bind(registry, name,
|
|
&wl_compositor_interface, 4);
|
|
|
|
} else if (strcmp(iface, wl_seat_interface.name) == 0) {
|
|
wl->seat = wl_registry_bind(registry, name,
|
|
&wl_seat_interface, 2);
|
|
wl_seat_add_listener(wl->seat, &seat_listener, wl);
|
|
|
|
} else if (strcmp(iface, wl_shm_interface.name) == 0) {
|
|
wl->shm = wl_registry_bind(registry, name,
|
|
&wl_shm_interface, 1);
|
|
|
|
} else if (strcmp(iface, zxdg_shell_v6_interface.name) == 0) {
|
|
wl->shell = wl_registry_bind(registry, name,
|
|
&zxdg_shell_v6_interface, 1);
|
|
zxdg_shell_v6_add_listener(wl->shell, &xdg_shell_listener, NULL);
|
|
}
|
|
}
|
|
|
|
static void registry_global_remove(void *data, struct wl_registry *registry,
|
|
uint32_t name) {
|
|
// TODO
|
|
}
|
|
|
|
static const struct wl_registry_listener registry_listener = {
|
|
.global = registry_global,
|
|
.global_remove = registry_global_remove
|
|
};
|
|
|
|
/*
|
|
* Initializes the wayland backend. Opens a connection to a remote wayland
|
|
* compositor and creates surfaces for each output, then registers globals on
|
|
* the specified display.
|
|
*/
|
|
static bool backend_start(struct wlr_backend *backend) {
|
|
struct wlr_wl_backend *wl = get_wl_backend_from_backend(backend);
|
|
wlr_log(WLR_INFO, "Initializating wayland backend");
|
|
|
|
wl->started = true;
|
|
|
|
if (wl->keyboard) {
|
|
create_wl_keyboard(wl->keyboard, wl);
|
|
}
|
|
|
|
for (size_t i = 0; i < wl->requested_outputs; ++i) {
|
|
wlr_wl_output_create(&wl->backend);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static void backend_destroy(struct wlr_backend *backend) {
|
|
if (!backend) {
|
|
return;
|
|
}
|
|
|
|
struct wlr_wl_backend *wl = get_wl_backend_from_backend(backend);
|
|
|
|
struct wlr_wl_output *output, *tmp_output;
|
|
wl_list_for_each_safe(output, tmp_output, &wl->outputs, link) {
|
|
wlr_output_destroy(&output->wlr_output);
|
|
}
|
|
|
|
struct wlr_input_device *input_device, *tmp_input_device;
|
|
wl_list_for_each_safe(input_device, tmp_input_device, &wl->devices, link) {
|
|
wlr_input_device_destroy(input_device);
|
|
}
|
|
|
|
wlr_signal_emit_safe(&wl->backend.events.destroy, &wl->backend);
|
|
|
|
wl_list_remove(&wl->local_display_destroy.link);
|
|
|
|
free(wl->seat_name);
|
|
|
|
wl_event_source_remove(wl->remote_display_src);
|
|
|
|
wlr_renderer_destroy(wl->renderer);
|
|
wlr_egl_finish(&wl->egl);
|
|
|
|
if (wl->pointer) {
|
|
wl_pointer_destroy(wl->pointer);
|
|
}
|
|
if (wl->seat) {
|
|
wl_seat_destroy(wl->seat);
|
|
}
|
|
if (wl->shm) {
|
|
wl_shm_destroy(wl->shm);
|
|
}
|
|
zxdg_shell_v6_destroy(wl->shell);
|
|
wl_compositor_destroy(wl->compositor);
|
|
wl_registry_destroy(wl->registry);
|
|
wl_display_disconnect(wl->remote_display);
|
|
free(wl);
|
|
}
|
|
|
|
static struct wlr_renderer *backend_get_renderer(struct wlr_backend *backend) {
|
|
struct wlr_wl_backend *wl = get_wl_backend_from_backend(backend);
|
|
return wl->renderer;
|
|
}
|
|
|
|
static struct wlr_backend_impl backend_impl = {
|
|
.start = backend_start,
|
|
.destroy = backend_destroy,
|
|
.get_renderer = backend_get_renderer,
|
|
};
|
|
|
|
bool wlr_backend_is_wl(struct wlr_backend *b) {
|
|
return b->impl == &backend_impl;
|
|
}
|
|
|
|
static void handle_display_destroy(struct wl_listener *listener, void *data) {
|
|
struct wlr_wl_backend *wl =
|
|
wl_container_of(listener, wl, local_display_destroy);
|
|
backend_destroy(&wl->backend);
|
|
}
|
|
|
|
struct wlr_backend *wlr_wl_backend_create(struct wl_display *display,
|
|
const char *remote, wlr_renderer_create_func_t create_renderer_func) {
|
|
wlr_log(WLR_INFO, "Creating wayland backend");
|
|
|
|
struct wlr_wl_backend *wl = calloc(1, sizeof(*wl));
|
|
if (!wl) {
|
|
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
|
return NULL;
|
|
}
|
|
|
|
wlr_backend_init(&wl->backend, &backend_impl);
|
|
|
|
wl->local_display = display;
|
|
wl_list_init(&wl->devices);
|
|
wl_list_init(&wl->outputs);
|
|
|
|
wl->remote_display = wl_display_connect(remote);
|
|
if (!wl->remote_display) {
|
|
wlr_log_errno(WLR_ERROR, "Could not connect to remote display");
|
|
goto error_wl;
|
|
}
|
|
|
|
wl->registry = wl_display_get_registry(wl->remote_display);
|
|
if (!wl->registry) {
|
|
wlr_log_errno(WLR_ERROR, "Could not obtain reference to remote registry");
|
|
goto error_display;
|
|
}
|
|
|
|
wl_registry_add_listener(wl->registry, ®istry_listener, wl);
|
|
wl_display_dispatch(wl->remote_display);
|
|
wl_display_roundtrip(wl->remote_display);
|
|
|
|
if (!wl->compositor) {
|
|
wlr_log(WLR_ERROR,
|
|
"Remote Wayland compositor does not support wl_compositor");
|
|
goto error_registry;
|
|
}
|
|
if (!wl->shell) {
|
|
wlr_log(WLR_ERROR,
|
|
"Remote Wayland compositor does not support zxdg_shell_v6");
|
|
goto error_registry;
|
|
}
|
|
|
|
struct wl_event_loop *loop = wl_display_get_event_loop(wl->local_display);
|
|
int fd = wl_display_get_fd(wl->remote_display);
|
|
int events = WL_EVENT_READABLE | WL_EVENT_ERROR | WL_EVENT_HANGUP;
|
|
wl->remote_display_src = wl_event_loop_add_fd(loop, fd, events,
|
|
dispatch_events, wl);
|
|
if (!wl->remote_display_src) {
|
|
wlr_log(WLR_ERROR, "Failed to create event source");
|
|
goto error_registry;
|
|
}
|
|
wl_event_source_check(wl->remote_display_src);
|
|
|
|
static EGLint config_attribs[] = {
|
|
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
|
EGL_RED_SIZE, 1,
|
|
EGL_GREEN_SIZE, 1,
|
|
EGL_BLUE_SIZE, 1,
|
|
EGL_ALPHA_SIZE, 1,
|
|
EGL_NONE,
|
|
};
|
|
|
|
if (!create_renderer_func) {
|
|
create_renderer_func = wlr_renderer_autocreate;
|
|
}
|
|
|
|
wl->renderer = create_renderer_func(&wl->egl, EGL_PLATFORM_WAYLAND_EXT,
|
|
wl->remote_display, config_attribs, WL_SHM_FORMAT_ARGB8888);
|
|
|
|
if (!wl->renderer) {
|
|
wlr_log(WLR_ERROR, "Could not create renderer");
|
|
goto error_event;
|
|
}
|
|
|
|
wl->local_display_destroy.notify = handle_display_destroy;
|
|
wl_display_add_destroy_listener(display, &wl->local_display_destroy);
|
|
|
|
return &wl->backend;
|
|
|
|
error_event:
|
|
wl_event_source_remove(wl->remote_display_src);
|
|
error_registry:
|
|
if (wl->compositor) {
|
|
wl_compositor_destroy(wl->compositor);
|
|
}
|
|
if (wl->shell) {
|
|
zxdg_shell_v6_destroy(wl->shell);
|
|
}
|
|
wl_registry_destroy(wl->registry);
|
|
error_display:
|
|
wl_display_disconnect(wl->remote_display);
|
|
error_wl:
|
|
free(wl);
|
|
return NULL;
|
|
}
|