diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index 2f3d954..6fa6aa8 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -2134,6 +2134,14 @@ g_array_sort_with_data
 g_array_index
 g_array_set_size
 g_array_free
+g_array_set_data
+g_array_get_data
+g_array_steal_data
+g_array_set_qdata
+g_array_get_qdata
+g_array_steal_qdata
+g_array_get_element_type
+g_array_set_element_type
 </SECTION>
 
 <SECTION>
diff --git a/docs/reference/glib/tmpl/arrays.sgml b/docs/reference/glib/tmpl/arrays.sgml
index 890e15c..0062047 100644
--- a/docs/reference/glib/tmpl/arrays.sgml
+++ b/docs/reference/glib/tmpl/arrays.sgml
@@ -337,3 +337,82 @@ separately.
 	The element data should be freed using g_free().
 
 
+<!-- ##### FUNCTION g_array_set_data ##### -->
+<para>
+
+</para>
+
+@array: 
+@key: 
+@data: 
+@destroy_func: 
+
+
+<!-- ##### FUNCTION g_array_get_data ##### -->
+<para>
+
+</para>
+
+@array: 
+@key: 
+@Returns: 
+
+
+<!-- ##### FUNCTION g_array_steal_data ##### -->
+<para>
+
+</para>
+
+@array: 
+@key: 
+@Returns: 
+
+
+<!-- ##### FUNCTION g_array_set_qdata ##### -->
+<para>
+
+</para>
+
+@array: 
+@quark: 
+@data: 
+@destroy_func: 
+
+
+<!-- ##### FUNCTION g_array_get_qdata ##### -->
+<para>
+
+</para>
+
+@array: 
+@quark: 
+@Returns: 
+
+
+<!-- ##### FUNCTION g_array_steal_qdata ##### -->
+<para>
+
+</para>
+
+@array: 
+@quark: 
+@Returns: 
+
+
+<!-- ##### MACRO g_array_get_element_type ##### -->
+<para>
+
+</para>
+
+@array: 
+
+
+<!-- ##### MACRO g_array_set_element_type ##### -->
+<para>
+
+</para>
+
+@array: 
+@type: 
+
+
diff --git a/docs/reference/glib/tmpl/glib-unused.sgml b/docs/reference/glib/tmpl/glib-unused.sgml
index ca73e16..54b4953 100644
--- a/docs/reference/glib/tmpl/glib-unused.sgml
+++ b/docs/reference/glib/tmpl/glib-unused.sgml
@@ -320,6 +320,21 @@ in any UNIX manual.
 @fd: 
 @size: 
 
+<!-- ##### MACRO g_array_get_element_gtype ##### -->
+<para>
+
+</para>
+
+@array: 
+
+<!-- ##### MACRO g_array_set_element_gtype ##### -->
+<para>
+
+</para>
+
+@array: 
+@gtype: 
+
 <!-- ##### FUNCTION g_channel_error_from_errno ##### -->
 <para>
 
diff --git a/glib/garray.c b/glib/garray.c
index 8cb6e1d..83bb090 100644
--- a/glib/garray.c
+++ b/glib/garray.c
@@ -39,6 +39,7 @@
 #include "gthread.h"
 #include "gmessages.h"
 #include "gqsort.h"
+#include "gdataset.h"
 
 #include "galias.h"
 
@@ -56,6 +57,7 @@ struct _GRealArray
   guint   zero_terminated : 1;
   guint   clear : 1;
   volatile gint ref_count;
+  GData  *qdata;
 };
 
 #define g_array_elt_len(array,i) ((array)->elt_size * (i))
@@ -192,6 +194,7 @@ g_array_free (GArray   *farray,
   else
     {
       g_slice_free1 (sizeof (GRealArray), array);
+      g_datalist_clear (&array->qdata);
     }
 
   return segment;
@@ -420,6 +423,152 @@ g_array_maybe_expand (GRealArray *array,
     }
 }
 
