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 +#include +#include +#include +#include +#include +#include +#include +#include +#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 +#include +#include +#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, ®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 || 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 +#include +#include +#include +#include +#include +#include +#include +#include +#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 +#include +#include +#include +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#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 +#include +#include +#include +#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); +}