Adds an initial implementation of a testing tool that uses the unit
test framework to run checks against an arbitrary Wayland compositor.
Note that this is not intended for Weston-specific testing, but for
generic Wayland testing.

Signed-off-by: Jon A. Cruz <j...@osg.samsung.com>

---

Changes from v1:

 - Added test fixture to launch compositor used for tests.
 - Hooked waycheck into "make check"
 - Corrected problem in version binding that was inherited from legacy
    test code.
 - Incorporated misc fixes from code review feedback.
 - Removed files duplicated in rebasing.

---
 .gitignore                                    |    1 +
 Makefile.am                                   |   52 +-
 doc/doxygen/devtools.dox                      |   10 +-
 doc/doxygen/tooldev.doxygen.in                |    3 +-
 doc/doxygen/tools.dox                         |    1 +
 doc/doxygen/tools.doxygen.in                  |    6 +-
 tools/waycheck/rough_draw.c                   |  285 ++++++
 tools/waycheck/rough_draw.h                   |   49 +
 tools/waycheck/waycheck.c                     |  457 +++++++++
 tools/waycheck/waycheck.dox                   |   29 +
 tools/wayland_fixtures/inc/wtst_compfixture.h |   76 ++
 tools/wayland_fixtures/inc/wtst_fixtures.h    |  268 ++++++
 tools/wayland_fixtures/src/wtst_compfixture.c |  411 ++++++++
 tools/wayland_fixtures/src/wtst_fixtures.c    | 1238 +++++++++++++++++++++++++
 14 files changed, 2875 insertions(+), 11 deletions(-)
 create mode 100644 tools/waycheck/rough_draw.c
 create mode 100644 tools/waycheck/rough_draw.h
 create mode 100644 tools/waycheck/waycheck.c
 create mode 100644 tools/waycheck/waycheck.dox
 create mode 100644 tools/wayland_fixtures/inc/wtst_compfixture.h
 create mode 100644 tools/wayland_fixtures/inc/wtst_fixtures.h
 create mode 100644 tools/wayland_fixtures/src/wtst_compfixture.c
 create mode 100644 tools/wayland_fixtures/src/wtst_fixtures.c

diff --git a/.gitignore b/.gitignore
index 11d23da..7278bcf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -106,4 +106,5 @@ weston.ini.5
 /tests/weston-ivi.ini
 internal-screenshot-00.png
 
+/waycheck
 /zuctest
diff --git a/Makefile.am b/Makefile.am
index cbb3b57..72f131e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -971,7 +971,7 @@ endif
 #
 
 noinst_LTLIBRARIES += libshared.la libshared-cairo.la \
-       libzunitc.la libzunitcmain.la
+       libzunitc.la libzunitcmain.la libwayland-fixtures.la
 
 libshared_la_CFLAGS = $(AM_CFLAGS) $(COMPOSITOR_CFLAGS)
 
@@ -1010,6 +1010,24 @@ libshared_cairo_la_SOURCES =                     \
        shared/frame.c                          \
        shared/cairo-util.h
 
+libwayland_fixtures_la_SOURCES = \
+       tools/wayland_fixtures/inc/wtst_compfixture.h   \
+       tools/wayland_fixtures/src/wtst_compfixture.c   \
+       tools/wayland_fixtures/inc/wtst_fixtures.h      \
+       tools/wayland_fixtures/src/wtst_fixtures.c      \
+       shared/helpers.h
+
+libwayland_fixtures_la_CFLAGS = \
+       -I$(top_srcdir)/tools/wayland_fixtures/inc      \
+       -I$(top_srcdir)/tools/zunitc/inc        \
+       $(TEST_CLIENT_CFLAGS)                   \
+       $(AM_CFLAGS)
+
+libwayland_fixtures_la_LIBADD = \
+       $(TEST_CLIENT_LIBS)     \
+       libzunitc.la            \
+       libshared.la
+
 libzunitc_la_SOURCES = \
        tools/zunitc/inc/zunitc/zunitc.h        \
        tools/zunitc/inc/zunitc/zunitc_impl.h   \
@@ -1044,12 +1062,12 @@ libzunitcmain_la_SOURCES = \
        tools/zunitc/src/main.c
 
 libzunitcmain_la_CFLAGS = \
-       $(AM_CFLAGS)                            \
-       -I$(top_srcdir)/tools/zunitc/inc
+       -I$(top_srcdir)/tools/zunitc/inc        \
+       $(AM_CFLAGS)
 
 libzunitcmain_la_LIBADD =      \
-       libzunitc.la            \
-       libshared.la
+       libshared.la            \
+       libzunitc.la
 
 #
 # tests subdirectory
@@ -1063,6 +1081,7 @@ internal_tests =                          \
 shared_tests =                                 \
        config-parser.test                      \
        vertex-clip.test                        \
+       waycheck                                \
        zuctest
 
 module_tests =                                 \
@@ -1304,7 +1323,7 @@ setbacklight_CFLAGS = $(AM_CFLAGS) $(SETBACKLIGHT_CFLAGS)
 setbacklight_LDADD = $(SETBACKLIGHT_LIBS)
 endif
 
-all-local: zuctest$(EXEEXT)
+all-local: waycheck$(EXEEXT) zuctest$(EXEEXT)
 
 noinst_PROGRAMS += zuctest$(EXEEXT)
 
@@ -1320,6 +1339,27 @@ zuctest_SOURCES =                                \
        tools/zunitc/test/fixtures_test.c       \
        tools/zunitc/test/zunitc_test.c
 
+noinst_PROGRAMS += waycheck$(EXEEXT)
+
+waycheck_LDADD =                       \
+       $(TEST_CLIENT_LIBS)             \
+       libwayland-fixtures.la          \
+       libshared.la
+
+waycheck_CFLAGS =                              \
+       -I$(top_srcdir)/tools/zunitc/inc        \
+       -I$(top_srcdir)/tools/wayland_fixtures/inc      \
+       -I$(top_builddir)/clients               \
+       -I$(top_srcdir)/shared                  \
+       $(TEST_CLIENT_CFLAGS)                   \
+       $(AM_CFLAGS)
+
+waycheck_SOURCES =                             \
+       tools/waycheck/waycheck.c               \
+       tools/waycheck/rough_draw.c             \
+       tools/waycheck/rough_draw.h             \
+       shared/helpers.h
+
 EXTRA_DIST +=                                                  \
        tests/weston-tests-env                                  \
        tests/internal-screenshot.ini                           \
diff --git a/doc/doxygen/devtools.dox b/doc/doxygen/devtools.dox
index 2d6672f..08d1572 100644
--- a/doc/doxygen/devtools.dox
+++ b/doc/doxygen/devtools.dox
@@ -28,10 +28,13 @@
 
 - @ref zunitc - Simple test framework
 
+- @ref waycheck - Simple integration/acceptance test tool
+
 @section tools_overview Overview
 
-The tools area currently consists of one sub-project (@ref zunitc) that is
-refined from the prior single weston/tests source folder.
+The tools area currently consists of two sub-projects (@ref zunitc and
+@ref waycheck) that are refined from the prior single weston/tests source
+folder.
 
 @subsection tools_overview_old Old Code Organization
 
@@ -44,7 +47,8 @@ stage where splitting apart into discrete layers was 
warranted.
 @subsection tools_overview_new New Code Organization
 
 The test code that is not weston-specific gets split out to a separate
-folder and/or folders.
+folder and/or folders. Then an additional testing tool 'waycheck' that is
+compositor-agnostic is added.
 
 @dotfile tools_arch_new.gv "Refactored test code organization"
 
diff --git a/doc/doxygen/tooldev.doxygen.in b/doc/doxygen/tooldev.doxygen.in
index b3d86f5..1915975 100644
--- a/doc/doxygen/tooldev.doxygen.in
+++ b/doc/doxygen/tooldev.doxygen.in
@@ -5,7 +5,8 @@ OPTIMIZE_OUTPUT_FOR_C  = YES
 EXTRACT_ALL            = YES
 INPUT                  = \
                       @top_srcdir@/doc/doxygen/devtools.dox \
-                      @top_srcdir@/tools/zunitc
+                      @top_srcdir@/tools/zunitc \
+                      @top_srcdir@/tools/waycheck
 RECURSIVE              = YES
 GENERATE_LATEX         = NO
 DOTFILE_DIRS           = @top_srcdir@/doc/doxygen
diff --git a/doc/doxygen/tools.dox b/doc/doxygen/tools.dox
index 9bbc11d..0be1372 100644
--- a/doc/doxygen/tools.dox
+++ b/doc/doxygen/tools.dox
@@ -28,4 +28,5 @@
 
 - @ref zunitc - Simple test framework
 
+- @ref waycheck - Simple integration/acceptance test tool
 */
diff --git a/doc/doxygen/tools.doxygen.in b/doc/doxygen/tools.doxygen.in
index 613edd4..88c2f65 100644
--- a/doc/doxygen/tools.doxygen.in
+++ b/doc/doxygen/tools.doxygen.in
@@ -5,7 +5,11 @@ OPTIMIZE_OUTPUT_FOR_C  = YES
 INPUT                  = \
                       @top_srcdir@/doc/doxygen/tools.dox \
                       @top_srcdir@/tools/zunitc/doc/zunitc.dox \
-                      @top_srcdir@/tools/zunitc/inc/zunitc/zunitc.h
+                      @top_srcdir@/tools/zunitc/inc/zunitc/zunitc.h \
+                      @top_srcdir@/tools/waycheck/waycheck.dox \
+                      @top_srcdir@/tools/wayland_fixtures/inc/wtst_fixtures.h \
+                      @top_srcdir@/tools/wayland_fixtures/src/wtst_fixtures.c \
+                      @top_srcdir@/tools/waycheck/rough_draw.h
 GENERATE_LATEX         = NO
 DOTFILE_DIRS           = @top_srcdir@/doc/doxygen
 STRIP_FROM_PATH        = @top_srcdir@
