diff --git a/configure.ac b/configure.ac
index ad81acb..dbfe36f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -464,6 +464,7 @@ plugins/media-keys/cut-n-paste/Makefile
 plugins/mouse/Makefile
 plugins/smartcard/Makefile
 plugins/sound/Makefile
+plugins/wacom/Makefile
 plugins/xrandr/Makefile
 plugins/xrdb/Makefile
 plugins/xrdb/data/Makefile
@@ -479,6 +480,7 @@ data/org.gnome.settings-daemon.plugins.media-keys.gschema.xml.in
 data/org.gnome.settings-daemon.peripherals.gschema.xml.in
 data/org.gnome.settings-daemon.plugins.housekeeping.gschema.xml.in
 data/org.gnome.settings-daemon.plugins.xrandr.gschema.xml.in
+data/org.gnome.settings-daemon.peripherals.wacom.gschema.xml.in
 po/Makefile.in
 ])
 
diff --git a/data/Makefile.am b/data/Makefile.am
index ecc1a17..310695d 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -13,6 +13,7 @@ gsettings_SCHEMAS =							\
 	org.gnome.settings-daemon.plugins.media-keys.gschema.xml	\
 	org.gnome.settings-daemon.plugins.xsettings.gschema.xml		\
 	org.gnome.settings-daemon.plugins.housekeeping.gschema.xml	\
+	org.gnome.settings-daemon.peripherals.wacom.gschema.xml		\
 	org.gnome.settings-daemon.plugins.xrandr.gschema.xml
 
 @INTLTOOL_XML_NOMERGE_RULE@
diff --git a/data/gnome-settings-daemon.convert b/data/gnome-settings-daemon.convert
index 99ea6e6..fa59247 100644
--- a/data/gnome-settings-daemon.convert
+++ b/data/gnome-settings-daemon.convert
@@ -105,3 +105,36 @@ dpi = /desktop/gnome/font_rendering/dpi
 hinting = /desktop/gnome/font_rendering/hinting
 priority = /apps/gnome_settings_daemon/plugins/xsettings/priority
 rgba-order = /desktop/gnome/font_rendering/rgba_order
+
+[org.gnome.settings-daemon.plugins.wacom]
+active = /apps/gnome_settings_daemon/plugins/wacom/active
+priority = /apps/gnome_settings_daemon/plugins/wacom/priority
+
+[org.gnome.settings-daemon.peripherals.wacom]
+rotation = /desktop/gnome/peripherals/wacom/rotation
+touch = /desktop/gnome/peripherals/wacom/touch
+tpcbutton = /desktop/gnome/peripherals/wacom/tpcbutton
+
+[org.gnome.settings-daemon.peripherals.wacom.stylus]
+is_absolute = /desktop/gnome/peripherals/wacom/stylus/is_absolute
+pressurecurve = /desktop/gnome/peripherals/wacom/stylus/pressurecurve
+area = /desktop/gnome/peripherals/wacom/stylus/area
+buttonmapping = /desktop/gnome/peripherals/wacom/stylus/buttonmapping
+pressurethreshold = /desktop/gnome/peripherals/wacom/stylus/pressurethreshold
+
+[org.gnome.settings-daemon.peripherals.wacom.eraser]
+is_absolute = /desktop/gnome/peripherals/wacom/eraser/is_absolute
+pressurecurve = /desktop/gnome/peripherals/wacom/eraser/pressurecurve
+area = /desktop/gnome/peripherals/wacom/eraser/area
+buttonmapping = /desktop/gnome/peripherals/wacom/eraser/buttonmapping
+pressurethreshold = /desktop/gnome/peripherals/wacom/eraser/pressurethreshold
+
+[org.gnome.settings-daemon.peripherals.wacom.cursor]
+is_absolute = /desktop/gnome/peripherals/wacom/cursor/is_absolute
+area = /desktop/gnome/peripherals/wacom/cursor/area
+buttonmapping = /desktop/gnome/peripherals/wacom/cursor/buttonmapping
+
+[org.gnome.settings-daemon.peripherals.wacom.pad]
+area = /desktop/gnome/peripherals/wacom/pad/area
+buttonmapping = /desktop/gnome/peripherals/wacom/pad/buttonmapping
+
diff --git a/data/gnome-settings-daemon.schemas.in b/data/gnome-settings-daemon.schemas.in
index 14fd2ac..fc12d95 100644
--- a/data/gnome-settings-daemon.schemas.in
+++ b/data/gnome-settings-daemon.schemas.in
@@ -534,5 +534,28 @@
       </locale>
     </schema>
 
+    <schema>
+      <key>/schemas/apps/gnome_settings_daemon/plugins/wacom/active</key>
+      <applyto>/apps/gnome_settings_daemon/plugins/wacom/active</applyto>
+      <owner>gnome-settings-daemon</owner>
+      <type>bool</type>
+      <default>TRUE</default>
+      <locale name="C">
+        <short>Enable wacom plugin</short>
+        <long>Set to True to enable the plugin to manage Wacom tablet settings.</long>
+      </locale>
+    </schema>
+    <schema>
+      <key>/schemas/apps/gnome_settings_daemon/plugins/wacom/priority</key>
+      <applyto>/apps/gnome_settings_daemon/plugins/wacom/priority</applyto>
+      <owner>gnome-settings-daemon</owner>
+      <type>int</type>
+      <default>10</default>
+      <locale name="C">
+        <short></short>
+        <long></long>
+      </locale>
+    </schema>
+
   </schemalist>
 </gconfschemafile>
diff --git a/data/gsd-enums.h b/data/gsd-enums.h
index e955c30..0d0fe98 100644
--- a/data/gsd-enums.h
+++ b/data/gsd-enums.h
@@ -82,4 +82,12 @@ typedef enum
   GSD_XRANDR_BOOT_BEHAVIOUR_DOCK
 } GsdXrandrBootBehaviour;
 
+typedef enum
+{
+  GSD_WACOM_ROTATION_NONE,
+  GSD_WACOM_ROTATION_CW,
+  GSD_WACOM_ROTATION_CCW,
+  GSD_WACOM_ROTATION_HALF
+} GsdWacomRotation;
+
 #endif /* __gsd_enums_h__ */
