[PATCH 4/4 v2] Add XWayland API with Present support in mind.

Axel Davy axel.davy at ens.fr
Thu Jan 16 13:29:38 PST 2014


The API enables to use the frame event and the buffer event.

Signed-off-by: Axel Davy <axel.davy at ens.fr>
---
v2: fix indentation + move a call from patch 1 to here + add a missing call
 hw/xfree86/xwayland/Makefile.am        |   1 +
 hw/xfree86/xwayland/xwayland-events.c  | 216 +++++++++++++++++++++++++++++++++
 hw/xfree86/xwayland/xwayland-private.h |   8 ++
 hw/xfree86/xwayland/xwayland-window.c  |   6 +
 hw/xfree86/xwayland/xwayland.h         |  14 +++
 5 files changed, 245 insertions(+)
 create mode 100644 hw/xfree86/xwayland/xwayland-events.c

diff --git a/hw/xfree86/xwayland/Makefile.am b/hw/xfree86/xwayland/Makefile.am
index 22ab154..cc45444 100644
--- a/hw/xfree86/xwayland/Makefile.am
+++ b/hw/xfree86/xwayland/Makefile.am
@@ -21,6 +21,7 @@ libxwayland_la_SOURCES =			\
 	xwayland-output.c			\
 	xwayland-cursor.c			\
 	xwayland-window.c			\
+	xwayland-events.c			\
 	xwayland-private.h			\
 	drm-client-protocol.h			\
 	drm-protocol.c				\
