From 21a7e57f2f4d66011b72a79087a7e911db72511c Mon Sep 17 00:00:00 2001 From: Jacob Moody Date: Mon, 4 Oct 2021 11:42:19 -0600 Subject: [PATCH 1/4] devdraw: add wayland backend --- src/cmd/devdraw/mkfile | 8 + src/cmd/devdraw/mkwsysrules.sh | 5 + src/cmd/devdraw/wl-cb.c | 458 +++++++++++++++++++++++++++++++++ src/cmd/devdraw/wl-draw.c | 58 +++++ src/cmd/devdraw/wl-inc.h | 64 +++++ src/cmd/devdraw/wl-screen.c | 204 +++++++++++++++ src/cmd/devdraw/wl-util.c | 87 +++++++ 7 files changed, 884 insertions(+) create mode 100644 src/cmd/devdraw/wl-cb.c create mode 100644 src/cmd/devdraw/wl-draw.c create mode 100644 src/cmd/devdraw/wl-inc.h create mode 100644 src/cmd/devdraw/wl-screen.c create mode 100644 src/cmd/devdraw/wl-util.c diff --git a/src/cmd/devdraw/mkfile b/src/cmd/devdraw/mkfile index 6bcf18909..4fde69110 100644 --- a/src/cmd/devdraw/mkfile +++ b/src/cmd/devdraw/mkfile @@ -39,6 +39,14 @@ latin1.h: $PLAN9/lib/keyboard $O.mklatinkbd $O.macargv: $MACARGV $LD -o $target $prereq +xdgshell=/usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml + +xdg-shell-protocol.c: + wayland-scanner private-code < $xdgshell > xdg-shell-protocol.c + +xdg-shell-protocol.h: + wayland-scanner client-header < $xdgshell > xdg-shell-protocol.h + %.$O: %.m $CC $CFLAGS $OBJCFLAGS -fobjc-arc -o $target $stem.m diff --git a/src/cmd/devdraw/mkwsysrules.sh b/src/cmd/devdraw/mkwsysrules.sh index 56dff55a3..7ed8c0dd8 100644 --- a/src/cmd/devdraw/mkwsysrules.sh +++ b/src/cmd/devdraw/mkwsysrules.sh @@ -58,6 +58,11 @@ elif [ $WSYSTYPE = mac ]; then echo 'WSYSOFILES=$WSYSOFILES mac-draw.o mac-screen.o' echo 'WSYSHFILES=' echo 'MACARGV=macargv.o' +elif [ $WSYSTYPE = wayland ]; then + echo 'WSYSOFILES=$WSYSOFILES wl-screen.o xdg-shell-protocol.o wl-util.o wl-cb.o wl-draw.o' + echo 'WSYSHFILES=xdg-shell-protocol.h wl-inc.h' + echo 'LDFLAGS=-lwayland-client -lxkbcommon -lrt' + echo 'CFLAGS=$CFLAGS -ggdb' elif [ $WSYSTYPE = nowsys ]; then echo 'WSYSOFILES=nowsys.o' fi diff --git a/src/cmd/devdraw/wl-cb.c b/src/cmd/devdraw/wl-cb.c new file mode 100644 index 000000000..69e27c843 --- /dev/null +++ b/src/cmd/devdraw/wl-cb.c @@ -0,0 +1,458 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include /* For mode constants */ +#include +#include +#include "xdg-shell-protocol.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "devdraw.h" +#include "wl-inc.h" + +#undef close +#undef send + +static void +noop() +{ +} + +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; + threadexitsall(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; + Rectangle r; + + fprint(2, "resizing\n"); + wl = data; + if(width == 0 || height == 0 || (width == wl->dx && height == wl->dy)) + return; + rpc_gfxdrawlock(); + wl->dx = width; + wl->dy = height; + r = Rect(0, 0, wl->dx, wl->dy); + wl->client->mouserect = r; + wlallocbuffer(wl); + wl->screen = allocmemimage(r, XRGB32); + rpc_gfxdrawunlock(); + gfx_replacescreenimage(wl->client, wl->screen); + gfx_mouseresized(wl->client); + wl->client->impl->rpc_flush(wl->client, Rect(0, 0, 0, 0)); +} + +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); + wl_callback_add_listener(cb, &wl_surface_frame_listener, wl); + wl->client->impl->rpc_flush(wl->client, Rect(0, 0, 0, 0)); +} + +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; + + if(state == 0) + return; + 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(utf32){ + gfx_keystroke(wl->client, utf32); + } +} + +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; + gfx_mousetrack(wl->client, 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; + gfx_mousetrack(wl->client, 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) +{ +} + +static void +pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface) +{ +} + +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 = noop, +}; + +static void +seat_handle_capabilities(void *data, struct wl_seat *seat, uint32_t capabilities) +{ + Wlwin *wl; + + wl = data; + if(capabilities & WL_SEAT_CAPABILITY_POINTER) { + struct wl_pointer *pointer = wl_seat_get_pointer(seat); + wl_pointer_add_listener(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; + + 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; + free(wl->clip.content); + qunlock(&wl->clip.lk); + close(fd); +} + +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) +{ + /* TODO accept offers if this isn't working */ +} + +static void +data_device_handle_selection(void *data, struct wl_data_device *data_device, struct wl_data_offer *offer) +{ + Wlwin *wl; + char *buf; + 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", fds[1]); + close(fds[1]); + + wl_display_roundtrip(wl->display); + + size = 8192*256; + buf = mallocz(size+1, 1); + for(pos = 0; (n = read(fds[0], buf+pos, size-pos)) > 0;){ + pos += n; + if(pos >= size){ + size *= 2; + buf = realloc(buf, size+1); + memset(buf+pos, 0, (size-pos)+1); + } + } + close(fds[0]); + qlock(&wl->clip.lk); + wl->clip.content = buf; + 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 +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); + } 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); + } +} + +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 xdg_toplevel *xdg_toplevel; + struct wl_callback *cb; + + registry = wl_display_get_registry(wl->display); + wl_registry_add_listener(registry, ®istry_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) + 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); + xdg_toplevel = xdg_surface_get_toplevel(xdg_surface); + xdg_surface_add_listener(xdg_surface, &xdg_surface_listener, wl); + xdg_toplevel_add_listener(xdg_toplevel, &xdg_toplevel_listener, wl); + + wl_surface_commit(wl->surface); + wl_display_roundtrip(wl->display); + + wl_surface_attach(wl->surface, wl->buffer, 0, 0); + wl_surface_damage(wl->surface, 0, 0, wl->dx, wl->dy); + wl_surface_commit(wl->surface); + + cb = wl_surface_frame(wl->surface); + wl_callback_add_listener(cb, &wl_surface_frame_listener, wl); +} + +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"); + 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/src/cmd/devdraw/wl-draw.c b/src/cmd/devdraw/wl-draw.c new file mode 100644 index 000000000..fdf7acecd --- /dev/null +++ b/src/cmd/devdraw/wl-draw.c @@ -0,0 +1,58 @@ +#include "u.h" +#include "libc.h" +#include "draw.h" +#include "memdraw.h" + +Memimage* +allocmemimage(Rectangle r, u32int chan) +{ + return _allocmemimage(r, chan); +} + +void +freememimage(Memimage *i) +{ + _freememimage(i); +} + +void +memfillcolor(Memimage *i, u32int val) +{ + _memfillcolor(i, val); +} + + +int +cloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata) +{ + return _cloadmemimage(i, r, data, ndata); +} + +void +memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point sp, Memimage *mask, Point mp, int op) +{ + Memdrawparam *par; + + par = _memimagedrawsetup(dst, r, src, sp, mask, mp, op); + if(par == nil) + return; + _memimagedraw(par); +} + +u32int +pixelbits(Memimage *m, Point p) +{ + return _pixelbits(m, p); +} + +int +loadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata) +{ + return _loadmemimage(i, r, data, ndata); +} + +int +unloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata) +{ + return _unloadmemimage(i, r, data, ndata); +} diff --git a/src/cmd/devdraw/wl-inc.h b/src/cmd/devdraw/wl-inc.h new file mode 100644 index 000000000..05cbe1b5f --- /dev/null +++ b/src/cmd/devdraw/wl-inc.h @@ -0,0 +1,64 @@ +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 Wlwin { + int dx; + int dy; + + /* p9p state */ + Client *client; + Memimage *screen; + + /* Wayland State */ + int runing; + struct wl_compositor *compositor; + struct wl_display *display; + struct wl_surface *surface; + struct xdg_wm_base *xdg_wm_base; + struct wl_buffer *buffer; + struct wl_shm *shm; + struct wl_seat *seat; + struct wl_data_device_manager *data_device_manager; + struct wl_data_device *data_device; + void *shm_data; + + /* Keyboard state */ + struct xkb_state *xkb_state; + struct xkb_context *xkb_context; + + /* Mouse state */ + Mouse mouse; + + Clipboard clip; +}; + +void wlallocbuffer(Wlwin*); +void wlsetcb(Wlwin*); +char* wlgetsnarf(Wlwin*); +void wlsetsnarf(Wlwin*, char*); diff --git a/src/cmd/devdraw/wl-screen.c b/src/cmd/devdraw/wl-screen.c new file mode 100644 index 000000000..e3a5248f3 --- /dev/null +++ b/src/cmd/devdraw/wl-screen.c @@ -0,0 +1,204 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include /* For mode constants */ +#include +#include +#include "xdg-shell-protocol.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "devdraw.h" +#include "wl-inc.h" + +static QLock wllk; + +static Wlwin *snarfwin; + +static clientruning; + +static void rpc_resizeimg(Client*); +static void rpc_resizewindow(Client*, Rectangle); +static void rpc_setcursor(Client*, Cursor*, Cursor2*); +static void rpc_setlabel(Client*, char*); +static void rpc_setmouse(Client*, Point); +static void rpc_topwin(Client*); +static void rpc_bouncemouse(Client*, Mouse); +static void rpc_flush(Client*, Rectangle); + +static ClientImpl wlimpl = { + rpc_resizeimg, + rpc_resizewindow, + rpc_setcursor, + rpc_setlabel, + rpc_setmouse, + rpc_topwin, + rpc_bouncemouse, + rpc_flush, +}; + +static Wlwin* +newwlwin(Client *c) +{ + Wlwin *wl; + + wl = mallocz(sizeof *wl, 1); + if(wl == nil) + sysfatal("malloc Wlwin"); + wl->client = c; + wl->dx = 1024; + wl->dy = 1024; + return wl; +} + +void +dispatchproc(void *a) +{ + Wlwin *wl; + wl = a; + for(;clientruning == 1 && wl->runing == 1;){ + wl_display_dispatch(wl->display); + } +} + +static Memimage* +wlattach(Client *client, char *label, char *winsize) +{ + Rectangle r; + Wlwin *wl; + + wl = newwlwin(nil); + snarfwin = wl; + wl->client = client; + wl->client->view = wl; + wl->client->impl = &wlimpl; + wl->display = wl_display_connect(NULL); + if(wl->display == nil) + sysfatal("could not connect to display"); + + wlsetcb(wl); + r = Rect(0, 0, wl->dx, wl->dy); + wl->screen = allocmemimage(r, XRGB32); + wl->runing = 1; + proccreate(dispatchproc, wl, 8192); + return wl->screen; +} + +void +rpc_gfxdrawlock(void) +{ + qlock(&wllk); +} + +void +rpc_gfxdrawunlock(void) +{ + qunlock(&wllk); +} + +void +gfx_main(void) +{ + clientruning = 1; + gfx_started(); +} + +Memimage* +rpc_attach(Client *client, char *label, char *winsize) +{ + return wlattach(client, label, winsize); +} + +void +rpc_flush(Client *client, Rectangle r) +{ + Wlwin *wl; + + wl = (Wlwin*)client->view; + qlock(&wllk); + memcpy(wl->shm_data, wl->screen->data->bdata, wl->dx*wl->dy*4); + wl_surface_attach(wl->surface, wl->buffer, 0, 0); + wl_surface_damage(wl->surface, 0, 0, wl->dx, wl->dy); + wl_surface_commit(wl->surface); + qunlock(&wllk); +} + +void +rpc_resizeimg(Client *client) +{ + Rectangle r; + Wlwin *wl; + + wl = (Wlwin*)client->view; + qlock(&wllk); + r = Rect(0, 0, wl->dx, wl->dy); + wl->screen = allocmemimage(r, XRGB32); + qunlock(&wllk); + gfx_replacescreenimage(client, wl->screen); +} + +void +rpc_resizewindow(Client *client, Rectangle r) +{ + fprint(2, "resize window stub\n"); +} + +void +rpc_setcursor(Client *client, Cursor *c, Cursor2 *c2) +{ + fprint(2, "Set cursor stub"); +} + +void +rpc_bouncemouse(Client *c, Mouse m) +{ + fprint(2, "bounce mouse stub\n"); +} + +void +rpc_setlabel(Client *c, char*) +{ + fprint(2, "set label stub\n"); +} + +void +rpc_topwin(Client *c) +{ + fprint(2, "top win stub\n"); +} + +void +rpc_setmouse(Client *c, Point p) +{ + fprint(2, "set mouse stub\n"); +} + +void +rpc_shutdown(void) +{ + clientruning = 0; +} + +char* +rpc_getsnarf(void) +{ + return wlgetsnarf(snarfwin); +} + +void +rpc_putsnarf(char *data) +{ + wlsetsnarf(snarfwin, data); +} diff --git a/src/cmd/devdraw/wl-util.c b/src/cmd/devdraw/wl-util.c new file mode 100644 index 000000000..b1069c1d3 --- /dev/null +++ b/src/cmd/devdraw/wl-util.c @@ -0,0 +1,87 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include /* For mode constants */ +#include +#include +#include "xdg-shell-protocol.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "devdraw.h" +#include "wl-inc.h" + +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 +wlallocbuffer(Wlwin *win) +{ + int stride, size; + int fd; + struct wl_shm_pool *pool; + + stride = win->dx * 4; + size = stride * win->dy; + + fd = wlcreateshm(size); + if(fd < 0) + sysfatal("could not mk_shm_fd"); + + win->shm_data = mmap(nil, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if(win->shm_data == MAP_FAILED) + sysfatal("could not mmap shm_data"); + + pool = wl_shm_create_pool(win->shm, fd, size); + win->buffer = wl_shm_pool_create_buffer(pool, 0, win->dx, win->dy, stride, WL_SHM_FORMAT_XRGB8888); + /* TODO: optimize alloc a larger pool */ + wl_shm_pool_destroy(pool); +} + From 0b5527950a4e487371819c883897c2ade7a2ff29 Mon Sep 17 00:00:00 2001 From: Jacob Moody Date: Tue, 5 Oct 2021 08:29:53 -0600 Subject: [PATCH 2/4] devdraw: add custom cursors and rework buffer logic --- src/cmd/devdraw/wl-cb.c | 40 ++++++++++++----- src/cmd/devdraw/wl-inc.h | 21 +++++---- src/cmd/devdraw/wl-screen.c | 24 +++++----- src/cmd/devdraw/wl-util.c | 87 +++++++++++++++++++++++++++++++------ 4 files changed, 130 insertions(+), 42 deletions(-) diff --git a/src/cmd/devdraw/wl-cb.c b/src/cmd/devdraw/wl-cb.c index 69e27c843..f8de1bdae 100644 --- a/src/cmd/devdraw/wl-cb.c +++ b/src/cmd/devdraw/wl-cb.c @@ -26,11 +26,6 @@ #undef close #undef send -static void -noop() -{ -} - static void xdg_surface_handle_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial) { @@ -60,7 +55,6 @@ xdg_toplevel_handle_configure(void *data, struct xdg_toplevel *xdg_toplevel, int Wlwin *wl; Rectangle r; - fprint(2, "resizing\n"); wl = data; if(width == 0 || height == 0 || (width == wl->dx && height == wl->dy)) return; @@ -236,6 +230,11 @@ pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time, 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 @@ -243,12 +242,33 @@ pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, uint32_t serial, { } +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; + /* p9p expects a scroll event to work like a button, a set and a release */ + gfx_mousetrack(wl->client, wl->mouse.xy.x, wl->mouse.xy.y, buttons, wl->mouse.msec); + gfx_mousetrack(wl->client, wl->mouse.xy.x, wl->mouse.xy.y, wl->mouse.buttons, wl->mouse.msec+1); +} + 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 = noop, + .axis = pointer_handle_axis, }; static void @@ -258,8 +278,8 @@ seat_handle_capabilities(void *data, struct wl_seat *seat, uint32_t capabilities wl = data; if(capabilities & WL_SEAT_CAPABILITY_POINTER) { - struct wl_pointer *pointer = wl_seat_get_pointer(seat); - wl_pointer_add_listener(pointer, &pointer_listener, wl); + 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); @@ -417,7 +437,7 @@ wlsetcb(Wlwin *wl) wl_surface_commit(wl->surface); wl_display_roundtrip(wl->display); - wl_surface_attach(wl->surface, wl->buffer, 0, 0); + 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); diff --git a/src/cmd/devdraw/wl-inc.h b/src/cmd/devdraw/wl-inc.h index 05cbe1b5f..b1dbab11b 100644 --- a/src/cmd/devdraw/wl-inc.h +++ b/src/cmd/devdraw/wl-inc.h @@ -30,6 +30,10 @@ struct Clipboard { struct Wlwin { int dx; int dy; + int monx; + int mony; + Mouse mouse; + Clipboard clip; /* p9p state */ Client *client; @@ -37,28 +41,29 @@ struct Wlwin { /* 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 wl_buffer *buffer; + 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; - void *shm_data; - + struct wl_pointer *pointer; /* Keyboard state */ struct xkb_state *xkb_state; struct xkb_context *xkb_context; - - /* Mouse state */ - Mouse mouse; - - Clipboard clip; }; void wlallocbuffer(Wlwin*); void wlsetcb(Wlwin*); char* wlgetsnarf(Wlwin*); void wlsetsnarf(Wlwin*, char*); +void wldrawcursor(Wlwin*, Cursor*); diff --git a/src/cmd/devdraw/wl-screen.c b/src/cmd/devdraw/wl-screen.c index e3a5248f3..979de966a 100644 --- a/src/cmd/devdraw/wl-screen.c +++ b/src/cmd/devdraw/wl-screen.c @@ -21,6 +21,7 @@ #include #include #include "devdraw.h" +#include "bigarrow.h" #include "wl-inc.h" static QLock wllk; @@ -58,8 +59,12 @@ newwlwin(Client *c) if(wl == nil) sysfatal("malloc Wlwin"); wl->client = c; + wl->client->view = wl; + wl->client->impl = &wlimpl; wl->dx = 1024; wl->dy = 1024; + wl->monx = 1920; + wl->mony = 1080; return wl; } @@ -79,11 +84,8 @@ wlattach(Client *client, char *label, char *winsize) Rectangle r; Wlwin *wl; - wl = newwlwin(nil); + wl = newwlwin(client); snarfwin = wl; - wl->client = client; - wl->client->view = wl; - wl->client->impl = &wlimpl; wl->display = wl_display_connect(NULL); if(wl->display == nil) sysfatal("could not connect to display"); @@ -91,6 +93,7 @@ wlattach(Client *client, char *label, char *winsize) wlsetcb(wl); r = Rect(0, 0, wl->dx, wl->dy); wl->screen = allocmemimage(r, XRGB32); + wldrawcursor(wl, &bigarrow); wl->runing = 1; proccreate(dispatchproc, wl, 8192); return wl->screen; @@ -129,7 +132,7 @@ rpc_flush(Client *client, Rectangle r) wl = (Wlwin*)client->view; qlock(&wllk); memcpy(wl->shm_data, wl->screen->data->bdata, wl->dx*wl->dy*4); - wl_surface_attach(wl->surface, wl->buffer, 0, 0); + 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); qunlock(&wllk); @@ -152,37 +155,36 @@ rpc_resizeimg(Client *client) void rpc_resizewindow(Client *client, Rectangle r) { - fprint(2, "resize window stub\n"); } void rpc_setcursor(Client *client, Cursor *c, Cursor2 *c2) { - fprint(2, "Set cursor stub"); + if(c == nil) + c = &bigarrow; + qlock(&wllk); + wldrawcursor(client->view, c); + qunlock(&wllk); } void rpc_bouncemouse(Client *c, Mouse m) { - fprint(2, "bounce mouse stub\n"); } void rpc_setlabel(Client *c, char*) { - fprint(2, "set label stub\n"); } void rpc_topwin(Client *c) { - fprint(2, "top win stub\n"); } void rpc_setmouse(Client *c, Point p) { - fprint(2, "set mouse stub\n"); } void diff --git a/src/cmd/devdraw/wl-util.c b/src/cmd/devdraw/wl-util.c index b1069c1d3..22a6d9189 100644 --- a/src/cmd/devdraw/wl-util.c +++ b/src/cmd/devdraw/wl-util.c @@ -60,28 +60,89 @@ wlcreateshm(off_t size) return -1; } - void -wlallocbuffer(Wlwin *win) +wlallocpool(Wlwin *wl) { - int stride, size; + int screenx, screeny; + int screensize, cursorsize; + int depth; int fd; - struct wl_shm_pool *pool; - stride = win->dx * 4; - size = stride * win->dy; + 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(size); + fd = wlcreateshm(screensize+cursorsize); if(fd < 0) sysfatal("could not mk_shm_fd"); - win->shm_data = mmap(nil, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if(win->shm_data == MAP_FAILED) + 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"); - pool = wl_shm_create_pool(win->shm, fd, size); - win->buffer = wl_shm_pool_create_buffer(pool, 0, win->dx, win->dy, stride, WL_SHM_FORMAT_XRGB8888); - /* TODO: optimize alloc a larger pool */ - wl_shm_pool_destroy(pool); + wl->pool = wl_shm_create_pool(wl->shm, fd, screensize+cursorsize); + wl->poolsize = screensize+cursorsize; +} + +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, Cursor *c) +{ + int i, j; + int pos, mask; + u32int *buf; + u16int 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; + } + } + 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); +} From 9b045517a1560469ef8ef1a5562f3a07edb6377b Mon Sep 17 00:00:00 2001 From: Jacob Moody Date: Wed, 6 Oct 2021 20:54:38 -0600 Subject: [PATCH 3/4] devdraw: server side wayland decorations and title. --- src/cmd/devdraw/mkfile | 7 +++++ src/cmd/devdraw/mkwsysrules.sh | 5 ++-- src/cmd/devdraw/wl-cb.c | 50 ++++++++++++++++++++-------------- src/cmd/devdraw/wl-inc.h | 7 +++++ src/cmd/devdraw/wl-screen.c | 47 ++++++++++++++++++++++++++------ 5 files changed, 85 insertions(+), 31 deletions(-) diff --git a/src/cmd/devdraw/mkfile b/src/cmd/devdraw/mkfile index 4fde69110..e88149cc1 100644 --- a/src/cmd/devdraw/mkfile +++ b/src/cmd/devdraw/mkfile @@ -40,6 +40,7 @@ $O.macargv: $MACARGV $LD -o $target $prereq xdgshell=/usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml +xdgdeco=/usr/share/wayland-protocols/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml xdg-shell-protocol.c: wayland-scanner private-code < $xdgshell > xdg-shell-protocol.c @@ -47,6 +48,12 @@ xdg-shell-protocol.c: xdg-shell-protocol.h: wayland-scanner client-header < $xdgshell > xdg-shell-protocol.h +xdg-decoration-protocol.c: + wayland-scanner private-code < $xdgdeco > xdg-decoration-protocol.c + +xdg-decoration-protocol.h: + wayland-scanner client-header < $xdgdeco > xdg-decoration-protocol.h + %.$O: %.m $CC $CFLAGS $OBJCFLAGS -fobjc-arc -o $target $stem.m diff --git a/src/cmd/devdraw/mkwsysrules.sh b/src/cmd/devdraw/mkwsysrules.sh index 7ed8c0dd8..c35f36398 100644 --- a/src/cmd/devdraw/mkwsysrules.sh +++ b/src/cmd/devdraw/mkwsysrules.sh @@ -59,10 +59,9 @@ elif [ $WSYSTYPE = mac ]; then echo 'WSYSHFILES=' echo 'MACARGV=macargv.o' elif [ $WSYSTYPE = wayland ]; then - echo 'WSYSOFILES=$WSYSOFILES wl-screen.o xdg-shell-protocol.o wl-util.o wl-cb.o wl-draw.o' - echo 'WSYSHFILES=xdg-shell-protocol.h wl-inc.h' + echo 'WSYSOFILES=$WSYSOFILES xdg-decoration-protocol.o xdg-shell-protocol.o wl-util.o wl-cb.o wl-draw.o wl-screen.o' + echo 'WSYSHFILES=xdg-shell-protocol.h xdg-decoration-protocol.h wl-inc.h' echo 'LDFLAGS=-lwayland-client -lxkbcommon -lrt' - echo 'CFLAGS=$CFLAGS -ggdb' elif [ $WSYSTYPE = nowsys ]; then echo 'WSYSOFILES=nowsys.o' fi diff --git a/src/cmd/devdraw/wl-cb.c b/src/cmd/devdraw/wl-cb.c index f8de1bdae..40bfc0a2e 100644 --- a/src/cmd/devdraw/wl-cb.c +++ b/src/cmd/devdraw/wl-cb.c @@ -9,6 +9,7 @@ #include #include #include "xdg-shell-protocol.h" +#include "xdg-decoration-protocol.h" #include #include @@ -53,22 +54,11 @@ 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; - Rectangle r; wl = data; if(width == 0 || height == 0 || (width == wl->dx && height == wl->dy)) return; - rpc_gfxdrawlock(); - wl->dx = width; - wl->dy = height; - r = Rect(0, 0, wl->dx, wl->dy); - wl->client->mouserect = r; - wlallocbuffer(wl); - wl->screen = allocmemimage(r, XRGB32); - rpc_gfxdrawunlock(); - gfx_replacescreenimage(wl->client, wl->screen); - gfx_mouseresized(wl->client); - wl->client->impl->rpc_flush(wl->client, Rect(0, 0, 0, 0)); + wlresize(wl, width, height); } const struct xdg_toplevel_listener xdg_toplevel_listener = { @@ -86,8 +76,8 @@ wl_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) wl = data; wl_callback_destroy(cb); cb = wl_surface_frame(wl->surface); + wlflush(wl); wl_callback_add_listener(cb, &wl_surface_frame_listener, wl); - wl->client->impl->rpc_flush(wl->client, Rect(0, 0, 0, 0)); } static void @@ -378,6 +368,16 @@ static const struct wl_data_device_listener data_device_listener = { .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) { @@ -393,8 +393,11 @@ handle_global(void *data, struct wl_registry *registry, uint32_t name, const cha 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); } } @@ -413,38 +416,45 @@ wlsetcb(Wlwin *wl) { struct wl_registry *registry; struct xdg_surface *xdg_surface; - struct xdg_toplevel *xdg_toplevel; struct wl_callback *cb; + struct zxdg_toplevel_decoration_v1 *deco; registry = wl_display_get_registry(wl->display); wl_registry_add_listener(registry, ®istry_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) + 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); - xdg_toplevel = xdg_surface_get_toplevel(xdg_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(xdg_toplevel, &xdg_toplevel_listener, wl); + xdg_toplevel_add_listener(wl->xdg_toplevel, &xdg_toplevel_listener, wl); wl_surface_commit(wl->surface); wl_display_roundtrip(wl->display); - 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); + 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) { diff --git a/src/cmd/devdraw/wl-inc.h b/src/cmd/devdraw/wl-inc.h index b1dbab11b..5a5dcb0d8 100644 --- a/src/cmd/devdraw/wl-inc.h +++ b/src/cmd/devdraw/wl-inc.h @@ -34,6 +34,7 @@ struct Wlwin { int mony; Mouse mouse; Clipboard clip; + int dirty; /* p9p state */ Client *client; @@ -49,6 +50,7 @@ struct Wlwin { 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; @@ -60,10 +62,15 @@ struct Wlwin { /* 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*, Cursor*); +void wlresize(Wlwin*, int, int); +void wlflush(Wlwin*); diff --git a/src/cmd/devdraw/wl-screen.c b/src/cmd/devdraw/wl-screen.c index 979de966a..5127c503d 100644 --- a/src/cmd/devdraw/wl-screen.c +++ b/src/cmd/devdraw/wl-screen.c @@ -28,7 +28,7 @@ static QLock wllk; static Wlwin *snarfwin; -static clientruning; +static int clientruning; static void rpc_resizeimg(Client*); static void rpc_resizewindow(Client*, Rectangle); @@ -68,6 +68,38 @@ newwlwin(Client *c) return wl; } +void +wlflush(Wlwin *wl) +{ + qlock(&wllk); + if(wl->dirty == 1) + memcpy(wl->shm_data, wl->screen->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; + qunlock(&wllk); +} + +void +wlresize(Wlwin *wl, int x, int y) +{ + Rectangle r; + + qlock(&wllk); + wl->dx = x; + wl->dy = y; + + wlallocbuffer(wl); + r = Rect(0, 0, wl->dx, wl->dy); + wl->client->mouserect = r; + wl->screen = allocmemimage(r, XRGB32); + wl->dirty = 1; + qunlock(&wllk); + gfx_replacescreenimage(wl->client, wl->screen); +} + void dispatchproc(void *a) { @@ -91,9 +123,10 @@ wlattach(Client *client, char *label, char *winsize) sysfatal("could not connect to display"); wlsetcb(wl); - r = Rect(0, 0, wl->dx, wl->dy); - wl->screen = allocmemimage(r, XRGB32); + wlsettitle(wl, label); + wlresize(wl, wl->dx, wl->dy); wldrawcursor(wl, &bigarrow); + wlflush(wl); wl->runing = 1; proccreate(dispatchproc, wl, 8192); return wl->screen; @@ -131,10 +164,7 @@ rpc_flush(Client *client, Rectangle r) wl = (Wlwin*)client->view; qlock(&wllk); - memcpy(wl->shm_data, wl->screen->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 = 1; qunlock(&wllk); } @@ -173,8 +203,9 @@ rpc_bouncemouse(Client *c, Mouse m) } void -rpc_setlabel(Client *c, char*) +rpc_setlabel(Client *c, char *s) { + wlsettitle(c->view, s); } void From 9c5244b1416299503d3670ca941dfc0fb8f9dc28 Mon Sep 17 00:00:00 2001 From: Jacob Moody Date: Thu, 7 Oct 2021 23:06:36 -0600 Subject: [PATCH 4/4] devdraw: tidy up wayland clipboard logic --- src/cmd/devdraw/wl-cb.c | 28 ++++++++++++++-------------- src/cmd/devdraw/wl-screen.c | 2 +- src/cmd/devdraw/wl-util.c | 5 ++++- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/cmd/devdraw/wl-cb.c b/src/cmd/devdraw/wl-cb.c index 40bfc0a2e..0f8289e20 100644 --- a/src/cmd/devdraw/wl-cb.c +++ b/src/cmd/devdraw/wl-cb.c @@ -5,7 +5,7 @@ #include #include #include -#include /* For mode constants */ +#include #include #include #include "xdg-shell-protocol.h" @@ -289,13 +289,15 @@ data_source_handle_send(void *data, struct wl_data_source *source, const char *m 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; - free(wl->clip.content); qunlock(&wl->clip.lk); close(fd); } @@ -320,14 +322,12 @@ static const struct wl_data_source_listener data_source_listener = { static void data_device_handle_data_offer(void *data, struct wl_data_device *data_device, struct wl_data_offer *offer) { - /* TODO accept offers if this isn't working */ } static void data_device_handle_selection(void *data, struct wl_data_device *data_device, struct wl_data_offer *offer) { Wlwin *wl; - char *buf; ulong n; ulong size; ulong pos; @@ -340,26 +340,25 @@ data_device_handle_selection(void *data, struct wl_data_device *data_device, str wl = data; pipe(fds); - wl_data_offer_receive(offer, "text/plain", fds[1]); + wl_data_offer_receive(offer, "text/plain;charset=utf-8", fds[1]); close(fds[1]); wl_display_roundtrip(wl->display); - size = 8192*256; - buf = mallocz(size+1, 1); - for(pos = 0; (n = read(fds[0], buf+pos, size-pos)) > 0;){ + 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; - buf = realloc(buf, size+1); - memset(buf+pos, 0, (size-pos)+1); + wl->clip.content = realloc(wl->clip.content, size+1); + memset(wl->clip.content+pos, 0, (size-pos)+1); } } close(fds[0]); - qlock(&wl->clip.lk); - wl->clip.content = buf; qunlock(&wl->clip.lk); - wl_data_offer_destroy(offer); } @@ -463,6 +462,7 @@ wlsetsnarf(Wlwin *wl, char *s) 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) @@ -470,7 +470,7 @@ wlsetsnarf(Wlwin *wl, char *s) 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"); + 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: diff --git a/src/cmd/devdraw/wl-screen.c b/src/cmd/devdraw/wl-screen.c index 5127c503d..3710b43ce 100644 --- a/src/cmd/devdraw/wl-screen.c +++ b/src/cmd/devdraw/wl-screen.c @@ -5,7 +5,7 @@ #include #include #include -#include /* For mode constants */ +#include #include #include #include "xdg-shell-protocol.h" diff --git a/src/cmd/devdraw/wl-util.c b/src/cmd/devdraw/wl-util.c index 22a6d9189..4480dda14 100644 --- a/src/cmd/devdraw/wl-util.c +++ b/src/cmd/devdraw/wl-util.c @@ -5,7 +5,7 @@ #include #include #include -#include /* For mode constants */ +#include #include #include #include "xdg-shell-protocol.h" @@ -87,6 +87,7 @@ wlallocpool(Wlwin *wl) wl->pool = wl_shm_create_pool(wl->shm, fd, screensize+cursorsize); wl->poolsize = screensize+cursorsize; + close(fd); } void @@ -141,6 +142,8 @@ wldrawcursor(Wlwin *wl, Cursor *c) 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);