diff --git a/data/org.gnome.settings-daemon.peripherals.wacom.gschema.xml.in.in b/data/org.gnome.settings-daemon.peripherals.wacom.gschema.xml.in.in
new file mode 100644
index 0000000..2f01b0b
--- /dev/null
+++ b/data/org.gnome.settings-daemon.peripherals.wacom.gschema.xml.in.in
@@ -0,0 +1,114 @@
+<schemalist>
+  <schema gettext-domain="@GETTEXT_PACKAGE@" id="org.gnome.settings-daemon.plugins.wacom" path="/org/gnome/settings-daemon/plugins/wacom/">
+    <key name="active" type="b">
+      <default>true</default>
+      <_summary>Activation of this plugin</_summary>
+      <_description>Whether this plugin would be activated by gnome-settings-daemon or not.</_description>
+    </key>
+    <key name="priority" type="i">
+      <default>6</default>
+      <_summary>Priority to use for this plugin</_summary>
+      <_description>Priority to use for this plugin in gnome-settings-daemon startup queue.</_description>
+    </key>
+  </schema>
+  <schema gettext-domain="@GETTEXT_PACKAGE@" id="org.gnome.settings-daemon.peripherals.wacom" path="/org/gnome/settings-daemon/peripherals/wacom/">
+    <key name="rotation" enum="org.gnome.settings-daemon.GsdWacomRotation">
+    <default>'none'</default>
+    <_summary>Wacom tablet rotation</_summary>
+    <_description>Set this to 'none', 'cw' for 90 degree clockwise, 'half' for 180 degree, and 'ccw' for 90 degree counterclockwise.</_description>
+    </key>
+    <key name="touch" type="b">
+      <default>false</default>
+      <_summary>Wacom touch feature</_summary>
+      <_description>Enable this to only move the cursor when the user touches the tablet.</_description>
+    </key>
+    <key name="tpcbutton" type="b">
+      <default>false</default>
+      <_summary>Wacom tablet PC feature</_summary>
+      <_description>Enable this to only report stylus events when the tip is pressed.</_description>
+    </key>
+  </schema>
+  <schema gettext-domain="@GETTEXT_PACKAGE@" id="org.gnome.settings-daemon.peripherals.wacom.stylus" path="/org/gnome/settings-daemon/peripherals/wacom/stylus/">
+    <key name="is-absolute" type="b">
+      <default>true</default>
+      <_summary>Wacom stylus absolute mode</_summary>
+      <_description>Enable this to set the stylus to absolute mode.</_description>
+    </key>
+    <key name="pressurecurve" type="ai">
+      <default>[0, 0, 100, 100]</default>
+      <_summary>Wacom stylus pressure curve</_summary>
+      <_description>Set this to x1, y1 and x2, y2 of the pressure curve applied to the stylus.</_description>
+    </key>
+    <key name="area" type="ai">
+      <default>[-1, -1, -1, -1]</default>
+      <_summary>Wacom stylus tablet area</_summary>
+      <_description>Set this to x1, y1 and x2, y2 of the area usable by the stylus.</_description>
+    </key>
+    <key name="buttonmapping" type="ai">
+      <default>[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]</default>
+      <_summary>Wacom stylus button mapping</_summary>
+      <_description>Set this to the logical button mapping.</_description>
+    </key>
+    <key name="pressurethreshold" type="i">
+      <default>-1</default>
+      <_summary>Wacom stylus pressure threshold</_summary>
+      <_description>Set this to the pressure value at which a stylus click event is generated.</_description>
+    </key>
+  </schema>
+  <schema gettext-domain="@GETTEXT_PACKAGE@" id="org.gnome.settings-daemon.peripherals.wacom.eraser" path="/org/gnome/settings-daemon/peripherals/wacom/eraser/">
+    <key name="is-absolute" type="b">
+      <default>true</default>
+      <_summary>Wacom eraser absolute mode</_summary>
+      <_description>Enable this to set the eraser to absolute mode.</_description>
+    </key>
+    <key name="pressurecurve" type="ai">
+      <default>[0, 0, 100, 100]</default>
+      <_summary>Wacom eraser pressure curve</_summary>
+      <_description>Set this to x1, y1 and x2, y2 of the pressure curve applied to the eraser.</_description>
+    </key>
+    <key name="area" type="ai">
+      <default>[-1, -1, -1, -1]</default>
+      <_summary>Wacom eraser tablet area</_summary>
+      <_description>Set this to x1, y1 and x2, y2 of the area usable by the eraser.</_description>
+    </key>
+    <key name="buttonmapping" type="ai">
+      <default>[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]</default>
+      <_summary>Wacom eraser button mapping</_summary>
+      <_description>Set this to the logical button mapping.</_description>
+    </key>
+    <key name="pressurethreshold" type="i">
+      <default>-1</default>
+      <_summary>Wacom eraser pressure threshold</_summary>
+      <_description>Set this to the pressure value at which an eraser click event is generated.</_description>
+    </key>
+  </schema>
+  <schema gettext-domain="@GETTEXT_PACKAGE@" id="org.gnome.settings-daemon.peripherals.wacom.cursor" path="/org/gnome/settings-daemon/peripherals/wacom/cursor/">
+    <key name="is-absolute" type="b">
+      <default>true</default>
+      <_summary>Wacom cursor absolute mode</_summary>
+      <_description>Enable this to set the cursor to absolute mode.</_description>
+    </key>
+    <key name="area" type="ai">
+      <default>[-1, -1, -1, -1]</default>
+      <_summary>Wacom cursor tablet area</_summary>
+      <_description>Set this to x1, y1 and x2, y2 of the area usable by the cursor.</_description>
+    </key>
+    <key name="buttonmapping" type="ai">
+      <default>[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]</default>
+      <_summary>Wacom cursor button mapping</_summary>
+      <_description>Set this to the logical button mapping.</_description>
+    </key>
+  </schema>
+  <schema gettext-domain="@GETTEXT_PACKAGE@" id="org.gnome.settings-daemon.peripherals.wacom.pad" path="/org/gnome/settings-daemon/peripherals/wacom/pad/">
+    <key name="area" type="ai">
+      <default>[-1, -1, -1, -1]</default>
+      <_summary>Wacom pad tablet area</_summary>
+      <_description>Set this to x1, y1 and x2, y2 of the area usable by the pad.</_description>
+    </key>
+    <key name="buttonmapping" type="ai">
+      <default>[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]</default>
+      <_summary>Wacom pad button mapping</_summary>
+      <_description>Set this to the logical button mapping.</_description>
+    </key>
+  </schema>
+</schemalist>
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 3107cf4..391fbdc 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -12,6 +12,7 @@ enabled_plugins =	\
 	media-keys	\
 	mouse		\
 	sound		\
