Reimplement the SVG validation using libxml instead of librsvg.

SVG validation should check for the ID and classes of each control (to avoid the error Jason pointed out initially with one of the SVG image), but librsvg is not the best tool for this, so reimplemented the SVG validation using libxml2 instead.

Patch updated.
>From 1cd785495d65b8ff133a91dfcbbfddb2d5032ff9 Mon Sep 17 00:00:00 2001
From: Olivier Fourdan <ofour...@redhat.com>
Date: Mon, 29 Oct 2012 18:08:27 +0100
Subject: [PATCH 3/4] tools: add tablet image viewer
 test: add image validation

for tablet images.

Built is optional and depends on availability of GTK+-2.x
librsvg-2.x and libxml-2.0 libraries.
---
 configure.ac               |    6 +
 test/Makefile.am           |    7 +
 test/tablet-svg-validity.c |  242 +++++++++++++++++++++++++++
 tools/Makefile.am          |    8 +
 tools/show-svg-image.c     |  389 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 652 insertions(+), 0 deletions(-)
 create mode 100644 test/tablet-svg-validity.c
 create mode 100644 tools/show-svg-image.c

diff --git a/configure.ac b/configure.ac
index 3fd7aa9..9b3ed73 100644
--- a/configure.ac
+++ b/configure.ac
@@ -32,6 +32,12 @@ AM_CONDITIONAL(HAVE_DOXYGEN, test "x$HAVE_DOXYGEN" = xyes)
 
 PKG_CHECK_MODULES(GLIB, glib-2.0 gudev-1.0)
 
