On Wed, Oct 31, 2012 at 02:18:43PM +0100, Olivier Fourdan wrote:
> 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

Please make sure you always have -Wall in your CFLAGS. THe show-svg-image
tool generates 15 warnings here. tablet-svg-validity has a few as well.

Cheers,
   Peter

> 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


------------------------------------------------------------------------------
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