+    wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
+
+    gtk_editable_delete_text( GTK_EDITABLE(m_text), (gint)from, (gint)to );
+
+    if (!value.IsEmpty())
+    {
+        gint pos = (gint)from;
+#if wxUSE_UNICODE
+        wxWX2MBbuf buf = value.mbc_str();
+        gtk_editable_insert_text( GTK_EDITABLE(m_text), buf, strlen(buf), &pos );
+#else
+        gtk_editable_insert_text( GTK_EDITABLE(m_text), value, value.Length(), &pos );
+#endif
+    }
+}
+
+void wxTextCtrl::Cut()
+{
+    wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
+
+#if (GTK_MINOR_VERSION > 0)
+    gtk_editable_cut_clipboard( GTK_EDITABLE(m_text) );
+#else
+    gtk_editable_cut_clipboard( GTK_EDITABLE(m_text), 0 );
+#endif
+}
+
+void wxTextCtrl::Copy()
+{
+    wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
+
+#if (GTK_MINOR_VERSION > 0)
+    gtk_editable_copy_clipboard( GTK_EDITABLE(m_text) );
+#else
+    gtk_editable_copy_clipboard( GTK_EDITABLE(m_text), 0 );
+#endif
+}
+
+void wxTextCtrl::Paste()
+{
+    wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
+
+#if (GTK_MINOR_VERSION > 0)
+    gtk_editable_paste_clipboard( GTK_EDITABLE(m_text) );
+#else
+    gtk_editable_paste_clipboard( GTK_EDITABLE(m_text), 0 );
+#endif
+}
+
+bool wxTextCtrl::CanCopy() const
+{
+    // Can copy if there's a selection
+    long from, to;
+    GetSelection(& from, & to);
+    return (from != to) ;
+}
+
+bool wxTextCtrl::CanCut() const
+{
+    // Can cut if there's a selection
+    long from, to;
+    GetSelection(& from, & to);
+    return (from != to) ;
+}
+
+bool wxTextCtrl::CanPaste() const
+{
+    return IsEditable() ;
+}
+
+// Undo/redo
+void wxTextCtrl::Undo()
+{
+    // TODO
+    wxFAIL_MSG( wxT("wxTextCtrl::Undo not implemented") );
+}
+
+void wxTextCtrl::Redo()
+{
+    // TODO
+    wxFAIL_MSG( wxT("wxTextCtrl::Redo not implemented") );
+}
+
+bool wxTextCtrl::CanUndo() const
+{
+    // TODO
+    wxFAIL_MSG( wxT("wxTextCtrl::CanUndo not implemented") );
+    return FALSE;
+}
+
+bool wxTextCtrl::CanRedo() const
+{
+    // TODO
+    wxFAIL_MSG( wxT("wxTextCtrl::CanRedo not implemented") );
+    return FALSE;
+}
+
+// If the return values from and to are the same, there is no
+// selection.
+void wxTextCtrl::GetSelection(long* from, long* to) const
+{
+    wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
+
+    if (!(GTK_EDITABLE(m_text)->has_selection))
+    {
+        if (from) *from = 0;
+        if (to)   *to = 0;
+        return;
+    }
+
+    if (from) *from = (long) GTK_EDITABLE(m_text)->selection_start_pos;
+    if (to)   *to = (long) GTK_EDITABLE(m_text)->selection_end_pos;
+}
+
+bool wxTextCtrl::IsEditable() const
+{
+    wxCHECK_MSG( m_text != NULL, FALSE, wxT("invalid text ctrl") );
+
+    return GTK_EDITABLE(m_text)->editable;
+}
+
+bool wxTextCtrl::IsModified() const
+{
+    return m_modified;
+}
+
+void wxTextCtrl::Clear()
+{
+    SetValue( wxT("") );
+}
+
+void wxTextCtrl::OnChar( wxKeyEvent &key_event )
+{
+    wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
+
+    if ((key_event.KeyCode() == WXK_RETURN) && (m_windowStyle & wxPROCESS_ENTER))
+    {
+        wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
+        event.SetEventObject(this);
+        if (GetEventHandler()->ProcessEvent(event)) return;
+    }
+
+    key_event.Skip();
+}
+
+GtkWidget* wxTextCtrl::GetConnectWidget()
+{
+    return GTK_WIDGET(m_text);
+}