diff --git a/examples/embedded.c b/examples/embedded.c new file mode 100644 index 00000000..1bf11643 --- /dev/null +++ b/examples/embedded.c @@ -0,0 +1,184 @@ +#define _POSIX_C_SOURCE 200112L +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "egl_common.h" +#include "xdg-shell-client-protocol.h" + +static struct wl_display *remote_display = NULL; +static struct wl_compositor *compositor = NULL; +static struct wl_subcompositor *subcompositor = NULL; +static struct xdg_wm_base *wm_base = NULL; + +static struct wl_egl_window *egl_window = NULL; +static struct wlr_egl_surface *egl_surface = NULL; +static struct wl_surface *main_surface = NULL; +static struct wl_callback *frame_callback = NULL; + +static struct wlr_scene *scene = NULL; +static struct wlr_scene_output *scene_output = NULL; +static struct wl_listener new_surface = {0}; +static struct wl_listener output_frame = {0}; + +int width = 500; +int height = 500; + +static void draw_main_surface(void); + +static void frame_handle_done(void *data, struct wl_callback *callback, uint32_t t) { + wl_callback_destroy(callback); + frame_callback = NULL; + draw_main_surface(); +} + +static const struct wl_callback_listener frame_listener = { + .done = frame_handle_done, +}; + +static void draw_main_surface(void) { + frame_callback = wl_surface_frame(main_surface); + wl_callback_add_listener(frame_callback, &frame_listener, NULL); + + eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context); + eglSwapInterval(egl_display, 0); + + glViewport(0, 0, width, height); + glClearColor(1, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + + eglSwapBuffers(egl_display, egl_surface); + wl_display_flush(remote_display); +} + +static void xdg_surface_handle_configure(void *data, + struct xdg_surface *xdg_surface, uint32_t serial) { + xdg_surface_ack_configure(xdg_surface, serial); + if (frame_callback == NULL) { + draw_main_surface(); + } +} + +static const struct xdg_surface_listener xdg_surface_listener = { + .configure = xdg_surface_handle_configure, +}; + +static void xdg_toplevel_handle_configure(void *data, + struct xdg_toplevel *xdg_toplevel, int32_t w, int32_t h, + struct wl_array *states) { + if (w != 0 && h != 0) { + width = w; + height = h; + } +} + +static const struct xdg_toplevel_listener xdg_toplevel_listener = { + .configure = xdg_toplevel_handle_configure, +}; + +static void handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) { + if (strcmp(interface, wl_compositor_interface.name) == 0) { + compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 4); + } else if (strcmp(interface, wl_subcompositor_interface.name) == 0) { + subcompositor = wl_registry_bind(registry, name, &wl_subcompositor_interface, 1); + } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { + wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); + } +} + +static void handle_global_remove(void *data, struct wl_registry *registry, + uint32_t name) { + // Who cares? +} + +static const struct wl_registry_listener registry_listener = { + .global = handle_global, + .global_remove = handle_global_remove, +}; + +static void output_handle_frame(struct wl_listener *listener, void *data) { + wlr_scene_output_commit(scene_output, NULL); + + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + wlr_scene_output_send_frame_done(scene_output, &now); +} + +static void handle_new_surface(struct wl_listener *listener, void *data) { + struct wlr_surface *wlr_surface = data; + wlr_scene_surface_create(&scene->tree, wlr_surface); +} + +int main(int argc, char *argv[]) { + wlr_log_init(WLR_DEBUG, NULL); + + remote_display = wl_display_connect(NULL); + struct wl_registry *registry = wl_display_get_registry(remote_display); + wl_registry_add_listener(registry, ®istry_listener, NULL); + wl_display_roundtrip(remote_display); + + egl_init(remote_display); + + struct wl_display *local_display = wl_display_create(); + struct wlr_backend *backend = wlr_wl_backend_create(local_display, remote_display); + struct wlr_renderer *renderer = wlr_renderer_autocreate(backend); + wlr_renderer_init_wl_display(renderer, local_display); + struct wlr_allocator *allocator = wlr_allocator_autocreate(backend, renderer); + scene = wlr_scene_create(); + struct wlr_compositor *wlr_compositor = wlr_compositor_create(local_display, 5, renderer); + + wlr_xdg_shell_create(local_display, 2); + + new_surface.notify = handle_new_surface; + wl_signal_add(&wlr_compositor->events.new_surface, &new_surface); + + wlr_backend_start(backend); + + main_surface = wl_compositor_create_surface(compositor); + struct xdg_surface *xdg_surface = xdg_wm_base_get_xdg_surface(wm_base, main_surface); + struct xdg_toplevel *xdg_toplevel = xdg_surface_get_toplevel(xdg_surface); + xdg_surface_add_listener(xdg_surface, &xdg_surface_listener, NULL); + xdg_toplevel_add_listener(xdg_toplevel, &xdg_toplevel_listener, NULL); + + egl_window = wl_egl_window_create(main_surface, width, height); + egl_surface = eglCreatePlatformWindowSurfaceEXT(egl_display, + egl_config, egl_window, NULL); + + struct wl_surface *child_surface = wl_compositor_create_surface(compositor); + struct wl_subsurface *subsurface = wl_subcompositor_get_subsurface(subcompositor, child_surface, main_surface); + wl_subsurface_set_position(subsurface, 20, 20); + struct wlr_output *output = wlr_wl_output_create_from_surface(backend, child_surface); + wlr_output_init_render(output, allocator, renderer); + scene_output = wlr_scene_output_create(scene, output); + + output_frame.notify = output_handle_frame; + wl_signal_add(&output->events.frame, &output_frame); + + struct wlr_output_state state; + wlr_output_state_init(&state); + wlr_output_state_set_enabled(&state, true); + wlr_output_commit_state(output, &state); + wlr_output_state_finish(&state); + + wl_surface_commit(main_surface); + wl_display_flush(remote_display); + + const char *socket = wl_display_add_socket_auto(local_display); + setenv("WAYLAND_DISPLAY", socket, true); + wlr_log(WLR_INFO, "Running embedded Wayland compositor on WAYLAND_DISPLAY=%s", socket); + + wl_display_run(local_display); + + return 0; +} diff --git a/examples/meson.build b/examples/meson.build index f0ebad64..9fee0596 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -223,3 +223,14 @@ foreach name, info : clients build_by_default: get_option('examples'), ) endforeach + +executable( + 'embedded', + [ + 'embedded.c', + 'egl_common.c', + protocols_code['xdg-shell'], + protocols_client_header['xdg-shell'], + ], + dependencies: [wlroots, wayland_client, wayland_egl, egl, glesv2], +)