Index: gtk/gdkcolor.override
===================================================================
--- gtk/gdkcolor.override	(revision 3014)
+++ gtk/gdkcolor.override	(working copy)
@@ -221,6 +221,58 @@
     return result;
 }
 %%
+override-slot GdkColor.tp_repr
+static int
+pygdk_color_to_string_smart(char *buffer, int length, GdkColor *color)
+{
+    /* We use g_snprintf() because PyString_FromFormat() doesn't support %0Nx-like formats
+     * (i.e. with leading zeros).
+     *
+     * Note that numbers here are used so that there is no off-by-one errors in
+     * 'eval(repr(color))', i.e. so that 'eval(repr(color)) == color'.  See
+     * pango_color_parse() for justification of these numbers.  Three-nibble color
+     * components are dimmed unimportant.
+     */
+    if (color->red % 0x1111 == 0 && color->green % 0x1111 == 0 && color->blue % 0x1111 == 0) {
+        return g_snprintf(buffer, length, "#%01x%01x%01x",
+                          color->red / 0x1111, color->green / 0x1111, color->blue / 0x1111);
+    }
+    else if (color->red % 0x0101 == 0 && color->green % 0x0101 == 0 && color->blue % 0x0101 == 0) {
+        return g_snprintf(buffer, length, "#%02x%02x%02x",
+                          color->red / 0x0101, color->green / 0x0101, color->blue / 0x0101);
+    }
+    else {
+        return g_snprintf(buffer, length, "#%04x%04x%04x",
+                          color->red, color->green, color->blue);
+    }
+}
+static PyObject *
+_wrap_gdk_color_tp_repr(PyGBoxed *self)
+{
+    static char buffer[0x40];
+    int length = 0;
+
+    length += g_snprintf(buffer + length, sizeof buffer - length, "%s('", self->ob_type->tp_name);
+    length += pygdk_color_to_string_smart(buffer + length, sizeof buffer - length,
+                                          pyg_boxed_get(self, GdkColor));
+    length += g_snprintf(buffer + length, sizeof buffer - length, "')");
+
+    return PyString_FromStringAndSize(buffer, length);
+}
+%%
+override-slot GdkColor.tp_str
+static PyObject *
+_wrap_gdk_color_tp_str(PyGBoxed *self)
+{
+    /* gtk.gdk.Color has a meaningful informal representation, so we define both __repr__
+     * and __str__, unlike for most other types.
+     */
+    static char buffer[1 + 4*3 + 1];  /* # + at most 4 digits per component + \0 */
+    int length = pygdk_color_to_string_smart(buffer, sizeof buffer, pyg_boxed_get(self, GdkColor));
+
+    return PyString_FromStringAndSize(buffer, length);
+}
+%%
 override gdk_colormap_query_color kwargs
 static PyObject *
 _wrap_gdk_colormap_query_color(PyGObject *self, PyObject *args,
Index: gtk/gdk.override
===================================================================
--- gtk/gdk.override	(revision 3014)
+++ gtk/gdk.override	(working copy)
@@ -503,6 +503,20 @@
     return 0;
 }
 %%
+override-slot GdkCursor.tp_repr
+static PyObject *
+_wrap_gdk_cursor_tp_repr(PyGObject *self)
+{
+    GdkCursor *cursor = pyg_boxed_get(self, GdkCursor);
+    GEnumValue *type = g_enum_get_value(g_type_class_peek(GDK_TYPE_CURSOR_TYPE), cursor->type);
+
+    /* We use <...> syntax because gtk.gdk.Cursor objects are generally impossible to
+     * reconstruct with eval(repr(...))  round-trip. */
+    return PyString_FromFormat("<%s at %p: %s>",
+                               self->ob_type->tp_name, self,
+                               type ? type->value_name : "UNKNOWN TYPE");
+}
+%%
 override gdk_region_get_clipbox noargs
 static PyObject *
 _wrap_gdk_region_get_clipbox(PyGObject *self)
Index: gtk/gdkevent.override
===================================================================
--- gtk/gdkevent.override	(revision 3013)
+++ gtk/gdkevent.override	(working copy)
@@ -918,3 +918,156 @@
     Py_INCREF(Py_None);
     return Py_None;
 }
