Note: This updated patch also adds support for groups (<g></g>) in SVG.

>From faed67e73057c6998fde65871075e9bfbcaa43af 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.

Signed-off-by: Olivier Fourdan <ofour...@redhat.com>
---
 configure.ac               |    6 +
 test/Makefile.am           |    7 +
 test/tablet-svg-validity.c |  246 ++++++++++++++++++++++++++++
 tools/Makefile.am          |    8 +
 tools/show-svg-image.c     |  387 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 654 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 4352b8b..64f4890 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/layouts/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..947ef4c
--- /dev/null
+++ b/test/tablet-svg-validity.c
@@ -0,0 +1,246 @@
+/*
+ * 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;
+
+		/* Descend the tree if dealing with a group */
+		if (xmlStrcmp(cur->name, (const xmlChar *) "g") == 0) {
+			xmlNodePtr sub_node;
+			sub_node = verify_has_sub (cur, sub);
+			if (sub_node != NULL)
+				return sub_node;
+		}
+
+		prop = xmlGetProp(cur, (xmlChar *) "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, const gchar *expected)
+{
+
+	xmlChar *prop;
+	gchar  **classes_present;
+	gchar  **classes_expected;
+	gchar  **ptr;
+
+	prop = xmlGetProp (cur, (xmlChar *) "class");
+	g_assert (prop != NULL);
+	g_assert (strlen((const char *) prop) > 0);
+
+	classes_present = g_strsplit ((const gchar *) 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;
+
+	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_layout (WacomDeviceDatabase *db, WacomDevice *device)
+{
+	const char *name;
+	const char *filename;
+	xmlChar    *prop;
+	xmlDocPtr   doc;
+	xmlNodePtr  cur;
+	char        button;
+	int         num_buttons;
+
+	name = libwacom_get_name(device);
+	if (strcmp(name, "Generic") == 0)
+		return;
+
+	filename = libwacom_get_layout_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 layout */
+	g_assert (xmlStrcmp(cur->name, (const xmlChar *) "svg") == 0);
+
+	/* width is provided */
+	prop = xmlGetProp(cur, (xmlChar *) "width") ;
+	g_assert (prop != NULL);
+	xmlFree(prop);
+
+	/* height is provided */
+	prop = xmlGetProp(cur, (xmlChar *) "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;
+
+	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_layout(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..d6f7fd3
--- /dev/null
+++ b/tools/show-svg-image.c
@@ -0,0 +1,387 @@
+/*
+ * 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 <librsvg/rsvg-cairo.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;
+		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;
+	gchar       *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_layout_filename (tablet->device), "\"/>\n"
+	                    "</svg>",
+	                    NULL);
+
+	tablet->handle = rsvg_handle_new_from_data ((guint8 *) 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 layout */
+	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;
+	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;
+	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_layout_filename(device);
+	if (filename == NULL) {
+		g_warning ("Device '%s' has no layout 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

------------------------------------------------------------------------------
LogMeIn Central: Instant, anywhere, Remote PC access and management.
Stay in control, update software, and manage PCs from one command center
Diagnose problems and improve visibility into emerging IT issues
Automate, monitor and manage. Do more in less time with Central
http://p.sf.net/sfu/logmein12331_d2d
_______________________________________________
Linuxwacom-devel mailing list
Linuxwacom-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxwacom-devel

Reply via email to