Commit 80de7230 authored by Ell's avatar Ell

app: add GimpAsyncSet

GimpAsyncSet represents a dynamic set of running GimpAsync objects.
The objects are automatically removed from the set once they're
synced.

GimpAsyncSet implements the GimpWaitable and GimpCancelable
interfaces, allowing the entire set to be waited-on or canceled.

Additionally, GimpAsyncSet provides an "empty" property, which
indicates whether the set is empty or not.  This allows responding
to the completion of all the GimpAsync objects through the set's
"notify::empty" signal, or drive UI changes through property
bindings.
parent e24ce886
......@@ -129,6 +129,7 @@ AM_LDFLAGS = \
-Wl,-u,$(SYMPREFIX)gimp_pdb_compat_param_spec \
-Wl,-u,$(SYMPREFIX)gimp_layer_mode_is_legacy \
-Wl,-u,$(SYMPREFIX)gimp_parallel_init \
-Wl,-u,$(SYMPREFIX)gimp_async_set_new \
-Wl,-u,$(SYMPREFIX)gimp_uncancelable_waitable_new \
-Wl,-u,$(SYMPREFIX)gimp_tool_cursors_get_resource
......
......@@ -87,6 +87,8 @@ libappcore_a_sources = \
gimp-utils.h \
gimpasync.c \
gimpasync.h \
gimpasyncset.c \
gimpasyncset.h \
gimpbezierdesc.h \
gimpbezierdesc.c \
gimpboundary.c \
......
......@@ -178,6 +178,7 @@ typedef struct _GimpMandala GimpMandala;
/* misc objects */
typedef struct _GimpAsync GimpAsync;
typedef struct _GimpAsyncSet GimpAsyncSet;
typedef struct _GimpBuffer GimpBuffer;
typedef struct _GimpDrawableFilter GimpDrawableFilter;
typedef struct _GimpEnvironTable GimpEnvironTable;
......
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpasyncset.c
* Copyright (C) 2018 Ell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include "core-types.h"
#include "gimpasync.h"
#include "gimpasyncset.h"
#include "gimpcancelable.h"
#include "gimpwaitable.h"
enum
{
PROP_0,
PROP_EMPTY
};
typedef struct _GimpAsyncSetCallbackInfo GimpAsyncSetCallbackInfo;
struct _GimpAsyncSetPrivate
{
GHashTable *asyncs;
};
/* local function prototypes */
static void gimp_async_set_waitable_iface_init (GimpWaitableInterface *iface);
static void gimp_async_set_cancelable_iface_init (GimpCancelableInterface *iface);
static void gimp_async_set_dispose (GObject *object);
static void gimp_async_set_finalize (GObject *object);
static void gimp_async_set_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_async_set_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void gimp_async_set_wait (GimpWaitable *waitable);
static gboolean gimp_async_set_try_wait (GimpWaitable *waitable);
static gboolean gimp_async_set_wait_until (GimpWaitable *waitable,
gint64 end_time);
static void gimp_async_set_cancel (GimpCancelable *cancelable);
static void gimp_async_set_async_callback (GimpAsync *async,
GimpAsyncSet *async_set);
static void gimp_async_set_clear_internal (GimpAsyncSet *async_set,
gboolean wait);
G_DEFINE_TYPE_WITH_CODE (GimpAsyncSet, gimp_async_set, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GIMP_TYPE_WAITABLE,
gimp_async_set_waitable_iface_init)
G_IMPLEMENT_INTERFACE (GIMP_TYPE_CANCELABLE,
gimp_async_set_cancelable_iface_init))
#define parent_class gimp_async_set_parent_class
/* private functions */
static void
gimp_async_set_class_init (GimpAsyncSetClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = gimp_async_set_dispose;
object_class->finalize = gimp_async_set_finalize;
object_class->set_property = gimp_async_set_set_property;
object_class->get_property = gimp_async_set_get_property;
g_object_class_install_property (object_class, PROP_EMPTY,
g_param_spec_boolean ("empty",
NULL, NULL,
FALSE,
GIMP_PARAM_READABLE));
g_type_class_add_private (klass, sizeof (GimpAsyncSetPrivate));
}
static void
gimp_async_set_waitable_iface_init (GimpWaitableInterface *iface)
{
iface->wait = gimp_async_set_wait;
iface->try_wait = gimp_async_set_try_wait;
iface->wait_until = gimp_async_set_wait_until;
}
static void
gimp_async_set_cancelable_iface_init (GimpCancelableInterface *iface)
{
iface->cancel = gimp_async_set_cancel;
}
static void
gimp_async_set_init (GimpAsyncSet *async_set)
{
async_set->priv = G_TYPE_INSTANCE_GET_PRIVATE (async_set,
GIMP_TYPE_ASYNC_SET,
GimpAsyncSetPrivate);
async_set->priv->asyncs = g_hash_table_new (NULL, NULL);
#ifdef TIME_ASYNC_SET_OPS
async_set->priv->start_time = g_get_monotonic_time ();
#endif
}
static void
gimp_async_set_dispose (GObject *object)
{
GimpAsyncSet *async_set = GIMP_ASYNC_SET (object);
gimp_async_set_clear (async_set);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
gimp_async_set_finalize (GObject *object)
{
GimpAsyncSet *async_set = GIMP_ASYNC_SET (object);
g_hash_table_unref (async_set->priv->asyncs);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gimp_async_set_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
switch (property_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_async_set_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GimpAsyncSet *async_set = GIMP_ASYNC_SET (object);
switch (property_id)
{
case PROP_EMPTY:
g_value_set_boolean (value, gimp_async_set_is_empty (async_set));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_async_set_wait (GimpWaitable *waitable)
{
GimpAsyncSet *async_set = GIMP_ASYNC_SET (waitable);
gimp_async_set_clear_internal (async_set, TRUE);
}
static gboolean
gimp_async_set_try_wait (GimpWaitable *waitable)
{
GimpAsyncSet *async_set = GIMP_ASYNC_SET (waitable);
while (! gimp_async_set_is_empty (async_set))
{
GimpAsync *async;
GHashTableIter iter;
g_hash_table_iter_init (&iter, async_set->priv->asyncs);
g_hash_table_iter_next (&iter, (gpointer *) &async, NULL);
if (! gimp_waitable_try_wait (GIMP_WAITABLE (async)))
return FALSE;
}
return TRUE;
}
static gboolean
gimp_async_set_wait_until (GimpWaitable *waitable,
gint64 end_time)
{
GimpAsyncSet *async_set = GIMP_ASYNC_SET (waitable);
while (! gimp_async_set_is_empty (async_set))
{
GimpAsync *async;
GHashTableIter iter;
g_hash_table_iter_init (&iter, async_set->priv->asyncs);
g_hash_table_iter_next (&iter, (gpointer *) &async, NULL);
if (! gimp_waitable_wait_until (GIMP_WAITABLE (async), end_time))
return FALSE;
}
return TRUE;
}
static void
gimp_async_set_cancel (GimpCancelable *cancelable)
{
GimpAsyncSet *async_set = GIMP_ASYNC_SET (cancelable);
GimpAsync *async;
GHashTableIter iter;
g_hash_table_iter_init (&iter, async_set->priv->asyncs);
while (g_hash_table_iter_next (&iter, (gpointer *) &async, NULL))
gimp_cancelable_cancel (GIMP_CANCELABLE (async));
}
static void
gimp_async_set_async_callback (GimpAsync *async,
GimpAsyncSet *async_set)
{
g_hash_table_remove (async_set->priv->asyncs, async);
if (gimp_async_set_is_empty (async_set))
g_object_notify (G_OBJECT (async_set), "empty");
}
static void
gimp_async_set_clear_internal (GimpAsyncSet *async_set,
gboolean wait)
{
GimpAsync *async;
GHashTableIter iter;
if (gimp_async_set_is_empty (async_set))
return;
g_hash_table_iter_init (&iter, async_set->priv->asyncs);
while (g_hash_table_iter_next (&iter, (gpointer *) &async, NULL))
{
gimp_async_remove_callback (
async,
(GimpAsyncCallback) gimp_async_set_async_callback,
async_set);
if (wait)
gimp_waitable_wait (GIMP_WAITABLE (async));
}
g_hash_table_remove_all (async_set->priv->asyncs);
g_object_notify (G_OBJECT (async_set), "empty");
}
/* public functions */
GimpAsyncSet *
gimp_async_set_new (void)
{
return g_object_new (GIMP_TYPE_ASYNC_SET,
NULL);
}
void
gimp_async_set_add (GimpAsyncSet *async_set,
GimpAsync *async)
{
g_return_if_fail (GIMP_IS_ASYNC_SET (async_set));
g_return_if_fail (GIMP_IS_ASYNC (async));
if (g_hash_table_add (async_set->priv->asyncs, async))
{
if (g_hash_table_size (async_set->priv->asyncs) == 1)
g_object_notify (G_OBJECT (async_set), "empty");
gimp_async_add_callback (
async,
(GimpAsyncCallback) gimp_async_set_async_callback,
async_set);
}
}
void
gimp_async_set_remove (GimpAsyncSet *async_set,
GimpAsync *async)
{
g_return_if_fail (GIMP_IS_ASYNC_SET (async_set));
g_return_if_fail (GIMP_IS_ASYNC (async));
if (g_hash_table_remove (async_set->priv->asyncs, async))
{
gimp_async_remove_callback (
async,
(GimpAsyncCallback) gimp_async_set_async_callback,
async_set);
if (g_hash_table_size (async_set->priv->asyncs) == 0)
g_object_notify (G_OBJECT (async_set), "empty");
}
}
void
gimp_async_set_clear (GimpAsyncSet *async_set)
{
g_return_if_fail (GIMP_IS_ASYNC_SET (async_set));
gimp_async_set_clear_internal (async_set, FALSE);
}
gboolean
gimp_async_set_is_empty (GimpAsyncSet *async_set)
{
g_return_val_if_fail (GIMP_IS_ASYNC_SET (async_set), FALSE);
return g_hash_table_size (async_set->priv->asyncs) == 0;
}
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpasyncset.h
* Copyright (C) 2018 Ell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GIMP_ASYNC_SET_H__
#define __GIMP_ASYNC_SET_H__
#define GIMP_TYPE_ASYNC_SET (gimp_async_set_get_type ())
#define GIMP_ASYNC_SET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_ASYNC_SET, GimpAsyncSet))
#define GIMP_ASYNC_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_ASYNC_SET, GimpAsyncSetClass))
#define GIMP_IS_ASYNC_SET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_ASYNC_SET))
#define GIMP_IS_ASYNC_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_ASYNC_SET))
#define GIMP_ASYNC_SET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_ASYNC_SET, GimpAsyncSetClass))
typedef struct _GimpAsyncSetPrivate GimpAsyncSetPrivate;
typedef struct _GimpAsyncSetClass GimpAsyncSetClass;
struct _GimpAsyncSet
{
GObject parent_instance;
GimpAsyncSetPrivate *priv;
};
struct _GimpAsyncSetClass
{
GObjectClass parent_class;
};
GType gimp_async_set_get_type (void) G_GNUC_CONST;
GimpAsyncSet * gimp_async_set_new (void);
void gimp_async_set_add (GimpAsyncSet *async_set,
GimpAsync *async);
void gimp_async_set_remove (GimpAsyncSet *async_set,
GimpAsync *async);
void gimp_async_set_clear (GimpAsyncSet *async_set);
gboolean gimp_async_set_is_empty (GimpAsyncSet *async_set);
#endif /* __GIMP_ASYNC_SET_H__ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment