Merge branch 'main-context-pusher' into 'master'

gmain: Add GMainContextPusher convenience API

See merge request GNOME/glib!983
This commit is contained in:
Sebastian Dröge 2019-10-24 11:58:34 +00:00
commit 2e9b2761d6
4 changed files with 120 additions and 0 deletions

View File

@ -781,6 +781,11 @@ g_main_set_poll_func
g_main_context_invoke
g_main_context_invoke_full
<SUBSECTION>
GMainContextPusher
g_main_context_pusher_new
g_main_context_pusher_free
<SUBSECTION>
g_main_context_get_thread_default
g_main_context_ref_thread_default

View File

@ -35,6 +35,10 @@ g_autoptr_cleanup_gstring_free (GString *string)
g_string_free (string, TRUE);
}
/* Ignore deprecations in case we refer to a type which was added in a more
* recent GLib version than the users #GLIB_VERSION_MAX_ALLOWED definition. */
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
/* If adding a cleanup here, please also add a test case to
* glib/tests/autoptr.c
*/
@ -54,6 +58,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GArray, g_array_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GPtrArray, g_ptr_array_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GByteArray, g_byte_array_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMainContext, g_main_context_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMainContextPusher, g_main_context_pusher_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMainLoop, g_main_loop_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSource, g_source_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMappedFile, g_mapped_file_unref)
@ -91,3 +96,5 @@ G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GVariantDict, g_variant_dict_clear)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVariantType, g_variant_type_free)
G_DEFINE_AUTO_CLEANUP_FREE_FUNC(GStrv, g_strfreev, NULL)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GRefString, g_ref_string_release)
G_GNUC_END_IGNORE_DEPRECATIONS

View File

@ -430,6 +430,89 @@ GMainContext *g_main_context_get_thread_default (void);
GLIB_AVAILABLE_IN_ALL
GMainContext *g_main_context_ref_thread_default (void);
/**
* GMainContextPusher:
*
* Opaque type. See g_main_context_pusher_new() for details.
*
* Since: 2.64
*/
typedef void GMainContextPusher GLIB_AVAILABLE_TYPE_IN_2_64;
/**
* g_main_context_pusher_new:
* @main_context: (transfer none): a main context to push
*
* Push @main_context as the new thread-default main context for the current
* thread, using g_main_context_push_thread_default(), and return a new
* #GMainContextPusher. Pop with g_main_context_pusher_free(). Using
* g_main_context_pop_thread_default() on @main_context while a
* #GMainContextPusher exists for it can lead to undefined behaviour.
*
* Using two #GMainContextPushers in the same scope is not allowed, as it leads
* to an undefined pop order.
*
* This is intended to be used with g_autoptr(). Note that g_autoptr()
* is only available when using GCC or clang, so the following example
* will only work with those compilers:
* |[
* typedef struct
* {
* ...
* GMainContext *context;
* ...
* } MyObject;
*
* static void
* my_object_do_stuff (MyObject *self)
* {
* g_autoptr(GMainContextPusher) pusher = g_main_context_pusher_new (self->context);
*
* // Code with main context as the thread default here
*
* if (cond)
* // No need to pop
* return;
*
* // Optionally early pop
* g_clear_pointer (&pusher, g_main_context_pusher_free);
*
* // Code with main context no longer the thread default here
* }
* ]|
*
* Returns: (transfer full): a #GMainContextPusher
* Since: 2.64
*/
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static inline GMainContextPusher *
g_main_context_pusher_new (GMainContext *main_context)
{
g_main_context_push_thread_default (main_context);
return (GMainContextPusher *) main_context;
}
G_GNUC_END_IGNORE_DEPRECATIONS
/**
* g_main_context_pusher_free:
* @pusher: (transfer full): a #GMainContextPusher
*
* Pop @pushers main context as the thread default main context.
* See g_main_context_pusher_new() for details.
*
* This will pop the #GMainContext as the current thread-default main context,
* but will not call g_main_context_unref() on it.
*
* Since: 2.64
*/
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static inline void
g_main_context_pusher_free (GMainContextPusher *pusher)
{
g_main_context_pop_thread_default ((GMainContext *) pusher);
}
G_GNUC_END_IGNORE_DEPRECATIONS
/* GMainLoop: */
GLIB_AVAILABLE_IN_ALL

View File

@ -161,6 +161,30 @@ test_g_main_context (void)
g_assert_nonnull (val);
}
static void
test_g_main_context_pusher (void)
{
GMainContext *context, *old_thread_default;
context = g_main_context_new ();
old_thread_default = g_main_context_get_thread_default ();
g_assert_false (old_thread_default == context);
if (TRUE)
{
g_autoptr(GMainContextPusher) val = g_main_context_pusher_new (context);
/* Check its now the thread-default main context */
g_assert_true (g_main_context_get_thread_default () == context);
}
/* Check its now the old thread-default main context */
g_assert_false (g_main_context_get_thread_default () == context);
g_assert_true (g_main_context_get_thread_default () == old_thread_default);
g_main_context_unref (context);
}
static void
test_g_main_loop (void)
{
@ -692,6 +716,7 @@ main (int argc, gchar *argv[])
g_test_add_func ("/autoptr/g_ptr_array", test_g_ptr_array);
g_test_add_func ("/autoptr/g_byte_array", test_g_byte_array);
g_test_add_func ("/autoptr/g_main_context", test_g_main_context);
g_test_add_func ("/autoptr/g_main_context_pusher", test_g_main_context_pusher);
g_test_add_func ("/autoptr/g_main_loop", test_g_main_loop);
g_test_add_func ("/autoptr/g_source", test_g_source);
g_test_add_func ("/autoptr/g_mapped_file", test_g_mapped_file);