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