+/**
+ * g_array_get_data:
+ * @array: A #GArray containing the associations.
+ * @key: Name of the key for that association.
+ *
+ * Gets a named field from @array<!-- -->'s table of associations (see g_array_set_data()).
+ *
+ * Returns: The data if found, or %NULL if no such data exists.
+ *
+ * Since: 2.22
+ */
+gpointer
+g_array_get_data (GArray      *array,
+                  const gchar *key)
+{
+  GRealArray *rarray = (GRealArray *) array;
+  GQuark quark;
+  if (rarray->qdata == NULL)
+    return NULL;
+  quark = g_quark_try_string (key);
+  return quark != 0 ? g_datalist_id_get_data (&rarray->qdata, quark) : NULL;
+}
+
+/**
+ * g_array_set_data:
+ * @array: A #GArray containing the associations.
+ * @key: Name of the key.
+ * @data: Data to associate with that key.
+ * @destroy_func: Function to call when the association is destroyed or %NULL.
+ *
+ * Each #GArray carries around a table of associations from
+ * strings to pointers.  This function lets you set an association.
+ * When the association is destroyed, @destroy_func is called
+ * with @data, if @data is not %NULL.
+ *
+ * If the object already had an association with that name,
+ * the old association will be destroyed.
+ *
+ * Since: 2.22
+ */
+void
+g_array_set_data (GArray         *array,
+                  const gchar    *key,
+                  gpointer        data,
+                  GDestroyNotify  destroy_func)
+{
+  GRealArray *rarray = (GRealArray *) array;
+  if (rarray->qdata == NULL)
+    g_datalist_init (&rarray->qdata);
+  g_datalist_id_set_data_full (&rarray->qdata, g_quark_from_string (key),
+                               data,
+                               data != NULL ? destroy_func : NULL);
+}
+
+/**
+ * g_array_steal_data:
+ * @array: A #GArray containing the associations.
+ * @key: Name of the key.
+ *
+ * Remove a specified datum from the object's data associations,
+ * without invoking the association's destroy handler.
+ *
+ * Returns: The data if found, or %NULL if no such data exists.
+ *
+ * Since: 2.22
+ */
+gpointer
+g_array_steal_data (GArray      *array,
+                    const gchar *key)
+{
+  GRealArray *rarray = (GRealArray *) array;
+  GQuark quark;
+  if (rarray->qdata == NULL)
+    return NULL;
+  quark = g_quark_try_string (key);
+  return quark != 0 ? g_datalist_id_remove_no_notify (&rarray->qdata, quark) : NULL;
+}
+
+/**
+ * g_array_get_qdata:
+ * @array: #GArray to get a stored user data pointer from.
+ * @quark: A #GQuark, naming the user data pointer.
+ *
+ * Like g_array_get_data() but uses a #GQuark instead of a string.
+ *
+ * Returns: The user data pointer set, or %NULL.
+ *
+ * Since: 2.22
+ */
+gpointer
+g_array_get_qdata (GArray *array,
+                   GQuark  quark)
+{
+  GRealArray *rarray = (GRealArray *) array;
+  if (rarray->qdata == NULL)
+    return NULL;
+  return quark != 0 ? g_datalist_id_get_data (&rarray->qdata, quark) : NULL;
+}
+
+/**
+ * g_array_set_qdata:
+ * @array: A #GArray containing the associations.
+ * @quark: A #GQuark, naming the user data pointer.
+ * @data: Data to associate with that key.
+ * @destroy_func: Function to call when the association is destroyed or %NULL.
+ *
+ * Like g_array_set_data() but uses a #GQuark instead of a string.
+ *
+ * Since: 2.22
+ */
+void
+g_array_set_qdata (GArray           *array,
+                   GQuark            quark,
+                   gpointer          data,
+                   GDestroyNotify    destroy_func)
+{
+  GRealArray *rarray = (GRealArray *) array;
+  if (rarray->qdata == NULL)
+    g_datalist_init (&rarray->qdata);
+  g_datalist_id_set_data_full (&rarray->qdata,
+                               quark,
+                               data,
+                               data != NULL ? destroy_func : NULL);
+}
+
+/**
+ * g_array_steal_qdata:
+ * @array: A #GArray containing the associations.
+ * @quark: A #GQuark, naming the user data pointer.
+ *
+ * Like g_array_set_data() but uses a #GQuark instead of a string.
+ *
+ * Returns: The data if found, or %NULL if no such data exists.
+ *
+ * Since: 2.22
+ */
+gpointer
+g_array_steal_qdata (GArray *array,
+                     GQuark  quark)
+{
+  GRealArray *rarray = (GRealArray *) array;
+  if (rarray->qdata == NULL)
+    return NULL;
+  return quark != 0 ? g_datalist_id_remove_no_notify (&rarray->qdata, quark) : NULL;
+}
+
 /* Pointer Array
  */
 
