tInitial Compositor skeleton - spkp - Stacking wayland compositor
 (HTM) git clone git://git.z3bra.org/spkp.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
 (DIR) commit 44185c5c8a0c3d205c90a8ca42a5ab899b71a7a8
 (HTM) Author: Willy Goiffon <dev@z3bra.org>
       Date:   Sat,  7 Nov 2020 11:50:20 +0100
       
       Initial Compositor skeleton
       
       Diffstat:
         A arg.h                               |      65 +++++++++++++++++++++++++++++++
         A compositor.c                        |     213 +++++++++++++++++++++++++++++++
         A config.def.h                        |       1 +
         A config.mk                           |      12 ++++++++++++
         A mkfile                              |      24 ++++++++++++++++++++++++
       
       5 files changed, 315 insertions(+), 0 deletions(-)
       ---
 (DIR) diff --git a/arg.h b/arg.h
       t@@ -0,0 +1,65 @@
       +/*
       + * Copy me if you can.
       + * by 20h
       + */
       +
       +#ifndef ARG_H__
       +#define ARG_H__
       +
       +extern char *argv0;
       +
       +/* use main(int argc, char *argv[]) */
       +#define ARGBEGIN        for (argv0 = *argv, argv++, argc--;\
       +                                        argv[0] && argv[0][1]\
       +                                        && argv[0][0] == '-';\
       +                                        argc--, argv++) {\
       +                                char argc_;\
       +                                char **argv_;\
       +                                int brk_;\
       +                                if (argv[0][1] == '-' && argv[0][2] == '\0') {\
       +                                        argv++;\
       +                                        argc--;\
       +                                        break;\
       +                                }\
       +                                for (brk_ = 0, argv[0]++, argv_ = argv;\
       +                                                argv[0][0] && !brk_;\
       +                                                argv[0]++) {\
       +                                        if (argv_ != argv)\
       +                                                break;\
       +                                        argc_ = argv[0][0];\
       +                                        switch (argc_)
       +
       +/* Handles obsolete -NUM syntax */
       +#define ARGNUM                                case '0':\
       +                                        case '1':\
       +                                        case '2':\
       +                                        case '3':\
       +                                        case '4':\
       +                                        case '5':\
       +                                        case '6':\
       +                                        case '7':\
       +                                        case '8':\
       +                                        case '9'
       +
       +#define ARGEND                        }\
       +                        }
       +
       +#define ARGC()                argc_
       +
       +#define ARGNUMF()        (brk_ = 1, estrtonum(argv[0], 0, INT_MAX))
       +
       +#define EARGF(x)        ((argv[0][1] == '\0' && argv[1] == NULL)?\
       +                                ((x), abort(), (char *)0) :\
       +                                (brk_ = 1, (argv[0][1] != '\0')?\
       +                                        (&argv[0][1]) :\
       +                                        (argc--, argv++, argv[0])))
       +
       +#define ARGF()                ((argv[0][1] == '\0' && argv[1] == NULL)?\
       +                                (char *)0 :\
       +                                (brk_ = 1, (argv[0][1] != '\0')?\
       +                                        (&argv[0][1]) :\
       +                                        (argc--, argv++, argv[0])))
       +
       +#define LNGARG()        &argv[0][0]
       +
       +#endif
 (DIR) diff --git a/compositor.c b/compositor.c
       t@@ -0,0 +1,213 @@
       +#include <assert.h>
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <wayland-server.h>
       +#include <wlr/backend.h>
       +#include <wlr/render/egl.h>
       +#include <wlr/render/wlr_renderer.h>
       +#include <wlr/types/wlr_output.h>
       +#include <wlr/types/wlr_output_damage.h>
       +
       +#include <wlr/types/wlr_idle.h>
       +#include <wlr/types/wlr_data_control_v1.h>
       +#include <wlr/types/wlr_gamma_control_v1.h>
       +#include <wlr/types/wlr_screencopy_v1.h>
       +#include <wlr/types/wlr_primary_selection_v1.h>
       +
       +#include "arg.h"
       +#include "config.h"
       +
       +/* keep track of internal compositor state */
       +struct state {
       +        struct wl_display *dpy;
       +        struct wl_event_loop *evloop;
       +        struct wlr_backend *backend;
       +        struct wl_listener new_output;
       +        struct wl_list outputs;
       +};
       +
       +/* compositor output */
       +struct output {
       +        struct state *server; /* pointer to the containing struct */
       +
       +        struct wlr_output *wlr_output;
       +        struct wlr_output_damage *damage;
       +
       +        struct wl_listener destroy;
       +        struct wl_listener damage_frame;
       +
       +        /* pointer to the next output */
       +        struct wl_list link;
       +};
       +
       +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_damage_frame(struct wl_listener *, void *);
       +
       +void
       +usage(char *pgm)
       +{
       +        fprintf(stderr, "usage: %s [-h]\n", pgm);
       +}
       +
       +/*
       + * Triggered whenever a new output (eg, monitor) is connected to the
       + * compositor. This output is configured (set "mode" if needed) and
       + * added to the outputs list.
       + * Listeners are setup on this output for when stuff needs to get
       + * rendered, or when output is disconnected.
       + */
       +void
       +cb_new_output(struct wl_listener *listener, void *data)
       +{
       +        struct state *server;
       +        struct output *output;
       +        struct wlr_output *wlr_output;
       +        struct wlr_output_mode *mode;
       +
       +        server = wl_container_of(listener, server, new_output);
       +        wlr_output = data;
       +
       +        /*
       +         * Configure output mode when advertized. This is only needed
       +         * for DRM backend, as other backends don't have such thing as an
       +         * "output" or "mode". They simply run within a window, and thus
       +         * have nothing to configure on their own.
       +         */
       +        if (!wl_list_empty(&wlr_output->modes)) {
       +                mode = wl_container_of(wlr_output->modes.prev, mode, link);
       +                wlr_output_set_mode(wlr_output, mode);
       +        }
       +
       +        output = calloc(1, sizeof(*output));
       +        output->server = server;
       +        output->wlr_output = wlr_output;
       +        output->damage = wlr_output_damage_create(wlr_output);
       +
       +        wl_list_insert(&server->outputs, &output->link);
       +
       +        /* setup callbacks for our output */
       +        output->destroy.notify = cb_destroy_output;
       +        output->damage_frame.notify = cb_damage_frame;
       +
       +        /* setup signals for above notifies */
       +        wl_signal_add(&wlr_output->events.destroy, &output->destroy);
       +        wl_signal_add(&output->damage->events.frame, &output->damage_frame);
       +
       +        wlr_output_create_global(wlr_output);
       +}
       +
       +/*
       + * Output gets disconnected. Remove it from the list and release memory
       + */
       +void
       +cb_destroy_output(struct wl_listener *listener, void *data)
       +{
       +        struct output *output;
       +
       +        output = wl_container_of(listener, output, destroy);
       +
       +        wl_list_remove(&output->link);
       +        wl_list_remove(&output->destroy.link);
       +        wl_list_remove(&output->damage_frame.link);
       +
       +        free(output);
       +}
       +
       +/*
       + * Output frame buffer was modified (damaged) since last render. Compute
       + * the new buffer for rendering.
       + */
       +void
       +cb_damage_frame(struct wl_listener *listener, void *data)
       +{
       +        bool needs_frame;
       +        struct output *output;
       +        struct wlr_output *wlr_output;
       +        struct wlr_renderer *renderer;
       +        pixman_region32_t damage;
       +
       +        output = wl_container_of(listener, output, damage_frame);
       +        wlr_output = output->wlr_output;
       +
       +        if (!wlr_output->enabled)
       +                return;
       +
       +        renderer = wlr_backend_get_renderer(wlr_output->backend);
       +
       +        /* create a damage buffer to render our frame */
       +        pixman_region32_init(&damage);
       +        wlr_output_damage_attach_render(output->damage, &needs_frame, &damage);
       +
       +        if (!needs_frame) {
       +                wlr_output_rollback(wlr_output);
       +                pixman_region32_fini(&damage);
       +                return;
       +        }
       +
       +        /* paint surface with the background color */
       +        wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
       +        wlr_renderer_clear(renderer, background);
       +        wlr_renderer_end(renderer);
       +
       +        /* apply damaged region on-screen */
       +        wlr_output_set_damage(wlr_output, &damage);
       +        pixman_region32_fini(&damage);
       +
       +        /* commit output, if needed */
       +        wlr_output_commit(wlr_output);
       +}
       +
       +int
       +main(int argc, char *argv[])
       +{
       +        char *argv0;
       +        const char *socket;
       +        struct state server;
       +
       +        ARGBEGIN {
       +        case 'h':
       +        default:
       +                usage(argv0);
       +                return -1;
       +                break; /* NOTREACHED */
       +        } ARGEND;
       +
       +        server.dpy = wl_display_create();
       +        assert(server.dpy);
       +        server.evloop = wl_display_get_event_loop(server.dpy);
       +        assert(server.evloop);
       +
       +        server.backend = wlr_backend_autocreate(server.dpy, NULL);
       +        assert(server.backend);
       +
       +        wl_list_init(&server.outputs);
       +
       +        server.new_output.notify = cb_new_output;
       +        wl_signal_add(&server.backend->events.new_output, &server.new_output);
       +
       +        socket = wl_display_add_socket_auto(server.dpy);
       +        assert(socket);
       +
       +        if (!wlr_backend_start(server.backend)) {
       +                fprintf(stderr, "Failed to start backend\n");
       +                wl_display_destroy(server.dpy);
       +                return -1;
       +        }
       +
       +        /* all these interfaces are managed internally by wlroots */
       +        wl_display_init_shm(server.dpy);
       +        wlr_gamma_control_manager_v1_create(server.dpy);
       +        wlr_screencopy_manager_v1_create(server.dpy);
       +        wlr_primary_selection_v1_device_manager_create(server.dpy);
       +        wlr_idle_create(server.dpy);
       +
       +        /* trigger internal event loop */
       +        wl_display_run(server.dpy);
       +        wl_display_destroy(server.dpy);
       +
       +        return 0;
       +}
 (DIR) diff --git a/config.def.h b/config.def.h
       t@@ -0,0 +1 @@
       +float background[4] = { 1.0, 0.6, 0.6, 0.3 };
 (DIR) diff --git a/config.mk b/config.mk
       t@@ -0,0 +1,12 @@
       +CC = cc
       +LD = ${CC}
       +
       +PREFIX = /usr/local
       +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_LIBS = -lwlroots -lwayland-server -lpixman-1
 (DIR) diff --git a/mkfile b/mkfile
       t@@ -0,0 +1,24 @@
       +<config.mk
       +
       +all:V: compositor
       +
       +%: %.o
       +        ${LD} ${LDFLAGS} $stem.o ${WL_LIBS} -o $stem
       +
       +compositor.o: config.h
       +%.o: %.c
       +        ${CC} ${CPPFLAGS} ${CFLAGS} ${WL_CFLAGS} -c $stem.c -o $stem.o
       +
       +config.h: config.def.h
       +        cp $prereq $target
       +
       +clean:V:
       +        rm -f compositor *.o
       +
       +install:V: compositor
       +        mkdir -p ${DESTDIR}${PREFIX}/bin
       +        cp compositor ${DESTDIR}${PREFIX}/bin/compositor
       +        chmod 755 ${DESTDIR}${PREFIX}/bin/compositor
       +
       +uninstall:V:
       +        rm ${DESTDIR}${PREFIX}/bin/compositor