[gimp] libgimp: have gimp_procedure_dialog_new() behave like g_object_new().



commit 8176bd0828b64d158f3af17a510f9b72a7d91cf3
Author: Jehan <jehan girinstud io>
Date:   Tue Aug 3 19:35:50 2021 +0200

    libgimp: have gimp_procedure_dialog_new() behave like g_object_new().
    
    It is now discouraged to create constructor-type _new() functions with
    custom code, which would make them behave differently that simply
    calling g_object_new() with the GType and relevant properties. The main
    reason is that some bindings would create objects with g_object_new() so
    it should create expected code too.
    See: https://gi.readthedocs.io/en/latest/writingbindableapis.html#custom-code-in-constructors
    
    Here it was complicated for a few reasons:
    - We hack "title" property to use the procedure's menu label by default
      (without the mnemonic). For this, I overrode the GtkWindow property.
    - We want "use-header-bar" to follow the application general settings by
      default. Since it is a CONSTRUCT_ONLY property, g_object_set() is not
      possible in _init() and _constructed(). Instead I had to override the
      constructor() method to set this at construction time (yet still allow
      API users to override this with the property at creation).
    - Similarly, "help-func" is a CONSTRUCT_ONLY property, so I used the
      same trick.
    - As for "help-id", I now just set it in _constructed(). This was the
      easy one.

 libgimp/gimpproceduredialog.c | 229 +++++++++++++++++++++++++++++-------------
 1 file changed, 157 insertions(+), 72 deletions(-)
---
diff --git a/libgimp/gimpproceduredialog.c b/libgimp/gimpproceduredialog.c
index 33b794899e..9a2a032d43 100644
--- a/libgimp/gimpproceduredialog.c
+++ b/libgimp/gimpproceduredialog.c
@@ -39,6 +39,10 @@ enum
   PROP_0,
   PROP_PROCEDURE,
   PROP_CONFIG,
+
+  /* From here the overridden properties. */
+  PROP_TITLE,
+
   N_PROPS
 };
 
@@ -72,42 +76,45 @@ typedef struct GimpProcedureDialogSensitiveData
 } GimpProcedureDialogSensitiveData;
 
 
-static void   gimp_procedure_dialog_constructed   (GObject      *object);
-static void   gimp_procedure_dialog_dispose       (GObject      *object);
-static void   gimp_procedure_dialog_set_property  (GObject      *object,
-                                                   guint         property_id,
-                                                   const GValue *value,
-                                                   GParamSpec   *pspec);
-static void   gimp_procedure_dialog_get_property  (GObject      *object,
-                                                   guint         property_id,
-                                                   GValue       *value,
-                                                   GParamSpec   *pspec);
-
-static void  gimp_procedure_dialog_real_fill_list (GimpProcedureDialog *dialog,
-                                                   GimpProcedure       *procedure,
-                                                   GimpProcedureConfig *config,
-                                                   GList               *properties);
-
-static void   gimp_procedure_dialog_reset_initial (GtkWidget           *button,
-                                                   GimpProcedureDialog *dialog);
-static void   gimp_procedure_dialog_reset_factory (GtkWidget           *button,
-                                                   GimpProcedureDialog *dialog);
-static void   gimp_procedure_dialog_load_defaults (GtkWidget           *button,
-                                                   GimpProcedureDialog *dialog);
-static void   gimp_procedure_dialog_save_defaults (GtkWidget           *button,
-                                                   GimpProcedureDialog *dialog);
-
-static gboolean gimp_procedure_dialog_check_mnemonic    (GimpProcedureDialog *dialog,
-                                                         GtkWidget           *widget,
-                                                         const gchar         *id,
-                                                         const gchar         *core_id);
+static GObject * gimp_procedure_dialog_constructor    (GType                  type,
+                                                       guint                  n_construct_properties,
+                                                       GObjectConstructParam *construct_properties);
+static void      gimp_procedure_dialog_constructed    (GObject               *object);
+static void      gimp_procedure_dialog_dispose        (GObject               *object);
+static void      gimp_procedure_dialog_set_property   (GObject               *object,
+                                                       guint                  property_id,
+                                                       const GValue          *value,
+                                                       GParamSpec            *pspec);
+static void      gimp_procedure_dialog_get_property   (GObject               *object,
+                                                       guint                  property_id,
+                                                       GValue                *value,
+                                                       GParamSpec            *pspec);
+
+static void      gimp_procedure_dialog_real_fill_list (GimpProcedureDialog   *dialog,
+                                                       GimpProcedure         *procedure,
+                                                       GimpProcedureConfig   *config,
+                                                       GList                 *properties);
+
+static void      gimp_procedure_dialog_reset_initial  (GtkWidget             *button,
+                                                       GimpProcedureDialog   *dialog);
+static void      gimp_procedure_dialog_reset_factory  (GtkWidget             *button,
+                                                       GimpProcedureDialog   *dialog);
+static void      gimp_procedure_dialog_load_defaults  (GtkWidget             *button,
+                                                       GimpProcedureDialog   *dialog);
+static void      gimp_procedure_dialog_save_defaults  (GtkWidget             *button,
+                                                       GimpProcedureDialog   *dialog);
+
+static gboolean  gimp_procedure_dialog_check_mnemonic (GimpProcedureDialog  *dialog,
+                                                       GtkWidget            *widget,
+                                                       const gchar          *id,
+                                                       const gchar          *core_id);
 static GtkWidget *
