Bunch of new stuff: simple compositor, cairo+gem use in client, events.

Kristian Høgsberg 16 years ago
parent 33bea964ca
commit a67a71a7cf
  1. 19
      Makefile
  2. 18
      NOTES
  3. 180
      client.c
  4. 131
      compositor.c
  5. 27
      event-loop.c
  6. 214
      wayland-client.c
  7. 28
      wayland-client.h
  8. 239
      wayland.c
  9. 32
      wayland.h

@ -1,17 +1,24 @@
CFLAGS = -Wall -g $(shell pkg-config --cflags libffi)
LDLIBS = $(shell pkg-config --libs libffi)
CFLAGS += -Wall -g $(shell pkg-config --cflags libffi libdrm)
LDLIBS += $(shell pkg-config --libs libffi libdrm)
all : wayland client
wayland_objs = wayland.o event-loop.o hash.o
wayland_objs = wayland.o event-loop.o hash.o compositor.o
wayland : $(wayland_objs)
gcc -o $@ $(wayland_objs) $(LDLIBS)
libwayland_objs = wayland-client.o
libwayland.so : $(libwayland_objs)
gcc -o $@ $(libwayland_objs) -shared
client_objs = client.o
client : CFLAGS += $(shell pkg-config --cflags cairo)
client : LDLIBS += $(shell pkg-config --libs cairo)
client : $(client_objs)
gcc -o $@ $(client_objs)
client : $(client_objs) libwayland.so
gcc -o $@ -L. -lwayland $(LDLIBS) $(client_objs)
clean :
rm client wayland *.o
rm -f client wayland *.o libwayland.so

18
NOTES

@ -33,6 +33,10 @@ Could be a "shell" for launching gdm X server, user session servers,
safe mode xservers, graphics text console. From gdm, we could also
launch a rdp session, solid ice sessions.
All surface commands (copy, attach, map=set quads) are buffered until
the client sends a commit command, which executes everything
atomically...
ISSUES:
@ -56,7 +60,21 @@ synaptics, 3-button emulation, xkb, scim
changing screen resolution, adding monitors.
RMI
The wayland protocol is a async object oriented protocol. All
requests are method invocations on some object. The request include
an object id that uniquely identifies an object on the server. Each
object implements an interface and the requests include an opcode that
identifies which method in the interface to invoke.
The server sends back events to the client, each event is emitted from
an object. Events can be error conditions. The event includes the
object id and the event opcode, from which the client can determine
the type of event. Events are generated both in repsonse to a request
(in which case the requet and the event constitutes a round trip) or
spontanously when the server state changes.
the get_interface method is called on an object to get an object
handle that implements the specified interface.

