|
Packit |
1470ea |
|
|
Packit |
1470ea |
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" xmlns:xi="http://www.w3.org/2003/XInclude" type="guide" style="task" id="custom-gsource.c" xml:lang="gl">
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<info>
|
|
Packit |
1470ea |
<link type="guide" xref="c#examples"/>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<credit type="author copyright">
|
|
Packit |
1470ea |
<name>Philip Withnall</name>
|
|
Packit |
1470ea |
<email its:translate="no">philip.withnall@collabora.co.uk</email>
|
|
Packit |
1470ea |
<years>2015</years>
|
|
Packit |
1470ea |
</credit>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<include xmlns="http://www.w3.org/2001/XInclude" href="legal.xml"/>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<desc>
|
|
Packit |
1470ea |
Tutorial for writing a custom GSource implementation
|
|
Packit |
1470ea |
</desc>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
|
|
Packit |
1470ea |
<mal:name>Fran Dieguez</mal:name>
|
|
Packit |
1470ea |
<mal:email>frandieguez@gnome.org</mal:email>
|
|
Packit |
1470ea |
<mal:years>2012-2013.</mal:years>
|
|
Packit |
1470ea |
</mal:credit>
|
|
Packit |
1470ea |
</info>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<title>Custom GSources</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<synopsis>
|
|
Packit |
1470ea |
<title>Summary</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
This article is a tutorial on creating a custom GSource . For
|
|
Packit |
1470ea |
the reference documentation, see the
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#GSource">GLib
|
|
Packit |
1470ea |
API reference</link>.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</synopsis>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="what-is-gsource">
|
|
Packit |
1470ea |
<title>What is GSource ?</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
A <link href="https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#GSource">GSource </link>
|
|
Packit |
1470ea |
is an expected event with an associated callback function which will be
|
|
Packit |
1470ea |
invoked when that event is received. An event could be a timeout or data
|
|
Packit |
1470ea |
being received on a socket, for example.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
GLib contains various types of GSource , but also allows
|
|
Packit |
1470ea |
applications to define their own, allowing custom events to be integrated
|
|
Packit |
1470ea |
into the main loop.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
The structure of a GSource and its virtual functions are
|
|
Packit |
1470ea |
documented in detail in the
|
|
Packit |
1470ea |
<link href="https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#GSourceFuncs">GLib
|
|
Packit |
1470ea |
API reference</link>.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="queue-source">
|
|
Packit |
1470ea |
<title>A Message Queue Source</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
As a running example, a message queue source will be used which dispatches
|
|
Packit |
1470ea |
its callback whenever a message is enqueued to a queue internal to the
|
|
Packit |
1470ea |
source (potentially from another thread).
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
This type of source is useful for efficiently transferring large numbers
|
|
Packit |
1470ea |
of messages between main contexts. The alternative is transferring each
|
|
Packit |
1470ea |
message as a separate idle GSource using
|
|
Packit |
1470ea |
g_source_attach() . For large numbers of messages, this means
|
|
Packit |
1470ea |
a lot of allocations and frees of GSource s.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="gsource-structure">
|
|
Packit |
1470ea |
<title>Structure</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Firstly, a structure for the source needs to be declared. This must
|
|
Packit |
1470ea |
contain a GSource as its parent, followed by the private
|
|
Packit |
1470ea |
fields for the source: the queue and a function to call to free each
|
|
Packit |
1470ea |
message once finished with.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
typedef struct {
|
|
Packit |
1470ea |
GSource parent;
|
|
Packit |
1470ea |
GAsyncQueue *queue; /* owned */
|
|
Packit |
1470ea |
GDestroyNotify destroy_message;
|
|
Packit |
1470ea |
} MessageQueueSource;
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="prepare-function">
|
|
Packit |
1470ea |
<title>Prepare Function</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Next, the prepare function for the source must be defined. This determines
|
|
Packit |
1470ea |
whether the source is ready to be dispatched. As this source is using an
|
|
Packit |
1470ea |
in-memory queue, this can be determined by checking the queue’s length: if
|
|
Packit |
1470ea |
there are elements in the queue, the source can be dispatched to handle
|
|
Packit |
1470ea |
them.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
return (g_async_queue_length (message_queue_source->queue) > 0);
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="check-function">
|
|
Packit |
1470ea |
<title>Check Function</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
As this source has no file descriptors, the prepare and check functions
|
|
Packit |
1470ea |
essentially have the same job, so a check function is not needed.
|
|
Packit |
1470ea |
Setting the field to NULL in GSourceFuncs
|
|
Packit |
1470ea |
bypasses the check function for this source type.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="dispatch-function">
|
|
Packit |
1470ea |
<title>Dispatch Function</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
For this source, the dispatch function is where the complexity lies. It
|
|
Packit |
1470ea |
needs to dequeue a message from the queue, then pass that message to the
|
|
Packit |
1470ea |
GSource ’s callback function. No messages may be queued: even
|
|
Packit |
1470ea |
through the prepare function returned true, another source wrapping the
|
|
Packit |
1470ea |
same queue may have been dispatched in the mean time and taken the final
|
|
Packit |
1470ea |
message from the queue. Further, if no callback has been set for the
|
|
Packit |
1470ea |
GSource (which is allowed), the message must be destroyed and
|
|
Packit |
1470ea |
silently dropped.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
If both a message and callback are set, the callback can be invoked on the
|
|
Packit |
1470ea |
message and its return value propagated as the return value of the
|
|
Packit |
1470ea |
dispatch function. This is FALSE to destroy the
|
|
Packit |
1470ea |
GSource and TRUE to keep it alive, just as for
|
|
Packit |
1470ea |
GSourceFunc — these semantics are the same for all dispatch
|
|
Packit |
1470ea |
function implementations.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/* Pop a message off the queue. */
|
|
Packit |
1470ea |
message = g_async_queue_try_pop (message_queue_source->queue);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/* If there was no message, bail. */
|
|
Packit |
1470ea |
if (message == NULL)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
/* Keep the source around to handle the next message. */
|
|
Packit |
1470ea |
return TRUE;
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/* @func may be %NULL if no callback was specified.
|
|
Packit |
1470ea |
* If so, drop the message. */
|
|
Packit |
1470ea |
if (func == NULL)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
if (message_queue_source->destroy_message != NULL)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
message_queue_source->destroy_message (message);
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/* Keep the source around to consume the next message. */
|
|
Packit |
1470ea |
return TRUE;
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
return func (message, user_data);
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="callback">
|
|
Packit |
1470ea |
<title>Callback Functions</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
The callback from a GSource does not have to have type
|
|
Packit |
1470ea |
GSourceFunc . It can be whatever function type is called in
|
|
Packit |
1470ea |
the source’s dispatch function, as long as that type is sufficiently
|
|
Packit |
1470ea |
documented.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Normally, g_source_set_callback() is used to set the
|
|
Packit |
1470ea |
callback function for a source instance. With its
|
|
Packit |
1470ea |
GDestroyNotify , a strong reference can be held to keep an
|
|
Packit |
1470ea |
object alive while the source is still alive:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
g_source_set_callback (source, callback_func,
|
|
Packit |
1470ea |
g_object_ref (object_to_strong_ref),
|
|
Packit |
1470ea |
(GDestroyNotify) g_object_unref);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
However, GSource has a layer of indirection for retrieving
|
|
Packit |
1470ea |
this callback, exposed as g_source_set_callback_indirect() .
|
|
Packit |
1470ea |
This allows GObject to set a GClosure as the callback for a
|
|
Packit |
1470ea |
source, which allows for sources which are automatically destroyed when
|
|
Packit |
1470ea |
an object is finalized — a weak reference, in contrast to the
|
|
Packit |
1470ea |
strong reference above:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
g_source_set_closure (source,
|
|
Packit |
1470ea |
g_cclosure_new_object (callback_func,
|
|
Packit |
1470ea |
object_to_weak_ref));
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
It also allows for a generic, closure-based ‘dummy’ callback, which can
|
|
Packit |
1470ea |
be used when a source needs to exist but no action needs to be performed
|
|
Packit |
1470ea |
in its callback:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
g_source_set_dummy_callback (source);
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="constructor">
|
|
Packit |
1470ea |
<title>Constructor</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Finally, the GSourceFuncs definition of the
|
|
Packit |
1470ea |
GSource can be written, alongside a construction function.
|
|
Packit |
1470ea |
It is typical practice to expose new source types simply as
|
|
Packit |
1470ea |
GSource s, not as the subtype structure; so the constructor
|
|
Packit |
1470ea |
returns a GSource* .
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
The example constructor here also demonstrates use of a child source to
|
|
Packit |
1470ea |
support cancellation conveniently. If the GCancellable is
|
|
Packit |
1470ea |
cancelled, the application’s callback will be dispatched and can check
|
|
Packit |
1470ea |
for cancellation. (The application code will need to make a pointer to
|
|
Packit |
1470ea |
the GCancellable available to its callback, as a field of the
|
|
Packit |
1470ea |
callback’s user data set in g_source_set_callback() ).
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
GSource *
|
|
Packit |
1470ea |
message_queue_source_new (GAsyncQueue *queue,
|
|
Packit |
1470ea |
GDestroyNotify destroy_message,
|
|
Packit |
1470ea |
GCancellable *cancellable)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
GSource *source; /* alias of @message_queue_source */
|
|
Packit |
1470ea |
MessageQueueSource *message_queue_source; /* alias of @source */
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
g_return_val_if_fail (queue != NULL, NULL);
|
|
Packit |
1470ea |
g_return_val_if_fail (cancellable == NULL ||
|
|
Packit |
1470ea |
G_IS_CANCELLABLE (cancellable), NULL);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
source = g_source_new (&message_queue_source_funcs,
|
|
Packit |
1470ea |
sizeof (MessageQueueSource));
|
|
Packit |
1470ea |
message_queue_source = (MessageQueueSource *) source;
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/* The caller can overwrite this name with something more useful later. */
|
|
Packit |
1470ea |
g_source_set_name (source, "MessageQueueSource");
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
message_queue_source->queue = g_async_queue_ref (queue);
|
|
Packit |
1470ea |
message_queue_source->destroy_message = destroy_message;
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/* Add a cancellable source. */
|
|
Packit |
1470ea |
if (cancellable != NULL)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
GSource *cancellable_source;
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
cancellable_source = g_cancellable_source_new (cancellable);
|
|
Packit |
1470ea |
g_source_set_dummy_callback (cancellable_source);
|
|
Packit |
1470ea |
g_source_add_child_source (source, cancellable_source);
|
|
Packit |
1470ea |
g_source_unref (cancellable_source);
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
return source;
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="full-listing">
|
|
Packit |
1470ea |
<title>Complete Example</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<listing>
|
|
Packit |
1470ea |
<title>Complete Example Code</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/**
|
|
Packit |
1470ea |
* MessageQueueSource:
|
|
Packit |
1470ea |
*
|
|
Packit |
1470ea |
* This is a #GSource which wraps a #GAsyncQueue and is dispatched whenever a
|
|
Packit |
1470ea |
* message can be pulled off the queue. Messages can be enqueued from any
|
|
Packit |
1470ea |
* thread.
|
|
Packit |
1470ea |
*
|
|
Packit |
1470ea |
* The callbacks dispatched by a #MessageQueueSource have type
|
|
Packit |
1470ea |
* #MessageQueueSourceFunc.
|
|
Packit |
1470ea |
*
|
|
Packit |
1470ea |
* #MessageQueueSource supports adding a #GCancellable child source which will
|
|
Packit |
1470ea |
* additionally dispatch if a provided #GCancellable is cancelled.
|
|
Packit |
1470ea |
*/
|
|
Packit |
1470ea |
typedef struct {
|
|
Packit |
1470ea |
GSource parent;
|
|
Packit |
1470ea |
GAsyncQueue *queue; /* owned */
|
|
Packit |
1470ea |
GDestroyNotify destroy_message;
|
|
Packit |
1470ea |
} MessageQueueSource;
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/**
|
|
Packit |
1470ea |
* MessageQueueSourceFunc:
|
|
Packit |
1470ea |
* @message: (transfer full) (nullable): message pulled off the queue
|
|
Packit |
1470ea |
* @user_data: user data provided to g_source_set_callback()
|
|
Packit |
1470ea |
*
|
|
Packit |
1470ea |
* Callback function type for #MessageQueueSource.
|
|
Packit |
1470ea |
*/
|
|
Packit |
1470ea |
typedef gboolean (*MessageQueueSourceFunc) (gpointer message,
|
|
Packit |
1470ea |
gpointer user_data);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
static gboolean
|
|
Packit |
1470ea |
message_queue_source_prepare (GSource *source,
|
|
Packit |
1470ea |
gint *timeout_)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
MessageQueueSource *message_queue_source = (MessageQueueSource *) source;
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
return (g_async_queue_length (message_queue_source->queue) > 0);
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
static gboolean
|
|
Packit |
1470ea |
message_queue_source_dispatch (GSource *source,
|
|
Packit |
1470ea |
GSourceFunc callback,
|
|
Packit |
1470ea |
gpointer user_data)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
MessageQueueSource *message_queue_source = (MessageQueueSource *) source;
|
|
Packit |
1470ea |
gpointer message;
|
|
Packit |
1470ea |
MessageQueueSourceFunc func = (MessageQueueSourceFunc) callback;
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/* Pop a message off the queue. */
|
|
Packit |
1470ea |
message = g_async_queue_try_pop (message_queue_source->queue);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/* If there was no message, bail. */
|
|
Packit |
1470ea |
if (message == NULL)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
/* Keep the source around to handle the next message. */
|
|
Packit |
1470ea |
return TRUE;
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/* @func may be %NULL if no callback was specified.
|
|
Packit |
1470ea |
* If so, drop the message. */
|
|
Packit |
1470ea |
if (func == NULL)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
if (message_queue_source->destroy_message != NULL)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
message_queue_source->destroy_message (message);
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/* Keep the source around to consume the next message. */
|
|
Packit |
1470ea |
return TRUE;
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
return func (message, user_data);
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
static void
|
|
Packit |
1470ea |
message_queue_source_finalize (GSource *source)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
MessageQueueSource *message_queue_source = (MessageQueueSource *) source;
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
g_async_queue_unref (message_queue_source->queue);
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
static gboolean
|
|
Packit |
1470ea |
message_queue_source_closure_callback (gpointer message,
|
|
Packit |
1470ea |
gpointer user_data)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
GClosure *closure = user_data;
|
|
Packit |
1470ea |
GValue param_value = G_VALUE_INIT;
|
|
Packit |
1470ea |
GValue result_value = G_VALUE_INIT;
|
|
Packit |
1470ea |
gboolean retval;
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/* The invoked function is responsible for freeing @message. */
|
|
Packit |
1470ea |
g_value_init (&result_value, G_TYPE_BOOLEAN);
|
|
Packit |
1470ea |
g_value_init (¶m_value, G_TYPE_POINTER);
|
|
Packit |
1470ea |
g_value_set_pointer (¶m_value, message);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
g_closure_invoke (closure, &result_value, 1, ¶m_value, NULL);
|
|
Packit |
1470ea |
retval = g_value_get_boolean (&result_value);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
g_value_unset (¶m_value);
|
|
Packit |
1470ea |
g_value_unset (&result_value);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
return retval;
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
static GSourceFuncs message_queue_source_funcs =
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
message_queue_source_prepare,
|
|
Packit |
1470ea |
NULL, /* check */
|
|
Packit |
1470ea |
message_queue_source_dispatch,
|
|
Packit |
1470ea |
message_queue_source_finalize,
|
|
Packit |
1470ea |
(GSourceFunc) message_queue_source_closure_callback,
|
|
Packit |
1470ea |
NULL,
|
|
Packit |
1470ea |
};
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/**
|
|
Packit |
1470ea |
* message_queue_source_new:
|
|
Packit |
1470ea |
* @queue: the queue to check
|
|
Packit |
1470ea |
* @destroy_message: (nullable): function to free a message, or %NULL
|
|
Packit |
1470ea |
* @cancellable: (nullable): a #GCancellable, or %NULL
|
|
Packit |
1470ea |
*
|
|
Packit |
1470ea |
* Create a new #MessageQueueSource, a type of #GSource which dispatches for
|
|
Packit |
1470ea |
* each message queued to it.
|
|
Packit |
1470ea |
*
|
|
Packit |
1470ea |
* If a callback function of type #MessageQueueSourceFunc is connected to the
|
|
Packit |
1470ea |
* returned #GSource using g_source_set_callback(), it will be invoked for each
|
|
Packit |
1470ea |
* message, with the message passed as its first argument. It is responsible for
|
|
Packit |
1470ea |
* freeing the message. If no callback is set, messages are automatically freed
|
|
Packit |
1470ea |
* as they are queued.
|
|
Packit |
1470ea |
*
|
|
Packit |
1470ea |
* Returns: (transfer full): a new #MessageQueueSource
|
|
Packit |
1470ea |
*/
|
|
Packit |
1470ea |
GSource *
|
|
Packit |
1470ea |
message_queue_source_new (GAsyncQueue *queue,
|
|
Packit |
1470ea |
GDestroyNotify destroy_message,
|
|
Packit |
1470ea |
GCancellable *cancellable)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
GSource *source; /* alias of @message_queue_source */
|
|
Packit |
1470ea |
MessageQueueSource *message_queue_source; /* alias of @source */
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
g_return_val_if_fail (queue != NULL, NULL);
|
|
Packit |
1470ea |
g_return_val_if_fail (cancellable == NULL ||
|
|
Packit |
1470ea |
G_IS_CANCELLABLE (cancellable), NULL);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
source = g_source_new (&message_queue_source_funcs,
|
|
Packit |
1470ea |
sizeof (MessageQueueSource));
|
|
Packit |
1470ea |
message_queue_source = (MessageQueueSource *) source;
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/* The caller can overwrite this name with something more useful later. */
|
|
Packit |
1470ea |
g_source_set_name (source, "MessageQueueSource");
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
message_queue_source->queue = g_async_queue_ref (queue);
|
|
Packit |
1470ea |
message_queue_source->destroy_message = destroy_message;
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
/* Add a cancellable source. */
|
|
Packit |
1470ea |
if (cancellable != NULL)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
GSource *cancellable_source;
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
cancellable_source = g_cancellable_source_new (cancellable);
|
|
Packit |
1470ea |
g_source_set_dummy_callback (cancellable_source);
|
|
Packit |
1470ea |
g_source_add_child_source (source, cancellable_source);
|
|
Packit |
1470ea |
g_source_unref (cancellable_source);
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
return source;
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</listing>
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="further-examples">
|
|
Packit |
1470ea |
<title>Further Examples</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Sources can be more complex than the example given above. In
|
|
Packit |
1470ea |
<link href="http://nice.freedesktop.org/">libnice</link>, a custom
|
|
Packit |
1470ea |
GSource is needed to poll a set of sockets which changes
|
|
Packit |
1470ea |
dynamically. The implementation is given as ComponentSource
|
|
Packit |
1470ea |
in <link href="http://cgit.freedesktop.org/libnice/libnice/tree/agent/component.c#n941">component.c</link>
|
|
Packit |
1470ea |
and demonstrates a more complex use of the prepare function.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Another example is a custom source to interface GnuTLS with GLib in its
|
|
Packit |
1470ea |
GTlsConnection implementation.
|
|
Packit |
1470ea |
<link href="https://git.gnome.org/browse/glib-networking/tree/tls/gnutls/gtlsconnection-gnutls.c#n871">GTlsConnectionGnutlsSource </link>
|
|
Packit |
1470ea |
synchronizes the main thread and a TLS worker thread which performs the
|
|
Packit |
1470ea |
blocking TLS operations.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
</page>
|