summary refs log tree commit diff
path: root/libnm/nm-libnm-aux
diff options
context:
space:
mode:
Diffstat (limited to 'libnm/nm-libnm-aux')
-rw-r--r--libnm/nm-libnm-aux/README.md15
-rw-r--r--libnm/nm-libnm-aux/nm-libnm-aux.c146
-rw-r--r--libnm/nm-libnm-aux/nm-libnm-aux.h24
3 files changed, 185 insertions, 0 deletions
diff --git a/libnm/nm-libnm-aux/README.md b/libnm/nm-libnm-aux/README.md
new file mode 100644
index 00000000..460b269e
--- /dev/null
+++ b/libnm/nm-libnm-aux/README.md
@@ -0,0 +1,15 @@
+nm-libnm-aux is a static library that:
+
+ - uses the public parts of "libnm"
+ - that can also be statically linked into other users of libnm.
+
+Basically, it is a static library with utility functions that extends
+libnm.
+
+That means:
+
+  - you can use it everywhere where you dynamically link with libnm.
+
+Also, since nm-libnm-aux itself only uses public (stable)
+API of libnm, you theoretically can copy the sources into your
+own source tree.
diff --git a/libnm/nm-libnm-aux/nm-libnm-aux.c b/libnm/nm-libnm-aux/nm-libnm-aux.c
new file mode 100644
index 00000000..169416b9
--- /dev/null
+++ b/libnm/nm-libnm-aux/nm-libnm-aux.c
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: LGPL-2.1+
+
+#include "nm-default.h"
+
+#include "nm-libnm-aux.h"
+
+/*****************************************************************************/
+
+NMClient *
+nmc_client_new_async_valist (GCancellable *cancellable,
+                             GAsyncReadyCallback callback,
+                             gpointer user_data,
+                             const char *first_property_name,
+                             va_list ap)
+{
+	NMClient *nmc;
+
+	nmc = NM_CLIENT (g_object_new_valist (NM_TYPE_CLIENT, first_property_name, ap));
+	g_async_initable_init_async (G_ASYNC_INITABLE (nmc),
+	                             G_PRIORITY_DEFAULT,
+	                             cancellable,
+	                             callback,
+	                             user_data);
+	return nmc;
+}
+
+NMClient *
+nmc_client_new_async (GCancellable *cancellable,
+                      GAsyncReadyCallback callback,
+                      gpointer user_data,
+                      const char *first_property_name,
+                      ...)
+{
+	NMClient *nmc;
+	va_list ap;
+
+	va_start (ap, first_property_name);
+	nmc = nmc_client_new_async_valist (cancellable,
+	                                   callback,
+	                                   user_data,
+	                                   first_property_name,
+	                                   ap);
+	va_end (ap);
+	return nmc;
+}
+
+/*****************************************************************************/
+
+typedef struct {
+	GMainLoop *main_loop;
+	NMClient *nmc;
+	GError *error;
+} ClientCreateData;
+
+static void
+_nmc_client_new_waitsync_cb (GObject *source_object,
+                             GAsyncResult *result,
+                             gpointer user_data)
+{
+	ClientCreateData *data = user_data;
+
+	g_async_initable_init_finish (G_ASYNC_INITABLE (source_object),
+	                              result,
+	                              &data->error);
+	g_main_loop_quit (data->main_loop);
+}
+
+/**
+ * nmc_client_new:
+ * @cancellable: the cancellable to abort the creation.
+ * @out_nmc: (out): (transfer full): if give, transfers a reference
+ *   to the NMClient instance. Note that this never fails to create
+ *   the NMClient GObject, but depending on the return value,
+ *   the instance was successfully initialized or not.
+ * @error: the error if creation fails.
+ * @first_property_name: the name of the first property
+ * @...: the value of the first property, followed optionally by more
+ *  name/value pairs, followed by %NULL
+ *
+ * Returns: %TRUE, if the client was successfully initalized.
+ *
+ * This uses nm_client_new_async() to create a NMClient instance,
+ * but it iterates the current GMainContext until the client is
+ * ready. As such, it waits for the client creation to complete
+ * (like sync nm_client_new()) but it iterates the caller's GMainContext
+ * (unlike sync nm_client_new()). This is often preferable, because
+ * sync nm_client_new() needs to create an additional internal GMainContext
+ * that it can iterate instead. That has a performance overhead that
+ * is often unnecessary.
+ */
+gboolean
+nmc_client_new_waitsync (GCancellable *cancellable,
+                         NMClient **out_nmc,
+                         GError **error,
+                         const char *first_property_name,
+                         ...)
+{
+	gs_unref_object NMClient *nmc = NULL;
+	nm_auto_unref_gmainloop GMainLoop *main_loop = g_main_loop_new (g_main_context_get_thread_default (), FALSE);
+	ClientCreateData data = {
+		.main_loop = main_loop,
+	};
+	va_list ap;
+
+#if NM_MORE_ASSERTS > 10
+	/* The sync initialization of NMClient is generally a bad idea, because it
+	 * brings the overhead of an additional GMainContext. Anyway, since our own
+	 * code no longer uses that, we hardly test those code paths. But they should
+	 * work just the same. Randomly use instead the sync initialization in a debug
+	 * build... */
+	if ((g_random_int () % 2) == 0) {
+		gboolean success;
+
+		va_start (ap, first_property_name);
+		nmc = NM_CLIENT (g_object_new_valist (NM_TYPE_CLIENT, first_property_name, ap));
+		va_end (ap);
+
+		/* iterate the context at least once, just so that the behavior from POV of the
+		 * caller is roughly the same. */
+		g_main_context_iteration (nm_client_get_main_context (nmc), FALSE);
+
+		success = g_initable_init (G_INITABLE (nmc),
+		                           cancellable,
+		                           error);
+		NM_SET_OUT (out_nmc, g_steal_pointer (&nmc));
+		return success;
+	}
+#endif
+
+	va_start (ap, first_property_name);
+	nmc = nmc_client_new_async_valist (cancellable,
+	                                   _nmc_client_new_waitsync_cb,
+	                                   &data,
+	                                   first_property_name,
+	                                   ap);
+	va_end (ap);
+
+	g_main_loop_run (main_loop);
+
+	NM_SET_OUT (out_nmc, g_steal_pointer (&nmc));
+	if (data.error) {
+		g_propagate_error (error, data.error);
+		return FALSE;
+	}
+	return TRUE;
+}
diff --git a/libnm/nm-libnm-aux/nm-libnm-aux.h b/libnm/nm-libnm-aux/nm-libnm-aux.h
new file mode 100644
index 00000000..a0aff19f
--- /dev/null
+++ b/libnm/nm-libnm-aux/nm-libnm-aux.h
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: LGPL-2.1+
+
+#ifndef __NM_LIBNM_AUX_H__
+#define __NM_LIBNM_AUX_H__
+
+NMClient *nmc_client_new_async_valist (GCancellable *cancellable,
+                                       GAsyncReadyCallback callback,
+                                       gpointer user_data,
+                                       const char *first_property_name,
+                                       va_list ap);
+
+NMClient *nmc_client_new_async (GCancellable *cancellable,
+                                GAsyncReadyCallback callback,
+                                gpointer user_data,
+                                const char *first_property_name,
+                                ...);
+
+gboolean nmc_client_new_waitsync (GCancellable *cancellable,
+                                  NMClient **out_nmc,
+                                  GError **error,
+                                  const char *first_property_name,
+                                  ...);
+
+#endif /* __NM_LIBNM_AUX_H__ */