Generate protocol types and metadata from xml
diff --git a/.gitignore b/.gitignore
index 1281071..de7aa72 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+*.deps
 *.o
 *.so
 *.pc
diff --git a/Makefile b/Makefile
index 2ea2d3a..fe2ea0f 100644
--- a/Makefile
+++ b/Makefile
@@ -3,22 +3,34 @@
 subdirs = clients spec
 libs = libwayland-server.so libwayland.so
 
-all : $(libs) compositor subdirs-all
+all : $(libs) compositor subdirs-all scanner
 
 libwayland-server.so :				\
+	wayland-protocol.o			\
 	wayland.o				\
 	event-loop.o				\
 	connection.o				\
 	wayland-util.o				\
-	wayland-hash.o				\
-	wayland-protocol.o
+	wayland-hash.o
 
 libwayland.so :					\
+	wayland-protocol.o			\
 	wayland-client.o			\
 	connection.o				\
 	wayland-util.o				\
-	wayland-hash.o				\
-	wayland-protocol.o
+	wayland-hash.o
+
+wayland.o : wayland-server-protocol.h
+wayland-client.o : wayland-client-protocol.h
+
+wayland-protocol.c : protocol.xml scanner
+	./scanner code < $< > $@
+
+wayland-server-protocol.h : protocol.xml scanner
+	./scanner server-header < $< > $@
+
+wayland-client-protocol.h : protocol.xml scanner
+	./scanner client-header < $< > $@
 
 $(libs) : CFLAGS += -fPIC $(FFI_CFLAGS)
 $(libs) : LDLIBS += $(FFI_LIBS)
@@ -35,6 +47,12 @@
 compositor : CFLAGS += $(COMPOSITOR_CFLAGS)
 compositor : LDLIBS += ./libwayland-server.so $(COMPOSITOR_LIBS) -rdynamic -lrt -lEGL -lm
 
+scanner :					\
+	scanner.o				\
+	wayland-util.o
+
+scanner : LDLIBS += $(EXPAT_LIBS)
+
 subdirs-all subdirs-clean :
 	for f in $(subdirs); do $(MAKE) -C $$f $(@:subdirs-%=%); done
 
@@ -46,7 +64,9 @@
 	install 70-wayland.rules ${udev_rules_dir}
 
 clean : subdirs-clean
-	rm -f compositor *.o *.so
+	rm -f compositor scanner *.o *.so
+	rm -f wayland-protocol.c \
+		wayland-server-protocol.h wayland-client-protocol.h
 
 config.mk : config.mk.in
 	./config.status
diff --git a/compositor-drm.c b/compositor-drm.c
index 05ab02a..b893fc4 100644
--- a/compositor-drm.c
+++ b/compositor-drm.c
@@ -34,7 +34,6 @@
 #include <EGL/eglext.h>
 
 #include "wayland.h"
-#include "wayland-protocol.h"
 #include "compositor.h"
 
 struct drm_compositor {
diff --git a/compositor-x11.c b/compositor-x11.c
index 6679e20..9c4f845 100644
--- a/compositor-x11.c
+++ b/compositor-x11.c
@@ -38,7 +38,6 @@
 #include <EGL/eglext.h>
 
 #include "wayland.h"
-#include "wayland-protocol.h"
 #include "compositor.h"
 
 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
diff --git a/compositor.c b/compositor.c
index ac2960e..165c547 100644
--- a/compositor.c
+++ b/compositor.c
@@ -38,7 +38,7 @@
 #include <EGL/eglext.h>
 
 #include "wayland.h"
-#include "wayland-protocol.h"
+#include "wayland-server-protocol.h"
 #include "cairo-util.h"
 #include "compositor.h"
 
@@ -425,8 +425,8 @@
 static void
 surface_attach(struct wl_client *client,
 	       struct wl_surface *surface, uint32_t name, 
-	       uint32_t width, uint32_t height, uint32_t stride,
-	       struct wl_object *visual)
+	       int32_t width, int32_t height, uint32_t stride,
+	       struct wl_visual *visual)
 {
 	struct wlsc_surface *es = (struct wlsc_surface *) surface;
 	struct wlsc_compositor *ec = es->compositor;
@@ -441,11 +441,11 @@
 	es->width = width;
 	es->height = height;
 
-	if (visual == &ec->argb_visual.base)
+	if (visual == &ec->argb_visual)
 		es->visual = &ec->argb_visual;
-	else if (visual == &ec->premultiplied_argb_visual.base)
+	else if (visual == &ec->premultiplied_argb_visual)
 		es->visual = &ec->premultiplied_argb_visual;
-	else if (visual == &ec->rgb_visual.base)
+	else if (visual == &ec->rgb_visual)
 		es->visual = &ec->rgb_visual;
 	else
 		/* FIXME: Smack client with an exception event */;
@@ -559,13 +559,13 @@
 	    (!surface || device->keyboard_focus->base.client != surface->base.client))
 		wl_surface_post_event(&device->keyboard_focus->base,
 				      &device->base,
-				      WL_INPUT_KEYBOARD_FOCUS,
+				      WL_INPUT_DEVICE_KEYBOARD_FOCUS,
 				      time, NULL, &device->keys);
 
 	if (surface)
 		wl_surface_post_event(&surface->base,
 				      &device->base,
-				      WL_INPUT_KEYBOARD_FOCUS,
+				      WL_INPUT_DEVICE_KEYBOARD_FOCUS,
 				      time, &surface->base, &device->keys);
 
 	device->keyboard_focus = surface;
