summaryrefslogtreecommitdiff
path: root/hw/xfree86/xwayland/xwayland.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/xfree86/xwayland/xwayland.c')
-rw-r--r--hw/xfree86/xwayland/xwayland.c393
1 files changed, 393 insertions, 0 deletions
diff --git a/hw/xfree86/xwayland/xwayland.c b/hw/xfree86/xwayland/xwayland.c
new file mode 100644
index 000000000..122346ced
--- /dev/null
+++ b/hw/xfree86/xwayland/xwayland.c
@@ -0,0 +1,393 @@
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of the
+ * copyright holders not be used in advertising or publicity
+ * pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#ifdef HAVE_XORG_CONFIG_H
+#include "xorg-config.h"
+#endif
+
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <wayland-util.h>
+#include <wayland-client.h>
+
+#include <extinit.h>
+
+#include <xf86Xinput.h>
+#include <xf86Crtc.h>
+#include <xf86Priv.h>
+#include <os.h>
+#include <selection.h>
+
+#include "xwayland.h"
+#include "xwayland-private.h"
+#include "xserver-client-protocol.h"
+
+/*
+ * TODO:
+ * - lose X kb focus when wayland surface loses it
+ * - active grabs, grab owner crack
+ */
+
+static DevPrivateKeyRec xwl_screen_private_key;
+
+static void
+xserver_client(void *data, struct xserver *xserver, int fd)
+{
+ AddClientOnOpenFD(fd);
+}
+
+static void
+xserver_listen_socket(void *data, struct xserver *xserver, int fd)
+{
+ ListenOnOpenFD(fd, TRUE);
+}
+
+const struct xserver_listener xwl_server_listener = {
+ xserver_client,
+ xserver_listen_socket
+};
+
+static void
+xwl_input_delayed_init(void *data, struct wl_callback *callback, uint32_t time)
+{
+ struct xwl_screen *xwl_screen = data;
+
+ ErrorF("xwl_input_delayed_init\n");
+
+ wl_callback_destroy(callback);
+ xwl_input_init(xwl_screen);
+}
+
+static const struct wl_callback_listener delayed_init_listner = {
+ xwl_input_delayed_init
+};
+
+static void
+registry_global(void *data, struct wl_registry *registry, uint32_t id,
+ const char *interface, uint32_t version)
+{
+ struct xwl_screen *xwl_screen = data;
+
+ if (strcmp (interface, "wl_compositor") == 0) {
+ xwl_screen->compositor =
+ wl_registry_bind(registry, id, &wl_compositor_interface, 1);
+ } else if (strcmp(interface, "wl_shm") == 0) {
+ xwl_screen->shm =
+ wl_registry_bind(registry, id, &wl_shm_interface, 1);
+ }
+}
+
+static void
+global_remove(void *data, struct wl_registry *registry, uint32_t name)
+{
+ /* Nothing to do here, wl_compositor and wl_shm should not be removed */
+}
+
+static const struct wl_registry_listener registry_listener = {
+ registry_global,
+ global_remove
+};
+
+static void
+wakeup_handler(void *data, int err, void *read_mask)
+{
+ struct xwl_screen *xwl_screen = data;
+ int ret;
+
+ if (err < 0)
+ return;
+
+ if (!FD_ISSET(xwl_screen->wayland_fd, (fd_set *) read_mask))
+ return;
+
+ ret = wl_display_dispatch(xwl_screen->display);
+ if (ret == -1)
+ FatalError("failed to dispatch Wayland events: %s\n", strerror(errno));
+}
+
+static void
+block_handler(void *data, struct timeval **tv, void *read_mask)
+{
+ struct xwl_screen *xwl_screen = data;
+ int ret;
+
+ ret = wl_display_dispatch_pending(xwl_screen->display);
+ if (ret == -1)
+ FatalError("failed to dispatch Wayland events: %s\n", strerror(errno));
+
+ ret = wl_display_flush(xwl_screen->display);
+ if (ret == -1)
+ FatalError("failed to write to XWayland fd: %s\n", strerror(errno));
+}
+
+int
+xwl_screen_init(struct xwl_screen *xwl_screen, ScreenPtr screen)
+{
+ struct wl_callback *callback;
+
+ xwl_screen->screen = screen;
+
+ if (!dixRegisterPrivateKey(&xwl_screen_private_key, PRIVATE_SCREEN, 0))
+ return BadAlloc;
+
+ dixSetPrivate(&screen->devPrivates,
+ &xwl_screen_private_key, xwl_screen);
+
+ xwl_screen_init_window(xwl_screen, screen);
+
+ xwl_screen_init_cursor(xwl_screen, screen);
+
+ AddGeneralSocket(xwl_screen->wayland_fd);
+ RegisterBlockAndWakeupHandlers(block_handler, wakeup_handler, xwl_screen);
+
+ callback = wl_display_sync(xwl_screen->display);
+ wl_callback_add_listener(callback, &delayed_init_listner, xwl_screen);
+
+ return Success;
+}
+
+struct xwl_screen *
+xwl_screen_get(ScreenPtr screen)
+{
+ return dixLookupPrivate(&screen->devPrivates, &xwl_screen_private_key);
+}
+
+struct xwl_screen *
+xwl_screen_create(void)
+{
+ struct xwl_screen *xwl_screen;
+
+ xwl_screen = calloc(sizeof *xwl_screen, 1);
+ if (xwl_screen == NULL) {
+ ErrorF("calloc failed\n");
+ return NULL;
+ }
+
+ xwl_screen->display = wl_display_connect(NULL);
+ if (xwl_screen->display == NULL) {
+ ErrorF("wl_display_create failed\n");
+ return NULL;
+ }
+
+ return xwl_screen;
+}
+
+Bool
+xwl_screen_pre_init(ScrnInfoPtr scrninfo, struct xwl_screen *xwl_screen,
+ uint32_t flags, struct xwl_driver *driver)
+{
+ int ret;
+
+ noScreenSaverExtension = TRUE;
+
+ xorg_list_init(&xwl_screen->output_list);
+ xorg_list_init(&xwl_screen->seat_list);
+ xorg_list_init(&xwl_screen->damage_window_list);
+ xorg_list_init(&xwl_screen->window_list);
+ xorg_list_init(&xwl_screen->authenticate_client_list);
+ xwl_screen->scrninfo = scrninfo;
+ xwl_screen->driver = driver;
+ xwl_screen->flags = flags;
+ xwl_screen->wayland_fd = wl_display_get_fd(xwl_screen->display);
+
+ if (xorgRootless)
+ xwl_screen->flags |= XWL_FLAGS_ROOTLESS;
+
+ /* Set up listener so we'll catch all events. */
+ xwl_screen->registry = wl_display_get_registry(xwl_screen->display);
+ wl_registry_add_listener(xwl_screen->registry, &registry_listener,
+ xwl_screen);
+ ret = wl_display_roundtrip(xwl_screen->display);
+ if (ret == -1) {
+ xf86DrvMsg(scrninfo->scrnIndex, X_ERROR,
+ "failed to dispatch Wayland events: %s\n", strerror(errno));
+ return FALSE;
+ }
+
+#ifdef WITH_LIBDRM
+ if (xwl_screen->driver->use_drm && !xwl_drm_initialised(xwl_screen))
+ if (xwl_drm_pre_init(xwl_screen) != Success)
+ return FALSE;
+#endif
+
+ xwayland_screen_preinit_output(xwl_screen, scrninfo);
+
+ return TRUE;
+}
+
+int
+xwl_create_window_buffer_shm(struct xwl_window *xwl_window,
+ PixmapPtr pixmap, int fd)
+{
+ struct wl_shm_pool *pool;
+ WindowPtr window = xwl_window->window;
+ ScreenPtr screen = window->drawable.pScreen;
+ VisualID visual = wVisual(window);
+ uint32_t format;
+ int size, stride, bpp, i;
+
+ for (i = 0; i < screen->numVisuals; i++)
+ if (screen->visuals[i].vid == visual)
+ break;
+
+ switch (screen->visuals[i].nplanes) {
+ case 32:
+ format = WL_SHM_FORMAT_ARGB8888;
+ bpp = 4;
+ break;
+ case 24:
+ default:
+ format = WL_SHM_FORMAT_XRGB8888;
+ bpp = 4;
+ break;
+#ifdef WL_SHM_FORMAT_RGB565
+ case 16:
+ /* XXX: Check run-time protocol version too */
+ format = WL_SHM_FORMAT_RGB565;
+ bpp = 2;
+ break;
+#endif
+ }
+
+ stride = pixmap->drawable.width * bpp;
+ size = stride * pixmap->drawable.height;
+
+ pool = wl_shm_create_pool(xwl_window->xwl_screen->shm, fd, size);
+ xwl_window->buffer = wl_shm_pool_create_buffer(pool, 0,
+ pixmap->drawable.width,
+ pixmap->drawable.height,
+ stride, format);
+ wl_shm_pool_destroy(pool);
+
+ return xwl_window->buffer ? Success : BadDrawable;
+}
+
+void xwl_screen_close(struct xwl_screen *xwl_screen)
+{
+ struct xwl_seat *xwl_seat, *itmp;
+ struct xwl_window *xwl_window, *wtmp;
+
+ if (xwl_screen->registry)
+ wl_registry_destroy(xwl_screen->registry);
+ xwl_screen->registry = NULL;
+
+ xorg_list_for_each_entry_safe(xwl_seat, itmp,
+ &xwl_screen->seat_list, link) {
+ wl_seat_destroy(xwl_seat->seat);
+ free(xwl_seat);
+ }
+ xorg_list_for_each_entry_safe(xwl_window, wtmp,
+ &xwl_screen->window_list, link) {
+ wl_buffer_destroy(xwl_window->buffer);
+ wl_surface_destroy(xwl_window->surface);
+ free(xwl_window);
+ }
+
+ xorg_list_init(&xwl_screen->seat_list);
+ xorg_list_init(&xwl_screen->damage_window_list);
+ xorg_list_init(&xwl_screen->window_list);
+ xorg_list_init(&xwl_screen->authenticate_client_list);
+
+ wl_display_roundtrip(xwl_screen->display);
+}
+
+void xwl_screen_destroy(struct xwl_screen *xwl_screen)
+{
+ struct xwl_output *xwl_output, *tmp;
+
+ xorg_list_for_each_entry_safe (xwl_output, tmp, &xwl_screen->output_list, link) {
+ xwl_output_remove(xwl_output);
+ break;
+ }
+
+ free(xwl_screen);
+}
+
+/* DDX driver must call this after submitting the rendering */
+void xwl_screen_post_damage(struct xwl_screen *xwl_screen)
+{
+ struct xwl_window *xwl_window;
+ RegionPtr region;
+ BoxPtr box;
+ int count, i;
+
+ xorg_list_for_each_entry(xwl_window, &xwl_screen->damage_window_list,
+ link_damage) {
+ region = DamageRegion(xwl_window->damage);
+ count = RegionNumRects(region);
+ for (i = 0; i < count; i++) {
+ box = &RegionRects(region)[i];
+ wl_surface_damage(xwl_window->surface,
+ box->x1, box->y1,
+ box->x2 - box->x1,
+ box->y2 - box->y1);
+ }
+ wl_surface_attach(xwl_window->surface,
+ xwl_window->buffer,
+ 0, 0);
+ wl_surface_commit(xwl_window->surface);
+ DamageEmpty(xwl_window->damage);
+ }
+
+ xorg_list_init(&xwl_screen->damage_window_list);
+}
+
+static void *
+xwl_setup(void *module, void *opts, int *errmaj, int *errmin)
+{
+ return module;
+}
+
+static void
+xwl_teardown(void *p)
+{
+}
+
+static XF86ModuleVersionInfo xwl_version_info = {
+ "xwayland",
+ MODULEVENDORSTRING,
+ MODINFOSTRING1,
+ MODINFOSTRING2,
+ XORG_VERSION_CURRENT,
+ 1, 0, 0,
+ ABI_CLASS_EXTENSION,
+ ABI_EXTENSION_VERSION,
+ MOD_CLASS_NONE,
+ { 0, 0, 0, 0 }
+};
+
+_X_EXPORT const XF86ModuleData xwaylandModuleData = {
+ &xwl_version_info,
+ &xwl_setup,
+ &xwl_teardown
+};
+
+int
+xwl_version(void)
+{
+ return xwl_version_info.minorversion;
+}