[gimp] app: fix GimpDeviceManager to not add the same display twice



commit 3ced1e18f44ed8a60f98743204fc94149e200659
Author: Michael Natterer <mitch gimp org>
Date:   Thu May 10 14:18:59 2018 +0200

    app: fix GimpDeviceManager to not add the same display twice
    
    Displays can be opened multiple times, which caused the device manager
    to try to add their devices multiple times (which gets prevented with
    warnings), and then remove the devices prematurely when the
    multiple-opened display gets closed the first time (which is even
    worse).
    
    Add a simple hash that keeps track of how often displays are open, and
    only add/remove their devices on first open and last close.
    
    This actually happened with gtk-inspector on the gtk3-port branch, but
    there is no reason this can't also happen in stable.

 app/widgets/gimpdevicemanager.c |   48 +++++++++++++++++++++++++++++++++-----
 app/widgets/gimpdevicemanager.h |    7 ++++-
 2 files changed, 46 insertions(+), 9 deletions(-)
---
diff --git a/app/widgets/gimpdevicemanager.c b/app/widgets/gimpdevicemanager.c
index b952bae..4598bae 100644
--- a/app/widgets/gimpdevicemanager.c
+++ b/app/widgets/gimpdevicemanager.c
@@ -44,18 +44,15 @@ enum
 };
 
 
-typedef struct _GimpDeviceManagerPrivate GimpDeviceManagerPrivate;
 
 struct _GimpDeviceManagerPrivate
 {
   Gimp           *gimp;
+  GHashTable     *displays;
   GimpDeviceInfo *current_device;
 };
 
-#define GET_PRIVATE(manager) \
-        G_TYPE_INSTANCE_GET_PRIVATE (manager, \
-                                     GIMP_TYPE_DEVICE_MANAGER, \
-                                     GimpDeviceManagerPrivate)
+#define GET_PRIVATE(obj) (((GimpDeviceManager *) (obj))->priv)
 
 
 static void   gimp_device_manager_constructed    (GObject           *object);
@@ -126,6 +123,12 @@ gimp_device_manager_class_init (GimpDeviceManagerClass *klass)
 static void
 gimp_device_manager_init (GimpDeviceManager *manager)
 {
+  manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
+                                               GIMP_TYPE_DEVICE_MANAGER,
+                                               GimpDeviceManagerPrivate);
+
+  manager->priv->displays = g_hash_table_new (g_direct_hash,
+                                              g_direct_equal);
 }
 
 static void
@@ -183,6 +186,10 @@ gimp_device_manager_dispose (GObject *object)
 static void
 gimp_device_manager_finalize (GObject *object)
 {
+  GimpDeviceManagerPrivate *private = GET_PRIVATE (object);
+
+  g_clear_pointer (&private->displays, g_hash_table_unref);
+
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -297,7 +304,19 @@ gimp_device_manager_display_opened (GdkDisplayManager *disp_manager,
                                     GdkDisplay        *gdk_display,
                                     GimpDeviceManager *manager)
 {
-  GList *list;
+  GimpDeviceManagerPrivate *private = GET_PRIVATE (manager);
+  GList                    *list;
+  gint                      count;
+
+  count = GPOINTER_TO_INT (g_hash_table_lookup (private->displays,
+                                                gdk_display));
+
+  g_hash_table_insert (private->displays, gdk_display,
+                       GINT_TO_POINTER (count + 1));
+
+  /*  don't add the same display twice  */
+  if (count > 0)
+    return;
 
   /*  create device info structures for present devices */
   for (list = gdk_display_list_devices (gdk_display); list; list = list->next)
@@ -317,7 +336,22 @@ gimp_device_manager_display_closed (GdkDisplay        *gdk_display,
                                     gboolean           is_error,
                                     GimpDeviceManager *manager)
 {
-  GList *list;
+  GimpDeviceManagerPrivate *private = GET_PRIVATE (manager);
+  GList                    *list;
+  gint                      count;
+
+  count = GPOINTER_TO_INT (g_hash_table_lookup (private->displays,
+                                                gdk_display));
+
+  /*  don't remove the same display twice  */
+  if (count > 1)
+    {
+      g_hash_table_insert (private->displays, gdk_display,
+                           GINT_TO_POINTER (count - 1));
+      return;
+    }
+
+  g_hash_table_remove (private->displays, gdk_display);
 
   for (list = gdk_display_list_devices (gdk_display); list; list = list->next)
     {
diff --git a/app/widgets/gimpdevicemanager.h b/app/widgets/gimpdevicemanager.h
index 8bd723a..b07eaa8 100644
--- a/app/widgets/gimpdevicemanager.h
+++ b/app/widgets/gimpdevicemanager.h
@@ -36,11 +36,14 @@ G_BEGIN_DECLS
 #define GIMP_DEVICE_MANAGER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_DEVICE_MANAGER, 
GimpDeviceManagerClass))
 
 
-typedef struct _GimpDeviceManagerClass GimpDeviceManagerClass;
+typedef struct _GimpDeviceManagerPrivate GimpDeviceManagerPrivate;
+typedef struct _GimpDeviceManagerClass   GimpDeviceManagerClass;
 
 struct _GimpDeviceManager
 {
-  GimpList  parent_instance;
+  GimpList                  parent_instance;
+
+  GimpDeviceManagerPrivate *priv;
 };
 
 struct _GimpDeviceManagerClass


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