@@ -583,12 +583,12 @@
 	    (!surface || device->pointer_focus->base.client != surface->base.client))
 		wl_surface_post_event(&device->pointer_focus->base,
 				      &device->base,
-				      WL_INPUT_POINTER_FOCUS,
+				      WL_INPUT_DEVICE_POINTER_FOCUS,
 				      time, NULL);
 	if (surface)
 		wl_surface_post_event(&surface->base,
 				      &device->base,
-				      WL_INPUT_POINTER_FOCUS,
+				      WL_INPUT_DEVICE_POINTER_FOCUS,
 				      time, &surface->base);
 
 	device->pointer_focus = surface;
@@ -644,7 +644,7 @@
 
 	if (es)
 		wl_surface_post_event(&es->base, &device->base,
-				      WL_INPUT_MOTION, time, x, y, sx, sy);
+				      WL_INPUT_DEVICE_MOTION, time, x, y, sx, sy);
 
 	wlsc_matrix_init(&device->sprite->matrix);
 	wlsc_matrix_scale(&device->sprite->matrix, 64, 64, 1);
@@ -675,7 +675,7 @@
 
 		/* FIXME: Swallow click on raise? */
 		wl_surface_post_event(&surface->base, &device->base,
-				      WL_INPUT_BUTTON, time, button, state);
+				      WL_INPUT_DEVICE_BUTTON, time, button, state);
 
 		wlsc_compositor_schedule_repaint(compositor);
 	}
@@ -730,7 +730,7 @@
 	if (device->keyboard_focus != NULL)
 		wl_surface_post_event(&device->keyboard_focus->base,
 				      &device->base,
-				      WL_INPUT_KEY, time, key, state);
+				      WL_INPUT_DEVICE_KEY, time, key, state);
 }
 
 static uint32_t
diff --git a/config.mk.in b/config.mk.in
index 00f465f..60af1cc 100644
--- a/config.mk.in
+++ b/config.mk.in
@@ -18,6 +18,8 @@
 POPPLER_CFLAGS = @POPPLER_CFLAGS@
 POPPLER_LIBS = @POPPLER_LIBS@
 
+EXPAT_LIBS = @EXPAT_LIBS@
+
 first : all
 
 -include .*.deps
diff --git a/configure.ac b/configure.ac
index fd64439..e544698 100644
--- a/configure.ac
+++ b/configure.ac
@@ -14,5 +14,16 @@
 fi
 AC_SUBST(GCC_CFLAGS)
 
