+    wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
+
+#ifndef __WXGTK20__
+    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
+    }
+#endif
+}
+
+void wxTextCtrl::Cut()
+{
+    wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
+
+#ifndef __WXGTK20__
+    gtk_editable_cut_clipboard( GTK_EDITABLE(m_text) DUMMY_CLIPBOARD_ARG );
+#endif
+}
+
+void wxTextCtrl::Copy()
+{
+    wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
+
+#ifndef __WXGTK20__
+    gtk_editable_copy_clipboard( GTK_EDITABLE(m_text) DUMMY_CLIPBOARD_ARG );
+#endif
+}
+
+void wxTextCtrl::Paste()
+{
+    wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
+
+#ifndef __WXGTK20__
+    gtk_editable_paste_clipboard( GTK_EDITABLE(m_text) DUMMY_CLIPBOARD_ARG );
+#endif
+}
+
+// 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* fromOut, long* toOut) const
+{
+    wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
+
+    gint from, to;
+#ifdef __WXGTK20__
+    if ( !gtk_editable_get_selection_bounds(GTK_EDITABLE(m_text), &from, &to) )
+#else
+    if ( !(GTK_EDITABLE(m_text)->has_selection) )
+#endif
+    {
+        from =
+        to = GetInsertionPoint();
+    }
+    else // got selection
+    {
+#ifndef __WXGTK20__
+        from = (long) GTK_EDITABLE(m_text)->selection_start_pos;
+        to = (long) GTK_EDITABLE(m_text)->selection_end_pos;
+#endif
+
+        if ( from > to )
+        {
+            // exchange them to be compatible with wxMSW
+            gint tmp = from;
+            from = to;
+            to = tmp;
+        }
+    }
+
+    if ( fromOut )
+        *fromOut = from;
+    if ( toOut )
+        *toOut = to;
+}
+
+bool wxTextCtrl::IsEditable() const
+{
+    wxCHECK_MSG( m_text != NULL, FALSE, wxT("invalid text ctrl") );
+
+#ifdef __WXGTK20__
+    return gtk_editable_get_editable(GTK_EDITABLE(m_text));
+#else
+    return GTK_EDITABLE(m_text)->editable;
+#endif
+}
+
+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);
+        event.SetString(GetValue());
+        if (GetEventHandler()->ProcessEvent(event)) return;
+    }
+
+    if ((key_event.KeyCode() == WXK_RETURN) && !(m_windowStyle & wxTE_MULTILINE))
+    {
+        // This will invoke the dialog default action, such
+        // as the clicking the default button.
+
+        wxWindow *top_frame = m_parent;
+        while (top_frame->GetParent() && !(top_frame->IsTopLevel()))
+            top_frame = top_frame->GetParent();
+
+        if (top_frame && GTK_IS_WINDOW(top_frame->m_widget))
+        {
+            GtkWindow *window = GTK_WINDOW(top_frame->m_widget);
+
+            if (window->default_widget)
+            {
+                gtk_widget_activate (window->default_widget);
+                return;
+            }
+        }
+    }
+
+    key_event.Skip();
+}
+
+GtkWidget* wxTextCtrl::GetConnectWidget()
+{
+    return GTK_WIDGET(m_text);
+}
+
+bool wxTextCtrl::IsOwnGtkWindow( GdkWindow *window )
+{
+    if (m_windowStyle & wxTE_MULTILINE)
+    {
+#ifdef __WXGTK20__
+        return window == gtk_text_view_get_window( GTK_TEXT_VIEW( m_text ), GTK_TEXT_WINDOW_TEXT );  // pure guesswork
+#else
+        return (window == GTK_TEXT(m_text)->text_area);
+#endif
+    }
+    else
+    {
+        return (window == GTK_ENTRY(m_text)->text_area);
+    }
+}
+
+// the font will change for subsequent text insertiongs
+bool wxTextCtrl::SetFont( const wxFont &font )
+{
+    wxCHECK_MSG( m_text != NULL, FALSE, wxT("invalid text ctrl") );
+
+    if ( !wxTextCtrlBase::SetFont(font) )
+    {
+        // font didn't change, nothing to do
+        return FALSE;
+    }
+
+    if ( m_windowStyle & wxTE_MULTILINE )
+    {
+        m_updateFont = TRUE;
+
+        m_defaultStyle.SetFont(font);
+
+        ChangeFontGlobally();
+    }
+
+    return TRUE;
+}
+
+void wxTextCtrl::ChangeFontGlobally()
+{
+    // this method is very inefficient and hence should be called as rarely as
+    // possible!
+    wxASSERT_MSG( (m_windowStyle & wxTE_MULTILINE) && m_updateFont,
+                  _T("shouldn't be called for single line controls") );
+
+    wxString value = GetValue();
+    if ( !value.IsEmpty() )
+    {
+        m_updateFont = FALSE;
+
+        Clear();
+        AppendText(value);
+    }
+}
+
+void wxTextCtrl::UpdateFontIfNeeded()
+{
+    if ( m_updateFont )
+        ChangeFontGlobally();
+}
+
+bool wxTextCtrl::SetForegroundColour(const wxColour& colour)
+{
+    if ( !wxControl::SetForegroundColour(colour) )
+        return FALSE;
+
+    // update default fg colour too
+    m_defaultStyle.SetTextColour(colour);
+
+    return TRUE;
+}
+
+bool wxTextCtrl::SetBackgroundColour( const wxColour &colour )
+{
+    wxCHECK_MSG( m_text != NULL, FALSE, wxT("invalid text ctrl") );
+
+    if ( !wxControl::SetBackgroundColour( colour ) )
+        return FALSE;
+
+    if (!m_widget->window)
+        return FALSE;
+
+    wxColour sysbg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
+    if (sysbg.Red() == colour.Red() &&
+        sysbg.Green() == colour.Green() &&
+        sysbg.Blue() == colour.Blue())
+    {
+        return FALSE; // FIXME or TRUE?
+    }
+
+    if (!m_backgroundColour.Ok())
+        return FALSE;
+
+    if (m_windowStyle & wxTE_MULTILINE)
+    {
+#ifndef __WXGTK20__
+        GdkWindow *window = GTK_TEXT(m_text)->text_area;
+        if (!window)
+            return FALSE;
+        m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
+        gdk_window_set_background( window, m_backgroundColour.GetColor() );
+        gdk_window_clear( window );
+#endif
+    }
+
+    // change active background color too
+    m_defaultStyle.SetBackgroundColour( colour );
+
+    return TRUE;
+}
+
+bool wxTextCtrl::SetStyle( long start, long end, const wxTextAttr& style )
+{
+    /* VERY dirty way to do that - removes the required text and re-adds it
+       with styling (FIXME) */
+    if ( m_windowStyle & wxTE_MULTILINE )
+    {
+#ifndef __WXGTK20__
+        if ( style.IsDefault() )
+        {
+            // nothing to do
+            return TRUE;
+        }
+
+        gint l = gtk_text_get_length( GTK_TEXT(m_text) );
+
+        wxCHECK_MSG( start >= 0 && end <= l, FALSE,
+                     _T("invalid range in wxTextCtrl::SetStyle") );
+
+        gint old_pos = gtk_editable_get_position( GTK_EDITABLE(m_text) );
+        char *text = gtk_editable_get_chars( GTK_EDITABLE(m_text), start, end );
+        wxString tmp(text,*wxConvCurrent);
+        g_free( text );
+
+        gtk_editable_delete_text( GTK_EDITABLE(m_text), start, end );
+        gtk_editable_set_position( GTK_EDITABLE(m_text), start );
+
+#if wxUSE_UNICODE
+        wxWX2MBbuf buf = tmp.mbc_str();
+        const char *txt = buf;
+        size_t txtlen = strlen(buf);
+#else
+        const char *txt = tmp;
+        size_t txtlen = tmp.length();
+#endif
+
+        // use the attributes from style which are set in it and fall back
+        // first to the default style and then to the text control default
+        // colours for the others
+        wxGtkTextInsert(m_text,
+                        wxTextAttr::Combine(style, m_defaultStyle, this),
+                        txt,
+                        txtlen);
+
+        /* does not seem to help under GTK+ 1.2 !!!
+        gtk_editable_set_position( GTK_EDITABLE(m_text), old_pos ); */
+        SetInsertionPoint( old_pos );
+#endif
+        return TRUE;
+    }
+    else // singe line
+    {
+        // cannot do this for GTK+'s Entry widget
+        return FALSE;
+    }
+}
+
+void wxTextCtrl::ApplyWidgetStyle()
+{
+    if (m_windowStyle & wxTE_MULTILINE)
+    {
+        // how ?
+    }
+    else
+    {
+        SetWidgetStyle();
+        gtk_widget_set_style( m_text, m_widgetStyle );
+    }
+}
+
+void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
+{
+    Cut();
+}
+
+void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
+{
+    Copy();
+}