app: allow waiting on idle asyncs

In gimp_idle_run_async(), connect to the async's "waiting" signal,
and run the async func in the context of the caller in response, to
avoid blocking indefinitely.

(cherry picked from commit 30f509c84d)
This commit is contained in:
Ell
2020-03-14 12:41:46 +02:00
parent 552c9565e4
commit 24db85bef6

View File

@ -884,6 +884,8 @@ gimp_g_list_compare (GList *list1,
typedef struct
{
gint ref_count;
GimpAsync *async;
gint idle_id;
@ -895,35 +897,92 @@ typedef struct
static GimpIdleRunAsyncData *
gimp_idle_run_async_data_new (void)
{
return g_slice_new0 (GimpIdleRunAsyncData);
GimpIdleRunAsyncData *data;
data = g_slice_new0 (GimpIdleRunAsyncData);
data->ref_count = 1;
return data;
}
static void
gimp_idle_run_async_data_free (GimpIdleRunAsyncData *data)
gimp_idle_run_async_data_inc_ref (GimpIdleRunAsyncData *data)
{
g_signal_handlers_disconnect_by_data (data->async, data);
data->ref_count++;
}
if (data->user_data && data->user_data_destroy_func)
data->user_data_destroy_func (data->user_data);
static void
gimp_idle_run_async_data_dec_ref (GimpIdleRunAsyncData *data)
{
data->ref_count--;
if (! gimp_async_is_stopped (data->async))
gimp_async_abort (data->async);
if (data->ref_count == 0)
{
g_signal_handlers_disconnect_by_data (data->async, data);
g_object_unref (data->async);
if (! gimp_async_is_stopped (data->async))
gimp_async_abort (data->async);
g_slice_free (GimpIdleRunAsyncData, data);
g_object_unref (data->async);
if (data->user_data && data->user_data_destroy_func)
data->user_data_destroy_func (data->user_data);
g_slice_free (GimpIdleRunAsyncData, data);
}
}
static void
gimp_idle_run_async_cancel (GimpAsync *async,
GimpIdleRunAsyncData *data)
{
g_source_remove (data->idle_id);
gimp_idle_run_async_data_inc_ref (data);
if (data->idle_id)
{
g_source_remove (data->idle_id);
data->idle_id = 0;
}
gimp_idle_run_async_data_dec_ref (data);
}
static void
gimp_idle_run_async_waiting (GimpAsync *async,
GimpIdleRunAsyncData *data)
{
gimp_idle_run_async_data_inc_ref (data);
if (data->idle_id)
{
g_source_remove (data->idle_id);
data->idle_id = 0;
}
g_signal_handlers_block_by_func (data->async,
gimp_idle_run_async_cancel,
data);
while (! gimp_async_is_stopped (data->async))
data->func (data->async, data->user_data);
g_signal_handlers_unblock_by_func (data->async,
gimp_idle_run_async_cancel,
data);
data->user_data = NULL;
gimp_idle_run_async_data_dec_ref (data);
}
static gboolean
gimp_idle_run_async_idle (GimpIdleRunAsyncData *data)
{
gimp_idle_run_async_data_inc_ref (data);
g_signal_handlers_block_by_func (data->async,
gimp_idle_run_async_cancel,
data);
@ -938,9 +997,13 @@ gimp_idle_run_async_idle (GimpIdleRunAsyncData *data)
{
data->user_data = NULL;
gimp_idle_run_async_data_dec_ref (data);
return G_SOURCE_REMOVE;
}
gimp_idle_run_async_data_dec_ref (data);
return G_SOURCE_CONTINUE;
}
@ -973,12 +1036,15 @@ gimp_idle_run_async_full (gint priority,
g_signal_connect (data->async, "cancel",
G_CALLBACK (gimp_idle_run_async_cancel),
data);
g_signal_connect (data->async, "waiting",
G_CALLBACK (gimp_idle_run_async_waiting),
data);
data->idle_id = g_idle_add_full (
priority,
(GSourceFunc) gimp_idle_run_async_idle,
data,
(GDestroyNotify) gimp_idle_run_async_data_free);
(GDestroyNotify) gimp_idle_run_async_data_dec_ref);
return g_object_ref (data->async);
}