+typedef struct {
+ GSource source;
+
+ GCancellable *cancellable;
+ guint cancelled_handler;
+} GCancellableSource;
+
+static void
+cancellable_source_cancelled (GCancellable *cancellable,
+ gpointer user_data)
+{
+ GSource *source = user_data;
+
+ if (!g_source_is_destroyed (source))
+ g_source_set_ready_time (source, 0);
+}
+
+static gboolean
+cancellable_source_dispatch (GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ GCancellableSourceFunc func = (GCancellableSourceFunc)callback;
+ GCancellableSource *cancellable_source = (GCancellableSource *)source;
+
+ g_source_set_ready_time (source, -1);
+ return (*func) (cancellable_source->cancellable, user_data);
+}
+
+static void
+cancellable_source_finalize (GSource *source)
+{
+ GCancellableSource *cancellable_source = (GCancellableSource *)source;
+
+ if (cancellable_source->cancellable)
+ {
+ g_cancellable_disconnect (cancellable_source->cancellable,
+ cancellable_source->cancelled_handler);
+ g_object_unref (cancellable_source->cancellable);
+ }
+}
+
+static gboolean
+cancellable_source_closure_callback (GCancellable *cancellable,
+ gpointer data)
+{
+ GClosure *closure = data;
+
+ GValue params = G_VALUE_INIT;
+ GValue result_value = G_VALUE_INIT;
+ gboolean result;
+
+ g_value_init (&result_value, G_TYPE_BOOLEAN);
+
+ g_value_init (¶ms, G_TYPE_CANCELLABLE);
+ g_value_set_object (¶ms, cancellable);
+
+ g_closure_invoke (closure, &result_value, 1, ¶ms, NULL);
+
+ result = g_value_get_boolean (&result_value);
+ g_value_unset (&result_value);
+ g_value_unset (¶ms);
+
+ return result;
+}
+
+static GSourceFuncs cancellable_source_funcs =
+{
+ NULL,
+ NULL,
+ cancellable_source_dispatch,
+ cancellable_source_finalize,
+ (GSourceFunc)cancellable_source_closure_callback,
+};
+
+/**
+ * g_cancellable_source_new: (skip)
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ *
+ * Creates a source that triggers if @cancellable is cancelled and
+ * calls its callback of type #GCancellableSourceFunc. This is
+ * primarily useful for attaching to another (non-cancellable) source
+ * with g_source_add_child_source() to add cancellability to it.
+ *
+ * For convenience, you can call this with a %NULL #GCancellable,
+ * in which case the source will never trigger.
+ *
+ * The new #GSource will hold a reference to the #GCancellable.
+ *
+ * Returns: (transfer full): the new #GSource.
+ *
+ * Since: 2.28
+ */
+GSource *
+g_cancellable_source_new (GCancellable *cancellable)
+{
+ GSource *source;
+ GCancellableSource *cancellable_source;
+
+ source = g_source_new (&cancellable_source_funcs, sizeof (GCancellableSource));
+ g_source_set_name (source, "GCancellable");
+ cancellable_source = (GCancellableSource *)source;
+
+ if (cancellable)
+ {
+ cancellable_source->cancellable = g_object_ref (cancellable);
+
+ /* We intentionally don't use g_cancellable_connect() here,
+ * because we don't want the "at most once" behavior.
+ */
+ cancellable_source->cancelled_handler =
+ g_signal_connect (cancellable, "cancelled",
+ G_CALLBACK (cancellable_source_cancelled),
+ source);
+ if (g_cancellable_is_cancelled (cancellable))
+ g_source_set_ready_time (source, 0);
+ }
+
+ return source;
+}