9front - general discussion about 9front
 help / color / mirror / Atom feed
* [9front] [drawterm] Wayland support and misc patches
@ 2021-10-14  1:59 Jacob Moody
  2021-10-15  2:22 ` Stanley Lieber
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Jacob Moody @ 2021-10-14  1:59 UTC (permalink / raw)
  To: 9front

[-- Attachment #1: Type: text/plain, Size: 1056 bytes --]

Hello,

I've written a wayland graphical backend for drawterm and have been dogfooding it for
a little bit now. I think most of the larger bugs have been worked out of it.
There is also a patch for adding pipewire support for devaudio.
For both of these there is a patch for adding a CONF=linux target

While working on these I found that there is code in libc/ that expects
to be compiled with -DPTHREAD to avoid resorting to spin locks.
I think we might want to add -DPTHREAD to the unix target CFLAGS.
However adding the define on my machine caused gcc to get confused about
the ordering of the members for kern/devmouse.c:/^Cursorinfo\tarrow/
There is a patch that specifies the members, which seemed to fix the issue. But I am sure what is causing this.

Also I am not sure why there was a sleep within the kern/term.c:/^resizeproc/ loop, but I noticed the delay
when working on the wayland backend. There is a patch for removing that sleep.

Not sure which, if any, of these are desirable to have upstream but wanted to offer them up.


Thanks,
moody

[-- Attachment #2: drawterm-wl.patch --]
[-- Type: text/x-patch, Size: 25298 bytes --]

diff --git a/gui-wl/Makefile b/gui-wl/Makefile
new file mode 100644
index 0000000..bc15a51
--- /dev/null
+++ b/gui-wl/Makefile
@@ -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)
+
diff --git a/gui-wl/wl-cb.c b/gui-wl/wl-cb.c
new file mode 100644
index 0000000..e50cf05
--- /dev/null
+++ b/gui-wl/wl-cb.c
@@ -0,0 +1,583 @@
+#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 struct {
+	Rendez z;
+	QLock lk;
+	int active;
+	long keytime;
+	int32_t key;
+	int32_t rate;
+	int32_t delay;
+} repeatstate;
+
+static int
+isactive(void *arg)
+{
+	return repeatstate.active;
+}
+
+void
+repeatproc(void*)
+{
+	int ms;
+	long keytime;
+
+	for(;;){
+		ksleep(&repeatstate.z, isactive, 0);
+		qlock(&repeatstate.lk);
+		keytime = repeatstate.keytime;
+		qunlock(&repeatstate.lk);
+		osmsleep(repeatstate.delay);
+
+repeat:
+		qlock(&repeatstate.lk);
+		if(repeatstate.active == 0 || keytime != repeatstate.keytime){
+			qunlock(&repeatstate.lk);
+			continue;
+		}
+		ms = 1000/repeatstate.rate;
+		kbdkey(repeatstate.key, 0);
+		kbdkey(repeatstate.key, 1);
+		qunlock(&repeatstate.lk);
+		osmsleep(ms);
+		goto repeat;
+	}
+}
+
+static void
+keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay)
+{
+	qlock(&repeatstate.lk);
+	repeatstate.rate = rate;
+	repeatstate.delay = delay;
+	qunlock(&repeatstate.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;
+	case XKB_KEY_Up:
+		utf32 = Kup;
+		break;
+	case XKB_KEY_Down:
+		utf32 = Kdown;
+		break;
+	case XKB_KEY_Left:
+		utf32 = Kleft;
+		break;
+	case XKB_KEY_Right:
+		utf32 = Kright;
+		break;
+	default:
+		utf32 = xkb_keysym_to_utf32(keysym);
+		break;
+	}
+	if(utf32 == 0)
+		return;
+
+	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);
+
+	kbdkey(utf32, state);
+	qlock(&repeatstate.lk);
+	repeatstate.active = state;
+	repeatstate.keytime = time;
+	repeatstate.key = utf32;
+	qunlock(&repeatstate.lk);
+	wakeup(&repeatstate.z);
+}
+
+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 = {
+	.keymap = keyboard_keymap,
+	.enter = keyboard_enter,
+	.leave = keyboard_leave,
+	.key = keyboard_key,
+	.modifiers = keyboard_modifiers,
+	.repeat_info = keyboard_repeat_info,
+};
+
+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;
+	if(wl->cursorsurface == nil)
+		return;
+	wl_pointer_set_cursor(wl->pointer, wl->pointerserial, wl->cursorsurface, -cursor.offset.x, -cursor.offset.y);
+}
+
+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 void
+seat_handle_name(void *data, struct wl_seat *seat, const char *name)
+{
+
+}
+
+static const struct wl_seat_listener seat_listener = {
+	.capabilities = seat_handle_capabilities,
+	.name = seat_handle_name,
+};
+
+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, 4);
+		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;
+
+	//Wayland doesn't do keyboard repeat, but also may
+	//not tell us what the user would like, so we
+	//pick some sane defaults.
+	repeatstate.delay = 200;
+	repeatstate.rate = 20;
+	kproc("keyboard repeat", repeatproc, 0);
+
+	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, "drawterm");
+
+	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;
+}
diff --git a/gui-wl/wl-inc.h b/gui-wl/wl-inc.h
new file mode 100644
index 0000000..ea056b5
--- /dev/null
+++ b/gui-wl/wl-inc.h
@@ -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*);
diff --git a/gui-wl/wl-screen.c b/gui-wl/wl-screen.c
new file mode 100644
index 0000000..c5f322d
--- /dev/null
+++ b/gui-wl/wl-screen.c
@@ -0,0 +1,199 @@
+#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 *gwin;
+
+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();
+	gwin = 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);
+
+	wl->runing = 1;
+	kproc("wldispatch", dispatchproc, wl);
+	terminit();
+	qlock(&drawlock);
+	wlflush(wl);
+	qunlock(&drawlock);
+	return wl;
+}
+
+void
+screeninit(void)
+{
+	wlattach("drawterm");
+}
+
+void
+guimain(void)
+{
+	cpubody();
+}
+
+Memdata*
+attachscreen(Rectangle *r, ulong *chan, int *depth, int *width, int *softscreen)
+{
+	*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 = gwin;
+	wl->dirty = 1;
+	wlflush(wl);
+}
+
+void
+screensize(Rectangle r, ulong chan)
+{
+	gwin->dirty = 1;
+}
+
+void
+setcursor(void)
+{
+	qlock(&drawlock);
+	wldrawcursor(gwin, &cursor);
+	qunlock(&drawlock);
+}
+
+void
+mouseset(Point p)
+{
+}
+
+char*
+clipread(void)
+{
+	return wlgetsnarf(gwin);
+}
+
+int
+clipwrite(char *data)
+{
+	wlsetsnarf(gwin, data);
+	return strlen(data);
+}
+
+void
+getcolor(ulong i, ulong *r, ulong *g, ulong *b)
+{
+}
+
+void
+setcolor(ulong index, ulong red, ulong green, ulong blue)
+{
+}
diff --git a/gui-wl/wl-util.c b/gui-wl/wl-util.c
new file mode 100644
index 0000000..47e0b45
--- /dev/null
+++ b/gui-wl/wl-util.c
@@ -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[] = "/drawterm--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);
+}
+
+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, -c->offset.x, -c->offset.y);
+}

[-- Attachment #3: drawterm-pipweireaudio.patch --]
[-- Type: text/x-patch, Size: 3611 bytes --]

diff --git a/kern/devaudio-pipewire.c b/kern/devaudio-pipewire.c
new file mode 100644
index 0000000..7d754fb
--- /dev/null
+++ b/kern/devaudio-pipewire.c
@@ -0,0 +1,177 @@
+#include	"u.h"
+#include	"lib.h"
+#include	"dat.h"
+#include	"fns.h"
+#include	"error.h"
+#include	"devaudio.h"
+
+#undef long
+#include <pipewire/pipewire.h>
+#include <spa/param/audio/format-utils.h>
+
+static struct {
+	Lock lk;
+	Rendez z;
+	int init;
+	struct pw_main_loop *loop;
+	struct pw_stream *output;
+
+	char buf[8192];
+	int written; /* 0 means empty buffer */
+} pwstate;
+
+static char *argv[] = { "drawterm" };
+static int argc = 1;
+
+static void
+on_process(void *data)
+{
+	struct pw_buffer *b;
+	struct spa_buffer *buf;
+	int16_t *dst;
+
+	lock(&pwstate.lk);
+	if(pwstate.written == 0){
+		unlock(&pwstate.lk);
+		return;
+	}
+	b = pw_stream_dequeue_buffer(pwstate.output);
+
+	buf = b->buffer;
+	dst = buf->datas[0].data;
+
+	memcpy(dst, pwstate.buf, pwstate.written);
+	buf->datas[0].chunk->offset = 0;
+	buf->datas[0].chunk->stride = sizeof(int16_t) * 2;
+	buf->datas[0].chunk->size = pwstate.written;
+
+	pw_stream_queue_buffer(pwstate.output, b);
+	pwstate.written = 0;
+	unlock(&pwstate.lk);
+	wakeup(&pwstate.z);
+}
+
+static const struct pw_stream_events stream_events = {
+	PW_VERSION_STREAM_EVENTS,
+	.process = on_process,
+};
+
+static void
+pwproc(void *arg)
+{
+	struct pw_main_loop *loop;
+
+	loop = arg;
+	pw_main_loop_run(loop);
+}
+
+void
+audiodevopen(void)
+{
+	const struct spa_pod *params[1];
+	struct spa_pod_builder b = SPA_POD_BUILDER_INIT(pwstate.buf, sizeof(pwstate.buf));
+	int err;
+
+	lock(&pwstate.lk);
+	if(pwstate.init > 0){
+		kproc("pipewire main loop", pwproc, pwstate.loop);
+		unlock(&pwstate.lk);
+		return;
+	}
+
+	pwstate.init++;
+	pw_init(&argc, (char***)&argv);
+	pwstate.loop = pw_main_loop_new(NULL);
+	if(pwstate.loop == NULL)
+		sysfatal("could not create loop");
+	pwstate.output = pw_stream_new_simple(
+		pw_main_loop_get_loop(pwstate.loop),
+		"drawterm",
+		pw_properties_new(
+			PW_KEY_MEDIA_TYPE, "Audio",
+			PW_KEY_MEDIA_CATEGORY, "Playback",
+			PW_KEY_MEDIA_ROLE, "Music",
+			NULL),
+		&stream_events,
+		NULL);
+
+	if(pwstate.output == NULL){
+		unlock(&pwstate.lk);
+		error("could not create pipewire output");
+		return;
+	}
+	params[0] = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat,
+		&SPA_AUDIO_INFO_RAW_INIT(
+			.format = SPA_AUDIO_FORMAT_S16_LE,
+			.channels = 2,
+			.rate = 44100 ));
+
+	err = pw_stream_connect(pwstate.output,
+		PW_DIRECTION_OUTPUT,
+		PW_ID_ANY,
+		PW_STREAM_FLAG_AUTOCONNECT |
+		PW_STREAM_FLAG_MAP_BUFFERS |
+		PW_STREAM_FLAG_RT_PROCESS,
+		params, 1);
+
+	unlock(&pwstate.lk);
+	if(err < 0){
+		error("could not connect pipewire stream");
+		return;
+	}
+
+	kproc("pipewire main loop", pwproc, pwstate.loop);
+}
+
+void
+audiodevclose(void)
+{
+	lock(&pwstate.lk);
+	pw_main_loop_quit(pwstate.loop);
+	unlock(&pwstate.lk);
+}
+
+int
+audiodevread(void *a, int n)
+{
+	error("no record support");
+	return -1;
+}
+
+static int
+canwrite(void *arg)
+{
+	return pwstate.written == 0;
+}
+
+int
+audiodevwrite(void *a, int n)
+{
+	if(n > sizeof(pwstate.buf)){
+		error("write too large");
+		return -1;
+	}
+	lock(&pwstate.lk);
+	if(pwstate.written != 0){
+		unlock(&pwstate.lk);
+		sleep(&pwstate.z, canwrite, 0);
+		lock(&pwstate.lk);
+	}
+	memcpy(pwstate.buf, a, n);
+	pwstate.written = n;
+	unlock(&pwstate.lk);
+	return n;
+}
+
+void
+audiodevsetvol(int what, int left, int right)
+{
+	error("no volume support");
+}
+
+void
+audiodevgetvol(int what, int *left, int *right)
+{
+	error("no volume support");
+}
+

[-- Attachment #4.1: Type: text/plain, Size: 381 bytes --]

from postmaster@4ess:
The following attachment had content that we can't
prove to be harmless.  To avoid possible automatic
execution, we changed the content headers.
The original header was:

	Content-Type: text/x-patch; charset=UTF-8; name="drawterm-pthreadcursor.patch"
	Content-Disposition: attachment; filename="drawterm-pthreadcursor.patch"
	Content-Transfer-Encoding: base64

[-- Attachment #4.2: drawterm-pthreadcursor.patch.suspect --]
[-- Type: application/octet-stream, Size: 799 bytes --]

diff --git a/kern/devmouse.c b/kern/devmouse.c
index 85825a9..dfbabf8 100644
--- a/kern/devmouse.c
+++ b/kern/devmouse.c
@@ -11,14 +11,14 @@
 Mouseinfo	mouse;
 Cursorinfo	cursor;
 Cursorinfo      arrow = {
-	0,
-	{ -1, -1 },
-	{ 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
+	.lk = 0,
+	.offset = { -1, -1 },
+	.clr = { 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
 	  0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
 	  0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
 	  0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
 	},
-	{ 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
+	.set = { 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
 	  0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
 	  0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
 	  0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,

[-- Attachment #5.1: Type: text/plain, Size: 373 bytes --]

from postmaster@4ess:
The following attachment had content that we can't
prove to be harmless.  To avoid possible automatic
execution, we changed the content headers.
The original header was:

	Content-Type: text/x-patch; charset=UTF-8; name="drawterm-termsleep.patch"
	Content-Disposition: attachment; filename="drawterm-termsleep.patch"
	Content-Transfer-Encoding: base64

[-- Attachment #5.2: drawterm-termsleep.patch.suspect --]
[-- Type: application/octet-stream, Size: 238 bytes --]

diff --git a/kern/term.c b/kern/term.c
index afc012a..39db71a 100644
--- a/kern/term.c
+++ b/kern/term.c
@@ -117,7 +117,6 @@ resizeproc(void *arg)
 		screenwin();
 		deletescreenimage();
 		resetscreenimage();
-		osmsleep(1000);
 	}
 }
 

[-- Attachment #6.1: Type: text/plain, Size: 373 bytes --]

from postmaster@4ess:
The following attachment had content that we can't
prove to be harmless.  To avoid possible automatic
execution, we changed the content headers.
The original header was:

	Content-Type: text/x-patch; charset=UTF-8; name="drawterm-linuxmake.patch"
	Content-Disposition: attachment; filename="drawterm-linuxmake.patch"
	Content-Transfer-Encoding: base64

[-- Attachment #6.2: drawterm-linuxmake.patch.suspect --]
[-- Type: application/octet-stream, Size: 718 bytes --]

diff --git a/Make.linux b/Make.linux
new file mode 100644
index 0000000..c9ad231
--- /dev/null
+++ b/Make.linux
@@ -0,0 +1,21 @@
+# Linux
+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 -DPTHREAD $(PTHREAD) -I/usr/include/pipewire-0.3 -I/usr/include/spa-0.2 -D_REENTRANT -O2
+O=o
+OS=posix
+GUI=wl
+LDADD=-lwayland-client -lxkbcommon -ggdb -lm -lrt -lpipewire-0.3
+LDFLAGS=$(PTHREAD)
+TARG=drawterm
+# AUDIO=none
+AUDIO=pipewire
+
+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)

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2021-10-17  3:57 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-14  1:59 [9front] [drawterm] Wayland support and misc patches Jacob Moody
2021-10-15  2:22 ` Stanley Lieber
2021-10-15 11:20 ` cinap_lenrek
2021-10-17  3:49 ` Stephen Gregoratto

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).