Add client side demarshalling for events.

This also consolidates the marshalling code in connection.c and
uses the same functions in the server and client for marshalling.
dev
Kristian Høgsberg 16 years ago
parent fabd4395ba
commit b3131d9268
  1. 6
      Makefile.in
  2. 144
      connection.c
  3. 15
      connection.h
  4. 272
      wayland-client.c
  5. 2
      wayland-protocol.c
  6. 2
      wayland-system-compositor.c
  7. 169
      wayland.c

@ -16,16 +16,14 @@ libwayland-server.so : \
wayland-util.o \ wayland-util.o \
wayland-protocol.o wayland-protocol.o
libwayland-server.so : CFLAGS += @FFI_CFLAGS@
libwayland-server.so : LDLIBS += @FFI_LIBS@ -ldl -rdynamic
libwayland.so : \ libwayland.so : \
wayland-client.o \ wayland-client.o \
connection.o \ connection.o \
wayland-util.o \ wayland-util.o \
wayland-protocol.o wayland-protocol.o
$(libs) : CFLAGS += -fPIC $(libs) : CFLAGS += -fPIC @FFI_CFLAGS@
$(libs) : LDLIBS += @FFI_LIBS@
$(libs) : $(libs) :
gcc -shared $^ $(LDLIBS) -o $@ gcc -shared $^ $(LDLIBS) -o $@