+	wacom		\
 	xrandr		\
 	xrdb		\
 	xsettings	\
diff --git a/plugins/wacom/Makefile.am b/plugins/wacom/Makefile.am
new file mode 100644
index 0000000..445f986
--- /dev/null
+++ b/plugins/wacom/Makefile.am
@@ -0,0 +1,38 @@
+plugin_LTLIBRARIES = libwacom.la
+
+libwacom_la_SOURCES = 		\
+	gsd-wacom-plugin.h	\
+	gsd-wacom-plugin.c	\
+	gsd-wacom-manager.h	\
+	gsd-wacom-manager.c
+
+libwacom_la_CPPFLAGS = \
+	-I$(top_srcdir)/gnome-settings-daemon		\
+	-I$(top_srcdir)/plugins/common/			\
+	-I$(top_srcdir)/data/				\
+	-DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \
+	-DLIBEXECDIR=\""$(libexecdir)"\" 		\
+	$(AM_CPPFLAGS)
+
+libwacom_la_CFLAGS = \
+	$(SETTINGS_PLUGIN_CFLAGS)	\
+	$(AM_CFLAGS)
+
+libwacom_la_LDFLAGS = 		\
+	$(GSD_PLUGIN_LDFLAGS)
+
+libwacom_la_LIBADD  = 							\
+	$(top_builddir)/plugins/common/libcommon.la			\
+	$(SETTINGS_PLUGIN_LIBS)						\
+	$(X11_LIBS)							\
+	$(XINPUT_LIBS)
+
+plugin_in_files = wacom.gnome-settings-plugin.in
+
+plugin_DATA = $(plugin_in_files:.gnome-settings-plugin.in=.gnome-settings-plugin)
+
+EXTRA_DIST = $(plugin_in_files)
+CLEANFILES = $(plugin_DATA)
+DISTCLEANFILES = $(plugin_DATA)
+
+@GSD_INTLTOOL_PLUGIN_RULE@
diff --git a/plugins/wacom/gsd-wacom-manager.c b/plugins/wacom/gsd-wacom-manager.c
new file mode 100644
index 0000000..c8b1c82
--- /dev/null
+++ b/plugins/wacom/gsd-wacom-manager.c
@@ -0,0 +1,917 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+
+#include <locale.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdkkeysyms.h>
+#include <X11/keysym.h>
+#include <X11/Xatom.h>
+
+#include <X11/extensions/XInput.h>
+#include <X11/extensions/XIproto.h>
+
+#include "gsd-enums.h"
+#include "gnome-settings-profile.h"
+#include "gsd-wacom-manager.h"
+
+/* Maximum number of buttons map-able. */
+#define WACOM_MAX_BUTTONS 32
+
+
+#define GSD_WACOM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_WACOM_MANAGER, GsdWacomManagerPrivate))
+
+/* Wacom supports two types of settings:
+ * Tablet-wide settings: applied to each tool on the tablet. e.g. rotation
+ * Tool-specific settings: applied to one tool only.
+ */
+#define SETTINGS_WACOM_DIR         "org.gnome.settings-daemon.peripherals.wacom"
+#define SETTINGS_STYLUS_DIR        SETTINGS_WACOM_DIR ".stylus"
+#define SETTINGS_CURSOR_DIR        SETTINGS_WACOM_DIR ".cursor"
+#define SETTINGS_ERASER_DIR        SETTINGS_WACOM_DIR ".eraser"
+#define SETTINGS_PAD_DIR           SETTINGS_WACOM_DIR ".pad"
+
+#define KEY_ROTATION            "rotation"
+#define KEY_TOUCH               "touch"
+#define KEY_TPCBUTTON           "tpcbutton"
+#define KEY_PRESSURECURVE       "pressurecurve"
+#define KEY_IS_ABSOLUTE         "is-absolute"
+#define KEY_AREA                "area"
+#define KEY_BUTTONS             "buttonmapping"
+#define KEY_PRESSURETHRESHOLD   "pressurethreshold"
+
+struct GsdWacomManagerPrivate
+{
+        GSettings *wacom_settings;
+        GSettings *stylus_settings;
+        GSettings *eraser_settings;
+        GSettings *cursor_settings;
+        GSettings *pad_settings;
+        GdkDeviceManager *device_manager;
+};
+
+static void     gsd_wacom_manager_class_init  (GsdWacomManagerClass *klass);
+static void     gsd_wacom_manager_init        (GsdWacomManager      *wacom_manager);
+static void     gsd_wacom_manager_finalize    (GObject             *object);
+static void     set_wacom_settings            (GsdWacomManager      *manager);
+static XDevice* device_is_wacom               (XDeviceInfo deviceinfo);
+
+G_DEFINE_TYPE (GsdWacomManager, gsd_wacom_manager, G_TYPE_OBJECT)
+
+static gpointer manager_object = NULL;
+
+static void
+gsd_wacom_manager_set_property (GObject        *object,
+                               guint           prop_id,
+                               const GValue   *value,
+                               GParamSpec     *pspec)
+{
+        GsdWacomManager *self;
+
+        self = GSD_WACOM_MANAGER (object);
+
+        switch (prop_id) {
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+gsd_wacom_manager_get_property (GObject        *object,
+                               guint           prop_id,
+                               GValue         *value,
+                               GParamSpec     *pspec)
+{
+        GsdWacomManager *self;
+
+        self = GSD_WACOM_MANAGER (object);
+
+        switch (prop_id) {
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static GObject *
+gsd_wacom_manager_constructor (GType                  type,
+                              guint                  n_construct_properties,
+                              GObjectConstructParam *construct_properties)
+{
+        GsdWacomManager      *wacom_manager;
+        GsdWacomManagerClass *klass;
+
+        klass = GSD_WACOM_MANAGER_CLASS (g_type_class_peek (GSD_TYPE_WACOM_MANAGER));
+
+        wacom_manager = GSD_WACOM_MANAGER (G_OBJECT_CLASS (gsd_wacom_manager_parent_class)->constructor (type,
+                                                                                                      n_construct_properties,
+                                                                                                      construct_properties));
+
+        return G_OBJECT (wacom_manager);
+}
+
+static void
+gsd_wacom_manager_dispose (GObject *object)
+{
+        GsdWacomManager *wacom_manager;
+
+        wacom_manager = GSD_WACOM_MANAGER (object);
+
+        G_OBJECT_CLASS (gsd_wacom_manager_parent_class)->dispose (object);
+}
+
+static void
+gsd_wacom_manager_class_init (GsdWacomManagerClass *klass)
+{
+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
+
+        object_class->get_property = gsd_wacom_manager_get_property;
+        object_class->set_property = gsd_wacom_manager_set_property;
+        object_class->constructor = gsd_wacom_manager_constructor;
+        object_class->dispose = gsd_wacom_manager_dispose;
+        object_class->finalize = gsd_wacom_manager_finalize;
+
+        g_type_class_add_private (klass, sizeof (GsdWacomManagerPrivate));
+}
+
+static void
+device_added_cb (GdkDeviceManager *device_manager,
+                 GdkDevice        *device,
+                 gpointer          user_data)
+{
+        if (gdk_device_get_source (device) == GDK_SOURCE_MOUSE)
+                set_wacom_settings ((GsdWacomManager *) user_data);
+}
+
+static void
+set_devicepresence_handler (GsdWacomManager *manager)
+{
+        GdkDeviceManager *device_manager;
+
+        device_manager = gdk_display_get_device_manager (gdk_display_get_default ());
+        if (device_manager == NULL)
+                return;
+
+        g_signal_connect (G_OBJECT (device_manager), "device-added",
+                          G_CALLBACK (device_added_cb), manager);
+        manager->priv->device_manager = device_manager;
+}
+
+static XDevice*
+device_is_wacom (XDeviceInfo deviceinfo)
+{
+        XDevice *device;
+        Atom realtype, prop;
+        int realformat;
+        unsigned long nitems, bytes_after;
+        unsigned char *data;
+
+        if (deviceinfo.type != XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), "STYLUS", False) &&
+            deviceinfo.type != XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), "CURSOR", False) &&
+            deviceinfo.type != XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), "ERASER", False) &&
+            deviceinfo.type != XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), "PAD", False))
+                return NULL;
+
+        prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), "Wacom Rotation", False);
+        if (!prop)
+                return NULL;
+
+        gdk_error_trap_push ();
+        device = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), deviceinfo.id);
+        if (gdk_error_trap_pop () || (device == NULL))
+                return NULL;
+
+        gdk_error_trap_push ();
+        if ((XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), device, prop, 0, 1, False,
+                                XA_INTEGER, &realtype, &realformat, &nitems,
+                                &bytes_after, &data) == Success) && (realtype != None)) {
+                gdk_error_trap_pop ();
+                XFree (data);
+                return device;
+        }
+        gdk_error_trap_pop ();
+
+        XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), device);
+        return NULL;
+}
+
+/* Run through all devices and call the callback on each wacom device. */
+static void
+wacom_foreach_device (void (*callback)(XDeviceInfo *info, XDevice* device, void *userdata), void *userdata)
+{
+        XDeviceInfo *device_info;
+        gint n_devices;
+        gint i;
+
+	g_debug ("Foreach device.");
+        device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), &n_devices);
+
+        for (i = 0; i < n_devices; i++) {
+                XDevice *device = NULL;
+
+                if ((device_info[i].use == IsXPointer) ||
+                    (device_info[i].use == IsXKeyboard))
+                        continue;
+
+                device = device_is_wacom (device_info[i]);
+                if (device == NULL)
+                        continue;
+
+                (*callback)(&device_info[i], device, userdata);
+
+                XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), device);
+        }
+
+        if (device_info != NULL)
+                XFreeDeviceList (device_info);
+}
+
+static void
+wacom_rotate_cb (XDeviceInfo *device_info, XDevice *device, void *userdata)
+{
+        int rc;
+        Atom prop;
+        Atom realtype;
+        int realformat;
+        unsigned long nitems, bytes_after;
+        unsigned char *data;
+
+        prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), "Wacom Rotation", False);
+        if (!prop)
+                return;
+
+        gdk_error_trap_push ();
+
+        rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), device, prop, 0, 1, False,
+                                 XA_INTEGER, &realtype, &realformat, &nitems,
+                                 &bytes_after, &data);
+
+        if (rc != Success || realtype != XA_INTEGER || realformat != 8) {
+                gdk_error_trap_pop ();
+                XFree (data);
+                return;
+        }
+
+        data[0] = *(gint*)userdata;
+        XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), device,
+                        prop, XA_INTEGER, 8,
+                        PropModeReplace, data, nitems);
+
+        XFree (data);
+        if (gdk_error_trap_pop ())
+                g_warning ("Error in rotating device \"%s\"", device_info->name);
+}
+
+static void
+wacom_rotate (GsdWacomManager *manager,
+              gint            rotation)
+{
+        wacom_foreach_device (wacom_rotate_cb, &rotation);
+}
+
+struct pressurecurve_data {
+        const gchar *device_type;
+        const gint32 *data; /* size 4 */
+};
+
+static void
+set_pressurecurve_cb (XDeviceInfo     *device_info,
+                      XDevice         *device,
+                      void            *userdata)
+{
+        int rc;
+        Atom prop;
+        Atom realtype;
+        int realformat;
+        unsigned long nitems, bytes_after;
+        unsigned long *data;
+        struct pressurecurve_data *pcurve_data = (struct pressurecurve_data*)userdata;
+
+        if (device_info->type != XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), pcurve_data->device_type, False))
+                return;
+
+        prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), "Wacom Pressurecurve", False);
+        if (!prop)
+                return;
+
+        gdk_error_trap_push ();
+
+        rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), device, prop, 0, 4, False,
+                                                XA_INTEGER, &realtype, &realformat, &nitems,
+                                                &bytes_after, (unsigned char**)&data);
+
+        if (rc != Success || realtype != XA_INTEGER || realformat != 32) {
+                gdk_error_trap_pop ();
+                XFree (data);
+                return;
+        }
+
+        /* property is inx1,y1,x2,y2 */
+        data[0] = pcurve_data->data[0];
+        data[1] = pcurve_data->data[1];
+        data[2] = pcurve_data->data[2];
+        data[3] = pcurve_data->data[3];
+        XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), device,
+                        prop, XA_INTEGER, 32,
+                        PropModeReplace, (unsigned char*)data, nitems);
+
+        XFree (data);
+        if (gdk_error_trap_pop ())
+                g_warning ("Error in setting pressurecurve for \"%s\"", device_info->name);
+}
+
+static void
+set_pressurecurve (GsdWacomManager *manager,
+                   GVariant      *value,
+                   const gchar     *device_type)
+{
+        struct pressurecurve_data pcurve_data;
+        gsize nvalues;
+
+        pcurve_data.data = g_variant_get_fixed_array (value, &nvalues, sizeof(gint32));
+
+        if (nvalues != 4) {
+                g_error ("Pressurecurve requires 4 values.");
+                return;
+        }
+        pcurve_data.device_type = device_type;
+
+        wacom_foreach_device (set_pressurecurve_cb, &pcurve_data);
+}
+
+static void
+stylus_pressurecurve (GsdWacomManager *manager,
+                      GVariant      *list)
+{
+        set_pressurecurve (manager, list, "STYLUS");
+}
+
+static void
+eraser_pressurecurve (GsdWacomManager *manager,
+                      GVariant      *list)
+{
+        set_pressurecurve (manager, list, "ERASER");
+}
+
+
+/* Area handling. Each area is defined as top x/y, bottom x/y and limits the
+ * usable area of the physical device to the given area (in device coords)
+ */
+typedef struct pressurecurve_data area_data;
+
+static void
+set_area_cb (XDeviceInfo     *device_info,
+             XDevice         *device,
+             void            *userdata)
+{
+        int rc;
+        Atom prop;
+        Atom realtype;
+        int realformat;
+        unsigned long nitems, bytes_after;
+        unsigned long *data;
+        area_data *area = (area_data*)userdata;
+
+        if (device_info->type != XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), area->device_type, False))
+                return;
+
+        prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), "Wacom Tablet Area", False);
+        if (!prop)
+                return;
+
+        gdk_error_trap_push ();
+
+        rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), device, prop, 0, 4, False,
+                                                XA_INTEGER, &realtype, &realformat, &nitems,
+                                                &bytes_after, (unsigned char**)&data);
+
+        if (rc != Success || realtype != XA_INTEGER || realformat != 32) {
+                gdk_error_trap_pop ();
+                XFree (data);
+                return;
+        }
+
+        /* property is in x1,y1,x2,y2 */
+        data[0] = area->data[0];
+        data[1] = area->data[1];
+        data[2] = area->data[2];
+        data[3] = area->data[3];
+        XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), device,
+                        prop, XA_INTEGER, 32,
+                        PropModeReplace, (unsigned char*)data, nitems);
+
+        XFree (data);
+        if (gdk_error_trap_pop ())
+                g_warning ("Error in setting tablet area for \"%s\"", device_info->name);
+}
+
+static void
+set_area (GsdWacomManager *manager,
+          GVariant          *value,
+          const gchar     *device_type)
+{
+        area_data area;
+        gsize nvalues;
+
+        area.data = g_variant_get_fixed_array (value, &nvalues, sizeof(gint32));
+        if (nvalues != 4) {
+                g_error ("Area configuration requires 4 values.");
+                return;
+        }
+
+        area.device_type = device_type;
+
+        wacom_foreach_device (set_area_cb, &area);
+}
+
+static void
+stylus_area (GsdWacomManager *manager,
+             GVariant          *list)
+{
+        set_area (manager, list, "STYLUS");
+}
+
+static void
+eraser_area (GsdWacomManager *manager,
+             GVariant      *list)
+{
+        set_area (manager, list, "ERASER");
+}
+
+static void
+cursor_area (GsdWacomManager *manager,
+             GVariant      *list)
+{
+        set_area (manager, list, "CURSOR");
+}
+
+static void
+pad_area (GsdWacomManager *manager,
+          GVariant      *list)
+{
+        set_area (manager, list, "PAD");
+}
+
+struct absolute_data {
+    const char *device_type;
+    gboolean absolute;
+};
+
+static void
+wacom_absolute_cb (XDeviceInfo *device_info, XDevice *device, void *userdata)
+{
+        struct absolute_data *data = userdata;
+
+        if (device_info->type != XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), data->device_type, False))
+                return;
+
+        gdk_error_trap_push ();
+        XSetDeviceMode (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), device, data->absolute ? Absolute : Relative);
+        gdk_error_trap_pop ();
+}
+
+static void
+stylus_set_absolute (GsdWacomManager *manager,
+                     gboolean is_absolute)
+{
+        struct absolute_data data = { "STYLUS", is_absolute };
+        wacom_foreach_device (wacom_absolute_cb, &data );
+}
+
+static void
+eraser_set_absolute (GsdWacomManager *manager,
+                     gboolean is_absolute)
+{
+        struct absolute_data data = { "ERASER", is_absolute };
+        wacom_foreach_device (wacom_absolute_cb, &data);
+}
+
+static void
+cursor_set_absolute (GsdWacomManager *manager,
+                     gboolean is_absolute)
+{
+        struct absolute_data data = { "CURSOR", is_absolute };
+        wacom_foreach_device (wacom_absolute_cb, &data);
+}
+
+struct buttonmap_data
+{
+        const gchar *device_type;
+        const guchar *map;
+        gsize nmap;
+};
+
+static void
+set_button_mapping_cb (XDeviceInfo *device_info,
+                       XDevice *device,
+                       void *userdata)
+{
+        int rc, i;
+        struct buttonmap_data *map = (struct buttonmap_data*)userdata;
+
+        if (device_info->type != XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), map->device_type, False))
+                return;
+
+        gdk_error_trap_push ();
+
+        for (i = 0;
+             i < 20 && (rc = XSetDeviceButtonMapping (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), device, (unsigned char*)map->map, map->nmap)) == MappingBusy;
+             ++i) {
+                g_usleep (300);
+        }
+
+        if (rc != Success)
+                g_warning ("Error in setting button mapping for \"%s\"", device_info->name);
+
+        gdk_error_trap_pop ();
+}
+
+
+static void
+set_button_mapping (GsdWacomManager *manager,
+                    GVariant      *value,
+                    const gchar     *device_type)
+{
+        struct buttonmap_data map;
+
+        map.map = g_variant_get_fixed_array (value, &map.nmap, sizeof(gint32));
+        map.device_type = device_type;
+
+        wacom_foreach_device (set_button_mapping_cb, &map);
+}
+
+static void
+stylus_button_mapping (GsdWacomManager *manager,
+                       GVariant *list)
+{
+    set_button_mapping (manager, list, "STYLUS");
+}
+
+static void
+eraser_button_mapping (GsdWacomManager *manager,
+                       GVariant *list)
+{
+    set_button_mapping (manager, list, "ERASER");
+}
+
+static void
+pad_button_mapping (GsdWacomManager *manager,
+                    GVariant *list)
+{
+    set_button_mapping (manager, list, "PAD");
+}
+
+static void
+cursor_button_mapping (GsdWacomManager *manager,
+                       GVariant *list)
+{
+    set_button_mapping (manager, list, "PAD");
+}
+
+
+
+static void
+wacom_touch_cb (XDeviceInfo *device_info, XDevice *device, void *userdata)
+{
+        int rc;
+        Atom prop;
+        Atom realtype;
+        int realformat;
+        unsigned long nitems, bytes_after;
+        unsigned char *data;
+
+        prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), "Wacom Enable Touch", False);
+        if (!prop)
+                return;
+
+        gdk_error_trap_push ();
+
+        rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), device, prop, 0, 1, False,
+                                 XA_INTEGER, &realtype, &realformat, &nitems,
+                                 &bytes_after, &data);
+
+        if (rc != Success || realtype != XA_INTEGER || realformat != 8) {
+                gdk_error_trap_pop ();
+                XFree (data);
+                return;
+        }
+
+        data[0] = *(gboolean*)userdata;
+        XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), device,
+                        prop, XA_INTEGER, 8,
+                        PropModeReplace, data, nitems);
+
+        XFree (data);
+        if (gdk_error_trap_pop ())
+                g_warning ("Error in rotating device \"%s\"", device_info->name);
+}
+
+static void
+wacom_touch (GsdWacomManager *manager,
+             gboolean         touch)
+{
+        wacom_foreach_device (wacom_touch_cb, &touch);
+}
+
+static void
+wacom_tpcbutton_cb (XDeviceInfo *device_info, XDevice *device, void *userdata)
+{
+        int rc;
+        Atom prop;
+        Atom realtype;
+        int realformat;
+        unsigned long nitems, bytes_after;
+        unsigned char *data;
+
+        prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), "Wacom Hover Click", False);
+        if (!prop)
+                return;
+
+        gdk_error_trap_push ();
+
+        rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), device, prop, 0, 1, False,
+                                 XA_INTEGER, &realtype, &realformat, &nitems,
+                                 &bytes_after, &data);
+
+        if (rc != Success || realtype != XA_INTEGER || realformat != 8) {
+                gdk_error_trap_pop ();
+                XFree (data);
+                return;
+        }
+
+        data[0] = *(gboolean*)userdata;
+        XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), device,
+                        prop, XA_INTEGER, 8,
+                        PropModeReplace, data, nitems);
+
+        XFree (data);
+        if (gdk_error_trap_pop ())
+                g_warning ("Error in rotating device \"%s\"", device_info->name);
+}
+
+static void
+wacom_tpcbutton (GsdWacomManager *manager,
+                 gboolean         tpcbutton)
+{
+        wacom_foreach_device (wacom_tpcbutton_cb, &tpcbutton);
+}
+
+struct pressuredata {
+        gint threshold;
+        char *device_type;
+};
+
+static void
+wacom_pressurethreshold_cb (XDeviceInfo *device_info, XDevice *device, void *userdata)
+{
+        int rc;
+        Atom prop;
+        Atom realtype;
+        int realformat;
+        unsigned long nitems, bytes_after;
+        unsigned char *data;
+        struct pressuredata *pdata = (struct pressuredata*)userdata;
+
+        if (device_info->type != XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), pdata->device_type, False))
+                return;
+
+        prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), "Wacom Pressure Threshold", False);
+        if (!prop)
+                return;
+
+        gdk_error_trap_push ();
+
+        rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), device, prop, 0, 1, False,
+                                 XA_INTEGER, &realtype, &realformat, &nitems,
+                                 &bytes_after, &data);
+
+        if (rc != Success || realtype != XA_INTEGER || realformat != 32) {
+                gdk_error_trap_pop ();
+                XFree (data);
+                return;
+        }
+
+        data[0] = *(gboolean*)userdata;
+        XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), device,
+                        prop, XA_INTEGER, 32,
+                        PropModeReplace, data, nitems);
+
+        XFree (data);
+        if (gdk_error_trap_pop ())
+                g_warning ("Error in rotating device \"%s\"", device_info->name);
+}
+
+static void
+stylus_pressurethreshold (GsdWacomManager *manager, gint threshold)
+{
+        struct pressuredata pdata;
+        pdata.threshold = threshold;
+        pdata.device_type = "STYLUS";
+        wacom_foreach_device (wacom_pressurethreshold_cb, &pdata);
+}
+
+static void
+eraser_pressurethreshold (GsdWacomManager *manager, gint threshold)
+{
+        struct pressuredata pdata;
+        pdata.threshold = threshold;
+        pdata.device_type = "ERASER";
+        wacom_foreach_device (wacom_pressurethreshold_cb, &pdata);
+}
+
+static void
+set_wacom_settings (GsdWacomManager *manager)
+{
+        wacom_rotate (manager, g_settings_get_int (manager->priv->wacom_settings, KEY_ROTATION));
+
+        wacom_touch (manager, g_settings_get_boolean (manager->priv->wacom_settings, KEY_TOUCH));
+        wacom_tpcbutton (manager, g_settings_get_boolean (manager->priv->wacom_settings, KEY_TPCBUTTON));
+
+        stylus_pressurecurve (manager,
+                              g_settings_get_value (manager->priv->stylus_settings, KEY_PRESSURECURVE));
+        eraser_pressurecurve (manager,
+                              g_settings_get_value (manager->priv->eraser_settings, KEY_PRESSURECURVE));
+
+        stylus_set_absolute (manager,
+                             g_settings_get_boolean (manager->priv->stylus_settings, KEY_IS_ABSOLUTE));
+        eraser_set_absolute (manager,
+                             g_settings_get_boolean (manager->priv->eraser_settings, KEY_IS_ABSOLUTE));
+        cursor_set_absolute (manager,
+                             g_settings_get_boolean (manager->priv->cursor_settings, KEY_IS_ABSOLUTE));
+        /* pad can't be set to absolute */
+
+
+        stylus_area (manager,
+                     g_settings_get_value (manager->priv->stylus_settings, KEY_AREA));
+        eraser_area (manager,
+                     g_settings_get_value (manager->priv->eraser_settings, KEY_AREA));
+        cursor_area (manager,
+                     g_settings_get_value (manager->priv->cursor_settings, KEY_AREA));
+        pad_area (manager,
+                  g_settings_get_value (manager->priv->pad_settings, KEY_AREA));
+
+        stylus_button_mapping (manager,
+                               g_settings_get_value (manager->priv->stylus_settings, KEY_BUTTONS));
+        eraser_button_mapping (manager,
+                               g_settings_get_value (manager->priv->eraser_settings, KEY_BUTTONS));
+        pad_button_mapping (manager,
+                            g_settings_get_value (manager->priv->pad_settings, KEY_BUTTONS));
+        cursor_button_mapping (manager,
+                               g_settings_get_value (manager->priv->cursor_settings, KEY_BUTTONS));
+
+        stylus_pressurethreshold (manager,
+                                  g_settings_get_int (manager->priv->stylus_settings, KEY_PRESSURETHRESHOLD));
+        eraser_pressurethreshold (manager,
+                                  g_settings_get_int (manager->priv->eraser_settings, KEY_PRESSURETHRESHOLD));
+}
+
+static void
+wacom_callback (GSettings          *settings,
+                const gchar        *key,
+                GsdWacomManager    *manager)
+{
+        set_wacom_settings (manager);
+}
+
+static void
+gsd_wacom_manager_init (GsdWacomManager *manager)
+{
+        manager->priv = GSD_WACOM_MANAGER_GET_PRIVATE (manager);
+}
+
+static gboolean
+gsd_wacom_manager_idle_cb (GsdWacomManager *manager)
+{
+        gnome_settings_profile_start (NULL);
+
+        manager->priv->wacom_settings = g_settings_new (SETTINGS_WACOM_DIR);
+        g_signal_connect (manager->priv->wacom_settings, "changed",
+                          G_CALLBACK (wacom_callback), manager);
+
+        manager->priv->stylus_settings = g_settings_new (SETTINGS_STYLUS_DIR);
+        g_signal_connect (manager->priv->stylus_settings, "changed",
+                          G_CALLBACK (wacom_callback), manager);
+
+        manager->priv->eraser_settings = g_settings_new (SETTINGS_ERASER_DIR);
+        g_signal_connect (manager->priv->eraser_settings, "changed",
+                          G_CALLBACK (wacom_callback), manager);
+
+        manager->priv->cursor_settings = g_settings_new (SETTINGS_CURSOR_DIR);
+        g_signal_connect (manager->priv->cursor_settings, "changed",
+                          G_CALLBACK (wacom_callback), manager);
+
+        manager->priv->pad_settings = g_settings_new (SETTINGS_PAD_DIR);
+        g_signal_connect (manager->priv->pad_settings, "changed",
+                          G_CALLBACK (wacom_callback), manager);
+
+        set_devicepresence_handler (manager);
+        set_wacom_settings (manager);
+
+        gnome_settings_profile_end (NULL);
+
+        return FALSE;
+}
+
+gboolean
+gsd_wacom_manager_start (GsdWacomManager *manager,
+                         GError         **error)
+{
+        gnome_settings_profile_start (NULL);
+
+        g_idle_add ((GSourceFunc) gsd_wacom_manager_idle_cb, manager);
+
+        gnome_settings_profile_end (NULL);
+
+        return TRUE;
+}
+
+void
+gsd_wacom_manager_stop (GsdWacomManager *manager)
+{
+        GsdWacomManagerPrivate *p = manager->priv;
+
+        g_debug ("Stopping wacom manager");
+
+        if (p->device_manager != NULL) {
+                g_object_unref (p->device_manager);
+                p->device_manager = NULL;
+        }
+
+        g_object_unref (p->wacom_settings);
+        p->wacom_settings = NULL;
+
+        g_object_unref (p->stylus_settings);
+        p->stylus_settings = NULL;
+
+        g_object_unref (p->eraser_settings);
+        p->eraser_settings = NULL;
+
+        g_object_unref (p->cursor_settings);
+        p->cursor_settings = NULL;
+
+        g_object_unref (p->pad_settings);
+        p->pad_settings = NULL;
+}
+
+static void
+gsd_wacom_manager_finalize (GObject *object)
+{
+        GsdWacomManager *wacom_manager;
+
+        g_return_if_fail (object != NULL);
+        g_return_if_fail (GSD_IS_WACOM_MANAGER (object));
+
+        wacom_manager = GSD_WACOM_MANAGER (object);
+
+        g_return_if_fail (wacom_manager->priv != NULL);
+
+        G_OBJECT_CLASS (gsd_wacom_manager_parent_class)->finalize (object);
+}
+
+GsdWacomManager *
+gsd_wacom_manager_new (void)
+{
+        if (manager_object != NULL) {
+                g_object_ref (manager_object);
+        } else {
+                manager_object = g_object_new (GSD_TYPE_WACOM_MANAGER, NULL);
+                g_object_add_weak_pointer (manager_object,
+                                           (gpointer *) &manager_object);
+        }
+
+        return GSD_WACOM_MANAGER (manager_object);
+}
diff --git a/plugins/wacom/gsd-wacom-manager.h b/plugins/wacom/gsd-wacom-manager.h
new file mode 100644
index 0000000..2aba48a
--- /dev/null
+++ b/plugins/wacom/gsd-wacom-manager.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef __GSD_WACOM_MANAGER_H
+#define __GSD_WACOM_MANAGER_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GSD_TYPE_WACOM_MANAGER         (gsd_wacom_manager_get_type ())
+#define GSD_WACOM_MANAGER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_WACOM_MANAGER, GsdWacomManager))
+#define GSD_WACOM_MANAGER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_WACOM_MANAGER, GsdWacomManagerClass))
+#define GSD_IS_WACOM_MANAGER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_WACOM_MANAGER))
+#define GSD_IS_WACOM_MANAGER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_WACOM_MANAGER))
+#define GSD_WACOM_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_WACOM_MANAGER, GsdWacomManagerClass))
+
+typedef struct GsdWacomManagerPrivate GsdWacomManagerPrivate;
+
+typedef struct
+{
+        GObject                     parent;
+        GsdWacomManagerPrivate *priv;
+} GsdWacomManager;
+
+typedef struct
+{
+        GObjectClass   parent_class;
+} GsdWacomManagerClass;
+
+GType                   gsd_wacom_manager_get_type            (void);
+
+GsdWacomManager *       gsd_wacom_manager_new                 (void);
+gboolean                gsd_wacom_manager_start               (GsdWacomManager *manager,
+                                                               GError         **error);
+void                    gsd_wacom_manager_stop                (GsdWacomManager *manager);
+
+G_END_DECLS
+
+#endif /* __GSD_WACOM_MANAGER_H */
diff --git a/plugins/wacom/gsd-wacom-plugin.c b/plugins/wacom/gsd-wacom-plugin.c
new file mode 100644
index 0000000..835c6cd
--- /dev/null
+++ b/plugins/wacom/gsd-wacom-plugin.c
@@ -0,0 +1,111 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+
+#include "gnome-settings-plugin.h"
+#include "gsd-wacom-plugin.h"
+#include "gsd-wacom-manager.h"
+
+struct GsdWacomPluginPrivate {
+        GsdWacomManager *manager;
+};
+
+#define GSD_WACOM_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), GSD_TYPE_WACOM_PLUGIN, GsdWacomPluginPrivate))
+
+GNOME_SETTINGS_PLUGIN_REGISTER (GsdWacomPlugin, gsd_wacom_plugin)
+
+static void
+gsd_wacom_plugin_init (GsdWacomPlugin *plugin)
+{
+        plugin->priv = GSD_WACOM_PLUGIN_GET_PRIVATE (plugin);
+
+        g_debug ("GsdWacomPlugin initializing");
+
+        plugin->priv->manager = gsd_wacom_manager_new ();
+}
+
+static void
+gsd_wacom_plugin_finalize (GObject *object)
+{
+        GsdWacomPlugin *plugin;
+
+        g_return_if_fail (object != NULL);
+        g_return_if_fail (GSD_IS_WACOM_PLUGIN (object));
+
+        g_debug ("GsdWacomPlugin finalizing");
+
+        plugin = GSD_WACOM_PLUGIN (object);
+
+        g_return_if_fail (plugin->priv != NULL);
+
+        if (plugin->priv->manager != NULL) {
+                g_object_unref (plugin->priv->manager);
+        }
+
+        G_OBJECT_CLASS (gsd_wacom_plugin_parent_class)->finalize (object);
+}
+
+static void
+impl_activate (GnomeSettingsPlugin *plugin)
+{
+        gboolean res;
+        GError  *error;
+
+        g_debug ("Activating wacom plugin");
+
+        error = NULL;
+        res = gsd_wacom_manager_start (GSD_WACOM_PLUGIN (plugin)->priv->manager, &error);
+        if (! res) {
+                g_warning ("Unable to start wacom manager: %s", error->message);
+                g_error_free (error);
+        }
+}
+
+static void
+impl_deactivate (GnomeSettingsPlugin *plugin)
+{
+        g_debug ("Deactivating wacom plugin");
+        gsd_wacom_manager_stop (GSD_WACOM_PLUGIN (plugin)->priv->manager);
+}
+
+static void
+gsd_wacom_plugin_class_init (GsdWacomPluginClass *klass)
+{
+        GObjectClass           *object_class = G_OBJECT_CLASS (klass);
+        GnomeSettingsPluginClass *plugin_class = GNOME_SETTINGS_PLUGIN_CLASS (klass);
+
+        object_class->finalize = gsd_wacom_plugin_finalize;
+
+        plugin_class->activate = impl_activate;
+        plugin_class->deactivate = impl_deactivate;
+
+        g_type_class_add_private (klass, sizeof (GsdWacomPluginPrivate));
+}
+
+static void
+gsd_wacom_plugin_class_finalize (GsdWacomPluginClass *klass)
+{
+}
+
diff --git a/plugins/wacom/gsd-wacom-plugin.h b/plugins/wacom/gsd-wacom-plugin.h
new file mode 100644
index 0000000..2669411
--- /dev/null
+++ b/plugins/wacom/gsd-wacom-plugin.h
@@ -0,0 +1,60 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef __GSD_WACOM_PLUGIN_H__
+#define __GSD_WACOM_PLUGIN_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gmodule.h>
+
+#include "gnome-settings-plugin.h"
+
+G_BEGIN_DECLS
+
+#define GSD_TYPE_WACOM_PLUGIN                (gsd_wacom_plugin_get_type ())
+#define GSD_WACOM_PLUGIN(o)                  (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_WACOM_PLUGIN, GsdWacomPlugin))
+#define GSD_WACOM_PLUGIN_CLASS(k)            (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_WACOM_PLUGIN, GsdWacomPluginClass))
+#define GSD_IS_WACOM_PLUGIN(o)               (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_WACOM_PLUGIN))
+#define GSD_IS_WACOM_PLUGIN_CLASS(k)         (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_WACOM_PLUGIN))
+#define GSD_WACOM_PLUGIN_GET_CLASS(o)        (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_WACOM_PLUGIN, GsdWacomPluginClass))
+
+typedef struct GsdWacomPluginPrivate GsdWacomPluginPrivate;
+
+typedef struct
+{
+        GnomeSettingsPlugin    parent;
+        GsdWacomPluginPrivate *priv;
+} GsdWacomPlugin;
+
+typedef struct
+{
+        GnomeSettingsPluginClass parent_class;
+} GsdWacomPluginClass;
+
+GType   gsd_wacom_plugin_get_type            (void) G_GNUC_CONST;
+
+/* All the plugins must implement this function */
+G_MODULE_EXPORT GType register_gnome_settings_plugin (GTypeModule *module);
+
+G_END_DECLS
+
+#endif /* __GSD_WACOM_PLUGIN_H__ */
diff --git a/plugins/wacom/wacom.gnome-settings-plugin.in b/plugins/wacom/wacom.gnome-settings-plugin.in
new file mode 100644
index 0000000..8f63f29
--- /dev/null
+++ b/plugins/wacom/wacom.gnome-settings-plugin.in
@@ -0,0 +1,8 @@
+[GNOME Settings Plugin]
+Module=wacom
+IAge=0
+_Name=Wacom
+_Description=Wacom plugin
+Authors=
+Copyright=Copyright © 2010
+Website=
