+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Tiago Vignatti
+ *
+ * xwayland-test: the idea is to guarantee that XWayland infrastructure in
+ * general works with Weston.
+ */
+
+#include "weston-test-runner.h"
+
+#include <assert.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <xcb/xcb.h>
+#include <xcb/dri2.h>
+#include <xf86drm.h>
+
+
+static int
+dri2_open(xcb_connection_t *c, xcb_screen_t *screen)
+{
+ xcb_dri2_connect_cookie_t cookie;
+ xcb_dri2_connect_reply_t *reply;
+ xcb_dri2_authenticate_cookie_t cookie_auth;
+ xcb_dri2_authenticate_reply_t *reply_auth;
+ char *driver, *device;
+ int fd;
+ drm_magic_t magic;
+
+ cookie = xcb_dri2_connect(c, screen->root, XCB_DRI2_DRIVER_TYPE_DRI);
+ reply = xcb_dri2_connect_reply(c, cookie, 0);
+ assert(reply);
+
+ driver = strndup(xcb_dri2_connect_driver_name (reply),
+ xcb_dri2_connect_driver_name_length (reply));
+ device = strndup(xcb_dri2_connect_device_name (reply),
+ xcb_dri2_connect_device_name_length (reply));
+
+ fd = open(device, O_RDWR);
+ printf ("Trying connect to %s driver on %s\n", driver, device);
+ free(driver);
+ free(device);
+
+ if (fd < 0)
+ return -1;
+
+ drmGetMagic(fd, &magic);
+
+ cookie_auth = xcb_dri2_authenticate(c, screen->root, magic);
+ reply_auth = xcb_dri2_authenticate_reply(c, cookie_auth, 0);
+ assert(reply_auth);
+
+ return fd;
+}
+
+static int
+create_window(void)
+{
+ xcb_connection_t *c;
+ xcb_screen_t *screen;
+ xcb_window_t win;
+ int fd;
+
+ c = xcb_connect (NULL, NULL);
+ if (c == NULL) {
+ printf("failed to get X11 connection\n");
+ return -1;
+ }
+
+ screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
+
+ win = xcb_generate_id(c);
+ xcb_create_window(c, XCB_COPY_FROM_PARENT, win, screen->root,
+ 0, 0, 150, 150, 1, XCB_WINDOW_CLASS_INPUT_OUTPUT,
+ screen->root_visual, 0, NULL);
+
+ xcb_change_property (c, XCB_PROP_MODE_REPLACE, win,
+ XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8,
+ 5, "title");
+ xcb_map_window(c, win);
+ xcb_flush(c);
+
+ fd = dri2_open(c, screen);
+ if (fd < 0)
+ return -1;
+
+ xcb_destroy_window(c, win);
+ xcb_disconnect(c);
+ return 0;
+}
+
+/*
+ * Ideally, the X Window Manager (XWM) and Weston Wayland compositor shouldn't
+ * be in the same process because they are using two different protocol
+ * streams in which one does not interface with the other. Probably the
+ * biggest problem with such architecture are the potentials dead locks that
+ * it may occur. So hypothetically, an X client might issue an X11 blocking
+ * request via X (DRI2Authenticate) which in turn sends a Wayland blocking
+ * request for Weston process it. X is blocked. At the same time, XWM might be
+ * trying to process an XChangeProperty, so it requests a blocking X11 call to
+ * the X server (xcb_get_property_reply -> xcb_wait_for_reply) which therefore
+ * will blocks there. It's a deadlock situation and this test is trying to
+ * catch that.
+ */
+static void
+check_dri2_authenticate(void)
+{
+ int i, num_tests;
+
+ /* TODO: explain why num_tests times */
+ num_tests = 10;
+ for (i = 0; i < num_tests; i++)
+ assert(create_window() == 0);
+}
+
+TEST(xwayland_client_test)
+{
+ check_dri2_authenticate();
+ exit(EXIT_SUCCESS);
+}