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