spkp

Stacking wayland compositor
git clone git://git.z3bra.org/sp:kp.git
Log | Files | Refs

commit 2e0eea982d5620cabeac0316a746210e025d2713
parent e92e912c7ee178d472aecde1434b0069cf4a3254
Author: Willy Goiffon <dev@z3bra.org>
Date:   Sun,  8 Nov 2020 11:34:02 +0100

Add xdg-shell protocol for client rendering

Diffstat:
Mcompositor.c | 150+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mconfig.mk | 4++--
Mmkfile | 14++++++++++----
3 files changed, 159 insertions(+), 9 deletions(-)

diff --git a/compositor.c b/compositor.c @@ -1,16 +1,23 @@ #include <assert.h> #include <stdio.h> #include <stdlib.h> +#include <time.h> #include <wayland-server.h> #include <wlr/backend.h> #include <wlr/render/wlr_renderer.h> -#include <wlr/types/wlr_output.h> -#include <wlr/types/wlr_idle.h> +#include <wlr/types/wlr_compositor.h> #include <wlr/types/wlr_data_control_v1.h> +#include <wlr/types/wlr_data_device.h> #include <wlr/types/wlr_gamma_control_v1.h> -#include <wlr/types/wlr_screencopy_v1.h> +#include <wlr/types/wlr_idle.h> +#include <wlr/types/wlr_matrix.h> +#include <wlr/types/wlr_output.h> #include <wlr/types/wlr_primary_selection_v1.h> +#include <wlr/types/wlr_screencopy_v1.h> +#include <wlr/types/wlr_xdg_shell.h> + +#include "xdg-shell-protocol.h" #include "arg.h" #include "config.h" @@ -21,10 +28,13 @@ struct state { struct wl_event_loop *evloop; struct wlr_backend *backend; struct wlr_renderer *renderer; + struct wlr_xdg_shell *shell; struct wl_listener new_output; + struct wl_listener new_window; struct wl_list outputs; + struct wl_list windows; }; /* compositor output */ @@ -34,17 +44,46 @@ struct output { struct wl_listener destroy; struct wl_listener frame; + struct wl_listener window; /* pointer to the next output */ struct wl_list link; }; +/* client surface window */ +struct window { + struct state *server; + struct wlr_xdg_surface *surface; + int mapped, x, y; + + struct wl_listener map; + struct wl_listener unmap; + struct wl_listener destroy; + + /* pointer to the next client */ + struct wl_list link; +}; + +struct rdata { + struct wlr_output *output; + struct window *window; + struct wlr_renderer *renderer; + struct timespec when; +}; + static void usage(char *); /* callback functions triggered when a new event occur */ static void cb_new_output(struct wl_listener *, void *); static void cb_destroy_output(struct wl_listener *, void *); static void cb_frame_output(struct wl_listener *, void *); +static void cb_new_window(struct wl_listener *, void *); + +static void cb_map_window(struct wl_listener *, void *); +static void cb_unmap_window(struct wl_listener *, void *); +static void cb_destroy_window(struct wl_listener *, void *); + +static void render(struct wlr_surface *, int, int, void *); void usage(char *pgm) @@ -123,6 +162,8 @@ void cb_frame_output(struct wl_listener *listener, void *data) { struct output *output; + struct window *window; + struct rdata rdata; struct wlr_output *wlr_output; struct wlr_renderer *renderer; @@ -143,6 +184,17 @@ cb_frame_output(struct wl_listener *listener, void *data) wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); wlr_renderer_clear(renderer, background); + wl_list_for_each_reverse(window, &output->server->windows, link) { + if (!window->mapped) + continue; + + rdata.output = wlr_output; + rdata.window = window; + rdata.renderer = renderer; + clock_gettime(CLOCK_MONOTONIC, &rdata.when); + wlr_xdg_surface_for_each_surface(window->surface, render, &rdata); + } + /* render cursor by software in case the GPU doesn't handle it */ wlr_output_render_software_cursors(wlr_output, NULL); @@ -151,6 +203,89 @@ cb_frame_output(struct wl_listener *listener, void *data) wlr_output_commit(wlr_output); } +/* + * A new application window (or view) is created. + */ +void +cb_new_window(struct wl_listener *listener, void *data) +{ + struct state *server; + struct wlr_xdg_surface *surface; + struct window *window; + + server = wl_container_of(listener, server, new_window); + surface = data; + + /* only register top level windows */ + if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) + return; + + window = calloc(1, sizeof(*window)); + window->server = server; + window->surface = surface; + + window->map.notify = cb_map_window; + window->unmap.notify = cb_unmap_window; + window->destroy.notify = cb_destroy_window; + + wl_signal_add(&surface->events.map, &window->map); + wl_signal_add(&surface->events.unmap, &window->unmap); + wl_signal_add(&surface->events.destroy, &window->destroy); + + wl_list_insert(&server->windows, &window->link); +} + +void +cb_map_window(struct wl_listener *listener, void *data) +{ + struct window *w; + + w = wl_container_of(listener, w, map); + w->mapped = 1; +} + +void +cb_unmap_window(struct wl_listener *listener, void *data) +{ + struct window *w; + + w = wl_container_of(listener, w, map); + w->mapped = 0; +} + +void +cb_destroy_window(struct wl_listener *listener, void *data) +{ +} + +void +render(struct wlr_surface *surface, int x, int y, void *data) +{ + float matrix[9]; + struct rdata *rdata; + struct window *window; + struct wlr_output *output; + struct wlr_texture *texture; + struct wlr_box box; + enum wl_output_transform transform; + + rdata = data; + window = rdata->window; + output = rdata->output; + + box.x = 0; + box.y = 0; + box.width = surface->current.width; + box.height = surface->current.height; + + texture = wlr_surface_get_texture(surface); + transform = wlr_output_transform_invert(surface->current.transform); + + wlr_matrix_project_box(matrix, &box, transform, 0, output->transform_matrix); + wlr_render_texture_with_matrix(rdata->renderer, texture, matrix, 1); + wlr_surface_send_frame_done(surface, &rdata->when); +} + int main(int argc, char *argv[]) { @@ -171,14 +306,23 @@ main(int argc, char *argv[]) server.backend = wlr_backend_autocreate(server.dpy, NULL); server.renderer = wlr_backend_get_renderer(server.backend); + server.shell = wlr_xdg_shell_create(server.dpy); wl_list_init(&server.outputs); + wl_list_init(&server.windows); + + wlr_compositor_create(server.dpy, server.renderer); + wlr_data_device_manager_create(server.dpy); server.new_output.notify = cb_new_output; + server.new_window.notify = cb_new_window; + wl_signal_add(&server.backend->events.new_output, &server.new_output); + wl_signal_add(&server.shell->events.new_surface, &server.new_window); socket = wl_display_add_socket_auto(server.dpy); setenv("WAYLAND_DISPLAY", socket, 1); + fprintf(stderr, "socket: %s\n", socket); if (!wlr_backend_start(server.backend)) { fprintf(stderr, "Failed to start backend\n"); diff --git a/config.mk b/config.mk @@ -7,6 +7,6 @@ MANDIR = ${PREFIX}/share/man CPPFLAGS = -DWLR_USE_UNSTABLE CFLAGS = -Wall -Wextra -pedantic -g LDFLAGS = -LIBS = -WL_CFLAGS = -I/usr/include/libdrm -I/usr/include/pixman-1 +WL_CFLAGS = -I./proto -I/usr/include/libdrm -I/usr/include/pixman-1 WL_LIBS = -lwlroots -lwayland-server -lpixman-1 +WL_PROTO = /usr/lib/wayland-protocols diff --git a/mkfile b/mkfile @@ -2,18 +2,24 @@ all:V: compositor -%: %.o - ${LD} ${LDFLAGS} $stem.o ${WL_LIBS} -o $stem +compositor: compositor.o proto/xdg-shell-protocol.o + ${LD} ${LDFLAGS} $prereq ${WL_LIBS} -o $target -compositor.o: config.h +compositor.o: config.h proto/xdg-shell-protocol.h %.o: %.c ${CC} ${CPPFLAGS} ${CFLAGS} ${WL_CFLAGS} -c $stem.c -o $stem.o config.h: config.def.h cp $prereq $target +proto/xdg-shell-protocol.c: ${WL_PROTO}/stable/xdg-shell/xdg-shell.xml + wayland-scanner public-code < $prereq > $target + +proto/xdg-shell-protocol.h: ${WL_PROTO}/stable/xdg-shell/xdg-shell.xml + wayland-scanner server-header < $prereq > $target + clean:V: - rm -f compositor *.o + rm -f compositor *.o proto/* install:V: compositor mkdir -p ${DESTDIR}${PREFIX}/bin