diff --git a/glib/garray.h b/glib/garray.h
index 6bc51f7..659718f 100644
--- a/glib/garray.h
+++ b/glib/garray.h
@@ -32,6 +32,7 @@
 #define __G_ARRAY_H__
 
 #include <glib/gtypes.h>
+#include <glib/gquark.h>
 
 G_BEGIN_DECLS
 
@@ -104,6 +105,53 @@ void    g_array_sort_with_data    (GArray           *array,
 				   GCompareDataFunc  compare_func,
 				   gpointer          user_data);
 
+gpointer g_array_get_data         (GArray           *array,
+                                   const gchar      *key);
+void     g_array_set_data         (GArray           *array,
+                                   const gchar      *key,
+                                   gpointer          data,
+                                   GDestroyNotify    destroy_func);
+gpointer g_array_steal_data       (GArray           *array,
+                                   const gchar      *key);
+gpointer g_array_get_qdata        (GArray           *array,
+                                   GQuark            quark);
+void     g_array_set_qdata        (GArray           *array,
+                                   GQuark            quark,
+                                   gpointer          data,
+                                   GDestroyNotify    destroy_func);
+gpointer g_array_steal_qdata      (GArray           *array,
+                                   GQuark            quark);
+/* extra hoops to ensure type-safety and having these functions in the GLib
+ * section of the docs
+ */
+/**
+ * g_array_get_element_type:
+ * @array: A #GArray.
+ *
+ * Gets the #GType for the elements stored in @array.
+ *
+ * Note that you will have to link to libgobject for this macro to work.
+ *
+ * Returns: The #GType for the elements stored in @array or #G_TYPE_INVALID if
+ * the type is not set.
+ *
+ * Since: 2.22
+ */
+#define g_array_get_element_type(array) (g_array_get_element_type_real (array))
+/**
+ * g_array_set_element_type:
+ * @array: A #GArray.
+ * @type: A #GType for the elements stored in @array.
+ *
+ * Sets the #GType for the elements stored in @array.
+ *
+ * Note that you will have to link to libgobject for this macro to work.
+ *
+ * Since: 2.22
+ */
+#define g_array_set_element_type(array,type) do { g_array_set_element_type_real (array, type); } while (0)
+
+
 /* Resizable pointer array.  This interface is much less complicated
  * than the above.  Add appends a pointer.  Remove fills any cleared 
  * spot and shortens the array. remove_fast will again distort order.  
diff --git a/glib/glib.symbols b/glib/glib.symbols
index f8410ca..d8b3e7f 100644
--- a/glib/glib.symbols
+++ b/glib/glib.symbols
@@ -28,6 +28,12 @@ g_array_set_size
 g_array_sized_new
 g_array_sort
 g_array_sort_with_data
+g_array_get_data
+g_array_get_qdata
+g_array_set_data
+g_array_set_qdata
+g_array_steal_data
+g_array_steal_qdata
 g_byte_array_append
 g_byte_array_free
 g_byte_array_unref
diff --git a/glib/tests/array-test.c b/glib/tests/array-test.c
index 3572ba3..f704b7a 100644
--- a/glib/tests/array-test.c
+++ b/glib/tests/array-test.c
@@ -99,6 +99,62 @@ array_ref_count (void)
   g_array_unref (garray2);
 }
 
+
+static gint num_on_foo_destroyed_invocations = 0;
+
+static void
+on_foo_destroyed (gpointer data)
+{
+  num_on_foo_destroyed_invocations++;
+  g_free (data);
+}
+
+static void
+array_associations (void)
+{
+  GArray *a;
+  GQuark q;
+
+  /* strings */
+  num_on_foo_destroyed_invocations = 0;
+  a = g_array_new (FALSE, FALSE, sizeof (gint));
+  g_assert (g_array_get_data (a, "foo") == NULL);
+  g_array_set_data (a, "foo", g_strdup ("blah"), on_foo_destroyed);
+  g_assert_cmpstr (g_array_get_data (a, "foo"), ==, "blah");
+  g_array_set_data (a, "foo", NULL, NULL);
+  g_assert_cmpint (num_on_foo_destroyed_invocations, ==, 1);
+  g_assert (g_array_get_data (a, "foo") == NULL);
+  g_array_set_data (a, "foo", NULL, NULL);
+  g_assert_cmpint (num_on_foo_destroyed_invocations, ==, 1);
+  g_array_set_data (a, "foo", g_strdup ("blah2"), on_foo_destroyed);
+  g_assert_cmpstr (g_array_get_data (a, "foo"), ==, "blah2");
+  g_array_ref (a);
+  g_array_unref (a);
+  g_assert_cmpint (num_on_foo_destroyed_invocations, ==, 1);
+  g_array_unref (a);
+  g_assert_cmpint (num_on_foo_destroyed_invocations, ==, 2);
+
+  /* quarks */
+  num_on_foo_destroyed_invocations = 0;
+  q = g_quark_from_string ("foo");
+  a = g_array_new (FALSE, FALSE, sizeof (gint));
+  g_assert (g_array_get_qdata (a, q) == NULL);
+  g_array_set_qdata (a, q, g_strdup ("blah"), on_foo_destroyed);
+  g_assert_cmpstr (g_array_get_qdata (a, q), ==, "blah");
+  g_array_set_qdata (a, q, NULL, NULL);
+  g_assert_cmpint (num_on_foo_destroyed_invocations, ==, 1);
+  g_assert (g_array_get_qdata (a, q) == NULL);
+  g_array_set_qdata (a, q, NULL, NULL);
+  g_assert_cmpint (num_on_foo_destroyed_invocations, ==, 1);
+  g_array_set_qdata (a, q, g_strdup ("blah2"), on_foo_destroyed);
+  g_assert_cmpstr (g_array_get_qdata (a, q), ==, "blah2");
+  g_array_ref (a);
+  g_array_unref (a);
+  g_assert_cmpint (num_on_foo_destroyed_invocations, ==, 1);
+  g_array_unref (a);
+  g_assert_cmpint (num_on_foo_destroyed_invocations, ==, 2);
+}
+
 static void
 pointer_array_add (void)
 {
@@ -290,6 +346,7 @@ main (int argc, char *argv[])
   g_test_add_func ("/array/append", array_append);
   g_test_add_func ("/array/prepend", array_prepend);
   g_test_add_func ("/array/ref-count", array_ref_count);
+  g_test_add_func ("/array/associations", array_associations);
 
   /* pointer arrays */
   g_test_add_func ("/pointerarray/add", pointer_array_add);
diff --git a/gobject/gboxed.c b/gobject/gboxed.c
index e3a6170..4875878 100644
--- a/gobject/gboxed.c
+++ b/gobject/gboxed.c
@@ -284,6 +284,22 @@ g_array_get_type (void)
                                             (GBoxedFreeFunc) g_array_unref);
   return type_id;
 }
