tAdd xdg-shell protocol for client rendering - spkp - Stacking wayland compositor
 (HTM) git clone git://git.z3bra.org/spkp.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
 (DIR) commit 2e0eea982d5620cabeac0316a746210e025d2713
 (DIR) parent e92e912c7ee178d472aecde1434b0069cf4a3254
 (HTM) Author: Willy Goiffon <dev@z3bra.org>
       Date:   Sun,  8 Nov 2020 11:34:02 +0100
       
       Add xdg-shell protocol for client rendering
       
       Diffstat:
         M compositor.c                        |     150 ++++++++++++++++++++++++++++++-
         M config.mk                           |       4 ++--
         M mkfile                              |      14 ++++++++++----
       
       3 files changed, 159 insertions(+), 9 deletions(-)
       ---
 (DIR) diff --git a/compositor.c b/compositor.c
       t@@ -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"
       t@@ -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 */
       t@@ -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)
       t@@ -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;
        
       t@@ -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);
        
       t@@ -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[])
        {
       t@@ -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");
 (DIR) diff --git a/config.mk b/config.mk
       t@@ -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
 (DIR) diff --git a/mkfile b/mkfile
       t@@ -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