diff --git a/gtk/gtkbuilder.c b/gtk/gtkbuilder.c
index fe15875..2de3d51 100644
--- a/gtk/gtkbuilder.c
+++ b/gtk/gtkbuilder.c
@@ -134,6 +134,13 @@
  * object has to be constructed before it can be used as the value of
  * a construct-only property.
  *
+ * It is also possible to define the value of a property by binding it to
+ * another property with a &lt;binding&gt; element. This causes the value
+ * of the property specified with the "to" attribute to be whatever the
+ * property "from" of object "source" is set to, even if that property
+ * is later set to another value. For more information about the property
+ * binding mechanism, see #GBinding (which GTK+ uses internally).
+ *
  * Signal handlers are set up with the <signal> element. The “name”
  * attribute specifies the name of the signal, and the “handler” attribute
  * specifies the function to connect to the signal. By default, GTK+ tries
@@ -244,6 +251,7 @@ struct _GtkBuilderPrivate
   GHashTable *callbacks;
   GSList *delayed_properties;
   GSList *signals;
+  GSList *bindings;
   gchar *filename;
   gchar *resource_prefix;
   GType template_type;
@@ -313,6 +321,9 @@ gtk_builder_finalize (GObject *object)
 
   g_slist_foreach (priv->signals, (GFunc) _free_signal_info, NULL);
   g_slist_free (priv->signals);
+
+  g_slist_foreach (priv->bindings, (GFunc) _free_binding_info, NULL);
+  g_slist_free (priv->bindings);
   
   G_OBJECT_CLASS (gtk_builder_parent_class)->finalize (object);
 }
@@ -855,15 +866,20 @@ _gtk_builder_add_signals (GtkBuilder *builder,
                                            g_slist_copy (signals));
 }
 
