Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wip: devdraw: wayland support #550

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions bin/9l
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,11 @@ then
fi
libsl="$libsl -lX11"
fi

if [ "x$needwayland" = xtrue -a "x$WSYSTYPE" != xnowsys ]
then
libsl="$(echo $libsl | sed 's/wayland/wayland-client -lwayland-cursor -lrt/')"
fi
fi
if $doautoframework
then
Expand Down
5 changes: 4 additions & 1 deletion man/man1/devdraw.1
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ invoked via
.SH DESCRIPTION
.I Devdraw
serves a custom graphics protocol and is the only program
that talks directly to X window servers.
that talks directly to host OS window servers.
On Macintosh, setting
.BI devdrawretina
to
.BI 1
will cause
.I devdraw
to use all available physical pixels on a retina display.
.PP
On Linux with Wayland support, mouse button 1 on the frame will allow
dragging to resize, and button 2 will allow for moving the frame.
.SH SOURCE
.B \*9/src/cmd/devdraw
.SH "SEE ALSO
Expand Down
10 changes: 9 additions & 1 deletion man/man1/install.1
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,16 @@ and
Values more complex than single words should be quoted
with single quotes.
.PP
On modern Linux systems, wayland development packages need to be installed to build native wayland support.
On Fedora, the required packages are
.BR wayland-devel ,
.BR wayland-protocol-devel ,
.BR libxkbcommon-devel ,
.BR freetype-devel ,
and
.BR fontconfig-devel .
On most Linux systems, the X11 header packages need to be installed
to build using X11. On Debian. the required packages are
to build using X11. On Debian, the required packages are
libfontconfig1-dev, libx11-dev, libxext-dev, and libxt-dev.
On Ubuntu, it suffices to install xorg-dev.
.PP
Expand Down
1 change: 1 addition & 0 deletions src/cmd/devdraw/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*-protocol.[ch]
4 changes: 2 additions & 2 deletions src/cmd/devdraw/devdraw.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ gfx_replacescreenimage(Client *c, Memimage *m)
c->screenimage = m;
m->screenref = 1;
if(om && --om->screenref == 0){
_freememimage(om);
freememimage(om);
}
qunlock(&drawlk);
gfx_mouseresized(c);
Expand Down Expand Up @@ -452,7 +452,7 @@ drawfreedimage(Client *client, DImage *dimage)
if(l->screenref==0)
freememimage(l);
else if(--l->screenref==0)
_freememimage(l);
freememimage(l);
}
Return:
free(dimage->fchar);
Expand Down
2 changes: 2 additions & 0 deletions src/cmd/devdraw/mkfile
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ HFILES=\

<$PLAN9/src/mkone

<mkwayland

$O.drawclient: drawclient.$O
$LD -o $target $prereq

Expand Down
19 changes: 19 additions & 0 deletions src/cmd/devdraw/mkwayland
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
way_proto=/usr/share/wayland-protocols

xdg-shell-protocol.c: $way_proto/stable/xdg-shell/xdg-shell.xml
wayland-scanner private-code < $prereq > $target

xdg-shell-client-protocol.h: $way_proto/stable/xdg-shell/xdg-shell.xml
wayland-scanner client-header < $prereq > $target

xdg-decoration-protocol.c: $way_proto/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml
wayland-scanner private-code < $prereq > $target

xdg-decoration-client-protocol.h: $way_proto/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml
wayland-scanner client-header < $prereq > $target

pointer-constraints-client-protocol.h: $way_proto/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml
wayland-scanner client-header < $prereq > $target