-              gimp_procedure_dialog_fill_container_list (GimpProcedureDialog *dialog,
-                                                         const gchar         *container_id,
-                                                         GtkContainer        *container,
-                                                         GList               *properties);
+            gimp_procedure_dialog_fill_container_list (GimpProcedureDialog  *dialog,
+                                                       const gchar          *container_id,
+                                                       GtkContainer         *container,
+                                                       GList                *properties);
 
-static void   gimp_procedure_dialog_sensitive_data_free (GimpProcedureDialogSensitiveData *data);
+static void gimp_procedure_dialog_sensitive_data_free (GimpProcedureDialogSensitiveData *data);
 
 
 G_DEFINE_TYPE_WITH_PRIVATE (GimpProcedureDialog, gimp_procedure_dialog,
@@ -123,6 +130,7 @@ gimp_procedure_dialog_class_init (GimpProcedureDialogClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
+  object_class->constructor  = gimp_procedure_dialog_constructor;
   object_class->constructed  = gimp_procedure_dialog_constructed;
   object_class->dispose      = gimp_procedure_dialog_dispose;
   object_class->get_property = gimp_procedure_dialog_get_property;
@@ -136,7 +144,7 @@ gimp_procedure_dialog_class_init (GimpProcedureDialogClass *klass)
                          "The GimpProcedure this dialog is used with",
                          GIMP_TYPE_PROCEDURE,
                          GIMP_PARAM_READWRITE |
-                         G_PARAM_CONSTRUCT);
+                         G_PARAM_CONSTRUCT_ONLY);
 
   props[PROP_CONFIG] =
     g_param_spec_object ("config",
@@ -146,7 +154,17 @@ gimp_procedure_dialog_class_init (GimpProcedureDialogClass *klass)
                          GIMP_PARAM_READWRITE |
                          G_PARAM_CONSTRUCT);
 
-  g_object_class_install_properties (object_class, N_PROPS, props);
+  g_object_class_install_properties (object_class, N_PROPS - 1, props);
+
+  /**
+   * GimpProcedureDialog:title:
+   *
+   * Overrides the "title" property of #GtkWindow.
+   * When %NULL, the title is taken from the #GimpProcedure menu label.
+   *
+   * Since: 3.0
+   */
+  g_object_class_override_property (object_class, PROP_TITLE, "title");
 }
 
 static void
@@ -162,11 +180,68 @@ gimp_procedure_dialog_init (GimpProcedureDialog *dialog)
                                                         (GDestroyNotify) 
gimp_procedure_dialog_sensitive_data_free);
 }
 
