~moody/drawterm

c9d5ac09c7b443242c81dde0fcd51db806a308d2 — Jacob Moody 3 months ago e65af5d
add wayland backend
6 files changed, 983 insertions(+), 0 deletions(-)

A Make.linux
A gui-wl/Makefile
A gui-wl/wl-cb.c
A gui-wl/wl-inc.h
A gui-wl/wl-screen.c
A gui-wl/wl-util.c
A Make.linux => Make.linux +22 -0
@@ 0,0 1,22 @@
# Unix
#PTHREAD=	# for Mac
PTHREAD=-pthread
AR=ar
AS=as
RANLIB=ranlib
CC=gcc
CFLAGS=-Wall -Wno-missing-braces -ggdb -I$(ROOT) -I$(ROOT)/include -I$(ROOT)/kern -c -D_THREAD_SAFE $(PTHREAD) -O2
O=o
OS=posix
GUI=wl
LDADD=-lwayland-client -lxkbcommon -ggdb -lm -lrt
LDFLAGS=$(PTHREAD)
TARG=drawterm
# AUDIO=none
AUDIO=unix

all: default

libmachdep.a:
	arch=`uname -m|sed 's/i.86/386/;s/Power Macintosh/power/; s/x86_64/amd64/; s/armv[567].*/arm/; s/aarch64/arm64/'`; \
	(cd posix-$$arch &&  make)

A gui-wl/Makefile => gui-wl/Makefile +36 -0
@@ 0,0 1,36 @@
ROOT=..
include ../Make.config
LIB=libgui.a

XDG_SHELL=/usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml
XDG_DECO=/usr/share/wayland-protocols/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml

HFILES=\
	xdg-shell-protocol.h\
	xdg-decoration-protocol.h\
	wl-inc.h\

OFILES=\
	xdg-shell-protocol.$O\
	xdg-decoration-protocol.$O\
	wl-cb.$O\
	wl-screen.$O\
	wl-util.$O\

xdg-shell-protocol.c:
	wayland-scanner private-code < $(XDG_SHELL) > xdg-shell-protocol.c

xdg-shell-protocol.h:
	wayland-scanner client-header < $(XDG_SHELL) > xdg-shell-protocol.h

xdg-decoration-protocol.c:
	wayland-scanner private-code < $(XDG_DECO) > xdg-decoration-protocol.c

xdg-decoration-protocol.h:
	wayland-scanner client-header < $(XDG_DECO) > xdg-decoration-protocol.h

default: $(LIB)
$(LIB): $(HFILES) $(OFILES)
	$(AR) r $(LIB) $(OFILES)
	$(RANLIB) $(LIB)


A gui-wl/wl-cb.c => gui-wl/wl-cb.c +493 -0
@@ 0,0 1,493 @@
#define _POSIX_C_SOURCE 200809L
#include <sys/mman.h>
#include <wayland-client.h>
#include <wayland-client-protocol.h>
#include <linux/input-event-codes.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <xkbcommon/xkbcommon.h>
#include "xdg-shell-protocol.h"
#include "xdg-decoration-protocol.h"

#include "u.h"
#include "lib.h"
#include "kern/dat.h"
#include "kern/fns.h"
#include "error.h"
#include "user.h"
#include <draw.h>
#include <memdraw.h>
#include <keyboard.h>
#include "screen.h"
#include "wl-inc.h"

#undef close
#undef send
#undef pipe
#undef write
#undef read

static void
xdg_surface_handle_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial)
{
	Wlwin *wl;

	wl = data;
	xdg_surface_ack_configure(xdg_surface, serial);
	wl_surface_commit(wl->surface);
}

const struct xdg_surface_listener xdg_surface_listener = {
	.configure = xdg_surface_handle_configure,
};

static void
xdg_toplevel_handle_close(void *data, struct xdg_toplevel *xdg_toplevel)
{
	Wlwin *wl;
	wl = data;
	wl->runing = 0;
	exits(nil);
}

