diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c
index 80d356d..62c20d8 100644
--- a/gtk/gtktextview.c
+++ b/gtk/gtktextview.c
@@ -131,6 +131,10 @@ enum
   INSERT_AT_CURSOR,
   DELETE_FROM_CURSOR,
   BACKSPACE,
+  INSERT_NEW_LINE,
+  INSERT_LINE_BREAK,
+  INSERT_TAB,
+  INSERT_BACK_TAB,
   CUT_CLIPBOARD,
   COPY_CLIPBOARD,
   PASTE_CLIPBOARD,
@@ -277,6 +281,8 @@ static void gtk_text_view_delete_from_cursor (GtkTextView           *text_view,
                                               GtkDeleteType          type,
                                               gint                   count);
 static void gtk_text_view_backspace        (GtkTextView           *text_view);
+static void gtk_text_view_insert_new_line  (GtkTextView           *text_view);
+static void gtk_text_view_insert_tab       (GtkTextView           *text_view);
 static void gtk_text_view_cut_clipboard    (GtkTextView           *text_view);
 static void gtk_text_view_copy_clipboard   (GtkTextView           *text_view);
 static void gtk_text_view_paste_clipboard  (GtkTextView           *text_view);
@@ -529,6 +535,10 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
   klass->insert_at_cursor = gtk_text_view_insert_at_cursor;
   klass->delete_from_cursor = gtk_text_view_delete_from_cursor;
   klass->backspace = gtk_text_view_backspace;
+  klass->insert_new_line = gtk_text_view_insert_new_line;
+  klass->insert_line_break = gtk_text_view_insert_new_line;
+  klass->insert_tab = gtk_text_view_insert_tab;
+  klass->insert_back_tab = gtk_text_view_insert_tab;
   klass->cut_clipboard = gtk_text_view_cut_clipboard;
   klass->copy_clipboard = gtk_text_view_copy_clipboard;
   klass->paste_clipboard = gtk_text_view_paste_clipboard;