@ -1,109 +1,135 @@
#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <i915_drm.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <ctype.h>
#include <math.h>
#include <cairo.h>
#include "wayland-client.h"
static const char gem_device[] = "/dev/dri/card0";
static const char socket_name[] = "\0wayland";
struct method {
const char *name;
uint32_t opcode;
};
static const struct method display_methods[] = {
{ "get_interface", 0 },
{ "create_surface", 1 },
{ NULL }
};
static const struct method surface_methods[] = {
{ "get_interface", 0 },
{ "post", 1 },
{ NULL }
};
struct interface {
const char *name;
const struct method *methods;
};
static const struct interface interfaces[] = {
{ "display", display_methods },
{ "surface", surface_methods },
{ NULL },
};
int send_request(int sock, const char *buffer, int buffer_len)
static uint32_t name_cairo_surface(int fd, cairo_surface_t *surface)
{
const struct method *methods;
char interface[32], method[32];
uint32_t request[3], id, new_id;
int i;
if (sscanf(buffer, "%d/%32[^:]:%32s %d\n",
&id, interface, method, &new_id) != 4) {
printf("invalid input, expected <id>/<interface>:<method>\n");
return -1;
}
struct drm_i915_gem_create create;
struct drm_gem_flink flink;
struct drm_i915_gem_pwrite pwrite;
int32_t width, height, stride;
width = cairo_image_surface_get_width(surface);
height = cairo_image_surface_get_height(surface);
stride = cairo_image_surface_get_stride(surface);
printf("got object id %d, interface \"%s\", name \"%s\"\n",
id, interface, method);
memset(&create, 0, sizeof(create));
create.size = height * stride;
for (i = 0; interfaces[i].name != NULL; i++) {
if (strcmp(interfaces[i].name, interface) == 0)
break;
if (ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create) != 0) {
fprintf(stderr, "gem create failed: %m\n");
return 0;
}
if (interfaces[i].name == NULL) {
printf("unknown interface \"%s\"\n", interface);
return -1;
pwrite.handle = create.handle;
pwrite.offset = 0;
pwrite.size = height * stride;
pwrite.data_ptr = (uint64_t) (uintptr_t)
cairo_image_surface_get_data(surface);
if (ioctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &pwrite) < 0) {
fprintf(stderr, "gem pwrite failed: %m\n");
return 0;
}
methods = interfaces[i].methods;
for (i = 0; methods[i].name != NULL; i++) {
if (strcmp(methods[i].name, method) == 0)
break;
flink.handle = create.handle;
if (ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink) != 0) {
fprintf(stderr, "gem flink failed: %m\n");
return 0;
}
if (methods[i].name == NULL) {
printf("unknown request \"%s\"\n", method);
return -1;
#if 0
/* We need to hold on to the handle until the server has received
* the attach request... we probably need a confirmation event.
* I guess the breadcrumb idea will suffice. */
struct drm_gem_close close;
close.handle = create.handle;
if (ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close) < 0) {
fprintf(stderr, "gem close failed: %m\n");
return 0;
}
#endif
request[0] = id;
request[1] = methods[i].opcode;
request[2] = new_id;
return flink.name;
}
static void *
draw_stuff(int width, int height)
{
cairo_surface_t *surface;
cairo_t *cr;
return write(sock, request, sizeof request);
surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
width, height);
cr = cairo_create(surface);
cairo_arc(cr, width / 2, height / 2, width / 2 - 10, 0, 2 * M_PI);
cairo_set_source_rgb(cr, 1, 0, 0);
cairo_fill_preserve(cr);
cairo_set_source_rgb(cr, 1, 1, 0);
cairo_stroke(cr);
cairo_arc(cr, width / 2, height / 2, width / 4 - 10, 0, 2 * M_PI);
cairo_set_source_rgb(cr, 0, 0, 1);
cairo_fill_preserve(cr);
cairo_set_source_rgb(cr, 1, 1, 0);
cairo_stroke(cr);
cairo_destroy(cr);
return surface;
}
int main(int argc, char *argv[])
{
struct sockaddr_un name;
socklen_t size;
int sock, len;
char buffer[256];
struct wl_connection *connection;
struct wl_display *display;
struct wl_surface *surface;
int width = 300, height = 300, fd;
uint32_t name;
cairo_surface_t *s;
fd = open(gem_device, O_RDWR);
if (fd < 0) {
fprintf(stderr, "drm open failed: %m\n");
return -1;
}
sock = socket(PF_LOCAL, SOCK_STREAM, 0);
if (sock < 0)
connection = wl_connection_create(socket_name);
if (connection == NULL) {
fprintf(stderr, "failed to create connection: %m\n");
return -1;
}
display = wl_connection_get_display(connection);
name.sun_family = AF_LOCAL;
memcpy(name.sun_path, socket_name, sizeof socket_name);
surface = wl_display_create_surface(display);
size = offsetof (struct sockaddr_un, sun_path) + sizeof socket_name;
s = draw_stuff(width, height);
name = name_cairo_surface(fd, s);
if (connect (sock, (struct sockaddr *) &name, size) < 0)
wl_surface_attach(surface, name, width, height,
cairo_image_surface_get_stride(s));
if (wl_connection_flush(connection) < 0) {
fprintf(stderr, "flush error: %m\n");
return -1;
}
while (len = read(STDIN_FILENO, buffer, sizeof buffer), len > 0)
if (send_request(sock, buffer, len) < 0)
break;
while (1)
wl_connection_iterate(connection);
return 0;
}