diff --git a/hw/xfree86/xwayland/xwayland-events.c b/hw/xfree86/xwayland/xwayland-events.c
new file mode 100644
index 0000000..3a986bf
--- /dev/null
+++ b/hw/xfree86/xwayland/xwayland-events.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright © 2014 Axel Davy
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of the
+ * copyright holders not be used in advertising or publicity
+ * pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+
+#include <unistd.h>
+
+#include <wayland-util.h>
+#include <wayland-client.h>
+
+#include <xf86Crtc.h>
+#include "xwayland.h"
+#include "xwayland-private.h"
+
+
+/*
+ * Handling of frame events and buffer events.
+ * API to use them
+ */
+
+struct _todo
+{
+    union
+    {
+	todo_func_frame tff;
+	todo_func_buffer tfb;
+    } tocall;
+    void *args;
+    struct wl_list link;
+};
+
+static void
+event_todo_free(struct wl_list *todo_list)
+{
+    struct _todo *pos, *tmp;
+    wl_list_for_each_safe(pos, tmp, todo_list, link) {
+	wl_list_remove(&pos->link);
+	free(pos);
+    }
+}
+
+static const struct wl_callback_listener frame_listener;
+
+static void
+frame_listener_callback(void *data,
+			struct wl_callback *callback, uint32_t time)
+{
+    struct xwl_window *xwl_window = data;
+    struct wl_list todo_list;
+    struct _todo *todo;
+
+    wl_callback_destroy(xwl_window->frame_callback);
+    xwl_window->frame_callback = wl_surface_frame(xwl_window->surface);
+    wl_callback_add_listener(xwl_window->frame_callback,
+			     &frame_listener, xwl_window);
+
+    if (wl_list_empty(&xwl_window->frame_todo))
+	return;
+
+    /* todo funcs are able to ask to be recalled */
+
+    wl_list_init(&todo_list);
+    wl_list_insert_list(&todo_list, &xwl_window->frame_todo);
+    wl_list_init(&xwl_window->frame_todo);
+    wl_list_for_each(todo, &todo_list, link)
+	todo->tocall.tff(0, time, todo->args);
+    event_todo_free(&todo_list);
+
+    /* We need to commit to let the compositor know the new frame callback */
+    if (!wl_list_empty(&xwl_window->frame_todo)) {
+	/* reverse the list. It is useful to keep the order between two
+	 * waiting functions that keep adding themselves to the todo list */
+	wl_list_init(&todo_list);
+	wl_list_insert_list(&todo_list, &xwl_window->frame_todo);
+	wl_list_init(&xwl_window->frame_todo);
+	wl_list_for_each(todo, &todo_list, link)
+	    wl_list_insert(&xwl_window->frame_todo, &todo->link);
+	wl_surface_commit(xwl_window->surface);
+    }
+}
+
+
+
+static const struct wl_callback_listener frame_listener = {
+    frame_listener_callback
+};
+
+
+static void
+wl_buffer_release_event(void *data, struct wl_buffer *buffer)
+{
+    struct xwl_pixmap *xwl_pixmap = data;
+    struct wl_list todo_list;
+    struct _todo *todo;
+
+    if (wl_list_empty(&xwl_pixmap->buffer_todo))
+	return;
+    wl_list_init(&todo_list);
+    wl_list_insert_list(&todo_list, &xwl_pixmap->buffer_todo);
+    wl_list_init(&xwl_pixmap->buffer_todo);
+    wl_list_for_each(todo, &todo_list, link)
+	todo->tocall.tfb(0, todo->args);
+    event_todo_free(&todo_list);
+}
+
+static struct wl_buffer_listener wl_buffer_listener = {
+    wl_buffer_release_event
+};
+
+void
+create_frame_listener(struct xwl_window *xwl_window)
+{
+    wl_list_init(&xwl_window->frame_todo);
+    xwl_window->frame_callback = wl_surface_frame(xwl_window->surface);
+    wl_callback_add_listener(xwl_window->frame_callback,
+			     &frame_listener, xwl_window);
+    wl_surface_commit(xwl_window->surface);
+}
+
+void
+destroy_frame_listener(struct xwl_window *xwl_window)
+{
+    struct _todo *pos, *tmp;
+    if (!xwl_window->frame_callback)
+	return;
+    wl_callback_destroy(xwl_window->frame_callback);
+    xwl_window->frame_callback = NULL;
+
+    wl_list_for_each_safe(pos, tmp, &xwl_window->frame_todo, link) {
+	pos->tocall.tff(XWL_TODO_OBJECT_DESTRUCTION, 0, pos->args);
+	wl_list_remove(&pos->link);
+	free(pos);
+    }
+}
+
+void
+create_buffer_listener(struct xwl_pixmap *xwl_pixmap)
+{
+    wl_list_init(&xwl_pixmap->buffer_todo);
+    wl_buffer_add_listener(xwl_pixmap->buffer, &wl_buffer_listener,
+			   xwl_pixmap);
+}
+
+void
+destroy_buffer_listener(struct xwl_pixmap *xwl_pixmap)
+{
+    struct _todo *pos, *tmp;
+    wl_list_for_each_safe(pos, tmp, &xwl_pixmap->buffer_todo, link) {
+	pos->tocall.tfb(XWL_TODO_OBJECT_DESTRUCTION, pos->args);
+	wl_list_remove(&pos->link);
+	free(pos);
+    }
+}
+
+Bool
+xwl_add_frame_todo(WindowPtr window, todo_func_frame tocall, void *arg)
+{
+    struct xwl_window *xwl_window = get_xwl_window(window);
+    struct _todo *todo;
+
+    if (!xwl_window)
+	return FALSE;
+    if (!xwl_window->frame_callback)
+	create_frame_listener(xwl_window);
+    if (!xwl_window->frame_callback)
+	return FALSE;
+    if (wl_list_empty(&xwl_window->frame_todo))
+	wl_surface_commit(xwl_window->surface);
+    todo = calloc(sizeof(struct _todo), 1);
+    if (!todo)
+	return FALSE;
+    todo->tocall.tff = tocall;
+    todo->args = arg;
+    wl_list_insert(&xwl_window->frame_todo, &todo->link);
+    return TRUE;
+}
+
+Bool
+xwl_add_buffer_release_todo(WindowPtr window,
+			    todo_func_buffer tocall, void *arg)
+{
+    struct xwl_window *xwl_window = get_xwl_window(window);
+    struct xwl_pixmap *xwl_pixmap;
+    struct _todo *todo;
+    if (!xwl_window)
+	return FALSE;
+    xwl_pixmap = xwl_window_get_buffer(xwl_window);
+    todo = calloc(sizeof(struct _todo), 1);
+    if (!todo)
+	return FALSE;
+    todo->tocall.tfb = tocall;
+    todo->args = arg;
+    wl_list_insert(&xwl_pixmap->buffer_todo, &todo->link);
+    return TRUE;
+}
diff --git a/hw/xfree86/xwayland/xwayland-private.h b/hw/xfree86/xwayland/xwayland-private.h
index 3131dac..3731f43 100644
--- a/hw/xfree86/xwayland/xwayland-private.h
+++ b/hw/xfree86/xwayland/xwayland-private.h
@@ -33,10 +33,13 @@ struct xwl_window {
     DamagePtr			 damage;
     struct xorg_list		 link;
     struct xorg_list		 link_damage;
+    struct wl_callback    	*frame_callback;
+    struct wl_list		 frame_todo;
 };
 
 struct xwl_pixmap {
     struct wl_buffer		*buffer;
+    struct wl_list		 buffer_todo;
 };
 
 struct xwl_output;