+static GObject *
+gimp_procedure_dialog_constructor (GType                  type,
+                                   guint                  n_construct_properties,
+                                   GObjectConstructParam *construct_properties)
+{
+  gboolean use_header_bar        = FALSE;
+  gboolean use_header_bar_edited = FALSE;
+  gboolean help_func_edited      = FALSE;
+
+  g_object_get (gtk_settings_get_default (),
+                "gtk-dialogs-use-header", &use_header_bar,
+                NULL);
+
+  for (guint i = 0; i < n_construct_properties; i++)
+    {
+      /* We need to override the default values of some properties and
+       * can't do it in _init() or _constructed() because it's too late
+       * for G_PARAM_CONSTRUCT_ONLY properties.
+       * Moreover we don't do it in _new() because we need this to work
+       * also in bindings sometimes using only constructors to
+       * initialize their object, hence we can't rely on our _new()
+       * function (relying on _new() functions doing more than the
+       * constructor is now discouraged by GTK/GLib developers).
+       */
+      GObjectConstructParam property;
+
+      property = construct_properties[i];
+      if (! use_header_bar_edited &&
+          g_strcmp0 (g_param_spec_get_name (property.pspec),
+                     "use-header-bar") == 0)
+        {
+          if (g_value_get_int (property.value) == -1)
+            g_value_set_int (property.value, (gint) use_header_bar);
+
+          use_header_bar_edited = TRUE;
+        }
+      else if (! help_func_edited &&
+               g_strcmp0 (g_param_spec_get_name (property.pspec),
+                          "help-func") == 0)
+        {
+          if (g_value_get_pointer (property.value) == NULL)
+            g_value_set_pointer (property.value,
+                                 gimp_standard_help_func);
+
+          help_func_edited = TRUE;
+        }
+
+      if (use_header_bar_edited && help_func_edited)
+        break;
+    }
+
+  return G_OBJECT_CLASS (parent_class)->constructor (type,
+                                                     n_construct_properties,
+                                                     construct_properties);
+}
+
 static void
 gimp_procedure_dialog_constructed (GObject *object)
 {
   GimpProcedureDialog *dialog;
   GimpProcedure       *procedure;
+  const gchar         *help_id;
   const gchar         *ok_label;
   GtkWidget           *hbox;
   GtkWidget           *button;
@@ -180,9 +255,17 @@ gimp_procedure_dialog_constructed (GObject *object)
   dialog = GIMP_PROCEDURE_DIALOG (object);
   procedure = dialog->priv->procedure;
 
-  role = g_strdup_printf ("gimp-%s", gimp_procedure_get_name (procedure));
+  role    = g_strdup_printf ("gimp-%s", gimp_procedure_get_name (procedure));
+  help_id = gimp_procedure_get_help_id (procedure);
   g_object_set (object,
-                "role", role,
+                "role",    role,
+                "help-id", help_id,
+                /* This may seem weird, but this is actually because we
+                 * are overriding this property and if the title is NULL
+                 * in particular, we create one out of the procedure's
+                 * menu label. So we force the reset this way.
+                 */
+                "title",   gtk_window_get_title (GTK_WINDOW (dialog)),
                 NULL);
   g_free (role);
 
@@ -319,6 +402,32 @@ gimp_procedure_dialog_set_property (GObject      *object,
           gimp_config_duplicate (GIMP_CONFIG (dialog->priv->config));
       break;
 
+    case PROP_TITLE:
+        {
+          GtkWidget   *bogus = NULL;
+          const gchar *title;
+
+          title = g_value_get_string (value);
+
+          if (title == NULL)
+            {
+              /* Use the procedure menu label, but remove mnemonic
+               * underscore. Ugly yet must reliable way as GTK does not
+               * expose a function to do this from a string (and better
+               * not to copy-paste the internal function from GTK code).
+               */
+              bogus = gtk_label_new (NULL);
+              gtk_label_set_markup_with_mnemonic (GTK_LABEL (g_object_ref_sink (bogus)),
+                                                  gimp_procedure_get_menu_label (dialog->priv->procedure));
+              title = gtk_label_get_text (GTK_LABEL (bogus));
+            }
+          if (title != NULL)
+            gtk_window_set_title (GTK_WINDOW (dialog), title);
+
+          g_clear_object (&bogus);
+        }
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -343,6 +452,11 @@ gimp_procedure_dialog_get_property (GObject    *object,
       g_value_set_object (value, dialog->priv->config);
       break;
 
+    case PROP_TITLE:
+      g_value_set_string (value,
+                          gtk_window_get_title (GTK_WINDOW (dialog)));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -404,46 +518,17 @@ gimp_procedure_dialog_new (GimpProcedure       *procedure,
                            GimpProcedureConfig *config,
                            const gchar         *title)
 {
-  GtkWidget   *dialog;
-  GtkWidget   *bogus = NULL;
-  const gchar *help_id;
-  gboolean     use_header_bar;
-
   g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), NULL);
   g_return_val_if_fail (GIMP_IS_PROCEDURE_CONFIG (config), NULL);
   g_return_val_if_fail (gimp_procedure_config_get_procedure (config) ==
                         procedure, NULL);
   g_return_val_if_fail (title != NULL || gimp_procedure_get_menu_label (procedure), NULL);
 
-  help_id = gimp_procedure_get_help_id (procedure);
-  if (title == NULL)
-    {
-      /* Remove mnemonic underscore. Ugly but must reliable way as GTK
-       * does not expose a function to do this from a string (and better
-       * not to copy-paste the internal function from GTK code).
-       */
-      bogus = gtk_label_new (NULL);
-      gtk_label_set_markup_with_mnemonic (GTK_LABEL (g_object_ref_sink (bogus)),
-                                          gimp_procedure_get_menu_label (procedure));
-      title = gtk_label_get_text (GTK_LABEL (bogus));
-    }
-
-  g_object_get (gtk_settings_get_default (),
-                "gtk-dialogs-use-header", &use_header_bar,
-                NULL);
-
-  dialog = g_object_new (GIMP_TYPE_PROCEDURE_DIALOG,
-                         "procedure",      procedure,
-                         "config",         config,
-                         "title",          title,
-                         "help-func",      gimp_standard_help_func,
-                         "help-id",        help_id,
-                         "use-header-bar", use_header_bar,
-                         NULL);
-
-  g_clear_object (&bogus);
-
-  return GTK_WIDGET (dialog);
+  return g_object_new (GIMP_TYPE_PROCEDURE_DIALOG,
+                       "procedure", procedure,
+                       "config",    config,
+                       "title",     title,
+                       NULL);
 }
 
 /**


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