Introduction to Glib |
The glib event loop manages all the sources of an event available for glib. These events can come from different kinds of sources like file descriptors (plain file descriptors, sockets, or pipes), time-outs, or any kind of source that can be added.
To allow multiple independent sets of events to be handled in different threads, each source is associated with a GMainContext.
Each event source is given a priority. The default priority is G_PRIORITY_DEFAULT and its value is 0. Values less than 0 denote higher priority and values greater than zero denote lower priority. The events from higher priority sources are processed earlier than events from lower priority sources.
The GMainLoop data type represents an event loop. GMainContext is a parameter to GMainLoop. If GMainContext is passed as NULL, then a main loop with the default context is created. After the sources are added to GMainContext and a GMainLoop variable is created, g_main_loop_run() is called. This checks continuously for events from its sources and dispatches them. Finally when all the events have been processed, g_main_loop_quit() must be called to return from g_main_loop_run().
NOTE! sources are associated with GMainContext and not with GMainLoop. Events from sources will be checked and dispatched from all the GMainLoop the GMainContext is associated with.
Glib provides ready-made functions for adding the following sources either to the default context or to a custom context:
The following example code demonstrates the way to add a time-out source to the default context. The program makes 10 calls to timeout_callback(), which at the 10th call, calls g_main_loop_quit to make the main loop return.
#include <glib.h> gboolean timeout_callback(gpointer data) { static int i = 0; i++; g_print("timeout_callback called %d times\n", i); if (10 == i) { g_main_loop_quit( (GMainLoop*)data ); return FALSE; } return TRUE; } int main() { GMainLoop *loop; loop = g_main_loop_new ( NULL , FALSE ); // add source to default context g_timeout_add (100 , timeout_callback , loop); g_main_loop_run (loop); g_main_loop_unref(loop); return 0; }
The following code demonstrates the method to add the time-out source to a different context than the default context:
#include <glib.h> gboolean timeout_callback(gpointer data) { static int i = 0; i++; g_print("timeout_callback called %d times\n",i); if(10 == i) { g_main_loop_quit((GMainLoop*)data); return FALSE; } return TRUE; } int main() { GMainLoop *loop = NULL; GMainContext *context; GSource *source; int id; //create a new time-out source source = g_timeout_source_new(10); //create a context context = g_main_context_new(); //attach source to context id = g_source_attach(source,context); //create a main loop with context loop = g_main_loop_new(context,FALSE); //set the callback for this source g_source_set_callback (source,timeout_callback,loop,NULL); g_main_loop_run (loop); g_main_loop_unref (loop); return 0; }
The same process can be used for other default sources like child watch, I/O, and idle source since they are glib APIs that allow the creation of a source directly.
The previous section applies only to four types of sources ( time-outs, I/O, child watch, and idle source ), for which glib provides ready-made functions. The program below demonstrates the creation of a new source.
#include <glib.h> gboolean callback(gpointer data) { static int i = 0; i++; g_print ("timeout_callback called %d times\n",i); if (10 == i) { g_main_loop_quit((GMainLoop*)data); return FALSE; } return TRUE; } gboolean prepare(GSource *source,gint *timeout_) { *timeout_ = -1; return TRUE; } gboolean check(GSource *source) { return TRUE; } gboolean dispatch(GSource *source,GSourceFunc callback,gpointer user_data) { if (callback(user_data)) return TRUE; else return FALSE; } int main() { GMainLoop *loop = NULL; GMainContext *context; GSource *source; int id; //create a variable of type GSourceFuncs GSourceFuncs SourceFuncs = { prepare, check, dispatch, NULL }; //create a new source source = g_source_new (&SourceFuncs , sizeof(GSource)); //create a context context = g_main_context_new (); //attach source to context id = g_source_attach (source,context); //create a main loop with context loop = g_main_loop_new (context,FALSE); //set the callback for this source g_source_set_callback (source,callback,loop,NULL); g_main_loop_run (loop); g_main_loop_unref (loop); return 0; }
The creation of a new source requires us to define at least 3 functions:
NOTE! Time may have passed since the previous prepare function was called, so the source should be checked again.
Single iteration of GMainContext can be run in g_main_context_iteration (). When a more detailed control of how the main loop runs is desired call the component function of g_main_context iteration() directly.
The component functions of g_main_context iteration() are listed below:
©Nokia 2007 |