};
#endif
+typedef struct _GMainDispatch GMainDispatch;
+
+struct _GMainDispatch
+{
+ gint depth;
+ GSList *source;
+};
+
struct _GMainContext
{
#ifdef G_THREADS_ENABLED
g_source_set_callback_indirect (source, new_callback, &g_source_callback_funcs);
}
+
+/**
+ * g_source_set_funcs:
+ * @source: a #GSource
+ * @funcs: the new #GSourceFuncs
+ *
+ * Sets the source functions (can be used to override
+ * default implementations) of an unattached source.
+ *
+ * Since: 2.12
+ */
+void
+g_source_set_funcs (GSource *source,
+ GSourceFuncs *funcs)
+{
+ g_return_if_fail (source != NULL);
+ g_return_if_fail (source->context == NULL);
+ g_return_if_fail (source->ref_count > 0);
+ g_return_if_fail (funcs != NULL);
+
+ source->source_funcs = funcs;
+}
+
/**
* g_source_set_priority:
* @source: a #GSource
/* Running the main loop */
-static gint *
-get_depth_pointer (void)
+static GMainDispatch *
+get_dispatch (void)
{
static GStaticPrivate depth_private = G_STATIC_PRIVATE_INIT;
- gint *depth_pointer = g_static_private_get (&depth_private);
- if (!depth_pointer)
+ GMainDispatch *dispatch = g_static_private_get (&depth_private);
+ if (!dispatch)
{
- depth_pointer = g_new (gint, 1);
- *depth_pointer = 0;
- g_static_private_set (&depth_private, depth_pointer, g_free);
+ dispatch = g_slice_new0 (GMainDispatch);
+ g_static_private_set (&depth_private, dispatch, NULL);
}
- return depth_pointer;
+ return dispatch;
}
/**
int
g_main_depth (void)
{
- gint *depth = get_depth_pointer ();
- return *depth;
+ GMainDispatch *dispatch = get_dispatch ();
+ return dispatch->depth;
+}
+
+/**
+ * g_main_current_source:
+ *
+ * Return value: The currently firing source for this thread or NULL.
+ */
+GSource *
+g_main_current_source (void)
+{
+ GMainDispatch *dispatch = get_dispatch ();
+ return dispatch->source ? dispatch->source->data : NULL;
}
+/**
+ * g_source_is_destroyed:
+ * @source: a #GSource
+ *
+ * Returns whether @source has been destroyed.
+ *
+ * This is important when you operate upon your objects
+ * from within idle handlers, but may have freed the object
+ * before the dispatch of your idle handler.
+ *
+ * <informalexample><programlisting>
+ * static gboolean
+ * idle_callback (gpointer data)
+ * {
+ * SomeWidget *self = data;
+ *
+ * GDK_THREADS_ENTER ();
+ * /<!-- -->* do stuff with self *<!-- -->/
+ * self->idle_id = 0;
+ * GDK_THREADS_LEAVE ();
+ *
+ * return FALSE;
+ * }
+ *
+ * static void
+ * some_widget_do_stuff_later (SomeWidget *self)
+ * {
+ * self->idle_id = g_idle_add (idle_callback, self);
+ * }
+ *
+ * static void
+ * some_widget_finalize (GObject *object)
+ * {
+ * SomeWidget *self = SOME_WIDGET (object);
+ *
+ * if (self->idle_id)
+ * g_source_remove (self->idle_id);
+ *
+ * G_OBJECT_CLASS (parent_class)->finalize (object);
+ * }
+ * </programlisting></informalexample>
+ *
+ * This will fail in a multi-threaded application if the
+ * widget is destroyed before the idle handler fires due
+ * to the use after free in the callback. A solution, to
+ * this particular problem, is to check to if the source
+ * has already been destroy within the callback.
+ *
+ * <informalexample><programlisting>
+ * static gboolean
+ * idle_callback (gpointer data)
+ * {
+ * SomeWidget *self = data;
+ *
+ * GDK_THREADS_ENTER ();
+ * if (!g_source_is_destroyed (g_main_get_current_source ()))
+ * {
+ * /<!-- -->* do stuff with self *<!-- -->/
+ * }
+ * GDK_THREADS_LEAVE ();
+ *
+ * return FALSE;
+ * }
+ * </programlisting></informalexample>
+ *
+ * Return value: %TRUE if the source has been destroyed
+ */
+gboolean
+g_source_is_destroyed (GSource *source)
+{
+ return SOURCE_DESTROYED (source);
+}
+
+
/* Temporarily remove all this source's file descriptors from the
* poll(), so that if data comes available for one of the file descriptors
* we don't continually spin in the poll()
static void
g_main_dispatch (GMainContext *context)
{
- gint *depth = get_depth_pointer ();
+ GMainDispatch *current = get_dispatch ();
guint i;
for (i = 0; i < context->pending_dispatches->len; i++)
UNLOCK_CONTEXT (context);
- (*depth)++;
+ current->depth++;
+ current->source = g_slist_prepend (current->source, source);
need_destroy = ! dispatch (source,
callback,
user_data);
- (*depth)--;
+ current->source = g_slist_remove (current->source, source);
+ current->depth--;
if (cb_funcs)
cb_funcs->unref (cb_data);
gint n_fds);
void g_main_context_dispatch (GMainContext *context);
-void g_main_context_set_poll_func (GMainContext *context,
- GPollFunc func);
+void g_main_context_set_poll_func (GMainContext *context,
+ GPollFunc func);
GPollFunc g_main_context_get_poll_func (GMainContext *context);
/* Low level functions for use by source implementations
*/
-void g_main_context_add_poll (GMainContext *context,
- GPollFD *fd,
- gint priority);
-void g_main_context_remove_poll (GMainContext *context,
- GPollFD *fd);
+void g_main_context_add_poll (GMainContext *context,
+ GPollFD *fd,
+ gint priority);
+void g_main_context_remove_poll (GMainContext *context,
+ GPollFD *fd);
+
+gint g_main_depth (void);
+GSource *g_main_current_source (void);
-int g_main_depth (void);
/* GMainLoop: */
GMainContext *g_source_get_context (GSource *source);
-void g_source_set_callback (GSource *source,
- GSourceFunc func,
- gpointer data,
- GDestroyNotify notify);
+void g_source_set_callback (GSource *source,
+ GSourceFunc func,
+ gpointer data,
+ GDestroyNotify notify);
+void g_source_set_funcs (GSource *source,
+ GSourceFuncs *funcs);
+gboolean g_source_is_destroyed (GSource *source);
/* Used to implement g_source_connect_closure and internally*/
void g_source_set_callback_indirect (GSource *source,