5ee1a60f1a
Instead of having the input driver push the events into the core server, only to have the server call back out to the compositor hooks, the driver now just calls the compositor directly. The input drivers are always dependent on the type of compositor anyway so there was no point in passing the events through the server. Now the server is only involved when it's time to actually send the events to the clients.
745 lines
18 KiB
C
745 lines
18 KiB
C
/*
|
|
* Copyright © 2008 Kristian Høgsberg
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
* documentation for any purpose is hereby granted without fee, provided that
|
|
* the above copyright notice appear in all copies and that both that copyright
|
|
* notice and this permission notice appear in supporting documentation, and
|
|
* that the name of the copyright holders not be used in advertising or
|
|
* publicity pertaining to distribution of the software without specific,
|
|
* written prior permission. The copyright holders make no representations
|
|
* about the suitability of this software for any purpose. It is provided "as
|
|
* is" without express or implied warranty.
|
|
*
|
|
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
|
* OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
#include <dlfcn.h>
|
|
#include <assert.h>
|
|
#include <ffi.h>
|
|
|
|
#include "wayland.h"
|
|
#include "connection.h"
|
|
|
|
struct wl_client {
|
|
struct wl_connection *connection;
|
|
struct wl_event_source *source;
|
|
struct wl_display *display;
|
|
struct wl_list object_list;
|
|
struct wl_list link;
|
|
uint32_t pending_frame;
|
|
};
|
|
|
|
struct wl_display {
|
|
struct wl_object base;
|
|
struct wl_event_loop *loop;
|
|
struct wl_hash objects;
|
|
|
|
struct wl_object *pointer;
|
|
|
|
struct wl_compositor *compositor;
|
|
struct wl_compositor_interface *compositor_interface;
|
|
|
|
struct wl_list surface_list;
|
|
struct wl_list client_list;
|
|
uint32_t client_id_range;
|
|
uint32_t id;
|
|
|
|
struct wl_list global_list;
|
|
};
|
|
|
|
struct wl_surface {
|
|
struct wl_object base;
|
|
|
|
struct wl_client *client;
|
|
/* provided by client */
|
|
int width, height;
|
|
int buffer;
|
|
int stride;
|
|
|
|
struct wl_map map;
|
|
struct wl_list link;
|
|
|
|
/* how to convert buffer contents to pixels in screen format;
|
|
* yuv->rgb, indexed->rgb, svg->rgb, but mostly just rgb->rgb. */
|
|
|
|
/* how to transform/render rectangular contents to polygons. */
|
|
|
|
void *compositor_data;
|
|
};
|
|
|
|
struct wl_object_ref {
|
|
struct wl_object *object;
|
|
struct wl_list link;
|
|
};
|
|
|
|
static void
|
|
wl_surface_destroy(struct wl_client *client,
|
|
struct wl_surface *surface)
|
|
{
|
|
const struct wl_compositor_interface *interface;
|
|
|
|
interface = client->display->compositor->interface;
|
|
interface->notify_surface_destroy(client->display->compositor,
|
|
surface);
|
|
wl_list_remove(&surface->link);
|
|
}
|
|
|
|
static void
|
|
wl_surface_attach(struct wl_client *client,
|
|
struct wl_surface *surface, uint32_t name,
|
|
uint32_t width, uint32_t height, uint32_t stride)
|
|
{
|
|
const struct wl_compositor_interface *interface;
|
|
|
|
interface = client->display->compositor->interface;
|
|
interface->notify_surface_attach(client->display->compositor,
|
|
surface, name, width, height, stride);
|
|
}
|
|
|
|
static void
|
|
wl_surface_map(struct wl_client *client, struct wl_surface *surface,
|
|
int32_t x, int32_t y, int32_t width, int32_t height)
|
|
{
|
|
const struct wl_compositor_interface *interface;
|
|
|
|
/* FIXME: This needs to take a tri-mesh argument... - count
|
|
* and a list of tris. 0 tris means unmap. */
|
|
|
|
surface->map.x = x;
|
|
surface->map.y = y;
|
|
surface->map.width = width;
|
|
surface->map.height = height;
|
|
|
|
interface = client->display->compositor->interface;
|
|
interface->notify_surface_map(client->display->compositor,
|
|
surface, &surface->map);
|
|
}
|
|
|
|
static void
|
|
wl_surface_copy(struct wl_client *client, struct wl_surface *surface,
|
|
int32_t dst_x, int32_t dst_y, uint32_t name, uint32_t stride,
|
|
int32_t x, int32_t y, int32_t width, int32_t height)
|
|
{
|
|
const struct wl_compositor_interface *interface;
|
|
|
|
interface = client->display->compositor->interface;
|
|
interface->notify_surface_copy(client->display->compositor,
|
|
surface, dst_x, dst_y,
|
|
name, stride, x, y, width, height);
|
|
}
|
|
|
|
static void
|
|
wl_surface_damage(struct wl_client *client, struct wl_surface *surface,
|
|
int32_t x, int32_t y, int32_t width, int32_t height)
|
|
{
|
|
const struct wl_compositor_interface *interface;
|
|
|
|
interface = client->display->compositor->interface;
|
|
interface->notify_surface_damage(client->display->compositor,
|
|
surface, x, y, width, height);
|
|
}
|
|
|
|
static const struct wl_method surface_methods[] = {
|
|
{ "destroy", wl_surface_destroy, "" },
|
|
{ "attach", wl_surface_attach, "uuuu" },
|
|
{ "map", wl_surface_map, "iiii" },
|
|
{ "copy", wl_surface_copy, "iiuuiiii" },
|
|
{ "damage", wl_surface_damage, "iiii" }
|
|
};
|
|
|
|
static const struct wl_interface surface_interface = {
|
|
"surface", 1,
|
|
ARRAY_LENGTH(surface_methods),
|
|
surface_methods,
|
|
};
|
|
|
|
static struct wl_surface *
|
|
wl_surface_create(struct wl_display *display,
|
|
struct wl_client *client, uint32_t id)
|
|
{
|
|
struct wl_surface *surface;
|
|
const struct wl_compositor_interface *interface;
|
|
|
|
surface = malloc(sizeof *surface);
|
|
if (surface == NULL)
|
|
return NULL;
|
|
|
|
surface->base.id = id;
|
|
surface->base.interface = &surface_interface;
|
|
surface->client = client;
|
|
|
|
wl_list_insert(display->surface_list.prev, &surface->link);
|
|
|
|
interface = display->compositor->interface;
|
|
interface->notify_surface_create(display->compositor, surface);
|
|
|
|
return surface;
|
|
}
|
|
|
|
WL_EXPORT void
|
|
wl_surface_set_data(struct wl_surface *surface, void *data)
|
|
{
|
|
surface->compositor_data = data;
|
|
}
|
|
|
|
WL_EXPORT void *
|
|
wl_surface_get_data(struct wl_surface *surface)
|
|
{
|
|
return surface->compositor_data;
|
|
}
|
|
|
|
void
|
|
wl_client_destroy(struct wl_client *client);
|
|
|
|
static void
|
|
wl_client_vmarshal(struct wl_client *client, struct wl_object *sender,
|
|
uint32_t opcode, va_list ap)
|
|
{
|
|
const struct wl_event *event;
|
|
struct wl_object *object;
|
|
uint32_t args[10], size;
|
|
int i, count;
|
|
|
|
event = &sender->interface->events[opcode];
|
|
count = strlen(event->signature) + 2;
|
|
assert(count <= ARRAY_LENGTH(args));
|
|
|
|
size = 0;
|
|
for (i = 2; i < count; i++) {
|
|
switch (event->signature[i - 2]) {
|
|
case 'u':
|
|
case 'i':
|
|
args[i] = va_arg(ap, uint32_t);
|
|
size += sizeof args[i];
|
|
break;
|
|
case 's':
|
|
/* FIXME */
|
|
args[i] = 0;
|
|
size += sizeof args[i];
|
|
break;
|
|
case 'o':
|
|
object = va_arg(ap, struct wl_object *);
|
|
args[i] = object->id;
|
|
size += sizeof args[i];
|
|
break;
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
size += 2 * sizeof args[0];
|
|
args[0] = sender->id;
|
|
args[1] = opcode | (size << 16);
|
|
wl_connection_write(client->connection, args, size);
|
|
}
|
|
|
|
static void
|
|
wl_client_marshal(struct wl_client *client, struct wl_object *sender,
|
|
uint32_t opcode, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap, opcode);
|
|
wl_client_vmarshal(client, sender, opcode, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
static void
|
|
wl_client_demarshal(struct wl_client *client, struct wl_object *target,
|
|
const struct wl_method *method, size_t size)
|
|
{
|
|
ffi_type *types[20];
|
|
ffi_cif cif;
|
|
uint32_t *p, result;
|
|
int i, j, count;
|
|
union {
|
|
uint32_t uint32;
|
|
const char *string;
|
|
void *object;
|
|
uint32_t new_id;
|
|
} values[20];
|
|
void *args[20];
|
|
struct wl_object *object;
|
|
uint32_t data[64];
|
|
|
|
count = strlen(method->signature) + 2;
|
|
if (count > ARRAY_LENGTH(types)) {
|
|
printf("too many args (%d)\n", count);
|
|
return;
|
|
}
|
|
|
|
if (sizeof data < size) {
|
|
printf("request too big, should malloc tmp buffer here\n");
|
|
return;
|
|
}
|
|
|
|
types[0] = &ffi_type_pointer;
|
|
values[0].object = client;
|
|
args[0] = &values[0];
|
|
|
|
types[1] = &ffi_type_pointer;
|
|
values[1].object = target;
|
|
args[1] = &values[1];
|
|
|
|
wl_connection_copy(client->connection, data, size);
|
|
p = &data[2];
|
|
j = 0;
|
|
for (i = 2; i < count; i++) {
|
|
switch (method->signature[i - 2]) {
|
|
case 'u':
|
|
case 'i':
|
|
types[i] = &ffi_type_uint32;
|
|
values[i].uint32 = *p;
|
|
p++;
|
|
break;
|
|
case 's':
|
|
types[i] = &ffi_type_pointer;
|
|
/* FIXME */
|
|
values[i].uint32 = *p++;
|
|
break;
|
|
case 'o':
|
|
types[i] = &ffi_type_pointer;
|
|
object = wl_hash_lookup(&client->display->objects, *p);
|
|
if (object == NULL)
|
|
printf("unknown object (%d)\n", *p);
|
|
if (object->interface != method->types[j])
|
|
printf("wrong object type\n");
|
|
values[i].object = object;
|
|
p++;
|
|
j++;
|
|
break;
|
|
case 'n':
|
|
types[i] = &ffi_type_uint32;
|
|
values[i].new_id = *p;
|
|
object = wl_hash_lookup(&client->display->objects, *p);
|
|
if (object != NULL)
|
|
printf("object already exists (%d)\n", *p);
|
|
p++;
|
|
break;
|
|
default:
|
|
printf("unknown type\n");
|
|
break;
|
|
}
|
|
args[i] = &values[i];
|
|
}
|
|
|
|
ffi_prep_cif(&cif, FFI_DEFAULT_ABI, count, &ffi_type_uint32, types);
|
|
ffi_call(&cif, FFI_FN(method->func), &result, args);
|
|
}
|
|
|
|
#define WL_DISPLAY_INVALID_OBJECT 0
|
|
#define WL_DISPLAY_INVALID_METHOD 1
|
|
#define WL_DISPLAY_NO_MEMORY 2
|
|
#define WL_DISPLAY_ACKNOWLEDGE 3
|
|
#define WL_DISPLAY_FRAME 4
|
|
|
|
static void
|
|
wl_client_connection_data(int fd, uint32_t mask, void *data)
|
|
{
|
|
struct wl_client *client = data;
|
|
struct wl_connection *connection = client->connection;
|
|
const struct wl_method *method;
|
|
struct wl_object *object;
|
|
uint32_t p[2], opcode, size;
|
|
uint32_t cmask = 0;
|
|
int len;
|
|
|
|
if (mask & WL_EVENT_READABLE)
|
|
cmask |= WL_CONNECTION_READABLE;
|
|
if (mask & WL_EVENT_WRITEABLE)
|
|
cmask |= WL_CONNECTION_WRITABLE;
|
|
|
|
len = wl_connection_data(connection, cmask);
|
|
if (len < 0) {
|
|
wl_client_destroy(client);
|
|
return;
|
|
}
|
|
|
|
while (len >= sizeof p) {
|
|
wl_connection_copy(connection, p, sizeof p);
|
|
opcode = p[1] & 0xffff;
|
|
size = p[1] >> 16;
|
|
if (len < size)
|
|
break;
|
|
|
|
object = wl_hash_lookup(&client->display->objects, p[0]);
|
|
if (object == NULL) {
|
|
wl_client_marshal(client, &client->display->base,
|
|
WL_DISPLAY_INVALID_OBJECT, p[0]);
|
|
wl_connection_consume(connection, size);
|
|
len -= size;
|
|
continue;
|
|
}
|
|
|
|
if (opcode >= object->interface->method_count) {
|
|
wl_client_marshal(client, &client->display->base,
|
|
WL_DISPLAY_INVALID_METHOD, p[0], opcode);
|
|
wl_connection_consume(connection, size);
|
|
len -= size;
|
|
continue;
|
|
}
|
|
|
|
method = &object->interface->methods[opcode];
|
|
wl_client_demarshal(client, object, method, size);
|
|
wl_connection_consume(connection, size);
|
|
len -= size;
|
|
}
|
|
}
|
|
|
|
static int
|
|
wl_client_connection_update(struct wl_connection *connection,
|
|
uint32_t mask, void *data)
|
|
{
|
|
struct wl_client *client = data;
|
|
uint32_t emask = 0;
|
|
|
|
if (mask & WL_CONNECTION_READABLE)
|
|
emask |= WL_EVENT_READABLE;
|
|
if (mask & WL_CONNECTION_WRITABLE)
|
|
emask |= WL_EVENT_WRITEABLE;
|
|
|
|
return wl_event_source_fd_update(client->source, mask);
|
|
}
|
|
|
|
static void
|
|
advertise_object(struct wl_client *client, struct wl_object *object)
|
|
{
|
|
const struct wl_interface *interface;
|
|
static const char pad[4];
|
|
uint32_t length, p[2];
|
|
|
|
interface = object->interface;
|
|
length = strlen(interface->name);
|
|
p[0] = object->id;
|
|
p[1] = length;
|
|
wl_connection_write(client->connection, p, sizeof p);
|
|
wl_connection_write(client->connection, interface->name, length);
|
|
wl_connection_write(client->connection, pad, -length & 3);
|
|
}
|
|
|
|
static struct wl_client *
|
|
wl_client_create(struct wl_display *display, int fd)
|
|
{
|
|
struct wl_client *client;
|
|
struct wl_object_ref *ref;
|
|
uint32_t count;
|
|
|
|
client = malloc(sizeof *client);
|
|
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_client_connection_data, client);
|
|
client->connection = wl_connection_create(fd,
|
|
wl_client_connection_update,
|
|
client);
|
|
wl_list_init(&client->object_list);
|
|
|
|
wl_connection_write(client->connection,
|
|
&display->client_id_range,
|
|
sizeof display->client_id_range);
|
|
display->client_id_range += 256;
|
|
|
|
/* Write list of global objects to client. */
|
|
count = wl_list_length(&display->global_list);
|
|
wl_connection_write(client->connection, &count, sizeof count);
|
|
|
|
ref = container_of(display->global_list.next,
|
|
struct wl_object_ref, link);
|
|
while (&ref->link != &display->global_list) {
|
|
advertise_object(client, ref->object);
|
|
|
|
ref = container_of(ref->link.next,
|
|
struct wl_object_ref, link);
|
|
}
|
|
|
|
wl_list_insert(display->client_list.prev, &client->link);
|
|
|
|
return client;
|
|
}
|
|
|
|
void
|
|
wl_client_destroy(struct wl_client *client)
|
|
{
|
|
struct wl_object_ref *ref;
|
|
|
|
printf("disconnect from client %p\n", client);
|
|
|
|
wl_list_remove(&client->link);
|
|
|
|
while (client->object_list.next != &client->object_list) {
|
|
ref = container_of(client->object_list.next,
|
|
struct wl_object_ref, link);
|
|
wl_list_remove(&ref->link);
|
|
wl_surface_destroy(client, (struct wl_surface *) ref->object);
|
|
free(ref);
|
|
}
|
|
|
|
wl_event_source_remove(client->source);
|
|
wl_connection_destroy(client->connection);
|
|
free(client);
|
|
}
|
|
|
|
static int
|
|
wl_display_create_surface(struct wl_client *client,
|
|
struct wl_display *display, uint32_t id)
|
|
{
|
|
struct wl_surface *surface;
|
|
struct wl_object_ref *ref;
|
|
|
|
surface = wl_surface_create(display, client, id);
|
|
|
|
ref = malloc(sizeof *ref);
|
|
if (ref == NULL) {
|
|
wl_client_marshal(client, &display->base,
|
|
WL_DISPLAY_NO_MEMORY);
|
|
return -1;
|
|
}
|
|
|
|
ref->object = &surface->base;
|
|
wl_hash_insert(&display->objects, &surface->base);
|
|
wl_list_insert(client->object_list.prev, &ref->link);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
wl_display_commit(struct wl_client *client,
|
|
struct wl_display *display, uint32_t key)
|
|
{
|
|
const struct wl_compositor_interface *interface;
|
|
uint32_t frame;
|
|
|
|
client->pending_frame = 1;
|
|
|
|
interface = display->compositor->interface;
|
|
frame = interface->notify_commit(display->compositor);
|
|
wl_client_marshal(client, &display->base,
|
|
WL_DISPLAY_ACKNOWLEDGE, key, frame);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct wl_method display_methods[] = {
|
|
{ "create_surface", wl_display_create_surface, "n" },
|
|
{ "commit", wl_display_commit, "u" }
|
|
};
|
|
|
|
static const struct wl_event display_events[] = {
|
|
{ "invalid_object", "u" },
|
|
{ "invalid_method", "uu" },
|
|
{ "no_memory", "" },
|
|
{ "acknowledge", "uu" },
|
|
{ "frame", "uu" }
|
|
};
|
|
|
|
static const struct wl_interface display_interface = {
|
|
"display", 1,
|
|
ARRAY_LENGTH(display_methods), display_methods,
|
|
ARRAY_LENGTH(display_events), display_events,
|
|
};
|
|
|
|
WL_EXPORT struct wl_display *
|
|
wl_display_create(void)
|
|
{
|
|
struct wl_display *display;
|
|
|
|
display = malloc(sizeof *display);
|
|
if (display == NULL)
|
|
return NULL;
|
|
|
|
display->loop = wl_event_loop_create();
|
|
if (display->loop == NULL) {
|
|
free(display);
|
|
return NULL;
|
|
}
|
|
|
|
wl_list_init(&display->surface_list);
|
|
wl_list_init(&display->client_list);
|
|
wl_list_init(&display->global_list);
|
|
|
|
display->client_id_range = 256; /* Gah, arbitrary... */
|
|
|
|
display->id = 1;
|
|
display->base.interface = &display_interface;
|
|
wl_display_add_object(display, &display->base);
|
|
if (wl_display_add_global(display, &display->base)) {
|
|
wl_event_loop_destroy(display->loop);
|
|
free(display);
|
|
return NULL;
|
|
}
|
|
|
|
return display;
|
|
}
|
|
|
|
WL_EXPORT void
|
|
wl_display_add_object(struct wl_display *display, struct wl_object *object)
|
|
{
|
|
object->id = display->id++;
|
|
wl_hash_insert(&display->objects, object);
|
|
}
|
|
|
|
WL_EXPORT int
|
|
wl_display_add_global(struct wl_display *display, struct wl_object *object)
|
|
{
|
|
struct wl_object_ref *ref;
|
|
|
|
ref = malloc(sizeof *ref);
|
|
if (ref == NULL)
|
|
return -1;
|
|
|
|
ref->object = object;
|
|
wl_list_insert(display->global_list.prev, &ref->link);
|
|
|
|
return 0;
|
|
}
|
|
|
|
WL_EXPORT void
|
|
wl_surface_post_event(struct wl_surface *surface,
|
|
struct wl_object *sender,
|
|
uint32_t event, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap, event);
|
|
wl_client_vmarshal(surface->client, sender, event, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
struct wl_input_device {
|
|
struct wl_object base;
|
|
struct wl_display *display;
|
|
uint32_t button_state[16];
|
|
uint32_t button_count;
|
|
int32_t x, y;
|
|
};
|
|
|
|
static const struct wl_method input_device_methods[] = {
|
|
};
|
|
|
|
static const struct wl_event input_device_events[] = {
|
|
{ "motion", "iiii" },
|
|
{ "button", "uu" },
|
|
{ "key", "uu" },
|
|
};
|
|
|
|
static const struct wl_interface input_device_interface = {
|
|
"input_device", 1,
|
|
ARRAY_LENGTH(input_device_methods),
|
|
input_device_methods,
|
|
ARRAY_LENGTH(input_device_events),
|
|
input_device_events,
|
|
};
|
|
|
|
WL_EXPORT const struct wl_interface *
|
|
wl_input_device_get_interface(void)
|
|
{
|
|
return &input_device_interface;
|
|
}
|
|
|
|
WL_EXPORT void
|
|
wl_display_post_frame(struct wl_display *display,
|
|
uint32_t frame, uint32_t msecs)
|
|
{
|
|
struct wl_client *client;
|
|
|
|
client = container_of(display->client_list.next,
|
|
struct wl_client, link);
|
|
|
|
while (&client->link != &display->client_list) {
|
|
if (client->pending_frame) {
|
|
wl_client_marshal(client, &display->base,
|
|
WL_DISPLAY_FRAME, frame, msecs);
|
|
client->pending_frame = 0;
|
|
}
|
|
client = container_of(client->link.next,
|
|
struct wl_client, link);
|
|
}
|
|
}
|
|
|
|
WL_EXPORT void
|
|
wl_display_set_compositor(struct wl_display *display,
|
|
struct wl_compositor *compositor)
|
|
{
|
|
display->compositor = compositor;
|
|
}
|
|
|
|
WL_EXPORT struct wl_event_loop *
|
|
wl_display_get_event_loop(struct wl_display *display)
|
|
{
|
|
return display->loop;
|
|
}
|
|
|
|
WL_EXPORT void
|
|
wl_display_run(struct wl_display *display)
|
|
{
|
|
while (1)
|
|
wl_event_loop_wait(display->loop);
|
|
}
|
|
|
|
static void
|
|
socket_data(int fd, uint32_t mask, void *data)
|
|
{
|
|
struct wl_display *display = data;
|
|
struct sockaddr_un name;
|
|
socklen_t length;
|
|
int client_fd;
|
|
|
|
length = sizeof name;
|
|
client_fd = accept (fd, (struct sockaddr *) &name, &length);
|
|
if (client_fd < 0)
|
|
fprintf(stderr, "failed to accept\n");
|
|
|
|
wl_client_create(display, client_fd);
|
|
}
|
|
|
|
WL_EXPORT int
|
|
wl_display_add_socket(struct wl_display *display,
|
|
const char *name, size_t name_size)
|
|
{
|
|
struct sockaddr_un addr;
|
|
int sock;
|
|
socklen_t size;
|
|
|
|
sock = socket(PF_LOCAL, SOCK_STREAM, 0);
|
|
if (sock < 0)
|
|
return -1;
|
|
|
|
addr.sun_family = AF_LOCAL;
|
|
memcpy(addr.sun_path, name, name_size);
|
|
|
|
size = offsetof (struct sockaddr_un, sun_path) + name_size;
|
|
if (bind(sock, (struct sockaddr *) &addr, size) < 0)
|
|
return -1;
|
|
|
|
if (listen(sock, 1) < 0)
|
|
return -1;
|
|
|
|
wl_event_loop_add_fd(display->loop, sock,
|
|
WL_EVENT_READABLE,
|
|
socket_data, display);
|
|
|
|
return 0;
|
|
}
|