+PKG_CHECK_MODULES(LIBXML, libxml-2.0 glib-2.0, HAVE_LIBXML="yes", HAVE_LIBXML="no")
+AM_CONDITIONAL(HAVE_LIBXML, test x$HAVE_LIBXML = xyes)
+
+PKG_CHECK_MODULES(GTK2, librsvg-2.0 glib-2.0 gtk+-2.0, HAVE_GTK2="yes", HAVE_GTK2="no")
+AM_CONDITIONAL(HAVE_GTK2, test x$HAVE_GTK2 = xyes)
+
 AC_CONFIG_FILES([Makefile
                  data/Makefile
                  data/images/Makefile
diff --git a/test/Makefile.am b/test/Makefile.am
index 6be4403..6b71c85 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -8,6 +8,13 @@ load_LDADD=$(top_builddir)/libwacom/libwacom.la
 dbverify_LDADD=$(top_builddir)/libwacom/libwacom.la
 tablet_validity_LDADD=$(top_builddir)/libwacom/libwacom.la
 
+if HAVE_LIBXML
+noinst_PROGRAMS += tablet-svg-validity
+tablet_svg_validity_SOURCES = tablet-svg-validity.c
+tablet_svg_validity_LDADD = $(top_builddir)/libwacom/libwacom.la $(LIBXML_LIBS)
+tablet_svg_validity_CFLAGS = $(LIBXML_CFLAGS)
+endif
+
 clean-local: clean-local-check
 .PHONY: clean-local-check
 
diff --git a/test/tablet-svg-validity.c b/test/tablet-svg-validity.c
new file mode 100644
index 0000000..f3eb0e3
--- /dev/null
+++ b/test/tablet-svg-validity.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright © 2012 Red Hat, Inc.
+ *
+ * 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 Red Hat
+ * not be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission.  Red
+ * Hat makes no representations about the suitability of this software
+ * for any purpose.  It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL THE AUTHORS 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.
+ *
+ * Authors:
+ *        Olivier Fourdan <ofour...@redhat.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libxml/parser.h>
+#include <libxml/xmlmemory.h>
+#include <glib.h>
+#include "libwacom.h"
+
+static xmlNodePtr
+verify_has_sub (xmlNodePtr cur, char *sub)
+{
+
+	cur = cur->xmlChildrenNode;
+	while (cur != NULL) {
+		xmlChar *prop;
+		prop = xmlGetProp(cur, "id");
+		if (prop) {
+			int status = xmlStrcmp(prop, (const xmlChar *) sub);
+			xmlFree(prop);
+			if (status == 0)
+				return cur;
+		}
+		cur = cur->next;
+	}
+
+	return NULL;
+}
+
+static gboolean
+class_found (gchar **classes, gchar *value)
+{
+	gchar **ptr = classes;
+	while (*ptr) {
+		if (strcmp (*ptr++, value) == 0)
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
+static void
+verify_has_class (xmlNodePtr cur, gchar *expected)
+{
+
+	xmlChar *prop;
+	gchar  **classes_present;
+	gchar  **classes_expected;
+	gchar  **ptr;
+
+	prop = xmlGetProp(cur, "class");
+	g_assert (prop != NULL);
+	g_assert (strlen(prop) > 0);
+
+	classes_present = g_strsplit (prop, " ", -1);
+	classes_expected = g_strsplit (expected, " ", -1);
+	ptr = classes_expected;
+
+	while (*ptr)
+		g_assert (class_found (classes_present, *ptr++));
+
+	g_strfreev (classes_present);
+	g_strfreev (classes_expected);
+}
+
+static void
+check_button (xmlNodePtr cur, WacomDevice *device, char button, gchar *type)
+{
+	char             *sub;
+	char             *class;
+	xmlNodePtr        node;
+	WacomButtonFlags  flags;
+
+	/* Check ID */
+	sub = g_strdup_printf ("%s%c", type, button);
+	node = verify_has_sub (cur, sub);
+	g_assert (node != NULL);
+	g_free (sub);
+
+	/* Check class */
+	flags = libwacom_get_button_flag(device, button);
+	if (flags & WACOM_BUTTON_MODESWITCH)
+		class = g_strdup_printf ("%c ModeSwitch %s", button, type);
+	else
+		class = g_strdup_printf ("%c %s", button, type);
+	verify_has_class (node, class);
+	g_free (class);
+}
+
+static void
+check_touch (xmlNodePtr cur, gchar *id, gchar *type)
+{
+	char             *sub;
+	char             *class;
+	xmlNodePtr        node;
+	WacomButtonFlags  flags;
+
+	node = verify_has_sub (cur, id);
+	g_assert (node != NULL);
+
+	class = g_strdup_printf ("%s %s", id, type);
+	verify_has_class (node, class);
+	g_free (class);
+
+	sub = g_strdup_printf ("Label%sUp", id);
+	node = verify_has_sub (cur, sub);
+	g_assert (node != NULL);
+	g_free (sub);
+
+	class = g_strdup_printf ("%sUp %s Label", id, id);
+	verify_has_class (node, class);
+	g_free (class);
+
+	sub = g_strdup_printf ("Label%sDown", id);
+	node = verify_has_sub (cur, sub);
+	g_assert (node != NULL);
+	g_free (sub);
+
+	class = g_strdup_printf ("%sDown %s Label", id, id);
+	verify_has_class (node, class);
+	g_free (class);
+}
+
+static void
+verify_tablet_image (WacomDeviceDatabase *db, WacomDevice *device)
+{
+	const char *name;
+	const char *filename;
+	xmlChar    *prop;
+	xmlDocPtr   doc;
+	xmlNodePtr  cur;
+	xmlNodePtr  node;
+	char        button;
+	int         num_buttons;
+	char       *class;
+
+	name = libwacom_get_name(device);
+	if (strcmp(name, "Generic") == 0)
+		return;
+
+	filename = libwacom_get_image_filename(device);
+	if (filename == NULL)
+		return;
+
+	g_message ("Verifying device '%s', SVG file '%s'", name, filename);
+
+	doc = xmlParseFile(filename);
+	g_assert (doc != NULL );
+
+	cur = xmlDocGetRootElement(doc);
+	g_assert (cur != NULL);
+
+	/* Check we got an SVG image */
+	g_assert (xmlStrcmp(cur->name, (const xmlChar *) "svg") == 0);
+
+	/* width is provided */
+	prop = xmlGetProp(cur, "width") ;
+	g_assert (prop != NULL);
+	xmlFree(prop);
+
+	/* height is provided */
+	prop = xmlGetProp(cur, "height") ;
+	g_assert (prop != NULL);
+	xmlFree(prop);
+
+	num_buttons = libwacom_get_num_buttons (device);
+	for (button = 'A'; button < 'A' + num_buttons; button++) {
+		check_button (cur, device, button, "Button");
+		check_button (cur, device, button, "Label");
+	}
+
+	/* Touch rings */
+	if (libwacom_has_ring(device))
+		check_touch (cur, "Ring", "TouchRing");
+	if (libwacom_has_ring2(device))
+		check_touch (cur, "Ring2", "TouchRing");
+	/* Touch strips */
+	if (libwacom_get_num_strips(device) > 0)
+		check_touch (cur, "Strip", "TouchStrip");
+	if (libwacom_get_num_strips(device) > 1)
+		check_touch (cur, "Strip2", "TouchStrip");
+
+	xmlFreeDoc(doc);
+
+	return;
+}
+
+
+int main(int argc, char **argv)
+{
+	WacomDeviceDatabase *db;
+	WacomDevice **device, **devices;
+
+	g_type_init ();
+	db = libwacom_database_new_for_path(TOPSRCDIR"/data");
+	if (!db)
+		printf("Failed to load data from %s", TOPSRCDIR"/data");
+	g_assert(db);
+
+	devices = libwacom_list_devices_from_database(db, NULL);
+	g_assert(devices);
+	g_assert(*devices);
+
+	for (device = devices; *device; device++)
+		verify_tablet_image(db, *device);
+
+	libwacom_database_destroy (db);
+
+	return 0;
+}
+
diff --git a/tools/Makefile.am b/tools/Makefile.am
index c204ab0..94fe401 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,6 +1,7 @@
 AM_CPPFLAGS=-I$(top_srcdir)/libwacom -DTOPSRCDIR="\"$(top_srcdir)\""
 
 noinst_PROGRAMS = generate-udev-rules list-devices
+
 generate_udev_rules_SOURCES = generate-udev-rules.c
 generate_udev_rules_LDADD=$(top_builddir)/libwacom/libwacom.la $(GLIB_LIBS)
 generate_udev_rules_CFLAGS=$(GLIB_CFLAGS)
@@ -13,3 +14,10 @@ libwacom_list_local_devices_SOURCES = list-local-devices.c
 libwacom_list_local_devices_LDADD=$(top_builddir)/libwacom/libwacom.la $(GLIB_LIBS)
 libwacom_list_local_devices_CFLAGS=$(GLIB_CFLAGS)
 
+if HAVE_GTK2
+noinst_PROGRAMS += show-svg-image
+show_svg_image_SOURCES = show-svg-image.c
+show_svg_image_LDADD = $(top_builddir)/libwacom/libwacom.la $(GTK2_LIBS)
+show_svg_image_CFLAGS = $(GTK2_CFLAGS)
+endif
+
diff --git a/tools/show-svg-image.c b/tools/show-svg-image.c
new file mode 100644
index 0000000..0792541
--- /dev/null
+++ b/tools/show-svg-image.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright © 2012 Red Hat, Inc.
+ *
+ * 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 Red Hat
+ * not be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission.  Red
+ * Hat makes no representations about the suitability of this software
+ * for any purpose.  It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL THE AUTHORS 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.
+ *
+ * Authors:
+ *        Olivier Fourdan <ofour...@redhat.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+#include <cairo.h>
+#include <librsvg/rsvg.h>
+#include "libwacom.h"
+
+
+#define INACTIVE_COLOR		"#2d2d2d"
+#define ACTIVE_COLOR		"#ffffff"
+#define STROKE_COLOR		"#b4b4b4"
+#define DARK_COLOR		"#141414"
+#define BACK_COLOR		"#000000"
+
+/* Convenient struct to store our stuff around */
+typedef struct
+{
+	RsvgHandle  *handle;
+	GtkWidget   *widget;
+	guint        timeout;
+	WacomDevice *device;
+	GdkRectangle area;
+	char         active_button;
+	int          num_buttons;
+} Tablet;
+
+static gboolean
+get_sub_location (cairo_t *cairo_context, RsvgHandle *handle, const char *sub, double *x, double *y, double *width, double *height)
+{
+	if (x || y) {
+		RsvgPositionData  position;
+		double tx, ty;
+
+		if (!rsvg_handle_get_position_sub (handle, &position, sub)) {
+			g_warning ("Failed to retrieve '%s' position", sub);
+			return FALSE;
+		}
+
+		tx = (double) position.x;
+		ty = (double) position.y;
+		cairo_user_to_device (cairo_context, &tx, &ty);
+
+		if (x)
+			*x = tx;
+		if (y)
+			*y = ty;
+	}
+
+	if (width || height) {
+		RsvgDimensionData dimensions;
+		double twidth, theight;
+
+		if (!rsvg_handle_get_dimensions_sub (handle, &dimensions, sub)) {
+			g_warning ("Failed to retrieve '%s' dimension", sub);
+			return FALSE;
+		}
+
+		twidth = (double) dimensions.width;
+		theight = (double) dimensions.height;
+		cairo_user_to_device_distance (cairo_context, &twidth, &theight);
+
+		if (width)
+			*width = twidth;
+		if (height)
+			*height = theight;
+	}
+
+	return TRUE;
+}
+
+static void
+print_button_labels (cairo_t *cairo_context, Tablet *tablet)
+{
+	char button;
+	GtkWidget *widget;
+	GtkAllocation allocation;
+
+	widget = GTK_WIDGET(tablet->widget);
+	gtk_widget_get_allocation(widget, &allocation);
+
+	for (button = 'A'; button < 'A' + tablet->num_buttons; button++) {
+		WacomButtonFlags  flags;
+		GtkStyle        *style;
+		PangoContext     *pango_context;
+		PangoLayout      *pango_layout;
+		PangoRectangle    pango_rect;
+		double            label_x, label_y;
+		double            btn_x, btn_y, btn_width, btn_height;
+		int               x, y;
+		gchar            *sub;
+		gchar            *markup;
+
+		flags = libwacom_get_button_flag(tablet->device, button);
+		sub = g_strdup_printf ("#Label%c", button);
+		if (!get_sub_location (cairo_context, tablet->handle, sub, &label_x, &label_y, NULL, NULL)) {
+			g_warning ("Failed to retrieve %s position", sub);
+			goto next;
+		}
+
+		/* Write the label */
+		style = gtk_widget_get_style (widget);
+		pango_context = gtk_widget_get_pango_context (widget);
+		pango_layout  = pango_layout_new (pango_context);
+		if (button == tablet->active_button) 
+			markup = g_strdup_printf ("<span foreground=\"" ACTIVE_COLOR "\" weight=\"bold\">Button %c</span>", button);
+		else
+			markup = g_strdup_printf ("<span foreground=\"" INACTIVE_COLOR "\" weight=\"bold\">Button %c</span>", button);
+		pango_layout_set_markup (pango_layout, markup, -1);
+		g_free (markup);
+
+		pango_layout_get_pixel_extents (pango_layout, NULL, &pango_rect);
+
+		if (flags & WACOM_BUTTON_POSITION_LEFT) {
+			pango_layout_set_alignment (pango_layout, PANGO_ALIGN_LEFT);
+			x = (int) label_x;
+			y = (int) label_y + pango_rect.height / 2;
+		} else if (flags & WACOM_BUTTON_POSITION_RIGHT) {
+			pango_layout_set_alignment (pango_layout, PANGO_ALIGN_RIGHT);
+			x = (int) label_x - pango_rect.width;
+			y = (int) label_y + pango_rect.height / 2;
+
+		} else {
+			pango_layout_set_alignment (pango_layout, PANGO_ALIGN_CENTER);
+			x = (int) label_x - pango_rect.width / 2;
+			y = (int) label_y;
+		}
+
+		gtk_paint_layout (style,
+			          gtk_widget_get_window (widget),
+			          0,
+			          TRUE,
+			  	  &allocation,
+			          widget,
+			          NULL,
+			          x,
+			          y,
+			          pango_layout);
+
+		g_object_unref (pango_layout);
+next:
+		g_free (sub);
+	}
+}
+
+static void
+update_tablet (Tablet *tablet)
+{
+	char        *width, *height;
+	char         button;
+	GError      *error;
+	guint8      *data;
+
+	if (tablet->handle)
+		g_object_unref (tablet->handle);
+
+	width = g_strdup_printf ("%d", tablet->area.width);
+	height = g_strdup_printf ("%d", tablet->area.height);
+
+	data = g_strconcat ("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
+	                    "<svg version=\"1.1\"\n"
+	                    "     xmlns=\"http://www.w3.org/2000/svg\"\n";
+	                    "     xmlns:xi=\"http://www.w3.org/2001/XInclude\"\n";
+	                    "     width=\"", width, "\"\n"
+	                    "     height=\"", height, "\">\n"
+	                    "  <style type=\"text/css\">\n"
+	                    "    * {\n"
+	                    "      stroke: ", STROKE_COLOR," !important;\n"
+	                    "      fill:   ", INACTIVE_COLOR," !important;\n"
+	                    "    }\n",
+	                    NULL);
+	g_free (width);
+	g_free (height);
+
+	for (button = 'A'; button < 'A' + tablet->num_buttons; button++) {
+		gchar class[] = {button, '\0'};
+		if (button == tablet->active_button) {
+			data = g_strconcat (data,
+			                    "    .", class, " {\n"
+			                    "      stroke: ", STROKE_COLOR," !important;\n"
+			                    "      fill:   ", button == tablet->active_button ? ACTIVE_COLOR : INACTIVE_COLOR, " !important;\n"
+			                    "    }\n",
+			                    NULL);
+	    }
+	}
+
+	/* Hide the existing labels */
+	data = g_strconcat (data,
+	                    "    .Label {\n"
+	                    "      stroke: none !important;\n"
+	                    "      fill:   ", BACK_COLOR, "  !important;\n"
+	                    "    }\n",
+	                    "    .TouchStrip,.TouchRing {\n"
+	                    "      stroke: ", INACTIVE_COLOR," !important;\n"
+	                    "      fill:   ", DARK_COLOR, "  !important;\n"
+	                    "    }\n",
+	                    "  </style>\n"
+	                    "  <xi:include href=\"", libwacom_get_image_filename (tablet->device), "\"/>\n"
+	                    "</svg>",
+	                    NULL);
+
+	tablet->handle = rsvg_handle_new_from_data (data, strlen(data), &error);
+	g_free (data);
+}
+
+static void
+on_expose_cb (GtkWidget *widget, GdkEvent *event, Tablet *tablet)
+{
+	GdkEventExpose *expose_event;
+	GtkAllocation  allocation;
+	cairo_t       *cairo_context;
+	float          scale;
+	double         twidth, theight;
+
+	expose_event = (GdkEventExpose *) event;
+
+	if (tablet->handle == NULL)
+		update_tablet (tablet);
+
+	/* Create a Cairo for the widget */
+	cairo_context = gdk_cairo_create (gtk_widget_get_window (widget));
+	cairo_set_operator (cairo_context, CAIRO_OPERATOR_CLEAR);
+	cairo_paint (cairo_context);
+	cairo_set_operator (cairo_context, CAIRO_OPERATOR_OVER);
+
+	/* Scale to fit in window */
+	gtk_widget_get_allocation(widget, &allocation);
+	scale = MIN ((float) allocation.width / tablet->area.width,
+	             (float) allocation.height / tablet->area.height);
+	cairo_scale (cairo_context, scale, scale);
+
+	/* Center the result in window */
+	twidth = (double) tablet->area.width;
+	theight = (double) tablet->area.height;
+	cairo_user_to_device_distance (cairo_context, &twidth, &theight);
+	twidth = ((double) allocation.width - twidth) / 2.0;
+	theight = ((double) allocation.height - theight) / 2.0;
+	cairo_device_to_user_distance (cairo_context, &twidth, &theight);
+	cairo_translate (cairo_context, twidth, theight);
+
+	/* And render the tablet image */
+	rsvg_handle_render_cairo (tablet->handle, cairo_context);
+	print_button_labels (cairo_context, tablet);
+	cairo_destroy (cairo_context);
+}
+
+static gboolean
+on_timer_cb (Tablet *tablet)
+{
+	GtkAllocation allocation;
+	GdkRectangle  rect;
+	int           num_buttons;
+
+	tablet->active_button++;
+	num_buttons = libwacom_get_num_buttons (tablet->device);
+	if (tablet->active_button >= 'A' + num_buttons)
+		tablet->active_button = 'A';
+	update_tablet (tablet);
+	gtk_widget_get_allocation (GTK_WIDGET(tablet->widget), &allocation);
+	gdk_window_invalidate_rect(gtk_widget_get_window (tablet->widget), &allocation, FALSE);
+
+	return TRUE;
+}
+
+static gboolean
+on_delete_cb (GtkWidget *widget, GdkEvent  *event, Tablet *tablet)
+{
+	gtk_main_quit ();
+
+	return TRUE;
+}
+
+int
+main (int argc, char **argv)
+{
+	GOptionContext      *context;
+	RsvgHandle          *handle;
+	RsvgDimensionData    dimensions;
+	GError              *error;
+	WacomDeviceDatabase *db;
+	WacomDevice         *device;
+	Tablet              *tablet;
+	GtkWidget           *widget;
+	GdkWindow           *gdk_win;
+	GdkColor             black;
+	char                *tabletname;
+	const char          *filename;
+	GOptionEntry         
+		options[] = {
+			{"tablet", 't', 0, G_OPTION_ARG_STRING, &tabletname, "Name of the tablet to show", "<string>"},
+			{NULL}
+		};
+
+	handle = NULL;
+	error = NULL;
+	tabletname = NULL;
+
+	context = g_option_context_new ("- libwacom tablet viewer");
+	g_option_context_add_main_entries (context, options, NULL);
+	g_option_context_add_group (context, gtk_get_option_group (TRUE));
+	g_option_context_set_help_enabled (context, TRUE);
+	g_option_context_parse (context, &argc, &argv, NULL);
+	g_option_context_free (context);
+
+	gtk_init (&argc, &argv);
+	if (tabletname == NULL) {
+		g_warning ("No tablet name provided, exiting");
+		return 1;
+	}
+	db = libwacom_database_new_for_path(TOPSRCDIR"/data");
+	if (!db) {
+		g_warning ("Failed to load libwacom database, exiting");
+		return 1;
+	}
+	device = libwacom_new_from_name(db, tabletname, NULL);
+	if (!device) {
+		g_warning ("Device '%s' not found in libwacom database, exiting", tabletname);
+		return 1;
+	}
+
+	filename = libwacom_get_image_filename(device);
+	if (filename == NULL) {
+		g_warning ("Device '%s' has no image available, exiting", tabletname);
+		return 1;
+	}
+	handle = rsvg_handle_new_from_file (filename, &error);
+	if (error || handle == NULL)
+		return 1;
+	rsvg_handle_get_dimensions (handle, &dimensions);
+	g_object_unref (handle);
+
+	tablet = g_new0 (Tablet, 1);
+	tablet->device = device;
+	tablet->area.width = dimensions.width;
+	tablet->area.height = dimensions.height;
+	tablet->handle = NULL;
+	tablet->active_button = 'A';
+	tablet->num_buttons = libwacom_get_num_buttons (device);
+	tablet->widget = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+	gtk_widget_set_app_paintable (tablet->widget, TRUE);
+	gtk_widget_realize (tablet->widget);
+	gdk_win = gtk_widget_get_window (tablet->widget);
+	gdk_color_parse (BACK_COLOR, &black);
+	gdk_window_set_background (gdk_win, &black);
+	gtk_window_set_default_size (GTK_WINDOW (tablet->widget), 800, 600);
+
+	g_signal_connect (tablet->widget, "expose-event", G_CALLBACK(on_expose_cb), tablet);
+	g_signal_connect (tablet->widget, "delete-event", G_CALLBACK(on_delete_cb), tablet);
+	tablet->timeout = g_timeout_add(500 /* ms */, (GSourceFunc) on_timer_cb, tablet);
+
+	gtk_widget_show (tablet->widget);
+
+	gtk_main();
+
+	libwacom_destroy(device);
+	libwacom_database_destroy(db);
+
+	return 0;
+}
-- 
1.7.1

------------------------------------------------------------------------------
Everyone hates slow websites. So do we.
Make your web apps faster with AppDynamics
Download AppDynamics Lite for free today:
http://p.sf.net/sfu/appdyn_sfd2d_oct
_______________________________________________
Linuxwacom-devel mailing list
Linuxwacom-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxwacom-devel

Reply via email to