@ -26,6 +26,8 @@
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <ffi.h>
#include <assert.h>
#include "wayland-util.h" #include "wayland-util.h"
#include "connection.h" #include "connection.h"
@ -218,3 +220,145 @@ wl_connection_write(struct wl_connection *connection, const void *data, size_t c
WL_CONNECTION_WRITABLE, WL_CONNECTION_WRITABLE,
connection->data); connection->data);
} }
void
wl_connection_vmarshal(struct wl_connection *connection,
struct wl_object *sender,
uint32_t opcode, va_list ap,
const struct wl_message *message)
{
struct wl_object *object;
uint32_t args[32], length, *p, size;
const char *s;
int i, count;
count = strlen(message->signature);
assert(count <= ARRAY_LENGTH(args));
p = &args[2];
for (i = 0; i < count; i++) {
switch (message->signature[i]) {
case 'u':
case 'i':
*p++ = va_arg(ap, uint32_t);
break;
case 's':
s = va_arg(ap, const char *);
length = strlen(s);
*p++ = length;
memcpy(p, s, length);
p += DIV_ROUNDUP(length, sizeof(*p));
break;
case 'o':
case 'n':
object = va_arg(ap, struct wl_object *);
*p++ = object->id;
break;
default:
assert(0);
break;
}
}
size = (p - args) * sizeof *p;
args[0] = sender->id;
args[1] = opcode | (size << 16);
wl_connection_write(connection, args, size);
}
void
wl_connection_demarshal(struct wl_connection *connection,
uint32_t size,
struct wl_hash *objects,
void (*func)(void),
void *data, struct wl_object *target,
const struct wl_message *message)
{
ffi_type *types[20];
ffi_cif cif;
uint32_t *p, result, length;
int i, count;
union {
uint32_t uint32;
char *string;
void *object;
uint32_t new_id;
} values[20];
void *args[20];
struct wl_object *object;
uint32_t buffer[64];
count = strlen(message->signature) + 2;
if (count > ARRAY_LENGTH(types)) {
printf("too many args (%d)\n", count);
return;
}
if (sizeof buffer < size) {
printf("request too big, should malloc tmp buffer here\n");
return;
}
types[0] = &ffi_type_pointer;
values[0].object = data;
args[0] = &values[0];
types[1] = &ffi_type_pointer;
values[1].object = target;
args[1] = &values[1];
wl_connection_copy(connection, buffer, size);
p = &buffer[2];
for (i = 2; i < count; i++) {
switch (message->signature[i - 2]) {
case 'u':
case 'i':
types[i] = &ffi_type_uint32;
values[i].uint32 = *p++;
break;
case 's':
types[i] = &ffi_type_pointer;
length = *p++;
values[i].string = malloc(length + 1);
if (values[i].string == NULL) {
/* FIXME: Send NO_MEMORY */
return;
}
memcpy(values[i].string, p, length);
values[i].string[length] = '\0';
p += DIV_ROUNDUP(length, sizeof *p);
break;
case 'o':
types[i] = &ffi_type_pointer;
object = wl_hash_lookup(objects, *p);
if (object == NULL)
printf("unknown object (%d)\n", *p);
values[i].object = object;
p++;
break;
case 'n':
types[i] = &ffi_type_uint32;
values[i].new_id = *p;
object = wl_hash_lookup(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, func, &result, args);
for (i = 2; i < count; i++) {
switch (message->signature[i - 2]) {
case 's':
free(values[i].string);
break;
}
}
}

@ -24,6 +24,7 @@
#define _CONNECTION_H_ #define _CONNECTION_H_
#include <stdarg.h> #include <stdarg.h>
#include "wayland-util.h"
struct wl_connection; struct wl_connection;
@ -41,7 +42,17 @@ void wl_connection_copy(struct wl_connection *connection, void *data, size_t siz
void wl_connection_consume(struct wl_connection *connection, size_t size); void wl_connection_consume(struct wl_connection *connection, size_t size);
int wl_connection_data(struct wl_connection *connection, uint32_t mask); int wl_connection_data(struct wl_connection *connection, uint32_t mask);
void wl_connection_write(struct wl_connection *connection, const void *data, size_t count); void wl_connection_write(struct wl_connection *connection, const void *data, size_t count);
void wl_connection_vmarshal(struct wl_connection *connection, uint32_t id,
uint32_t opcode, const char *signature, va_list ap); void wl_connection_vmarshal(struct wl_connection *connection,
struct wl_object *sender,
uint32_t opcode, va_list ap,
const struct wl_message *message);
void wl_connection_demarshal(struct wl_connection *connection,
uint32_t size,
struct wl_hash *objects,
void (*func)(void),
void *data, struct wl_object *target,
const struct wl_message *message);
#endif #endif

@ -103,6 +103,41 @@ connection_update(struct wl_connection *connection,
return 0; return 0;
} }
static void
output_handle_geometry(struct wl_display *display,
struct wl_output *output, int32_t width, int32_t height)
{
output->width = width;
output->height = height;
}
struct wl_output_listener {
void (*geometry)(struct wl_display *display,
struct wl_output *output,
int32_t width, int32_t height);
};
static const struct wl_output_listener output_listener = {
output_handle_geometry
};
static void
add_output(struct wl_display *display, struct wl_global *global)
{
struct wl_output *output;
output = malloc(sizeof *output);
if (output == NULL)
return;
output->proxy.base.interface = &wl_output_interface;
output->proxy.base.implementation = (void(**)(void)) &output_listener;
output->proxy.base.id = global->id;
output->proxy.display = display;
display->output = output;
wl_hash_insert(display->objects, &output->proxy.base);
}
WL_EXPORT void WL_EXPORT void
wl_display_get_geometry(struct wl_display *display, int32_t *width, int32_t *height) wl_display_get_geometry(struct wl_display *display, int32_t *width, int32_t *height)
{ {
@ -150,6 +185,79 @@ wl_display_get_rgb_visual(struct wl_display *display)
struct wl_visual, link); struct wl_visual, link);
} }
static void
display_handle_invalid_object(struct wl_display *display,
struct wl_object *object, uint32_t id)
{
fprintf(stderr, "sent request to invalid object\n");
}
static void
display_handle_invalid_method(struct wl_display *display,
struct wl_object *object,
uint32_t id, uint32_t opcode)
{
fprintf(stderr, "sent invalid request opcode\n");
}
static void
display_handle_no_memory(struct wl_display *display,
struct wl_object *object)
{
fprintf(stderr, "server out of memory\n");
}
static void
display_handle_global(struct wl_display *display,
struct wl_object *object,
uint32_t id, const char *interface, uint32_t version)
{
struct wl_global *global;
global = malloc(sizeof *global);
if (global == NULL)
return;
global->id = id;
global->interface = strdup(interface);
global->version = version;
wl_list_insert(display->global_list.prev, &global->link);
if (strcmp(global->interface, "display") == 0)
wl_hash_insert(display->objects, &display->proxy.base);
if (strcmp(global->interface, "visual") == 0)
add_visual(display, global);
else if (strcmp(global->interface, "output") == 0)
add_output(display, global);
}
static void
display_handle_range(struct wl_display *display,
struct wl_object *object, uint32_t range)
{
display->next_range = range;
}
struct wl_display_listener {
void (*invalid_object)(struct wl_display *display,
struct wl_object *object, uint32_t id);
void (*invalid_method)(struct wl_display *display,
struct wl_object *object,
uint32_t id, uint32_t opcode);
void (*no_memory)(struct wl_display *display, struct wl_object *object);
void (*global)(struct wl_display *display, struct wl_object *object,
uint32_t id, const char *interface, uint32_t version);
void (*range)(struct wl_display *display,
struct wl_object *object, uint32_t range);
};
static const struct wl_display_listener display_listener = {
display_handle_invalid_object,
display_handle_invalid_method,
display_handle_no_memory,
display_handle_global,
display_handle_range
};
WL_EXPORT struct wl_display * WL_EXPORT struct wl_display *
wl_display_create(const char *name, size_t name_size) wl_display_create(const char *name, size_t name_size)
{ {
@ -184,10 +292,9 @@ wl_display_create(const char *name, size_t name_size)
wl_list_init(&display->visual_list); wl_list_init(&display->visual_list);
display->proxy.base.interface = &wl_display_interface; display->proxy.base.interface = &wl_display_interface;
display->proxy.base.implementation = NULL; display->proxy.base.implementation = (void(**)(void)) &display_listener;
display->proxy.base.id = 1; display->proxy.base.id = 1;
display->proxy.display = display; display->proxy.display = display;
wl_hash_insert(display->objects, &display->proxy.base);
display->connection = wl_connection_create(display->fd, display->connection = wl_connection_create(display->fd,
connection_update, connection_update,
@ -239,100 +346,6 @@ wl_display_get_fd(struct wl_display *display,
return display->fd; return display->fd;
} }
struct wl_output_listener {
void (*geometry)(struct wl_display *display,
struct wl_output *output,
int32_t width, int32_t height);
};
static void
handle_geometry(struct wl_display *display,
struct wl_output *output, int32_t width, int32_t height)
{
output->width = width;
output->height = height;
}
static const struct wl_output_listener output_listener = {
handle_geometry
};
static void
add_output(struct wl_display *display, struct wl_global *global)
{
struct wl_output *output;
output = malloc(sizeof *output);
if (output == NULL)
return;
output->proxy.base.interface = &wl_output_interface;
output->proxy.base.implementation = (void(**)(void)) &output_listener;
output->proxy.base.id = global->id;
output->proxy.display = display;
display->output = output;
wl_hash_insert(display->objects, &output->proxy.base);
}
static void
handle_display_event(struct wl_display *display,
uint32_t opcode, uint32_t *p, uint32_t size)
{
struct wl_global *global;
uint32_t length;
switch (opcode) {
case WL_DISPLAY_INVALID_OBJECT:
fprintf(stderr, "sent request to invalid object\n");
break;
case WL_DISPLAY_INVALID_METHOD:
fprintf(stderr, "sent invalid request opcode\n");
break;
case WL_DISPLAY_NO_MEMORY:
fprintf(stderr, "server out of memory\n");
break;
case WL_DISPLAY_GLOBAL:
global = malloc(sizeof *global);
if (global == NULL)
return;
global->id = p[0];
length = p[1];
global->interface = malloc(length + 1);
if (global->interface == NULL) {
free(global);
return;
}
memcpy(global->interface, &p[2], length);
global->interface[length] = '\0';
global->version = p[2 + DIV_ROUNDUP(length, sizeof *p)];
wl_list_insert(display->global_list.prev, &global->link);
if (strcmp(global->interface, "visual") == 0)
add_visual(display, global);
else if (strcmp(global->interface, "output") == 0)
add_output(display, global);
break;
case WL_DISPLAY_RANGE:
display->next_range = p[0];
break;
}
}
static void
handle_output_event(struct wl_display *display,
uint32_t opcode, uint32_t *p, uint32_t size)
{
switch (opcode) {
case WL_OUTPUT_GEOMETRY:
handle_geometry(display, display->output, p[0], p[1]);
break;
}
}
static void static void
handle_event(struct wl_display *display, handle_event(struct wl_display *display,
uint32_t id, uint32_t opcode, uint32_t size) uint32_t id, uint32_t opcode, uint32_t size)
@ -341,15 +354,24 @@ handle_event(struct wl_display *display,
struct wl_object *object; struct wl_object *object;
wl_connection_copy(display->connection, p, size); wl_connection_copy(display->connection, p, size);
if (id == 1)
object = &display->proxy.base;
else
object = wl_hash_lookup(display->objects, id); object = wl_hash_lookup(display->objects, id);
if (object == &display->proxy.base) if (object != NULL)
handle_display_event(display, opcode, p + 2, size); wl_connection_demarshal(display->connection,
else if (object == &display->output->proxy.base && opcode == 0) size,
handle_output_event(display, opcode, p + 2, size); display->objects,
object->implementation[opcode],
display,
object,
&object->interface->events[opcode]);
else if (display->event_handler != NULL) else if (display->event_handler != NULL)
display->event_handler(display, id, opcode, size, p + 2, display->event_handler(display, id,
opcode, size, p + 2,
display->event_handler_data); display->event_handler_data);
wl_connection_consume(display->connection, size); wl_connection_consume(display->connection, size);
} }
@ -428,57 +450,17 @@ wl_display_get_compositor(struct wl_display *display)
return compositor; return compositor;
} }
static void
wl_proxy_vmarshal(struct wl_proxy *target, uint32_t opcode, va_list ap)
{
struct wl_object *object;
uint32_t args[32], length, *p, size;
const char *s, *signature;
int i, count;
signature = target->base.interface->methods[opcode].signature;
count = strlen(signature);
/* FIXME: Make sure we don't overwrite args array. */
p = &args[2];
for (i = 0; i < count; i++) {
switch (signature[i]) {
case 'u':
case 'i':
*p++ = va_arg(ap, uint32_t);
break;
case 's':
s = va_arg(ap, const char *);
length = strlen(s);
*p++ = length;
memcpy(p, s, length);
p += DIV_ROUNDUP(length, sizeof(*p));
break;
case 'n':
case 'o':
object = va_arg(ap, struct wl_object *);
*p++ = object->id;
break;
default:
assert(0);
break;
}
}
size = (p - args) * sizeof *p;
args[0] = target->base.id;
args[1] = opcode | (size << 16);
wl_connection_write(target->display->connection, args, size);
}
static void static void
wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...) wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...)
{ {
va_list ap; va_list ap;
va_start(ap, opcode); va_start(ap, opcode);
wl_proxy_vmarshal(proxy, opcode, ap); wl_connection_vmarshal(proxy->display->connection,
&proxy->base, opcode, ap,
&proxy->base.interface->methods[opcode]);
va_end(ap); va_end(ap);
} }
WL_EXPORT struct wl_surface * WL_EXPORT struct wl_surface *