pointer-constraints-protocol.c: $way_proto/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml
wayland-scanner private-code < $prereq > $target
9 changes: 9 additions & 0 deletions src/cmd/devdraw/mkwsysrules.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ if [ "x$WSYSTYPE" = "x" ]; then
exit 1
fi
WSYSTYPE=mac
elif command -v wayland-scanner >/dev/null 2>&1; then
WSYSTYPE=wayland
elif [ -d "$X11" ]; then
WSYSTYPE=x11
else
Expand All @@ -54,6 +56,13 @@ if [ $WSYSTYPE = x11 ]; then
XO=`ls x11-*.c 2>/dev/null | sed 's/\.c$/.o/'`
echo 'WSYSOFILES=$WSYSOFILES '$XO
echo 'WSYSHFILES=x11-inc.h x11-keysym2ucs.h x11-memdraw.h'
elif [ $WSYSTYPE = wayland ]; then
protos='pointer-constraints xdg-decoration xdg-shell'
PROTOO=$(for p in $protos; do printf '%s-protocol.o ' $p; done; printf '\n'; )
PROTOH=$(for p in $protos; do printf '%s-client-protocol.h ' $p; done; printf '\n'; )
WAYO=`ls wayland-*.c 2>/dev/null | sed 's/\.c$/.o/' | paste -s -d ' '`
echo "WSYSOFILES=\$WSYSOFILES $WAYO $PROTOO"
echo "WSYSHFILES=wayland-inc.h $PROTOH"
elif [ $WSYSTYPE = mac ]; then
echo 'WSYSOFILES=$WSYSOFILES mac-draw.o mac-screen.o'
echo 'WSYSHFILES='
Expand Down
157 changes: 157 additions & 0 deletions src/cmd/devdraw/wayland-draw.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
#include <u.h>
#include "wayland-inc.h"
#include <libc.h>
#include <draw.h>
#include <memdraw.h>

#include "wayland-shm.h"
#include <sys/mman.h>

AUTOLIB(wayland);

Memimage *
allocmemimage(Rectangle r, u32int chan) {
int d;
Memimage *i;
if ((d = chantodepth(chan)) == 0) {
werrstr("bad channel descriptor %.8lux", chan);
return nil;
}
// fprint(2, "allocmemimage: start\n");
// Too lazy to write a real allocator, just create shm mappings and rely on
// wayland's book-keeping to tear them down.
int l = wordsperline(r, d);
int nw = l * Dy(r);
uint32 sz = sizeof(shmTab) + ((1 + nw) * sizeof(ulong));
Memdata *md = malloc(sizeof(Memdata));
if (md == nil) {
// fprint(2, "allocmemimage: malloc fail\n");
return nil;
}
// fprint(2, "allocmemimage: shm\n");
int fd = allocate_shm_file(sz);
if (fd == -1) {
// fprint(2, "allocmemimage: shm fail\n");
free(md);
return nil;
}
// fprint(2, "allocmemimage: mmap\n");
uchar *data = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED) {
// fprint(2, "allocmemimage: map fail\n");
free(md);
close(fd);
return nil;
}

md->ref = 1;
md->base = (u32int *)data;
shmTab *t = (shmTab *)data;
t->md = md;
t->fd = fd;
t->sz = sz;
// Should only be 24 bytes used, max.
md->bdata = (uchar *)(md->base + sizeof(shmTab));
md->allocd = 1;
// fprint(2, "allocmemimage: allocmemimaged\n");
i = allocmemimaged(r, chan, md, t);
if (i == nil) {
// fprint(2, "allocmemimage: allocmemimaged fail\n");
munmap(data, sz);
free(md);
close(fd);
return nil;
}
md->imref = i;
return i;
}

/*
static void
buffer_release(void *opaque, struct wl_buffer *buf) {
wl_buffer_destroy(buf);
}
static struct wl_buffer_listener kill_buffer = {
.release = buffer_release,
};
void
mk_buffer(window *w, Memimage *i) {
if (i == nil)
return;
if (i->X != nil)
return;
if (i->data->ref == 0 || !i->data->allocd) // zombie memimage ???
return;
shmTab *tab = (shmTab *)i->data->base;
Globals *g = w->global;
struct wl_shm_pool *pool = wl_shm_create_pool(g->wl_shm, tab->fd, tab->sz);
if (pool == nil) {
fprint(2, "mk_buffer: pool fail\n");
return;
}
struct wl_buffer *buf = wl_shm_pool_create_buffer(
pool, 64, Dx(i->r), Dy(i->r), Dx(i->r) * 4, WL_SHM_FORMAT_XRGB8888);
if (buf == nil) {
fprint(2, "mk_buffer: buffer fail\n");
return;
}
wl_shm_pool_destroy(pool);
fprint(2, "mkbuffer: %p\n", i);
i->X = buf;
wl_buffer_add_listener(buf, &kill_buffer, NULL);
}
*/