@ -0,0 +1,131 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <i915_drm.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/fb.h>
#include "wayland.h"
struct lame_compositor {
struct wl_compositor base;
void *fb;
int32_t width, height, stride;
int gem_fd;
};
void notify_surface_create(struct wl_compositor *compositor,
struct wl_surface *surface)
{
}
void notify_surface_attach(struct wl_compositor *compositor,
struct wl_surface *surface, uint32_t name,
uint32_t width, uint32_t height, uint32_t stride)
{
struct lame_compositor *lc = (struct lame_compositor *) compositor;
struct drm_i915_gem_pread pread;
struct drm_gem_open open_arg;
struct drm_gem_close close_arg;
char *data, *dst;
int i, ret, x = 600, y = 200;
open_arg.name = name;
ret = ioctl(lc->gem_fd, DRM_IOCTL_GEM_OPEN, &open_arg);
if (ret != 0) {
fprintf(stderr, "failed to gem_open name %d, fd=%d: %m\n", name, lc->gem_fd);
return;
}
data = malloc(open_arg.size);
if (data == NULL) {
fprintf(stderr, "swap buffers malloc failed\n");
return;
}
pread.size = open_arg.size;
pread.handle = open_arg.handle;
pread.pad = 0;
pread.offset = 0;
pread.size = stride * height;
pread.data_ptr = (long) data;
if (ioctl(lc->gem_fd, DRM_IOCTL_I915_GEM_PREAD, &pread)) {
fprintf(stderr, "gem pread failed");
return;
}
dst = lc->fb + lc->stride * y + x * 4;
for (i = 0; i < height; i++)
memcpy(dst + lc->stride * i, data + stride * i, width * 4);
close_arg.handle = open_arg.handle;
ret = ioctl(lc->gem_fd, DRM_IOCTL_GEM_CLOSE, &close_arg);
if (ret != 0) {
fprintf(stderr, "failed to gem_close name %d: %m\n", name);
}
free(data);
}
struct wl_compositor_interface interface = {
notify_surface_create,
notify_surface_attach
};
static const char fb_device[] = "/dev/fb";
static const char gem_device[] = "/dev/dri/card0";
struct wl_compositor *
wl_compositor_create(void)
{
struct lame_compositor *lc;
struct fb_fix_screeninfo fix;
struct fb_var_screeninfo var;
int fd;
lc = malloc(sizeof *lc);
if (lc == NULL)
return NULL;
lc->base.interface = &interface;
fd = open(fb_device, O_RDWR);
if (fd < 0) {
fprintf(stderr, "open %s failed: %m\n", fb_device);
return NULL;
}
if (ioctl(fd, FBIOGET_FSCREENINFO, &fix) < 0) {
fprintf(stderr, "fb get fixed failed\n");
return NULL;
}
if (ioctl(fd, FBIOGET_VSCREENINFO, &var) < 0) {
fprintf(stderr, "fb get fixed failed\n");
return NULL;
}
lc->stride = fix.line_length;
lc->width = var.xres;
lc->height = var.yres;
lc->fb = mmap(NULL, lc->stride * lc->height,
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
if (lc->fb == MAP_FAILED) {
fprintf(stderr, "fb map failed\n");
return NULL;
}
lc->gem_fd = open(gem_device, O_RDWR);
if (lc->gem_fd < 0) {
fprintf(stderr, "failed to open drm device\n");
return NULL;
}
return &lc->base;
}

@ -60,6 +60,24 @@ wl_event_loop_remove_source(struct wl_event_loop *loop,
return epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
}
int
wl_event_loop_update_source(struct wl_event_loop *loop,
struct wl_event_source *source,
uint32_t mask)
{
struct epoll_event ep;
ep.events = 0;
if (mask & WL_EVENT_READABLE)
ep.events |= EPOLLIN;
if (mask & WL_EVENT_WRITEABLE)
ep.events |= EPOLLOUT;
ep.data.ptr = source;
return epoll_ctl(loop->epoll_fd,
EPOLL_CTL_MOD, source->fd, &ep);
}
struct wl_event_loop *
wl_event_loop_create(void)
{
@ -93,6 +111,7 @@ wl_event_loop_wait(struct wl_event_loop *loop)
struct epoll_event ep[32];
struct wl_event_source *source;
int i, count;
uint32_t mask;
count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), -1);
if (count < 0)
@ -100,7 +119,13 @@ wl_event_loop_wait(struct wl_event_loop *loop)
for (i = 0; i < count; i++) {
source = ep[i].data.ptr;
source->func(source->fd, ep[i].events, source->data);
mask = 0;
if (ep[i].events & EPOLLIN)
mask |= WL_EVENT_READABLE;
if (ep[i].events & EPOLLOUT)
mask |= WL_EVENT_WRITEABLE;
source->func(source->fd, mask, source->data);
}
return 0;

