Moving main loop to GLib.
- From: Owen Taylor <otaylor redhat com>
- To: gtk-devel-list redhat com
- Subject: Moving main loop to GLib.
- Date: Wed, 18 Nov 1998 19:31:16 -0500
Moving the main loop to GLIB is something that has been
discussed for a long time. The following is based on
discussions I had with Tim Janik a month or two ago. I may
have forgotten some things we agreed upon; if so, he can
yell at me.
Moving the main loop to GLIB is desirable, because it enables
non-GUI applications to take advantage of a good event
loop and of event driven programming. In particular, it
would be desirable to use the main loop for ORBit.
The main reason why this operation is not simply copying
code is that the X events from GDK need to be integrated
into the event loop. To facilitate this, the proposed
GLIB interface is meant to be extensible. The core
code polls and dispatches events from various "event sources".
To get to the interface. The interfaces for handling
input functions, idle functions should look extremely
familiar. They are just the interfaces from GTK+ and
GDK, regularized a bit:
guint g_timeout_add_full (guint priority,
guint32 interval,
GFunc function,
gpointer data,
GDestroyNotify notify);
guint g_timeout_add (guint32 interval,
GFunc function,
gpointer data);
void g_timeout_remove (guint tag);
void g_timeout_remove_by_data (gpointer data);
guint g_idle_add (GFunc function,
gpointer data);
guint g_idle_add_full (gint priority,
GFunc function,
gpointer data,
GDestroyNotify destroy);
void g_idle_remove (guint tag);
void g_idle_remove_by_data (gpointer data);
typedef guint (*GInputFunction) (gpointer data,
gint source,
GInputCondition condition);
typedef enum
{
GDK_INPUT_READ = 1 << 0,
GDK_INPUT_WRITE = 1 << 1,
GDK_INPUT_EXCEPTION = 1 << 2
} GInputCondition;
guint g_input_add_full (gint priority,
gint source,
GInputCondition condition,
GInputFunction function,
gpointer data,
GDestroyNotify destroy);
gint g_input_add (gint source,
GInputCondition condition,
GInputFunction function,
gpointer data);
void g_input_remove (guint tag);
void g_input_remove_by_id (guint tag);
Note that GInputFunction now returns a gboolean, like the
other functions. gdk_input_add() can use wrapper functions
to preserve the old system of void returns.
To run the main loop, we use the following interface.
The main difference for this is that run() and quit()
are done for a specific GMainLoop *, instead of
for the current main loop. This avoids the problem
one occasionally sees where one has a main window and
a dialog up, one quits the main window, and the dialog
stays up until you quit it.
/* Create a new "main loop".
*/
GMainLoop *g_main_new ();
/* Run until a paired g_main_quit() */
void g_main_run (GMainLoop *loop);
void g_main_quit (GMainLoop *loop);
/* Destroy a GMainLoop. (Do we need to refcount these?) */
void g_main_destroy (GMainLoop *loop);
/* Run a single iteration of the mainloop. If block is FALSE,
* will never block
*/
void g_main_iteration (gboolean block);
/* See if any events are pending
*/
gboolean g_main_pending ();
Now, on to the low level part. The fundemental structure is a
GSource:
/* An event source */
struct _GSource {
gint priority;
GSList *poll_fds;
guint timeout;
/* Get read for a poll */
gboolean (*prepare) (GSource *source);
/* Check (after a poll) if any callbacks need dispatching */
gboolean (*check) (GSource *source);
/* Dispatch any pending callbacks */
void (*dispatch) (GSource *source);
/* Continue dispatching events after a recursive call to g_main_run() */
void (*restart) (GSource *source);
/* private data for GLib. Initialize to NULL */
GSourcePrivate *private;
}
poll_fds is a GSList, of essentially, struct poll_fd.
We provide definitions for the important parts of GPoll
to handle systems that don't support this.
typedef enum {
G_POLL_IN = POLLIN,
G_POLL_OUT = POLLOUT,
G_POLL_PRI = POLLPRI,
G_POLL_ERR = POLLERR,
G_POLL_HUP = POLLHUP,
} GPollFlags;
struct _GPollFD {
gint fd;
gushort events;
gushort revents;
};
The algorithm is, for each run of g_main_iteration(), we:
1) While the list of currently pending sources is non-empty
call (*restart) on the head, and (*dispatch) on the rest,
removing sources from the list after each returns
2) Call (*prepare) for each source.
3) Poll with the union of the pollfd's from each source,
and the minimum of all the timeouts from all sources.
(timeout < 0 == infinite)
4) For each source, if (*check) returns true, add the
source to the pending list. Once one source returns
true, stop after checking all sources at that priority.
5) While the list of currently pending sources is non-empty,
call (*dispatch) on each source, removing the source
after the call.
Comments are appreciated.
Regards,
Owen
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]