+void
+_gtk_builder_add_bindings (GtkBuilder *builder,
+			   GSList     *bindings)
+{
+  builder->priv->bindings = g_slist_concat (builder->priv->bindings,
+					    g_slist_copy (bindings));
+}
+
 static void
 gtk_builder_apply_delayed_properties (GtkBuilder *builder)
 {
   GSList *l, *props;
   DelayedProperty *property;
   GObject *object;
-  GType object_type;
-  GObjectClass *oclass;
-  GParamSpec *pspec;
 
   /* take the list over from the builder->priv.
    *
@@ -876,43 +892,73 @@ gtk_builder_apply_delayed_properties (GtkBuilder *builder)
   for (l = props; l; l = l->next)
     {
       property = (DelayedProperty*)l->data;
-      object = g_hash_table_lookup (builder->priv->objects, property->object);
+      object = gtk_builder_get_object (builder, property->object);
       g_assert (object != NULL);
 
-      object_type = G_OBJECT_TYPE (object);
-      g_assert (object_type != G_TYPE_INVALID);
-
-      oclass = g_type_class_ref (object_type);
-      g_assert (oclass != NULL);
-
-      pspec = g_object_class_find_property (G_OBJECT_CLASS (oclass),
-                                            property->name);
-      if (!pspec)
-        g_warning ("Unknown property: %s.%s", g_type_name (object_type),
-                   property->name);
-      else
+      if (g_object_class_find_property (G_OBJECT_GET_CLASS (object),
+					property->name))
         {
-          GObject *obj;
+          GObject *obj = gtk_builder_get_object (builder, property->value);
 
-          obj = g_hash_table_lookup (builder->priv->objects, property->value);
-          if (!obj)
-            g_warning ("No object called: %s", property->value);
-          else
+          if (obj)
             g_object_set (object, property->name, obj, NULL);
+          else
+            g_warning ("No object called: %s", property->value);
         }
+      else
+        g_warning ("Unknown property: %s.%s", 
+                   G_OBJECT_TYPE_NAME (object),
+                   property->name);
+      
       g_free (property->value);
       g_free (property->object);
       g_free (property->name);
       g_slice_free (DelayedProperty, property);
-      g_type_class_unref (oclass);
     }
   g_slist_free (props);
 }
 
+static void
+gtk_builder_create_bindings (GtkBuilder *builder)
+{
+  GSList *l;
+
+  for (l = builder->priv->bindings; l; l = g_slist_next (l))
+    {
+      BindingInfo *binding = l->data;
+      GObject *target, *source;
+
+      target = gtk_builder_get_object (builder, binding->object_name);
+      source = gtk_builder_get_object (builder, binding->source);
+
+      if (!target && !source)
+        g_warning ("Could not find target '%s' nor source '%s' to bind '%s' property to '%s'",
+                   binding->object_name, binding->source, binding->from, binding->to);
+      else if (!target)
+        g_warning ("Could not find target '%s' to bind '%s' property to '%s'",
+                   binding->object_name, binding->from, binding->to);
+      else if (!source)
+        g_warning ("Could not find source '%s' to bind '%s' property to '%s'",
+                   binding->source, binding->from, binding->to);
+      else
+        {
+          g_object_bind_property (source, binding->from,
+                                  target, binding->to,
+                                  G_BINDING_SYNC_CREATE);
+        }
+
+      _free_binding_info (binding, NULL);
+    }
+
+  g_slist_free (builder->priv->bindings);
+  builder->priv->bindings = NULL;
+}
+
 void
 _gtk_builder_finish (GtkBuilder *builder)
 {
   gtk_builder_apply_delayed_properties (builder);
+  gtk_builder_create_bindings (builder);
 }
 
 /**
diff --git a/gtk/gtkbuilder.rnc b/gtk/gtkbuilder.rnc
index 6e3aea3..9c284f4 100644
--- a/gtk/gtkbuilder.rnc
+++ b/gtk/gtkbuilder.rnc
@@ -13,7 +13,7 @@ object = element object {
   attribute class { text },
   attribute type-func { text } ?,
   attribute constructor { text } ?,
-  (property | signal | child | ANY) *
+  (property | signal | binding | child | ANY) *
 }
 
 template = element template {
@@ -40,6 +40,12 @@ signal = element signal {
   empty
 }
 
+binding = element binding {
+  attribute to { text },
+  attribute from { text },
+  attribute source { text }
+}
+
 child = element child {
   attribute type { text } ?,
   attribute internal-child { text } ?,
diff --git a/gtk/gtkbuilder.rng b/gtk/gtkbuilder.rng
index 341d19f..815a96f 100644
--- a/gtk/gtkbuilder.rng
+++ b/gtk/gtkbuilder.rng
@@ -51,6 +51,7 @@
         <choice>
           <ref name="property"/>
           <ref name="signal"/>
+          <ref name="binding"/>
           <ref name="child"/>
           <ref name="ANY"/>
         </choice>
@@ -134,6 +135,20 @@
       <empty/>
     </element>
   </define>
+  <define name="binding">
+    <element name="binding">
+      <attribute name="to">
+        <text/>
+      </attribute>
+      <attribute name="from">
+        <text/>
+      </attribute>
+      <attribute name="source">
+        <text/>
+      </attribute>
+      <empty/>
+    </element>
+  </define>
   <define name="child">
     <element name="child">
       <optional>
diff --git a/gtk/gtkbuilderparser.c b/gtk/gtkbuilderparser.c
index cab2176..131f8f7 100644
--- a/gtk/gtkbuilderparser.c
+++ b/gtk/gtkbuilderparser.c
@@ -644,6 +644,67 @@ parse_property (ParserData   *data,
 }
 
 static void
+parse_binding (ParserData   *data,
+               const gchar  *element_name,
+               const gchar **names,
+               const gchar **values,
+               GError      **error)
+{
+  BindingInfo *info;
+  const gchar *to = NULL;
+  const gchar *from = NULL;
+  const gchar *source = NULL;
+  ObjectInfo *object_info;
+  int i;
+  
+  object_info = state_peek_info (data, ObjectInfo);
+  if (!object_info || strcmp (object_info->tag.name, "object") != 0)
+    {
+      error_invalid_tag (data, element_name, NULL, error);
+      return;
+    }
+
+  for (i = 0; names[i] != NULL; i++)
+    {
+      if (strcmp (names[i], "to") == 0)
+	to = values[i];
+      else if (strcmp (names[i], "from") == 0)
+	from = values[i];
+      else if (strcmp (names[i], "source") == 0)
+	source = values[i];
+      else
+	{
+	  error_invalid_attribute (data, element_name, names[i], error);
+	  return;
+	}
+    }
+
+  if (!to)
+    {
+      error_missing_attribute (data, element_name, "to", error);
+      return;
+    }
+  if (!from)
+    {
+      error_missing_attribute (data, element_name, "from", error);
+      return;
+    }
+  if (!source)
+    {
+      error_missing_attribute (data, element_name, "source", error);
+      return;
+    }
+
+  info = g_slice_new0 (BindingInfo);
+  info->to = g_strdup (to);
+  info->from = g_strdup (from);
+  info->source = g_strdup (source);
+  state_push (data, info);
+
+  info->tag.name = element_name;
+}
+
+static void
 free_property_info (PropertyInfo *info)
 {
   g_free (info->data);
@@ -746,6 +807,17 @@ _free_signal_info (SignalInfo *info,
   g_slice_free (SignalInfo, info);
 }
 
+void
+_free_binding_info (BindingInfo *info,
+                    gpointer user_data)
+{
+  g_free (info->object_name);
+  g_free (info->to);
+  g_free (info->from);
+  g_free (info->source);
+  g_slice_free (BindingInfo, info);
+}
+
 static void
 free_requires_info (RequiresInfo *info,
                     gpointer user_data)
@@ -994,6 +1066,8 @@ start_element (GMarkupParseContext *context,
     parse_child (data, element_name, names, values, error);
   else if (strcmp (element_name, "property") == 0)
     parse_property (data, element_name, names, values, error);
+  else if (strcmp (element_name, "binding") == 0)
+    parse_binding (data, element_name, names, values, error);
   else if (strcmp (element_name, "signal") == 0)
     parse_signal (data, element_name, names, values, error);
   else if (strcmp (element_name, "interface") == 0)
@@ -1085,6 +1159,49 @@ end_element (GMarkupParseContext *context,
     {
       ObjectInfo *object_info = state_pop_info (data, ObjectInfo);
       ChildInfo* child_info = state_peek_info (data, ChildInfo);
+      GSList *l;
+
+      /* Check for conflicting property binding definitions and
+       * conflicts between property binding and value definitions.
+       */
+      for (l = object_info->bindings; l; l = l->next)
+        {
+          BindingInfo *b = (BindingInfo*)l->data;
+          GSList *l2;
+
+          for (l2 = object_info->bindings; l2; l2 = l2->next)
+            {
+              BindingInfo *b2 = (BindingInfo*)l2->data;
+              if (b != b2 && !strcmp (b->to, b2->to))
+                {
+                  g_set_error (error,
+                               GTK_BUILDER_ERROR,
+                               GTK_BUILDER_ERROR_INVALID_VALUE,
+                               "Duplicate binding for property: `%s'",
+                               b->to);
+                  break;
+                }
+            }
+
+          /* If we broke out of the last loop, we already found an error */
+          if (l2)
+            break;
+
+          for (l2 = object_info->properties; l2; l2 = l2->next)
+            {
+              PropertyInfo *p = (PropertyInfo*)l2->data;
+              if (!strcmp (b->to, p->name))
+                {
+                  g_set_error (error,
+                               GTK_BUILDER_ERROR,
+                               GTK_BUILDER_ERROR_INVALID_VALUE,
+                               "Value supplied for property defined as "
+                               "bound: `%s'",
+                               b->to);
+                  break;
+                }
+            }
+        }
 
       if (data->requested_objects && data->inside_requested_object &&
           (data->cur_object_level == data->requested_object_level))
@@ -1112,6 +1229,7 @@ end_element (GMarkupParseContext *context,
           GTK_BUILDABLE_GET_IFACE (object_info->object)->parser_finished)
         data->finalizers = g_slist_prepend (data->finalizers, object_info->object);
       _gtk_builder_add_signals (data->builder, object_info->signals);
+      _gtk_builder_add_bindings (data->builder, object_info->bindings);
 
       free_object_info (object_info);
     }