diff --git a/tools/waycheck/rough_draw.c b/tools/waycheck/rough_draw.c
new file mode 100644
index 0000000..ae2dd33
--- /dev/null
+++ b/tools/waycheck/rough_draw.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright © 2015 Samsung Electronics Co., Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/**
+ * @file simple drawing for test.
+ *
+ * @todo refactor to use pixman instead of direct manipulation.
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#include "rough_draw.h"
+#include "shared/helpers.h"
+
+/**
+ * Very simple way to track colors.
+ */
+struct colorval {
+       float r;
+       float g;
+       float b;
+       float a;
+       enum wl_shm_format form;
+       int used;
+       uint8_t raw[4];
+};
+
+static void
+populate_color(struct colorval *color, enum wl_shm_format form)
+{
+       memset(color->raw, 0, sizeof(color->raw));
+       color->form = form;
+       switch (form) {
+       case WL_SHM_FORMAT_ARGB8888:
+               color->used = 4;
+               color->raw[3] = (0xff * color->a) + 0.5;
+               color->raw[2] = (0xff * color->r) + 0.5;
+               color->raw[1] = (0xff * color->g) + 0.5;
+               color->raw[0] = (0xff * color->b) + 0.5;
+               break;
+       case WL_SHM_FORMAT_RGB565:
+               color->used = 2;
+               color->raw[1] = (uint8_t)((0x1f * color->r) + 0.5) << 3;
+               color->raw[0] = (0x3f * color->g) + 0.5;
+               color->raw[1] |= 0x07 & (color->raw[0] >> 3);
+               color->raw[0] <<= 5;
+               color->raw[0] |= (uint8_t)((0x1f * color->b) + 0.5);
+               break;
+       default:
+               color->used = 0;
+       }
+}
+
+static void
+fill_rect(uint8_t *raw, struct colorval *color,
+         int width, int height, int stride)
+{
+       int y = 0;
+       for (y = 0; y < height; ++y) {
+               int x = 0;
+               uint8_t *ptr = raw + (y * stride);
+               for (x = 0; x < width; ++x) {
+                       memcpy(ptr, &color->raw[0], color->used);
+                       ptr += color->used;
+               }
+       }
+}
+
+static void
+blend(struct colorval *dest,
+      struct colorval const *val1, struct colorval const *val2,
+      double factor)
+{
+       dest->r = (val1->r * (1.0 - factor)) + (val2->r * factor);
+       dest->g = (val1->g * (1.0 - factor)) + (val2->g * factor);
+       dest->b = (val1->b * (1.0 - factor)) + (val2->b * factor);
+       dest->a = (val1->a * (1.0 - factor)) + (val2->a * factor);
+       populate_color(dest, val1->form);
+}
+
+static void
+hgrad_rect(uint8_t *buf,
+          struct colorval const *val1, struct colorval const *val2,
+          int width, int height, int stride)
+{
+       int x = 0;
+       int y = 0;
+       int pw = val1->used;
+       struct colorval color = {.a=1.0};
+       double dwidth = (double)width;
+       for (x = 0; x < width; ++x) {
+               uint8_t *ptr = buf + x * pw;
+               blend(&color, val1, val2, x / dwidth);
+               for (y = 0; y < height; ++y) {
+                       memcpy(ptr, &color.raw[0], color.used);
+                       ptr += stride;
+               }
+       }
+}
+
+/*
+ * Approximates common color bars with black at 16 and white at 235.
+ */
+static const double lvblk = (16 + 0.00 * (235 - 16)) / 255.0;
+static const double lvwht = (16 + 1.00 * (235 - 16)) / 255.0;
+static const double lvupr = (16 + 0.75 * (235 - 16)) / 255.0;
+static const double lvmid = (16 + 0.40 * (235 - 16)) / 255.0;
+static const double lvb15 = (16 + 0.15 * (235 - 16)) / 255.0;
+static const double lvb_2 = (16 - 0.02 * (235 - 16)) / 255.0;
+static const double lvb02 = (16 + 0.02 * (235 - 16)) / 255.0;
+static const double lvb04 = (16 + 0.04 * (235 - 16)) / 255.0;
+
+/**
+ * Draws a simple color-bars test pattern to the specified buffer.
+ */
+void
+rd_draw_bars(uint8_t *buf, enum wl_shm_format form, int stride,
+            int width, int height)
+{
+       size_t i;
+       int y0, y1, y2;
+       int h1, h2;
+       int w1, w2, w3, w4, hw;
+       int xr;
+       int pw;
+       int xoff;
+       double bar_span;
+       size_t bar_count;
+       struct colorval bars[] = {
+               {.r=lvmid, .g=lvmid, .b=lvmid, .a=1.0},
+               {.r=lvupr, .g=lvupr, .b=lvupr, .a=1.0},
+               {.r=lvupr, .g=lvupr, .b=lvblk, .a=1.0},
+               {.r=lvblk, .g=lvupr, .b=lvupr, .a=1.0},
+               {.r=lvblk, .g=lvupr, .b=lvblk, .a=1.0},
+               {.r=lvupr, .g=lvblk, .b=lvupr, .a=1.0},
+               {.r=lvupr, .g=lvblk, .b=lvblk, .a=1.0},
+               {.r=lvblk, .g=lvblk, .b=lvupr, .a=1.0},
+               {.r=lvmid, .g=lvmid, .b=lvmid, .a=1.0},
+               {.r=lvb15, .g=lvb15, .b=lvb15, .a=1.0},
+               {.r=lvwht, .g=lvwht, .b=lvwht, .a=1.0},
+               {.r=lvblk, .g=lvblk, .b=lvblk, .a=1.0},
+               {.r=lvb_2, .g=lvb_2, .b=lvb_2, .a=1.0},
+               {.r=lvb02, .g=lvb02, .b=lvb02, .a=1.0},
+               {.r=lvb04, .g=lvb04, .b=lvb04, .a=1.0},
+       };
+
+       if (!buf)
+               return;
+
+       for (i = 0; i < ARRAY_LENGTH(bars); ++i)
+               populate_color(&bars[i], form);
+
+       pw = bars[0].used;
+       y0 = ((height * 1.75) / 3);
+       y1 = ((height * 2) / 3);
+       y2 = ((height * 3) / 4);
+       h1 = y1 - y0;
+       h2 = height - y2;
+       w1 = width / 8;
+       w2 = (width * 0.75) / 7;
+       xr = pw * ((width * 7) / 8);
+
+       /* left gray: */
+       fill_rect(buf, &bars[0], w1, y0, stride);
+       fill_rect(buf + (y0 * stride), &bars[3], w1, h1, stride);
+       fill_rect(buf + (y1 * stride), &bars[2], w1, h1, stride);
+       fill_rect(buf + (y2 * stride), &bars[9], w1, h2, stride);
+
+       /* right gray */
+       fill_rect(buf + xr, &bars[0], w1, y0, stride);
+       fill_rect(buf + xr + (y0 * stride), &bars[7], w1, h1, stride);
+       fill_rect(buf + xr + (y1 * stride), &bars[6], w1, h1, stride);
+       fill_rect(buf + xr + (y2 * stride), &bars[9], w1, h2, stride);
+
+       xoff = w1 * pw;
+       fill_rect(buf + xoff + (y0 * stride), &bars[10], w2, h1, stride);
+       fill_rect(buf + xoff + (y1 * stride), &bars[11], w2, h1, stride);
+
+       bar_span = (width * 0.75);
+       bar_count = 7;
+       for (i = 0; i < bar_count; ++i)
+       {
+               int ww = (bar_span * (i + 1)) / bar_count;
+               xoff = (bar_span * i) / bar_count;
+               ww -= xoff;
+               xoff += w1;
+               fill_rect(buf + xoff * pw, &bars[i + 1], ww, y0, stride);
+       }
+
+
+       hw = width - (w1 + w1 + w2);
+       /* Gray horiz: */
+       xoff = w1 + w2;
+       fill_rect(buf + xoff * pw + (y0 * stride), &bars[1], hw, h1, stride);
+       hgrad_rect(buf + xoff * pw + (y1 * stride), &bars[11], &bars[10],
+                  hw, h1, stride);
+
+       /* note - horizontal positions of lower bars are not simple values */
+
+       xoff = (width * 0.85625) / 3;
+       w3 = (width * 0.64375) / 3;
+       fill_rect(buf + w1 * pw + (y2 * stride), &bars[11], width - (w1 * 2),
+                 h2, stride);
+       fill_rect(buf + xoff * pw + (y2 * stride), &bars[10], w3,
+                 h2, stride);
+
+       w4 = (width * 0.10625) / 3;
+       xoff = (width * 1.765625) / 3;
+       fill_rect(buf + xoff * pw + (y2 * stride), &bars[12], w4, h2, stride);
+
+       xoff = (width * 1.98125) / 3;
+       fill_rect(buf + xoff * pw + (y2 * stride), &bars[13], w4, h2, stride);
+
+       xoff = (width * 2.196875) / 3;
+       fill_rect(buf + xoff * pw + (y2 * stride), &bars[14], w4, h2, stride);
+}
+
+/**
+ * Draws a simple cross-hairs image suitable for a cursor to the specified
+ * buffer.
+ */
+void
+rd_draw_crosshairs(uint8_t *buf, enum wl_shm_format form, int stride,
+                  int width, int height)
+{
+       int pw;
+       int x = (width + 1) / 2;
+       int y = (height + 1) / 2;
+       struct colorval fg = {.r=0, .g=0, .b=0, .a=0.5};
+       struct colorval bg = {.r=0.5, .g=0.5, .b=0.5, .a=0.5};
+
+       if (!buf)
+               return;
+
+       populate_color(&fg, form);
+       populate_color(&bg, form);
+       pw = fg.used;
+
+       fill_rect(buf + ((y - 1) * stride), &bg, width, 3, stride);
+       fill_rect(buf + (y * stride), &fg, width, 1, stride);
+
+       fill_rect(buf + ((y - 2) * stride), &bg, width / 3, 5, stride);
+       fill_rect(buf + ((y - 1) * stride), &fg, width / 3, 3, stride);
+       fill_rect(buf + ((y - 2) * stride + (width * 2 / 3) * pw), &bg,
+                 width / 3, 5, stride);
+       fill_rect(buf + ((y - 1) * stride + (width * 2 / 3) * pw), &fg,
+                 width / 3, 3, stride);
+
+
+       fill_rect(buf + (x - 1) * pw, &bg, 3, height, stride);
+       fill_rect(buf + x * pw, &fg, 1, height, stride);
+
+       fill_rect(buf + (x - 2) * pw, &bg, 5, height / 3, stride);
+       fill_rect(buf + (x - 1) * pw, &fg, 3, height / 3, stride);
+
+       fill_rect(buf + (x - 2) * pw + ((height * 2 / 3) * stride), &bg,
+                 5, height / 3, stride);
+       fill_rect(buf + (x - 1) * pw + ((height * 2 / 3) * stride), &fg,
+                 3, height / 3, stride);
+}
diff --git a/tools/waycheck/rough_draw.h b/tools/waycheck/rough_draw.h
new file mode 100644
index 0000000..18e05b3
--- /dev/null
+++ b/tools/waycheck/rough_draw.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright © 2015 Samsung Electronics Co., Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef ROUGH_DRAW_H
+#define ROUGH_DRAW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#include <wayland-client-protocol.h>
+
+void
+rd_draw_bars(uint8_t *buf, enum wl_shm_format form, int stride,
+            int width, int height);
+
+void
+rd_draw_crosshairs(uint8_t *buf, enum wl_shm_format form, int stride,
+                  int width, int height);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ROUGH_DRAW_H */
diff --git a/tools/waycheck/waycheck.c b/tools/waycheck/waycheck.c
new file mode 100644
index 0000000..b0420c0
--- /dev/null
+++ b/tools/waycheck/waycheck.c
@@ -0,0 +1,457 @@
+/*
+ * Copyright © 2015 Samsung Electronics Co., Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdbool.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <sys/mman.h>
+
+#include <linux/input.h>
+#include <wayland-client.h>
+
+
+#include "os-compatibility.h"
+#include "rough_draw.h"
+#include "shared/config-parser.h"
+#include "shared/helpers.h"
+#include "shared/zalloc.h"
+#include "wtst_compfixture.h"
+#include "wtst_fixtures.h"
+#include "zunitc/zunitc.h"
+
+#define ARGB32_SIZE 4
+
+static const uint32_t PIXEL_FORMAT = WL_SHM_FORMAT_ARGB8888;
+
+static struct wtst_comp_fxt *g_fxt = NULL;
+
+static void *
+setup_suite_config(const void *data)
+{
+       struct wtst_comp_fxt *fxt = wtst_comp_fxt_create();
+
+       ZUC_ASSERTG_NOT_NULL(fxt, out);
+
+out:
+       g_fxt = fxt;
+       return fxt;
+}
+
+static void
+cleanup_suite_config(void *data)
+{
+       struct wtst_comp_fxt *fxt = data;
+
+       g_fxt = NULL;
+       ZUC_ASSERT_NOT_NULL(fxt);
+       wtst_comp_fxt_destroy(fxt);
+}
+
+static void *
+setup_test_config(void *data)
+{
+       struct wtst_ctx *ctx = wtst_ctx_create(g_fxt ? g_fxt->sockname : NULL);
+       ZUC_ASSERTG_NOT_NULL(ctx, out);
+
+out:
+       return ctx;
+}
+
+static void
+cleanup_test_config(void *data)
+{
+       struct wtst_ctx *ctx = data;
+       ZUC_ASSERT_NOT_NULL(ctx);
+       wtst_ctx_destroy(ctx);
+}
+
+static struct zuc_fixture base_test_f = {
+       .set_up_test_case = setup_suite_config,
+       .tear_down_test_case = cleanup_suite_config,
+       .set_up = setup_test_config,
+       .tear_down = cleanup_test_config
+};
+
+/* A very simple case that only exercises the test fixture. */
+ZUC_TEST_F(base_test_f, hello_wayland, data)
+{
+       ZUC_ASSERT_NOT_NULL(data);
+}
+
+ZUC_TEST_F(base_test_f, advertises_required, data)
+{
+       int num_required = 0;
+       int i = 0;
+       char const *required[] = {
+               "wl_compositor",
+               "wl_data_device_manager",
+               "wl_output",
+               "wl_seat",
+               "wl_shell",
+               "wl_shm",
+               "wl_subcompositor",
+       };
+       struct wtst_ctx *ctx = data;
+
+       num_required = ARRAY_LENGTH(required);
+       for (i = 0; i < num_required; i++) {
+               ZUC_TRACEPOINT("Check %s\n", required[i]);
+               ZUC_ASSERT_TRUE(wtst_is_global_advertised(ctx, required[i]));
+       }
+}
+
+typedef void (*button_callback_func_t)(uint32_t serial, uint32_t time,
+                                      uint32_t button, uint32_t state);
+
+struct surface_extras {
+       button_callback_func_t button_cb;
+       uint8_t *membuf;
+       struct wl_buffer *buffer;
+       struct wl_surface *cursor;
+       int32_t hit_x;
+       int32_t hit_y;
+};
+
+static void
+setup_surface_extras(struct wtst_surface *wsurf)
+{
+       ZUC_ASSERT_NOT_NULL(wsurf);
+       ZUC_ASSERT_NULL(wsurf->data);
+       struct surface_extras *extras = zalloc(sizeof(*extras));
+       ZUC_ASSERT_NOT_NULL(extras);
+       wsurf->data = extras;
+}
+
+/**
+ * @todo refactor to be more generically helpful then move this along with
+ * the corresponding helper functions to fixtures lib
+ */
+struct wtst_shm_pool {
+       struct wl_shm_pool *pool;
+
+       int fd;
+       uint8_t *membuf;
+       size_t flen;
+       size_t used;
+};
+
+/* Simple testing helpers: */
+static uint8_t *
+wtst_shm_pool_get_membuf(struct wtst_shm_pool *pool)
+{
+       ZUC_ASSERTG_NOT_NULL(pool, err);
+       return pool->membuf;
+err:
+       return NULL;
+}
+
+static struct wl_shm_pool *
+wtst_shm_pool_get_pool(struct wtst_shm_pool *pool)
+{
+       ZUC_ASSERTG_NOT_NULL(pool, err);
+       return pool->pool;
+err:
+       return NULL;
+}
+
+static void
+wtst_shm_pool_consume(struct wtst_shm_pool *pool, size_t mem_used)
+{
+       ZUC_ASSERT_NOT_NULL(pool);
+       pool->used += mem_used;
+}
+
+static struct wtst_shm_pool *
+wtst_create_mempool(struct wl_shm *shm, int fd, size_t flen)
+{
+       struct wtst_shm_pool *wtst_pool = zalloc(sizeof(struct wtst_shm_pool));
+       ZUC_ASSERTG_NOT_NULL(wtst_pool, err);
+
+       wtst_pool->fd = fd;
+       wtst_pool->flen = flen;
+       wtst_pool->membuf = mmap(NULL, flen, PROT_READ | PROT_WRITE,
+                                MAP_SHARED, fd, 0);
+       ZUC_ASSERTG_TRUE(wtst_pool->membuf != MAP_FAILED, err_free);
+
+       wtst_pool->pool = wl_shm_create_pool(shm, fd, flen);
+       ZUC_ASSERTG_NOT_NULL(wtst_pool->pool, err_unmap);
+
+       return wtst_pool;
+err_unmap:
+       munmap(wtst_pool->membuf, flen);
+err_free:
+       free(wtst_pool);
+err:
+       return NULL;
+}
+
+static void
+setup_cursor(struct wtst_shm_pool *pool,
+            unsigned int width, unsigned int height,
+            int32_t hit_x, int32_t hit_y,
+            struct wl_compositor *compositor,
+            struct surface_extras *extras)
+{
+       int32_t stride = width * ARGB32_SIZE;
+       ZUC_ASSERT_NOT_NULL(extras);
+       extras->hit_x = hit_x;
+       extras->hit_y = hit_y;
+
+       extras->cursor = wl_compositor_create_surface(compositor);
+       ZUC_ASSERT_NOT_NULL(extras->cursor);
+
+       extras->membuf = pool->membuf;
+       extras->membuf += pool->used / sizeof(*extras->membuf);
+       rd_draw_crosshairs(extras->membuf, WL_SHM_FORMAT_ARGB8888,
+                          width * ARGB32_SIZE,
+                          width, height);
+
+       extras->buffer = wl_shm_pool_create_buffer(pool->pool,
+                                                  pool->used,
+                                                  width,
+                                                  height,
+                                                  stride,
+                                                  PIXEL_FORMAT);
+       pool->used += width * height * ARGB32_SIZE;
+       ZUC_ASSERT_NOT_NULL(extras->buffer);
+}
+
+static void
+set_button_cb(struct wtst_shell_surface *shell_surface,
+             button_callback_func_t callback)
+{
+       struct wtst_surface *wsurf = NULL;
+       ZUC_ASSERT_NOT_NULL(shell_surface);
+       ZUC_ASSERT_NOT_NULL(shell_surface->surface);
+       ZUC_ASSERT_NOT_NULL(shell_surface->surface->wl_surface);
+
+       wsurf = shell_surface->surface;
+       ZUC_ASSERT_NOT_NULL(wsurf);
+       ZUC_ASSERT_NOT_NULL(wsurf->data);
+
+       ((struct surface_extras *)wsurf->data)->button_cb = callback;
+}
+
+static bool keep_alive = true;
+
+static void
+handle_button(uint32_t serial, uint32_t time,
+             uint32_t button, uint32_t state)
+{
+       keep_alive = false;
+}
+
+static void
+example_test_enter(void *data,
+                  struct wl_pointer *wl_pointer,
+                  uint32_t serial, struct wl_surface *surface,
+                  wl_fixed_t surface_x, wl_fixed_t surface_y)
+{
+       struct wtst_pointer *pointer = data;
+       if (pointer && pointer->focus && pointer->focus->data) {
+               struct surface_extras *extras = pointer->focus->data;
+               wl_surface_attach(extras->cursor, extras->buffer, 0, 0);
+               wl_surface_commit(extras->cursor);
+               wl_pointer_set_cursor(pointer->wl_pointer, serial,
+                                     extras->cursor,
+                                     extras->hit_x, extras->hit_y);
+       }
+}
+
+static void
+example_test_leave(void *data,
+                  struct wl_pointer *wl_pointer, uint32_t serial,
+                  struct wl_surface *wl_surface)
+{
+}
+
+static void
+example_test_motion(void *data,
+                   struct wl_pointer *wl_pointer, uint32_t time,
+                   wl_fixed_t surface_x, wl_fixed_t surface_y)
+{
+}
+
+static void
+example_test_button(void *data,
+                   struct wl_pointer *wl_pointer, uint32_t serial,
+                   uint32_t time, uint32_t button, uint32_t state)
+{
+       struct wtst_pointer *pointer = data;
+       if (pointer && pointer->focus && pointer->focus->data) {
+               struct surface_extras *extras = pointer->focus->data;
+               if (extras->button_cb)
+                       extras->button_cb(serial, time, button, state);
+       }
+}
+
+static void
+example_test_axis(void *data,
+                 struct wl_pointer *wl_pointer, uint32_t time,
+                 uint32_t axis, wl_fixed_t value)
+{
+}
+
+static const struct wl_pointer_listener pointer_listener = {
+       .enter = example_test_enter,
+       .leave = example_test_leave,
+       .motion = example_test_motion,
+       .button = example_test_button,
+       .axis = example_test_axis
+};
+
+ZUC_TEST_F(base_test_f, simple_setup, data)
+{
+       struct wtst_ctx *ctx = data;
+       size_t needed = 0;
+       int anon = 0;
+       const int surf_width = 355;
+       const int surf_height = 200;
+       const int cursor_size = 45;
+       const int mid_hit = cursor_size / 2;
+       struct wtst_shm_pool *pool = NULL;
+       struct wl_buffer *buffer = NULL;
+       struct wtst_shell_surface *sh_surface = NULL;
+
+       keep_alive = false; /* Don't run the main loop for normal testing */
+
+       wtst_set_dump_pointer_events(WTST_DBG_POINTER_ALL
+                                    & ~WTST_DBG_POINTER_MOTION);
+
+       needed = ARGB32_SIZE * surf_width * surf_height;
+       needed += ARGB32_SIZE * cursor_size * cursor_size;
+
+       anon = os_create_anonymous_file(needed);
+       buffer = NULL;
+       pool = wtst_create_mempool(ctx->shm, anon, needed);
+       if (!pool) {
+               close(anon);
+               ZUC_ASSERT_NOT_NULL(pool);
+       } else {
+               struct wl_shm_pool *shpool = NULL;
+               uint8_t *mem = wtst_shm_pool_get_membuf(pool);
+               rd_draw_bars(mem, WL_SHM_FORMAT_ARGB8888,
+                            surf_width * ARGB32_SIZE,
+                            surf_width, surf_height);
+
+               shpool = wtst_shm_pool_get_pool(pool);
+               buffer = wl_shm_pool_create_buffer(shpool,
+                                                0,
+                                                surf_width,
+                                                surf_height,
+                                                surf_width * ARGB32_SIZE,
+                                                PIXEL_FORMAT);
+               wtst_shm_pool_consume(pool,
+                                     surf_width * surf_height * ARGB32_SIZE);
+               ZUC_ASSERT_NOT_NULL(buffer);
+       }
+
+       sh_surface = wtst_create_shell_surface(ctx->compositor, ctx->shell);
+       setup_surface_extras(sh_surface->surface);
+
+       wl_surface_attach(sh_surface->surface->wl_surface, buffer, 0, 0);
+       wl_surface_commit(sh_surface->surface->wl_surface);
+
+       setup_cursor(pool, cursor_size, cursor_size, mid_hit, mid_hit,
+                    ctx->compositor, sh_surface->surface->data);
+
+       set_button_cb(sh_surface, handle_button);
+       wtst_pointer_add_listener(ctx->input->pointer,
+                                 &pointer_listener, ctx->input->pointer);
+
+       while (keep_alive) {
+               if (wl_display_dispatch(ctx->display) < 0)
+                       keep_alive = false;
+       }
+
+       wtst_destroy_shell_surface(sh_surface);
+       wl_buffer_destroy(buffer);
+}
+
+/**
+ * Set up environment and fixture data for launching weston.
+ */
+static void
+prep_for_weston(int argc, char* argv[])
+{
+       char *path = NULL;
+       char *params[] = {
+               "--backend=headless-backend.so",
+               NULL
+       };
+
+       wtst_comp_fxt_set_environment("weston",
+                                     argc > 0 ? argv[0] : NULL,
+                                     getenv("PATH"));
+
+       /* Certain Weston internal code uses this variable */
+       path = wtst_comp_fxt_get_absbase();
+       setenv("WESTON_BUILD_DIR", path, 1);
+       free(path);
+       
+       wtst_comp_fxt_set_params("waycheck", "--log", "--socket", params);
+}
+
+/*
+ * Since we need to hook argv[0] to check on runtime path, we can not use
+ * the stock zunitc main() lib.
+ * This is copied from that with the needed addition of grabbing the name of
+ * the executable.
+ */
+int
+main(int argc, char* argv[])
+{
+       bool helped = false;
+       int rc = zuc_initialize(&argc, argv, &helped);
+
+       /* TODO add command-line param to allow overriding the name. */ 
+       /* This next line is the only addition to the stock zunitc main. */
+       prep_for_weston(argc, argv);
+       
+       if ((rc == EXIT_SUCCESS) && !helped) {
+               /* Stop if any unrecognized parameters were encountered. */
+               if (argc > 1) {
+                       printf("%s: unrecognized option '%s'\n",
+                              argv[0], argv[1]);
+                       printf("Try '%s --help' for more information.\n",
+                              argv[0]);
+                       rc = EXIT_FAILURE;
+               } else {
+                       rc = ZUC_RUN_TESTS();
+               }
+       }
+
+       zuc_cleanup();
+       return rc;
+}
diff --git a/tools/waycheck/waycheck.dox b/tools/waycheck/waycheck.dox
new file mode 100644
index 0000000..66ae65b
--- /dev/null
+++ b/tools/waycheck/waycheck.dox
@@ -0,0 +1,29 @@
+/*
+ * Copyright © 2015 Samsung Electronics Co., 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.
+ */
+
+/**
+@page waycheck
+
+A simple integration/acceptance tool to exercise Wayland compositors.
+
+Tests use @ref zunitc for their infrastructure, and most include use of a 
common wtst_ctx test fixture.
+*/
\ No newline at end of file
diff --git a/tools/wayland_fixtures/inc/wtst_compfixture.h 
b/tools/wayland_fixtures/inc/wtst_compfixture.h
new file mode 100644
index 0000000..f8c9868
--- /dev/null
+++ b/tools/wayland_fixtures/inc/wtst_compfixture.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright © 2015 Samsung Electronics Co., Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WTST_COMP_FIXTURE_H
+#define WTST_COMP_FIXTURE_H
+
+/**
+ * @file
+ * Simple fixture to ensure a proper compositor is running.
+ */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Simple fixture to launch the Wayland compositor to test, defaulting to
+ * weston.
+ */
+struct wtst_comp_fxt {
+       /**
+        * Name of wayland socket used for this instance.
+        * Note that this may be NULL if the defaults are to be used.
+        */
+       const char *sockname;
+
+       /** Context for internal implementation details. */
+       struct wtst_comp_fxt_private *private;
+};
+
+struct wtst_comp_fxt *
+wtst_comp_fxt_create(void);
+
+void
+wtst_comp_fxt_destroy(struct wtst_comp_fxt *fxt);
+
+void
+wtst_comp_fxt_set_environment(const char *compname, const char *argv0,
+                             const char *path);
+
+char *
+wtst_comp_fxt_get_absbase(void);
+
+void
+wtst_comp_fxt_set_params(const char *log_name, const char *log_param,
+                        const char *sock_param, char **params);
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* WTST_COMP_FIXTURE_H */
diff --git a/tools/wayland_fixtures/inc/wtst_fixtures.h 
b/tools/wayland_fixtures/inc/wtst_fixtures.h
new file mode 100644
index 0000000..64f94c1
--- /dev/null
+++ b/tools/wayland_fixtures/inc/wtst_fixtures.h
@@ -0,0 +1,268 @@
+/*
+ * Copyright © 2015 Samsung Electronics Co., Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WTST_FIXTURES_H
+#define WTST_FIXTURES_H
+
+/**
+ * @file
+ * Common helpers for Wayland tests.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <wayland-client.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Test fixture that holds the basics for simple Wayland client testing.
+ *
+ * @see wtst_ctx_create()
+ * @see wtst_ctx_destroy()
+ */
+struct wtst_ctx
+{
+       /** The display the client is connected to. */
+       struct wl_display *display;
+
+       /** The registry the client is connected to. */
+       struct wl_registry *registry;
+
+       /** Main compositor as advertised and updated by the registry. */
+       struct wl_compositor *compositor;
+
+       /**
+        * Main shared memory object as advertised and updated by the
+        * registry.
+        */
+       struct wl_shm *shm;
+
+       /** The seat that is actually used for input events. */
+       struct wtst_input *input;
+
+       /**
+        * Server can have more wl_seats. We need keep them all until we
+        * find the one that we need. After that, the others
+        * will be destroyed, so this list will have the length of 1.
+        * If some day in the future we will need the other seats,
+        * we can just keep them here.
+        */
+       struct wl_list inputs;
+
+       /**
+        * The output used during testing.
+        */
+       struct wtst_output *output;
+
+       /**
+        * The surface used during testing.
+        */
+       struct wtst_surface *surface;
+
+       /**
+        * Flag indicating the presence of DRM.
+        */
+       bool has_wl_drm;
+
+       /** Main shell as advertised and updated by the registry. */
+       struct wl_shell *shell;
+
+       /** Listener registered with the registry. */
+       struct wl_registry_listener *reg_listener;
+
+       /** Context for internal implementation details. */
+       struct wtst_ctx_private *private;
+};
+
+/**
+ * Structure for tracking Wayland registry globals.
+ */
+struct wtst_global {
+       uint32_t name;          /**< name of the global object. */
+       char *interface;        /**< interface the global object implements. */
+       uint32_t version;       /**< given version of the interface
+                                  implemented by the the global object. */
+       struct wl_list link;    /**< list implementation hook. */
+};
+
+/**
+ * Structure for tracking wl_seat instances for input.
+ */
+struct wtst_input {
+       struct wl_seat *wl_seat;        /**< The target Wayland seat. */
+       struct wtst_pointer *pointer;   /**< Pointer for the seat. */
+       struct wtst_keyboard *keyboard; /**< Keyboard for the seat. */
+       struct wtst_touch *touch;       /**< Touch device for the seat. */
+       uint32_t seat_version;          /**< The version of the seat. */
+       char *seat_name;                /**< Name of the seat. */
+       enum wl_seat_capability caps;   /**< Base seat capabilities. */
+       struct wl_list link;            /**< list implementation hook. */
+};
+
+/**
+ * Structure for tracking Wayland pointers.
+ */
+struct wtst_pointer {
+       struct wl_pointer *wl_pointer;  /**< The target Wayland pointer. */
+       struct wtst_surface *focus;     /**< Tracked focused surface. */
+       int x;                          /**< Tracked x coord on the surface
+                                          'focus'. */
+       int y;                          /**< Tracked y coord on the surface
+                                          'focus'. */
+       uint32_t button;
+       uint32_t state;
+       struct wtst_pointer_private *private; /**< private instance data. */
+};
+
+/**
+ * Structure for tracking Wayland keyboards.
+ */
+struct wtst_keyboard {
+       struct wl_keyboard *wl_keyboard;
+       struct wtst_surface *focus;
+       uint32_t key;
+       uint32_t state;
+       uint32_t mods_depressed;
+       uint32_t mods_latched;
+       uint32_t mods_locked;
+       uint32_t group;
+       struct {
+               int rate;
+               int delay;
+       } repeat_info;
+};
+
+/**
+ * Structure for tracking Wayland touch instances.
+ */
+struct wtst_touch {
+       struct wl_touch *wl_touch;      /**< The target Wayland touch. */
+       int down_x;                     /**< Tracked down x position. */
+       int down_y;                     /**< Tracked down y position. */
+       int x;                          /**< Tracked x position. */
+       int y;                          /**< Tracked y potision. */
+       int id;                 /**< Tracked ID. */
+       int up_id;                      /**< Id of last wl_touch.up event */
+       int frame_no;                   /**< Count of frame events. */
+       int cancel_no;                  /**< Count of cancel events. */
+};
+
+/**
+ * Structure for tracking output instances.
+ */
+struct wtst_output {
+       struct wl_output *wl_output;    /**< The target Wayland output. */
+       int x;                          /**< Tracked x. */
+       int y;                          /**< Tracked y. */
+       int width;                      /**< Tracked width. */
+       int height;                     /**< Tracked height. */
+       int scale;                      /**< Tracked scale. */
+       bool initialized;               /**< Tracked initialized flag. */
+};
+
+/**
+ * Strcuture for tracking Wayland surfaces.
+ */
+struct wtst_surface {
+       struct wl_surface *wl_surface;  /**< The target Wayland surface. */
+       struct wl_buffer *wl_buffer;    /**< Buffer created for working with
+                                          this surface. */
+       struct wtst_output *output;     /**< Tracked output for this surface. */
+       int x;                          /**< Tracked x. */
+       int y;                          /**< Tracked y. */
+       int width;                      /**< Tracked width. */
+       int height;                     /**< Tracked height. */
+       void *data;                     /**< private instance data. */
+};
+
+/**
+ * Structure for tracking Wayland shell surfaces.
+ */
+struct wtst_shell_surface {
+       struct wl_shell_surface *wl_shell_surface;      /**< The target Wayland
+                                                          shell surface. */
+       struct wtst_surface *surface; /**< surface that this is wrapping. */
+};
+
+/**
+ * Enum to control what debugging information is dumped during tests.
+ */
+enum wtst_dbgevents_pointer {
+       WTST_DBG_POINTER_NONE = 0x00,
+       WTST_DBG_POINTER_ENTER = 0x01,
+       WTST_DBG_POINTER_LEAVE = 0x02,
+       WTST_DBG_POINTER_MOTION = 0x04,
+       WTST_DBG_POINTER_BUTTON = 0x08,
+       WTST_DBG_POINTER_AXIS = 0x10,
+       WTST_DBG_POINTER_ALL = 0x1f
+};
+
+struct wtst_ctx *
+wtst_ctx_create(const char *display);
+
+struct wtst_ctx *
+wtst_ctx_create_with_surface(const char *display, int width, int height);
+
+struct wtst_ctx *
+wtst_ctx_create_chained(const char *display,
+                       struct wl_registry_listener *reg_listener,
+                       void *reg_data);
+
+struct wtst_ctx *
+wtst_ctx_create_with_surface_chained(const char *display,
+                                    int width, int height,
+                                    struct wl_registry_listener *reg_listener,
+                                    void *reg_data);
+
+void
+wtst_ctx_destroy(struct wtst_ctx *ctx);
+
+int
+wtst_is_global_advertised(struct wtst_ctx *ctx, char const *interface);
+
+int
+wtst_pointer_add_listener(struct wtst_pointer *pointer,
+                         const struct wl_pointer_listener *listener,
+                         void *data);
+
+void
+wtst_set_dump_pointer_events(enum wtst_dbgevents_pointer mask);
+
+struct wtst_shell_surface *
+wtst_create_shell_surface(struct wl_compositor *compositor,
+                         struct wl_shell *shell);
+
+void
+wtst_destroy_shell_surface(struct wtst_shell_surface *wss);
+  
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* WTST_FIXTURES_H */
diff --git a/tools/wayland_fixtures/src/wtst_compfixture.c 
b/tools/wayland_fixtures/src/wtst_compfixture.c
new file mode 100644
index 0000000..02f80b0
--- /dev/null
+++ b/tools/wayland_fixtures/src/wtst_compfixture.c
@@ -0,0 +1,411 @@
+/*
+ * Copyright © 2015 Samsung Electronics Co., Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include "wtst_compfixture.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "shared/zalloc.h"
+#include "zunitc/zunitc.h"
+
+#define MAX_ARGS 256
+
+#define MAX_SOCK_PARAM_LEN 36
+
+#define NS_PER_MS 1000000
+#define WAIT_DURATION_MS 2000
+
+static char g_compname[NAME_MAX] = {0};
+static char g_basepath[PATH_MAX] = {0};
+static char *g_abs_basepath = NULL;
+static char *g_pathenv = NULL;
+static char *g_sock_param = NULL;
+static char *g_log_param = NULL;
+static char *g_log_name = NULL;
+static char **g_extra_params = NULL;
+
+struct wtst_comp_fxt_private {
+       pid_t pid;
+       char sockname[MAX_SOCK_PARAM_LEN];
+};
+
+static struct wtst_comp_fxt_private *
+wtst_comp_fxt_private_create(void)
+{
+       struct wtst_comp_fxt_private *private = zalloc(sizeof(*private));
+
+       ZUC_ASSERTG_NOT_NULL(private, out);
+       private->pid = -1;
+
+out:
+       return private;
+}
+
+static void
+wtst_comp_fxt_private_destroy(struct wtst_comp_fxt_private *private)
+{
+       if (!private)
+               return;
+
+       if (private->pid != -1)
+               kill(private->pid, SIGTERM);
+
+       free(private);
+}
+
+/**
+ * Helper function to create a common name based on the passed in pid.
+ *
+ * @param str the output buffer to write the string to.
+ * @param strlen the size of the output buffer.
+ * @param id the pid to base the name on.
+ */
+static void
+populate_sockname(char *str, size_t strlen, pid_t id)
+{
+       snprintf(str, strlen, "WAYLANDTEST_%u", (unsigned int)id);
+}
+
+static void
+create_logdir(void)
+{
+       char dir[PATH_MAX] = {0};
+       snprintf(dir, sizeof(dir), "%s/logs", g_abs_basepath);
+       mkdir(dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+}
+
+/**
+ * Helper to wait for a local socket with a given name to become available.
+ *
+ * @param sockname the socket name to connect to.
+ */
+static void
+wait_for_local_socket(const char *sockname)
+{
+       socklen_t size = 0;
+       int name_size = 0;
+       int fd = -1;
+       int rc = 0;
+       int code = 0;
+       struct timespec ts = {.tv_nsec = 1 * NS_PER_MS};
+       struct sockaddr_un addr = {.sun_family = AF_LOCAL};
+       const char *runtime_dir =  getenv("XDG_RUNTIME_DIR");
+
+       if (!runtime_dir) {
+               return;
+       }
+       name_size = snprintf(addr.sun_path, sizeof(addr.sun_path),
+                            "%s/%s", runtime_dir, sockname) + 1;
+       if (name_size > (int)sizeof(addr.sun_path))
+               return;
+       size = offsetof(struct sockaddr_un, sun_path) + name_size;
+
+       fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
+       if (fd < 0) {
+               int flags = 0;
+               if (errno != EINVAL)
+                       return;
+               fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+               if (fd < 0)
+                       return;
+               flags = fcntl(fd, F_GETFD);
+               if (flags == -1)
+                       goto exit;
+               if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
+                       goto exit;
+       }
+
+       rc = 0;
+       do {
+               if (rc == -1) {
+                       nanosleep(&ts, NULL);
+                       ts.tv_nsec *= 2;
+               }
+               errno = 0;
+               rc = connect(fd, (struct sockaddr *)&addr, size);
+               code = errno;
+       } while ((rc == -1)
+                && (ts.tv_nsec < WAIT_DURATION_MS * NS_PER_MS)
+                && ((code == ENOENT) || (code == EAGAIN) || (code == EINTR)));
+
+ exit:
+       close(fd);
+}
+
+/**
+ * Creates an instance of the compositor-launch test fixture.
+ *
+ * @return a pointer to a test fixture upon success, NULL otherwise.
+ * @see wtst_comp_fxt_destroy()
+ */
+struct wtst_comp_fxt *
+wtst_comp_fxt_create(void)
+{
+       pid_t pid = -1;
+
+       struct wtst_comp_fxt *fxt = zalloc(sizeof(*fxt));
+       ZUC_ASSERTG_NOT_NULL(fxt, err);
+
+       fxt->private = wtst_comp_fxt_private_create();
+       ZUC_ASSERTG_NOT_NULL(fxt->private, err_free);
+       fxt->sockname = NULL;
+
+       create_logdir();
+
+       fflush(NULL); /* important. avoid duplication of output */
+       pid = fork();
+       switch (pid) {
+       case -1: /* Error forking */
+               printf("%s:%d: error: Problem with fork: %d\n",
+                      __FILE__, __LINE__, errno);
+               ZUC_MARK_FATAL("Error forking");
+               ZUC_ASSERTG_NE(-1, pid, err_free);
+               break;
+       case 0: { /* child */
+               int rc = EXIT_SUCCESS;
+               char **curr = NULL;
+               int argc = 0;
+               char *argv[MAX_ARGS] = {0};
+               pid_t id = getpid();
+               size_t offset = 0;
+               int logfd = -1;
+               char progname[PATH_MAX] = {0};
+               char logname[PATH_MAX] = {0};
+               char sockparam[MAX_SOCK_PARAM_LEN] = {0};
+               char logparam[PATH_MAX] = {0};
+               sigset_t allsigs;
+
+               strcpy(sockparam, g_sock_param ? g_sock_param : "--socket");
+               strcat(sockparam, "=");
+               offset = strlen(sockparam);
+               populate_sockname(sockparam + offset,
+                                 sizeof(sockparam) - offset,
+                                 id);
+
+               if (g_basepath[0])
+                       snprintf(progname, sizeof(progname), "%s/%s",
+                                g_basepath, g_compname);
+               else
+                       snprintf(progname, sizeof(progname), "%s", g_compname);
+
+               /*
+                * Note: the following snprintf's can have (int)id added
+                * with %d to differentiate runs from multiple simultaneous
+                * instances.
+                */
+
+               snprintf(logname, sizeof(logname), "%s/logs/%s-serverlog.txt",
+                        g_abs_basepath,
+                        g_log_name ? g_log_name : "test");
+               unlink(logname);
+
+               snprintf(logparam, sizeof(logparam),
+                        "%s=%s/logs/%s-serverlog.txt",
+                        g_log_param ? g_log_param : "--log", g_abs_basepath,
+                        g_log_name ? g_log_name : "test");
+
+               /* Redirect stdout and stderr to a file */
+               snprintf(logname, sizeof(logname), "%s/logs/%s-log.txt",
+                        g_abs_basepath,
+                        g_log_name ? g_log_name : "test");
+               logfd = open(logname, O_RDWR | O_CREAT | O_TRUNC,
+                            S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
+               dup2(logfd, fileno(stdout));
+               dup2(logfd, fileno(stderr));
+               fflush(stdout);
+               fflush(stderr);
+               close(logfd);
+               logfd = -1;
+
+               argv[argc++] = progname;
+               argv[argc++] = sockparam;
+               argv[argc++] = logparam;
+               if (g_extra_params)
+                       for (curr = g_extra_params;
+                            *curr && (argc < MAX_ARGS); ++curr)
+                               argv[argc++] = *curr;
+               argv[argc] = NULL;
+
+               sigfillset(&allsigs);
+               sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
+
+               rc = execv(progname, argv);
+               
+               zuc_cleanup();
+               exit(rc);
+               break;
+       }
+       default: { /* parent */
+               fxt->private->pid = pid;
+               populate_sockname(fxt->private->sockname,
+                                 sizeof(fxt->private->sockname), pid);
+               fxt->sockname = fxt->private->sockname;
+               wait_for_local_socket(fxt->sockname);
+       }
+       }
+
+       return fxt;
+
+err_free:
+       wtst_comp_fxt_destroy(fxt);
+err:
+       return NULL;
+}
+
+/**
+ * Destroys a test fixture.
+ *
+ * @param fxt pointer to a test fixture to destroy.
+ * It should have previously been created via wtst_comp_fxt_create().
+ * @see wtst_comp_fxt_create()
+ */
+void
+wtst_comp_fxt_destroy(struct wtst_comp_fxt *fxt)
+{
+       if (!fxt)
+               return;
+
+       wtst_comp_fxt_private_destroy(fxt->private);
+       free(fxt);
+}
+
+/**
+ * Set the environment to be used for determining behavior.
+ * This includes storing values in global variables for later use by the
+ * constructor.
+ *
+ * @param compname the name of the compositor to launch.
+ * @param argv0 the first arg passsed to the program, normally containing
+ * the name used to execute the program, or NULL if no args are passed to
+ * main().
+ * @param path the PATH environment in use at the time the program is
+ * launched.
+ */
+void
+wtst_comp_fxt_set_environment(const char *compname,
+                             const char *argv0,
+                             const char *path)
+{
+       char tmp[PATH_MAX] = {0};
+       struct stat st = {.st_size = 0};
+
+       strncpy(g_compname, compname ? compname : "weston", sizeof(g_compname));
+       g_basepath[0] = 0;
+       free(g_pathenv);
+       g_pathenv = NULL;
+       if (path)
+               g_pathenv = strdup(path);
+
+       if (argv0) {
+               char *ptr = strrchr(argv0, '/');
+
+               if (ptr) {
+                       size_t len = ptr - argv0;
+
+                       strncpy(tmp, argv0, len);
+                       strcat(tmp, "/");
+                       strcat(tmp, g_compname);
+                       if (!stat(tmp, &st))
+                               strncpy(g_basepath, argv0, len);
+               }
+       }
+
+       if (g_pathenv && !g_basepath[0]) {
+               char *save = NULL;
+               char *ptr = strdup(g_pathenv);
+               char *val = strtok_r(ptr, ":", &save);
+               while (val && !g_basepath[0]) {
+                       snprintf(tmp, sizeof(tmp), "%s/%s", val, g_compname);
+                       if (!stat(tmp, &st))
+                               strncpy(g_basepath, val, sizeof(g_basepath));
+                       else
+                               val = strtok_r(NULL, ":", &save);
+               }
+               free(ptr);
+       }
+
+       g_abs_basepath = realpath(g_basepath[0] ? g_basepath : ".", NULL);
+}
+
+/**
+ * Returns a copy of the current base path in absolute form.
+ */
+char *
+wtst_comp_fxt_get_absbase(void)
+{
+       return g_abs_basepath ? strdup(g_abs_basepath) : realpath(".", NULL);
+}
+
+/**
+ * Sets parameters to use for launching the compositor.
+ * @param sock_param parameter string to use for setting the socket.
+ * @param log_param parameter string to use for setting the log.
+ * @param params additional parameters to include, or NULL for none.
+ */
+void
+wtst_comp_fxt_set_params(const char *log_name, const char *log_param,
+                        const char *sock_param, char **params)
+{
+       size_t i = 0;
+       size_t count = 0;
+       char **curr = NULL;
+
+       free(g_sock_param);
+       free(g_log_param);
+       free(g_log_name);
+       g_sock_param = sock_param ? strdup(sock_param) : NULL;
+       g_log_param = log_param ? strdup(log_param) : NULL;
+       g_log_name = log_name ? strdup(log_name) : NULL;
+
+
+       if (g_extra_params) {
+               for (curr = g_extra_params; *curr; ++curr) {
+                       free(*curr);
+               }
+               free(g_extra_params);
+               g_extra_params = NULL;    
+       }
+       if (params) {
+               for (curr = params; *curr; ++curr)
+                       count++;
+               g_extra_params = calloc(count + 1, sizeof(char*));
+               for (i = 0; i < count; ++i)
+                       g_extra_params[i] = strdup(params[i]);
+       }
+}
diff --git a/tools/wayland_fixtures/src/wtst_fixtures.c 
b/tools/wayland_fixtures/src/wtst_fixtures.c
new file mode 100644
index 0000000..91225d5
--- /dev/null
+++ b/tools/wayland_fixtures/src/wtst_fixtures.c
@@ -0,0 +1,1238 @@
+/*
+ * Copyright © 2015 Samsung Electronics Co., Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include "wtst_fixtures.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include "shared/helpers.h"
+#include "shared/os-compatibility.h"
+#include "shared/zalloc.h"
+#include "zunitc/zunitc.h"
+
+/**
+ * Private data for implementation of test fixture context.
+ */
+struct wtst_ctx_private {
+
+       /** List of all known global advertised by the registry. */
+       struct wl_list global_list;
+
+       /** List of formats supported by the wl_shm. */
+       struct wl_list format_list;
+
+       /** Chained registry listener to invoke. */
+       struct wl_registry_listener *chained;
+
+       /** Data to pass back to chained registry listener. */
+       void *chained_data;
+
+       /** Current main compositor name advertised by the registry. */
+       uint32_t wl_compositor_name;
+
+       /** Current main compositor version advertised by the registry. */
+       uint32_t wl_compositor_version;
+
+       /** Current shared memory object name advertised by the registry. */
+       uint32_t wl_shm_name;
+
+       /** Current shared memory object version advertised by the registry. */
+       uint32_t wl_shm_version;
+
+       /** Current wl_shell/xdg_shell name advertised by the registry. */
+       uint32_t wl_shell_name;
+
+       /** Current wl_shell/xdg_shell version advertised by the registry. */
+       uint32_t wl_shell_version;
+};
+
+static void
+input_update_devices(struct wtst_input *input);
+
+static enum wtst_dbgevents_pointer g_pointer_dbg_mask = WTST_DBG_POINTER_ALL;
+
+/**
+ * Sets what events will be dumped during testing.
+ *
+ * @param mask a mask of which events to dump out.
+ */
+void
+wtst_set_dump_pointer_events(enum wtst_dbgevents_pointer mask)
+{
+       g_pointer_dbg_mask = mask;
+}
+
+static void
+input_destroy(struct wtst_input *inp)
+{
+       wl_list_remove(&inp->link);
+       if (inp->seat_version >= WL_SEAT_RELEASE_SINCE_VERSION)
+               wl_seat_release(inp->wl_seat);
+       else
+               wl_seat_destroy(inp->wl_seat);
+       free(inp);
+}
+
+/**
+ * Private data for implementation of pointer tracking.
+ */
+struct
+wtst_pointer_private
+{
+       /** opaque data. */
+       void *data;
+
+       /** connected listener. */
+       const struct wl_pointer_listener *listener;
+
+       /** list implementation hook. */
+       struct wl_list link;
+};
+
+static void
+output_handle_geometry(void *data,
+                      struct wl_output *wl_output,
+                      int x, int y,
+                      int physical_width, int physical_height,
+                      int subpixel,
+                      const char *make, const char *model,
+                      int32_t transform)
+{
+       struct wtst_output *output = data;
+
+       output->x = x;
+       output->y = y;
+}
+
+static void
+output_handle_mode(void *data,
+                  struct wl_output *wl_output,
+                  uint32_t flags,
+                  int width, int height,
+                  int refresh)
+{
+       struct wtst_output *output = data;
+
+       if (flags & WL_OUTPUT_MODE_CURRENT) {
+               output->width = width;
+               output->height = height;
+       }
+}
+
+static void
+output_handle_scale(void *data,
+                   struct wl_output *wl_output,
+                   int scale)
+{
+       struct wtst_output *output = data;
+
+       output->scale = scale;
+}
+
+static void
+output_handle_done(void *data,
+                  struct wl_output *wl_output)
+{
+       struct wtst_output *output = data;
+
+       output->initialized = true;
+}
+
+static void
+seat_handle_capabilities(void *data, struct wl_seat *seat,
+                        enum wl_seat_capability caps)
+{
+       struct wtst_input *input = data;
+
+       input->caps = caps;
+
+       /* we will create/update the devices only with the right (test) seat.
+        * If we haven't discovered which seat is the test seat, just
+        * store capabilities and bail out */
+       if (input->seat_name && strcmp(input->seat_name, "test-seat") == 0)
+               input_update_devices(input);
+
+       fprintf(stderr, "test-client: got seat %p capabilities: %x\n",
+               input, caps);
+}
+
+static void
+seat_handle_name(void *data, struct wl_seat *seat, const char *name)
+{
+       struct wtst_input *input = data;
+
+       input->seat_name = strdup(name);
+       ZUC_ASSERT_NOT_NULL(input->seat_name);
+
+       fprintf(stderr, "test-client: got seat %p name: \'%s\'\n",
+               input, name);
+}
+
+static void
+shell_surface_ping(void *data,
+                  struct wl_shell_surface *shell_surface,
+                  uint32_t serial)
+{
+    wl_shell_surface_pong(shell_surface, serial);
+}
+
+static void
+shell_surface_configure(void *data,
+                       struct wl_shell_surface *shell_surface,
+                       uint32_t edges,
+                       int32_t width, int32_t height)
+{
+}
+
+static void
+shell_surface_popup_done(void *data, struct wl_shell_surface *shell_surface)
+{
+}
+
+
+static void
+pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
+                    uint32_t serial, struct wl_surface *wl_surface,
+                    wl_fixed_t x, wl_fixed_t y)
+{
+       struct wtst_pointer *pointer = data;
+       struct wtst_pointer_private *entry = NULL;
+       struct wtst_pointer_private *tmp = NULL;
+
+       pointer->focus = wl_surface_get_user_data(wl_surface);
+       pointer->x = wl_fixed_to_int(x);
+       pointer->y = wl_fixed_to_int(y);
+
+       if (g_pointer_dbg_mask & WTST_DBG_POINTER_ENTER)
+               fprintf(stderr, "test-client: "
+                       "got pointer enter %d %d, surface %p\n",
+                       pointer->x, pointer->y, pointer->focus);
+
+       wl_list_for_each_safe(entry, tmp, &pointer->private->link, link)
+               if (entry->listener && entry->listener->enter)
+                       entry->listener->enter(entry->data, wl_pointer,
+                                              serial, wl_surface, x, y);
+}
+
+static void
+pointer_handle_leave(void *data, struct wl_pointer *wl_pointer,
+                    uint32_t serial, struct wl_surface *wl_surface)
+{
+       struct wtst_pointer *pointer = data;
+       struct wtst_pointer_private *entry = NULL;
+       struct wtst_pointer_private *tmp = NULL;
+
+       pointer->focus = NULL;
+
+       if (g_pointer_dbg_mask & WTST_DBG_POINTER_LEAVE)
+               fprintf(stderr, "test-client: "
+                       "got pointer leave, surface %p\n",
+                       wl_surface_get_user_data(wl_surface));
+
+       wl_list_for_each_safe(entry, tmp, &pointer->private->link, link)
+               if (entry->listener && entry->listener->leave)
+                       entry->listener->leave(entry->data, wl_pointer,
+                                              serial, wl_surface);
+}
+
+static void
+pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
+                     uint32_t time, wl_fixed_t x, wl_fixed_t y)
+{
+       struct wtst_pointer *pointer = data;
+       struct wtst_pointer_private *entry = NULL;
+       struct wtst_pointer_private *tmp = NULL;
+
+       pointer->x = wl_fixed_to_int(x);
+       pointer->y = wl_fixed_to_int(y);
+
+       if (g_pointer_dbg_mask & WTST_DBG_POINTER_MOTION)
+               fprintf(stderr, "test-client: "
+                       "got pointer motion %d %d\n",
+                       pointer->x, pointer->y);
+
+       wl_list_for_each_safe(entry, tmp, &pointer->private->link, link)
+               if (entry->listener && entry->listener->motion)
+                       entry->listener->motion(entry->data, wl_pointer,
+                          time, x, y);
+}
+
+static void
+pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
+                     uint32_t serial, uint32_t time,
+                     uint32_t button, uint32_t state)
+{
+       struct wtst_pointer *pointer = data;
+       struct wtst_pointer_private *entry = NULL;
+       struct wtst_pointer_private *tmp = NULL;
+
+       pointer->button = button;
+       pointer->state = state;
+
+       if (g_pointer_dbg_mask & WTST_DBG_POINTER_BUTTON)
+               fprintf(stderr, "test-client: "
+                       "got pointer button %u %u\n",
+                       button, state);
+
+       wl_list_for_each_safe(entry, tmp, &pointer->private->link, link)
+               if (entry->listener && entry->listener->button)
+                       entry->listener->button(entry->data, wl_pointer,
+                                               serial, time, button, state);
+}
+
+static void
+pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
+                   uint32_t time, uint32_t axis, wl_fixed_t value)
+{
+       struct wtst_pointer *pointer = data;
+       struct wtst_pointer_private *entry = NULL;
+       struct wtst_pointer_private *tmp = NULL;
+
+       fprintf(stderr, "test-client: got pointer axis %u %f\n",
+               axis, wl_fixed_to_double(value));
+
+       wl_list_for_each_safe(entry, tmp, &pointer->private->link, link)
+               if (entry->listener && entry->listener->axis)
+                       entry->listener->axis(entry->data, wl_pointer,
+                                             time, axis, value);
+}
+
+static void
+keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard,
+                      uint32_t format, int fd, uint32_t size)
+{
+       close(fd);
+
+       fprintf(stderr, "test-client: got keyboard keymap\n");
+}
+
+static void
+keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard,
+                     uint32_t serial,
+                     struct wl_surface *wl_surface,
+                     struct wl_array *keys)
+{
+       struct wtst_keyboard *keyboard = data;
+
+       keyboard->focus = wl_surface_get_user_data(wl_surface);
+
+       fprintf(stderr, "test-client: got keyboard enter, surface %p\n",
+               keyboard->focus);
+}
+
+static void
+keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard,
+                     uint32_t serial,
+                     struct wl_surface *wl_surface)
+{
+       struct wtst_keyboard *keyboard = data;
+
+       keyboard->focus = NULL;
+
+       fprintf(stderr, "test-client: got keyboard leave, surface %p\n",
+               wl_surface_get_user_data(wl_surface));
+}
+
+static void
+keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard,
+                   uint32_t serial, uint32_t time, uint32_t key,
+                   uint32_t state)
+{
+       struct wtst_keyboard *keyboard = data;
+
+       keyboard->key = key;
+       keyboard->state = state;
+
+       fprintf(stderr, "test-client: got keyboard key %u %u\n", key, state);
+}
+
+static void
+keyboard_handle_modifiers(void *data,
+                         struct wl_keyboard *wl_keyboard,
+                         uint32_t serial, uint32_t mods_depressed,
+                         uint32_t mods_latched,
+                         uint32_t mods_locked,
+                         uint32_t group)
+{
+       struct wtst_keyboard *keyboard = data;
+
+       keyboard->mods_depressed = mods_depressed;
+       keyboard->mods_latched = mods_latched;
+       keyboard->mods_locked = mods_locked;
+       keyboard->group = group;
+
+       fprintf(stderr, "test-client: got keyboard modifiers %u %u %u %u\n",
+               mods_depressed, mods_latched, mods_locked, group);
+}
+
+static void
+keyboard_handle_repeat_info(void *data,
+                           struct wl_keyboard *wl_keyboard,
+                           int32_t rate, int32_t delay)
+{
+       struct wtst_keyboard *keyboard = data;
+
+       keyboard->repeat_info.rate = rate;
+       keyboard->repeat_info.delay = delay;
+
+       fprintf(stderr, "test-client: got keyboard repeat_info %d %d\n",
+               rate, delay);
+}
+
+static void
+touch_handle_down(void *data, struct wl_touch *wl_touch,
+                 uint32_t serial, uint32_t time,
+                 struct wl_surface *surface,
+                 int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
+{
+       struct wtst_touch *touch = data;
+
+       touch->down_x = wl_fixed_to_int(x_w);
+       touch->down_y = wl_fixed_to_int(y_w);
+       touch->id = id;
+
+       fprintf(stderr, "test-client: got touch down %d %d, surf: %p, id: %d\n",
+               touch->down_x, touch->down_y, surface, id);
+}
+
+static void
+touch_handle_up(void *data, struct wl_touch *wl_touch,
+               uint32_t serial, uint32_t time, int32_t id)
+{
+       struct wtst_touch *touch = data;
+       touch->up_id = id;
+
+       fprintf(stderr, "test-client: got touch up, id: %d\n", id);
+}
+
+static void
+touch_handle_motion(void *data, struct wl_touch *wl_touch,
+                   uint32_t time, int32_t id,
+                   wl_fixed_t x_w, wl_fixed_t y_w)
+{
+       struct wtst_touch *touch = data;
+       touch->x = wl_fixed_to_int(x_w);
+       touch->y = wl_fixed_to_int(y_w);
+
+       fprintf(stderr, "test-client: got touch motion, %d %d, id: %d\n",
+               touch->x, touch->y, id);
+}
+
+static void
+touch_handle_frame(void *data, struct wl_touch *wl_touch)
+{
+       struct wtst_touch *touch = data;
+
+       ++touch->frame_no;
+
+       fprintf(stderr, "test-client: got touch frame (%d)\n", touch->frame_no);
+}
+
+static void
+touch_handle_cancel(void *data, struct wl_touch *wl_touch)
+{
+       struct wtst_touch *touch = data;
+
+       ++touch->cancel_no;
+
+       fprintf(stderr, "test-client: got touch cancel (%d)\n",
+               touch->cancel_no);
+}
+
+static void
+surface_handle_enter(void *data, struct wl_surface *wl_surface,
+                    struct wl_output *output)
+{
+       struct wtst_surface *surface = data;
+
+       surface->output = wl_output_get_user_data(output);
+
+       fprintf(stderr, "test-client: got surface enter output %p\n",
+               surface->output);
+}
+
+static void
+surface_handle_leave(void *data, struct wl_surface *wl_surface,
+                    struct wl_output *output)
+{
+       struct wtst_surface *surface = data;
+
+       surface->output = NULL;
+
+       fprintf(stderr, "test-client: got surface leave output %p\n",
+               wl_output_get_user_data(output));
+}
+
+/**
+ * Item for listing supported memory formats.
+ */
+struct shm_format {
+       uint32_t format;        /**< Format type. */
+
+       struct wl_list link;    /**< list implementation hook. */
+};
+
+static bool
+has_shm_format(struct wtst_ctx *ctx, uint32_t format)
+{
+       bool status = false;
+       struct shm_format *format_info = NULL;
+
+       wl_list_for_each(format_info, &ctx->private->format_list, link)
+               status |= (format == format_info->format);
+
+       return status;
+}
+
+static void
+shm_handle_format(void *data, struct wl_shm *wl_shm, uint32_t format)
+{
+       struct wtst_ctx *ctx = data;
+       struct shm_format *shm_format = zalloc(sizeof(*shm_format));
+
+       ZUC_ASSERT_NOT_NULL(shm_format);
+       shm_format->format = format;
+       wl_list_insert(&ctx->private->format_list, &shm_format->link);
+}
+
+struct wl_shm_listener shm_listener = {
+       shm_handle_format
+};
+
+static const struct wl_shell_surface_listener
+shell_surface_listener = {
+       .ping = shell_surface_ping,
+       .configure = shell_surface_configure,
+       .popup_done = shell_surface_popup_done
+};
+
+static const struct wl_output_listener output_listener = {
+       output_handle_geometry,
+       output_handle_mode,
+       output_handle_done,
+       output_handle_scale,
+};
+
+static const struct wl_seat_listener seat_listener = {
+       seat_handle_capabilities,
+       seat_handle_name,
+};
+
+static const struct wl_pointer_listener pointer_listener = {
+       pointer_handle_enter,
+       pointer_handle_leave,
+       pointer_handle_motion,
+       pointer_handle_button,
+       pointer_handle_axis,
+};
+
+static const struct wl_keyboard_listener keyboard_listener = {
+       keyboard_handle_keymap,
+       keyboard_handle_enter,
+       keyboard_handle_leave,
+       keyboard_handle_key,
+       keyboard_handle_modifiers,
+       keyboard_handle_repeat_info
+};
+
+static const struct wl_touch_listener touch_listener = {
+       touch_handle_down,
+       touch_handle_up,
+       touch_handle_motion,
+       touch_handle_frame,
+       touch_handle_cancel,
+};
+
+static const struct wl_surface_listener surface_listener = {
+       surface_handle_enter,
+       surface_handle_leave
+};
+
+static bool is_singleton_interface(const char *interface)
+{
+        size_t i = 0;
+       const char *known_singletons[] = {
+               "wl_compositor",
+               "wl_display",
+               "wl_compositor",
+               "wl_shm",
+               "wl_data_device_manager",
+       };
+
+       for (i = 0; i < ARRAY_LENGTH(known_singletons); ++i)
+               if (strcmp(known_singletons[i], interface) == 0)
+                       return true;
+
+       return false;
+}
+
+static void
+add_global_advert(struct wtst_ctx *ctx,
+                 uint32_t name,
+                 const char *interface,
+                 uint32_t version)
+{
+       struct wtst_global *curr = NULL;
+       struct wtst_global *tmp = NULL;
+
+       if (!ctx || !ctx->private)
+               return;
+
+       /* See if we've got this interface already */
+       wl_list_for_each(tmp, &ctx->private->global_list, link)
+               if (strcmp(tmp->interface, interface) == 0) {
+                       curr = tmp;
+                       break;
+               }
+
+       if (curr) {
+               /* These are not supposed to change. */
+               if (is_singleton_interface(interface)) {
+                       ZUC_FATAL("Singleton advertised more than once.");
+
+                       ZUC_ASSERT_EQ(curr->name, name);
+                       ZUC_ASSERT_EQ(curr->version, version);
+               }
+       } else {
+               struct wtst_global *glbl = zalloc(sizeof(*glbl));
+               ZUC_ASSERT_NOT_NULL(glbl);
+               glbl->name = name;
+               glbl->interface = strdup(interface);
+               glbl->version = version;
+               wl_list_insert(&ctx->private->global_list, &glbl->link);
+       }
+}
+
+static void
+warn_if_newer(const char *name, uint32_t version, uint32_t used_ver)
+{
+       if (version > used_ver)
+               fprintf(stderr, "test-client: warning: %s advertised "
+                       "version %d but code only supports %d\n",
+                       name, version, used_ver);
+}
+
+static void
+reg_global(void *data,
+          struct wl_registry *registry,
+          uint32_t name,
+          const char *interface,
+          uint32_t version)
+{
+       struct wtst_ctx *ctx = (struct wtst_ctx *)data;
+       struct wtst_input *input = NULL;
+
+       ZUC_ASSERT_STREQ("wl_compositor", wl_compositor_interface.name);
+
+       add_global_advert(ctx, name, interface, version);
+
+       if (strcmp(interface, wl_compositor_interface.name) == 0) {
+               int used_ver = MIN(version, 4);
+
+               warn_if_newer("wl_compositor", version, used_ver);
+               ctx->compositor = wl_registry_bind(registry, name,
+                                                  &wl_compositor_interface,
+                                                  used_ver);
+               ctx->private->wl_compositor_name = name;
+               ctx->private->wl_compositor_version = used_ver;
+       } else if (strcmp(interface, wl_seat_interface.name) == 0) {
+               int used_ver = MIN(version, 5);
+
+               warn_if_newer("wl_seat", version, used_ver);
+               input = zalloc(sizeof(*input));
+               ZUC_ASSERT_NOT_NULL(input);
+               input->wl_seat = wl_registry_bind(registry, name,
+                                                 &wl_seat_interface, used_ver);
+               wl_seat_add_listener(input->wl_seat, &seat_listener, input);
+               input->seat_version = used_ver;
+               wl_list_insert(&ctx->inputs, &input->link);
+       } else if (strcmp(interface, wl_shm_interface.name) == 0) {
+               int used_ver = MIN(version, 1);
+
+               warn_if_newer("wl_shm", version, used_ver);
+               ZUC_ASSERT_NULL(ctx->shm);
+               ctx->shm = wl_registry_bind(registry, name,
+                                           &wl_shm_interface, used_ver);
+               ctx->private->wl_shm_name = name;
+               ctx->private->wl_shm_version = used_ver;
+               wl_shm_add_listener(ctx->shm, &shm_listener, ctx);
+       } else if (strcmp(interface, wl_output_interface.name) == 0) {
+               int used_ver = MIN(version, 2);
+               struct wtst_output *output = zalloc(sizeof(*output));
+
+               warn_if_newer("wl_output", version, used_ver);
+               ZUC_ASSERT_NOT_NULL(output);
+               output->wl_output = wl_registry_bind(registry, name,
+                                                    &wl_output_interface,
+                                                    used_ver);
+               wl_output_add_listener(output->wl_output,
+                                      &output_listener, output);
+               ctx->output = output;
+       } else if (strcmp(interface, wl_shell_interface.name) == 0) {
+               int used_ver = MIN(version, 1);
+
+               warn_if_newer("wl_shell", version, used_ver);
+               ZUC_ASSERT_NULL(ctx->shell);
+               ctx->shell = wl_registry_bind(registry, name,
+                                             &wl_shell_interface, used_ver);
+               ctx->private->wl_shell_name = name;
+               ctx->private->wl_shell_version = used_ver;
+       } else if (strcmp(interface, "wl_drm") == 0) {
+               ctx->has_wl_drm = true;
+       }
+
+       if (ctx->private->chained && ctx->private->chained->global) {
+               ctx->private->chained->global(ctx->private->chained_data,
+                                             registry, name,
+                                             interface, version);
+       }
+}
+
+static void
+reg_global_remove(void *data,
+                 struct wl_registry *registry,
+                 uint32_t name)
+{
+       struct wtst_ctx *ctx = (struct wtst_ctx *)data;
+
+       /*
+        * Note that removal of wl_compositor, wl_shm and wl_shell are not
+        * likely to occur. However, handling the cases will make crashes
+        * easier to debug if some implementation has an odd behavior.
+        */
+       if (name == ctx->private->wl_compositor_name) {
+               if (ctx->compositor)
+                       wl_compositor_destroy(ctx->compositor);
+               ctx->compositor = NULL;
+               ctx->private->wl_compositor_name = 0;
+               ctx->private->wl_compositor_version = 0;
+       } else if (name == ctx->private->wl_shm_name) {
+               if (ctx->shm)
+                       wl_shm_destroy(ctx->shm);
+               ctx->shm = NULL;
+               ctx->private->wl_shm_name = 0;
+               ctx->private->wl_shm_version = 0;
+       } else if (name == ctx->private->wl_shell_name) {
+               if (ctx->shell)
+                       wl_shell_destroy(ctx->shell);
+               ctx->shell = NULL;
+               ctx->private->wl_shell_name = 0;
+               ctx->private->wl_shell_version = 0;
+       }
+
+       if (ctx->private->chained && ctx->private->chained->global_remove) {
+               ctx->private->chained->global_remove(ctx->private->chained_data,
+                                                    registry, name);
+       }
+}
+
+static struct wtst_surface *
+wrap_wl_surface(struct wl_surface *wl_surface)
+{
+       struct wtst_surface *wsurf = NULL;
+       ZUC_ASSERTG_NOT_NULL(wl_surface, out);
+       wsurf = zalloc(sizeof(*wsurf));
+       ZUC_ASSERTG_NOT_NULL(wsurf, out);
+
+       wsurf->wl_surface = wl_surface;
+       wl_surface_add_listener(wl_surface, &surface_listener, wsurf);
+
+out:
+       return wsurf;
+}
+
+/*
+ * TODO follow-up by moving shm buffer code to a common API.
+ */
+static struct wl_buffer *
+create_shm_buffer(struct wl_shm *shm, int width, int height, void **pixels)
+{
+       int stride = width * 4;
+       int size = stride * height;
+       struct wl_shm_pool *pool = NULL;
+       struct wl_buffer *buffer = NULL;
+       int fd = -1;
+       void *data = NULL;
+
+       if (pixels)
+               *pixels = NULL;
+
+       fd = os_create_anonymous_file(size);
+       ZUC_ASSERTG_TRUE(fd >= 0, out);
+
+       data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+       ZUC_ASSERTG_NE(MAP_FAILED, data, out_close);
+
+       pool = wl_shm_create_pool(shm, fd, size);
+       ZUC_ASSERTG_NOT_NULL(pool, out_close);
+       buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride,
+                                          WL_SHM_FORMAT_ARGB8888);
+       ZUC_ASSERTG_NOT_NULL(buffer, out_free);
+
+       if (pixels)
+               *pixels = data;
+
+out_free:
+       wl_shm_pool_destroy(pool);
+out_close:
+       close(fd);
+out:
+       return buffer;
+}
+
+static void
+wtst_surface_destroy(struct wtst_surface *surface)
+{
+       ZUC_ASSERT_NOT_NULL(surface);
+       wl_surface_destroy(surface->wl_surface);
+       free(surface);
+}
+
+static struct wtst_ctx_private *
+wtst_ctx_private_create(void)
+{
+       struct wtst_ctx_private *private = zalloc(sizeof(*private));
+
+       ZUC_ASSERTG_NOT_NULL(private, out);
+
+       wl_list_init(&private->global_list);
+       wl_list_init(&private->format_list);
+
+out:
+       return private;
+}
+
+static void
+wtst_ctx_private_destroy(struct wtst_ctx_private *private)
+{
+       if (!private)
+               return;
+
+       if (!wl_list_empty(&private->global_list)) {
+               struct wtst_global *entry = NULL;
+               struct wtst_global *tmp = NULL;
+               wl_list_for_each_reverse_safe(entry, tmp,
+                                             &private->global_list, link) {
+                       wl_list_remove(&entry->link);
+                       free(entry);
+               }
+       }
+
+       if (!wl_list_empty(&private->format_list)) {
+               struct shm_format *entry = NULL;
+               struct shm_format *tmp = NULL;
+               wl_list_for_each_reverse_safe(entry, tmp,
+                                             &private->format_list, link) {
+                       wl_list_remove(&entry->link);
+                       free(entry);
+               }
+       }
+
+       free(private);
+}
+
+/**
+ * Find the test-seat and set it in client while destroying other inputs.
+ * @todo probably need to defer input selection to higher layers and not
+ * hardcode to "test-seat" here.
+ */
+static void
+wtst_ctx_set_input(struct wtst_ctx *ctx)
+{
+       /* For now prune all but first. Later support looking for named seats */
+       struct wtst_input *inp, *inptmp;
+       wl_list_for_each_safe(inp, inptmp, &ctx->inputs, link) {
+               ZUC_ASSERT_TRUE(inp->seat_name && "BUG: input with no name");
+               if (!ctx->input) {
+                       ctx->input = inp;
+                       input_update_devices(inp);
+               } else {
+                       input_destroy(inp);
+               }
+       }
+
+       /* we keep only one input */
+       ZUC_ASSERT_EQ(1, wl_list_length(&ctx->inputs));
+}
+
+/**
+ * Creates an instance of the test fixture.
+ *
+ * @param display name of the wayland display to connect to or NULL for
+ * the default.
+ * @return a pointer to a test fixture upon success, NULL otherwise.
+ * @see wtst_ctx_destroy()
+ */
+struct wtst_ctx *
+wtst_ctx_create(const char *display)
+{
+       return wtst_ctx_create_chained(display, NULL, NULL);
+}
+
+/**
+ * Creates an instance of the test fixture with a corresponding surface.
+ *
+ * @param display name of the wayland display to connect to or NULL for
+ * the default.
+ * @param width the width for the surface.
+ * @param height the height for the surface.
+ * @return a pointer to a test fixture upon success, NULL otherwise.
+ * @see wtst_ctx_destroy()
+ */
+struct wtst_ctx *
+wtst_ctx_create_with_surface(const char *display, int width, int height)
+{
+       struct wtst_ctx *ctx =
+               wtst_ctx_create_with_surface_chained(display, width, height,
+                                                    NULL, NULL);
+       return ctx;
+}
+
+/**
+ * Creates an instance of the test fixture that is chained and with a
+ * corresponding surface.
+ * Additional registry advertisements will be passed on.
+ *
+ * @param display name for the Wayland display to connect to.
+ * @param width the width for the surface.
+ * @param height the height for the surface.
+ * @param reg_listener the registry listener to chain in.
+ * @param reg_data pointer to pass back to registry listener.
+ * @return a pointer to a test fixture upon success, NULL otherwise.
+ * @see wtst_ctx_destroy()
+ */
+struct wtst_ctx *
+wtst_ctx_create_with_surface_chained(const char *display,
+                                    int width, int height,
+                                    struct wl_registry_listener *reg_listener,
+                                    void *reg_data)
+{
+       struct wl_surface *wl_surface = NULL;
+       struct wtst_surface *surface = NULL;
+       struct wtst_ctx *ctx = wtst_ctx_create_chained(display,
+                                                      reg_listener, reg_data);
+       ZUC_ASSERTG_NOT_NULL(ctx, err);
+
+       wl_surface = wl_compositor_create_surface(ctx->compositor);
+       ZUC_ASSERTG_NOT_NULL(wl_surface, err_free);
+
+       surface = wrap_wl_surface(wl_surface);
+       ZUC_ASSERTG_NOT_NULL(surface, err_destroy);
+
+       ctx->surface = surface;
+
+       surface->width = width;
+       surface->height = height;
+
+       surface->wl_buffer = create_shm_buffer(ctx->shm, width, height,
+                                              &surface->data);
+
+       memset(surface->data, 64, width * height * 4);
+
+       return ctx;
+err_destroy:
+       wl_surface_destroy(wl_surface);
+err_free:
+       wtst_ctx_destroy(ctx);
+err:
+       return NULL;
+}
+
+/**
+ * Creates an instance of the test fixture that is chained.
+ * Additional registry advertisements will be passed on.
+ *
+ * @param display name of the wayland display to connect to or NULL for
+ * the default.
+ * @param reg_listener the registry listener to chain in.
+ * @param reg_data pointer to pass back to registry listener.
+ * @return a pointer to a test fixture upon success, NULL otherwise.
+ * @see wtst_ctx_destroy()
+ */
+struct wtst_ctx *
+wtst_ctx_create_chained(const char *display,
+                       struct wl_registry_listener *reg_listener,
+                       void *reg_data)
+{
+       struct wtst_ctx *ctx = zalloc(sizeof(*ctx));
+       ZUC_ASSERTG_NOT_NULL(ctx, err);
+
+       wl_list_init(&ctx->inputs);
+       ctx->reg_listener = zalloc(sizeof(*(ctx->reg_listener)));
+       ZUC_ASSERTG_NOT_NULL(ctx->reg_listener, err_free);
+
+       /* connect to display. */
+       ctx->display = wl_display_connect(display);
+       ZUC_ASSERTG_NOT_NULL(ctx->display, err_free);
+
+       ctx->private = wtst_ctx_private_create();
+       ZUC_ASSERTG_NOT_NULL(ctx->private, err_free);
+
+       ctx->private->chained = reg_listener;
+       ctx->private->chained_data = reg_data;
+
+       /* setup registry so we can bind to interfaces. */
+       ctx->registry = wl_display_get_registry(ctx->display);
+       ctx->reg_listener->global = reg_global;
+       ctx->reg_listener->global_remove = reg_global_remove;
+       wl_registry_add_listener(ctx->registry,
+                                ctx->reg_listener,
+                                ctx);
+
+       /* this roundtrip makes sure we have all globals
+        * and we have bound to them: */
+       wl_display_roundtrip(ctx->display);
+
+       /* this roundtrip makes sure we got all wl_shm
+        * format and wl_seat.* and wl_output events: */
+       wl_display_roundtrip(ctx->display);
+
+       /* find the right input for us */
+       wtst_ctx_set_input(ctx);
+
+       /* must have WL_SHM_FORMAT_ARGB32 */
+       ZUC_ASSERTG_TRUE(has_shm_format(ctx, WL_SHM_FORMAT_ARGB8888), err_free);
+
+       /* must have an output */
+       ZUC_ASSERTG_NOT_NULL(ctx->output, err_free);
+
+       /* the output must be initialized */
+       ZUC_ASSERTG_TRUE(ctx->output->initialized, err_free);
+
+       /* must have seat set */
+       ZUC_ASSERTG_NOT_NULL(ctx->input, err_free);
+
+       return ctx;
+
+err_free:
+       wtst_ctx_destroy(ctx);
+err:
+       return NULL;
+}
+
+/**
+ * Destroys a test fixture.
+ *
+ * @param ctx pointer to a test fixture to destroy.
+ * It should have previously been created via wtst_ctx_create().
+ * @see wtst_ctx_create()
+ */
+void
+wtst_ctx_destroy(struct wtst_ctx *ctx)
+{
+       if (!ctx)
+               return;
+
+       if (ctx->surface)
+               wtst_surface_destroy(ctx->surface);
+
+       if (ctx->registry)
+               wl_registry_destroy(ctx->registry);
+
+       if (ctx->reg_listener)
+               free(ctx->reg_listener);
+
+       if (ctx->shell)
+               wl_shell_destroy(ctx->shell);
+
+       if (ctx->shm)
+               wl_shm_destroy(ctx->shm);
+
+       if (ctx->compositor)
+               wl_compositor_destroy(ctx->compositor);
+
+       if (ctx->display)
+               wl_display_disconnect(ctx->display);
+
+       wtst_ctx_private_destroy(ctx->private);
+       free(ctx);
+}
+
+static struct wtst_pointer *
+wtst_pointer_create(void)
+{
+       struct wtst_pointer *pointer = zalloc(sizeof(*pointer));
+       ZUC_ASSERTG_NOT_NULL(pointer, err);
+
+       pointer->private = zalloc(sizeof(*pointer->private));
+       ZUC_ASSERTG_NOT_NULL(pointer->private, err_free);
+       wl_list_init(&pointer->private->link);
+
+       return pointer;
+err_free:
+       free(pointer);
+err:
+       return NULL;
+}
+
+/**
+ * Adds a listener to a specified pointer.
+ *
+ * @param pointer the pointer instance to add a listener to.
+ * @param listener the listener to add.
+ * @param data callback data.
+ */
+int
+wtst_pointer_add_listener(struct wtst_pointer *pointer,
+                         const struct wl_pointer_listener *listener,
+                         void *data)
+{
+       struct wtst_pointer_private *priv = zalloc(sizeof(*priv));
+       ZUC_ASSERTG_NOT_NULL(priv, err);
+       priv->data = data;
+       priv->listener = listener;
+       wl_list_insert(&pointer->private->link, &priv->link);
+       return 0;
+err:
+       return -1;
+}
+
+void
+input_update_devices(struct wtst_input *input)
+{
+       struct wl_seat *seat = input->wl_seat;
+       enum wl_seat_capability caps = input->caps;
+
+       if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
+               struct wtst_pointer *pointer = wtst_pointer_create();
+               pointer->wl_pointer = wl_seat_get_pointer(seat);
+               wl_pointer_add_listener(pointer->wl_pointer, &pointer_listener,
+                                       pointer);
+               input->pointer = pointer;
+       } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
+               wl_pointer_destroy(input->pointer->wl_pointer);
+               free(input->pointer);
+               input->pointer = NULL;
+       }
+
+       if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
+               struct wtst_keyboard *keyboard = zalloc(sizeof(*keyboard));
+               ZUC_ASSERT_NOT_NULL(keyboard);
+               keyboard->wl_keyboard = wl_seat_get_keyboard(seat);
+               wl_keyboard_add_listener(keyboard->wl_keyboard,
+                                        &keyboard_listener, keyboard);
+               input->keyboard = keyboard;
+       } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
+               wl_keyboard_destroy(input->keyboard->wl_keyboard);
+               free(input->keyboard);
+               input->keyboard = NULL;
+       }
+
+       if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->touch) {
+               struct wtst_touch *touch = zalloc(sizeof(*touch));
+               ZUC_ASSERT_NOT_NULL(touch);
+               touch->wl_touch = wl_seat_get_touch(seat);
+               wl_touch_add_listener(touch->wl_touch, &touch_listener,
+                                        touch);
+               input->touch = touch;
+       } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->touch) {
+               wl_touch_destroy(input->touch->wl_touch);
+               free(input->touch);
+               input->touch = NULL;
+       }
+}
+
+/**
+ * Determines of an interface has been advertized by the Wayland registry
+ * as being present.
+ *
+ * @param ctx the test fixture in use.
+ * @param interface the name of the interface to query.
+ * @return true if the interface is supported, false otherwise.
+ */
+int
+wtst_is_global_advertised(struct wtst_ctx *ctx, char const *interface)
+{
+       int found = 0;
+       if (ctx && ctx->private && interface) {
+               struct wtst_global *tmp = NULL;
+               wl_list_for_each(tmp, &ctx->private->global_list, link)
+                       if (strcmp(interface, tmp->interface) == 0) {
+                               found = true;
+                               break;
+                       }
+       }
+       return found;
+}
+
+/**
+ * Creates a wl_shell_surface and packages it in a wtst_shell_surface wrapper.
+ */
+struct wtst_shell_surface *
+wtst_create_shell_surface(struct wl_compositor *compositor,
+                         struct wl_shell *shell)
+{
+       struct wl_surface *wl_surface = NULL;
+       struct wtst_shell_surface *wss = zalloc(sizeof(*wss));
+       ZUC_ASSERTG_NOT_NULL(wss, err);
+
+       wl_surface = wl_compositor_create_surface(compositor);
+       ZUC_ASSERTG_NOT_NULL(wl_surface, err_free);
+
+       wss->surface = wrap_wl_surface(wl_surface);
+       ZUC_ASSERTG_NOT_NULL(wss->surface, err_destroy);
+       wl_surface = NULL; /* ownership was transferred. */
+
+       wss->wl_shell_surface =
+               wl_shell_get_shell_surface(shell, wss->surface->wl_surface);
+       ZUC_ASSERTG_NOT_NULL(wss->wl_shell_surface, err_destroy);
+
+       wl_shell_surface_add_listener(wss->wl_shell_surface,
+                                     &shell_surface_listener,
+                                     wss);
+       wl_shell_surface_set_toplevel(wss->wl_shell_surface);
+
+       return wss;
+
+err_destroy:
+       if (wl_surface)
+               wl_surface_destroy(wl_surface);
+
+       if (wss->surface) {
+               if (wss->surface->wl_surface)
+                       wl_surface_destroy(wss->surface->wl_surface);
+               free(wss->surface);
+       }
+err_free:
+       free(wss);
+err:
+       return NULL;
+}
+
+void
+wtst_destroy_shell_surface(struct wtst_shell_surface *wss)
+{
+       ZUC_ASSERT_NOT_NULL(wss);
+       wl_shell_surface_destroy(wss->wl_shell_surface);
+       wtst_surface_destroy(wss->surface);
+       free(wss);
+}
-- 
2.5.0

_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to