@ -0,0 +1,214 @@
#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <ctype.h>
#include <sys/poll.h>
static const char socket_name[] = "\0wayland";
struct wl_buffer {
char data[4096];
int head, tail;
};
struct wl_connection {
int fd;
struct wl_buffer in, out;
struct wl_display *display;
uint32_t id;
};
struct wl_proxy {
struct wl_connection *connection;
uint32_t id;
};
struct wl_display {
struct wl_proxy proxy;
};
struct wl_surface {
struct wl_proxy proxy;
};
struct wl_connection *
wl_connection_create(const char *address)
{
struct wl_connection *connection;
struct wl_display *display;
struct sockaddr_un name;
socklen_t size;
char buffer[256];
uint32_t id, length;
connection = malloc(sizeof *connection);
if (connection == NULL)
return NULL;
memset(connection, 0, sizeof *connection);
connection->id = 256; /* Need to get our id-range. */
connection->fd = socket(PF_LOCAL, SOCK_STREAM, 0);
if (connection->fd < 0) {
free(connection);
return NULL;
}
name.sun_family = AF_LOCAL;
memcpy(name.sun_path, address, strlen(address + 1) + 2);
size = offsetof (struct sockaddr_un, sun_path) + sizeof socket_name;
if (connect (connection->fd, (struct sockaddr *) &name, size) < 0) {
close(connection->fd);
free(connection);
return NULL;
}
/* FIXME: actually discover advertised objects here. */
read(connection->fd, &id, sizeof id);
read(connection->fd, &length, sizeof length);
read(connection->fd, buffer, (length + 3) & ~3);
display = malloc(sizeof *display);
display->proxy.connection = connection;
display->proxy.id = id;
connection->display = display;
return connection;
}
void
wl_connection_destroy(struct wl_connection *connection)
{
close(connection->fd);
free(connection->display);
free(connection);
}
int
wl_connection_get_fd(struct wl_connection *connection)
{
return connection->fd;
}
static void
handle_event(struct wl_connection *connection)
{
struct wl_buffer *b;
uint32_t *p, opcode, size;
b = &connection->in;
p = (uint32_t *) (b->data + b->tail);
opcode = p[1] & 0xffff;
size = p[1] >> 16;
printf("signal from object %d, opcode %d, size %d\n",
p[0], opcode, size);
b->tail += size;
}
void
wl_connection_iterate(struct wl_connection *connection)
{
struct wl_buffer *b;
uint32_t *p, opcode, size;
int len;
b = &connection->in;
len = read(connection->fd, b->data + b->head, sizeof b->data);
b->head += len;
while (len > 0) {
if (b->head - b->tail < 8)
break;
p = (uint32_t *) (b->data + b->tail);
opcode = p[1] & 0xffff;
size = p[1] >> 16;
if (b->head - b->tail < size)
break;
handle_event(connection);
}
if (len < 0) {
fprintf(stderr, "read error: %m\n");
exit(EXIT_FAILURE);
}
}
int
wl_connection_flush(struct wl_connection *connection)
{
struct wl_buffer *b;
int len;
b = &connection->out;
if (b->head == b->tail)
return 0;
len = write(connection->fd, b->data + b->tail, b->head - b->tail);
b->tail += len;
return len;
};
struct wl_display *
wl_connection_get_display(struct wl_connection *connection)
{
return connection->display;
}
#define WL_DISPLAY_CREATE_SURFACE 0
struct wl_surface *
wl_display_create_surface(struct wl_display *display)
{
struct wl_surface *surface;
struct wl_connection *connection;
uint32_t request[3];
surface = malloc(sizeof *surface);
if (surface == NULL)
return NULL;
connection = display->proxy.connection;
surface->proxy.id = connection->id++;
surface->proxy.connection = connection;
request[0] = display->proxy.id;
request[1] = WL_DISPLAY_CREATE_SURFACE | ((sizeof request) << 16);
request[2] = surface->proxy.id;
memcpy(connection->out.data + connection->out.head,
request, sizeof request);
connection->out.head += sizeof request;
return surface;
}
#define WL_SURFACE_ATTACH 0
void wl_surface_attach(struct wl_surface *surface,
uint32_t name, int width, int height, int stride)
{
uint32_t request[6];
struct wl_connection *connection;
request[0] = surface->proxy.id;
request[1] = WL_SURFACE_ATTACH | ((sizeof request) << 16);
request[2] = name;
request[3] = width;
request[4] = height;
request[5] = stride;
connection = surface->proxy.connection;
memcpy(connection->out.data + connection->out.head,
request, sizeof request);
connection->out.head += sizeof request;
}