static void
xdg_toplevel_handle_configure(void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, struct wl_array *states)
{
	Wlwin *wl;

	wl = data;
	if(width == 0 || height == 0 || (width == wl->dx && height == wl->dy))
		return;
	wlresize(wl, width, height);
}

const struct xdg_toplevel_listener xdg_toplevel_listener = {
	.configure = xdg_toplevel_handle_configure,
	.close = xdg_toplevel_handle_close,
};

static const struct wl_callback_listener wl_surface_frame_listener;

static void
wl_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time)
{
	Wlwin *wl;

	wl = data;
	wl_callback_destroy(cb);
	cb = wl_surface_frame(wl->surface);
	qlock(&drawlock);
	wlflush(wl);
	qunlock(&drawlock);
	wl_callback_add_listener(cb, &wl_surface_frame_listener, wl);
}

static void
keyboard_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size)
{
	static struct xkb_keymap *keymap = nil;
	char *keymap_string;
	Wlwin *wl;

	wl = data;
	keymap_string = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
	xkb_keymap_unref(keymap);
	keymap = xkb_keymap_new_from_string(wl->xkb_context, keymap_string, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
	munmap(keymap_string, size);
	close(fd);
	xkb_state_unref(wl->xkb_state);
	wl->xkb_state = xkb_state_new(keymap);
}

static void
keyboard_enter (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys)
{
	Wlwin *wl;

	wl = data;
	qlock(&wl->clip.lk);
	wl->clip.serial = serial;
	qunlock(&wl->clip.lk);
}

static void
keyboard_leave (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface)
{
}

static void
keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
{
	Wlwin *wl;
	uint32_t utf32;

	wl = data;
	xkb_keysym_t keysym = xkb_state_key_get_one_sym(wl->xkb_state, key+8);
	switch(keysym) {
	case XKB_KEY_Return:
		utf32 = '\n';
		break;
	case XKB_KEY_Tab:
		utf32 = '\t';
		break;
	default:
		utf32 = xkb_keysym_to_utf32(keysym);
		break;
	}
	if(xkb_state_mod_name_is_active(wl->xkb_state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_EFFECTIVE) > 0)
	if(utf32 >= 'a' && utf32 <= 'z')
		utf32 -= ('a' - 1);
	if(utf32){
		kbdkey(utf32, state);
	}
}

static void
keyboard_modifiers (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
{
	Wlwin *wl;

	wl = data;
	xkb_state_update_mask(wl->xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
}

static const struct wl_callback_listener wl_surface_frame_listener = {
	.done = wl_surface_frame_done,
};

static struct wl_keyboard_listener keyboard_listener = {
	&keyboard_keymap,
	&keyboard_enter,
	&keyboard_leave,
	&keyboard_key,
	&keyboard_modifiers
};

enum{
	WlMouse1 = 272,
	WlMouse2 = 274,
	WlMouse3 = 273,

	P9Mouse1 = 1,
	P9Mouse2 = 2,
	P9Mouse3 = 4,
};

static void
pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
{
	Wlwin *wl;

	wl = data;
	if(state)
		switch(button){
		case WlMouse1: /* M1 */
			wl->mouse.buttons |= P9Mouse1;
			break;
		case WlMouse2: /* M2 */
			wl->mouse.buttons |= P9Mouse2;
			break;
		case WlMouse3: /* M3 */
			wl->mouse.buttons |= P9Mouse3;
			break;
		}
	else
		switch(button){
		case WlMouse1: /* M1 */
			wl->mouse.buttons &= ~P9Mouse1;
			break;
		case WlMouse2: /* M2 */
			wl->mouse.buttons &= ~P9Mouse2;
			break;
		case WlMouse3: /* M3 */
			wl->mouse.buttons &= ~P9Mouse3;
			break;
		}

	wl->mouse.msec = time;
	absmousetrack(wl->mouse.xy.x, wl->mouse.xy.y, wl->mouse.buttons, wl->mouse.msec);
}

static void
pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
{
	Wlwin *wl;

	wl = data;
	wl->mouse.xy.x = surface_x / 256;
	wl->mouse.xy.y = surface_y / 256;
	wl->mouse.msec = time;
	absmousetrack(wl->mouse.xy.x, wl->mouse.xy.y, wl->mouse.buttons, wl->mouse.msec);
}

static void
pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y)
{
	Wlwin *wl;

	wl = data;
	wl->pointerserial = serial;
	wl_pointer_set_cursor(wl->pointer, wl->pointerserial, wl->cursorsurface, 0, 0);
}

static void
pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface)
{
}

static void
pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value)
{
	Wlwin *wl;
	int buttons;

	if(axis == 1)
		return; /* Horizontal scroll */
	wl = data;
	buttons = wl->mouse.buttons;
	if(value < 0){
		buttons |= 8;
	} else {
		buttons |= 16;
	}
	wl->mouse.msec = time;
	/* p9 expects a scroll event to work like a button, a set and a release */
	absmousetrack(wl->mouse.xy.x, wl->mouse.xy.y, buttons, wl->mouse.msec);
	absmousetrack(wl->mouse.xy.x, wl->mouse.xy.y, wl->mouse.buttons, wl->mouse.msec);
}