@@ -886,6 +896,96 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
 		  G_TYPE_NONE, 0);
 
   /**
+   * GtkTextView::insert-new-line:
+   * @text_view: the object which received the signal
+   *
+   * The ::insert-new-line signal is a 
+   * <link linkend="keybinding-signals">keybinding signal</link> 
+   * which gets emitted when the user asks for it.
+   * 
+   * The default bindings for this signal are
+   * GDK_Return and GDK_ISO_Enter.
+   *
+   * Since: 2.20
+   */
+  signals[INSERT_NEW_LINE] =
+    g_signal_new (I_("insert-new-line"),
+		  G_OBJECT_CLASS_TYPE (gobject_class),
+		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+		  G_STRUCT_OFFSET (GtkTextViewClass, insert_new_line),
+		  NULL, NULL,
+		  _gtk_marshal_VOID__VOID,
+		  G_TYPE_NONE, 0);
+
+  /**
+   * GtkTextView::insert-line-break:
+   * @text_view: the object which received the signal
+   *
+   * The ::insert-line-break signal is a 
+   * <link linkend="keybinding-signals">keybinding signal</link> 
+   * which gets emitted when the user asks for it.
+   * 
+   * The default binding for this signal is
+   * GDK_KP_Enter.
+   *
+   * Since: 2.20
+   */
+  signals[INSERT_LINE_BREAK] =
+    g_signal_new (I_("insert-line-break"),
+		  G_OBJECT_CLASS_TYPE (gobject_class),
+		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+		  G_STRUCT_OFFSET (GtkTextViewClass, insert_line_break),
+		  NULL, NULL,
+		  _gtk_marshal_VOID__VOID,
+		  G_TYPE_NONE, 0);
+
+  /**
+   * GtkTextView::insert-tab:
+   * @text_view: the object which received the signal
+   *
+   * The ::insert-tab signal is a 
+   * <link linkend="keybinding-signals">keybinding signal</link> 
+   * which gets emitted when the user asks for it.
+   *
+   * The default bindings for this signal are
+   * GDK_Tab and GDK_KP_Tab.
+   *
+   * Since: 2.20
+   */
+  signals[INSERT_TAB] =
+    g_signal_new (I_("insert-tab"),
+		  G_OBJECT_CLASS_TYPE (gobject_class),
+		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+		  G_STRUCT_OFFSET (GtkTextViewClass, insert_tab),
+		  NULL, NULL,
+		  _gtk_marshal_VOID__VOID,
+		  G_TYPE_NONE, 0);
+
+  /**
+   * GtkTextView::insert-back-tab:
+   * @text_view: the object which received the signal
+   *
+   * The ::insert-back-tab signal is a 
+   * <link linkend="keybinding-signals">keybinding signal</link> 
+   * which gets emitted when the user asks for it. The back tab is a
+   * keycap on your tab key. This can be used to unindent a line or the
+   * lines in a selection.
+   *
+   * The default bindings for this signal is
+   * GDK_ISO_Left_Tab.
+   *
+   * Since: 2.20
+   */
+  signals[INSERT_BACK_TAB] =
+    g_signal_new (I_("insert-back-tab"),
+		  G_OBJECT_CLASS_TYPE (gobject_class),
+		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+		  G_STRUCT_OFFSET (GtkTextViewClass, insert_back_tab),
+		  NULL, NULL,
+		  _gtk_marshal_VOID__VOID,
+		  G_TYPE_NONE, 0);
+
+  /**
    * GtkTextView::cut-clipboard:
    * @text_view: the object which received the signal
    *
@@ -1211,6 +1311,51 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_SHIFT_MASK,
 				"backspace", 0);
 
+  gtk_binding_entry_add_signal (binding_set, GDK_Return, 0,
+				"insert-new-line", 0);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0,
+				"insert-new-line", 0);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0,
+				"insert-new-line", 0);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_Return, GDK_SHIFT_MASK,
+				"insert-new-line", 0);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, GDK_SHIFT_MASK,
+				"insert-new-line", 0);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, GDK_SHIFT_MASK,
+				"insert-new-line", 0);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_Return, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
+				"insert-new-line", 0);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
+				"insert-new-line", 0);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
+				"insert-new-line", 0);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_Return, GDK_CONTROL_MASK,
+				"insert-line-break", 0);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, GDK_CONTROL_MASK,
+				"insert-line-break", 0);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, GDK_CONTROL_MASK,
+				"insert-line-break", 0);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_Tab, 0,
+				"insert-tab", 0);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, 0,
+				"insert-tab", 0);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_ISO_Left_Tab, 0,
+				"insert-back-tab", 0);
+
   gtk_binding_entry_add_signal (binding_set, GDK_Delete, GDK_CONTROL_MASK,
 				"delete-from-cursor", 2,
 				G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
@@ -4244,21 +4389,6 @@ gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event)
     {
       retval = TRUE;
     }
-  /* use overall editability not can_insert, more predictable for users */
-  else if (text_view->editable &&
-           (event->keyval == GDK_Return ||
-            event->keyval == GDK_ISO_Enter ||
-            event->keyval == GDK_KP_Enter))
-    {
-      /* this won't actually insert the newline if the cursor isn't
-       * editable
-       */
-      gtk_text_view_reset_im_context (text_view);
-      gtk_text_view_commit_text (text_view, "\n");
-
-      obscure = TRUE;
-      retval = TRUE;
-    }
   /* Pass through Tab as literal tab, unless Control is held down */
   else if ((event->keyval == GDK_Tab ||
             event->keyval == GDK_KP_Tab ||
@@ -4268,13 +4398,7 @@ gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event)
       /* If the text widget isn't editable overall, or if the application
        * has turned off "accepts_tab", move the focus instead
        */
-      if (text_view->accepts_tab && text_view->editable)
-	{
-	  gtk_text_view_reset_im_context (text_view);
-	  gtk_text_view_commit_text (text_view, "\t");
-	  obscure = TRUE;
-	}
-      else
+      if (!text_view->accepts_tab && !text_view->editable)
 	g_signal_emit_by_name (text_view, "move-focus",
                                (event->state & GDK_SHIFT_MASK) ?
                                GTK_DIR_TAB_BACKWARD : GTK_DIR_TAB_FORWARD);
@@ -5767,6 +5891,68 @@ gtk_text_view_backspace (GtkTextView *text_view)
 }
 
 static void