+static GQuark _array_quark = 0;
+GType
+g_array_get_element_type_real (GArray *array)
+{
+  if (G_UNLIKELY (_array_quark == 0))
+    _array_quark = g_quark_from_string ("g-array-element-type");
+  return (GType) GPOINTER_TO_UINT (g_array_get_qdata (array, _array_quark));
+}
+void
+g_array_set_element_type_real (GArray *array,
+                                GType   gtype)
+{
+  if (G_UNLIKELY (_array_quark == 0))
+    _array_quark = g_quark_from_string ("g-array-element-type");
+  g_array_set_qdata (array, _array_quark, GUINT_TO_POINTER (gtype), NULL);
+}
 
 GType
 g_ptr_array_get_type (void)
diff --git a/gobject/gboxed.h b/gobject/gboxed.h
index 82e2722..09a0938 100644
--- a/gobject/gboxed.h
+++ b/gobject/gboxed.h
@@ -212,6 +212,11 @@ GType   g_regex_get_type        (void)  G_GNUC_CONST;
  * A C representable type name for #G_TYPE_STRV.
  */
 typedef gchar** GStrv;
+
+/* these functions are used by g_array_[set|get]_element_type() macros in libglib */
+GType g_array_get_element_type_real (GArray *array);
+void  g_array_set_element_type_real (GArray *array,
+                                     GType   gtype);
      
 G_END_DECLS
 