@ -0,0 +1,28 @@
#ifndef _WAYLAND_CLIENT_H
#define _WAYLAND_CLIENT_H
struct wl_connection;
struct wl_display;
struct wl_surface;
struct wl_connection *
wl_connection_create(const char *address);
void
wl_connection_destroy(struct wl_connection *connection);
int
wl_connection_get_fd(struct wl_connection *connection);
void
wl_connection_iterate(struct wl_connection *connection);
int
wl_connection_flush(struct wl_connection *connection);
struct wl_display *
wl_connection_get_display(struct wl_connection *connection);
struct wl_surface *
wl_display_create_surface(struct wl_display *display);
void
wl_surface_attach(struct wl_surface *surface,
uint32_t name, int width, int height, int stride);
#endif

@ -15,8 +15,13 @@
struct wl_region {
};
struct wl_buffer {
char data[4096];
int head, tail;
};
struct wl_client {
char protocol_buffer[4096];
struct wl_buffer input, output;
struct wl_event_source *source;
struct wl_display *display;
};
@ -25,6 +30,9 @@ struct wl_display {
struct wl_object base;
struct wl_event_loop *loop;
struct wl_hash objects;
struct wl_compositor *compositor;
struct wl_compositor_interface *compositor_interface;
};
struct wl_surface {
@ -46,29 +54,18 @@ struct wl_surface {
};
static void
wl_surface_get_interface(struct wl_client *client,
struct wl_surface *surface,
const char *interface, uint32_t id)
wl_surface_attach(struct wl_client *client,
struct wl_surface *surface, uint32_t name,
uint32_t width, uint32_t height, uint32_t stride)
{
/* client sends a new object id, and an interface identifier
* to name the object that implements the interface */
printf("surface::get_interface\n");
}
struct wl_compositor_interface *interface;
static const struct wl_argument get_interface_arguments[] = {
{ WL_ARGUMENT_STRING },
{ WL_ARGUMENT_NEW_ID }
};
static void
wl_surface_post(struct wl_client *client,
struct wl_surface *surface, uint32_t name,
uint32_t width, uint32_t height, uint32_t stride)
{
printf("surface::post\n");
interface = client->display->compositor->interface;
interface->notify_surface_attach(client->display->compositor,
surface, name, width, height, stride);
}
static const struct wl_argument post_arguments[] = {
static const struct wl_argument attach_arguments[] = {
{ WL_ARGUMENT_UINT32 },
{ WL_ARGUMENT_UINT32 },
{ WL_ARGUMENT_UINT32 },
@ -89,10 +86,8 @@ static const struct wl_argument update_arguments[] = {
};
static const struct wl_method surface_methods[] = {
{ "get_interface", wl_surface_get_interface,
ARRAY_LENGTH(get_interface_arguments), get_interface_arguments },
{ "post", wl_surface_post,
ARRAY_LENGTH(post_arguments), post_arguments }
{ "attach", wl_surface_attach,
ARRAY_LENGTH(attach_arguments), attach_arguments }
};
static const struct wl_interface surface_interface = {
@ -105,6 +100,7 @@ struct wl_surface *
wl_surface_create(struct wl_display *display, uint32_t id)
{
struct wl_surface *surface;
struct wl_compositor_interface *interface;
surface = malloc(sizeof *surface);
if (surface == NULL)
@ -112,12 +108,9 @@ wl_surface_create(struct wl_display *display, uint32_t id)
surface->base.id = id;
surface->base.interface = &surface_interface;
/* doesn't create any pixel buffers, just the wl_surface
* object. the client allocates and attaches pixel buffers
* itself and renders to them, then posts them using
* wl_window_post. */
/* add to display list */
interface = display->compositor->interface;
interface->notify_surface_create(display->compositor, surface);
return surface;
}
@ -125,6 +118,28 @@ wl_surface_create(struct wl_display *display, uint32_t id)
static void
wl_client_data(int fd, uint32_t mask, void *data);
static int
advertise_object(struct wl_client *client, struct wl_object *object)
{
const struct wl_interface *interface;
uint32_t length, *p;
interface = object->interface;
p = (uint32_t *) (client->output.data + client->output.head);
length = strlen(interface->name);
*p++ = object->id;
*p++ = length;
memcpy(p, interface->name, length);
memset((char *) p + length, 0, -length & 3);
client->output.head += 8 + ((length + 3) & ~3);
wl_event_loop_update_source(client->display->loop, client->source,
WL_EVENT_READABLE | WL_EVENT_WRITEABLE);
return 0;
}
struct wl_client *
wl_client_create(struct wl_display *display, int fd)
{
@ -134,22 +149,13 @@ wl_client_create(struct wl_display *display, int fd)
if (client == NULL)
return NULL;
memset(client, 0, sizeof *client);
client->display = display;
client->source = wl_event_loop_add_fd(display->loop, fd,
WL_EVENT_READABLE |
WL_EVENT_READABLE,
wl_client_data, client);
printf("new client: %p\n", client);
/* Send global objects to client in hand shake response, eg:
*
* display: 0,
* glyph_cache: 1
* some other extension global object: 2
*
* etc */
advertise_object(client, &display->base);
return client;
}
@ -164,7 +170,7 @@ wl_client_destroy(struct wl_client *client)
static void
demarshal(struct wl_client *client, struct wl_object *target,
const struct wl_method *method, uint32_t *data, int len)
const struct wl_method *method, uint32_t *data)
{
ffi_type *types[10];
ffi_cif cif;
@ -198,11 +204,9 @@ demarshal(struct wl_client *client, struct wl_object *target,
case WL_ARGUMENT_UINT32:
types[i + 2] = &ffi_type_uint32;
values[i + 2].uint32 = *p;
printf("got uint32 (%d)\n", *p);
p++;
break;
case WL_ARGUMENT_STRING:
printf("got string\n");
types[i + 2] = &ffi_type_pointer;
/* FIXME */
values[i + 2].uint32 = *p++;
@ -215,7 +219,6 @@ demarshal(struct wl_client *client, struct wl_object *target,
if (object->interface != method->arguments[i].data)
printf("wrong object type\n");
values[i + 2].object = object;
printf("got object (%d)\n", *p);
p++;
break;
case WL_ARGUMENT_NEW_ID:
@ -224,7 +227,6 @@ demarshal(struct wl_client *client, struct wl_object *target,
object = wl_hash_lookup(&client->display->objects, *p);
if (object != NULL)
printf("object already exists (%d)\n", *p);
printf("got new_id (%d)\n", *p);
p++;
break;
default:
@ -239,75 +241,107 @@ demarshal(struct wl_client *client, struct wl_object *target,
ffi_call(&cif, FFI_FN(method->func), &result, args);
}
static void
wl_client_event(struct wl_client *client, struct wl_object *object, uint32_t event)
{
const struct wl_interface *interface;
uint32_t *p;
interface = object->interface;
p = (void *) client->output.data + client->output.head;
p[0] = object->id;
p[1] = event | (8 << 16);
client->output.head += 8;
wl_event_loop_update_source(client->display->loop, client->source,
WL_EVENT_READABLE | WL_EVENT_WRITEABLE);
}
#define WL_DISPLAY_INVALID_OBJECT 0
#define WL_DISPLAY_INVALID_METHOD 1
static void
wl_client_process_input(struct wl_client *client)
{
const struct wl_method *method;
struct wl_object *object;
uint32_t *p, opcode, size;
while (1) {
if (client->input.head - client->input.tail < 2 * sizeof *p)
break;
p = (uint32_t *) (client->input.data + client->input.tail);
opcode = p[1] & 0xffff;
size = p[1] >> 16;
if (client->input.head - client->input.tail < size)
break;
object = wl_hash_lookup(&client->display->objects,
p[0]);
if (object == NULL) {
wl_client_event(client, &client->display->base,
WL_DISPLAY_INVALID_OBJECT);
client->input.tail += size;
continue;
}
if (opcode >= object->interface->method_count) {
wl_client_event(client, &client->display->base,
WL_DISPLAY_INVALID_METHOD);
client->input.tail += size;
continue;
}
method = &object->interface->methods[opcode];
demarshal(client, object, method, p + 2);
client->input.tail += size;
}
}
static void
wl_client_data(int fd, uint32_t mask, void *data)
{
struct wl_client *client = data;
struct wl_object *object;
const struct wl_method *method;
char buffer[256];
uint32_t *p;
int len;
if (mask & WL_EVENT_READABLE) {
len = read(fd, buffer, sizeof buffer);
if (len == 0) {
wl_client_destroy(client);
len = read(fd, client->input.data, sizeof client->input.data);
if (len > 0) {
client->input.head += len;
wl_client_process_input(client);
} else if (len == 0 && errno == ECONNRESET) {
fprintf(stderr,
"read from client %p: %m (%d)\n",
client, errno);
} else {
printf("got %d bytes from client %p\n",
len, client);
if (len < 2 * sizeof *p)
/* read more... */
return;
p = (uint32_t *) buffer;
object = wl_hash_lookup(&client->display->objects,
p[0]);
if (object == NULL) {
/* send error */
printf("invalid object\n");
return;
}
if (p[1] >= object->interface->method_count) {
/* send error */
printf("invalid method\n");
return;
}
method = &object->interface->methods[p[1]];
printf("calling method %s on interface %s\n",
method->name, object->interface->name);
demarshal(client, object, method, p + 2, len - 8);
wl_client_destroy(client);
}
}
if (mask & WL_EVENT_WRITEABLE) {
len = write(fd, client->output.data + client->output.tail,
client->output.head - client->output.tail);
client->output.tail += len;
if (client->output.tail == client->output.head)
wl_event_loop_update_source(client->display->loop,
client->source,
WL_EVENT_READABLE);
}
}
static void
wl_display_get_interface(struct wl_client *client,
struct wl_display *display,
const char *interface, uint32_t id)
{
/* client sends a new object id, and an interface identifier
* to name the object that implements the interface */
printf("display::get_interface\n");
}
static int
wl_display_create_surface(struct wl_client *client,
struct wl_display *display, uint32_t id)
{
struct wl_surface *surface;
printf("display::create_surface, client %p, display %p, new_id=%d\n",
client, display, id);
surface = wl_surface_create(display, id);
wl_hash_insert(&display->objects, &surface->base);
/* FIXME: garbage collect client resources when client exits. */
return 0;
}
@ -316,14 +350,19 @@ static const struct wl_argument create_surface_arguments[] = {
};
static const struct wl_method display_methods[] = {
{ "get_interface", wl_display_get_interface,
ARRAY_LENGTH(get_interface_arguments), get_interface_arguments },
{ "create_surface", wl_display_create_surface,
ARRAY_LENGTH(create_surface_arguments), create_surface_arguments },
};
static const struct wl_event display_events[] = {
{ "invalid_object" },
{ "invalid_method" },
};
static const struct wl_interface display_interface = {
"display", 1, ARRAY_LENGTH(display_methods), display_methods,
"display", 1,
ARRAY_LENGTH(display_methods), display_methods,
ARRAY_LENGTH(display_events), display_events,
};
struct wl_display *
@ -348,6 +387,13 @@ wl_display_create(void)
return display;
}
void
wl_display_set_compositor(struct wl_display *display,
struct wl_compositor *compositor)
{
display->compositor = compositor;
}
void
wl_display_run(struct wl_display *display)
{
@ -397,7 +443,8 @@ wl_display_add_socket(struct wl_display *display)
if (listen(sock, 1) < 0)
return -1;
wl_event_loop_add_fd(display->loop, sock, WL_EVENT_READABLE,
wl_event_loop_add_fd(display->loop, sock,
WL_EVENT_READABLE,
socket_data, display);
return 0;
@ -407,6 +454,7 @@ wl_display_add_socket(struct wl_display *display)
int main(int argc, char *argv[])
{
struct wl_display *display;
struct wl_compositor *compositor;
display = wl_display_create();
@ -415,6 +463,9 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
compositor = wl_compositor_create();
wl_display_set_compositor(display, compositor);
printf("wayland online, display is %p\n", display);
wl_display_run(display);

@ -18,6 +18,10 @@ struct wl_event_source *wl_event_loop_add_fd(struct wl_event_loop *loop,
int fd, uint32_t mask,
wl_event_loop_func_t func,
void *data);
int wl_event_loop_update_source(struct wl_event_loop *loop,
struct wl_event_source *source,
uint32_t mask);
int wl_event_loop_remove_source(struct wl_event_loop *loop,
struct wl_event_source *source);
int wl_event_loop_wait(struct wl_event_loop *loop);
@ -52,11 +56,17 @@ struct wl_method {
const struct wl_argument *arguments;
};
struct wl_event {
const char *name;
};
struct wl_interface {
const char *name;
int version;
int method_count;
const struct wl_method *methods;
int event_count;
const struct wl_event *events;
};
struct wl_object {
@ -64,4 +74,26 @@ struct wl_object {
uint32_t id;
};
struct wl_surface;
struct wl_display;
struct wl_compositor {
struct wl_compositor_interface *interface;
};
struct wl_compositor_interface {
void (*notify_surface_create)(struct wl_compositor *compositor,
struct wl_surface *surface);
void (*notify_surface_attach)(struct wl_compositor *compositor,
struct wl_surface *surface, uint32_t name,
uint32_t width, uint32_t height, uint32_t stride);
};
struct wl_compositor *wl_compositor_create(void);
void wl_display_set_compositor(struct wl_display *display,
struct wl_compositor *compositor);
#endif

Loading…
Cancel
Save