+%%
+override-slot GdkEvent.tp_repr
+static PyObject *
+_wrap_gdk_event_tp_repr(PyGObject *self)
+{
+    static char buffer[0x400];
+    int length = 0;
+
+    GdkEvent *event = pyg_boxed_get(self, GdkEvent);
+    GEnumValue *type = g_enum_get_value(g_type_class_peek(GDK_TYPE_EVENT_TYPE), event->type);
+
+    length += g_snprintf(buffer + length, sizeof buffer - length, "<%s at %p: %s",
+                         self->ob_type->tp_name, self, type ? type->value_name : "UNKNOWN TYPE");
+
+    /* Depending on event type we will append values of some most important attributes to
+     * representation string.  In any case, this information is not enough to reconstruct
+     * the event object (and in any case gtk.gdk.Event is incapable of doing so),
+     * therefore the <...> syntax.
+     */
+    switch(event->type) {
+    case GDK_NOTHING: break;
+    case GDK_DELETE: break;
+    case GDK_DESTROY: break;
+    case GDK_EXPOSE:
+        {
+            length += g_snprintf(buffer + length, sizeof buffer - length, " area=[%d, %d, %d, %d]",
+                                 event->expose.area.x, event->expose.area.y,
+                                 event->expose.area.width, event->expose.area.height);
+            break;
+        }
+    case GDK_MOTION_NOTIFY:
+        {
+            length += g_snprintf(buffer + length, sizeof buffer - length, " x=%.2f, y=%.2f",
+                                 event->motion.x, event->motion.y);
+            break;
+        }
+    case GDK_BUTTON_PRESS:
+    case GDK_2BUTTON_PRESS:
+    case GDK_3BUTTON_PRESS:
+    case GDK_BUTTON_RELEASE:
+        {
+            length += g_snprintf(buffer + length, sizeof buffer - length,
+                                 " x=%.2f, y=%.2f, button=%d",
+                                 event->button.x, event->button.y, event->button.button);
+            break;
+        }
+    case GDK_KEY_PRESS:
+    case GDK_KEY_RELEASE:
+        {
+            const gchar *key = gdk_keyval_name(event->key.keyval);
+
+            if (key)
+                length += g_snprintf(buffer + length, sizeof buffer - length, " keyval=%s", key);
+            else
+                length += g_snprintf(buffer + length, sizeof buffer - length,
+                                     " keyval=%d", event->key.keyval);
+            break;
+        }
+    case GDK_ENTER_NOTIFY:
+    case GDK_LEAVE_NOTIFY:
+        {
+            GEnumValue *mode = g_enum_get_value(g_type_class_peek(GDK_TYPE_CROSSING_MODE),
+                                                event->crossing.mode);
+            length += g_snprintf(buffer + length, sizeof buffer - length,
+                                 " x=%.2f, y=%.2f, mode=%s",
+                                 event->crossing.x, event->crossing.y,
+                                 mode ? mode->value_name : "UNKNOWN");
+            break;
+        }
+    case GDK_FOCUS_CHANGE: break;
+    case GDK_CONFIGURE:
+        {
+            length += g_snprintf(buffer + length, sizeof buffer - length,
+                                 " x=%d, y=%d, width=%d, height=%d",
+                                 event->configure.x, event->configure.y,
+                                 event->configure.width, event->configure.height);
+            break;
+        }
+    case GDK_MAP: break;
+    case GDK_UNMAP: break;
+    case GDK_PROPERTY_NOTIFY:
+        {
+            length += g_snprintf(buffer + length, sizeof buffer - length, " atom=%s",
+                                 gdk_atom_name(event->property.atom));
+            break;
+        }
+    case GDK_SELECTION_CLEAR:
+    case GDK_SELECTION_REQUEST:
+    case GDK_SELECTION_NOTIFY:
+        {
+            length += g_snprintf(buffer + length, sizeof buffer - length,
+                                 " selection=%s, target=%s, property=%s",
+                                 gdk_atom_name(event->selection.selection),
+                                 gdk_atom_name(event->selection.target),
+                                 gdk_atom_name(event->selection.property));
+            break;
+        }
+    case GDK_PROXIMITY_IN: break;
+    case GDK_PROXIMITY_OUT: break;
+    case GDK_DRAG_ENTER: break;
+    case GDK_DRAG_LEAVE: break;
+    case GDK_DRAG_MOTION: break;
+    case GDK_DRAG_STATUS: break;
+    case GDK_DROP_START: break;
+    case GDK_DROP_FINISHED: break;
+    case GDK_CLIENT_EVENT: break;
+    case GDK_VISIBILITY_NOTIFY:
+        {
+            GEnumValue *state = g_enum_get_value(g_type_class_peek(GDK_TYPE_VISIBILITY_STATE),
+                                                event->visibility.state);
+            length += g_snprintf(buffer + length, sizeof buffer - length,
+                                 " state=%s", state ? state->value_name : "UNKNOWN");
+            break;
+        }
+    case GDK_NO_EXPOSE: break;
+    case GDK_SCROLL:
+        {
+            GEnumValue *direction = g_enum_get_value(g_type_class_peek(GDK_TYPE_SCROLL_DIRECTION),
+                                                     event->scroll.direction);
+            length += g_snprintf(buffer + length, sizeof buffer - length,
+                                 " x=%.2f, y=%.2f, direction=%s",
+                                 event->scroll.x, event->scroll.y,
+                                 direction ? direction->value_name : "UNKNOWN");
+            break;
+        }
+    case GDK_WINDOW_STATE: break;
+    case GDK_SETTING:
+        {
+            GEnumValue *action = g_enum_get_value(g_type_class_peek(GDK_TYPE_SETTING_ACTION),
+                                                  event->setting.action);
+            length += g_snprintf(buffer + length, sizeof buffer - length,
+                                 " action=%s, name=%s",
+                                 action ? action->value_name : "UNKNOWN",
+                                 event->setting.name);
+            break;
+        }
+    case GDK_OWNER_CHANGE:
+        {
+            GEnumValue *reason = g_enum_get_value(g_type_class_peek(GDK_TYPE_OWNER_CHANGE),
+                                                  event->owner_change.reason);
+            length += g_snprintf(buffer + length, sizeof buffer - length,
+                                 " reason=%s, selection=%s",
+                                 reason ? reason->value_name : "UNKNOWN",
+                                 gdk_atom_name(event->owner_change.selection));
+            break;
+        }
+    default:
+        break;
+    }
+
+    length += g_snprintf(buffer + length, sizeof buffer - length, ">");
+    return PyString_FromStringAndSize(buffer, length);
+}
Index: gtk/gdkrectangle.override
===================================================================
--- gtk/gdkrectangle.override	(revision 3014)
+++ gtk/gdkrectangle.override	(working copy)
@@ -247,3 +247,12 @@
     Py_INCREF(result);
     return result;
 }