@@ -1160,6 +1278,15 @@ end_element (GMarkupParseContext *context,
       object_info->signals =
         g_slist_prepend (object_info->signals, signal_info);
     }
+  else if (strcmp (element_name, "binding") == 0)
+    {
+      BindingInfo *binding_info = state_pop_info (data, BindingInfo);
+      ObjectInfo *object_info = (ObjectInfo*)state_peek_info (data, CommonInfo);
+
+      binding_info->object_name = g_strdup (object_info->id);
+      object_info->bindings =
+        g_slist_prepend (object_info->bindings, binding_info);
+    }
   else if (strcmp (element_name, "placeholder") == 0)
     {
     }
diff --git a/gtk/gtkbuilderprivate.h b/gtk/gtkbuilderprivate.h
index b653373..329d978 100644
--- a/gtk/gtkbuilderprivate.h
+++ b/gtk/gtkbuilderprivate.h
@@ -36,6 +36,7 @@ typedef struct {
   gchar *constructor;
   GSList *properties;
   GSList *signals;
+  GSList *bindings;
   GObject *object;
   CommonInfo *parent;
   gboolean applied_properties;
@@ -69,6 +70,14 @@ typedef struct {
 typedef struct {
   TagInfo tag;
   gchar *object_name;
+  gchar *to;
+  gchar *from;
+  gchar *source;
+} BindingInfo;
+
+typedef struct {
+  TagInfo tag;
+  gchar *object_name;
   gchar *name;
   gchar *handler;
   GConnectFlags flags;
@@ -134,9 +143,13 @@ void      _gtk_builder_add (GtkBuilder *builder,
                             ChildInfo *child_info);
 void      _gtk_builder_add_signals (GtkBuilder *builder,
 				    GSList     *signals);
+void      _gtk_builder_add_bindings (GtkBuilder  *builder,
+				     GSList      *bindings);
 void      _gtk_builder_finish (GtkBuilder *builder);
-void _free_signal_info (SignalInfo *info,
-                        gpointer user_data);
+void      _free_signal_info (SignalInfo *info,
+                             gpointer user_data);
+void      _free_binding_info (BindingInfo *info,
+                              gpointer user_data);
 
 /* Internal API which might be made public at some point */
 gboolean _gtk_builder_boolean_from_string (const gchar  *string,
diff --git a/testsuite/gtk/builder.c b/testsuite/gtk/builder.c
index 43a0441..aded7df 100644
--- a/testsuite/gtk/builder.c
+++ b/testsuite/gtk/builder.c
@@ -2777,6 +2777,54 @@ test_no_ids (void)
   g_object_unref (builder);
 }
 
+static void
+test_property_bindings (void)
+{
+  const gchar *buffer =
+    "<interface>"
+    "  <object class=\"GtkWindow\" id=\"window\">"
+    "    <child>"
+    "      <object class=\"GtkVBox\" id=\"vbox\">"
+    "        <property name=\"visible\">True</property>"
+    "        <property name=\"orientation\">vertical</property>"
+    "        <child>"
+    "          <object class=\"GtkCheckButton\" id=\"checkbutton\">"
+    "            <property name=\"active\">false</property>"
+    "          </object>"
+    "        </child>"
+    "        <child>"
+    "          <object class=\"GtkButton\" id=\"button\">"
+    "            <binding to=\"sensitive\" from=\"active\" source=\"checkbutton\"/>"
+    "          </object>"
+    "        </child>"
+    "      </object>"
+    "    </child>"
+    "  </object>"
+    "</interface>";
+
+  GtkBuilder *builder;
+  GObject *checkbutton, *button, *window;
+  
+  builder = builder_new_from_string (buffer, -1, NULL);
+  
+  checkbutton = gtk_builder_get_object (builder, "checkbutton");
+  g_assert (checkbutton != NULL);
+  g_assert (GTK_IS_CHECK_BUTTON (checkbutton));
+  g_assert (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbutton)));
+
+  button = gtk_builder_get_object (builder, "button");
+  g_assert (button != NULL);
+  g_assert (GTK_IS_BUTTON (button));
+  g_assert (!gtk_widget_get_sensitive (GTK_WIDGET (button)));
+
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), TRUE);
+  g_assert (gtk_widget_get_sensitive (GTK_WIDGET (button)));
+  
+  window = gtk_builder_get_object (builder, "window");
+  gtk_widget_destroy (GTK_WIDGET (window));
+  g_object_unref (builder);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -2827,6 +2875,7 @@ main (int argc, char **argv)
   g_test_add_func ("/Builder/LevelBar", test_level_bar);
   g_test_add_func ("/Builder/Expose Object", test_expose_object);
   g_test_add_func ("/Builder/No IDs", test_no_ids);
+  g_test_add_func ("/Builder/Property Bindings", test_property_bindings);
 
   return g_test_run();
 }
