On Tue, Nov 06, 2012 at 03:06:59PM +0100, Olivier Fourdan wrote:
> 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;

show-svg-image.c: In function ‘on_expose_cb’:
show-svg-image.c:238:18: warning: variable ‘expose_event’ set but not used
[-Wunused-but-set-variable]
looks like one can just drop it, that's what I did here after merging.

All four patches merged, thank you.

One comment I have is regarding commit messages: the prefix ("lib:", "test:"
etc) is for guidance and not strictly required. What git somewhat enforces
though is one line for summary, a blank line, then detailed descriptions.

So looking at patch 4/4 (actual patch, for some reason the email subject
lines are swapped) you have data: blah and test: blah in the commit message.
This isn't necessary, just pick the one where the main change happens
(usually lib or data, since that is the meat of the repository). Ideally
there's one logical change (in this case add the data) and various extra
bits that accompany it (in this case testing)

OTOH, patch 3/4 introduces both an XML validator and a image display tool.
IMO these should be in two different patches to make tracking these changes
easier, and they are two, not one, logical changes. I've split them up here
locally, so no further patch sets required.

Also, last comment: if the rules above seem arbitrary, they pretty much are,
sorry :) The best rule to follow is the "one logical change per patch".

(I've also added the two new binaries to .gitignore)

Cheers,
   Peter

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