From: Quentin Glidic <sardemff7+...@sardemff7.net> Signed-off-by: Quentin Glidic <sardemff7+...@sardemff7.net> ---
I added Wayland support to a GLib-based daemon, which needed main loop integration. It required a GSource for the Wayland fd, and I decided to split this part to make it easier for other projects to reuse that. Here is the code, as a tiny library. I added more relevant to have it integrated in the libwayland codebase rather than in its onw project wrt the size of the library. The coding style is not fully Wayland-compliant but I will fix that if this code is to be accepted. Makefile.am | 6 +- configure.ac | 23 +++++- glib/Makefile.am | 33 ++++++++ glib/libwayland-glib.c | 182 +++++++++++++++++++++++++++++++++++++++++++++ glib/libwayland-glib.h | 43 +++++++++++ glib/libwayland-glib.pc.in | 12 +++ 6 files changed, 297 insertions(+), 2 deletions(-) create mode 100644 glib/Makefile.am create mode 100644 glib/libwayland-glib.c create mode 100644 glib/libwayland-glib.h create mode 100644 glib/libwayland-glib.pc.in diff --git a/Makefile.am b/Makefile.am index ddf39d1..1be6fed 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,7 +2,11 @@ if BUILD_DOCS doc_subdir = doc endif -SUBDIRS = src protocol $(doc_subdir) tests cursor +if ENABLE_GLIB +glib_subdir = glib +endif + +SUBDIRS = src protocol $(doc_subdir) tests cursor $(glib_subdir) ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} diff --git a/configure.ac b/configure.ac index 3b79c54..ec71188 100644 --- a/configure.ac +++ b/configure.ac @@ -50,7 +50,7 @@ AC_CHECK_DECL(TFD_CLOEXEC,[], AC_CHECK_DECL(CLOCK_MONOTONIC,[], [AC_MSG_ERROR("CLOCK_MONOTONIC is needed to compile wayland")], [[#include <time.h>]]) -AC_CHECK_HEADERS([execinfo.h]) +AC_CHECK_HEADERS([execinfo.h errno.h]) AC_ARG_ENABLE([scanner], [AC_HELP_STRING([--disable-scanner], @@ -126,6 +126,25 @@ if test "x$enable_documentation" = "xyes"; then fi AM_CONDITIONAL([HAVE_PUBLICAN], [test "x$PUBLICAN" != "x"]) + +# GLib main loop integration library + +glib_min_major="2" +glib_min_minor="36" +glib_min_version="${glib_min_major}.${glib_min_minor}" + +AC_ARG_ENABLE([glib], + [AC_HELP_STRING([--enable-glib], + [Enable GLib main loop integration library])], + [], + [enable_glib=no]) +if test "x$enable_glib" = "xyes"; then + PKG_CHECK_MODULES(GLIB, [glib-2.0 >= $glib_min_version]) + AC_DEFINE_UNQUOTED([GLIB_VERSION_MIN_REQUIRED], [(G_ENCODE_VERSION(${glib_min_major},${glib_min_minor}))], [The lower GLib version supported]) +fi +AM_CONDITIONAL([ENABLE_GLIB], [test "x$enable_glib" = "xyes"]) + + AC_CONFIG_FILES([Makefile cursor/Makefile cursor/wayland-cursor.pc @@ -134,6 +153,8 @@ AC_CONFIG_FILES([Makefile doc/publican/Makefile doc/doxygen/Makefile doc/man/Makefile + glib/Makefile + glib/libwayland-glib.pc src/Makefile src/wayland-server-uninstalled.pc src/wayland-client-uninstalled.pc diff --git a/glib/Makefile.am b/glib/Makefile.am new file mode 100644 index 0000000..68acece --- /dev/null +++ b/glib/Makefile.am @@ -0,0 +1,33 @@ +LIBWAYLAND_GLIB_CURRENT=0 +LIBWAYLAND_GLIB_REVISION=0 +LIBWAYLAND_GLIB_AGE=0 + +lib_LTLIBRARIES = \ + libwayland-glib.la + +pkginclude_HEADERS = \ + libwayland-glib.h + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = \ + libwayland-glib.pc + + +libwayland_glib_la_SOURCES = \ + libwayland-glib.c + +libwayland_glib_la_CPPFLAGS = \ + -DG_LOG_DOMAIN=\"GWayland\" + +libwayland_glib_la_CFLAGS = \ + $(GCC_CFLAGS) \ + -I$(top_srcdir)/src \ + $(GLIB_CFLAGS) + +libwayland_glib_la_LDFLAGS = \ + -version-info $(LIBWAYLAND_GLIB_CURRENT):$(LIBWAYLAND_GLIB_REVISION):$(LIBWAYLAND_GLIB_AGE) \ + -export-dynamic + +libwayland_glib_la_LIBADD = \ + $(top_builddir)/src/libwayland-client.la \ + $(GLIB_LIBS) diff --git a/glib/libwayland-glib.c b/glib/libwayland-glib.c new file mode 100644 index 0000000..c918374 --- /dev/null +++ b/glib/libwayland-glib.c @@ -0,0 +1,182 @@ +/* + * libwayland-glib - Library to integrate Wayland nicely with GLib + * + * Copyright © 2012-2013 Quentin "Sardem FF7" Glidic + * + * 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_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif /* HAVE_ERRNO_H */ + +#include <glib.h> +#include <wayland-client.h> + +#include <libwayland-glib.h> + +struct _GWaylandSource { + GSource source; + gboolean display_owned; + struct wl_display *display; + gpointer fd; + int error; +}; + +static gboolean +_g_wayland_source_prepare(GSource *source, gint *timeout) +{ + GWaylandSource *self = (GWaylandSource *)source; + + if ( wl_display_flush(self->display) < 0) + self->error = errno; + + *timeout = -1; + return FALSE; +} + +static gboolean +_g_wayland_source_check(GSource *source) +{ + GWaylandSource *self = (GWaylandSource *)source; + + return ( g_source_query_unix_fd(source, self->fd) > 0 ); +} + +static gboolean +_g_wayland_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) +{ + GWaylandSource *self = (GWaylandSource *)source; + + if ( self->error > 0 ) + { + errno = self->error; + if ( callback != NULL ) + return callback(user_data); + return FALSE; + } + + GIOCondition revents; + revents = g_source_query_unix_fd(source, self->fd); + + if ( revents & G_IO_IN ) + { + if ( wl_display_dispatch(self->display) < 0 ) + { + if ( callback != NULL ) + return callback(user_data); + return FALSE; + } + } + + errno = 0; + if ( revents & (G_IO_ERR | G_IO_HUP) ) + { + if ( callback != NULL ) + return callback(user_data); + return FALSE; + } + + return TRUE; +} + +static void +_g_wayland_source_finalize(GSource *source) +{ + GWaylandSource *self = (GWaylandSource *)source; + + if ( self->display_owned ) + wl_display_disconnect(self->display); +} + +static GSourceFuncs _g_wayland_source_funcs = { + _g_wayland_source_prepare, + _g_wayland_source_check, + _g_wayland_source_dispatch, + _g_wayland_source_finalize +}; + + +GWaylandSource * +g_wayland_source_new(GMainContext *context, const gchar *name) +{ + struct wl_display *display; + GWaylandSource *source; + + display = wl_display_connect(name); + if ( display == NULL ) + return NULL; + + source = g_wayland_source_new_for_display(context, display); + source->display_owned = TRUE; + return source; +} + +GWaylandSource * +g_wayland_source_new_for_display(GMainContext *context, struct wl_display *display) +{ + GWaylandSource *source; + + source = (GWaylandSource *)g_source_new(&_g_wayland_source_funcs, sizeof(GWaylandSource)); + + source->display = display; + + source->fd = g_source_add_unix_fd((GSource *)source, wl_display_get_fd(display), G_IO_IN | G_IO_ERR | G_IO_HUP); + + g_source_attach((GSource *)source, context); + + return source; +} + +void +g_wayland_source_ref(GWaylandSource *self) +{ + g_return_if_fail(self != NULL); + + g_source_ref((GSource *)self); +} + +void +g_wayland_source_unref(GWaylandSource *self) +{ + g_return_if_fail(self != NULL); + + g_source_unref((GSource *)self); +} + +void +g_wayland_source_set_error_callback(GWaylandSource *self, GSourceFunc callback, gpointer user_data, GDestroyNotify destroy_notify) +{ + g_return_if_fail(self != NULL); + + g_source_set_callback((GSource *)self, callback, user_data, destroy_notify); +} + +struct wl_display * +g_wayland_source_get_display(GWaylandSource *self) +{ + g_return_val_if_fail(self != NULL, NULL); + + return self->display; +} diff --git a/glib/libwayland-glib.h b/glib/libwayland-glib.h new file mode 100644 index 0000000..ac6a6bb --- /dev/null +++ b/glib/libwayland-glib.h @@ -0,0 +1,43 @@ +/* + * libwayland-glib - Library to integrate Wayland nicely with GLib + * + * Copyright © 2012-2013 Quentin "Sardem FF7" Glidic + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + * + */ + +#ifndef __LIBWAYLAND_GLIB_H__ +#define __LIBWAYLAND_GLIB_H__ + +G_BEGIN_DECLS + +typedef struct _GWaylandSource GWaylandSource; + +GWaylandSource *g_wayland_source_new(GMainContext *context, const gchar *name); +GWaylandSource *g_wayland_source_new_for_display(GMainContext *context, struct wl_display *display); +void g_wayland_source_ref(GWaylandSource *self); +void g_wayland_source_unref(GWaylandSource *self); + +void g_wayland_source_set_error_callback(GWaylandSource *self, GSourceFunc callback, gpointer user_data, GDestroyNotify destroy_notify); +struct wl_display *g_wayland_source_get_display(GWaylandSource *source); + +G_END_DECLS + +#endif /* __LIBWAYLAND_GLIB_H__ */ diff --git a/glib/libwayland-glib.pc.in b/glib/libwayland-glib.pc.in new file mode 100644 index 0000000..17a2387 --- /dev/null +++ b/glib/libwayland-glib.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +pkgincludedir=${includedir}/@PACKAGE@ + +Name: libwayland-glib +Description: Library to integrate Wayland nicely with GLib +Version: @VERSION@ +Requires: glib-2.0 +Libs: -L${libdir} -lwayland-glib +Cflags: -I${pkgincludedir} -- 1.8.4 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel