[gimp] app: get rid of GtkInputDialog, also brings us closer to XI2



commit c6bbeda4440b72e2914496b03c74e45674c11024
Author: Michael Natterer <mitch gimp org>
Date:   Fri Feb 12 15:46:07 2010 +0100

    app: get rid of GtkInputDialog, also brings us closer to XI2
    
    Added two new widgets, GimpDeviceInfoEditor, which is an editor/view
    widget for GimpDeviceInfo, and GimpDeviceEditor, which is an editor
    widget for all devices. Both are pretty much ugly right now and look a
    lot like the old GtkInputDialog, but are at least internally cleaned
    up and easily changable code and ui wise. Consider this a completely
    intermediate state.
    
    Also cleaned up GimpDeviceInfo so it's possible to have a proper
    view on it, and did the needed changes to the preferences dialog
    to use the new stuff.

 app/dialogs/preferences-dialog.c   |   69 +++---
 app/widgets/Makefile.am            |    4 +
 app/widgets/gimpdeviceeditor.c     |  129 ++++++++++
 app/widgets/gimpdeviceeditor.h     |   48 ++++
 app/widgets/gimpdeviceinfo.c       |  228 +++++++++++++-----
 app/widgets/gimpdeviceinfo.h       |   36 +++-
 app/widgets/gimpdeviceinfoeditor.c |  469 ++++++++++++++++++++++++++++++++++++
 app/widgets/gimpdeviceinfoeditor.h |   51 ++++
 app/widgets/widgets-types.h        |    2 +
 9 files changed, 944 insertions(+), 92 deletions(-)
---
diff --git a/app/dialogs/preferences-dialog.c b/app/dialogs/preferences-dialog.c
index 742684d..5eb841a 100644
--- a/app/dialogs/preferences-dialog.c
+++ b/app/dialogs/preferences-dialog.c
@@ -19,9 +19,6 @@
 
 #include <string.h>
 
-#undef GTK_DISABLE_DEPRECATED /* GtkInputDialog */
-#undef GSEAL_ENABLE
-
 #include <gtk/gtk.h>
 
 #include "libgimpmath/gimpmath.h"
@@ -41,7 +38,7 @@
 #include "widgets/gimpcontainercombobox.h"
 #include "widgets/gimpcontainerview.h"
 #include "widgets/gimpcontrollerlist.h"
-#include "widgets/gimpdeviceinfo.h"
+#include "widgets/gimpdeviceeditor.h"
 #include "widgets/gimpdevices.h"
 #include "widgets/gimpdialogfactory.h"
 #include "widgets/gimpgrideditor.h"
@@ -103,9 +100,9 @@ static void   prefs_resolution_calibrate_callback (GtkWidget  *widget,
                                                    GtkWidget  *entry);
 static void   prefs_input_devices_dialog          (GtkWidget  *widget,
                                                    Gimp       *gimp);
-static void   prefs_input_dialog_able_callback    (GtkWidget  *widget,
-                                                   GdkDevice  *device,
-                                                   gpointer    data);
+static void   prefs_input_devices_dialog_response (GtkWidget  *dialog,
+                                                   gint        response_id,
+                                                   Gimp       *gimp);
 static void   prefs_menus_save_callback           (GtkWidget  *widget,
                                                    Gimp       *gimp);
 static void   prefs_menus_clear_callback          (GtkWidget  *widget,
@@ -498,15 +495,28 @@ prefs_input_devices_dialog (GtkWidget *widget,
 {
   static GtkWidget *input_dialog = NULL;
 
+  GtkWidget *content_area;
+  GtkWidget *editor;
+
   if (input_dialog)
     {
       gtk_window_present (GTK_WINDOW (input_dialog));
       return;
     }
 
-  input_dialog = g_object_new (GTK_TYPE_INPUT_DIALOG,
-                               "title", _("Configure Input Devices"),
-                               NULL);
+  input_dialog = gimp_dialog_new (_("Configure Input Devices"), "preferences",
+                                  NULL, 0,
+                                  NULL, NULL,
+
+                                  GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
+                                  GTK_STOCK_SAVE,  GTK_RESPONSE_OK,
+
+                                  NULL);
+
+  gtk_dialog_set_alternative_button_order (GTK_DIALOG (input_dialog),
+                                           GTK_RESPONSE_OK,
+                                           GTK_RESPONSE_CLOSE,
+                                           -1);
 
   g_object_add_weak_pointer (G_OBJECT (input_dialog),
                              (gpointer) &input_dialog);
@@ -515,32 +525,35 @@ prefs_input_devices_dialog (GtkWidget *widget,
                                 GTK_WINDOW (prefs_dialog));
   gtk_window_set_destroy_with_parent (GTK_WINDOW (input_dialog), TRUE);
 
-  g_signal_connect_swapped (GTK_INPUT_DIALOG (input_dialog)->save_button,
-                            "clicked",
-                            G_CALLBACK (gimp_devices_save),
-                            gimp);
+  g_signal_connect (input_dialog, "response",
+                    G_CALLBACK (prefs_input_devices_dialog_response),
+                    gimp);
 
-  g_signal_connect_swapped (GTK_INPUT_DIALOG (input_dialog)->close_button,
-                            "clicked",
-                            G_CALLBACK (gtk_widget_destroy),
-                            input_dialog);
+  content_area = gtk_dialog_get_content_area (GTK_DIALOG (input_dialog));
 
-  g_signal_connect (input_dialog, "enable-device",
-                    G_CALLBACK (prefs_input_dialog_able_callback),
-                    NULL);
-  g_signal_connect (input_dialog, "disable-device",
-                    G_CALLBACK (prefs_input_dialog_able_callback),
-                    NULL);
+  editor = gimp_device_editor_new ();
+  gtk_container_set_border_width (GTK_CONTAINER (editor), 12);
+  gtk_container_add (GTK_CONTAINER (content_area), editor);
+  gtk_widget_show (editor);
 
   gtk_widget_show (input_dialog);
 }
 
 static void
-prefs_input_dialog_able_callback (GtkWidget *widget,
-                                  GdkDevice *device,
-                                  gpointer   data)
+prefs_input_devices_dialog_response (GtkWidget *dialog,
+                                     gint       response_id,
+                                     Gimp      *gimp)
 {
-  gimp_device_info_changed_by_device (device);
+  switch (response_id)
+    {
+    case GTK_RESPONSE_OK:
+      gimp_devices_save (gimp, TRUE);
+      break;
+
+    default:
+      gtk_widget_destroy (dialog);
+      break;
+    }
 }
 
 static void
diff --git a/app/widgets/Makefile.am b/app/widgets/Makefile.am
index a595be1..b1b09ad 100644
--- a/app/widgets/Makefile.am
+++ b/app/widgets/Makefile.am
@@ -112,8 +112,12 @@ libappwidgets_a_sources = \
 	gimpdataeditor.h		\
 	gimpdatafactoryview.c		\
 	gimpdatafactoryview.h		\
+	gimpdeviceeditor.c		\
+	gimpdeviceeditor.h		\
 	gimpdeviceinfo.c		\
 	gimpdeviceinfo.h		\
+	gimpdeviceinfoeditor.c		\
+	gimpdeviceinfoeditor.h		\
 	gimpdevices.c			\
 	gimpdevices.h			\
 	gimpdevicestatus.c		\
diff --git a/app/widgets/gimpdeviceeditor.c b/app/widgets/gimpdeviceeditor.c
new file mode 100644
index 0000000..f15d5dc
--- /dev/null
+++ b/app/widgets/gimpdeviceeditor.c
@@ -0,0 +1,129 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+
+#include "libgimpwidgets/gimpwidgets.h"
+
+#include "widgets-types.h"
+
+#include "core/gimpmarshal.h"
+
+#include "gimpdeviceeditor.h"
+#include "gimpdeviceinfo.h"
+#include "gimpdeviceinfoeditor.h"
+
+#include "gimp-intl.h"
+
+
+typedef struct _GimpDeviceEditorPrivate GimpDeviceEditorPrivate;
+
+struct _GimpDeviceEditorPrivate
+{
+  GtkWidget *notebook;
+};
+
+
+#define GIMP_DEVICE_EDITOR_GET_PRIVATE(editor) \
+        G_TYPE_INSTANCE_GET_PRIVATE (editor, \
+                                     GIMP_TYPE_DEVICE_EDITOR, \
+                                     GimpDeviceEditorPrivate)
+
+
+static void gimp_device_editor_screen_changed (GtkWidget *widget,
+                                               GdkScreen *previous_screen);
+
+
+G_DEFINE_TYPE (GimpDeviceEditor, gimp_device_editor, GTK_TYPE_HBOX)
+
+
+static void
+gimp_device_editor_class_init (GimpDeviceEditorClass *klass)
+{
+  GObjectClass   *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  widget_class->screen_changed = gimp_device_editor_screen_changed;
+
+  g_type_class_add_private (object_class, sizeof (GimpDeviceEditorPrivate));
+}
+
+static void
+gimp_device_editor_init (GimpDeviceEditor *editor)
+{
+  GimpDeviceEditorPrivate *private = GIMP_DEVICE_EDITOR_GET_PRIVATE (editor);
+
+  gtk_box_set_spacing (GTK_BOX (editor), 12);
+
+  private->notebook = gtk_notebook_new ();
+  gtk_notebook_set_tab_pos (GTK_NOTEBOOK (private->notebook), GTK_POS_LEFT);
+  gtk_box_pack_start (GTK_BOX (editor), private->notebook, TRUE, TRUE, 0);
+  gtk_widget_show (private->notebook);
+}
+
+static void
+gimp_device_editor_screen_changed (GtkWidget *widget,
+                                   GdkScreen *previous_screen)
+{
+  GimpDeviceEditor        *editor       = GIMP_DEVICE_EDITOR (widget);
+  GimpDeviceEditorPrivate *private      = GIMP_DEVICE_EDITOR_GET_PRIVATE (editor);
+  GdkDevice               *core_pointer = NULL;
+  GList                   *devices      = NULL;
+  GList                   *list;
+
+  if (gtk_widget_has_screen (widget))
+    {
+      GdkDisplay *display = gtk_widget_get_display (widget);
+
+      devices      = gdk_display_list_devices (display);
+      core_pointer = gdk_display_get_core_pointer (display);
+    }
+
+  gtk_container_foreach (GTK_CONTAINER (private->notebook),
+                         (GtkCallback) gtk_widget_destroy,
+                         NULL);
+
+  if (g_list_length (devices) <= 1)
+    return;
+
+  for (list = devices; list; list = g_list_next (list))
+    {
+      GdkDevice *device = list->data;
+
+      if (device != core_pointer)
+        {
+          GimpDeviceInfo *info = gimp_device_info_get_by_device (device);
+          GtkWidget      *widget;
+
+          widget = gimp_device_info_editor_new (info);
+          gtk_container_set_border_width (GTK_CONTAINER (widget), 12);
+
+          gtk_notebook_append_page (GTK_NOTEBOOK (private->notebook),
+                                    widget,
+                                    gtk_label_new (gimp_object_get_name (info)));
+          gtk_widget_show (widget);
+        }
+    }
+}
+
+GtkWidget *
+gimp_device_editor_new (void)
+{
+  return g_object_new (GIMP_TYPE_DEVICE_EDITOR, NULL);
+}
diff --git a/app/widgets/gimpdeviceeditor.h b/app/widgets/gimpdeviceeditor.h
new file mode 100644
index 0000000..c50e9f8
--- /dev/null
+++ b/app/widgets/gimpdeviceeditor.h
@@ -0,0 +1,48 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_DEVICE_EDITOR_H__
+#define __GIMP_DEVICE_EDITOR_H__
+
+
+#define GIMP_TYPE_DEVICE_EDITOR            (gimp_device_editor_get_type ())
+#define GIMP_DEVICE_EDITOR(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_DEVICE_EDITOR, GimpDeviceEditor))
+#define GIMP_DEVICE_EDITOR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_DEVICE_EDITOR, GimpDeviceEditorClass))
+#define GIMP_IS_DEVICE_EDITOR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_DEVICE_EDITOR))
+#define GIMP_IS_DEVICE_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_DEVICE_EDITOR))
+#define GIMP_DEVICE_EDITOR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_DEVICE_EDITOR, GimpDeviceEditorClass))
+
+
+typedef struct _GimpDeviceEditorClass GimpDeviceEditorClass;
+
+struct _GimpDeviceEditor
+{
+  GtkHBox  parent_instance;
+};
+
+struct _GimpDeviceEditorClass
+{
+  GtkHBoxClass  parent_class;
+};
+
+
+GType       gimp_device_editor_get_type (void) G_GNUC_CONST;
+
+GtkWidget * gimp_device_editor_new      (void);
+
+
+#endif /* __GIMP_DEVICE_EDITOR_H__ */
diff --git a/app/widgets/gimpdeviceinfo.c b/app/widgets/gimpdeviceinfo.c
index 74d5a90..e9b7b17 100644
--- a/app/widgets/gimpdeviceinfo.c
+++ b/app/widgets/gimpdeviceinfo.c
@@ -129,9 +129,9 @@ gimp_device_info_init (GimpDeviceInfo *device_info)
   device_info->device   = NULL;
   device_info->display  = NULL;
   device_info->mode     = GDK_MODE_DISABLED;
-  device_info->num_axes = 0;
+  device_info->n_axes   = 0;
   device_info->axes     = NULL;
-  device_info->num_keys = 0;
+  device_info->n_keys   = 0;
   device_info->keys     = NULL;
 }
 
@@ -210,10 +210,7 @@ gimp_device_info_set_property (GObject      *object,
   switch (property_id)
     {
     case PROP_MODE:
-      if (device)
-        gdk_device_set_mode (device, g_value_get_enum (value));
-      else
-        device_info->mode = g_value_get_enum (value);
+      gimp_device_info_set_mode (device_info, g_value_get_enum (value));
       break;
 
     case PROP_AXES:
@@ -233,8 +230,8 @@ gimp_device_info_set_property (GObject      *object,
               {
                 n_device_values = array->n_values;
 
-                device_info->num_axes = n_device_values;
-                device_info->axes     = g_new0 (GdkAxisUse, n_device_values);
+                device_info->n_axes = n_device_values;
+                device_info->axes   = g_new0 (GdkAxisUse, n_device_values);
               }
 
             for (i = 0; i < n_device_values; i++)
@@ -243,10 +240,7 @@ gimp_device_info_set_property (GObject      *object,
 
                 axis_use = g_value_get_enum (g_value_array_get_nth (array, i));
 
-                if (device)
-                  gdk_device_set_axis_use (device, i, axis_use);
-                else
-                  device_info->axes[i] = axis_use;
+                gimp_device_info_set_axis_use (device_info, i, axis_use);
               }
           }
       }
@@ -269,8 +263,8 @@ gimp_device_info_set_property (GObject      *object,
               {
                 n_device_values = array->n_values;
 
-                device_info->num_keys = n_device_values;
-                device_info->keys     = g_new0 (GdkDeviceKey, n_device_values);
+                device_info->n_keys = n_device_values;
+                device_info->keys   = g_new0 (GdkDeviceKey, n_device_values);
               }
 
             for (i = 0; i < n_device_values; i++)
@@ -283,15 +277,7 @@ gimp_device_info_set_property (GObject      *object,
 
                 gtk_accelerator_parse (accel, &keyval, &modifiers);
 
-                if (device)
-                  {
-                    gdk_device_set_key (device, i, keyval, modifiers);
-                  }
-                else
-                  {
-                    device_info->keys[i].keyval    = keyval;
-                    device_info->keys[i].modifiers = modifiers;
-                  }
+                gimp_device_info_set_key (device_info, i, keyval, modifiers);
               }
           }
       }
@@ -310,31 +296,30 @@ gimp_device_info_get_property (GObject    *object,
                                GParamSpec *pspec)
 {
   GimpDeviceInfo *device_info = GIMP_DEVICE_INFO (object);
-  GdkDevice      *device      = device_info->device;
 
   switch (property_id)
     {
     case PROP_MODE:
-      if (device)
-        g_value_set_enum (value, device->mode);
-      else
-        g_value_set_enum (value, device_info->mode);
+      g_value_set_enum (value, gimp_device_info_get_mode (device_info));
       break;
 
     case PROP_AXES:
       {
         GValueArray *array;
         GValue       enum_value = { 0, };
+        gint         n_axes;
         gint         i;
 
         array = g_value_array_new (6);
         g_value_init (&enum_value, GDK_TYPE_AXIS_USE);
 
-        for (i = 0; i < (device ? device->num_axes : device_info->num_axes); i++)
+        n_axes = gimp_device_info_get_n_axes (device_info);
+
+        for (i = 0; i < n_axes; i++)
           {
             g_value_set_enum (&enum_value,
-                              device ?
-                              device->axes[i].use : device_info->axes[i]);
+                              gimp_device_info_get_axis_use (device_info, i));
+
             g_value_array_append (array, &enum_value);
           }
 
@@ -348,17 +333,20 @@ gimp_device_info_get_property (GObject    *object,
       {
         GValueArray *array;
         GValue       string_value = { 0, };
+        gint         n_keys;
         gint         i;
 
         array = g_value_array_new (32);
         g_value_init (&string_value, G_TYPE_STRING);
 
-        for (i = 0; i < (device ? device->num_keys : device_info->num_keys); i++)
+        n_keys = gimp_device_info_get_n_keys (device_info);
+
+        for (i = 0; i < n_keys; i++)
           {
-            GdkModifierType modifiers = (device ? device->keys[i].modifiers :
-                                         device_info->keys[i].modifiers);
-            guint           keyval    = (device ? device->keys[i].keyval :
-                                         device_info->keys[i].keyval);
+            guint           keyval;
+            GdkModifierType modifiers;
+
+            gimp_device_info_get_key (device_info, i, &keyval, &modifiers);
 
             if (keyval)
               {
@@ -392,6 +380,9 @@ gimp_device_info_get_property (GObject    *object,
     }
 }
 
+
+/*  public functions  */
+
 GimpDeviceInfo *
 gimp_device_info_new (Gimp        *gimp,
                       const gchar *name)
@@ -405,6 +396,144 @@ gimp_device_info_new (Gimp        *gimp,
                        NULL);
 }
 
+GdkInputMode
+gimp_device_info_get_mode (GimpDeviceInfo *info)
+{
+  g_return_val_if_fail (GIMP_IS_DEVICE_INFO (info), GDK_MODE_DISABLED);
+
+  if (info->device)
+    return info->device->mode;
+  else
+    return info->mode;
+}
+
+void
+gimp_device_info_set_mode (GimpDeviceInfo *info,
+                           GdkInputMode    mode)
+{
+  g_return_if_fail (GIMP_IS_DEVICE_INFO (info));
+
+  if (mode != gimp_device_info_get_mode (info))
+    {
+      if (info->device)
+        gdk_device_set_mode (info->device, mode);
+      else
+        info->mode = mode;
+
+      g_object_notify (G_OBJECT (info), "mode");
+      gimp_device_info_changed (info);
+    }
+}
+
+gint
+gimp_device_info_get_n_axes (GimpDeviceInfo *info)
+{
+  g_return_val_if_fail (GIMP_IS_DEVICE_INFO (info), 0);
+
+  if (info->device)
+    return info->device->num_axes;
+  else
+    return info->n_axes;
+}
+
+GdkAxisUse
+gimp_device_info_get_axis_use (GimpDeviceInfo *info,
+                               gint            axis)
+{
+  g_return_val_if_fail (GIMP_IS_DEVICE_INFO (info), GDK_AXIS_IGNORE);
+  g_return_val_if_fail (axis >= 0 && axis < gimp_device_info_get_n_axes (info),
+                        GDK_AXIS_IGNORE);
+
+  if (info->device)
+    return info->device->axes[axis].use;
+  else
+    return info->axes[axis];
+}
+
+void
+gimp_device_info_set_axis_use (GimpDeviceInfo *info,
+                               gint            axis,
+                               GdkAxisUse      use)
+{
+  g_return_if_fail (GIMP_IS_DEVICE_INFO (info));
+  g_return_if_fail (axis >= 0 && axis < gimp_device_info_get_n_axes (info));
+
+  if (use != gimp_device_info_get_axis_use (info, axis))
+    {
+      if (info->device)
+        gdk_device_set_axis_use (info->device, axis, use);
+      else
+        info->axes[axis] = use;
+
+      g_object_notify (G_OBJECT (info), "axes");
+    }
+}
+
+gint
+gimp_device_info_get_n_keys (GimpDeviceInfo *info)
+{
+  g_return_val_if_fail (GIMP_IS_DEVICE_INFO (info), 0);
+
+  if (info->device)
+    return info->device->num_keys;
+  else
+    return info->n_keys;
+}
+
+void
+gimp_device_info_get_key (GimpDeviceInfo  *info,
+                          gint             key,
+                          guint           *keyval,
+                          GdkModifierType *modifiers)
+{
+  g_return_if_fail (GIMP_IS_DEVICE_INFO (info));
+  g_return_if_fail (key >= 0 && key < gimp_device_info_get_n_keys (info));
+  g_return_if_fail (keyval != NULL);
+  g_return_if_fail (modifiers != NULL);
+
+  if (info->device)
+    {
+      *keyval    = info->device->keys[key].keyval;
+      *modifiers = info->device->keys[key].modifiers;
+    }
+  else
+    {
+      *keyval    = info->keys[key].keyval;
+      *modifiers = info->keys[key].modifiers;
+    }
+}
+
+void
+gimp_device_info_set_key (GimpDeviceInfo *info,
+                          gint             key,
+                          guint            keyval,
+                          GdkModifierType  modifiers)
+{
+  guint           old_keyval;
+  GdkModifierType old_modifiers;
+
+  g_return_if_fail (GIMP_IS_DEVICE_INFO (info));
+  g_return_if_fail (key >= 0 && key < gimp_device_info_get_n_keys (info));
+
+  gimp_device_info_get_key (info, key, &old_keyval, &old_modifiers);
+
+  if (keyval    != old_keyval ||
+      modifiers != old_modifiers)
+    {
+      if (info->device)
+        {
+          gdk_device_set_key (info->device, key, keyval, modifiers);
+        }
+      else
+        {
+          info->keys[key].keyval    = keyval;
+          info->keys[key].modifiers = modifiers;
+        }
+
+      g_object_notify (G_OBJECT (info), "keys");
+    }
+}
+
 GimpDeviceInfo *
 gimp_device_info_set_from_device (GimpDeviceInfo *device_info,
                                   GdkDevice      *device,
@@ -416,16 +545,16 @@ gimp_device_info_set_from_device (GimpDeviceInfo *device_info,
 
   g_object_set_data (G_OBJECT (device), GIMP_DEVICE_INFO_DATA_KEY, device_info);
 
-  device_info->device     = device;
-  device_info->display    = display;
+  device_info->device  = device;
+  device_info->display = display;
 
-  device_info->mode       = device->mode;
+  device_info->mode    = device->mode;
 
-  device_info->num_axes   = device->num_axes;
-  device_info->axes       = NULL;
+  device_info->n_axes  = device->num_axes;
+  device_info->axes    = NULL;
 
-  device_info->num_keys   = device->num_keys;
-  device_info->keys       = NULL;
+  device_info->n_keys  = device->num_keys;
+  device_info->keys    = NULL;
 
   return device_info;
 }
@@ -445,16 +574,3 @@ gimp_device_info_get_by_device (GdkDevice *device)
 
   return g_object_get_data (G_OBJECT (device), GIMP_DEVICE_INFO_DATA_KEY);
 }
-
-void
-gimp_device_info_changed_by_device (GdkDevice *device)
-{
-  GimpDeviceInfo *device_info;
-
-  g_return_if_fail (GDK_IS_DEVICE (device));
-
-  device_info = gimp_device_info_get_by_device (device);
-
-  if (device_info)
-    gimp_device_info_changed (device_info);
-}
diff --git a/app/widgets/gimpdeviceinfo.h b/app/widgets/gimpdeviceinfo.h
index 83e2ef5..71203a2 100644
--- a/app/widgets/gimpdeviceinfo.h
+++ b/app/widgets/gimpdeviceinfo.h
@@ -55,9 +55,9 @@ struct _GimpDeviceInfo
   /*  either "device" or the options below are set  */
 
   GdkInputMode   mode;
-  gint           num_axes;
+  gint           n_axes;
   GdkAxisUse    *axes;
-  gint           num_keys;
+  gint           n_keys;
   GdkDeviceKey  *keys;
 };
 
@@ -71,16 +71,36 @@ struct _GimpDeviceInfoClass
 
 GType            gimp_device_info_get_type          (void) G_GNUC_CONST;
 
-GimpDeviceInfo * gimp_device_info_new               (Gimp           *gimp,
-                                                     const gchar    *name);
-
-GimpDeviceInfo * gimp_device_info_set_from_device   (GimpDeviceInfo *device_info,
+GimpDeviceInfo * gimp_device_info_new               (Gimp            *gimp,
+                                                     const gchar     *name);
+
+GdkInputMode     gimp_device_info_get_mode          (GimpDeviceInfo  *info);
+void             gimp_device_info_set_mode          (GimpDeviceInfo  *info,
+                                                     GdkInputMode     mode);
+
+gint             gimp_device_info_get_n_axes        (GimpDeviceInfo  *info);
+GdkAxisUse       gimp_device_info_get_axis_use      (GimpDeviceInfo  *info,
+                                                     gint             axis);
+void             gimp_device_info_set_axis_use      (GimpDeviceInfo  *info,
+                                                     gint             axis,
+                                                     GdkAxisUse       use);
+
+gint             gimp_device_info_get_n_keys        (GimpDeviceInfo  *info);
+void             gimp_device_info_get_key           (GimpDeviceInfo  *info,
+                                                     gint             key,
+                                                     guint           *keyval,
+                                                     GdkModifierType *modifiers);
+void             gimp_device_info_set_key           (GimpDeviceInfo *info,
+                                                     gint             key,
+                                                     guint            keyval,
+                                                     GdkModifierType  modifiers);
+
+GimpDeviceInfo * gimp_device_info_set_from_device   (GimpDeviceInfo *info,
                                                      GdkDevice      *device,
                                                      GdkDisplay     *display);
-void             gimp_device_info_changed           (GimpDeviceInfo *device_info);
+void             gimp_device_info_changed           (GimpDeviceInfo *info);
 
 GimpDeviceInfo * gimp_device_info_get_by_device     (GdkDevice      *device);
-void             gimp_device_info_changed_by_device (GdkDevice      *device);
 
 
 G_END_DECLS
diff --git a/app/widgets/gimpdeviceinfoeditor.c b/app/widgets/gimpdeviceinfoeditor.c
new file mode 100644
index 0000000..50bdbd4
--- /dev/null
+++ b/app/widgets/gimpdeviceinfoeditor.c
@@ -0,0 +1,469 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995-1999 Spencer Kimball and Peter Mattis
+ *
+ * gimpdeviceinfoeditor.c
+ * Copyright (C) 2010 Michael Natterer <mitch gimp org>
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+
+#include "libgimpwidgets/gimpwidgets.h"
+
+#include "widgets-types.h"
+
+#include "gimpdeviceinfo.h"
+#include "gimpdeviceinfoeditor.h"
+
+#include "gimp-intl.h"
+
+
+enum
+{
+  PROP_0,
+  PROP_INFO
+};
+
+
+typedef struct _GimpInputKeyInfo GimpInputKeyInfo;
+
+struct _GimpInputKeyInfo
+{
+  gint                  index;
+  GtkWidget            *entry;
+  GimpDeviceInfoEditor *editor;
+};
+
+
+typedef struct _GimpDeviceInfoEditorPrivate GimpDeviceInfoEditorPrivate;
+
+struct _GimpDeviceInfoEditorPrivate
+{
+  GimpDeviceInfo *info;
+
+  GtkWidget      *axis_combos[GDK_AXIS_LAST - GDK_AXIS_X];
+};
+
+#define GIMP_DEVICE_INFO_EDITOR_GET_PRIVATE(editor) \
+        G_TYPE_INSTANCE_GET_PRIVATE (editor, \
+                                     GIMP_TYPE_DEVICE_INFO_EDITOR, \
+                                     GimpDeviceInfoEditorPrivate)
+
+
+static GObject * gimp_device_info_editor_constructor  (GType                  type,
+                                                       guint                  n_params,
+                                                       GObjectConstructParam *params);
+static void      gimp_device_info_editor_finalize     (GObject               *object);
+static void      gimp_device_info_editor_set_property (GObject               *object,
+                                                       guint                  property_id,
+                                                       const GValue          *value,
+                                                       GParamSpec            *pspec);
+static void      gimp_device_info_editor_get_property (GObject               *object,
+                                                       guint                  property_id,
+                                                       GValue                *value,
+                                                       GParamSpec            *pspec);
+
+void             gimp_device_info_editor_axis_changed (GimpIntComboBox       *combo,
+                                                       GimpDeviceInfoEditor  *editor);
+
+static gboolean  gimp_device_info_editor_key_press    (GtkWidget        *widget,
+                                                       GdkEventKey      *event,
+                                                       GimpInputKeyInfo *key);
+static void      gimp_device_info_editor_clear_key    (GtkWidget        *widget,
+                                                       GimpInputKeyInfo *key);
+static void      gimp_device_info_editor_set_key      (GimpInputKeyInfo *key,
+                                                       guint             keyval,
+                                                       GdkModifierType   modifiers);
+
+
+G_DEFINE_TYPE (GimpDeviceInfoEditor, gimp_device_info_editor, GTK_TYPE_VBOX)
+
+#define parent_class gimp_device_info_editor_parent_class
+
+
+static void
+gimp_device_info_editor_class_init (GimpDeviceInfoEditorClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->constructor  = gimp_device_info_editor_constructor;
+  object_class->finalize     = gimp_device_info_editor_finalize;
+  object_class->set_property = gimp_device_info_editor_set_property;
+  object_class->get_property = gimp_device_info_editor_get_property;
+
+  g_object_class_install_property (object_class, PROP_INFO,
+                                   g_param_spec_object ("info",
+                                                        NULL, NULL,
+                                                        GIMP_TYPE_DEVICE_INFO,
+                                                        GIMP_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT_ONLY));
+
+  g_type_class_add_private (object_class, sizeof (GimpDeviceInfoEditorPrivate));
+}
+
+static void
+gimp_device_info_editor_init (GimpDeviceInfoEditor *editor)
+{
+  gtk_box_set_spacing (GTK_BOX (editor), 6);
+}
+
+static GObject *
+gimp_device_info_editor_constructor (GType                   type,
+                                     guint                   n_params,
+                                     GObjectConstructParam  *params)
+{
+  GObject                     *object;
+  GimpDeviceInfoEditor        *editor;
+  GimpDeviceInfoEditorPrivate *private;
+  GtkWidget                   *hbox;
+  GtkWidget                   *label;
+  GtkWidget                   *combo;
+  GtkWidget                   *table;
+  gint                         n_keys;
+  gint                         i;
+
+  object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params);
+
+  editor  = GIMP_DEVICE_INFO_EDITOR (object);
+  private = GIMP_DEVICE_INFO_EDITOR_GET_PRIVATE (object);
+
+  g_assert (GIMP_IS_DEVICE_INFO (private->info));
+
+  /*  the mode menu  */
+
+  hbox = gtk_hbox_new (FALSE, 6);
+  gtk_box_pack_start (GTK_BOX (editor), hbox, FALSE, FALSE, 0);
+  gtk_widget_show (hbox);
+
+  label = gtk_label_new_with_mnemonic (_("_Mode:"));
+  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+  gtk_widget_show (label);
+
+  combo = gimp_prop_enum_combo_box_new (G_OBJECT (private->info), "mode",
+                                        0, 0);
+  gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
+  gtk_widget_show (combo);
+
+  gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
+
+  /*  the axes  */
+
+  table = gtk_table_new (GDK_AXIS_LAST, 2, FALSE);
+  gtk_table_set_row_spacings (GTK_TABLE (table), 4);
+  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+  gtk_box_pack_start (GTK_BOX (editor), table, FALSE, FALSE, 0);
+  gtk_widget_show (table);
+
+  for (i = GDK_AXIS_X; i < GDK_AXIS_LAST; i++)
+    {
+      static const gchar *const axis_use_strings[] =
+      {
+        N_("_X:"),
+        N_("_Y:"),
+        N_("_Pressure:"),
+        N_("X _tilt:"),
+        N_("Y t_ilt:"),
+        N_("_Wheel:")
+      };
+
+      gint n_axes = gimp_device_info_get_n_axes (private->info);
+      gint j;
+
+      combo = gimp_int_combo_box_new (_("none"), -1,
+                                      NULL);
+      gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo), -1);
+      private->axis_combos[i - 1] = combo;
+      gimp_table_attach_aligned (GTK_TABLE (table), 0, i - 1,
+                                 axis_use_strings[i - 1], 0.0, 0.5,
+                                 combo, 1, FALSE);
+
+      for (j = 0; j < n_axes; j++)
+        {
+          gchar string[16];
+
+          g_snprintf (string, sizeof (string), "%d", j + 1);
+
+          gimp_int_combo_box_append (GIMP_INT_COMBO_BOX (combo),
+                                     GIMP_INT_STORE_VALUE, j,
+                                     GIMP_INT_STORE_LABEL, string,
+                                     -1);
+
+          if (gimp_device_info_get_axis_use (private->info, j) == i)
+            gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo), j);
+        }
+
+      g_signal_connect (combo, "changed",
+                        G_CALLBACK (gimp_device_info_editor_axis_changed),
+                        editor);
+    }
+
+  /*  the keys  */
+
+  n_keys = gimp_device_info_get_n_keys (private->info);
+
+  table = gtk_table_new (n_keys, 2, FALSE);
+  gtk_table_set_row_spacings (GTK_TABLE (table), 4);
+  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+  gtk_box_pack_start (GTK_BOX (editor), table, FALSE, FALSE, 0);
+  gtk_widget_show (table);
+
+  for (i = 0; i < n_keys; i++)
+    {
+      GimpInputKeyInfo *key = g_new (GimpInputKeyInfo, 1);
+      GtkWidget        *button;
+      gchar             string[32];
+      guint             keyval;
+      GdkModifierType   modifiers;
+
+      key->index  = i;
+      key->editor = editor;
+
+      g_snprintf (string, sizeof (string), "_%d:", i + 1);
+
+      hbox = gtk_hbox_new (FALSE, 6);
+
+      key->entry = gtk_entry_new ();
+      gtk_label_set_mnemonic_widget (GTK_LABEL (label), key->entry);
+      gtk_box_pack_start (GTK_BOX (hbox), key->entry, TRUE, TRUE, 0);
+
+      gimp_table_attach_aligned (GTK_TABLE (table), 0, i - 1,
+                                 string, 0.0, 0.5,
+                                 hbox, 1, FALSE);
+
+      g_signal_connect (key->entry, "key-press-event",
+                        G_CALLBACK (gimp_device_info_editor_key_press),
+                        key);
+      g_object_set_data_full (G_OBJECT (key->entry), "key", key,
+                              (GDestroyNotify) g_free);
+
+      button = gtk_button_new_with_mnemonic (_("Cl_ear"));
+      gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
+      gtk_widget_show (button);
+
+      g_signal_connect (button, "clicked",
+                        G_CALLBACK (gimp_device_info_editor_clear_key),
+                        key);
+
+      gimp_device_info_get_key (private->info, i, &keyval, &modifiers);
+
+      gimp_device_info_editor_set_key (key, keyval, modifiers);
+    }
+
+  return object;
+}
+
+static void
+gimp_device_info_editor_finalize (GObject *object)
+{
+  GimpDeviceInfoEditorPrivate *private;
+
+  private = GIMP_DEVICE_INFO_EDITOR_GET_PRIVATE (object);
+
+  if (private->info)
+    {
+      g_object_unref (private->info);
+      private->info = NULL;
+    }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gimp_device_info_editor_set_property (GObject      *object,
+                                      guint         property_id,
+                                      const GValue *value,
+                                      GParamSpec   *pspec)
+{
+  GimpDeviceInfoEditorPrivate *private;
+
+  private = GIMP_DEVICE_INFO_EDITOR_GET_PRIVATE (object);
+
+  switch (property_id)
+    {
+    case PROP_INFO:
+      private->info = g_value_dup_object (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gimp_device_info_editor_get_property (GObject    *object,
+                                      guint       property_id,
+                                      GValue     *value,
+                                      GParamSpec *pspec)
+{
+  GimpDeviceInfoEditorPrivate *private;
+
+  private = GIMP_DEVICE_INFO_EDITOR_GET_PRIVATE (object);
+
+  switch (property_id)
+    {
+    case PROP_INFO:
+      g_value_set_object (value, private->info);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+void
+gimp_device_info_editor_axis_changed (GimpIntComboBox      *combo,
+                                      GimpDeviceInfoEditor *editor)
+{
+  GimpDeviceInfoEditorPrivate *private;
+  GdkAxisUse                   new_use;
+
+  private = GIMP_DEVICE_INFO_EDITOR_GET_PRIVATE (editor);
+
+  for (new_use = GDK_AXIS_X; new_use < GDK_AXIS_LAST; new_use++)
+    {
+      if (private->axis_combos[new_use - 1] == (GtkWidget *) combo)
+        {
+          GdkAxisUse old_use  = GDK_AXIS_IGNORE;
+          gint       new_axis = -1;
+          gint       old_axis = -1;
+          gint       n_axes;
+          gint       i;
+
+          gimp_int_combo_box_get_active (combo, &new_axis);
+
+          n_axes = gimp_device_info_get_n_axes (private->info);
+
+          for (i = 0; i < n_axes; i++)
+            if (gimp_device_info_get_axis_use (private->info, i) == new_use)
+              {
+                old_axis = i;
+                break;
+              }
+
+          if (new_axis == old_axis)
+            return;
+
+          if (new_axis != -1)
+            old_use = gimp_device_info_get_axis_use (private->info, new_axis);
+
+          /* we must always have an x and a y axis */
+          if ((new_axis == -1 && (new_use == GDK_AXIS_X ||
+                                  new_use == GDK_AXIS_Y)) ||
+              (old_axis == -1 && (old_use == GDK_AXIS_X ||
+                                  old_use == GDK_AXIS_Y)))
+            {
+              gimp_int_combo_box_set_active (combo, old_axis);
+            }
+          else
+            {
+              if (new_axis != -1)
+                gimp_device_info_set_axis_use (private->info, new_axis, new_use);
+
+              if (old_axis != -1)
+                gimp_device_info_set_axis_use (private->info, old_axis, old_use);
+
+              if (old_use != GDK_AXIS_IGNORE)
+                gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (private->axis_combos[old_use - 1]),
+                                               old_axis);
+            }
+
+          break;
+        }
+    }
+}
+
+static gboolean
+gimp_device_info_editor_key_press (GtkWidget        *widget,
+                                   GdkEventKey      *event,
+                                   GimpInputKeyInfo *key)
+{
+  GimpDeviceInfoEditorPrivate *private;
+
+  private = GIMP_DEVICE_INFO_EDITOR_GET_PRIVATE (key->editor);
+
+  gimp_device_info_editor_set_key (key, event->keyval, event->state & 0xFF);
+
+  gimp_device_info_set_key (private->info, key->index,
+                            event->keyval, event->state & 0xFF);
+
+  return TRUE;
+}
+
+static void
+gimp_device_info_editor_clear_key (GtkWidget        *widget,
+                                   GimpInputKeyInfo *key)
+{
+  GimpDeviceInfoEditorPrivate *private;
+
+  private = GIMP_DEVICE_INFO_EDITOR_GET_PRIVATE (key->editor);
+
+  gimp_device_info_editor_set_key (key, 0, 0);
+
+  gimp_device_info_set_key (private->info, key->index, 0, 0);
+}
+
+static void
+gimp_device_info_editor_set_key (GimpInputKeyInfo *key,
+                                 guint             keyval,
+                                 GdkModifierType   modifiers)
+{
+  GString *str;
+  gchar    chars[2];
+
+  if (keyval)
+    {
+      str = g_string_new (NULL);
+
+      if (modifiers & GDK_SHIFT_MASK)
+        g_string_append (str, "Shift+");
+      if (modifiers & GDK_CONTROL_MASK)
+        g_string_append (str, "Ctrl+");
+      if (modifiers & GDK_MOD1_MASK)
+        g_string_append (str, "Alt+");
+
+      if ((keyval >= 0x20) && (keyval <= 0xFF))
+        {
+          chars[0] = keyval;
+          chars[1] = 0;
+          g_string_append (str, chars);
+        }
+      else
+        g_string_append (str, _("(unknown)"));
+
+      gtk_entry_set_text (GTK_ENTRY (key->entry),
+                          g_string_free (str, FALSE));
+    }
+  else
+    {
+      gtk_entry_set_text (GTK_ENTRY (key->entry), _("(disabled)"));
+    }
+}
+
+
+/*  public functions  */
+
+GtkWidget *
+gimp_device_info_editor_new (GimpDeviceInfo *info)
+{
+  g_return_val_if_fail (GIMP_IS_DEVICE_INFO (info), NULL);
+
+  return g_object_new (GIMP_TYPE_DEVICE_INFO_EDITOR,
+                       "info", info,
+                       NULL);
+}
diff --git a/app/widgets/gimpdeviceinfoeditor.h b/app/widgets/gimpdeviceinfoeditor.h
new file mode 100644
index 0000000..caad7e5
--- /dev/null
+++ b/app/widgets/gimpdeviceinfoeditor.h
@@ -0,0 +1,51 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpdeviceinfoeditor.h
+ * Copyright (C) 2010 Michael Natterer <mitch gimp org>
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_DEVICE_INFO_EDITOR_H__
+#define __GIMP_DEVICE_INFO_EDITOR_H__
+
+
+#define GIMP_TYPE_DEVICE_INFO_EDITOR            (gimp_device_info_editor_get_type ())
+#define GIMP_DEVICE_INFO_EDITOR(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_DEVICE_INFO_EDITOR, GimpDeviceInfoEditor))
+#define GIMP_DEVICE_INFO_EDITOR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_DEVICE_INFO_EDITOR, GimpDeviceInfoEditorClass))
+#define GIMP_IS_DEVICE_INFO_EDITOR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_DEVICE_INFO_EDITOR))
+#define GIMP_IS_DEVICE_INFO_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_DEVICE_INFO_EDITOR))
+#define GIMP_DEVICE_INFO_EDITOR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_DEVICE_INFO_EDITOR, GimpDeviceInfoEditorClass))
+
+
+typedef struct _GimpDeviceInfoEditorClass GimpDeviceInfoEditorClass;
+
+struct _GimpDeviceInfoEditor
+{
+  GtkVBox  parent_instance;
+};
+
+struct _GimpDeviceInfoEditorClass
+{
+  GtkVBoxClass  parent_class;
+};
+
+
+GType       gimp_device_info_editor_get_type (void) G_GNUC_CONST;
+
+GtkWidget * gimp_device_info_editor_new      (GimpDeviceInfo *info);
+
+
+#endif /* __GIMP_DEVICE_INFO_EDITOR_H__ */
diff --git a/app/widgets/widgets-types.h b/app/widgets/widgets-types.h
index bd7be48..23ccedb 100644
--- a/app/widgets/widgets-types.h
+++ b/app/widgets/widgets-types.h
@@ -161,6 +161,8 @@ typedef struct _GimpControllerEditor         GimpControllerEditor;
 typedef struct _GimpControllerList           GimpControllerList;
 typedef struct _GimpCurveView                GimpCurveView;
 typedef struct _GimpDashEditor               GimpDashEditor;
+typedef struct _GimpDeviceEditor             GimpDeviceEditor;
+typedef struct _GimpDeviceInfoEditor         GimpDeviceInfoEditor;
 typedef struct _GimpFgBgEditor               GimpFgBgEditor;
 typedef struct _GimpFgBgView                 GimpFgBgView;
 typedef struct _GimpFileProcView             GimpFileProcView;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]