@ -29,7 +29,7 @@ static const struct wl_message display_events[] = {
{ "invalid_object", "u" }, { "invalid_object", "u" },
{ "invalid_method", "uu" }, { "invalid_method", "uu" },
{ "no_memory", "" }, { "no_memory", "" },
{ "global", "osu" }, { "global", "nsu" },
{ "range", "u" }, { "range", "u" },
}; };

@ -702,7 +702,9 @@ create_input_device(struct egl_compositor *ec, const char *glob)
memset(device, 0, sizeof *device); memset(device, 0, sizeof *device);
device->base.interface = &wl_input_device_interface; device->base.interface = &wl_input_device_interface;
device->base.implementation = NULL;
wl_display_add_object(ec->wl_display, &device->base); wl_display_add_object(ec->wl_display, &device->base);
wl_display_add_global(ec->wl_display, &device->base, NULL);
device->x = 100; device->x = 100;
device->y = 100; device->y = 100;
device->pointer_surface = device->pointer_surface =

@ -73,61 +73,6 @@ struct wl_global {
void void
wl_client_destroy(struct wl_client *client); 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_message *event;
struct wl_object *object;
uint32_t args[32], length, *p, size;
const char *s;
int i, count;
event = &sender->interface->events[opcode];
count = strlen(event->signature);
assert(count <= ARRAY_LENGTH(args));
p = &args[2];
for (i = 0; i < count; i++) {
switch (event->signature[i]) {
case 'u':
case 'i':
*p++ = va_arg(ap, uint32_t);
break;
case 's':
s = va_arg(ap, const char *);
length = strlen(s);
*p++ = length;
memcpy(p, s, length);
p += DIV_ROUNDUP(length, sizeof(*p));
break;
case 'o':
object = va_arg(ap, struct wl_object *);
*p++ = object->id;
break;
default:
assert(0);
break;
}
}
size = (p - args) * sizeof *p;
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);
}
WL_EXPORT void WL_EXPORT void
wl_client_post_event(struct wl_client *client, struct wl_object *sender, wl_client_post_event(struct wl_client *client, struct wl_object *sender,
uint32_t opcode, ...) uint32_t opcode, ...)
@ -135,93 +80,12 @@ wl_client_post_event(struct wl_client *client, struct wl_object *sender,
va_list ap; va_list ap;
va_start(ap, opcode); va_start(ap, opcode);
wl_client_vmarshal(client, sender, opcode, ap); wl_connection_vmarshal(client->connection,
sender, opcode, ap,
&sender->interface->events[opcode]);
va_end(ap); va_end(ap);
} }
static void
wl_client_demarshal(struct wl_client *client, struct wl_object *target,
uint32_t opcode, size_t size)
{
const struct wl_message *method;
ffi_type *types[20];
ffi_cif cif;
uint32_t *p, result;
int i, 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];
void (*func)(void);
method = &target->interface->methods[opcode];
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];
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);
values[i].object = object;
p++;
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];
}
func = target->implementation[opcode];
ffi_prep_cif(&cif, FFI_DEFAULT_ABI, count, &ffi_type_uint32, types);
ffi_call(&cif, func, &result, args);
}
static void static void
wl_client_connection_data(int fd, uint32_t mask, void *data) wl_client_connection_data(int fd, uint32_t mask, void *data)
{ {
@ -252,7 +116,7 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
object = wl_hash_lookup(client->display->objects, p[0]); object = wl_hash_lookup(client->display->objects, p[0]);
if (object == NULL) { if (object == NULL) {
wl_client_marshal(client, &client->display->base, wl_client_post_event(client, &client->display->base,
WL_DISPLAY_INVALID_OBJECT, p[0]); WL_DISPLAY_INVALID_OBJECT, p[0]);
wl_connection_consume(connection, size); wl_connection_consume(connection, size);
len -= size; len -= size;
@ -260,14 +124,21 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
} }
if (opcode >= object->interface->method_count) { if (opcode >= object->interface->method_count) {
wl_client_marshal(client, &client->display->base, wl_client_post_event(client, &client->display->base,
WL_DISPLAY_INVALID_METHOD, p[0], opcode); WL_DISPLAY_INVALID_METHOD, p[0], opcode);
wl_connection_consume(connection, size); wl_connection_consume(connection, size);
len -= size; len -= size;
continue; continue;
} }
wl_client_demarshal(client, object, opcode, size); wl_connection_demarshal(client->connection,
size,
client->display->objects,
object->implementation[opcode],
client,
object,
&object->interface->methods[opcode]);
wl_connection_consume(connection, size); wl_connection_consume(connection, size);
len -= size; len -= size;
} }
@ -291,7 +162,7 @@ wl_client_connection_update(struct wl_connection *connection,
static void static void
wl_display_post_range(struct wl_display *display, struct wl_client *client) wl_display_post_range(struct wl_display *display, struct wl_client *client)
{ {
wl_client_marshal(client, &client->display->base, wl_client_post_event(client, &client->display->base,
WL_DISPLAY_RANGE, display->client_id_range); WL_DISPLAY_RANGE, display->client_id_range);
display->client_id_range += 256; display->client_id_range += 256;
client->id_count += 256; client->id_count += 256;
@ -323,7 +194,7 @@ wl_client_create(struct wl_display *display, int fd)
global = container_of(display->global_list.next, global = container_of(display->global_list.next,
struct wl_global, link); struct wl_global, link);
while (&global->link != &display->global_list) { while (&global->link != &display->global_list) {
wl_client_marshal(client, &client->display->base, wl_client_post_event(client, &client->display->base,
WL_DISPLAY_GLOBAL, WL_DISPLAY_GLOBAL,
global->object, global->object,
global->object->interface->name, global->object->interface->name,
@ -395,7 +266,7 @@ wl_client_add_surface(struct wl_client *client,
ref = malloc(sizeof *ref); ref = malloc(sizeof *ref);
if (ref == NULL) { if (ref == NULL) {
wl_client_marshal(client, &display->base, wl_client_post_event(client, &display->base,
WL_DISPLAY_NO_MEMORY); WL_DISPLAY_NO_MEMORY);
return -1; return -1;
} }
@ -415,7 +286,7 @@ wl_client_send_acknowledge(struct wl_client *client,
wl_list_remove(&client->link); wl_list_remove(&client->link);
wl_list_insert(client->display->pending_frame_list.prev, wl_list_insert(client->display->pending_frame_list.prev,
&client->link); &client->link);
wl_client_marshal(client, &compositor->base, wl_client_post_event(client, &compositor->base,
WL_COMPOSITOR_ACKNOWLEDGE, key, frame); WL_COMPOSITOR_ACKNOWLEDGE, key, frame);
} }
@ -505,7 +376,9 @@ wl_surface_post_event(struct wl_surface *surface,
va_list ap; va_list ap;
va_start(ap, event); va_start(ap, event);
wl_client_vmarshal(surface->client, sender, event, ap); wl_connection_vmarshal(surface->client->connection,
sender, event, ap,
&sender->interface->events[event]);
va_end(ap); va_end(ap);
} }
@ -520,7 +393,7 @@ wl_display_post_frame(struct wl_display *display,
struct wl_client, link); struct wl_client, link);
while (&client->link != &display->pending_frame_list) { while (&client->link != &display->pending_frame_list) {
wl_client_marshal(client, &compositor->base, wl_client_post_event(client, &compositor->base,
WL_COMPOSITOR_FRAME, frame, msecs); WL_COMPOSITOR_FRAME, frame, msecs);
client = container_of(client->link.next, client = container_of(client->link.next,
struct wl_client, link); struct wl_client, link);

Loading…
Cancel
Save