+%%
+override-slot GdkRectangle.tp_repr
+static PyObject *
+_wrap_gdk_rectangle_tp_repr(PyGBoxed *self)
+{
+    GdkRectangle *rect = pyg_boxed_get(self, GdkRectangle);
+    return PyString_FromFormat("%s(%d, %d, %d, %d)", self->ob_type->tp_name,
+                               rect->x, rect->y, rect->width, rect->height);
+}
Index: docs/reference/pygtk-gdkcolor.xml
===================================================================
--- docs/reference/pygtk-gdkcolor.xml	(revision 3014)
+++ docs/reference/pygtk-gdkcolor.xml	(working copy)
@@ -117,6 +117,16 @@
       the constructor.
     </para>
 
+    <para>
+      Also beginning with PyGTK 2.14 <classname>gtk.gdk.Color</classname> objects have
+      custom support for <function>str</function> and <function>repr</function> Python
+      functions.  For any color it holds that:
+    </para>
+
+    <programlisting>
+  color == eval(repr(color))
+    </programlisting>
+
   </refsect1>
 
   <refsect1 id="constructor-gdkcolor">
@@ -220,6 +230,13 @@
                 where r, g and b are hex digits representing the red,
                 green and blue components respectively.
             </para>
+
+            <note>
+                <para>Starting with PyGTK 2.14 you can also
+                use <literal>str(color)</literal> code.  However, that can return a
+                shorter (3, 6 or 12 hexadecimal digits) string if shorter version means
+                the same for the constructor.</para>
+            </note>
         </refsect2>
     </refsect1>
 
