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