static const struct wl_pointer_listener pointer_listener = {
	.enter = pointer_handle_enter,
	.leave = pointer_handle_leave,
	.motion = pointer_handle_motion,
	.button = pointer_handle_button,
	.axis = pointer_handle_axis,
};

static void
seat_handle_capabilities(void *data, struct wl_seat *seat, uint32_t capabilities)
{
	Wlwin *wl;

	wl = data;
	if(capabilities & WL_SEAT_CAPABILITY_POINTER) {
		wl->pointer = wl_seat_get_pointer(seat);
		wl_pointer_add_listener(wl->pointer, &pointer_listener, wl);
	}
	if(capabilities & WL_SEAT_CAPABILITY_KEYBOARD) {
		struct wl_keyboard *keyboard = wl_seat_get_keyboard(seat);
		wl_keyboard_add_listener(keyboard, &keyboard_listener, wl);
	}
}

static const struct wl_seat_listener seat_listener = {
	.capabilities = seat_handle_capabilities,
};

static void
data_source_handle_send(void *data, struct wl_data_source *source, const char *mime_type, int fd)
{
	ulong n;
	ulong pos;
	ulong len;
	Wlwin *wl;

	if(strcmp(mime_type, "text/plain;charset=utf-8") != 0)
		return;

	wl = data;
	qlock(&wl->clip.lk);
	len = strlen(wl->clip.content);
	for(pos = 0; (n = write(fd, wl->clip.content+pos, len-pos)) > 0 && pos < len; pos += n)
		;
	wl->clip.posted = 0;
	close(fd);
	qunlock(&wl->clip.lk);
}

static void
data_source_handle_cancelled(void *data, struct wl_data_source *source)
{
	Wlwin *wl;

	wl = data;
	qlock(&wl->clip.lk);
	wl->clip.posted = 0;
	qunlock(&wl->clip.lk);
	wl_data_source_destroy(source);
}

static const struct wl_data_source_listener data_source_listener = {
	.send = data_source_handle_send,
	.cancelled = data_source_handle_cancelled,
};

static void
data_device_handle_data_offer(void *data, struct wl_data_device *data_device, struct wl_data_offer *offer)
{
}

static void
data_device_handle_selection(void *data, struct wl_data_device *data_device, struct wl_data_offer *offer)
{
	Wlwin *wl;
	ulong n;
	ulong size;
	ulong pos;
	int fds[2];

	// An application has set the clipboard contents
	if (offer == NULL) {
		return;
	}

	wl = data;
	pipe(fds);
	wl_data_offer_receive(offer, "text/plain;charset=utf-8", fds[1]);
	close(fds[1]);

	wl_display_roundtrip(wl->display);

	qlock(&wl->clip.lk);
	size = 8192;
	wl->clip.content = realloc(wl->clip.content, size+1);
	memset(wl->clip.content, 0, size+1);
	for(pos = 0; (n = read(fds[0], wl->clip.content+pos, size-pos)) > 0;){
		pos += n;
		if(pos >= size){
			size *= 2;
			wl->clip.content = realloc(wl->clip.content, size+1);
			memset(wl->clip.content+pos, 0, (size-pos)+1);
		}
	}
	close(fds[0]);
	qunlock(&wl->clip.lk);
	wl_data_offer_destroy(offer);
}