Index: docs/reference/pygtk-gdkevent.xml
===================================================================
--- docs/reference/pygtk-gdkevent.xml	(revision 3013)
+++ docs/reference/pygtk-gdkevent.xml	(working copy)
@@ -1920,6 +1920,17 @@
     <para><literal>gtk.gdk.ALL_EVENTS_MASK</literal> is a combination of all
 the event masks.</para>
 
+    <para>
+      Starting with PyGTK 2.14 <classname>gtk.gdk.Event</classname> objects have custom
+      support for <function>repr</function> Python function.  Text representation will
+      include event type and a few most important event attributes,
+      e.g. <literal>x</literal>, <literal>y</literal> and <literal>button</literal>
+      for <literal>gtk.gdk.BUTTON_PRESS</literal> events.  However, round-tripping
+      through <literal>eval(repr(event))</literal> is not possible: representation string
+      uses <literal>&lt;...&gt;</literal> form.
+    </para>
+
+
   </refsect1>
 
   <refsect1 id="constructor-gdkevent">
Index: docs/reference/pygtk-gdkrectangle.xml
===================================================================
--- docs/reference/pygtk-gdkrectangle.xml	(revision 3014)
+++ docs/reference/pygtk-gdkrectangle.xml	(working copy)
@@ -113,6 +113,16 @@
   rectangle = gtk.gdk.Rectangle(*tuple)
     </programlisting>
 
+    <para>
+      Also beginning with PyGTK 2.14 <classname>gtk.gdk.Rectangle</classname> objects have
+      custom support for <function>repr</function> Python function.  For any rectangle it
+      holds that:
+    </para>
+
+    <programlisting>
+  rectangle == eval(repr(rectangle))
+    </programlisting>
+
   </refsect1>
 
   <refsect1 id="constructor-gdkrectangle">
Index: tests/test_rectangle.py
===================================================================
--- tests/test_rectangle.py	(revision 3014)
+++ tests/test_rectangle.py	(working copy)
@@ -23,6 +23,18 @@
             {} [gtk.gdk.Rectangle()] = 'must raise'
         self.assertRaises(TypeError, dict_key)
 
+    def test_repr(self):
+        for rectangle in self._test_rectangle_list():
+            self.assertEqual(rectangle, eval(repr(rectangle)))
 
+    def _test_rectangle_list(self):
+        return [gtk.gdk.Rectangle(),
+                gtk.gdk.Rectangle(0, 0, 100, 100),
+                gtk.gdk.Rectangle(-10, 10, 30, 50),
+                gtk.gdk.Rectangle(-100, -100, 20, 25),
+                gtk.gdk.Rectangle(0, 0, 0, 20),
+                gtk.gdk.Rectangle(1, 1, 20, 0)]
+
+
 if __name__ == '__main__':
     unittest.main()
Index: tests/test_color.py
===================================================================
--- tests/test_color.py	(revision 3014)
+++ tests/test_color.py	(working copy)
@@ -55,6 +55,25 @@
             {} [gtk.gdk.Color()] = 'must raise'
         self.assertRaises(TypeError, dict_key)
 
+    def test_repr(self):
+        for color in self._test_color_list():
+            self.assertEqual(color, eval(repr(color)))
 
+    def test_str(self):
+        for color in self._test_color_list():
+            self.assertEqual(color, gtk.gdk.Color(str(color)))
+
+    def _test_color_list(self):
+        return [gtk.gdk.Color(),
+                gtk.gdk.Color(10, 20, 30),
+                gtk.gdk.Color(65535, 65535, 65535),
+                gtk.gdk.Color('red'),
+                gtk.gdk.Color('#aaa'),
+                gtk.gdk.Color('#f0a000'),
+                gtk.gdk.Color('#123abcdef'),
+                gtk.gdk.Color('#123412341234'),
+                gtk.gdk.Color('#fedcfedcfedc')]
+
+
 if __name__ == '__main__':
     unittest.main()
