tizen 2.4 release accepted/tizen_2.4_mobile tizen_2.4 accepted/tizen/2.4/mobile/20151029.030542 submit/tizen_2.4/20151028.065121 tizen_2.4_mobile_release
authorjk7744.park <jk7744.park@samsung.com>
Mon, 26 Oct 2015 07:05:09 +0000 (16:05 +0900)
committerjk7744.park <jk7744.park@samsung.com>
Mon, 26 Oct 2015 07:05:09 +0000 (16:05 +0900)
114 files changed:
.gbs.conf [new file with mode: 0644]
.gitignore [new file with mode: 0644]
COPYING [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
README [new file with mode: 0644]
TODO [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0644]
cursor/convert_font.c [new file with mode: 0644]
cursor/cursor-data.h [new file with mode: 0644]
cursor/cursor.pcf [new file with mode: 0644]
cursor/os-compatibility.c [new file with mode: 0644]
cursor/os-compatibility.h [new file with mode: 0644]
cursor/wayland-cursor-uninstalled.pc.in [new file with mode: 0644]
cursor/wayland-cursor.c [new file with mode: 0644]
cursor/wayland-cursor.h [new file with mode: 0644]
cursor/wayland-cursor.pc.in [new file with mode: 0644]
cursor/xcursor.c [new file with mode: 0644]
cursor/xcursor.h [new file with mode: 0644]
doc/Contributing [new file with mode: 0644]
doc/Makefile.am [new file with mode: 0644]
doc/doxygen/.gitignore [new file with mode: 0644]
doc/doxygen/Makefile.am [new file with mode: 0644]
doc/doxygen/dot/wayland-architecture.gv [new file with mode: 0644]
doc/doxygen/dot/x-architecture.gv [new file with mode: 0644]
doc/doxygen/wayland.doxygen.in [new file with mode: 0644]
doc/man/Makefile.am [new file with mode: 0644]
doc/man/wl_display_connect.xml [new file with mode: 0644]
doc/publican/.gitignore [new file with mode: 0644]
doc/publican/Makefile.am [new file with mode: 0644]
doc/publican/doxygen-to-publican.xsl [new file with mode: 0644]
doc/publican/merge-mapcoords.xsl [new file with mode: 0644]
doc/publican/protocol-interfaces-to-docbook.xsl [new file with mode: 0644]
doc/publican/protocol-to-docbook.xsl [new file with mode: 0644]
doc/publican/sources/Architecture.xml [new file with mode: 0644]
doc/publican/sources/Author_Group.xml [new file with mode: 0644]
doc/publican/sources/Book_Info.xml [new file with mode: 0644]
doc/publican/sources/Client.xml [new file with mode: 0644]
doc/publican/sources/Compositors.xml [new file with mode: 0644]
doc/publican/sources/Foreword.xml [new file with mode: 0644]
doc/publican/sources/Introduction.xml [new file with mode: 0644]
doc/publican/sources/Preface.xml [new file with mode: 0644]
doc/publican/sources/Protocol.xml [new file with mode: 0644]
doc/publican/sources/Revision_History.xml [new file with mode: 0644]
doc/publican/sources/Server.xml [new file with mode: 0644]
doc/publican/sources/Wayland.ent [new file with mode: 0644]
doc/publican/sources/Wayland.xml [new file with mode: 0644]
doc/publican/sources/css/brand.css [new file with mode: 0644]
doc/publican/sources/css/common.css [new file with mode: 0644]
doc/publican/sources/css/default.css [new file with mode: 0644]
doc/publican/sources/css/epub.css [new file with mode: 0644]
doc/publican/sources/css/print.css [new file with mode: 0644]
doc/publican/sources/images/icon.svg [new file with mode: 0644]
doc/publican/sources/images/wayland.png [new file with mode: 0644]
m4/.gitignore [new file with mode: 0644]
packaging/baselibs.conf [new file with mode: 0644]
packaging/wayland.changes [new file with mode: 0644]
packaging/wayland.manifest [new file with mode: 0644]
packaging/wayland.spec [new file with mode: 0644]
protocol/.gitignore [new file with mode: 0644]
protocol/wayland.dtd [new file with mode: 0644]
protocol/wayland.xml [new file with mode: 0644]
protocol/wayland_multiseat.xml [new file with mode: 0644]
spec/.gitignore [new file with mode: 0644]
spec/wayland-architecture.png [new file with mode: 0644]
spec/x-architecture.png [new file with mode: 0644]
src/.gitignore [new file with mode: 0644]
src/connection.c [new file with mode: 0644]
src/event-loop.c [new file with mode: 0644]
src/scanner.c [new file with mode: 0644]
src/scanner.mk [new file with mode: 0644]
src/wayland-client-uninstalled.pc.in [new file with mode: 0644]
src/wayland-client.c [new file with mode: 0644]
src/wayland-client.h [new file with mode: 0644]
src/wayland-client.pc.in [new file with mode: 0644]
src/wayland-egl.h [new file with mode: 0644]
src/wayland-os.c [new file with mode: 0644]
src/wayland-os.h [new file with mode: 0644]
src/wayland-private.h [new file with mode: 0644]
src/wayland-scanner-uninstalled.pc.in [new file with mode: 0644]
src/wayland-scanner.pc.in [new file with mode: 0644]
src/wayland-server-uninstalled.pc.in [new file with mode: 0644]
src/wayland-server.c [new file with mode: 0644]
src/wayland-server.h [new file with mode: 0644]
src/wayland-server.pc.in [new file with mode: 0644]
src/wayland-shm.c [new file with mode: 0644]
src/wayland-util.c [new file with mode: 0644]
src/wayland-util.h [new file with mode: 0644]
src/wayland-version.h.in [new file with mode: 0644]
tests/array-test.c [new file with mode: 0644]
tests/client-test.c [new file with mode: 0644]
tests/connection-test.c [new file with mode: 0644]
tests/cpp-compile-test.cpp [new file with mode: 0644]
tests/display-test.c [new file with mode: 0644]
tests/event-loop-test.c [new file with mode: 0644]
tests/exec-fd-leak-checker.c [new file with mode: 0644]
tests/fixed-benchmark.c [new file with mode: 0644]
tests/fixed-test.c [new file with mode: 0644]
tests/list-test.c [new file with mode: 0644]
tests/map-test.c [new file with mode: 0644]
tests/message-test.c [new file with mode: 0644]
tests/os-wrappers-test.c [new file with mode: 0644]
tests/queue-test.c [new file with mode: 0644]
tests/resources-test.c [new file with mode: 0644]
tests/sanity-test.c [new file with mode: 0644]
tests/signal-test.c [new file with mode: 0644]
tests/socket-test.c [new file with mode: 0644]
tests/test-compositor.c [new file with mode: 0644]
tests/test-compositor.h [new file with mode: 0644]
tests/test-helpers.c [new file with mode: 0644]
tests/test-runner.c [new file with mode: 0644]
tests/test-runner.h [new file with mode: 0644]
wayland-scanner.m4 [new file with mode: 0644]
wayland-scanner.mk [new file with mode: 0644]

diff --git a/.gbs.conf b/.gbs.conf
new file mode 100644 (file)
index 0000000..fa9fdc5
--- /dev/null
+++ b/.gbs.conf
@@ -0,0 +1,3 @@
+[general]
+upstream_branch = upstream
+upstream_tag = ${upstreamversion}
diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..defe625
--- /dev/null
@@ -0,0 +1,59 @@
+*.deps
+*.jpg
+*.la
+*.lo
+*.o
+*.pc
+*.so
+*.swp
+*.3
+*.7
+*.log
+*.trs
+*.tar.xz
+*~
+.libs
+.dirstamp
+cscope.out
+ctags
+/aclocal.m4
+/wayland-scanner.m4
+/autom4te.cache
+/compile
+/config.guess
+/config.h
+/config.h.in
+/config.log
+/config.mk
+/config.status
+/config.sub
+/configure
+/depcomp
+/install-sh
+/libtool
+/ltmain.sh
+/missing
+/stamp-h1
+/test-driver
+Makefile
+Makefile.in
+array-test
+client-test
+connection-test
+cpp-compile-test
+display-test
+event-loop-test
+exec-fd-leak-checker
+fixed-benchmark
+fixed-test
+list-test
+map-test
+message-test
+os-wrappers-test
+queue-test
+resources-test
+sanity-test
+signal-test
+socket-test
+/wayland-scanner
+protocol/*.[ch]
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..6ba3d98
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,22 @@
+Copyright © 2008-2012 Kristian Høgsberg
+Copyright © 2010-2012 Intel Corporation
+Copyright © 2011 Benjamin Franzke
+Copyright © 2012 Collabora, Ltd.
+
+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.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..351b85e
--- /dev/null
@@ -0,0 +1,215 @@
+if BUILD_DOCS
+SUBDIRS = doc
+endif
+
+ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
+
+aclocaldir = $(datadir)/aclocal
+dist_aclocal_DATA = wayland-scanner.m4
+
+dist_pkgdata_DATA =                            \
+       wayland-scanner.mk                      \
+       protocol/wayland.xml    \
+       protocol/wayland.dtd
+
+if HAVE_MULTISEAT
+GCC_CFLAGS += -DHAVE_MULTISEAT
+wayland_api = $(top_srcdir)/protocol/wayland_multiseat.xml
+dist_pkgdata_DATA += protocol/wayland_multiseat.xml
+else
+wayland_api = $(top_srcdir)/protocol/wayland.xml
+endif
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA =
+
+lib_LTLIBRARIES = libwayland-server.la libwayland-client.la
+noinst_LTLIBRARIES = libwayland-util.la
+
+include_HEADERS =                              \
+       src/wayland-util.h                      \
+       src/wayland-server.h                    \
+       src/wayland-client.h                    \
+       src/wayland-egl.h                       \
+       src/wayland-version.h
+
+nodist_include_HEADERS =                       \
+       protocol/wayland-server-protocol.h      \
+       protocol/wayland-client-protocol.h
+
+libwayland_util_la_SOURCES =                   \
+       src/connection.c                        \
+       src/wayland-util.c                      \
+       src/wayland-util.h                      \
+       src/wayland-os.c                        \
+       src/wayland-os.h                        \
+       src/wayland-private.h
+
+libwayland_server_la_CFLAGS = $(FFI_CFLAGS) $(GCC_CFLAGS) -pthread
+libwayland_server_la_LIBADD = $(FFI_LIBS) libwayland-util.la -lrt -lm
+libwayland_server_la_LDFLAGS = -version-info 1:0:1
+libwayland_server_la_SOURCES =                 \
+       src/wayland-server.c                    \
+       src/wayland-shm.c                       \
+       src/event-loop.c
+
+nodist_libwayland_server_la_SOURCES =          \
+       protocol/wayland-server-protocol.h      \
+       protocol/wayland-protocol.c
+
+libwayland_client_la_CFLAGS = $(FFI_CFLAGS) $(GCC_CFLAGS) -pthread
+libwayland_client_la_LIBADD = $(FFI_LIBS) libwayland-util.la -lrt -lm
+libwayland_client_la_LDFLAGS = -version-info 3:0:3
+libwayland_client_la_SOURCES =                 \
+       src/wayland-client.c
+
+nodist_libwayland_client_la_SOURCES =          \
+       protocol/wayland-client-protocol.h      \
+       protocol/wayland-protocol.c
+
+pkgconfig_DATA += src/wayland-client.pc src/wayland-server.pc
+
+if ENABLE_SCANNER
+wayland_scanner = $(top_builddir)/wayland-scanner
+bin_PROGRAMS = wayland-scanner
+wayland_scanner_SOURCES = src/scanner.c
+wayland_scanner_CFLAGS = $(EXPAT_CFLAGS) $(AM_CFLAGS)
+wayland_scanner_LDADD = $(EXPAT_LIBS) libwayland-util.la
+$(BUILT_SOURCES) : wayland-scanner
+pkgconfig_DATA += src/wayland-scanner.pc
+else
+wayland_scanner = wayland-scanner
+endif
+
+protocol/%-protocol.c : $(wayland_api)
+       $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) code < $< > $@
+
+protocol/%-server-protocol.h : $(wayland_api)
+       $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) server-header < $< > $@
+
+protocol/%-client-protocol.h : $(wayland_api)
+       $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) client-header < $< > $@
+
+BUILT_SOURCES =                                        \
+       $(nodist_libwayland_server_la_SOURCES)  \
+       $(nodist_libwayland_client_la_SOURCES)
+
+CLEANFILES = $(BUILT_SOURCES)
+DISTCLEANFILES = src/wayland-version.h
+EXTRA_DIST = src/wayland-version.h.in
+
+
+
+lib_LTLIBRARIES += libwayland-cursor.la
+
+include_HEADERS += cursor/wayland-cursor.h
+
+libwayland_cursor_la_SOURCES =                 \
+       cursor/wayland-cursor.c                 \
+       cursor/os-compatibility.c               \
+       cursor/os-compatibility.h               \
+       cursor/cursor-data.h                    \
+       cursor/xcursor.c                        \
+       cursor/xcursor.h
+libwayland_cursor_la_LIBADD = libwayland-client.la
+
+pkgconfig_DATA += cursor/wayland-cursor.pc
+
+libwayland_cursor_la_CFLAGS =                  \
+       $(GCC_CFLAGS)                           \
+       -I$(top_builddir)/src                   \
+       -I$(top_srcdir)/src                     \
+       -DICONDIR=\"$(ICONDIR)\"
+
+
+TESTS =                                                \
+       array-test                              \
+       client-test                             \
+       display-test                            \
+       connection-test                         \
+       event-loop-test                         \
+       fixed-test                              \
+       list-test                               \
+       map-test                                \
+       os-wrappers-test                        \
+       sanity-test                             \
+       socket-test                             \
+       queue-test                              \
+       signal-test                             \
+       resources-test                          \
+       message-test
+
+if ENABLE_CPP_TEST
+TESTS += cpp-compile-test
+endif
+
+check_PROGRAMS =                               \
+       $(TESTS)                                \
+       exec-fd-leak-checker
+
+noinst_PROGRAMS =                              \
+       fixed-benchmark
+
+check_LTLIBRARIES = libtest-runner.la
+
+libtest_runner_la_SOURCES =                    \
+       tests/test-runner.c                     \
+       tests/test-runner.h                     \
+       tests/test-helpers.c                    \
+       tests/test-compositor.h                 \
+       tests/test-compositor.c
+libtest_runner_la_LIBADD =                     \
+       libwayland-util.la                      \
+       libwayland-client.la                    \
+       libwayland-server.la                    \
+       -lrt -ldl $(FFI_LIBS)
+
+
+array_test_SOURCES = tests/array-test.c
+array_test_LDADD = libtest-runner.la
+client_test_SOURCES = tests/client-test.c
+client_test_LDADD = libtest-runner.la
+display_test_SOURCES = tests/display-test.c
+display_test_LDADD = libtest-runner.la
+connection_test_SOURCES = tests/connection-test.c
+connection_test_LDADD = libtest-runner.la
+event_loop_test_SOURCES = tests/event-loop-test.c
+event_loop_test_LDADD = libtest-runner.la
+fixed_test_SOURCES = tests/fixed-test.c
+fixed_test_LDADD = libtest-runner.la
+list_test_SOURCES = tests/list-test.c
+list_test_LDADD = libtest-runner.la
+map_test_SOURCES = tests/map-test.c
+map_test_LDADD = libtest-runner.la
+sanity_test_SOURCES = tests/sanity-test.c
+sanity_test_LDADD = libtest-runner.la
+socket_test_SOURCES = tests/socket-test.c
+socket_test_LDADD = libtest-runner.la
+queue_test_SOURCES = tests/queue-test.c
+queue_test_LDADD = libtest-runner.la
+signal_test_SOURCES = tests/signal-test.c
+signal_test_LDADD = libtest-runner.la
+resources_test_SOURCES = tests/resources-test.c
+resources_test_LDADD = libtest-runner.la
+message_test_SOURCES = tests/message-test.c
+message_test_LDADD = libtest-runner.la
+
+if ENABLE_CPP_TEST
+cpp_compile_test_SOURCES = tests/cpp-compile-test.cpp
+endif
+
+fixed_benchmark_SOURCES = tests/fixed-benchmark.c
+fixed_benchmark_LDADD = libtest-runner.la
+
+os_wrappers_test_SOURCES = tests/os-wrappers-test.c
+os_wrappers_test_LDADD = libtest-runner.la
+
+AM_CPPFLAGS =                                  \
+       -I$(top_builddir)/src                   \
+       -I$(top_srcdir)/src                     \
+       -I$(top_builddir)/protocol
+
+AM_CFLAGS = $(GCC_CFLAGS) $(FFI_CFLAGS)
+
+exec_fd_leak_checker_SOURCES = tests/exec-fd-leak-checker.c
+exec_fd_leak_checker_LDADD = libtest-runner.la
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..63ffa31
--- /dev/null
+++ b/README
@@ -0,0 +1,35 @@
+What is Wayland?
+
+Wayland is a project to define a protocol for a compositor to talk to
+its clients as well as a library implementation of the protocol.  The
+compositor can be a standalone display server running on Linux kernel
+modesetting and evdev input devices, an X application, or a wayland
+client itself.  The clients can be traditional applications, X servers
+(rootless or fullscreen) or other display servers.
+
+The wayland protocol is essentially only about input handling and
+buffer management.  The compositor receives input events and forwards
+them to the relevant client.  The clients creates buffers and renders
+into them and notifies the compositor when it needs to redraw.  The
+protocol also handles drag and drop, selections, window management and
+other interactions that must go through the compositor.  However, the
+protocol does not handle rendering, which is one of the features that
+makes wayland so simple.  All clients are expected to handle rendering
+themselves, typically through cairo or OpenGL.
+
+The weston compositor is a reference implementation of a wayland
+compositor and the weston repository also includes a few example
+clients.
+
+Building the wayland libraries is fairly simple, aside from libffi,
+they don't have many dependencies:
+
+    $ git clone git://anongit.freedesktop.org/wayland/wayland
+    $ cd wayland
+    $ ./autogen.sh --prefix=PREFIX
+    $ make
+    $ make install
+
+where PREFIX is where you want to install the libraries.  See
+http://wayland.freedesktop.org for more complete build instructions
+for wayland, weston, xwayland and various toolkits.
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..8cb8d34
--- /dev/null
+++ b/TODO
@@ -0,0 +1,149 @@
+Core wayland protocol
+
+ - Maybe try to make remote wayland actually happen, to see if there
+   is something in the protocol/architecture that makes it harder than
+   it should be.
+
+ICCCM
+
+ - mime-type guidelines for data_source (ie, both dnd and selection):
+   recommended types for text or images, types that a clipboard
+   manager must support, mime-types must be listed in preferred order
+
+ - we need a "no kb focus please" mechanism.  Or should this be
+   implicit in a specific surface type?
+
+EWMH
+
+ - configure should provide dx_left, dx_right, dy_top, dy_bottom, or
+   dx, dy, width and height.
+
+ - move to workspace, keep on top, on all workspaces, minimize etc
+   requests for implementing client side window menu? or just make a
+   "show window menu" request to let the compositor display and manage
+   a popup window?
+
+ - window move and resize functionality for kb and touch.
+
+ - Protocol for specifying title bar rectangle (for moving
+   unresponsive apps).  Rectangle for close button, so we can popup
+   force-close dialog if application doesn't respond to ping event
+   when user clicks there.  We could use the region mechanism here
+   too.
+
+ - popup placement protocol logic.
+
+ - subsurface mechanism.  we need this for cases where we would use an
+   X subwindow for gl or video other different visual type.
+
+EGL/gbm
+
+ - Land Robert Braggs EGL extensions: frame age, swap with damage
+
+ - Make it possible to share buffers from compositor to clients.
+   Tricky part here is how to indicate to EGL on the server side that
+   it should make an EGLImage available to a client.  We'll need a
+   "create a wl_buffer for this EGLImage for this client" kind of
+   entry point.
+
+ - Protocol for arbitrating access to scanout buffers (physically
+   contiguous memory).  When a client goes fullscreen (or ideally as
+   the compositor starts the animation that will make it fullscreen)
+   we send a "give up your scanout buffer" to the current fullscreen
+   client (if any) and when the client acks that we send a "try to
+   allocate a scanout buffer now" event to the fullscreen-to-be
+   client.
+
+
+Misc
+
+ - glyph cache
+
+    - Needs a mechanism to pass buffers to client.
+
+      buffer = drm.create_buffer(); /* buffer with stuff in it */
+
+      cache.upload(buffer, x, y, width, height, int hash)
+
+      drm.buffer: id, name, stride etc /* event to announce cache buffer */
+
+      cache.image: hash, buffer, x, y, stride /* event to announce
+                                             * location in cache */
+
+      cache.reject: hash   /* no upload for you! */
+
+      cache.retire: buffer /* cache has stopped using buffer, please
+                           * reupload whatever you had in that buffer */
+
+ - A "please suspend" event from the compositor, to indicate to an
+   application that it's no longer visible/active.  Or maybe discard
+   buffer, as in "wayland discarded your buffer, it's no longer
+   visible, you can stop updating it now.", reattach, as in "oh hey,
+   I'm about to show your buffer that I threw away, what was it
+   again?".  for wayland system compositor vt switcing, for example,
+   to be able to throw away the surfaces in the session we're
+   switching away from.  for minimized windows that we don't want live
+   thumb nails for. etc.
+
+
+Clients and ports
+
+ - port gtk+
+
+    - draw window decorations in gtkwindow.c
+
+    - Details about pointer grabs. wayland doesn't have active grabs,
+      menus will behave subtly different.  Under X, clicking a menu
+      open grabs the pointer and clicking outside the window pops down
+      the menu and swallows the click.  without active grabs we can't
+      swallow the click.  I'm sure there much more...
+
+    - dnd, copy-paste
+
+ - Investigate DirectFB on Wayland (or is that Wayland on DirectFB?)
+
+ - SDL port, bnf has work in progress here:
+   http://cgit.freedesktop.org/~bnf/sdl-wayland/
+
+
+Ideas
+
+ - A wayland settings protocol to tell clients about themes (icons,
+   cursors, widget themes), fonts details (family, hinting
+   preferences) etc.  Just send all settings at connect time, send
+   updates when a setting change.  Getting a little close to gconf
+   here, but could be pretty simple:
+
+     interface "settings":
+       event int_value(string name, int value)
+       event string_value(string name, string value)
+
+   but maybe it's better to just require that clients get that from
+   somewhere else (gconf/dbus).
+
+
+Crazy ideas
+
+ - AF_WAYLAND - A new socket type.  Eliminate compositor context
+   switch by making kernel understand enough of wayland that it can
+   forward input events as wayland events and do page flipping in
+   response to surface_attach requests:
+
+    - ioctl(wayland_fd, "surface_attach to object 5 should do a kms page
+                        flip on ctrc 2");
+
+    - what about multiple crtcs? what about frame event for other
+      clients?
+
+    - forward these input devices to the client
+
+    - "scancode 124 pressed or released with scan codes 18,22 and 30
+       held down gives control back to userspace wayland.
+
+    - what about maintaining cursor position? what about pointer
+      acceleration?  maybe this only works in "client cursor mode",
+      where wayland hides the cursor and only sends relative events?
+      Solves the composited cursor problem.  How does X show its
+      cursor then?
+
+    - Probably not worth it.
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..916169a
--- /dev/null
@@ -0,0 +1,9 @@
+#! /bin/sh
+
+test -n "$srcdir" || srcdir=`dirname "$0"`
+test -n "$srcdir" || srcdir=.
+(
+  cd "$srcdir" &&
+  autoreconf --force -v --install
+) || exit
+test -n "$NOCONFIGURE" || "$srcdir/configure" "$@"
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..cdde3df
--- /dev/null
@@ -0,0 +1,180 @@
+AC_PREREQ([2.64])
+
+m4_define([wayland_major_version], [1])
+m4_define([wayland_minor_version], [7])
+m4_define([wayland_micro_version],  [0])
+m4_define([wayland_version],
+          [wayland_major_version.wayland_minor_version.wayland_micro_version])
+
+AC_INIT([wayland],
+        [wayland_version],
+        [https://bugs.freedesktop.org/enter_bug.cgi?product=Wayland&component=wayland&version=wayland_version],
+        [wayland],
+        [http://wayland.freedesktop.org/])
+
+AC_SUBST([WAYLAND_VERSION_MAJOR], [wayland_major_version])
+AC_SUBST([WAYLAND_VERSION_MINOR], [wayland_minor_version])
+AC_SUBST([WAYLAND_VERSION_MICRO], [wayland_micro_version])
+AC_SUBST([WAYLAND_VERSION], [wayland_version])
+
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+
+AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz subdir-objects])
+
+AM_SILENT_RULES([yes])
+
+# Check for programs
+AC_PROG_CC
+AC_PROG_CXX
+AC_PROG_GREP
+
+# check if we have C++ compiler. This is hacky workaround,
+# for a reason why it is this way see
+# http://lists.gnu.org/archive/html/bug-autoconf/2010-05/msg00001.html
+have_cpp_compiler=yes
+
+if ! which "$CXX" &>/dev/null; then
+       have_cpp_compiler=no
+fi
+
+AM_CONDITIONAL(ENABLE_CPP_TEST, test "x$have_cpp_compiler" = "xyes")
+
+# Initialize libtool
+LT_PREREQ([2.2])
+LT_INIT
+
+PKG_PROG_PKG_CONFIG()
+PKG_CHECK_MODULES(FFI, [libffi])
+
+if test "x$GCC" = "xyes"; then
+       GCC_CFLAGS="-Wall -Wextra -Wno-unused-parameter -g -Wstrict-prototypes -Wmissing-prototypes -fvisibility=hidden"
+fi
+AC_SUBST(GCC_CFLAGS)
+
+AC_CHECK_FUNCS([accept4 mkostemp posix_fallocate])
+
+AC_CHECK_DECL(SFD_CLOEXEC,[],
+             [AC_MSG_ERROR("SFD_CLOEXEC is needed to compile wayland")],
+             [[#include <sys/signalfd.h>]])
+AC_CHECK_DECL(TFD_CLOEXEC,[],
+             [AC_MSG_ERROR("TFD_CLOEXEC is needed to compile wayland")],
+             [[#include <sys/timerfd.h>]])
+AC_CHECK_DECL(CLOCK_MONOTONIC,[],
+             [AC_MSG_ERROR("CLOCK_MONOTONIC is needed to compile wayland")],
+             [[#include <time.h>]])
+AC_CHECK_HEADERS([execinfo.h])
+
+AC_ARG_ENABLE([scanner],
+              [AC_HELP_STRING([--disable-scanner],
+                              [Disable compilation of wayland-scanner])],
+              [],
+              [enable_scanner=yes])
+
+AC_ARG_ENABLE([documentation],
+             [AC_HELP_STRING([--disable-documentation],
+                             [Disable building the documentation])],
+             [],
+             [enable_documentation=yes])
+
+AM_CONDITIONAL(ENABLE_SCANNER, test "x$enable_scanner" = xyes)
+
+AC_ARG_ENABLE([multiseat],
+              [AC_HELP_STRING([--enable-multiseat],
+                              [Enable multiseat feature])],
+              [],
+              [enable_multiseat=no])
+
+AM_CONDITIONAL(HAVE_MULTISEAT, test "x$enable_multiseat" = xyes)
+
+AC_ARG_WITH(icondir, [  --with-icondir=<dir>    Look for cursor icons here],
+                    [  ICONDIR=$withval],
+                    [  ICONDIR=${datadir}/icons])
+AC_SUBST([ICONDIR])
+
+if test "x$enable_scanner" = "xyes"; then
+       PKG_CHECK_MODULES(EXPAT, [expat], [],
+               [AC_CHECK_HEADERS(expat.h, [],
+                       [AC_MSG_ERROR([Can't find expat.h. Please install expat.])])
+                SAVE_LIBS="$LIBS"
+                AC_SEARCH_LIBS(XML_ParserCreate, expat, [],
+                       [AC_MSG_ERROR([Can't find expat library. Please install expat.])])
+                EXPAT_LIBS="$LIBS"
+                LIBS="$SAVE_LIBS"
+                AC_SUBST(EXPAT_LIBS)
+               ])
+fi
+
+AC_PATH_PROG(XSLTPROC, xsltproc)
+AM_CONDITIONAL([HAVE_XSLTPROC], [test "x$XSLTPROC" != "x"])
+
+AC_MSG_CHECKING([for docbook manpages stylesheet])
+MANPAGES_STYLESHEET=http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl
+AC_PATH_PROGS_FEATURE_CHECK([XSLTPROC_TMP], [xsltproc],
+                           AS_IF([`"$ac_path_XSLTPROC_TMP" --nonet "$MANPAGES_STYLESHEET" > /dev/null 2>&1`],
+                                 [HAVE_MANPAGES_STYLESHEET=yes]))
+if test "x$HAVE_MANPAGES_STYLESHEET" = "xyes"; then
+       AM_CONDITIONAL([HAVE_MANPAGES_STYLESHEET], true)
+       AC_SUBST(MANPAGES_STYLESHEET)
+       AC_MSG_RESULT([yes])
+else
+       AM_CONDITIONAL([HAVE_MANPAGES_STYLESHEET], false)
+       AC_MSG_RESULT([no])
+fi
+
+AM_CONDITIONAL(BUILD_DOCS, [test x$enable_documentation = xyes])
+if test "x$enable_documentation" = "xyes"; then
+       AC_PATH_PROG(DOXYGEN, doxygen)
+
+       if test "x$DOXYGEN" = "x"; then
+               AC_MSG_ERROR([Documentation build requested but doxygen not found. Install doxygen or disable the documentation using --disable-documentation])
+       fi
+
+       AC_MSG_CHECKING([for compatible doxygen version])
+       doxygen_version=`$DOXYGEN --version`
+       AS_VERSION_COMPARE([$doxygen_version], [1.6.0],
+                          [AC_MSG_RESULT([no])
+                           AC_MSG_ERROR([Doxygen $doxygen_version too old. Doxygen 1.6+ required for documentation build. Install required doxygen version or disable the documentation using --disable-documentation])],
+                          [AC_MSG_RESULT([yes])],
+                          [AC_MSG_RESULT([yes])])
+
+       AC_PATH_PROG(XMLTO, xmlto)
+
+       if test "x$XMLTO" = "x"; then
+               AC_MSG_ERROR([Documentation build requested but xmlto not found. Install xmlto or disable the documentation using --disable-documentation])
+       fi
+
+       AC_PATH_PROG(DOT, dot)
+       if test "x$DOT" = "x"; then
+               AC_MSG_ERROR([Documentation build requested but graphviz's dot not found. Install graphviz or disable the documentation using --disable-documentation])
+       fi
+       AC_MSG_CHECKING([for compatible dot version])
+       dot_version=`$DOT -V 2>&1|$GREP -oP '(?<=version\W)@<:@0-9.@:>@*(?=\W(.*))'`
+       AS_VERSION_COMPARE([$dot_version], [2.26.0],
+                          [AC_MSG_RESULT([no])
+                           AC_MSG_ERROR([Graphviz dot $dot_version too old. Graphviz 2.26+ required for documentation build. Install required graphviz version or disable the documentation using --disable-documentation])],
+                          [AC_MSG_RESULT([yes])],
+                          [AC_MSG_RESULT([yes])])
+
+       AC_CONFIG_FILES([
+       doc/doxygen/wayland.doxygen
+       ])
+
+fi
+AM_CONDITIONAL([HAVE_XMLTO], [test "x$XMLTO" != "x"])
+
+AC_CONFIG_FILES([Makefile
+                cursor/wayland-cursor.pc
+                cursor/wayland-cursor-uninstalled.pc
+                doc/Makefile
+                doc/publican/Makefile
+                doc/doxygen/Makefile
+                doc/man/Makefile
+                src/wayland-server-uninstalled.pc
+                src/wayland-client-uninstalled.pc
+                src/wayland-scanner-uninstalled.pc
+                src/wayland-server.pc
+                src/wayland-client.pc
+                src/wayland-scanner.pc
+                src/wayland-version.h])
+AC_OUTPUT
diff --git a/cursor/convert_font.c b/cursor/convert_font.c
new file mode 100644 (file)
index 0000000..de1b8ad
--- /dev/null
@@ -0,0 +1,531 @@
+/*
+ * Copyright © 2012 Philipp Brüschweiler
+ *
+ * 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.
+ */
+
+/*
+ * This is a small, hacky tool to extract cursors from a .pcf file.
+ * The information about the file format has been gathered from
+ * http://fontforge.org/pcf-format.html
+ */
+
+#include <assert.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define max(a, b) ((a) > (b) ? (a) : (b))
+
+struct glyph {
+       char *name;
+       int16_t left_bearing, right_bearing, ascent, descent;
+
+       int16_t width, height;
+       int16_t hotx, hoty;
+
+       int32_t data_format;
+       char *data;
+};
+
+static struct {
+       int count;
+       struct glyph *glyphs;
+} extracted_font = {0, NULL};
+
+#define PCF_PROPERTIES             (1<<0)
+#define PCF_ACCELERATORS           (1<<1)
+#define PCF_METRICS                (1<<2)
+#define PCF_BITMAPS                (1<<3)
+#define PCF_INK_METRICS                    (1<<4)
+#define        PCF_BDF_ENCODINGS           (1<<5)
+#define PCF_SWIDTHS                (1<<6)
+#define PCF_GLYPH_NAMES                    (1<<7)
+#define PCF_BDF_ACCELERATORS       (1<<8)
+
+#define PCF_DEFAULT_FORMAT     0x00000000
+#define PCF_INKBOUNDS          0x00000200
+#define PCF_ACCEL_W_INKBOUNDS  0x00000100
+#define PCF_COMPRESSED_METRICS 0x00000100
+
+#define        PCF_FORMAT_MASK         0xffffff00
+
+struct pcf_header {
+       char header[4];
+       int32_t table_count;
+       struct toc_entry {
+               int32_t type;
+               int32_t format;
+               int32_t size;
+               int32_t offset;
+       } tables[0];
+};
+
+struct compressed_metrics {
+       uint8_t left_sided_bearing;
+       uint8_t right_side_bearing;
+       uint8_t character_width;
+       uint8_t character_ascent;
+       uint8_t character_descent;
+};
+
+struct uncompressed_metrics {
+       int16_t left_sided_bearing;
+       int16_t right_side_bearing;
+       int16_t character_width;
+       int16_t character_ascent;
+       int16_t character_descent;
+       uint16_t character_attributes;
+};
+
+struct metrics {
+       int32_t format;
+       union {
+               struct {
+                       int16_t count;
+                       struct compressed_metrics compressed_metrics[0];
+               } compressed;
+               struct {
+                       int32_t count;
+                       struct uncompressed_metrics uncompressed_metrics[0];
+               } uncompressed;
+       };
+};
+
+struct glyph_names {
+       int32_t format;
+       int32_t glyph_count;
+       int32_t offsets[0];
+};
+
+struct bitmaps {
+       int32_t format;
+       int32_t glyph_count;
+       int32_t offsets[0];
+};
+
+static void
+handle_compressed_metrics(int32_t count, struct compressed_metrics *m)
+{
+       printf("metrics count: %d\n", count);
+       extracted_font.count = count;
+       extracted_font.glyphs = calloc(count, sizeof(struct glyph));
+
+       int i;
+       for (i = 0; i < count; ++i) {
+               struct glyph *glyph = &extracted_font.glyphs[i];
+               glyph->left_bearing =
+                       ((int16_t) m[i].left_sided_bearing) - 0x80;
+               glyph->right_bearing =
+                       ((int16_t) m[i].right_side_bearing) - 0x80;
+               glyph->width = ((int16_t) m[i].character_width) - 0x80;
+               glyph->ascent = ((int16_t) m[i].character_ascent) - 0x80;
+               glyph->descent = ((int16_t) m[i].character_descent) - 0x80;
+
+               /* computed stuff */
+               glyph->height = glyph->ascent + glyph->descent;
+
+               glyph->hotx = -glyph->left_bearing;
+               glyph->hoty = glyph->ascent;
+       }
+}
+
+static void
+handle_metrics(void *metricbuf)
+{
+       struct metrics *metrics = metricbuf;
+       printf("metric format: %x\n", metrics->format);
+
+       if ((metrics->format & PCF_FORMAT_MASK) == PCF_DEFAULT_FORMAT) {
+               printf("todo...\n");
+       } else if ((metrics->format & PCF_FORMAT_MASK) ==
+                  PCF_COMPRESSED_METRICS) {
+               handle_compressed_metrics(
+                   metrics->compressed.count,
+                   &metrics->compressed.compressed_metrics[0]);
+       } else {
+               printf("incompatible format\n");
+               abort();
+       }
+}
+
+static void
+handle_glyph_names(struct glyph_names *names)
+{
+       printf("glyph count %d\n", names->glyph_count);
+
+       if (names->glyph_count != extracted_font.count) {
+               abort();
+       }
+
+       printf("glyph names format %x\n", names->format);
+
+       void *names_start = ((void*) names) + sizeof(struct glyph_names)
+               + (names->glyph_count + 1) * sizeof(int32_t);
+
+       int i;
+       for (i = 0; i < names->glyph_count; ++i) {
+               int32_t start = names->offsets[i];
+               int32_t end = names->offsets[i+1];
+               char *name = names_start + start;
+               extracted_font.glyphs[i].name = calloc(1, end - start + 1);
+               memcpy(extracted_font.glyphs[i].name, name, end - start);
+       }
+}
+
+static void
+handle_bitmaps(struct bitmaps *bitmaps)
+{
+       printf("bitmaps count %d\n", bitmaps->glyph_count);
+
+       if (bitmaps->glyph_count != extracted_font.count) {
+               abort();
+       }
+
+       printf("format %x\n", bitmaps->format);
+
+       if (bitmaps->format != 2) {
+               printf("format not yet supported\n");
+               abort();
+       }
+
+       void *bitmaps_start = ((void*) bitmaps) + sizeof(struct bitmaps)
+               + (bitmaps->glyph_count + 4) * sizeof(int32_t);
+
+       int i;
+       for (i = 0; i < bitmaps->glyph_count; ++i) {
+               int32_t offset = bitmaps->offsets[i];
+               struct glyph *glyph = &extracted_font.glyphs[i];
+               glyph->data_format = bitmaps->format;
+
+               glyph->data = bitmaps_start + offset;
+       }
+}
+
+static void
+handle_pcf(void *fontbuf)
+{
+       struct pcf_header *header = fontbuf;
+       printf("tablecount %d\n", header->table_count);
+
+       int i;
+       for (i = 0; i < header->table_count; ++i) {
+               struct toc_entry *entry = &header->tables[i];
+               printf("type: %d\n", entry->type);
+               if (entry->type == PCF_METRICS) {
+                       handle_metrics(fontbuf + entry->offset);
+               } else if (entry->type == PCF_GLYPH_NAMES) {
+                       handle_glyph_names(fontbuf + entry->offset);
+               } else if (entry->type == PCF_BITMAPS) {
+                       handle_bitmaps(fontbuf + entry->offset);
+               }
+       }
+}
+
+static char
+get_glyph_pixel(struct glyph *glyph, int x, int y)
+{
+       int absx = glyph->hotx + x;
+       int absy = glyph->hoty + y;
+
+       if (absx < 0 || absx >= glyph->width ||
+           absy < 0 || absy >= glyph->height)
+               return 0;
+
+       int stride = (glyph->width + 31) / 32 * 4;
+       unsigned char block = glyph->data[absy * stride + (absx/8)];
+       int idx = absx % 8;
+       return (block >> idx) & 1;
+}
+
+static struct {
+       uint32_t *data;
+       size_t capacity, size;
+} data_buffer;
+
+static void
+init_data_buffer()
+{
+       data_buffer.data = malloc(sizeof(uint32_t) * 10);
+       data_buffer.capacity = 10;
+       data_buffer.size = 0;
+}
+
+static void
+add_pixel(uint32_t pixel)
+{
+       if (data_buffer.size == data_buffer.capacity) {
+               data_buffer.capacity *= 2;
+               data_buffer.data =
+                       realloc(data_buffer.data,
+                               sizeof(uint32_t) * data_buffer.capacity);
+       }
+       data_buffer.data[data_buffer.size++] = pixel;
+}
+
+struct reconstructed_glyph {
+       int32_t width, height;
+       int32_t hotspot_x, hotspot_y;
+       size_t offset;
+       char *name;
+};
+
+static void
+reconstruct_glyph(struct glyph *cursor, struct glyph *mask, char *name,
+                 struct reconstructed_glyph *glyph)
+{
+       int minx = min(-cursor->hotx, -mask->hotx);
+       int maxx = max(cursor->right_bearing, mask->right_bearing);
+
+       int miny = min(-cursor->hoty, -mask->hoty);
+       int maxy = max(cursor->height - cursor->hoty,
+                      mask->height - mask->hoty);
+
+       int width = maxx - minx;
+       int height = maxy - miny;
+
+       glyph->name = strdup(name);
+       glyph->width = width;
+       glyph->height = height;
+       glyph->hotspot_x = -minx;
+       glyph->hotspot_y = -miny;
+       glyph->offset = data_buffer.size;
+
+       int x, y;
+       for (y = miny; y < maxy; ++y) {
+               for (x = minx; x < maxx; ++x) {
+                       char alpha = get_glyph_pixel(mask, x, y);
+                       if (alpha) {
+                               char color = get_glyph_pixel(cursor, x, y);
+                               if (color)
+                                       add_pixel(0xff000000);
+                               else
+                                       add_pixel(0xffffffff);
+                       } else {
+                               add_pixel(0);
+                       }
+               }
+       }
+}
+
+/* From http://cgit.freedesktop.org/xorg/lib/libXfont/tree/src/builtins/fonts.c */
+static const char cursor_licence[] =
+       "/*\n"
+       "* Copyright 1999 SuSE, Inc.\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\n"
+       "* copyright notice and this permission notice appear in supporting\n"
+       "* documentation, and that the name of SuSE not be used in advertising or\n"
+       "* publicity pertaining to distribution of the software without specific,\n"
+       "* written prior permission.  SuSE makes no representations about the\n"
+       "* suitability of this software for any purpose.  It is provided \"as is\"\n"
+       "* without express or implied warranty.\n"
+       "*\n"
+       "* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL\n"
+       "* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE\n"
+       "* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n"
+       "* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION\n"
+       "* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN\n"
+       "* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n"
+       "*\n"
+       "* Author:  Keith Packard, SuSE, Inc.\n"
+       "*/\n";
+
+static void
+write_output_file(struct reconstructed_glyph *glyphs, int n)
+{
+       int i, j, counter, size;
+       FILE *file = fopen("cursor-data.h", "w");
+       uint32_t *data;
+
+       fprintf(file, "%s\n", cursor_licence);
+
+       fprintf(file, "static uint32_t cursor_data[] = {\n\t");
+
+       counter = 0;
+       for (i = 0; i < n; ++i) {
+               data = data_buffer.data + glyphs[i].offset;
+               size = glyphs[i].width * glyphs[i].height;
+
+               for (j = 0; j < size; ++j) {
+                       fprintf(file, "0x%08x, ", data[j]);
+                       if (++counter % 6 == 0)
+                               fprintf(file, "\n\t");
+               }
+       }
+       fprintf(file, "\n};\n\n");
+
+       fprintf(file,
+               "static struct {\n"
+               "\tchar *name;\n"
+               "\tint width, height;\n"
+               "\tint hotspot_x, hotspot_y;\n"
+               "\tsize_t offset;\n"
+               "} cursor_metadata[] = {\n");
+
+       for (i = 0; i < n; ++i)
+               fprintf(file, "\t{ \"%s\", %d, %d, %d, %d, %zu },\n",
+                       glyphs[i].name,
+                       glyphs[i].width, glyphs[i].height,
+                       glyphs[i].hotspot_x, glyphs[i].hotspot_y,
+                       glyphs[i].offset);
+
+       fprintf(file, "};");
+
+       fclose(file);
+}
+
+struct glyph *
+find_mask_glyph(char *name)
+{
+       const char mask[] = "_mask";
+       const int masklen = strlen(mask);
+
+       int len = strlen(name);
+       int i;
+       for (i = 0; i < extracted_font.count; ++i) {
+               struct glyph *g = &extracted_font.glyphs[i];
+               int l2 = strlen(g->name);
+               if ((l2 == len + masklen) &&
+                   (memcmp(g->name, name, len) == 0) &&
+                   (memcmp(g->name + len, mask, masklen) == 0)) {
+                       return g;
+               }
+       }
+       return NULL;
+}
+
+static void
+output_all_cursors()
+{
+       int i, j;
+       struct reconstructed_glyph *glyphs =
+               malloc(sizeof(struct reconstructed_glyph) *
+                      extracted_font.count/2);
+       j = 0;
+
+       for (i = 0; i < extracted_font.count; ++i) {
+               struct glyph *g = &extracted_font.glyphs[i];
+               if (strstr(g->name, "_mask"))
+                       continue;
+
+               struct glyph *mask = find_mask_glyph(g->name);
+
+               reconstruct_glyph(g, mask, g->name, &glyphs[j]);
+               j++;
+       }
+
+       write_output_file(glyphs, extracted_font.count/2);
+}
+
+static void
+find_cursor_and_mask(const char *name,
+                    struct glyph **cursor,
+                    struct glyph **mask)
+{
+       int i;
+       char mask_name[100];
+       sprintf(mask_name, "%s_mask", name);
+
+       *cursor = *mask = NULL;
+
+       for (i = 0; i < extracted_font.count && (!*mask || !*cursor); ++i) {
+               struct glyph *g = &extracted_font.glyphs[i];
+               if (!strcmp(name, g->name))
+                       *cursor = g;
+               else if (!strcmp(mask_name, g->name))
+                       *mask = g;
+       }
+}
+
+static struct {
+       char *target_name, *source_name;
+} interesting_cursors[] = {
+       { "bottom_left_corner", "bottom_left_corner" },
+       { "bottom_right_corner", "bottom_right_corner" },
+       { "bottom_side", "bottom_side" },
+       { "grabbing", "fleur" },
+       { "left_ptr", "left_ptr" },
+       { "left_side", "left_side" },
+       { "right_side", "right_side" },
+       { "top_left_corner", "top_left_corner" },
+       { "top_right_corner", "top_right_corner" },
+       { "top_side", "top_side" },
+       { "xterm", "xterm" },
+       { "hand1", "hand1" },
+       { "watch", "watch" }
+};
+
+static void
+output_interesting_cursors()
+{
+       int i;
+       int n = sizeof(interesting_cursors) / sizeof(interesting_cursors[0]);
+       struct reconstructed_glyph *glyphs =
+               malloc(n * sizeof(*glyphs));
+
+       for (i = 0; i < n; ++i) {
+               struct glyph *cursor, *mask;
+               find_cursor_and_mask(interesting_cursors[i].source_name,
+                                    &cursor, &mask);
+               if (!cursor) {
+                       printf("no cursor for %s\n",
+                              interesting_cursors[i].source_name);
+                       abort();
+               }
+               if (!mask) {
+                       printf("no mask for %s\n",
+                              interesting_cursors[i].source_name);
+                       abort();
+               }
+               reconstruct_glyph(cursor, mask,
+                                 interesting_cursors[i].target_name,
+                                 &glyphs[i]);
+       }
+
+       write_output_file(glyphs, n);
+}
+
+int main()
+{
+       const char filename[] = "cursor.pcf";
+
+       int fd = open(filename, O_RDONLY);
+       struct stat filestat;
+
+       fstat(fd, &filestat);
+
+       void *fontbuf = mmap(NULL, filestat.st_size, PROT_READ,
+                            MAP_PRIVATE, fd, 0);
+
+       handle_pcf(fontbuf);
+
+       init_data_buffer();
+
+       //output_all_cursors();
+       output_interesting_cursors();
+}
diff --git a/cursor/cursor-data.h b/cursor/cursor-data.h
new file mode 100644 (file)
index 0000000..4c5e672
--- /dev/null
@@ -0,0 +1,548 @@
+/*
+* Copyright 1999 SuSE, Inc.
+*
+* 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 SuSE not be used in advertising or
+* publicity pertaining to distribution of the software without specific,
+* written prior permission.  SuSE makes no representations about the
+* suitability of this software for any purpose.  It is provided "as is"
+* without express or implied warranty.
+*
+* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
+* 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.
+*
+* Author:  Keith Packard, SuSE, Inc.
+*/
+
+static uint32_t cursor_data[] = {
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 
+       0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 
+       0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xff000000, 
+       0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 
+       0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 
+       0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 
+       0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+       0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 
+       0xff000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0x00000000, 
+       0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 
+       0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 
+       0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 
+       0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 
+       0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 
+       0xff000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 
+       0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 
+       0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 
+       0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 
+       0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xffffffff, 0xff000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 
+       0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 
+       0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 
+       0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+       0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 
+       0xff000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 
+       0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 
+       0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 
+       0xffffffff, 0x00000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0xff000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 
+       0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xff000000, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 
+       0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 
+       0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 
+       0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+       0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 
+       0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 
+       0x00000000, 0x00000000, 
+};
+
+static struct cursor_metadata {
+       char *name;
+       int width, height;
+       int hotspot_x, hotspot_y;
+       size_t offset;
+} cursor_metadata[] = {
+       { "bottom_left_corner", 16, 16, 1, 14, 0 },
+       { "bottom_right_corner", 16, 16, 14, 14, 256 },
+       { "bottom_side", 15, 16, 7, 14, 512 },
+       { "grabbing", 16, 16, 8, 8, 752 },
+       { "left_ptr", 10, 16, 1, 1, 1008 },
+       { "left_side", 16, 15, 1, 7, 1168 },
+       { "right_side", 16, 15, 14, 7, 1408 },
+       { "top_left_corner", 16, 16, 1, 1, 1648 },
+       { "top_right_corner", 16, 16, 14, 1, 1904 },
+       { "top_side", 15, 16, 7, 1, 2160 },
+       { "xterm", 9, 16, 4, 8, 2400 },
+       { "hand1", 13, 16, 12, 0, 2544 },
+       { "watch", 16, 16, 15, 9, 2752 },
+};
diff --git a/cursor/cursor.pcf b/cursor/cursor.pcf
new file mode 100644 (file)
index 0000000..812fcc5
Binary files /dev/null and b/cursor/cursor.pcf differ
diff --git a/cursor/os-compatibility.c b/cursor/os-compatibility.c
new file mode 100644 (file)
index 0000000..0c41242
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "config.h"
+#include "os-compatibility.h"
+
+#ifndef HAVE_MKOSTEMP
+static int
+set_cloexec_or_close(int fd)
+{
+       long flags;
+
+       if (fd == -1)
+               return -1;
+
+       flags = fcntl(fd, F_GETFD);
+       if (flags == -1)
+               goto err;
+
+       if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
+               goto err;
+
+       return fd;
+
+err:
+       close(fd);
+       return -1;
+}
+#endif
+
+static int
+create_tmpfile_cloexec(char *tmpname)
+{
+       int fd;
+
+#ifdef HAVE_MKOSTEMP
+       fd = mkostemp(tmpname, O_CLOEXEC);
+       if (fd >= 0)
+               unlink(tmpname);
+#else
+       fd = mkstemp(tmpname);
+       if (fd >= 0) {
+               fd = set_cloexec_or_close(fd);
+               unlink(tmpname);
+       }
+#endif
+
+       return fd;
+}
+
+/*
+ * Create a new, unique, anonymous file of the given size, and
+ * return the file descriptor for it. The file descriptor is set
+ * CLOEXEC. The file is immediately suitable for mmap()'ing
+ * the given size at offset zero.
+ *
+ * The file should not have a permanent backing store like a disk,
+ * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
+ *
+ * The file name is deleted from the file system.
+ *
+ * The file is suitable for buffer sharing between processes by
+ * transmitting the file descriptor over Unix sockets using the
+ * SCM_RIGHTS methods.
+ *
+ * If the C library implements posix_fallocate(), it is used to
+ * guarantee that disk space is available for the file at the
+ * given size. If disk space is insufficent, errno is set to ENOSPC.
+ * If posix_fallocate() is not supported, program may receive
+ * SIGBUS on accessing mmap()'ed file contents instead.
+ */
+int
+os_create_anonymous_file(off_t size)
+{
+       static const char template[] = "/weston-shared-XXXXXX";
+       const char *path;
+       char *name;
+       int fd;
+       int ret;
+
+       path = getenv("XDG_RUNTIME_DIR");
+       if (!path) {
+               errno = ENOENT;
+               return -1;
+       }
+
+       name = malloc(strlen(path) + sizeof(template));
+       if (!name)
+               return -1;
+
+       strcpy(name, path);
+       strcat(name, template);
+
+       fd = create_tmpfile_cloexec(name);
+
+       free(name);
+
+       if (fd < 0)
+               return -1;
+
+#ifdef HAVE_POSIX_FALLOCATE
+       ret = posix_fallocate(fd, 0, size);
+       if (ret != 0) {
+               close(fd);
+               errno = ret;
+               return -1;
+       }
+#else
+       ret = ftruncate(fd, size);
+       if (ret < 0) {
+               close(fd);
+               return -1;
+       }
+#endif
+
+       return fd;
+}
diff --git a/cursor/os-compatibility.h b/cursor/os-compatibility.h
new file mode 100644 (file)
index 0000000..947555c
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * 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 OS_COMPATIBILITY_H
+#define OS_COMPATIBILITY_H
+
+#include <sys/types.h>
+
+int
+os_create_anonymous_file(off_t size);
+
+#endif /* OS_COMPATIBILITY_H */
diff --git a/cursor/wayland-cursor-uninstalled.pc.in b/cursor/wayland-cursor-uninstalled.pc.in
new file mode 100644 (file)
index 0000000..f52b113
--- /dev/null
@@ -0,0 +1,8 @@
+libdir=@abs_builddir@/.libs
+includedir=@abs_srcdir@
+
+Name: Wayland Cursor
+Description: Wayland cursor helper library (not installed)
+Version: @WAYLAND_VERSION@
+Cflags: -I${includedir}
+Libs: -L${libdir} -lwayland-cursor
diff --git a/cursor/wayland-cursor.c b/cursor/wayland-cursor.c
new file mode 100644 (file)
index 0000000..dba3b51
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * 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 "config.h"
+#include "xcursor.h"
+#include "wayland-cursor.h"
+#include "wayland-client.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "os-compatibility.h"
+
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+
+struct shm_pool {
+       struct wl_shm_pool *pool;
+       int fd;
+       unsigned int size;
+       unsigned int used;
+       char *data;
+};
+
+static struct shm_pool *
+shm_pool_create(struct wl_shm *shm, int size)
+{
+       struct shm_pool *pool;
+
+       pool = malloc(sizeof *pool);
+       if (!pool)
+               return NULL;
+
+       pool->fd = os_create_anonymous_file(size);
+       if (pool->fd < 0)
+               goto err_free;
+
+       pool->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED,
+                         pool->fd, 0);
+
+       if (pool->data == MAP_FAILED)
+               goto err_close;
+
+       pool->pool = wl_shm_create_pool(shm, pool->fd, size);
+       pool->size = size;
+       pool->used = 0;
+
+       return pool;
+
+err_close:
+       close(pool->fd);
+err_free:
+       free(pool);
+       return NULL;
+}
+
+static int
+shm_pool_resize(struct shm_pool *pool, int size)
+{
+       if (ftruncate(pool->fd, size) < 0)
+               return 0;
+
+#ifdef HAVE_POSIX_FALLOCATE
+       errno = posix_fallocate(pool->fd, 0, size);
+       if (errno != 0)
+               return 0;
+#endif
+
+       wl_shm_pool_resize(pool->pool, size);
+
+       munmap(pool->data, pool->size);
+
+       pool->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED,
+                         pool->fd, 0);
+       if (pool->data == (void *)-1)
+               return 0;
+       pool->size = size;
+
+       return 1;
+}
+
+static int
+shm_pool_allocate(struct shm_pool *pool, int size)
+{
+       int offset;
+
+       if (pool->used + size > pool->size)
+               if (!shm_pool_resize(pool, 2 * pool->size + size))
+                       return -1;
+
+       offset = pool->used;
+       pool->used += size;
+
+       return offset;
+}
+
+static void
+shm_pool_destroy(struct shm_pool *pool)
+{
+       munmap(pool->data, pool->size);
+       wl_shm_pool_destroy(pool->pool);
+       close(pool->fd);
+       free(pool);
+}
+
+
+struct wl_cursor_theme {
+       unsigned int cursor_count;
+       struct wl_cursor **cursors;
+       struct wl_shm *shm;
+       struct shm_pool *pool;
+       char *name;
+       int size;
+};
+
+struct cursor_image {
+       struct wl_cursor_image image;
+       struct wl_cursor_theme *theme;
+       struct wl_buffer *buffer;
+       int offset; /* data offset of this image in the shm pool */
+};
+
+struct cursor {
+       struct wl_cursor cursor;
+       uint32_t total_delay; /* length of the animation in ms */
+};
+
+/** Get an shm buffer for a cursor image
+ *
+ * \param image The cursor image
+ * \return An shm buffer for the cursor image. The user should not destroy
+ * the returned buffer.
+ */
+WL_EXPORT struct wl_buffer *
+wl_cursor_image_get_buffer(struct wl_cursor_image *_img)
+{
+       struct cursor_image *image = (struct cursor_image *) _img;
+       struct wl_cursor_theme *theme = image->theme;
+
+       if (!image->buffer) {
+               image->buffer =
+                       wl_shm_pool_create_buffer(theme->pool->pool,
+                                                 image->offset,
+                                                 _img->width, _img->height,
+                                                 _img->width * 4,
+                                                 WL_SHM_FORMAT_ARGB8888);
+       };
+
+       return image->buffer;
+}
+
+static void
+wl_cursor_image_destroy(struct wl_cursor_image *_img)
+{
+       struct cursor_image *image = (struct cursor_image *) _img;
+
+       if (image->buffer)
+               wl_buffer_destroy(image->buffer);
+
+       free(image);
+}
+
+static void
+wl_cursor_destroy(struct wl_cursor *cursor)
+{
+       unsigned int i;
+
+       for (i = 0; i < cursor->image_count; i++)
+               wl_cursor_image_destroy(cursor->images[i]);
+
+       free(cursor->name);
+       free(cursor);
+}
+
+#include "cursor-data.h"
+
+static struct wl_cursor *
+wl_cursor_create_from_data(struct cursor_metadata *metadata,
+                          struct wl_cursor_theme *theme)
+{
+       struct cursor *cursor;
+       struct cursor_image *image;
+       int size;
+
+       cursor = malloc(sizeof *cursor);
+       if (!cursor)
+               return NULL;
+
+       cursor->cursor.image_count = 1;
+       cursor->cursor.images = malloc(sizeof *cursor->cursor.images);
+       if (!cursor->cursor.images)
+               goto err_free_cursor;
+
+       cursor->cursor.name = strdup(metadata->name);
+       cursor->total_delay = 0;
+
+       image = malloc(sizeof *image);
+       if (!image)
+               goto err_free_images;
+
+       cursor->cursor.images[0] = (struct wl_cursor_image *) image;
+       image->theme = theme;
+       image->buffer = NULL;
+       image->image.width = metadata->width;
+       image->image.height = metadata->height;
+       image->image.hotspot_x = metadata->hotspot_x;
+       image->image.hotspot_y = metadata->hotspot_y;
+       image->image.delay = 0;
+
+       size = metadata->width * metadata->height * sizeof(uint32_t);
+       image->offset = shm_pool_allocate(theme->pool, size);
+
+       if (image->offset < 0)
+               goto err_free_image;
+
+       memcpy(theme->pool->data + image->offset,
+              cursor_data + metadata->offset, size);
+
+       return &cursor->cursor;
+
+err_free_image:
+       free(image);
+
+err_free_images:
+       free(cursor->cursor.name);
+       free(cursor->cursor.images);
+
+err_free_cursor:
+       free(cursor);
+       return NULL;
+}
+
+static void
+load_default_theme(struct wl_cursor_theme *theme)
+{
+       uint32_t i;
+
+       free(theme->name);
+       theme->name = strdup("default");
+
+       theme->cursor_count = ARRAY_LENGTH(cursor_metadata);
+       theme->cursors = malloc(theme->cursor_count * sizeof(*theme->cursors));
+
+       if (theme->cursors == NULL) {
+               theme->cursor_count = 0;
+               return;
+       }
+
+       for (i = 0; i < theme->cursor_count; ++i) {
+               theme->cursors[i] =
+                       wl_cursor_create_from_data(&cursor_metadata[i], theme);
+
+               if (theme->cursors[i] == NULL)
+                       break;
+       }
+       theme->cursor_count = i;
+}
+
+static struct wl_cursor *
+wl_cursor_create_from_xcursor_images(XcursorImages *images,
+                                    struct wl_cursor_theme *theme)
+{
+       struct cursor *cursor;
+       struct cursor_image *image;
+       int i, size;
+
+       cursor = malloc(sizeof *cursor);
+       if (!cursor)
+               return NULL;
+
+       cursor->cursor.images =
+               malloc(images->nimage * sizeof cursor->cursor.images[0]);
+       if (!cursor->cursor.images) {
+               free(cursor);
+               return NULL;
+       }
+
+       cursor->cursor.name = strdup(images->name);
+       cursor->total_delay = 0;
+
+       for (i = 0; i < images->nimage; i++) {
+               image = malloc(sizeof *image);
+               if (image == NULL)
+                       break;
+
+               image->theme = theme;
+               image->buffer = NULL;
+
+               image->image.width = images->images[i]->width;
+               image->image.height = images->images[i]->height;
+               image->image.hotspot_x = images->images[i]->xhot;
+               image->image.hotspot_y = images->images[i]->yhot;
+               image->image.delay = images->images[i]->delay;
+
+               size = image->image.width * image->image.height * 4;
+               image->offset = shm_pool_allocate(theme->pool, size);
+               if (image->offset < 0) {
+                       free(image);
+                       break;
+               }
+
+               /* copy pixels to shm pool */
+               memcpy(theme->pool->data + image->offset,
+                      images->images[i]->pixels, size);
+               cursor->total_delay += image->image.delay;
+               cursor->cursor.images[i] = (struct wl_cursor_image *) image;
+       }
+       cursor->cursor.image_count = i;
+
+       if (cursor->cursor.image_count == 0) {
+               free(cursor->cursor.name);
+               free(cursor->cursor.images);
+               free(cursor);
+               return NULL;
+       }
+
+       return &cursor->cursor;
+}
+
+static void
+load_callback(XcursorImages *images, void *data)
+{
+       struct wl_cursor_theme *theme = data;
+       struct wl_cursor *cursor;
+
+       if (wl_cursor_theme_get_cursor(theme, images->name)) {
+               XcursorImagesDestroy(images);
+               return;
+       }
+
+       cursor = wl_cursor_create_from_xcursor_images(images, theme);
+
+       if (cursor) {
+               theme->cursor_count++;
+               theme->cursors =
+                       realloc(theme->cursors,
+                               theme->cursor_count * sizeof theme->cursors[0]);
+
+               if (theme->cursors == NULL) {
+                       theme->cursor_count--;
+                       free(cursor);
+               } else {
+                       theme->cursors[theme->cursor_count - 1] = cursor;
+               }
+       }
+
+       XcursorImagesDestroy(images);
+}
+
+/** Load a cursor theme to memory shared with the compositor
+ *
+ * \param name The name of the cursor theme to load. If %NULL, the default
+ * theme will be loaded.
+ * \param size Desired size of the cursor images.
+ * \param shm The compositor's shm interface.
+ *
+ * \return An object representing the theme that should be destroyed with
+ * wl_cursor_theme_destroy() or %NULL on error. If no theme with the given
+ * name exists, a default theme will be loaded.
+ */
+WL_EXPORT struct wl_cursor_theme *
+wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm)
+{
+       struct wl_cursor_theme *theme;
+
+       theme = malloc(sizeof *theme);
+       if (!theme)
+               return NULL;
+
+       if (!name)
+               name = "default";
+
+       theme->name = strdup(name);
+       if (!theme->name)
+               goto out_error_name;
+       theme->size = size;
+       theme->cursor_count = 0;
+       theme->cursors = NULL;
+
+       theme->pool = shm_pool_create(shm, size * size * 4);
+       if (!theme->pool)
+               goto out_error_pool;
+
+       xcursor_load_theme(name, size, load_callback, theme);
+
+       if (theme->cursor_count == 0)
+               load_default_theme(theme);
+
+       return theme;
+
+out_error_pool:
+       free(theme->name);
+out_error_name:
+       free(theme);
+       return NULL;
+}
+
+/** Destroys a cursor theme object
+ *
+ * \param theme The cursor theme to be destroyed
+ */
+WL_EXPORT void
+wl_cursor_theme_destroy(struct wl_cursor_theme *theme)
+{
+       unsigned int i;
+
+       for (i = 0; i < theme->cursor_count; i++)
+               wl_cursor_destroy(theme->cursors[i]);
+
+       shm_pool_destroy(theme->pool);
+
+       free(theme->name);
+       free(theme->cursors);
+       free(theme);
+}
+
+/** Get the cursor for a given name from a cursor theme
+ *
+ * \param theme The cursor theme
+ * \param name Name of the desired cursor
+ * \return The theme's cursor of the given name or %NULL if there is no
+ * such cursor
+ */
+WL_EXPORT struct wl_cursor *
+wl_cursor_theme_get_cursor(struct wl_cursor_theme *theme,
+                          const char *name)
+{
+       unsigned int i;
+
+       for (i = 0; i < theme->cursor_count; i++) {
+               if (strcmp(name, theme->cursors[i]->name) == 0)
+                       return theme->cursors[i];
+       }
+
+       return NULL;
+}
+
+/** Find the frame for a given elapsed time in a cursor animation
+ *
+ * \param cursor The cursor
+ * \param time Elapsed time since the beginning of the animation
+ *
+ * \return The index of the image that should be displayed for the
+ * given time in the cursor animation.
+ */
+WL_EXPORT int
+wl_cursor_frame(struct wl_cursor *_cursor, uint32_t time)
+{
+       struct cursor *cursor = (struct cursor *) _cursor;
+       uint32_t t;
+       int i;
+
+       if (cursor->cursor.image_count == 1)
+               return 0;
+
+       i = 0;
+       t = time % cursor->total_delay;
+
+       while (t - cursor->cursor.images[i]->delay < t)
+               t -= cursor->cursor.images[i++]->delay;
+
+       return i;
+}
diff --git a/cursor/wayland-cursor.h b/cursor/wayland-cursor.h
new file mode 100644 (file)
index 0000000..c7548ae
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * 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_CURSOR_H
+#define WAYLAND_CURSOR_H
+
+#include <stdint.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+struct wl_cursor_theme;
+
+struct wl_cursor_image {
+       uint32_t width;         /* actual width */
+       uint32_t height;        /* actual height */
+       uint32_t hotspot_x;     /* hot spot x (must be inside image) */
+       uint32_t hotspot_y;     /* hot spot y (must be inside image) */
+       uint32_t delay;         /* animation delay to next frame (ms) */
+};
+
+struct wl_cursor {
+       unsigned int image_count;
+       struct wl_cursor_image **images;
+       char *name;
+};
+
+struct wl_shm;
+
+struct wl_cursor_theme *
+wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm);
+
+void
+wl_cursor_theme_destroy(struct wl_cursor_theme *theme);
+
+struct wl_cursor *
+wl_cursor_theme_get_cursor(struct wl_cursor_theme *theme,
+                          const char *name);
+
+struct wl_buffer *
+wl_cursor_image_get_buffer(struct wl_cursor_image *image);
+
+int
+wl_cursor_frame(struct wl_cursor *cursor, uint32_t time);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/cursor/wayland-cursor.pc.in b/cursor/wayland-cursor.pc.in
new file mode 100644 (file)
index 0000000..fbbf5ff
--- /dev/null
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Wayland Cursor
+Description: Wayland cursor helper library
+Version: @WAYLAND_VERSION@
+Cflags: -I${includedir}
+Libs: -L${libdir} -lwayland-cursor
diff --git a/cursor/xcursor.c b/cursor/xcursor.c
new file mode 100644 (file)
index 0000000..f9d9669
--- /dev/null
@@ -0,0 +1,968 @@
+/*
+ * Copyright © 2002 Keith Packard
+ *
+ * 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 Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD 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 "xcursor.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+
+/*
+ * From libXcursor/include/X11/extensions/Xcursor.h
+ */
+
+#define XcursorTrue    1
+#define XcursorFalse   0
+
+/*
+ * Cursor files start with a header.  The header
+ * contains a magic number, a version number and a
+ * table of contents which has type and offset information
+ * for the remaining tables in the file.
+ *
+ * File minor versions increment for compatible changes
+ * File major versions increment for incompatible changes (never, we hope)
+ *
+ * Chunks of the same type are always upward compatible.  Incompatible
+ * changes are made with new chunk types; the old data can remain under
+ * the old type.  Upward compatible changes can add header data as the
+ * header lengths are specified in the file.
+ *
+ *  File:
+ *     FileHeader
+ *     LISTofChunk
+ *
+ *  FileHeader:
+ *     CARD32          magic       magic number
+ *     CARD32          header      bytes in file header
+ *     CARD32          version     file version
+ *     CARD32          ntoc        number of toc entries
+ *     LISTofFileToc   toc         table of contents
+ *
+ *  FileToc:
+ *     CARD32          type        entry type
+ *     CARD32          subtype     entry subtype (size for images)
+ *     CARD32          position    absolute file position
+ */
+
+#define XCURSOR_MAGIC  0x72756358  /* "Xcur" LSBFirst */
+
+/*
+ * Current Xcursor version number.  Will be substituted by configure
+ * from the version in the libXcursor configure.ac file.
+ */
+
+#define XCURSOR_LIB_MAJOR 1
+#define XCURSOR_LIB_MINOR 1
+#define XCURSOR_LIB_REVISION 13
+#define XCURSOR_LIB_VERSION    ((XCURSOR_LIB_MAJOR * 10000) + \
+                                (XCURSOR_LIB_MINOR * 100) + \
+                                (XCURSOR_LIB_REVISION))
+
+/*
+ * This version number is stored in cursor files; changes to the
+ * file format require updating this version number
+ */
+#define XCURSOR_FILE_MAJOR     1
+#define XCURSOR_FILE_MINOR     0
+#define XCURSOR_FILE_VERSION   ((XCURSOR_FILE_MAJOR << 16) | (XCURSOR_FILE_MINOR))
+#define XCURSOR_FILE_HEADER_LEN        (4 * 4)
+#define XCURSOR_FILE_TOC_LEN   (3 * 4)
+
+typedef struct _XcursorFileToc {
+    XcursorUInt            type;       /* chunk type */
+    XcursorUInt            subtype;    /* subtype (size for images) */
+    XcursorUInt            position;   /* absolute position in file */
+} XcursorFileToc;
+
+typedef struct _XcursorFileHeader {
+    XcursorUInt            magic;      /* magic number */
+    XcursorUInt            header;     /* byte length of header */
+    XcursorUInt            version;    /* file version number */
+    XcursorUInt            ntoc;       /* number of toc entries */
+    XcursorFileToc  *tocs;     /* table of contents */
+} XcursorFileHeader;
+
+/*
+ * The rest of the file is a list of chunks, each tagged by type
+ * and version.
+ *
+ *  Chunk:
+ *     ChunkHeader
+ *     <extra type-specific header fields>
+ *     <type-specific data>
+ *
+ *  ChunkHeader:
+ *     CARD32      header      bytes in chunk header + type header
+ *     CARD32      type        chunk type
+ *     CARD32      subtype     chunk subtype
+ *     CARD32      version     chunk type version
+ */
+
+#define XCURSOR_CHUNK_HEADER_LEN    (4 * 4)
+
+typedef struct _XcursorChunkHeader {
+    XcursorUInt            header;     /* bytes in chunk header */
+    XcursorUInt            type;       /* chunk type */
+    XcursorUInt            subtype;    /* chunk subtype (size for images) */
+    XcursorUInt            version;    /* version of this type */
+} XcursorChunkHeader;
+
+/*
+ * Here's a list of the known chunk types
+ */
+
+/*
+ * Comments consist of a 4-byte length field followed by
+ * UTF-8 encoded text
+ *
+ *  Comment:
+ *     ChunkHeader header      chunk header
+ *     CARD32      length      bytes in text
+ *     LISTofCARD8 text        UTF-8 encoded text
+ */
+
+#define XCURSOR_COMMENT_TYPE       0xfffe0001
+#define XCURSOR_COMMENT_VERSION            1
+#define XCURSOR_COMMENT_HEADER_LEN  (XCURSOR_CHUNK_HEADER_LEN + (1 *4))
+#define XCURSOR_COMMENT_COPYRIGHT   1
+#define XCURSOR_COMMENT_LICENSE            2
+#define XCURSOR_COMMENT_OTHER      3
+#define XCURSOR_COMMENT_MAX_LEN            0x100000
+
+typedef struct _XcursorComment {
+    XcursorUInt            version;
+    XcursorUInt            comment_type;
+    char           *comment;
+} XcursorComment;
+
+/*
+ * Each cursor image occupies a separate image chunk.
+ * The length of the image header follows the chunk header
+ * so that future versions can extend the header without
+ * breaking older applications
+ *
+ *  Image:
+ *     ChunkHeader     header  chunk header
+ *     CARD32          width   actual width
+ *     CARD32          height  actual height
+ *     CARD32          xhot    hot spot x
+ *     CARD32          yhot    hot spot y
+ *     CARD32          delay   animation delay
+ *     LISTofCARD32    pixels  ARGB pixels
+ */
+
+#define XCURSOR_IMAGE_TYPE         0xfffd0002
+#define XCURSOR_IMAGE_VERSION      1
+#define XCURSOR_IMAGE_HEADER_LEN    (XCURSOR_CHUNK_HEADER_LEN + (5*4))
+#define XCURSOR_IMAGE_MAX_SIZE     0x7fff      /* 32767x32767 max cursor size */
+
+typedef struct _XcursorFile XcursorFile;
+
+struct _XcursorFile {
+    void    *closure;
+    int            (*read)  (XcursorFile *file, unsigned char *buf, int len);
+    int            (*write) (XcursorFile *file, unsigned char *buf, int len);
+    int            (*seek)  (XcursorFile *file, long offset, int whence);
+};
+
+typedef struct _XcursorComments {
+    int                    ncomment;   /* number of comments */
+    XcursorComment  **comments;        /* array of XcursorComment pointers */
+} XcursorComments;
+
+/*
+ * From libXcursor/src/file.c
+ */
+
+static XcursorImage *
+XcursorImageCreate (int width, int height)
+{
+    XcursorImage    *image;
+
+    image = malloc (sizeof (XcursorImage) +
+                   width * height * sizeof (XcursorPixel));
+    if (!image)
+       return NULL;
+    image->version = XCURSOR_IMAGE_VERSION;
+    image->pixels = (XcursorPixel *) (image + 1);
+    image->size = width > height ? width : height;
+    image->width = width;
+    image->height = height;
+    image->delay = 0;
+    return image;
+}
+
+static void
+XcursorImageDestroy (XcursorImage *image)
+{
+    free (image);
+}
+
+static XcursorImages *
+XcursorImagesCreate (int size)
+{
+    XcursorImages   *images;
+
+    images = malloc (sizeof (XcursorImages) +
+                    size * sizeof (XcursorImage *));
+    if (!images)
+       return NULL;
+    images->nimage = 0;
+    images->images = (XcursorImage **) (images + 1);
+    images->name = NULL;
+    return images;
+}
+
+void
+XcursorImagesDestroy (XcursorImages *images)
+{
+    int        n;
+
+    if (!images)
+        return;
+
+    for (n = 0; n < images->nimage; n++)
+       XcursorImageDestroy (images->images[n]);
+    if (images->name)
+       free (images->name);
+    free (images);
+}
+
+static void
+XcursorImagesSetName (XcursorImages *images, const char *name)
+{
+    char    *new;
+
+    if (!images || !name)
+        return;
+
+    new = malloc (strlen (name) + 1);
+
+    if (!new)
+       return;
+
+    strcpy (new, name);
+    if (images->name)
+       free (images->name);
+    images->name = new;
+}
+
+static XcursorBool
+_XcursorReadUInt (XcursorFile *file, XcursorUInt *u)
+{
+    unsigned char   bytes[4];
+
+    if (!file || !u)
+        return XcursorFalse;
+
+    if ((*file->read) (file, bytes, 4) != 4)
+       return XcursorFalse;
+    *u = ((bytes[0] << 0) |
+         (bytes[1] << 8) |
+         (bytes[2] << 16) |
+         (bytes[3] << 24));
+    return XcursorTrue;
+}
+
+static void
+_XcursorFileHeaderDestroy (XcursorFileHeader *fileHeader)
+{
+    free (fileHeader);
+}
+
+static XcursorFileHeader *
+_XcursorFileHeaderCreate (int ntoc)
+{
+    XcursorFileHeader  *fileHeader;
+
+    if (ntoc > 0x10000)
+       return NULL;
+    fileHeader = malloc (sizeof (XcursorFileHeader) +
+                        ntoc * sizeof (XcursorFileToc));
+    if (!fileHeader)
+       return NULL;
+    fileHeader->magic = XCURSOR_MAGIC;
+    fileHeader->header = XCURSOR_FILE_HEADER_LEN;
+    fileHeader->version = XCURSOR_FILE_VERSION;
+    fileHeader->ntoc = ntoc;
+    fileHeader->tocs = (XcursorFileToc *) (fileHeader + 1);
+    return fileHeader;
+}
+
+static XcursorFileHeader *
+_XcursorReadFileHeader (XcursorFile *file)
+{
+    XcursorFileHeader  head, *fileHeader;
+    XcursorUInt                skip;
+    unsigned int       n;
+
+    if (!file)
+        return NULL;
+
+    if (!_XcursorReadUInt (file, &head.magic))
+       return NULL;
+    if (head.magic != XCURSOR_MAGIC)
+       return NULL;
+    if (!_XcursorReadUInt (file, &head.header))
+       return NULL;
+    if (!_XcursorReadUInt (file, &head.version))
+       return NULL;
+    if (!_XcursorReadUInt (file, &head.ntoc))
+       return NULL;
+    skip = head.header - XCURSOR_FILE_HEADER_LEN;
+    if (skip)
+       if ((*file->seek) (file, skip, SEEK_CUR) == EOF)
+           return NULL;
+    fileHeader = _XcursorFileHeaderCreate (head.ntoc);
+    if (!fileHeader)
+       return NULL;
+    fileHeader->magic = head.magic;
+    fileHeader->header = head.header;
+    fileHeader->version = head.version;
+    fileHeader->ntoc = head.ntoc;
+    for (n = 0; n < fileHeader->ntoc; n++)
+    {
+       if (!_XcursorReadUInt (file, &fileHeader->tocs[n].type))
+           break;
+       if (!_XcursorReadUInt (file, &fileHeader->tocs[n].subtype))
+           break;
+       if (!_XcursorReadUInt (file, &fileHeader->tocs[n].position))
+           break;
+    }
+    if (n != fileHeader->ntoc)
+    {
+       _XcursorFileHeaderDestroy (fileHeader);
+       return NULL;
+    }
+    return fileHeader;
+}
+
+static XcursorBool
+_XcursorSeekToToc (XcursorFile         *file,
+                  XcursorFileHeader    *fileHeader,
+                  int                  toc)
+{
+    if (!file || !fileHeader || \
+        (*file->seek) (file, fileHeader->tocs[toc].position, SEEK_SET) == EOF)
+       return XcursorFalse;
+    return XcursorTrue;
+}
+
+static XcursorBool
+_XcursorFileReadChunkHeader (XcursorFile       *file,
+                            XcursorFileHeader  *fileHeader,
+                            int                toc,
+                            XcursorChunkHeader *chunkHeader)
+{
+    if (!file || !fileHeader || !chunkHeader)
+        return XcursorFalse;
+    if (!_XcursorSeekToToc (file, fileHeader, toc))
+       return XcursorFalse;
+    if (!_XcursorReadUInt (file, &chunkHeader->header))
+       return XcursorFalse;
+    if (!_XcursorReadUInt (file, &chunkHeader->type))
+       return XcursorFalse;
+    if (!_XcursorReadUInt (file, &chunkHeader->subtype))
+       return XcursorFalse;
+    if (!_XcursorReadUInt (file, &chunkHeader->version))
+       return XcursorFalse;
+    /* sanity check */
+    if (chunkHeader->type != fileHeader->tocs[toc].type ||
+       chunkHeader->subtype != fileHeader->tocs[toc].subtype)
+       return XcursorFalse;
+    return XcursorTrue;
+}
+
+#define dist(a,b)   ((a) > (b) ? (a) - (b) : (b) - (a))
+
+static XcursorDim
+_XcursorFindBestSize (XcursorFileHeader *fileHeader,
+                     XcursorDim        size,
+                     int               *nsizesp)
+{
+    unsigned int n;
+    int                nsizes = 0;
+    XcursorDim bestSize = 0;
+    XcursorDim thisSize;
+
+    if (!fileHeader || !nsizesp)
+        return 0;
+
+    for (n = 0; n < fileHeader->ntoc; n++)
+    {
+       if (fileHeader->tocs[n].type != XCURSOR_IMAGE_TYPE)
+           continue;
+       thisSize = fileHeader->tocs[n].subtype;
+       if (!bestSize || dist (thisSize, size) < dist (bestSize, size))
+       {
+           bestSize = thisSize;
+           nsizes = 1;
+       }
+       else if (thisSize == bestSize)
+           nsizes++;
+    }
+    *nsizesp = nsizes;
+    return bestSize;
+}
+
+static int
+_XcursorFindImageToc (XcursorFileHeader        *fileHeader,
+                     XcursorDim        size,
+                     int               count)
+{
+    unsigned int       toc;
+    XcursorDim         thisSize;
+
+    if (!fileHeader)
+        return 0;
+
+    for (toc = 0; toc < fileHeader->ntoc; toc++)
+    {
+       if (fileHeader->tocs[toc].type != XCURSOR_IMAGE_TYPE)
+           continue;
+       thisSize = fileHeader->tocs[toc].subtype;
+       if (thisSize != size)
+           continue;
+       if (!count)
+           break;
+       count--;
+    }
+    if (toc == fileHeader->ntoc)
+       return -1;
+    return toc;
+}
+
+static XcursorImage *
+_XcursorReadImage (XcursorFile         *file,
+                  XcursorFileHeader    *fileHeader,
+                  int                  toc)
+{
+    XcursorChunkHeader chunkHeader;
+    XcursorImage       head;
+    XcursorImage       *image;
+    int                        n;
+    XcursorPixel       *p;
+
+    if (!file || !fileHeader)
+        return NULL;
+
+    if (!_XcursorFileReadChunkHeader (file, fileHeader, toc, &chunkHeader))
+       return NULL;
+    if (!_XcursorReadUInt (file, &head.width))
+       return NULL;
+    if (!_XcursorReadUInt (file, &head.height))
+       return NULL;
+    if (!_XcursorReadUInt (file, &head.xhot))
+       return NULL;
+    if (!_XcursorReadUInt (file, &head.yhot))
+       return NULL;
+    if (!_XcursorReadUInt (file, &head.delay))
+       return NULL;
+    /* sanity check data */
+    if (head.width >= 0x10000 || head.height > 0x10000)
+       return NULL;
+    if (head.width == 0 || head.height == 0)
+       return NULL;
+    if (head.xhot > head.width || head.yhot > head.height)
+       return NULL;
+
+    /* Create the image and initialize it */
+    image = XcursorImageCreate (head.width, head.height);
+    if (image == NULL)
+           return NULL;
+    if (chunkHeader.version < image->version)
+       image->version = chunkHeader.version;
+    image->size = chunkHeader.subtype;
+    image->xhot = head.xhot;
+    image->yhot = head.yhot;
+    image->delay = head.delay;
+    n = image->width * image->height;
+    p = image->pixels;
+    while (n--)
+    {
+       if (!_XcursorReadUInt (file, p))
+       {
+           XcursorImageDestroy (image);
+           return NULL;
+       }
+       p++;
+    }
+    return image;
+}
+
+static XcursorImages *
+XcursorXcFileLoadImages (XcursorFile *file, int size)
+{
+    XcursorFileHeader  *fileHeader;
+    XcursorDim         bestSize;
+    int                        nsize;
+    XcursorImages      *images;
+    int                        n;
+    int                        toc;
+
+    if (!file || size < 0)
+       return NULL;
+    fileHeader = _XcursorReadFileHeader (file);
+    if (!fileHeader)
+       return NULL;
+    bestSize = _XcursorFindBestSize (fileHeader, (XcursorDim) size, &nsize);
+    if (!bestSize)
+    {
+        _XcursorFileHeaderDestroy (fileHeader);
+       return NULL;
+    }
+    images = XcursorImagesCreate (nsize);
+    if (!images)
+    {
+        _XcursorFileHeaderDestroy (fileHeader);
+       return NULL;
+    }
+    for (n = 0; n < nsize; n++)
+    {
+       toc = _XcursorFindImageToc (fileHeader, bestSize, n);
+       if (toc < 0)
+           break;
+       images->images[images->nimage] = _XcursorReadImage (file, fileHeader,
+                                                           toc);
+       if (!images->images[images->nimage])
+           break;
+       images->nimage++;
+    }
+    _XcursorFileHeaderDestroy (fileHeader);
+    if (images->nimage != nsize)
+    {
+       XcursorImagesDestroy (images);
+       images = NULL;
+    }
+    return images;
+}
+
+static int
+_XcursorStdioFileRead (XcursorFile *file, unsigned char *buf, int len)
+{
+    FILE    *f = file->closure;
+    return fread (buf, 1, len, f);
+}
+
+static int
+_XcursorStdioFileWrite (XcursorFile *file, unsigned char *buf, int len)
+{
+    FILE    *f = file->closure;
+    return fwrite (buf, 1, len, f);
+}
+
+static int
+_XcursorStdioFileSeek (XcursorFile *file, long offset, int whence)
+{
+    FILE    *f = file->closure;
+    return fseek (f, offset, whence);
+}
+
+static void
+_XcursorStdioFileInitialize (FILE *stdfile, XcursorFile *file)
+{
+    file->closure = stdfile;
+    file->read = _XcursorStdioFileRead;
+    file->write = _XcursorStdioFileWrite;
+    file->seek = _XcursorStdioFileSeek;
+}
+
+static XcursorImages *
+XcursorFileLoadImages (FILE *file, int size)
+{
+    XcursorFile        f;
+
+    if (!file)
+        return NULL;
+
+    _XcursorStdioFileInitialize (file, &f);
+    return XcursorXcFileLoadImages (&f, size);
+}
+
+/*
+ * From libXcursor/src/library.c
+ */
+
+#ifndef ICONDIR
+#define ICONDIR "/usr/X11R6/lib/X11/icons"
+#endif
+
+#ifndef XCURSORPATH
+#define XCURSORPATH "~/.icons:/usr/share/icons:/usr/share/pixmaps:~/.cursors:/usr/share/cursors/xorg-x11:"ICONDIR
+#endif
+
+static const char *
+XcursorLibraryPath (void)
+{
+    static const char  *path;
+
+    if (!path)
+    {
+       path = getenv ("XCURSOR_PATH");
+       if (!path)
+           path = XCURSORPATH;
+    }
+    return path;
+}
+
+static  void
+_XcursorAddPathElt (char *path, const char *elt, int len)
+{
+    int            pathlen = strlen (path);
+
+    /* append / if the path doesn't currently have one */
+    if (path[0] == '\0' || path[pathlen - 1] != '/')
+    {
+       strcat (path, "/");
+       pathlen++;
+    }
+    if (len == -1)
+       len = strlen (elt);
+    /* strip leading slashes */
+    while (len && elt[0] == '/')
+    {
+       elt++;
+       len--;
+    }
+    strncpy (path + pathlen, elt, len);
+    path[pathlen + len] = '\0';
+}
+
+static char *
+_XcursorBuildThemeDir (const char *dir, const char *theme)
+{
+    const char     *colon;
+    const char     *tcolon;
+    char           *full;
+    char           *home;
+    int                    dirlen;
+    int                    homelen;
+    int                    themelen;
+    int                    len;
+
+    if (!dir || !theme)
+        return NULL;
+
+    colon = strchr (dir, ':');
+    if (!colon)
+       colon = dir + strlen (dir);
+
+    dirlen = colon - dir;
+
+    tcolon = strchr (theme, ':');
+    if (!tcolon)
+       tcolon = theme + strlen (theme);
+
+    themelen = tcolon - theme;
+
+    home = NULL;
+    homelen = 0;
+    if (*dir == '~')
+    {
+       home = getenv ("HOME");
+       if (!home)
+           return NULL;
+       homelen = strlen (home);
+       dir++;
+       dirlen--;
+    }
+
+    /*
+     * add space for any needed directory separators, one per component,
+     * and one for the trailing null
+     */
+    len = 1 + homelen + 1 + dirlen + 1 + themelen + 1;
+
+    full = malloc (len);
+    if (!full)
+       return NULL;
+    full[0] = '\0';
+
+    if (home)
+       _XcursorAddPathElt (full, home, -1);
+    _XcursorAddPathElt (full, dir, dirlen);
+    _XcursorAddPathElt (full, theme, themelen);
+    return full;
+}
+
+static char *
+_XcursorBuildFullname (const char *dir, const char *subdir, const char *file)
+{
+    char    *full;
+
+    if (!dir || !subdir || !file)
+        return NULL;
+
+    full = malloc (strlen (dir) + 1 + strlen (subdir) + 1 + strlen (file) + 1);
+    if (!full)
+       return NULL;
+    full[0] = '\0';
+    _XcursorAddPathElt (full, dir, -1);
+    _XcursorAddPathElt (full, subdir, -1);
+    _XcursorAddPathElt (full, file, -1);
+    return full;
+}
+
+static const char *
+_XcursorNextPath (const char *path)
+{
+    char    *colon = strchr (path, ':');
+
+    if (!colon)
+       return NULL;
+    return colon + 1;
+}
+
+#define XcursorWhite(c)        ((c) == ' ' || (c) == '\t' || (c) == '\n')
+#define XcursorSep(c) ((c) == ';' || (c) == ',')
+
+static char *
+_XcursorThemeInherits (const char *full)
+{
+    char    line[8192];
+    char    *result = NULL;
+    FILE    *f;
+
+    if (!full)
+        return NULL;
+
+    f = fopen (full, "r");
+    if (f)
+    {
+       while (fgets (line, sizeof (line), f))
+       {
+           if (!strncmp (line, "Inherits", 8))
+           {
+               char    *l = line + 8;
+               char    *r;
+               while (*l == ' ') l++;
+               if (*l != '=') continue;
+               l++;
+               while (*l == ' ') l++;
+               result = malloc (strlen (l) + 1);
+               if (result)
+               {
+                   r = result;
+                   while (*l)
+                   {
+                       while (XcursorSep(*l) || XcursorWhite (*l)) l++;
+                       if (!*l)
+                           break;
+                       if (r != result)
+                           *r++ = ':';
+                       while (*l && !XcursorWhite(*l) &&
+                              !XcursorSep(*l))
+                           *r++ = *l++;
+                   }
+                   *r++ = '\0';
+               }
+               break;
+           }
+       }
+       fclose (f);
+    }
+    return result;
+}
+
+static FILE *
+XcursorScanTheme (const char *theme, const char *name)
+{
+    FILE       *f = NULL;
+    char       *full;
+    char       *dir;
+    const char  *path;
+    char       *inherits = NULL;
+    const char *i;
+
+    if (!theme || !name)
+        return NULL;
+
+    /*
+     * Scan this theme
+     */
+    for (path = XcursorLibraryPath ();
+        path && f == NULL;
+        path = _XcursorNextPath (path))
+    {
+       dir = _XcursorBuildThemeDir (path, theme);
+       if (dir)
+       {
+           full = _XcursorBuildFullname (dir, "cursors", name);
+           if (full)
+           {
+               f = fopen (full, "r");
+               free (full);
+           }
+           if (!f && !inherits)
+           {
+               full = _XcursorBuildFullname (dir, "", "index.theme");
+               if (full)
+               {
+                   inherits = _XcursorThemeInherits (full);
+                   free (full);
+               }
+           }
+           free (dir);
+       }
+    }
+    /*
+     * Recurse to scan inherited themes
+     */
+    for (i = inherits; i && f == NULL; i = _XcursorNextPath (i))
+       f = XcursorScanTheme (i, name);
+    if (inherits != NULL)
+       free (inherits);
+    return f;
+}
+
+XcursorImages *
+XcursorLibraryLoadImages (const char *file, const char *theme, int size)
+{
+    FILE           *f = NULL;
+    XcursorImages   *images = NULL;
+
+    if (!file)
+        return NULL;
+
+    if (theme)
+       f = XcursorScanTheme (theme, file);
+    if (!f)
+       f = XcursorScanTheme ("default", file);
+    if (f)
+    {
+       images = XcursorFileLoadImages (f, size);
+       if (images)
+           XcursorImagesSetName (images, file);
+       fclose (f);
+    }
+    return images;
+}
+
+static void
+load_all_cursors_from_dir(const char *path, int size,
+                         void (*load_callback)(XcursorImages *, void *),
+                         void *user_data)
+{
+       FILE *f;
+       DIR *dir = opendir(path);
+       struct dirent *ent;
+       char *full;
+       XcursorImages *images;
+
+       if (!dir)
+               return;
+
+       for(ent = readdir(dir); ent; ent = readdir(dir)) {
+#ifdef _DIRENT_HAVE_D_TYPE
+               if (ent->d_type != DT_UNKNOWN &&
+                   (ent->d_type != DT_REG && ent->d_type != DT_LNK))
+                       continue;
+#endif
+
+               full = _XcursorBuildFullname(path, "", ent->d_name);
+               if (!full)
+                       continue;
+
+               f = fopen(full, "r");
+               if (!f) {
+                       free(full);
+                       continue;
+               }
+
+               images = XcursorFileLoadImages(f, size);
+
+               if (images) {
+                       XcursorImagesSetName(images, ent->d_name);
+                       load_callback(images, user_data);
+               }
+
+               fclose (f);
+               free(full);
+       }
+
+       closedir(dir);
+}
+
+/** Load all the cursor of a theme
+ *
+ * This function loads all the cursor images of a given theme and its
+ * inherited themes. Each cursor is loaded into an XcursorImages object
+ * which is passed to the caller's load callback. If a cursor appears
+ * more than once across all the inherited themes, the load callback
+ * will be called multiple times, with possibly different XcursorImages
+ * object which have the same name. The user is expected to destroy the
+ * XcursorImages objects passed to the callback with
+ * XcursorImagesDestroy().
+ *
+ * \param theme The name of theme that should be loaded
+ * \param size The desired size of the cursor images
+ * \param load_callback A callback function that will be called
+ * for each cursor loaded. The first parameter is the XcursorImages
+ * object representing the loaded cursor and the second is a pointer
+ * to data provided by the user.
+ * \param user_data The data that should be passed to the load callback
+ */
+void
+xcursor_load_theme(const char *theme, int size,
+                   void (*load_callback)(XcursorImages *, void *),
+                   void *user_data)
+{
+       char *full, *dir;
+       char *inherits = NULL;
+       const char *path, *i;
+
+       if (!theme)
+               theme = "default";
+
+       for (path = XcursorLibraryPath();
+            path;
+            path = _XcursorNextPath(path)) {
+               dir = _XcursorBuildThemeDir(path, theme);
+               if (!dir)
+                       continue;
+
+               full = _XcursorBuildFullname(dir, "cursors", "");
+
+               if (full) {
+                       load_all_cursors_from_dir(full, size, load_callback,
+                                                 user_data);
+                       free(full);
+               }
+
+               if (!inherits) {
+                       full = _XcursorBuildFullname(dir, "", "index.theme");
+                       if (full) {
+                               inherits = _XcursorThemeInherits(full);
+                               free(full);
+                       }
+               }
+
+               free(dir);
+       }
+
+       for (i = inherits; i; i = _XcursorNextPath(i))
+               xcursor_load_theme(i, size, load_callback, user_data);
+
+       if (inherits)
+               free(inherits);
+}
diff --git a/cursor/xcursor.h b/cursor/xcursor.h
new file mode 100644 (file)
index 0000000..f518767
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright © 2002 Keith Packard
+ *
+ * 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 Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD 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 XCURSOR_H
+#define XCURSOR_H
+
+typedef int            XcursorBool;
+typedef unsigned int   XcursorUInt;
+
+typedef XcursorUInt    XcursorDim;
+typedef XcursorUInt    XcursorPixel;
+
+typedef struct _XcursorImage {
+    XcursorUInt            version;    /* version of the image data */
+    XcursorDim     size;       /* nominal size for matching */
+    XcursorDim     width;      /* actual width */
+    XcursorDim     height;     /* actual height */
+    XcursorDim     xhot;       /* hot spot x (must be inside image) */
+    XcursorDim     yhot;       /* hot spot y (must be inside image) */
+    XcursorUInt            delay;      /* animation delay to next frame (ms) */
+    XcursorPixel    *pixels;   /* pointer to pixels */
+} XcursorImage;
+
+/*
+ * Other data structures exposed by the library API
+ */
+typedef struct _XcursorImages {
+    int                    nimage;     /* number of images */
+    XcursorImage    **images;  /* array of XcursorImage pointers */
+    char           *name;      /* name used to load images */
+} XcursorImages;
+
+XcursorImages *
+XcursorLibraryLoadImages (const char *file, const char *theme, int size);
+
+void
+XcursorImagesDestroy (XcursorImages *images);
+
+void
+xcursor_load_theme(const char *theme, int size,
+                   void (*load_callback)(XcursorImages *, void *),
+                   void *user_data);
+#endif
diff --git a/doc/Contributing b/doc/Contributing
new file mode 100644 (file)
index 0000000..c51b7e8
--- /dev/null
@@ -0,0 +1,83 @@
+= Contributing to Wayland =
+
+== Sending patches ==
+
+Patches should be sent to wayland-devel@lists.freedesktop.org, using
+git send-email. See git's documentation for help [1].
+
+The first line of a commit message should contain a prefix indicating
+what part is affected by the patch followed by one sentence that
+describes the change. For examples:
+
+    protocol: Support scaled outputs and surfaces
+
+and
+
+    doc: generate server documentation from XML too
+
+If in doubt what prefix to use, look at other commits that change the
+same file(s) as the patch being sent.
+
+The body of the commit message should describe what the patch changes
+and why, and also note any particular side effects. This shouldn't be
+empty on most of the cases. It shouldn't take a lot of effort to write
+a commit message for an obvious change, so an empty commit message
+body is only acceptable if the questions "What?" and "Why" are already
+answered on the one-line summary.
+
+The lines of the commit message should have at most 76 characters, to
+cope with the way git log presents them.
+
+See [2] for a recommend reading on writing commit messages.
+
+== Coding style ==
+
+You should follow the style of the file you're editing. In general, we
+try to follow the rules below.
+
+- indent with tabs, and a tab is always 8 characters wide
+- opening braces are on the same line as the if statement;
+- no braces in an if-body with just one statement;
+- if one of the branches of an if-else codition has braces, than the
+  other branch should also have braces;
+- there is always an empty line between variable declarations and the
+  code;
+
+static int
+my_function(void)
+{
+       int a = 0;
+
+       if (a)
+               b();
+       else
+               c();
+
+       if (a) {
+               b();
+               c();
+       } else {
+               d();
+       }
+}
+
+- lines should be less than 80 characters wide;
+- when breaking lines with functions calls, the parameters are aligned
+  with the opening parenthesis;
+- when assigning a variable with the result of a function call, if the
+  line would be longer we break it around the equal '=' sign if it makes
+  sense;
+
+       long_variable_name =
+               function_with_a_really_long_name(parameter1, parameter2,
+                                                parameter3, parameter4);
+
+       x = function_with_a_really_long_name(parameter1, parameter2,
+                                            parameter3, parameter4);
+
+== References ==
+
+       [1] http://git-scm.com/documentation
+
+       [2] http://who-t.blogspot.de/2009/12/on-commit-messages.html
+
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644 (file)
index 0000000..14637af
--- /dev/null
@@ -0,0 +1,3 @@
+SUBDIRS = doxygen publican man
+
+EXTRA_DIST = Contributing
diff --git a/doc/doxygen/.gitignore b/doc/doxygen/.gitignore
new file mode 100644 (file)
index 0000000..5f82598
--- /dev/null
@@ -0,0 +1,2 @@
+wayland.doxygen
+xml/
diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am
new file mode 100644 (file)
index 0000000..edf3652
--- /dev/null
@@ -0,0 +1,76 @@
+
+.SUFFIXES = .gv .png .map
+
+noinst_DATA = xml/Client/index.xml xml/Server/index.xml
+dist_noinst_DATA = wayland.doxygen.in
+
+scanned_src_files_shared =                             \
+       $(top_srcdir)/src/wayland-util.c        \
+       $(top_srcdir)/src/wayland-util.h
+
+scanned_src_files_Client =                             \
+       $(scanned_src_files_shared)                     \
+       $(top_srcdir)/src/wayland-client.c      \
+       $(top_srcdir)/src/wayland-client.h
+
+scanned_src_files_Server =                             \
+       $(scanned_src_files_shared)                     \
+       $(top_srcdir)/src/wayland-server.c      \
+       $(top_srcdir)/src/wayland-server.h      \
+       $(top_srcdir)/src/wayland-shm.c
+
+scanned_src_files_man =                                        \
+       $(scanned_src_files_Server)                     \
+       $(top_srcdir)/src/wayland-client.c      \
+       $(top_srcdir)/src/wayland-client.h
+
+diagramsdir := $(srcdir)/dot
+diagramssrc := $(wildcard $(diagramsdir)/*.gv)
+diagrams := $(patsubst $(diagramsdir)/%,xml/%,$(diagramssrc:.gv=.png))
+diagram_maps := $(patsubst $(diagramsdir)/%,xml/%,$(diagramssrc:.gv=.map))
+
+# find all man/man3/wl_foo.3 pages
+# for this to work, we need to create them before the man target (hence
+# all-local below)
+dist_man3_MANS = $(shell test -d man && find man/man3 -name "wl_*.3" -printf "man/man3/%P\n")
+
+# Listing various directories that might need to be created.
+alldirs := xml xml/Client xml/Server man/man3
+
+$(diagrams): $(diagramssrc)
+
+$(diagram_maps):  $(diagramssrc)
+
+xml/%/index.xml: $(scanned_src_files_%) wayland.doxygen $(diagrams) $(diagram_maps) | xml/%
+       $(AM_V_GEN)(cat wayland.doxygen; \
+          echo "GENERATE_XML=YES"; \
+          echo "XML_OUTPUT=xml/$*"; \
+          echo "INPUT= $(scanned_src_files_$*)"; \
+          ) | $(DOXYGEN) -
+
+man/man3/wl_display.3: $(scanned_src_files_man) wayland.doxygen | man/man3
+       $(AM_V_GEN)(cat wayland.doxygen; \
+          echo "GENERATE_MAN=YES"; \
+          echo "MAN_OUTPUT=man"; \
+          echo "JAVADOC_AUTOBRIEF=NO"; \
+          echo "INPUT= $(scanned_src_files_man)"; \
+          ) | $(DOXYGEN) -
+
+xml/%.png: $(diagramsdir)/%.gv | xml
+       $(AM_V_GEN)$(DOT) -Tpng -o$@ $<
+
+xml/%.map: $(diagramsdir)/%.gv | xml
+       $(AM_V_GEN)$(DOT) -Tcmapx_np -o$@ $<
+
+# general rule to create one of the listed directories.
+$(alldirs):
+       $(AM_V_GEN)$(MKDIR_P) $@
+
+# there is no man-local
+all-local: man/man3/wl_display.3
+
+clean-local:
+       rm -rf xml/
+       rm -rf man/
+
+EXTRA_DIST = $(diagramssrc)
diff --git a/doc/doxygen/dot/wayland-architecture.gv b/doc/doxygen/dot/wayland-architecture.gv
new file mode 100644 (file)
index 0000000..2d5db84
--- /dev/null
@@ -0,0 +1,39 @@
+digraph arch_wayland {
+    edge[
+        fontname="DejaVu Sans",
+        dir="both",
+        arrowtail="dot",
+        arrowsize=.5,
+        fontname="DejaVu Sans",
+        fontsize="18",
+    ]
+
+    node[
+        shape="Mrecord",
+        color=none,
+        fillcolor="#ffbc00",
+        style="filled",
+        fontname="DejaVu Sans",
+        fontsize="18",
+   ]
+
+    c1 [label="Wayland Client", URL="#c1"]
+    c2 [label="Wayland Client", URL="#c2"]
+
+    comp [tooltip="Wayland Compositor", label="|{|Wayland\nCompositor|}|", URL="#comp"]
+
+    impl [tooltip="KMS evdev Kernel", label="|{{KMS|evdev}|Kernel}|", URL="#impl"]
+
+
+    c1 -> comp [taillabel="③", labeldistance=2.5, URL="#step_3"];
+    c2 -> comp;
+
+    comp -> c1 [label="②", URL="#step_2"];
+    comp -> c2;
+
+    comp -> impl [xlabel = "④", URL="#step_4"];
+    comp -> impl [style = invis, label="    "];
+    impl -> comp [xlabel = "①", URL="#step_1"];
+
+    c1 -> c2 [style=invis];
+}
diff --git a/doc/doxygen/dot/x-architecture.gv b/doc/doxygen/dot/x-architecture.gv
new file mode 100644 (file)
index 0000000..4ea49bf
--- /dev/null
@@ -0,0 +1,54 @@
+digraph arch_x {
+    edge[
+        fontname="DejaVu Sans",
+        dir="both",
+        arrowtail="dot",
+        arrowsize=.5,
+        fontname="DejaVu Sans",
+        fontsize="18",
+    ]
+
+    node[
+        shape="Mrecord",
+        color=none,
+        fillcolor="#ffbc00",
+        style="filled",
+        fontname="DejaVu Sans",
+        fontsize="18",
+    ]
+
+    {
+        rank=same;
+        c1 [label="X Client", URL="#c1"]
+        c3 [label="X Client", URL="#c3"]
+    }
+    c2 [label="X Client", URL="#c2"]
+
+    {
+        rank=same;
+        xserver [tooltip="X Server", label="|{|X Server|}|", URL="#xserver"]
+        comp [tooltip="Compositor", label="|{|Compositor|}|", URL="#comp"]
+    }
+
+    impl [tooltip="KMS evdev Kernel", label="|{{KMS|evdev}|Kernel}|", URL="#impl"]
+
+    c1 -> xserver [taillabel="③", labeldistance=2, URL="#step_3"];
+    c2 -> xserver;
+    c3 -> xserver;
+
+    xserver -> c1 [taillabel="②", labeldistance=2, URL="#step_2"];
+    xserver -> c2;
+    xserver -> c3;
+
+    xserver -> impl [taillabel="⑥", labeldistance=1.75, URL="#step_6"];
+    xserver -> impl [style=invis, label="    "];
+    impl -> xserver [taillabel="①", labeldistance=1.75, URL="#step_1"];
+
+    xserver -> comp [style=invis];
+    xserver -> comp [taillabel="④", labeldistance=1.75, labelangle=-45, URL="#step_4"];
+    comp -> xserver [taillabel="⑤", URL="#step_5"];
+    comp -> xserver [style=invis]
+
+    c1 -> c2 [style=invis];
+    c3 -> c2 [style=invis];
+ }
diff --git a/doc/doxygen/wayland.doxygen.in b/doc/doxygen/wayland.doxygen.in
new file mode 100644 (file)
index 0000000..e64512f
--- /dev/null
@@ -0,0 +1,1736 @@
+# Doxyfile 1.7.6.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a hash (#) is considered a comment and will be ignored.
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or sequence of words) that should
+# identify the project. Note that if you do not use Doxywizard you need
+# to put quotes around the project name if it contains spaces.
+
+PROJECT_NAME           = "Wayland"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         = @VERSION@
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer
+# a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = @top_builddir@/doc/doxygen
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                += comment{1}="/* \1 *<!-- -->/"
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding
+# "class=itcl::class" will allow you to use the command class in the
+# itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this
+# tag. The format is ext=language, where ext is a file extension, and language
+# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
+# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
+# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
+# unions are shown inside the group in which they are included (e.g. using
+# @ingroup) instead of on a separate page (for HTML and Man pages) or
+# section (for LaTeX and RTF).
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
+# unions with only public data fields will be shown inline in the documentation
+# of the scope in which they are defined (i.e. file, namespace, or group
+# documentation), provided this scope is documented. If set to NO (the default),
+# structs, classes, and unions are shown on a separate page (for HTML and Man
+# pages) or section (for LaTeX and RTF).
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
+# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
+# their name and scope. Since this can be an expensive process and often the
+# same symbol appear multiple times in the code, doxygen keeps a cache of
+# pre-resolved symbols. If the cache is too small doxygen will become slower.
+# If the cache is too large, memory is wasted. The cache size is given by this
+# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
+# do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even
+# if there is only one candidate or it is obvious which candidate to choose
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. The create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files
+# containing the references data. This must be a list of .bib files. The
+# .bib extension is automatically appended if omitted. Using this command
+# requires the bibtex tool to be installed. See also
+# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
+# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
+# feature you need bibtex and perl available in the search path.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  =
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = NO
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header. Note that when using a custom header you are responsible
+#  for the proper inclusion of any scripts and style sheets that doxygen
+# needs, which is dependent on the configuration options used.
+# It is advised to generate a default header using "doxygen -w html
+# header.html footer.html stylesheet.css YourConfigFile" and then modify
+# that header. Note that the header is subject to change so you typically
+# have to redo this when upgrading to a newer version of doxygen or when
+# changing the value of configuration settings such as GENERATE_TREEVIEW!
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# style sheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that
+# the files will be copied as-is; there are no commands or markers available.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the style sheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+#  will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
+# at top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it. Since the tabs have the same information as the
+# navigation tree you can set this option to NO if you already set
+# GENERATE_TREEVIEW to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+# Since the tree basically has the same information as the tab index you
+# could consider to set DISABLE_INDEX to NO when enabling this option.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML
+# documentation. Note that a value of 0 will completely suppress the enum
+# values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the
+# mathjax.org site, so you can quickly see the result without installing
+# MathJax, but it is strongly recommended to install a local copy of MathJax
+# before deployment.
+
+MATHJAX_RELPATH        = http://www.mathjax.org/mathjax
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
+# names that should be enabled during MathJax rendering.
+
+MATHJAX_EXTENSIONS     =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a PHP enabled web server instead of at the web client
+# using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server
+# based approach is that it scales better to large projects and allows
+# full text search. The disadvantages are that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
+# the generated latex document. The footer should contain everything after
+# the last chapter. If it is left blank doxygen will generate a
+# standard footer. Notice: only use this tag if you know what you are doing!
+
+LATEX_FOOTER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
+# http://en.wikipedia.org/wiki/BibTeX for more info.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load style sheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# pointed to by INCLUDE_PATH will be searched when a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             = WL_EXPORT=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that
+# overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS        = 0
+
+# By default doxygen will use the Helvetica font for all dot files that
+# doxygen generates. When you want a differently looking font you can specify
+# the font name using DOT_FONTNAME. You need to make sure dot is able to find
+# the font, which can be done by putting it in a standard location or by setting
+# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the Helvetica font.
+# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
+# set the path where dot can find it.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are svg, png, jpg, or gif.
+# If left blank png will be used. If you choose svg you need to set
+# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible in IE 9+ (other browsers do not have this requirement).
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+# Note that this requires a modern browser other than Internet Explorer.
+# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
+# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible. Older versions of IE do not have SVG support.
+
+INTERACTIVE_SVG        = NO
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = YES
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am
new file mode 100644 (file)
index 0000000..41665eb
--- /dev/null
@@ -0,0 +1,51 @@
+#
+# This generates man-pages out of the Docbook XML files. Simply add your files
+# to the $MANPAGES array. If aliases are created, please add them to the
+# MANPAGES_ALIASES array so they get installed correctly.
+#
+
+MANPAGES = \
+       wl_display_connect.3
+MANPAGES_ALIASES = \
+       wl_display_connect_to_fd.3
+
+XML_FILES = \
+       ${patsubst %.1,%.xml,${patsubst %.3,%.xml,${patsubst %.5,%.xml,${patsubst %.7,%.xml,$(MANPAGES)}}}}
+CLEANFILES =
+EXTRA_DIST = $(XML_FILES)
+
+if HAVE_XSLTPROC
+if HAVE_MANPAGES_STYLESHEET
+
+CLEANFILES += $(MANPAGES) $(MANPAGES_ALIASES)
+EXTRA_DIST += $(MANPAGES) $(MANPAGES_ALIASES)
+dist_man_MANS = $(MANPAGES) $(MANPAGES_ALIASES)
+
+XSLTPROC_FLAGS = \
+       --stringparam man.authors.section.enabled 0 \
+       --stringparam man.copyright.section.enabled 0 \
+       --stringparam funcsynopsis.style ansi \
+       --stringparam man.output.quietly 1 \
+       --nonet
+
+XSLTPROC_PROCESS_MAN = \
+       $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \
+       $(XSLTPROC) -o $@ $(XSLTPROC_FLAGS) $(MANPAGES_STYLESHEET) $< && \
+       $(SED) -i -e 's/^\.so \(.*\)\.\(.\)$$/\.so man\2\/\1\.\2/' $(MANPAGES_ALIASES)
+
+%.1: %.xml
+       $(XSLTPROC_PROCESS_MAN)
+
+%.3: %.xml
+       $(XSLTPROC_PROCESS_MAN)
+
+%.5: %.xml
+       $(XSLTPROC_PROCESS_MAN)
+
+%.7: %.xml
+       $(XSLTPROC_PROCESS_MAN)
+
+wl_display_connect_to_fd.3: wl_display_connect.3
+
+endif # HAVE_MANPAGES_STYLESHEET
+endif # HAVE_XSLTPROC
diff --git a/doc/man/wl_display_connect.xml b/doc/man/wl_display_connect.xml
new file mode 100644 (file)
index 0000000..7e6e05c
--- /dev/null
@@ -0,0 +1,88 @@
+<?xml version='1.0'?> <!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+          "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<!--
+  Written 2012 by David Herrmann <dh.herrmann@googlemail.com>
+  Dedicated to the Public Domain
+-->
+
+<refentry id="wl_display_connect">
+  <refentryinfo>
+    <title>wl_display_connect</title>
+    <productname>wayland-client</productname>
+    <date>September 2012</date>
+    <authorgroup>
+      <author>
+        <contrib>Developer</contrib>
+        <firstname>David</firstname>
+        <surname>Herrmann</surname>
+        <email>dh.herrmann@googlemail.com</email>
+      </author>
+    </authorgroup>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>wl_display_connect</refentrytitle>
+    <manvolnum>3</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>wl_display_connect</refname>
+    <refname>wl_display_connect_to_fd</refname>
+    <refpurpose>Connect to a Wayland socket</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+
+      <funcsynopsisinfo>#include &lt;wayland-client.h&gt;</funcsynopsisinfo>
+
+      <funcprototype>
+        <funcdef>struct wl_display *<function>wl_display_connect</function></funcdef>
+        <paramdef>const char *<parameter>name</parameter></paramdef>
+      </funcprototype>
+
+      <funcprototype>
+        <funcdef>struct wl_display *<function>wl_display_connect_to_fd</function></funcdef>
+        <paramdef>int <parameter>fd</parameter></paramdef>
+      </funcprototype>
+
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+    <para><function>wl_display_connect</function> connects to a Wayland socket
+          that was previously opened by a Wayland server. The server socket must
+          be placed in <envar>XDG_RUNTIME_DIR</envar> for this function to
+          find it. The <varname>name</varname> argument specifies the name of
+          the socket or <constant>NULL</constant> to use the default (which is
+          <constant>"wayland-0"</constant>). The environment variable
+          <envar>WAYLAND_DISPLAY</envar> replaces the default value. If
+          <envar>WAYLAND_SOCKET</envar> is set, this function behaves like
+          <function>wl_display_connect_to_fd</function> with the file-descriptor
+          number taken from the environment variable.</para>
+
+    <para><function>wl_display_connect_to_fd</function> connects to a Wayland
+          socket with an explicit file-descriptor. The file-descriptor is passed
+          as argument <varname>fd</varname>.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Return Value</title>
+    <para><function>wl_display_connect</function> and
+          <function>wl_display_connect_to_fd</function> return a new display
+          context object or NULL on failure. <varname>errno</varname> is set
+          correspondingly.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>See Also</title>
+    <para>
+      <citerefentry><refentrytitle>wayland-client</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>wl_display_disconnect</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>wl_display_iterate</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+    </para>
+  </refsect1>
+</refentry>
diff --git a/doc/publican/.gitignore b/doc/publican/.gitignore
new file mode 100644 (file)
index 0000000..c1656e7
--- /dev/null
@@ -0,0 +1,3 @@
+Wayland
+en-US/
+publican-copy.cfg
diff --git a/doc/publican/Makefile.am b/doc/publican/Makefile.am
new file mode 100644 (file)
index 0000000..57728a0
--- /dev/null
@@ -0,0 +1,166 @@
+# Documentation is built with xmlto, but some of the recipes in here are
+# leftovers from building with Publican (https://fedorahosted.org/publican/)
+#
+# How this build works:
+# * the main target is Wayland, documentation ends up in $(builddir)/Wayland/
+# * hand-written chapters and CSS files are located in sources. These are
+#   copied into $(builddir)/en-US/
+# * ProtocolSpec.xml is generated from $(top_srcdir)/protocol/wayland.xml,
+#   changed into docbook via XSLT and saved in $(builddir)/en-US/
+# * ProtocolInterfaces.xml, same as above, uses a different XSLT
+# * *API.xml is generated from the doxygen output and saved in
+#   $(builddir)/en-US
+# * run xmlto on $(builddir)/en-US, output to $(builddir)/Wayland/en-US
+
+doxydir := $(top_builddir)/doc/doxygen
+html_destdir := $(builddir)/Wayland/en-US/html
+
+publican_sources = \
+       $(srcdir)/sources/Wayland.ent \
+       $(srcdir)/sources/Wayland.xml \
+       $(srcdir)/sources/Book_Info.xml \
+       $(srcdir)/sources/Author_Group.xml \
+       $(srcdir)/sources/Foreword.xml \
+       $(srcdir)/sources/Preface.xml \
+       $(srcdir)/sources/Revision_History.xml \
+       $(srcdir)/sources/Protocol.xml \
+       $(srcdir)/sources/Compositors.xml \
+       $(srcdir)/sources/images/icon.svg  \
+       $(srcdir)/sources/images/wayland.png \
+       $(srcdir)/sources/Client.xml \
+       $(srcdir)/sources/Server.xml
+
+processed_sources := \
+       $(srcdir)/sources/Architecture.xml \
+       $(srcdir)/sources/Introduction.xml
+
+css_sources = \
+       $(srcdir)/sources/css/brand.css \
+       $(srcdir)/sources/css/common.css \
+       $(srcdir)/sources/css/default.css \
+       $(srcdir)/sources/css/epub.css \
+       $(srcdir)/sources/css/print.css
+
+img_sources = \
+       $(srcdir)/sources/images/icon.svg \
+       $(srcdir)/sources/images/wayland.png
+
+doxygen_img_sources := \
+       $(doxydir)/xml/wayland-architecture.png \
+       $(doxydir)/xml/x-architecture.png
+
+map_sources := \
+       $(doxydir)/xml/x-architecture.map \
+       $(doxydir)/xml/wayland-architecture.map
+
+if HAVE_XMLTO
+if HAVE_XSLTPROC
+noinst_DATA = $(builddir)/Wayland $(publican_targets)
+XMLTO_PARAM = \
+       --skip-validation \
+       --stringparam chunk.section.depth=0 \
+       --stringparam toc.section.depth=1 \
+       --stringparam html.stylesheet=css/default.css
+
+# Listing various directories that might need to be created.
+alldirs := $(builddir)/en-US $(builddir)/en-US/images $(html_destdir) $(html_destdir)/css $(html_destdir)/images
+
+
+html_css_targets = $(addprefix $(html_destdir)/css/,$(notdir $(css_sources)))
+html_img_targets = $(addprefix $(html_destdir)/images/,$(notdir $(img_sources)))
+doxygen_img_targets := $(doxygen_img_sources:$(doxydir)/xml/%=$(html_destdir)/images/%)
+map_targets := $(map_sources:$(doxydir)/xml/%=$(builddir)/en-US/images/%)
+processed_targets := $(processed_sources:$(srcdir)/sources/%=$(builddir)/en-US/%)
+
+$(builddir)/Wayland: $(publican_targets) $(html_css_targets) $(html_img_targets) $(processed_targets) $(doxygen_img_targets) | $(builddir)/en-US
+       $(AM_V_GEN)$(XMLTO) $(XMLTO_PARAM) html $(builddir)/en-US/Wayland.xml -o $(html_destdir)
+       @touch $@
+
+$(html_destdir)/css/%: $(srcdir)/sources/css/% | $(html_destdir)/css
+       $(AM_V_GEN)cp -f $< $@
+
+$(html_destdir)/images/%: $(srcdir)/sources/images/% | $(html_destdir)/images
+       $(AM_V_GEN)cp -f $< $@
+
+$(html_destdir)/images/%: $(doxydir)/xml/% | $(html_destdir)/images
+       $(AM_V_GEN)cp -f $< $@
+
+pubdir = $(docdir)/Wayland/en-US
+
+publican_targets = $(publican_sources:$(srcdir)/sources/%=$(builddir)/en-US/%) \
+       $(builddir)/en-US/ProtocolSpec.xml \
+       $(builddir)/en-US/ProtocolInterfaces.xml \
+       $(builddir)/en-US/ClientAPI.xml \
+       $(builddir)/en-US/ServerAPI.xml
+
+# The Protocol.xml is purely generated and required before running publican
+$(builddir)/en-US/ProtocolSpec.xml: $(top_srcdir)/protocol/wayland.xml $(srcdir)/protocol-to-docbook.xsl | $(builddir)/en-US
+       $(AM_V_GEN)$(XSLTPROC) $(srcdir)/protocol-to-docbook.xsl \
+               $(top_srcdir)/protocol/wayland.xml > $@
+
+$(builddir)/en-US/ProtocolInterfaces.xml: $(top_srcdir)/protocol/wayland.xml $(srcdir)/protocol-interfaces-to-docbook.xsl | $(builddir)/en-US
+       $(AM_V_GEN)$(XSLTPROC) $(srcdir)/protocol-interfaces-to-docbook.xsl \
+               $(top_srcdir)/protocol/wayland.xml > $@
+
+# * use doxygen's combine.xslt to merge the xml files into one single file
+# * pipe that through the doxygen-to-publican stylesheet
+$(builddir)/en-US/%API.xml: $(doxydir)/xml/%/index.xml $(srcdir)/doxygen-to-publican.xsl | $(builddir)/en-US
+       $(AM_V_GEN)$(XSLTPROC) $(doxydir)/xml/$*/combine.xslt \
+               $(doxydir)/xml/$*/index.xml | \
+               $(XSLTPROC) --stringparam which $* \
+               $(srcdir)/doxygen-to-publican.xsl - > $@
+
+# Copy the sources source files into en-US destination
+# This is required for out-of-source-tree build as publican does not allow us
+# to specify the location of the source code.
+$(builddir)/en-US/%: $(srcdir)/sources/% $(publican_sources) | $(builddir)/en-US/images
+       $(AM_V_GEN)cp -f $< $@
+       $(AM_V_at)chmod a+w $@
+
+$(builddir)/en-US/images/%: $(doxydir)/xml/% | $(builddir)/en-US/images
+       $(AM_V_GEN)cp -f $< $@
+       $(AM_V_at)chmod a+w $@
+
+# More specific rule to override explicitly listed targets and perform xslt
+# modifications on them.
+# Note that we can't use $< as all targets must be there
+$(processed_targets): $(processed_sources) $(map_targets) $(srcdir)/merge-mapcoords.xsl | $(builddir)/en-US/images
+       $(AM_V_GEN)$(XSLTPROC) --stringparam basedir $(builddir)/en-US \
+               $(srcdir)/merge-mapcoords.xsl $(addprefix $(srcdir)/sources/,$(notdir $@)) > $@
+
+# general rule to create one of the listed directories.
+$(alldirs):
+       $(AM_V_GEN)$(MKDIR_P) $@
+
+CLEANFILES = $(publican_targets)
+
+clean-local:
+       $(AM_V_at)rm -fr $(builddir)/en-US
+       $(AM_V_at)rm -fr $(builddir)/Wayland
+
+install-data-local:
+       test -z "$(pubdir)/html/css" || $(mkdir_p) "$(DESTDIR)$(pubdir)/html/css"
+       test -z "$(pubdir)/html/images" || $(mkdir_p) "$(DESTDIR)$(pubdir)/html/images"
+       list=`find $(builddir)/Wayland/en-US -type f`; \
+       for p in $$list; do \
+         echo " $(INSTALL_DATA) '$$p' '$(DESTDIR)$(docdir)/$$p'"; \
+         $(INSTALL_DATA) "$$p" "$(DESTDIR)$(docdir)/$$p"; \
+       done;
+
+uninstall-local:
+       @if test -n $(DESTDIR)$(docdir); then \
+         if test -d $(DESTDIR)$(docdir); then \
+           echo " rm -fr $(DESTDIR)$(docdir)/Wayland;"; \
+           rm -fr $(DESTDIR)$(docdir)/Wayland; \
+         fi; \
+       fi;
+
+endif
+endif
+
+EXTRA_DIST = \
+       $(publican_sources) $(processed_sources) $(css_sources) $(img_sources) \
+       protocol-to-docbook.xsl \
+       protocol-interfaces-to-docbook.xsl \
+       doxygen-to-publican.xsl \
+       merge-mapcoords.xsl
diff --git a/doc/publican/doxygen-to-publican.xsl b/doc/publican/doxygen-to-publican.xsl
new file mode 100644 (file)
index 0000000..7c3b507
--- /dev/null
@@ -0,0 +1,147 @@
+<?xml version="1.0" ?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:output method="xml" encoding="UTF-8" indent="yes" />
+<xsl:param name="which" />
+
+<xsl:template match="/">
+  <xsl:apply-templates select="/doxygen/compounddef[@kind!='file' and @kind!='dir']" />
+
+  <section id="{$which}-Functions">
+    <title>Functions</title>
+    <para />
+    <variablelist>
+      <xsl:apply-templates select="/doxygen/compounddef[@kind='file']/sectiondef/memberdef" />
+    </variablelist>
+  </section>
+
+</xsl:template>
+
+<xsl:template match="parameteritem">
+    <varlistentry>
+        <term>
+          <xsl:apply-templates select="parameternamelist/parametername"/>
+        </term>
+      <listitem>
+        <simpara><xsl:apply-templates select="parameterdescription"/></simpara>
+      </listitem>
+    </varlistentry>
+</xsl:template>
+
+<xsl:template match="parameterlist">
+  <xsl:if test="parameteritem">
+      <variablelist>
+        <xsl:apply-templates select="parameteritem" />
+      </variablelist>
+  </xsl:if>
+</xsl:template>
+
+<xsl:template match="ref">
+  <link linkend="{$which}-{@refid}"><xsl:value-of select="." /></link>
+</xsl:template>
+
+<xsl:template match="simplesect[@kind='return']">
+  <variablelist>
+    <varlistentry>
+      <term>Returns:</term>
+      <listitem>
+        <simpara><xsl:apply-templates /></simpara>
+      </listitem>
+    </varlistentry>
+  </variablelist>
+</xsl:template>
+
+<xsl:template match="simplesect[@kind='see']">
+  See also: <xsl:apply-templates />
+</xsl:template>
+
+<xsl:template match="simplesect[@kind='since']">
+  Since: <xsl:apply-templates />
+</xsl:template>
+
+<xsl:template match="simplesect[@kind='note']">
+  <emphasis>Note: <xsl:apply-templates /></emphasis>
+</xsl:template>
+
+<xsl:template match="sp">
+  <xsl:text> </xsl:text>
+</xsl:template>
+
+<xsl:template match="programlisting">
+  <programlisting><xsl:apply-templates /></programlisting>
+</xsl:template>
+
+<xsl:template match="itemizedlist">
+  <itemizedlist><xsl:apply-templates select="listitem" /></itemizedlist>
+</xsl:template>
+
+<xsl:template match="listitem">
+  <listitem><simpara><xsl:apply-templates /></simpara></listitem>
+</xsl:template>
+
+<!-- stops cross-references in the section titles -->
+<xsl:template match="briefdescription">
+  <xsl:value-of select="." />
+</xsl:template>
+
+<!-- this opens a para for each detaileddescription/para. I could not find a
+     way to extract the right text for the description from the
+     source otherwise. Downside: we can't use para for return value, "see
+     also", etc.  because they're already inside a para. So they're lists.
+
+     It also means we don't control the order of when something is added to
+     the output, it matches the input file
+     -->
+<xsl:template match="detaileddescription/para">
+  <para><xsl:apply-templates /></para>
+</xsl:template>
+
+<xsl:template match="detaileddescription">
+  <xsl:apply-templates select="para" />
+</xsl:template>
+
+<!-- methods -->
+<xsl:template match="memberdef" >
+  <xsl:if test="@kind = 'function' and @static = 'no' or
+                @kind !='function' and normalize-space(briefdescription) != ''">
+    <varlistentry id="{$which}-{@id}">
+        <term>
+          <xsl:value-of select="name"/>
+          <xsl:if test="normalize-space(briefdescription) != ''">
+            - <xsl:apply-templates select="briefdescription" />
+          </xsl:if>
+        </term>
+        <listitem>
+          <synopsis>
+            <xsl:apply-templates select="definition"/><xsl:apply-templates select="argsstring"/>
+          </synopsis>
+          <xsl:apply-templates select="detaileddescription" />
+        </listitem>
+    </varlistentry>
+  </xsl:if>
+</xsl:template>
+
+<!-- classes -->
+<xsl:template match="compounddef" >
+    <section id="{$which}-{@id}">
+        <title>
+            <xsl:value-of select="compoundname" />
+            <xsl:if test="normalize-space(briefdescription) != ''">
+                - <xsl:apply-templates select="briefdescription" />
+            </xsl:if>
+        </title>
+        <xsl:choose>
+          <xsl:when test="normalize-space(detaileddescription) != ''">
+            <xsl:apply-templates select="detaileddescription" />
+          </xsl:when>
+          <xsl:otherwise>
+            <para />
+          </xsl:otherwise>
+        </xsl:choose>
+        <xsl:if test="sectiondef/memberdef[@kind='function' and @static='no']">
+          <variablelist>
+            <xsl:apply-templates select="sectiondef/memberdef" />
+          </variablelist>
+        </xsl:if>
+    </section>
+</xsl:template>
+</xsl:stylesheet>
diff --git a/doc/publican/merge-mapcoords.xsl b/doc/publican/merge-mapcoords.xsl
new file mode 100644 (file)
index 0000000..7adaca3
--- /dev/null
@@ -0,0 +1,64 @@
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+  <xsl:param name="basedir"/>
+  <xsl:output method="xml" encoding="utf-8" indent="yes"/>
+  <!-- -->
+  <!-- Template for the root so we can add a DOCTYPE -->
+  <xsl:template match="/">
+    <xsl:text disable-output-escaping="yes"><![CDATA[<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+]]></xsl:text>
+    <xsl:apply-templates select="@*|node()"/>
+  </xsl:template>
+  <!-- -->
+  <xsl:template match="@*|node()">
+    <xsl:copy>
+      <xsl:apply-templates select="@*|node()"/>
+    </xsl:copy>
+  </xsl:template>
+  <!-- -->
+  <!-- suppress existing image map areas -->
+  <xsl:template match="area"/>
+  <!-- -->
+  <xsl:template match="areaspec[area][name(..)='imageobjectco']">
+    <xsl:element name="areaspec">
+      <xsl:apply-templates select="@*"/>
+      <xsl:text>&#xa;</xsl:text>
+      <xsl:variable name="pngfile" select="../imageobject/imagedata/@fileref"/>
+      <xsl:variable name="mapfile" select="concat(substring($pngfile, 1, string-length($pngfile)-3), 'map')"/>
+      <xsl:variable name="maproot" select="document(concat($basedir, '/', $mapfile))"/>
+      <!-- -->
+      <!-- now emit the needed areas -->
+      <xsl:for-each select="area">
+       <xsl:variable name="anchor" select="."/>
+       <xsl:variable name="other" select="($maproot)//area[@href=($anchor)/@x_steal]"/>
+       <xsl:choose>
+         <xsl:when test="$other">
+           <xsl:text>&#x9;    </xsl:text>
+           <xsl:element name="area">
+             <xsl:attribute name="id">
+               <xsl:value-of select="@id"/>
+             </xsl:attribute>
+             <xsl:attribute name="linkends">
+               <xsl:value-of select="@linkends"/>
+             </xsl:attribute>
+             <xsl:attribute name="coords">
+               <xsl:value-of select="($other)/@coords"/>
+             </xsl:attribute>
+           </xsl:element>
+         </xsl:when>
+         <xsl:otherwise>
+           <xsl:text>&#x9;    </xsl:text>
+           <xsl:comment>
+             <xsl:value-of select="concat('Warning: unable to locate area tagged ', ($anchor)/@x_steal)"/>
+           </xsl:comment>
+         </xsl:otherwise>
+       </xsl:choose>
+       <xsl:text>&#xa;</xsl:text>
+      </xsl:for-each>
+      <!-- -->
+      <xsl:text>&#x9;  </xsl:text>
+    </xsl:element>
+  </xsl:template>
+</xsl:stylesheet>
diff --git a/doc/publican/protocol-interfaces-to-docbook.xsl b/doc/publican/protocol-interfaces-to-docbook.xsl
new file mode 100644 (file)
index 0000000..f68216d
--- /dev/null
@@ -0,0 +1,51 @@
+<?xml version="1.0" ?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:output method="xml" encoding="UTF-8" indent="yes" />
+
+<xsl:template match="/">
+  <!-- insert docbook's DOCTYPE blurb -->
+    <xsl:text disable-output-escaping = "yes"><![CDATA[
+<!DOCTYPE appendix PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+  <!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+]]></xsl:text>
+
+  <section id="sect-Protocol-Interfaces">
+    <title>Interfaces</title>
+    <para>
+      The protocol includes several interfaces which are used for
+      interacting with the server.  Each interface provides requests,
+      events, and errors (which are really just special events) as described
+      above.  Specific compositor implementations may have their own
+      interfaces provided as extensions, but there are several which are
+      always expected to be present.
+    </para>
+
+    <para>
+      Core interfaces:
+      <variablelist>
+        <xsl:apply-templates select="protocol/interface" />
+      </variablelist>
+    </para>
+  </section>
+</xsl:template>
+
+<!-- Interfaces summary -->
+<xsl:template match="interface" >
+<varlistentry>
+  <term>
+    <link linkend="protocol-spec-{@name}">
+      <xsl:value-of select="@name" />
+    </link>
+  </term>
+  <listitem>
+    <simpara>
+      <xsl:value-of select="description/@summary" />
+    </simpara>
+  </listitem>
+</varlistentry>
+</xsl:template>
+
+</xsl:stylesheet>
+<!-- vim: set expandtab shiftwidth=2: -->
diff --git a/doc/publican/protocol-to-docbook.xsl b/doc/publican/protocol-to-docbook.xsl
new file mode 100644 (file)
index 0000000..7b45969
--- /dev/null
@@ -0,0 +1,189 @@
+<?xml version="1.0" ?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:output method="xml" encoding="UTF-8" indent="yes" />
+
+<xsl:template match="/">
+  <!-- insert docbook's DOCTYPE blurb -->
+    <xsl:text disable-output-escaping = "yes"><![CDATA[
+<!DOCTYPE appendix PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+  <!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+]]></xsl:text>
+
+  <appendix id="appe-Wayland-Protocol">
+    <title>Wayland Protocol Specification</title>
+    <xsl:apply-templates select="protocol/copyright" />
+
+    <xsl:apply-templates select="protocol/interface" />
+  </appendix>
+</xsl:template>
+
+<!-- Break text blocks separated by two new lines into paragraphs -->
+<xsl:template name="break">
+     <xsl:param name="text" />
+     <xsl:param name="linebreak" select="'&#10;&#10;'" />
+     <xsl:choose>
+       <xsl:when test="contains($text,$linebreak)">
+         <para>
+           <xsl:value-of select="substring-before($text,$linebreak)" />
+         </para>
+         <xsl:call-template name="break">
+           <xsl:with-param name="text" select="substring-after($text,$linebreak)" />
+         </xsl:call-template>
+       </xsl:when>
+       <xsl:otherwise>
+         <para><xsl:value-of select="$text" /></para>
+       </xsl:otherwise>
+     </xsl:choose>
+</xsl:template>
+
+<!-- Copyright blurb -->
+<xsl:template match="copyright">
+  <para>
+    <literallayout>
+      <xsl:value-of select="." disable-output-escaping="yes"/>
+    </literallayout>
+  </para>
+</xsl:template>
+
+<!-- Interface descriptions -->
+<xsl:template match="interface" >
+  <section id="protocol-spec-{@name}">
+    <title>
+      <xsl:value-of select="@name" />
+      <!-- only show summary if it exists -->
+      <xsl:if test="description/@summary">
+       - <xsl:value-of select="description/@summary" />
+      </xsl:if>
+    </title>
+    <xsl:call-template name="break">
+      <xsl:with-param name="text" select="description" />
+    </xsl:call-template>
+    <xsl:if test="request">
+      <section>
+        <title>Requests provided by <xsl:value-of select="@name" /></title>
+        <xsl:apply-templates select="request" />
+      </section>
+    </xsl:if>
+    <xsl:if test="event">
+      <section>
+        <title>Events provided by <xsl:value-of select="@name" /></title>
+        <xsl:apply-templates select="event" />
+      </section>
+    </xsl:if>
+    <xsl:if test="enum">
+      <section>
+        <title>Enums provided by <xsl:value-of select="@name" /></title>
+      <xsl:apply-templates select="enum" />
+      </section>
+    </xsl:if>
+  </section>
+</xsl:template>
+
+<!-- table contents for enum values -->
+<xsl:template match="entry">
+  <varlistentry>
+    <term><xsl:value-of select="@name"/></term>
+    <listitem>
+      <simpara>
+        <xsl:value-of select="@value"/>
+        <xsl:if test="@summary" >
+          - <xsl:value-of select="@summary"/>
+        </xsl:if>
+      </simpara>
+    </listitem>
+  </varlistentry>
+</xsl:template>
+
+<!-- table contents for request/event arguments -->
+<xsl:template match="arg">
+  <varlistentry>
+    <term><xsl:value-of select="@name"/></term>
+    <listitem>
+        <simpara>
+          <xsl:value-of select="@type"/>
+          <xsl:if test="@summary" >
+            - <xsl:value-of select="@summary"/>
+          </xsl:if>
+        </simpara>
+    </listitem>
+  </varlistentry>
+</xsl:template>
+
+<!-- id arguments -->
+<xsl:template match="arg[@type='object' and @interface]">
+  <varlistentry>
+    <term><xsl:value-of select="@name"/></term>
+    <listitem>
+        <simpara>
+          <link linkend="protocol-spec-{@interface}">
+            <xsl:value-of select="@interface"/>
+          </link>
+          <xsl:if test="@summary" >
+            - <xsl:value-of select="@summary"/>
+          </xsl:if>
+        </simpara>
+    </listitem>
+  </varlistentry>
+</xsl:template>
+
+<!-- new_id arguments -->
+<xsl:template match="arg[@type='new_id' and @interface]">
+  <varlistentry>
+    <term><xsl:value-of select="@name"/></term>
+    <listitem>
+        <simpara>
+          id for the new
+          <link linkend="protocol-spec-{@interface}">
+            <xsl:value-of select="@interface"/>
+          </link>
+          <xsl:if test="@summary" >
+            - <xsl:value-of select="@summary"/>
+          </xsl:if>
+        </simpara>
+    </listitem>
+  </varlistentry>
+</xsl:template>
+
+<!-- Request/event list -->
+<xsl:template match="request|event">
+  <section id="protocol-spec-{../@name}-{name()}-{@name}">
+    <title>
+      <xsl:value-of select="../@name"/>::<xsl:value-of select="@name" />
+      <xsl:if test="description/@summary">
+        - <xsl:value-of select="description/@summary" />
+      </xsl:if>
+    </title>
+    <para>
+      <variablelist>
+        <xsl:apply-templates select="arg"/>
+      </variablelist>
+    </para>
+    <xsl:call-template name="break">
+      <xsl:with-param name="text" select="description" />
+    </xsl:call-template>
+  </section>
+</xsl:template>
+
+<!-- Enumeration -->
+<xsl:template match="enum">
+  <section id="protocol-spec-{../@name}-{name()}-{@name}">
+    <title>
+      <xsl:value-of select="../@name"/>::<xsl:value-of select="@name" />
+      <xsl:if test="description/@summary">
+        - <xsl:value-of select="description/@summary" />
+      </xsl:if>
+    </title>
+    <xsl:call-template name="break">
+      <xsl:with-param name="text" select="description" />
+    </xsl:call-template>
+    <variablelist>
+      <xsl:apply-templates select="entry"/>
+    </variablelist>
+  </section>
+</xsl:template>
+
+</xsl:stylesheet>
+
+<!-- vim: set expandtab shiftwidth=2: -->
diff --git a/doc/publican/sources/Architecture.xml b/doc/publican/sources/Architecture.xml
new file mode 100644 (file)
index 0000000..5d9ada0
--- /dev/null
@@ -0,0 +1,344 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+<chapter id="chap-Wayland-Architecture">
+  <title>Wayland Architecture</title>
+  <section id="sect-Wayland-Architecture-wayland_architecture">
+    <title>X vs. Wayland Architecture</title>
+    <para>
+      A good way to understand the Wayland architecture
+      and how it is different from X is to follow an event
+      from the input device to the point where the change
+      it affects appears on screen.
+    </para>
+    <para>
+      This is where we are now with X:
+    </para>
+    <figure>
+      <title>X architecture diagram</title>
+      <mediaobjectco>
+       <imageobjectco>
+         <areaspec id="map1" units="other" otherunits="imagemap">
+           <area id="area1_1" linkends="x_flow_1" x_steal="#step_1"/>
+           <area id="area1_2" linkends="x_flow_2" x_steal="#step_2"/>
+           <area id="area1_3" linkends="x_flow_3" x_steal="#step_3"/>
+           <area id="area1_4" linkends="x_flow_4" x_steal="#step_4"/>
+           <area id="area1_5" linkends="x_flow_5" x_steal="#step_5"/>
+           <area id="area1_6" linkends="x_flow_6" x_steal="#step_6"/>
+         </areaspec>
+         <imageobject>
+           <imagedata fileref="images/x-architecture.png" format="PNG" />
+         </imageobject>
+       </imageobjectco>
+      </mediaobjectco>
+    </figure>
+    <para>
+      <orderedlist>
+       <listitem id="x_flow_1">
+         <para>
+           The kernel gets an event from an input
+           device and sends it to X through the evdev
+           input driver. The kernel does all the hard
+           work here by driving the device and
+           translating the different device specific
+           event protocols to the linux evdev input
+           event standard.
+         </para>
+       </listitem>
+       <listitem id="x_flow_2">
+         <para>
+           The X server determines which window the
+           event affects and sends it to the clients
+           that have selected for the event in question
+           on that window. The X server doesn't
+           actually know how to do this right, since
+           the window location on screen is controlled
+           by the compositor and may be transformed in
+           a number of ways that the X server doesn't
+           understand (scaled down, rotated, wobbling,
+           etc).
+         </para>
+       </listitem>
+       <listitem id="x_flow_3">
+         <para>
+           The client looks at the event and decides
+           what to do. Often the UI will have to change
+           in response to the event - perhaps a check
+           box was clicked or the pointer entered a
+           button that must be highlighted. Thus the
+           client sends a rendering request back to the
+           X server.
+         </para>
+       </listitem>
+       <listitem id="x_flow_4">
+         <para>
+           When the X server receives the rendering
+           request, it sends it to the driver to let it
+           program the hardware to do the rendering.
+           The X server also calculates the bounding
+           region of the rendering, and sends that to
+           the compositor as a damage event.
+         </para>
+       </listitem>
+       <listitem id="x_flow_5">
+         <para>
+           The damage event tells the compositor that
+           something changed in the window and that it
+           has to recomposite the part of the screen
+           where that window is visible. The compositor
+           is responsible for rendering the entire
+           screen contents based on its scenegraph and
+           the contents of the X windows. Yet, it has
+           to go through the X server to render this.
+         </para>
+       </listitem>
+       <listitem id="x_flow_6">
+         <para>
+           The X server receives the rendering requests
+           from the compositor and either copies the
+           compositor back buffer to the front buffer
+           or does a pageflip. In the general case, the
+           X server has to do this step so it can
+           account for overlapping windows, which may
+           require clipping and determine whether or
+           not it can page flip. However, for a
+           compositor, which is always fullscreen, this
+           is another unnecessary context switch.
+         </para>
+       </listitem>
+      </orderedlist>
+    </para>
+    <para>
+      As suggested above, there are a few problems with this
+      approach. The X server doesn't have the information to
+      decide which window should receive the event, nor can it
+      transform the screen coordinates to window local
+      coordinates. And even though X has handed responsibility for
+      the final painting of the screen to the compositing manager,
+      X still controls the front buffer and modesetting. Most of
+      the complexity that the X server used to handle is now
+      available in the kernel or self contained libraries (KMS,
+      evdev, mesa, fontconfig, freetype, cairo, Qt etc). In
+      general, the X server is now just a middle man that
+      introduces an extra step between applications and the
+      compositor and an extra step between the compositor and the
+      hardware.
+    </para>
+    <para>
+      In Wayland the compositor is the display server. We transfer
+      the control of KMS and evdev to the compositor. The Wayland
+      protocol lets the compositor send the input events directly
+      to the clients and lets the client send the damage event
+      directly to the compositor:
+    </para>
+    <figure>
+      <title>Wayland architecture diagram</title>
+      <mediaobjectco>
+       <imageobjectco>
+         <areaspec id="mapB" units="other" otherunits="imagemap">
+           <area id="areaB_1" linkends="wayland_flow_1" x_steal="#step_1"/>
+           <area id="areaB_2" linkends="wayland_flow_2" x_steal="#step_2"/>
+           <area id="areaB_3" linkends="wayland_flow_3" x_steal="#step_3"/>
+           <area id="areaB_4" linkends="wayland_flow_4" x_steal="#step_4"/>
+         </areaspec>
+         <imageobject>
+           <imagedata fileref="images/wayland-architecture.png" format="PNG" />
+         </imageobject>
+       </imageobjectco>
+      </mediaobjectco>
+    </figure>
+    <para>
+      <orderedlist>
+       <listitem id="wayland_flow_1">
+         <para>
+           The kernel gets an event and sends
+           it to the compositor. This
+           is similar to the X case, which is
+           great, since we get to reuse all the
+           input drivers in the kernel.
+         </para>
+       </listitem>
+       <listitem id="wayland_flow_2">
+         <para>
+           The compositor looks through its
+           scenegraph to determine which window
+           should receive the event. The
+           scenegraph corresponds to what's on
+           screen and the compositor
+           understands the transformations that
+           it may have applied to the elements
+           in the scenegraph. Thus, the
+           compositor can pick the right window
+           and transform the screen coordinates
+           to window local coordinates, by
+           applying the inverse
+           transformations. The types of
+           transformation that can be applied
+           to a window is only restricted to
+           what the compositor can do, as long
+           as it can compute the inverse
+           transformation for the input events.
+         </para>
+       </listitem>
+       <listitem id="wayland_flow_3">
+         <para>
+           As in the X case, when the client
+           receives the event, it updates the
+           UI in response. But in the Wayland
+           case, the rendering happens in the
+           client, and the client just sends a
+           request to the compositor to
+           indicate the region that was
+           updated.
+         </para>
+       </listitem>
+       <listitem id="wayland_flow_4">
+         <para>
+           The compositor collects damage
+           requests from its clients and then
+           recomposites the screen. The
+           compositor can then directly issue
+           an ioctl to schedule a pageflip with
+           KMS.
+         </para>
+       </listitem>
+
+
+      </orderedlist>
+    </para>
+  </section>
+  <section id="sect-Wayland-Architecture-wayland_rendering">
+    <title>Wayland Rendering</title>
+    <para>
+      One of the details I left out in the above overview
+      is how clients actually render under Wayland. By
+      removing the X server from the picture we also
+      removed the mechanism by which X clients typically
+      render. But there's another mechanism that we're
+      already using with DRI2 under X: direct rendering.
+      With direct rendering, the client and the server
+      share a video memory buffer. The client links to a
+      rendering library such as OpenGL that knows how to
+      program the hardware and renders directly into the
+      buffer. The compositor in turn can take the buffer
+      and use it as a texture when it composites the
+      desktop. After the initial setup, the client only
+      needs to tell the compositor which buffer to use and
+      when and where it has rendered new content into it.
+    </para>
+
+    <para>
+      This leaves an application with two ways to update its window contents:
+    </para>
+    <para>
+      <orderedlist>
+       <listitem>
+         <para>
+           Render the new content into a new buffer and tell the compositor
+           to use that instead of the old buffer. The application can
+           allocate a new buffer every time it needs to update the window
+           contents or it can keep two (or more) buffers around and cycle
+           between them. The buffer management is entirely under
+           application control.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           Render the new content into the buffer that it previously
+           told the compositor to to use. While it's possible to just
+           render directly into the buffer shared with the compositor,
+           this might race with the compositor. What can happen is that
+           repainting the window contents could be interrupted by the
+           compositor repainting the desktop. If the application gets
+           interrupted just after clearing the window but before
+           rendering the contents, the compositor will texture from a
+           blank buffer. The result is that the application window will
+           flicker between a blank window or half-rendered content. The
+           traditional way to avoid this is to render the new content
+           into a back buffer and then copy from there into the
+           compositor surface. The back buffer can be allocated on the
+           fly and just big enough to hold the new content, or the
+           application can keep a buffer around. Again, this is under
+           application control.
+         </para>
+       </listitem>
+      </orderedlist>
+    </para>
+    <para>
+      In either case, the application must tell the compositor
+      which area of the surface holds new contents. When the
+      application renders directly to the shared buffer, the
+      compositor needs to be noticed that there is new content.
+      But also when exchanging buffers, the compositor doesn't
+      assume anything changed, and needs a request from the
+      application before it will repaint the desktop. The idea
+      that even if an application passes a new buffer to the
+      compositor, only a small part of the buffer may be
+      different, like a blinking cursor or a spinner.
+    </para>
+  </section>
+  <section id="sect-Wayland-Architecture-wayland_hw_enabling">
+    <title>Hardware Enabling for Wayland</title>
+    <para>
+      Typically, hardware enabling includes modesetting/display
+      and EGL/GLES2. On top of that Wayland needs a way to share
+      buffers efficiently between processes. There are two sides
+      to that, the client side and the server side.
+    </para>
+    <para>
+      On the client side we've defined a Wayland EGL platform. In
+      the EGL model, that consists of the native types
+      (EGLNativeDisplayType, EGLNativeWindowType and
+      EGLNativePixmapType) and a way to create those types. In
+      other words, it's the glue code that binds the EGL stack and
+      its buffer sharing mechanism to the generic Wayland API. The
+      EGL stack is expected to provide an implementation of the
+      Wayland EGL platform. The full API is in the wayland-egl.h
+      header. The open source implementation in the mesa EGL stack
+      is in wayland-egl.c and platform_wayland.c.
+    </para>
+    <para>
+      Under the hood, the EGL stack is expected to define a
+      vendor-specific protocol extension that lets the client side
+      EGL stack communicate buffer details with the compositor in
+      order to share buffers. The point of the wayland-egl.h API
+      is to abstract that away and just let the client create an
+      EGLSurface for a Wayland surface and start rendering. The
+      open source stack uses the drm Wayland extension, which lets
+      the client discover the drm device to use and authenticate
+      and then share drm (GEM) buffers with the compositor.
+    </para>
+    <para>
+      The server side of Wayland is the compositor and core UX for
+      the vertical, typically integrating task switcher, app
+      launcher, lock screen in one monolithic application. The
+      server runs on top of a modesetting API (kernel modesetting,
+      OpenWF Display or similar) and composites the final UI using
+      a mix of EGL/GLES2 compositor and hardware overlays if
+      available. Enabling modesetting, EGL/GLES2 and overlays is
+      something that should be part of standard hardware bringup.
+      The extra requirement for Wayland enabling is the
+      EGL_WL_bind_wayland_display extension that lets the
+      compositor create an EGLImage from a generic Wayland shared
+      buffer. It's similar to the EGL_KHR_image_pixmap extension
+      to create an EGLImage from an X pixmap.
+    </para>
+    <para>
+      The extension has a setup step where you have to bind the
+      EGL display to a Wayland display. Then as the compositor
+      receives generic Wayland buffers from the clients (typically
+      when the client calls eglSwapBuffers), it will be able to
+      pass the struct wl_buffer pointer to eglCreateImageKHR as
+      the EGLClientBuffer argument and with EGL_WAYLAND_BUFFER_WL
+      as the target. This will create an EGLImage, which can then
+      be used by the compositor as a texture or passed to the
+      modesetting code to use as an overlay plane. Again, this is
+      implemented by the vendor specific protocol extension, which
+      on the server side will receive the driver specific details
+      about the shared buffer and turn that into an EGL image when
+      the user calls eglCreateImageKHR.
+    </para>
+  </section>
+</chapter>
diff --git a/doc/publican/sources/Author_Group.xml b/doc/publican/sources/Author_Group.xml
new file mode 100644 (file)
index 0000000..2bdde62
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE authorgroup PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+<authorgroup>
+  <author>
+    <firstname>Kristian</firstname>
+    <surname>Høgsberg</surname>
+    <affiliation>
+      <orgname>Intel Corporation</orgname>
+    </affiliation>
+    <email>krh@bitplanet.net</email>
+  </author>
+</authorgroup>
+
diff --git a/doc/publican/sources/Book_Info.xml b/doc/publican/sources/Book_Info.xml
new file mode 100644 (file)
index 0000000..38e5bfc
--- /dev/null
@@ -0,0 +1,71 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE bookinfo PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+<bookinfo id="book-Wayland-Wayland">
+  <title>Wayland</title>
+  <subtitle>The Wayland display server</subtitle>
+  <productname>Documentation</productname>
+  <productnumber>0.1</productnumber>
+  <edition>1</edition>
+  <pubsnumber>0</pubsnumber>
+  <abstract>
+    <para>
+      Wayland is a protocol for a compositor to talk to
+      its clients as well as a C library implementation of
+      that protocol. The compositor can be a standalone
+      display server running on Linux kernel modesetting
+      and evdev input devices, an X application, or a
+      Wayland client itself. The clients can be
+      traditional applications, X servers (rootless or
+      fullscreen) or other display servers.
+    </para>
+  </abstract>
+  <corpauthor>
+    <inlinemediaobject>
+      <imageobject>
+       <imagedata fileref="images/wayland.png" format="PNG" />
+      </imageobject>
+      <textobject>
+        <phrase>
+          Wayland logo
+        </phrase>
+      </textobject>
+    </inlinemediaobject>
+  </corpauthor>
+
+  <legalnotice lang="en-US">
+    <para>
+      Copyright <trademark class="copyright"></trademark> &YEAR; &HOLDER;
+    </para>
+
+    <para>
+      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.
+    </para>
+
+    <para>
+      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.
+    </para>
+  </legalnotice>
+
+
+  <xi:include href="Author_Group.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+</bookinfo>
diff --git a/doc/publican/sources/Client.xml b/doc/publican/sources/Client.xml
new file mode 100644 (file)
index 0000000..a1e3341
--- /dev/null
@@ -0,0 +1,92 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+  <!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+  <!ENTITY doxygen SYSTEM "ClientAPI.xml">
+%BOOK_ENTITIES;
+]>
+<appendix id="sect-Library-Client">
+  <title>Client API</title>
+  <section><title>Introduction</title>
+  <para>
+    The open-source reference implementation of Wayland protocol is
+    split in two C libraries, libwayland-client and <link
+    linkend="sect-Library-Server">libwayland-server</link>. Their main
+    responsibility is to handle the Inter-process communication
+    (<emphasis>IPC</emphasis>) with each other, therefore guaranteeing
+    the protocol objects marshaling and messages synchronization.
+  </para>
+  <para>
+    A client uses libwayland-client to communicate with one or more
+    wayland servers. A <link
+    linkend="Client-classwl__display">wl_display</link> object is
+    created and manages each open connection to a server. At least one
+    <link linkend="Client-classwl__event__queue">wl_event_queue</link>
+    object is created for each wl_display, this holds events as they
+    are recieved from the server until they can be
+    processed. Multi-threading is supported by creating an additional
+    wl_event_queue for each additional thread, each object can have
+    it's events placed in a particular queue, so potentially a
+    different thread could be made to handle the events for each
+    object created.
+  </para>
+  <para>
+    Though some conveinence functions are provided, libwayland-client
+    is designed to allow the calling code to wait for events, so that
+    different polling mechanisms can be used. A file descriptor is
+    provided, when it becomes ready for reading the calling code can
+    ask libwayland-client to read the available events from it into
+    the wl_event_queue objects.
+  </para>
+  <para>
+    The library only provides low-level access to the wayland objects.
+    Each object created by the client is represented by a <link
+    linkend="Client-classwl__proxy">wl_proxy</link> object that this
+    library creates. This includes the id that is actually
+    communicated over the socket to the server, a void* data pointer
+    that is intended to point at a client's representation of the
+    object, and a pointer to a static <link
+    linkend="Client-structwl__interface">wl_interface</link> object,
+    which is generated from the xml and identifies the object's class
+    and can be used for introspection into the messages and events.
+  </para>
+  <para>
+    Messages are sent by calling wl_proxy_marshal. This will write a
+    message to the socket, by using the message id and the
+    wl_interface to identify the types of each argument and convert
+    them into stream format.  Most software will call type-safe
+    wrappers generated from the xml description of the <link
+    linkend="appe-Wayland-Protocol">Wayland protocols</link>. For
+    instance the C header file generated from the xml defines the
+    following inline function to transmit the <link
+    linkend="protocol-spec-wl_surface-request-attach">wl_surface::attach</link>
+    message:
+  </para>
+  <programlisting>static inline void
+wl_surface_attach(struct wl_surface *wl_surface, struct wl_buffer *buffer, int32_t x, int32_t y)
+{
+  wl_proxy_marshal((struct wl_proxy *) wl_surface, WL_SURFACE_ATTACH, buffer, x, y);
+}</programlisting>
+  <para>
+    Events (messages from the server) are handled by calling a
+    "dispatcher" callback the client stores in the wl_proxy for each
+    event. A language binding for a string-based interpreter, such as
+    CPython, might have a dispatcher that uses the event name from the
+    wl_interface to identify the function to call. The default
+    dispatcher uses the message id number to index an array of
+    functions pointers, called a wl_listener, and the wl_interface to
+    convert data from the stream into arguments to the function. The
+    C header file generated from the xml defines a per-class structure
+    that forces the function pointers to be of the correct type, for
+    instance the <link
+    linkend="protocol-spec-wl_surface-event-enter">wl_surface::enter</link>
+    event defines this pointer in the wl_surface_listener object:
+  </para>
+  <programlisting>struct wl_surface_listener {
+  void (*enter)(void *data, struct wl_surface *, struct wl_output *);
+  ...
+}</programlisting>
+  <para>
+  </para>
+  </section>
+  &doxygen;
+</appendix>
diff --git a/doc/publican/sources/Compositors.xml b/doc/publican/sources/Compositors.xml
new file mode 100644 (file)
index 0000000..eea627c
--- /dev/null
@@ -0,0 +1,128 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+<chapter id="chap-Compositors">
+  <title>Types of Compositors</title>
+
+  <para>
+    Compositors come in different types, depending on which
+    role they play in the overall architecture of the OS.
+    For instance, a
+    <link linkend="sect-Compositors-System-Compositor">system compositor</link>
+    can be used for booting the system, handling multiple user switching, a
+    possible console terminal emulator and so forth. A different compositor, a
+    <link linkend="sect-Compositors-Session-Compositor">session compositor</link>
+    would provide the actual desktop environment. There are many ways for
+    different types of compositors to co-exist.
+  </para>
+  <para>
+    In this section, we introduce three types of Wayland compositors relying
+    on <link linkend="sect-Library-Server">libwayland-server</link>.
+  </para>
+
+  <section id="sect-Compositors-System-Compositor">
+    <title>System Compositor</title>
+    <para>
+      A system compositor can run from early boot until shutdown.
+      It effectively replaces the kernel vt system, and can tie in
+      with the systems graphical boot setup and multiseat support.
+    </para>
+    <para>
+      A system compositor can host different types of session
+      compositors, and let us switch between multiple sessions
+      (fast user switching, or secure/personal desktop switching).
+    </para>
+    <para>
+      A linux implementation of a system compositor will typically
+      use libudev, egl, kms, evdev and cairo.
+    </para>
+    <para>
+      For fullscreen clients, the system compositor can reprogram the
+      video scanout address to read directly from the client provided
+      buffer.
+    </para>
+  </section>
+  <section id="sect-Compositors-Session-Compositor">
+    <title>Session Compositor</title>
+    <para>
+      A session compositor is responsible for a single user session.
+      If a system compositor is present, the session compositor will
+      run nested under the system compositor. Nesting is feasible because
+      the protocol is asynchronous; roundtrips would be too expensive
+      when nesting is involved. If no system compositor is present, a
+      session compositor can run directly on the hw.
+     </para>
+     <para>
+      X applications can continue working under a session compositor
+      by means of a root-less X server that is activated on demand.
+     </para>
+    <para>
+       Possible examples for session compositors include
+      <itemizedlist>
+        <listitem>
+          <para>
+           gnome-shell
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           moblin
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           kwin
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           kmscon
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           rdp session
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           Weston with X11 or Wayland backend is a session compositor nested
+           in another session compositor.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           fullscreen X session under Wayland
+         </para>
+       </listitem>
+      </itemizedlist>
+    </para>
+  </section>
+  <section id="sect-Compositors-Embedding-Compositor">
+    <title>Embedding Compositor</title>
+    <para>
+      X11 lets clients embed windows from other clients, or lets clients
+      copy pixmap contents rendered by another client into their window.
+      This is often used for applets in a panel, browser plugins and similar.
+      Wayland doesn't directly allow this, but clients can communicate GEM
+      buffer names out-of-band, for example, using D-Bus, or command line
+      arguments when the panel launches the applet.  Another option is to
+      use a nested Wayland instance.  For this, the Wayland server will have
+      to be a library that the host application links to.  The host
+      application will then pass the Wayland server socket name to the
+      embedded application, and will need to implement the Wayland
+      compositor interface.  The host application composites the client
+      surfaces as part of it's window, that is, in the web page or in the
+      panel.  The benefit of nesting the Wayland server is that it provides
+      the requests the embedded client needs to inform the host about buffer
+      updates and a mechanism for forwarding input events from the host
+      application.
+    </para>
+    <para>
+      An example for this kind of setup is firefox embedding the flash
+      player as a kind of special-purpose compositor.
+    </para>
+  </section>
+</chapter>
diff --git a/doc/publican/sources/Foreword.xml b/doc/publican/sources/Foreword.xml
new file mode 100644 (file)
index 0000000..e6875a3
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+
+<preface>
+  <title>Preface</title>
+
+  <para>
+  This document describes the (i) Wayland architecture, (ii) Wayland model of
+  operation and (iii) its library API. Also, the Wayland protocol specification is shown
+  in the Appendix. This document is aimed primarily at Wayland developers and
+  those looking to program with it; it does not cover application development.
+  </para>
+  <para>
+  There have been many contributors to this document and since this is only the
+  first edition many errors are expected to be found. We appreciate
+  corrections.
+  </para>
+  <literallayout>
+Yours,
+
+        the Wayland open-source community
+        November 2012
+  </literallayout>
+</preface>
diff --git a/doc/publican/sources/Introduction.xml b/doc/publican/sources/Introduction.xml
new file mode 100644 (file)
index 0000000..7516c33
--- /dev/null
@@ -0,0 +1,116 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+<chapter id="chap-Introduction">
+  <title>Introduction</title>
+  <section id="sect-Motivation">
+    <title>Motivation</title>
+    <para>
+      Most Linux and Unix-based systems rely on the X Window System (or
+      simply <emphasis>X</emphasis>) as the low-level protocol for building
+      bitmap graphics interfaces. On these systems, the X stack has grown to
+      encompass functionality arguably belonging in client libraries,
+      helper libraries, or the host operating system kernel.  Support for
+      things like PCI resource management, display configuration management,
+      direct rendering, and memory management has been integrated into the X
+      stack, imposing limitations like limited support for standalone
+      applications, duplication in other projects (e.g. the Linux fb layer
+      or the DirectFB project), and high levels of complexity for systems
+      combining multiple elements (for example radeon memory map handling
+      between the fb driver and X driver, or VT switching).
+    </para>
+    <para>
+      Moreover, X has grown to incorporate modern features like offscreen
+      rendering and scene composition, but subject to the limitations of the
+      X architecture.  For example, the X implementation of composition adds
+      additional context switches and makes things like input redirection
+      difficult.
+    </para>
+    <mediaobject>
+      <imageobject>
+       <imagedata fileref="images/x-architecture.png" format="PNG" />
+      </imageobject>
+      <textobject>
+        <phrase>
+          X architecture diagram
+        </phrase>
+      </textobject>
+    </mediaobject>
+    <para>
+      The diagram above illustrates the central role of the X server and
+      compositor in operations, and the steps required to get contents on to
+      the screen.
+    </para>
+    <para>
+      Over time, X developers came to understand the shortcomings of this
+      approach and worked to split things up.  Over the past several years,
+      a lot of functionality has moved out of the X server and into
+      client-side libraries or kernel drivers. One of the first components
+      to move out was font rendering, with freetype and fontconfig providing
+      an alternative to the core X fonts.  Direct rendering OpenGL as a
+      graphics driver in a client side library went through some iterations,
+      ending up as DRI2, which abstracted most of the direct rendering
+      buffer management from client code. Then cairo came along and provided
+      a modern 2D rendering library independent of X, and compositing
+      managers took over control of the rendering of the desktop as toolkits
+      like GTK+ and Qt moved away from using X APIs for rendering. Recently,
+      memory and display management have moved to the Linux kernel, further
+      reducing the scope of X and its driver stack.  The end result is a
+      highly modular graphics stack.
+    </para>
+
+  </section>
+
+  <section id="sect-Compositing-manager-display-server">
+    <title>The compositing manager as the display server</title>
+    <para>
+      Wayland is a new display server and compositing protocol, and Weston
+      is the implementation of this protocol which builds on top of all the
+      components above. We are trying to distill out the functionality in
+      the X server that is still used by the modern Linux desktop. This
+      turns out to be not a whole lot. Applications can allocate their own
+      off-screen buffers and render their window contents directly, using
+      hardware accelerated libraries like libGL, or high quality software
+      implementations like those found in Cairo. In the end, what’s needed
+      is a way to present the resulting window surface for display, and a
+      way to receive and arbitrate input among multiple clients. This is
+      what Wayland provides, by piecing together the components already in
+      the eco-system in a slightly different way.
+    </para>
+    <para>
+      X will always be relevant, in the same way Fortran compilers and VRML
+      browsers are, but it’s time that we think about moving it out of the
+      critical path and provide it as an optional component for legacy
+      applications.
+    </para>
+    <para>
+      Overall, the philosophy of Wayland is to provide clients with a way to
+      manage windows and how their contents is displayed.  Rendering is left
+      to clients, and system wide memory management interfaces are used to
+      pass buffer handles between clients and the compositing manager.
+    </para>
+    <mediaobject>
+      <imageobject>
+       <imagedata fileref="images/wayland-architecture.png" format="PNG" />
+      </imageobject>
+      <textobject>
+        <phrase>
+          Wayland architecture diagram
+        </phrase>
+      </textobject>
+    </mediaobject>
+    <para>
+      The figure above illustrates how Wayland clients interact with a
+      Wayland server.  Note that window management and composition are
+      handled entirely in the server, significantly reducing complexity
+      while marginally improving performance through reduced context
+      switching.  The resulting system is easier to build and extend than a
+      similar X system, because often changes need only be made in one
+      place.  Or in the case of protocol extensions, two (rather than 3 or 4
+      in the X case where window management and/or composition handling may
+      also need to be updated).
+    </para>
+  </section>
+</chapter>
diff --git a/doc/publican/sources/Preface.xml b/doc/publican/sources/Preface.xml
new file mode 100644 (file)
index 0000000..61720a9
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+
+<preface>
+  <title>Acknowledgments</title>
+
+  <para>
+  TODO: Kristian has to fill up this with one or two paragraphs and a small
+  "thank you": http://en.wikipedia.org/wiki/Preface
+  </para>
+  <literallayout>
+Best,
+
+        Kristian Høgsberg
+  </literallayout>
+</preface>
diff --git a/doc/publican/sources/Protocol.xml b/doc/publican/sources/Protocol.xml
new file mode 100644 (file)
index 0000000..33dd64d
--- /dev/null
@@ -0,0 +1,538 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+<chapter id="chap-Protocol">
+  <title>Wayland Protocol and Model of Operation</title>
+  <section id="sect-Protocol-Basic-Principles">
+    <title>Basic Principles</title>
+    <para>
+      The Wayland protocol is an asynchronous object oriented protocol.  All
+      requests are method invocations on some object.  The requests 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.
+    </para>
+    <para>
+      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 response to requests
+      (in which case the request and the event constitutes a round trip) or
+      spontaneously when the server state changes.
+    </para>
+    <para>
+      <itemizedlist>
+       <listitem>
+         <para>
+           State is broadcast on connect, events are sent
+           out when state changes. Clients must listen for
+           these changes and cache the state.
+           There is no need (or mechanism) to query server state.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           The server will broadcast the presence of a number of global objects,
+           which in turn will broadcast their current state.
+         </para>
+       </listitem>
+      </itemizedlist>
+    </para>
+  </section>
+  <section id="sect-Protocol-Code-Generation">
+    <title>Code Generation</title>
+    <para>
+      The interfaces, requests and events are defined in
+      <filename>protocol/wayland.xml</filename>.
+      This xml is used to generate the function prototypes that can be used by
+      clients and compositors.
+      When multiseat is enabled, <filename>protocol/wayland_multiseat.xml</filename>
+      is used.
+    </para>
+    <para>
+      The protocol entry points are generated as inline functions which just
+      wrap the <function>wl_proxy_*</function> functions.  The inline functions aren't
+      part of the library ABI and language bindings should generate their
+      own stubs for the protocol entry points from the xml.
+    </para>
+  </section>
+  <section id="sect-Protocol-Wire-Format">
+    <title>Wire Format</title>
+    <para>
+      The protocol is sent over a UNIX domain stream socket, where the endpoint
+      usually is named <systemitem class="service">wayland-0</systemitem>
+      (although it can be changed via <emphasis>WAYLAND_DISPLAY</emphasis>
+      in the environment).  The protocol is message-based.  A
+      message sent by a client to the server is called request.  A message
+      from the server to a client is called event.  Every message is
+      structured as 32-bit words, values are represented in the host's
+      byte-order.
+    </para>
+    <para>
+      The message header has 2 words in it:
+      <itemizedlist>
+       <listitem>
+         <para>
+           The first word is the sender's object ID (32-bit).
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           The second has 2 parts of 16-bit.  The upper 16-bits are the message
+           size in bytes, starting at the header (i.e. it has a minimum value of 8).The lower is the request/event opcode.
+         </para>
+       </listitem>
+      </itemizedlist>
+      The payload describes the request/event arguments.  Every argument is always
+      aligned to 32-bits. Where padding is required, the value of padding bytes is
+      undefined. There is no prefix that describes the type, but it is
+      inferred implicitly from the xml specification.
+    </para>
+    <para>
+
+      The representation of argument types are as follows:
+      <variablelist>
+       <varlistentry>
+         <term>int</term>
+         <term>uint</term>
+         <listitem>
+           <para>
+             The value is the 32-bit value of the signed/unsigned
+             int.
+           </para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term>fixed</term>
+         <listitem>
+           <para>
+             Signed 24.8 decimal numbers. It is a signed decimal type which
+             offers a sign bit, 23 bits of integer precision and 8 bits of
+             decimal precision. This is exposed as an opaque struct with
+             conversion helpers to and from double and int on the C API side.
+           </para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term>string</term>
+         <listitem>
+           <para>
+             Starts with an unsigned 32-bit length, followed by the
+             string contents, including terminating null byte, then padding
+             to a 32-bit boundary.
+           </para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term>object</term>
+         <listitem>
+           <para>
+             32-bit object ID.
+           </para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term>new_id</term>
+         <listitem>
+           <para>
+             The 32-bit object ID.  On requests, the client
+             decides the ID.  The only events with <type>new_id</type> are
+             advertisements of globals, and the server will use IDs below
+             0x10000.
+           </para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term>array</term>
+         <listitem>
+           <para>
+             Starts with 32-bit array size in bytes, followed by the array
+             contents verbatim, and finally padding to a 32-bit boundary.
+           </para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term>fd</term>
+         <listitem>
+           <para>
+             The file descriptor is not stored in the message buffer, but in
+             the ancillary data of the UNIX domain socket message (msg_control).
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+    </para>
+  </section>
+  <xi:include href="ProtocolInterfaces.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
+  <section id="sect-Protocol-Versioning">
+    <title>Versioning</title>
+    <para>
+      Every interface is versioned and every protocol object implements a
+      particular version of its interface.  For global objects, the maximum
+      version supported by the server is advertised with the global and the
+      actual verion of the created protocol object is determined by the
+      version argument passed to wl_registry.bind().  For objects that are
+      not globals, their version is inferred from the object that created
+      them.
+    </para>
+    <para>
+      In order to keep things sane, this has a few implications for
+      interface versions:
+      <itemizedlist>
+       <listitem>
+         <para>
+           The object creation hierarchy must be a tree.  Otherwise,
+           infering object versions from the parent object becomes a much
+           more difficult to properly track.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           When the version of an interface increases, so does the version
+           of its parent (recursively until you get to a global interface)
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           A global interface's version number acts like a counter for all
+           of its child interfaces.  Whenever a child interface gets
+           modified, the global parent's interface version number also
+           increases (see above).  The child interface then takes on the
+           same version number as the new version of its parent global
+           interface.
+         </para>
+       </listitem>
+      </itemizedlist>
+    </para>
+    <para>
+      To illustrate the above, consider the wl_compositor interface.  It
+      has two children, wl_surface and wl_region.  As of wayland version
+      1.2, wl_surface and wl_compositor are both at version 3.  If
+      something is added to the wl_region interface, both wl_region and
+      wl_compositor will get bumpped to version 4.  If, afterwards,
+      wl_surface is changed, both wl_compositor and wl_surface will be at
+      version 5.  In this way the global interface version is used as a
+      sort of "counter" for all of its child interfaces.  This makes it
+      very simple to know the version of the child given the version of its
+      parent.  The child is at the highest possible interface version that
+      is less than or equal to its parent's version.
+    </para>
+    <para>
+      It is worth noting a particular exception to the above versioning
+      scheme.  The wl_display (and, by extension, wl_registry) interface
+      cannot change because it is the core protocol object and its version
+      is never advertised nor is there a mechanism to request a different
+      version.
+    </para>
+  </section>
+  <section id="sect-Protocol-Connect-Time">
+    <title>Connect Time</title>
+    <para>
+      There is no fixed connection setup information, the server emits
+      multiple events at connect time, to indicate the presence and
+      properties of global objects: outputs, compositor, input devices.
+    </para>
+  </section>
+  <section id="sect-Protocol-Security-and-Authentication">
+    <title>Security and Authentication</title>
+    <para>
+      <itemizedlist>
+       <listitem>
+         <para>
+           mostly about access to underlying buffers, need new drm auth
+           mechanism (the grant-to ioctl idea), need to check the cmd stream?
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           getting the server socket depends on the compositor type, could
+           be a system wide name, through fd passing on the session dbus.
+           or the client is forked by the compositor and the fd is
+           already opened.
+         </para>
+       </listitem>
+      </itemizedlist>
+    </para>
+  </section>
+  <section id="sect-Protocol-Creating-Objects">
+    <title>Creating Objects</title>
+    <para>
+      Each object has a unique ID.  The IDs are allocated by the entity
+      creating the object (either client or server).  IDs allocated by the
+      client are in the range [1, 0xfeffffff] while IDs allocated by the
+      server are in the range [0xff000000, 0xffffffff].  The 0 ID is
+      reserved to represent a null or non-existant object.
+
+      For efficiency purposes, the IDs are densely packed in the sense that
+      the ID N will not be used until N-1 has been used.  Any ID allocation
+      algorithm that does not maintain this property is incompatible with
+      the implementation in libwayland.
+    </para>
+  </section>
+  <section id="sect-Protocol-Compositor">
+    <title>Compositor</title>
+    <para>
+      The compositor is a global object, advertised at connect time.
+    </para>
+    <para>
+      See <xref linkend="protocol-spec-wl_compositor"/> for the
+      protocol description.
+    </para>
+  </section>
+  <section id="sect-Protocol-Surface">
+    <title>Surfaces</title>
+    <para>
+      A surface manages a rectangular grid of pixels that clients create
+      for displaying their content to the screen.  Clients don't know
+      the global position of their surfaces, and cannot access other
+      clients' surfaces.
+    </para>
+    <para>
+      Once the client has finished writing pixels, it 'commits' the
+      buffer; this permits the compositor to access the buffer and read
+      the pixels.  When the compositor is finished, it releases the
+      buffer back to the client.
+    </para>
+    <para>
+      See <xref linkend="protocol-spec-wl_surface"/> for the protocol
+      description.
+    </para>
+  </section>
+  <section id="sect-Protocol-Input">
+    <title>Input</title>
+    <para>
+      A seat represents a group of input devices including mice,
+      keyboards and touchscreens. It has a keyboard and pointer
+      focus. Seats are global objects. Pointer events are delivered
+      in surface local coordinates.
+    </para>
+    <para>
+      The compositor maintains an implicit grab when a button is
+      pressed, to ensure that the corresponding button release
+      event gets delivered to the same surface. But there is no way
+      for clients to take an explicit grab. Instead, surfaces can
+      be mapped as 'popup', which combines transient window semantics
+      with a pointer grab.
+    </para>
+    <para>
+      To avoid race conditions, input events that are likely to
+      trigger further requests (such as button presses, key events,
+      pointer motions) carry serial numbers, and requests such as
+      wl_surface.set_popup require that the serial number of the
+      triggering event is specified. The server maintains a
+      monotonically increasing counter for these serial numbers.
+    </para>
+    <para>
+      Input events also carry timestamps with millisecond granularity.
+      Their base is undefined, so they can't be compared against
+      system time (as obtained with clock_gettime or gettimeofday).
+      They can be compared with each other though, and for instance
+      be used to identify sequences of button presses as double
+      or triple clicks.
+    </para>
+    <para>
+      See <xref linkend="protocol-spec-wl_seat"/> for the
+      protocol description.
+    </para>
+    <para>
+      Talk about:
+
+      <itemizedlist>
+       <listitem>
+         <para>
+           keyboard map, change events
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           xkb on Wayland
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           multi pointer Wayland
+         </para>
+       </listitem>
+      </itemizedlist>
+    </para>
+    <para>
+      A surface can change the pointer image when the surface is the pointer
+      focus of the input device.  Wayland doesn't automatically change the
+      pointer image when a pointer enters a surface, but expects the
+      application to set the cursor it wants in response to the pointer
+      focus and motion events.  The rationale is that a client has to manage
+      changing pointer images for UI elements within the surface in response
+      to motion events anyway, so we'll make that the only mechanism for
+      setting or changing the pointer image.  If the server receives a request
+      to set the pointer image after the surface loses pointer focus, the
+      request is ignored.  To the client this will look like it successfully
+      set the pointer image.
+    </para>
+    <para>
+      The compositor will revert the pointer image back to a default image
+      when no surface has the pointer focus for that device.  Clients can
+      revert the pointer image back to the default image by setting a NULL
+      image.
+    </para>
+    <para>
+      What if the pointer moves from one window which has set a special
+      pointer image to a surface that doesn't set an image in response to
+      the motion event?  The new surface will be stuck with the special
+      pointer image.  We can't just revert the pointer image on leaving a
+      surface, since if we immediately enter a surface that sets a different
+      image, the image will flicker.  Broken app, I suppose.
+    </para>
+  </section>
+  <section id="sect-Protocol-Output">
+    <title>Output</title>
+    <para>
+      An output is a global object, advertised at connect time or as it
+      comes and goes.
+    </para>
+    <para>
+      See <xref linkend="protocol-spec-wl_output"/> for the protocol
+      description.
+    </para>
+    <para>
+    </para>
+    <itemizedlist>
+      <listitem>
+       <para>
+         laid out in a big (compositor) coordinate system
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         basically xrandr over Wayland
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         geometry needs position in compositor coordinate system
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         events to advertise available modes, requests to move and change
+         modes
+       </para>
+      </listitem>
+    </itemizedlist>
+  </section>
+  <section id="sect-Protocol-data-sharing">
+    <title>Data sharing between clients</title>
+    <para>
+      The Wayland protocol provides clients a mechanism for sharing
+      data that allows the implementation of copy-paste and
+      drag-and-drop. The client providing the data creates a
+      <function>wl_data_source</function> object and the clients
+      obtaining the data will see it as <function>wl_data_offer</function>
+      object. This interface allows the clients to agree on a mutually
+      supported mime type and transfer the data via a file descriptor
+      that is passed through the protocol.
+    </para>
+    <para>
+      The next section explains the negotiation between data source and
+      data offer objects. <xref linkend="sect-Protocol-data-sharing-devices"/>
+      explains how these objects are created and passed to different
+      clients using the <function>wl_data_device</function> interface
+      that implements copy-paste and drag-and-drop support.
+    </para>
+    <para>
+      See <xref linkend="protocol-spec-wl_data_offer"/>,
+      <xref linkend="protocol-spec-wl_data_source"/>,
+      <xref linkend="protocol-spec-wl_data_device"/> and
+      <xref linkend="protocol-spec-wl_data_device_manager"/> for
+      protocol descriptions.
+    </para>
+    <para>
+      MIME is defined in RFC's 2045-2049. A
+      <ulink url="ftp://ftp.isi.edu/in-notes/iana/assignments/media-types/">
+      registry of MIME types</ulink> is maintained by the Internet Assigned
+      Numbers Authority (IANA).
+    </para>
+    <section>
+      <title>Data negotiation</title>
+      <para>
+       A client providing data to other clients will create a <function>wl_data_source</function>
+       object and advertise the mime types for the formats it supports for
+       that data through the <function>wl_data_source.offer</function>
+       request. On the receiving end, the data offer object will generate one
+       <function>wl_data_offer.offer</function> event for each supported mime
+       type.
+      </para>
+      <para>
+       The actual data transfer happens when the receiving client sends a
+       <function>wl_data_offer.receive</function> request. This request takes
+       a mime type and a file descriptor as arguments. This request will generate a
+       <function>wl_data_source.send</function> event on the sending client
+       with the same arguments, and the latter client is expected to write its
+       data to the given file descriptor using the chosen mime type.
+      </para>
+    </section>
+    <section id="sect-Protocol-data-sharing-devices">
+      <title>Data devices</title>
+      <para>
+       Data devices glue data sources and offers together. A data device is
+       associated with a <function>wl_seat</function> and is obtained by the clients using the
+       <function>wl_data_device_manager</function> factory object, which is also responsible for
+       creating data sources.
+      </para>
+      <para>
+       Clients are informed of new data offers through the
+       <function>wl_data_device.data_offer</function> event. After this
+       event is generated the data offer will advertise the available mime
+       types. New data offers are introduced prior to their use for
+       copy-paste or drag-and-drop.
+      </para>
+      <section>
+       <title>Selection</title>
+       <para>
+         Each data device has a selection data source. Clients create a data
+         source object using the device manager and may set it as the
+         current selection for a given data device. Whenever the current
+         selection changes, the client with keyboard focus receives a
+         <function>wl_data_device.selection</function> event. This event is
+         also generated on a client immediately before it receives keyboard
+         focus.
+       </para>
+       <para>
+         The data offer is introduced with
+         <function>wl_data_device.data_offer</function> event before the
+         selection event.
+       </para>
+      </section>
+      <section>
+       <title>Drag and Drop</title>
+       <para>
+         A drag-and-drop operation is started using the
+         <function>wl_data_device.start_drag</function> request. This
+         requests causes a pointer grab that will generate enter, motion and
+         leave events on the data device. A data source is supplied as
+         argument to start_drag, and data offers associated with it are
+         supplied to clients surfaces under the pointer in the
+         <function>wl_data_device.enter</function> event. The data offer
+         is introduced to the client prior to the enter event with the
+         <function>wl_data_device.data_offer</function> event.
+       </para>
+       <para>
+         Clients are expected to provide feedback to the data sending client
+         by calling the <function>wl_data_offer.accept</function> request with
+         a mime type it accepts. If none of the advertised mime types is
+         supported by the receiving client, it should supply NULL to the
+         accept request. The accept request causes the sending client to
+         receive a <function>wl_data_source.target</function> event with the
+         chosen mime type.
+       </para>
+       <para>
+         When the drag ends, the receiving client receives a
+         <function>wl_data_device.drop</function> event at which it is expected
+         to transfer the data using the
+         <function>wl_data_offer.receive</function> request.
+       </para>
+      </section>
+    </section>
+  </section>
+</chapter>
diff --git a/doc/publican/sources/Revision_History.xml b/doc/publican/sources/Revision_History.xml
new file mode 100644 (file)
index 0000000..2c540fe
--- /dev/null
@@ -0,0 +1,7 @@
+<revhistory>
+  <revision>
+    <revnumber>1-0</revnumber>
+    <authorinitials>krh</authorinitials>
+    <revremark>Initial version</revremark>
+  </revision>
+</revhistory>
diff --git a/doc/publican/sources/Server.xml b/doc/publican/sources/Server.xml
new file mode 100644 (file)
index 0000000..f627d64
--- /dev/null
@@ -0,0 +1,49 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+  <!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+  <!ENTITY doxygen SYSTEM "ServerAPI.xml">
+%BOOK_ENTITIES;
+]>
+<appendix id="sect-Library-Server">
+  <title>Server API</title>
+  <section><title>Introduction</title>
+  <para>
+    The open-source reference implementation of Wayland protocol is
+    split in two C libraries, <link
+    linkend="sect-Library-Client">libwayland-client</link> and
+    libwayland-server. Their main responsibility is to handle the
+    Inter-process communication (<emphasis>IPC</emphasis>) with each
+    other, therefore guaranteeing the protocol objects marshaling and
+    messages synchronization.
+  </para>
+  <para>
+    The server library is designed to work much like libwayland-client,
+    although it is considerably complicated due to the server needing
+    to support multiple versions of the protocol. It is best to learn
+    libwayland-client first.
+  </para>
+  <para>
+    Each open socket to a client is represented by a <link
+    linkend="Server-structwl__client">wl_client</link>.  The equvalent
+    of the <link linkend="Client-classwl__proxy">wl_proxy</link> that
+    libwayland-client uses to represent an object is <link
+    linkend="Server-structwl__resource">wl_resource</link> for
+    client-created objects, and <link
+    linkend="Server-structwl__global">wl_global</link> for objects
+    created by the server.
+  </para>
+  <para>
+    Often a server is also a client for another Wayland server, and
+    thus must link with both libwayland-client and libwayland-server.
+    This produces some type name conflicts (such as the <link
+    linkend="Client-classwl__display">client wl_display</link> and
+    <link linkend="Server-structwl__display">server wl_display</link>,
+    but the duplicate-but-not-the-same types are opaque, and accessed
+    only inside the correct library where it came from. Naturally that
+    means that the program writer needs to always know if a pointer to
+    a wl_display is for the server or client side and use the
+    corresponding functions.
+  </para>
+  </section>
+  &doxygen;
+</appendix>
diff --git a/doc/publican/sources/Wayland.ent b/doc/publican/sources/Wayland.ent
new file mode 100644 (file)
index 0000000..da18a95
--- /dev/null
@@ -0,0 +1,4 @@
+<!ENTITY PRODUCT "Documentation">
+<!ENTITY BOOKID "Wayland">
+<!ENTITY YEAR "2012">
+<!ENTITY HOLDER "Kristian Høgsberg, Intel Corporation">
diff --git a/doc/publican/sources/Wayland.xml b/doc/publican/sources/Wayland.xml
new file mode 100644 (file)
index 0000000..2f47f13
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+<book>
+  <xi:include href="Book_Info.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+  <xi:include href="Foreword.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+  <xi:include href="Preface.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+  <xi:include href="Introduction.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+  <xi:include href="Compositors.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+  <xi:include href="Architecture.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+  <xi:include href="Protocol.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+  <xi:include href="ProtocolSpec.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+  <xi:include href="Client.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
+  <xi:include href="Server.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
+</book>
diff --git a/doc/publican/sources/css/brand.css b/doc/publican/sources/css/brand.css
new file mode 100644 (file)
index 0000000..d86cba9
--- /dev/null
@@ -0,0 +1,14 @@
+/*headings*/
+h1, h2, h3, h4, h5, h6,
+div.producttitle,
+div.subtitle,
+div.author div.author,
+div.translator div.translator,
+div.othercredit div.othercredit,
+div.editor div.editor,
+div.contrib div.contrib,
+.title,
+.titlepage .edition,
+.titlepage .releaseinfo {
+       color: #336699;
+}
diff --git a/doc/publican/sources/css/common.css b/doc/publican/sources/css/common.css
new file mode 100644 (file)
index 0000000..a05648e
--- /dev/null
@@ -0,0 +1,1769 @@
+* {
+       widows: 4 !important;
+       orphans: 4 !important;
+}
+
+body, h1, h2, h3, h4, h5, h6, pre, li, div {
+       line-height: 1.29em;
+}
+
+body {
+       background-color: white;
+       margin:0 auto;
+       font-family: "liberation sans", "Myriad ", "Bitstream Vera Sans", "Lucida Grande", "Luxi Sans", "Trebuchet MS", helvetica, verdana, arial, sans-serif;
+       font-size: 14px;
+       max-width: 770px;
+       color: black;
+}
+
+body.toc_embeded {
+       /*for web hosting system only*/
+       margin-left: 300px;
+}
+
+object.toc, iframe.toc {
+       /*for web hosting system only*/
+       border-style: none;
+       position: fixed;
+       width: 290px;
+       height: 99.99%;
+       top: 0;
+       left: 0;
+       z-index: 100;
+       border-style: none;
+       border-right:1px solid #999;
+}
+
+/* Hide web menu */
+
+body.notoc {
+       margin-left: 3em;
+}
+
+iframe.notoc {
+       border-style:none;
+       border: none;
+       padding: 0px;
+       position:fixed;
+       width: 21px;
+       height: 29px;
+       top: 0px;
+       left:0;
+       overflow: hidden;
+       margin: 0px;
+       margin-left: -3px;
+}
+/* End hide web menu */
+
+/* desktop styles */
+body.desktop {
+       margin-left: 26em;
+}
+
+body.desktop .book > .toc {
+       display:block;
+       width:24em;
+       height:99.99%;
+       position:fixed;
+       overflow:auto;
+       top:0px;
+       left:0px;
+/*     padding-left:1em; */
+       background-color:#EEEEEE;
+       font-size: 12px;
+}
+
+body.pdf {
+       max-width: 100%;
+}
+
+.toc {
+       line-height:1.35em;
+}
+
+.toc .glossary,
+.toc .chapter, .toc .appendix {
+       margin-top:1em;
+}
+
+.toc .part {
+       margin-top:1em;
+       display:block;
+}
+
+span.glossary,
+span.appendix {
+       display:block;
+       margin-top:0.5em;
+}
+
+div {
+       padding-top:0px;
+}
+
+div.section {
+       page-break-inside: avoid;
+}
+
+p, div.para {
+       padding-top: 0px;
+       margin-top: 1em;
+       padding-bottom: 0px;
+       margin-bottom: 1em;
+}
+
+div.formalpara {
+       padding-top: 0px;
+       margin-top: 1em;
+       padding-bottom: 0px;
+       margin-bottom: 1em;
+}
+
+.varlistentry div.para {
+       page-break-before: avoid;
+
+}
+
+/*Links*/
+a {
+       outline: none;
+}
+
+a:link {
+       text-decoration: none;
+       border-bottom: 1px dotted ;
+       color:#3366cc;
+}
+
+body.pdf a:link {
+       word-wrap: break-word;
+}
+
+a:visited {
+       text-decoration:none;
+       border-bottom: 1px dotted ;
+       color:#003366;
+}
+
+div.longdesc-link {
+       float:right;
+       color:#999;
+}
+
+.toc a, .qandaset a {
+       font-weight:normal;
+       border:none;
+}
+
+.toc a:hover, .qandaset a:hover
+{
+       border-bottom: 1px dotted;
+}
+
+/*headings*/
+h1, h2, h3, h4, h5, h6 {
+       color: #336699;
+       margin-top: 0px;
+       margin-bottom: 0px;
+       background-color: transparent;
+       margin-bottom: 0px;
+       margin-top: 20px;
+       page-break-inside: avoid;
+       page-break-after: avoid;
+       word-wrap: break-word;
+}
+
+h1 {
+       font-size: 22px;
+}
+
+.titlepage h1.title {
+       text-align:left;
+}
+
+.book > .titlepage h1.title {
+       text-align: center;
+}
+
+.article > .titlepage h1.title,
+.article > .titlepage h2.title {
+       text-align: center;
+}
+
+.set .titlepage > div > div > h1.title {
+       text-align: center;
+}
+
+.part > .titlepage h1.title {
+       text-align: center;
+       font-size: 24px;
+}
+
+div.producttitle {
+       margin-top: 0px;
+       margin-bottom: 20px;
+       font-size: 48px;
+       font-weight: bold;
+/*     background: #003d6e url(../images/h1-bg.png) top left repeat-x; */
+       color:  #336699;
+       text-align: center;
+       padding-top: 12px;
+}
+
+.titlepage .corpauthor {
+       margin-top: 1em;
+       text-align: center;
+}
+
+.section h1.title {
+       font-size: 18px;
+       padding: 0px;
+       color: #336699;
+       text-align: left;
+       background: white;
+}
+
+h2 {
+       font-size: 20px;
+       margin-top: 30px;
+}
+
+
+.book div.subtitle, .book h2.subtitle, .book h3.subtitle {
+       margin-top: 1em;
+       margin-bottom: 1em;
+       font-size: 18px;
+       text-align: center;
+}
+
+div.subtitle {
+       color:  #336699;
+       font-weight: bold;
+}
+
+h1.legalnotice {
+       font-size: 24px;
+}
+
+.preface > div > div > div > h2.title,
+.preface > div > div > div > h1.title {
+       margin-top: 1em;
+       font-size: 24px;
+}
+
+.appendix h2 {
+       font-size: 24px;
+}
+
+
+
+h3 {
+       font-size: 14px;
+       padding-top:0px;
+       padding-bottom: 0px;
+       margin-bottom: 0px;
+}
+h4 {
+       font-size: 14px;
+       padding-top:0px;
+       padding-bottom:0px;
+}
+
+h5 {
+       font-size: 14px;
+}
+
+h6 {
+       font-size: 14px;
+       margin-bottom: 0px;
+}
+
+.abstract h6 {
+       margin-top:1em;
+       margin-bottom:.5em;
+       font-size: 24px;
+}
+
+.index > div > div > div > h2.title {
+       font-size: 24px;
+}
+
+.chapter > div > div > div > h2.title {
+       font-size: 24px;
+}
+
+.section > div > div > div > h2.title {
+       font-size: 21px;
+       page-break-inside: avoid;
+       page-break-before: avoid;
+       page-break-after: avoid;
+}
+
+.section > div > div > div > h3.title {
+       font-size: 17px;
+}
+
+/*element rules*/
+hr {
+       border-collapse: collapse;
+       border-style:none;
+       border-top: 1px dotted #ccc;
+       width:100%;
+}
+
+/* web site rules */
+ul.languages, .languages li {
+       display:inline;
+       padding:0px;
+}
+
+.languages li a {
+       padding:0px .5em;
+       text-decoration: none;
+}
+
+.languages li p, .languages li div.para {
+       display:inline;
+}
+
+.languages li a:link, .languages li a:visited {
+       color:#444;
+}
+
+.languages li a:hover, .languages li a:focus, .languages li a:active {
+       color:black;
+}
+
+ul.languages {
+       display:block;
+       background-color:#eee;
+       padding:.5em;
+}
+
+/*supporting stylesheets*/
+
+/*unique to the webpage only*/
+.books {
+       position:relative;
+}
+
+.versions li {
+       width:100%;
+       clear:both;
+       display:block;
+}
+
+a.version {
+       font-size: 20px;
+       text-decoration:none;
+       width:100%;
+       display:block;
+       padding:1em 0px .2em 0px;
+       clear:both;
+}
+
+a.version:before {
+       content:"Version";
+       font-size: smaller;
+}
+
+a.version:visited, a.version:link {
+       color:#666;
+}
+
+a.version:focus, a.version:hover {
+       color:black;
+}
+
+.books {
+       display:block;
+       position:relative;
+       clear:both;
+       width:100%;
+}
+
+.books li {
+       display:block;
+       width:200px;
+       float:left;
+       position:relative;
+       clear: none ;
+}
+
+.books .html {
+       width:170px;
+       display:block;
+}
+
+.books .pdf {
+       position:absolute;
+       left:170px;
+       top:0px;
+       font-size: smaller;
+}
+
+.books .pdf:link, .books .pdf:visited {
+       color:#555;
+}
+
+.books .pdf:hover, .books .pdf:focus {
+       color:#000;
+}
+
+.books li a {
+       text-decoration:none;
+}
+
+.books li a:hover {
+       color:black;
+}
+
+/*products*/
+.products li {
+       display: block;
+       width:300px;
+       float:left;
+}
+
+.products li a {
+       width:300px;
+       padding:.5em 0px;
+}
+
+.products ul {
+       clear:both;
+}
+
+/*revision history*/
+.revhistory {
+       display:block;
+}
+
+.revhistory table {
+       background-color:transparent;
+       border-color:#fff;
+       padding:0px;
+       margin: 0;
+       border-collapse:collapse;
+       border-style:none;
+}
+
+.revhistory td {
+       text-align :left;
+       padding:0px;
+       border: none;
+       border-top: 1px solid #fff;
+       font-weight: bold;
+}
+
+.revhistory .simplelist td {
+       font-weight: normal;
+}
+
+.revhistory .simplelist {
+       margin-bottom: 1.5em;
+       margin-left: 1em;
+}
+
+.revhistory table th {
+       display: none;
+}
+
+
+/*credits*/
+.authorgroup div {
+       clear:both;
+       text-align: center;
+}
+
+div.author div.author,
+div.translator div.translator,
+div.othercredit div.othercredit,
+div.editor div.editor,
+div.contrib div.contrib {
+       margin: 0px;
+       padding: 0px;
+       margin-top: 12px;
+       font-size: 14px;
+       font-weight: bold;
+       color: #336699;
+}
+
+div.editedby {
+       margin-top: 15px;
+       margin-bottom: -0.8em;
+}
+
+div.authorgroup .author,
+div.authorgroup.editor,
+div.authorgroup.translator,
+div.authorgroup.othercredit,
+div.authorgroup.contrib {
+       display: block;
+       font-size: 14px;
+       page-break-inside: avoid;
+}
+
+.revhistory .author {
+       display: inline;
+}
+
+.othercredit h3 {
+       padding-top: 1em;
+}
+
+
+.othercredit {
+       margin:0px;
+       padding:0px;
+}
+
+.releaseinfo {
+       clear: both;
+}
+
+.copyright {
+       margin-top: 1em;
+}
+
+/* qanda sets */
+.answer {
+       margin-bottom:1em;
+       border-bottom:1px dotted #ccc;
+}
+
+.qandaset .toc {
+       border-bottom:1px dotted #ccc;
+}
+
+.question {
+       font-weight:bold;
+}
+
+.answer .data, .question .data {
+       padding-left: 2.6em;
+}
+
+.answer .label, .question .label {
+       float:left;
+       font-weight:bold;
+}
+
+/* inline syntax highlighting */
+.perl_Alert {
+       color: #0000ff;
+}
+
+.perl_BaseN {
+       color: #007f00;
+}
+
+.perl_BString {
+       color: #5C3566;
+}
+
+.perl_Char {
+       color: #ff00ff;
+}
+
+.perl_Comment {
+       color: #888888;
+}
+
+
+.perl_DataType {
+       color: #0000ff;
+}
+
+
+.perl_DecVal {
+       color: #00007f;
+}
+
+
+.perl_Error {
+       color: #ff0000;
+}
+
+
+.perl_Float {
+       color: #00007f;
+}
+
+
+.perl_Function {
+       color: #007f00;
+}
+
+
+.perl_IString {
+       color: #5C3566;
+}
+
+
+.perl_Keyword {
+       color: #002F5D;
+}
+
+
+.perl_Operator {
+       color: #ffa500;
+}
+
+
+.perl_Others {
+       color: #b03060;
+}
+
+
+.perl_RegionMarker {
+       color: #96b9ff;
+}
+
+
+.perl_Reserved {
+       color: #9b30ff;
+}
+
+
+.perl_String {
+       color: #5C3566;
+}
+
+
+.perl_Variable {
+       color: #0000ff;
+}
+
+
+.perl_Warning {
+       color: #0000ff;
+}
+
+/*Lists*/
+ul {
+    list-style-image: url("../images/dot.png");
+    list-style-type: circle;
+    padding-left: 1.6em;
+}
+
+ul ul {
+    list-style-image: url("../images/dot2.png");
+    list-style-type: circle;
+}
+
+ol.1 {
+       list-style-type: decimal;
+}
+
+ol.a,
+ol ol {
+       list-style-type: lower-alpha;
+}
+
+ol.i {
+       list-style-type: lower-roman;
+}
+ol.A {
+       list-style-type: upper-alpha;
+}
+
+ol.I {
+       list-style-type: upper-roman;
+}
+
+dt {
+       font-weight:bold;
+       margin-bottom:0px;
+       padding-bottom:0px;
+}
+
+dd {
+       margin:0px;
+       margin-left:2em;
+       padding-top:0px;
+}
+
+li {
+       padding-top: 0px;
+       margin-top: 0px;
+       padding-bottom: 0px;
+/*     margin-bottom: 16px; */
+}
+
+/*images*/
+img {
+       display:block;
+       margin: 2em 0;
+       max-width: 100%;
+}
+
+.inlinemediaobject,
+.inlinemediaobject img,
+.inlinemediaobject object {
+       display:inline;
+       margin:0px;
+       overflow: hidden;
+}
+
+.figure {
+    margin-top: 1em;
+    width: 100%;
+}
+
+.figure img,
+.mediaobject img {
+       display:block;
+       margin: 0em;
+       page-break-inside: avoid;
+}
+
+.figure .title {
+       margin-bottom:2em;
+       padding:0px;
+}
+
+/*document modes*/
+.confidential {
+       background-color:#900;
+       color:White;
+       padding:.5em .5em;
+       text-transform:uppercase;
+       text-align:center;
+}
+
+.longdesc-link {
+       display:none;
+}
+
+.longdesc {
+       display:none;
+}
+
+.prompt {
+       padding:0px .3em;
+}
+
+/*user interface styles*/
+.screen .replaceable {
+}
+
+.guibutton, .guilabel {
+       font-family: "liberation mono", "bitstream vera mono", "dejavu mono", monospace;
+       font-weight: bold;
+}
+
+.example {
+       background-color: #ffffff;
+       border-left: 3px solid #aaaaaa;
+       padding-top: 1px;
+       padding-bottom: 0.1em;
+       padding-left: 1em;
+}
+
+.equation {
+       border-left: 3px solid #aaaaaa;
+       background-color: #ffffff;
+       padding-top: 1px;
+       padding-bottom: 0.1em;
+       padding-left: 1em;
+}
+
+.equation-contents {
+       margin-left: 4em;
+}
+
+div.title {
+       margin-bottom: 1em;
+       font-weight: 14px;
+       font-weight: bold;
+       color: #336699;
+       page-break-inside: avoid;
+       page-break-after: avoid;
+       word-wrap: break-word;
+}
+
+.example-contents {
+       background-color: #ffffff;
+}
+
+.example-contents .para {
+/*      padding: 10px;*/
+}
+
+/*terminal/console text*/
+.computeroutput,
+.option {
+       font-family:"liberation mono", "bitstream vera mono", "dejavu mono", monospace;
+       font-weight:bold;
+}
+
+.replaceable {
+       font-style: italic;
+}
+
+.command, .filename, .keycap, .classname, .literal {
+       font-family:"liberation mono", "bitstream vera mono", "dejavu mono", monospace;
+       font-weight:bold;
+}
+
+/* no bold in toc */
+.toc * {
+       font-weight: inherit;
+}
+
+.toc H1 {
+       font-weight: bold;
+}
+
+
+div.programlisting {
+       white-space: pre-wrap; /* css-3 */
+       white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */
+       white-space: -pre-wrap; /* Opera 4-6 */
+       white-space: -o-pre-wrap; /* Opera 7 */
+       word-wrap: break-word; /* Internet Explorer 5.5+ */
+}
+
+pre {
+       font-family:"liberation mono", "bitstream vera mono", "dejavu mono", monospace;
+       display:block;
+       background-color: #f5f5f5;
+       color: #000000;
+/*     border: 1px solid #aaaaaa; */
+       margin-bottom: 1em;
+       padding:.5em 1em;
+       white-space: pre-wrap; /* css-3 */
+       white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */
+       white-space: -pre-wrap; /* Opera 4-6 */
+       white-space: -o-pre-wrap; /* Opera 7 */
+       word-wrap: break-word; /* Internet Explorer 5.5+ */
+       font-size: 0.9em;
+       border-style:none;
+       box-shadow: 0 2px 5px #AAAAAA inset;
+       -moz-box-shadow:  0 2px 5px #AAAAAA inset;
+       -webkit-box-shadow: 0 2px 5px #AAAAAA inset;
+       -o-box-shadow: 0 2px 5px #AAAAAA inset;
+}
+
+body.pdf pre {
+       border: 1px solid #AAAAAA;
+       box-shadow: none;
+       -moz-box-shadow: none;
+       -webkit-box-shadow: none;
+       -o-box-shadow: none;
+}
+
+
+pre .replaceable,
+pre .keycap {
+}
+
+code {
+       font-family:"liberation mono", "bitstream vera mono", "dejavu mono", monospace;
+       white-space: pre-wrap;
+       word-wrap: break-word;
+       font-weight:bold;
+}
+
+.parameter code {
+       display: inline;
+       white-space: pre-wrap; /* css-3 */
+       white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */
+       white-space: -pre-wrap; /* Opera 4-6 */
+       white-space: -o-pre-wrap; /* Opera 7 */
+       word-wrap: break-word; /* Internet Explorer 5.5+ */
+}
+
+code.email {
+       font-weight: normal;
+       font-family: "liberation sans", "Myriad ", "Bitstream Vera Sans", "Lucida Grande", "Luxi Sans", "Trebuchet MS", helvetica, verdana, arial, sans-serif;
+
+}
+
+/*Notifications*/
+div.warning:before {
+       content:url(../images/warning.png);
+       padding-left: 5px;
+}
+
+div.note:before {
+       content:url(../images/note.png);
+       padding-left: 5px;
+}
+
+div.important:before {
+       content:url(../images/important.png);
+       padding-left: 5px;
+}
+
+div.warning, div.note, div.important {
+       color: black;
+       margin: 0px;
+       padding: 0px;
+       background: none;
+       background-color: white;
+       margin-bottom: 1em;
+       border-bottom: 1px solid #aaaaaa;
+       page-break-inside: avoid;
+}
+
+div.admonition_header p {
+       margin: 0px;
+       padding: 0px;
+       color: #eeeeec;
+       padding-top: 0px;
+       padding-bottom: 0px;
+       height: 1.4em;
+       line-height: 1.4em;
+       font-size: 17px;
+       display:inline;
+}
+
+div.admonition_header {
+       background-origin:content-box;
+       clear: both;
+       margin: 0px;
+       padding: 0px;
+       margin-top: -40px;
+       padding-left: 58px;
+       line-height: 1.0px;
+       font-size: 1.0px;
+}
+
+div.warning div.admonition_header {
+       background: url(../images/red.png) top left repeat-x;
+       background-color: #590000;
+       background: -webkit-linear-gradient(#a40000,#590000);
+       background: linear-gradient(#a40000,#590000);
+}
+
+div.note div.admonition_header {
+       background: url(../images/green.png) top right repeat-x;
+       background-color: #597800;
+       background: -webkit-linear-gradient(#769f00,#597800);
+       background: linear-gradient(#769f00,#597800);
+}
+
+div.important div.admonition_header {
+       background: url(../images/yellow.png) top right repeat-x;
+       background-color: #a6710f;
+       background: -webkit-linear-gradient(#d08e13,#a6710f);
+       background: linear-gradient(#d08e13,#a6710f);
+}
+
+div.warning p:first-child,
+div.warning div.para:first-child,
+div.note p:first-child,
+div.note div.para:first-child,
+div.important p:first-child,
+div.important div.para:first-child {
+       padding: 0px;
+       margin: 0px;
+}
+
+div.admonition {
+       border: none;
+       border-left: 1px solid #aaaaaa;
+       border-right: 1px solid #aaaaaa;
+       padding:0px;
+       margin:0px;
+       padding-top: 1.5em;
+       padding-bottom: 1em;
+       padding-left: 2em;
+       padding-right: 1em;
+       background-color: #eeeeec;
+       -moz-border-radius: 0px;
+       -webkit-border-radius: 0px;
+       border-radius: 0px;
+}
+
+/*Page Title*/
+#title  {
+       display:block;
+       height:45px;
+       padding-bottom:1em;
+       margin:0px;
+}
+
+#title a.left{
+       display:inline;
+       border:none;
+}
+
+#title a.left img{
+       border:none;
+       float:left;
+       margin:0px;
+       margin-top:.7em;
+}
+
+#title a.right {
+       padding-bottom:1em;
+}
+
+#title a.right img {
+       border:none;
+       float:right;
+       margin:0px;
+       margin-top:.7em;
+}
+
+/*Table*/
+div.table {
+/*     page-break-inside: avoid; */
+}
+
+table {
+       border: 1px solid #444;
+       width:100%;
+       border-collapse:collapse;
+       table-layout: fixed;
+       word-wrap: break-word;
+}
+
+table.blockquote,
+table.simplelist,
+.calloutlist table {
+       border-style: none;
+}
+
+table th {
+       text-align:left;
+       background-color:#6699cc;
+       padding:.3em .5em;
+       color:white;
+}
+
+table td {
+       padding:.15em .5em;
+}
+
+table tr.even td {
+       background-color:#f5f5f5;
+}
+
+tr:nth-child(even) {
+       background-color: #eeeeee;
+
+}
+
+
+table th p:first-child, table td p:first-child, table  li p:first-child,
+table th div.para:first-child, table td div.para:first-child, table  li div.para:first-child {
+       margin-top:0px;
+       padding-top:0px;
+       display:inline;
+}
+
+th, td {
+       border-style:none;
+       vertical-align: top;
+/*     border: 1px solid #000; */
+}
+
+.blockquote td,
+.simplelist th,
+.simplelist td {
+       border: none;
+}
+
+table table td {
+       border-bottom:1px dotted #aaa;
+       background-color:white;
+       padding:.6em 0px;
+}
+
+table table {
+       border:1px solid white;
+}
+
+td.remarkval {
+       color:#444;
+}
+
+td.fieldval {
+       font-weight:bold;
+}
+
+.lbname, .lbtype, .lbdescr, .lbdriver, .lbhost {
+       color:white;
+       font-weight:bold;
+       background-color:#999;
+       width:120px;
+}
+
+td.remarkval {
+       width:230px;
+}
+
+td.tname {
+       font-weight:bold;
+}
+
+th.dbfield {
+       width:120px;
+}
+
+th.dbtype {
+       width:70px;
+}
+
+th.dbdefault {
+       width:70px;
+}
+
+th.dbnul {
+       width:70px;
+}
+
+th.dbkey {
+       width:70px;
+}
+
+span.book {
+       margin-top:4em;
+       display:block;
+       font-size: 11pt;
+}
+
+span.book a{
+       font-weight:bold;
+}
+span.chapter {
+       display:block;
+}
+
+table.simplelist td, .calloutlist table td {
+       border-style: none;
+}
+
+
+table.lt-4-cols.lt-7-rows td {
+       border: none;
+}
+/*to simplify layout*/
+
+
+table.lt-4-cols.gt-14-rows tr:nth-child(odd) {
+       background-color: #fafafa;
+}
+/* to keep simple but stripe rows */
+
+
+.gt-8-cols td {
+       border-left: 1px solid #ccc;
+}
+
+.gt-8-cols td:first-child {
+       border-left: 0;
+}
+/* to apply vertical lines to differentiate columns*/
+
+/*Breadcrumbs*/
+#breadcrumbs ul li.first:before {
+       content:" ";
+}
+
+#breadcrumbs {
+       color:#900;
+       padding:3px;
+       margin-bottom:25px;
+}
+
+#breadcrumbs ul {
+       margin-left:0;
+       padding-left:0;
+       display:inline;
+       border:none;
+}
+
+#breadcrumbs ul li {
+       margin-left:0;
+       padding-left:2px;
+       border:none;
+       list-style:none;
+       display:inline;
+}
+
+#breadcrumbs ul li:before {
+       content:"\0020 \0020 \0020 \00BB \0020";
+       color:#333;
+}
+
+dl {
+       margin-top: 0px;
+       margin-left: 28px;
+}
+
+.toc dl {
+       margin-left: 10px;
+}
+
+/*index*/
+.glossary h3,
+.index h3 {
+       font-size: 20px;
+       color:#aaa;
+       margin:0px;
+}
+
+.indexdiv {
+       margin-bottom:1em;
+}
+
+.glossary dt,
+.index dt {
+       color:#444;
+       padding-top:.5em;
+}
+
+.glossary dl dl dt,
+.index dl dl dt {
+       color:#777;
+       font-weight:normal;
+       padding-top:0px;
+}
+
+.index dl dl dt:before {
+       content:"- ";
+       color:#ccc;
+}
+
+/*changes*/
+.footnote {
+       font-size: 10px;
+       margin: 0px;
+       color: #222;
+}
+
+.footnotes {
+       margin-bottom: 60px;
+}
+
+table .footnote {
+}
+
+sup {
+       margin:0px;
+       padding:0px;
+       font-size: 10px;
+       padding-left:0px;
+}
+
+.footnote {
+       position:relative;
+}
+
+.footnote sup  {
+       color: black;
+       left: .4em;
+}
+
+.footnote a:link,
+.footnote a:visited {
+       text-decoration:none;
+       border: none;
+}
+
+.footnote .para sup  {
+/*     position:absolute; */
+       vertical-align:text-bottom;
+}
+
+a.footnote {
+       padding-right: 0.5em;
+       text-decoration:none;
+       border: none;
+}
+
+.footnote sup a:link,
+.footnote sup a:visited {
+       color:#92917d;
+       text-decoration:none;
+}
+
+.footnote:hover sup a {
+       text-decoration:none;
+}
+
+.footnote p,.footnote div.para {
+       padding-left:1em;
+}
+
+.footnote a:link,
+.footnote a:visited before{
+       color:#00537c;
+}
+
+.footnote a:hover {
+}
+
+/**/
+.pdf-break {
+       page-break-before: always;
+}
+
+div.legalnotice {
+       page-break-before: always;
+}
+
+div.abstract {
+       page-break-before: always;
+/*     page-break-after: always;*/
+}
+
+div.chapter {
+       page-break-before: always;
+}
+
+
+div.titlepage, div.titlepage > div, div.titlepage > div > div {
+       page-break-inside: avoid;
+       page-break-after: avoid;
+}
+
+div.preface, div.part {
+       page-break-before: always;
+}
+
+div.appendix {
+       page-break-before: always;
+}
+
+div.section {
+       page-break-inside: auto;
+       page-break-before: auto;
+       page-break-after: auto;
+}
+
+
+dt.varlistentry {
+       page-break-inside: avoid;
+       page-break-after: avoid;
+}
+
+dd {
+       page-break-before: avoid;
+}
+
+div.note .replaceable,
+div.important .replaceable,
+div.warning .replaceable,
+div.note .keycap,
+div.important .keycap,
+div.warning .keycap
+{
+}
+
+ul li p:last-child, ul li para:last-child {
+       margin-bottom:0px;
+       padding-bottom:0px;
+}
+
+/*document navigation*/
+.docnav a, .docnav strong {
+       border:none;
+       text-decoration:none;
+       font-weight:normal;
+}
+
+.docnav {
+       list-style:none;
+       margin:0px;
+       padding:0px;
+       position:relative;
+       width:100%;
+       padding-bottom:2em;
+       padding-top:1em;
+        height:2.5em;
+        line-height:2.5em;
+/*
+       border-top:1px dotted #ccc;
+        background-color: rgba(240, 240, 240, 0.9);
+-webkitbox-shadow: 0px .15em .5em rgba(0,0,0,0.2);
+  -moz-box-shadow: 0px .15em .5em rgba(0,0,0,0.2);
+       box-shadow: 0px .15em .5em rgba(0,0,0,0.2);
+*/
+}
+
+.docnav li {
+       list-style:none;
+       margin:0px;
+       padding:0px;
+       display:inline;
+       font-size: 14px;
+}
+
+.docnav li:before {
+       content:" ";
+}
+
+.docnav li.previous, .docnav li.next {
+       position:absolute;
+       top:1.5em;
+}
+
+.docnav li.up, .docnav li.home {
+       margin:0px 1.5em;
+}
+
+.docnav.top li.home {
+       color: #336699;
+       font-size: 22pt;
+       font-weight: bold;
+}
+
+
+.docnav li.previous {
+       left:0px;
+       text-align:left;
+}
+
+.docnav li.next {
+       right:0px;
+       text-align:right;
+}
+
+.docnav li.previous strong, .docnav li.next strong {
+       height: 17px;
+       display: block;
+}
+
+.docnav {
+       margin:0 auto;
+       text-align:center;
+}
+
+.docnav li.next a strong {
+       background:  url(../images/stock-go-forward.png) right 120% no-repeat;
+       padding-top:3px;
+       padding-bottom:4px;
+       padding-right:28px;
+}
+
+.docnav li.previous a strong {
+       background: url(../images/stock-go-back.png) left 120% no-repeat;
+       padding-top:3px;
+       padding-bottom:4px;
+       padding-left:28px;
+       padding-right:0.5em;
+}
+
+.docnav li.home a strong {
+       background: url(../images/stock-home.png) top left no-repeat;
+       padding:5px;
+       padding-left:28px;
+}
+
+.docnav li.up a strong {
+       background: url(../images/stock-go-up.png) top left no-repeat;
+       padding:5px;
+       padding-left:28px;
+}
+
+.docnav a:link, .docnav a:visited {
+       color:#666;
+}
+
+.docnav a:hover, .docnav a:focus, .docnav a:active {
+       color:black;
+}
+
+.docnav a {
+       max-width: 10px;
+       overflow:hidden;
+}
+
+.docnav a:link strong {
+       text-decoration:none;
+}
+
+.docnav {
+       margin:0 auto;
+       text-align:center;
+}
+
+ul.docnav {
+       margin-bottom: 1em;
+}
+/* Reports */
+.reports ul {
+       list-style:none;
+       margin:0px;
+       padding:0px;
+}
+
+.reports li{
+       margin:0px;
+       padding:0px;
+}
+
+.reports li.odd {
+       background-color: #eeeeee;
+       margin:0px;
+       padding:0px;
+}
+
+.reports dl {
+       display:inline;
+       margin:0px;
+       padding:0px;
+       float:right;
+       margin-right: 17em;
+       margin-top:-1.3em;
+}
+
+.reports dt {
+       display:inline;
+       margin:0px;
+       padding:0px;
+}
+
+.reports dd {
+       display:inline;
+       margin:0px;
+       padding:0px;
+       padding-right:.5em;
+}
+
+.reports h2, .reports h3{
+       display:inline;
+       padding-right:.5em;
+       font-size: 14px;
+       font-weight:normal;
+}
+
+.reports div.progress {
+       display:inline;
+       float:right;
+       width:16em;
+       background:#c00 url(../images/shine.png) top left repeat-x;
+       margin:0px;
+       margin-top:-1.3em;
+       padding:0px;
+       border:none;
+}
+
+/*uniform*/
+body.results, body.reports {
+       max-width:57em ;
+       padding:0px;
+}
+
+/*Progress Bar*/
+div.progress {
+       display:block;
+       float:left;
+       width:16em;
+       background:#c00 url(../images/shine.png) top left repeat-x;
+       height:1em;
+}
+
+div.progress span {
+       height:1em;
+       float:left;
+}
+
+div.progress span.translated {
+       background:#6c3 url(../images/shine.png) top left repeat-x;
+}
+
+div.progress span.fuzzy {
+       background:#ff9f00 url(../images/shine.png) top left repeat-x;
+}
+
+
+/*Results*/
+
+.results ul {
+       list-style:none;
+       margin:0px;
+       padding:0px;
+}
+
+.results li{
+       margin:0px;
+       padding:0px;
+}
+
+.results li.odd {
+       background-color: #eeeeee;
+       margin:0px;
+       padding:0px;
+}
+
+.results dl {
+       display:inline;
+       margin:0px;
+       padding:0px;
+       float:right;
+       margin-right: 17em;
+       margin-top:-1.3em;
+}
+
+.results dt {
+       display:inline;
+       margin:0px;
+       padding:0px;
+}
+
+.results dd {
+       display:inline;
+       margin:0px;
+       padding:0px;
+       padding-right:.5em;
+}
+
+.results h2, .results h3 {
+       display:inline;
+       padding-right:.5em;
+       font-size: 14px;
+       font-weight:normal;
+}
+
+.results div.progress {
+       display:inline;
+       float:right;
+       width:16em;
+       background:#c00 url(../images/shine.png) top left repeat-x;
+       margin:0px;
+       margin-top:-1.3em;
+       padding:0px;
+       border:none;
+}
+
+/* Dirty EVIL Mozilla hack for round corners */
+pre {
+       -moz-border-radius:11px;
+       -webkit-border-radius:11px;
+       border-radius: 11px;
+/*     page-break-inside: avoid; */
+}
+
+.example {
+       -moz-border-radius:0px;
+       -webkit-border-radius:0px;
+       border-radius: 0px;
+       page-break-inside: avoid;
+}
+
+/* move these invisible fields out of the flow */
+.example > a:first-child,
+.table > a:first-child {
+    float: left;
+}
+
+.package, .citetitle {
+       font-style: italic;
+}
+
+.titlepage .edition,
+.titlepage .releaseinfo {
+       color: #336699;
+       background-color: transparent;
+       margin-top: 1em;
+       margin-bottom: 1em;
+       font-size: 20px;
+       font-weight: bold;
+       text-align: center;
+}
+
+span.remark {
+       background-color: #ff00ff;
+}
+
+.draft {
+       background-image: url(../images/watermark-draft.png);
+       background-repeat: repeat-y;
+        background-position: center;
+}
+
+.foreignphrase {
+       font-style: inherit;
+}
+
+dt {
+       clear:both;
+       page-break-inside: avoid;
+       page-break-after: avoid;
+}
+
+dt img {
+       border-style: none;
+       max-width: 112px;
+}
+
+dt object {
+       max-width: 112px;
+}
+
+dt .inlinemediaobject, dt object {
+       display: inline;
+       float: left;
+       margin-bottom: 1em;
+       padding-right: 1em;
+       width: 112px;
+}
+
+dl:after {
+       display: block;
+       clear: both;
+       content: "";
+}
+
+.toc dd {
+       padding-bottom: 0px;
+       margin-bottom: 1em;
+       padding-left: 1.3em;
+       margin-left: 0px;
+}
+
+div.toc > dl > dt {
+       padding-bottom: 0px;
+       margin-bottom: 0px;
+       margin-top: 1em;
+}
+
+
+.strikethrough {
+       text-decoration: line-through;
+}
+
+.underline {
+       text-decoration: underline;
+}
+
+.calloutlist img, .callout {
+       padding: 0px;
+       margin: 0px;
+       width: 12pt;
+       display: inline;
+       vertical-align: middle;
+}
+
+li.step > a:first-child {
+       display: block;
+}
+
+.stepalternatives {
+       list-style-image: none;
+       list-style-type: upper-alpha;
+}
+.task {
+/*     page-break-inside: avoid; */
+}
+
+
+.added {
+       background-color: #99ff99;
+}
+
+.changed {
+       background-color: #ffff77;
+}
+
+.deleted {
+       background-color: #ff4455;
+       text-decoration: line-through;
+}
diff --git a/doc/publican/sources/css/default.css b/doc/publican/sources/css/default.css
new file mode 100644 (file)
index 0000000..bf38ebb
--- /dev/null
@@ -0,0 +1,3 @@
+@import url("common.css");
+@import url("overrides.css");
+@import url("lang.css");
diff --git a/doc/publican/sources/css/epub.css b/doc/publican/sources/css/epub.css
new file mode 100644 (file)
index 0000000..b0ffd43
--- /dev/null
@@ -0,0 +1,115 @@
+/*headings*/
+h1, h2, h3, h4, h5, h6,
+div.producttitle,
+div.subtitle,
+div.author div.author,
+div.translator div.translator,
+div.othercredit div.othercredit,
+div.editor div.editor,
+div.contrib div.contrib,
+.title,
+.titlepage .edition {
+}
+
+div.para {
+       margin-top: 1em;
+}
+/* inline syntax highlighting */
+.perl_Alert {
+       color: #0000ff;
+}
+
+.perl_BaseN {
+       color: #007f00;
+}
+
+.perl_BString {
+       color: #5C3566;
+}
+
+.perl_Char {
+       color: #ff00ff;
+}
+
+.perl_Comment {
+       color: #888888;
+}
+
+
+.perl_DataType {
+       color: #0000ff;
+}
+
+
+.perl_DecVal {
+       color: #00007f;
+}
+
+
+.perl_Error {
+       color: #ff0000;
+}
+
+
+.perl_Float {
+       color: #00007f;
+}
+
+
+.perl_Function {
+       color: #007f00;
+}
+
+
+.perl_IString {
+       color: #5C3566;
+}
+
+
+.perl_Keyword {
+       color: #002F5D;
+}
+
+
+.perl_Operator {
+       color: #ffa500;
+}
+
+
+.perl_Others {
+       color: #b03060;
+}
+
+
+.perl_RegionMarker {
+       color: #96b9ff;
+}
+
+
+.perl_Reserved {
+       color: #9b30ff;
+}
+
+
+.perl_String {
+       color: #5C3566;
+}
+
+
+.perl_Variable {
+       color: #0000ff;
+}
+
+
+.perl_Warning {
+       color: #0000ff;
+}
+
+b, strong {
+       font-weight: bolder;
+}
+
+code.command {
+       font-family: monospace;
+       font-weight: bolder;
+}
diff --git a/doc/publican/sources/css/print.css b/doc/publican/sources/css/print.css
new file mode 100644 (file)
index 0000000..54088f4
--- /dev/null
@@ -0,0 +1,15 @@
+@import url("common.css");
+@import url("overrides.css");
+@import url("lang.css");
+
+#tocframe {
+       display: none;
+}
+
+body.toc_embeded {
+       margin-left: 30px;
+}
+
+.producttitle {
+       color: #336699;
+}
diff --git a/doc/publican/sources/images/icon.svg b/doc/publican/sources/images/icon.svg
new file mode 100644 (file)
index 0000000..b2f16d0
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.0" width="32" height="32" id="svg3017">
+  <defs id="defs3019">
+    <linearGradient id="linearGradient2381">
+      <stop id="stop2383" style="stop-color:#ffffff;stop-opacity:1" offset="0"/>
+      <stop id="stop2385" style="stop-color:#ffffff;stop-opacity:0" offset="1"/>
+    </linearGradient>
+    <linearGradient x1="296.4996" y1="188.81061" x2="317.32471" y2="209.69398" id="linearGradient2371" xlink:href="#linearGradient2381" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.90776,0,0,0.90776,24.35648,49.24131)"/>
+  </defs>
+  <g transform="matrix(0.437808,-0.437808,0.437808,0.437808,-220.8237,43.55311)" id="g5089">
+    <path d="m 8.4382985,-6.28125 c -0.6073916,0 -4.3132985,5.94886271 -4.3132985,8.25 l 0,26.71875 c 0,0.846384 0.5818159,1.125 1.15625,1.125 l 25.5625,0 c 0.632342,0 1.125001,-0.492658 1.125,-1.125 l 0,-5.21875 0.28125,0 c 0.49684,0 0.906249,-0.409411 0.90625,-0.90625 l 0,-27.9375 c 0,-0.4968398 -0.40941,-0.90625 -0.90625,-0.90625 l -23.8117015,0 z" transform="translate(282.8327,227.1903)" id="path5091" style="fill:#5c5c4f;stroke:#000000;stroke-width:3.23021388;stroke-miterlimit:4;stroke-dasharray:none"/>
+    <rect width="27.85074" height="29.369793" rx="1.1414107" ry="1.1414107" x="286.96509" y="227.63805" id="rect5093" style="fill:#032c87"/>
+    <path d="m 288.43262,225.43675 25.2418,0 0,29.3698 -26.37615,0.0241 1.13435,-29.39394 z" id="rect5095" style="fill:#ffffff"/>
+    <path d="m 302.44536,251.73726 c 1.38691,7.85917 -0.69311,11.28365 -0.69311,11.28365 2.24384,-1.60762 3.96426,-3.47694 4.90522,-5.736 0.96708,2.19264 1.83294,4.42866 4.27443,5.98941 0,0 -1.59504,-7.2004 -1.71143,-11.53706 l -6.77511,0 z" id="path5097" style="fill:#a70000;fill-opacity:1;stroke-width:2"/>
+    <rect width="25.241802" height="29.736675" rx="0.89682275" ry="0.89682275" x="290.73544" y="220.92249" id="rect5099" style="fill:#809cc9"/>
+    <path d="m 576.47347,725.93939 6.37084,0.41502 0.4069,29.51809 c -1.89202,-1.31785 -6.85427,-3.7608 -8.26232,-1.68101 l 0,-26.76752 c 0,-0.82246 0.66212,-1.48458 1.48458,-1.48458 z" transform="matrix(0.499065,-0.866565,0,1,0,0)" id="rect5101" style="fill:#4573b3;fill-opacity:1"/>
+    <path d="m 293.2599,221.89363 20.73918,0 c 0.45101,0 0.8141,0.3631 0.8141,0.81411 0.21547,6.32836 -19.36824,21.7635 -22.36739,17.59717 l 0,-17.59717 c 0,-0.45101 0.3631,-0.81411 0.81411,-0.81411 z" id="path5103" style="opacity:0.65536726;fill:url(#linearGradient2371);fill-opacity:1"/>
+  </g>
+</svg>
diff --git a/doc/publican/sources/images/wayland.png b/doc/publican/sources/images/wayland.png
new file mode 100644 (file)
index 0000000..c993792
Binary files /dev/null and b/doc/publican/sources/images/wayland.png differ
diff --git a/m4/.gitignore b/m4/.gitignore
new file mode 100644 (file)
index 0000000..38066dd
--- /dev/null
@@ -0,0 +1,5 @@
+libtool.m4
+ltoptions.m4
+ltsugar.m4
+ltversion.m4
+lt~obsolete.m4
diff --git a/packaging/baselibs.conf b/packaging/baselibs.conf
new file mode 100644 (file)
index 0000000..6cc465e
--- /dev/null
@@ -0,0 +1,3 @@
+libwayland-client
+libwayland-cursor
+libwayland-server
diff --git a/packaging/wayland.changes b/packaging/wayland.changes
new file mode 100644 (file)
index 0000000..fc199a7
--- /dev/null
@@ -0,0 +1,33 @@
+* Mon Feb 16 2015 Manuel Bachmann <manuel.bachmann@open.eurogiciel.org> 1.7.0@8e9d5a1
+- Update to 1.7.0
+
+* Wed Nov 19 2014 Manuel Bachmann <manuel.bachmann@open.eurogiciel.org> 1.6.0@339e83a
+- Update to 1.6.0
+
+* Wed Feb 12 2014 Ossama Othman <ossama.othman@intel.com> 1.4.0@2450fe2
+- Update to 1.4.0
+
+* Thu Oct 17 2013 Ossama Othman <ossama.othman@intel.com> 1.3.0@2c3dbb8
+- Update to 1.3.0
+
+* Tue Jul 16 2013 Ossama Othman <ossama.othman@intel.com> 1.2.0@db1f961
+- Update to 1.2.0
+
+* Tue Jun 18 2013 Anas Nashif <anas.nashif@intel.com> accepted/tizen/20130606.153536@ff8eca6
+- Fixed gbs.conf
+
+* Wed Jun 05 2013 Rusty Lynch <rusty.lynch@intel.com> 1.1.0@55ad268
+- Updating to 1.1.0
+
+* Sat May 11 2013 Anas Nashif <anas.nashif@intel.com> submit/tizen/20130509.184835@8a428ae
+- Set license using %license
+
+* Fri Apr 05 2013 Anas Nashif <anas.nashif@intel.com> 1.0.6@413f185
+- Update to 1.0.6
+
+* Wed Feb 13 2013 Anas Nashif <anas.nashif@intel.com> accepted/trunk/20130207.031256@c0801a3
+- Update to 1.0.4
+
+* Mon Dec 17 2012 Anas Nashif <anas.nashif@intel.com> 1.0.3@d98211f
+- Update to 1.0.3
+
diff --git a/packaging/wayland.manifest b/packaging/wayland.manifest
new file mode 100644 (file)
index 0000000..017d22d
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+ <request>
+    <domain name="_"/>
+ </request>
+</manifest>
diff --git a/packaging/wayland.spec b/packaging/wayland.spec
new file mode 100644 (file)
index 0000000..08eb3ec
--- /dev/null
@@ -0,0 +1,124 @@
+Name:          wayland
+Version:       1.7.0
+Release:       0
+Summary:       Wayland Compositor Infrastructure
+License:       MIT
+Group:         Graphics & UI Framework/Wayland Window System
+URL:           http://wayland.freedesktop.org/
+
+#Git-Clone:    git://anongit.freedesktop.org/wayland/wayland
+#Git-Web:      http://cgit.freedesktop.org/wayland/wayland/
+Source:                %name-%version.tar.xz
+Source1001:    wayland.manifest
+BuildRequires: autoconf >= 2.64, automake >= 1.11
+BuildRequires: libtool >= 2.2
+BuildRequires: pkgconfig
+BuildRequires:  pkgconfig(libffi)
+BuildRequires:  expat-devel
+
+%description
+Wayland is a protocol for a compositor to talk to its clients as well
+as a C library implementation of that protocol. The compositor can be
+a standalone display server running on Linux kernel modesetting and
+evdev input devices, an X application, or a wayland client itself.
+The clients can be traditional applications, X servers (rootless or
+fullscreen) or other display servers.
+
+%package -n libwayland-client
+Group:         Graphics & UI Framework/Wayland Window System
+Summary:       Wayland core client library
+
+%description -n libwayland-client
+Wayland is a protocol for a compositor to talk to its clients as well
+as a C library implementation of that protocol. The compositor can be
+a standalone display server running on Linux kernel modesetting and
+evdev input devices, an X application, or a wayland client itself.
+The clients can be traditional applications, X servers (rootless or
+fullscreen) or other display servers.
+
+%package -n libwayland-cursor
+Group:         Graphics & UI Framework/Wayland Window System
+Summary:       Wayland cursor library
+
+%description -n libwayland-cursor
+The purpose of this library is to be the equivalent of libXcursor in
+the X world. This library is compatible with X cursor themes and
+loads them directly into an shm pool making it easy for the clients
+to get buffer for each cursor image.
+
+%package -n libwayland-server
+Group:         Graphics & UI Framework/Wayland Window System
+Summary:       Wayland core server library
+
+%description -n libwayland-server
+Wayland is a protocol for a compositor to talk to its clients as well
+as a C library implementation of that protocol. The compositor can be
+a standalone display server running on Linux kernel modesetting and
+evdev input devices, an X application, or a wayland client itself.
+The clients can be traditional applications, X servers (rootless or
+fullscreen) or other display servers.
+
+%package devel
+Summary:       Development files for the Wayland Compositor Infrastructure
+Group:         Graphics & UI Framework/Development
+Requires:      libwayland-client = %version
+Requires:      libwayland-cursor = %version
+Requires:      libwayland-server = %version
+
+%description devel
+Wayland is a protocol for a compositor to talk to its clients as well
+as a C library implementation of that protocol. The compositor can be
+a standalone display server running on Linux kernel modesetting and
+evdev input devices, an X application, or a wayland client itself.
+The clients can be traditional applications, X servers (rootless or
+fullscreen) or other display servers.
+
+This package contains all necessary include files and libraries needed
+to develop applications that require these.
+
+%prep
+%setup -q
+cp %{SOURCE1001} .
+mkdir -p ./m4
+
+%build
+%reconfigure --disable-static --disable-documentation
+make %{?_smp_mflags}
+
+%install
+%make_install
+
+%post -n libwayland-client -p /sbin/ldconfig
+%postun -n libwayland-client -p /sbin/ldconfig
+%post -n libwayland-cursor -p /sbin/ldconfig
+%postun -n libwayland-cursor -p /sbin/ldconfig
+%post -n libwayland-server -p /sbin/ldconfig
+%postun -n libwayland-server -p /sbin/ldconfig
+
+%files -n libwayland-client
+%manifest %{name}.manifest
+%defattr(-,root,root)
+%_libdir/libwayland-client.so.0*
+
+%files -n libwayland-cursor
+%manifest %{name}.manifest
+%defattr(-,root,root)
+%_libdir/libwayland-cursor.so.0*
+
+%files -n libwayland-server
+%manifest %{name}.manifest
+%defattr(-,root,root)
+%_libdir/libwayland-server.so.0*
+
+%files devel
+%manifest %{name}.manifest
+%defattr(-,root,root)
+%_bindir/wayland-scanner
+%_includedir/wayland-*.h
+%_libdir/libwayland-*.so
+%_libdir/pkgconfig/wayland-*.pc
+%_datadir/wayland/wayland*
+%_datadir/aclocal
+%doc README TODO
+
+%changelog
diff --git a/protocol/.gitignore b/protocol/.gitignore
new file mode 100644 (file)
index 0000000..78f49d2
--- /dev/null
@@ -0,0 +1,2 @@
+wayland.html
+.wayland.xml.valid
diff --git a/protocol/wayland.dtd b/protocol/wayland.dtd
new file mode 100644 (file)
index 0000000..b8b1573
--- /dev/null
@@ -0,0 +1,29 @@
+<!ELEMENT protocol (copyright?, interface+)>
+  <!ATTLIST protocol name CDATA #REQUIRED>
+<!ELEMENT copyright (#PCDATA)>
+<!ELEMENT interface (description?,(request|event|enum)+)>
+  <!ATTLIST interface name CDATA #REQUIRED>
+  <!ATTLIST interface version CDATA #REQUIRED>
+<!ELEMENT request (description?,arg*)>
+  <!ATTLIST request name CDATA #REQUIRED>
+  <!ATTLIST request type CDATA #IMPLIED>
+  <!ATTLIST request since CDATA #IMPLIED>
+<!ELEMENT event (description?,arg*)>
+  <!ATTLIST event name CDATA #REQUIRED>
+  <!ATTLIST event since CDATA #IMPLIED>
+<!ELEMENT enum (description?,entry*)>
+  <!ATTLIST enum name CDATA #REQUIRED>
+  <!ATTLIST enum since CDATA #IMPLIED>
+<!ELEMENT entry (description?)>
+  <!ATTLIST entry name CDATA #REQUIRED>
+  <!ATTLIST entry value CDATA #REQUIRED>
+  <!ATTLIST entry summary CDATA #IMPLIED>
+  <!ATTLIST entry since CDATA #IMPLIED>
+<!ELEMENT arg (description?)>
+  <!ATTLIST arg name CDATA #REQUIRED>
+  <!ATTLIST arg type CDATA #REQUIRED>
+  <!ATTLIST arg summary CDATA #IMPLIED>
+  <!ATTLIST arg interface CDATA #IMPLIED>
+  <!ATTLIST arg allow-null CDATA #IMPLIED>
+<!ELEMENT description (#PCDATA)>
+  <!ATTLIST description summary CDATA #REQUIRED>
diff --git a/protocol/wayland.xml b/protocol/wayland.xml
new file mode 100644 (file)
index 0000000..17ec69a
--- /dev/null
@@ -0,0 +1,2154 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="wayland">
+
+  <copyright>
+    Copyright © 2008-2011 Kristian Høgsberg
+    Copyright © 2010-2011 Intel Corporation
+    Copyright © 2012-2013 Collabora, Ltd.
+
+    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.
+  </copyright>
+
+  <interface name="wl_display" version="1">
+    <description summary="core global object">
+      The core global object.  This is a special singleton object.  It
+      is used for internal Wayland protocol features.
+    </description>
+
+    <request name="sync">
+      <description summary="asynchronous roundtrip">
+       The sync request asks the server to emit the 'done' event
+       on the returned wl_callback object.  Since requests are
+       handled in-order and events are delivered in-order, this can
+       be used as a barrier to ensure all previous requests and the
+       resulting events have been handled.
+
+       The object returned by this request will be destroyed by the
+       compositor after the callback is fired and as such the client must not
+       attempt to use it after that point.
+
+       The callback_data passed in the callback is the event serial.
+      </description>
+      <arg name="callback" type="new_id" interface="wl_callback"/>
+    </request>
+
+    <request name="get_registry">
+      <description summary="get global registry object">
+       This request creates a registry object that allows the client
+       to list and bind the global objects available from the
+       compositor.
+      </description>
+      <arg name="registry" type="new_id" interface="wl_registry"/>
+    </request>
+
+    <event name="error">
+      <description summary="fatal error event">
+       The error event is sent out when a fatal (non-recoverable)
+       error has occurred.  The object_id argument is the object
+       where the error occurred, most often in response to a request
+       to that object.  The code identifies the error and is defined
+       by the object interface.  As such, each interface defines its
+       own set of error codes.  The message is an brief description
+       of the error, for (debugging) convenience.
+      </description>
+      <arg name="object_id" type="object"/>
+      <arg name="code" type="uint"/>
+      <arg name="message" type="string"/>
+    </event>
+
+    <enum name="error">
+      <description summary="global error values">
+       These errors are global and can be emitted in response to any
+       server request.
+      </description>
+      <entry name="invalid_object" value="0"
+            summary="server couldn't find object"/>
+      <entry name="invalid_method" value="1"
+            summary="method doesn't exist on the specified interface"/>
+      <entry name="no_memory" value="2"
+            summary="server is out of memory"/>
+    </enum>
+
+    <event name="delete_id">
+      <description summary="acknowledge object ID deletion">
+       This event is used internally by the object ID management
+       logic.  When a client deletes an object, the server will send
+       this event to acknowledge that it has seen the delete request.
+       When the client receive this event, it will know that it can
+       safely reuse the object ID.
+      </description>
+      <arg name="id" type="uint" />
+    </event>
+  </interface>
+
+  <interface name="wl_registry" version="1">
+    <description summary="global registry object">
+      The global registry object.  The server has a number of global
+      objects that are available to all clients.  These objects
+      typically represent an actual object in the server (for example,
+      an input device) or they are singleton objects that provide
+      extension functionality.
+
+      When a client creates a registry object, the registry object
+      will emit a global event for each global currently in the
+      registry.  Globals come and go as a result of device or
+      monitor hotplugs, reconfiguration or other events, and the
+      registry will send out global and global_remove events to
+      keep the client up to date with the changes.  To mark the end
+      of the initial burst of events, the client can use the
+      wl_display.sync request immediately after calling
+      wl_display.get_registry.
+
+      A client can bind to a global object by using the bind
+      request.  This creates a client-side handle that lets the object
+      emit events to the client and lets the client invoke requests on
+      the object.
+    </description>
+
+    <request name="bind">
+      <description summary="bind an object to the display">
+       Binds a new, client-created object to the server using the
+        specified name as the identifier.
+      </description>
+      <arg name="name" type="uint" summary="unique name for the object"/>
+      <arg name="id" type="new_id"/>
+    </request>
+
+    <event name="global">
+      <description summary="announce global object">
+       Notify the client of global objects.
+
+        The event notifies the client that a global object with
+        the given name is now available, and it implements the
+        given version of the given interface.
+      </description>
+      <arg name="name" type="uint"/>
+      <arg name="interface" type="string"/>
+      <arg name="version" type="uint"/>
+    </event>
+
+    <event name="global_remove">
+      <description summary="announce removal of global object">
+       Notify the client of removed global objects.
+
+        This event notifies the client that the global identified
+        by name is no longer available.  If the client bound to
+        the global using the bind request, the client should now
+        destroy that object.
+
+       The object remains valid and requests to the object will be
+       ignored until the client destroys it, to avoid races between
+       the global going away and a client sending a request to it.
+      </description>
+      <arg name="name" type="uint"/>
+    </event>
+  </interface>
+
+  <interface name="wl_callback" version="1">
+    <description summary="callback object">
+      Clients can handle the 'done' event to get notified when
+      the related request is done.
+    </description>
+    <event name="done">
+      <description summary="done event">
+       Notify the client when the related request is done.
+      </description>
+      <arg name="callback_data" type="uint" summary="request-specific data for the wl_callback"/>
+    </event>
+  </interface>
+
+  <interface name="wl_compositor" version="3">
+    <description summary="the compositor singleton">
+      A compositor.  This object is a singleton global.  The
+      compositor is in charge of combining the contents of multiple
+      surfaces into one displayable output.
+    </description>
+
+    <request name="create_surface">
+      <description summary="create new surface">
+       Ask the compositor to create a new surface.
+      </description>
+      <arg name="id" type="new_id" interface="wl_surface"/>
+    </request>
+
+    <request name="create_region">
+      <description summary="create new region">
+       Ask the compositor to create a new region.
+      </description>
+      <arg name="id" type="new_id" interface="wl_region"/>
+    </request>
+  </interface>
+
+  <interface name="wl_shm_pool" version="1">
+    <description summary="a shared memory pool">
+      The wl_shm_pool object encapsulates a piece of memory shared
+      between the compositor and client.  Through the wl_shm_pool
+      object, the client can allocate shared memory wl_buffer objects.
+      All objects created through the same pool share the same
+      underlying mapped memory. Reusing the mapped memory avoids the
+      setup/teardown overhead and is useful when interactively resizing
+      a surface or for many small buffers.
+    </description>
+
+    <request name="create_buffer">
+      <description summary="create a buffer from the pool">
+       Create a wl_buffer object from the pool.
+
+       The buffer is created offset bytes into the pool and has
+       width and height as specified.  The stride arguments specifies
+       the number of bytes from beginning of one row to the beginning
+       of the next.  The format is the pixel format of the buffer and
+       must be one of those advertised through the wl_shm.format event.
+
+       A buffer will keep a reference to the pool it was created from
+       so it is valid to destroy the pool immediately after creating
+       a buffer from it.
+      </description>
+
+      <arg name="id" type="new_id" interface="wl_buffer"/>
+      <arg name="offset" type="int"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+      <arg name="stride" type="int"/>
+      <arg name="format" type="uint"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the pool">
+       Destroy the shared memory pool.
+
+       The mmapped memory will be released when all
+       buffers that have been created from this pool
+       are gone.
+      </description>
+    </request>
+
+    <request name="resize">
+      <description summary="change the size of the pool mapping">
+       This request will cause the server to remap the backing memory
+       for the pool from the file descriptor passed when the pool was
+       created, but using the new size.  This request can only be
+       used to make the pool bigger.
+      </description>
+
+      <arg name="size" type="int"/>
+    </request>
+  </interface>
+
+  <interface name="wl_shm" version="1">
+    <description summary="shared memory support">
+      A global singleton object that provides support for shared
+      memory.
+
+      Clients can create wl_shm_pool objects using the create_pool
+      request.
+
+      At connection setup time, the wl_shm object emits one or more
+      format events to inform clients about the valid pixel formats
+      that can be used for buffers.
+    </description>
+
+    <enum name="error">
+      <description summary="wl_shm error values">
+       These errors can be emitted in response to wl_shm requests.
+      </description>
+      <entry name="invalid_format" value="0" summary="buffer format is not known"/>
+      <entry name="invalid_stride" value="1" summary="invalid size or stride during pool or buffer creation"/>
+      <entry name="invalid_fd" value="2" summary="mmapping the file descriptor failed"/>
+    </enum>
+
+    <enum name="format">
+      <description summary="pixel formats">
+       This describes the memory layout of an individual pixel.
+
+       All renderers should support argb8888 and xrgb8888 but any other
+       formats are optional and may not be supported by the particular
+       renderer in use.
+      </description>
+      <entry name="argb8888" value="0" summary="32-bit ARGB format"/>
+      <entry name="xrgb8888" value="1" summary="32-bit RGB format"/>
+      <!-- The drm format codes match the #defines in drm_fourcc.h.
+           The formats actually supported by the compositor will be
+           reported by the format event. -->
+      <entry name="c8" value="0x20203843"/>
+      <entry name="rgb332" value="0x38424752"/>
+      <entry name="bgr233" value="0x38524742"/>
+      <entry name="xrgb4444" value="0x32315258"/>
+      <entry name="xbgr4444" value="0x32314258"/>
+      <entry name="rgbx4444" value="0x32315852"/>
+      <entry name="bgrx4444" value="0x32315842"/>
+      <entry name="argb4444" value="0x32315241"/>
+      <entry name="abgr4444" value="0x32314241"/>
+      <entry name="rgba4444" value="0x32314152"/>
+      <entry name="bgra4444" value="0x32314142"/>
+      <entry name="xrgb1555" value="0x35315258"/>
+      <entry name="xbgr1555" value="0x35314258"/>
+      <entry name="rgbx5551" value="0x35315852"/>
+      <entry name="bgrx5551" value="0x35315842"/>
+      <entry name="argb1555" value="0x35315241"/>
+      <entry name="abgr1555" value="0x35314241"/>
+      <entry name="rgba5551" value="0x35314152"/>
+      <entry name="bgra5551" value="0x35314142"/>
+      <entry name="rgb565" value="0x36314752"/>
+      <entry name="bgr565" value="0x36314742"/>
+      <entry name="rgb888" value="0x34324752"/>
+      <entry name="bgr888" value="0x34324742"/>
+      <entry name="xbgr8888" value="0x34324258"/>
+      <entry name="rgbx8888" value="0x34325852"/>
+      <entry name="bgrx8888" value="0x34325842"/>
+      <entry name="abgr8888" value="0x34324241"/>
+      <entry name="rgba8888" value="0x34324152"/>
+      <entry name="bgra8888" value="0x34324142"/>
+      <entry name="xrgb2101010" value="0x30335258"/>
+      <entry name="xbgr2101010" value="0x30334258"/>
+      <entry name="rgbx1010102" value="0x30335852"/>
+      <entry name="bgrx1010102" value="0x30335842"/>
+      <entry name="argb2101010" value="0x30335241"/>
+      <entry name="abgr2101010" value="0x30334241"/>
+      <entry name="rgba1010102" value="0x30334152"/>
+      <entry name="bgra1010102" value="0x30334142"/>
+      <entry name="yuyv" value="0x56595559"/>
+      <entry name="yvyu" value="0x55595659"/>
+      <entry name="uyvy" value="0x59565955"/>
+      <entry name="vyuy" value="0x59555956"/>
+      <entry name="ayuv" value="0x56555941"/>
+      <entry name="nv12" value="0x3231564e"/>
+      <entry name="nv21" value="0x3132564e"/>
+      <entry name="nv16" value="0x3631564e"/>
+      <entry name="nv61" value="0x3136564e"/>
+      <entry name="yuv410" value="0x39565559"/>
+      <entry name="yvu410" value="0x39555659"/>
+      <entry name="yuv411" value="0x31315559"/>
+      <entry name="yvu411" value="0x31315659"/>
+      <entry name="yuv420" value="0x32315559"/>
+      <entry name="yvu420" value="0x32315659"/>
+      <entry name="yuv422" value="0x36315559"/>
+      <entry name="yvu422" value="0x36315659"/>
+      <entry name="yuv444" value="0x34325559"/>
+      <entry name="yvu444" value="0x34325659"/>
+    </enum>
+
+    <request name="create_pool">
+      <description summary="create a shm pool">
+       Create a new wl_shm_pool object.
+
+       The pool can be used to create shared memory based buffer
+       objects.  The server will mmap size bytes of the passed file
+        descriptor, to use as backing memory for the pool.
+      </description>
+
+      <arg name="id" type="new_id" interface="wl_shm_pool"/>
+      <arg name="fd" type="fd"/>
+      <arg name="size" type="int"/>
+    </request>
+
+    <event name="format">
+      <description summary="pixel format description">
+       Informs the client about a valid pixel format that
+       can be used for buffers. Known formats include
+       argb8888 and xrgb8888.
+      </description>
+      <arg name="format" type="uint"/>
+    </event>
+  </interface>
+
+  <interface name="wl_buffer" version="1">
+    <description summary="content for a wl_surface">
+      A buffer provides the content for a wl_surface. Buffers are
+      created through factory interfaces such as wl_drm, wl_shm or
+      similar. It has a width and a height and can be attached to a
+      wl_surface, but the mechanism by which a client provides and
+      updates the contents is defined by the buffer factory interface.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy a buffer">
+       Destroy a buffer. If and how you need to release the backing
+       storage is defined by the buffer factory interface.
+
+       For possible side-effects to a surface, see wl_surface.attach.
+      </description>
+    </request>
+
+    <event name="release">
+      <description summary="compositor releases buffer">
+       Sent when this wl_buffer is no longer used by the compositor.
+       The client is now free to re-use or destroy this buffer and its
+       backing storage.
+
+       If a client receives a release event before the frame callback
+       requested in the same wl_surface.commit that attaches this
+       wl_buffer to a surface, then the client is immediately free to
+       re-use the buffer and its backing storage, and does not need a
+       second buffer for the next surface content update. Typically
+       this is possible, when the compositor maintains a copy of the
+       wl_surface contents, e.g. as a GL texture. This is an important
+       optimization for GL(ES) compositors with wl_shm clients.
+      </description>
+    </event>
+  </interface>
+
+
+  <interface name="wl_data_offer" version="1">
+    <description summary="offer to transfer data">
+      A wl_data_offer represents a piece of data offered for transfer
+      by another client (the source client).  It is used by the
+      copy-and-paste and drag-and-drop mechanisms.  The offer
+      describes the different mime types that the data can be
+      converted to and provides the mechanism for transferring the
+      data directly from the source client.
+    </description>
+
+    <request name="accept">
+      <description summary="accept one of the offered mime types">
+       Indicate that the client can accept the given mime type, or
+       NULL for not accepted.
+
+       Used for feedback during drag-and-drop.
+      </description>
+
+      <arg name="serial" type="uint"/>
+      <arg name="mime_type" type="string" allow-null="true"/>
+    </request>
+
+    <request name="receive">
+      <description summary="request that the data is transferred">
+       To transfer the offered data, the client issues this request
+       and indicates the mime type it wants to receive.  The transfer
+       happens through the passed file descriptor (typically created
+       with the pipe system call).  The source client writes the data
+       in the mime type representation requested and then closes the
+       file descriptor.
+
+       The receiving client reads from the read end of the pipe until
+       EOF and then closes its end, at which point the transfer is
+       complete.
+      </description>
+      <arg name="mime_type" type="string"/>
+      <arg name="fd" type="fd"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy data offer">
+       Destroy the data offer.
+      </description>
+    </request>
+
+    <event name="offer">
+      <description summary="advertise offered mime type">
+       Sent immediately after creating the wl_data_offer object.  One
+       event per offered mime type.
+      </description>
+
+      <arg name="mime_type" type="string"/>
+    </event>
+  </interface>
+
+  <interface name="wl_data_source" version="1">
+    <description summary="offer to transfer data">
+      The wl_data_source object is the source side of a wl_data_offer.
+      It is created by the source client in a data transfer and
+      provides a way to describe the offered data and a way to respond
+      to requests to transfer the data.
+    </description>
+
+    <request name="offer">
+      <description summary="add an offered mime type">
+       This request adds a mime type to the set of mime types
+       advertised to targets.  Can be called several times to offer
+       multiple types.
+      </description>
+      <arg name="mime_type" type="string"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the data source">
+       Destroy the data source.
+      </description>
+    </request>
+
+    <event name="target">
+      <description summary="a target accepts an offered mime type">
+       Sent when a target accepts pointer_focus or motion events.  If
+       a target does not accept any of the offered types, type is NULL.
+
+       Used for feedback during drag-and-drop.
+      </description>
+
+      <arg name="mime_type" type="string" allow-null="true"/>
+    </event>
+
+    <event name="send">
+      <description summary="send the data">
+       Request for data from the client.  Send the data as the
+       specified mime type over the passed file descriptor, then
+       close it.
+      </description>
+
+      <arg name="mime_type" type="string"/>
+      <arg name="fd" type="fd"/>
+    </event>
+
+    <event name="cancelled">
+      <description summary="selection was cancelled">
+       This data source has been replaced by another data source.
+       The client should clean up and destroy this data source.
+      </description>
+    </event>
+
+  </interface>
+
+  <interface name="wl_data_device" version="2">
+    <description summary="data transfer device">
+      There is one wl_data_device per seat which can be obtained
+      from the global wl_data_device_manager singleton.
+
+      A wl_data_device provides access to inter-client data transfer
+      mechanisms such as copy-and-paste and drag-and-drop.
+    </description>
+
+    <enum name="error">
+      <entry name="role" value="0" summary="given wl_surface has another role"/>
+    </enum>
+
+    <request name="start_drag">
+      <description summary="start drag-and-drop operation">
+       This request asks the compositor to start a drag-and-drop
+       operation on behalf of the client.
+
+       The source argument is the data source that provides the data
+       for the eventual data transfer. If source is NULL, enter, leave
+       and motion events are sent only to the client that initiated the
+       drag and the client is expected to handle the data passing
+       internally.
+
+       The origin surface is the surface where the drag originates and
+       the client must have an active implicit grab that matches the
+       serial.
+
+       The icon surface is an optional (can be NULL) surface that
+       provides an icon to be moved around with the cursor.  Initially,
+       the top-left corner of the icon surface is placed at the cursor
+       hotspot, but subsequent wl_surface.attach request can move the
+       relative position. Attach requests must be confirmed with
+       wl_surface.commit as usual. The icon surface is given the role of
+       a drag-and-drop icon. If the icon surface already has another role,
+       it raises a protocol error.
+
+       The current and pending input regions of the icon wl_surface are
+       cleared, and wl_surface.set_input_region is ignored until the
+       wl_surface is no longer used as the icon surface. When the use
+       as an icon ends, the current and pending input regions become
+       undefined, and the wl_surface is unmapped.
+      </description>
+      <arg name="source" type="object" interface="wl_data_source" allow-null="true"/>
+      <arg name="origin" type="object" interface="wl_surface"/>
+      <arg name="icon" type="object" interface="wl_surface" allow-null="true"/>
+      <arg name="serial" type="uint" summary="serial of the implicit grab on the origin"/>
+    </request>
+
+    <request name="set_selection">
+      <description summary="copy data to the selection">
+       This request asks the compositor to set the selection
+       to the data from the source on behalf of the client.
+
+       To unset the selection, set the source to NULL.
+      </description>
+      <arg name="source" type="object" interface="wl_data_source" allow-null="true"/>
+      <arg name="serial" type="uint" summary="serial of the event that triggered this request"/>
+    </request>
+
+    <event name="data_offer">
+      <description summary="introduce a new wl_data_offer">
+       The data_offer event introduces a new wl_data_offer object,
+       which will subsequently be used in either the
+       data_device.enter event (for drag-and-drop) or the
+       data_device.selection event (for selections).  Immediately
+       following the data_device_data_offer event, the new data_offer
+       object will send out data_offer.offer events to describe the
+       mime types it offers.
+      </description>
+
+      <arg name="id" type="new_id" interface="wl_data_offer"/>
+    </event>
+
+    <event name="enter">
+      <description summary="initiate drag-and-drop session">
+       This event is sent when an active drag-and-drop pointer enters
+       a surface owned by the client.  The position of the pointer at
+       enter time is provided by the x and y arguments, in surface
+       local coordinates.
+      </description>
+
+      <arg name="serial" type="uint"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <arg name="x" type="fixed"/>
+      <arg name="y" type="fixed"/>
+      <arg name="id" type="object" interface="wl_data_offer" allow-null="true"/>
+    </event>
+
+    <event name="leave">
+      <description summary="end drag-and-drop session">
+       This event is sent when the drag-and-drop pointer leaves the
+       surface and the session ends.  The client must destroy the
+       wl_data_offer introduced at enter time at this point.
+      </description>
+    </event>
+
+    <event name="motion">
+      <description summary="drag-and-drop session motion">
+       This event is sent when the drag-and-drop pointer moves within
+       the currently focused surface. The new position of the pointer
+       is provided by the x and y arguments, in surface local
+       coordinates.
+      </description>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="x" type="fixed"/>
+      <arg name="y" type="fixed"/>
+    </event>
+
+    <event name="drop">
+      <description summary="end drag-and-drag session successfully">
+       The event is sent when a drag-and-drop operation is ended
+       because the implicit grab is removed.
+      </description>
+    </event>
+
+    <event name="selection">
+      <description summary="advertise new selection">
+       The selection event is sent out to notify the client of a new
+       wl_data_offer for the selection for this device.  The
+       data_device.data_offer and the data_offer.offer events are
+       sent out immediately before this event to introduce the data
+       offer object.  The selection event is sent to a client
+       immediately before receiving keyboard focus and when a new
+       selection is set while the client has keyboard focus.  The
+       data_offer is valid until a new data_offer or NULL is received
+       or until the client loses keyboard focus.  The client must
+       destroy the previous selection data_offer, if any, upon receiving
+       this event.
+      </description>
+      <arg name="id" type="object" interface="wl_data_offer" allow-null="true"/>
+    </event>
+
+    <!-- Version 2 additions -->
+
+    <request name="release" type="destructor" since="2">
+      <description summary="destroy data device">
+       This request destroys the data device.
+      </description>
+    </request>
+  </interface>
+
+  <interface name="wl_data_device_manager" version="2">
+    <description summary="data transfer interface">
+      The wl_data_device_manager is a singleton global object that
+      provides access to inter-client data transfer mechanisms such as
+      copy-and-paste and drag-and-drop.  These mechanisms are tied to
+      a wl_seat and this interface lets a client get a wl_data_device
+      corresponding to a wl_seat.
+    </description>
+
+    <request name="create_data_source">
+      <description summary="create a new data source">
+        Create a new data source.
+      </description>
+      <arg name="id" type="new_id" interface="wl_data_source"/>
+    </request>
+
+    <request name="get_data_device">
+      <description summary="create a new data device">
+        Create a new data device for a given seat.
+      </description>
+      <arg name="id" type="new_id" interface="wl_data_device"/>
+      <arg name="seat" type="object" interface="wl_seat"/>
+    </request>
+  </interface>
+
+  <interface name="wl_shell" version="1">
+    <description summary="create desktop-style surfaces">
+      This interface is implemented by servers that provide
+      desktop-style user interfaces.
+
+      It allows clients to associate a wl_shell_surface with
+      a basic surface.
+    </description>
+
+    <enum name="error">
+      <entry name="role" value="0" summary="given wl_surface has another role"/>
+    </enum>
+
+    <request name="get_shell_surface">
+      <description summary="create a shell surface from a surface">
+       Create a shell surface for an existing surface. This gives
+       the wl_surface the role of a shell surface. If the wl_surface
+       already has another role, it raises a protocol error.
+
+       Only one shell surface can be associated with a given surface.
+      </description>
+      <arg name="id" type="new_id" interface="wl_shell_surface"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </request>
+  </interface>
+
+  <interface name="wl_shell_surface" version="1">
+
+    <description summary="desktop-style metadata interface">
+      An interface that may be implemented by a wl_surface, for
+      implementations that provide a desktop-style user interface.
+
+      It provides requests to treat surfaces like toplevel, fullscreen
+      or popup windows, move, resize or maximize them, associate
+      metadata like title and class, etc.
+
+      On the server side the object is automatically destroyed when
+      the related wl_surface is destroyed.  On client side,
+      wl_shell_surface_destroy() must be called before destroying
+      the wl_surface object.
+    </description>
+
+    <request name="pong">
+      <description summary="respond to a ping event">
+       A client must respond to a ping event with a pong request or
+       the client may be deemed unresponsive.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the ping event"/>
+    </request>
+
+    <request name="move">
+      <description summary="start an interactive move">
+       Start a pointer-driven move of the surface.
+
+       This request must be used in response to a button press event.
+       The server may ignore move requests depending on the state of
+       the surface (e.g. fullscreen or maximized).
+      </description>
+      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/>
+      <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/>
+    </request>
+
+    <enum name="resize">
+      <description summary="edge values for resizing">
+       These values are used to indicate which edge of a surface
+       is being dragged in a resize operation. The server may
+       use this information to adapt its behavior, e.g. choose
+       an appropriate cursor image.
+      </description>
+      <entry name="none" value="0"/>
+      <entry name="top" value="1"/>
+      <entry name="bottom" value="2"/>
+      <entry name="left" value="4"/>
+      <entry name="top_left" value="5"/>
+      <entry name="bottom_left" value="6"/>
+      <entry name="right" value="8"/>
+      <entry name="top_right" value="9"/>
+      <entry name="bottom_right" value="10"/>
+    </enum>
+
+    <request name="resize">
+      <description summary="start an interactive resize">
+       Start a pointer-driven resizing of the surface.
+
+       This request must be used in response to a button press event.
+       The server may ignore resize requests depending on the state of
+       the surface (e.g. fullscreen or maximized).
+      </description>
+      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/>
+      <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/>
+      <arg name="edges" type="uint" summary="which edge or corner is being dragged"/>
+    </request>
+
+    <request name="set_toplevel">
+      <description summary="make the surface a toplevel surface">
+       Map the surface as a toplevel surface.
+
+       A toplevel surface is not fullscreen, maximized or transient.
+      </description>
+    </request>
+
+    <enum name="transient">
+      <description summary="details of transient behaviour">
+       These flags specify details of the expected behaviour
+       of transient surfaces. Used in the set_transient request.
+      </description>
+      <entry name="inactive" value="0x1" summary="do not set keyboard focus"/>
+    </enum>
+
+    <request name="set_transient">
+      <description summary="make the surface a transient surface">
+       Map the surface relative to an existing surface.
+
+       The x and y arguments specify the locations of the upper left
+       corner of the surface relative to the upper left corner of the
+       parent surface, in surface local coordinates.
+
+       The flags argument controls details of the transient behaviour.
+      </description>
+
+      <arg name="parent" type="object" interface="wl_surface"/>
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="flags" type="uint"/>
+    </request>
+
+    <enum name="fullscreen_method">
+      <description summary="different method to set the surface fullscreen">
+       Hints to indicate to the compositor how to deal with a conflict
+       between the dimensions of the surface and the dimensions of the
+       output. The compositor is free to ignore this parameter.
+      </description>
+      <entry name="default" value="0" summary="no preference, apply default policy"/>
+      <entry name="scale" value="1" summary="scale, preserve the surface's aspect ratio and center on output"/>
+      <entry name="driver" value="2" summary="switch output mode to the smallest mode that can fit the surface, add black borders to compensate size mismatch"/>
+      <entry name="fill" value="3" summary="no upscaling, center on output and add black borders to compensate size mismatch"/>
+    </enum>
+
+    <request name="set_fullscreen">
+      <description summary="make the surface a fullscreen surface">
+       Map the surface as a fullscreen surface.
+
+       If an output parameter is given then the surface will be made
+       fullscreen on that output. If the client does not specify the
+       output then the compositor will apply its policy - usually
+       choosing the output on which the surface has the biggest surface
+       area.
+
+       The client may specify a method to resolve a size conflict
+       between the output size and the surface size - this is provided
+       through the method parameter.
+
+       The framerate parameter is used only when the method is set
+       to "driver", to indicate the preferred framerate. A value of 0
+       indicates that the app does not care about framerate.  The
+       framerate is specified in mHz, that is framerate of 60000 is 60Hz.
+
+       A method of "scale" or "driver" implies a scaling operation of
+       the surface, either via a direct scaling operation or a change of
+       the output mode. This will override any kind of output scaling, so
+       that mapping a surface with a buffer size equal to the mode can
+       fill the screen independent of buffer_scale.
+
+       A method of "fill" means we don't scale up the buffer, however
+       any output scale is applied. This means that you may run into
+       an edge case where the application maps a buffer with the same
+       size of the output mode but buffer_scale 1 (thus making a
+       surface larger than the output). In this case it is allowed to
+       downscale the results to fit the screen.
+
+       The compositor must reply to this request with a configure event
+       with the dimensions for the output on which the surface will
+       be made fullscreen.
+      </description>
+      <arg name="method" type="uint"/>
+      <arg name="framerate" type="uint"/>
+      <arg name="output" type="object" interface="wl_output" allow-null="true"/>
+    </request>
+
+    <request name="set_popup">
+      <description summary="make the surface a popup surface">
+       Map the surface as a popup.
+
+       A popup surface is a transient surface with an added pointer
+       grab.
+
+       An existing implicit grab will be changed to owner-events mode,
+       and the popup grab will continue after the implicit grab ends
+       (i.e. releasing the mouse button does not cause the popup to
+       be unmapped).
+
+       The popup grab continues until the window is destroyed or a
+       mouse button is pressed in any other clients window. A click
+       in any of the clients surfaces is reported as normal, however,
+       clicks in other clients surfaces will be discarded and trigger
+       the callback.
+
+       The x and y arguments specify the locations of the upper left
+       corner of the surface relative to the upper left corner of the
+       parent surface, in surface local coordinates.
+      </description>
+
+      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/>
+      <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/>
+      <arg name="parent" type="object" interface="wl_surface"/>
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="flags" type="uint"/>
+    </request>
+
+    <request name="set_maximized">
+      <description summary="make the surface a maximized surface">
+       Map the surface as a maximized surface.
+
+       If an output parameter is given then the surface will be
+       maximized on that output. If the client does not specify the
+       output then the compositor will apply its policy - usually
+       choosing the output on which the surface has the biggest surface
+       area.
+
+       The compositor will reply with a configure event telling
+       the expected new surface size. The operation is completed
+       on the next buffer attach to this surface.
+
+       A maximized surface typically fills the entire output it is
+       bound to, except for desktop element such as panels. This is
+       the main difference between a maximized shell surface and a
+       fullscreen shell surface.
+
+       The details depend on the compositor implementation.
+      </description>
+      <arg name="output" type="object" interface="wl_output" allow-null="true"/>
+    </request>
+
+    <request name="set_title">
+      <description summary="set surface title">
+       Set a short title for the surface.
+
+       This string may be used to identify the surface in a task bar,
+       window list, or other user interface elements provided by the
+       compositor.
+
+       The string must be encoded in UTF-8.
+      </description>
+      <arg name="title" type="string"/>
+    </request>
+
+    <request name="set_class">
+      <description summary="set surface class">
+       Set a class for the surface.
+
+       The surface class identifies the general class of applications
+       to which the surface belongs. A common convention is to use the
+       file name (or the full path if it is a non-standard location) of
+       the application's .desktop file as the class.
+      </description>
+      <arg name="class_" type="string"/>
+    </request>
+
+    <event name="ping">
+      <description summary="ping client">
+       Ping a client to check if it is receiving events and sending
+       requests. A client is expected to reply with a pong request.
+      </description>
+      <arg name="serial" type="uint"/>
+    </event>
+
+    <event name="configure">
+      <description summary="suggest resize">
+       The configure event asks the client to resize its surface.
+
+       The size is a hint, in the sense that the client is free to
+       ignore it if it doesn't resize, pick a smaller size (to
+       satisfy aspect ratio or resize in steps of NxM pixels).
+
+       The edges parameter provides a hint about how the surface
+       was resized. The client may use this information to decide
+       how to adjust its content to the new size (e.g. a scrolling
+       area might adjust its content position to leave the viewable
+       content unmoved).
+
+       The client is free to dismiss all but the last configure
+       event it received.
+
+       The width and height arguments specify the size of the window
+       in surface local coordinates.
+      </description>
+
+      <arg name="edges" type="uint"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </event>
+
+    <event name="popup_done">
+      <description summary="popup interaction is done">
+       The popup_done event is sent out when a popup grab is broken,
+       that is, when the user clicks a surface that doesn't belong
+       to the client owning the popup surface.
+      </description>
+    </event>
+  </interface>
+
+  <interface name="wl_surface" version="3">
+    <description summary="an onscreen surface">
+      A surface is a rectangular area that is displayed on the screen.
+      It has a location, size and pixel contents.
+
+      The size of a surface (and relative positions on it) is described
+      in surface local coordinates, which may differ from the buffer
+      local coordinates of the pixel content, in case a buffer_transform
+      or a buffer_scale is used.
+
+      A surface without a "role" is fairly useless, a compositor does
+      not know where, when or how to present it. The role is the
+      purpose of a wl_surface. Examples of roles are a cursor for a
+      pointer (as set by wl_pointer.set_cursor), a drag icon
+      (wl_data_device.start_drag), a sub-surface
+      (wl_subcompositor.get_subsurface), and a window as defined by a
+      shell protocol (e.g. wl_shell.get_shell_surface).
+
+      A surface can have only one role at a time. Initially a
+      wl_surface does not have a role. Once a wl_surface is given a
+      role, it is set permanently for the whole lifetime of the
+      wl_surface object. Giving the current role again is allowed,
+      unless explicitly forbidden by the relevant interface
+      specification.
+
+      Surface roles are given by requests in other interfaces such as
+      wl_pointer.set_cursor. The request should explicitly mention
+      that this request gives a role to a wl_surface. Often, this
+      request also creates a new protocol object that represents the
+      role and adds additional functionality to wl_surface. When a
+      client wants to destroy a wl_surface, they must destroy this 'role
+      object' before the wl_surface.
+
+      Destroying the role object does not remove the role from the
+      wl_surface, but it may stop the wl_surface from "playing the role".
+      For instance, if a wl_subsurface object is destroyed, the wl_surface
+      it was created for will be unmapped and forget its position and
+      z-order. It is allowed to create a wl_subsurface for the same
+      wl_surface again, but it is not allowed to use the wl_surface as
+      a cursor (cursor is a different role than sub-surface, and role
+      switching is not allowed).
+    </description>
+
+    <enum name="error">
+      <description summary="wl_surface error values">
+        These errors can be emitted in response to wl_surface requests.
+      </description>
+      <entry name="invalid_scale" value="0" summary="buffer scale value is invalid"/>
+      <entry name="invalid_transform" value="1" summary="buffer transform value is invalid"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="delete surface">
+       Deletes the surface and invalidates its object ID.
+      </description>
+    </request>
+
+    <request name="attach">
+      <description summary="set the surface contents">
+       Set a buffer as the content of this surface.
+
+       The new size of the surface is calculated based on the buffer
+       size transformed by the inverse buffer_transform and the
+       inverse buffer_scale. This means that the supplied buffer
+       must be an integer multiple of the buffer_scale.
+
+       The x and y arguments specify the location of the new pending
+       buffer's upper left corner, relative to the current buffer's upper
+       left corner, in surface local coordinates. In other words, the
+       x and y, combined with the new surface size define in which
+       directions the surface's size changes.
+
+       Surface contents are double-buffered state, see wl_surface.commit.
+
+       The initial surface contents are void; there is no content.
+       wl_surface.attach assigns the given wl_buffer as the pending
+       wl_buffer. wl_surface.commit makes the pending wl_buffer the new
+       surface contents, and the size of the surface becomes the size
+       calculated from the wl_buffer, as described above. After commit,
+       there is no pending buffer until the next attach.
+
+       Committing a pending wl_buffer allows the compositor to read the
+       pixels in the wl_buffer. The compositor may access the pixels at
+       any time after the wl_surface.commit request. When the compositor
+       will not access the pixels anymore, it will send the
+       wl_buffer.release event. Only after receiving wl_buffer.release,
+       the client may re-use the wl_buffer. A wl_buffer that has been
+       attached and then replaced by another attach instead of committed
+       will not receive a release event, and is not used by the
+       compositor.
+
+       Destroying the wl_buffer after wl_buffer.release does not change
+       the surface contents. However, if the client destroys the
+       wl_buffer before receiving the wl_buffer.release event, the surface
+       contents become undefined immediately.
+
+       If wl_surface.attach is sent with a NULL wl_buffer, the
+       following wl_surface.commit will remove the surface content.
+      </description>
+
+      <arg name="buffer" type="object" interface="wl_buffer" allow-null="true"/>
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+    </request>
+
+    <request name="damage">
+      <description summary="mark part of the surface damaged">
+       This request is used to describe the regions where the pending
+       buffer is different from the current surface contents, and where
+       the surface therefore needs to be repainted. The pending buffer
+       must be set by wl_surface.attach before sending damage. The
+       compositor ignores the parts of the damage that fall outside of
+       the surface.
+
+       Damage is double-buffered state, see wl_surface.commit.
+
+       The damage rectangle is specified in surface local coordinates.
+
+       The initial value for pending damage is empty: no damage.
+       wl_surface.damage adds pending damage: the new pending damage
+       is the union of old pending damage and the given rectangle.
+
+       wl_surface.commit assigns pending damage as the current damage,
+       and clears pending damage. The server will clear the current
+       damage as it repaints the surface.
+      </description>
+
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+
+    <request name="frame">
+      <description summary="request a frame throttling hint">
+       Request a notification when it is a good time start drawing a new
+       frame, by creating a frame callback. This is useful for throttling
+       redrawing operations, and driving animations.
+
+       When a client is animating on a wl_surface, it can use the 'frame'
+       request to get notified when it is a good time to draw and commit the
+       next frame of animation. If the client commits an update earlier than
+       that, it is likely that some updates will not make it to the display,
+       and the client is wasting resources by drawing too often.
+
+       The frame request will take effect on the next wl_surface.commit.
+       The notification will only be posted for one frame unless
+       requested again. For a wl_surface, the notifications are posted in
+       the order the frame requests were committed.
+
+       The server must send the notifications so that a client
+       will not send excessive updates, while still allowing
+       the highest possible update rate for clients that wait for the reply
+       before drawing again. The server should give some time for the client
+       to draw and commit after sending the frame callback events to let them
+       hit the next output refresh.
+
+       A server should avoid signalling the frame callbacks if the
+       surface is not visible in any way, e.g. the surface is off-screen,
+       or completely obscured by other opaque surfaces.
+
+       The object returned by this request will be destroyed by the
+       compositor after the callback is fired and as such the client must not
+       attempt to use it after that point.
+
+       The callback_data passed in the callback is the current time, in
+       milliseconds, with an undefined base.
+      </description>
+
+      <arg name="callback" type="new_id" interface="wl_callback"/>
+    </request>
+
+    <request name="set_opaque_region">
+      <description summary="set opaque region">
+       This request sets the region of the surface that contains
+       opaque content.
+
+       The opaque region is an optimization hint for the compositor
+       that lets it optimize out redrawing of content behind opaque
+       regions.  Setting an opaque region is not required for correct
+       behaviour, but marking transparent content as opaque will result
+       in repaint artifacts.
+
+       The opaque region is specified in surface local coordinates.
+
+       The compositor ignores the parts of the opaque region that fall
+       outside of the surface.
+
+       Opaque region is double-buffered state, see wl_surface.commit.
+
+       wl_surface.set_opaque_region changes the pending opaque region.
+       wl_surface.commit copies the pending region to the current region.
+       Otherwise, the pending and current regions are never changed.
+
+       The initial value for opaque region is empty. Setting the pending
+       opaque region has copy semantics, and the wl_region object can be
+       destroyed immediately. A NULL wl_region causes the pending opaque
+       region to be set to empty.
+      </description>
+
+      <arg name="region" type="object" interface="wl_region" allow-null="true"/>
+    </request>
+
+    <request name="set_input_region">
+      <description summary="set input region">
+       This request sets the region of the surface that can receive
+       pointer and touch events.
+
+       Input events happening outside of this region will try the next
+       surface in the server surface stack. The compositor ignores the
+       parts of the input region that fall outside of the surface.
+
+       The input region is specified in surface local coordinates.
+
+       Input region is double-buffered state, see wl_surface.commit.
+
+       wl_surface.set_input_region changes the pending input region.
+       wl_surface.commit copies the pending region to the current region.
+       Otherwise the pending and current regions are never changed,
+       except cursor and icon surfaces are special cases, see
+       wl_pointer.set_cursor and wl_data_device.start_drag.
+
+       The initial value for input region is infinite. That means the
+       whole surface will accept input. Setting the pending input region
+       has copy semantics, and the wl_region object can be destroyed
+       immediately. A NULL wl_region causes the input region to be set
+       to infinite.
+      </description>
+
+      <arg name="region" type="object" interface="wl_region" allow-null="true"/>
+    </request>
+
+    <request name="commit">
+      <description summary="commit pending surface state">
+       Surface state (input, opaque, and damage regions, attached buffers,
+       etc.) is double-buffered. Protocol requests modify the pending
+       state, as opposed to current state in use by the compositor. Commit
+       request atomically applies all pending state, replacing the current
+       state. After commit, the new pending state is as documented for each
+       related request.
+
+       On commit, a pending wl_buffer is applied first, all other state
+       second. This means that all coordinates in double-buffered state are
+       relative to the new wl_buffer coming into use, except for
+       wl_surface.attach itself. If there is no pending wl_buffer, the
+       coordinates are relative to the current surface contents.
+
+       All requests that need a commit to become effective are documented
+       to affect double-buffered state.
+
+       Other interfaces may add further double-buffered surface state.
+      </description>
+    </request>
+
+    <event name="enter">
+      <description summary="surface enters an output">
+       This is emitted whenever a surface's creation, movement, or resizing
+       results in some part of it being within the scanout region of an
+       output.
+
+       Note that a surface may be overlapping with zero or more outputs.
+      </description>
+      <arg name="output" type="object" interface="wl_output"/>
+    </event>
+
+    <event name="leave">
+      <description summary="surface leaves an output">
+       This is emitted whenever a surface's creation, movement, or resizing
+       results in it no longer having any part of it within the scanout region
+       of an output.
+      </description>
+      <arg name="output" type="object" interface="wl_output"/>
+    </event>
+
+    <!-- Version 2 additions -->
+
+    <request name="set_buffer_transform" since="2">
+      <description summary="sets the buffer transformation">
+       This request sets an optional transformation on how the compositor
+       interprets the contents of the buffer attached to the surface. The
+       accepted values for the transform parameter are the values for
+       wl_output.transform.
+
+       Buffer transform is double-buffered state, see wl_surface.commit.
+
+       A newly created surface has its buffer transformation set to normal.
+
+       wl_surface.set_buffer_transform changes the pending buffer
+       transformation. wl_surface.commit copies the pending buffer
+       transformation to the current one. Otherwise, the pending and current
+       values are never changed.
+
+       The purpose of this request is to allow clients to render content
+       according to the output transform, thus permiting the compositor to
+       use certain optimizations even if the display is rotated. Using
+       hardware overlays and scanning out a client buffer for fullscreen
+       surfaces are examples of such optimizations. Those optimizations are
+       highly dependent on the compositor implementation, so the use of this
+       request should be considered on a case-by-case basis.
+
+       Note that if the transform value includes 90 or 270 degree rotation,
+       the width of the buffer will become the surface height and the height
+       of the buffer will become the surface width.
+
+       If transform is not one of the values from the
+       wl_output.transform enum the invalid_transform protocol error
+       is raised.
+      </description>
+      <arg name="transform" type="int"/>
+    </request>
+
+    <!-- Version 3 additions -->
+
+    <request name="set_buffer_scale" since="3">
+      <description summary="sets the buffer scaling factor">
+       This request sets an optional scaling factor on how the compositor
+       interprets the contents of the buffer attached to the window.
+
+       Buffer scale is double-buffered state, see wl_surface.commit.
+
+       A newly created surface has its buffer scale set to 1.
+
+       wl_surface.set_buffer_scale changes the pending buffer scale.
+       wl_surface.commit copies the pending buffer scale to the current one.
+       Otherwise, the pending and current values are never changed.
+
+       The purpose of this request is to allow clients to supply higher
+       resolution buffer data for use on high resolution outputs. Its
+       intended that you pick the same buffer scale as the scale of the
+       output that the surface is displayed on.This means the compositor
+       can avoid scaling when rendering the surface on that output.
+
+       Note that if the scale is larger than 1, then you have to attach
+       a buffer that is larger (by a factor of scale in each dimension)
+       than the desired surface size.
+
+       If scale is not positive the invalid_scale protocol error is
+       raised.
+      </description>
+      <arg name="scale" type="int"/>
+    </request>
+   </interface>
+
+  <interface name="wl_seat" version="4">
+    <description summary="group of input devices">
+      A seat is a group of keyboards, pointer and touch devices. This
+      object is published as a global during start up, or when such a
+      device is hot plugged.  A seat typically has a pointer and
+      maintains a keyboard focus and a pointer focus.
+    </description>
+
+    <enum name="capability">
+      <description summary="seat capability bitmask">
+        This is a bitmask of capabilities this seat has; if a member is
+        set, then it is present on the seat.
+      </description>
+      <entry name="pointer" value="1" summary="The seat has pointer devices"/>
+      <entry name="keyboard" value="2" summary="The seat has one or more keyboards"/>
+      <entry name="touch" value="4" summary="The seat has touch devices"/>
+    </enum>
+
+    <event name="capabilities">
+      <description summary="seat capabilities changed">
+        This is emitted whenever a seat gains or loses the pointer,
+       keyboard or touch capabilities.  The argument is a capability
+       enum containing the complete set of capabilities this seat has.
+      </description>
+      <arg name="capabilities" type="uint"/>
+    </event>
+
+    <request name="get_pointer">
+      <description summary="return pointer object">
+        The ID provided will be initialized to the wl_pointer interface
+       for this seat.
+
+        This request only takes effect if the seat has the pointer
+        capability.
+      </description>
+      <arg name="id" type="new_id" interface="wl_pointer"/>
+    </request>
+
+    <request name="get_keyboard">
+      <description summary="return keyboard object">
+        The ID provided will be initialized to the wl_keyboard interface
+       for this seat.
+
+        This request only takes effect if the seat has the keyboard
+        capability.
+      </description>
+      <arg name="id" type="new_id" interface="wl_keyboard"/>
+    </request>
+
+    <request name="get_touch">
+      <description summary="return touch object">
+        The ID provided will be initialized to the wl_touch interface
+       for this seat.
+
+        This request only takes effect if the seat has the touch
+        capability.
+      </description>
+      <arg name="id" type="new_id" interface="wl_touch"/>
+    </request>
+
+    <!-- Version 2 of additions -->
+
+    <event name="name" since="2">
+      <description summary="unique identifier for this seat">
+       In a multiseat configuration this can be used by the client to help
+       identify which physical devices the seat represents. Based on
+       the seat configuration used by the compositor.
+      </description>
+      <arg name="name" type="string"/>
+    </event>
+
+  </interface>
+
+  <interface name="wl_pointer" version="3">
+    <description summary="pointer input device">
+      The wl_pointer interface represents one or more input devices,
+      such as mice, which control the pointer location and pointer_focus
+      of a seat.
+
+      The wl_pointer interface generates motion, enter and leave
+      events for the surfaces that the pointer is located over,
+      and button and axis events for button presses, button releases
+      and scrolling.
+    </description>
+
+    <enum name="error">
+      <entry name="role" value="0" summary="given wl_surface has another role"/>
+    </enum>
+
+    <request name="set_cursor">
+      <description summary="set the pointer surface">
+       Set the pointer surface, i.e., the surface that contains the
+       pointer image (cursor). This request gives the surface the role
+       of a cursor. If the surface already has another role, it raises
+       a protocol error.
+
+       The cursor actually changes only if the pointer
+       focus for this device is one of the requesting client's surfaces
+       or the surface parameter is the current pointer surface. If
+       there was a previous surface set with this request it is
+       replaced. If surface is NULL, the pointer image is hidden.
+
+       The parameters hotspot_x and hotspot_y define the position of
+       the pointer surface relative to the pointer location. Its
+       top-left corner is always at (x, y) - (hotspot_x, hotspot_y),
+       where (x, y) are the coordinates of the pointer location, in surface
+       local coordinates.
+
+       On surface.attach requests to the pointer surface, hotspot_x
+       and hotspot_y are decremented by the x and y parameters
+       passed to the request. Attach must be confirmed by
+       wl_surface.commit as usual.
+
+       The hotspot can also be updated by passing the currently set
+       pointer surface to this request with new values for hotspot_x
+       and hotspot_y.
+
+       The current and pending input regions of the wl_surface are
+       cleared, and wl_surface.set_input_region is ignored until the
+       wl_surface is no longer used as the cursor. When the use as a
+       cursor ends, the current and pending input regions become
+       undefined, and the wl_surface is unmapped.
+      </description>
+
+      <arg name="serial" type="uint" summary="serial of the enter event"/>
+      <arg name="surface" type="object" interface="wl_surface" allow-null="true"/>
+      <arg name="hotspot_x" type="int" summary="x coordinate in surface-relative coordinates"/>
+      <arg name="hotspot_y" type="int" summary="y coordinate in surface-relative coordinates"/>
+    </request>
+
+    <event name="enter">
+      <description summary="enter event">
+       Notification that this seat's pointer is focused on a certain
+       surface.
+
+       When an seat's focus enters a surface, the pointer image
+       is undefined and a client should respond to this event by setting
+       an appropriate pointer image with the set_cursor request.
+      </description>
+
+      <arg name="serial" type="uint"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <arg name="surface_x" type="fixed" summary="x coordinate in surface-relative coordinates"/>
+      <arg name="surface_y" type="fixed" summary="y coordinate in surface-relative coordinates"/>
+    </event>
+
+    <event name="leave">
+      <description summary="leave event">
+       Notification that this seat's pointer is no longer focused on
+       a certain surface.
+
+       The leave notification is sent before the enter notification
+       for the new focus.
+      </description>
+      <arg name="serial" type="uint"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </event>
+
+    <event name="motion">
+      <description summary="pointer motion event">
+       Notification of pointer location change. The arguments
+       surface_x and surface_y are the location relative to the
+       focused surface.
+      </description>
+
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="surface_x" type="fixed" summary="x coordinate in surface-relative coordinates"/>
+      <arg name="surface_y" type="fixed" summary="y coordinate in surface-relative coordinates"/>
+    </event>
+
+    <enum name="button_state">
+      <description summary="physical button state">
+        Describes the physical state of a button which provoked the button
+       event.
+      </description>
+      <entry name="released" value="0" summary="The button is not pressed"/>
+      <entry name="pressed" value="1" summary="The button is pressed"/>
+    </enum>
+
+    <event name="button">
+      <description summary="pointer button event">
+       Mouse button click and release notifications.
+
+       The location of the click is given by the last motion or
+       enter event.
+        The time argument is a timestamp with millisecond
+        granularity, with an undefined base.
+      </description>
+
+      <arg name="serial" type="uint"/>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="button" type="uint"/>
+      <arg name="state" type="uint"/>
+    </event>
+
+    <enum name="axis">
+      <description summary="axis types">
+       Describes the axis types of scroll events.
+      </description>
+      <entry name="vertical_scroll" value="0"/>
+      <entry name="horizontal_scroll" value="1"/>
+    </enum>
+
+    <event name="axis">
+      <description summary="axis event">
+       Scroll and other axis notifications.
+
+       For scroll events (vertical and horizontal scroll axes), the
+       value parameter is the length of a vector along the specified
+       axis in a coordinate space identical to those of motion events,
+       representing a relative movement along the specified axis.
+
+       For devices that support movements non-parallel to axes multiple
+       axis events will be emitted.
+
+       When applicable, for example for touch pads, the server can
+       choose to emit scroll events where the motion vector is
+       equivalent to a motion event vector.
+
+       When applicable, clients can transform its view relative to the
+       scroll distance.
+      </description>
+
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="axis" type="uint"/>
+      <arg name="value" type="fixed"/>
+    </event>
+
+    <!-- Version 3 additions -->
+
+    <request name="release" type="destructor" since="3">
+      <description summary="release the pointer object"/>
+    </request>
+
+  </interface>
+
+  <interface name="wl_keyboard" version="4">
+    <description summary="keyboard input device">
+      The wl_keyboard interface represents one or more keyboards
+      associated with a seat.
+    </description>
+
+    <enum name="keymap_format">
+      <description summary="keyboard mapping format">
+       This specifies the format of the keymap provided to the
+       client with the wl_keyboard.keymap event.
+      </description>
+      <entry name="no_keymap" value="0"
+            summary="no keymap; client must understand how to interpret the raw keycode"/>
+      <entry name="xkb_v1" value="1"
+             summary="libxkbcommon compatible; to determine the xkb keycode, clients must add 8 to the key event keycode"/>
+    </enum>
+
+    <event name="keymap">
+      <description summary="keyboard mapping">
+       This event provides a file descriptor to the client which can be
+       memory-mapped to provide a keyboard mapping description.
+      </description>
+      <arg name="format" type="uint"/>
+      <arg name="fd" type="fd"/>
+      <arg name="size" type="uint"/>
+    </event>
+
+    <event name="enter">
+      <description summary="enter event">
+       Notification that this seat's keyboard focus is on a certain
+       surface.
+      </description>
+      <arg name="serial" type="uint"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <arg name="keys" type="array" summary="the currently pressed keys"/>
+    </event>
+
+    <event name="leave">
+      <description summary="leave event">
+       Notification that this seat's keyboard focus is no longer on
+       a certain surface.
+
+       The leave notification is sent before the enter notification
+       for the new focus.
+      </description>
+      <arg name="serial" type="uint"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </event>
+
+    <enum name="key_state">
+      <description summary="physical key state">
+       Describes the physical state of a key which provoked the key event.
+      </description>
+      <entry name="released" value="0" summary="key is not pressed"/>
+      <entry name="pressed" value="1" summary="key is pressed"/>
+    </enum>
+
+    <event name="key">
+      <description summary="key event">
+       A key was pressed or released.
+        The time argument is a timestamp with millisecond
+        granularity, with an undefined base.
+      </description>
+
+      <arg name="serial" type="uint"/>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="key" type="uint"/>
+      <arg name="state" type="uint"/>
+    </event>
+
+    <event name="modifiers">
+      <description summary="modifier and group state">
+       Notifies clients that the modifier and/or group state has
+       changed, and it should update its local state.
+      </description>
+
+      <arg name="serial" type="uint"/>
+      <arg name="mods_depressed" type="uint"/>
+      <arg name="mods_latched" type="uint"/>
+      <arg name="mods_locked" type="uint"/>
+      <arg name="group" type="uint"/>
+    </event>
+
+    <!-- Version 3 additions -->
+
+    <request name="release" type="destructor" since="3">
+      <description summary="release the keyboard object"/>
+    </request>
+
+    <!-- Version 4 additions -->
+
+    <event name="repeat_info" since="4">
+      <description summary="repeat rate and delay">
+        Informs the client about the keyboard's repeat rate and delay.
+
+        This event is sent as soon as the wl_keyboard object has been created,
+        and is guaranteed to be received by the client before any key press
+        event.
+
+        Negative values for either rate or delay are illegal. A rate of zero
+        will disable any repeating (regardless of the value of delay).
+
+        This event can be sent later on as well with a new value if necessary,
+        so clients should continue listening for the event past the creation
+        of wl_keyboard.
+      </description>
+
+      <arg name="rate" type="int"
+           summary="the rate of repeating keys in characters per second"/>
+      <arg name="delay" type="int"
+           summary="delay in milliseconds since key down until repeating starts"/>
+    </event>
+  </interface>
+
+  <interface name="wl_touch" version="3">
+    <description summary="touchscreen input device">
+      The wl_touch interface represents a touchscreen
+      associated with a seat.
+
+      Touch interactions can consist of one or more contacts.
+      For each contact, a series of events is generated, starting
+      with a down event, followed by zero or more motion events,
+      and ending with an up event. Events relating to the same
+      contact point can be identified by the ID of the sequence.
+    </description>
+
+    <event name="down">
+      <description summary="touch down event and beginning of a touch sequence">
+       A new touch point has appeared on the surface. This touch point is
+       assigned a unique @id. Future events from this touchpoint reference
+       this ID. The ID ceases to be valid after a touch up event and may be
+       re-used in the future.
+      </description>
+      <arg name="serial" type="uint"/>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <arg name="id" type="int" summary="the unique ID of this touch point"/>
+      <arg name="x" type="fixed" summary="x coordinate in surface-relative coordinates"/>
+      <arg name="y" type="fixed" summary="y coordinate in surface-relative coordinates"/>
+    </event>
+
+    <event name="up">
+      <description summary="end of a touch event sequence">
+       The touch point has disappeared. No further events will be sent for
+       this touchpoint and the touch point's ID is released and may be
+       re-used in a future touch down event.
+      </description>
+      <arg name="serial" type="uint"/>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="id" type="int" summary="the unique ID of this touch point"/>
+    </event>
+
+    <event name="motion">
+      <description summary="update of touch point coordinates">
+       A touchpoint has changed coordinates.
+      </description>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="id" type="int" summary="the unique ID of this touch point"/>
+      <arg name="x" type="fixed" summary="x coordinate in surface-relative coordinates"/>
+      <arg name="y" type="fixed" summary="y coordinate in surface-relative coordinates"/>
+    </event>
+
+    <event name="frame">
+      <description summary="end of touch frame event">
+       Indicates the end of a contact point list.
+      </description>
+    </event>
+
+    <event name="cancel">
+      <description summary="touch session cancelled">
+       Sent if the compositor decides the touch stream is a global
+       gesture. No further events are sent to the clients from that
+       particular gesture. Touch cancellation applies to all touch points
+       currently active on this client's surface. The client is
+       responsible for finalizing the touch points, future touch points on
+       this surface may re-use the touch point ID.
+      </description>
+    </event>
+
+    <!-- Version 3 additions -->
+
+    <request name="release" type="destructor" since="3">
+      <description summary="release the touch object"/>
+    </request>
+  </interface>
+
+  <interface name="wl_output" version="2">
+    <description summary="compositor output region">
+      An output describes part of the compositor geometry.  The
+      compositor works in the 'compositor coordinate system' and an
+      output corresponds to rectangular area in that space that is
+      actually visible.  This typically corresponds to a monitor that
+      displays part of the compositor space.  This object is published
+      as global during start up, or when a monitor is hotplugged.
+    </description>
+
+    <enum name="subpixel">
+      <description summary="subpixel geometry information">
+       This enumeration describes how the physical
+       pixels on an output are layed out.
+      </description>
+      <entry name="unknown" value="0"/>
+      <entry name="none" value="1"/>
+      <entry name="horizontal_rgb" value="2"/>
+      <entry name="horizontal_bgr" value="3"/>
+      <entry name="vertical_rgb" value="4"/>
+      <entry name="vertical_bgr" value="5"/>
+    </enum>
+
+    <enum name="transform">
+      <description summary="transform from framebuffer to output">
+       This describes the transform that a compositor will apply to a
+       surface to compensate for the rotation or mirroring of an
+       output device.
+
+       The flipped values correspond to an initial flip around a
+       vertical axis followed by rotation.
+
+       The purpose is mainly to allow clients render accordingly and
+       tell the compositor, so that for fullscreen surfaces, the
+       compositor will still be able to scan out directly from client
+       surfaces.
+      </description>
+
+      <entry name="normal" value="0"/>
+      <entry name="90" value="1"/>
+      <entry name="180" value="2"/>
+      <entry name="270" value="3"/>
+      <entry name="flipped" value="4"/>
+      <entry name="flipped_90" value="5"/>
+      <entry name="flipped_180" value="6"/>
+      <entry name="flipped_270" value="7"/>
+    </enum>
+
+    <event name="geometry">
+      <description summary="properties of the output">
+       The geometry event describes geometric properties of the output.
+       The event is sent when binding to the output object and whenever
+       any of the properties change.
+      </description>
+      <arg name="x" type="int"
+          summary="x position within the global compositor space"/>
+      <arg name="y" type="int"
+          summary="y position within the global compositor space"/>
+      <arg name="physical_width" type="int"
+          summary="width in millimeters of the output"/>
+      <arg name="physical_height" type="int"
+          summary="height in millimeters of the output"/>
+      <arg name="subpixel" type="int"
+          summary="subpixel orientation of the output"/>
+      <arg name="make" type="string"
+          summary="textual description of the manufacturer"/>
+      <arg name="model" type="string"
+          summary="textual description of the model"/>
+      <arg name="transform" type="int"
+          summary="transform that maps framebuffer to output"/>
+    </event>
+
+    <enum name="mode">
+      <description summary="mode information">
+       These flags describe properties of an output mode.
+       They are used in the flags bitfield of the mode event.
+      </description>
+      <entry name="current" value="0x1"
+            summary="indicates this is the current mode"/>
+      <entry name="preferred" value="0x2"
+            summary="indicates this is the preferred mode"/>
+    </enum>
+
+    <event name="mode">
+      <description summary="advertise available modes for the output">
+       The mode event describes an available mode for the output.
+
+       The event is sent when binding to the output object and there
+       will always be one mode, the current mode.  The event is sent
+       again if an output changes mode, for the mode that is now
+       current.  In other words, the current mode is always the last
+       mode that was received with the current flag set.
+
+       The size of a mode is given in physical hardware units of
+        the output device. This is not necessarily the same as
+        the output size in the global compositor space. For instance,
+        the output may be scaled, as described in wl_output.scale,
+        or transformed , as described in wl_output.transform.
+      </description>
+      <arg name="flags" type="uint" summary="bitfield of mode flags"/>
+      <arg name="width" type="int" summary="width of the mode in hardware units"/>
+      <arg name="height" type="int" summary="height of the mode in hardware units"/>
+      <arg name="refresh" type="int" summary="vertical refresh rate in mHz"/>
+    </event>
+
+    <event name="done" since="2">
+      <description summary="sent all information about output">
+        This event is sent after all other properties has been
+        sent after binding to the output object and after any
+        other property changes done after that. This allows
+        changes to the output properties to be seen as
+        atomic, even if they happen via multiple events.
+      </description>
+    </event>
+
+    <event name="scale" since="2">
+      <description summary="output scaling properties">
+       This event contains scaling geometry information
+        that is not in the geometry event. It may be sent after
+        binding the output object or if the output scale changes
+        later. If it is not sent, the client should assume a
+       scale of 1.
+
+       A scale larger than 1 means that the compositor will
+       automatically scale surface buffers by this amount
+       when rendering. This is used for very high resolution
+       displays where applications rendering at the native
+       resolution would be too small to be legible.
+
+       It is intended that scaling aware clients track the
+       current output of a surface, and if it is on a scaled
+       output it should use wl_surface.set_buffer_scale with
+       the scale of the output. That way the compositor can
+       avoid scaling the surface, and the client can supply
+       a higher detail image.
+      </description>
+      <arg name="factor" type="int" summary="scaling factor of output"/>
+    </event>
+
+  </interface>
+
+  <interface name="wl_region" version="1">
+    <description summary="region interface">
+      A region object describes an area.
+
+      Region objects are used to describe the opaque and input
+      regions of a surface.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy region">
+       Destroy the region.  This will invalidate the object ID.
+      </description>
+    </request>
+
+    <request name="add">
+      <description summary="add rectangle to region">
+       Add the specified rectangle to the region.
+      </description>
+
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+
+    <request name="subtract">
+      <description summary="subtract rectangle from region">
+       Subtract the specified rectangle from the region.
+      </description>
+
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+
+  </interface>
+
+  <interface name="wl_subcompositor" version="1">
+    <description summary="sub-surface compositing">
+      The global interface exposing sub-surface compositing capabilities.
+      A wl_surface, that has sub-surfaces associated, is called the
+      parent surface. Sub-surfaces can be arbitrarily nested and create
+      a tree of sub-surfaces.
+
+      The root surface in a tree of sub-surfaces is the main
+      surface. The main surface cannot be a sub-surface, because
+      sub-surfaces must always have a parent.
+
+      A main surface with its sub-surfaces forms a (compound) window.
+      For window management purposes, this set of wl_surface objects is
+      to be considered as a single window, and it should also behave as
+      such.
+
+      The aim of sub-surfaces is to offload some of the compositing work
+      within a window from clients to the compositor. A prime example is
+      a video player with decorations and video in separate wl_surface
+      objects. This should allow the compositor to pass YUV video buffer
+      processing to dedicated overlay hardware when possible.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="unbind from the subcompositor interface">
+       Informs the server that the client will not be using this
+       protocol object anymore. This does not affect any other
+       objects, wl_subsurface objects included.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="bad_surface" value="0"
+             summary="the to-be sub-surface is invalid"/>
+    </enum>
+
+    <request name="get_subsurface">
+      <description summary="give a surface the role sub-surface">
+       Create a sub-surface interface for the given surface, and
+       associate it with the given parent surface. This turns a
+       plain wl_surface into a sub-surface.
+
+       The to-be sub-surface must not already have another role, and it
+       must not have an existing wl_subsurface object. Otherwise a protocol
+       error is raised.
+      </description>
+
+      <arg name="id" type="new_id" interface="wl_subsurface"
+           summary="the new subsurface object id"/>
+      <arg name="surface" type="object" interface="wl_surface"
+           summary="the surface to be turned into a sub-surface"/>
+      <arg name="parent" type="object" interface="wl_surface"
+           summary="the parent surface"/>
+    </request>
+  </interface>
+
+  <interface name="wl_subsurface" version="1">
+    <description summary="sub-surface interface to a wl_surface">
+      An additional interface to a wl_surface object, which has been
+      made a sub-surface. A sub-surface has one parent surface. A
+      sub-surface's size and position are not limited to that of the parent.
+      Particularly, a sub-surface is not automatically clipped to its
+      parent's area.
+
+      A sub-surface becomes mapped, when a non-NULL wl_buffer is applied
+      and the parent surface is mapped. The order of which one happens
+      first is irrelevant. A sub-surface is hidden if the parent becomes
+      hidden, or if a NULL wl_buffer is applied. These rules apply
+      recursively through the tree of surfaces.
+
+      The behaviour of wl_surface.commit request on a sub-surface
+      depends on the sub-surface's mode. The possible modes are
+      synchronized and desynchronized, see methods
+      wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized
+      mode caches the wl_surface state to be applied when the parent's
+      state gets applied, and desynchronized mode applies the pending
+      wl_surface state directly. A sub-surface is initially in the
+      synchronized mode.
+
+      Sub-surfaces have also other kind of state, which is managed by
+      wl_subsurface requests, as opposed to wl_surface requests. This
+      state includes the sub-surface position relative to the parent
+      surface (wl_subsurface.set_position), and the stacking order of
+      the parent and its sub-surfaces (wl_subsurface.place_above and
+      .place_below). This state is applied when the parent surface's
+      wl_surface state is applied, regardless of the sub-surface's mode.
+      As the exception, set_sync and set_desync are effective immediately.
+
+      The main surface can be thought to be always in desynchronized mode,
+      since it does not have a parent in the sub-surfaces sense.
+
+      Even if a sub-surface is in desynchronized mode, it will behave as
+      in synchronized mode, if its parent surface behaves as in
+      synchronized mode. This rule is applied recursively throughout the
+      tree of surfaces. This means, that one can set a sub-surface into
+      synchronized mode, and then assume that all its child and grand-child
+      sub-surfaces are synchronized, too, without explicitly setting them.
+
+      If the wl_surface associated with the wl_subsurface is destroyed, the
+      wl_subsurface object becomes inert. Note, that destroying either object
+      takes effect immediately. If you need to synchronize the removal
+      of a sub-surface to the parent surface update, unmap the sub-surface
+      first by attaching a NULL wl_buffer, update parent, and then destroy
+      the sub-surface.
+
+      If the parent wl_surface object is destroyed, the sub-surface is
+      unmapped.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="remove sub-surface interface">
+       The sub-surface interface is removed from the wl_surface object
+       that was turned into a sub-surface with
+       wl_subcompositor.get_subsurface request. The wl_surface's association
+       to the parent is deleted, and the wl_surface loses its role as
+       a sub-surface. The wl_surface is unmapped.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="bad_surface" value="0"
+             summary="wl_surface is not a sibling or the parent"/>
+    </enum>
+
+    <request name="set_position">
+      <description summary="reposition the sub-surface">
+       This schedules a sub-surface position change.
+       The sub-surface will be moved so, that its origin (top-left
+       corner pixel) will be at the location x, y of the parent surface
+       coordinate system. The coordinates are not restricted to the parent
+       surface area. Negative values are allowed.
+
+       The next wl_surface.commit on the parent surface will reset
+       the sub-surface's position to the scheduled coordinates.
+
+       If more than one set_position request is invoked by the client before
+       the commit of the parent surface, the position of a new request always
+       replaces the scheduled position from any previous request.
+
+       The initial position is 0, 0.
+      </description>
+
+      <arg name="x" type="int" summary="coordinate in the parent surface"/>
+      <arg name="y" type="int" summary="coordinate in the parent surface"/>
+    </request>
+
+    <request name="place_above">
+      <description summary="restack the sub-surface">
+       This sub-surface is taken from the stack, and put back just
+       above the reference surface, changing the z-order of the sub-surfaces.
+       The reference surface must be one of the sibling surfaces, or the
+       parent surface. Using any other surface, including this sub-surface,
+       will cause a protocol error.
+
+       The z-order is double-buffered. Requests are handled in order and
+       applied immediately to a pending state, then committed to the active
+       state on the next commit of the parent surface.
+       See wl_surface.commit and wl_subcompositor.get_subsurface.
+
+       A new sub-surface is initially added as the top-most in the stack
+       of its siblings and parent.
+      </description>
+
+      <arg name="sibling" type="object" interface="wl_surface"
+           summary="the reference surface"/>
+    </request>
+
+    <request name="place_below">
+      <description summary="restack the sub-surface">
+       The sub-surface is placed just below of the reference surface.
+       See wl_subsurface.place_above.
+      </description>
+
+      <arg name="sibling" type="object" interface="wl_surface"
+           summary="the reference surface"/>
+    </request>
+
+    <request name="set_sync">
+      <description summary="set sub-surface to synchronized mode">
+       Change the commit behaviour of the sub-surface to synchronized
+       mode, also described as the parent dependant mode.
+
+       In synchronized mode, wl_surface.commit on a sub-surface will
+       accumulate the committed state in a cache, but the state will
+       not be applied and hence will not change the compositor output.
+       The cached state is applied to the sub-surface immediately after
+       the parent surface's state is applied. This ensures atomic
+       updates of the parent and all its synchronized sub-surfaces.
+       Applying the cached state will invalidate the cache, so further
+       parent surface commits do not (re-)apply old state.
+
+       See wl_subsurface for the recursive effect of this mode.
+      </description>
+    </request>
+
+    <request name="set_desync">
+      <description summary="set sub-surface to desynchronized mode">
+       Change the commit behaviour of the sub-surface to desynchronized
+       mode, also described as independent or freely running mode.
+
+       In desynchronized mode, wl_surface.commit on a sub-surface will
+       apply the pending state directly, without caching, as happens
+       normally with a wl_surface. Calling wl_surface.commit on the
+       parent surface has no effect on the sub-surface's wl_surface
+       state. This mode allows a sub-surface to be updated on its own.
+
+       If cached state exists when wl_surface.commit is called in
+       desynchronized mode, the pending state is added to the cached
+       state, and applied as whole. This invalidates the cache.
+
+       Note: even if a sub-surface is set to desynchronized, a parent
+       sub-surface may override it to behave as synchronized. For details,
+       see wl_subsurface.
+
+       If a surface's parent surface behaves as desynchronized, then
+       the cached state is applied on set_desync.
+      </description>
+    </request>
+
+  </interface>
+
+</protocol>
diff --git a/protocol/wayland_multiseat.xml b/protocol/wayland_multiseat.xml
new file mode 100644 (file)
index 0000000..cd12152
--- /dev/null
@@ -0,0 +1,2113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="wayland">
+
+  <copyright>
+    Copyright © 2008-2011 Kristian Høgsberg
+    Copyright © 2010-2011 Intel Corporation
+    Copyright © 2012-2013 Collabora, Ltd.
+
+    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.
+  </copyright>
+
+  <interface name="wl_display" version="1">
+    <description summary="core global object">
+      The core global object.  This is a special singleton object.  It
+      is used for internal Wayland protocol features.
+    </description>
+
+    <request name="sync">
+      <description summary="asynchronous roundtrip">
+       The sync request asks the server to emit the 'done' event
+       on the returned wl_callback object.  Since requests are
+       handled in-order and events are delivered in-order, this can
+       be used as a barrier to ensure all previous requests and the
+       resulting events have been handled.
+
+       The object returned by this request will be destroyed by the
+       compositor after the callback is fired and as such the client must not
+       attempt to use it after that point.
+
+       The callback_data passed in the callback is the event serial.
+      </description>
+      <arg name="callback" type="new_id" interface="wl_callback"/>
+    </request>
+
+    <request name="get_registry">
+      <description summary="get global registry object">
+       This request creates a registry object that allows the client
+       to list and bind the global objects available from the
+       compositor.
+      </description>
+      <arg name="registry" type="new_id" interface="wl_registry"/>
+    </request>
+
+    <event name="error">
+      <description summary="fatal error event">
+       The error event is sent out when a fatal (non-recoverable)
+       error has occurred.  The object_id argument is the object
+       where the error occurred, most often in response to a request
+       to that object.  The code identifies the error and is defined
+       by the object interface.  As such, each interface defines its
+       own set of error codes.  The message is an brief description
+       of the error, for (debugging) convenience.
+      </description>
+      <arg name="object_id" type="object"/>
+      <arg name="code" type="uint"/>
+      <arg name="message" type="string"/>
+    </event>
+
+    <enum name="error">
+      <description summary="global error values">
+       These errors are global and can be emitted in response to any
+       server request.
+      </description>
+      <entry name="invalid_object" value="0"
+            summary="server couldn't find object"/>
+      <entry name="invalid_method" value="1"
+            summary="method doesn't exist on the specified interface"/>
+      <entry name="no_memory" value="2"
+            summary="server is out of memory"/>
+    </enum>
+
+    <event name="delete_id">
+      <description summary="acknowledge object ID deletion">
+       This event is used internally by the object ID management
+       logic.  When a client deletes an object, the server will send
+       this event to acknowledge that it has seen the delete request.
+       When the client receive this event, it will know that it can
+       safely reuse the object ID.
+      </description>
+      <arg name="id" type="uint" />
+    </event>
+  </interface>
+
+  <interface name="wl_registry" version="1">
+    <description summary="global registry object">
+      The global registry object.  The server has a number of global
+      objects that are available to all clients.  These objects
+      typically represent an actual object in the server (for example,
+      an input device) or they are singleton objects that provide
+      extension functionality.
+
+      When a client creates a registry object, the registry object
+      will emit a global event for each global currently in the
+      registry.  Globals come and go as a result of device or
+      monitor hotplugs, reconfiguration or other events, and the
+      registry will send out global and global_remove events to
+      keep the client up to date with the changes.  To mark the end
+      of the initial burst of events, the client can use the
+      wl_display.sync request immediately after calling
+      wl_display.get_registry.
+
+      A client can bind to a global object by using the bind
+      request.  This creates a client-side handle that lets the object
+      emit events to the client and lets the client invoke requests on
+      the object.
+    </description>
+
+    <request name="bind">
+      <description summary="bind an object to the display">
+       Binds a new, client-created object to the server using the
+        specified name as the identifier.
+      </description>
+      <arg name="name" type="uint" summary="unique name for the object"/>
+      <arg name="id" type="new_id"/>
+    </request>
+
+    <event name="global">
+      <description summary="announce global object">
+       Notify the client of global objects.
+
+        The event notifies the client that a global object with
+        the given name is now available, and it implements the
+        given version of the given interface.
+      </description>
+      <arg name="name" type="uint"/>
+      <arg name="interface" type="string"/>
+      <arg name="version" type="uint"/>
+    </event>
+
+    <event name="global_remove">
+      <description summary="announce removal of global object">
+       Notify the client of removed global objects.
+
+        This event notifies the client that the global identified
+        by name is no longer available.  If the client bound to
+        the global using the bind request, the client should now
+        destroy that object.
+
+       The object remains valid and requests to the object will be
+       ignored until the client destroys it, to avoid races between
+       the global going away and a client sending a request to it.
+      </description>
+      <arg name="name" type="uint"/>
+    </event>
+  </interface>
+
+  <interface name="wl_callback" version="1">
+    <description summary="callback object">
+      Clients can handle the 'done' event to get notified when
+      the related request is done.
+    </description>
+    <event name="done">
+      <description summary="done event">
+       Notify the client when the related request is done.
+      </description>
+      <arg name="callback_data" type="uint" summary="request-specific data for the wl_callback"/>
+    </event>
+  </interface>
+
+  <interface name="wl_compositor" version="3">
+    <description summary="the compositor singleton">
+      A compositor.  This object is a singleton global.  The
+      compositor is in charge of combining the contents of multiple
+      surfaces into one displayable output.
+    </description>
+
+    <request name="create_surface">
+      <description summary="create new surface">
+       Ask the compositor to create a new surface.
+      </description>
+      <arg name="id" type="new_id" interface="wl_surface"/>
+    </request>
+
+    <request name="create_region">
+      <description summary="create new region">
+       Ask the compositor to create a new region.
+      </description>
+      <arg name="id" type="new_id" interface="wl_region"/>
+    </request>
+  </interface>
+
+  <interface name="wl_shm_pool" version="1">
+    <description summary="a shared memory pool">
+      The wl_shm_pool object encapsulates a piece of memory shared
+      between the compositor and client.  Through the wl_shm_pool
+      object, the client can allocate shared memory wl_buffer objects.
+      All objects created through the same pool share the same
+      underlying mapped memory. Reusing the mapped memory avoids the
+      setup/teardown overhead and is useful when interactively resizing
+      a surface or for many small buffers.
+    </description>
+
+    <request name="create_buffer">
+      <description summary="create a buffer from the pool">
+       Create a wl_buffer object from the pool.
+
+       The buffer is created offset bytes into the pool and has
+       width and height as specified.  The stride arguments specifies
+       the number of bytes from beginning of one row to the beginning
+       of the next.  The format is the pixel format of the buffer and
+       must be one of those advertised through the wl_shm.format event.
+
+       A buffer will keep a reference to the pool it was created from
+       so it is valid to destroy the pool immediately after creating
+       a buffer from it.
+      </description>
+
+      <arg name="id" type="new_id" interface="wl_buffer"/>
+      <arg name="offset" type="int"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+      <arg name="stride" type="int"/>
+      <arg name="format" type="uint"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the pool">
+       Destroy the shared memory pool.
+
+       The mmapped memory will be released when all
+       buffers that have been created from this pool
+       are gone.
+      </description>
+    </request>
+
+    <request name="resize">
+      <description summary="change the size of the pool mapping">
+       This request will cause the server to remap the backing memory
+       for the pool from the file descriptor passed when the pool was
+       created, but using the new size.  This request can only be
+       used to make the pool bigger.
+      </description>
+
+      <arg name="size" type="int"/>
+    </request>
+  </interface>
+
+  <interface name="wl_shm" version="1">
+    <description summary="shared memory support">
+      A global singleton object that provides support for shared
+      memory.
+
+      Clients can create wl_shm_pool objects using the create_pool
+      request.
+
+      At connection setup time, the wl_shm object emits one or more
+      format events to inform clients about the valid pixel formats
+      that can be used for buffers.
+    </description>
+
+    <enum name="error">
+      <description summary="wl_shm error values">
+       These errors can be emitted in response to wl_shm requests.
+      </description>
+      <entry name="invalid_format" value="0" summary="buffer format is not known"/>
+      <entry name="invalid_stride" value="1" summary="invalid size or stride during pool or buffer creation"/>
+      <entry name="invalid_fd" value="2" summary="mmapping the file descriptor failed"/>
+    </enum>
+
+    <enum name="format">
+      <description summary="pixel formats">
+       This describes the memory layout of an individual pixel.
+
+       All renderers should support argb8888 and xrgb8888 but any other
+       formats are optional and may not be supported by the particular
+       renderer in use.
+      </description>
+      <entry name="argb8888" value="0" summary="32-bit ARGB format"/>
+      <entry name="xrgb8888" value="1" summary="32-bit RGB format"/>
+      <!-- The drm format codes match the #defines in drm_fourcc.h.
+           The formats actually supported by the compositor will be
+           reported by the format event. -->
+      <entry name="c8" value="0x20203843"/>
+      <entry name="rgb332" value="0x38424752"/>
+      <entry name="bgr233" value="0x38524742"/>
+      <entry name="xrgb4444" value="0x32315258"/>
+      <entry name="xbgr4444" value="0x32314258"/>
+      <entry name="rgbx4444" value="0x32315852"/>
+      <entry name="bgrx4444" value="0x32315842"/>
+      <entry name="argb4444" value="0x32315241"/>
+      <entry name="abgr4444" value="0x32314241"/>
+      <entry name="rgba4444" value="0x32314152"/>
+      <entry name="bgra4444" value="0x32314142"/>
+      <entry name="xrgb1555" value="0x35315258"/>
+      <entry name="xbgr1555" value="0x35314258"/>
+      <entry name="rgbx5551" value="0x35315852"/>
+      <entry name="bgrx5551" value="0x35315842"/>
+      <entry name="argb1555" value="0x35315241"/>
+      <entry name="abgr1555" value="0x35314241"/>
+      <entry name="rgba5551" value="0x35314152"/>
+      <entry name="bgra5551" value="0x35314142"/>
+      <entry name="rgb565" value="0x36314752"/>
+      <entry name="bgr565" value="0x36314742"/>
+      <entry name="rgb888" value="0x34324752"/>
+      <entry name="bgr888" value="0x34324742"/>
+      <entry name="xbgr8888" value="0x34324258"/>
+      <entry name="rgbx8888" value="0x34325852"/>
+      <entry name="bgrx8888" value="0x34325842"/>
+      <entry name="abgr8888" value="0x34324241"/>
+      <entry name="rgba8888" value="0x34324152"/>
+      <entry name="bgra8888" value="0x34324142"/>
+      <entry name="xrgb2101010" value="0x30335258"/>
+      <entry name="xbgr2101010" value="0x30334258"/>
+      <entry name="rgbx1010102" value="0x30335852"/>
+      <entry name="bgrx1010102" value="0x30335842"/>
+      <entry name="argb2101010" value="0x30335241"/>
+      <entry name="abgr2101010" value="0x30334241"/>
+      <entry name="rgba1010102" value="0x30334152"/>
+      <entry name="bgra1010102" value="0x30334142"/>
+      <entry name="yuyv" value="0x56595559"/>
+      <entry name="yvyu" value="0x55595659"/>
+      <entry name="uyvy" value="0x59565955"/>
+      <entry name="vyuy" value="0x59555956"/>
+      <entry name="ayuv" value="0x56555941"/>
+      <entry name="nv12" value="0x3231564e"/>
+      <entry name="nv21" value="0x3132564e"/>
+      <entry name="nv16" value="0x3631564e"/>
+      <entry name="nv61" value="0x3136564e"/>
+      <entry name="yuv410" value="0x39565559"/>
+      <entry name="yvu410" value="0x39555659"/>
+      <entry name="yuv411" value="0x31315559"/>
+      <entry name="yvu411" value="0x31315659"/>
+      <entry name="yuv420" value="0x32315559"/>
+      <entry name="yvu420" value="0x32315659"/>
+      <entry name="yuv422" value="0x36315559"/>
+      <entry name="yvu422" value="0x36315659"/>
+      <entry name="yuv444" value="0x34325559"/>
+      <entry name="yvu444" value="0x34325659"/>
+    </enum>
+
+    <request name="create_pool">
+      <description summary="create a shm pool">
+       Create a new wl_shm_pool object.
+
+       The pool can be used to create shared memory based buffer
+       objects.  The server will mmap size bytes of the passed file
+        descriptor, to use as backing memory for the pool.
+      </description>
+
+      <arg name="id" type="new_id" interface="wl_shm_pool"/>
+      <arg name="fd" type="fd"/>
+      <arg name="size" type="int"/>
+    </request>
+
+    <event name="format">
+      <description summary="pixel format description">
+       Informs the client about a valid pixel format that
+       can be used for buffers. Known formats include
+       argb8888 and xrgb8888.
+      </description>
+      <arg name="format" type="uint"/>
+    </event>
+  </interface>
+
+  <interface name="wl_buffer" version="1">
+    <description summary="content for a wl_surface">
+      A buffer provides the content for a wl_surface. Buffers are
+      created through factory interfaces such as wl_drm, wl_shm or
+      similar. It has a width and a height and can be attached to a
+      wl_surface, but the mechanism by which a client provides and
+      updates the contents is defined by the buffer factory interface.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy a buffer">
+       Destroy a buffer. If and how you need to release the backing
+       storage is defined by the buffer factory interface.
+
+       For possible side-effects to a surface, see wl_surface.attach.
+      </description>
+    </request>
+
+    <event name="release">
+      <description summary="compositor releases buffer">
+       Sent when this wl_buffer is no longer used by the compositor.
+       The client is now free to re-use or destroy this buffer and its
+       backing storage.
+
+       If a client receives a release event before the frame callback
+       requested in the same wl_surface.commit that attaches this
+       wl_buffer to a surface, then the client is immediately free to
+       re-use the buffer and its backing storage, and does not need a
+       second buffer for the next surface content update. Typically
+       this is possible, when the compositor maintains a copy of the
+       wl_surface contents, e.g. as a GL texture. This is an important
+       optimization for GL(ES) compositors with wl_shm clients.
+      </description>
+    </event>
+  </interface>
+
+
+  <interface name="wl_data_offer" version="1">
+    <description summary="offer to transfer data">
+      A wl_data_offer represents a piece of data offered for transfer
+      by another client (the source client).  It is used by the
+      copy-and-paste and drag-and-drop mechanisms.  The offer
+      describes the different mime types that the data can be
+      converted to and provides the mechanism for transferring the
+      data directly from the source client.
+    </description>
+
+    <request name="accept">
+      <description summary="accept one of the offered mime types">
+       Indicate that the client can accept the given mime type, or
+       NULL for not accepted.
+
+       Used for feedback during drag-and-drop.
+      </description>
+
+      <arg name="serial" type="uint"/>
+      <arg name="mime_type" type="string" allow-null="true"/>
+    </request>
+
+    <request name="receive">
+      <description summary="request that the data is transferred">
+       To transfer the offered data, the client issues this request
+       and indicates the mime type it wants to receive.  The transfer
+       happens through the passed file descriptor (typically created
+       with the pipe system call).  The source client writes the data
+       in the mime type representation requested and then closes the
+       file descriptor.
+
+       The receiving client reads from the read end of the pipe until
+       EOF and the closes its end, at which point the transfer is
+       complete.
+      </description>
+      <arg name="mime_type" type="string"/>
+      <arg name="fd" type="fd"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy data offer">
+       Destroy the data offer.
+      </description>
+    </request>
+
+    <event name="offer">
+      <description summary="advertise offered mime type">
+       Sent immediately after creating the wl_data_offer object.  One
+       event per offered mime type.
+      </description>
+
+      <arg name="mime_type" type="string"/>
+    </event>
+  </interface>
+
+  <interface name="wl_data_source" version="1">
+    <description summary="offer to transfer data">
+      The wl_data_source object is the source side of a wl_data_offer.
+      It is created by the source client in a data transfer and
+      provides a way to describe the offered data and a way to respond
+      to requests to transfer the data.
+    </description>
+
+    <request name="offer">
+      <description summary="add an offered mime type">
+       This request adds a mime type to the set of mime types
+       advertised to targets.  Can be called several times to offer
+       multiple types.
+      </description>
+      <arg name="mime_type" type="string"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the data source">
+       Destroy the data source.
+      </description>
+    </request>
+
+    <event name="target">
+      <description summary="a target accepts an offered mime type">
+       Sent when a target accepts pointer_focus or motion events.  If
+       a target does not accept any of the offered types, type is NULL.
+
+       Used for feedback during drag-and-drop.
+      </description>
+
+      <arg name="mime_type" type="string" allow-null="true"/>
+    </event>
+
+    <event name="send">
+      <description summary="send the data">
+       Request for data from the client.  Send the data as the
+       specified mime type over the passed file descriptor, then
+       close it.
+      </description>
+
+      <arg name="mime_type" type="string"/>
+      <arg name="fd" type="fd"/>
+    </event>
+
+    <event name="cancelled">
+      <description summary="selection was cancelled">
+       This data source has been replaced by another data source.
+       The client should clean up and destroy this data source.
+      </description>
+    </event>
+
+  </interface>
+
+  <interface name="wl_data_device" version="1">
+    <description summary="data transfer device">
+      There is one wl_data_device per seat which can be obtained
+      from the global wl_data_device_manager singleton.
+
+      A wl_data_device provides access to inter-client data transfer
+      mechanisms such as copy-and-paste and drag-and-drop.
+    </description>
+    <request name="start_drag">
+      <description summary="start drag-and-drop operation">
+       This request asks the compositor to start a drag-and-drop
+       operation on behalf of the client.
+
+       The source argument is the data source that provides the data
+       for the eventual data transfer. If source is NULL, enter, leave
+       and motion events are sent only to the client that initiated the
+       drag and the client is expected to handle the data passing
+       internally.
+
+       The origin surface is the surface where the drag originates and
+       the client must have an active implicit grab that matches the
+       serial.
+
+       The icon surface is an optional (can be NULL) surface that
+       provides an icon to be moved around with the cursor.  Initially,
+       the top-left corner of the icon surface is placed at the cursor
+       hotspot, but subsequent wl_surface.attach request can move the
+       relative position. Attach requests must be confirmed with
+       wl_surface.commit as usual.
+
+       The current and pending input regions of the icon wl_surface are
+       cleared, and wl_surface.set_input_region is ignored until the
+       wl_surface is no longer used as the icon surface. When the use
+       as an icon ends, the current and pending input regions become
+       undefined, and the wl_surface is unmapped.
+      </description>
+      <arg name="source" type="object" interface="wl_data_source" allow-null="true"/>
+      <arg name="origin" type="object" interface="wl_surface"/>
+      <arg name="icon" type="object" interface="wl_surface" allow-null="true"/>
+      <arg name="serial" type="uint" summary="serial of the implicit grab on the origin"/>
+    </request>
+
+    <request name="set_selection">
+      <description summary="copy data to the selection">
+       This request asks the compositor to set the selection
+       to the data from the source on behalf of the client.
+
+       To unset the selection, set the source to NULL.
+      </description>
+      <arg name="source" type="object" interface="wl_data_source" allow-null="true"/>
+      <arg name="serial" type="uint" summary="serial of the event that triggered this request"/>
+    </request>
+
+    <event name="data_offer">
+      <description summary="introduce a new wl_data_offer">
+       The data_offer event introduces a new wl_data_offer object,
+       which will subsequently be used in either the
+       data_device.enter event (for drag-and-drop) or the
+       data_device.selection event (for selections).  Immediately
+       following the data_device_data_offer event, the new data_offer
+       object will send out data_offer.offer events to describe the
+       mime types it offers.
+      </description>
+
+      <arg name="id" type="new_id" interface="wl_data_offer"/>
+    </event>
+
+    <event name="enter">
+      <description summary="initiate drag-and-drop session">
+       This event is sent when an active drag-and-drop pointer enters
+       a surface owned by the client.  The position of the pointer at
+       enter time is provided by the x and y arguments, in surface
+       local coordinates.
+      </description>
+
+      <arg name="serial" type="uint"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <arg name="x" type="fixed"/>
+      <arg name="y" type="fixed"/>
+      <arg name="id" type="object" interface="wl_data_offer" allow-null="true"/>
+    </event>
+
+    <event name="leave">
+      <description summary="end drag-and-drop session">
+       This event is sent when the drag-and-drop pointer leaves the
+       surface and the session ends.  The client must destroy the
+       wl_data_offer introduced at enter time at this point.
+      </description>
+    </event>
+
+    <event name="motion">
+      <description summary="drag-and-drop session motion">
+       This event is sent when the drag-and-drop pointer moves within
+       the currently focused surface. The new position of the pointer
+       is provided by the x and y arguments, in surface local
+       coordinates.
+      </description>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="x" type="fixed"/>
+      <arg name="y" type="fixed"/>
+    </event>
+
+    <event name="drop">
+      <description summary="end drag-and-drag session successfully">
+       The event is sent when a drag-and-drop operation is ended
+       because the implicit grab is removed.
+      </description>
+    </event>
+
+    <event name="selection">
+      <description summary="advertise new selection">
+       The selection event is sent out to notify the client of a new
+       wl_data_offer for the selection for this device.  The
+       data_device.data_offer and the data_offer.offer events are
+       sent out immediately before this event to introduce the data
+       offer object.  The selection event is sent to a client
+       immediately before receiving keyboard focus and when a new
+       selection is set while the client has keyboard focus.  The
+       data_offer is valid until a new data_offer or NULL is received
+       or until the client loses keyboard focus.
+      </description>
+      <arg name="id" type="object" interface="wl_data_offer" allow-null="true"/>
+    </event>
+  </interface>
+
+  <interface name="wl_data_device_manager" version="1">
+    <description summary="data transfer interface">
+      The wl_data_device_manager is a singleton global object that
+      provides access to inter-client data transfer mechanisms such as
+      copy-and-paste and drag-and-drop.  These mechanisms are tied to
+      a wl_seat and this interface lets a client get a wl_data_device
+      corresponding to a wl_seat.
+    </description>
+
+    <request name="create_data_source">
+      <description summary="create a new data source">
+        Create a new data source.
+      </description>
+      <arg name="id" type="new_id" interface="wl_data_source"/>
+    </request>
+
+    <request name="get_data_device">
+      <description summary="create a new data device">
+        Create a new data device for a given seat.
+      </description>
+      <arg name="id" type="new_id" interface="wl_data_device"/>
+      <arg name="seat" type="object" interface="wl_seat"/>
+    </request>
+  </interface>
+
+  <interface name="wl_shell" version="1">
+    <description summary="create desktop-style surfaces">
+      This interface is implemented by servers that provide
+      desktop-style user interfaces.
+
+      It allows clients to associate a wl_shell_surface with
+      a basic surface.
+    </description>
+
+    <request name="get_shell_surface">
+      <description summary="create a shell surface from a surface">
+       Create a shell surface for an existing surface.
+
+       Only one shell surface can be associated with a given surface.
+      </description>
+      <arg name="id" type="new_id" interface="wl_shell_surface"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </request>
+  </interface>
+
+  <interface name="wl_shell_surface" version="1">
+
+    <description summary="desktop-style metadata interface">
+      An interface that may be implemented by a wl_surface, for
+      implementations that provide a desktop-style user interface.
+
+      It provides requests to treat surfaces like toplevel, fullscreen
+      or popup windows, move, resize or maximize them, associate
+      metadata like title and class, etc.
+
+      On the server side the object is automatically destroyed when
+      the related wl_surface is destroyed.  On client side,
+      wl_shell_surface_destroy() must be called before destroying
+      the wl_surface object.
+    </description>
+
+    <request name="pong">
+      <description summary="respond to a ping event">
+       A client must respond to a ping event with a pong request or
+       the client may be deemed unresponsive.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the ping event"/>
+    </request>
+
+    <request name="move">
+      <description summary="start an interactive move">
+       Start a pointer-driven move of the surface.
+
+       This request must be used in response to a button press event.
+       The server may ignore move requests depending on the state of
+       the surface (e.g. fullscreen or maximized).
+      </description>
+      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/>
+      <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/>
+    </request>
+
+    <enum name="resize">
+      <description summary="edge values for resizing">
+       These values are used to indicate which edge of a surface
+       is being dragged in a resize operation. The server may
+       use this information to adapt its behavior, e.g. choose
+       an appropriate cursor image.
+      </description>
+      <entry name="none" value="0"/>
+      <entry name="top" value="1"/>
+      <entry name="bottom" value="2"/>
+      <entry name="left" value="4"/>
+      <entry name="top_left" value="5"/>
+      <entry name="bottom_left" value="6"/>
+      <entry name="right" value="8"/>
+      <entry name="top_right" value="9"/>
+      <entry name="bottom_right" value="10"/>
+    </enum>
+
+    <request name="resize">
+      <description summary="start an interactive resize">
+       Start a pointer-driven resizing of the surface.
+
+       This request must be used in response to a button press event.
+       The server may ignore resize requests depending on the state of
+       the surface (e.g. fullscreen or maximized).
+      </description>
+      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/>
+      <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/>
+      <arg name="edges" type="uint" summary="which edge or corner is being dragged"/>
+    </request>
+
+    <request name="set_toplevel">
+      <description summary="make the surface a toplevel surface">
+       Map the surface as a toplevel surface.
+
+       A toplevel surface is not fullscreen, maximized or transient.
+      </description>
+    </request>
+
+    <enum name="transient">
+      <description summary="details of transient behaviour">
+       These flags specify details of the expected behaviour
+       of transient surfaces. Used in the set_transient request.
+      </description>
+      <entry name="inactive" value="0x1" summary="do not set keyboard focus"/>
+    </enum>
+
+    <request name="set_transient">
+      <description summary="make the surface a transient surface">
+       Map the surface relative to an existing surface.
+
+       The x and y arguments specify the locations of the upper left
+       corner of the surface relative to the upper left corner of the
+       parent surface, in surface local coordinates.
+
+       The flags argument controls details of the transient behaviour.
+      </description>
+
+      <arg name="parent" type="object" interface="wl_surface"/>
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="flags" type="uint"/>
+    </request>
+
+    <enum name="fullscreen_method">
+      <description summary="different method to set the surface fullscreen">
+       Hints to indicate to the compositor how to deal with a conflict
+       between the dimensions of the surface and the dimensions of the
+       output. The compositor is free to ignore this parameter.
+      </description>
+      <entry name="default" value="0" summary="no preference, apply default policy"/>
+      <entry name="scale" value="1" summary="scale, preserve the surface's aspect ratio and center on output"/>
+      <entry name="driver" value="2" summary="switch output mode to the smallest mode that can fit the surface, add black borders to compensate size mismatch"/>
+      <entry name="fill" value="3" summary="no upscaling, center on output and add black borders to compensate size mismatch"/>
+    </enum>
+
+    <request name="set_fullscreen">
+      <description summary="make the surface a fullscreen surface">
+       Map the surface as a fullscreen surface.
+
+       If an output parameter is given then the surface will be made
+       fullscreen on that output. If the client does not specify the
+       output then the compositor will apply its policy - usually
+       choosing the output on which the surface has the biggest surface
+       area.
+
+       The client may specify a method to resolve a size conflict
+       between the output size and the surface size - this is provided
+       through the method parameter.
+
+       The framerate parameter is used only when the method is set
+       to "driver", to indicate the preferred framerate. A value of 0
+       indicates that the app does not care about framerate.  The
+       framerate is specified in mHz, that is framerate of 60000 is 60Hz.
+
+       A method of "scale" or "driver" implies a scaling operation of
+       the surface, either via a direct scaling operation or a change of
+       the output mode. This will override any kind of output scaling, so
+       that mapping a surface with a buffer size equal to the mode can
+       fill the screen independent of buffer_scale.
+
+       A method of "fill" means we don't scale up the buffer, however
+       any output scale is applied. This means that you may run into
+       an edge case where the application maps a buffer with the same
+       size of the output mode but buffer_scale 1 (thus making a
+       surface larger than the output). In this case it is allowed to
+       downscale the results to fit the screen.
+
+       The compositor must reply to this request with a configure event
+       with the dimensions for the output on which the surface will
+       be made fullscreen.
+      </description>
+      <arg name="method" type="uint"/>
+      <arg name="framerate" type="uint"/>
+      <arg name="output" type="object" interface="wl_output" allow-null="true"/>
+    </request>
+
+    <request name="set_popup">
+      <description summary="make the surface a popup surface">
+       Map the surface as a popup.
+
+       A popup surface is a transient surface with an added pointer
+       grab.
+
+       An existing implicit grab will be changed to owner-events mode,
+       and the popup grab will continue after the implicit grab ends
+       (i.e. releasing the mouse button does not cause the popup to
+       be unmapped).
+
+       The popup grab continues until the window is destroyed or a
+       mouse button is pressed in any other clients window. A click
+       in any of the clients surfaces is reported as normal, however,
+       clicks in other clients surfaces will be discarded and trigger
+       the callback.
+
+       The x and y arguments specify the locations of the upper left
+       corner of the surface relative to the upper left corner of the
+       parent surface, in surface local coordinates.
+      </description>
+
+      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/>
+      <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/>
+      <arg name="parent" type="object" interface="wl_surface"/>
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="flags" type="uint"/>
+    </request>
+
+    <request name="set_maximized">
+      <description summary="make the surface a maximized surface">
+       Map the surface as a maximized surface.
+
+       If an output parameter is given then the surface will be
+       maximized on that output. If the client does not specify the
+       output then the compositor will apply its policy - usually
+       choosing the output on which the surface has the biggest surface
+       area.
+
+       The compositor will reply with a configure event telling
+       the expected new surface size. The operation is completed
+       on the next buffer attach to this surface.
+
+       A maximized surface typically fills the entire output it is
+       bound to, except for desktop element such as panels. This is
+       the main difference between a maximized shell surface and a
+       fullscreen shell surface.
+
+       The details depend on the compositor implementation.
+      </description>
+      <arg name="output" type="object" interface="wl_output" allow-null="true"/>
+    </request>
+
+    <request name="set_title">
+      <description summary="set surface title">
+       Set a short title for the surface.
+
+       This string may be used to identify the surface in a task bar,
+       window list, or other user interface elements provided by the
+       compositor.
+
+       The string must be encoded in UTF-8.
+      </description>
+      <arg name="title" type="string"/>
+    </request>
+
+    <request name="set_class">
+      <description summary="set surface class">
+       Set a class for the surface.
+
+       The surface class identifies the general class of applications
+       to which the surface belongs. A common convention is to use the
+       file name (or the full path if it is a non-standard location) of
+       the application's .desktop file as the class.
+      </description>
+      <arg name="class_" type="string"/>
+    </request>
+
+    <event name="ping">
+      <description summary="ping client">
+       Ping a client to check if it is receiving events and sending
+       requests. A client is expected to reply with a pong request.
+      </description>
+      <arg name="serial" type="uint"/>
+    </event>
+
+    <event name="configure">
+      <description summary="suggest resize">
+       The configure event asks the client to resize its surface.
+
+       The size is a hint, in the sense that the client is free to
+       ignore it if it doesn't resize, pick a smaller size (to
+       satisfy aspect ratio or resize in steps of NxM pixels).
+
+       The edges parameter provides a hint about how the surface
+       was resized. The client may use this information to decide
+       how to adjust its content to the new size (e.g. a scrolling
+       area might adjust its content position to leave the viewable
+       content unmoved).
+
+       The client is free to dismiss all but the last configure
+       event it received.
+
+       The width and height arguments specify the size of the window
+       in surface local coordinates.
+      </description>
+
+      <arg name="edges" type="uint"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </event>
+
+    <event name="popup_done">
+      <description summary="popup interaction is done">
+       The popup_done event is sent out when a popup grab is broken,
+       that is, when the user clicks a surface that doesn't belong
+       to the client owning the popup surface.
+      </description>
+    </event>
+  </interface>
+
+  <interface name="wl_surface" version="3">
+    <description summary="an onscreen surface">
+      A surface is a rectangular area that is displayed on the screen.
+      It has a location, size and pixel contents.
+
+      The size of a surface (and relative positions on it) is described
+      in surface local coordinates, which may differ from the buffer
+      local coordinates of the pixel content, in case a buffer_transform
+      or a buffer_scale is used.
+
+      Surfaces are also used for some special purposes, e.g. as
+      cursor images for pointers, drag icons, etc.
+    </description>
+
+    <enum name="error">
+      <description summary="wl_surface error values">
+        These errors can be emitted in response to wl_surface requests.
+      </description>
+      <entry name="invalid_scale" value="0" summary="buffer scale value is invalid"/>
+      <entry name="invalid_transform" value="1" summary="buffer transform value is invalid"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="delete surface">
+       Deletes the surface and invalidates its object ID.
+      </description>
+    </request>
+
+    <request name="attach">
+      <description summary="set the surface contents">
+       Set a buffer as the content of this surface.
+
+       The new size of the surface is calculated based on the buffer
+       size transformed by the inverse buffer_transform and the
+       inverse buffer_scale. This means that the supplied buffer
+       must be an integer multiple of the buffer_scale.
+
+       The x and y arguments specify the location of the new pending
+       buffer's upper left corner, relative to the current buffer's upper
+       left corner, in surface local coordinates. In other words, the
+       x and y, combined with the new surface size define in which
+       directions the surface's size changes.
+
+       Surface contents are double-buffered state, see wl_surface.commit.
+
+       The initial surface contents are void; there is no content.
+       wl_surface.attach assigns the given wl_buffer as the pending
+       wl_buffer. wl_surface.commit makes the pending wl_buffer the new
+       surface contents, and the size of the surface becomes the size
+       calculated from the wl_buffer, as described above. After commit,
+       there is no pending buffer until the next attach.
+
+       Committing a pending wl_buffer allows the compositor to read the
+       pixels in the wl_buffer. The compositor may access the pixels at
+       any time after the wl_surface.commit request. When the compositor
+       will not access the pixels anymore, it will send the
+       wl_buffer.release event. Only after receiving wl_buffer.release,
+       the client may re-use the wl_buffer. A wl_buffer that has been
+       attached and then replaced by another attach instead of committed
+       will not receive a release event, and is not used by the
+       compositor.
+
+       Destroying the wl_buffer after wl_buffer.release does not change
+       the surface contents. However, if the client destroys the
+       wl_buffer before receiving the wl_buffer.release event, the surface
+       contents become undefined immediately.
+
+       If wl_surface.attach is sent with a NULL wl_buffer, the
+       following wl_surface.commit will remove the surface content.
+      </description>
+
+      <arg name="buffer" type="object" interface="wl_buffer" allow-null="true"/>
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+    </request>
+
+    <request name="damage">
+      <description summary="mark part of the surface damaged">
+       This request is used to describe the regions where the pending
+       buffer is different from the current surface contents, and where
+       the surface therefore needs to be repainted. The pending buffer
+       must be set by wl_surface.attach before sending damage. The
+       compositor ignores the parts of the damage that fall outside of
+       the surface.
+
+       Damage is double-buffered state, see wl_surface.commit.
+
+       The damage rectangle is specified in surface local coordinates.
+
+       The initial value for pending damage is empty: no damage.
+       wl_surface.damage adds pending damage: the new pending damage
+       is the union of old pending damage and the given rectangle.
+
+       wl_surface.commit assigns pending damage as the current damage,
+       and clears pending damage. The server will clear the current
+       damage as it repaints the surface.
+      </description>
+
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+
+    <request name="frame">
+      <description summary="request a frame throttling hint">
+       Request a notification when it is a good time start drawing a new
+       frame, by creating a frame callback. This is useful for throttling
+       redrawing operations, and driving animations.
+
+       When a client is animating on a wl_surface, it can use the 'frame'
+       request to get notified when it is a good time to draw and commit the
+       next frame of animation. If the client commits an update earlier than
+       that, it is likely that some updates will not make it to the display,
+       and the client is wasting resources by drawing too often.
+
+       The frame request will take effect on the next wl_surface.commit.
+       The notification will only be posted for one frame unless
+       requested again. For a wl_surface, the notifications are posted in
+       the order the frame requests were committed.
+
+       The server must send the notifications so that a client
+       will not send excessive updates, while still allowing
+       the highest possible update rate for clients that wait for the reply
+       before drawing again. The server should give some time for the client
+       to draw and commit after sending the frame callback events to let them
+       hit the next output refresh.
+
+       A server should avoid signalling the frame callbacks if the
+       surface is not visible in any way, e.g. the surface is off-screen,
+       or completely obscured by other opaque surfaces.
+
+       The object returned by this request will be destroyed by the
+       compositor after the callback is fired and as such the client must not
+       attempt to use it after that point.
+
+       The callback_data passed in the callback is the current time, in
+       milliseconds, with an undefined base.
+      </description>
+
+      <arg name="callback" type="new_id" interface="wl_callback"/>
+    </request>
+
+    <request name="set_opaque_region">
+      <description summary="set opaque region">
+       This request sets the region of the surface that contains
+       opaque content.
+
+       The opaque region is an optimization hint for the compositor
+       that lets it optimize out redrawing of content behind opaque
+       regions.  Setting an opaque region is not required for correct
+       behaviour, but marking transparent content as opaque will result
+       in repaint artifacts.
+
+       The opaque region is specified in surface local coordinates.
+
+       The compositor ignores the parts of the opaque region that fall
+       outside of the surface.
+
+       Opaque region is double-buffered state, see wl_surface.commit.
+
+       wl_surface.set_opaque_region changes the pending opaque region.
+       wl_surface.commit copies the pending region to the current region.
+       Otherwise, the pending and current regions are never changed.
+
+       The initial value for opaque region is empty. Setting the pending
+       opaque region has copy semantics, and the wl_region object can be
+       destroyed immediately. A NULL wl_region causes the pending opaque
+       region to be set to empty.
+      </description>
+
+      <arg name="region" type="object" interface="wl_region" allow-null="true"/>
+    </request>
+
+    <request name="set_input_region">
+      <description summary="set input region">
+       This request sets the region of the surface that can receive
+       pointer and touch events.
+
+       Input events happening outside of this region will try the next
+       surface in the server surface stack. The compositor ignores the
+       parts of the input region that fall outside of the surface.
+
+       The input region is specified in surface local coordinates.
+
+       Input region is double-buffered state, see wl_surface.commit.
+
+       wl_surface.set_input_region changes the pending input region.
+       wl_surface.commit copies the pending region to the current region.
+       Otherwise the pending and current regions are never changed,
+       except cursor and icon surfaces are special cases, see
+       wl_pointer.set_cursor and wl_data_device.start_drag.
+
+       The initial value for input region is infinite. That means the
+       whole surface will accept input. Setting the pending input region
+       has copy semantics, and the wl_region object can be destroyed
+       immediately. A NULL wl_region causes the input region to be set
+       to infinite.
+      </description>
+
+      <arg name="region" type="object" interface="wl_region" allow-null="true"/>
+    </request>
+
+    <request name="commit">
+      <description summary="commit pending surface state">
+       Surface state (input, opaque, and damage regions, attached buffers,
+       etc.) is double-buffered. Protocol requests modify the pending
+       state, as opposed to current state in use by the compositor. Commit
+       request atomically applies all pending state, replacing the current
+       state. After commit, the new pending state is as documented for each
+       related request.
+
+       On commit, a pending wl_buffer is applied first, all other state
+       second. This means that all coordinates in double-buffered state are
+       relative to the new wl_buffer coming into use, except for
+       wl_surface.attach itself. If there is no pending wl_buffer, the
+       coordinates are relative to the current surface contents.
+
+       All requests that need a commit to become effective are documented
+       to affect double-buffered state.
+
+       Other interfaces may add further double-buffered surface state.
+      </description>
+    </request>
+
+    <event name="enter">
+      <description summary="surface enters an output">
+       This is emitted whenever a surface's creation, movement, or resizing
+       results in some part of it being within the scanout region of an
+       output.
+
+       Note that a surface may be overlapping with zero or more outputs.
+      </description>
+      <arg name="output" type="object" interface="wl_output"/>
+    </event>
+
+    <event name="leave">
+      <description summary="surface leaves an output">
+       This is emitted whenever a surface's creation, movement, or resizing
+       results in it no longer having any part of it within the scanout region
+       of an output.
+      </description>
+      <arg name="output" type="object" interface="wl_output"/>
+    </event>
+
+    <!-- Version 2 additions -->
+
+    <request name="set_buffer_transform" since="2">
+      <description summary="sets the buffer transformation">
+       This request sets an optional transformation on how the compositor
+       interprets the contents of the buffer attached to the surface. The
+       accepted values for the transform parameter are the values for
+       wl_output.transform.
+
+       Buffer transform is double-buffered state, see wl_surface.commit.
+
+       A newly created surface has its buffer transformation set to normal.
+
+       wl_surface.set_buffer_transform changes the pending buffer
+       transformation. wl_surface.commit copies the pending buffer
+       transformation to the current one. Otherwise, the pending and current
+       values are never changed.
+
+       The purpose of this request is to allow clients to render content
+       according to the output transform, thus permiting the compositor to
+       use certain optimizations even if the display is rotated. Using
+       hardware overlays and scanning out a client buffer for fullscreen
+       surfaces are examples of such optimizations. Those optimizations are
+       highly dependent on the compositor implementation, so the use of this
+       request should be considered on a case-by-case basis.
+
+       Note that if the transform value includes 90 or 270 degree rotation,
+       the width of the buffer will become the surface height and the height
+       of the buffer will become the surface width.
+
+       If transform is not one of the values from the
+       wl_output.transform enum the invalid_transform protocol error
+       is raised.
+      </description>
+      <arg name="transform" type="int"/>
+    </request>
+
+    <!-- Version 3 additions -->
+
+    <request name="set_buffer_scale" since="3">
+      <description summary="sets the buffer scaling factor">
+       This request sets an optional scaling factor on how the compositor
+       interprets the contents of the buffer attached to the window.
+
+       Buffer scale is double-buffered state, see wl_surface.commit.
+
+       A newly created surface has its buffer scale set to 1.
+
+       wl_surface.set_buffer_scale changes the pending buffer scale.
+       wl_surface.commit copies the pending buffer scale to the current one.
+       Otherwise, the pending and current values are never changed.
+
+       The purpose of this request is to allow clients to supply higher
+       resolution buffer data for use on high resolution outputs. Its
+       intended that you pick the same buffer scale as the scale of the
+       output that the surface is displayed on.This means the compositor
+       can avoid scaling when rendering the surface on that output.
+
+       Note that if the scale is larger than 1, then you have to attach
+       a buffer that is larger (by a factor of scale in each dimension)
+       than the desired surface size.
+
+       If scale is not positive the invalid_scale protocol error is
+       raised.
+      </description>
+      <arg name="scale" type="int"/>
+    </request>
+   </interface>
+
+  <interface name="wl_seat" version="4">
+    <description summary="group of input devices">
+      A seat is a group of keyboards, pointer and touch devices. This
+      object is published as a global during start up, or when such a
+      device is hot plugged.  A seat typically has a pointer and
+      maintains a keyboard focus and a pointer focus.
+    </description>
+
+    <enum name="capability">
+      <description summary="seat capability bitmask">
+        This is a bitmask of capabilities this seat has; if a member is
+        set, then it is present on the seat.
+      </description>
+      <entry name="pointer" value="1" summary="The seat has pointer devices"/>
+      <entry name="keyboard" value="2" summary="The seat has one or more keyboards"/>
+      <entry name="touch" value="4" summary="The seat has touch devices"/>
+    </enum>
+
+    <event name="capabilities">
+      <description summary="seat capabilities changed">
+        This is emitted whenever a seat gains or loses the pointer,
+       keyboard or touch capabilities.  The argument is a capability
+       enum containing the complete set of capabilities this seat has.
+      </description>
+      <arg name="capabilities" type="uint"/>
+    </event>
+
+    <request name="get_pointer">
+      <description summary="return pointer object">
+        The ID provided will be initialized to the wl_pointer interface
+       for this seat.
+
+        This request only takes effect if the seat has the pointer
+        capability.
+      </description>
+      <arg name="id" type="new_id" interface="wl_pointer"/>
+    </request>
+
+    <request name="get_keyboard">
+      <description summary="return keyboard object">
+        The ID provided will be initialized to the wl_keyboard interface
+       for this seat.
+
+        This request only takes effect if the seat has the keyboard
+        capability.
+      </description>
+      <arg name="id" type="new_id" interface="wl_keyboard"/>
+    </request>
+
+    <request name="get_touch">
+      <description summary="return touch object">
+        The ID provided will be initialized to the wl_touch interface
+       for this seat.
+
+        This request only takes effect if the seat has the touch
+        capability.
+      </description>
+      <arg name="id" type="new_id" interface="wl_touch"/>
+    </request>
+
+    <!-- Version 2 of additions -->
+
+    <event name="name" since="2">
+      <description summary="unique identifier for this seat">
+       In a multiseat configuration this can be used by the client to help
+       identify which physical devices the seat represents. Based on
+       the seat configuration used by the compositor.
+      </description>
+      <arg name="name" type="string"/>
+    </event>
+
+  </interface>
+
+  <interface name="wl_pointer" version="3">
+    <description summary="pointer input device">
+      The wl_pointer interface represents one or more input devices,
+      such as mice, which control the pointer location and pointer_focus
+      of a seat.
+
+      The wl_pointer interface generates motion, enter and leave
+      events for the surfaces that the pointer is located over,
+      and button and axis events for button presses, button releases
+      and scrolling.
+    </description>
+
+    <request name="set_cursor">
+      <description summary="set the pointer surface">
+       Set the pointer surface, i.e., the surface that contains the
+       pointer image (cursor). This request only takes effect if the pointer
+       focus for this device is one of the requesting client's surfaces
+       or the surface parameter is the current pointer surface. If
+       there was a previous surface set with this request it is
+       replaced. If surface is NULL, the pointer image is hidden.
+
+       The parameters hotspot_x and hotspot_y define the position of
+       the pointer surface relative to the pointer location. Its
+       top-left corner is always at (x, y) - (hotspot_x, hotspot_y),
+       where (x, y) are the coordinates of the pointer location, in surface
+       local coordinates.
+
+       On surface.attach requests to the pointer surface, hotspot_x
+       and hotspot_y are decremented by the x and y parameters
+       passed to the request. Attach must be confirmed by
+       wl_surface.commit as usual.
+
+       The hotspot can also be updated by passing the currently set
+       pointer surface to this request with new values for hotspot_x
+       and hotspot_y.
+
+       The current and pending input regions of the wl_surface are
+       cleared, and wl_surface.set_input_region is ignored until the
+       wl_surface is no longer used as the cursor. When the use as a
+       cursor ends, the current and pending input regions become
+       undefined, and the wl_surface is unmapped.
+      </description>
+
+      <arg name="serial" type="uint" summary="serial of the enter event"/>
+      <arg name="surface" type="object" interface="wl_surface" allow-null="true"/>
+      <arg name="hotspot_x" type="int" summary="x coordinate in surface-relative coordinates"/>
+      <arg name="hotspot_y" type="int" summary="y coordinate in surface-relative coordinates"/>
+    </request>
+
+    <event name="enter">
+      <description summary="enter event">
+       Notification that this seat's pointer is focused on a certain
+       surface.
+
+       When an seat's focus enters a surface, the pointer image
+       is undefined and a client should respond to this event by setting
+       an appropriate pointer image with the set_cursor request.
+      </description>
+
+      <arg name="serial" type="uint"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <arg name="surface_x" type="fixed" summary="x coordinate in surface-relative coordinates"/>
+      <arg name="surface_y" type="fixed" summary="y coordinate in surface-relative coordinates"/>
+    </event>
+
+    <event name="leave">
+      <description summary="leave event">
+       Notification that this seat's pointer is no longer focused on
+       a certain surface.
+
+       The leave notification is sent before the enter notification
+       for the new focus.
+      </description>
+      <arg name="serial" type="uint"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </event>
+
+    <event name="motion">
+      <description summary="pointer motion event">
+       Notification of pointer location change. The arguments
+       surface_x and surface_y are the location relative to the
+       focused surface.
+      </description>
+
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="surface_x" type="fixed" summary="x coordinate in surface-relative coordinates"/>
+      <arg name="surface_y" type="fixed" summary="y coordinate in surface-relative coordinates"/>
+    </event>
+
+    <enum name="button_state">
+      <description summary="physical button state">
+        Describes the physical state of a button which provoked the button
+       event.
+      </description>
+      <entry name="released" value="0" summary="The button is not pressed"/>
+      <entry name="pressed" value="1" summary="The button is pressed"/>
+    </enum>
+
+    <event name="button">
+      <description summary="pointer button event">
+       Mouse button click and release notifications.
+
+       The location of the click is given by the last motion or
+       enter event.
+        The time argument is a timestamp with millisecond
+        granularity, with an undefined base.
+      </description>
+
+      <arg name="serial" type="uint"/>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="button" type="uint"/>
+      <arg name="state" type="uint"/>
+    </event>
+
+    <enum name="axis">
+      <description summary="axis types">
+       Describes the axis types of scroll events.
+      </description>
+      <entry name="vertical_scroll" value="0"/>
+      <entry name="horizontal_scroll" value="1"/>
+    </enum>
+
+    <event name="axis">
+      <description summary="axis event">
+       Scroll and other axis notifications.
+
+       For scroll events (vertical and horizontal scroll axes), the
+       value parameter is the length of a vector along the specified
+       axis in a coordinate space identical to those of motion events,
+       representing a relative movement along the specified axis.
+
+       For devices that support movements non-parallel to axes multiple
+       axis events will be emitted.
+
+       When applicable, for example for touch pads, the server can
+       choose to emit scroll events where the motion vector is
+       equivalent to a motion event vector.
+
+       When applicable, clients can transform its view relative to the
+       scroll distance.
+      </description>
+
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="axis" type="uint"/>
+      <arg name="value" type="fixed"/>
+    </event>
+
+    <!-- Version 3 additions -->
+
+    <request name="release" type="destructor" since="3">
+      <description summary="release the pointer object"/>
+    </request>
+
+  </interface>
+
+  <interface name="wl_keyboard" version="4">
+    <description summary="keyboard input device">
+      The wl_keyboard interface represents one or more keyboards
+      associated with a seat.
+    </description>
+
+    <enum name="keymap_format">
+      <description summary="keyboard mapping format">
+       This specifies the format of the keymap provided to the
+       client with the wl_keyboard.keymap event.
+      </description>
+      <entry name="no_keymap" value="0"
+            summary="no keymap; client must understand how to interpret the raw keycode"/>
+      <entry name="xkb_v1" value="1"
+             summary="libxkbcommon compatible; to determine the xkb keycode, clients must add 8 to the key event keycode"/>
+    </enum>
+
+    <event name="keymap">
+      <description summary="keyboard mapping">
+       This event provides a file descriptor to the client which can be
+       memory-mapped to provide a keyboard mapping description.
+      </description>
+      <arg name="format" type="uint"/>
+      <arg name="fd" type="fd"/>
+      <arg name="size" type="uint"/>
+    </event>
+
+    <event name="enter">
+      <description summary="enter event">
+       Notification that this seat's keyboard focus is on a certain
+       surface.
+      </description>
+      <arg name="serial" type="uint"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <arg name="keys" type="array" summary="the currently pressed keys"/>
+    </event>
+
+    <event name="leave">
+      <description summary="leave event">
+       Notification that this seat's keyboard focus is no longer on
+       a certain surface.
+
+       The leave notification is sent before the enter notification
+       for the new focus.
+      </description>
+      <arg name="serial" type="uint"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </event>
+
+    <enum name="key_state">
+      <description summary="physical key state">
+       Describes the physical state of a key which provoked the key event.
+      </description>
+      <entry name="released" value="0" summary="key is not pressed"/>
+      <entry name="pressed" value="1" summary="key is pressed"/>
+    </enum>
+
+    <event name="key">
+      <description summary="key event">
+       A key was pressed or released.
+        The time argument is a timestamp with millisecond
+        granularity, with an undefined base.
+      </description>
+
+      <arg name="serial" type="uint"/>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="key" type="uint"/>
+      <arg name="state" type="uint"/>
+    </event>
+
+    <event name="modifiers">
+      <description summary="modifier and group state">
+       Notifies clients that the modifier and/or group state has
+       changed, and it should update its local state.
+      </description>
+
+      <arg name="serial" type="uint"/>
+      <arg name="mods_depressed" type="uint"/>
+      <arg name="mods_latched" type="uint"/>
+      <arg name="mods_locked" type="uint"/>
+      <arg name="group" type="uint"/>
+    </event>
+
+    <!-- Version 3 additions -->
+
+    <request name="release" type="destructor" since="3">
+      <description summary="release the keyboard object"/>
+    </request>
+
+    <!-- Version 4 additions -->
+
+    <event name="repeat_info" since="4">
+      <description summary="repeat rate and delay">
+        Informs the client about the keyboard's repeat rate and delay.
+
+        This event is sent as soon as the wl_keyboard object has been created,
+        and is guaranteed to be received by the client before any key press
+        event.
+
+        Negative values for either rate or delay are illegal. A rate of zero
+        will disable any repeating (regardless of the value of delay).
+
+        This event can be sent later on as well with a new value if necessary,
+        so clients should continue listening for the event past the creation
+        of wl_keyboard.
+      </description>
+
+      <arg name="rate" type="int"
+           summary="the rate of repeating keys in characters per second"/>
+      <arg name="delay" type="int"
+           summary="delay in milliseconds since key down until repeating starts"/>
+    </event>
+  </interface>
+
+  <interface name="wl_touch" version="3">
+    <description summary="touchscreen input device">
+      The wl_touch interface represents a touchscreen
+      associated with a seat.
+
+      Touch interactions can consist of one or more contacts.
+      For each contact, a series of events is generated, starting
+      with a down event, followed by zero or more motion events,
+      and ending with an up event. Events relating to the same
+      contact point can be identified by the ID of the sequence.
+    </description>
+
+    <event name="down">
+      <description summary="touch down event and beginning of a touch sequence">
+       A new touch point has appeared on the surface. This touch point is
+       assigned a unique @id. Future events from this touchpoint reference
+       this ID. The ID ceases to be valid after a touch up event and may be
+       re-used in the future.
+      </description>
+      <arg name="serial" type="uint"/>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <arg name="id" type="int" summary="the unique ID of this touch point"/>
+      <arg name="x" type="fixed" summary="x coordinate in surface-relative coordinates"/>
+      <arg name="y" type="fixed" summary="y coordinate in surface-relative coordinates"/>
+    </event>
+
+    <event name="up">
+      <description summary="end of a touch event sequence">
+       The touch point has disappeared. No further events will be sent for
+       this touchpoint and the touch point's ID is released and may be
+       re-used in a future touch down event.
+      </description>
+      <arg name="serial" type="uint"/>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="id" type="int" summary="the unique ID of this touch point"/>
+    </event>
+
+    <event name="motion">
+      <description summary="update of touch point coordinates">
+       A touchpoint has changed coordinates.
+      </description>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="id" type="int" summary="the unique ID of this touch point"/>
+      <arg name="x" type="fixed" summary="x coordinate in surface-relative coordinates"/>
+      <arg name="y" type="fixed" summary="y coordinate in surface-relative coordinates"/>
+    </event>
+
+    <event name="frame">
+      <description summary="end of touch frame event">
+       Indicates the end of a contact point list.
+      </description>
+    </event>
+
+    <event name="cancel">
+      <description summary="touch session cancelled">
+       Sent if the compositor decides the touch stream is a global
+       gesture. No further events are sent to the clients from that
+       particular gesture. Touch cancellation applies to all touch points
+       currently active on this client's surface. The client is
+       responsible for finalizing the touch points, future touch points on
+       this surface may re-use the touch point ID.
+      </description>
+    </event>
+
+    <!-- Version 3 additions -->
+
+    <request name="release" type="destructor" since="3">
+      <description summary="release the touch object"/>
+    </request>
+  </interface>
+
+  <interface name="wl_output" version="3">
+    <description summary="compositor output region">
+      An output describes part of the compositor geometry.  The
+      compositor works in the 'compositor coordinate system' and an
+      output corresponds to rectangular area in that space that is
+      actually visible.  This typically corresponds to a monitor that
+      displays part of the compositor space.  This object is published
+      as global during start up, or when a monitor is hotplugged.
+    </description>
+
+    <enum name="subpixel">
+      <description summary="subpixel geometry information">
+       This enumeration describes how the physical
+       pixels on an output are layed out.
+      </description>
+      <entry name="unknown" value="0"/>
+      <entry name="none" value="1"/>
+      <entry name="horizontal_rgb" value="2"/>
+      <entry name="horizontal_bgr" value="3"/>
+      <entry name="vertical_rgb" value="4"/>
+      <entry name="vertical_bgr" value="5"/>
+    </enum>
+
+    <enum name="transform">
+      <description summary="transform from framebuffer to output">
+       This describes the transform that a compositor will apply to a
+       surface to compensate for the rotation or mirroring of an
+       output device.
+
+       The flipped values correspond to an initial flip around a
+       vertical axis followed by rotation.
+
+       The purpose is mainly to allow clients render accordingly and
+       tell the compositor, so that for fullscreen surfaces, the
+       compositor will still be able to scan out directly from client
+       surfaces.
+      </description>
+
+      <entry name="normal" value="0"/>
+      <entry name="90" value="1"/>
+      <entry name="180" value="2"/>
+      <entry name="270" value="3"/>
+      <entry name="flipped" value="4"/>
+      <entry name="flipped_90" value="5"/>
+      <entry name="flipped_180" value="6"/>
+      <entry name="flipped_270" value="7"/>
+    </enum>
+
+    <event name="geometry">
+      <description summary="properties of the output">
+       The geometry event describes geometric properties of the output.
+       The event is sent when binding to the output object and whenever
+       any of the properties change.
+      </description>
+      <arg name="x" type="int"
+          summary="x position within the global compositor space"/>
+      <arg name="y" type="int"
+          summary="y position within the global compositor space"/>
+      <arg name="physical_width" type="int"
+          summary="width in millimeters of the output"/>
+      <arg name="physical_height" type="int"
+          summary="height in millimeters of the output"/>
+      <arg name="subpixel" type="int"
+          summary="subpixel orientation of the output"/>
+      <arg name="make" type="string"
+          summary="textual description of the manufacturer"/>
+      <arg name="model" type="string"
+          summary="textual description of the model"/>
+      <arg name="transform" type="int"
+          summary="transform that maps framebuffer to output"/>
+    </event>
+
+    <enum name="mode">
+      <description summary="mode information">
+       These flags describe properties of an output mode.
+       They are used in the flags bitfield of the mode event.
+      </description>
+      <entry name="current" value="0x1"
+            summary="indicates this is the current mode"/>
+      <entry name="preferred" value="0x2"
+            summary="indicates this is the preferred mode"/>
+    </enum>
+
+    <event name="mode">
+      <description summary="advertise available modes for the output">
+       The mode event describes an available mode for the output.
+
+       The event is sent when binding to the output object and there
+       will always be one mode, the current mode.  The event is sent
+       again if an output changes mode, for the mode that is now
+       current.  In other words, the current mode is always the last
+       mode that was received with the current flag set.
+
+       The size of a mode is given in physical hardware units of
+        the output device. This is not necessarily the same as
+        the output size in the global compositor space. For instance,
+        the output may be scaled, as described in wl_output.scale,
+        or transformed , as described in wl_output.transform.
+      </description>
+      <arg name="flags" type="uint" summary="bitfield of mode flags"/>
+      <arg name="width" type="int" summary="width of the mode in hardware units"/>
+      <arg name="height" type="int" summary="height of the mode in hardware units"/>
+      <arg name="refresh" type="int" summary="vertical refresh rate in mHz"/>
+    </event>
+
+    <event name="done" since="2">
+      <description summary="sent all information about output">
+        This event is sent after all other properties has been
+        sent after binding to the output object and after any
+        other property changes done after that. This allows
+        changes to the output properties to be seen as
+        atomic, even if they happen via multiple events.
+      </description>
+    </event>
+
+    <event name="scale" since="2">
+      <description summary="output scaling properties">
+       This event contains scaling geometry information
+        that is not in the geometry event. It may be sent after
+        binding the output object or if the output scale changes
+        later. If it is not sent, the client should assume a
+       scale of 1.
+
+       A scale larger than 1 means that the compositor will
+       automatically scale surface buffers by this amount
+       when rendering. This is used for very high resolution
+       displays where applications rendering at the native
+       resolution would be too small to be legible.
+
+       It is intended that scaling aware clients track the
+       current output of a surface, and if it is on a scaled
+       output it should use wl_surface.set_buffer_scale with
+       the scale of the output. That way the compositor can
+       avoid scaling the surface, and the client can supply
+       a higher detail image.
+      </description>
+      <arg name="factor" type="int" summary="scaling factor of output"/>
+    </event>
+
+    <!-- Version 3 of additions -->
+
+    <event name="name" since="3">
+      <description summary="name of the output">
+  In a multiseat configuration this can be used by the client to help
+  identify the name of the output and consequently the name can be used to
+  select the output(s) based on the configuration.
+      </description>
+      <arg name="name" type="string"/>
+    </event>
+
+    <event name="seatname" since="3">
+      <description summary="name of the seat the output is constrained to">
+  In a multiseat configuration this can be used by the client to help
+  identify the seat which the given output is constrained to and consequently
+  select the output(s) based on the client own seat.
+      </description>
+      <arg name="name" type="string"/>
+    </event>
+  </interface>
+
+  <interface name="wl_region" version="1">
+    <description summary="region interface">
+      A region object describes an area.
+
+      Region objects are used to describe the opaque and input
+      regions of a surface.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy region">
+       Destroy the region.  This will invalidate the object ID.
+      </description>
+    </request>
+
+    <request name="add">
+      <description summary="add rectangle to region">
+       Add the specified rectangle to the region.
+      </description>
+
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+
+    <request name="subtract">
+      <description summary="subtract rectangle from region">
+       Subtract the specified rectangle from the region.
+      </description>
+
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+
+  </interface>
+
+  <interface name="wl_subcompositor" version="1">
+    <description summary="sub-surface compositing">
+      The global interface exposing sub-surface compositing capabilities.
+      A wl_surface, that has sub-surfaces associated, is called the
+      parent surface. Sub-surfaces can be arbitrarily nested and create
+      a tree of sub-surfaces.
+
+      The root surface in a tree of sub-surfaces is the main
+      surface. The main surface cannot be a sub-surface, because
+      sub-surfaces must always have a parent.
+
+      A main surface with its sub-surfaces forms a (compound) window.
+      For window management purposes, this set of wl_surface objects is
+      to be considered as a single window, and it should also behave as
+      such.
+
+      The aim of sub-surfaces is to offload some of the compositing work
+      within a window from clients to the compositor. A prime example is
+      a video player with decorations and video in separate wl_surface
+      objects. This should allow the compositor to pass YUV video buffer
+      processing to dedicated overlay hardware when possible.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="unbind from the subcompositor interface">
+       Informs the server that the client will not be using this
+       protocol object anymore. This does not affect any other
+       objects, wl_subsurface objects included.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="bad_surface" value="0"
+             summary="the to-be sub-surface is invalid"/>
+    </enum>
+
+    <request name="get_subsurface">
+      <description summary="give a surface the role sub-surface">
+       Create a sub-surface interface for the given surface, and
+       associate it with the given parent surface. This turns a
+       plain wl_surface into a sub-surface.
+
+       The to-be sub-surface must not already have a dedicated
+       purpose, like any shell surface type, cursor image, drag icon,
+       or sub-surface. Otherwise a protocol error is raised.
+      </description>
+
+      <arg name="id" type="new_id" interface="wl_subsurface"
+           summary="the new subsurface object id"/>
+      <arg name="surface" type="object" interface="wl_surface"
+           summary="the surface to be turned into a sub-surface"/>
+      <arg name="parent" type="object" interface="wl_surface"
+           summary="the parent surface"/>
+    </request>
+  </interface>
+
+  <interface name="wl_subsurface" version="1">
+    <description summary="sub-surface interface to a wl_surface">
+      An additional interface to a wl_surface object, which has been
+      made a sub-surface. A sub-surface has one parent surface. A
+      sub-surface's size and position are not limited to that of the parent.
+      Particularly, a sub-surface is not automatically clipped to its
+      parent's area.
+
+      A sub-surface becomes mapped, when a non-NULL wl_buffer is applied
+      and the parent surface is mapped. The order of which one happens
+      first is irrelevant. A sub-surface is hidden if the parent becomes
+      hidden, or if a NULL wl_buffer is applied. These rules apply
+      recursively through the tree of surfaces.
+
+      The behaviour of wl_surface.commit request on a sub-surface
+      depends on the sub-surface's mode. The possible modes are
+      synchronized and desynchronized, see methods
+      wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized
+      mode caches the wl_surface state to be applied when the parent's
+      state gets applied, and desynchronized mode applies the pending
+      wl_surface state directly. A sub-surface is initially in the
+      synchronized mode.
+
+      Sub-surfaces have also other kind of state, which is managed by
+      wl_subsurface requests, as opposed to wl_surface requests. This
+      state includes the sub-surface position relative to the parent
+      surface (wl_subsurface.set_position), and the stacking order of
+      the parent and its sub-surfaces (wl_subsurface.place_above and
+      .place_below). This state is applied when the parent surface's
+      wl_surface state is applied, regardless of the sub-surface's mode.
+      As the exception, set_sync and set_desync are effective immediately.
+
+      The main surface can be thought to be always in desynchronized mode,
+      since it does not have a parent in the sub-surfaces sense.
+
+      Even if a sub-surface is in desynchronized mode, it will behave as
+      in synchronized mode, if its parent surface behaves as in
+      synchronized mode. This rule is applied recursively throughout the
+      tree of surfaces. This means, that one can set a sub-surface into
+      synchronized mode, and then assume that all its child and grand-child
+      sub-surfaces are synchronized, too, without explicitly setting them.
+
+      If the wl_surface associated with the wl_subsurface is destroyed, the
+      wl_subsurface object becomes inert. Note, that destroying either object
+      takes effect immediately. If you need to synchronize the removal
+      of a sub-surface to the parent surface update, unmap the sub-surface
+      first by attaching a NULL wl_buffer, update parent, and then destroy
+      the sub-surface.
+
+      If the parent wl_surface object is destroyed, the sub-surface is
+      unmapped.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="remove sub-surface interface">
+       The sub-surface interface is removed from the wl_surface object
+       that was turned into a sub-surface with
+       wl_subcompositor.get_subsurface request. The wl_surface's association
+       to the parent is deleted, and the wl_surface loses its role as
+       a sub-surface. The wl_surface is unmapped.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="bad_surface" value="0"
+             summary="wl_surface is not a sibling or the parent"/>
+    </enum>
+
+    <request name="set_position">
+      <description summary="reposition the sub-surface">
+       This schedules a sub-surface position change.
+       The sub-surface will be moved so, that its origin (top-left
+       corner pixel) will be at the location x, y of the parent surface
+       coordinate system. The coordinates are not restricted to the parent
+       surface area. Negative values are allowed.
+
+       The next wl_surface.commit on the parent surface will reset
+       the sub-surface's position to the scheduled coordinates.
+
+       If more than one set_position request is invoked by the client before
+       the commit of the parent surface, the position of a new request always
+       replaces the scheduled position from any previous request.
+
+       The initial position is 0, 0.
+      </description>
+
+      <arg name="x" type="int" summary="coordinate in the parent surface"/>
+      <arg name="y" type="int" summary="coordinate in the parent surface"/>
+    </request>
+
+    <request name="place_above">
+      <description summary="restack the sub-surface">
+       This sub-surface is taken from the stack, and put back just
+       above the reference surface, changing the z-order of the sub-surfaces.
+       The reference surface must be one of the sibling surfaces, or the
+       parent surface. Using any other surface, including this sub-surface,
+       will cause a protocol error.
+
+       The z-order is double-buffered. Requests are handled in order and
+       applied immediately to a pending state, then committed to the active
+       state on the next commit of the parent surface.
+       See wl_surface.commit and wl_subcompositor.get_subsurface.
+
+       A new sub-surface is initially added as the top-most in the stack
+       of its siblings and parent.
+      </description>
+
+      <arg name="sibling" type="object" interface="wl_surface"
+           summary="the reference surface"/>
+    </request>
+
+    <request name="place_below">
+      <description summary="restack the sub-surface">
+       The sub-surface is placed just below of the reference surface.
+       See wl_subsurface.place_above.
+      </description>
+
+      <arg name="sibling" type="object" interface="wl_surface"
+           summary="the reference surface"/>
+    </request>
+
+    <request name="set_sync">
+      <description summary="set sub-surface to synchronized mode">
+       Change the commit behaviour of the sub-surface to synchronized
+       mode, also described as the parent dependant mode.
+
+       In synchronized mode, wl_surface.commit on a sub-surface will
+       accumulate the committed state in a cache, but the state will
+       not be applied and hence will not change the compositor output.
+       The cached state is applied to the sub-surface immediately after
+       the parent surface's state is applied. This ensures atomic
+       updates of the parent and all its synchronized sub-surfaces.
+       Applying the cached state will invalidate the cache, so further
+       parent surface commits do not (re-)apply old state.
+
+       See wl_subsurface for the recursive effect of this mode.
+      </description>
+    </request>
+
+    <request name="set_desync">
+      <description summary="set sub-surface to desynchronized mode">
+       Change the commit behaviour of the sub-surface to desynchronized
+       mode, also described as independent or freely running mode.
+
+       In desynchronized mode, wl_surface.commit on a sub-surface will
+       apply the pending state directly, without caching, as happens
+       normally with a wl_surface. Calling wl_surface.commit on the
+       parent surface has no effect on the sub-surface's wl_surface
+       state. This mode allows a sub-surface to be updated on its own.
+
+       If cached state exists when wl_surface.commit is called in
+       desynchronized mode, the pending state is added to the cached
+       state, and applied as whole. This invalidates the cache.
+
+       Note: even if a sub-surface is set to desynchronized, a parent
+       sub-surface may override it to behave as synchronized. For details,
+       see wl_subsurface.
+
+       If a surface's parent surface behaves as desynchronized, then
+       the cached state is applied on set_desync.
+      </description>
+    </request>
+
+  </interface>
+
+</protocol>
diff --git a/spec/.gitignore b/spec/.gitignore
new file mode 100644 (file)
index 0000000..4962683
--- /dev/null
@@ -0,0 +1,3 @@
+main.aux
+main.log
+main.pdf
diff --git a/spec/wayland-architecture.png b/spec/wayland-architecture.png
new file mode 100644 (file)
index 0000000..4f92e0f
Binary files /dev/null and b/spec/wayland-architecture.png differ
diff --git a/spec/x-architecture.png b/spec/x-architecture.png
new file mode 100644 (file)
index 0000000..098205b
Binary files /dev/null and b/spec/x-architecture.png differ
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644 (file)
index 0000000..4421b46
--- /dev/null
@@ -0,0 +1 @@
+/wayland-version.h
diff --git a/src/connection.c b/src/connection.c
new file mode 100644 (file)
index 0000000..2545194
--- /dev/null
@@ -0,0 +1,1248 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ * Copyright © 2013 Jason Ekstrand
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/uio.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <ffi.h>
+
+#include "wayland-util.h"
+#include "wayland-private.h"
+#include "wayland-os.h"
+
+#define DIV_ROUNDUP(n, a) ( ((n) + ((a) - 1)) / (a) )
+
+struct wl_buffer {
+       char data[4096];
+       uint32_t head, tail;
+};
+
+#define MASK(i) ((i) & 4095)
+
+#define MAX_FDS_OUT    28
+#define CLEN           (CMSG_LEN(MAX_FDS_OUT * sizeof(int32_t)))
+
+struct wl_connection {
+       struct wl_buffer in, out;
+       struct wl_buffer fds_in, fds_out;
+       int fd;
+       int want_flush;
+};
+
+static int
+wl_buffer_put(struct wl_buffer *b, const void *data, size_t count)
+{
+       uint32_t head, size;
+
+       if (count > sizeof(b->data)) {
+               wl_log("Data too big for buffer (%d > %d).\n",
+                      count, sizeof(b->data));
+               errno = E2BIG;
+               return -1;
+       }
+
+       head = MASK(b->head);
+       if (head + count <= sizeof b->data) {
+               memcpy(b->data + head, data, count);
+       } else {
+               size = sizeof b->data - head;
+               memcpy(b->data + head, data, size);
+               memcpy(b->data, (const char *) data + size, count - size);
+       }
+
+       b->head += count;
+
+       return 0;
+}
+
+static void
+wl_buffer_put_iov(struct wl_buffer *b, struct iovec *iov, int *count)
+{
+       uint32_t head, tail;
+
+       head = MASK(b->head);
+       tail = MASK(b->tail);
+       if (head < tail) {
+               iov[0].iov_base = b->data + head;
+               iov[0].iov_len = tail - head;
+               *count = 1;
+       } else if (tail == 0) {
+               iov[0].iov_base = b->data + head;
+               iov[0].iov_len = sizeof b->data - head;
+               *count = 1;
+       } else {
+               iov[0].iov_base = b->data + head;
+               iov[0].iov_len = sizeof b->data - head;
+               iov[1].iov_base = b->data;
+               iov[1].iov_len = tail;
+               *count = 2;
+       }
+}
+
+static void
+wl_buffer_get_iov(struct wl_buffer *b, struct iovec *iov, int *count)
+{
+       uint32_t head, tail;
+
+       head = MASK(b->head);
+       tail = MASK(b->tail);
+       if (tail < head) {
+               iov[0].iov_base = b->data + tail;
+               iov[0].iov_len = head - tail;
+               *count = 1;
+       } else if (head == 0) {
+               iov[0].iov_base = b->data + tail;
+               iov[0].iov_len = sizeof b->data - tail;
+               *count = 1;
+       } else {
+               iov[0].iov_base = b->data + tail;
+               iov[0].iov_len = sizeof b->data - tail;
+               iov[1].iov_base = b->data;
+               iov[1].iov_len = head;
+               *count = 2;
+       }
+}
+
+static void
+wl_buffer_copy(struct wl_buffer *b, void *data, size_t count)
+{
+       uint32_t tail, size;
+
+       tail = MASK(b->tail);
+       if (tail + count <= sizeof b->data) {
+               memcpy(data, b->data + tail, count);
+       } else {
+               size = sizeof b->data - tail;
+               memcpy(data, b->data + tail, size);
+               memcpy((char *) data + size, b->data, count - size);
+       }
+}
+
+static uint32_t
+wl_buffer_size(struct wl_buffer *b)
+{
+       return b->head - b->tail;
+}
+
+struct wl_connection *
+wl_connection_create(int fd)
+{
+       struct wl_connection *connection;
+
+       connection = malloc(sizeof *connection);
+       if (connection == NULL)
+               return NULL;
+       memset(connection, 0, sizeof *connection);
+       connection->fd = fd;
+
+       return connection;
+}
+
+static void
+close_fds(struct wl_buffer *buffer, int max)
+{
+       int32_t fds[sizeof(buffer->data) / sizeof(int32_t)], i, count;
+       size_t size;
+
+       size = buffer->head - buffer->tail;
+       if (size == 0)
+               return;
+
+       wl_buffer_copy(buffer, fds, size);
+       count = size / sizeof fds[0];
+       if (max > 0 && max < count)
+               count = max;
+       for (i = 0; i < count; i++)
+               close(fds[i]);
+       buffer->tail += size;
+}
+
+int
+wl_connection_destroy(struct wl_connection *connection)
+{
+       int fd = connection->fd;
+
+       close_fds(&connection->fds_out, -1);
+       close_fds(&connection->fds_in, -1);
+       free(connection);
+
+       return fd;
+}
+
+void
+wl_connection_copy(struct wl_connection *connection, void *data, size_t size)
+{
+       wl_buffer_copy(&connection->in, data, size);
+}
+
+void
+wl_connection_consume(struct wl_connection *connection, size_t size)
+{
+       connection->in.tail += size;
+}
+
+static void
+build_cmsg(struct wl_buffer *buffer, char *data, int *clen)
+{
+       struct cmsghdr *cmsg;
+       size_t size;
+
+       size = buffer->head - buffer->tail;
+       if (size > MAX_FDS_OUT * sizeof(int32_t))
+               size = MAX_FDS_OUT * sizeof(int32_t);
+
+       if (size > 0) {
+               cmsg = (struct cmsghdr *) data;
+               cmsg->cmsg_level = SOL_SOCKET;
+               cmsg->cmsg_type = SCM_RIGHTS;
+               cmsg->cmsg_len = CMSG_LEN(size);
+               wl_buffer_copy(buffer, CMSG_DATA(cmsg), size);
+               *clen = cmsg->cmsg_len;
+       } else {
+               *clen = 0;
+       }
+}
+
+static int
+decode_cmsg(struct wl_buffer *buffer, struct msghdr *msg)
+{
+       struct cmsghdr *cmsg;
+       size_t size, max, i;
+       int overflow = 0;
+
+       for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
+            cmsg = CMSG_NXTHDR(msg, cmsg)) {
+               if (cmsg->cmsg_level != SOL_SOCKET ||
+                   cmsg->cmsg_type != SCM_RIGHTS)
+                       continue;
+
+               size = cmsg->cmsg_len - CMSG_LEN(0);
+               max = sizeof(buffer->data) - wl_buffer_size(buffer);
+               if (size > max || overflow) {
+                       overflow = 1;
+                       size /= sizeof(int32_t);
+                       for (i = 0; i < size; i++)
+                               close(((int*)CMSG_DATA(cmsg))[i]);
+               } else if (wl_buffer_put(buffer, CMSG_DATA(cmsg), size) < 0) {
+                               return -1;
+               }
+       }
+
+       if (overflow) {
+               errno = EOVERFLOW;
+               return -1;
+       }
+
+       return 0;
+}
+
+int
+wl_connection_flush(struct wl_connection *connection)
+{
+       struct iovec iov[2];
+       struct msghdr msg;
+       char cmsg[CLEN];
+       int len = 0, count, clen;
+       uint32_t tail;
+
+       if (!connection->want_flush)
+               return 0;
+
+       tail = connection->out.tail;
+       while (connection->out.head - connection->out.tail > 0) {
+               wl_buffer_get_iov(&connection->out, iov, &count);
+
+               build_cmsg(&connection->fds_out, cmsg, &clen);
+
+               msg.msg_name = NULL;
+               msg.msg_namelen = 0;
+               msg.msg_iov = iov;
+               msg.msg_iovlen = count;
+               msg.msg_control = (clen > 0) ? cmsg : NULL;
+               msg.msg_controllen = clen;
+               msg.msg_flags = 0;
+
+               do {
+                       len = sendmsg(connection->fd, &msg,
+                                     MSG_NOSIGNAL | MSG_DONTWAIT);
+               } while (len == -1 && errno == EINTR);
+
+               if (len == -1)
+                       return -1;
+
+               close_fds(&connection->fds_out, MAX_FDS_OUT);
+
+               connection->out.tail += len;
+       }
+
+       connection->want_flush = 0;
+
+       return connection->out.head - tail;
+}
+
+int
+wl_connection_read(struct wl_connection *connection)
+{
+       struct iovec iov[2];
+       struct msghdr msg;
+       char cmsg[CLEN];
+       int len, count, ret;
+
+       if (wl_buffer_size(&connection->in) >= sizeof(connection->in.data)) {
+               errno = EOVERFLOW;
+               return -1;
+       }
+
+       wl_buffer_put_iov(&connection->in, iov, &count);
+
+       msg.msg_name = NULL;
+       msg.msg_namelen = 0;
+       msg.msg_iov = iov;
+       msg.msg_iovlen = count;
+       msg.msg_control = cmsg;
+       msg.msg_controllen = sizeof cmsg;
+       msg.msg_flags = 0;
+
+       do {
+               len = wl_os_recvmsg_cloexec(connection->fd, &msg, MSG_DONTWAIT);
+       } while (len < 0 && errno == EINTR);
+
+       if (len <= 0)
+               return len;
+
+       ret = decode_cmsg(&connection->fds_in, &msg);
+       if (ret)
+               return -1;
+
+       connection->in.head += len;
+
+       return connection->in.head - connection->in.tail;
+}
+
+int
+wl_connection_write(struct wl_connection *connection,
+                   const void *data, size_t count)
+{
+       if (connection->out.head - connection->out.tail +
+           count > ARRAY_LENGTH(connection->out.data)) {
+               connection->want_flush = 1;
+               if (wl_connection_flush(connection) < 0)
+                       return -1;
+       }
+
+       if (wl_buffer_put(&connection->out, data, count) < 0)
+               return -1;
+
+       connection->want_flush = 1;
+
+       return 0;
+}
+
+int
+wl_connection_queue(struct wl_connection *connection,
+                   const void *data, size_t count)
+{
+       if (connection->out.head - connection->out.tail +
+           count > ARRAY_LENGTH(connection->out.data)) {
+               connection->want_flush = 1;
+               if (wl_connection_flush(connection) < 0)
+                       return -1;
+       }
+
+       return wl_buffer_put(&connection->out, data, count);
+}
+
+static int
+wl_message_count_arrays(const struct wl_message *message)
+{
+       int i, arrays;
+
+       for (i = 0, arrays = 0; message->signature[i]; i++) {
+               if (message->signature[i] == 'a')
+                       arrays++;
+       }
+
+       return arrays;
+}
+
+static int
+wl_connection_put_fd(struct wl_connection *connection, int32_t fd)
+{
+       if (wl_buffer_size(&connection->fds_out) == MAX_FDS_OUT * sizeof fd) {
+               connection->want_flush = 1;
+               if (wl_connection_flush(connection) < 0)
+                       return -1;
+       }
+
+       return wl_buffer_put(&connection->fds_out, &fd, sizeof fd);
+}
+
+const char *
+get_next_argument(const char *signature, struct argument_details *details)
+{
+       details->nullable = 0;
+       for(; *signature; ++signature) {
+               switch(*signature) {
+               case 'i':
+               case 'u':
+               case 'f':
+               case 's':
+               case 'o':
+               case 'n':
+               case 'a':
+               case 'h':
+                       details->type = *signature;
+                       return signature + 1;
+               case '?':
+                       details->nullable = 1;
+               }
+       }
+       details->type = '\0';
+       return signature;
+}
+
+int
+arg_count_for_signature(const char *signature)
+{
+       int count = 0;
+       for(; *signature; ++signature) {
+               switch(*signature) {
+               case 'i':
+               case 'u':
+               case 'f':
+               case 's':
+               case 'o':
+               case 'n':
+               case 'a':
+               case 'h':
+                       ++count;
+               }
+       }
+       return count;
+}
+
+int
+wl_message_get_since(const struct wl_message *message)
+{
+       int since;
+
+       since = atoi(message->signature);
+
+       if (since == 0)
+               since = 1;
+
+       return since;
+}
+
+void
+wl_argument_from_va_list(const char *signature, union wl_argument *args,
+                        int count, va_list ap)
+{
+       int i;
+       const char *sig_iter;
+       struct argument_details arg;
+
+       sig_iter = signature;
+       for (i = 0; i < count; i++) {
+               sig_iter = get_next_argument(sig_iter, &arg);
+
+               switch(arg.type) {
+               case 'i':
+                       args[i].i = va_arg(ap, int32_t);
+                       break;
+               case 'u':
+                       args[i].u = va_arg(ap, uint32_t);
+                       break;
+               case 'f':
+                       args[i].f = va_arg(ap, wl_fixed_t);
+                       break;
+               case 's':
+                       args[i].s = va_arg(ap, const char *);
+                       break;
+               case 'o':
+                       args[i].o = va_arg(ap, struct wl_object *);
+                       break;
+               case 'n':
+                       args[i].o = va_arg(ap, struct wl_object *);
+                       break;
+               case 'a':
+                       args[i].a = va_arg(ap, struct wl_array *);
+                       break;
+               case 'h':
+                       args[i].h = va_arg(ap, int32_t);
+                       break;
+               case '\0':
+                       return;
+               }
+       }
+}
+
+struct wl_closure *
+wl_closure_marshal(struct wl_object *sender, uint32_t opcode,
+                  union wl_argument *args,
+                  const struct wl_message *message)
+{
+       struct wl_closure *closure;
+       struct wl_object *object;
+       int i, count, fd, dup_fd;
+       const char *signature;
+       struct argument_details arg;
+
+       count = arg_count_for_signature(message->signature);
+       if (count > WL_CLOSURE_MAX_ARGS) {
+               wl_log("too many args (%d)\n", count);
+               errno = EINVAL;
+               return NULL;
+       }
+
+       closure = malloc(sizeof *closure);
+       if (closure == NULL) {
+               errno = ENOMEM;
+               return NULL;
+       }
+
+       memcpy(closure->args, args, count * sizeof *args);
+
+       signature = message->signature;
+       for (i = 0; i < count; i++) {
+               signature = get_next_argument(signature, &arg);
+
+               switch (arg.type) {
+               case 'f':
+               case 'u':
+               case 'i':
+                       break;
+               case 's':
+                       if (!arg.nullable && args[i].s == NULL)
+                               goto err_null;
+                       break;
+               case 'o':
+                       if (!arg.nullable && args[i].o == NULL)
+                               goto err_null;
+                       break;
+               case 'n':
+                       object = args[i].o;
+                       if (!arg.nullable && object == NULL)
+                               goto err_null;
+
+                       closure->args[i].n = object ? object->id : 0;
+                       break;
+               case 'a':
+                       if (!arg.nullable && args[i].a == NULL)
+                               goto err_null;
+                       break;
+               case 'h':
+                       fd = args[i].h;
+                       dup_fd = wl_os_dupfd_cloexec(fd, 0);
+                       if (dup_fd < 0) {
+                               wl_log("dup failed: %m");
+                               abort();
+                       }
+                       closure->args[i].h = dup_fd;
+                       break;
+               default:
+                       wl_log("unhandled format code: '%c'\n",
+                               arg.type);
+                       assert(0);
+                       break;
+               }
+       }
+
+       closure->sender_id = sender->id;
+       closure->opcode = opcode;
+       closure->message = message;
+       closure->count = count;
+
+       return closure;
+
+err_null:
+       wl_closure_destroy(closure);
+       wl_log("error marshalling arguments for %s (signature %s): "
+              "null value passed for arg %i\n", message->name,
+              message->signature, i);
+       errno = EINVAL;
+       return NULL;
+}
+
+struct wl_closure *
+wl_closure_vmarshal(struct wl_object *sender, uint32_t opcode, va_list ap,
+                   const struct wl_message *message)
+{
+       union wl_argument args[WL_CLOSURE_MAX_ARGS];
+
+       wl_argument_from_va_list(message->signature, args,
+                                WL_CLOSURE_MAX_ARGS, ap);
+
+       return wl_closure_marshal(sender, opcode, args, message);
+}
+
+struct wl_closure *
+wl_connection_demarshal(struct wl_connection *connection,
+                       uint32_t size,
+                       struct wl_map *objects,
+                       const struct wl_message *message)
+{
+       uint32_t *p, *next, *end, length, id;
+       int fd;
+       char *s;
+       unsigned int i, count, num_arrays;
+       const char *signature;
+       struct argument_details arg;
+       struct wl_closure *closure;
+       struct wl_array *array, *array_extra;
+
+       count = arg_count_for_signature(message->signature);
+       if (count > WL_CLOSURE_MAX_ARGS) {
+               wl_log("too many args (%d)\n", count);
+               errno = EINVAL;
+               wl_connection_consume(connection, size);
+               return NULL;
+       }
+
+       num_arrays = wl_message_count_arrays(message);
+       closure = malloc(sizeof *closure + size + num_arrays * sizeof *array);
+       if (closure == NULL) {
+               errno = ENOMEM;
+               wl_connection_consume(connection, size);
+               return NULL;
+       }
+
+       array_extra = closure->extra;
+       p = (uint32_t *)(closure->extra + num_arrays);
+       end = p + size / sizeof *p;
+
+       wl_connection_copy(connection, p, size);
+       closure->sender_id = *p++;
+       closure->opcode = *p++ & 0x0000ffff;
+
+       signature = message->signature;
+       for (i = 0; i < count; i++) {
+               signature = get_next_argument(signature, &arg);
+
+               if (arg.type != 'h' && p + 1 > end) {
+                       wl_log("message too short, "
+                              "object (%d), message %s(%s)\n",
+                              *p, message->name, message->signature);
+                       errno = EINVAL;
+                       goto err;
+               }
+
+               switch (arg.type) {
+               case 'u':
+                       closure->args[i].u = *p++;
+                       break;
+               case 'i':
+                       closure->args[i].i = *p++;
+                       break;
+               case 'f':
+                       closure->args[i].f = *p++;
+                       break;
+               case 's':
+                       length = *p++;
+
+                       if (length == 0) {
+                               closure->args[i].s = NULL;
+                               break;
+                       }
+
+                       next = p + DIV_ROUNDUP(length, sizeof *p);
+                       if (next > end) {
+                               wl_log("message too short, "
+                                      "object (%d), message %s(%s)\n",
+                                      closure->sender_id, message->name,
+                                      message->signature);
+                               errno = EINVAL;
+                               goto err;
+                       }
+
+                       s = (char *) p;
+
+                       if (length > 0 && s[length - 1] != '\0') {
+                               wl_log("string not nul-terminated, "
+                                      "message %s(%s)\n",
+                                      message->name, message->signature);
+                               errno = EINVAL;
+                               goto err;
+                       }
+
+                       closure->args[i].s = s;
+                       p = next;
+                       break;
+               case 'o':
+                       id = *p++;
+                       closure->args[i].n = id;
+
+                       if (id == 0 && !arg.nullable) {
+                               wl_log("NULL object received on non-nullable "
+                                      "type, message %s(%s)\n", message->name,
+                                      message->signature);
+                               errno = EINVAL;
+                               goto err;
+                       }
+                       break;
+               case 'n':
+                       id = *p++;
+                       closure->args[i].n = id;
+
+                       if (id == 0 && !arg.nullable) {
+                               wl_log("NULL new ID received on non-nullable "
+                                      "type, message %s(%s)\n", message->name,
+                                      message->signature);
+                               errno = EINVAL;
+                               goto err;
+                       }
+
+                       if (wl_map_reserve_new(objects, id) < 0) {
+                               wl_log("not a valid new object id (%u), "
+                                      "message %s(%s)\n",
+                                      id, message->name, message->signature);
+                               errno = EINVAL;
+                               goto err;
+                       }
+
+                       break;
+               case 'a':
+                       length = *p++;
+
+                       next = p + DIV_ROUNDUP(length, sizeof *p);
+                       if (next > end) {
+                               wl_log("message too short, "
+                                      "object (%d), message %s(%s)\n",
+                                      closure->sender_id, message->name,
+                                      message->signature);
+                               errno = EINVAL;
+                               goto err;
+                       }
+
+                       array_extra->size = length;
+                       array_extra->alloc = 0;
+                       array_extra->data = p;
+
+                       closure->args[i].a = array_extra++;
+                       p = next;
+                       break;
+               case 'h':
+                       if (connection->fds_in.tail == connection->fds_in.head) {
+                               wl_log("file descriptor expected, "
+                                      "object (%d), message %s(%s)\n",
+                                      closure->sender_id, message->name,
+                                      message->signature);
+                               errno = EINVAL;
+                               goto err;
+                       }
+
+                       wl_buffer_copy(&connection->fds_in, &fd, sizeof fd);
+                       connection->fds_in.tail += sizeof fd;
+                       closure->args[i].h = fd;
+                       break;
+               default:
+                       wl_log("unknown type\n");
+                       assert(0);
+                       break;
+               }
+       }
+
+       closure->count = count;
+       closure->message = message;
+
+       wl_connection_consume(connection, size);
+
+       return closure;
+
+ err:
+       wl_closure_destroy(closure);
+       wl_connection_consume(connection, size);
+
+       return NULL;
+}
+
+int
+wl_interface_equal(const struct wl_interface *a, const struct wl_interface *b)
+{
+       /* In most cases the pointer equality test is sufficient.
+        * However, in some cases, depending on how things are split
+        * across shared objects, we can end up with multiple
+        * instances of the interface metadata constants.  So if the
+        * pointers match, the interfaces are equal, if they don't
+        * match we have to compare the interface names. */
+
+       return a == b || strcmp(a->name, b->name) == 0;
+}
+
+int
+wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects)
+{
+       struct wl_object *object;
+       const struct wl_message *message;
+       const char *signature;
+       struct argument_details arg;
+       int i, count;
+       uint32_t id;
+
+       message = closure->message;
+       signature = message->signature;
+       count = arg_count_for_signature(signature);
+       for (i = 0; i < count; i++) {
+               signature = get_next_argument(signature, &arg);
+               switch (arg.type) {
+               case 'o':
+                       id = closure->args[i].n;
+                       closure->args[i].o = NULL;
+
+                       object = wl_map_lookup(objects, id);
+                       if (object == WL_ZOMBIE_OBJECT) {
+                               /* references object we've already
+                                * destroyed client side */
+                               object = NULL;
+                       } else if (object == NULL && id != 0) {
+                               wl_log("unknown object (%u), message %s(%s)\n",
+                                      id, message->name, message->signature);
+                               object = NULL;
+                               errno = EINVAL;
+                               return -1;
+                       }
+
+                       if (object != NULL && message->types[i] != NULL &&
+                           !wl_interface_equal((object)->interface,
+                                               message->types[i])) {
+                               wl_log("invalid object (%u), type (%s), "
+                                      "message %s(%s)\n",
+                                      id, (object)->interface->name,
+                                      message->name, message->signature);
+                               errno = EINVAL;
+                               return -1;
+                       }
+                       closure->args[i].o = object;
+               }
+       }
+
+       return 0;
+}
+
+static void
+convert_arguments_to_ffi(const char *signature, uint32_t flags,
+                        union wl_argument *args,
+                        int count, ffi_type **ffi_types, void** ffi_args)
+{
+       int i;
+       const char *sig_iter;
+       struct argument_details arg;
+
+       sig_iter = signature;
+       for (i = 0; i < count; i++) {
+               sig_iter = get_next_argument(sig_iter, &arg);
+
+               switch(arg.type) {
+               case 'i':
+                       ffi_types[i] = &ffi_type_sint32;
+                       ffi_args[i] = &args[i].i;
+                       break;
+               case 'u':
+                       ffi_types[i] = &ffi_type_uint32;
+                       ffi_args[i] = &args[i].u;
+                       break;
+               case 'f':
+                       ffi_types[i] = &ffi_type_sint32;
+                       ffi_args[i] = &args[i].f;
+                       break;
+               case 's':
+                       ffi_types[i] = &ffi_type_pointer;
+                       ffi_args[i] = &args[i].s;
+                       break;
+               case 'o':
+                       ffi_types[i] = &ffi_type_pointer;
+                       ffi_args[i] = &args[i].o;
+                       break;
+               case 'n':
+                       if (flags & WL_CLOSURE_INVOKE_CLIENT) {
+                               ffi_types[i] = &ffi_type_pointer;
+                               ffi_args[i] = &args[i].o;
+                       } else {
+                               ffi_types[i] = &ffi_type_uint32;
+                               ffi_args[i] = &args[i].n;
+                       }
+                       break;
+               case 'a':
+                       ffi_types[i] = &ffi_type_pointer;
+                       ffi_args[i] = &args[i].a;
+                       break;
+               case 'h':
+                       ffi_types[i] = &ffi_type_sint32;
+                       ffi_args[i] = &args[i].h;
+                       break;
+               default:
+                       wl_log("unknown type\n");
+                       assert(0);
+                       break;
+               }
+       }
+}
+
+void
+wl_closure_invoke(struct wl_closure *closure, uint32_t flags,
+                 struct wl_object *target, uint32_t opcode, void *data)
+{
+       int count;
+       ffi_cif cif;
+       ffi_type *ffi_types[WL_CLOSURE_MAX_ARGS + 2];
+       void * ffi_args[WL_CLOSURE_MAX_ARGS + 2];
+       void (* const *implementation)(void);
+
+       count = arg_count_for_signature(closure->message->signature);
+
+       ffi_types[0] = &ffi_type_pointer;
+       ffi_args[0] = &data;
+       ffi_types[1] = &ffi_type_pointer;
+       ffi_args[1] = &target;
+
+       convert_arguments_to_ffi(closure->message->signature, flags, closure->args,
+                                count, ffi_types + 2, ffi_args + 2);
+
+       ffi_prep_cif(&cif, FFI_DEFAULT_ABI,
+                    count + 2, &ffi_type_void, ffi_types);
+
+       implementation = target->implementation;
+       if (!implementation[opcode]) {
+               wl_log("listener function for opcode %u of %s is NULL\n",
+                       opcode, target->interface->name);
+               abort();
+       }
+       ffi_call(&cif, implementation[opcode], NULL, ffi_args);
+}
+
+void
+wl_closure_dispatch(struct wl_closure *closure, wl_dispatcher_func_t dispatcher,
+                   struct wl_object *target, uint32_t opcode)
+{
+       dispatcher(target->implementation, target, opcode, closure->message,
+                  closure->args);
+}
+
+static int
+copy_fds_to_connection(struct wl_closure *closure,
+                      struct wl_connection *connection)
+{
+       const struct wl_message *message = closure->message;
+       uint32_t i, count;
+       struct argument_details arg;
+       const char *signature = message->signature;
+       int fd;
+
+       count = arg_count_for_signature(signature);
+       for (i = 0; i < count; i++) {
+               signature = get_next_argument(signature, &arg);
+               if (arg.type != 'h')
+                       continue;
+
+               fd = closure->args[i].h;
+               if (wl_connection_put_fd(connection, fd)) {
+                       wl_log("request could not be marshaled: "
+                              "can't send file descriptor");
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+
+static uint32_t
+buffer_size_for_closure(struct wl_closure *closure)
+{
+       const struct wl_message *message = closure->message;
+       int i, count;
+       struct argument_details arg;
+       const char *signature;
+       uint32_t size, buffer_size = 0;
+
+       signature = message->signature;
+       count = arg_count_for_signature(signature);
+       for (i = 0; i < count; i++) {
+               signature = get_next_argument(signature, &arg);
+
+               switch (arg.type) {
+               case 'h':
+                       break;
+               case 'u':
+               case 'i':
+               case 'f':
+               case 'o':
+               case 'n':
+                       buffer_size++;
+                       break;
+               case 's':
+                       if (closure->args[i].s == NULL) {
+                               buffer_size++;
+                               break;
+                       }
+
+                       size = strlen(closure->args[i].s) + 1;
+                       buffer_size += 1 + DIV_ROUNDUP(size, sizeof(uint32_t));
+                       break;
+               case 'a':
+                       if (closure->args[i].a == NULL) {
+                               buffer_size++;
+                               break;
+                       }
+
+                       size = closure->args[i].a->size;
+                       buffer_size += (1 + DIV_ROUNDUP(size, sizeof(uint32_t)));
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return buffer_size + 2;
+}
+
+static int
+serialize_closure(struct wl_closure *closure, uint32_t *buffer,
+                 size_t buffer_count)
+{
+       const struct wl_message *message = closure->message;
+       unsigned int i, count, size;
+       uint32_t *p, *end;
+       struct argument_details arg;
+       const char *signature;
+
+       if (buffer_count < 2)
+               goto overflow;
+
+       p = buffer + 2;
+       end = buffer + buffer_count;
+
+       signature = message->signature;
+       count = arg_count_for_signature(signature);
+       for (i = 0; i < count; i++) {
+               signature = get_next_argument(signature, &arg);
+
+               if (arg.type == 'h')
+                       continue;
+
+               if (p + 1 > end)
+                       goto overflow;
+
+               switch (arg.type) {
+               case 'u':
+                       *p++ = closure->args[i].u;
+                       break;
+               case 'i':
+                       *p++ = closure->args[i].i;
+                       break;
+               case 'f':
+                       *p++ = closure->args[i].f;
+                       break;
+               case 'o':
+                       *p++ = closure->args[i].o ? closure->args[i].o->id : 0;
+                       break;
+               case 'n':
+                       *p++ = closure->args[i].n;
+                       break;
+               case 's':
+                       if (closure->args[i].s == NULL) {
+                               *p++ = 0;
+                               break;
+                       }
+
+                       size = strlen(closure->args[i].s) + 1;
+                       *p++ = size;
+
+                       if (p + DIV_ROUNDUP(size, sizeof *p) > end)
+                               goto overflow;
+
+                       memcpy(p, closure->args[i].s, size);
+                       p += DIV_ROUNDUP(size, sizeof *p);
+                       break;
+               case 'a':
+                       if (closure->args[i].a == NULL) {
+                               *p++ = 0;
+                               break;
+                       }
+
+                       size = closure->args[i].a->size;
+                       *p++ = size;
+
+                       if (p + DIV_ROUNDUP(size, sizeof *p) > end)
+                               goto overflow;
+
+                       memcpy(p, closure->args[i].a->data, size);
+                       p += DIV_ROUNDUP(size, sizeof *p);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       size = (p - buffer) * sizeof *p;
+
+       buffer[0] = closure->sender_id;
+       buffer[1] = size << 16 | (closure->opcode & 0x0000ffff);
+
+       return size;
+
+overflow:
+       errno = ERANGE;
+       return -1;
+}
+
+int
+wl_closure_send(struct wl_closure *closure, struct wl_connection *connection)
+{
+       int size;
+       uint32_t buffer_size;
+       uint32_t *buffer;
+       int result;
+
+       if (copy_fds_to_connection(closure, connection))
+               return -1;
+
+       buffer_size = buffer_size_for_closure(closure);
+       buffer = malloc(buffer_size * sizeof buffer[0]);
+       if (buffer == NULL)
+               return -1;
+
+       size = serialize_closure(closure, buffer, buffer_size);
+       if (size < 0) {
+               free(buffer);
+               return -1;
+       }
+
+       result = wl_connection_write(connection, buffer, size);
+       free(buffer);
+
+       return result;
+}
+
+int
+wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection)
+{
+       int size;
+       uint32_t buffer_size;
+       uint32_t *buffer;
+       int result;
+
+       if (copy_fds_to_connection(closure, connection))
+               return -1;
+
+       buffer_size = buffer_size_for_closure(closure);
+       buffer = malloc(buffer_size * sizeof buffer[0]);
+       if (buffer == NULL)
+               return -1;
+
+       size = serialize_closure(closure, buffer, buffer_size);
+       if (size < 0) {
+               free(buffer);
+               return -1;
+       }
+
+       result = wl_connection_queue(connection, buffer, size);
+       free(buffer);
+
+       return result;
+}
+
+void
+wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send)
+{
+       int i;
+       struct argument_details arg;
+       const char *signature = closure->message->signature;
+       struct timespec tp;
+       unsigned int time;
+
+       clock_gettime(CLOCK_REALTIME, &tp);
+       time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
+
+       fprintf(stderr, "[%10.3f] %s%s@%u.%s(",
+               time / 1000.0,
+               send ? " -> " : "",
+               target->interface->name, target->id,
+               closure->message->name);
+
+       for (i = 0; i < closure->count; i++) {
+               signature = get_next_argument(signature, &arg);
+               if (i > 0)
+                       fprintf(stderr, ", ");
+
+               switch (arg.type) {
+               case 'u':
+                       fprintf(stderr, "%u", closure->args[i].u);
+                       break;
+               case 'i':
+                       fprintf(stderr, "%d", closure->args[i].i);
+                       break;
+               case 'f':
+                       fprintf(stderr, "%f",
+                               wl_fixed_to_double(closure->args[i].f));
+                       break;
+               case 's':
+                       fprintf(stderr, "\"%s\"", closure->args[i].s);
+                       break;
+               case 'o':
+                       if (closure->args[i].o)
+                               fprintf(stderr, "%s@%u",
+                                       closure->args[i].o->interface->name,
+                                       closure->args[i].o->id);
+                       else
+                               fprintf(stderr, "nil");
+                       break;
+               case 'n':
+                       fprintf(stderr, "new id %s@",
+                               (closure->message->types[i]) ?
+                                closure->message->types[i]->name :
+                                 "[unknown]");
+                       if (closure->args[i].n != 0)
+                               fprintf(stderr, "%u", closure->args[i].n);
+                       else
+                               fprintf(stderr, "nil");
+                       break;
+               case 'a':
+                       fprintf(stderr, "array");
+                       break;
+               case 'h':
+                       fprintf(stderr, "fd %d", closure->args[i].h);
+                       break;
+               }
+       }
+
+       fprintf(stderr, ")\n");
+}
+
+void
+wl_closure_destroy(struct wl_closure *closure)
+{
+       free(closure);
+}
diff --git a/src/event-loop.c b/src/event-loop.c
new file mode 100644 (file)
index 0000000..d257d78
--- /dev/null
@@ -0,0 +1,452 @@
+/*
+ * 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 <stddef.h>
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/epoll.h>
+#include <sys/signalfd.h>
+#include <sys/timerfd.h>
+#include <unistd.h>
+#include <assert.h>
+#include "wayland-private.h"
+#include "wayland-server.h"
+#include "wayland-os.h"
+
+struct wl_event_loop {
+       int epoll_fd;
+       struct wl_list check_list;
+       struct wl_list idle_list;
+       struct wl_list destroy_list;
+
+       struct wl_signal destroy_signal;
+};
+
+struct wl_event_source_interface {
+       int (*dispatch)(struct wl_event_source *source,
+                       struct epoll_event *ep);
+};
+
+struct wl_event_source {
+       struct wl_event_source_interface *interface;
+       struct wl_event_loop *loop;
+       struct wl_list link;
+       void *data;
+       int fd;
+};
+
+struct wl_event_source_fd {
+       struct wl_event_source base;
+       wl_event_loop_fd_func_t func;
+       int fd;
+};
+
+static int
+wl_event_source_fd_dispatch(struct wl_event_source *source,
+                           struct epoll_event *ep)
+{
+       struct wl_event_source_fd *fd_source = (struct wl_event_source_fd *) source;
+       uint32_t mask;
+
+       mask = 0;
+       if (ep->events & EPOLLIN)
+               mask |= WL_EVENT_READABLE;
+       if (ep->events & EPOLLOUT)
+               mask |= WL_EVENT_WRITABLE;
+       if (ep->events & EPOLLHUP)
+               mask |= WL_EVENT_HANGUP;
+       if (ep->events & EPOLLERR)
+               mask |= WL_EVENT_ERROR;
+
+       return fd_source->func(fd_source->fd, mask, source->data);
+}
+
+struct wl_event_source_interface fd_source_interface = {
+       wl_event_source_fd_dispatch,
+};
+
+static struct wl_event_source *
+add_source(struct wl_event_loop *loop,
+          struct wl_event_source *source, uint32_t mask, void *data)
+{
+       struct epoll_event ep;
+
+       if (source->fd < 0) {
+               free(source);
+               return NULL;
+       }
+
+       source->loop = loop;
+       source->data = data;
+       wl_list_init(&source->link);
+
+       memset(&ep, 0, sizeof ep);
+       if (mask & WL_EVENT_READABLE)
+               ep.events |= EPOLLIN;
+       if (mask & WL_EVENT_WRITABLE)
+               ep.events |= EPOLLOUT;
+       ep.data.ptr = source;
+
+       if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, source->fd, &ep) < 0) {
+               close(source->fd);
+               free(source);
+               return NULL;
+       }
+
+       return source;
+}
+
+WL_EXPORT struct wl_event_source *
+wl_event_loop_add_fd(struct wl_event_loop *loop,
+                    int fd, uint32_t mask,
+                    wl_event_loop_fd_func_t func,
+                    void *data)
+{
+       struct wl_event_source_fd *source;
+
+       source = malloc(sizeof *source);
+       if (source == NULL)
+               return NULL;
+
+       source->base.interface = &fd_source_interface;
+       source->base.fd = wl_os_dupfd_cloexec(fd, 0);
+       source->func = func;
+       source->fd = fd;
+
+       return add_source(loop, &source->base, mask, data);
+}
+
+WL_EXPORT int
+wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask)
+{
+       struct wl_event_loop *loop = source->loop;
+       struct epoll_event ep;
+
+       memset(&ep, 0, sizeof ep);
+       if (mask & WL_EVENT_READABLE)
+               ep.events |= EPOLLIN;
+       if (mask & WL_EVENT_WRITABLE)
+               ep.events |= EPOLLOUT;
+       ep.data.ptr = source;
+
+       return epoll_ctl(loop->epoll_fd, EPOLL_CTL_MOD, source->fd, &ep);
+}
+
+struct wl_event_source_timer {
+       struct wl_event_source base;
+       wl_event_loop_timer_func_t func;
+};
+
+static int
+wl_event_source_timer_dispatch(struct wl_event_source *source,
+                              struct epoll_event *ep)
+{
+       struct wl_event_source_timer *timer_source =
+               (struct wl_event_source_timer *) source;
+       uint64_t expires;
+       int len;
+
+       len = read(source->fd, &expires, sizeof expires);
+       if (!(len == -1 && errno == EAGAIN) && len != sizeof expires)
+               /* Is there anything we can do here?  Will this ever happen? */
+               wl_log("timerfd read error: %m\n");
+
+       return timer_source->func(timer_source->base.data);
+}
+
+struct wl_event_source_interface timer_source_interface = {
+       wl_event_source_timer_dispatch,
+};
+
+WL_EXPORT struct wl_event_source *
+wl_event_loop_add_timer(struct wl_event_loop *loop,
+                       wl_event_loop_timer_func_t func,
+                       void *data)
+{
+       struct wl_event_source_timer *source;
+
+       source = malloc(sizeof *source);
+       if (source == NULL)
+               return NULL;
+
+       source->base.interface = &timer_source_interface;
+       source->base.fd = timerfd_create(CLOCK_MONOTONIC,
+                                                                        TFD_CLOEXEC | TFD_NONBLOCK);
+       source->func = func;
+
+       return add_source(loop, &source->base, WL_EVENT_READABLE, data);
+}
+
+WL_EXPORT int
+wl_event_source_timer_update(struct wl_event_source *source, int ms_delay)
+{
+       struct itimerspec its;
+
+       its.it_interval.tv_sec = 0;
+       its.it_interval.tv_nsec = 0;
+       its.it_value.tv_sec = ms_delay / 1000;
+       its.it_value.tv_nsec = (ms_delay % 1000) * 1000 * 1000;
+       if (timerfd_settime(source->fd, 0, &its, NULL) < 0)
+               return -1;
+
+       return 0;
+}
+
+struct wl_event_source_signal {
+       struct wl_event_source base;
+       int signal_number;
+       wl_event_loop_signal_func_t func;
+};
+
+static int
+wl_event_source_signal_dispatch(struct wl_event_source *source,
+                              struct epoll_event *ep)
+{
+       struct wl_event_source_signal *signal_source =
+               (struct wl_event_source_signal *) source;
+       struct signalfd_siginfo signal_info;
+       int len;
+
+       len = read(source->fd, &signal_info, sizeof signal_info);
+       if (!(len == -1 && errno == EAGAIN) && len != sizeof signal_info)
+               /* Is there anything we can do here?  Will this ever happen? */
+               wl_log("signalfd read error: %m\n");
+
+       return signal_source->func(signal_source->signal_number,
+                                  signal_source->base.data);
+}
+
+struct wl_event_source_interface signal_source_interface = {
+       wl_event_source_signal_dispatch,
+};
+
+WL_EXPORT struct wl_event_source *
+wl_event_loop_add_signal(struct wl_event_loop *loop,
+                       int signal_number,
+                       wl_event_loop_signal_func_t func,
+                       void *data)
+{
+       struct wl_event_source_signal *source;
+       sigset_t mask;
+
+       source = malloc(sizeof *source);
+       if (source == NULL)
+               return NULL;
+
+       source->base.interface = &signal_source_interface;
+       source->signal_number = signal_number;
+
+       sigemptyset(&mask);
+       sigaddset(&mask, signal_number);
+       source->base.fd = signalfd(-1, &mask, SFD_CLOEXEC | SFD_NONBLOCK);
+       sigprocmask(SIG_BLOCK, &mask, NULL);
+
+       source->func = func;
+
+       return add_source(loop, &source->base, WL_EVENT_READABLE, data);
+}
+
+struct wl_event_source_idle {
+       struct wl_event_source base;
+       wl_event_loop_idle_func_t func;
+};
+
+struct wl_event_source_interface idle_source_interface = {
+       NULL,
+};
+
+WL_EXPORT struct wl_event_source *
+wl_event_loop_add_idle(struct wl_event_loop *loop,
+                      wl_event_loop_idle_func_t func,
+                      void *data)
+{
+       struct wl_event_source_idle *source;
+
+       source = malloc(sizeof *source);
+       if (source == NULL)
+               return NULL;
+
+       source->base.interface = &idle_source_interface;
+       source->base.loop = loop;
+       source->base.fd = -1;
+
+       source->func = func;
+       source->base.data = data;
+
+       wl_list_insert(loop->idle_list.prev, &source->base.link);
+
+       return &source->base;
+}
+
+WL_EXPORT void
+wl_event_source_check(struct wl_event_source *source)
+{
+       wl_list_insert(source->loop->check_list.prev, &source->link);
+}
+
+WL_EXPORT int
+wl_event_source_remove(struct wl_event_source *source)
+{
+       struct wl_event_loop *loop = source->loop;
+
+       /* We need to explicitly remove the fd, since closing the fd
+        * isn't enough in case we've dup'ed the fd. */
+       if (source->fd >= 0) {
+               epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, source->fd, NULL);
+               close(source->fd);
+               source->fd = -1;
+       }
+
+       wl_list_remove(&source->link);
+       wl_list_insert(&loop->destroy_list, &source->link);
+
+       return 0;
+}
+
+static void
+wl_event_loop_process_destroy_list(struct wl_event_loop *loop)
+{
+       struct wl_event_source *source, *next;
+
+       wl_list_for_each_safe(source, next, &loop->destroy_list, link)
+               free(source);
+
+       wl_list_init(&loop->destroy_list);
+}
+
+WL_EXPORT struct wl_event_loop *
+wl_event_loop_create(void)
+{
+       struct wl_event_loop *loop;
+
+       loop = malloc(sizeof *loop);
+       if (loop == NULL)
+               return NULL;
+
+       loop->epoll_fd = wl_os_epoll_create_cloexec();
+       if (loop->epoll_fd < 0) {
+               free(loop);
+               return NULL;
+       }
+       wl_list_init(&loop->check_list);
+       wl_list_init(&loop->idle_list);
+       wl_list_init(&loop->destroy_list);
+
+       wl_signal_init(&loop->destroy_signal);
+
+       return loop;
+}
+
+WL_EXPORT void
+wl_event_loop_destroy(struct wl_event_loop *loop)
+{
+       wl_signal_emit(&loop->destroy_signal, loop);
+
+       wl_event_loop_process_destroy_list(loop);
+       close(loop->epoll_fd);
+       free(loop);
+}
+
+static int
+post_dispatch_check(struct wl_event_loop *loop)
+{
+       struct epoll_event ep;
+       struct wl_event_source *source, *next;
+       int n;
+
+       ep.events = 0;
+       n = 0;
+       wl_list_for_each_safe(source, next, &loop->check_list, link)
+               n += source->interface->dispatch(source, &ep);
+
+       return n;
+}
+
+WL_EXPORT void
+wl_event_loop_dispatch_idle(struct wl_event_loop *loop)
+{
+       struct wl_event_source_idle *source;
+
+       while (!wl_list_empty(&loop->idle_list)) {
+               source = container_of(loop->idle_list.next,
+                                     struct wl_event_source_idle, base.link);
+               source->func(source->base.data);
+               wl_event_source_remove(&source->base);
+       }
+}
+
+WL_EXPORT int
+wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout)
+{
+       struct epoll_event ep[32];
+       struct wl_event_source *source;
+       int i, count, n;
+
+       wl_event_loop_dispatch_idle(loop);
+
+       count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
+       if (count < 0)
+               return -1;
+
+       for (i = 0; i < count; i++) {
+               source = ep[i].data.ptr;
+               if (source->fd != -1)
+                       source->interface->dispatch(source, &ep[i]);
+       }
+
+       wl_event_loop_process_destroy_list(loop);
+
+       wl_event_loop_dispatch_idle(loop);
+
+       do {
+               n = post_dispatch_check(loop);
+       } while (n > 0);
+
+       return 0;
+}
+
+WL_EXPORT int
+wl_event_loop_get_fd(struct wl_event_loop *loop)
+{
+       return loop->epoll_fd;
+}
+
+WL_EXPORT void
+wl_event_loop_add_destroy_listener(struct wl_event_loop *loop,
+                                  struct wl_listener *listener)
+{
+       wl_signal_add(&loop->destroy_signal, listener);
+}
+
+WL_EXPORT struct wl_listener *
+wl_event_loop_get_destroy_listener(struct wl_event_loop *loop,
+                                  wl_notify_func_t notify)
+{
+       return wl_signal_get(&loop->destroy_signal, notify);
+}
+
diff --git a/src/scanner.c b/src/scanner.c
new file mode 100644 (file)
index 0000000..1f1e59a
--- /dev/null
@@ -0,0 +1,1326 @@
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2011 Intel Corporation
+ *
+ * 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 <stdbool.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <expat.h>
+
+#include "wayland-util.h"
+
+enum side {
+       CLIENT,
+       SERVER,
+};
+
+static int
+usage(int ret)
+{
+       fprintf(stderr, "usage: ./scanner [client-header|server-header|code]\n");
+       fprintf(stderr, "\n");
+       fprintf(stderr, "Converts XML protocol descriptions supplied on "
+                       "stdin to client headers,\n"
+                       "server headers, or protocol marshalling code.\n");
+       exit(ret);
+}
+
+#define XML_BUFFER_SIZE 4096
+
+struct location {
+       const char *filename;
+       int line_number;
+};
+
+struct description {
+       char *summary;
+       char *text;
+};
+
+struct protocol {
+       char *name;
+       char *uppercase_name;
+       struct wl_list interface_list;
+       int type_index;
+       int null_run_length;
+       char *copyright;
+       struct description *description;
+};
+
+struct interface {
+       struct location loc;
+       char *name;
+       char *uppercase_name;
+       int version;
+       int since;
+       struct wl_list request_list;
+       struct wl_list event_list;
+       struct wl_list enumeration_list;
+       struct wl_list link;
+       struct description *description;
+};
+
+struct message {
+       struct location loc;
+       char *name;
+       char *uppercase_name;
+       struct wl_list arg_list;
+       struct wl_list link;
+       int arg_count;
+       int new_id_count;
+       int type_index;
+       int all_null;
+       int destructor;
+       int since;
+       struct description *description;
+};
+
+enum arg_type {
+       NEW_ID,
+       INT,
+       UNSIGNED,
+       FIXED,
+       STRING,
+       OBJECT,
+       ARRAY,
+       FD
+};
+
+struct arg {
+       char *name;
+       enum arg_type type;
+       int nullable;
+       char *interface_name;
+       struct wl_list link;
+       char *summary;
+};
+
+struct enumeration {
+       char *name;
+       char *uppercase_name;
+       struct wl_list entry_list;
+       struct wl_list link;
+       struct description *description;
+};
+
+struct entry {
+       char *name;
+       char *uppercase_name;
+       char *value;
+       char *summary;
+       struct wl_list link;
+};
+
+struct parse_context {
+       struct location loc;
+       XML_Parser parser;
+       struct protocol *protocol;
+       struct interface *interface;
+       struct message *message;
+       struct enumeration *enumeration;
+       struct description *description;
+       char character_data[8192];
+       unsigned int character_data_length;
+};
+
+static void *
+fail_on_null(void *p)
+{
+       if (p == NULL) {
+               fprintf(stderr, "wayland-scanner: out of memory\n");
+               exit(EXIT_FAILURE);
+       }
+
+       return p;
+}
+
+static void *
+xmalloc(size_t s)
+{
+       return fail_on_null(malloc(s));
+}
+
+static char *
+xstrdup(const char *s)
+{
+       return fail_on_null(strdup(s));
+}
+
+static char *
+uppercase_dup(const char *src)
+{
+       char *u;
+       int i;
+
+       u = xstrdup(src);
+       for (i = 0; u[i]; i++)
+               u[i] = toupper(u[i]);
+       u[i] = '\0';
+
+       return u;
+}
+
+static const char *indent(int n)
+{
+       const char *whitespace[] = {
+               "\t\t\t\t\t\t\t\t\t\t\t\t",
+               "\t\t\t\t\t\t\t\t\t\t\t\t ",
+               "\t\t\t\t\t\t\t\t\t\t\t\t  ",
+               "\t\t\t\t\t\t\t\t\t\t\t\t   ",
+               "\t\t\t\t\t\t\t\t\t\t\t\t    ",
+               "\t\t\t\t\t\t\t\t\t\t\t\t     ",
+               "\t\t\t\t\t\t\t\t\t\t\t\t      ",
+               "\t\t\t\t\t\t\t\t\t\t\t\t       "
+       };
+
+       return whitespace[n % 8] + 12 - n / 8;
+}
+
+static void
+desc_dump(char *desc, const char *fmt, ...) WL_PRINTF(2, 3);
+
+static void
+desc_dump(char *desc, const char *fmt, ...)
+{
+       va_list ap;
+       char buf[128], hang;
+       int col, i, j, k, startcol, newlines;
+
+       va_start(ap, fmt);
+       vsnprintf(buf, sizeof buf, fmt, ap);
+       va_end(ap);
+
+       for (i = 0, col = 0; buf[i] != '*'; i++) {
+               if (buf[i] == '\t')
+                       col = (col + 8) & ~7;
+               else
+                       col++;
+       }
+
+       printf("%s", buf);
+
+       if (!desc) {
+               printf("(none)\n");
+               return;
+       }
+
+       startcol = col;
+       col += strlen(&buf[i]);
+       if (col - startcol > 2)
+               hang = '\t';
+       else
+               hang = ' ';
+
+       for (i = 0; desc[i]; ) {
+               k = i;
+               newlines = 0;
+               while (desc[i] && isspace(desc[i])) {
+                       if (desc[i] == '\n')
+                               newlines++;
+                       i++;
+               }
+               if (!desc[i])
+                       break;
+
+               j = i;
+               while (desc[i] && !isspace(desc[i]))
+                       i++;
+
+               if (newlines > 1)
+                       printf("\n%s*", indent(startcol));
+               if (newlines > 1 || col + i - j > 72) {
+                       printf("\n%s*%c", indent(startcol), hang);
+                       col = startcol;
+               }
+
+               if (col > startcol && k > 0)
+                       col += printf(" ");
+               col += printf("%.*s", i - j, &desc[j]);
+       }
+       putchar('\n');
+}
+
+static void
+fail(struct location *loc, const char *msg, ...)
+{
+       va_list ap;
+
+       va_start(ap, msg);
+       fprintf(stderr, "%s:%d: error: ",
+               loc->filename, loc->line_number);
+       vfprintf(stderr, msg, ap);
+       fprintf(stderr, "\n");
+       va_end(ap);
+       exit(EXIT_FAILURE);
+}
+
+static void
+warn(struct location *loc, const char *msg, ...)
+{
+       va_list ap;
+
+       va_start(ap, msg);
+       fprintf(stderr, "%s:%d: warning: ",
+               loc->filename, loc->line_number);
+       vfprintf(stderr, msg, ap);
+       fprintf(stderr, "\n");
+       va_end(ap);
+}
+
+static bool
+is_nullable_type(struct arg *arg)
+{
+       switch (arg->type) {
+       /* Strings, objects, and arrays are possibly nullable */
+       case STRING:
+       case OBJECT:
+       case NEW_ID:
+       case ARRAY:
+               return true;
+       default:
+               return false;
+       }
+}
+
+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;
+       struct enumeration *enumeration;
+       struct entry *entry;
+       struct description *description;
+       const char *name, *type, *interface_name, *value, *summary, *since;
+       const char *allow_null;
+       char *end;
+       int i, version;
+
+       ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser);
+       name = NULL;
+       type = NULL;
+       version = 0;
+       interface_name = NULL;
+       value = NULL;
+       summary = NULL;
+       description = NULL;
+       since = NULL;
+       allow_null = NULL;
+       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(atts[i], "value") == 0)
+                       value = atts[i + 1];
+               if (strcmp(atts[i], "interface") == 0)
+                       interface_name = atts[i + 1];
+               if (strcmp(atts[i], "summary") == 0)
+                       summary = atts[i + 1];
+               if (strcmp(atts[i], "since") == 0)
+                       since = atts[i + 1];
+               if (strcmp(atts[i], "allow-null") == 0)
+                       allow_null = atts[i + 1];
+       }
+
+       ctx->character_data_length = 0;
+       if (strcmp(element_name, "protocol") == 0) {
+               if (name == NULL)
+                       fail(&ctx->loc, "no protocol name given");
+
+               ctx->protocol->name = xstrdup(name);
+               ctx->protocol->uppercase_name = uppercase_dup(name);
+               ctx->protocol->description = NULL;
+       } else if (strcmp(element_name, "copyright") == 0) {
+               
+       } else if (strcmp(element_name, "interface") == 0) {
+               if (name == NULL)
+                       fail(&ctx->loc, "no interface name given");
+
+               if (version == 0)
+                       fail(&ctx->loc, "no interface version given");
+
+               interface = xmalloc(sizeof *interface);
+               interface->loc = ctx->loc;
+               interface->name = xstrdup(name);
+               interface->uppercase_name = uppercase_dup(name);
+               interface->version = version;
+               interface->description = NULL;
+               interface->since = 1;
+               wl_list_init(&interface->request_list);
+               wl_list_init(&interface->event_list);
+               wl_list_init(&interface->enumeration_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)
+                       fail(&ctx->loc, "no request name given");
+
+               message = xmalloc(sizeof *message);
+               message->loc = ctx->loc;
+               message->name = xstrdup(name);
+               message->uppercase_name = uppercase_dup(name);
+               wl_list_init(&message->arg_list);
+               message->arg_count = 0;
+               message->new_id_count = 0;
+               message->description = NULL;
+
+               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);
+
+               if (type != NULL && strcmp(type, "destructor") == 0)
+                       message->destructor = 1;
+               else
+                       message->destructor = 0;
+
+               if (since != NULL) {
+                       int prev_errno = errno;
+                       errno = 0;
+                       version = strtol(since, &end, 0);
+                       if (errno != 0 || end == since || *end != '\0')
+                               fail(&ctx->loc,
+                                    "invalid integer (%s)\n", since);
+                       errno = prev_errno;
+               } else {
+                       version = 1;
+               }
+
+               if (version < ctx->interface->since)
+                       warn(&ctx->loc, "since version not increasing\n");
+               ctx->interface->since = version;
+               message->since = version;
+
+               if (strcmp(name, "destroy") == 0 && !message->destructor)
+                       fail(&ctx->loc, "destroy request should be destructor type");
+
+               ctx->message = message;
+       } else if (strcmp(element_name, "arg") == 0) {
+               if (name == NULL)
+                       fail(&ctx->loc, "no argument name given");
+
+               arg = xmalloc(sizeof *arg);
+               arg->name = xstrdup(name);
+
+               if (strcmp(type, "int") == 0)
+                       arg->type = INT;
+               else if (strcmp(type, "uint") == 0)
+                       arg->type = UNSIGNED;
+               else if (strcmp(type, "fixed") == 0)
+                       arg->type = FIXED;
+               else if (strcmp(type, "string") == 0)
+                       arg->type = STRING;
+               else if (strcmp(type, "array") == 0)
+                       arg->type = ARRAY;
+               else if (strcmp(type, "fd") == 0)
+                       arg->type = FD;
+               else if (strcmp(type, "new_id") == 0) {
+                       arg->type = NEW_ID;
+               } else if (strcmp(type, "object") == 0) {
+                       arg->type = OBJECT;
+               } else {
+                       fail(&ctx->loc, "unknown type (%s)", type);
+               }
+
+               switch (arg->type) {
+               case NEW_ID:
+                       ctx->message->new_id_count++;
+
+                       /* Fall through to OBJECT case. */
+
+               case OBJECT:
+                       if (interface_name)
+                               arg->interface_name = xstrdup(interface_name);
+                       else
+                               arg->interface_name = NULL;
+                       break;
+               default:
+                       if (interface_name != NULL)
+                               fail(&ctx->loc, "interface attribute not allowed for type %s", type);
+                       break;
+               }
+
+               if (allow_null == NULL || strcmp(allow_null, "false") == 0)
+                       arg->nullable = 0;
+               else if (strcmp(allow_null, "true") == 0)
+                       arg->nullable = 1;
+               else
+                       fail(&ctx->loc, "invalid value for allow-null attribute (%s)", allow_null);
+
+               if (allow_null != NULL && !is_nullable_type(arg))
+                       fail(&ctx->loc, "allow-null is only valid for objects, strings, and arrays");
+
+               arg->summary = NULL;
+               if (summary)
+                       arg->summary = xstrdup(summary);
+
+               wl_list_insert(ctx->message->arg_list.prev, &arg->link);
+               ctx->message->arg_count++;
+       } else if (strcmp(element_name, "enum") == 0) {
+               if (name == NULL)
+                       fail(&ctx->loc, "no enum name given");
+
+               enumeration = xmalloc(sizeof *enumeration);
+               enumeration->name = xstrdup(name);
+               enumeration->uppercase_name = uppercase_dup(name);
+               enumeration->description = NULL;
+               wl_list_init(&enumeration->entry_list);
+
+               wl_list_insert(ctx->interface->enumeration_list.prev,
+                              &enumeration->link);
+
+               ctx->enumeration = enumeration;
+       } else if (strcmp(element_name, "entry") == 0) {
+               if (name == NULL)
+                       fail(&ctx->loc, "no entry name given");
+
+               entry = xmalloc(sizeof *entry);
+               entry->name = xstrdup(name);
+               entry->uppercase_name = uppercase_dup(name);
+               entry->value = xstrdup(value);
+               if (summary)
+                       entry->summary = xstrdup(summary);
+               else
+                       entry->summary = NULL;
+               wl_list_insert(ctx->enumeration->entry_list.prev,
+                              &entry->link);
+       } else if (strcmp(element_name, "description") == 0) {
+               if (summary == NULL)
+                       fail(&ctx->loc, "description without summary");
+
+               description = xmalloc(sizeof *description);
+               description->summary = xstrdup(summary);
+
+               if (ctx->message)
+                       ctx->message->description = description;
+               else if (ctx->enumeration)
+                       ctx->enumeration->description = description;
+               else if (ctx->interface)
+                       ctx->interface->description = description;
+               else
+                       ctx->protocol->description = description;
+               ctx->description = description;
+       }
+}
+
+static void
+end_element(void *data, const XML_Char *name)
+{
+       struct parse_context *ctx = data;
+
+       if (strcmp(name, "copyright") == 0) {
+               ctx->protocol->copyright =
+                       strndup(ctx->character_data,
+                               ctx->character_data_length);
+       } else if (strcmp(name, "description") == 0) {
+               ctx->description->text =
+                       strndup(ctx->character_data,
+                               ctx->character_data_length);
+               ctx->description = NULL;
+       } else if (strcmp(name, "request") == 0 ||
+                  strcmp(name, "event") == 0) {
+               ctx->message = NULL;
+       } else if (strcmp(name, "enum") == 0) {
+               ctx->enumeration = NULL;
+       }
+}
+
+static void
+character_data(void *data, const XML_Char *s, int len)
+{
+       struct parse_context *ctx = data;
+
+       if (ctx->character_data_length + len > sizeof (ctx->character_data)) {
+               fprintf(stderr, "too much character data");
+               exit(EXIT_FAILURE);
+           }
+
+       memcpy(ctx->character_data + ctx->character_data_length, s, len);
+       ctx->character_data_length += len;
+}
+
+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 %s_%s\t%d\n",
+                      interface->uppercase_name, m->uppercase_name, opcode++);
+
+       printf("\n");
+}
+
+static void
+emit_opcode_versions(struct wl_list *message_list, struct interface *interface)
+{
+       struct message *m;
+
+       wl_list_for_each(m, message_list, link)
+               printf("#define %s_%s_SINCE_VERSION\t%d\n",
+                      interface->uppercase_name, m->uppercase_name, m->since);
+
+       printf("\n");
+}
+
+static void
+emit_type(struct arg *a)
+{
+       switch (a->type) {
+       default:
+       case INT:
+       case FD:
+               printf("int32_t ");
+               break;
+       case NEW_ID:
+       case UNSIGNED:
+               printf("uint32_t ");
+               break;
+       case FIXED:
+               printf("wl_fixed_t ");
+               break;
+       case STRING:
+               printf("const char *");
+               break;
+       case OBJECT:
+               printf("struct %s *", a->interface_name);
+               break;
+       case ARRAY:
+               printf("struct wl_array *");
+               break;
+       }
+}
+
+static void
+emit_stubs(struct wl_list *message_list, struct interface *interface)
+{
+       struct message *m;
+       struct arg *a, *ret;
+       int has_destructor, has_destroy;
+
+       printf("static inline void\n"
+              "%s_set_user_data(struct %s *%s, void *user_data)\n"
+              "{\n"
+              "\twl_proxy_set_user_data((struct wl_proxy *) %s, user_data);\n"
+              "}\n\n",
+              interface->name, interface->name, interface->name,
+              interface->name);
+
+       printf("static inline void *\n"
+              "%s_get_user_data(struct %s *%s)\n"
+              "{\n"
+              "\treturn wl_proxy_get_user_data((struct wl_proxy *) %s);\n"
+              "}\n\n",
+              interface->name, interface->name, interface->name,
+              interface->name);
+
+       has_destructor = 0;
+       has_destroy = 0;
+       wl_list_for_each(m, message_list, link) {
+               if (m->destructor)
+                       has_destructor = 1;
+               if (strcmp(m->name, "destroy") == 0)
+                       has_destroy = 1;
+       }
+
+       if (!has_destructor && has_destroy) {
+               fail(&interface->loc,
+                    "interface '%s' has method named destroy "
+                    "but no destructor",
+                    interface->name);
+               exit(EXIT_FAILURE);
+       }
+
+       if (!has_destroy && strcmp(interface->name, "wl_display") != 0)
+               printf("static inline void\n"
+                      "%s_destroy(struct %s *%s)\n"
+                      "{\n"
+                      "\twl_proxy_destroy("
+                      "(struct wl_proxy *) %s);\n"
+                      "}\n\n",
+                      interface->name, interface->name, interface->name,
+                      interface->name);
+
+       if (wl_list_empty(message_list))
+               return;
+
+       wl_list_for_each(m, message_list, link) {
+               if (m->new_id_count > 1) {
+                       warn(&m->loc,
+                            "request '%s::%s' has more than "
+                            "one new_id arg, not emitting stub\n",
+                            interface->name, m->name);
+                       continue;
+               }
+
+               ret = NULL;
+               wl_list_for_each(a, &m->arg_list, link) {
+                       if (a->type == NEW_ID)
+                               ret = a;
+               }
+
+               if (ret && ret->interface_name == NULL)
+                       printf("static inline void *\n");
+               else if (ret)
+                       printf("static inline struct %s *\n",
+                              ret->interface_name);
+               else
+                       printf("static inline void\n");
+
+               printf("%s_%s(struct %s *%s",
+                      interface->name, m->name,
+                      interface->name, interface->name);
+
+               wl_list_for_each(a, &m->arg_list, link) {
+                       if (a->type == NEW_ID && a->interface_name == NULL) {
+                               printf(", const struct wl_interface *interface"
+                                      ", uint32_t version");
+                               continue;
+                       } else if (a->type == NEW_ID)
+                               continue;
+                       printf(", ");
+                       emit_type(a);
+                       printf("%s", a->name);
+               }
+
+               printf(")\n"
+                      "{\n");
+               if (ret) {
+                       printf("\tstruct wl_proxy *%s;\n\n"
+                              "\t%s = wl_proxy_marshal_constructor("
+                              "(struct wl_proxy *) %s,\n"
+                              "\t\t\t %s_%s, ",
+                              ret->name, ret->name,
+                              interface->name,
+                              interface->uppercase_name,
+                              m->uppercase_name);
+
+                       if (ret->interface_name == NULL)
+                               printf("interface");
+                       else
+                               printf("&%s_interface", ret->interface_name);
+               } else {
+                       printf("\twl_proxy_marshal((struct wl_proxy *) %s,\n"
+                              "\t\t\t %s_%s",
+                              interface->name,
+                              interface->uppercase_name,
+                              m->uppercase_name);
+               }
+
+               wl_list_for_each(a, &m->arg_list, link) {
+                       if (a->type == NEW_ID) {
+                               if (a->interface_name == NULL)
+                                       printf(", interface->name, version");
+                               printf(", NULL");
+                       } else {
+                               printf(", %s", a->name);
+                       }
+               }
+               printf(");\n");
+
+               if (m->destructor)
+                       printf("\n\twl_proxy_destroy("
+                              "(struct wl_proxy *) %s);\n",
+                              interface->name);
+
+               if (ret && ret->interface_name == NULL)
+                       printf("\n\treturn (void *) %s;\n", ret->name);
+               else if (ret)
+                       printf("\n\treturn (struct %s *) %s;\n",
+                              ret->interface_name, ret->name);
+
+               printf("}\n\n");
+       }
+}
+
+static void
+emit_event_wrappers(struct wl_list *message_list, struct interface *interface)
+{
+       struct message *m;
+       struct arg *a;
+
+       /* We provide hand written functions for the display object */
+       if (strcmp(interface->name, "wl_display") == 0)
+               return;
+
+       wl_list_for_each(m, message_list, link) {
+               printf("static inline void\n"
+                      "%s_send_%s(struct wl_resource *resource_",
+                      interface->name, m->name);
+
+               wl_list_for_each(a, &m->arg_list, link) {
+                       printf(", ");
+                       switch (a->type) {
+                       case NEW_ID:
+                       case OBJECT:
+                               printf("struct wl_resource *");
+                               break;
+                       default:
+                               emit_type(a);
+                       }
+                       printf("%s", a->name);
+               }
+
+               printf(")\n"
+                      "{\n"
+                      "\twl_resource_post_event(resource_, %s_%s",
+                      interface->uppercase_name, m->uppercase_name);
+
+               wl_list_for_each(a, &m->arg_list, link)
+                       printf(", %s", a->name);
+
+               printf(");\n");
+               printf("}\n\n");
+       }
+}
+
+static void
+emit_enumerations(struct interface *interface)
+{
+       struct enumeration *e;
+       struct entry *entry;
+
+       wl_list_for_each(e, &interface->enumeration_list, link) {
+               struct description *desc = e->description;
+
+               printf("#ifndef %s_%s_ENUM\n",
+                      interface->uppercase_name, e->uppercase_name);
+               printf("#define %s_%s_ENUM\n",
+                      interface->uppercase_name, e->uppercase_name);
+
+               if (desc) {
+                       printf("/**\n");
+                       desc_dump(desc->summary,
+                                 " * %s_%s - ",
+                                 interface->name, e->name);
+                       wl_list_for_each(entry, &e->entry_list, link) {
+                               desc_dump(entry->summary,
+                                         " * @%s_%s_%s: ",
+                                         interface->uppercase_name,
+                                         e->uppercase_name,
+                                         entry->uppercase_name);
+                       }
+                       if (desc->text) {
+                               printf(" *\n");
+                               desc_dump(desc->text, " * ");
+                       }
+                       printf(" */\n");
+               }
+               printf("enum %s_%s {\n", interface->name, e->name);
+               wl_list_for_each(entry, &e->entry_list, link)
+                       printf("\t%s_%s_%s = %s,\n",
+                              interface->uppercase_name,
+                              e->uppercase_name,
+                              entry->uppercase_name, entry->value);
+               printf("};\n");
+               printf("#endif /* %s_%s_ENUM */\n\n",
+                      interface->uppercase_name, e->uppercase_name);
+       }
+}
+
+static void
+emit_structs(struct wl_list *message_list, struct interface *interface, enum side side)
+{
+       struct message *m;
+       struct arg *a;
+       int n;
+
+       if (wl_list_empty(message_list))
+               return;
+
+       if (interface->description) {
+               struct description *desc = interface->description;
+               printf("/**\n");
+               desc_dump(desc->summary, " * %s - ", interface->name);
+               wl_list_for_each(m, message_list, link) {
+                       struct description *mdesc = m->description;
+                       desc_dump(mdesc ? mdesc->summary : "(none)",
+                                 " * @%s: ",
+                                 m->name);
+               }
+               printf(" *\n");
+               desc_dump(desc->text, " * ");
+               printf(" */\n");
+       }
+       printf("struct %s_%s {\n", interface->name,
+              (side == SERVER) ? "interface" : "listener");
+
+       wl_list_for_each(m, message_list, link) {
+               struct description *mdesc = m->description;
+
+               printf("\t/**\n");
+               desc_dump(mdesc ? mdesc->summary : "(none)",
+                         "\t * %s - ", m->name);
+               wl_list_for_each(a, &m->arg_list, link) {
+                       if (side == SERVER && a->type == NEW_ID &&
+                           a->interface_name == NULL)
+                               printf("\t * @interface: name of the objects interface\n"
+                                      "\t * @version: version of the objects interface\n");
+
+
+                       desc_dump(a->summary ? a->summary : "(none)",
+                                 "\t * @%s: ", a->name);
+               }
+               if (mdesc) {
+                       printf("\t *\n");
+                       desc_dump(mdesc->text, "\t * ");
+               }
+               if (m->since > 1) {
+                       printf("\t * @since: %d\n", m->since);
+               }
+               printf("\t */\n");
+               printf("\tvoid (*%s)(", m->name);
+
+               n = strlen(m->name) + 17;
+               if (side == SERVER) {
+                       printf("struct wl_client *client,\n"
+                              "%sstruct wl_resource *resource",
+                              indent(n));
+               } else {
+                       printf("void *data,\n"),
+                       printf("%sstruct %s *%s",
+                              indent(n), interface->name, interface->name);
+               }
+
+               wl_list_for_each(a, &m->arg_list, link) {
+                       printf(",\n%s", indent(n));
+
+                       if (side == SERVER && a->type == OBJECT)
+                               printf("struct wl_resource *");
+                       else if (side == SERVER && a->type == NEW_ID && a->interface_name == NULL)
+                               printf("const char *interface, uint32_t version, uint32_t ");
+                       else if (side == CLIENT && a->type == OBJECT && a->interface_name == NULL)
+                               printf("void *");
+
+                       else if (side == CLIENT && a->type == NEW_ID)
+                               printf("struct %s *", a->interface_name);
+                       else
+                               emit_type(a);
+
+                       printf("%s", a->name);
+               }
+
+               printf(");\n");
+       }
+
+       printf("};\n\n");
+
+       if (side == CLIENT) {
+           printf("static inline int\n"
+                  "%s_add_listener(struct %s *%s,\n"
+                  "%sconst struct %s_listener *listener, void *data)\n"
+                  "{\n"
+                  "\treturn wl_proxy_add_listener((struct wl_proxy *) %s,\n"
+                  "%s(void (**)(void)) listener, data);\n"
+                  "}\n\n",
+                  interface->name, interface->name, interface->name,
+                  indent(14 + strlen(interface->name)),
+                  interface->name,
+                  interface->name,
+                  indent(37));
+       }
+}
+
+static void
+format_copyright(const char *copyright)
+{
+       int bol = 1, start = 0, i;
+
+       for (i = 0; copyright[i]; i++) {
+               if (bol && (copyright[i] == ' ' || copyright[i] == '\t')) {
+                       continue;
+               } else if (bol) {
+                       bol = 0;
+                       start = i;
+               }
+
+               if (copyright[i] == '\n' || copyright[i] == '\0') {
+                       printf("%s %.*s\n",
+                              i == 0 ? "/*" : " *",
+                              i - start, copyright + start);
+                       bol = 1;
+               }
+       }
+       printf(" */\n\n");
+}
+
+static void
+emit_header(struct protocol *protocol, enum side side)
+{
+       struct interface *i;
+       const char *s = (side == SERVER) ? "SERVER" : "CLIENT";
+
+       if (protocol->copyright)
+               format_copyright(protocol->copyright);
+
+       printf("#ifndef %s_%s_PROTOCOL_H\n"
+              "#define %s_%s_PROTOCOL_H\n"
+              "\n"
+              "#ifdef  __cplusplus\n"
+              "extern \"C\" {\n"
+              "#endif\n"
+              "\n"
+              "#include <stdint.h>\n"
+              "#include <stddef.h>\n"
+              "#include \"%s\"\n\n"
+              "struct wl_client;\n"
+              "struct wl_resource;\n\n",
+              protocol->uppercase_name, s,
+              protocol->uppercase_name, s,
+              (side == SERVER) ? "wayland-server.h" : "wayland-client.h");
+
+       wl_list_for_each(i, &protocol->interface_list, link)
+               printf("struct %s;\n", i->name);
+       printf("\n");
+
+       wl_list_for_each(i, &protocol->interface_list, link) {
+               printf("extern const struct wl_interface "
+                      "%s_interface;\n",
+                      i->name);
+       }
+       printf("\n");
+
+       wl_list_for_each(i, &protocol->interface_list, link) {
+
+               emit_enumerations(i);
+
+               if (side == SERVER) {
+                       emit_structs(&i->request_list, i, side);
+                       emit_opcodes(&i->event_list, i);
+                       emit_opcode_versions(&i->event_list, i);
+                       emit_event_wrappers(&i->event_list, i);
+               } else {
+                       emit_structs(&i->event_list, i, side);
+                       emit_opcodes(&i->request_list, i);
+                       emit_stubs(&i->request_list, i);
+               }
+       }
+
+       printf("#ifdef  __cplusplus\n"
+              "}\n"
+              "#endif\n"
+              "\n"
+              "#endif\n");
+}
+
+static void
+emit_types_forward_declarations(struct protocol *protocol,
+                               struct wl_list *message_list,
+                               struct wl_array *types)
+{
+       struct message *m;
+       struct arg *a;
+       int length;
+       char **p;
+
+       wl_list_for_each(m, message_list, link) {
+               length = 0;
+               m->all_null = 1;
+               wl_list_for_each(a, &m->arg_list, link) {
+                       length++;
+                       switch (a->type) {
+                       case NEW_ID:
+                       case OBJECT:
+                               if (!a->interface_name)
+                                       continue;
+
+                               m->all_null = 0;
+                               p = fail_on_null(wl_array_add(types, sizeof *p));
+                               *p = a->interface_name;
+                               break;
+                       default:
+                               break;
+                       }
+               }
+
+               if (m->all_null && length > protocol->null_run_length)
+                       protocol->null_run_length = length;
+       }
+}
+
+static void
+emit_null_run(struct protocol *protocol)
+{
+       int i;
+
+       for (i = 0; i < protocol->null_run_length; i++)
+               printf("\tNULL,\n");
+}
+
+static void
+emit_types(struct protocol *protocol, struct wl_list *message_list)
+{
+       struct message *m;
+       struct arg *a;
+
+       wl_list_for_each(m, message_list, link) {
+               if (m->all_null) {
+                       m->type_index = 0;
+                       continue;
+               }
+
+               m->type_index =
+                       protocol->null_run_length + protocol->type_index;
+               protocol->type_index += m->arg_count;
+
+               wl_list_for_each(a, &m->arg_list, link) {
+                       switch (a->type) {
+                       case NEW_ID:
+                       case OBJECT:
+                               if (a->interface_name)
+                                       printf("\t&%s_interface,\n",
+                                              a->interface_name);
+                               else
+                                       printf("\tNULL,\n");
+                               break;
+                       default:
+                               printf("\tNULL,\n");
+                               break;
+                       }
+               }
+       }
+}
+
+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);
+
+               if (m->since > 1)
+                       printf("%d", m->since);
+
+               wl_list_for_each(a, &m->arg_list, link) {
+                       if (is_nullable_type(a) && a->nullable)
+                               printf("?");
+
+                       switch (a->type) {
+                       default:
+                       case INT:
+                               printf("i");
+                               break;
+                       case NEW_ID:
+                               if (a->interface_name == NULL)
+                                       printf("su");
+                               printf("n");
+                               break;
+                       case UNSIGNED:
+                               printf("u");
+                               break;
+                       case FIXED:
+                               printf("f");
+                               break;
+                       case STRING:
+                               printf("s");
+                               break;
+                       case OBJECT:
+                               printf("o");
+                               break;
+                       case ARRAY:
+                               printf("a");
+                               break;
+                       case FD:
+                               printf("h");
+                               break;
+                       }
+               }
+               printf("\", types + %d },\n", m->type_index);
+       }
+
+       printf("};\n\n");
+}
+
+static int
+cmp_names(const void *p1, const void *p2)
+{
+       const char * const *s1 = p1, * const *s2 = p2;
+
+       return strcmp(*s1, *s2);
+}
+
+static void
+emit_code(struct protocol *protocol)
+{
+       struct interface *i;
+       struct wl_array types;
+       char **p, *prev;
+
+       if (protocol->copyright)
+               format_copyright(protocol->copyright);
+
+       printf("#include <stdlib.h>\n"
+              "#include <stdint.h>\n"
+              "#include \"wayland-util.h\"\n\n");
+
+       wl_array_init(&types);
+       wl_list_for_each(i, &protocol->interface_list, link) {
+               emit_types_forward_declarations(protocol, &i->request_list, &types);
+               emit_types_forward_declarations(protocol, &i->event_list, &types);
+       }
+       qsort(types.data, types.size / sizeof *p, sizeof *p, cmp_names);
+       prev = NULL;
+       wl_array_for_each(p, &types) {
+               if (prev && strcmp(*p, prev) == 0)
+                       continue;
+               printf("extern const struct wl_interface %s_interface;\n", *p);
+               prev = *p;
+       }
+       wl_array_release(&types);
+       printf("\n");
+
+       printf("static const struct wl_interface *types[] = {\n");
+       emit_null_run(protocol);
+       wl_list_for_each(i, &protocol->interface_list, link) {
+               emit_types(protocol, &i->request_list);
+               emit_types(protocol, &i->event_list);
+       }
+       printf("};\n\n");
+
+       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 "
+                      "%s_interface = {\n"
+                      "\t\"%s\", %d,\n",
+                      i->name, i->name, i->version);
+
+               if (!wl_list_empty(&i->request_list))
+                       printf("\t%d, %s_requests,\n",
+                              wl_list_length(&i->request_list), i->name);
+               else
+                       printf("\t0, NULL,\n");
+
+               if (!wl_list_empty(&i->event_list))
+                       printf("\t%d, %s_events,\n",
+                              wl_list_length(&i->event_list), i->name);
+               else
+                       printf("\t0, NULL,\n");
+
+               printf("};\n\n");
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       struct parse_context ctx;
+       struct protocol protocol;
+       int len;
+       void *buf;
+       enum {
+               CLIENT_HEADER,
+               SERVER_HEADER,
+               CODE,
+       } mode;
+
+       if (argc != 2)
+               usage(EXIT_FAILURE);
+       else if (strcmp(argv[1], "help") == 0 || strcmp(argv[1], "--help") == 0)
+               usage(EXIT_SUCCESS);
+       else if (strcmp(argv[1], "client-header") == 0)
+               mode = CLIENT_HEADER;
+       else if (strcmp(argv[1], "server-header") == 0)
+               mode = SERVER_HEADER;
+       else if (strcmp(argv[1], "code") == 0)
+               mode = CODE;
+       else
+               usage(EXIT_FAILURE);
+
+       wl_list_init(&protocol.interface_list);
+       protocol.type_index = 0;
+       protocol.null_run_length = 0;
+       protocol.copyright = NULL;
+       memset(&ctx, 0, sizeof ctx);
+       ctx.protocol = &protocol;
+
+       ctx.loc.filename = "<stdin>";
+       ctx.parser = XML_ParserCreate(NULL);
+       XML_SetUserData(ctx.parser, &ctx);
+       if (ctx.parser == NULL) {
+               fprintf(stderr, "failed to create parser\n");
+               exit(EXIT_FAILURE);
+       }
+
+       XML_SetElementHandler(ctx.parser, start_element, end_element);
+       XML_SetCharacterDataHandler(ctx.parser, character_data);
+
+       do {
+               buf = XML_GetBuffer(ctx.parser, XML_BUFFER_SIZE);
+               len = fread(buf, 1, XML_BUFFER_SIZE, stdin);
+               if (len < 0) {
+                       fprintf(stderr, "fread: %m\n");
+                       exit(EXIT_FAILURE);
+               }
+               if (XML_ParseBuffer(ctx.parser, len, len == 0) == 0) {
+                       fprintf(stderr,
+                               "Error parsing XML at line %ld col %ld: %s\n",
+                               XML_GetCurrentLineNumber(ctx.parser),
+                               XML_GetCurrentColumnNumber(ctx.parser),
+                               XML_ErrorString(XML_GetErrorCode(ctx.parser)));
+                       exit(EXIT_FAILURE);
+               }
+       } while (len > 0);
+
+       XML_ParserFree(ctx.parser);
+
+       switch (mode) {
+               case CLIENT_HEADER:
+                       emit_header(&protocol, CLIENT);
+                       break;
+               case SERVER_HEADER:
+                       emit_header(&protocol, SERVER);
+                       break;
+               case CODE:
+                       emit_code(&protocol);
+                       break;
+       }
+
+       return 0;
+}
diff --git a/src/scanner.mk b/src/scanner.mk
new file mode 100644 (file)
index 0000000..1b6963c
--- /dev/null
@@ -0,0 +1,8 @@
+%-protocol.c : $(protocoldir)/%.xml
+       $(AM_V_GEN)$(wayland_scanner) code < $< > $@
+
+%-server-protocol.h : $(protocoldir)/%.xml
+       $(AM_V_GEN)$(wayland_scanner) server-header < $< > $@
+
+%-client-protocol.h : $(protocoldir)/%.xml
+       $(AM_V_GEN)$(wayland_scanner) client-header < $< > $@
diff --git a/src/wayland-client-uninstalled.pc.in b/src/wayland-client-uninstalled.pc.in
new file mode 100644 (file)
index 0000000..3086621
--- /dev/null
@@ -0,0 +1,8 @@
+libdir=@abs_builddir@/.libs
+includedir=@abs_srcdir@
+Name: Wayland Client
+Description: Wayland client side library (not installed)
+Version: @PACKAGE_VERSION@
+Cflags: -I${includedir}
+Libs: -L${libdir} -lwayland-client
diff --git a/src/wayland-client.c b/src/wayland-client.c
new file mode 100644 (file)
index 0000000..917d603
--- /dev/null
@@ -0,0 +1,1896 @@
+/*
+ * Copyright © 2008-2012 Kristian Høgsberg
+ * Copyright © 2010-2012 Intel Corporation
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <ctype.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <pthread.h>
+
+#include "wayland-util.h"
+#include "wayland-os.h"
+#include "wayland-client.h"
+#include "wayland-private.h"
+
+/** \cond */
+
+enum wl_proxy_flag {
+       WL_PROXY_FLAG_ID_DELETED = (1 << 0),
+       WL_PROXY_FLAG_DESTROYED = (1 << 1)
+};
+
+struct wl_proxy {
+       struct wl_object object;
+       struct wl_display *display;
+       struct wl_event_queue *queue;
+       uint32_t flags;
+       int refcount;
+       void *user_data;
+       wl_dispatcher_func_t dispatcher;
+};
+
+struct wl_global {
+       uint32_t id;
+       char *interface;
+       uint32_t version;
+       struct wl_list link;
+};
+
+struct wl_event_queue {
+       struct wl_list event_list;
+       struct wl_display *display;
+};
+
+struct wl_display {
+       struct wl_proxy proxy;
+       struct wl_connection *connection;
+
+       /* errno of the last wl_display error */
+       int last_error;
+
+       /* When display gets an error event from some object, it stores
+        * information about it here, so that client can get this
+        * information afterwards */
+       struct {
+               /* Code of the error. It can be compared to
+                * the interface's errors enumeration. */
+               uint32_t code;
+               /* interface (protocol) in which the error occurred */
+               const struct wl_interface *interface;
+               /* id of the proxy that caused the error. There's no warranty
+                * that the proxy is still valid. It's up to client how it will
+                * use it */
+               uint32_t id;
+       } protocol_error;
+       int fd;
+       struct wl_map objects;
+       struct wl_event_queue display_queue;
+       struct wl_event_queue default_queue;
+       pthread_mutex_t mutex;
+
+       int reader_count;
+       uint32_t read_serial;
+       pthread_cond_t reader_cond;
+};
+
+/** \endcond */
+
+static int debug_client = 0;
+
+/**
+ * This helper function wakes up all threads that are
+ * waiting for display->reader_cond (i. e. when reading is done,
+ * canceled, or an error occured)
+ *
+ * NOTE: must be called with display->mutex locked
+ */
+static void
+display_wakeup_threads(struct wl_display *display)
+{
+       /* Thread can get sleeping only in read_events(). If we're
+        * waking it up, it means that the read completed or was
+        * canceled, so we must increase the read_serial.
+        * This prevents from indefinite sleeping in read_events().
+        */
+       ++display->read_serial;
+
+       pthread_cond_broadcast(&display->reader_cond);
+}
+
+/**
+ * This function is called for local errors (no memory, server hung up)
+ *
+ * \param display
+ * \param error    error value (EINVAL, EFAULT, ...)
+ *
+ * \note this function is called with display mutex locked
+ */
+static void
+display_fatal_error(struct wl_display *display, int error)
+{
+       if (display->last_error)
+               return;
+
+       if (!error)
+               error = EFAULT;
+
+       display->last_error = error;
+
+       display_wakeup_threads(display);
+}
+
+/**
+ * This function is called for error events
+ * and indicates that in some object an error occured.
+ * Difference between this function and display_fatal_error()
+ * is that this one handles errors that will come by wire,
+ * whereas display_fatal_error() is called for local errors.
+ *
+ * \param display
+ * \param code    error code
+ * \param id      id of the object that generated the error
+ * \param intf    protocol interface
+ */
+static void
+display_protocol_error(struct wl_display *display, uint32_t code,
+                      uint32_t id, const struct wl_interface *intf)
+{
+       int err;
+
+       if (display->last_error)
+               return;
+
+       /* set correct errno */
+       if (wl_interface_equal(intf, &wl_display_interface)) {
+               switch (code) {
+               case WL_DISPLAY_ERROR_INVALID_OBJECT:
+               case WL_DISPLAY_ERROR_INVALID_METHOD:
+                       err = EINVAL;
+                       break;
+               case WL_DISPLAY_ERROR_NO_MEMORY:
+                       err = ENOMEM;
+                       break;
+               default:
+                       err = EFAULT;
+               }
+       } else {
+               err = EPROTO;
+       }
+
+       pthread_mutex_lock(&display->mutex);
+
+       display->last_error = err;
+
+       display->protocol_error.code = code;
+       display->protocol_error.id = id;
+       display->protocol_error.interface = intf;
+
+       /*
+        * here it is not necessary to wake up threads like in
+        * display_fatal_error, because this function is called from
+        * an event handler and that means that read_events() is done
+        * and woke up all threads. Since wl_display_prepare_read()
+        * fails when there are events in the queue, no threads
+        * can sleep in read_events() during dispatching
+        * (and therefore during calling this function), so this is safe.
+        */
+
+       pthread_mutex_unlock(&display->mutex);
+}
+
+static void
+wl_event_queue_init(struct wl_event_queue *queue, struct wl_display *display)
+{
+       wl_list_init(&queue->event_list);
+       queue->display = display;
+}
+
+static void
+decrease_closure_args_refcount(struct wl_closure *closure)
+{
+       const char *signature;
+       struct argument_details arg;
+       int i, count;
+       struct wl_proxy *proxy;
+
+       signature = closure->message->signature;
+       count = arg_count_for_signature(signature);
+       for (i = 0; i < count; i++) {
+               signature = get_next_argument(signature, &arg);
+               switch (arg.type) {
+               case 'n':
+               case 'o':
+                       proxy = (struct wl_proxy *) closure->args[i].o;
+                       if (proxy) {
+                               if (proxy->flags & WL_PROXY_FLAG_DESTROYED)
+                                       closure->args[i].o = NULL;
+
+                               proxy->refcount--;
+                               if (!proxy->refcount)
+                                       free(proxy);
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+void
+proxy_destroy(struct wl_proxy *proxy);
+
+static void
+wl_event_queue_release(struct wl_event_queue *queue)
+{
+       struct wl_closure *closure;
+       struct wl_proxy *proxy;
+
+       while (!wl_list_empty(&queue->event_list)) {
+               closure = container_of(queue->event_list.next,
+                                      struct wl_closure, link);
+               wl_list_remove(&closure->link);
+
+               decrease_closure_args_refcount(closure);
+
+               proxy = closure->proxy;
+               if (proxy->refcount == 1)
+                       proxy_destroy(proxy);
+               else
+                       --proxy->refcount;
+
+               wl_closure_destroy(closure);
+       }
+}
+
+/** Destroy an event queue
+ *
+ * \param queue The event queue to be destroyed
+ *
+ * Destroy the given event queue. Any pending event on that queue is
+ * discarded.
+ *
+ * The \ref wl_display object used to create the queue should not be
+ * destroyed until all event queues created with it are destroyed with
+ * this function.
+ *
+ * \memberof wl_event_queue
+ */
+WL_EXPORT void
+wl_event_queue_destroy(struct wl_event_queue *queue)
+{
+       struct wl_display *display = queue->display;
+
+       pthread_mutex_lock(&display->mutex);
+       wl_event_queue_release(queue);
+       free(queue);
+       pthread_mutex_unlock(&display->mutex);
+}
+
+/** Create a new event queue for this display
+ *
+ * \param display The display context object
+ * \return A new event queue associated with this display or NULL on
+ * failure.
+ *
+ * \memberof wl_event_queue
+ */
+WL_EXPORT struct wl_event_queue *
+wl_display_create_queue(struct wl_display *display)
+{
+       struct wl_event_queue *queue;
+
+       queue = malloc(sizeof *queue);
+       if (queue == NULL)
+               return NULL;
+
+       wl_event_queue_init(queue, display);
+
+       return queue;
+}
+
+static struct wl_proxy *
+proxy_create(struct wl_proxy *factory, const struct wl_interface *interface)
+{
+       struct wl_proxy *proxy;
+       struct wl_display *display = factory->display;
+
+       proxy = malloc(sizeof *proxy);
+       if (proxy == NULL)
+               return NULL;
+
+       memset(proxy, 0, sizeof *proxy);
+
+       proxy->object.interface = interface;
+       proxy->display = display;
+       proxy->queue = factory->queue;
+       proxy->refcount = 1;
+
+       proxy->object.id = wl_map_insert_new(&display->objects, 0, proxy);
+
+       return proxy;
+}
+
+/** Create a proxy object with a given interface
+ *
+ * \param factory Factory proxy object
+ * \param interface Interface the proxy object should use
+ * \return A newly allocated proxy object or NULL on failure
+ *
+ * This function creates a new proxy object with the supplied interface. The
+ * proxy object will have an id assigned from the client id space. The id
+ * should be created on the compositor side by sending an appropriate request
+ * with \ref wl_proxy_marshal().
+ *
+ * The proxy will inherit the display and event queue of the factory object.
+ *
+ * \note This should not normally be used by non-generated code.
+ *
+ * \sa wl_display, wl_event_queue, wl_proxy_marshal()
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT struct wl_proxy *
+wl_proxy_create(struct wl_proxy *factory, const struct wl_interface *interface)
+{
+       struct wl_display *display = factory->display;
+       struct wl_proxy *proxy;
+
+       pthread_mutex_lock(&display->mutex);
+       proxy = proxy_create(factory, interface);
+       pthread_mutex_unlock(&display->mutex);
+
+       return proxy;
+}
+
+/* The caller should hold the display lock */
+static struct wl_proxy *
+wl_proxy_create_for_id(struct wl_proxy *factory,
+                      uint32_t id, const struct wl_interface *interface)
+{
+       struct wl_proxy *proxy;
+       struct wl_display *display = factory->display;
+
+       proxy = malloc(sizeof *proxy);
+       if (proxy == NULL)
+               return NULL;
+
+       memset(proxy, 0, sizeof *proxy);
+
+       proxy->object.interface = interface;
+       proxy->object.id = id;
+       proxy->display = display;
+       proxy->queue = factory->queue;
+       proxy->refcount = 1;
+
+       wl_map_insert_at(&display->objects, 0, id, proxy);
+
+       return proxy;
+}
+
+void
+proxy_destroy(struct wl_proxy *proxy)
+{
+       if (proxy->flags & WL_PROXY_FLAG_ID_DELETED)
+               wl_map_remove(&proxy->display->objects, proxy->object.id);
+       else if (proxy->object.id < WL_SERVER_ID_START)
+               wl_map_insert_at(&proxy->display->objects, 0,
+                                proxy->object.id, WL_ZOMBIE_OBJECT);
+       else
+               wl_map_insert_at(&proxy->display->objects, 0,
+                                proxy->object.id, NULL);
+
+
+       proxy->flags |= WL_PROXY_FLAG_DESTROYED;
+
+       proxy->refcount--;
+       if (!proxy->refcount)
+               free(proxy);
+}
+
+/** Destroy a proxy object
+ *
+ * \param proxy The proxy to be destroyed
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT void
+wl_proxy_destroy(struct wl_proxy *proxy)
+{
+       struct wl_display *display = proxy->display;
+
+       pthread_mutex_lock(&display->mutex);
+       proxy_destroy(proxy);
+       pthread_mutex_unlock(&display->mutex);
+}
+
+/** Set a proxy's listener
+ *
+ * \param proxy The proxy object
+ * \param implementation The listener to be added to proxy
+ * \param data User data to be associated with the proxy
+ * \return 0 on success or -1 on failure
+ *
+ * Set proxy's listener to \c implementation and its user data to
+ * \c data. If a listener has already been set, this function
+ * fails and nothing is changed.
+ *
+ * \c implementation is a vector of function pointers. For an opcode
+ * \c n, \c implementation[n] should point to the handler of \c n for
+ * the given object.
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT int
+wl_proxy_add_listener(struct wl_proxy *proxy,
+                     void (**implementation)(void), void *data)
+{
+       if (proxy->object.implementation || proxy->dispatcher) {
+               wl_log("proxy %p already has listener\n", proxy);
+               return -1;
+       }
+
+       proxy->object.implementation = implementation;
+       proxy->user_data = data;
+
+       return 0;
+}
+
+/** Get a proxy's listener
+ *
+ * \param proxy The proxy object
+ * \return The address of the proxy's listener or NULL if no listener is set
+ *
+ * Gets the address to the proxy's listener; which is the listener set with
+ * \ref wl_proxy_add_listener.
+ *
+ * This function is useful in clients with multiple listeners on the same
+ * interface to allow the identification of which code to execute.
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT const void *
+wl_proxy_get_listener(struct wl_proxy *proxy)
+{
+       return proxy->object.implementation;
+}
+
+/** Set a proxy's listener (with dispatcher)
+ *
+ * \param proxy The proxy object
+ * \param dispatcher The dispatcher to be used for this proxy
+ * \param implementation The dispatcher-specific listener implementation
+ * \param data User data to be associated with the proxy
+ * \return 0 on success or -1 on failure
+ *
+ * Set proxy's listener to use \c dispatcher_func as its dispatcher and \c
+ * dispatcher_data as its dispatcher-specific implementation and its user data
+ * to \c data. If a listener has already been set, this function
+ * fails and nothing is changed.
+ *
+ * The exact details of dispatcher_data depend on the dispatcher used.  This
+ * function is intended to be used by language bindings, not user code.
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT int
+wl_proxy_add_dispatcher(struct wl_proxy *proxy,
+                       wl_dispatcher_func_t dispatcher,
+                       const void *implementation, void *data)
+{
+       if (proxy->object.implementation || proxy->dispatcher) {
+               wl_log("proxy %p already has listener\n");
+               return -1;
+       }
+
+       proxy->object.implementation = implementation;
+       proxy->dispatcher = dispatcher;
+       proxy->user_data = data;
+
+       return 0;
+}
+
+static struct wl_proxy *
+create_outgoing_proxy(struct wl_proxy *proxy, const struct wl_message *message,
+                     union wl_argument *args,
+                     const struct wl_interface *interface)
+{
+       int i, count;
+       const char *signature;
+       struct argument_details arg;
+       struct wl_proxy *new_proxy = NULL;
+
+       signature = message->signature;
+       count = arg_count_for_signature(signature);
+       for (i = 0; i < count; i++) {
+               signature = get_next_argument(signature, &arg);
+
+               switch (arg.type) {
+               case 'n':
+                       new_proxy = proxy_create(proxy, interface);
+                       if (new_proxy == NULL)
+                               return NULL;
+
+                       args[i].o = &new_proxy->object;
+                       break;
+               }
+       }
+
+       return new_proxy;
+}
+
+/** Prepare a request to be sent to the compositor
+ *
+ * \param proxy The proxy object
+ * \param opcode Opcode of the request to be sent
+ * \param args Extra arguments for the given request
+ * \param interface The interface to use for the new proxy
+ *
+ * Translates the request given by opcode and the extra arguments into the
+ * wire format and write it to the connection buffer.  This version takes an
+ * array of the union type wl_argument.
+ *
+ * For new-id arguments, this function will allocate a new wl_proxy
+ * and send the ID to the server.  The new wl_proxy will be returned
+ * on success or NULL on errror with errno set accordingly.
+ *
+ * \note This is intended to be used by language bindings and not in
+ * non-generated code.
+ *
+ * \sa wl_proxy_marshal()
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT struct wl_proxy *
+wl_proxy_marshal_array_constructor(struct wl_proxy *proxy,
+                                  uint32_t opcode, union wl_argument *args,
+                                  const struct wl_interface *interface)
+{
+       struct wl_closure *closure;
+       struct wl_proxy *new_proxy = NULL;
+       const struct wl_message *message;
+
+       pthread_mutex_lock(&proxy->display->mutex);
+
+       message = &proxy->object.interface->methods[opcode];
+       if (interface) {
+               new_proxy = create_outgoing_proxy(proxy, message,
+                                                 args, interface);
+               if (new_proxy == NULL)
+                       goto err_unlock;
+       }
+
+       closure = wl_closure_marshal(&proxy->object, opcode, args, message);
+       if (closure == NULL) {
+               wl_log("Error marshalling request: %m\n");
+               abort();
+       }
+
+       if (debug_client)
+               wl_closure_print(closure, &proxy->object, true);
+
+       if (wl_closure_send(closure, proxy->display->connection)) {
+               wl_log("Error sending request: %m\n");
+               abort();
+       }
+
+       wl_closure_destroy(closure);
+
+ err_unlock:
+       pthread_mutex_unlock(&proxy->display->mutex);
+
+       return new_proxy;
+}
+
+
+/** Prepare a request to be sent to the compositor
+ *
+ * \param proxy The proxy object
+ * \param opcode Opcode of the request to be sent
+ * \param ... Extra arguments for the given request
+ *
+ * This function is similar to wl_proxy_marshal_constructor(), except
+ * it doesn't create proxies for new-id arguments.
+ *
+ * \note This should not normally be used by non-generated code.
+ *
+ * \sa wl_proxy_create()
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT void
+wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...)
+{
+       union wl_argument args[WL_CLOSURE_MAX_ARGS];
+       va_list ap;
+
+       va_start(ap, opcode);
+       wl_argument_from_va_list(proxy->object.interface->methods[opcode].signature,
+                                args, WL_CLOSURE_MAX_ARGS, ap);
+       va_end(ap);
+
+       wl_proxy_marshal_array_constructor(proxy, opcode, args, NULL);
+}
+
+/** Prepare a request to be sent to the compositor
+ *
+ * \param proxy The proxy object
+ * \param opcode Opcode of the request to be sent
+ * \param interface The interface to use for the new proxy
+ * \param ... Extra arguments for the given request
+ * \return A new wl_proxy for the new_id argument or NULL on error
+ *
+ * Translates the request given by opcode and the extra arguments into the
+ * wire format and write it to the connection buffer.
+ *
+ * For new-id arguments, this function will allocate a new wl_proxy
+ * and send the ID to the server.  The new wl_proxy will be returned
+ * on success or NULL on errror with errno set accordingly.
+ *
+ * \note This should not normally be used by non-generated code.
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT struct wl_proxy *
+wl_proxy_marshal_constructor(struct wl_proxy *proxy, uint32_t opcode,
+                            const struct wl_interface *interface, ...)
+{
+       union wl_argument args[WL_CLOSURE_MAX_ARGS];
+       va_list ap;
+
+       va_start(ap, interface);
+       wl_argument_from_va_list(proxy->object.interface->methods[opcode].signature,
+                                args, WL_CLOSURE_MAX_ARGS, ap);
+       va_end(ap);
+
+       return wl_proxy_marshal_array_constructor(proxy, opcode,
+                                                 args, interface);
+}
+
+/** Prepare a request to be sent to the compositor
+ *
+ * \param proxy The proxy object
+ * \param opcode Opcode of the request to be sent
+ * \param args Extra arguments for the given request
+ *
+ * This function is similar to wl_proxy_marshal_array_constructor(), except
+ * it doesn't create proxies for new-id arguments.
+ *
+ * \note This is intended to be used by language bindings and not in
+ * non-generated code.
+ *
+ * \sa wl_proxy_marshal()
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT void
+wl_proxy_marshal_array(struct wl_proxy *proxy, uint32_t opcode,
+                      union wl_argument *args)
+{
+       wl_proxy_marshal_array_constructor(proxy, opcode, args, NULL);
+}
+
+static void
+display_handle_error(void *data,
+                    struct wl_display *display, void *object,
+                    uint32_t code, const char *message)
+{
+       struct wl_proxy *proxy = object;
+
+       wl_log("%s@%u: error %d: %s\n",
+              proxy->object.interface->name, proxy->object.id, code, message);
+
+       display_protocol_error(display, code, proxy->object.id,
+                              proxy->object.interface);
+}
+
+static void
+display_handle_delete_id(void *data, struct wl_display *display, uint32_t id)
+{
+       struct wl_proxy *proxy;
+
+       pthread_mutex_lock(&display->mutex);
+
+       proxy = wl_map_lookup(&display->objects, id);
+
+       if (!proxy)
+               wl_log("error: received delete_id for unknown id (%u)\n", id);
+
+       if (proxy && proxy != WL_ZOMBIE_OBJECT)
+               proxy->flags |= WL_PROXY_FLAG_ID_DELETED;
+       else
+               wl_map_remove(&display->objects, id);
+
+       pthread_mutex_unlock(&display->mutex);
+}
+
+static const struct wl_display_listener display_listener = {
+       display_handle_error,
+       display_handle_delete_id
+};
+
+static int
+connect_to_socket(const char *name)
+{
+       struct sockaddr_un addr;
+       socklen_t size;
+       const char *runtime_dir;
+       int name_size, fd;
+
+#ifdef HAVE_MULTISEAT
+       runtime_dir = getenv("WAYLAND_CLIENT_DIR");
+       if (runtime_dir == NULL)
+#endif
+       runtime_dir = getenv("XDG_RUNTIME_DIR");
+       if (!runtime_dir) {
+               wl_log("error: XDG_RUNTIME_DIR not set in the environment.\n");
+               /* to prevent programs reporting
+                * "failed to create display: Success" */
+               errno = ENOENT;
+               return -1;
+       }
+
+       if (name == NULL)
+               name = getenv("WAYLAND_DISPLAY");
+       if (name == NULL)
+               name = "wayland-0";
+
+       fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0);
+       if (fd < 0)
+               return -1;
+
+       memset(&addr, 0, sizeof addr);
+       addr.sun_family = AF_LOCAL;
+       name_size =
+               snprintf(addr.sun_path, sizeof addr.sun_path,
+                        "%s/%s", runtime_dir, name) + 1;
+#ifdef HAVE_MULTISEAT
+       unsetenv("WAYLAND_CLIENT_DIR");
+#endif
+
+       assert(name_size > 0);
+       if (name_size > (int)sizeof addr.sun_path) {
+               wl_log("error: socket path \"%s/%s\" plus null terminator"
+                      " exceeds 108 bytes\n", runtime_dir, name);
+               close(fd);
+               /* to prevent programs reporting
+                * "failed to add socket: Success" */
+               errno = ENAMETOOLONG;
+               return -1;
+       };
+
+       size = offsetof (struct sockaddr_un, sun_path) + name_size;
+
+       if (connect(fd, (struct sockaddr *) &addr, size) < 0) {
+               close(fd);
+               return -1;
+       }
+
+       return fd;
+}
+
+/** Connect to Wayland display on an already open fd
+ *
+ * \param fd The fd to use for the connection
+ * \return A \ref wl_display object or \c NULL on failure
+ *
+ * The wl_display takes ownership of the fd and will close it when the
+ * display is destroyed.  The fd will also be closed in case of
+ * failure.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT struct wl_display *
+wl_display_connect_to_fd(int fd)
+{
+       struct wl_display *display;
+       const char *debug;
+
+       debug = getenv("WAYLAND_DEBUG");
+       if (debug && (strstr(debug, "client") || strstr(debug, "1")))
+               debug_client = 1;
+
+       display = malloc(sizeof *display);
+       if (display == NULL) {
+               close(fd);
+               return NULL;
+       }
+
+       memset(display, 0, sizeof *display);
+
+       display->fd = fd;
+       wl_map_init(&display->objects, WL_MAP_CLIENT_SIDE);
+       wl_event_queue_init(&display->default_queue, display);
+       wl_event_queue_init(&display->display_queue, display);
+       pthread_mutex_init(&display->mutex, NULL);
+       pthread_cond_init(&display->reader_cond, NULL);
+       display->reader_count = 0;
+
+       wl_map_insert_new(&display->objects, 0, NULL);
+
+       display->proxy.object.interface = &wl_display_interface;
+       display->proxy.object.id =
+               wl_map_insert_new(&display->objects, 0, display);
+       display->proxy.display = display;
+       display->proxy.object.implementation = (void(**)(void)) &display_listener;
+       display->proxy.user_data = display;
+       display->proxy.queue = &display->default_queue;
+       display->proxy.flags = 0;
+       display->proxy.refcount = 1;
+
+       display->connection = wl_connection_create(display->fd);
+       if (display->connection == NULL)
+               goto err_connection;
+
+       return display;
+
+ err_connection:
+       pthread_mutex_destroy(&display->mutex);
+       pthread_cond_destroy(&display->reader_cond);
+       wl_map_release(&display->objects);
+       close(display->fd);
+       free(display);
+
+       return NULL;
+}
+
+/** Connect to a Wayland display
+ *
+ * \param name Name of the Wayland display to connect to
+ * \return A \ref wl_display object or \c NULL on failure
+ *
+ * Connect to the Wayland display named \c name. If \c name is \c NULL,
+ * its value will be replaced with the WAYLAND_DISPLAY environment
+ * variable if it is set, otherwise display "wayland-0" will be used.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT struct wl_display *
+wl_display_connect(const char *name)
+{
+       char *connection, *end;
+       int flags, fd;
+
+       connection = getenv("WAYLAND_SOCKET");
+       if (connection) {
+               int prev_errno = errno;
+               errno = 0;
+               fd = strtol(connection, &end, 0);
+               if (errno != 0 || connection == end || *end != '\0')
+                       return NULL;
+               errno = prev_errno;
+
+               flags = fcntl(fd, F_GETFD);
+               if (flags != -1)
+                       fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
+               unsetenv("WAYLAND_SOCKET");
+       } else {
+               fd = connect_to_socket(name);
+               if (fd < 0)
+                       return NULL;
+       }
+
+       return wl_display_connect_to_fd(fd);
+}
+
+/** Close a connection to a Wayland display
+ *
+ * \param display The display context object
+ *
+ * Close the connection to \c display and free all resources associated
+ * with it.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT void
+wl_display_disconnect(struct wl_display *display)
+{
+       wl_connection_destroy(display->connection);
+       wl_map_release(&display->objects);
+       wl_event_queue_release(&display->default_queue);
+       wl_event_queue_release(&display->display_queue);
+       pthread_mutex_destroy(&display->mutex);
+       pthread_cond_destroy(&display->reader_cond);
+       close(display->fd);
+
+       free(display);
+}
+
+/** Get a display context's file descriptor
+ *
+ * \param display The display context object
+ * \return Display object file descriptor
+ *
+ * Return the file descriptor associated with a display so it can be
+ * integrated into the client's main loop.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT int
+wl_display_get_fd(struct wl_display *display)
+{
+       return display->fd;
+}
+
+static void
+sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
+{
+       int *done = data;
+
+       *done = 1;
+       wl_callback_destroy(callback);
+}
+
+static const struct wl_callback_listener sync_listener = {
+       sync_callback
+};
+
+/** Block until all pending request are processed by the server
+ *
+ * \param display The display context object
+ * \param queue The queue on which to run the roundtrip
+ * \return The number of dispatched events on success or -1 on failure
+ *
+ * Blocks until the server process all currently issued requests and
+ * sends out pending events on the event queue.
+ *
+ * \note This function uses wl_display_dispatch_queue() internally. If you
+ * are using wl_display_read_events() from more threads, don't use this function
+ * (or make sure that calling wl_display_roundtrip_queue() doesn't interfere
+ * with calling wl_display_prepare_read() and wl_display_read_events())
+ *
+ * \sa wl_display_roundtrip()
+ * \memberof wl_event_queue
+ */
+WL_EXPORT int
+wl_display_roundtrip_queue(struct wl_display *display, struct wl_event_queue *queue)
+{
+       struct wl_callback *callback;
+       int done, ret = 0;
+
+       done = 0;
+       callback = wl_display_sync(display);
+       if (callback == NULL)
+               return -1;
+       wl_proxy_set_queue((struct wl_proxy *) callback, queue);
+       wl_callback_add_listener(callback, &sync_listener, &done);
+       while (!done && ret >= 0)
+               ret = wl_display_dispatch_queue(display, queue);
+
+       if (ret == -1 && !done)
+               wl_callback_destroy(callback);
+
+       return ret;
+}
+
+/** Block until all pending request are processed by the server
+ *
+ * \param display The display context object
+ * \return The number of dispatched events on success or -1 on failure
+ *
+ * Blocks until the server process all currently issued requests and
+ * sends out pending events on the default event queue.
+ *
+ * \note This function uses wl_display_dispatch_queue() internally. If you
+ * are using wl_display_read_events() from more threads, don't use this function
+ * (or make sure that calling wl_display_roundtrip() doesn't interfere
+ * with calling wl_display_prepare_read() and wl_display_read_events())
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT int
+wl_display_roundtrip(struct wl_display *display)
+{
+       return wl_display_roundtrip_queue(display, &display->default_queue);
+}
+
+static int
+create_proxies(struct wl_proxy *sender, struct wl_closure *closure)
+{
+       struct wl_proxy *proxy;
+       const char *signature;
+       struct argument_details arg;
+       uint32_t id;
+       int i;
+       int count;
+
+       signature = closure->message->signature;
+       count = arg_count_for_signature(signature);
+       for (i = 0; i < count; i++) {
+               signature = get_next_argument(signature, &arg);
+               switch (arg.type) {
+               case 'n':
+                       id = closure->args[i].n;
+                       if (id == 0) {
+                               closure->args[i].o = NULL;
+                               break;
+                       }
+                       proxy = wl_proxy_create_for_id(sender, id,
+                                                      closure->message->types[i]);
+                       if (proxy == NULL)
+                               return -1;
+                       closure->args[i].o = (struct wl_object *)proxy;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static void
+increase_closure_args_refcount(struct wl_closure *closure)
+{
+       const char *signature;
+       struct argument_details arg;
+       int i, count;
+       struct wl_proxy *proxy;
+
+       signature = closure->message->signature;
+       count = arg_count_for_signature(signature);
+       for (i = 0; i < count; i++) {
+               signature = get_next_argument(signature, &arg);
+               switch (arg.type) {
+               case 'n':
+               case 'o':
+                       proxy = (struct wl_proxy *) closure->args[i].o;
+                       if (proxy)
+                               proxy->refcount++;
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static int
+queue_event(struct wl_display *display, int len)
+{
+       uint32_t p[2], id;
+       int opcode, size;
+       struct wl_proxy *proxy;
+       struct wl_closure *closure;
+       const struct wl_message *message;
+       struct wl_event_queue *queue;
+
+       wl_connection_copy(display->connection, p, sizeof p);
+       id = p[0];
+       opcode = p[1] & 0xffff;
+       size = p[1] >> 16;
+       if (len < size)
+               return 0;
+
+       proxy = wl_map_lookup(&display->objects, id);
+       if (proxy == WL_ZOMBIE_OBJECT) {
+               wl_connection_consume(display->connection, size);
+               return size;
+       } else if (proxy == NULL) {
+               wl_connection_consume(display->connection, size);
+               return size;
+       }
+
+       message = &proxy->object.interface->events[opcode];
+       closure = wl_connection_demarshal(display->connection, size,
+                                         &display->objects, message);
+       if (!closure)
+               return -1;
+
+       if (create_proxies(proxy, closure) < 0) {
+               wl_closure_destroy(closure);
+               return -1;
+       }
+
+       if (wl_closure_lookup_objects(closure, &display->objects) != 0) {
+               wl_closure_destroy(closure);
+               return -1;
+       }
+
+       increase_closure_args_refcount(closure);
+       proxy->refcount++;
+       closure->proxy = proxy;
+
+       if (proxy == &display->proxy)
+               queue = &display->display_queue;
+       else
+               queue = proxy->queue;
+
+       wl_list_insert(queue->event_list.prev, &closure->link);
+
+       return size;
+}
+
+static void
+dispatch_event(struct wl_display *display, struct wl_event_queue *queue)
+{
+       struct wl_closure *closure;
+       struct wl_proxy *proxy;
+       int opcode;
+       bool proxy_destroyed;
+
+       closure = container_of(queue->event_list.next,
+                              struct wl_closure, link);
+       wl_list_remove(&closure->link);
+       opcode = closure->opcode;
+
+       /* Verify that the receiving object is still valid by checking if has
+        * been destroyed by the application. */
+
+       decrease_closure_args_refcount(closure);
+       proxy = closure->proxy;
+       proxy_destroyed = !!(proxy->flags & WL_PROXY_FLAG_DESTROYED);
+
+       proxy->refcount--;
+       if (proxy_destroyed) {
+               if (!proxy->refcount)
+                       free(proxy);
+
+               wl_closure_destroy(closure);
+               return;
+       }
+
+       pthread_mutex_unlock(&display->mutex);
+
+       if (proxy->dispatcher) {
+               if (debug_client)
+                       wl_closure_print(closure, &proxy->object, false);
+
+               wl_closure_dispatch(closure, proxy->dispatcher,
+                                   &proxy->object, opcode);
+       } else if (proxy->object.implementation) {
+               if (debug_client)
+                       wl_closure_print(closure, &proxy->object, false);
+
+               wl_closure_invoke(closure, WL_CLOSURE_INVOKE_CLIENT,
+                                 &proxy->object, opcode, proxy->user_data);
+       }
+
+       wl_closure_destroy(closure);
+
+       pthread_mutex_lock(&display->mutex);
+}
+
+static int
+read_events(struct wl_display *display)
+{
+       int total, rem, size;
+       uint32_t serial;
+
+       display->reader_count--;
+       if (display->reader_count == 0) {
+               total = wl_connection_read(display->connection);
+               if (total == -1) {
+                       if (errno == EAGAIN) {
+                               /* we must wake up threads whenever
+                                * the reader_count dropped to 0 */
+                               display_wakeup_threads(display);
+
+                               return 0;
+                       }
+
+                       display_fatal_error(display, errno);
+                       return -1;
+               } else if (total == 0) {
+                       /* The compositor has closed the socket. This
+                        * should be considered an error so we'll fake
+                        * an errno */
+                       errno = EPIPE;
+                       display_fatal_error(display, errno);
+                       return -1;
+               }
+
+               for (rem = total; rem >= 8; rem -= size) {
+                       size = queue_event(display, rem);
+                       if (size == -1) {
+                               display_fatal_error(display, errno);
+                               return -1;
+                       } else if (size == 0) {
+                               break;
+                       }
+               }
+
+               display_wakeup_threads(display);
+       } else {
+               serial = display->read_serial;
+               while (display->read_serial == serial)
+                       pthread_cond_wait(&display->reader_cond,
+                                         &display->mutex);
+
+               if (display->last_error) {
+                       errno = display->last_error;
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static void
+cancel_read(struct wl_display *display)
+{
+       display->reader_count--;
+       if (display->reader_count == 0)
+               display_wakeup_threads(display);
+}
+
+/** Read events from display file descriptor
+ *
+ * \param display The display context object
+ * \return 0 on success or -1 on error.  In case of error errno will
+ * be set accordingly
+ *
+ * This will read events from the file descriptor for the display.
+ * This function does not dispatch events, it only reads and queues
+ * events into their corresponding event queues. If no data is
+ * available on the file descriptor, wl_display_read_events() returns
+ * immediately. To dispatch events that may have been queued, call
+ * wl_display_dispatch_pending() or wl_display_dispatch_queue_pending().
+ *
+ * Before calling this function, wl_display_prepare_read() must be
+ * called first. When running in more threads (which is the usual
+ * case, since we'd use wl_display_dispatch() otherwise), every thread
+ * must call wl_display_prepare_read() before calling this function.
+ *
+ * After calling wl_display_prepare_read() there can be some extra code
+ * before calling wl_display_read_events(), for example poll() or alike.
+ * Example of code in a thread:
+ *
+ * \code
+ *
+ *   while (wl_display_prepare_read(display) < 0)
+ *           wl_display_dispatch_pending(display);
+ *   wl_display_flush(display);
+ *
+ *   ... some code ...
+ *
+ *   fds[0].fd = wl_display_get_fd(display);
+ *   fds[0].events = POLLIN;
+ *   poll(fds, 1, -1);
+ *
+ *   if (!everything_ok()) {
+ *     wl_display_cancel_read(display);
+ *     handle_error();
+ *   }
+ *
+ *   if (wl_display_read_events(display) < 0)
+ *     handle_error();
+ *
+ *   ...
+ * \endcode
+ *
+ * After wl_display_prepare_read() succeeds, other threads that enter
+ * wl_display_read_events() will sleep until the very last thread enters
+ * it too or cancels. Therefore when the display fd becomes (or already
+ * is) readable, wl_display_read_events() should be called as soon as
+ * possible to unblock all threads. If wl_display_read_events() will not
+ * be called, then wl_display_cancel_read() must be called instead to let
+ * the other threads continue.
+ *
+ * This function must not be called simultaneously with wl_display_dispatch().
+ * It may lead to deadlock. If programmer wants, for some reason, use
+ * wl_display_dispatch() in one thread and wl_display_prepare_read() with
+ * wl_display_read_events() in another, extra care must be taken to serialize
+ * these calls, i. e. use mutexes or similar (on whole prepare + read sequence)
+ *
+ * \sa wl_display_prepare_read(), wl_display_cancel_read(),
+ * wl_display_dispatch_pending(), wl_display_dispatch()
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT int
+wl_display_read_events(struct wl_display *display)
+{
+       int ret;
+
+       pthread_mutex_lock(&display->mutex);
+
+       if (display->last_error) {
+               cancel_read(display);
+               pthread_mutex_unlock(&display->mutex);
+
+               errno = display->last_error;
+               return -1;
+       }
+
+       ret = read_events(display);
+
+       pthread_mutex_unlock(&display->mutex);
+
+       return ret;
+}
+
+static int
+dispatch_queue(struct wl_display *display, struct wl_event_queue *queue)
+{
+       int count;
+
+       if (display->last_error)
+               goto err;
+
+       count = 0;
+       while (!wl_list_empty(&display->display_queue.event_list)) {
+               dispatch_event(display, &display->display_queue);
+               if (display->last_error)
+                       goto err;
+               count++;
+       }
+
+       while (!wl_list_empty(&queue->event_list)) {
+               dispatch_event(display, queue);
+               if (display->last_error)
+                       goto err;
+               count++;
+       }
+
+       return count;
+
+err:
+       errno = display->last_error;
+
+       return -1;
+}
+
+/** Prepare to read events from the display to this queue
+ *
+ * \param display The display context object
+ * \param queue The event queue to use
+ * \return 0 on success or -1 if event queue was not empty
+ *
+ * Atomically makes sure the queue is empty and stops any other thread
+ * from placing events into this (or any) queue.  Caller must
+ * eventually call either wl_display_cancel_read() or
+ * wl_display_read_events(), usually after waiting for the
+ * display fd to become ready for reading, to release the lock.
+ *
+ * \sa wl_display_prepare_read
+ * \memberof wl_event_queue
+ */
+WL_EXPORT int
+wl_display_prepare_read_queue(struct wl_display *display,
+                             struct wl_event_queue *queue)
+{
+       int ret;
+
+       pthread_mutex_lock(&display->mutex);
+
+       if (!wl_list_empty(&queue->event_list)) {
+               errno = EAGAIN;
+               ret = -1;
+       } else {
+               display->reader_count++;
+               ret = 0;
+       }
+
+       pthread_mutex_unlock(&display->mutex);
+
+       return ret;
+}
+
+/** Prepare to read events from the display's file descriptor
+ *
+ * \param display The display context object
+ * \return 0 on success or -1 if event queue was not empty
+ *
+ * This function must be called before reading from the file
+ * descriptor using wl_display_read_events(). Calling
+ * wl_display_prepare_read() announces the calling thread's intention
+ * to read and ensures that until the thread is ready to read and
+ * calls wl_display_read_events(), no other thread will read from the
+ * file descriptor. This only succeeds if the event queue is empty
+ * though, and if there are undispatched events in the queue, -1 is
+ * returned and errno set to EAGAIN.
+ *
+ * If a thread successfully calls wl_display_prepare_read(), it must
+ * either call wl_display_read_events() when it's ready or cancel the
+ * read intention by calling wl_display_cancel_read().
+ *
+ * Use this function before polling on the display fd or to integrate
+ * the fd into a toolkit event loop in a race-free way.
+ * A correct usage would be (we left out most of error checking):
+ *
+ * \code
+ * while (wl_display_prepare_read(display) != 0)
+ *         wl_display_dispatch_pending(display);
+ * wl_display_flush(display);
+ *
+ * ret = poll(fds, nfds, -1);
+ * if (has_error(ret))
+ *         wl_display_cancel_read(display);
+ * else
+ *         wl_display_read_events(display);
+ *
+ * wl_display_dispatch_pending(display);
+ * \endcode
+ *
+ * Here we call wl_display_prepare_read(), which ensures that between
+ * returning from that call and eventually calling
+ * wl_display_read_events(), no other thread will read from the fd and
+ * queue events in our queue. If the call to wl_display_prepare_read() fails,
+ * we dispatch the pending events and try again until we're successful.
+ *
+ * When using wl_display_dispatch() we'd have something like:
+ *
+ * \code
+ * wl_display_dispatch_pending(display);
+ * wl_display_flush(display);
+ * poll(fds, nfds, -1);
+ * wl_display_dispatch(display);
+ * \endcode
+ *
+ * This sequence in not thread-safe. The race is immediately after poll(),
+ * where one thread could preempt and read events before the other thread calls
+ * wl_display_dispatch(). This call now blocks and starves the other
+ * fds in the event loop.
+ *
+ * Another race would be when using more event queues.
+ * When one thread calls wl_display_dispatch(_queue)(), then it
+ * reads all events from display's fd and queues them in appropriate
+ * queues. Then it dispatches only its own queue and the other events
+ * are sitting in their queues, waiting for dispatching. If that happens
+ * before the other thread managed to call poll(), it will
+ * block with events queued.
+ *
+ * wl_display_prepare_read() function doesn't acquire exclusive access
+ * to the display's fd. It only registers that the thread calling this function
+ * has intention to read from fd.
+ * When all registered readers call wl_display_read_events(),
+ * only one (at random) eventually reads and queues the events and the
+ * others are sleeping meanwhile. This way we avoid races and still
+ * can read from more threads.
+ *
+ * If the relevant queue is not the default queue, then
+ * wl_display_prepare_read_queue() and wl_display_dispatch_queue_pending()
+ * need to be used instead.
+ *
+ * \sa wl_display_cancel_read(), wl_display_read_events()
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT int
+wl_display_prepare_read(struct wl_display *display)
+{
+       return wl_display_prepare_read_queue(display, &display->default_queue);
+}
+
+/** Cancel read intention on display's fd
+ *
+ * \param display The display context object
+ *
+ * After a thread successfully called wl_display_prepare_read() it must
+ * either call wl_display_read_events() or wl_display_cancel_read().
+ * If the threads do not follow this rule it will lead to deadlock.
+ *
+ * \sa wl_display_prepare_read(), wl_display_read_events()
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT void
+wl_display_cancel_read(struct wl_display *display)
+{
+       pthread_mutex_lock(&display->mutex);
+
+       cancel_read(display);
+
+       pthread_mutex_unlock(&display->mutex);
+}
+
+/** Dispatch events in an event queue
+ *
+ * \param display The display context object
+ * \param queue The event queue to dispatch
+ * \return The number of dispatched events on success or -1 on failure
+ *
+ * Dispatch all incoming events for objects assigned to the given
+ * event queue. On failure -1 is returned and errno set appropriately.
+ *
+ * The behaviour of this function is exactly the same as the behaviour of
+ * wl_display_dispatch(), but it dispatches events on given queue,
+ * not on the default queue.
+ *
+ * This function blocks if there are no events to dispatch (if there are,
+ * it only dispatches these events and returns immediately).
+ * When this function returns after blocking, it means that it read events
+ * from display's fd and queued them to appropriate queues.
+ * If among the incoming events were some events assigned to the given queue,
+ * they are dispatched by this moment.
+ *
+ * \note Since Wayland 1.5 the display has an extra queue
+ * for its own events (i. e. delete_id). This queue is dispatched always,
+ * no matter what queue we passed as an argument to this function.
+ * That means that this function can return non-0 value even when it
+ * haven't dispatched any event for the given queue.
+ *
+ * This function has the same constrains for using in multi-threaded apps
+ * as \ref wl_display_dispatch().
+ *
+ * \sa wl_display_dispatch(), wl_display_dispatch_pending(),
+ * wl_display_dispatch_queue_pending()
+ *
+ * \memberof wl_event_queue
+ */
+WL_EXPORT int
+wl_display_dispatch_queue(struct wl_display *display,
+                         struct wl_event_queue *queue)
+{
+       struct pollfd pfd[2];
+       int ret;
+
+       pthread_mutex_lock(&display->mutex);
+
+       ret = dispatch_queue(display, queue);
+       if (ret == -1)
+               goto err_unlock;
+       if (ret > 0) {
+               pthread_mutex_unlock(&display->mutex);
+               return ret;
+       }
+
+       /* We ignore EPIPE here, so that we try to read events before
+        * returning an error.  When the compositor sends an error it
+        * will close the socket, and if we bail out here we don't get
+        * a chance to process the error. */
+       ret = wl_connection_flush(display->connection);
+       if (ret < 0 && errno != EAGAIN && errno != EPIPE) {
+               display_fatal_error(display, errno);
+               goto err_unlock;
+       }
+
+       display->reader_count++;
+
+       pthread_mutex_unlock(&display->mutex);
+
+       pfd[0].fd = display->fd;
+       pfd[0].events = POLLIN;
+       do {
+               ret = poll(pfd, 1, -1);
+       } while (ret == -1 && errno == EINTR);
+
+       if (ret == -1) {
+               wl_display_cancel_read(display);
+               return -1;
+       }
+
+       pthread_mutex_lock(&display->mutex);
+
+       if (read_events(display) == -1)
+               goto err_unlock;
+
+       ret = dispatch_queue(display, queue);
+       if (ret == -1)
+               goto err_unlock;
+
+       pthread_mutex_unlock(&display->mutex);
+
+       return ret;
+
+ err_unlock:
+       pthread_mutex_unlock(&display->mutex);
+       return -1;
+}
+
+/** Dispatch pending events in an event queue
+ *
+ * \param display The display context object
+ * \param queue The event queue to dispatch
+ * \return The number of dispatched events on success or -1 on failure
+ *
+ * Dispatch all incoming events for objects assigned to the given
+ * event queue. On failure -1 is returned and errno set appropriately.
+ * If there are no events queued, this function returns immediately.
+ *
+ * \memberof wl_event_queue
+ * \since 1.0.2
+ */
+WL_EXPORT int
+wl_display_dispatch_queue_pending(struct wl_display *display,
+                                 struct wl_event_queue *queue)
+{
+       int ret;
+
+       pthread_mutex_lock(&display->mutex);
+
+       ret = dispatch_queue(display, queue);
+
+       pthread_mutex_unlock(&display->mutex);
+
+       return ret;
+}
+
+/** Process incoming events
+ *
+ * \param display The display context object
+ * \return The number of dispatched events on success or -1 on failure
+ *
+ * Dispatch the display's default event queue.
+ *
+ * If the default event queue is empty, this function blocks until there are
+ * events to be read from the display fd. Events are read and queued on
+ * the appropriate event queues. Finally, events on the default event queue
+ * are dispatched.
+ *
+ * In multi-threaded environment, programmer may want to use
+ * wl_display_read_events(). However, use of wl_display_read_events()
+ * must not be mixed with wl_display_dispatch(). See wl_display_read_events()
+ * and wl_display_prepare_read() for more details.
+ *
+ * \note It is not possible to check if there are events on the queue
+ * or not. For dispatching default queue events without blocking, see \ref
+ * wl_display_dispatch_pending().
+ *
+ * \sa wl_display_dispatch_pending(), wl_display_dispatch_queue(),
+ * wl_display_read_events()
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT int
+wl_display_dispatch(struct wl_display *display)
+{
+       return wl_display_dispatch_queue(display, &display->default_queue);
+}
+
+/** Dispatch default queue events without reading from the display fd
+ *
+ * \param display The display context object
+ * \return The number of dispatched events or -1 on failure
+ *
+ * This function dispatches events on the main event queue. It does not
+ * attempt to read the display fd and simply returns zero if the main
+ * queue is empty, i.e., it doesn't block.
+ *
+ * This is necessary when a client's main loop wakes up on some fd other
+ * than the display fd (network socket, timer fd, etc) and calls \ref
+ * wl_display_dispatch_queue() from that callback. This may queue up
+ * events in other queues while reading all data from the display fd.
+ * When the main loop returns from the handler, the display fd
+ * no longer has data, causing a call to \em poll(2) (or similar
+ * functions) to block indefinitely, even though there are events ready
+ * to dispatch.
+ *
+ * To proper integrate the wayland display fd into a main loop, the
+ * client should always call wl_display_dispatch_pending() and then
+ * \ref wl_display_flush() prior to going back to sleep. At that point,
+ * the fd typically doesn't have data so attempting I/O could block, but
+ * events queued up on the default queue should be dispatched.
+ *
+ * A real-world example is a main loop that wakes up on a timerfd (or a
+ * sound card fd becoming writable, for example in a video player), which
+ * then triggers GL rendering and eventually eglSwapBuffers().
+ * eglSwapBuffers() may call wl_display_dispatch_queue() if it didn't
+ * receive the frame event for the previous frame, and as such queue
+ * events in the default queue.
+ *
+ * \sa wl_display_dispatch(), wl_display_dispatch_queue(),
+ * wl_display_flush()
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT int
+wl_display_dispatch_pending(struct wl_display *display)
+{
+       return wl_display_dispatch_queue_pending(display,
+                                                &display->default_queue);
+}
+
+/** Retrieve the last error that occurred on a display
+ *
+ * \param display The display context object
+ * \return The last error that occurred on \c display or 0 if no error occurred
+ *
+ * Return the last error that occurred on the display. This may be an error sent
+ * by the server or caused by the local client.
+ *
+ * \note Errors are \b fatal. If this function returns non-zero the display
+ * can no longer be used.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT int
+wl_display_get_error(struct wl_display *display)
+{
+       int ret;
+
+       pthread_mutex_lock(&display->mutex);
+
+       ret = display->last_error;
+
+       pthread_mutex_unlock(&display->mutex);
+
+       return ret;
+}
+
+/** Retrieves the information about a protocol error:
+ *
+ * \param display    The Wayland display
+ * \param interface  if not NULL, stores the interface where the error occurred
+ * \param id         if not NULL, stores the object id that generated
+ *                   the error. There's no guarantee the object is
+ *                   still valid; the client must know if it deleted the object.
+ * \return           The error code as defined in the interface specification.
+ *
+ * \code
+ * int err = wl_display_get_error(display);
+ *
+ * if (err == EPROTO) {
+ *        code = wl_display_get_protocol_error(display, &interface, &id);
+ *        handle_error(code, interface, id);
+ * }
+ *
+ * ...
+ * \endcode
+ * \memberof wl_display
+ */
+WL_EXPORT uint32_t
+wl_display_get_protocol_error(struct wl_display *display,
+                             const struct wl_interface **interface,
+                             uint32_t *id)
+{
+       uint32_t ret;
+
+       pthread_mutex_lock(&display->mutex);
+
+       ret = display->protocol_error.code;
+
+       if (interface)
+               *interface = display->protocol_error.interface;
+       if (id)
+               *id = display->protocol_error.id;
+
+       pthread_mutex_unlock(&display->mutex);
+
+       return ret;
+}
+
+
+/** Send all buffered requests on the display to the server
+ *
+ * \param display The display context object
+ * \return The number of bytes sent on success or -1 on failure
+ *
+ * Send all buffered data on the client side to the server. Clients
+ * should call this function before blocking. On success, the number
+ * of bytes sent to the server is returned. On failure, this
+ * function returns -1 and errno is set appropriately.
+ *
+ * wl_display_flush() never blocks.  It will write as much data as
+ * possible, but if all data could not be written, errno will be set
+ * to EAGAIN and -1 returned.  In that case, use poll on the display
+ * file descriptor to wait for it to become writable again.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT int
+wl_display_flush(struct wl_display *display)
+{
+       int ret;
+
+       pthread_mutex_lock(&display->mutex);
+
+       if (display->last_error) {
+               errno = display->last_error;
+               ret = -1;
+       } else {
+               ret = wl_connection_flush(display->connection);
+               if (ret < 0 && errno != EAGAIN)
+                       display_fatal_error(display, errno);
+       }
+
+       pthread_mutex_unlock(&display->mutex);
+
+       return ret;
+}
+
+/** Set the user data associated with a proxy
+ *
+ * \param proxy The proxy object
+ * \param user_data The data to be associated with proxy
+ *
+ * Set the user data associated with \c proxy. When events for this
+ * proxy are received, \c user_data will be supplied to its listener.
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT void
+wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data)
+{
+       proxy->user_data = user_data;
+}
+
+/** Get the user data associated with a proxy
+ *
+ * \param proxy The proxy object
+ * \return The user data associated with proxy
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT void *
+wl_proxy_get_user_data(struct wl_proxy *proxy)
+{
+       return proxy->user_data;
+}
+
+/** Get the id of a proxy object
+ *
+ * \param proxy The proxy object
+ * \return The id the object associated with the proxy
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT uint32_t
+wl_proxy_get_id(struct wl_proxy *proxy)
+{
+       return proxy->object.id;
+}
+
+/** Get the interface name (class) of a proxy object
+ *
+ * \param proxy The proxy object
+ * \return The interface name of the object associated with the proxy
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT const char *
+wl_proxy_get_class(struct wl_proxy *proxy)
+{
+       return proxy->object.interface->name;
+}
+
+/** Assign a proxy to an event queue
+ *
+ * \param proxy The proxy object
+ * \param queue The event queue that will handle this proxy or NULL
+ *
+ * Assign proxy to event queue. Events coming from \c proxy will be
+ * queued in \c queue from now. If queue is NULL, then the display's
+ * default queue is set to the proxy.
+ *
+ * \note By default, the queue set in proxy is the one inherited from parent.
+ *
+ * \sa wl_display_dispatch_queue()
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT void
+wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue)
+{
+       if (queue)
+               proxy->queue = queue;
+       else
+               proxy->queue = &proxy->display->default_queue;
+}
+
+WL_EXPORT void
+wl_log_set_handler_client(wl_log_func_t handler)
+{
+       wl_log_handler = handler;
+}
diff --git a/src/wayland-client.h b/src/wayland-client.h
new file mode 100644 (file)
index 0000000..71cd822
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * 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_CLIENT_H
+#define WAYLAND_CLIENT_H
+
+#include "wayland-util.h"
+#include "wayland-version.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/** \class wl_proxy
+ *
+ * \brief Represents a protocol object on the client side.
+ *
+ * A wl_proxy acts as a client side proxy to an object existing in the
+ * compositor. The proxy is responsible for converting requests made by the
+ * clients with \ref wl_proxy_marshal() into Wayland's wire format. Events
+ * coming from the compositor are also handled by the proxy, which will in
+ * turn call the handler set with \ref wl_proxy_add_listener().
+ *
+ * \note With the exception of function \ref wl_proxy_set_queue(), functions
+ * accessing a wl_proxy are not normally used by client code. Clients
+ * should normally use the higher level interface generated by the scanner to
+ * interact with compositor objects.
+ *
+ */
+struct wl_proxy;
+
+/** \class wl_display
+ *
+ * \brief Represents a connection to the compositor and acts as a proxy to
+ * the wl_display singleton object.
+ *
+ * A wl_display object represents a client connection to a Wayland
+ * compositor. It is created with either \ref wl_display_connect() or
+ * \ref wl_display_connect_to_fd(). A connection is terminated using
+ * \ref wl_display_disconnect().
+ *
+ * A wl_display is also used as the \ref wl_proxy for the wl_display
+ * singleton object on the compositor side.
+ *
+ * A wl_display object handles all the data sent from and to the
+ * compositor. When a \ref wl_proxy marshals a request, it will write its wire
+ * representation to the display's write buffer. The data is sent to the
+ * compositor when the client calls \ref wl_display_flush().
+ *
+ * Incoming data is handled in two steps: queueing and dispatching. In the
+ * queue step, the data coming from the display fd is interpreted and
+ * added to a queue. On the dispatch step, the handler for the incoming
+ * event set by the client on the corresponding \ref wl_proxy is called.
+ *
+ * A wl_display has at least one event queue, called the <em>default
+ * queue</em>. Clients can create additional event queues with \ref
+ * wl_display_create_queue() and assign \ref wl_proxy's to it. Events
+ * occurring in a particular proxy are always queued in its assigned queue.
+ * A client can ensure that a certain assumption, such as holding a lock
+ * or running from a given thread, is true when a proxy event handler is
+ * called by assigning that proxy to an event queue and making sure that
+ * this queue is only dispatched when the assumption holds.
+ *
+ * The default queue is dispatched by calling \ref wl_display_dispatch().
+ * This will dispatch any events queued on the default queue and attempt
+ * to read from the display fd if it's empty. Events read are then queued
+ * on the appropriate queues according to the proxy assignment.
+ *
+ * A user created queue is dispatched with \ref wl_display_dispatch_queue().
+ * This function behaves exactly the same as wl_display_dispatch()
+ * but it dispatches given queue instead of the default queue.
+ *
+ * A real world example of event queue usage is Mesa's implementation of
+ * eglSwapBuffers() for the Wayland platform. This function might need
+ * to block until a frame callback is received, but dispatching the default
+ * queue could cause an event handler on the client to start drawing
+ * again. This problem is solved using another event queue, so that only
+ * the events handled by the EGL code are dispatched during the block.
+ *
+ * This creates a problem where a thread dispatches a non-default
+ * queue, reading all the data from the display fd. If the application
+ * would call \em poll(2) after that it would block, even though there
+ * might be events queued on the default queue. Those events should be
+ * dispatched with \ref wl_display_dispatch_(queue_)pending() before
+ * flushing and blocking.
+ */
+struct wl_display;
+
+/** \class wl_event_queue
+ *
+ * \brief A queue for \ref wl_proxy object events.
+ *
+ * Event queues allows the events on a display to be handled in a thread-safe
+ * manner. See \ref wl_display for details.
+ *
+ */
+struct wl_event_queue;
+
+void wl_event_queue_destroy(struct wl_event_queue *queue);
+
+void wl_proxy_marshal(struct wl_proxy *p, uint32_t opcode, ...);
+void wl_proxy_marshal_array(struct wl_proxy *p, uint32_t opcode,
+                           union wl_argument *args);
+struct wl_proxy *wl_proxy_create(struct wl_proxy *factory,
+                                const struct wl_interface *interface);
+struct wl_proxy *wl_proxy_marshal_constructor(struct wl_proxy *proxy,
+                                             uint32_t opcode,
+                                             const struct wl_interface *interface,
+                                             ...);
+struct wl_proxy *
+wl_proxy_marshal_array_constructor(struct wl_proxy *proxy,
+                                  uint32_t opcode, union wl_argument *args,
+                                  const struct wl_interface *interface);
+
+void wl_proxy_destroy(struct wl_proxy *proxy);
+int wl_proxy_add_listener(struct wl_proxy *proxy,
+                         void (**implementation)(void), void *data);
+const void *wl_proxy_get_listener(struct wl_proxy *proxy);
+int wl_proxy_add_dispatcher(struct wl_proxy *proxy,
+                           wl_dispatcher_func_t dispatcher_func,
+                           const void * dispatcher_data, void *data);
+void wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data);
+void *wl_proxy_get_user_data(struct wl_proxy *proxy);
+uint32_t wl_proxy_get_id(struct wl_proxy *proxy);
+const char *wl_proxy_get_class(struct wl_proxy *proxy);
+void wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue);
+
+#include "wayland-client-protocol.h"
+
+struct wl_display *wl_display_connect(const char *name);
+struct wl_display *wl_display_connect_to_fd(int fd);
+void wl_display_disconnect(struct wl_display *display);
+int wl_display_get_fd(struct wl_display *display);
+int wl_display_dispatch(struct wl_display *display);
+int wl_display_dispatch_queue(struct wl_display *display,
+                             struct wl_event_queue *queue);
+int wl_display_dispatch_queue_pending(struct wl_display *display,
+                                     struct wl_event_queue *queue);
+int wl_display_dispatch_pending(struct wl_display *display);
+int wl_display_get_error(struct wl_display *display);
+uint32_t wl_display_get_protocol_error(struct wl_display *display,
+                                      const struct wl_interface **interface,
+                                      uint32_t *id);
+
+int wl_display_flush(struct wl_display *display);
+int wl_display_roundtrip_queue(struct wl_display *display,
+                               struct wl_event_queue *queue);
+int wl_display_roundtrip(struct wl_display *display);
+struct wl_event_queue *wl_display_create_queue(struct wl_display *display);
+
+int wl_display_prepare_read_queue(struct wl_display *display,
+                                 struct wl_event_queue *queue);
+int wl_display_prepare_read(struct wl_display *display);
+void wl_display_cancel_read(struct wl_display *display);
+int wl_display_read_events(struct wl_display *display);
+
+void wl_log_set_handler_client(wl_log_func_t handler);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/wayland-client.pc.in b/src/wayland-client.pc.in
new file mode 100644 (file)
index 0000000..eef61da
--- /dev/null
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+datarootdir=@datarootdir@
+pkgdatadir=@datadir@/@PACKAGE@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Wayland Client
+Description: Wayland client side library
+Version: @WAYLAND_VERSION@
+Cflags: -I${includedir}
+Libs: -L${libdir} -lwayland-client
diff --git a/src/wayland-egl.h b/src/wayland-egl.h
new file mode 100644 (file)
index 0000000..c40280b
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright © 2011 Kristian Høgsberg
+ * Copyright © 2011 Benjamin Franzke
+ *
+ * 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_EGL_H
+#define WAYLAND_EGL_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include <wayland-client.h>
+
+#define WL_EGL_PLATFORM 1
+
+struct wl_egl_window;
+
+struct wl_egl_window *
+wl_egl_window_create(struct wl_surface *surface,
+                    int width, int height);
+
+void
+wl_egl_window_destroy(struct wl_egl_window *egl_window);
+
+void
+wl_egl_window_resize(struct wl_egl_window *egl_window,
+                    int width, int height,
+                    int dx, int dy);
+
+void
+wl_egl_window_get_attached_size(struct wl_egl_window *egl_window,
+                               int *width, int *height);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/wayland-os.c b/src/wayland-os.c
new file mode 100644 (file)
index 0000000..1185e1d
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/epoll.h>
+
+#include "../config.h"
+#include "wayland-os.h"
+
+static int
+set_cloexec_or_close(int fd)
+{
+       long flags;
+
+       if (fd == -1)
+               return -1;
+
+       flags = fcntl(fd, F_GETFD);
+       if (flags == -1)
+               goto err;
+
+       if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
+               goto err;
+
+       return fd;
+
+err:
+       close(fd);
+       return -1;
+}
+
+int
+wl_os_socket_cloexec(int domain, int type, int protocol)
+{
+       int fd;
+
+       fd = socket(domain, type | SOCK_CLOEXEC, protocol);
+       if (fd >= 0)
+               return fd;
+       if (errno != EINVAL)
+               return -1;
+
+       fd = socket(domain, type, protocol);
+       return set_cloexec_or_close(fd);
+}
+
+int
+wl_os_dupfd_cloexec(int fd, long minfd)
+{
+       int newfd;
+
+       newfd = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
+       if (newfd >= 0)
+               return newfd;
+       if (errno != EINVAL)
+               return -1;
+
+       newfd = fcntl(fd, F_DUPFD, minfd);
+       return set_cloexec_or_close(newfd);
+}
+
+static ssize_t
+recvmsg_cloexec_fallback(int sockfd, struct msghdr *msg, int flags)
+{
+       ssize_t len;
+       struct cmsghdr *cmsg;
+       unsigned char *data;
+       int *fd;
+       int *end;
+
+       len = recvmsg(sockfd, msg, flags);
+       if (len == -1)
+               return -1;
+
+       if (!msg->msg_control || msg->msg_controllen == 0)
+               return len;
+
+       cmsg = CMSG_FIRSTHDR(msg);
+       for (; cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+               if (cmsg->cmsg_level != SOL_SOCKET ||
+                   cmsg->cmsg_type != SCM_RIGHTS)
+                       continue;
+
+               data = CMSG_DATA(cmsg);
+               end = (int *)(data + cmsg->cmsg_len - CMSG_LEN(0));
+               for (fd = (int *)data; fd < end; ++fd)
+                       *fd = set_cloexec_or_close(*fd);
+       }
+
+       return len;
+}
+
+ssize_t
+wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags)
+{
+       ssize_t len;
+
+       len = recvmsg(sockfd, msg, flags | MSG_CMSG_CLOEXEC);
+       if (len >= 0)
+               return len;
+       if (errno != EINVAL)
+               return -1;
+
+       return recvmsg_cloexec_fallback(sockfd, msg, flags);
+}
+
+int
+wl_os_epoll_create_cloexec(void)
+{
+       int fd;
+
+#ifdef EPOLL_CLOEXEC
+       fd = epoll_create1(EPOLL_CLOEXEC);
+       if (fd >= 0)
+               return fd;
+       if (errno != EINVAL)
+               return -1;
+#endif
+
+       fd = epoll_create(1);
+       return set_cloexec_or_close(fd);
+}
+
+int
+wl_os_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
+{
+       int fd;
+
+#ifdef HAVE_ACCEPT4
+       fd = accept4(sockfd, addr, addrlen, SOCK_CLOEXEC);
+       if (fd >= 0)
+               return fd;
+       if (errno != ENOSYS)
+               return -1;
+#endif
+
+       fd = accept(sockfd, addr, addrlen);
+       return set_cloexec_or_close(fd);
+}
diff --git a/src/wayland-os.h b/src/wayland-os.h
new file mode 100644 (file)
index 0000000..c612975
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * 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_OS_H
+#define WAYLAND_OS_H
+
+int
+wl_os_socket_cloexec(int domain, int type, int protocol);
+
+int
+wl_os_dupfd_cloexec(int fd, long minfd);
+
+ssize_t
+wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags);
+
+int
+wl_os_epoll_create_cloexec(void);
+
+int
+wl_os_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
+
+
+/*
+ * The following are for wayland-os.c and the unit tests.
+ * Do not use them elsewhere.
+ */
+
+#ifdef __linux__
+
+#ifndef SOCK_CLOEXEC
+#define SOCK_CLOEXEC 02000000
+#endif
+
+#ifndef F_DUPFD_CLOEXEC
+#define F_DUPFD_CLOEXEC 1030
+#endif
+
+#ifndef MSG_CMSG_CLOEXEC
+#define MSG_CMSG_CLOEXEC 0x40000000
+#endif
+
+#endif /* __linux__ */
+
+#endif
diff --git a/src/wayland-private.h b/src/wayland-private.h
new file mode 100644 (file)
index 0000000..db76081
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2011 Intel Corporation
+ * Copyright © 2013 Jason Ekstrand
+ *
+ * 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_PRIVATE_H
+#define WAYLAND_PRIVATE_H
+
+#include <stdarg.h>
+
+#define WL_HIDE_DEPRECATED 1
+
+#include "wayland-util.h"
+
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+
+#define container_of(ptr, type, member) ({                             \
+       const __typeof__( ((type *)0)->member ) *__mptr = (ptr);        \
+       (type *)( (char *)__mptr - offsetof(type,member) );})
+
+#define WL_MAP_SERVER_SIDE 0
+#define WL_MAP_CLIENT_SIDE 1
+#define WL_SERVER_ID_START 0xff000000
+#define WL_CLOSURE_MAX_ARGS 20
+
+struct wl_object {
+       const struct wl_interface *interface;
+       const void *implementation;
+       uint32_t id;
+};
+
+extern struct wl_object global_zombie_object;
+#define WL_ZOMBIE_OBJECT ((void*)&global_zombie_object)
+
+/* Flags for wl_map_insert_new and wl_map_insert_at.  Flags can be queried with
+ * wl_map_lookup_flags.  The current implementation has room for 1 bit worth of
+ * flags.  If more flags are ever added, the implementation of wl_map will have
+ * to change to allow for new flags */
+enum wl_map_entry_flags {
+       WL_MAP_ENTRY_LEGACY = (1 << 0)
+};
+
+struct wl_map {
+       struct wl_array client_entries;
+       struct wl_array server_entries;
+       uint32_t side;
+       uint32_t free_list;
+};
+
+typedef void (*wl_iterator_func_t)(void *element, void *data);
+
+void wl_map_init(struct wl_map *map, uint32_t side);
+void wl_map_release(struct wl_map *map);
+uint32_t wl_map_insert_new(struct wl_map *map, uint32_t flags, void *data);
+int wl_map_insert_at(struct wl_map *map, uint32_t flags, uint32_t i, void *data);
+int wl_map_reserve_new(struct wl_map *map, uint32_t i);
+void wl_map_remove(struct wl_map *map, uint32_t i);
+void *wl_map_lookup(struct wl_map *map, uint32_t i);
+uint32_t wl_map_lookup_flags(struct wl_map *map, uint32_t i);
+void wl_map_for_each(struct wl_map *map, wl_iterator_func_t func, void *data);
+
+struct wl_connection;
+struct wl_closure;
+struct wl_proxy;
+
+int wl_interface_equal(const struct wl_interface *iface1,
+                      const struct wl_interface *iface2);
+
+struct wl_connection *wl_connection_create(int fd);
+int wl_connection_destroy(struct wl_connection *connection);
+void wl_connection_copy(struct wl_connection *connection, void *data, size_t size);
+void wl_connection_consume(struct wl_connection *connection, size_t size);
+
+int wl_connection_flush(struct wl_connection *connection);
+int wl_connection_read(struct wl_connection *connection);
+
+int wl_connection_write(struct wl_connection *connection, const void *data, size_t count);
+int wl_connection_queue(struct wl_connection *connection,
+                       const void *data, size_t count);
+
+struct wl_closure {
+       int count;
+       const struct wl_message *message;
+       uint32_t opcode;
+       uint32_t sender_id;
+       union wl_argument args[WL_CLOSURE_MAX_ARGS];
+       struct wl_list link;
+       struct wl_proxy *proxy;
+       struct wl_array extra[0];
+};
+
+struct argument_details {
+       char type;
+       int nullable;
+};
+
+const char *
+get_next_argument(const char *signature, struct argument_details *details);
+
+int
+arg_count_for_signature(const char *signature);
+
+int
+wl_message_get_since(const struct wl_message *message);
+
+void
+wl_argument_from_va_list(const char *signature, union wl_argument *args,
+                        int count, va_list ap);
+
+struct wl_closure *
+wl_closure_marshal(struct wl_object *sender,
+                   uint32_t opcode, union wl_argument *args,
+                   const struct wl_message *message);
+struct wl_closure *
+wl_closure_vmarshal(struct wl_object *sender,
+                   uint32_t opcode, va_list ap,
+                   const struct wl_message *message);
+
+struct wl_closure *
+wl_connection_demarshal(struct wl_connection *connection,
+                       uint32_t size,
+                       struct wl_map *objects,
+                       const struct wl_message *message);
+
+int
+wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects);
+
+enum wl_closure_invoke_flag {
+       WL_CLOSURE_INVOKE_CLIENT = (1 << 0),
+       WL_CLOSURE_INVOKE_SERVER = (1 << 1)
+};
+
+void
+wl_closure_invoke(struct wl_closure *closure, uint32_t flags,
+                 struct wl_object *target, uint32_t opcode, void *data);
+void
+wl_closure_dispatch(struct wl_closure *closure, wl_dispatcher_func_t dispatcher,
+                   struct wl_object *target, uint32_t opcode);
+int
+wl_closure_send(struct wl_closure *closure, struct wl_connection *connection);
+int
+wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection);
+void
+wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send);
+void
+wl_closure_destroy(struct wl_closure *closure);
+
+extern wl_log_func_t wl_log_handler;
+
+void wl_log(const char *fmt, ...);
+
+struct wl_display;
+
+struct wl_array *
+wl_display_get_additional_shm_formats(struct wl_display *display);
+
+#endif
diff --git a/src/wayland-scanner-uninstalled.pc.in b/src/wayland-scanner-uninstalled.pc.in
new file mode 100644 (file)
index 0000000..8dcfef3
--- /dev/null
@@ -0,0 +1,6 @@
+pkgdatadir=@abs_top_srcdir@
+wayland_scanner=@abs_builddir@/wayland-scanner
+Name: Wayland Scanner
+Description: Wayland scanner (not installed)
+Version: @PACKAGE_VERSION@
diff --git a/src/wayland-scanner.pc.in b/src/wayland-scanner.pc.in
new file mode 100644 (file)
index 0000000..7b2a4c9
--- /dev/null
@@ -0,0 +1,9 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+datarootdir=@datarootdir@
+pkgdatadir=@datadir@/@PACKAGE@
+wayland_scanner=@bindir@/wayland-scanner
+
+Name: Wayland Scanner
+Description: Wayland scanner
+Version: @WAYLAND_VERSION@
diff --git a/src/wayland-server-uninstalled.pc.in b/src/wayland-server-uninstalled.pc.in
new file mode 100644 (file)
index 0000000..9057782
--- /dev/null
@@ -0,0 +1,8 @@
+libdir=@abs_builddir@/.libs
+includedir=@abs_srcdir@
+Name: Wayland Server
+Description: Server side implementation of the Wayland protocol (not installed)
+Version: @PACKAGE_VERSION@
+Cflags: -I${includedir}
+Libs: -L${libdir} -lwayland-server
diff --git a/src/wayland-server.c b/src/wayland-server.c
new file mode 100644 (file)
index 0000000..2893a86
--- /dev/null
@@ -0,0 +1,1533 @@
+/*
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdbool.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 <sys/time.h>
+#include <fcntl.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#ifdef HAVE_MULTISEAT
+#include <sys/types.h>
+#include <grp.h>
+#endif
+#include <ffi.h>
+
+#include "wayland-private.h"
+#include "wayland-server.h"
+#include "wayland-server-protocol.h"
+#include "wayland-os.h"
+
+/* This is the size of the char array in struct sock_addr_un.
+   No Wayland socket can be created with a path longer than this,
+   including the null terminator. */
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX  108
+#endif
+
+#define LOCK_SUFFIX    ".lock"
+#define LOCK_SUFFIXLEN 5
+
+struct wl_socket {
+       int fd;
+       int fd_lock;
+       struct sockaddr_un addr;
+       char lock_addr[UNIX_PATH_MAX + LOCK_SUFFIXLEN];
+       struct wl_list link;
+       struct wl_event_source *source;
+       char *display_name;
+};
+
+struct wl_client {
+       struct wl_connection *connection;
+       struct wl_event_source *source;
+       struct wl_display *display;
+       struct wl_resource *display_resource;
+       uint32_t id_count;
+       uint32_t mask;
+       struct wl_list link;
+       struct wl_map objects;
+       struct wl_signal destroy_signal;
+       struct ucred ucred;
+       int error;
+};
+
+struct wl_display {
+       struct wl_event_loop *loop;
+       int run;
+
+       uint32_t id;
+       uint32_t serial;
+
+       struct wl_list registry_resource_list;
+       struct wl_list global_list;
+       struct wl_list socket_list;
+       struct wl_list client_list;
+
+       struct wl_signal destroy_signal;
+
+       struct wl_array additional_shm_formats;
+};
+
+struct wl_global {
+       struct wl_display *display;
+       const struct wl_interface *interface;
+       uint32_t name;
+       uint32_t version;
+       void *data;
+       wl_global_bind_func_t bind;
+       struct wl_list link;
+};
+
+struct wl_resource {
+       struct wl_object object;
+       wl_resource_destroy_func_t destroy;
+       struct wl_list link;
+       struct wl_signal destroy_signal;
+       struct wl_client *client;
+       void *data;
+       int version;
+       wl_dispatcher_func_t dispatcher;
+};
+
+static int debug_server = 0;
+
+WL_EXPORT void
+wl_resource_post_event_array(struct wl_resource *resource, uint32_t opcode,
+                            union wl_argument *args)
+{
+       struct wl_closure *closure;
+       struct wl_object *object = &resource->object;
+
+       closure = wl_closure_marshal(object, opcode, args,
+                                    &object->interface->events[opcode]);
+
+       if (closure == NULL) {
+               resource->client->error = 1;
+               return;
+       }
+
+       if (wl_closure_send(closure, resource->client->connection))
+               resource->client->error = 1;
+
+       if (debug_server)
+               wl_closure_print(closure, object, true);
+
+       wl_closure_destroy(closure);
+}
+
+WL_EXPORT void
+wl_resource_post_event(struct wl_resource *resource, uint32_t opcode, ...)
+{
+       union wl_argument args[WL_CLOSURE_MAX_ARGS];
+       struct wl_object *object = &resource->object;
+       va_list ap;
+
+       va_start(ap, opcode);
+       wl_argument_from_va_list(object->interface->events[opcode].signature,
+                                args, WL_CLOSURE_MAX_ARGS, ap);
+       va_end(ap);
+
+       wl_resource_post_event_array(resource, opcode, args);
+}
+
+
+WL_EXPORT void
+wl_resource_queue_event_array(struct wl_resource *resource, uint32_t opcode,
+                             union wl_argument *args)
+{
+       struct wl_closure *closure;
+       struct wl_object *object = &resource->object;
+
+       closure = wl_closure_marshal(object, opcode, args,
+                                    &object->interface->events[opcode]);
+
+       if (closure == NULL) {
+               resource->client->error = 1;
+               return;
+       }
+
+       if (wl_closure_queue(closure, resource->client->connection))
+               resource->client->error = 1;
+
+       if (debug_server)
+               wl_closure_print(closure, object, true);
+
+       wl_closure_destroy(closure);
+}
+
+WL_EXPORT void
+wl_resource_queue_event(struct wl_resource *resource, uint32_t opcode, ...)
+{
+       union wl_argument args[WL_CLOSURE_MAX_ARGS];
+       struct wl_object *object = &resource->object;
+       va_list ap;
+
+       va_start(ap, opcode);
+       wl_argument_from_va_list(object->interface->events[opcode].signature,
+                                args, WL_CLOSURE_MAX_ARGS, ap);
+       va_end(ap);
+
+       wl_resource_queue_event_array(resource, opcode, args);
+}
+
+WL_EXPORT void
+wl_resource_post_error(struct wl_resource *resource,
+                      uint32_t code, const char *msg, ...)
+{
+       struct wl_client *client = resource->client;
+       char buffer[128];
+       va_list ap;
+
+       va_start(ap, msg);
+       vsnprintf(buffer, sizeof buffer, msg, ap);
+       va_end(ap);
+
+       client->error = 1;
+
+       /*
+        * When a client aborts, its resources are destroyed in id order,
+        * which means the display resource is destroyed first. If destruction
+        * of any later resources results in a protocol error, we end up here
+        * with a NULL display_resource. Do not try to send errors to an
+        * already dead client.
+        */
+       if (!client->display_resource)
+               return;
+
+       wl_resource_post_event(client->display_resource,
+                              WL_DISPLAY_ERROR, resource, code, buffer);
+}
+
+static int
+wl_client_connection_data(int fd, uint32_t mask, void *data)
+{
+       struct wl_client *client = data;
+       struct wl_connection *connection = client->connection;
+       struct wl_resource *resource;
+       struct wl_object *object;
+       struct wl_closure *closure;
+       const struct wl_message *message;
+       uint32_t p[2];
+       uint32_t resource_flags;
+       int opcode, size;
+       int len;
+
+       if (mask & (WL_EVENT_ERROR | WL_EVENT_HANGUP)) {
+               wl_client_destroy(client);
+               return 1;
+       }
+
+       if (mask & WL_EVENT_WRITABLE) {
+               len = wl_connection_flush(connection);
+               if (len < 0 && errno != EAGAIN) {
+                       wl_client_destroy(client);
+                       return 1;
+               } else if (len >= 0) {
+                       wl_event_source_fd_update(client->source,
+                                                 WL_EVENT_READABLE);
+               }
+       }
+
+       len = 0;
+       if (mask & WL_EVENT_READABLE) {
+               len = wl_connection_read(connection);
+               if (len == 0 || (len < 0 && errno != EAGAIN)) {
+                       wl_client_destroy(client);
+                       return 1;
+               }
+       }
+
+       while ((size_t) len >= sizeof p) {
+               wl_connection_copy(connection, p, sizeof p);
+               opcode = p[1] & 0xffff;
+               size = p[1] >> 16;
+               if (len < size)
+                       break;
+
+               resource = wl_map_lookup(&client->objects, p[0]);
+               resource_flags = wl_map_lookup_flags(&client->objects, p[0]);
+               if (resource == NULL) {
+                       wl_resource_post_error(client->display_resource,
+                                              WL_DISPLAY_ERROR_INVALID_OBJECT,
+                                              "invalid object %u", p[0]);
+                       break;
+               }
+
+               object = &resource->object;
+               if (opcode >= object->interface->method_count) {
+                       wl_resource_post_error(client->display_resource,
+                                              WL_DISPLAY_ERROR_INVALID_METHOD,
+                                              "invalid method %d, object %s@%u",
+                                              opcode,
+                                              object->interface->name,
+                                              object->id);
+                       break;
+               }
+
+               message = &object->interface->methods[opcode];
+               if (!(resource_flags & WL_MAP_ENTRY_LEGACY) &&
+                   resource->version > 0 &&
+                   resource->version < wl_message_get_since(message)) {
+                       wl_resource_post_error(client->display_resource,
+                                              WL_DISPLAY_ERROR_INVALID_METHOD,
+                                              "invalid method %d, object %s@%u",
+                                              opcode,
+                                              object->interface->name,
+                                              object->id);
+                       break;
+               }
+
+
+               closure = wl_connection_demarshal(client->connection, size,
+                                                 &client->objects, message);
+               len -= size;
+
+               if (closure == NULL && errno == ENOMEM) {
+                       wl_resource_post_no_memory(resource);
+                       break;
+               } else if (closure == NULL ||
+                          wl_closure_lookup_objects(closure, &client->objects) < 0) {
+                       wl_resource_post_error(client->display_resource,
+                                              WL_DISPLAY_ERROR_INVALID_METHOD,
+                                              "invalid arguments for %s@%u.%s",
+                                              object->interface->name,
+                                              object->id,
+                                              message->name);
+                       wl_closure_destroy(closure);
+                       break;
+               }
+
+               if (debug_server)
+                       wl_closure_print(closure, object, false);
+
+               if ((resource_flags & WL_MAP_ENTRY_LEGACY) ||
+                   resource->dispatcher == NULL) {
+                       wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER,
+                                         object, opcode, client);
+               } else {
+                       wl_closure_dispatch(closure, resource->dispatcher,
+                                           object, opcode);
+               }
+
+               wl_closure_destroy(closure);
+
+               if (client->error)
+                       break;
+       }
+
+       if (client->error)
+               wl_client_destroy(client);
+
+       return 1;
+}
+
+/** Flush pending events to the client
+ *
+ * \param client The client object
+ *
+ * Events sent to clients are queued in a buffer and written to the
+ * socket later - typically when the compositor has handled all
+ * requests and goes back to block in the event loop.  This function
+ * flushes all queued up events for a client immediately.
+ *
+ * \memberof wl_client
+ */
+WL_EXPORT void
+wl_client_flush(struct wl_client *client)
+{
+       wl_connection_flush(client->connection);
+}
+
+/** Get the display object for the given client
+ *
+ * \param client The client object
+ * \return The display object the client is associated with.
+ *
+ * \memberof wl_client
+ */
+WL_EXPORT struct wl_display *
+wl_client_get_display(struct wl_client *client)
+{
+       return client->display;
+}
+
+static int
+bind_display(struct wl_client *client, struct wl_display *display);
+
+/** Create a client for the given file descriptor
+ *
+ * \param display The display object
+ * \param fd The file descriptor for the socket to the client
+ * \return The new client object or NULL on failure.
+ *
+ * Given a file descriptor corresponding to one end of a socket, this
+ * function will create a wl_client struct and add the new client to
+ * the compositors client list.  At that point, the client is
+ * initialized and ready to run, as if the client had connected to the
+ * servers listening socket.  When the client eventually sends
+ * requests to the compositor, the wl_client argument to the request
+ * handler will be the wl_client returned from this function.
+ *
+ * The other end of the socket can be passed to
+ * wl_display_connect_to_fd() on the client side or used with the
+ * WAYLAND_SOCKET environment variable on the client side.
+ *
+ * On failure this function sets errno accordingly and returns NULL.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT struct wl_client *
+wl_client_create(struct wl_display *display, int fd)
+{
+       struct wl_client *client;
+       socklen_t len;
+
+       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);
+
+       if (!client->source)
+               goto err_client;
+
+       len = sizeof client->ucred;
+       if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED,
+                      &client->ucred, &len) < 0)
+               goto err_source;
+
+       client->connection = wl_connection_create(fd);
+       if (client->connection == NULL)
+               goto err_source;
+
+       wl_map_init(&client->objects, WL_MAP_SERVER_SIDE);
+
+       if (wl_map_insert_at(&client->objects, 0, 0, NULL) < 0)
+               goto err_map;
+
+       wl_signal_init(&client->destroy_signal);
+       if (bind_display(client, display) < 0)
+               goto err_map;
+
+       wl_list_insert(display->client_list.prev, &client->link);
+
+       return client;
+
+err_map:
+       wl_map_release(&client->objects);
+       wl_connection_destroy(client->connection);
+err_source:
+       wl_event_source_remove(client->source);
+err_client:
+       free(client);
+       return NULL;
+}
+
+/** Return Unix credentials for the client
+ *
+ * \param client The display object
+ * \param pid Returns the process ID
+ * \param uid Returns the user ID
+ * \param gid Returns the group ID
+ *
+ * This function returns the process ID, the user ID and the group ID
+ * for the given client.  The credentials come from getsockopt() with
+ * SO_PEERCRED, on the client socket fd.  All the pointers can be
+ * NULL, if the caller is not interested in a particular ID.
+ *
+ * Be aware that for clients that a compositor forks and execs and
+ * then connects using socketpair(), this function will return the
+ * credentials for the compositor.  The credentials for the socketpair
+ * are set at creation time in the compositor.
+ *
+ * \memberof wl_client
+ */
+WL_EXPORT void
+wl_client_get_credentials(struct wl_client *client,
+                         pid_t *pid, uid_t *uid, gid_t *gid)
+{
+       if (pid)
+               *pid = client->ucred.pid;
+       if (uid)
+               *uid = client->ucred.uid;
+       if (gid)
+               *gid = client->ucred.gid;
+}
+
+/** Look up an object in the client name space
+ *
+ * \param client The client object
+ * \param id The object id
+ * \return The object or NULL if there is not object for the given ID
+ *
+ * This looks up an object in the client object name space by its
+ * object ID.
+ *
+ * \memberof wl_client
+ */
+WL_EXPORT struct wl_resource *
+wl_client_get_object(struct wl_client *client, uint32_t id)
+{
+       return wl_map_lookup(&client->objects, id);
+}
+
+WL_EXPORT void
+wl_client_post_no_memory(struct wl_client *client)
+{
+       wl_resource_post_error(client->display_resource,
+                              WL_DISPLAY_ERROR_NO_MEMORY, "no memory");
+}
+
+WL_EXPORT void
+wl_resource_post_no_memory(struct wl_resource *resource)
+{
+       wl_resource_post_error(resource->client->display_resource,
+                              WL_DISPLAY_ERROR_NO_MEMORY, "no memory");
+}
+
+static void
+destroy_resource(void *element, void *data)
+{
+       struct wl_resource *resource = element;
+       struct wl_client *client = resource->client;
+       uint32_t flags;
+
+       wl_signal_emit(&resource->destroy_signal, resource);
+
+       flags = wl_map_lookup_flags(&client->objects, resource->object.id);
+       if (resource->destroy)
+               resource->destroy(resource);
+
+       if (!(flags & WL_MAP_ENTRY_LEGACY))
+               free(resource);
+}
+
+WL_EXPORT void
+wl_resource_destroy(struct wl_resource *resource)
+{
+       struct wl_client *client = resource->client;
+       uint32_t id;
+
+       id = resource->object.id;
+       destroy_resource(resource, NULL);
+
+       if (id < WL_SERVER_ID_START) {
+               if (client->display_resource) {
+                       wl_resource_queue_event(client->display_resource,
+                                               WL_DISPLAY_DELETE_ID, id);
+               }
+               wl_map_insert_at(&client->objects, 0, id, NULL);
+       } else {
+               wl_map_remove(&client->objects, id);
+       }
+}
+
+WL_EXPORT uint32_t
+wl_resource_get_id(struct wl_resource *resource)
+{
+       return resource->object.id;
+}
+
+WL_EXPORT struct wl_list *
+wl_resource_get_link(struct wl_resource *resource)
+{
+       return &resource->link;
+}
+
+WL_EXPORT struct wl_resource *
+wl_resource_from_link(struct wl_list *link)
+{
+       struct wl_resource *resource;
+
+       return wl_container_of(link, resource, link);
+}
+
+WL_EXPORT struct wl_resource *
+wl_resource_find_for_client(struct wl_list *list, struct wl_client *client)
+{
+       struct wl_resource *resource;
+
+       if (client == NULL)
+               return NULL;
+
+       wl_list_for_each(resource, list, link) {
+               if (resource->client == client)
+                       return resource;
+       }
+
+       return NULL;
+}
+
+WL_EXPORT struct wl_client *
+wl_resource_get_client(struct wl_resource *resource)
+{
+       return resource->client;
+}
+
+WL_EXPORT void
+wl_resource_set_user_data(struct wl_resource *resource, void *data)
+{
+       resource->data = data;
+}
+
+WL_EXPORT void *
+wl_resource_get_user_data(struct wl_resource *resource)
+{
+       return resource->data;
+}
+
+WL_EXPORT int
+wl_resource_get_version(struct wl_resource *resource)
+{
+       return resource->version;
+}
+
+WL_EXPORT void
+wl_resource_set_destructor(struct wl_resource *resource,
+                          wl_resource_destroy_func_t destroy)
+{
+       resource->destroy = destroy;
+}
+
+WL_EXPORT int
+wl_resource_instance_of(struct wl_resource *resource,
+                       const struct wl_interface *interface,
+                       const void *implementation)
+{
+       return wl_interface_equal(resource->object.interface, interface) &&
+               resource->object.implementation == implementation;
+}
+
+WL_EXPORT void
+wl_resource_add_destroy_listener(struct wl_resource *resource,
+                                struct wl_listener * listener)
+{
+       wl_signal_add(&resource->destroy_signal, listener);
+}
+
+WL_EXPORT struct wl_listener *
+wl_resource_get_destroy_listener(struct wl_resource *resource,
+                                wl_notify_func_t notify)
+{
+       return wl_signal_get(&resource->destroy_signal, notify);
+}
+
+WL_EXPORT void
+wl_client_add_destroy_listener(struct wl_client *client,
+                              struct wl_listener *listener)
+{
+       wl_signal_add(&client->destroy_signal, listener);
+}
+
+WL_EXPORT struct wl_listener *
+wl_client_get_destroy_listener(struct wl_client *client,
+                              wl_notify_func_t notify)
+{
+       return wl_signal_get(&client->destroy_signal, notify);
+}
+
+WL_EXPORT void
+wl_client_destroy(struct wl_client *client)
+{
+       uint32_t serial = 0;
+
+       wl_signal_emit(&client->destroy_signal, client);
+
+       wl_client_flush(client);
+       wl_map_for_each(&client->objects, destroy_resource, &serial);
+       wl_map_release(&client->objects);
+       wl_event_source_remove(client->source);
+       close(wl_connection_destroy(client->connection));
+       wl_list_remove(&client->link);
+       free(client);
+}
+
+static void
+registry_bind(struct wl_client *client,
+             struct wl_resource *resource, uint32_t name,
+             const char *interface, uint32_t version, uint32_t id)
+{
+       struct wl_global *global;
+       struct wl_display *display = resource->data;
+
+       wl_list_for_each(global, &display->global_list, link)
+               if (global->name == name)
+                       break;
+
+       if (&global->link == &display->global_list)
+               wl_resource_post_error(resource,
+                                      WL_DISPLAY_ERROR_INVALID_OBJECT,
+                                      "invalid global %s (%d)", interface, name);
+       else if (global->version < version)
+               wl_resource_post_error(resource,
+                                      WL_DISPLAY_ERROR_INVALID_OBJECT,
+                                      "invalid version for global %s (%d): have %d, wanted %d",
+                                      interface, name, global->version, version);
+       else
+               global->bind(client, global->data, version, id);
+}
+
+static const struct wl_registry_interface registry_interface = {
+       registry_bind
+};
+
+static void
+display_sync(struct wl_client *client,
+            struct wl_resource *resource, uint32_t id)
+{
+       struct wl_resource *callback;
+       uint32_t serial;
+
+       callback = wl_resource_create(client, &wl_callback_interface, 1, id);
+       if (callback == NULL) {
+               wl_client_post_no_memory(client);
+               return;
+       }
+
+       serial = wl_display_get_serial(client->display);
+       wl_callback_send_done(callback, serial);
+       wl_resource_destroy(callback);
+}
+
+static void
+unbind_resource(struct wl_resource *resource)
+{
+       wl_list_remove(&resource->link);
+}
+
+static void
+display_get_registry(struct wl_client *client,
+                    struct wl_resource *resource, uint32_t id)
+{
+       struct wl_display *display = resource->data;
+       struct wl_resource *registry_resource;
+       struct wl_global *global;
+
+       registry_resource =
+               wl_resource_create(client, &wl_registry_interface, 1, id);
+       if (registry_resource == NULL) {
+               wl_client_post_no_memory(client);
+               return;
+       }
+
+       wl_resource_set_implementation(registry_resource,
+                                      &registry_interface,
+                                      display, unbind_resource);
+
+       wl_list_insert(&display->registry_resource_list,
+                      &registry_resource->link);
+
+       wl_list_for_each(global, &display->global_list, link)
+               wl_resource_post_event(registry_resource,
+                                      WL_REGISTRY_GLOBAL,
+                                      global->name,
+                                      global->interface->name,
+                                      global->version);
+}
+
+static const struct wl_display_interface display_interface = {
+       display_sync,
+       display_get_registry
+};
+
+static void
+destroy_client_display_resource(struct wl_resource *resource)
+{
+       resource->client->display_resource = NULL;
+}
+
+static int
+bind_display(struct wl_client *client, struct wl_display *display)
+{
+       client->display_resource =
+               wl_resource_create(client, &wl_display_interface, 1, 1);
+       if (client->display_resource == NULL) {
+               wl_client_post_no_memory(client);
+               return -1;
+       }
+
+       wl_resource_set_implementation(client->display_resource,
+                                      &display_interface, display,
+                                      destroy_client_display_resource);
+       return 0;
+}
+
+/** Create Wayland display object.
+ *
+ * \return The Wayland display object. Null if failed to create
+ *
+ * This creates the wl_display object.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT struct wl_display *
+wl_display_create(void)
+{
+       struct wl_display *display;
+       const char *debug;
+
+       debug = getenv("WAYLAND_DEBUG");
+       if (debug && (strstr(debug, "server") || strstr(debug, "1")))
+               debug_server = 1;
+
+       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->global_list);
+       wl_list_init(&display->socket_list);
+       wl_list_init(&display->client_list);
+       wl_list_init(&display->registry_resource_list);
+
+       wl_signal_init(&display->destroy_signal);
+
+       display->id = 1;
+       display->serial = 0;
+
+       wl_array_init(&display->additional_shm_formats);
+
+       return display;
+}
+
+static void
+wl_socket_destroy(struct wl_socket *s)
+{
+       if (s->source)
+               wl_event_source_remove(s->source);
+       if (s->addr.sun_path[0])
+               unlink(s->addr.sun_path);
+       if (s->fd >= 0)
+               close(s->fd);
+       if (s->lock_addr[0])
+               unlink(s->lock_addr);
+       if (s->fd_lock >= 0)
+               close(s->fd_lock);
+
+       free(s);
+}
+
+static struct wl_socket *
+wl_socket_alloc(void)
+{
+       struct wl_socket *s;
+
+       s = malloc(sizeof *s);
+       if (!s)
+               return NULL;
+
+       memset(s, 0, sizeof *s);
+       s->fd = -1;
+       s->fd_lock = -1;
+
+       return s;
+}
+
+/** Destroy Wayland display object.
+ *
+ * \param display The Wayland display object which should be destroyed.
+ * \return None.
+ *
+ * This function emits the wl_display destroy signal, releases
+ * all the sockets added to this display, free's all the globals associated
+ * with this display, free's memory of additional shared memory formats and
+ * destroy the display object.
+ *
+ * \sa wl_display_add_destroy_listener
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT void
+wl_display_destroy(struct wl_display *display)
+{
+       struct wl_socket *s, *next;
+       struct wl_global *global, *gnext;
+
+       wl_signal_emit(&display->destroy_signal, display);
+
+       wl_list_for_each_safe(s, next, &display->socket_list, link) {
+               wl_socket_destroy(s);
+       }
+       wl_event_loop_destroy(display->loop);
+
+       wl_list_for_each_safe(global, gnext, &display->global_list, link)
+               free(global);
+
+       wl_array_release(&display->additional_shm_formats);
+
+       free(display);
+}
+
+WL_EXPORT struct wl_global *
+wl_global_create(struct wl_display *display,
+                const struct wl_interface *interface, int version,
+                void *data, wl_global_bind_func_t bind)
+{
+       struct wl_global *global;
+       struct wl_resource *resource;
+
+       if (interface->version < version) {
+               wl_log("wl_global_create: implemented version higher "
+                      "than interface version%m\n");
+               return NULL;
+       }
+
+       global = malloc(sizeof *global);
+       if (global == NULL)
+               return NULL;
+
+       global->display = display;
+       global->name = display->id++;
+       global->interface = interface;
+       global->version = version;
+       global->data = data;
+       global->bind = bind;
+       wl_list_insert(display->global_list.prev, &global->link);
+
+       wl_list_for_each(resource, &display->registry_resource_list, link)
+               wl_resource_post_event(resource,
+                                      WL_REGISTRY_GLOBAL,
+                                      global->name,
+                                      global->interface->name,
+                                      global->version);
+
+       return global;
+}
+
+WL_EXPORT void
+wl_global_destroy(struct wl_global *global)
+{
+       struct wl_display *display = global->display;
+       struct wl_resource *resource;
+
+       wl_list_for_each(resource, &display->registry_resource_list, link)
+               wl_resource_post_event(resource, WL_REGISTRY_GLOBAL_REMOVE,
+                                      global->name);
+       wl_list_remove(&global->link);
+       free(global);
+}
+
+/** Get the current serial number
+ *
+ * \param display The display object
+ *
+ * This function returns the most recent serial number, but does not
+ * increment it.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT uint32_t
+wl_display_get_serial(struct wl_display *display)
+{
+       return display->serial;
+}
+
+/** Get the next serial number
+ *
+ * \param display The display object
+ *
+ * This function increments the display serial number and returns the
+ * new value.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT uint32_t
+wl_display_next_serial(struct wl_display *display)
+{
+       display->serial++;
+
+       return display->serial;
+}
+
+WL_EXPORT struct wl_event_loop *
+wl_display_get_event_loop(struct wl_display *display)
+{
+       return display->loop;
+}
+
+WL_EXPORT void
+wl_display_terminate(struct wl_display *display)
+{
+       display->run = 0;
+}
+
+WL_EXPORT void
+wl_display_run(struct wl_display *display)
+{
+       display->run = 1;
+
+       while (display->run) {
+               wl_display_flush_clients(display);
+               wl_event_loop_dispatch(display->loop, -1);
+       }
+}
+
+WL_EXPORT void
+wl_display_flush_clients(struct wl_display *display)
+{
+       struct wl_client *client, *next;
+       int ret;
+
+       wl_list_for_each_safe(client, next, &display->client_list, link) {
+               ret = wl_connection_flush(client->connection);
+               if (ret < 0 && errno == EAGAIN) {
+                       wl_event_source_fd_update(client->source,
+                                                 WL_EVENT_WRITABLE |
+                                                 WL_EVENT_READABLE);
+               } else if (ret < 0) {
+                       wl_client_destroy(client);
+               }
+       }
+}
+
+static int
+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 = wl_os_accept_cloexec(fd, (struct sockaddr *) &name,
+                                        &length);
+       if (client_fd < 0)
+               wl_log("failed to accept: %m\n");
+       else
+               if (!wl_client_create(display, client_fd))
+                       close(client_fd);
+
+       return 1;
+}
+
+static int
+wl_socket_lock(struct wl_socket *socket)
+{
+       struct stat socket_stat;
+
+       snprintf(socket->lock_addr, sizeof socket->lock_addr,
+                "%s%s", socket->addr.sun_path, LOCK_SUFFIX);
+
+       socket->fd_lock = open(socket->lock_addr, O_CREAT | O_CLOEXEC,
+                              (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP));
+
+       if (socket->fd_lock < 0) {
+               wl_log("unable to open lockfile %s check permissions\n",
+                       socket->lock_addr);
+               goto err;
+       }
+
+       if (flock(socket->fd_lock, LOCK_EX | LOCK_NB) < 0) {
+               wl_log("unable to lock lockfile %s, maybe another compositor is running\n",
+                       socket->lock_addr);
+               goto err_fd;
+       }
+
+       if (stat(socket->addr.sun_path, &socket_stat) < 0 ) {
+               if (errno != ENOENT) {
+                       wl_log("did not manage to stat file %s\n",
+                               socket->addr.sun_path);
+                       goto err_fd;
+               }
+       } else if (socket_stat.st_mode & S_IWUSR ||
+                  socket_stat.st_mode & S_IWGRP) {
+               unlink(socket->addr.sun_path);
+       }
+
+       return 0;
+err_fd:
+       close(socket->fd_lock);
+       socket->fd_lock = -1;
+err:
+       *socket->lock_addr = 0;
+       /* we did not set this value here, but without lock the
+        * socket won't be created anyway. This prevents the
+        * wl_socket_destroy from unlinking already existing socket
+        * created by other compositor */
+       *socket->addr.sun_path = 0;
+
+       return -1;
+}
+
+static int
+wl_socket_init_for_display_name(struct wl_socket *s, const char *name)
+{
+       int name_size;
+       const char *runtime_dir;
+
+#ifdef HAVE_MULTISEAT
+       runtime_dir = getenv("WAYLAND_SERVER_DIR");
+       if (runtime_dir == NULL)
+#endif
+       runtime_dir = getenv("XDG_RUNTIME_DIR");
+
+       if (!runtime_dir) {
+               wl_log("error: XDG_RUNTIME_DIR not set in the environment\n");
+
+               /* to prevent programs reporting
+                * "failed to add socket: Success" */
+               errno = ENOENT;
+               return -1;
+       }
+
+       s->addr.sun_family = AF_LOCAL;
+       name_size = snprintf(s->addr.sun_path, sizeof s->addr.sun_path,
+                            "%s/%s", runtime_dir, name) + 1;
+
+       s->display_name = (s->addr.sun_path + name_size - 1) - strlen(name);
+
+#ifdef HAVE_MULTISEAT
+       if (getenv("WAYLAND_SERVER_DIR")) {
+               unsetenv("WAYLAND_SERVER_DIR");
+               setenv("WAYLAND_CLIENT_DIR", runtime_dir, 1);
+       }
+#endif
+
+       assert(name_size > 0);
+       if (name_size > (int)sizeof s->addr.sun_path) {
+               wl_log("error: socket path \"%s/%s\" plus null terminator"
+                      " exceeds 108 bytes\n", runtime_dir, name);
+               *s->addr.sun_path = 0;
+               /* to prevent programs reporting
+                * "failed to add socket: Success" */
+               errno = ENAMETOOLONG;
+               return -1;
+       }
+
+       return 0;
+}
+
+static int
+_wl_display_add_socket(struct wl_display *display, struct wl_socket *s)
+{
+       socklen_t size;
+#ifdef HAVE_MULTISEAT
+       const char *socket_mode_str;
+       const char *socket_group_str;
+       const struct group *socket_group;
+       unsigned socket_mode;
+#endif
+
+       s->fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0);
+       if (s->fd < 0) {
+               return -1;
+       }
+
+       size = offsetof (struct sockaddr_un, sun_path) + strlen(s->addr.sun_path);
+       if (bind(s->fd, (struct sockaddr *) &s->addr, size) < 0) {
+               wl_log("bind() failed with error: %m\n");
+               return -1;
+       }
+
+       if (listen(s->fd, 128) < 0) {
+               wl_log("listen() failed with error: %m\n");
+               return -1;
+       }
+
+#ifdef HAVE_MULTISEAT
+       socket_group_str = getenv("WAYLAND_SERVER_GROUP");
+       if (socket_group_str != NULL) {
+               socket_group = getgrnam(socket_group_str);
+               if (socket_group != NULL) {
+                       if (chown(s->addr.sun_path,
+                               -1, socket_group->gr_gid) != 0)
+                               wl_log("chown(\"%s\") failed: %s",
+                                               s->addr.sun_path,
+                                               strerror(errno));
+               }
+       }
+
+       socket_mode_str = getenv("WAYLAND_SERVER_MODE");
+       if (socket_mode_str != NULL) {
+               if (sscanf(socket_mode_str, "%o", &socket_mode) > 0)
+                       if (chmod(s->addr.sun_path, socket_mode) != 0) {
+                               wl_log("chmod(\"%s\") failed: %s",
+                                               s->addr.sun_path,
+                                               strerror(errno));
+                       }
+       }
+#endif
+
+       s->source = wl_event_loop_add_fd(display->loop, s->fd,
+                                        WL_EVENT_READABLE,
+                                        socket_data, display);
+       if (s->source == NULL) {
+               return -1;
+       }
+
+       wl_list_insert(display->socket_list.prev, &s->link);
+       return 0;
+}
+
+WL_EXPORT const char *
+wl_display_add_socket_auto(struct wl_display *display)
+{
+       struct wl_socket *s;
+       int displayno = 0;
+       char display_name[16] = "";
+
+       /* A reasonable number of maximum default sockets. If
+        * you need more than this, use the explicit add_socket API. */
+       const int MAX_DISPLAYNO = 32;
+
+       s = wl_socket_alloc();
+       if (s == NULL)
+               return NULL;
+
+       do {
+               snprintf(display_name, sizeof display_name, "wayland-%d", displayno);
+               if (wl_socket_init_for_display_name(s, display_name) < 0) {
+                       wl_socket_destroy(s);
+                       return NULL;
+               }
+
+               if (wl_socket_lock(s) < 0)
+                       continue;
+
+               if (_wl_display_add_socket(display, s) < 0) {
+                       wl_socket_destroy(s);
+                       return NULL;
+               }
+
+               return s->display_name;
+       } while (displayno++ < MAX_DISPLAYNO);
+
+       /* Ran out of display names. */
+       wl_socket_destroy(s);
+       errno = EINVAL;
+       return NULL;
+}
+
+/** Add a socket to Wayland display for the clients to connect.
+ *
+ * \param display Wayland display to which the socket should be added.
+ * \param name Name of the Unix socket.
+ * \return 0 if success. -1 if failed.
+ *
+ * This adds a Unix socket to Wayland display which can be used by clients to
+ * connect to Wayland display.
+ *
+ * If NULL is passed as name, then it would look for WAYLAND_DISPLAY env
+ * variable for the socket name. If WAYLAND_DISPLAY is not set, then default
+ * wayland-0 is used.
+ *
+ * The Unix socket will be created in the directory pointed to by environment
+ * variable XDG_RUNTIME_DIR. If XDG_RUNTIME_DIR is not set, then this function
+ * fails and returns -1.
+ *
+ * The length of socket path, i.e., the path set in XDG_RUNTIME_DIR and the
+ * socket name, must not exceed the maxium length of a Unix socket path.
+ * The function also fails if the user do not have write permission in the
+ * XDG_RUNTIME_DIR path or if the socket name is already in use.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT int
+wl_display_add_socket(struct wl_display *display, const char *name)
+{
+       struct wl_socket *s;
+
+       s = wl_socket_alloc();
+       if (s == NULL)
+               return -1;
+
+       if (name == NULL)
+               name = getenv("WAYLAND_DISPLAY");
+       if (name == NULL)
+               name = "wayland-0";
+
+       if (wl_socket_init_for_display_name(s, name) < 0) {
+               wl_socket_destroy(s);
+               return -1;
+       }
+
+       if (wl_socket_lock(s) < 0) {
+               wl_socket_destroy(s);
+               return -1;
+       }
+
+       if (_wl_display_add_socket(display, s) < 0) {
+               wl_socket_destroy(s);
+               return -1;
+       }
+
+       return 0;
+}
+
+WL_EXPORT void
+wl_display_add_destroy_listener(struct wl_display *display,
+                               struct wl_listener *listener)
+{
+       wl_signal_add(&display->destroy_signal, listener);
+}
+
+WL_EXPORT struct wl_listener *
+wl_display_get_destroy_listener(struct wl_display *display,
+                               wl_notify_func_t notify)
+{
+       return wl_signal_get(&display->destroy_signal, notify);
+}
+
+WL_EXPORT void
+wl_resource_set_implementation(struct wl_resource *resource,
+                              const void *implementation,
+                              void *data, wl_resource_destroy_func_t destroy)
+{
+       resource->object.implementation = implementation;
+       resource->data = data;
+       resource->destroy = destroy;
+       resource->dispatcher = NULL;
+}
+
+WL_EXPORT void
+wl_resource_set_dispatcher(struct wl_resource *resource,
+                          wl_dispatcher_func_t dispatcher,
+                          const void *implementation,
+                          void *data, wl_resource_destroy_func_t destroy)
+{
+       resource->dispatcher = dispatcher;
+       resource->object.implementation = implementation;
+       resource->data = data;
+       resource->destroy = destroy;
+}
+
+WL_EXPORT struct wl_resource *
+wl_resource_create(struct wl_client *client,
+                  const struct wl_interface *interface,
+                  int version, uint32_t id)
+{
+       struct wl_resource *resource;
+
+       resource = malloc(sizeof *resource);
+       if (resource == NULL)
+               return NULL;
+
+       if (id == 0)
+               id = wl_map_insert_new(&client->objects, 0, NULL);
+
+       resource->object.id = id;
+       resource->object.interface = interface;
+       resource->object.implementation = NULL;
+
+       wl_signal_init(&resource->destroy_signal);
+
+       resource->destroy = NULL;
+       resource->client = client;
+       resource->data = NULL;
+       resource->version = version;
+       resource->dispatcher = NULL;
+
+       if (wl_map_insert_at(&client->objects, 0, id, resource) < 0) {
+               wl_resource_post_error(client->display_resource,
+                                      WL_DISPLAY_ERROR_INVALID_OBJECT,
+                                      "invalid new id %d", id);
+               free(resource);
+               return NULL;
+       }
+
+       return resource;
+}
+
+WL_EXPORT void
+wl_log_set_handler_server(wl_log_func_t handler)
+{
+       wl_log_handler = handler;
+}
+
+/** Add support for a wl_shm pixel format
+ *
+ * \param display The display object
+ * \param format The wl_shm pixel format to advertise
+ * \return A pointer to the wl_shm format that was added to the list
+ * or NULL if adding it to the list failed.
+ *
+ * Add the specified wl_shm format to the list of formats the wl_shm
+ * object advertises when a client binds to it.  Adding a format to
+ * the list means that clients will know that the compositor supports
+ * this format and may use it for creating wl_shm buffers.  The
+ * compositor must be able to handle the pixel format when a client
+ * requests it.
+ *
+ * The compositor by default supports WL_SHM_FORMAT_ARGB8888 and
+ * WL_SHM_FORMAT_XRGB8888.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT uint32_t *
+wl_display_add_shm_format(struct wl_display *display, uint32_t format)
+{
+       uint32_t *p = NULL;
+
+       p = wl_array_add(&display->additional_shm_formats, sizeof *p);
+
+       if (p != NULL)
+               *p = format;
+       return p;
+}
+
+/**
+ * Get list of additional wl_shm pixel formats
+ *
+ * \param display The display object
+ *
+ * This function returns the list of addition wl_shm pixel formats
+ * that the compositor supports.  WL_SHM_FORMAT_ARGB8888 and
+ * WL_SHM_FORMAT_XRGB8888 are always supported and not included in the
+ * array, but all formats added through wl_display_add_shm_format()
+ * will be in the array.
+ *
+ * \sa wl_display_add_shm_format()
+ *
+ * \memberof wl_display
+ */
+struct wl_array *
+wl_display_get_additional_shm_formats(struct wl_display *display)
+{
+       return &display->additional_shm_formats;
+}
+
+/** \cond */ /* Deprecated functions below. */
+
+uint32_t
+wl_client_add_resource(struct wl_client *client,
+                      struct wl_resource *resource) WL_DEPRECATED;
+
+WL_EXPORT uint32_t
+wl_client_add_resource(struct wl_client *client,
+                      struct wl_resource *resource)
+{
+       if (resource->object.id == 0) {
+               resource->object.id =
+                       wl_map_insert_new(&client->objects,
+                                         WL_MAP_ENTRY_LEGACY, resource);
+       } else if (wl_map_insert_at(&client->objects, WL_MAP_ENTRY_LEGACY,
+                                 resource->object.id, resource) < 0) {
+               wl_resource_post_error(client->display_resource,
+                                      WL_DISPLAY_ERROR_INVALID_OBJECT,
+                                      "invalid new id %d",
+                                      resource->object.id);
+               return 0;
+       }
+
+       resource->client = client;
+       wl_signal_init(&resource->destroy_signal);
+
+       return resource->object.id;
+}
+
+struct wl_resource *
+wl_client_add_object(struct wl_client *client,
+                    const struct wl_interface *interface,
+                    const void *implementation,
+                    uint32_t id, void *data) WL_DEPRECATED;
+
+WL_EXPORT struct wl_resource *
+wl_client_add_object(struct wl_client *client,
+                    const struct wl_interface *interface,
+                    const void *implementation, uint32_t id, void *data)
+{
+       struct wl_resource *resource;
+
+       resource = wl_resource_create(client, interface, -1, id);
+       if (resource == NULL)
+               wl_client_post_no_memory(client);
+       else
+               wl_resource_set_implementation(resource,
+                                              implementation, data, NULL);
+
+       return resource;
+}
+
+struct wl_resource *
+wl_client_new_object(struct wl_client *client,
+                    const struct wl_interface *interface,
+                    const void *implementation, void *data) WL_DEPRECATED;
+
+WL_EXPORT struct wl_resource *
+wl_client_new_object(struct wl_client *client,
+                    const struct wl_interface *interface,
+                    const void *implementation, void *data)
+{
+       struct wl_resource *resource;
+
+       resource = wl_resource_create(client, interface, -1, 0);
+       if (resource == NULL)
+               wl_client_post_no_memory(client);
+       else
+               wl_resource_set_implementation(resource,
+                                              implementation, data, NULL);
+
+       return resource;
+}
+
+struct wl_global *
+wl_display_add_global(struct wl_display *display,
+                     const struct wl_interface *interface,
+                     void *data, wl_global_bind_func_t bind) WL_DEPRECATED;
+
+WL_EXPORT struct wl_global *
+wl_display_add_global(struct wl_display *display,
+                     const struct wl_interface *interface,
+                     void *data, wl_global_bind_func_t bind)
+{
+       return wl_global_create(display, interface, interface->version, data, bind);
+}
+
+void
+wl_display_remove_global(struct wl_display *display,
+                        struct wl_global *global) WL_DEPRECATED;
+
+WL_EXPORT void
+wl_display_remove_global(struct wl_display *display, struct wl_global *global)
+{
+       wl_global_destroy(global);
+}
+
+/** \endcond */
+
+/* Functions at the end of this file are deprecated.  Instead of adding new
+ * code here, add it before the comment above that states:
+ * Deprecated functions below.
+ */
diff --git a/src/wayland-server.h b/src/wayland-server.h
new file mode 100644 (file)
index 0000000..af2f03d
--- /dev/null
@@ -0,0 +1,457 @@
+/*
+ * 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_SERVER_H
+#define WAYLAND_SERVER_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <stdint.h>
+#include "wayland-util.h"
+#include "wayland-version.h"
+
+enum {
+       WL_EVENT_READABLE = 0x01,
+       WL_EVENT_WRITABLE = 0x02,
+       WL_EVENT_HANGUP   = 0x04,
+       WL_EVENT_ERROR    = 0x08
+};
+
+struct wl_event_loop;
+struct wl_event_source;
+typedef int (*wl_event_loop_fd_func_t)(int fd, uint32_t mask, void *data);
+typedef int (*wl_event_loop_timer_func_t)(void *data);
+typedef int (*wl_event_loop_signal_func_t)(int signal_number, void *data);
+typedef void (*wl_event_loop_idle_func_t)(void *data);
+
+struct wl_event_loop *wl_event_loop_create(void);
+void wl_event_loop_destroy(struct wl_event_loop *loop);
+struct wl_event_source *wl_event_loop_add_fd(struct wl_event_loop *loop,
+                                            int fd, uint32_t mask,
+                                            wl_event_loop_fd_func_t func,
+                                            void *data);
+int wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask);
+struct wl_event_source *wl_event_loop_add_timer(struct wl_event_loop *loop,
+                                               wl_event_loop_timer_func_t func,
+                                               void *data);
+struct wl_event_source *
+wl_event_loop_add_signal(struct wl_event_loop *loop,
+                       int signal_number,
+                       wl_event_loop_signal_func_t func,
+                       void *data);
+
+int wl_event_source_timer_update(struct wl_event_source *source,
+                                int ms_delay);
+int wl_event_source_remove(struct wl_event_source *source);
+void wl_event_source_check(struct wl_event_source *source);
+
+
+int wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout);
+void wl_event_loop_dispatch_idle(struct wl_event_loop *loop);
+struct wl_event_source *wl_event_loop_add_idle(struct wl_event_loop *loop,
+                                              wl_event_loop_idle_func_t func,
+                                              void *data);
+int wl_event_loop_get_fd(struct wl_event_loop *loop);
+
+struct wl_client;
+struct wl_display;
+struct wl_listener;
+struct wl_resource;
+struct wl_global;
+typedef void (*wl_notify_func_t)(struct wl_listener *listener, void *data);
+
+void wl_event_loop_add_destroy_listener(struct wl_event_loop *loop,
+                                       struct wl_listener * listener);
+struct wl_listener *wl_event_loop_get_destroy_listener(
+                                       struct wl_event_loop *loop,
+                                       wl_notify_func_t notify);
+
+struct wl_display *wl_display_create(void);
+void wl_display_destroy(struct wl_display *display);
+struct wl_event_loop *wl_display_get_event_loop(struct wl_display *display);
+int wl_display_add_socket(struct wl_display *display, const char *name);
+const char *wl_display_add_socket_auto(struct wl_display *display);
+void wl_display_terminate(struct wl_display *display);
+void wl_display_run(struct wl_display *display);
+void wl_display_flush_clients(struct wl_display *display);
+
+typedef void (*wl_global_bind_func_t)(struct wl_client *client, void *data,
+                                     uint32_t version, uint32_t id);
+
+uint32_t wl_display_get_serial(struct wl_display *display);
+uint32_t wl_display_next_serial(struct wl_display *display);
+
+void wl_display_add_destroy_listener(struct wl_display *display,
+                                    struct wl_listener *listener);
+struct wl_listener *wl_display_get_destroy_listener(struct wl_display *display,
+                                                   wl_notify_func_t notify);
+
+struct wl_global *wl_global_create(struct wl_display *display,
+                                  const struct wl_interface *interface,
+                                  int version,
+                                  void *data, wl_global_bind_func_t bind);
+void wl_global_destroy(struct wl_global *global);
+
+struct wl_client *wl_client_create(struct wl_display *display, int fd);
+void wl_client_destroy(struct wl_client *client);
+void wl_client_flush(struct wl_client *client);
+void wl_client_get_credentials(struct wl_client *client,
+                              pid_t *pid, uid_t *uid, gid_t *gid);
+
+void wl_client_add_destroy_listener(struct wl_client *client,
+                                   struct wl_listener *listener);
+struct wl_listener *wl_client_get_destroy_listener(struct wl_client *client,
+                                                  wl_notify_func_t notify);
+
+struct wl_resource *
+wl_client_get_object(struct wl_client *client, uint32_t id);
+void
+wl_client_post_no_memory(struct wl_client *client);
+
+/** \class wl_listener
+ *
+ * \brief A single listener for Wayland signals
+ *
+ * wl_listener provides the means to listen for wl_signal notifications. Many
+ * Wayland objects use wl_listener for notification of significant events like
+ * object destruction.
+ *
+ * Clients should create wl_listener objects manually and can register them as
+ * listeners to signals using #wl_signal_add, assuming the signal is
+ * directly accessible. For opaque structs like wl_event_loop, adding a
+ * listener should be done through provided accessor methods. A listener can
+ * only listen to one signal at a time.
+ *
+ * \code
+ * struct wl_listener your_listener;
+ *
+ * your_listener.notify = your_callback_method;
+ *
+ * // Direct access
+ * wl_signal_add(&some_object->destroy_signal, &your_listener);
+ *
+ * // Accessor access
+ * wl_event_loop *loop = ...;
+ * wl_event_loop_add_destroy_listener(loop, &your_listener);
+ * \endcode
+ *
+ * If the listener is part of a larger struct, #wl_container_of can be used
+ * to retrieve a pointer to it:
+ *
+ * \code
+ * void your_listener(struct wl_listener *listener, void *data)
+ * {
+ *     struct your_data *data;
+ *
+ *     your_data = wl_container_of(listener, data, your_member_name);
+ * }
+ * \endcode
+ *
+ * If you need to remove a listener from a signal, use wl_list_remove().
+ *
+ * \code
+ * wl_list_remove(&your_listener.link);
+ * \endcode
+ *
+ * \sa wl_signal
+ */
+struct wl_listener {
+       struct wl_list link;
+       wl_notify_func_t notify;
+};
+
+/** \class wl_signal
+ *
+ * \brief A source of a type of observable event
+ *
+ * Signals are recognized points where significant events can be observed.
+ * Compositors as well as the server can provide signals. Observers are
+ * wl_listener's that are added through #wl_signal_add. Signals are emitted
+ * using #wl_signal_emit, which will invoke all listeners until that
+ * listener is removed by wl_list_remove() (or whenever the signal is
+ * destroyed).
+ *
+ * \sa wl_listener for more information on using wl_signal
+ */
+struct wl_signal {
+       struct wl_list listener_list;
+};
+
+/** Initialize a new \ref wl_signal for use.
+ *
+ * \param signal The signal that will be initialized
+ *
+ * \memberof wl_signal
+ */
+static inline void
+wl_signal_init(struct wl_signal *signal)
+{
+       wl_list_init(&signal->listener_list);
+}
+
+/** Add the specified listener to this signal.
+ *
+ * \param signal The signal that will emit events to the listener
+ * \param listener The listener to add
+ *
+ * \memberof wl_signal
+ */
+static inline void
+wl_signal_add(struct wl_signal *signal, struct wl_listener *listener)
+{
+       wl_list_insert(signal->listener_list.prev, &listener->link);
+}
+
+/** Gets the listener struct for the specified callback.
+ *
+ * \param signal The signal that contains the specified listener
+ * \param notify The listener that is the target of this search
+ * \return the list item that corresponds to the specified listener, or NULL
+ * if none was found
+ *
+ * \memberof wl_signal
+ */
+static inline struct wl_listener *
+wl_signal_get(struct wl_signal *signal, wl_notify_func_t notify)
+{
+       struct wl_listener *l;
+
+       wl_list_for_each(l, &signal->listener_list, link)
+               if (l->notify == notify)
+                       return l;
+
+       return NULL;
+}
+
+/** Emits this signal, notifying all registered listeners.
+ *
+ * \param signal The signal object that will emit the signal
+ * \param data The data that will be emitted with the signal
+ *
+ * \memberof wl_signal
+ */
+static inline void
+wl_signal_emit(struct wl_signal *signal, void *data)
+{
+       struct wl_listener *l, *next;
+
+       wl_list_for_each_safe(l, next, &signal->listener_list, link)
+               l->notify(l, data);
+}
+
+typedef void (*wl_resource_destroy_func_t)(struct wl_resource *resource);
+
+#ifndef WL_HIDE_DEPRECATED
+
+struct wl_object {
+       const struct wl_interface *interface;
+       const void *implementation;
+       uint32_t id;
+};
+
+struct wl_resource {
+       struct wl_object object;
+       wl_resource_destroy_func_t destroy;
+       struct wl_list link;
+       struct wl_signal destroy_signal;
+       struct wl_client *client;
+       void *data;
+};
+
+struct wl_buffer {
+       struct wl_resource resource;
+       int32_t width, height;
+       uint32_t busy_count;
+} WL_DEPRECATED;
+
+
+uint32_t
+wl_client_add_resource(struct wl_client *client,
+                      struct wl_resource *resource) WL_DEPRECATED;
+
+struct wl_resource *
+wl_client_add_object(struct wl_client *client,
+                    const struct wl_interface *interface,
+                    const void *implementation,
+                    uint32_t id, void *data) WL_DEPRECATED;
+struct wl_resource *
+wl_client_new_object(struct wl_client *client,
+                    const struct wl_interface *interface,
+                    const void *implementation, void *data) WL_DEPRECATED;
+
+struct wl_global *
+wl_display_add_global(struct wl_display *display,
+                     const struct wl_interface *interface,
+                     void *data,
+                     wl_global_bind_func_t bind) WL_DEPRECATED;
+
+void
+wl_display_remove_global(struct wl_display *display,
+                        struct wl_global *global) WL_DEPRECATED;
+
+#endif
+
+/*
+ * Post an event to the client's object referred to by 'resource'.
+ * 'opcode' is the event number generated from the protocol XML
+ * description (the event name). The variable arguments are the event
+ * parameters, in the order they appear in the protocol XML specification.
+ *
+ * The variable arguments' types are:
+ * - type=uint:        uint32_t
+ * - type=int:         int32_t
+ * - type=fixed:       wl_fixed_t
+ * - type=string:      (const char *) to a nil-terminated string
+ * - type=array:       (struct wl_array *)
+ * - type=fd:          int, that is an open file descriptor
+ * - type=new_id:      (struct wl_object *) or (struct wl_resource *)
+ * - type=object:      (struct wl_object *) or (struct wl_resource *)
+ */
+void wl_resource_post_event(struct wl_resource *resource,
+                           uint32_t opcode, ...);
+void wl_resource_post_event_array(struct wl_resource *resource,
+                                 uint32_t opcode, union wl_argument *args);
+void wl_resource_queue_event(struct wl_resource *resource,
+                            uint32_t opcode, ...);
+void wl_resource_queue_event_array(struct wl_resource *resource,
+                                  uint32_t opcode, union wl_argument *args);
+
+/* msg is a printf format string, variable args are its args. */
+void wl_resource_post_error(struct wl_resource *resource,
+                           uint32_t code, const char *msg, ...)
+       __attribute__ ((format (printf, 3, 4)));
+void wl_resource_post_no_memory(struct wl_resource *resource);
+
+#include "wayland-server-protocol.h"
+
+struct wl_display *
+wl_client_get_display(struct wl_client *client);
+
+struct wl_resource *
+wl_resource_create(struct wl_client *client,
+                  const struct wl_interface *interface,
+                  int version, uint32_t id);
+void
+wl_resource_set_implementation(struct wl_resource *resource,
+                              const void *implementation,
+                              void *data,
+                              wl_resource_destroy_func_t destroy);
+void
+wl_resource_set_dispatcher(struct wl_resource *resource,
+                          wl_dispatcher_func_t dispatcher,
+                          const void *implementation,
+                          void *data,
+                          wl_resource_destroy_func_t destroy);
+
+void
+wl_resource_destroy(struct wl_resource *resource);
+uint32_t
+wl_resource_get_id(struct wl_resource *resource);
+struct wl_list *
+wl_resource_get_link(struct wl_resource *resource);
+struct wl_resource *
+wl_resource_from_link(struct wl_list *resource);
+struct wl_resource *
+wl_resource_find_for_client(struct wl_list *list, struct wl_client *client);
+struct wl_client *
+wl_resource_get_client(struct wl_resource *resource);
+void
+wl_resource_set_user_data(struct wl_resource *resource, void *data);
+void *
+wl_resource_get_user_data(struct wl_resource *resource);
+int
+wl_resource_get_version(struct wl_resource *resource);
+void
+wl_resource_set_destructor(struct wl_resource *resource,
+                          wl_resource_destroy_func_t destroy);
+int
+wl_resource_instance_of(struct wl_resource *resource,
+                       const struct wl_interface *interface,
+                       const void *implementation);
+
+void
+wl_resource_add_destroy_listener(struct wl_resource *resource,
+                                struct wl_listener * listener);
+struct wl_listener *
+wl_resource_get_destroy_listener(struct wl_resource *resource,
+                                wl_notify_func_t notify);
+
+#define wl_resource_for_each(resource, list)                                   \
+       for (resource = 0, resource = wl_resource_from_link((list)->next);      \
+            wl_resource_get_link(resource) != (list);                          \
+            resource = wl_resource_from_link(wl_resource_get_link(resource)->next))
+
+#define wl_resource_for_each_safe(resource, tmp, list)                                 \
+       for (resource = 0, tmp = 0,                                                     \
+            resource = wl_resource_from_link((list)->next),    \
+            tmp = wl_resource_from_link((list)->next->next);   \
+            wl_resource_get_link(resource) != (list);                          \
+            resource = tmp,                                                    \
+            tmp = wl_resource_from_link(wl_resource_get_link(resource)->next))
+
+struct wl_shm_buffer;
+
+void
+wl_shm_buffer_begin_access(struct wl_shm_buffer *buffer);
+
+void
+wl_shm_buffer_end_access(struct wl_shm_buffer *buffer);
+
+struct wl_shm_buffer *
+wl_shm_buffer_get(struct wl_resource *resource);
+
+void *
+wl_shm_buffer_get_data(struct wl_shm_buffer *buffer);
+
+int32_t
+wl_shm_buffer_get_stride(struct wl_shm_buffer *buffer);
+
+uint32_t
+wl_shm_buffer_get_format(struct wl_shm_buffer *buffer);
+
+int32_t
+wl_shm_buffer_get_width(struct wl_shm_buffer *buffer);
+
+int32_t
+wl_shm_buffer_get_height(struct wl_shm_buffer *buffer);
+
+int
+wl_display_init_shm(struct wl_display *display);
+
+uint32_t *
+wl_display_add_shm_format(struct wl_display *display, uint32_t format);
+
+struct wl_shm_buffer *
+wl_shm_buffer_create(struct wl_client *client,
+                    uint32_t id, int32_t width, int32_t height,
+                    int32_t stride, uint32_t format);
+
+void wl_log_set_handler_server(wl_log_func_t handler);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/wayland-server.pc.in b/src/wayland-server.pc.in
new file mode 100644 (file)
index 0000000..50dff53
--- /dev/null
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+datarootdir=@datarootdir@
+pkgdatadir=@datadir@/@PACKAGE@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Wayland Server
+Description: Server side implementation of the Wayland protocol
+Version: @WAYLAND_VERSION@
+Cflags: -I${includedir}
+Libs: -L${libdir} -lwayland-server
diff --git a/src/wayland-shm.c b/src/wayland-shm.c
new file mode 100644 (file)
index 0000000..b6b31d6
--- /dev/null
@@ -0,0 +1,572 @@
+/*
+ * 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.
+ *
+ * Authors:
+ *    Kristian Høgsberg <krh@bitplanet.net>
+ *    Benjamin Franzke <benjaminfranzke@googlemail.com>
+ *
+ */
+
+#define _GNU_SOURCE
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <assert.h>
+#include <signal.h>
+#include <pthread.h>
+
+#include "wayland-private.h"
+#include "wayland-server.h"
+
+/* This once_t is used to synchronize installing the SIGBUS handler
+ * and creating the TLS key. This will be done in the first call
+ * wl_shm_buffer_begin_access which can happen from any thread */
+static pthread_once_t wl_shm_sigbus_once = PTHREAD_ONCE_INIT;
+static pthread_key_t wl_shm_sigbus_data_key;
+static struct sigaction wl_shm_old_sigbus_action;
+
+struct wl_shm_pool {
+       struct wl_resource *resource;
+       int refcount;
+       char *data;
+       int32_t size;
+};
+
+struct wl_shm_buffer {
+       struct wl_resource *resource;
+       int32_t width, height;
+       int32_t stride;
+       uint32_t format;
+       int offset;
+       struct wl_shm_pool *pool;
+};
+
+struct wl_shm_sigbus_data {
+       struct wl_shm_pool *current_pool;
+       int access_count;
+       int fallback_mapping_used;
+};
+
+static void
+shm_pool_unref(struct wl_shm_pool *pool)
+{
+       pool->refcount--;
+       if (pool->refcount)
+               return;
+
+       munmap(pool->data, pool->size);
+       free(pool);
+}
+
+static void
+destroy_buffer(struct wl_resource *resource)
+{
+       struct wl_shm_buffer *buffer = wl_resource_get_user_data(resource);
+
+       if (buffer->pool)
+               shm_pool_unref(buffer->pool);
+       free(buffer);
+}
+
+static void
+shm_buffer_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static const struct wl_buffer_interface shm_buffer_interface = {
+       shm_buffer_destroy
+};
+
+static bool
+format_is_supported(struct wl_client *client, uint32_t format)
+{
+       struct wl_display *display = wl_client_get_display(client);
+       struct wl_array *formats;
+       uint32_t *p;
+
+       switch (format) {
+       case WL_SHM_FORMAT_ARGB8888:
+       case WL_SHM_FORMAT_XRGB8888:
+               return true;
+       default:
+               formats = wl_display_get_additional_shm_formats(display);
+               wl_array_for_each(p, formats)
+                       if(*p == format)
+                               return true;
+       }
+
+       return false;
+}
+
+static void
+shm_pool_create_buffer(struct wl_client *client, struct wl_resource *resource,
+                      uint32_t id, int32_t offset,
+                      int32_t width, int32_t height,
+                      int32_t stride, uint32_t format)
+{
+       struct wl_shm_pool *pool = wl_resource_get_user_data(resource);
+       struct wl_shm_buffer *buffer;
+
+       if (!format_is_supported(client, format)) {
+               wl_resource_post_error(resource,
+                                      WL_SHM_ERROR_INVALID_FORMAT,
+                                      "invalid format 0x%x", format);
+               return;
+       }
+
+       if (offset < 0 || width <= 0 || height <= 0 || stride < width ||
+           INT32_MAX / stride <= height ||
+           offset > pool->size - stride * height) {
+               wl_resource_post_error(resource,
+                                      WL_SHM_ERROR_INVALID_STRIDE,
+                                      "invalid width, height or stride (%dx%d, %u)",
+                                      width, height, stride);
+               return;
+       }
+
+       buffer = malloc(sizeof *buffer);
+       if (buffer == NULL) {
+               wl_client_post_no_memory(client);
+               return;
+       }
+
+       buffer->width = width;
+       buffer->height = height;
+       buffer->format = format;
+       buffer->stride = stride;
+       buffer->offset = offset;
+       buffer->pool = pool;
+       pool->refcount++;
+
+       buffer->resource =
+               wl_resource_create(client, &wl_buffer_interface, 1, id);
+       if (buffer->resource == NULL) {
+               wl_client_post_no_memory(client);
+               shm_pool_unref(pool);
+               free(buffer);
+               return;
+       }
+
+       wl_resource_set_implementation(buffer->resource,
+                                      &shm_buffer_interface,
+                                      buffer, destroy_buffer);
+}
+
+static void
+destroy_pool(struct wl_resource *resource)
+{
+       struct wl_shm_pool *pool = wl_resource_get_user_data(resource);
+
+       shm_pool_unref(pool);
+}
+
+static void
+shm_pool_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static void
+shm_pool_resize(struct wl_client *client, struct wl_resource *resource,
+               int32_t size)
+{
+       struct wl_shm_pool *pool = wl_resource_get_user_data(resource);
+       void *data;
+
+       if (size < pool->size) {
+               wl_resource_post_error(resource,
+                                      WL_SHM_ERROR_INVALID_FD,
+                                      "shrinking pool invalid");
+               return;
+       }
+
+       data = mremap(pool->data, pool->size, size, MREMAP_MAYMOVE);
+       if (data == MAP_FAILED) {
+               wl_resource_post_error(resource,
+                                      WL_SHM_ERROR_INVALID_FD,
+                                      "failed mremap");
+               return;
+       }
+
+       pool->data = data;
+       pool->size = size;
+}
+
+struct wl_shm_pool_interface shm_pool_interface = {
+       shm_pool_create_buffer,
+       shm_pool_destroy,
+       shm_pool_resize
+};
+
+static void
+shm_create_pool(struct wl_client *client, struct wl_resource *resource,
+               uint32_t id, int fd, int32_t size)
+{
+       struct wl_shm_pool *pool;
+
+       pool = malloc(sizeof *pool);
+       if (pool == NULL) {
+               wl_client_post_no_memory(client);
+               goto err_close;
+       }
+
+       if (size <= 0) {
+               wl_resource_post_error(resource,
+                                      WL_SHM_ERROR_INVALID_STRIDE,
+                                      "invalid size (%d)", size);
+               goto err_free;
+       }
+
+       pool->refcount = 1;
+       pool->size = size;
+       pool->data = mmap(NULL, size,
+                         PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+       if (pool->data == MAP_FAILED) {
+               wl_resource_post_error(resource,
+                                      WL_SHM_ERROR_INVALID_FD,
+                                      "failed mmap fd %d", fd);
+               goto err_close;
+       }
+       close(fd);
+
+       pool->resource =
+               wl_resource_create(client, &wl_shm_pool_interface, 1, id);
+       if (!pool->resource) {
+               wl_client_post_no_memory(client);
+               munmap(pool->data, pool->size);
+               free(pool);
+               return;
+       }
+
+       wl_resource_set_implementation(pool->resource,
+                                      &shm_pool_interface,
+                                      pool, destroy_pool);
+
+       return;
+
+err_close:
+       close(fd);
+err_free:
+       free(pool);
+}
+
+static const struct wl_shm_interface shm_interface = {
+       shm_create_pool
+};
+
+static void
+bind_shm(struct wl_client *client,
+        void *data, uint32_t version, uint32_t id)
+{
+       struct wl_resource *resource;
+       struct wl_display *display = wl_client_get_display(client);
+       struct wl_array *additional_formats;
+       uint32_t *p;
+
+       resource = wl_resource_create(client, &wl_shm_interface, 1, id);
+       if (!resource) {
+               wl_client_post_no_memory(client);
+               return;
+       }
+
+       wl_resource_set_implementation(resource, &shm_interface, data, NULL);
+
+       wl_shm_send_format(resource, WL_SHM_FORMAT_ARGB8888);
+       wl_shm_send_format(resource, WL_SHM_FORMAT_XRGB8888);
+
+       additional_formats = wl_display_get_additional_shm_formats(display);
+       wl_array_for_each(p, additional_formats)
+               wl_shm_send_format(resource, *p);
+}
+
+WL_EXPORT int
+wl_display_init_shm(struct wl_display *display)
+{
+       if (!wl_global_create(display, &wl_shm_interface, 1, NULL, bind_shm))
+               return -1;
+
+       return 0;
+}
+
+WL_EXPORT struct wl_shm_buffer *
+wl_shm_buffer_create(struct wl_client *client,
+                    uint32_t id, int32_t width, int32_t height,
+                    int32_t stride, uint32_t format)
+{
+       struct wl_shm_buffer *buffer;
+
+       if (!format_is_supported(client, format))
+               return NULL;
+
+       buffer = malloc(sizeof *buffer + stride * height);
+       if (buffer == NULL)
+               return NULL;
+
+       buffer->width = width;
+       buffer->height = height;
+       buffer->format = format;
+       buffer->stride = stride;
+       buffer->offset = 0;
+       buffer->pool = NULL;
+
+       buffer->resource =
+               wl_resource_create(client, &wl_buffer_interface, 1, id);
+       if (buffer->resource == NULL) {
+               free(buffer);
+               return NULL;
+       }
+
+       wl_resource_set_implementation(buffer->resource,
+                                      &shm_buffer_interface,
+                                      buffer, destroy_buffer);
+
+       return buffer;
+}
+
+WL_EXPORT struct wl_shm_buffer *
+wl_shm_buffer_get(struct wl_resource *resource)
+{
+       if (resource == NULL)
+               return NULL;
+
+       if (wl_resource_instance_of(resource, &wl_buffer_interface,
+                                   &shm_buffer_interface))
+               return wl_resource_get_user_data(resource);
+       else
+               return NULL;
+}
+
+WL_EXPORT int32_t
+wl_shm_buffer_get_stride(struct wl_shm_buffer *buffer)
+{
+       return buffer->stride;
+}
+
+
+/** Get a pointer to the memory for the SHM buffer
+ *
+ * \param buffer The buffer object
+ *
+ * Returns a pointer which can be used to read the data contained in
+ * the given SHM buffer.
+ *
+ * As this buffer is memory-mapped, reading from it may generate
+ * SIGBUS signals. This can happen if the client claims that the
+ * buffer is larger than it is or if something truncates the
+ * underlying file. To prevent this signal from causing the compositor
+ * to crash you should call wl_shm_buffer_begin_access and
+ * wl_shm_buffer_end_access around code that reads from the memory.
+ *
+ * \memberof wl_shm_buffer
+ */
+WL_EXPORT void *
+wl_shm_buffer_get_data(struct wl_shm_buffer *buffer)
+{
+       if (buffer->pool)
+               return buffer->pool->data + buffer->offset;
+       else
+               return buffer + 1;
+}
+
+WL_EXPORT uint32_t
+wl_shm_buffer_get_format(struct wl_shm_buffer *buffer)
+{
+       return buffer->format;
+}
+
+WL_EXPORT int32_t
+wl_shm_buffer_get_width(struct wl_shm_buffer *buffer)
+{
+       return buffer->width;
+}
+
+WL_EXPORT int32_t
+wl_shm_buffer_get_height(struct wl_shm_buffer *buffer)
+{
+       return buffer->height;
+}
+
+static void
+reraise_sigbus(void)
+{
+       /* If SIGBUS is raised for some other reason than accessing
+        * the pool then we'll uninstall the signal handler so we can
+        * reraise it. This would presumably kill the process */
+       sigaction(SIGBUS, &wl_shm_old_sigbus_action, NULL);
+       raise(SIGBUS);
+}
+
+static void
+sigbus_handler(int signum, siginfo_t *info, void *context)
+{
+       struct wl_shm_sigbus_data *sigbus_data =
+               pthread_getspecific(wl_shm_sigbus_data_key);
+       struct wl_shm_pool *pool;
+
+       if (sigbus_data == NULL) {
+               reraise_sigbus();
+               return;
+       }
+
+       pool = sigbus_data->current_pool;
+
+       /* If the offending address is outside the mapped space for
+        * the pool then the error is a real problem so we'll reraise
+        * the signal */
+       if (pool == NULL ||
+           (char *) info->si_addr < pool->data ||
+           (char *) info->si_addr >= pool->data + pool->size) {
+               reraise_sigbus();
+               return;
+       }
+
+       sigbus_data->fallback_mapping_used = 1;
+
+       /* This should replace the previous mapping */
+       if (mmap(pool->data, pool->size,
+                PROT_READ | PROT_WRITE,
+                MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS,
+                0, 0) == (void *) -1) {
+               reraise_sigbus();
+               return;
+       }
+}
+
+static void
+destroy_sigbus_data(void *data)
+{
+       struct wl_shm_sigbus_data *sigbus_data = data;
+
+       free(sigbus_data);
+}
+
+static void
+init_sigbus_data_key(void)
+{
+       struct sigaction new_action = {
+               .sa_sigaction = sigbus_handler,
+               .sa_flags = SA_SIGINFO | SA_NODEFER
+       };
+
+       sigemptyset(&new_action.sa_mask);
+
+       sigaction(SIGBUS, &new_action, &wl_shm_old_sigbus_action);
+
+       pthread_key_create(&wl_shm_sigbus_data_key, destroy_sigbus_data);
+}
+
+/** Mark that the given SHM buffer is about to be accessed
+ *
+ * \param buffer The SHM buffer
+ *
+ * An SHM buffer is a memory-mapped file given by the client.
+ * According to POSIX, reading from a memory-mapped region that
+ * extends off the end of the file will cause a SIGBUS signal to be
+ * generated. Normally this would cause the compositor to terminate.
+ * In order to make the compositor robust against clients that change
+ * the size of the underlying file or lie about its size, you should
+ * protect access to the buffer by calling this function before
+ * reading from the memory and call wl_shm_buffer_end_access
+ * afterwards. This will install a signal handler for SIGBUS which
+ * will prevent the compositor from crashing.
+ *
+ * After calling this function the signal handler will remain
+ * installed for the lifetime of the compositor process. Note that
+ * this function will not work properly if the compositor is also
+ * installing its own handler for SIGBUS.
+ *
+ * If a SIGBUS signal is received for an address within the range of
+ * the SHM pool of the given buffer then the client will be sent an
+ * error event when wl_shm_buffer_end_access is called. If the signal
+ * is for an address outside that range then the signal handler will
+ * reraise the signal which would will likely cause the compositor to
+ * terminate.
+ *
+ * It is safe to nest calls to these functions as long as the nested
+ * calls are all accessing the same buffer. The number of calls to
+ * wl_shm_buffer_end_access must match the number of calls to
+ * wl_shm_buffer_begin_access. These functions are thread-safe and it
+ * is allowed to simultaneously access different buffers or the same
+ * buffer from multiple threads.
+ *
+ * \memberof wl_shm_buffer
+ */
+WL_EXPORT void
+wl_shm_buffer_begin_access(struct wl_shm_buffer *buffer)
+{
+       struct wl_shm_pool *pool = buffer->pool;
+       struct wl_shm_sigbus_data *sigbus_data;
+
+       pthread_once(&wl_shm_sigbus_once, init_sigbus_data_key);
+
+       sigbus_data = pthread_getspecific(wl_shm_sigbus_data_key);
+       if (sigbus_data == NULL) {
+               sigbus_data = malloc(sizeof *sigbus_data);
+               if (sigbus_data == NULL)
+                       return;
+
+               memset(sigbus_data, 0, sizeof *sigbus_data);
+
+               pthread_setspecific(wl_shm_sigbus_data_key, sigbus_data);
+       }
+
+       assert(sigbus_data->current_pool == NULL ||
+              sigbus_data->current_pool == pool);
+
+       sigbus_data->current_pool = pool;
+       sigbus_data->access_count++;
+}
+
+/** Ends the access to a buffer started by wl_shm_buffer_begin_access
+ *
+ * \param buffer The SHM buffer
+ *
+ * This should be called after wl_shm_buffer_begin_access once the
+ * buffer is no longer being accessed. If a SIGBUS signal was
+ * generated in-between these two calls then the resource for the
+ * given buffer will be sent an error.
+ *
+ * \memberof wl_shm_buffer
+ */
+WL_EXPORT void
+wl_shm_buffer_end_access(struct wl_shm_buffer *buffer)
+{
+       struct wl_shm_sigbus_data *sigbus_data =
+               pthread_getspecific(wl_shm_sigbus_data_key);
+
+       assert(sigbus_data && sigbus_data->access_count >= 1);
+
+       if (--sigbus_data->access_count == 0) {
+               if (sigbus_data->fallback_mapping_used) {
+                       wl_resource_post_error(buffer->resource,
+                                              WL_SHM_ERROR_INVALID_FD,
+                                              "error accessing SHM buffer");
+                       sigbus_data->fallback_mapping_used = 0;
+               }
+
+               sigbus_data->current_pool = NULL;
+       }
+}
diff --git a/src/wayland-util.c b/src/wayland-util.c
new file mode 100644 (file)
index 0000000..db51ebb
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2011 Intel Corporation
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "wayland-util.h"
+#include "wayland-private.h"
+
+struct wl_object global_zombie_object;
+
+WL_EXPORT void
+wl_list_init(struct wl_list *list)
+{
+       list->prev = list;
+       list->next = list;
+}
+
+WL_EXPORT void
+wl_list_insert(struct wl_list *list, struct wl_list *elm)
+{
+       elm->prev = list;
+       elm->next = list->next;
+       list->next = elm;
+       elm->next->prev = elm;
+}
+
+WL_EXPORT void
+wl_list_remove(struct wl_list *elm)
+{
+       elm->prev->next = elm->next;
+       elm->next->prev = elm->prev;
+       elm->next = NULL;
+       elm->prev = NULL;
+}
+
+WL_EXPORT int
+wl_list_length(const struct wl_list *list)
+{
+       struct wl_list *e;
+       int count;
+
+       count = 0;
+       e = list->next;
+       while (e != list) {
+               e = e->next;
+               count++;
+       }
+
+       return count;
+}
+
+WL_EXPORT int
+wl_list_empty(const struct wl_list *list)
+{
+       return list->next == list;
+}
+
+WL_EXPORT void
+wl_list_insert_list(struct wl_list *list, struct wl_list *other)
+{
+       if (wl_list_empty(other))
+               return;
+
+       other->next->prev = list;
+       other->prev->next = list->next;
+       list->next->prev = other->prev;
+       list->next = other->next;
+}
+
+WL_EXPORT void
+wl_array_init(struct wl_array *array)
+{
+       memset(array, 0, sizeof *array);
+}
+
+WL_EXPORT void
+wl_array_release(struct wl_array *array)
+{
+       free(array->data);
+}
+
+WL_EXPORT void *
+wl_array_add(struct wl_array *array, size_t size)
+{
+       size_t alloc;
+       void *data, *p;
+
+       if (array->alloc > 0)
+               alloc = array->alloc;
+       else
+               alloc = 16;
+
+       while (alloc < array->size + size)
+               alloc *= 2;
+
+       if (array->alloc < alloc) {
+               if (array->alloc > 0)
+                       data = realloc(array->data, alloc);
+               else
+                       data = malloc(alloc);
+
+               if (data == NULL)
+                       return 0;
+               array->data = data;
+               array->alloc = alloc;
+       }
+
+       p = array->data + array->size;
+       array->size += size;
+
+       return p;
+}
+
+WL_EXPORT int
+wl_array_copy(struct wl_array *array, struct wl_array *source)
+{
+       if (array->size < source->size) {
+               if (!wl_array_add(array, source->size - array->size))
+                       return -1;
+       } else {
+               array->size = source->size;
+       }
+
+       memcpy(array->data, source->data, source->size);
+       return 0;
+}
+
+/** \cond */
+
+union map_entry {
+       uintptr_t next;
+       void *data;
+};
+
+#define map_entry_is_free(entry) ((entry).next & 0x1)
+#define map_entry_get_data(entry) ((void *)((entry).next & ~(uintptr_t)0x3))
+#define map_entry_get_flags(entry) (((entry).next >> 1) & 0x1)
+
+WL_EXPORT void
+wl_map_init(struct wl_map *map, uint32_t side)
+{
+       memset(map, 0, sizeof *map);
+       map->side = side;
+}
+
+WL_EXPORT void
+wl_map_release(struct wl_map *map)
+{
+       wl_array_release(&map->client_entries);
+       wl_array_release(&map->server_entries);
+}
+
+WL_EXPORT uint32_t
+wl_map_insert_new(struct wl_map *map, uint32_t flags, void *data)
+{
+       union map_entry *start, *entry;
+       struct wl_array *entries;
+       uint32_t base;
+
+       if (map->side == WL_MAP_CLIENT_SIDE) {
+               entries = &map->client_entries;
+               base = 0;
+       } else {
+               entries = &map->server_entries;
+               base = WL_SERVER_ID_START;
+       }
+
+       if (map->free_list) {
+               start = entries->data;
+               entry = &start[map->free_list >> 1];
+               map->free_list = entry->next;
+       } else {
+               entry = wl_array_add(entries, sizeof *entry);
+               if (!entry)
+                       return 0;
+               start = entries->data;
+       }
+
+       entry->data = data;
+       entry->next |= (flags & 0x1) << 1;
+
+       return (entry - start) + base;
+}
+
+WL_EXPORT int
+wl_map_insert_at(struct wl_map *map, uint32_t flags, uint32_t i, void *data)
+{
+       union map_entry *start;
+       uint32_t count;
+       struct wl_array *entries;
+
+       if (i < WL_SERVER_ID_START) {
+               entries = &map->client_entries;
+       } else {
+               entries = &map->server_entries;
+               i -= WL_SERVER_ID_START;
+       }
+
+       count = entries->size / sizeof *start;
+       if (count < i)
+               return -1;
+
+       if (count == i)
+               wl_array_add(entries, sizeof *start);
+
+       start = entries->data;
+       start[i].data = data;
+       start[i].next |= (flags & 0x1) << 1;
+
+       return 0;
+}
+
+WL_EXPORT int
+wl_map_reserve_new(struct wl_map *map, uint32_t i)
+{
+       union map_entry *start;
+       uint32_t count;
+       struct wl_array *entries;
+
+       if (i < WL_SERVER_ID_START) {
+               if (map->side == WL_MAP_CLIENT_SIDE)
+                       return -1;
+
+               entries = &map->client_entries;
+       } else {
+               if (map->side == WL_MAP_SERVER_SIDE)
+                       return -1;
+
+               entries = &map->server_entries;
+               i -= WL_SERVER_ID_START;
+       }
+
+       count = entries->size / sizeof *start;
+
+       if (count < i)
+               return -1;
+
+       if (count == i) {
+               wl_array_add(entries, sizeof *start);
+               start = entries->data;
+               start[i].data = NULL;
+       } else {
+               start = entries->data;
+               if (start[i].data != NULL) {
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+WL_EXPORT void
+wl_map_remove(struct wl_map *map, uint32_t i)
+{
+       union map_entry *start;
+       struct wl_array *entries;
+
+       if (i < WL_SERVER_ID_START) {
+               if (map->side == WL_MAP_SERVER_SIDE)
+                       return;
+
+               entries = &map->client_entries;
+       } else {
+               if (map->side == WL_MAP_CLIENT_SIDE)
+                       return;
+
+               entries = &map->server_entries;
+               i -= WL_SERVER_ID_START;
+       }
+
+       start = entries->data;
+       start[i].next = map->free_list;
+       map->free_list = (i << 1) | 1;
+}
+
+WL_EXPORT void *
+wl_map_lookup(struct wl_map *map, uint32_t i)
+{
+       union map_entry *start;
+       uint32_t count;
+       struct wl_array *entries;
+
+       if (i < WL_SERVER_ID_START) {
+               entries = &map->client_entries;
+       } else {
+               entries = &map->server_entries;
+               i -= WL_SERVER_ID_START;
+       }
+
+       start = entries->data;
+       count = entries->size / sizeof *start;
+
+       if (i < count && !map_entry_is_free(start[i]))
+               return map_entry_get_data(start[i]);
+
+       return NULL;
+}
+
+WL_EXPORT uint32_t
+wl_map_lookup_flags(struct wl_map *map, uint32_t i)
+{
+       union map_entry *start;
+       uint32_t count;
+       struct wl_array *entries;
+
+       if (i < WL_SERVER_ID_START) {
+               entries = &map->client_entries;
+       } else {
+               entries = &map->server_entries;
+               i -= WL_SERVER_ID_START;
+       }
+
+       start = entries->data;
+       count = entries->size / sizeof *start;
+
+       if (i < count && !map_entry_is_free(start[i]))
+               return map_entry_get_flags(start[i]);
+
+       return 0;
+}
+
+static void
+for_each_helper(struct wl_array *entries, wl_iterator_func_t func, void *data)
+{
+       union map_entry *start, *end, *p;
+
+       start = entries->data;
+       end = (union map_entry *) ((char *) entries->data + entries->size);
+
+       for (p = start; p < end; p++)
+               if (p->data && !map_entry_is_free(*p))
+                       func(map_entry_get_data(*p), data);
+}
+
+WL_EXPORT void
+wl_map_for_each(struct wl_map *map, wl_iterator_func_t func, void *data)
+{
+       for_each_helper(&map->client_entries, func, data);
+       for_each_helper(&map->server_entries, func, data);
+}
+
+/** \endcond */
+
+static void
+wl_log_stderr_handler(const char *fmt, va_list arg)
+{
+       vfprintf(stderr, fmt, arg);
+}
+
+wl_log_func_t wl_log_handler = wl_log_stderr_handler;
+
+void
+wl_log(const char *fmt, ...)
+{
+       va_list argp;
+
+       va_start(argp, fmt);
+       wl_log_handler(fmt, argp);
+       va_end(argp);
+}
diff --git a/src/wayland-util.h b/src/wayland-util.h
new file mode 100644 (file)
index 0000000..a4b22b5
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * 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.
+ */
+
+/** \file wayland-util.h
+ *
+ * \brief Utility classes, functions, and macros.
+ */
+
+#ifndef WAYLAND_UTIL_H
+#define WAYLAND_UTIL_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include <math.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include <stdarg.h>
+
+/* GCC visibility */
+#if defined(__GNUC__) && __GNUC__ >= 4
+#define WL_EXPORT __attribute__ ((visibility("default")))
+#else
+#define WL_EXPORT
+#endif
+
+/* Deprecated attribute */
+#if defined(__GNUC__) && __GNUC__ >= 4
+#define WL_DEPRECATED __attribute__ ((deprecated))
+#else
+#define WL_DEPRECATED
+#endif
+
+/* Printf annotation */
+#if defined(__GNUC__) && __GNUC__ >= 4
+#define WL_PRINTF(x, y) __attribute__((__format__(__printf__, x, y)))
+#else
+#define WL_PRINTF(x, y)
+#endif
+
+struct wl_message {
+       const char *name;
+       const char *signature;
+       const struct wl_interface **types;
+};
+
+struct wl_interface {
+       const char *name;
+       int version;
+       int method_count;
+       const struct wl_message *methods;
+       int event_count;
+       const struct wl_message *events;
+};
+
+/** \class wl_list
+ *
+ * \brief doubly-linked list
+ *
+ * The list head is of "struct wl_list" type, and must be initialized
+ * using wl_list_init().  All entries in the list must be of the same
+ * type.  The item type must have a "struct wl_list" member. This
+ * member will be initialized by wl_list_insert(). There is no need to
+ * call wl_list_init() on the individual item. To query if the list is
+ * empty in O(1), use wl_list_empty().
+ *
+ * Let's call the list reference "struct wl_list foo_list", the item type as
+ * "item_t", and the item member as "struct wl_list link".
+ *
+ * The following code will initialize a list:
+ * \code
+ * struct wl_list foo_list;
+ *
+ * struct item_t {
+ *     int foo;
+ *     struct wl_list link;
+ * };
+ * struct item_t item1, item2, item3;
+ *
+ * wl_list_init(&foo_list);
+ * wl_list_insert(&foo_list, &item1.link);     // Pushes item1 at the head
+ * wl_list_insert(&foo_list, &item2.link);     // Pushes item2 at the head
+ * wl_list_insert(&item2.link, &item3.link);   // Pushes item3 after item2
+ * \endcode
+ *
+ * The list now looks like [item2, item3, item1]
+ *
+ * Iterate the list in ascending order:
+ * \code
+ * item_t *item;
+ * wl_list_for_each(item, foo_list, link) {
+ *     Do_something_with_item(item);
+ * }
+ * \endcode
+ */
+struct wl_list {
+       struct wl_list *prev;
+       struct wl_list *next;
+};
+
+void wl_list_init(struct wl_list *list);
+void wl_list_insert(struct wl_list *list, struct wl_list *elm);
+void wl_list_remove(struct wl_list *elm);
+int wl_list_length(const struct wl_list *list);
+int wl_list_empty(const struct wl_list *list);
+void wl_list_insert_list(struct wl_list *list, struct wl_list *other);
+
+/**
+ * Retrieves a pointer to the containing struct of a given member item.
+ *
+ * This macro allows conversion from a pointer to a item to its containing
+ * struct. This is useful if you have a contained item like a wl_list,
+ * wl_listener, or wl_signal, provided via a callback or other means and would
+ * like to retrieve the struct that contains it.
+ *
+ * To demonstrate, the following example retrieves a pointer to
+ * `example_container` given only its `destroy_listener` member:
+ *
+ * \code
+ * struct example_container {
+ *     struct wl_listener destroy_listener;
+ *     // other members...
+ * };
+ *
+ * void example_container_destroy(struct wl_listener *listener, void *data)
+ * {
+ *     struct example_container *ctr;
+ *
+ *     ctr = wl_container_of(listener, ctr, destroy_listener);
+ *     // destroy ctr...
+ * }
+ * \endcode
+ *
+ * \param ptr A valid pointer to the contained item.
+ *
+ * \param sample A pointer to the type of content that the list item
+ * stores. Sample does not need be a valid pointer; a null or
+ * an uninitialised pointer will suffice.
+ *
+ * \param member The named location of ptr within the sample type.
+ *
+ * \return The container for the specified pointer.
+ */
+#define wl_container_of(ptr, sample, member)                           \
+       (__typeof__(sample))((char *)(ptr) -                            \
+                            offsetof(__typeof__(*sample), member))
+/* If the above macro causes problems on your compiler you might be
+ * able to find an alternative name for the non-standard __typeof__
+ * operator and add a special case here */
+
+#define wl_list_for_each(pos, head, member)                            \
+       for (pos = wl_container_of((head)->next, pos, member);  \
+            &pos->member != (head);                                    \
+            pos = wl_container_of(pos->member.next, pos, member))
+
+#define wl_list_for_each_safe(pos, tmp, head, member)                  \
+       for (pos = wl_container_of((head)->next, pos, member),          \
+            tmp = wl_container_of((pos)->member.next, tmp, member);    \
+            &pos->member != (head);                                    \
+            pos = tmp,                                                 \
+            tmp = wl_container_of(pos->member.next, tmp, member))
+
+#define wl_list_for_each_reverse(pos, head, member)                    \
+       for (pos = wl_container_of((head)->prev, pos, member);  \
+            &pos->member != (head);                                    \
+            pos = wl_container_of(pos->member.prev, pos, member))
+
+#define wl_list_for_each_reverse_safe(pos, tmp, head, member)          \
+       for (pos = wl_container_of((head)->prev, pos, member),  \
+            tmp = wl_container_of((pos)->member.prev, tmp, member);    \
+            &pos->member != (head);                                    \
+            pos = tmp,                                                 \
+            tmp = wl_container_of(pos->member.prev, tmp, member))
+
+struct wl_array {
+       size_t size;
+       size_t alloc;
+       void *data;
+};
+
+#define wl_array_for_each(pos, array)                                  \
+       for (pos = (array)->data;                                       \
+            (const char *) pos < ((const char *) (array)->data + (array)->size); \
+            (pos)++)
+
+void wl_array_init(struct wl_array *array);
+void wl_array_release(struct wl_array *array);
+void *wl_array_add(struct wl_array *array, size_t size);
+int wl_array_copy(struct wl_array *array, struct wl_array *source);
+
+typedef int32_t wl_fixed_t;
+
+static inline double
+wl_fixed_to_double (wl_fixed_t f)
+{
+       union {
+               double d;
+               int64_t i;
+       } u;
+
+       u.i = ((1023LL + 44LL) << 52) + (1LL << 51) + f;
+
+       return u.d - (3LL << 43);
+}
+
+static inline wl_fixed_t
+wl_fixed_from_double(double d)
+{
+       union {
+               double d;
+               int64_t i;
+       } u;
+
+       u.d = d + (3LL << (51 - 8));
+
+       return u.i;
+}
+
+static inline int wl_fixed_to_int(wl_fixed_t f)
+{
+       return f / 256;
+}
+static inline wl_fixed_t wl_fixed_from_int(int i)
+{
+       return i * 256;
+}
+
+/**
+ * \brief A union representing all of the basic data types that can be passed
+ * along the wayland wire format.
+ *
+ * This union represents all of the basic data types that can be passed in the
+ * wayland wire format.  It is used by dispatchers and runtime-friendly
+ * versions of the event and request marshaling functions.
+ */
+union wl_argument {
+       int32_t i; /**< signed integer */
+       uint32_t u; /**< unsigned integer */
+       wl_fixed_t f; /**< fixed point */
+       const char *s; /**< string */
+       struct wl_object *o; /**< object */
+       uint32_t n; /**< new_id */
+       struct wl_array *a; /**< array */
+       int32_t h; /**< file descriptor */
+};
+
+/**
+ * \brief A function pointer type for a dispatcher.
+ *
+ * A dispatcher is a function that handles the emitting of callbacks in client
+ * code.  For programs directly using the C library, this is done by using
+ * libffi to call function pointers.  When binding to languages other than C,
+ * dispatchers provide a way to abstract the function calling process to be
+ * friendlier to other function calling systems.
+ *
+ * A dispatcher takes five arguments:  The first is the dispatcher-specific
+ * implementation data associated with the target object.  The second is the
+ * object on which the callback is being invoked (either wl_proxy or
+ * wl_resource).  The third and fourth arguments are the opcode the wl_messsage
+ * structure corresponding to the callback being emitted.  The final argument
+ * is an array of arguments recieved from the other process via the wire
+ * protocol.
+ */
+typedef int (*wl_dispatcher_func_t)(const void *, void *, uint32_t,
+                                   const struct wl_message *,
+                                   union wl_argument *);
+
+typedef void (*wl_log_func_t)(const char *, va_list) WL_PRINTF(1, 0);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/wayland-version.h.in b/src/wayland-version.h.in
new file mode 100644 (file)
index 0000000..9a746ca
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * 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_VERSION_H
+#define WAYLAND_VERSION_H
+
+#define WAYLAND_VERSION_MAJOR @WAYLAND_VERSION_MAJOR@
+#define WAYLAND_VERSION_MINOR @WAYLAND_VERSION_MINOR@
+#define WAYLAND_VERSION_MICRO @WAYLAND_VERSION_MICRO@
+#define WAYLAND_VERSION "@WAYLAND_VERSION@"
+
+#endif
diff --git a/tests/array-test.c b/tests/array-test.c
new file mode 100644 (file)
index 0000000..c457e42
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * 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 <assert.h>
+#include "wayland-private.h"
+#include "test-runner.h"
+
+TEST(array_init)
+{
+       const int iterations = 4122; /* this is arbitrary */
+       int i;
+
+       /* Init array an arbitray amount of times and verify the
+        * defaults are sensible. */
+
+       for (i = 0; i < iterations; i++) {
+               struct wl_array array;
+               wl_array_init(&array);
+               assert(array.size == 0);
+               assert(array.alloc == 0);
+               assert(array.data == 0);
+       }
+}
+
+TEST(array_add)
+{
+       struct mydata {
+               unsigned int a;
+               unsigned int b;
+               double c;
+               double d;
+       };
+
+       const unsigned int iterations = 1321; /* this is arbitrary */
+       const int datasize = sizeof(struct mydata);
+       struct wl_array array;
+       size_t i;
+
+       wl_array_init(&array);
+
+       /* add some data */
+       for (i = 0; i < iterations; i++) {
+               struct mydata* ptr = wl_array_add(&array, datasize);
+               assert(ptr);
+               assert((i + 1) * datasize == array.size);
+
+               ptr->a = i * 3;
+               ptr->b = 20000 - i;
+               ptr->c = (double)(i);
+               ptr->d = (double)(i / 2.);
+       }
+
+       /* verify the data */
+       for (i = 0; i < iterations; ++i) {
+               const int index = datasize * i;
+               struct mydata* check = (struct mydata*)(array.data + index);
+
+               assert(check->a == i * 3);
+               assert(check->b == 20000 - i);
+               assert(check->c == (double)(i));
+               assert(check->d == (double)(i/2.));
+       }
+
+       wl_array_release(&array);
+}
+
+TEST(array_copy)
+{
+       const int iterations = 1529; /* this is arbitrary */
+       struct wl_array source;
+       struct wl_array copy;
+       int i;
+
+       wl_array_init(&source);
+
+       /* add some data */
+       for (i = 0; i < iterations; i++) {
+               int *p = wl_array_add(&source, sizeof(int));
+               assert(p);
+               *p = i * 2 + i;
+       }
+
+       /* copy the array */
+       wl_array_init(&copy);
+       wl_array_copy(&copy, &source);
+
+       /* check the copy */
+       for (i = 0; i < iterations; i++) {
+               const int index = sizeof(int) * i;
+               int *s = (int *)(source.data + index);
+               int *c = (int *)(copy.data + index);
+
+               assert(*s == *c); /* verify the values are the same */
+               assert(s != c); /* ensure the addresses aren't the same */
+               assert(*s == i * 2 + i); /* sanity check */
+       }
+
+       wl_array_release(&source);
+       wl_array_release(&copy);
+}
+
+TEST(array_for_each)
+{
+       static const int elements[] = { 77, 12, 45192, 53280, 334455 };
+       struct wl_array array;
+       int *p, i;
+
+       wl_array_init(&array);
+       for (i = 0; i < 5; i++) {
+               p = wl_array_add(&array, sizeof *p);
+               assert(p);
+               *p = elements[i];
+       }
+
+       i = 0;
+       wl_array_for_each(p, &array)
+               assert(*p == elements[i++]);
+       assert(i == 5);
+
+       wl_array_release(&array);
+}
diff --git a/tests/client-test.c b/tests/client-test.c
new file mode 100644 (file)
index 0000000..fde3877
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "wayland-private.h"
+#include "wayland-server.h"
+#include "test-runner.h"
+
+struct client_destroy_listener {
+       struct wl_listener listener;
+       int done;
+};
+
+static void
+client_destroy_notify(struct wl_listener *l, void *data)
+{
+       struct client_destroy_listener *listener =
+               container_of(l, struct client_destroy_listener, listener);
+
+       listener->done = 1;
+}
+
+TEST(client_destroy_listener)
+{
+       struct wl_display *display;
+       struct wl_client *client;
+       struct client_destroy_listener a, b;
+       int s[2];
+
+       assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0);
+       display = wl_display_create();
+       assert(display);
+       client = wl_client_create(display, s[0]);
+       assert(client);
+
+       a.listener.notify = client_destroy_notify;
+       a.done = 0;
+       wl_client_add_destroy_listener(client, &a.listener);
+
+       assert(wl_client_get_destroy_listener(client, client_destroy_notify) ==
+              &a.listener);
+
+       b.listener.notify = client_destroy_notify;
+       b.done = 0;
+       wl_client_add_destroy_listener(client, &b.listener);
+
+       wl_list_remove(&a.listener.link);
+
+       wl_client_destroy(client);
+
+       assert(!a.done);
+       assert(b.done);
+
+       close(s[0]);
+       close(s[1]);
+
+       wl_display_destroy(display);
+}
+
diff --git a/tests/connection-test.c b/tests/connection-test.c
new file mode 100644 (file)
index 0000000..d34e9a5
--- /dev/null
@@ -0,0 +1,652 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * 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 <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <poll.h>
+
+#include "wayland-private.h"
+#include "test-runner.h"
+#include "test-compositor.h"
+
+static const char message[] = "Hello, world";
+
+static struct wl_connection *
+setup(int *s)
+{
+       struct wl_connection *connection;
+
+       assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0);
+
+       connection = wl_connection_create(s[0]);
+       assert(connection);
+
+       return connection;
+}
+
+TEST(connection_create)
+{
+       struct wl_connection *connection;
+       int s[2];
+
+       connection = setup(s);
+       wl_connection_destroy(connection);
+       close(s[0]);
+       close(s[1]);
+}
+
+TEST(connection_write)
+{
+       struct wl_connection *connection;
+       int s[2];
+       char buffer[64];
+
+       connection = setup(s);
+
+       assert(wl_connection_write(connection, message, sizeof message) == 0);
+       assert(wl_connection_flush(connection) == sizeof message);
+       assert(read(s[1], buffer, sizeof buffer) == sizeof message);
+       assert(memcmp(message, buffer, sizeof message) == 0);
+
+       wl_connection_destroy(connection);
+       close(s[0]);
+       close(s[1]);
+}
+
+TEST(connection_data)
+{
+       struct wl_connection *connection;
+       int s[2];
+       char buffer[64];
+
+       connection = setup(s);
+
+       assert(write(s[1], message, sizeof message) == sizeof message);
+       assert(wl_connection_read(connection) == sizeof message);
+       wl_connection_copy(connection, buffer, sizeof message);
+       assert(memcmp(message, buffer, sizeof message) == 0);
+       wl_connection_consume(connection, sizeof message);
+
+       wl_connection_destroy(connection);
+       close(s[0]);
+       close(s[1]);
+}
+
+TEST(connection_queue)
+{
+       struct wl_connection *connection;
+       int s[2];
+       char buffer[64];
+
+       connection = setup(s);
+
+       /* Test that wl_connection_queue() puts data in the output
+        * buffer without flush it.  Verify that the data did get in
+        * the buffer by writing another message and making sure that
+        * we receive the two messages on the other fd. */
+
+       assert(wl_connection_queue(connection, message, sizeof message) == 0);
+       assert(wl_connection_flush(connection) == 0);
+       assert(wl_connection_write(connection, message, sizeof message) == 0);
+       assert(wl_connection_flush(connection) == 2 * sizeof message);
+       assert(read(s[1], buffer, sizeof buffer) == 2 * sizeof message);
+       assert(memcmp(message, buffer, sizeof message) == 0);
+       assert(memcmp(message, buffer + sizeof message, sizeof message) == 0);
+
+       wl_connection_destroy(connection);
+       close(s[0]);
+       close(s[1]);
+}
+
+struct marshal_data {
+       struct wl_connection *read_connection;
+       struct wl_connection *write_connection;
+       int s[2];
+       uint32_t buffer[10];
+       union {
+               uint32_t u;
+               int32_t i;
+               const char *s;
+               int h;
+       } value;
+};
+
+static void
+setup_marshal_data(struct marshal_data *data)
+{
+       assert(socketpair(AF_UNIX,
+                         SOCK_STREAM | SOCK_CLOEXEC, 0, data->s) == 0);
+       data->read_connection = wl_connection_create(data->s[0]);
+       assert(data->read_connection);
+       data->write_connection = wl_connection_create(data->s[1]);
+       assert(data->write_connection);
+}
+
+static void
+release_marshal_data(struct marshal_data *data)
+{
+       close(wl_connection_destroy(data->read_connection));
+       close(wl_connection_destroy(data->write_connection));
+}
+
+static void
+marshal(struct marshal_data *data, const char *format, int size, ...)
+{
+       struct wl_closure *closure;
+       static const uint32_t opcode = 4444;
+       static struct wl_object sender = { NULL, NULL, 1234 };
+       struct wl_message message = { "test", format, NULL };
+       va_list ap;
+
+       va_start(ap, size);
+       closure = wl_closure_vmarshal(&sender, opcode, ap, &message);
+       va_end(ap);
+
+       assert(closure);
+       assert(wl_closure_send(closure, data->write_connection) == 0);
+       wl_closure_destroy(closure);
+       assert(wl_connection_flush(data->write_connection) == size);
+       assert(read(data->s[0], data->buffer, sizeof data->buffer) == size);
+
+       assert(data->buffer[0] == sender.id);
+       assert(data->buffer[1] == (opcode | (size << 16)));
+}
+
+TEST(connection_marshal)
+{
+       struct marshal_data data;
+       struct wl_object object;
+       struct wl_array array;
+       static const char text[] = "curry";
+
+       setup_marshal_data(&data);
+
+       marshal(&data, "i", 12, 42);
+       assert(data.buffer[2] == 42);
+
+       marshal(&data, "u", 12, 55);
+       assert(data.buffer[2] == 55);
+
+       marshal(&data, "s", 20, "frappo");
+       assert(data.buffer[2] == 7);
+       assert(strcmp((char *) &data.buffer[3], "frappo") == 0);
+
+       object.id = 557799;
+       marshal(&data, "o", 12, &object);
+       assert(data.buffer[2] == object.id);
+
+       marshal(&data, "n", 12, &object);
+       assert(data.buffer[2] == object.id);
+
+       marshal(&data, "?n", 12, NULL);
+       assert(data.buffer[2] == 0);
+
+       array.data = (void *) text;
+       array.size = sizeof text;
+       marshal(&data, "a", 20, &array);
+       assert(data.buffer[2] == array.size);
+       assert(memcmp(&data.buffer[3], text, array.size) == 0);
+
+       release_marshal_data(&data);
+}
+
+static void
+expected_fail_marshal(int expected_error, const char *format, ...)
+{
+       struct wl_closure *closure;
+       static const uint32_t opcode = 4444;
+       static const struct wl_interface test_interface = { 
+               .name = "test_object"
+       };
+       static struct wl_object sender = { 0 };
+       struct wl_message message = { "test", format, NULL };
+
+       sender.interface = &test_interface;
+       sender.id = 1234;
+       va_list ap;
+
+       va_start(ap, format);
+       closure = wl_closure_vmarshal(&sender, opcode, ap, &message);
+       va_end(ap);
+
+       assert(closure == NULL);
+       assert(errno == expected_error);
+}
+
+static void
+expected_fail_marshal_send(struct marshal_data *data, int expected_error,
+                          const char *format, ...)
+{
+       struct wl_closure *closure;
+       static const uint32_t opcode = 4444;
+       static struct wl_object sender = { NULL, NULL, 1234 };
+       struct wl_message message = { "test", format, NULL };
+       va_list ap;
+
+       va_start(ap, format);
+       closure = wl_closure_vmarshal(&sender, opcode, ap, &message);
+       va_end(ap);
+
+       assert(closure);
+       assert(wl_closure_send(closure, data->write_connection) < 0);
+       assert(errno == expected_error);
+
+       wl_closure_destroy(closure);
+}
+
+TEST(connection_marshal_nullables)
+{
+       struct marshal_data data;
+       struct wl_object object;
+       struct wl_array array;
+       const char text[] = "curry";
+
+       setup_marshal_data(&data);
+
+       expected_fail_marshal(EINVAL, "o", NULL);
+       expected_fail_marshal(EINVAL, "s", NULL);
+       expected_fail_marshal(EINVAL, "a", NULL);
+
+       marshal(&data, "?o", 12, NULL);
+       assert(data.buffer[2] == 0);
+
+       marshal(&data, "?a", 12, NULL);
+       assert(data.buffer[2] == 0);
+
+       marshal(&data, "?s", 12, NULL);
+       assert(data.buffer[2] == 0);
+
+       object.id = 55293;
+       marshal(&data, "?o", 12, &object);
+       assert(data.buffer[2] == object.id);
+
+       array.data = (void *) text;
+       array.size = sizeof text;
+       marshal(&data, "?a", 20, &array);
+       assert(data.buffer[2] == array.size);
+       assert(memcmp(&data.buffer[3], text, array.size) == 0);
+
+       marshal(&data, "?s", 20, text);
+       assert(data.buffer[2] == sizeof text);
+       assert(strcmp((char *) &data.buffer[3], text) == 0);
+
+       release_marshal_data(&data);
+}
+
+static void
+validate_demarshal_u(struct marshal_data *data,
+                    struct wl_object *object, uint32_t u)
+{
+       assert(data->value.u == u);
+}
+
+static void
+validate_demarshal_i(struct marshal_data *data,
+                    struct wl_object *object, int32_t i)
+{
+       assert(data->value.i == i);
+}
+
+static void
+validate_demarshal_s(struct marshal_data *data,
+                    struct wl_object *object, const char *s)
+{
+       if (data->value.s != NULL)
+               assert(strcmp(data->value.s, s) == 0);
+       else
+               assert(s == NULL);
+}
+
+static void
+validate_demarshal_h(struct marshal_data *data,
+                    struct wl_object *object, int fd)
+{
+       struct stat buf1, buf2;
+
+       assert(fd != data->value.h);
+       fstat(fd, &buf1);
+       fstat(data->value.h, &buf2);
+       assert(buf1.st_dev == buf2.st_dev);
+       assert(buf1.st_ino == buf2.st_ino);
+       close(fd);
+       close(data->value.h);
+}
+
+static void
+validate_demarshal_f(struct marshal_data *data,
+                    struct wl_object *object, wl_fixed_t f)
+{
+       assert(data->value.i == f);
+}
+
+static void
+demarshal(struct marshal_data *data, const char *format,
+         uint32_t *msg, void (*func)(void))
+{
+       struct wl_message message = { "test", format, NULL };
+       struct wl_closure *closure;
+       struct wl_map objects;
+       struct wl_object object = { NULL, &func, 0 };
+       int size = msg[1];
+
+       assert(write(data->s[1], msg, size) == size);
+       assert(wl_connection_read(data->read_connection) == size);
+
+       wl_map_init(&objects, WL_MAP_SERVER_SIDE);
+       object.id = msg[0];
+       closure = wl_connection_demarshal(data->read_connection,
+                                         size, &objects, &message);
+       assert(closure);
+       wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER, &object, 0, data);
+       wl_closure_destroy(closure);
+}
+
+TEST(connection_demarshal)
+{
+       struct marshal_data data;
+       uint32_t msg[10];
+
+       setup_marshal_data(&data);
+
+       data.value.u = 8000;
+       msg[0] = 400200;        /* object id */
+       msg[1] = 12;            /* size = 12, opcode = 0 */
+       msg[2] = data.value.u;
+       demarshal(&data, "u", msg, (void *) validate_demarshal_u);
+
+       data.value.i = -557799;
+       msg[0] = 400200;
+       msg[1] = 12;
+       msg[2] = data.value.i;
+       demarshal(&data, "i", msg, (void *) validate_demarshal_i);
+
+       data.value.s = "superdude";
+       msg[0] = 400200;
+       msg[1] = 24;
+       msg[2] = 10;
+       memcpy(&msg[3], data.value.s, msg[2]);
+       demarshal(&data, "s", msg, (void *) validate_demarshal_s);
+
+       data.value.s = "superdude";
+       msg[0] = 400200;
+       msg[1] = 24;
+       msg[2] = 10;
+       memcpy(&msg[3], data.value.s, msg[2]);
+       demarshal(&data, "?s", msg, (void *) validate_demarshal_s);
+
+       data.value.i = wl_fixed_from_double(-90000.2390);
+       msg[0] = 400200;
+       msg[1] = 12;
+       msg[2] = data.value.i;
+       demarshal(&data, "f", msg, (void *) validate_demarshal_f);
+
+       data.value.s = NULL;
+       msg[0] = 400200;
+       msg[1] = 12;
+       msg[2] = 0;
+       demarshal(&data, "?s", msg, (void *) validate_demarshal_s);     
+
+       release_marshal_data(&data);
+}
+
+static void
+marshal_demarshal(struct marshal_data *data, 
+                 void (*func)(void), int size, const char *format, ...)
+{
+       struct wl_closure *closure;
+       static const int opcode = 4444;
+       static struct wl_object sender = { NULL, NULL, 1234 };
+       struct wl_message message = { "test", format, NULL };
+       struct wl_map objects;
+       struct wl_object object = { NULL, &func, 0 };
+       va_list ap;
+       uint32_t msg[1] = { 1234 };
+
+       va_start(ap, format);
+       closure = wl_closure_vmarshal(&sender, opcode, ap, &message);
+       va_end(ap);
+
+       assert(closure);
+       assert(wl_closure_send(closure, data->write_connection) == 0);
+       wl_closure_destroy(closure);
+       assert(wl_connection_flush(data->write_connection) == size);
+
+       assert(wl_connection_read(data->read_connection) == size);
+
+       wl_map_init(&objects, WL_MAP_SERVER_SIDE);
+       object.id = msg[0];
+       closure = wl_connection_demarshal(data->read_connection,
+                                         size, &objects, &message);
+       assert(closure);
+       wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER, &object, 0, data);
+       wl_closure_destroy(closure);
+}
+
+TEST(connection_marshal_demarshal)
+{
+       struct marshal_data data;
+       char f[] = "/tmp/wayland-tests-XXXXXX";
+
+       setup_marshal_data(&data);
+
+       data.value.u = 889911;
+       marshal_demarshal(&data, (void *) validate_demarshal_u,
+                         12, "u", data.value.u);
+
+       data.value.i = -13;
+       marshal_demarshal(&data, (void *) validate_demarshal_i,
+                         12, "i", data.value.i);
+
+       data.value.s = "cookie robots";
+       marshal_demarshal(&data, (void *) validate_demarshal_s,
+                         28, "s", data.value.s);
+
+       data.value.s = "cookie robots";
+       marshal_demarshal(&data, (void *) validate_demarshal_s,
+                         28, "?s", data.value.s);
+
+       data.value.h = mkstemp(f);
+       assert(data.value.h >= 0);
+       unlink(f);
+       marshal_demarshal(&data, (void *) validate_demarshal_h,
+                         8, "h", data.value.h);
+
+       data.value.i = wl_fixed_from_double(1234.5678);
+       marshal_demarshal(&data, (void *) validate_demarshal_f,
+                         12, "f", data.value.i);
+
+       data.value.i = wl_fixed_from_double(-90000.2390);
+       marshal_demarshal(&data, (void *) validate_demarshal_f,
+                         12, "f", data.value.i);
+
+       data.value.i = wl_fixed_from_double((1 << 23) - 1 + 0.0941);
+       marshal_demarshal(&data, (void *) validate_demarshal_f,
+                         12, "f", data.value.i);
+
+       release_marshal_data(&data);
+}
+
+TEST(connection_marshal_alot)
+{
+       struct marshal_data data;
+       char f[64];
+       int i;
+
+       setup_marshal_data(&data);
+       
+       /* We iterate enough to make sure we wrap the circular buffers
+        * for both regular data an fds. */
+
+       for (i = 0; i < 2000; i++) {
+               strcpy(f, "/tmp/wayland-tests-XXXXXX");
+               data.value.h = mkstemp(f);
+               assert(data.value.h >= 0);
+               unlink(f);
+               marshal_demarshal(&data, (void *) validate_demarshal_h,
+                                 8, "h", data.value.h);
+       }
+
+       release_marshal_data(&data);
+}
+
+TEST(connection_marshal_too_big)
+{
+       struct marshal_data data;
+       char *big_string = malloc(5000);
+
+       assert(big_string);
+
+       memset(big_string, ' ', 4999);
+       big_string[4999] = '\0';
+
+       setup_marshal_data(&data);
+
+       expected_fail_marshal_send(&data, E2BIG, "s", big_string);
+
+       release_marshal_data(&data);
+       free(big_string);
+}
+
+static void
+marshal_helper(const char *format, void *handler, ...)
+{
+       struct wl_closure *closure;
+       static struct wl_object sender = { NULL, NULL, 1234 };
+       struct wl_object object = { NULL, &handler, 0 };
+       static const int opcode = 4444;
+       struct wl_message message = { "test", format, NULL };
+       va_list ap;
+       int done;
+
+       va_start(ap, handler);
+       closure = wl_closure_vmarshal(&sender, opcode, ap, &message);
+       va_end(ap);
+
+       assert(closure);
+       done = 0;
+       wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER, &object, 0, &done);
+       wl_closure_destroy(closure);
+       assert(done);
+}
+
+static void
+suu_handler(void *data, struct wl_object *object,
+           const char *s, uint32_t u1, uint32_t u2)
+{
+       int *done = data;
+
+       assert(strcmp(s, "foo") == 0);
+       assert(u1 = 500);
+       assert(u2 = 404040);
+       *done = 1;
+}
+
+TEST(invoke_closure)
+{
+       marshal_helper("suu", suu_handler, "foo", 500, 404040);
+}
+
+static void
+leak_closure(void)
+{
+       struct wl_callback *cb;
+       struct pollfd pfd;
+       struct client *c = client_connect();
+
+       cb = wl_display_sync(c->wl_display);
+       assert(cb);
+       assert(wl_display_flush(c->wl_display) > 0);
+
+       /* we don't need it, it is referenced */
+       wl_callback_destroy(cb);
+
+       pfd.fd = wl_display_get_fd(c->wl_display);
+       pfd.events = POLLIN;
+
+       test_set_timeout(2);
+       assert(poll(&pfd, 1, -1) == 1);
+
+       /* read events, but do not dispatch them */
+       assert(wl_display_prepare_read(c->wl_display) == 0);
+       assert(wl_display_read_events(c->wl_display) == 0);
+
+       /*
+        * now we have wl_callback.done and wl_display.delete_id queued;
+        * if we now release the queue (in wl_display_disconnect())
+        * we should not leak memory
+        */
+
+       client_disconnect(c);
+}
+
+TEST(closure_leaks)
+{
+       struct display *d = display_create();
+
+       client_create(d, leak_closure);
+       display_run(d);
+
+       display_destroy(d);
+}
+
+static void
+leak_after_error(void)
+{
+       struct client *c = client_connect();
+
+       /* this should return -1, because we'll send error
+        * from server. */
+       assert(stop_display(c, 1) == -1);
+       assert(wl_display_dispatch_pending(c->wl_display) == -1);
+       assert(wl_display_get_error(c->wl_display) == ENOMEM);
+
+       /* after we got error, we have display_resume event
+        * in the queue. It should be freed in wl_display_disconnect().
+        * Let's see! */
+
+       wl_proxy_destroy((struct wl_proxy *) c->tc);
+       wl_display_disconnect(c->wl_display);
+       free(c);
+}
+
+TEST(closure_leaks_after_error)
+{
+       struct display *d = display_create();
+       struct client_info *cl;
+
+       cl = client_create(d, leak_after_error);
+       display_run(d);
+
+       wl_client_post_no_memory(cl->wl_client);
+       display_resume(d);
+
+       display_destroy(d);
+}
diff --git a/tests/cpp-compile-test.cpp b/tests/cpp-compile-test.cpp
new file mode 100644 (file)
index 0000000..1e84e63
--- /dev/null
@@ -0,0 +1,5 @@
+/* This source should compile fine with C++ compiler */
+#include "wayland-server-protocol.h"
+
+int main() { return 0; }
+
diff --git a/tests/display-test.c b/tests/display-test.c
new file mode 100644 (file)
index 0000000..0f86215
--- /dev/null
@@ -0,0 +1,608 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ * Copyright © 2013 Jason Ekstrand
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pthread.h>
+
+#include "wayland-private.h"
+#include "wayland-server.h"
+#include "wayland-client.h"
+#include "test-runner.h"
+#include "test-compositor.h"
+
+struct display_destroy_listener {
+       struct wl_listener listener;
+       int done;
+};
+
+static void
+display_destroy_notify(struct wl_listener *l, void *data)
+{
+       struct display_destroy_listener *listener;
+
+       listener = container_of(l, struct display_destroy_listener, listener);
+       listener->done = 1;
+}
+
+TEST(display_destroy_listener)
+{
+       struct wl_display *display;
+       struct display_destroy_listener a, b;
+
+       display = wl_display_create();
+       assert(display);
+
+       a.listener.notify = &display_destroy_notify;
+       a.done = 0;
+       wl_display_add_destroy_listener(display, &a.listener);
+
+       assert(wl_display_get_destroy_listener(display, display_destroy_notify) ==
+              &a.listener);
+
+       b.listener.notify = display_destroy_notify;
+       b.done = 0;
+       wl_display_add_destroy_listener(display, &b.listener);
+
+       wl_list_remove(&a.listener.link);
+
+       wl_display_destroy(display);
+
+       assert(!a.done);
+       assert(b.done);
+}
+
+/* Fake 'client' which does not use wl_display_connect, and thus leaves the
+ * file descriptor passed through WAYLAND_SOCKET intact. This should not
+ * trigger an assertion in the leak check. */
+static void
+empty_client(void)
+{
+       return;
+}
+
+TEST(tc_leaks_tests)
+{
+       struct display *d = display_create();
+       client_create(d, empty_client);
+       display_run(d);
+       display_destroy(d);
+}
+
+static void
+registry_handle_globals(void *data, struct wl_registry *registry,
+                       uint32_t id, const char *intf, uint32_t ver)
+{
+       struct wl_seat **seat = data;
+
+       if (strcmp(intf, "wl_seat") == 0) {
+               *seat = wl_registry_bind(registry, id,
+                                        &wl_seat_interface, ver);
+               assert(*seat);
+       }
+}
+
+static const struct wl_registry_listener registry_listener = {
+       registry_handle_globals,
+       NULL
+};
+
+static struct wl_seat *
+client_get_seat(struct client *c)
+{
+       struct wl_seat *seat;
+       struct wl_registry *reg = wl_display_get_registry(c->wl_display);
+       assert(reg);
+
+       wl_registry_add_listener(reg, &registry_listener, &seat);
+       wl_display_roundtrip(c->wl_display);
+       assert(seat);
+
+       wl_registry_destroy(reg);
+
+       return seat;
+}
+
+static void
+check_for_error(struct client *c, struct wl_proxy *proxy)
+{
+       uint32_t ec, id;
+       int err;
+       const struct wl_interface *intf;
+
+       /* client should be disconnected */
+       assert(wl_display_roundtrip(c->wl_display) == -1);
+
+       err = wl_display_get_error(c->wl_display);
+       assert(err == EPROTO);
+
+       ec = wl_display_get_protocol_error(c->wl_display, &intf, &id);
+       assert(ec == 23);
+       assert(intf == &wl_seat_interface);
+       assert(id == wl_proxy_get_id(proxy));
+}
+
+static void
+bind_seat(struct wl_client *client, void *data,
+         uint32_t vers, uint32_t id)
+{
+       struct display *d = data;
+       struct client_info *ci;
+       struct wl_resource *res;
+
+       /* find the right client_info struct and save the
+        * resource as its data, so that we can use it later */
+       wl_list_for_each(ci, &d->clients, link) {
+               if (ci->wl_client == client)
+                       break;
+       }
+
+       res = wl_resource_create(client, &wl_seat_interface, vers, id);
+       assert(res);
+
+       ci->data = res;
+}
+
+static void
+client_disconnect_nocheck(struct client *c)
+{
+       wl_proxy_destroy((struct wl_proxy *) c->tc);
+       wl_display_disconnect(c->wl_display);
+       free(c);
+}
+
+static void
+post_error_main(void)
+{
+       struct client *c = client_connect();
+       struct wl_seat *seat = client_get_seat(c);
+
+       /* stop display so that it can post the error.
+        * The function should return -1, because of the posted error */
+       assert(stop_display(c, 1) == -1);
+
+       /* display should have posted error, check it! */
+       check_for_error(c, (struct wl_proxy *) seat);
+
+       /* don't call client_disconnect(c), because then the test would be
+        * aborted due to checks for error in this function */
+       wl_proxy_destroy((struct wl_proxy *) seat);
+       client_disconnect_nocheck(c);
+}
+
+TEST(post_error_to_one_client)
+{
+       struct display *d = display_create();
+       struct client_info *cl;
+
+       wl_global_create(d->wl_display, &wl_seat_interface,
+                        1, d, bind_seat);
+
+       cl = client_create(d, post_error_main);
+       display_run(d);
+
+       /* the display was stopped by client, so it can
+        * proceed in the code and post an error */
+       assert(cl->data);
+       wl_resource_post_error((struct wl_resource *) cl->data,
+                              23, "Dummy error");
+
+       /* this one should be ignored */
+       wl_resource_post_error((struct wl_resource *) cl->data,
+                              21, "Dummy error (ignore)");
+
+       display_resume(d);
+       display_destroy(d);
+}
+
+static void
+post_error_main2(void)
+{
+       struct client *c = client_connect();
+       struct wl_seat *seat = client_get_seat(c);
+
+       /* the error should not be posted for this client */
+       assert(stop_display(c, 2) >= 0);
+
+       wl_proxy_destroy((struct wl_proxy *) seat);
+       client_disconnect(c);
+}
+
+static void
+post_error_main3(void)
+{
+       struct client *c = client_connect();
+       struct wl_seat *seat = client_get_seat(c);
+
+       assert(stop_display(c, 2) == -1);
+       check_for_error(c, (struct wl_proxy *) seat);
+
+       /* don't call client_disconnect(c), because then the test would be
+        * aborted due to checks for error in this function */
+       wl_proxy_destroy((struct wl_proxy *) seat);
+       client_disconnect_nocheck(c);
+}
+
+/* all the testcases could be in one TEST, but splitting it
+ * apart is better for debugging when the test fails */
+TEST(post_error_to_one_from_two_clients)
+{
+       struct display *d = display_create();
+       struct client_info *cl;
+
+       wl_global_create(d->wl_display, &wl_seat_interface,
+                        1, d, bind_seat);
+
+       client_create(d, post_error_main2);
+       cl = client_create(d, post_error_main3);
+       display_run(d);
+
+       /* post error only to the second client */
+       assert(cl->data);
+       wl_resource_post_error((struct wl_resource *) cl->data,
+                              23, "Dummy error");
+       wl_resource_post_error((struct wl_resource *) cl->data,
+                              21, "Dummy error (ignore)");
+
+       display_resume(d);
+       display_destroy(d);
+}
+
+/* all the testcases could be in one TEST, but splitting it
+ * apart is better for debugging when the test fails */
+TEST(post_error_to_two_clients)
+{
+       struct display *d = display_create();
+       struct client_info *cl, *cl2;
+
+       wl_global_create(d->wl_display, &wl_seat_interface,
+                        1, d, bind_seat);
+
+       cl = client_create(d, post_error_main3);
+       cl2 = client_create(d, post_error_main3);
+
+       display_run(d);
+
+       /* Try to send the error to both clients */
+       assert(cl->data && cl2->data);
+       wl_resource_post_error((struct wl_resource *) cl->data,
+                              23, "Dummy error");
+       wl_resource_post_error((struct wl_resource *) cl->data,
+                              21, "Dummy error (ignore)");
+
+       wl_resource_post_error((struct wl_resource *) cl2->data,
+                              23, "Dummy error");
+       wl_resource_post_error((struct wl_resource *) cl2->data,
+                              21, "Dummy error (ignore)");
+
+       display_resume(d);
+       display_destroy(d);
+}
+
+static void
+post_nomem_main(void)
+{
+       struct client *c = client_connect();
+       struct wl_seat *seat = client_get_seat(c);
+
+       assert(stop_display(c, 1) == -1);
+       assert(wl_display_get_error(c->wl_display) == ENOMEM);
+
+       wl_proxy_destroy((struct wl_proxy *) seat);
+       client_disconnect_nocheck(c);
+}
+
+TEST(post_nomem_tst)
+{
+       struct display *d = display_create();
+       struct client_info *cl;
+
+       wl_global_create(d->wl_display, &wl_seat_interface,
+                        1, d, bind_seat);
+
+       cl = client_create(d, post_nomem_main);
+       display_run(d);
+
+       assert(cl->data);
+       wl_resource_post_no_memory((struct wl_resource *) cl->data);
+       display_resume(d);
+
+       /* first client terminated. Run it again,
+        * but post no memory to client */
+       cl = client_create(d, post_nomem_main);
+       display_run(d);
+
+       assert(cl->data);
+       wl_client_post_no_memory(cl->wl_client);
+       display_resume(d);
+
+       display_destroy(d);
+}
+
+static void
+register_reading(struct wl_display *display)
+{
+       while(wl_display_prepare_read(display) != 0 && errno == EAGAIN)
+               assert(wl_display_dispatch_pending(display) >= 0);
+       assert(wl_display_flush(display) >= 0);
+}
+
+/* create thread that will call prepare+read so that
+ * it will block */
+static pthread_t
+create_thread(struct client *c, void *(*func)(void*))
+{
+       pthread_t thread;
+
+       c->display_stopped = 0;
+       /* func must set display->stopped to 1 before sleeping */
+       assert(pthread_create(&thread, NULL, func, c) == 0);
+
+       /* make sure the thread is sleeping. It's a little bit racy
+        * (setting display_stopped to 1 and calling wl_display_read_events)
+        * so call usleep once again after the loop ends - it should
+        * be sufficient... */
+       while (c->display_stopped == 0)
+               test_usleep(500);
+       test_usleep(10000);
+
+       return thread;
+}
+
+static void *
+thread_read_error(void *data)
+{
+       struct client *c = data;
+
+       register_reading(c->wl_display);
+
+       /*
+        * Calling the read right now will block this thread
+        * until the other thread will read the data.
+        * However, after invoking an error, this
+        * thread should be woken up or it will block indefinitely.
+        */
+       c->display_stopped = 1;
+       assert(wl_display_read_events(c->wl_display) == -1);
+
+       assert(wl_display_dispatch_pending(c->wl_display) == -1);
+       assert(wl_display_get_error(c->wl_display));
+
+       pthread_exit(NULL);
+}
+
+/* test posting an error in multi-threaded environment. */
+static void
+threading_post_err(void)
+{
+       DISABLE_LEAK_CHECKS;
+
+       struct client *c = client_connect();
+       pthread_t thread;
+
+       /* register read intention */
+       register_reading(c->wl_display);
+
+       /* use this var as an indicator that thread is sleeping */
+       c->display_stopped = 0;
+
+       /* create new thread that will register its intention too */
+       thread = create_thread(c, thread_read_error);
+
+       /* so now we have sleeping thread waiting for a pthread_cond signal.
+        * The main thread must call wl_display_read_events().
+        * If this call fails, then it won't call broadcast at the
+        * end of the function and the sleeping thread will block indefinitely.
+        * Make the call fail and watch if libwayland will unblock the thread! */
+
+       /* create error on fd, so that wl_display_read_events will fail.
+        * The same can happen when server hangs up */
+       close(wl_display_get_fd(c->wl_display));
+       /* this read events will fail and will
+        * post an error that should wake the sleeping thread
+        * and dispatch the incoming events */
+       assert(wl_display_read_events(c->wl_display) == -1);
+
+       /* kill test in 3 seconds. This should be enough time for the
+        * thread to exit if it's not blocking. If everything is OK, than
+        * the thread was woken up and the test will end before the SIGALRM */
+       test_set_timeout(3);
+       pthread_join(thread, NULL);
+
+       client_disconnect_nocheck(c);
+}
+
+TEST(threading_errors_tst)
+{
+       struct display *d = display_create();
+
+       client_create(d, threading_post_err);
+       display_run(d);
+
+       display_destroy(d);
+}
+
+static void *
+thread_prepare_and_read(void *data)
+{
+       struct client *c = data;
+
+       register_reading(c->wl_display);
+
+       c->display_stopped = 1;
+
+       assert(wl_display_read_events(c->wl_display) == 0);
+       assert(wl_display_dispatch_pending(c->wl_display) == 0);
+
+       pthread_exit(NULL);
+}
+
+/* test cancel read*/
+static void
+threading_cancel_read(void)
+{
+       DISABLE_LEAK_CHECKS;
+
+       struct client *c = client_connect();
+       pthread_t th1, th2, th3;
+
+       register_reading(c->wl_display);
+
+       th1 = create_thread(c, thread_prepare_and_read);
+       th2 = create_thread(c, thread_prepare_and_read);
+       th3 = create_thread(c, thread_prepare_and_read);
+
+       /* all the threads are sleeping, waiting until read or cancel
+        * is called. Cancel the read and let the threads proceed */
+       wl_display_cancel_read(c->wl_display);
+
+       /* kill test in 3 seconds. This should be enough time for the
+        * thread to exit if it's not blocking. If everything is OK, than
+        * the thread was woken up and the test will end before the SIGALRM */
+       test_set_timeout(3);
+       pthread_join(th1, NULL);
+       pthread_join(th2, NULL);
+       pthread_join(th3, NULL);
+
+       client_disconnect(c);
+}
+
+TEST(threading_cancel_read_tst)
+{
+       struct display *d = display_create();
+
+       client_create(d, threading_cancel_read);
+       display_run(d);
+
+       display_destroy(d);
+}
+
+static void
+threading_read_eagain(void)
+{
+       DISABLE_LEAK_CHECKS;
+
+       struct client *c = client_connect();
+       pthread_t th1, th2, th3;
+
+       register_reading(c->wl_display);
+
+       th1 = create_thread(c, thread_prepare_and_read);
+       th2 = create_thread(c, thread_prepare_and_read);
+       th3 = create_thread(c, thread_prepare_and_read);
+
+       /* All the threads are sleeping, waiting until read or cancel
+        * is called. Since we have no data on socket waiting,
+        * the wl_connection_read should end up with error and set errno
+        * to EAGAIN. Check if the threads are woken up in this case. */
+       assert(wl_display_read_events(c->wl_display) == 0);
+       /* errno should be still set to EAGAIN if wl_connection_read
+        * set it - check if we're testing the right case */
+       assert(errno == EAGAIN);
+
+       test_set_timeout(3);
+       pthread_join(th1, NULL);
+       pthread_join(th2, NULL);
+       pthread_join(th3, NULL);
+
+       client_disconnect(c);
+}
+
+TEST(threading_read_eagain_tst)
+{
+       struct display *d = display_create();
+       client_create(d, threading_read_eagain);
+
+       display_run(d);
+
+       display_destroy(d);
+}
+
+static void *
+thread_prepare_and_read2(void *data)
+{
+       struct client *c = data;
+
+       while(wl_display_prepare_read(c->wl_display) != 0 && errno == EAGAIN)
+               assert(wl_display_dispatch_pending(c->wl_display) == -1);
+       assert(wl_display_flush(c->wl_display) == -1);
+
+       c->display_stopped = 1;
+
+       assert(wl_display_read_events(c->wl_display) == -1);
+       assert(wl_display_dispatch_pending(c->wl_display) == -1);
+
+       pthread_exit(NULL);
+}
+
+static void
+threading_read_after_error(void)
+{
+       DISABLE_LEAK_CHECKS;
+
+       struct client *c = client_connect();
+       pthread_t thread;
+
+       /* create an error */
+       close(wl_display_get_fd(c->wl_display));
+       assert(wl_display_dispatch(c->wl_display) == -1);
+
+       /* try to prepare for reading */
+       while(wl_display_prepare_read(c->wl_display) != 0 && errno == EAGAIN)
+               assert(wl_display_dispatch_pending(c->wl_display) == -1);
+       assert(wl_display_flush(c->wl_display) == -1);
+
+       assert(pthread_create(&thread, NULL,
+                             thread_prepare_and_read2, c) == 0);
+
+       /* make sure thread is sleeping */
+       while (c->display_stopped == 0)
+               test_usleep(500);
+       test_usleep(10000);
+
+       assert(wl_display_read_events(c->wl_display) == -1);
+
+       /* kill test in 3 seconds */
+       test_set_timeout(3);
+       pthread_join(thread, NULL);
+
+       client_disconnect_nocheck(c);
+}
+
+TEST(threading_read_after_error_tst)
+{
+       struct display *d = display_create();
+
+       client_create(d, threading_read_after_error);
+       display_run(d);
+
+       display_destroy(d);
+}
diff --git a/tests/event-loop-test.c b/tests/event-loop-test.c
new file mode 100644 (file)
index 0000000..1a45db1
--- /dev/null
@@ -0,0 +1,382 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ * Copyright © 2012 Jason Ekstrand
+ *
+ * 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 <assert.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/time.h>
+
+#include "wayland-private.h"
+#include "wayland-server.h"
+#include "test-runner.h"
+
+static int
+fd_dispatch(int fd, uint32_t mask, void *data)
+{
+       int *p = data;
+
+       assert(mask == 0);
+       ++(*p);
+
+       return 0;
+}
+
+TEST(event_loop_post_dispatch_check)
+{
+       struct wl_event_loop *loop = wl_event_loop_create();
+       struct wl_event_source *source;
+       int dispatch_ran = 0;
+       int p[2];
+
+       assert(loop);
+       assert(pipe(p) == 0);
+
+       source = wl_event_loop_add_fd(loop, p[0], WL_EVENT_READABLE,
+                                     fd_dispatch, &dispatch_ran);
+       assert(source);
+       wl_event_source_check(source);
+
+       wl_event_loop_dispatch(loop, 0);
+       assert(dispatch_ran == 1);
+
+       assert(close(p[0]) == 0);
+       assert(close(p[1]) == 0);
+       wl_event_source_remove(source);
+       wl_event_loop_destroy(loop);
+}
+
+struct free_source_context {
+       struct wl_event_source *source1, *source2;
+       int p1[2], p2[2];
+       int count;
+};
+
+static int
+free_source_callback(int fd, uint32_t mask, void *data)
+{
+       struct free_source_context *context = data;
+
+       context->count++;
+
+       /* Remove other source */
+       if (fd == context->p1[0]) {
+               wl_event_source_remove(context->source2);
+               context->source2 = NULL;
+       } else if (fd == context->p2[0]) {
+               wl_event_source_remove(context->source1);
+               context->source1 = NULL;
+       } else {
+               assert(0);
+       }
+
+       return 1;
+}
+
+TEST(event_loop_free_source_with_data)
+{
+       struct wl_event_loop *loop = wl_event_loop_create();
+       struct free_source_context context;
+       int data;
+
+       /* This test is a little tricky to get right, since we don't
+        * have any guarantee from the event loop (ie epoll) on the
+        * order of which it reports events.  We want to have one
+        * source free the other, but we don't know which one is going
+        * to run first.  So we add two fd sources with a callback
+        * that frees the other source and check that only one of them
+        * run (and that we don't crash, of course).
+        */
+
+       assert(loop);
+
+       context.count = 0;
+       assert(pipe(context.p1) == 0);
+       assert(pipe(context.p2) == 0);
+       context.source1 =
+               wl_event_loop_add_fd(loop, context.p1[0], WL_EVENT_READABLE,
+                                    free_source_callback, &context);
+       assert(context.source1);
+       context.source2 =
+               wl_event_loop_add_fd(loop, context.p2[0], WL_EVENT_READABLE,
+                                    free_source_callback, &context);
+       assert(context.source2);
+
+       data = 5;
+       assert(write(context.p1[1], &data, sizeof data) == sizeof data);
+       assert(write(context.p2[1], &data, sizeof data) == sizeof data);
+
+       wl_event_loop_dispatch(loop, 0);
+
+       assert(context.count == 1);
+
+       if (context.source1)
+               wl_event_source_remove(context.source1);
+       if (context.source2)
+               wl_event_source_remove(context.source2);
+       wl_event_loop_destroy(loop);
+
+       assert(close(context.p1[0]) == 0);
+       assert(close(context.p1[1]) == 0);
+       assert(close(context.p2[0]) == 0);
+       assert(close(context.p2[1]) == 0);
+}
+
+static int
+signal_callback(int signal_number, void *data)
+{
+       int *got_it = data;
+
+       assert(signal_number == SIGUSR1);
+       ++(*got_it);
+
+       return 1;
+}
+
+TEST(event_loop_signal)
+{
+       struct wl_event_loop *loop = wl_event_loop_create();
+       struct wl_event_source *source;
+       int got_it = 0;
+
+       source = wl_event_loop_add_signal(loop, SIGUSR1,
+                                         signal_callback, &got_it);
+       assert(source);
+
+       wl_event_loop_dispatch(loop, 0);
+       assert(!got_it);
+       kill(getpid(), SIGUSR1);
+       wl_event_loop_dispatch(loop, 0);
+       assert(got_it == 1);
+
+       wl_event_source_remove(source);
+       wl_event_loop_destroy(loop);
+}
+
+TEST(event_loop_multiple_same_signals)
+{
+       struct wl_event_loop *loop = wl_event_loop_create();
+       struct wl_event_source *s1, *s2;
+       int calls_no = 0;
+       int i;
+
+       s1 = wl_event_loop_add_signal(loop, SIGUSR1,
+                                     signal_callback, &calls_no);
+       assert(s1);
+
+       s2 = wl_event_loop_add_signal(loop, SIGUSR1,
+                                     signal_callback, &calls_no);
+       assert(s2);
+
+       assert(wl_event_loop_dispatch(loop, 0) == 0);
+       assert(!calls_no);
+
+       /* Try it more times */
+       for (i = 0; i < 5; ++i) {
+               calls_no = 0;
+               kill(getpid(), SIGUSR1);
+               assert(wl_event_loop_dispatch(loop, 0) == 0);
+               assert(calls_no == 2);
+       }
+
+       wl_event_source_remove(s1);
+
+       /* Try it again  with one source */
+       calls_no = 0;
+       kill(getpid(), SIGUSR1);
+       assert(wl_event_loop_dispatch(loop, 0) == 0);
+       assert(calls_no == 1);
+
+       wl_event_source_remove(s2);
+
+       wl_event_loop_destroy(loop);
+}
+
+static int
+timer_callback(void *data)
+{
+       int *got_it = data;
+
+       ++(*got_it);
+
+       return 1;
+}
+
+TEST(event_loop_timer)
+{
+       struct wl_event_loop *loop = wl_event_loop_create();
+       struct wl_event_source *source;
+       int got_it = 0;
+
+       source = wl_event_loop_add_timer(loop, timer_callback, &got_it);
+       assert(source);
+       wl_event_source_timer_update(source, 10);
+       wl_event_loop_dispatch(loop, 0);
+       assert(!got_it);
+       wl_event_loop_dispatch(loop, 20);
+       assert(got_it == 1);
+
+       wl_event_source_remove(source);
+       wl_event_loop_destroy(loop);
+}
+
+#define MSEC_TO_USEC(msec) ((msec) * 1000)
+
+struct timer_update_context {
+       struct wl_event_source *source1, *source2;
+       int count;
+};
+
+static int
+timer_update_callback_1(void *data)
+{
+       struct timer_update_context *context = data;
+
+       context->count++;
+       wl_event_source_timer_update(context->source2, 1000);
+       return 1;
+}
+
+static int
+timer_update_callback_2(void *data)
+{
+       struct timer_update_context *context = data;
+
+       context->count++;
+       wl_event_source_timer_update(context->source1, 1000);
+       return 1;
+}
+
+TEST(event_loop_timer_updates)
+{
+       struct wl_event_loop *loop = wl_event_loop_create();
+       struct timer_update_context context;
+       struct timeval start_time, end_time, interval;
+
+       /* Create two timers that should expire at the same time (after 10ms).
+        * The first timer to receive its expiry callback updates the other timer
+        * with a much larger timeout (1s). This highlights a bug where
+        * wl_event_source_timer_dispatch would block for this larger timeout
+        * when reading from the timer fd, before calling the second timer's
+        * callback.
+        */
+
+       context.source1 = wl_event_loop_add_timer(loop, timer_update_callback_1,
+                                                 &context);
+       assert(context.source1);
+       assert(wl_event_source_timer_update(context.source1, 10) == 0);
+
+       context.source2 = wl_event_loop_add_timer(loop, timer_update_callback_2,
+                                                 &context);
+       assert(context.source2);
+       assert(wl_event_source_timer_update(context.source2, 10) == 0);
+
+       context.count = 0;
+
+       /* Since calling the functions between source2's update and
+        * wl_event_loop_dispatch() takes some time, it may happen
+        * that only one timer expires until we call epoll_wait.
+        * This naturally means that only one source is dispatched
+        * and the test fails. To fix that, sleep 15 ms before
+        * calling wl_event_loop_dispatch(). That should be enough
+        * for the second timer to expire.
+        *
+        * https://bugs.freedesktop.org/show_bug.cgi?id=80594
+        */
+       usleep(MSEC_TO_USEC(15));
+
+       gettimeofday(&start_time, NULL);
+       wl_event_loop_dispatch(loop, 20);
+       gettimeofday(&end_time, NULL);
+
+       assert(context.count == 2);
+
+       /* Dispatching the events should not have taken much more than 20ms,
+        * since this is the timeout passed to wl_event_loop_dispatch. If it
+        * blocked, then it will have taken over 1s.
+        * Of course, it could take over 1s anyway on a very slow or heavily
+        * loaded system, so this test isn't 100% perfect.
+        */
+
+       timersub(&end_time, &start_time, &interval);
+       assert(interval.tv_sec < 1);
+
+       wl_event_source_remove(context.source1);
+       wl_event_source_remove(context.source2);
+       wl_event_loop_destroy(loop);
+}
+
+struct event_loop_destroy_listener {
+       struct wl_listener listener;
+       int done;
+};
+
+static void
+event_loop_destroy_notify(struct wl_listener *l, void *data)
+{
+       struct event_loop_destroy_listener *listener =
+               container_of(l, struct event_loop_destroy_listener, listener);
+
+       listener->done = 1;
+}
+
+TEST(event_loop_destroy)
+{
+       struct wl_event_loop *loop;
+       struct wl_display * display;
+       struct event_loop_destroy_listener a, b;
+
+       loop = wl_event_loop_create();
+       assert(loop);
+
+       a.listener.notify = &event_loop_destroy_notify;
+       a.done = 0;
+       wl_event_loop_add_destroy_listener(loop, &a.listener);
+
+       assert(wl_event_loop_get_destroy_listener(loop,
+              event_loop_destroy_notify) == &a.listener);
+
+       b.listener.notify = &event_loop_destroy_notify;
+       b.done = 0;
+       wl_event_loop_add_destroy_listener(loop, &b.listener);
+
+       wl_list_remove(&a.listener.link);
+       wl_event_loop_destroy(loop);
+
+       assert(!a.done);
+       assert(b.done);
+
+       /* Test to make sure it gets fired on display destruction */
+       display = wl_display_create();
+       assert(display);
+       loop = wl_display_get_event_loop(display);
+       assert(loop);
+
+       a.done = 0;
+       wl_event_loop_add_destroy_listener(loop, &a.listener);
+
+       wl_display_destroy(display);
+
+       assert(a.done);
+}
+
diff --git a/tests/exec-fd-leak-checker.c b/tests/exec-fd-leak-checker.c
new file mode 100644 (file)
index 0000000..66209ad
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * 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 <stdio.h>
+#include <errno.h>
+#include <limits.h>
+
+#include "test-runner.h"
+
+static int
+parse_count(const char *str, int *value)
+{
+       char *end;
+       long v;
+
+       errno = 0;
+       v = strtol(str, &end, 0);
+       if ((errno == ERANGE && (v == LONG_MAX || v == LONG_MIN)) ||
+           (errno != 0 && v == 0) ||
+           (end == str) ||
+           (*end != '\0')) {
+               return -1;
+       }
+
+       if (v < 0 || v > INT_MAX) {
+               return -1;
+       }
+
+       *value = v;
+       return 0;
+}
+
+int main(int argc, char *argv[])
+{
+       int expected;
+
+       if (argc != 2)
+               goto help_out;
+
+       if (parse_count(argv[1], &expected) < 0)
+               goto help_out;
+
+       if (count_open_fds() == expected)
+               return EXIT_SUCCESS;
+       else
+               return EXIT_FAILURE;
+
+help_out:
+       fprintf(stderr, "Usage: %s N\n"
+               "where N is the expected number of open file descriptors.\n"
+               "This program exits with a failure if the number "
+               "does not match exactly.\n", argv[0]);
+
+       return EXIT_FAILURE;
+}
diff --git a/tests/fixed-benchmark.c b/tests/fixed-benchmark.c
new file mode 100644 (file)
index 0000000..0719063
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <assert.h>
+#include "wayland-private.h"
+
+volatile double global_d;
+
+static void
+noop_conversion(void)
+{
+       wl_fixed_t f;
+       union {
+               int64_t i;
+               double d;
+       } u;
+
+       for (f = 0; f < INT32_MAX; f++) {
+               u.i = f;
+               global_d = u.d;
+       }
+}
+
+static void
+magic_conversion(void)
+{
+       wl_fixed_t f;
+
+       for (f = 0; f < INT32_MAX; f++)
+               global_d = wl_fixed_to_double(f);
+}
+
+static void
+mul_conversion(void)
+{
+       wl_fixed_t f;
+
+       /* This will get optimized into multiplication by 1/256 */
+       for (f = 0; f < INT32_MAX; f++)
+               global_d = f / 256.0;
+}
+
+double factor = 256.0;
+
+static void
+div_conversion(void)
+{
+       wl_fixed_t f;
+
+       for (f = 0; f < INT32_MAX; f++)
+               global_d = f / factor;
+}
+
+static void
+benchmark(const char *s, void (*f)(void))
+{
+       struct timespec start, stop, elapsed;
+
+       clock_gettime(CLOCK_MONOTONIC, &start);
+       f();
+       clock_gettime(CLOCK_MONOTONIC, &stop);
+
+       elapsed.tv_sec = stop.tv_sec - start.tv_sec;
+       elapsed.tv_nsec = stop.tv_nsec - start.tv_nsec;
+       if (elapsed.tv_nsec < 0) {
+               elapsed.tv_nsec += 1000000000;
+               elapsed.tv_sec--;
+       }
+       printf("benchmarked %s:\t%ld.%09lds\n",
+              s, elapsed.tv_sec, elapsed.tv_nsec);
+}
+
+int main(int argc, char *argv[])
+{
+       benchmark("noop", noop_conversion);
+       benchmark("magic", magic_conversion);
+       benchmark("div", div_conversion);
+       benchmark("mul", mul_conversion);
+
+       return 0;
+}
diff --git a/tests/fixed-test.c b/tests/fixed-test.c
new file mode 100644 (file)
index 0000000..739a3b1
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * 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 <stdio.h>
+#include <assert.h>
+#include "wayland-private.h"
+#include "test-runner.h"
+
+TEST(fixed_double_conversions)
+{
+       wl_fixed_t f;
+       double d;
+
+       d = 62.125;
+       f = wl_fixed_from_double(d);
+       fprintf(stderr, "double %lf to fixed %x\n", d, f);
+       assert(f == 0x3e20);
+
+       d = -1200.625;
+       f = wl_fixed_from_double(d);
+       fprintf(stderr, "double %lf to fixed %x\n", d, f);
+       assert(f == -0x4b0a0);
+
+       f = random();
+       d = wl_fixed_to_double(f);
+       fprintf(stderr, "fixed %x to double %lf\n", f, d);
+       assert(d == f / 256.0);
+
+       f = 0x012030;
+       d = wl_fixed_to_double(f);
+       fprintf(stderr, "fixed %x to double %lf\n", f, d);
+       assert(d == 288.1875);
+
+       f = 0x70000000;
+       d = wl_fixed_to_double(f);
+       fprintf(stderr, "fixed %x to double %lf\n", f, d);
+       assert(d == f / 256);
+
+       f = -0x012030;
+       d = wl_fixed_to_double(f);
+       fprintf(stderr, "fixed %x to double %lf\n", f, d);
+       assert(d == -288.1875);
+
+       f = 0x80000000;
+       d = wl_fixed_to_double(f);
+       fprintf(stderr, "fixed %x to double %lf\n", f, d);
+       assert(d == f / 256);
+}
+
+TEST(fixed_int_conversions)
+{
+       wl_fixed_t f;
+       int i;
+
+       i = 62;
+       f = wl_fixed_from_int(i);
+       assert(f == 62 * 256);
+
+       i = -2080;
+       f = wl_fixed_from_int(i);
+       assert(f == -2080 * 256);
+
+       f = 0x277013;
+       i = wl_fixed_to_int(f);
+       assert(i == 0x2770);
+
+       f = -0x5044;
+       i = wl_fixed_to_int(f);
+       assert(i == -0x50);
+}
diff --git a/tests/list-test.c b/tests/list-test.c
new file mode 100644 (file)
index 0000000..6058fe3
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "wayland-private.h"
+#include "test-runner.h"
+
+TEST(list_init)
+{
+       struct wl_list list;
+
+       wl_list_init(&list);
+       assert(list.next == &list);
+       assert(list.prev == &list);
+       assert(wl_list_empty(&list));
+}
+
+struct element {
+       int i;
+       struct wl_list link;
+};
+
+TEST(list_insert)
+{
+       struct wl_list list;
+       struct element e;
+
+       wl_list_init(&list);
+       wl_list_insert(&list, &e.link);
+       assert(list.next == &e.link);
+       assert(list.prev == &e.link);
+       assert(e.link.next == &list);
+       assert(e.link.prev == &list);
+}
+
+TEST(list_iterator)
+{
+       struct wl_list list;
+       struct element e1, e2, e3, e4, *e;
+       int reference[] = { 708090, 102030, 5588, 12 };
+       unsigned int i;
+
+       e1.i = 708090;
+       e2.i = 102030;
+       e3.i = 5588;
+       e4.i = 12;
+
+       wl_list_init(&list);
+       wl_list_insert(list.prev, &e1.link);
+       wl_list_insert(list.prev, &e2.link);
+       wl_list_insert(list.prev, &e3.link);
+       wl_list_insert(list.prev, &e4.link);
+
+       i = 0;
+       wl_list_for_each(e, &list, link) {
+               assert(i < ARRAY_LENGTH(reference));
+               assert(e->i == reference[i]);
+               i++;
+       }
+       assert(i == ARRAY_LENGTH(reference));
+
+       i = 0;
+       wl_list_for_each_reverse(e, &list, link) {
+               assert(i < ARRAY_LENGTH(reference));
+               assert(e->i == reference[ARRAY_LENGTH(reference) - i - 1]);
+               i++;
+       }
+       assert(i == ARRAY_LENGTH(reference));
+}
+
+static int
+validate_list(struct wl_list *list, int *reference, int length)
+{
+       struct element *e;
+       int i;
+
+       i = 0;
+       wl_list_for_each(e, list, link) {
+               if (i >= length)
+                       return 0;
+               if (e->i != reference[i])
+                       return 0;
+               i++;
+       }
+               
+       if (i != length)
+               return 0;
+
+       return 1;
+}
+
+TEST(list_remove)
+{
+       struct wl_list list;
+       struct element e1, e2, e3;
+       int reference1[] = { 17, 8888, 1000 }, reference2[] = { 17, 1000 };
+
+       e1.i = 17;
+       e2.i = 8888;
+       e3.i = 1000;
+
+       wl_list_init(&list);
+       wl_list_insert(&list, &e1.link);
+       wl_list_insert(list.prev, &e2.link);
+       wl_list_insert(list.prev, &e3.link);
+       assert(validate_list(&list, reference1, ARRAY_LENGTH(reference1)));
+
+       wl_list_remove(&e2.link);
+       assert(validate_list(&list, reference2, ARRAY_LENGTH(reference2)));
+}
+
+TEST(list_insert_list)
+{
+       struct wl_list list, other;
+       struct element e1, e2, e3, e4, e5, e6;
+       int reference1[] = { 17, 8888, 1000 };
+       int reference2[] = { 76543, 1, -500 };
+       int reference3[] = { 17, 76543, 1, -500, 8888, 1000 };
+
+       e1.i = 17;
+       e2.i = 8888;
+       e3.i = 1000;
+
+       wl_list_init(&list);
+       wl_list_insert(&list, &e1.link);
+       wl_list_insert(list.prev, &e2.link);
+       wl_list_insert(list.prev, &e3.link);
+       assert(validate_list(&list, reference1, ARRAY_LENGTH(reference1)));
+
+       e4.i = 76543;
+       e5.i = 1;
+       e6.i = -500;
+
+       wl_list_init(&other);
+       wl_list_insert(&other, &e4.link);
+       wl_list_insert(other.prev, &e5.link);
+       wl_list_insert(other.prev, &e6.link);
+       assert(validate_list(&other, reference2, ARRAY_LENGTH(reference2)));
+
+       wl_list_insert_list(list.next, &other);
+       assert(validate_list(&list, reference3, ARRAY_LENGTH(reference3)));
+}
diff --git a/tests/map-test.c b/tests/map-test.c
new file mode 100644 (file)
index 0000000..3df374c
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "wayland-private.h"
+#include "test-runner.h"
+
+TEST(map_insert_new)
+{
+       struct wl_map map;
+       uint32_t i, j, k, a, b, c;
+
+       wl_map_init(&map, WL_MAP_SERVER_SIDE);
+       i = wl_map_insert_new(&map, 0, &a);
+       j = wl_map_insert_new(&map, 0, &b);
+       k = wl_map_insert_new(&map, 0, &c);
+       assert(i == WL_SERVER_ID_START);
+       assert(j == WL_SERVER_ID_START + 1);
+       assert(k == WL_SERVER_ID_START + 2);
+
+       assert(wl_map_lookup(&map, i) == &a);
+       assert(wl_map_lookup(&map, j) == &b);
+       assert(wl_map_lookup(&map, k) == &c);
+    wl_map_release(&map);
+
+       wl_map_init(&map, WL_MAP_CLIENT_SIDE);
+       i = wl_map_insert_new(&map, 0, &a);
+       assert(i == 0);
+       assert(wl_map_lookup(&map, i) == &a);
+
+       wl_map_release(&map);
+}
+
+TEST(map_insert_at)
+{
+       struct wl_map map;
+       uint32_t a, b, c;
+
+       wl_map_init(&map, WL_MAP_CLIENT_SIDE);
+       assert(wl_map_insert_at(&map, 0, WL_SERVER_ID_START, &a) == 0);
+       assert(wl_map_insert_at(&map, 0, WL_SERVER_ID_START + 3, &b) == -1);
+       assert(wl_map_insert_at(&map, 0, WL_SERVER_ID_START + 1, &c) == 0);
+
+       assert(wl_map_lookup(&map, WL_SERVER_ID_START) == &a);
+       assert(wl_map_lookup(&map, WL_SERVER_ID_START + 1) == &c);
+
+       wl_map_release(&map);
+}
+
+TEST(map_remove)
+{
+       struct wl_map map;
+       uint32_t i, j, k, l, a, b, c, d;
+
+       wl_map_init(&map, WL_MAP_SERVER_SIDE);
+       i = wl_map_insert_new(&map, 0, &a);
+       j = wl_map_insert_new(&map, 0, &b);
+       k = wl_map_insert_new(&map, 0, &c);
+       assert(i == WL_SERVER_ID_START);
+       assert(j == WL_SERVER_ID_START + 1);
+       assert(k == WL_SERVER_ID_START + 2);
+
+       assert(wl_map_lookup(&map, i) == &a);
+       assert(wl_map_lookup(&map, j) == &b);
+       assert(wl_map_lookup(&map, k) == &c);
+
+       wl_map_remove(&map, j);
+       assert(wl_map_lookup(&map, j) == NULL);
+
+       /* Verify that we insert d at the hole left by removing b */
+       l = wl_map_insert_new(&map, 0, &d);
+       assert(l == WL_SERVER_ID_START + 1);
+       assert(wl_map_lookup(&map, l) == &d);
+
+       wl_map_release(&map);
+}
+
+TEST(map_flags)
+{
+       struct wl_map map;
+       uint32_t i, j, a, b;
+
+       wl_map_init(&map, WL_MAP_SERVER_SIDE);
+       i = wl_map_insert_new(&map, 0, &a);
+       j = wl_map_insert_new(&map, 1, &b);
+       assert(i == WL_SERVER_ID_START);
+       assert(j == WL_SERVER_ID_START + 1);
+
+       assert(wl_map_lookup(&map, i) == &a);
+       assert(wl_map_lookup(&map, j) == &b);
+
+    assert(wl_map_lookup_flags(&map, i) == 0);
+    assert(wl_map_lookup_flags(&map, j) == 1);
+
+       wl_map_release(&map);
+}
diff --git a/tests/message-test.c b/tests/message-test.c
new file mode 100644 (file)
index 0000000..b5b00a4
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2014 Jonas Ådahl
+ *
+ * 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 <assert.h>
+
+#include "wayland-client.h"
+#include "wayland-private.h"
+#include "wayland-server.h"
+#include "test-runner.h"
+
+TEST(message_version)
+{
+       unsigned int i;
+       const struct {
+               const struct wl_message *message;
+               int expected_version;
+       } messages[] = {
+               { &wl_pointer_interface.events[WL_POINTER_ENTER], 1 },
+               { &wl_surface_interface.events[WL_SURFACE_ENTER], 1 },
+               { &wl_pointer_interface.methods[WL_POINTER_SET_CURSOR], 1 },
+               { &wl_pointer_interface.methods[WL_POINTER_RELEASE], 3 },
+               { &wl_surface_interface.methods[WL_SURFACE_DESTROY], 1 },
+               { &wl_surface_interface.methods[WL_SURFACE_SET_BUFFER_TRANSFORM], 2 },
+               { &wl_surface_interface.methods[WL_SURFACE_SET_BUFFER_SCALE], 3 },
+       };
+
+       for (i = 0; i < ARRAY_LENGTH(messages); ++i) {
+               assert(wl_message_get_since(messages[i].message) ==
+                      messages[i].expected_version);
+       }
+}
diff --git a/tests/os-wrappers-test.c b/tests/os-wrappers-test.c
new file mode 100644 (file)
index 0000000..e5cdac4
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ * Copyright © 2012 Intel Corporation
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/epoll.h>
+
+#include "wayland-private.h"
+#include "test-runner.h"
+#include "wayland-os.h"
+
+static int fall_back;
+
+static int (*real_socket)(int, int, int);
+static int wrapped_calls_socket;
+
+static int (*real_fcntl)(int, int, ...);
+static int wrapped_calls_fcntl;
+
+static ssize_t (*real_recvmsg)(int, struct msghdr *, int);
+static int wrapped_calls_recvmsg;
+
+static int (*real_epoll_create1)(int);
+static int wrapped_calls_epoll_create1;
+
+static void
+init_fallbacks(int do_fallbacks)
+{
+       fall_back = do_fallbacks;
+       real_socket = dlsym(RTLD_NEXT, "socket");
+       real_fcntl = dlsym(RTLD_NEXT, "fcntl");
+       real_recvmsg = dlsym(RTLD_NEXT, "recvmsg");
+       real_epoll_create1 = dlsym(RTLD_NEXT, "epoll_create1");
+}
+
+__attribute__ ((visibility("default"))) int
+socket(int domain, int type, int protocol)
+{
+       wrapped_calls_socket++;
+
+       if (fall_back && (type & SOCK_CLOEXEC)) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       return real_socket(domain, type, protocol);
+}
+
+__attribute__ ((visibility("default"))) int
+fcntl(int fd, int cmd, ...)
+{
+       va_list ap;
+       void *arg;
+
+       wrapped_calls_fcntl++;
+
+       if (fall_back && (cmd == F_DUPFD_CLOEXEC)) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       va_start(ap, cmd);
+       arg = va_arg(ap, void*);
+       va_end(ap);
+
+       return real_fcntl(fd, cmd, arg);
+}
+
+__attribute__ ((visibility("default"))) ssize_t
+recvmsg(int sockfd, struct msghdr *msg, int flags)
+{
+       wrapped_calls_recvmsg++;
+
+       if (fall_back && (flags & MSG_CMSG_CLOEXEC)) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       return real_recvmsg(sockfd, msg, flags);
+}
+
+__attribute__ ((visibility("default"))) int
+epoll_create1(int flags)
+{
+       wrapped_calls_epoll_create1++;
+
+       if (fall_back) {
+               wrapped_calls_epoll_create1++; /* epoll_create() not wrapped */
+               errno = EINVAL;
+               return -1;
+       }
+
+       return real_epoll_create1(flags);
+}
+
+static void
+do_os_wrappers_socket_cloexec(int n)
+{
+       int fd;
+       int nr_fds;
+
+       nr_fds = count_open_fds();
+
+       /* simply create a socket that closes on exec */
+       fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0);
+       assert(fd >= 0);
+
+       /*
+        * Must have 2 calls if falling back, but must also allow
+        * falling back without a forced fallback.
+        */
+       assert(wrapped_calls_socket > n);
+
+       exec_fd_leak_check(nr_fds);
+}
+
+TEST(os_wrappers_socket_cloexec)
+{
+       /* normal case */
+       init_fallbacks(0);
+       do_os_wrappers_socket_cloexec(0);
+}
+
+TEST(os_wrappers_socket_cloexec_fallback)
+{
+       /* forced fallback */
+       init_fallbacks(1);
+       do_os_wrappers_socket_cloexec(1);
+}
+
+static void
+do_os_wrappers_dupfd_cloexec(int n)
+{
+       int base_fd;
+       int fd;
+       int nr_fds;
+
+       nr_fds = count_open_fds();
+
+       base_fd = socket(PF_LOCAL, SOCK_STREAM, 0);
+       assert(base_fd >= 0);
+
+       fd = wl_os_dupfd_cloexec(base_fd, 13);
+       assert(fd >= 13);
+
+       close(base_fd);
+
+       /*
+        * Must have 4 calls if falling back, but must also allow
+        * falling back without a forced fallback.
+        */
+       assert(wrapped_calls_fcntl > n);
+
+       exec_fd_leak_check(nr_fds);
+}
+
+TEST(os_wrappers_dupfd_cloexec)
+{
+       init_fallbacks(0);
+       do_os_wrappers_dupfd_cloexec(0);
+}
+
+TEST(os_wrappers_dupfd_cloexec_fallback)
+{
+       init_fallbacks(1);
+       do_os_wrappers_dupfd_cloexec(3);
+}
+
+struct marshal_data {
+       struct wl_connection *read_connection;
+       struct wl_connection *write_connection;
+       int s[2];
+       uint32_t read_mask;
+       uint32_t write_mask;
+       union {
+               int h[3];
+       } value;
+       int nr_fds_begin;
+       int nr_fds_conn;
+       int wrapped_calls;
+};
+
+static void
+setup_marshal_data(struct marshal_data *data)
+{
+       assert(socketpair(AF_UNIX,
+                         SOCK_STREAM | SOCK_CLOEXEC, 0, data->s) == 0);
+
+       data->read_connection = wl_connection_create(data->s[0]);
+       assert(data->read_connection);
+
+       data->write_connection = wl_connection_create(data->s[1]);
+       assert(data->write_connection);
+}
+
+static void
+marshal_demarshal(struct marshal_data *data, 
+                 void (*func)(void), int size, const char *format, ...)
+{
+       struct wl_closure *closure;
+       static const int opcode = 4444;
+       static struct wl_object sender = { NULL, NULL, 1234 };
+       struct wl_message message = { "test", format, NULL };
+       struct wl_map objects;
+       struct wl_object object = { NULL, &func, 1234 };
+       va_list ap;
+       uint32_t msg[1] = { 1234 };
+
+       va_start(ap, format);
+       closure = wl_closure_vmarshal(&sender, opcode, ap, &message);
+       va_end(ap);
+
+       assert(closure);
+       assert(wl_closure_send(closure, data->write_connection) == 0);
+       wl_closure_destroy(closure);
+       assert(wl_connection_flush(data->write_connection) == size);
+
+       assert(wl_connection_read(data->read_connection) == size);
+
+       wl_map_init(&objects, WL_MAP_SERVER_SIDE);
+       object.id = msg[0];
+       closure = wl_connection_demarshal(data->read_connection,
+                                         size, &objects, &message);
+       assert(closure);
+       wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER, &object, 0, data);
+       wl_closure_destroy(closure);
+}
+
+static void
+validate_recvmsg_h(struct marshal_data *data,
+                  struct wl_object *object, int fd1, int fd2, int fd3)
+{
+       struct stat buf1, buf2;
+
+       assert(fd1 >= 0);
+       assert(fd2 >= 0);
+       assert(fd3 >= 0);
+
+       assert(fd1 != data->value.h[0]);
+       assert(fd2 != data->value.h[1]);
+       assert(fd3 != data->value.h[2]);
+
+       assert(fstat(fd3, &buf1) == 0);
+       assert(fstat(data->value.h[2], &buf2) == 0);
+       assert(buf1.st_dev == buf2.st_dev);
+       assert(buf1.st_ino == buf2.st_ino);
+
+       /* close the original file descriptors */
+       close(data->value.h[0]);
+       close(data->value.h[1]);
+       close(data->value.h[2]);
+
+       /* the dup'd (received) fds should still be open */
+       assert(count_open_fds() == data->nr_fds_conn + 3);
+
+       /*
+        * Must have 2 calls if falling back, but must also allow
+        * falling back without a forced fallback.
+        */
+       assert(wrapped_calls_recvmsg > data->wrapped_calls);
+
+       if (data->wrapped_calls == 0 && wrapped_calls_recvmsg > 1)
+               printf("recvmsg fell back unforced.\n");
+
+       /* all fds opened during the test in any way should be gone on exec */
+       exec_fd_leak_check(data->nr_fds_begin);
+}
+
+static void
+do_os_wrappers_recvmsg_cloexec(int n)
+{
+       struct marshal_data data;
+
+       data.nr_fds_begin = count_open_fds();
+       data.wrapped_calls = n;
+
+       setup_marshal_data(&data);
+       data.nr_fds_conn = count_open_fds();
+
+       assert(pipe(data.value.h) >= 0);
+
+       data.value.h[2] = open("/dev/zero", O_RDONLY);
+       assert(data.value.h[2] >= 0);
+
+       marshal_demarshal(&data, (void *) validate_recvmsg_h,
+                         8, "hhh", data.value.h[0], data.value.h[1],
+                         data.value.h[2]);
+}
+
+TEST(os_wrappers_recvmsg_cloexec)
+{
+       init_fallbacks(0);
+       do_os_wrappers_recvmsg_cloexec(0);
+}
+
+TEST(os_wrappers_recvmsg_cloexec_fallback)
+{
+       init_fallbacks(1);
+       do_os_wrappers_recvmsg_cloexec(1);
+}
+
+static void
+do_os_wrappers_epoll_create_cloexec(int n)
+{
+       int fd;
+       int nr_fds;
+
+       nr_fds = count_open_fds();
+
+       fd = wl_os_epoll_create_cloexec();
+       assert(fd >= 0);
+
+#ifdef EPOLL_CLOEXEC
+       assert(wrapped_calls_epoll_create1 == n);
+#else
+       printf("No epoll_create1.\n");
+#endif
+
+       exec_fd_leak_check(nr_fds);
+}
+
+TEST(os_wrappers_epoll_create_cloexec)
+{
+       init_fallbacks(0);
+       do_os_wrappers_epoll_create_cloexec(1);
+}
+
+TEST(os_wrappers_epoll_create_cloexec_fallback)
+{
+       init_fallbacks(1);
+       do_os_wrappers_epoll_create_cloexec(2);
+}
+
+/* FIXME: add tests for wl_os_accept_cloexec() */
diff --git a/tests/queue-test.c b/tests/queue-test.c
new file mode 100644 (file)
index 0000000..9eb913c
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * Copyright © 2012 Jonas Ådahl
+ *
+ * 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 <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <assert.h>
+
+#include "wayland-client.h"
+#include "wayland-server.h"
+#include "test-runner.h"
+#include "test-compositor.h"
+
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+
+static void
+registry_handle_global(void *data, struct wl_registry *registry,
+                      uint32_t id, const char *interface, uint32_t version)
+{
+       int *pcounter = data;
+       (*pcounter)++;
+       assert(*pcounter == 1);
+       wl_registry_destroy(registry);
+}
+
+static const struct wl_registry_listener registry_listener = {
+       registry_handle_global,
+       NULL
+};
+
+/* Test that destroying a proxy object doesn't result in any more
+ * callback being invoked, even though were many queued. */
+static void
+client_test_proxy_destroy(void)
+{
+       struct wl_display *display;
+       struct wl_registry *registry;
+       int counter = 0;
+
+       display = wl_display_connect(NULL);
+       assert(display);
+
+       registry = wl_display_get_registry(display);
+       assert(registry != NULL);
+       wl_registry_add_listener(registry, &registry_listener,
+                                &counter);
+       assert(wl_display_roundtrip(display) != -1);
+
+       assert(counter == 1);
+
+       /* don't destroy the registry, we have already destroyed them
+        * in the global handler */
+       wl_display_disconnect(display);
+}
+
+struct multiple_queues_state {
+       struct wl_display *display;
+       struct wl_callback* callback2;
+       bool done;
+};
+
+static void
+sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
+{
+       struct multiple_queues_state *state = data;
+
+       state->done = true;
+       wl_callback_destroy(callback);
+
+       wl_display_dispatch_pending(state->display);
+
+       wl_callback_destroy(state->callback2);
+}
+
+static const struct wl_callback_listener sync_listener = {
+       sync_callback
+};
+
+/* Test that when receiving the first of two synchronization
+ * callback events, destroying the second one doesn't cause any
+ * errors even if the delete_id event is handled out of order. */
+static void
+client_test_multiple_queues(void)
+{
+       struct wl_event_queue *queue;
+       struct wl_callback *callback1;
+       struct multiple_queues_state state;
+       int ret = 0;
+
+       state.display = wl_display_connect(NULL);
+       assert(state.display);
+
+       queue = wl_display_create_queue(state.display);
+       assert(queue);
+
+       state.done = false;
+       callback1 = wl_display_sync(state.display);
+       assert(callback1 != NULL);
+       wl_callback_add_listener(callback1, &sync_listener, &state);
+       wl_proxy_set_queue((struct wl_proxy *) callback1, queue);
+
+       state.callback2 = wl_display_sync(state.display);
+       assert(state.callback2 != NULL);
+       wl_callback_add_listener(state.callback2, &sync_listener, NULL);
+       wl_proxy_set_queue((struct wl_proxy *) state.callback2, queue);
+
+       wl_display_flush(state.display);
+
+       while (!state.done && !ret)
+               ret = wl_display_dispatch_queue(state.display, queue);
+
+       wl_event_queue_destroy(queue);
+       wl_display_disconnect(state.display);
+
+       exit(ret == -1 ? -1 : 0);
+}
+
+static void
+sync_callback_roundtrip(void *data, struct wl_callback *callback, uint32_t serial)
+{
+       bool *done = data;
+       *done = true;
+}
+
+static const struct wl_callback_listener sync_listener_roundtrip = {
+       sync_callback_roundtrip
+};
+
+/* Test that doing a roundtrip on a queue only the events on that
+ * queue get dispatched. */
+static void
+client_test_queue_roundtrip(void)
+{
+       struct wl_event_queue *queue;
+       struct wl_callback *callback1;
+       struct wl_callback *callback2;
+       struct wl_display *display;
+       bool done1 = false;
+       bool done2 = false;
+
+       display = wl_display_connect(NULL);
+       assert(display);
+
+       queue = wl_display_create_queue(display);
+       assert(queue);
+
+       /* arm a callback on the default queue */
+       callback1 = wl_display_sync(display);
+       assert(callback1 != NULL);
+       wl_callback_add_listener(callback1, &sync_listener_roundtrip, &done1);
+
+       /* arm a callback on the other queue */
+       callback2 = wl_display_sync(display);
+       assert(callback2 != NULL);
+       wl_callback_add_listener(callback2, &sync_listener_roundtrip, &done2);
+       wl_proxy_set_queue((struct wl_proxy *) callback2, queue);
+
+       /* roundtrip on default queue must not dispatch the other queue. */
+       wl_display_roundtrip(display);
+       assert(done1 == true);
+       assert(done2 == false);
+
+       /* re-arm the sync callback on the default queue, so we see that
+        * wl_display_roundtrip_queue() does not dispatch the default queue. */
+       wl_callback_destroy(callback1);
+       done1 = false;
+       callback1 = wl_display_sync(display);
+       assert(callback1 != NULL);
+       wl_callback_add_listener(callback1, &sync_listener_roundtrip, &done1);
+
+       wl_display_roundtrip_queue(display, queue);
+       assert(done1 == false);
+       assert(done2 == true);
+
+       wl_callback_destroy(callback1);
+       wl_callback_destroy(callback2);
+       wl_event_queue_destroy(queue);
+
+       wl_display_disconnect(display);
+}
+
+static void
+dummy_bind(struct wl_client *client,
+          void *data, uint32_t version, uint32_t id)
+{
+}
+
+TEST(queue_proxy_destroy)
+{
+       struct display *d;
+       const struct wl_interface *dummy_interfaces[] = {
+               &wl_seat_interface,
+               &wl_pointer_interface,
+               &wl_keyboard_interface,
+               &wl_surface_interface
+       };
+       unsigned int i;
+
+       d = display_create();
+
+       for (i = 0; i < ARRAY_LENGTH(dummy_interfaces); i++)
+               wl_global_create(d->wl_display, dummy_interfaces[i],
+                                dummy_interfaces[i]->version,
+                                NULL, dummy_bind);
+
+       test_set_timeout(2);
+
+       client_create(d, client_test_proxy_destroy);
+       display_run(d);
+
+       display_destroy(d);
+}
+
+TEST(queue_multiple_queues)
+{
+       struct display *d = display_create();
+
+       test_set_timeout(2);
+
+       client_create(d, client_test_multiple_queues);
+       display_run(d);
+
+       display_destroy(d);
+}
+
+TEST(queue_roundtrip)
+{
+       struct display *d = display_create();
+
+       test_set_timeout(2);
+
+       client_create(d, client_test_queue_roundtrip);
+       display_run(d);
+
+       display_destroy(d);
+}
diff --git a/tests/resources-test.c b/tests/resources-test.c
new file mode 100644 (file)
index 0000000..a6ce3ae
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright © 2013 Marek Chalupa
+ *
+ * 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 <assert.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "wayland-server.h"
+#include "test-runner.h"
+
+TEST(create_resource_tst)
+{
+       struct wl_display *display;
+       struct wl_client *client;
+       struct wl_resource *res;
+       struct wl_list *link;
+       int s[2];
+       uint32_t id;
+
+       assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0);
+       display = wl_display_create();
+       assert(display);
+       client = wl_client_create(display, s[0]);
+       assert(client);
+
+       res = wl_resource_create(client, &wl_display_interface, 4, 0);
+       assert(res);
+
+       /* setters/getters */
+       assert(wl_resource_get_version(res) == 4);
+
+       assert(client == wl_resource_get_client(res));
+       id = wl_resource_get_id(res);
+       assert(wl_client_get_object(client, id) == res);
+
+       link = wl_resource_get_link(res);
+       assert(link);
+       assert(wl_resource_from_link(link) == res);
+
+       wl_resource_set_user_data(res, (void *) 0xbee);
+       assert(wl_resource_get_user_data(res) == (void *) 0xbee);
+
+       wl_resource_destroy(res);
+       wl_client_destroy(client);
+       wl_display_destroy(display);
+       close(s[1]);
+}
+
+static void
+res_destroy_func(struct wl_resource *res)
+{
+       assert(res);
+
+       _Bool *destr = wl_resource_get_user_data(res);
+       *destr = 1;
+}
+
+static _Bool notify_called = 0;
+static void
+destroy_notify(struct wl_listener *l, void *data)
+{
+       assert(l && data);
+       notify_called = 1;
+}
+
+TEST(destroy_res_tst)
+{
+       struct wl_display *display;
+       struct wl_client *client;
+       struct wl_resource *res;
+       int s[2];
+       unsigned id;
+       struct wl_list *link;
+
+       _Bool destroyed = 0;
+       struct wl_listener destroy_listener = {
+               .notify = &destroy_notify
+       };
+
+       assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0);
+       display = wl_display_create();
+       assert(display);
+       client = wl_client_create(display, s[0]);
+       assert(client);
+
+       res = wl_resource_create(client, &wl_display_interface, 4, 0);
+       assert(res);
+       wl_resource_set_implementation(res, NULL, &destroyed, res_destroy_func);
+       wl_resource_add_destroy_listener(res, &destroy_listener);
+
+       id = wl_resource_get_id(res);
+       link = wl_resource_get_link(res);
+       assert(link);
+
+       wl_resource_destroy(res);
+       assert(destroyed);
+       assert(notify_called); /* check if signal was emitted */
+       assert(wl_client_get_object(client, id) == NULL);
+
+       res = wl_resource_create(client, &wl_display_interface, 2, 0);
+       assert(res);
+       destroyed = 0;
+       notify_called = 0;
+       wl_resource_set_destructor(res, res_destroy_func);
+       wl_resource_set_user_data(res, &destroyed);
+       wl_resource_add_destroy_listener(res, &destroy_listener);
+       /* client should destroy the resource upon its destruction */
+       wl_client_destroy(client);
+       assert(destroyed);
+       assert(notify_called);
+
+       wl_display_destroy(display);
+       close(s[1]);
+}
+
+TEST(create_resource_with_same_id)
+{
+       struct wl_display *display;
+       struct wl_client *client;
+       struct wl_resource *res, *res2;
+       int s[2];
+       uint32_t id;
+
+       assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0);
+       display = wl_display_create();
+       assert(display);
+       client = wl_client_create(display, s[0]);
+       assert(client);
+
+       res = wl_resource_create(client, &wl_display_interface, 2, 0);
+       assert(res);
+       id = wl_resource_get_id(res);
+       assert(wl_client_get_object(client, id) == res);
+
+       /* this one should replace the old one */
+       res2 = wl_resource_create(client, &wl_display_interface, 1, id);
+       assert(res2 != NULL);
+       assert(wl_client_get_object(client, id) == res2);
+
+       wl_resource_destroy(res2);
+       wl_resource_destroy(res);
+
+       wl_client_destroy(client);
+       wl_display_destroy(display);
+       close(s[1]);
+}
diff --git a/tests/sanity-test.c b/tests/sanity-test.c
new file mode 100644 (file)
index 0000000..b5a6fae
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * 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 <assert.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include "test-runner.h"
+#include "wayland-util.h"
+
+#define WL_HIDE_DEPRECATED
+#include "test-compositor.h"
+
+extern int leak_check_enabled;
+
+TEST(empty)
+{
+}
+
+TEST(exit_success)
+{
+       exit(EXIT_SUCCESS);
+}
+
+FAIL_TEST(exit_failure)
+{
+       exit(EXIT_FAILURE);
+}
+
+FAIL_TEST(fail_abort)
+{
+       abort();
+}
+
+FAIL_TEST(fail_kill)
+{
+       kill(getpid(), SIGTERM);
+}
+
+FAIL_TEST(fail_segv)
+{
+       * (char **) 0 = "Goodbye, world";
+}
+
+FAIL_TEST(sanity_assert)
+{
+       /* must fail */
+       assert(0);
+}
+
+FAIL_TEST(sanity_malloc_direct)
+{
+       void *p;
+
+       assert(leak_check_enabled);
+
+       p = malloc(10); /* memory leak */
+       assert(p);      /* assert that we got memory, also prevents
+                        * the malloc from getting optimized away. */
+       free(NULL);     /* NULL must not be counted */
+}
+
+TEST(disable_leak_checks)
+{
+       volatile void *mem;
+       assert(leak_check_enabled);
+       /* normally this should be on the beginning of the test.
+        * Here we need to be sure, that the leak checks are
+        * turned on */
+       DISABLE_LEAK_CHECKS;
+
+       mem = malloc(16);
+       assert(mem);
+}
+
+FAIL_TEST(sanity_malloc_indirect)
+{
+       struct wl_array array;
+
+       assert(leak_check_enabled);
+
+       wl_array_init(&array);
+
+       /* call into library that calls malloc */
+       wl_array_add(&array, 14);
+
+       /* not freeing array, must leak */
+}
+
+FAIL_TEST(tc_client_memory_leaks)
+{
+       struct display *d = display_create();
+       client_create(d, sanity_malloc_direct);
+       display_run(d);
+       display_destroy(d);
+}
+
+FAIL_TEST(tc_client_memory_leaks2)
+{
+       struct display *d = display_create();
+       client_create(d, sanity_malloc_indirect);
+       display_run(d);
+       display_destroy(d);
+}
+
+FAIL_TEST(sanity_fd_leak)
+{
+       int fd[2];
+
+       assert(leak_check_enabled);
+
+       /* leak 2 file descriptors */
+       if (pipe(fd) < 0)
+               exit(EXIT_SUCCESS); /* failed to fail */
+}
+
+FAIL_TEST(sanity_fd_leak_exec)
+{
+       int fd[2];
+       int nr_fds = count_open_fds();
+
+       /* leak 2 file descriptors */
+       if (pipe(fd) < 0)
+               exit(EXIT_SUCCESS); /* failed to fail */
+
+       exec_fd_leak_check(nr_fds);
+}
+
+TEST(sanity_fd_exec)
+{
+       int fd[2];
+       int nr_fds = count_open_fds();
+
+       /* create 2 file descriptors, that should pass over exec */
+       assert(pipe(fd) >= 0);
+
+       exec_fd_leak_check(nr_fds + 2);
+}
+
+static void
+sanity_fd_no_leak(void)
+{
+       int fd[2];
+
+       assert(leak_check_enabled);
+
+       /* leak 2 file descriptors */
+       if (pipe(fd) < 0)
+               exit(EXIT_SUCCESS); /* failed to fail */
+
+       close(fd[0]);
+       close(fd[1]);
+}
+
+static void
+sanity_client_no_leak(void)
+{
+       struct wl_display *display = wl_display_connect(NULL);
+       assert(display);
+
+       wl_display_disconnect(display);
+}
+
+TEST(tc_client_no_fd_leaks)
+{
+       struct display *d = display_create();
+
+       /* Client which does not consume the WAYLAND_DISPLAY socket. */
+       client_create(d, sanity_fd_no_leak);
+       display_run(d);
+
+       /* Client which does consume the WAYLAND_DISPLAY socket. */
+       client_create(d, sanity_client_no_leak);
+       display_run(d);
+
+       display_destroy(d);
+}
+
+FAIL_TEST(tc_client_fd_leaks)
+{
+       struct display *d = display_create();
+
+       client_create(d, sanity_fd_leak);
+       display_run(d);
+
+       display_destroy(d);
+}
+
+FAIL_TEST(tc_client_fd_leaks_exec)
+{
+       struct display *d = display_create();
+
+       client_create(d, sanity_fd_leak);
+       display_run(d);
+
+       display_destroy(d);
+}
+
+FAIL_TEST(timeout_tst)
+{
+       test_set_timeout(1);
+       /* test should reach timeout */
+       test_sleep(2);
+}
+
+TEST(timeout2_tst)
+{
+       /* the test should end before reaching timeout,
+        * thus it should pass */
+       test_set_timeout(1);
+       /* 200 000 microsec = 0.2 sec */
+       test_usleep(200000);
+}
+
+FAIL_TEST(timeout_reset_tst)
+{
+       test_set_timeout(5);
+       test_set_timeout(10);
+       test_set_timeout(1);
+
+       /* test should fail on timeout */
+       test_sleep(2);
+}
+
+TEST(timeout_turnoff)
+{
+       test_set_timeout(1);
+       test_set_timeout(0);
+
+       test_usleep(2);
+}
+
+/* test timeouts with test-compositor */
+FAIL_TEST(tc_timeout_tst)
+{
+       struct display *d = display_create();
+       client_create(d, timeout_tst);
+       display_run(d);
+       display_destroy(d);
+}
+
+FAIL_TEST(tc_timeout2_tst)
+{
+       struct display *d = display_create();
+       client_create(d, timeout_reset_tst);
+       display_run(d);
+       display_destroy(d);
+}
+
+TEST(tc_timeout3_tst)
+{
+       struct display *d = display_create();
+
+       client_create(d, timeout2_tst);
+       display_run(d);
+
+       client_create(d, timeout_turnoff);
+       display_run(d);
+
+       display_destroy(d);
+}
diff --git a/tests/signal-test.c b/tests/signal-test.c
new file mode 100644 (file)
index 0000000..db83abc
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright © 2013 Marek Chalupa
+ *
+ * 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 <assert.h>
+
+#include "wayland-server.h"
+#include "test-runner.h"
+
+static void
+signal_notify(struct wl_listener *listener, void *data)
+{
+       /* only increase counter*/
+       ++(*((int *) data));
+}
+
+TEST(signal_init)
+{
+       struct wl_signal signal;
+
+       wl_signal_init(&signal);
+
+       /* Test if listeners' list is initialized */
+       assert(&signal.listener_list == signal.listener_list.next
+               && "Maybe wl_signal implementation changed?");
+       assert(signal.listener_list.next == signal.listener_list.prev
+               && "Maybe wl_signal implementation changed?");
+}
+
+TEST(signal_add_get)
+{
+       struct wl_signal signal;
+
+       /* we just need different values of notify */
+       struct wl_listener l1 = {.notify = (wl_notify_func_t) 0x1};
+       struct wl_listener l2 = {.notify = (wl_notify_func_t) 0x2};
+       struct wl_listener l3 = {.notify = (wl_notify_func_t) 0x3};
+       /* one real, why not */
+       struct wl_listener l4 = {.notify = signal_notify};
+
+       wl_signal_init(&signal);
+
+       wl_signal_add(&signal, &l1);
+       wl_signal_add(&signal, &l2);
+       wl_signal_add(&signal, &l3);
+       wl_signal_add(&signal, &l4);
+
+       assert(wl_signal_get(&signal, signal_notify) == &l4);
+       assert(wl_signal_get(&signal, (wl_notify_func_t) 0x3) == &l3);
+       assert(wl_signal_get(&signal, (wl_notify_func_t) 0x2) == &l2);
+       assert(wl_signal_get(&signal, (wl_notify_func_t) 0x1) == &l1);
+
+       /* get should not be destructive */
+       assert(wl_signal_get(&signal, signal_notify) == &l4);
+       assert(wl_signal_get(&signal, (wl_notify_func_t) 0x3) == &l3);
+       assert(wl_signal_get(&signal, (wl_notify_func_t) 0x2) == &l2);
+       assert(wl_signal_get(&signal, (wl_notify_func_t) 0x1) == &l1);
+}
+
+TEST(signal_emit_to_one_listener)
+{
+       int count = 0;
+       int counter;
+
+       struct wl_signal signal;
+       struct wl_listener l1 = {.notify = signal_notify};
+
+       wl_signal_init(&signal);
+       wl_signal_add(&signal, &l1);
+
+       for (counter = 0; counter < 100; counter++)
+               wl_signal_emit(&signal, &count);
+
+       assert(counter == count);
+}
+
+TEST(signal_emit_to_more_listeners)
+{
+       int count = 0;
+       int counter;
+
+       struct wl_signal signal;
+       struct wl_listener l1 = {.notify = signal_notify};
+       struct wl_listener l2 = {.notify = signal_notify};
+       struct wl_listener l3 = {.notify = signal_notify};
+
+       wl_signal_init(&signal);
+       wl_signal_add(&signal, &l1);
+       wl_signal_add(&signal, &l2);
+       wl_signal_add(&signal, &l3);
+
+       for (counter = 0; counter < 100; counter++)
+               wl_signal_emit(&signal, &count);
+
+       assert(3 * counter == count);
+}
diff --git a/tests/socket-test.c b/tests/socket-test.c
new file mode 100644 (file)
index 0000000..4a2272c
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * 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 <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "wayland-client.h"
+#include "wayland-server.h"
+#include "test-runner.h"
+
+/* Paths longer than what the .sun_path array can contain must be rejected.
+   This is a hard limitation of assigning a name to AF_UNIX/AF_LOCAL sockets.
+   See `man 7 unix`. */
+
+static const struct sockaddr_un example_sockaddr_un;
+
+#define TOO_LONG (1 + sizeof example_sockaddr_un.sun_path)
+
+/* Ensure the connection doesn't fail due to lack of XDG_RUNTIME_DIR. */
+static const char *
+require_xdg_runtime_dir(void)
+{
+       char *val = getenv("XDG_RUNTIME_DIR");
+       if (!val)
+               assert(0 && "set $XDG_RUNTIME_DIR to run this test");
+
+       return val;
+}
+
+TEST(socket_path_overflow_client_connect)
+{
+       char path[TOO_LONG];
+       struct wl_display *d;
+
+       require_xdg_runtime_dir();
+
+       memset(path, 'a', sizeof path);
+       path[sizeof path - 1] = '\0';
+
+       d = wl_display_connect(path);
+       assert(d == NULL);
+       assert(errno == ENAMETOOLONG);
+}
+
+TEST(socket_path_overflow_server_create)
+{
+       char path[TOO_LONG];
+       struct wl_display *d;
+       int ret;
+
+       require_xdg_runtime_dir();
+
+       memset(path, 'a', sizeof path);
+       path[sizeof path - 1] = '\0';
+
+       d = wl_display_create();
+       assert(d != NULL);
+
+       ret = wl_display_add_socket(d, path);
+       assert(ret < 0);
+       assert(errno == ENAMETOOLONG);
+
+       wl_display_destroy(d);
+}
+
+TEST(add_existing_socket)
+{
+       char path[sizeof example_sockaddr_un.sun_path];
+       const char *name = "wayland-test-0";
+       const char *xdg_runtime_dir;
+       struct wl_display *d;
+       int ret;
+       size_t len;
+
+       xdg_runtime_dir = require_xdg_runtime_dir();
+
+       d = wl_display_create();
+       assert(d != NULL);
+
+       /* this one should be OK */
+       ret = wl_display_add_socket(d, name);
+       assert(ret == 0);
+
+       /* this on should fail */
+       ret = wl_display_add_socket(d, name);
+       assert(ret < 0);
+
+       /* the original socket should still exists,
+        * this was a bug introduced in e2c0d47b0c77f18cd90e9c6eabb358c4d89681c8 */
+       len = snprintf(path, sizeof example_sockaddr_un.sun_path, "%s/%s",
+                      xdg_runtime_dir, name);
+       assert(len < sizeof example_sockaddr_un.sun_path
+              && "Bug in test. Path too long");
+
+       assert(access(path, F_OK) != -1);
+
+       /* still should exists the original socket */
+       ret = wl_display_add_socket(d, name);
+       assert(ret < 0);
+
+       wl_display_destroy(d);
+}
+
+TEST(add_socket_auto)
+{
+       /* the number of auto sockets is currently 32 */
+       const int MAX_SOCKETS = 32;
+
+       char path[sizeof example_sockaddr_un.sun_path];
+       const char *name;
+       const char *xdg_runtime_dir;
+       struct wl_display *d;
+       int i;
+       size_t len;
+
+       xdg_runtime_dir = require_xdg_runtime_dir();
+
+       d = wl_display_create();
+       assert(d != NULL);
+
+       for (i = 0; i <= MAX_SOCKETS; ++i) {
+               name = wl_display_add_socket_auto(d);
+               assert(name != NULL);
+
+               len = snprintf(path, sizeof example_sockaddr_un.sun_path,
+                              "%s/%s", xdg_runtime_dir, name);
+               assert(len < sizeof example_sockaddr_un.sun_path
+                      && "Bug in test. Path too long");
+
+               /* was the socket? */
+               assert(access(path, F_OK) != -1);
+
+               /* is the name sequential? */
+               len = snprintf(path, sizeof example_sockaddr_un.sun_path,
+                              "wayland-%d", i);
+               assert(strcmp(name, path) == 0);
+       }
+
+       /* next addition should return NULL */
+       name = wl_display_add_socket_auto(d);
+       assert(name == NULL);
+
+       /* check if the socket was not deleted the last time */
+       name = wl_display_add_socket_auto(d);
+       assert(name == NULL);
+
+       wl_display_destroy(d);
+}
diff --git a/tests/test-compositor.c b/tests/test-compositor.c
new file mode 100644 (file)
index 0000000..da2a55f
--- /dev/null
@@ -0,0 +1,488 @@
+/*
+ * Copyright (c) 2014 Red Hat, Inc.
+ *
+ * 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 <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+#define WL_HIDE_DEPRECATED
+
+#include "test-runner.h"
+#include "test-compositor.h"
+
+/* --- Protocol --- */
+struct test_compositor;
+
+static const struct wl_message tc_requests[] = {
+       /* this request serves as a barrier for synchronizing*/
+       { "stop_display", "u", NULL }
+};
+
+static const struct wl_message tc_events[] = {
+       { "display_resumed", "", NULL }
+};
+
+const struct wl_interface test_compositor_interface = {
+       "test", 1,
+       1, tc_requests,
+       1, tc_events
+};
+
+struct test_compositor_interface {
+       void (*stop_display)(struct wl_client *client,
+                            struct wl_resource *resource,
+                            uint32_t num);
+};
+
+struct test_compositor_listener {
+       void (*display_resumed)(void *data, struct test_compositor *tc);
+
+};
+
+enum {
+       STOP_DISPLAY = 0
+};
+
+enum {
+       DISPLAY_RESUMED = 0
+};
+
+/* Since tests can run parallely, we need unique socket names
+ * for each test, otherwise the test can fail on wl_display_add_socket. */
+static const char *
+get_socket_name(void)
+{
+       struct timeval tv;
+       static char retval[64];
+
+       gettimeofday(&tv, NULL);
+       snprintf(retval, sizeof retval, "wayland-test-%d-%ld%ld",
+                getpid(), tv.tv_sec, tv.tv_usec);
+
+       return retval;
+}
+
+/**
+ * Check client's state and terminate display when all clients exited
+ */
+static void
+client_destroyed(struct wl_listener *listener, void *data)
+{
+       struct display *d;
+       struct client_info *ci;
+       siginfo_t status;
+
+       ci = wl_container_of(listener, ci, destroy_listener);
+       d = ci->display;
+
+       assert(waitid(P_PID, ci->pid, &status, WEXITED) != -1);
+
+       switch (status.si_code) {
+       case CLD_KILLED:
+       case CLD_DUMPED:
+               fprintf(stderr, "Client '%s' was killed by signal %d\n",
+                       ci->name, status.si_status);
+               ci->exit_code = status.si_status;
+               break;
+       case CLD_EXITED:
+               if (status.si_status != EXIT_SUCCESS)
+                       fprintf(stderr, "Client '%s' exited with code %d\n",
+                               ci->name, status.si_status);
+
+               ci->exit_code = status.si_status;
+               break;
+       }
+
+       ++d->clients_terminated_no;
+       if (d->clients_no == d->clients_terminated_no) {
+               wl_display_terminate(d->wl_display);
+       }
+
+       /* the clients are not removed from the list, because
+        * at the end of the test we check the exit codes of all
+        * clients. In the case that the test would go through
+        * the clients list manually, zero out the wl_client as a sign
+        * that the client is not running anymore */
+       ci->wl_client = NULL;
+}
+
+static void
+run_client(void (*client_main)(void), int wayland_sock, int client_pipe)
+{
+       char s[8];
+       int cur_alloc, cur_fds;
+       int can_continue = 0;
+
+       /* Wait until display signals that client can continue */
+       assert(read(client_pipe, &can_continue, sizeof(int)) == sizeof(int));
+
+       if (can_continue == 0)
+               abort(); /* error in parent */
+
+       /* for wl_display_connect() */
+       snprintf(s, sizeof s, "%d", wayland_sock);
+       setenv("WAYLAND_SOCKET", s, 0);
+
+       cur_alloc = get_current_alloc_num();
+       cur_fds = count_open_fds();
+
+       client_main();
+
+       /* Clients using wl_display_connect() will end up closing the socket
+        * passed in through the WAYLAND_SOCKET environment variable. When
+        * doing this, it clears the environment variable, so if it's been
+        * unset, then we assume the client consumed the file descriptor and
+        * do not count it towards leak checking. */
+       if (!getenv("WAYLAND_SOCKET"))
+               cur_fds--;
+
+       check_leaks(cur_alloc, cur_fds);
+}
+
+static struct client_info *
+display_create_client(struct display *d,
+                     void (*client_main)(void),
+                     const char *name)
+{
+       int pipe_cli[2];
+       int sock_wayl[2];
+       pid_t pid;
+       int can_continue = 0;
+       struct client_info *cl;
+
+       assert(pipe(pipe_cli) == 0 && "Failed creating pipe");
+       assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sock_wayl) == 0
+              && "Failed creating socket pair");
+
+       pid = fork();
+       assert(pid != -1 && "Fork failed");
+
+       if (pid == 0) {
+               close(sock_wayl[1]);
+               close(pipe_cli[1]);
+
+               run_client(client_main, sock_wayl[0], pipe_cli[0]);
+
+               close(sock_wayl[0]);
+               close(pipe_cli[0]);
+
+               exit(0);
+       }
+
+       close(sock_wayl[0]);
+       close(pipe_cli[0]);
+
+       cl = calloc(1, sizeof(struct client_info));
+       assert(cl && "Out of memory");
+
+       wl_list_insert(&d->clients, &cl->link);
+
+       cl->display = d;
+       cl->name = name;
+       cl->pid = pid;
+       cl->pipe = pipe_cli[1];
+       cl->destroy_listener.notify = &client_destroyed;
+
+       cl->wl_client = wl_client_create(d->wl_display, sock_wayl[1]);
+       if (!cl->wl_client) {
+               int ret;
+
+               /* abort the client */
+               ret = write(cl->pipe, &can_continue, sizeof(int));
+               assert(ret == sizeof(int) && "aborting the client failed");
+               assert(0 && "Couldn't create wayland client");
+       }
+
+       wl_client_add_destroy_listener(cl->wl_client,
+                                      &cl->destroy_listener);
+
+       ++d->clients_no;
+
+       return cl;
+}
+
+struct client_info *
+client_create_with_name(struct display *d, void (*client_main)(void),
+                       const char *name)
+{
+       int can_continue = 1;
+       struct client_info *cl = display_create_client(d, client_main, name);
+
+       /* let the show begin! */
+       assert(write(cl->pipe, &can_continue, sizeof(int)) == sizeof(int));
+
+       return cl;
+}
+
+/* wfr = waiting for resume */
+struct wfr {
+       struct wl_resource *resource;
+       struct wl_list link;
+};
+
+static void
+handle_stop_display(struct wl_client *client,
+                   struct wl_resource *resource, uint32_t num)
+{
+       struct display *d = wl_resource_get_user_data(resource);
+       struct wfr *wfr;
+
+       assert(d->wfr_num < num
+              && "test error: Too many clients sent stop_display request");
+
+       ++d->wfr_num;
+
+       wfr = malloc(sizeof *wfr);
+       if (!wfr) {
+               wl_client_post_no_memory(client);
+               assert(0 && "Out of memory");
+       }
+
+       wfr->resource = resource;
+       wl_list_insert(&d->waiting_for_resume, &wfr->link);
+
+       if (d->wfr_num == num)
+               wl_display_terminate(d->wl_display);
+}
+
+static const struct test_compositor_interface tc_implementation = {
+       handle_stop_display
+};
+
+static void
+tc_bind(struct wl_client *client, void *data,
+       uint32_t ver, uint32_t id)
+{
+       struct wl_resource *res;
+
+       res = wl_resource_create(client, &test_compositor_interface, ver, id);
+       if (!res) {
+               wl_client_post_no_memory(client);
+               assert(0 && "Out of memory");
+       }
+
+       wl_resource_set_implementation(res, &tc_implementation, data, NULL);
+}
+
+struct display *
+display_create(void)
+{
+       struct display *d = NULL;
+       struct wl_global *g;
+       const char *socket_name;
+       int stat = 0;
+
+       d = calloc(1, sizeof *d);
+       assert(d && "Out of memory");
+
+       d->wl_display = wl_display_create();
+       assert(d->wl_display && "Creating display failed");
+
+       /* hope the path won't be longer than 108 ... */
+       socket_name = get_socket_name();
+       stat = wl_display_add_socket(d->wl_display, socket_name);
+       assert(stat == 0 && "Failed adding socket");
+
+       wl_list_init(&d->clients);
+       d->clients_no = d->clients_terminated_no = 0;
+
+       wl_list_init(&d->waiting_for_resume);
+       d->wfr_num = 0;
+
+       g = wl_global_create(d->wl_display, &test_compositor_interface,
+                            1, d, tc_bind);
+       assert(g && "Creating test global failed");
+
+       return d;
+}
+
+void
+display_run(struct display *d)
+{
+       assert(d->wfr_num == 0
+              && "test error: Have waiting clients. Use display_resume.");
+       wl_display_run(d->wl_display);
+}
+
+void
+display_resume(struct display *d)
+{
+       struct wfr *wfr, *next;
+
+       assert(d->wfr_num > 0 && "test error: No clients waiting.");
+
+       wl_list_for_each_safe(wfr, next, &d->waiting_for_resume, link) {
+               wl_resource_post_event(wfr->resource, DISPLAY_RESUMED);
+               wl_list_remove(&wfr->link);
+               free(wfr);
+       }
+
+       assert(wl_list_empty(&d->waiting_for_resume));
+       d->wfr_num = 0;
+
+       wl_display_run(d->wl_display);
+}
+
+void
+display_destroy(struct display *d)
+{
+       struct client_info *cl, *next;
+       int failed = 0;
+
+       assert(d->wfr_num == 0
+              && "test error: Didn't you forget to call display_resume?");
+
+       wl_list_for_each_safe(cl, next, &d->clients, link) {
+               assert(cl->wl_client == NULL);
+
+               if (cl->exit_code != 0) {
+                       ++failed;
+                       fprintf(stderr, "Client '%s' failed\n", cl->name);
+               }
+
+               close(cl->pipe);
+               free(cl);
+       }
+
+       wl_display_destroy(d->wl_display);
+       free(d);
+
+       if (failed) {
+               fprintf(stderr, "%d child(ren) failed\n", failed);
+               abort();
+       }
+}
+
+/*
+ * --- Client helper functions ---
+ */
+static void
+handle_display_resumed(void *data, struct test_compositor *tc)
+{
+       struct client *c = data;
+
+       c->display_stopped = 0;
+}
+
+static const struct test_compositor_listener tc_listener = {
+       handle_display_resumed
+};
+
+static void
+registry_handle_globals(void *data, struct wl_registry *registry,
+                       uint32_t id, const char *intf, uint32_t ver)
+{
+       struct client *c = data;
+
+       if (strcmp(intf, "test") != 0)
+               return;
+
+       c->tc = wl_registry_bind(registry, id, &test_compositor_interface, ver);
+       assert(c->tc && "Failed binding to registry");
+
+       wl_proxy_add_listener((struct wl_proxy *) c->tc,
+                             (void *) &tc_listener, c);
+}
+
+static const struct wl_registry_listener registry_listener =
+{
+       registry_handle_globals,
+       NULL
+};
+
+struct client *client_connect()
+{
+       struct wl_registry *reg;
+       struct client *c = calloc(1, sizeof *c);
+       assert(c && "Out of memory");
+
+       c->wl_display = wl_display_connect(NULL);
+       assert(c->wl_display && "Failed connecting to display");
+
+       /* create test_compositor proxy. Do it with temporary
+        * registry so that client can define it's own listener later */
+       reg = wl_display_get_registry(c->wl_display);
+       assert(reg);
+       wl_registry_add_listener(reg, &registry_listener, c);
+       wl_display_roundtrip(c->wl_display);
+       assert(c->tc);
+
+       wl_registry_destroy(reg);
+
+       return c;
+}
+
+static void
+check_error(struct wl_display *display)
+{
+       uint32_t ec, id;
+       const struct wl_interface *intf;
+       int err;
+
+       err = wl_display_get_error(display);
+       /* write out message about protocol error */
+       if (err == EPROTO) {
+               ec = wl_display_get_protocol_error(display, &intf, &id);
+               fprintf(stderr, "Client: Got protocol error %u on interface %s"
+                               " (object %u)\n", ec, intf->name, id);
+       }
+
+       if (err) {
+               fprintf(stderr, "Client error: %s\n", strerror(err));
+               abort();
+       }
+}
+
+void
+client_disconnect(struct client *c)
+{
+       /* check for errors */
+       check_error(c->wl_display);
+
+       wl_proxy_destroy((struct wl_proxy *) c->tc);
+       wl_display_disconnect(c->wl_display);
+       free(c);
+}
+
+/* num is number of clients that requests to stop display.
+ * Display is stopped after it recieve num STOP_DISPLAY requests */
+int
+stop_display(struct client *c, int num)
+{
+       int n = 0;
+
+       c->display_stopped = 1;
+       wl_proxy_marshal((struct wl_proxy *) c->tc, STOP_DISPLAY, num);
+
+       while (c->display_stopped && n >= 0) {
+               n = wl_display_dispatch(c->wl_display);
+       }
+
+       return n;
+}
diff --git a/tests/test-compositor.h b/tests/test-compositor.h
new file mode 100644 (file)
index 0000000..c41b17b
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2014 Red Hat, Inc.
+ *
+ * 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 <unistd.h>
+
+#include "wayland-server.h"
+#include "wayland-client.h"
+
+/* info about a client on server side */
+struct client_info {
+       struct display *display;
+       struct wl_client *wl_client;
+       struct wl_listener destroy_listener;
+       const char *name; /* for debugging */
+
+       int pipe;
+       pid_t pid;
+       int exit_code;
+
+       struct wl_list link;
+       void *data; /* for arbitrary use */
+};
+
+struct display {
+       struct wl_display *wl_display;
+
+       struct wl_list clients;
+       uint32_t clients_no;
+       uint32_t clients_terminated_no;
+
+       /* list of clients waiting for display_resumed event */
+       struct wl_list waiting_for_resume;
+       uint32_t wfr_num;
+};
+
+/* This is a helper structure for clients.
+ * Instead of calling wl_display_connect() and all the other stuff,
+ * client can use client_connect and it will return this structure
+ * filled. */
+struct client {
+       struct wl_display *wl_display;
+       struct test_compositor *tc;
+
+       int display_stopped;
+};
+
+struct client *client_connect(void);
+void client_disconnect(struct client *);
+int stop_display(struct client *, int);
+
+/**
+ * Usual workflow:
+ *
+ *    d = display_create();
+ *
+ *    wl_global_create(d->wl_display, ...);
+ *    ... other setups ...
+ *
+ *    client_create(d, client_main);
+ *    client_create(d, client_main2);
+ *
+ *    display_run(d);
+ *    display_destroy(d);
+ */
+struct display *display_create(void);
+void display_destroy(struct display *d);
+void display_run(struct display *d);
+
+/* After n clients called stop_display(..., n), the display
+ * is stopped and can process the code after display_run().
+ * This function rerun the display again and send display_resumed
+ * event to waiting clients, so the clients will stop waiting and continue */
+void display_resume(struct display *d);
+
+struct client_info *client_create_with_name(struct display *d,
+                                           void (*client_main)(void),
+                                           const char *name);
+#define client_create(d, c) client_create_with_name((d), (c), (#c))
diff --git a/tests/test-helpers.c b/tests/test-helpers.c
new file mode 100644 (file)
index 0000000..c05f4b1
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * 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 <assert.h>
+#include <errno.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "test-runner.h"
+
+int
+count_open_fds(void)
+{
+       DIR *dir;
+       struct dirent *ent;
+       int count = 0;
+
+       dir = opendir("/proc/self/fd");
+       assert(dir && "opening /proc/self/fd failed.");
+
+       errno = 0;
+       while ((ent = readdir(dir))) {
+               const char *s = ent->d_name;
+               if (s[0] == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0)))
+                       continue;
+               count++;
+       }
+       assert(errno == 0 && "reading /proc/self/fd failed.");
+
+       closedir(dir);
+
+       return count;
+}
+
+void
+exec_fd_leak_check(int nr_expected_fds)
+{
+       const char *exe = "./exec-fd-leak-checker";
+       char number[16] = { 0 };
+
+       snprintf(number, sizeof number - 1, "%d", nr_expected_fds);
+       execl(exe, exe, number, (char *)NULL);
+       assert(0 && "execing fd leak checker failed");
+}
+
+#define USEC_TO_NSEC(n) (1000 * (n))
+
+/* our implementation of usleep and sleep functions that are safe to use with
+ * timeouts (timeouts are implemented using alarm(), so it is not safe use
+ * usleep and sleep. See man pages of these functions)
+ */
+void
+test_usleep(useconds_t usec)
+{
+       struct timespec ts = {
+               .tv_sec = 0,
+               .tv_nsec = USEC_TO_NSEC(usec)
+       };
+
+       assert(nanosleep(&ts, NULL) == 0);
+}
+
+/* we must write the whole function instead of
+ * wrapping test_usleep, because useconds_t may not
+ * be able to contain such a big number of microseconds */
+void
+test_sleep(unsigned int sec)
+{
+       struct timespec ts = {
+               .tv_sec = sec,
+               .tv_nsec = 0
+       };
+
+       assert(nanosleep(&ts, NULL) == 0);
+}
diff --git a/tests/test-runner.c b/tests/test-runner.c
new file mode 100644 (file)
index 0000000..1e5f587
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <assert.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/ptrace.h>
+#include <sys/prctl.h>
+#ifndef PR_SET_PTRACER
+# define PR_SET_PTRACER 0x59616d61
+#endif
+
+#include "test-runner.h"
+
+static int num_alloc;
+static void* (*sys_malloc)(size_t);
+static void (*sys_free)(void*);
+static void* (*sys_realloc)(void*, size_t);
+static void* (*sys_calloc)(size_t, size_t);
+
+/* when set to 1, check if tests are not leaking memory and opened files.
+ * It is turned on by default. It can be turned off by
+ * WAYLAND_TEST_NO_LEAK_CHECK environment variable. */
+int leak_check_enabled;
+
+/* when this var is set to 0, every call to test_set_timeout() is
+ * suppressed - handy when debugging the test. Can be set by
+ * WAYLAND_TEST_NO_TIMEOUTS environment variable. */
+static int timeouts_enabled = 1;
+
+/* set to one if the output goes to the terminal */
+static int is_atty = 0;
+
+extern const struct test __start_test_section, __stop_test_section;
+
+__attribute__ ((visibility("default"))) void *
+malloc(size_t size)
+{
+       num_alloc++;
+       return sys_malloc(size);
+}
+
+__attribute__ ((visibility("default"))) void
+free(void* mem)
+{
+       if (mem != NULL)
+               num_alloc--;
+       sys_free(mem);
+}
+
+__attribute__ ((visibility("default"))) void *
+realloc(void* mem, size_t size)
+{
+       if (mem == NULL)
+               num_alloc++;
+       return sys_realloc(mem, size);
+}
+
+__attribute__ ((visibility("default"))) void *
+calloc(size_t nmemb, size_t size)
+{
+       if (sys_calloc == NULL)
+               return NULL;
+
+       num_alloc++;
+
+       return sys_calloc(nmemb, size);
+}
+
+static const struct test *
+find_test(const char *name)
+{
+       const struct test *t;
+
+       for (t = &__start_test_section; t < &__stop_test_section; t++)
+               if (strcmp(t->name, name) == 0)
+                       return t;
+
+       return NULL;
+}
+
+static void
+usage(const char *name, int status)
+{
+       const struct test *t;
+
+       fprintf(stderr, "Usage: %s [TEST]\n\n"
+               "With no arguments, run all test.  Specify test case to run\n"
+               "only that test without forking.  Available tests:\n\n",
+               name);
+
+       for (t = &__start_test_section; t < &__stop_test_section; t++)
+               fprintf(stderr, "  %s\n", t->name);
+
+       fprintf(stderr, "\n");
+
+       exit(status);
+}
+
+void
+test_set_timeout(unsigned int to)
+{
+       int re;
+
+       if (!timeouts_enabled) {
+               fprintf(stderr, "Timeouts suppressed.\n");
+               return;
+       }
+
+       re = alarm(to);
+       fprintf(stderr, "Timeout was %sset", re ? "re-" : "");
+
+       if (to != 0)
+               fprintf(stderr, " to %d second%s from now.\n",
+                       to, to > 1 ? "s" : "");
+       else
+               fprintf(stderr, " off.\n");
+}
+
+static void
+sigalrm_handler(int signum)
+{
+       fprintf(stderr, "Test timed out.\n");
+       abort();
+}
+
+int
+get_current_alloc_num(void)
+{
+       return num_alloc;
+}
+
+void
+check_leaks(int supposed_alloc, int supposed_fds)
+{
+       int num_fds;
+
+       if (leak_check_enabled) {
+               if (supposed_alloc != num_alloc) {
+                       fprintf(stderr, "Memory leak detected in test. "
+                               "Allocated %d blocks, unfreed %d\n", num_alloc,
+                               num_alloc - supposed_alloc);
+                       abort();
+               }
+
+               num_fds = count_open_fds();
+               if (supposed_fds != num_fds) {
+                       fprintf(stderr, "fd leak detected in test. "
+                               "Opened %d files, unclosed %d\n", num_fds,
+                               num_fds - supposed_fds);
+                       abort();
+               }
+       } else {
+               fprintf(stderr, "Leak checks disabled\n");
+       }
+}
+
+static void
+run_test(const struct test *t)
+{
+       int cur_alloc, cur_fds;
+       struct sigaction sa;
+
+       if (timeouts_enabled) {
+               sa.sa_handler = sigalrm_handler;
+               sa.sa_flags = 0;
+               sigemptyset(&sa.sa_mask);
+               assert(sigaction(SIGALRM, &sa, NULL) == 0);
+       }
+
+       cur_alloc = get_current_alloc_num();
+       cur_fds = count_open_fds();
+
+       t->run();
+
+       /* turn off timeout (if any) after test completition */
+       if (timeouts_enabled)
+               alarm(0);
+
+       check_leaks(cur_alloc, cur_fds);
+
+       exit(EXIT_SUCCESS);
+}
+
+#ifndef PATH_MAX
+#define PATH_MAX 256
+#endif
+
+static void
+set_xdg_runtime_dir(void)
+{
+       char xdg_runtime_dir[PATH_MAX];
+       const char *xrd_env;
+
+       xrd_env = getenv("XDG_RUNTIME_DIR");
+       /* if XDG_RUNTIME_DIR is not set in environ, fallback to /tmp */
+       assert((snprintf(xdg_runtime_dir, PATH_MAX, "%s/wayland-tests",
+                        xrd_env ? xrd_env : "/tmp") < PATH_MAX)
+               && "test error: XDG_RUNTIME_DIR too long");
+
+       if (mkdir(xdg_runtime_dir, 0700) == -1)
+               if (errno != EEXIST) {
+                       perror("Creating XDG_RUNTIME_DIR");
+                       abort();
+               }
+
+       if (setenv("XDG_RUNTIME_DIR", xdg_runtime_dir, 1) == -1) {
+               perror("Setting XDG_RUNTIME_DIR");
+               abort();
+       }
+}
+
+static void
+rmdir_xdg_runtime_dir(void)
+{
+       const char *xrd_env = getenv("XDG_RUNTIME_DIR");
+       assert(xrd_env && "No XDG_RUNTIME_DIR set");
+
+       /* rmdir may fail if some test didn't do clean up */
+       if (rmdir(xrd_env) == -1)
+               perror("Cleaning XDG_RUNTIME_DIR");
+}
+
+#define RED    "\033[31m"
+#define GREEN  "\033[32m"
+
+static void
+stderr_set_color(const char *color)
+{
+       /* use colors only when the output is connected to
+        * the terminal */
+       if (is_atty)
+               fprintf(stderr, "%s", color);
+}
+
+static void
+stderr_reset_color(void)
+{
+       if (is_atty)
+               fprintf(stderr, "\033[0m");
+}
+
+/* this function is taken from libinput/test/litest.c
+ * (rev 028513a0a723e97941c39)
+ *
+ * Returns: 1 if a debugger is confirmed present; 0 if no debugger is
+ * present or if it can't be determined.
+ */
+static int
+is_debugger_attached(void)
+{
+       int status;
+       int rc;
+       pid_t pid;
+       int pipefd[2];
+
+       if (pipe(pipefd) == -1) {
+               perror("pipe");
+               return 0;
+       }
+
+       pid = fork();
+       if (pid == -1) {
+               perror("fork");
+               close(pipefd[0]);
+               close(pipefd[1]);
+               return 0;
+       } else if (pid == 0) {
+               char buf;
+               pid_t ppid = getppid();
+
+               /* Wait until parent is ready */
+               close(pipefd[1]);  /* Close unused write end */
+               read(pipefd[0], &buf, 1);
+               close(pipefd[0]);
+               if (buf == '-')
+                       _exit(1);
+               if (ptrace(PTRACE_ATTACH, ppid, NULL, NULL) != 0)
+                       _exit(1);
+               if (!waitpid(-1, NULL, 0))
+                       _exit(1);
+               ptrace(PTRACE_CONT, NULL, NULL);
+               ptrace(PTRACE_DETACH, ppid, NULL, NULL);
+               _exit(0);
+       } else {
+               close(pipefd[0]);
+
+               /* Enable child to ptrace the parent process */
+               rc = prctl(PR_SET_PTRACER, pid);
+               if (rc != 0 && errno != EINVAL) {
+                       /* An error prevents us from telling if a debugger is attached.
+                        * Instead of propagating the error, assume no debugger present.
+                        * But note the error to the log as a clue for troubleshooting.
+                        * Then flag the error state to the client by sending '-'.
+                        */
+                       perror("prctl");
+                       write(pipefd[1], "-", 1);
+               } else {
+                       /* Signal to client that parent is ready by passing '+' */
+                       write(pipefd[1], "+", 1);
+               }
+               close(pipefd[1]);
+
+               waitpid(pid, &status, 0);
+               rc = WEXITSTATUS(status);
+       }
+
+       return rc;
+}
+
+int main(int argc, char *argv[])
+{
+       const struct test *t;
+       pid_t pid;
+       int total, pass;
+       siginfo_t info;
+
+       /* Load system malloc, free, and realloc */
+       sys_calloc = dlsym(RTLD_NEXT, "calloc");
+       sys_realloc = dlsym(RTLD_NEXT, "realloc");
+       sys_malloc = dlsym(RTLD_NEXT, "malloc");
+       sys_free = dlsym(RTLD_NEXT, "free");
+
+       if (isatty(fileno(stderr)))
+               is_atty = 1;
+
+       if (is_debugger_attached()) {
+               leak_check_enabled = 0;
+               timeouts_enabled = 0;
+       } else {
+               leak_check_enabled = !getenv("WAYLAND_TEST_NO_LEAK_CHECK");
+               timeouts_enabled = !getenv("WAYLAND_TEST_NO_TIMEOUTS");
+       }
+
+       if (argc == 2 && strcmp(argv[1], "--help") == 0)
+               usage(argv[0], EXIT_SUCCESS);
+
+       if (argc == 2) {
+               t = find_test(argv[1]);
+               if (t == NULL) {
+                       fprintf(stderr, "unknown test: \"%s\"\n", argv[1]);
+                       usage(argv[0], EXIT_FAILURE);
+               }
+
+               set_xdg_runtime_dir();
+               /* run_test calls exit() */
+               assert(atexit(rmdir_xdg_runtime_dir) == 0);
+
+               run_test(t);
+       }
+
+       /* set our own XDG_RUNTIME_DIR */
+       set_xdg_runtime_dir();
+
+       pass = 0;
+       for (t = &__start_test_section; t < &__stop_test_section; t++) {
+               int success = 0;
+
+               pid = fork();
+               assert(pid >= 0);
+
+               if (pid == 0)
+                       run_test(t); /* never returns */
+
+               if (waitid(P_PID, pid, &info, WEXITED)) {
+                       stderr_set_color(RED);
+                       fprintf(stderr, "waitid failed: %m\n");
+                       stderr_reset_color();
+
+                       abort();
+               }
+
+               switch (info.si_code) {
+               case CLD_EXITED:
+                       if (info.si_status == EXIT_SUCCESS)
+                               success = !t->must_fail;
+                       else
+                               success = t->must_fail;
+
+                       stderr_set_color(success ? GREEN : RED);
+                       fprintf(stderr, "test \"%s\":\texit status %d",
+                               t->name, info.si_status);
+
+                       break;
+               case CLD_KILLED:
+               case CLD_DUMPED:
+                       if (t->must_fail)
+                               success = 1;
+
+                       stderr_set_color(success ? GREEN : RED);
+                       fprintf(stderr, "test \"%s\":\tsignal %d",
+                               t->name, info.si_status);
+
+                       break;
+               }
+
+               if (success) {
+                       pass++;
+                       fprintf(stderr, ", pass.\n");
+               } else
+                       fprintf(stderr, ", fail.\n");
+
+               stderr_reset_color();
+
+               /* print separator line */
+               fprintf(stderr, "----------------------------------------\n");
+       }
+
+       total = &__stop_test_section - &__start_test_section;
+       fprintf(stderr, "%d tests, %d pass, %d fail\n",
+               total, pass, total - pass);
+
+       /* cleaning */
+       rmdir_xdg_runtime_dir();
+
+       return pass == total ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/tests/test-runner.h b/tests/test-runner.h
new file mode 100644 (file)
index 0000000..6054da5
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef _TEST_RUNNER_H_
+#define _TEST_RUNNER_H_
+
+#ifdef NDEBUG
+#error "Tests must not be built with NDEBUG defined, they rely on assert()."
+#endif
+
+#include <unistd.h>
+
+struct test {
+       const char *name;
+       void (*run)(void);
+       int must_fail;
+} __attribute__ ((aligned (16)));
+
+#define TEST(name)                                             \
+       static void name(void);                                 \
+                                                               \
+       const struct test test##name                            \
+                __attribute__ ((section ("test_section"))) = { \
+               #name, name, 0                                  \
+       };                                                      \
+                                                               \
+       static void name(void)
+
+#define FAIL_TEST(name)                                                \
+       static void name(void);                                 \
+                                                               \
+       const struct test test##name                            \
+                __attribute__ ((section ("test_section"))) = { \
+               #name, name, 1                                  \
+       };                                                      \
+                                                               \
+       static void name(void)
+
+int
+count_open_fds(void);
+
+void
+exec_fd_leak_check(int nr_expected_fds); /* never returns */
+
+int
+get_current_alloc_num(void);
+
+void
+check_leaks(int supposed_allocs, int supposed_fds);
+
+/*
+ * set/reset the timeout in seconds. The timeout starts
+ * at the point of invoking this function
+ */
+void
+test_set_timeout(unsigned int);
+
+/* test-runner uses alarm() and SIGALRM, so we can not
+ * use usleep and sleep functions in tests (see 'man usleep'
+ * or 'man sleep', respectively). Following functions are safe
+ * to use in tests */
+void
+test_usleep(useconds_t);
+
+void
+test_sleep(unsigned int);
+
+#define DISABLE_LEAK_CHECKS                    \
+       do {                                    \
+               extern int leak_check_enabled;  \
+               leak_check_enabled = 0;         \
+       } while (0);
+
+#endif
diff --git a/wayland-scanner.m4 b/wayland-scanner.m4
new file mode 100644 (file)
index 0000000..4e4222a
--- /dev/null
@@ -0,0 +1,13 @@
+AC_DEFUN([WAYLAND_SCANNER_RULES], [
+    PKG_PROG_PKG_CONFIG
+
+    PKG_CHECK_MODULES([WAYLAND_SCANNER], [wayland-scanner])
+
+    wayland_scanner=`$PKG_CONFIG --variable=wayland_scanner wayland-scanner`
+    AC_SUBST([wayland_scanner])
+
+    wayland_scanner_rules=`$PKG_CONFIG --variable=pkgdatadir wayland-scanner`/wayland-scanner.mk
+    AC_SUBST_FILE([wayland_scanner_rules])
+
+    AC_SUBST([wayland_protocoldir], [$1])
+])
diff --git a/wayland-scanner.mk b/wayland-scanner.mk
new file mode 100644 (file)
index 0000000..0a72062
--- /dev/null
@@ -0,0 +1,8 @@
+%-protocol.c : $(wayland_protocoldir)/%.xml
+       $(AM_V_GEN)$(wayland_scanner) code < $< > $@
+
+%-server-protocol.h : $(wayland_protocoldir)/%.xml
+       $(AM_V_GEN)$(wayland_scanner) server-header < $< > $@
+
+%-client-protocol.h : $(wayland_protocoldir)/%.xml
+       $(AM_V_GEN)$(wayland_scanner) client-header < $< > $@