void
freememimage(Memimage *i) {
if (i == nil)
return;
if (i->data->ref-- == 1 && i->data->allocd) {
if (i->data->base) {
shmTab *tab = (shmTab *)i->data->base;
if (tab->md != i->data) {
fprint(2, "maritan memdata\n");
return _freememimage(i);
};
close(tab->fd);
munmap(i->data->base, tab->sz);
}
free(i->data);
}
free(i);
}

/*
void
memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point sp,
Memimage *mask, Point mp, int op) {
fprint(2, "memimagedraw\n");
}
void
memfillcolor(Memimage *m, u32int val) {
_memfillcolor(m, val);
}
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
cloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata) {
return _cloadmemimage(i, r, data, ndata);
}

int
unloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata) {
return _unloadmemimage(i, r, data, ndata);
}
114 changes: 114 additions & 0 deletions src/cmd/devdraw/wayland-inc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#include <u.h>
#include <libc.h>
#include <wayland-client.h>
#include <wayland-cursor.h>
#include <xkbcommon/xkbcommon.h>

#include "xdg-shell-client-protocol.h"
#include "xdg-decoration-client-protocol.h"
#include "pointer-constraints-client-protocol.h"

struct bounds {
int x, y;
};

struct output_elem {
struct wl_output *o;
int scale, dpi, on;
double px, mm;
struct wl_list link;
};

typedef struct Globals {
struct wl_display *wl_display;
struct wl_registry *wl_registry;
struct wl_shm *wl_shm;
struct wl_cursor_theme *wl_cursor_theme;
struct wl_compositor *wl_compositor;
struct wl_subcompositor *wl_subcompositor;
struct xdg_wm_base *xdg_wm_base;
struct wl_seat *wl_seat;
struct wl_data_device_manager *data_device_manager;
struct wl_data_device *data_device;
struct wl_data_offer *snarf_offer;
int snarf_fd;
char *snarf_buf;
struct zwp_pointer_constraints_v1 *pointer_constraints;
struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1;
struct wl_list output_list;

uint32_t seat_capabilities;
struct pixfmt {
uint32_t wl;
uint32_t p9;
} pixfmt;
struct bounds bounds;
} Globals;

// This is the singleton for a given process.
//
// Wayland specific code should be using the passed data pointer, this is just
// for the plan9 interface callbacks.
extern Globals procState;

// Window is a big bag of state for painting a window on screen.
typedef struct window {
// RWLock mu;
Globals *global;
struct wl_keyboard *wl_keyboard;
struct wl_pointer *wl_pointer;
struct wl_surface *wl_surface;
struct xdg_surface *xdg_surface;
struct xdg_toplevel *xdg_toplevel;
struct zwp_pointer_constraints_v1 *pointer_constraints;
// Frame and border need to be re-organized: "frame" was originally the
// window contents with the main surface being the border, but this
// arrangement breaks pointer warping in GNOME. This state of affair is
// weird, but actually works.
struct border {
struct edge {
struct wl_subsurface *subsurface;
struct wl_surface *surface;
int skip;
int x, y;
} edge[4]; // top, bottom, left, right
struct wl_shm_pool *pool;
} decoration;
struct bounds bounds, cursize, wantsize;
int scale;
int resizing;
// Mouse members: x, y, button state, time and entry serial.
struct mouse {
// RWLock mu;
int X, Y, B, T, S;
int in; // which surface?
} m;
struct cursor {
// RWLock mu;
struct wl_surface *surface;
struct wl_shm_pool *pool;
uint32 *buf;
int x, y;
} cursor;
// Keyboard members: xkb members and serial
struct keyboard {
// RWLock mu;
struct xkb_context *context;
struct xkb_keymap *keymap;
struct xkb_state *state;
int S;
int32 rate, delay;
int32 time, key, event, delayed;
} kb;
} window;

struct Memdata;
typedef struct shmTab {
struct Memdata *md;
int fd;
size_t sz;
} shmTab;

extern int borderSz;
extern int barSz;
extern const int curBufSz;
Loading