+gtk_text_view_insert_new_line (GtkTextView *text_view)
+{
+  GtkTextIter insert;
+
+  gtk_text_view_reset_im_context (text_view);
+
+  /* A newline added deletes the selection, if one exists */
+  gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
+                                    text_view->editable);
+
+  gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
+                                    &insert,
+                                    gtk_text_buffer_get_insert (get_buffer (text_view)));
+
+  gtk_text_buffer_begin_user_action (get_buffer (text_view));
+
+  gtk_text_buffer_insert_interactive (get_buffer (text_view),
+                                      &insert,
+                                      "\n",
+                                      1,
+                                      text_view->editable);
+
+  gtk_text_buffer_end_user_action (get_buffer (text_view));
+
+  gtk_text_view_set_virtual_cursor_pos (text_view, -1, -1);
+  DV(g_print (G_STRLOC": scrolling onscreen\n"));
+  gtk_text_view_scroll_mark_onscreen (text_view,
+                                      gtk_text_buffer_get_insert (get_buffer (text_view)));
+}
+
+static void
+gtk_text_view_insert_tab (GtkTextView *text_view)
+{
+  GtkTextIter insert;
+
+  gtk_text_view_reset_im_context (text_view);
+
+  /* A newline added deletes the selection, if one exists */
+  gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
+                                    text_view->editable);
+
+  gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
+                                    &insert,
+                                    gtk_text_buffer_get_insert (get_buffer (text_view)));
+
+  gtk_text_buffer_begin_user_action (get_buffer (text_view));
+
+  gtk_text_buffer_insert_interactive (get_buffer (text_view),
+                                      &insert,
+                                      "\t",
+                                      1,
+                                      text_view->editable);
+
+  gtk_text_buffer_end_user_action (get_buffer (text_view));
+
+  gtk_text_view_set_virtual_cursor_pos (text_view, -1, -1);
+  DV(g_print (G_STRLOC": scrolling onscreen\n"));
+  gtk_text_view_scroll_mark_onscreen (text_view,
+                                      gtk_text_buffer_get_insert (get_buffer (text_view)));
+}
+
+static void
 gtk_text_view_cut_clipboard (GtkTextView *text_view)
 {
   GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
diff --git a/gtk/gtktextview.h b/gtk/gtktextview.h
index 2dfe23f..e77e022 100644
--- a/gtk/gtktextview.h
+++ b/gtk/gtktextview.h
@@ -189,6 +189,10 @@ struct _GtkTextViewClass
                                   GtkDeleteType type,
                                   gint          count);
   void (* backspace)             (GtkTextView *text_view);
+  void (* insert_new_line)       (GtkTextView *text_view);
+  void (* insert_line_break)     (GtkTextView *text_view);
+  void (* insert_tab)            (GtkTextView *text_view);
+  void (* insert_back_tab)       (GtkTextView *text_view);
 
   /* cut copy paste */
   void (* cut_clipboard)   (GtkTextView *text_view);
@@ -208,10 +212,6 @@ struct _GtkTextViewClass
   void (*_gtk_reserved1) (void);
   void (*_gtk_reserved2) (void);
   void (*_gtk_reserved3) (void);
-  void (*_gtk_reserved4) (void);
-  void (*_gtk_reserved5) (void);
-  void (*_gtk_reserved6) (void);
-  void (*_gtk_reserved7) (void);
 };
 
 GType          gtk_text_view_get_type              (void) G_GNUC_CONST;
