--- /dev/null
+[general]
+upstream_branch = upstream
+upstream_tag = ${upstreamversion}
--- /dev/null
+*.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]
--- /dev/null
+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.
--- /dev/null
+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
--- /dev/null
+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.
--- /dev/null
+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.
--- /dev/null
+#! /bin/sh
+
+test -n "$srcdir" || srcdir=`dirname "$0"`
+test -n "$srcdir" || srcdir=.
+(
+ cd "$srcdir" &&
+ autoreconf --force -v --install
+) || exit
+test -n "$NOCONFIGURE" || "$srcdir/configure" "$@"
--- /dev/null
+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
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+* 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 },
+};
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+= 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
+
--- /dev/null
+SUBDIRS = doxygen publican man
+
+EXTRA_DIST = Contributing
--- /dev/null
+wayland.doxygen
+xml/
--- /dev/null
+
+.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)
--- /dev/null
+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];
+}
--- /dev/null
+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];
+ }
--- /dev/null
+# 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
--- /dev/null
+#
+# 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
--- /dev/null
+<?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 <wayland-client.h></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>
--- /dev/null
+Wayland
+en-US/
+publican-copy.cfg
--- /dev/null
+# 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
--- /dev/null
+<?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>
--- /dev/null
+<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>
</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>	 </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>	 </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>
</xsl:text>
+ </xsl:for-each>
+ <!-- -->
+ <xsl:text>	 </xsl:text>
+ </xsl:element>
+ </xsl:template>
+</xsl:stylesheet>
--- /dev/null
+<?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: -->
--- /dev/null
+<?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="' '" />
+ <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: -->
--- /dev/null
+<?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>
--- /dev/null
+<?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>
+
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<revhistory>
+ <revision>
+ <revnumber>1-0</revnumber>
+ <authorinitials>krh</authorinitials>
+ <revremark>Initial version</revremark>
+ </revision>
+</revhistory>
--- /dev/null
+<?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>
--- /dev/null
+<!ENTITY PRODUCT "Documentation">
+<!ENTITY BOOKID "Wayland">
+<!ENTITY YEAR "2012">
+<!ENTITY HOLDER "Kristian Høgsberg, Intel Corporation">
--- /dev/null
+<?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>
--- /dev/null
+/*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;
+}
--- /dev/null
+* {
+ 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;
+}
--- /dev/null
+@import url("common.css");
+@import url("overrides.css");
+@import url("lang.css");
--- /dev/null
+/*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;
+}
--- /dev/null
+@import url("common.css");
+@import url("overrides.css");
+@import url("lang.css");
+
+#tocframe {
+ display: none;
+}
+
+body.toc_embeded {
+ margin-left: 30px;
+}
+
+.producttitle {
+ color: #336699;
+}
--- /dev/null
+<?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>
--- /dev/null
+libtool.m4
+ltoptions.m4
+ltsugar.m4
+ltversion.m4
+lt~obsolete.m4
--- /dev/null
+libwayland-client
+libwayland-cursor
+libwayland-server
--- /dev/null
+* 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
+
--- /dev/null
+<manifest>
+ <request>
+ <domain name="_"/>
+ </request>
+</manifest>
--- /dev/null
+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
--- /dev/null
+wayland.html
+.wayland.xml.valid
--- /dev/null
+<!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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+main.aux
+main.log
+main.pdf
--- /dev/null
+/wayland-version.h
--- /dev/null
+/*
+ * 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] = ⌖
+
+ 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);
+}
--- /dev/null
+/*
+ * 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);
+}
+
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+%-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 < $< > $@
--- /dev/null
+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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+pkgdatadir=@abs_top_srcdir@
+wayland_scanner=@abs_builddir@/wayland-scanner
+
+Name: Wayland Scanner
+Description: Wayland scanner (not installed)
+Version: @PACKAGE_VERSION@
--- /dev/null
+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@
--- /dev/null
+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
--- /dev/null
+/*
+ * 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,
+ ®istry_interface,
+ display, unbind_resource);
+
+ wl_list_insert(&display->registry_resource_list,
+ ®istry_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.
+ */
--- /dev/null
+/*
+ * 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
--- /dev/null
+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
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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(©);
+ wl_array_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(©);
+}
+
+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);
+}
--- /dev/null
+/*
+ * 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);
+}
+
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/* This source should compile fine with C++ compiler */
+#include "wayland-server-protocol.h"
+
+int main() { return 0; }
+
--- /dev/null
+/*
+ * 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, ®istry_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);
+}
--- /dev/null
+/*
+ * 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);
+}
+
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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)));
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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() */
--- /dev/null
+/*
+ * 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, ®istry_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);
+}
--- /dev/null
+/*
+ * 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]);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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, ®istry_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;
+}
--- /dev/null
+/*
+ * 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))
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#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
--- /dev/null
+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])
+])
--- /dev/null
+%-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 < $< > $@