mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-05-03 20:46:53 +02:00
Add g_main_depth() (Request from Tim Janik and Stefan Westerfeld)
Sun Feb 29 21:34:34 2004 Owen Taylor <otaylor@redhat.com> * glib/gmain.[ch]: Add g_main_depth() (Request from Tim Janik and Stefan Westerfeld)
This commit is contained in:
parent
7b3042f8a7
commit
0875017ad1
@ -1,3 +1,8 @@
|
|||||||
|
Sun Feb 29 21:34:34 2004 Owen Taylor <otaylor@redhat.com>
|
||||||
|
|
||||||
|
* glib/gmain.[ch]: Add g_main_depth() (Request from
|
||||||
|
Tim Janik and Stefan Westerfeld)
|
||||||
|
|
||||||
Mon Mar 1 00:26:11 2004 Matthias Clasen <maclas@gmx.de>
|
Mon Mar 1 00:26:11 2004 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
* NEWS: Update for 2.3.4
|
* NEWS: Update for 2.3.4
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
Sun Feb 29 21:34:34 2004 Owen Taylor <otaylor@redhat.com>
|
||||||
|
|
||||||
|
* glib/gmain.[ch]: Add g_main_depth() (Request from
|
||||||
|
Tim Janik and Stefan Westerfeld)
|
||||||
|
|
||||||
Mon Mar 1 00:26:11 2004 Matthias Clasen <maclas@gmx.de>
|
Mon Mar 1 00:26:11 2004 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
* NEWS: Update for 2.3.4
|
* NEWS: Update for 2.3.4
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
Sun Feb 29 21:34:34 2004 Owen Taylor <otaylor@redhat.com>
|
||||||
|
|
||||||
|
* glib/gmain.[ch]: Add g_main_depth() (Request from
|
||||||
|
Tim Janik and Stefan Westerfeld)
|
||||||
|
|
||||||
Mon Mar 1 00:26:11 2004 Matthias Clasen <maclas@gmx.de>
|
Mon Mar 1 00:26:11 2004 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
* NEWS: Update for 2.3.4
|
* NEWS: Update for 2.3.4
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
Sun Feb 29 21:34:34 2004 Owen Taylor <otaylor@redhat.com>
|
||||||
|
|
||||||
|
* glib/gmain.[ch]: Add g_main_depth() (Request from
|
||||||
|
Tim Janik and Stefan Westerfeld)
|
||||||
|
|
||||||
Mon Mar 1 00:26:11 2004 Matthias Clasen <maclas@gmx.de>
|
Mon Mar 1 00:26:11 2004 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
* NEWS: Update for 2.3.4
|
* NEWS: Update for 2.3.4
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
Sun Feb 29 21:34:34 2004 Owen Taylor <otaylor@redhat.com>
|
||||||
|
|
||||||
|
* glib/gmain.[ch]: Add g_main_depth() (Request from
|
||||||
|
Tim Janik and Stefan Westerfeld)
|
||||||
|
|
||||||
Mon Mar 1 00:26:11 2004 Matthias Clasen <maclas@gmx.de>
|
Mon Mar 1 00:26:11 2004 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
* NEWS: Update for 2.3.4
|
* NEWS: Update for 2.3.4
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
Sun Feb 29 21:34:34 2004 Owen Taylor <otaylor@redhat.com>
|
||||||
|
|
||||||
|
* glib/gmain.[ch]: Add g_main_depth() (Request from
|
||||||
|
Tim Janik and Stefan Westerfeld)
|
||||||
|
|
||||||
Mon Mar 1 00:26:11 2004 Matthias Clasen <maclas@gmx.de>
|
Mon Mar 1 00:26:11 2004 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
* NEWS: Update for 2.3.4
|
* NEWS: Update for 2.3.4
|
||||||
|
@ -419,6 +419,7 @@ g_main_context_get_poll_func
|
|||||||
GPollFunc
|
GPollFunc
|
||||||
g_main_context_add_poll
|
g_main_context_add_poll
|
||||||
g_main_context_remove_poll
|
g_main_context_remove_poll
|
||||||
|
g_main_depth
|
||||||
g_main_set_poll_func
|
g_main_set_poll_func
|
||||||
|
|
||||||
<SUBSECTION>
|
<SUBSECTION>
|
||||||
|
144
glib/gmain.c
144
glib/gmain.c
@ -1719,10 +1719,151 @@ g_get_current_time (GTimeVal *result)
|
|||||||
|
|
||||||
/* Running the main loop */
|
/* Running the main loop */
|
||||||
|
|
||||||
|
static gint *
|
||||||
|
get_depth_pointer (void)
|
||||||
|
{
|
||||||
|
static GStaticPrivate depth_private = G_STATIC_PRIVATE_INIT;
|
||||||
|
gint *depth_pointer = g_static_private_get (&depth_private);
|
||||||
|
if (!depth_pointer)
|
||||||
|
{
|
||||||
|
depth_pointer = g_new (gint, 1);
|
||||||
|
*depth_pointer = 0;
|
||||||
|
g_static_private_set (&depth_private, depth_pointer, g_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
return depth_pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_main_depth:
|
||||||
|
*
|
||||||
|
* Return value: The main loop recursion level in the current thread
|
||||||
|
*
|
||||||
|
* Returns the depth of the stack of calls to
|
||||||
|
* g_main_context_dispatch() on any #GMainContext in the current thread.
|
||||||
|
* That is, when called from the toplevel, it gives 0. When
|
||||||
|
* called from within a callback from g_main_context_iteration()
|
||||||
|
* (or g_main_loop_run(), etc.) it returns 1. When called from within
|
||||||
|
* a callback to a recursive call to g_main_context_iterate(),
|
||||||
|
* it returns 2. And so forth.
|
||||||
|
*
|
||||||
|
* This function is useful in a situation like the following:
|
||||||
|
* Imagine an extremely simple "garbage collected" system.
|
||||||
|
*
|
||||||
|
* <example>
|
||||||
|
* static GList *free_list;
|
||||||
|
*
|
||||||
|
* gpointer
|
||||||
|
* allocate_memory (gsize size)
|
||||||
|
* {
|
||||||
|
* gpointer result = g_malloc (size);
|
||||||
|
* free_list = g_list_prepend (free_list, result);
|
||||||
|
* return result;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* void
|
||||||
|
* free_allocated_memory (void)
|
||||||
|
* {
|
||||||
|
* GList *l;
|
||||||
|
* for (l = free_list; l; l = l->next);
|
||||||
|
* g_free (l->data);
|
||||||
|
* g_list_free (free_list);
|
||||||
|
* free_list = NULL;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* [...]
|
||||||
|
*
|
||||||
|
* while (TRUE);
|
||||||
|
* {
|
||||||
|
* g_main_context_iteration (NULL, TRUE);
|
||||||
|
* free_allocated_memory();
|
||||||
|
* }
|
||||||
|
* </example>
|
||||||
|
*
|
||||||
|
* This works from an application, however, if you want to do the same
|
||||||
|
* thing from a library, it gets more difficult, since you no longer
|
||||||
|
* control the main loop. You might think you can simply use an idle
|
||||||
|
* function to make the call to free_allocated_memory(), but that
|
||||||
|
* doesn't work, since the idle function could be called from a
|
||||||
|
* recursive callback. This can be fixed by using g_main_context_depth()
|
||||||
|
*
|
||||||
|
* <example>
|
||||||
|
* gpointer
|
||||||
|
* allocate_memory (gsize size)
|
||||||
|
* {
|
||||||
|
* FreeListBlock *block = g_new (FreeListBlock, 1);\
|
||||||
|
* block->mem = g_malloc (size);
|
||||||
|
* block->depth = g_main_context_depth (NULL);
|
||||||
|
* free_list = g_list_prepend (free_list, block);
|
||||||
|
* return block->mem;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* void
|
||||||
|
* free_allocated_memory (void)
|
||||||
|
* {
|
||||||
|
* GList *l;
|
||||||
|
*
|
||||||
|
* int depth = g_main_context_depth();
|
||||||
|
* for (l = free_list; l; );
|
||||||
|
* {
|
||||||
|
* GList *next = l->next;
|
||||||
|
* FreeListBlock *block = l->data;
|
||||||
|
* if (block->depth > depth);
|
||||||
|
* {
|
||||||
|
* g_free (block->mem);
|
||||||
|
* g_free (block);
|
||||||
|
* free_list = g_list_delete_link (free_list, l);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* l = next;
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </example>
|
||||||
|
*
|
||||||
|
* There is a temptation to use g_main_context_depth() to solve
|
||||||
|
* problems with reentrancy. For instance, while waiting for data
|
||||||
|
* to be received from the network in response to a menu item,
|
||||||
|
* the menu item might be selected again. It might seem that
|
||||||
|
* one could write:
|
||||||
|
*
|
||||||
|
* if (g_main_context_depth(NULL) > 1)
|
||||||
|
* return;
|
||||||
|
*
|
||||||
|
* This should be avoided since the user then sees selecting the
|
||||||
|
* menu item do nothing. Furthermore, you'll find yourself adding
|
||||||
|
* these checks all over your code, since there are doubtless many,
|
||||||
|
* many things that the user could do. Instead, you can use the
|
||||||
|
* following techniques:
|
||||||
|
*
|
||||||
|
* <orderedlist>
|
||||||
|
* <listitem>
|
||||||
|
* <para>
|
||||||
|
* Use gtk_widget_set_sensitive() or modal dialogs to prevent
|
||||||
|
* the user from interacting with elements while the main
|
||||||
|
* loop is recursing.
|
||||||
|
* </para>
|
||||||
|
* </listitem>
|
||||||
|
* <listitem>
|
||||||
|
* <para>
|
||||||
|
* Avoid main loop recursion in situations where you can't handle
|
||||||
|
* arbitrary callbacks. Instead, structure your code so that you
|
||||||
|
* simply return to the main loop and then get called again when
|
||||||
|
* there is more work to do.
|
||||||
|
* </para>
|
||||||
|
* </listitem>
|
||||||
|
**/
|
||||||
|
int
|
||||||
|
g_main_depth (void)
|
||||||
|
{
|
||||||
|
gint *depth = get_depth_pointer ();
|
||||||
|
return *depth;
|
||||||
|
}
|
||||||
|
|
||||||
/* HOLDS: context's lock */
|
/* HOLDS: context's lock */
|
||||||
static void
|
static void
|
||||||
g_main_dispatch (GMainContext *context)
|
g_main_dispatch (GMainContext *context)
|
||||||
{
|
{
|
||||||
|
gint *depth = get_depth_pointer ();
|
||||||
guint i;
|
guint i;
|
||||||
|
|
||||||
for (i = 0; i < context->pending_dispatches->len; i++)
|
for (i = 0; i < context->pending_dispatches->len; i++)
|
||||||
@ -1762,9 +1903,12 @@ g_main_dispatch (GMainContext *context)
|
|||||||
|
|
||||||
UNLOCK_CONTEXT (context);
|
UNLOCK_CONTEXT (context);
|
||||||
|
|
||||||
|
(*depth)++;
|
||||||
need_destroy = ! dispatch (source,
|
need_destroy = ! dispatch (source,
|
||||||
callback,
|
callback,
|
||||||
user_data);
|
user_data);
|
||||||
|
(*depth)--;
|
||||||
|
|
||||||
LOCK_CONTEXT (context);
|
LOCK_CONTEXT (context);
|
||||||
|
|
||||||
if (cb_funcs)
|
if (cb_funcs)
|
||||||
|
@ -188,6 +188,8 @@ void g_main_context_add_poll (GMainContext *context,
|
|||||||
void g_main_context_remove_poll (GMainContext *context,
|
void g_main_context_remove_poll (GMainContext *context,
|
||||||
GPollFD *fd);
|
GPollFD *fd);
|
||||||
|
|
||||||
|
int g_main_depth (void);
|
||||||
|
|
||||||
/* GMainLoop: */
|
/* GMainLoop: */
|
||||||
|
|
||||||
GMainLoop *g_main_loop_new (GMainContext *context,
|
GMainLoop *g_main_loop_new (GMainContext *context,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user