[virt-tools-list] [PATCH 4/7] Backport GApplication code from glib 2.40

Eduardo Lima (Etrunko) etrunko at redhat.com
Fri Dec 11 16:40:33 UTC 2015


Ideally, glib was required to be at least 2.40.0, but due to the fact
that SLES still uses 2.38, we need to backport the code that is
available only in glib version 2.40.0 onwards.

Signed-off-by: Eduardo Lima (Etrunko) <etrunko at redhat.com>
---
 src/virt-glib-compat.c | 368 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/virt-glib-compat.h |  10 ++
 2 files changed, 378 insertions(+)

diff --git a/src/virt-glib-compat.c b/src/virt-glib-compat.c
index c15ff28..4748993 100644
--- a/src/virt-glib-compat.c
+++ b/src/virt-glib-compat.c
@@ -32,3 +32,371 @@ GByteArray *g_byte_array_new_take (guint8 *data, gsize len)
   return array;
 }
 #endif
+
+#ifndef GLIB_VERSION_2_40
+static void
+free_option_entry (gpointer data)
+{
+  GOptionEntry *entry = data;
+
+  switch (entry->arg)
+    {
+    case G_OPTION_ARG_STRING:
+    case G_OPTION_ARG_FILENAME:
+      g_free (*(gchar **) entry->arg_data);
+      break;
+
+    case G_OPTION_ARG_STRING_ARRAY:
+    case G_OPTION_ARG_FILENAME_ARRAY:
+      g_strfreev (*(gchar ***) entry->arg_data);
+      break;
+
+    default:
+      /* most things require no free... */
+      break;
+    }
+
+  /* ...except for the space that we allocated for it ourselves */
+  g_free (entry->arg_data);
+
+  g_slice_free (GOptionEntry, entry);
+}
+
+static void
+g_application_pack_option_entries (GApplication *application,
+                                   GVariantDict *dict)
+{
+  GHashTableIter iter;
+  gpointer item;
+
+  g_hash_table_iter_init (&iter, application->priv->packed_options);
+  while (g_hash_table_iter_next (&iter, NULL, &item))
+    {
+      GOptionEntry *entry = item;
+      GVariant *value = NULL;
+
+      switch (entry->arg)
+        {
+        case G_OPTION_ARG_NONE:
+          if (*(gboolean *) entry->arg_data != 2)
+            value = g_variant_new_boolean (*(gboolean *) entry->arg_data);
+          break;
+
+        case G_OPTION_ARG_STRING:
+          if (*(gchar **) entry->arg_data)
+            value = g_variant_new_string (*(gchar **) entry->arg_data);
+          break;
+
+        case G_OPTION_ARG_INT:
+          if (*(gint32 *) entry->arg_data)
+            value = g_variant_new_int32 (*(gint32 *) entry->arg_data);
+          break;
+
+        case G_OPTION_ARG_FILENAME:
+          if (*(gchar **) entry->arg_data)
+            value = g_variant_new_bytestring (*(gchar **) entry->arg_data);
+          break;
+
+        case G_OPTION_ARG_STRING_ARRAY:
+          if (*(gchar ***) entry->arg_data)
+            value = g_variant_new_strv (*(const gchar ***) entry->arg_data, -1);
+          break;
+
+        case G_OPTION_ARG_FILENAME_ARRAY:
+          if (*(gchar ***) entry->arg_data)
+            value = g_variant_new_bytestring_array (*(const gchar ***) entry->arg_data, -1);
+          break;
+
+        case G_OPTION_ARG_DOUBLE:
+          if (*(gdouble *) entry->arg_data)
+            value = g_variant_new_double (*(gdouble *) entry->arg_data);
+          break;
+
+        case G_OPTION_ARG_INT64:
+          if (*(gint64 *) entry->arg_data)
+            value = g_variant_new_int64 (*(gint64 *) entry->arg_data);
+          break;
+
+        default:
+          g_assert_not_reached ();
+        }
+
+      if (value)
+        g_variant_dict_insert_value (dict, entry->long_name, value);
+    }
+}
+
+static GVariantDict *
+g_application_parse_command_line (GApplication   *application,
+                                  gchar        ***arguments,
+                                  GError        **error)
+{
+  gboolean become_service = FALSE;
+  GVariantDict *dict = NULL;
+  GOptionContext *context;
+
+  /* Due to the memory management of GOptionGroup we can only parse
+   * options once.  That's because once you add a group to the
+   * GOptionContext there is no way to get it back again.  This is fine:
+   * local_command_line() should never get invoked more than once
+   * anyway.  Add a sanity check just to be sure.
+   */
+  g_return_val_if_fail (!application->priv->options_parsed, NULL);
+
+  context = g_option_context_new (NULL);
+
+  /* If the application has not registered local options and it has
+   * G_APPLICATION_HANDLES_COMMAND_LINE then we have to assume that
+   * their primary instance commandline handler may want to deal with
+   * the arguments.  We must therefore ignore them.
+   *
+   * We must also ignore --help in this case since some applications
+   * will try to handle this from the remote side.  See #737869.
+   */
+  if (application->priv->main_options == NULL && (application->priv->flags & G_APPLICATION_HANDLES_COMMAND_LINE))
+    {
+      g_option_context_set_ignore_unknown_options (context, TRUE);
+      g_option_context_set_help_enabled (context, FALSE);
+    }
+
+  /* Add the main option group, if it exists */
+  if (application->priv->main_options)
+    {
+      /* This consumes the main_options */
+      g_option_context_set_main_group (context, application->priv->main_options);
+      application->priv->main_options = NULL;
+    }
+
+  /* Add any other option groups if they exist.  Adding them to the
+   * context will consume them, so we free the list as we go...
+   */
+  while (application->priv->option_groups)
+    {
+      g_option_context_add_group (context, application->priv->option_groups->data);
+      application->priv->option_groups = g_slist_delete_link (application->priv->option_groups,
+                                                              application->priv->option_groups);
+    }
+
+  /* In the case that we are not explicitly marked as a service or a
+   * launcher then we want to add the "--gapplication-service" option to
+   * allow the process to be made into a service.
+   */
+  if ((application->priv->flags & (G_APPLICATION_IS_SERVICE | G_APPLICATION_IS_LAUNCHER)) == 0)
+    {
+      GOptionGroup *option_group;
+      GOptionEntry entries[] = {
+        { "gapplication-service", '\0', 0, G_OPTION_ARG_NONE, &become_service,
+          N_("Enter GApplication service mode (use from D-Bus service files)") },
+        { NULL }
+      };
+
+      option_group = g_option_group_new ("gapplication",
+                                         _("GApplication options"), _("Show GApplication options"),
+                                         NULL, NULL);
+      g_option_group_set_translation_domain (option_group, GETTEXT_PACKAGE);
+      g_option_group_add_entries (option_group, entries);
+
+      g_option_context_add_group (context, option_group);
+    }
+
+  /* Now we parse... */
+  if (!g_option_context_parse_strv (context, arguments, error))
+    goto out;
+
+  /* Check for --gapplication-service */
+  if (become_service)
+    application->priv->flags |= G_APPLICATION_IS_SERVICE;
+
+  dict = g_variant_dict_new (NULL);
+  if (application->priv->packed_options)
+    {
+      g_application_pack_option_entries (application, dict);
+      g_hash_table_unref (application->priv->packed_options);
+      application->priv->packed_options = NULL;
+    }
+
+out:
+  /* Make sure we don't run again */
+  application->priv->options_parsed = TRUE;
+
+  g_option_context_free (context);
+
+  return dict;
+}
+
+static void
+add_packed_option (GApplication *application,
+                   GOptionEntry *entry)
+{
+  switch (entry->arg)
+    {
+    case G_OPTION_ARG_NONE:
+      entry->arg_data = g_new (gboolean, 1);
+      *(gboolean *) entry->arg_data = 2;
+      break;
+
+    case G_OPTION_ARG_INT:
+      entry->arg_data = g_new0 (gint, 1);
+      break;
+
+    case G_OPTION_ARG_STRING:
+    case G_OPTION_ARG_FILENAME:
+    case G_OPTION_ARG_STRING_ARRAY:
+    case G_OPTION_ARG_FILENAME_ARRAY:
+      entry->arg_data = g_new0 (gpointer, 1);
+      break;
+
+    case G_OPTION_ARG_INT64:
+      entry->arg_data = g_new0 (gint64, 1);
+      break;
+
+    case G_OPTION_ARG_DOUBLE:
+      entry->arg_data = g_new0 (gdouble, 1);
+      break;
+
+    default:
+      g_return_if_reached ();
+    }
+
+  if (!application->priv->packed_options)
+    application->priv->packed_options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, free_option_entry);
+
+  g_hash_table_insert (application->priv->packed_options,
+                       g_strdup (entry->long_name),
+                       g_slice_dup (GOptionEntry, entry));
+}
+
+void
+g_application_add_main_option_entries (GApplication       *application,
+                                       const GOptionEntry *entries)
+{
+  gint i;
+
+  g_return_if_fail (G_IS_APPLICATION (application));
+  g_return_if_fail (entries != NULL);
+
+  if (!application->priv->main_options)
+    {
+      application->priv->main_options = g_option_group_new (NULL, NULL, NULL, NULL, NULL);
+      g_option_group_set_translation_domain (application->priv->main_options, NULL);
+    }
+
+  for (i = 0; entries[i].long_name; i++)
+    {
+      GOptionEntry my_entries[2] = { { NULL }, { NULL } };
+      my_entries[0] = entries[i];
+
+      if (!my_entries[0].arg_data)
+        add_packed_option (application, &my_entries[0]);
+
+      g_option_group_add_entries (application->priv->main_options, my_entries);
+    }
+}
+
+void
+g_application_add_option_group (GApplication *application,
+                                GOptionGroup *group)
+{
+  g_return_if_fail (G_IS_APPLICATION (application));
+  g_return_if_fail (group != NULL);
+
+  application->priv->option_groups = g_slist_prepend (application->priv->option_groups, group);
+}
+
+gboolean
+g_application_real_local_command_line (GApplication   *application,
+                                       gchar        ***arguments,
+                                       int            *exit_status)
+{
+  GError *error = NULL;
+  GVariantDict *options;
+  gint n_args;
+
+  options = g_application_parse_command_line (application, arguments, &error);
+  if (!options)
+    {
+      g_printerr ("%s\n", error->message);
+      *exit_status = 1;
+      return TRUE;
+    }
+
+  g_signal_emit (application, g_application_signals[SIGNAL_HANDLE_LOCAL_OPTIONS], 0, options, exit_status);
+
+  if (*exit_status >= 0)
+    {
+      g_variant_dict_unref (options);
+      return TRUE;
+    }
+
+  if (!g_application_register (application, NULL, &error))
+    {
+      g_printerr ("Failed to register: %s\n", error->message);
+      g_variant_dict_unref (options);
+      g_error_free (error);
+      *exit_status = 1;
+      return TRUE;
+    }
+
+  n_args = g_strv_length (*arguments);
+
+  if (application->priv->flags & G_APPLICATION_IS_SERVICE)
+    {
+      if ((*exit_status = n_args > 1))
+        {
+          g_printerr ("GApplication service mode takes no arguments.\n");
+          application->priv->flags &= ~G_APPLICATION_IS_SERVICE;
+          *exit_status = 1;
+        }
+      else
+        *exit_status = 0;
+    }
+  else if (application->priv->flags & G_APPLICATION_HANDLES_COMMAND_LINE)
+    {
+      g_application_call_command_line (application,
+                                       (const gchar **) *arguments,
+                                       g_variant_dict_end (options),
+                                       exit_status);
+    }
+  else
+    {
+      if (n_args <= 1)
+        {
+          g_application_activate (application);
+          *exit_status = 0;
+        }
+
+      else
+        {
+          if (~application->priv->flags & G_APPLICATION_HANDLES_OPEN)
+            {
+              g_critical ("This application can not open files.");
+              *exit_status = 1;
+            }
+          else
+            {
+              GFile **files;
+              gint n_files;
+              gint i;
+
+              n_files = n_args - 1;
+              files = g_new (GFile *, n_files);
+
+              for (i = 0; i < n_files; i++)
+                files[i] = g_file_new_for_commandline_arg ((*arguments)[i + 1]);
+
+              g_application_open (application, files, n_files, "");
+
+              for (i = 0; i < n_files; i++)
+                g_object_unref (files[i]);
+              g_free (files);
+
+              *exit_status = 0;
+            }
+        }
+    }
+
+  g_variant_dict_unref (options);
+
+  return TRUE;
+}
+#endif
diff --git a/src/virt-glib-compat.h b/src/virt-glib-compat.h
index 1242289..29fcdef 100644
--- a/src/virt-glib-compat.h
+++ b/src/virt-glib-compat.h
@@ -78,6 +78,16 @@ GByteArray *g_byte_array_new_take (guint8 *data, gsize len);
 #define g_mutex_new() g_new0(GMutex, 1)
 #endif
 
+#ifndef GLIB_VERSION_2_40
+#include <gio/gio.h>
+void     g_application_add_main_option_entries (GApplication       *application,
+                                                const GOptionEntry *entries);
+void     g_application_add_option_group (GApplication *application,
+                                         GOptionGroup *group);
+gboolean g_application_real_local_command_line (GApplication   *application,
+                                                gchar        ***arguments,
+                                                int            *exit_status);
+#endif
 G_END_DECLS
 
 #endif // _VIRT_GLIB_COMPAT_H
-- 
2.5.0




More information about the virt-tools-list mailing list