diff --git a/gobject/gobject.symbols b/gobject/gobject.symbols
index a43dd08..00e1d18 100644
--- a/gobject/gobject.symbols
+++ b/gobject/gobject.symbols
@@ -32,6 +32,8 @@ g_value_take_boxed
 g_value_dup_boxed
 g_value_get_boxed
 g_value_set_static_boxed
+g_array_get_element_type_real
+g_array_set_element_type_real
 #ifndef G_DISABLE_DEPRECATED
 g_value_set_boxed_take_ownership
 #endif
diff --git a/gobject/tests/Makefile.am b/gobject/tests/Makefile.am
index ed63a82..60a67ce 100644
--- a/gobject/tests/Makefile.am
+++ b/gobject/tests/Makefile.am
@@ -8,3 +8,7 @@ libgobject_LDADD = ../libgobject-2.0.la $(top_builddir)/gthread/libgthread-2.0.l
 TEST_PROGS             += threadtests
 threadtests_SOURCES	= threadtests.c
 threadtests_LDADD	= $(libgobject_LDADD)
+
+TEST_PROGS             += boxedtests
+boxedtests_SOURCES	= boxedtests.c
+boxedtests_LDADD	= $(libgobject_LDADD)
--- /dev/null	2009-05-01 09:31:40.420283668 -0400
+++ gobject/tests/boxedtests.c	2009-05-02 11:21:05.000000000 -0400
@@ -0,0 +1,48 @@
+/* GLib testing framework examples and tests
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Authors: David Zeuthen
+ *
+ * This work is provided "as is"; redistribution and modification
+ * in whole or in part, in any medium, physical or electronic is
+ * permitted without restriction.
+ *
+ * This work 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.
+ *
+ * In no event shall the authors or contributors be liable for any
+ * direct, indirect, incidental, special, exemplary, or consequential
+ * damages (including, but not limited to, procurement of substitute
+ * goods or services; loss of use, data, or profits; or business
+ * interruption) however caused and on any theory of liability, whether
+ * in contract, strict liability, or tort (including negligence or
+ * otherwise) arising in any way out of the use of this software, even
+ * if advised of the possibility of such damage.
+ */
+#include <glib.h>
+#include <glib-object.h>
+
+static void
+test_boxed_garray (void)
+{
+  GArray *a;
+
+  a = g_array_new (FALSE, FALSE, sizeof (gint));
+  g_assert (g_array_get_element_type (a) == G_TYPE_INVALID);
+  g_array_set_element_type (a, G_TYPE_INT);
+  g_assert (g_array_get_element_type (a) == G_TYPE_INT);
+  g_array_unref (a);
+}
+
+int
+main (int   argc,
+      char *argv[])
+{
+  g_thread_init (NULL);
+  g_test_init (&argc, &argv, NULL);
+  g_type_init ();
+
+  g_test_add_func ("/GObject/boxed-garray", test_boxed_garray);
+
+  return g_test_run();
+}