static const struct wl_data_device_listener data_device_listener = {
	.data_offer = data_device_handle_data_offer,
	.selection = data_device_handle_selection,
};

static void
xdg_wm_base_ping(void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
{
	xdg_wm_base_pong(xdg_wm_base, serial);
}

static const struct xdg_wm_base_listener xdg_wm_base_listener = {
	.ping = xdg_wm_base_ping,
};

static void
handle_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version)
{
	Wlwin *wl;

	wl = data;
	if(strcmp(interface, wl_shm_interface.name) == 0) {
		wl->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
	} else if(strcmp(interface, wl_seat_interface.name) == 0) {
		wl->seat = wl_registry_bind(registry, name, &wl_seat_interface, 1);
		wl_seat_add_listener(wl->seat, &seat_listener, wl);
	} else if(strcmp(interface, wl_compositor_interface.name) == 0) {
		wl->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 1);
	} else if(strcmp(interface, xdg_wm_base_interface.name) == 0) {
		wl->xdg_wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1);
		xdg_wm_base_add_listener(wl->xdg_wm_base, &xdg_wm_base_listener, wl);
	} else if(strcmp(interface, wl_data_device_manager_interface.name) == 0) {
		wl->data_device_manager = wl_registry_bind(registry, name, &wl_data_device_manager_interface, 3);
	} else if(strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) {
		wl->decoman = wl_registry_bind(registry, name, &zxdg_decoration_manager_v1_interface, 1);
	}
}

static void
handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
{
}

const struct wl_registry_listener registry_listener = {
	.global = handle_global,
	.global_remove = handle_global_remove,
};

void
wlsetcb(Wlwin *wl)
{
	struct wl_registry *registry;
	struct xdg_surface *xdg_surface;
	struct wl_callback *cb;
	struct zxdg_toplevel_decoration_v1 *deco;

	registry = wl_display_get_registry(wl->display);
	wl_registry_add_listener(registry, &registry_listener, wl);
	wl_display_roundtrip(wl->display);
	wl->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
	
	if(wl->shm == nil || wl->compositor == nil || wl->xdg_wm_base == nil || wl->seat == nil || wl->decoman == nil)
		sysfatal("Registration fell short");


	wl->data_device = wl_data_device_manager_get_data_device(wl->data_device_manager, wl->seat);
	wl_data_device_add_listener(wl->data_device, &data_device_listener, wl);
	wlallocbuffer(wl);
	wl->surface = wl_compositor_create_surface(wl->compositor);

	xdg_surface = xdg_wm_base_get_xdg_surface(wl->xdg_wm_base, wl->surface);
	wl->xdg_toplevel = xdg_surface_get_toplevel(xdg_surface);
	deco = zxdg_decoration_manager_v1_get_toplevel_decoration(wl->decoman, wl->xdg_toplevel);
	zxdg_toplevel_decoration_v1_set_mode(deco, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
	xdg_surface_add_listener(xdg_surface, &xdg_surface_listener, wl);
	xdg_toplevel_add_listener(wl->xdg_toplevel, &xdg_toplevel_listener, wl);

	wl_surface_commit(wl->surface);
	wl_display_roundtrip(wl->display);

	xdg_toplevel_set_app_id(wl->xdg_toplevel, "devdraw");

	cb = wl_surface_frame(wl->surface);
	wl_callback_add_listener(cb, &wl_surface_frame_listener, wl);
}

void
wlsettitle(Wlwin *wl, char *s)
{
	xdg_toplevel_set_title(wl->xdg_toplevel, s);
}

void
wlsetsnarf(Wlwin *wl, char *s)
{
	struct wl_data_source *source;

	qlock(&wl->clip.lk);
	if(wl->clip.content != nil)
		free(wl->clip.content);

	wl->clip.content = strdup(s);
	/* Do we still own the clipboard? */
	if(wl->clip.posted == 1)
		goto done;

	source = wl_data_device_manager_create_data_source(wl->data_device_manager);
	wl_data_source_add_listener(source, &data_source_listener, wl);
	wl_data_source_offer(source, "text/plain;charset=utf-8");
	wl_data_device_set_selection(wl->data_device, source, wl->clip.serial);
	wl->clip.posted = 1;
done:
	qunlock(&wl->clip.lk);
}

char*
wlgetsnarf(Wlwin *wl)
{
	char *s;
	qlock(&wl->clip.lk);
	s = strdup(wl->clip.content);
	qunlock(&wl->clip.lk);
	return s;
}

A gui-wl/wl-inc.h => gui-wl/wl-inc.h +78 -0
@@ 0,0 1,78 @@
typedef struct Wlwin Wlwin;
typedef struct Clipboard Clipboard;

/* The contents of the clipboard
 * are not stored in the compositor.
 * Instead we signal that we have content
 * and the compositor gives us a pipe
 * to the program that wants it when
 * the content is pasted. */
struct Clipboard {
	QLock lk;
	char *content;

	/* Wayland requires that in order
	 * to put data in to the clipboard
	 * you must be the focused application.
	 * So we must provide the serial we get
	 * on keyboard.enter. */
	u32int serial;

	/* Because we dont actually cough
	 * up the buffer until someone else
	 * asks, we can change the contents
	 * locally without a round trip.
	 * Posted stores if we already made
	 * our round trip */
	int posted;
};

struct Mouse {
	Point xy;
	int buttons;
	ulong msec;
};

struct Wlwin {
	int dx;
	int dy;
	int monx;
	int mony;
	Mouse mouse;
	Clipboard clip;
	int dirty;

	/* Wayland State */
	int runing;
	int poolsize;
	int pointerserial;
	void *shm_data;
	struct wl_compositor *compositor;
	struct wl_display *display;
	struct wl_surface *surface;
	struct wl_surface *cursorsurface;
	struct xdg_wm_base *xdg_wm_base;
	struct xdg_toplevel *xdg_toplevel;
	struct wl_shm_pool *pool;
	struct wl_buffer *screenbuffer;
	struct wl_buffer *cursorbuffer;
	struct wl_shm *shm;
	struct wl_seat *seat;
	struct wl_data_device_manager *data_device_manager;
	struct wl_data_device *data_device;
	struct wl_pointer *pointer;
	/* Keyboard state */
	struct xkb_state *xkb_state;
	struct xkb_context *xkb_context;

	struct zxdg_decoration_manager_v1 *decoman;
};

void wlallocbuffer(Wlwin*);
void wlsetcb(Wlwin*);
void wlsettitle(Wlwin*, char*);
char* wlgetsnarf(Wlwin*);
void wlsetsnarf(Wlwin*, char*);
void wldrawcursor(Wlwin*, Cursorinfo*);
void wlresize(Wlwin*, int, int);
void wlflush(Wlwin*);

A gui-wl/wl-screen.c => gui-wl/wl-screen.c +201 -0
@@ 0,0 1,201 @@
#define _POSIX_C_SOURCE 200809L
#include <sys/mman.h>
#include <wayland-client.h>
#include <wayland-client-protocol.h>
#include <linux/input-event-codes.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <xkbcommon/xkbcommon.h>
#include "xdg-shell-protocol.h"

#include "u.h"
#include "lib.h"
#include "kern/dat.h"
#include "kern/fns.h"
#include "error.h"
#include "user.h"
#include <draw.h>
#include <memdraw.h>
#include <keyboard.h>
#include <cursor.h>
#include "screen.h"
#include "wl-inc.h"

#undef close

static Wlwin *snarfwin;

static int clientruning;

Memimage *gscreen;

static Wlwin*
newwlwin(void)
{
	Wlwin *wl;

	wl = mallocz(sizeof *wl, 1);
	if(wl == nil)
		sysfatal("malloc Wlwin");
	wl->dx = 1024;
	wl->dy = 1024;
	wl->monx = 1920;
	wl->mony = 1080;
	return wl;
}

void
wlflush(Wlwin *wl)
{
	if(wl->dirty == 1)
		memcpy(wl->shm_data, gscreen->data->bdata, wl->dx*wl->dy*4);

	wl_surface_attach(wl->surface, wl->screenbuffer, 0, 0);
	wl_surface_damage(wl->surface, 0, 0, wl->dx, wl->dy);
	wl_surface_commit(wl->surface);
	wl->dirty = 0;
}

void
wlresize(Wlwin *wl, int x, int y)
{
	Rectangle r;

	wl->dx = x;
	wl->dy = y;

	qlock(&drawlock);
	wlallocbuffer(wl);
	r = Rect(0, 0, wl->dx, wl->dy);
	gscreen = allocmemimage(r, XRGB32);
	gscreen->clipr = ZR;
	qunlock(&drawlock);

	screenresize(r);

	qlock(&drawlock);
	wl->dirty = 1;
	wlflush(wl);
	qunlock(&drawlock);
}

void
dispatchproc(void *a)
{
	Wlwin *wl;
	wl = a;
	for(;wl->runing == 1;){
		wl_display_dispatch(wl->display);
	}
}

static Wlwin*
wlattach(char *label)
{
	Rectangle r;
	Wlwin *wl;

	wl = newwlwin();
	snarfwin = wl;
	wl->display = wl_display_connect(NULL);
	if(wl->display == nil)
		sysfatal("could not connect to display");

	memimageinit();
	wlsetcb(wl);
	wlflush(wl);
	wlsettitle(wl, label);

	r = Rect(0, 0, wl->dx, wl->dy);
	gscreen = allocmemimage(r, XRGB32);
	gscreen->clipr = r;
	gscreen->r = r;
	rectclip(&(gscreen->clipr), gscreen->r);

	wldrawcursor(wl, &arrow);
	wl->runing = 1;
	kproc("wldispatch", dispatchproc, wl);
	terminit();
	wlflush(wl);
	return wl;
}

void
screeninit(void)
{
	wlattach("drawterm");
}

void
guimain(void)
{
	cpubody();
}

Memdata*
attachscreen(Rectangle *r, ulong *chan, int *depth, int *width, int *softscreen)
{
	Wlwin *wl;

	wl = snarfwin;
	*r = gscreen->clipr;
	*chan = gscreen->chan;
	*depth = gscreen->depth;
	*width = gscreen->width;
	*softscreen = 1;

	gscreen->data->ref++;
	return gscreen->data;
}

void
flushmemscreen(Rectangle r)
{
	Wlwin *wl;

	wl = snarfwin;
	wl->dirty = 1;
	wlflush(wl);
}

void
screensize(Rectangle r, ulong chan)
{
	snarfwin->dirty = 1;
}

void
setcursor(void)
{
	wldrawcursor(snarfwin, &cursor);
}

void
mouseset(Point p)
{
}

char*
clipread(void)
{
	return wlgetsnarf(snarfwin);
}

int
clipwrite(char *data)
{
	wlsetsnarf(snarfwin, data);
	return strlen(data);
}

void
getcolor(ulong i, ulong *r, ulong *g, ulong *b)
{
}

void
setcolor(ulong index, ulong red, ulong green, ulong blue)
{
}

A gui-wl/wl-util.c => gui-wl/wl-util.c +153 -0
@@ 0,0 1,153 @@
#define _POSIX_C_SOURCE 200809L
#include <sys/mman.h>
#include <wayland-client.h>
#include <wayland-client-protocol.h>
#include <linux/input-event-codes.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <xkbcommon/xkbcommon.h>
#include "xdg-shell-protocol.h"

#include "u.h"
#include "lib.h"
#include "kern/dat.h"
#include "kern/fns.h"
#include "error.h"
#include "user.h"
#include <draw.h>
#include <memdraw.h>
#include <keyboard.h>
#include <cursor.h>
#include "screen.h"
#include "wl-inc.h"

#undef close

static void
randname(char *buf)
{
	struct timespec ts;
	int i;

	clock_gettime(CLOCK_REALTIME, &ts);
	long r = ts.tv_nsec;
	for(i=0; i < 6; i++) {
		buf[i] = 'A'+(r&15)+(r+16)*2;
		r >>= 5;
	}
}

static int
wlcreateshm(off_t size)
{
	char name[] = "/devdraw--XXXXXX";
	int retries = 100;
	int fd;

	do {
		randname(name + strlen(name) - 6);
		--retries;
		fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
		if(fd >= 0){
			shm_unlink(name);
			if(ftruncate(fd, size) < 0){
				close(fd);
				return -1;
			}
			return fd;
		}
	} while (retries > 0 && errno == EEXIST);
	return -1;
}

void
wlallocpool(Wlwin *wl)
{
	int screenx, screeny;
	int screensize, cursorsize;
	int depth;
	int fd;

	if(wl->pool != nil)
		wl_shm_pool_destroy(wl->pool);

	depth = 4;
	screenx = wl->dx > wl->monx ? wl->dx : wl->monx;
	screeny = wl->dy > wl->mony ? wl->dy : wl->mony;
	screensize = screenx * screeny * depth;
	cursorsize = 16 * 16 * depth;

	fd = wlcreateshm(screensize+cursorsize);
	if(fd < 0)
		sysfatal("could not mk_shm_fd");

	wl->shm_data = mmap(nil, screensize+cursorsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
	if(wl->shm_data == MAP_FAILED)
		sysfatal("could not mmap shm_data");

	wl->pool = wl_shm_create_pool(wl->shm, fd, screensize+cursorsize);
	wl->poolsize = screensize+cursorsize;
	close(fd);
}

void
wlallocbuffer(Wlwin *wl)
{
	int depth;
	int size;

	depth = 4;
	size = wl->dx * wl->dy * depth;
	if(wl->pool == nil || size+(16*16*depth) > wl->poolsize)
		wlallocpool(wl);

	if(wl->screenbuffer != nil)
		wl_buffer_destroy(wl->screenbuffer);
	if(wl->cursorbuffer != nil)
		wl_buffer_destroy(wl->cursorbuffer);

	wl->screenbuffer = wl_shm_pool_create_buffer(wl->pool, 0, wl->dx, wl->dy, wl->dx*4, WL_SHM_FORMAT_XRGB8888);
	wl->cursorbuffer = wl_shm_pool_create_buffer(wl->pool, size, 16, 16, 16*4, WL_SHM_FORMAT_ARGB8888);
}

static enum {
	White = 0xFFFFFFFF,
	Black = 0xFF000000,
	Green = 0xFF00FF00,
	Transparent = 0x00000000,
};

void
wldrawcursor(Wlwin *wl, Cursorinfo *c)
{
	int i, j;
	int pos, mask;
	u32int *buf;
	uint16_t clr[16], set[16];

	buf = wl->shm_data+(wl->dx*wl->dy*4);
	for(i=0,j=0; i < 16; i++,j+=2){
		clr[i] = c->clr[j]<<8 | c->clr[j+1];
		set[i] = c->set[j]<<8 | c->set[j+1];
	}
	for(i=0; i < 16; i++){
		for(j = 0; j < 16; j++){
			pos = i*16 + j;
			mask = (1<<16) >> j;

			buf[pos] = Transparent;
			if(clr[i] & mask)
				buf[pos] = White;
			if(set[i] & mask)
				buf[pos] = Black;
		}
	}
	if(wl->cursorsurface != nil)
		wl_surface_destroy(wl->cursorsurface);
	wl->cursorsurface = wl_compositor_create_surface(wl->compositor);
	wl_surface_attach(wl->cursorsurface, wl->cursorbuffer, 0, 0);
	wl_surface_commit(wl->cursorsurface);
	wl_pointer_set_cursor(wl->pointer, wl->pointerserial, wl->cursorsurface, 0, 0);
}