+EXPAT_LIB=""
+AC_ARG_WITH(expat, [  --with-expat=<dir>      Use expat from here],
+		   [ expat=$withval
+		     CPPFLAGS="$CPPFLAGS -I$withval/include"
+		     LDFLAGS="$LDFLAGS -L$withval/lib" ] )
+AC_CHECK_HEADERS(expat.h, [AC_DEFINE(HAVE_EXPAT_H)], 
+		 [AC_MSG_ERROR([Can't find expat.h. Please install expat.])])
+AC_CHECK_LIB(expat, XML_ParserCreate, [EXPAT_LIBS="-lexpat"],
+	     [AC_MSG_ERROR([Can't find expat library. Please install expat.])])
+AC_SUBST(EXPAT_LIBS)
+
 AC_CONFIG_FILES([config.mk wayland-server.pc wayland.pc])
 AC_OUTPUT
diff --git a/protocol.xml b/protocol.xml
new file mode 100644
index 0000000..b5cb783
--- /dev/null
+++ b/protocol.xml
@@ -0,0 +1,137 @@
+<protocol>
+
+  <interface name="display" version="1">
+    <event name="invalid_object">
+      <arg name="object_id" type="uint"/>
+    </event>
+
+    <event name="invalid_method">
+      <arg name="object_id" type="uint"/>
+      <arg name="opcode" type="uint"/>
+    </event>
+
+    <event name="no_memory"/>
+
+    <event name="global">
+      <arg name="id" type="new_id"/>
+      <arg name="name" type="string"/>
+      <arg name="version" type="uint"/>
+    </event>
+
+    <event name="range">
+      <arg name="base" type="uint"/>
+    </event>
+  </interface>
+
+  <interface name="compositor" version="1">
+    <request name="create_surface">
+      <arg name="id" type="new_id"/>
+    </request>
+
+    <request name="commit">
+      <arg name="key" type="uint"/>
+    </request>
+
+    <event name="device">
+      <arg name="name" type="string"/>
+    </event>
+
+    <event name="acknowledge">
+      <arg name="key" type="uint"/>
+      <arg name="frame" type="uint"/>
+    </event>
+
+    <event name="frame">
+      <arg name="frame" type="uint"/>
+      <arg name="timestamp" type="uint"/>
+    </event>
+  </interface>
+
+  <interface name="shell" version="1">
+    <request name="move">
+      <arg name="time" type="uint"/>
+    </request>
+
+    <request name="resize">
+      <arg name="time" type="uint"/>
+      <arg name="edges" type="uint"/>
+    </request>
+
+    <event name="configure">
+      <arg name="surface" type="surface"/>
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </event>
+  </interface>
+
+  <interface name="surface" version="1">
+    <request name="destroy"/>
+
+    <request name="attach">
+      <arg name="name" type="uint"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+      <arg name="stride" type="uint"/>
+      <arg name="visual" type="visual"/>
+    </request>
+
+    <request name="map">
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+
+    <request name="damage">
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+  </interface>
+
+  <interface name="input_device" version="1">
+    <event name="motion">
+      <arg name="time" type="uint"/>
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="surface_x" type="int"/>
+      <arg name="surface_y" type="int"/>
+    </event>
+
+    <event name="button">
+      <arg name="time" type="uint"/>
+      <arg name="button" type="uint"/>
+      <arg name="state" type="uint"/>
+    </event>
+
+    <event name="key">
+      <arg name="time" type="uint"/>
+      <arg name="key" type="uint"/>
+      <arg name="state" type="uint"/>
+    </event>
+
+    <event name="pointer_focus">
+      <arg name="time" type="uint"/>
+      <arg name="surface" type="surface"/>
+    </event>
+
+    <event name="keyboard_focus">
+      <arg name="time" type="uint"/>
+      <arg name="surface" type="surface"/>
+      <arg name="keys" type="array"/>
+    </event>
+  </interface>
+
+  <interface name="output" version="1">
+    <event name="geometry">
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </event>
+  </interface>
+
+  <interface name="visual" version="1">
+
+</protocol>
\ No newline at end of file
diff --git a/scanner.c b/scanner.c
new file mode 100644
index 0000000..47e13ee
--- /dev/null
+++ b/scanner.c
@@ -0,0 +1,443 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <expat.h>
+
+#include "wayland-util.h"
+
+static const char copyright[] =
+	"/*\n"
+	" * Copyright © 2010 Kristian Høgsberg\n"
+	" *\n"
+	" * Permission to use, copy, modify, distribute, and sell this software and its\n"
+	" * documentation for any purpose is hereby granted without fee, provided that\n"
+	" * the above copyright notice appear in all copies and that both that copyright\n"
+	" * notice and this permission notice appear in supporting documentation, and\n"
+	" * that the name of the copyright holders not be used in advertising or\n"
+	" * publicity pertaining to distribution of the software without specific,\n"
+	" * written prior permission.  The copyright holders make no representations\n"
+	" * about the suitability of this software for any purpose.  It is provided \"as\n"
+	" * is\" without express or implied warranty.\n"
+	" *\n"
+	" * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,\n"
+	" * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO\n"
+	" * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR\n"
+	" * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,\n"
+	" * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER\n"
+	" * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE\n"
+	" * OF THIS SOFTWARE.\n"
+	" */\n";
+
+static int
+usage(int ret)
+{
+	fprintf(stderr, "usage: ./scanner [header|code]\n");
+	exit(ret);
+}
+
+#define XML_BUFFER_SIZE 4096
+
+struct protocol {
+	struct wl_list interface_list;
+};
+
+struct interface {
+	char *name;
+	char *uppercase_name;
+	int version;
+	struct wl_list request_list;
+	struct wl_list event_list;
+	struct wl_list link;
+};
+
+struct message {
+	char *name;
+	char *uppercase_name;
+	struct wl_list arg_list;
+	struct wl_list link;
+};
+
+enum arg_type {
+	NEW_ID,
+	INT,
+	UNSIGNED,
+	STRING,
+	OBJECT,
+	ARRAY
+};
+
+struct arg {
+	char *name;
+	enum arg_type type;
+	char *object_name;
+	struct wl_list link;
+};
+
+struct parse_context {
+	struct protocol *protocol;
+	struct interface *interface;
+	struct message *message;
+};
+
+static char *
+uppercase_dup(const char *src)
+{
+	char *u;
+	int i;
+
+	u = strdup(src);
+	for (i = 0; u[i]; i++)
+		u[i] = toupper(u[i]);
+	u[i] = '\0';
+
+	return u;
+}
+
+static void
+start_element(void *data, const char *element_name, const char **atts)
+{
+	struct parse_context *ctx = data;
+	struct interface *interface;
+	struct message *message;
+	struct arg *arg;
+	const char *name, *type;
+	int i, version;
+
+	name = 0;
+	type = 0;
+	version = 0;
+	for (i = 0; atts[i]; i += 2) {
+		if (strcmp(atts[i], "name") == 0)
+			name = atts[i + 1];
+		if (strcmp(atts[i], "version") == 0)
+			version = atoi(atts[i + 1]);
+		if (strcmp(atts[i], "type") == 0)
+			type = atts[i + 1];
+	}
+
+	if (strcmp(element_name, "interface") == 0) {
+		if (name == NULL) {
+			fprintf(stderr, "no interface name given\n");
+			exit(EXIT_FAILURE);
+		}
+
+		if (version == 0) {
+			fprintf(stderr, "no interface version given\n");
+			exit(EXIT_FAILURE);
+		}
+
+		interface = malloc(sizeof *interface);
+		interface->name = strdup(name);
+		interface->uppercase_name = uppercase_dup(name);
+		interface->version = version;
+		wl_list_init(&interface->request_list);
+		wl_list_init(&interface->event_list);
+		wl_list_insert(ctx->protocol->interface_list.prev,
+			       &interface->link);
+		ctx->interface = interface;
+	} else if (strcmp(element_name, "request") == 0 ||
+		   strcmp(element_name, "event") == 0) {
+		if (name == NULL) {
+			fprintf(stderr, "no request name given\n");
+			exit(EXIT_FAILURE);
+		}
+
+		message = malloc(sizeof *message);
+		message->name = strdup(name);
+		message->uppercase_name = uppercase_dup(name);
+		wl_list_init(&message->arg_list);
+
+		if (strcmp(element_name, "request") == 0)
+			wl_list_insert(ctx->interface->request_list.prev,
+				       &message->link);
+		else
+			wl_list_insert(ctx->interface->event_list.prev,
+				       &message->link);
+
+		ctx->message = message;
+	} else if (strcmp(element_name, "arg") == 0) {
+		arg = malloc(sizeof *arg);
+		arg->name = strdup(name);
+
+		if (strcmp(type, "new_id") == 0)
+			arg->type = NEW_ID;
+		else if (strcmp(type, "int") == 0)
+			arg->type = INT;
+		else if (strcmp(type, "uint") == 0)
+			arg->type = UNSIGNED;
+		else if (strcmp(type, "string") == 0)
+			arg->type = STRING;
+		else if (strcmp(type, "array") == 0)
+			arg->type = ARRAY;
+		else {
+			arg->type = OBJECT;
+			arg->object_name = strdup(type);
+		}
+
+		wl_list_insert(ctx->message->arg_list.prev,
+			       &arg->link);
+	}
+}
+
+static void
+emit_opcodes(struct wl_list *message_list, struct interface *interface)
+{
+	struct message *m;
+	int opcode;
+
+	if (wl_list_empty(message_list))
+		return;
+
+	opcode = 0;
+	wl_list_for_each(m, message_list, link)
+		printf("#define WL_%s_%s\t%d\n",
+		       interface->uppercase_name, m->uppercase_name, opcode++);
+
+	printf("\n");
+}
+
+static void
+emit_structs(struct wl_list *message_list, struct interface *interface)
+{
+	struct message *m;
+	struct arg *a;
+	int is_interface;
+
+	is_interface = message_list == &interface->request_list;
+	printf("struct wl_%s_%s {\n", interface->name,
+	       is_interface ? "interface" : "listener");
+
+	wl_list_for_each(m, message_list, link) {
+		printf("\tvoid (*%s)(", m->name);
+
+		if (is_interface) {
+			printf("struct wl_client *client, struct wl_%s *%s",
+			       interface->name, interface->name);
+		} else {
+			printf("void *data, struct wl_%s *%s",
+			       interface->name, interface->name);
+		}
+
+		if (!wl_list_empty(&m->arg_list))
+			printf(", ");
+
+		wl_list_for_each(a, &m->arg_list, link) {
+			switch (a->type) {
+			default:
+			case INT:
+				printf("int32_t ");
+				break;
+			case NEW_ID:
+			case UNSIGNED:
+				printf("uint32_t ");
+				break;
+			case STRING:
+				printf("const char *");
+				break;
+			case OBJECT:
+				printf("struct wl_%s *", a->object_name);
+				break;
+			case ARRAY:
+				printf("struct wl_array *");
+				break;
+			}
+			printf("%s%s",
+			       a->name,
+			       a->link.next == &m->arg_list ? "" : ", ");
+		}
+
+		printf(");\n");
+	}
+
+	printf("};\n\n");
+}
+
+static void
+emit_header(struct protocol *protocol, int server)
+{
+	struct interface *i;
+
+	printf("%s\n\n"
+	       "#ifndef WAYLAND_PROTOCOL_H\n"
+	       "#define WAYLAND_PROTOCOL_H\n"
+	       "\n"
+	       "#ifdef  __cplusplus\n"
+	       "extern \"C\" {\n"
+	       "#endif\n"
+	       "\n"
+	       "#include <stdint.h>\n"
+	       "#include \"wayland-util.h\"\n\n"
+	       "struct wl_client;\n\n", copyright);
+
+	wl_list_for_each(i, &protocol->interface_list, link)
+		printf("struct wl_%s;\n", i->name);
+	printf("\n");
+
+	wl_list_for_each(i, &protocol->interface_list, link) {
+
+		if (server) {
+			emit_structs(&i->request_list, i);
+			emit_opcodes(&i->event_list, i);
+		} else {
+			emit_structs(&i->event_list, i);
+			emit_opcodes(&i->request_list, i);
+		}
+
+		printf("extern const struct wl_interface "
+		       "wl_%s_interface;\n\n",
+		       i->name);
+	}
+
+	printf("#ifdef  __cplusplus\n"
+	       "}\n"
+	       "#endif\n"
+	       "\n"
+	       "#endif\n");
+}
+
+static void
+emit_messages(struct wl_list *message_list,
+	      struct interface *interface, const char *suffix)
+{
+	struct message *m;
+	struct arg *a;
+
+	if (wl_list_empty(message_list))
+		return;
+
+	printf("static const struct wl_message "
+	       "%s_%s[] = {\n",
+	       interface->name, suffix);
+
+	wl_list_for_each(m, message_list, link) {
+		printf("\t{ \"%s\", \"", m->name);
+		wl_list_for_each(a, &m->arg_list, link) {
+			switch (a->type) {
+			default:
+			case INT:
+				printf("i");
+				break;
+			case NEW_ID:
+				printf("n");
+				break;
+			case UNSIGNED:
+				printf("u");
+				break;
+			case STRING:
+				printf("s");
+				break;
+			case OBJECT:
+				printf("o");
+				break;
+			case ARRAY:
+				printf("a");
+				break;
+			}
+		}
+		printf("\" },\n");
+	}
+
+	printf("};\n\n");
+}
+
+static void
+emit_code(struct protocol *protocol)
+{
+	struct interface *i;
+
+	printf("%s\n\n"
+	       "#include <stdlib.h>\n"
+	       "#include <stdint.h>\n"
+	       "#include \"wayland-util.h\"\n\n",
+	       copyright);
+
+	wl_list_for_each(i, &protocol->interface_list, link) {
+
+		emit_messages(&i->request_list, i, "requests");
+		emit_messages(&i->event_list, i, "events");
+
+		printf("WL_EXPORT const struct wl_interface "
+		       "wl_%s_interface = {\n"
+		       "\t\"%s\", %d,\n",
+		       i->name, i->name, i->version);
+
+		if (!wl_list_empty(&i->request_list))
+			printf("\tARRAY_LENGTH(%s_requests), %s_requests,\n",
+			       i->name, i->name);
+		else
+			printf("\t0, NULL,\n");
+
+		if (!wl_list_empty(&i->event_list))
+			printf("\tARRAY_LENGTH(%s_events), %s_events,\n",
+			       i->name, i->name);
+		else
+			printf("\t0, NULL,\n");
+
+		printf("};\n\n");
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	struct parse_context ctx;
+	struct protocol protocol;
+	XML_Parser parser;
+	int len;
+	void *buf;
+
+	if (argc != 2)
+		usage(EXIT_FAILURE);
+
+	wl_list_init(&protocol.interface_list);
+	ctx.protocol = &protocol;
+
+	parser = XML_ParserCreate(NULL);
+	XML_SetUserData(parser, &ctx);
+	if (parser == NULL) {
+		fprintf(stderr, "failed to create parser\n");
+		exit(EXIT_FAILURE);
+	}
+
+	XML_SetElementHandler(parser, start_element, NULL);
+	do {
+		buf = XML_GetBuffer(parser, XML_BUFFER_SIZE);
+		len = fread(buf, 1, XML_BUFFER_SIZE, stdin);
+		if (len < 0) {
+			fprintf(stderr, "fread: %s\n", strerror(errno));
+			exit(EXIT_FAILURE);
+		}
+		XML_ParseBuffer(parser, len, len == 0);
+
+	} while (len > 0);
+
+	XML_ParserFree(parser);
+
+	if (strcmp(argv[1], "client-header") == 0) {
+		emit_header(&protocol, 0);
+	} else if (strcmp(argv[1], "server-header") == 0) {
+		emit_header(&protocol, 1);
+	} else if (strcmp(argv[1], "code") == 0) {
+		emit_code(&protocol);
+	}
+
+	return 0;
+}
diff --git a/wayland-client.c b/wayland-client.c
index 912d682..eb9d698 100644
--- a/wayland-client.c
+++ b/wayland-client.c
@@ -33,7 +33,7 @@
 #include <assert.h>
 #include <sys/poll.h>
 
-#include "wayland-protocol.h"
+#include "wayland-client-protocol.h"
 #include "connection.h"
 #include "wayland-util.h"
 #include "wayland-client.h"
@@ -334,19 +334,6 @@
 	display->next_range = range;
 }
 
-struct wl_display_listener {
-	void (*invalid_object)(void *data,
-			       struct wl_display *display, uint32_t id);
-	void (*invalid_method)(void *data, struct wl_display *display,
-			       uint32_t id, uint32_t opcode);
-	void (*no_memory)(void *data,
-			  struct wl_display *display);
-	void (*global)(void *data, struct wl_display *display,
-		       uint32_t id, const char *interface, uint32_t version);
-	void (*range)(void *data,
-		      struct wl_display *display, uint32_t range);
-};
-
 static const struct wl_display_listener display_listener = {
 	display_handle_invalid_object,
 	display_handle_invalid_method,
diff --git a/wayland-client.h b/wayland-client.h
index 2938ac8..482e32d 100644
--- a/wayland-client.h
+++ b/wayland-client.h
@@ -24,16 +24,12 @@
 #define _WAYLAND_CLIENT_H
 
 #include "wayland-util.h"
+#include "wayland-client-protocol.h"
 
 #ifdef  __cplusplus
 extern "C" {
 #endif
 
-struct wl_object;
-struct wl_display;
-struct wl_surface;
-struct wl_visual;
-
 #define WL_DISPLAY_READABLE 0x01
 #define WL_DISPLAY_WRITABLE 0x02
 
@@ -70,18 +66,6 @@
 struct wl_visual *
 wl_display_get_rgb_visual(struct wl_display *display);
 
-struct wl_compositor_listener {
-	void (*device)(void *data,
-		       struct wl_compositor *compositor,
-		       const char *device);
-	void (*acknowledge)(void *data,
-			    struct wl_compositor *compositor,
-			    uint32_t key, uint32_t frame);
-	void (*frame)(void *data,
-		      struct wl_compositor *compositor,
-		      uint32_t frame, uint32_t timestamp);
-};
-
 struct wl_surface *
 wl_compositor_create_surface(struct wl_compositor *compositor);
 void
@@ -104,43 +88,11 @@
 void wl_surface_set_user_data(struct wl_surface *surface, void *user_data);
 void *wl_surface_get_user_data(struct wl_surface *surface);
 
-struct wl_output;
-struct wl_output_listener {
-	void (*geometry)(void *data,
-			 struct wl_output *output,
-			 int32_t width, int32_t height);
-};
-
 int
 wl_output_add_listener(struct wl_output *output,
 		       const struct wl_output_listener *listener,
 		       void *data);
 
-struct wl_input_device;
-struct wl_input_device_listener {
-	void (*motion)(void *data,
-		       struct wl_input_device *input_device,
-		       uint32_t time,
-		       int32_t x, int32_t y, int32_t sx, int32_t sy);
-	void (*button)(void *data,
-		       struct wl_input_device *input_device,
-		       uint32_t time,
-		       uint32_t button, uint32_t state);
-	void (*key)(void *data,
-		    struct wl_input_device *input_device,
-		    uint32_t time,
-		    uint32_t button, uint32_t state);
-	void (*pointer_focus)(void *data,
-			      struct wl_input_device *input_device,
-			      uint32_t time,
-			      struct wl_surface *surface);
-	void (*keyboard_focus)(void *data,
-			       struct wl_input_device *input_device,
-			       uint32_t time,
-			       struct wl_surface *surface,
-			       struct wl_array *keys);
-};
-
 int
 wl_input_device_add_listener(struct wl_input_device *input_device,
 			     const struct wl_input_device_listener *listener,
diff --git a/wayland-protocol.c b/wayland-protocol.c
deleted file mode 100644
index 5a989d4..0000000
--- a/wayland-protocol.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * 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 "wayland-util.h"
-#include "wayland-protocol.h"
-
-static const struct wl_message display_events[] = {
-	{ "invalid_object", "u" },
-	{ "invalid_method", "uu" },
-	{ "no_memory", "" },
-	{ "global", "nsu" },
-	{ "range", "u" },
-};
-
-WL_EXPORT const struct wl_interface wl_display_interface = {
-	"display", 1,
-	0, NULL,
-	ARRAY_LENGTH(display_events), display_events,
-};
-
-
-static const struct wl_message compositor_methods[] = {
-	{ "create_surface", "n" },
-	{ "commit", "u" }
-};
-
-static const struct wl_message compositor_events[] = {
-	{ "device", "s" },
-	{ "acknowledge", "uu" },
-	{ "frame", "uu" }
-};
-
-WL_EXPORT const struct wl_interface wl_compositor_interface = {
-	"compositor", 1,
-	ARRAY_LENGTH(compositor_methods), compositor_methods,
-	ARRAY_LENGTH(compositor_events), compositor_events,
-};
-
-
-static const struct wl_message surface_methods[] = {
-	{ "destroy", "" },
-	{ "attach", "uuuuo" },
-	{ "map", "iiii" },
-	{ "damage", "iiii" }
-};
-
-WL_EXPORT const struct wl_interface wl_surface_interface = {
-	"surface", 1,
-	ARRAY_LENGTH(surface_methods), surface_methods,
-	0, NULL,
-};
-
-
-static const struct wl_message input_device_events[] = {
-	{ "motion", "uiiii" },
-	{ "button", "uuu" },
-	{ "key", "uuu" },
-	{ "pointer_focus", "uo" },
-	{ "keyboard_focus", "uoa" },
-};
-
-WL_EXPORT const struct wl_interface wl_input_device_interface = {
-	"input_device", 1,
-	0, NULL,
-	ARRAY_LENGTH(input_device_events), input_device_events,
-};
-
-
-static const struct wl_message output_events[] = {
-	{ "geometry", "uu" },
-};
-
-WL_EXPORT const struct wl_interface wl_output_interface = {
-	"output", 1,
-	0, NULL,
-	ARRAY_LENGTH(output_events), output_events,
-};
-
-WL_EXPORT const struct wl_interface wl_visual_interface = {
-	"visual", 1,
-	0, NULL,
-	0, NULL,
-};
diff --git a/wayland-protocol.h b/wayland-protocol.h
deleted file mode 100644
index eca2108..0000000
--- a/wayland-protocol.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef WAYLAND_PROTOCOL_H
-#define WAYLAND_PROTOCOL_H
-
-#ifdef  __cplusplus
-extern "C" {
-#endif
-
-#include <stdint.h>
-
-#define WL_DISPLAY_INVALID_OBJECT	0
-#define WL_DISPLAY_INVALID_METHOD	1
-#define WL_DISPLAY_NO_MEMORY		2
-#define WL_DISPLAY_GLOBAL		3
-#define WL_DISPLAY_RANGE		4
-
-extern const struct wl_interface wl_display_interface;
-
-
-#define WL_COMPOSITOR_CREATE_SURFACE	0
-#define WL_COMPOSITOR_COMMIT		1
-
-#define WL_COMPOSITOR_DEVICE		0
-#define WL_COMPOSITOR_ACKNOWLEDGE	1
-#define WL_COMPOSITOR_FRAME		2
-
-extern const struct wl_interface wl_compositor_interface;
-
-
-#define WL_SURFACE_DESTROY	0
-#define WL_SURFACE_ATTACH	1
-#define WL_SURFACE_MAP		2
-#define WL_SURFACE_DAMAGE	3
-
-extern const struct wl_interface wl_surface_interface;
-
-
-#define WL_INPUT_MOTION		0
-#define WL_INPUT_BUTTON		1
-#define WL_INPUT_KEY		2
-#define WL_INPUT_POINTER_FOCUS	3
-#define WL_INPUT_KEYBOARD_FOCUS	4
-
-extern const struct wl_interface wl_input_device_interface;
-
-
-#define WL_OUTPUT_GEOMETRY	0
-
-extern const struct wl_interface wl_output_interface;
-
-
-extern const struct wl_interface wl_visual_interface;
-
-#ifdef  __cplusplus
-}
-#endif
-
-#endif
diff --git a/wayland.c b/wayland.c
index dcadf26..de2a5c0 100644
--- a/wayland.c
+++ b/wayland.c
@@ -34,8 +34,8 @@
 #include <assert.h>
 #include <ffi.h>
 
-#include "wayland-protocol.h"
 #include "wayland.h"
+#include "wayland-server-protocol.h"
 #include "connection.h"
 
 struct wl_client {
diff --git a/wayland.h b/wayland.h
index d4bdbc8..511fdef 100644
--- a/wayland.h
+++ b/wayland.h
@@ -29,6 +29,7 @@
 
 #include <stdint.h>
 #include "wayland-util.h"
+#include "wayland-server-protocol.h"
 
 enum {
 	WL_EVENT_READABLE = 0x01,
@@ -99,27 +100,6 @@
 	struct wl_list link;
 };
 
-struct wl_compositor_interface {
-	void (*create_surface)(struct wl_client *client,
-			       struct wl_compositor *compositor, uint32_t id);
-	void (*commit)(struct wl_client *client,
-		       struct wl_compositor *compositor, uint32_t key);
-};
-
-struct wl_surface_interface {
-	void (*destroy)(struct wl_client *client,
-			struct wl_surface *surface);
-	void (*attach)(struct wl_client *client,
-		       struct wl_surface *surface, uint32_t name, 
-		       uint32_t width, uint32_t height, uint32_t stride,
-		       struct wl_object *visual);
-	void (*map)(struct wl_client *client,
-		    struct wl_surface *surface,
-		    int32_t x, int32_t y, int32_t width, int32_t height);
-	void (*damage)(struct wl_client *client, struct wl_surface *surface,
-		       int32_t x, int32_t y, int32_t width, int32_t height);
-};
-
 void
 wl_client_post_event(struct wl_client *client,
 		      struct wl_object *sender,