@@ -144,6 +147,11 @@ void xwl_pixmap_attach_buffer(PixmapPtr pixmap, struct wl_buffer *buffer);
 struct xwl_pixmap *xwl_window_get_buffer(struct xwl_window *xwl_window);
 struct xwl_window *get_xwl_window(WindowPtr window);
 
+void create_frame_listener(struct xwl_window* xwl_window);
+void destroy_frame_listener(struct xwl_window* xwl_window);
+void create_buffer_listener(struct xwl_pixmap *xwl_pixmap);
+void destroy_buffer_listener(struct xwl_pixmap* xwl_pixmap);
+
 extern const struct xserver_listener xwl_server_listener;
 
 #endif /* _XWAYLAND_PRIVATE_H_ */
diff --git a/hw/xfree86/xwayland/xwayland-window.c b/hw/xfree86/xwayland/xwayland-window.c
index 1e6c09b..b9fdbbb 100644
--- a/hw/xfree86/xwayland/xwayland-window.c
+++ b/hw/xfree86/xwayland/xwayland-window.c
@@ -72,6 +72,7 @@ xwl_pixmap_attach_buffer(PixmapPtr pixmap, struct wl_buffer *buffer)
 	return;
     }
     xwl_pixmap->buffer = buffer;
+    create_buffer_listener(xwl_pixmap);
     dixSetPrivate(&pixmap->devPrivates, &xwl_pixmap_private_key, xwl_pixmap);
 }
 
@@ -221,6 +222,10 @@ xwl_unrealize_window(WindowPtr window)
     if (!xwl_window)
 	return ret;
 
+    /* The frame listener is created automatically when needed.
+     * Clean it if needed. */
+    destroy_frame_listener(xwl_window);
+
     wl_surface_destroy(xwl_window->surface);
     xorg_list_del(&xwl_window->link);
     if (RegionNotEmpty(DamageRegion(xwl_window->damage)))
@@ -262,6 +267,7 @@ xwl_destroy_pixmap(PixmapPtr pixmap)
 	struct xwl_pixmap *xwl_pixmap =
 	    dixLookupPrivate(&pixmap->devPrivates, &xwl_pixmap_private_key);
 	if (xwl_pixmap) {
+	    destroy_buffer_listener(xwl_pixmap);
 	    wl_buffer_destroy(xwl_pixmap->buffer);
 	    dixSetPrivate(&pixmap->devPrivates, &xwl_pixmap_private_key,
 			  NULL);
diff --git a/hw/xfree86/xwayland/xwayland.h b/hw/xfree86/xwayland/xwayland.h
index c380618..daf87f6 100644
--- a/hw/xfree86/xwayland/xwayland.h
+++ b/hw/xfree86/xwayland/xwayland.h
@@ -38,6 +38,13 @@ struct xwl_driver {
                                 PixmapPtr pixmap);
 };
 
+/* This flag indicated the todo_func is called because the object
+ * is beeing destroyed */
+#define XWL_TODO_OBJECT_DESTRUCTION 0x01
+
+typedef void (*todo_func_buffer)(int flags, void *arg);
+typedef void (*todo_func_frame)(int flags, uint32_t time, void *arg);
+
 #define XWL_FLAGS_ROOTLESS 0x01
 
 extern _X_EXPORT int
@@ -90,4 +97,11 @@ extern _X_EXPORT int
 xwl_create_window_buffer_shm(struct xwl_window *xwl_window,
 			     PixmapPtr pixmap, int fd);
 
+extern _X_EXPORT Bool
+xwl_add_frame_todo(WindowPtr window, todo_func_frame tocall, void *arg);
+
+extern _X_EXPORT Bool
+xwl_add_buffer_release_todo(WindowPtr window,
+			    todo_func_buffer tocall, void *arg);
+
 #endif /* _XWAYLAND_H_ */
-- 
1.8.3.2



More information about the wayland-devel mailing list