+    return TRUE;
+}
+
+bool wxTextCtrl::SetStyle( long start, long end, const wxTextAttr& style )
+{
+    if ( m_windowStyle & wxTE_MULTILINE )
+    {
+        if ( style.IsDefault() )
+        {
+            // nothing to do
+            return TRUE;
+        }
+#ifdef __WXGTK20__
+        GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(m_text) );
+        gint l = gtk_text_buffer_get_char_count( text_buffer );
+
+        wxCHECK_MSG( start >= 0 && end <= l, FALSE,
+                     _T("invalid range in wxTextCtrl::SetStyle") );
+
+        GtkTextIter starti, endi;
+        gtk_text_buffer_get_iter_at_offset( text_buffer, &starti, start );
+        gtk_text_buffer_get_iter_at_offset( text_buffer, &endi, end );
+
+        // 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
+        wxTextAttr attr = wxTextAttr::Combine(style, m_defaultStyle, this);
+
+        PangoFontDescription *font_description = attr.HasFont()
+                             ? attr.GetFont().GetNativeFontInfo()->description
+                             : NULL;
+
+        GdkColor *colFg = attr.HasTextColour() ? attr.GetTextColour().GetColor()
+                                               : NULL;
+
+        GdkColor *colBg = attr.HasBackgroundColour()
+                            ? attr.GetBackgroundColour().GetColor()
+                            : NULL;
+
+        GtkTextTag *tag;
+        tag = gtk_text_buffer_create_tag( text_buffer, NULL, "font-desc", font_description,
+                                         "foreground-gdk", colFg,
+                                         "background-gdk", colBg, NULL );
+        gtk_text_buffer_apply_tag( text_buffer, tag, &starti, &endi );
+
+         return TRUE;
+#else
+        // VERY dirty way to do that - removes the required text and re-adds it
+        // with styling (FIXME)
+         
+        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();
+}
+
+void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
+{
+    Paste();
+}
+
+void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
+{
+    Undo();
+}
+
+void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
+{
+    Redo();
+}
+
+void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
+{
+    event.Enable( CanCut() );
+}
+
+void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
+{
+    event.Enable( CanCopy() );
+}
+
+void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
+{
+    event.Enable( CanPaste() );
+}
+
+void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
+{
+    event.Enable( CanUndo() );
+}
+
+void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
+{
+    event.Enable( CanRedo() );
+}
+
+void wxTextCtrl::OnInternalIdle()
+{
+    wxCursor cursor = m_cursor;
+    if (g_globalCursor.Ok()) cursor = g_globalCursor;
+
+    if (cursor.Ok())
+    {
+#ifndef __WXGTK20__
+        GdkWindow *window = (GdkWindow*) NULL;
+        if (HasFlag(wxTE_MULTILINE))
+            window = GTK_TEXT(m_text)->text_area;
+        else
+            window = GTK_ENTRY(m_text)->text_area;
+
+        if (window)
+            gdk_window_set_cursor( window, cursor.GetCursor() );
+
+        if (!g_globalCursor.Ok())
+            cursor = *wxSTANDARD_CURSOR;
+
+        window = m_widget->window;
+        if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
+            gdk_window_set_cursor( window, cursor.GetCursor() );
+#endif
+    }
+
+    if (g_delayedFocus == this)
+    {
+        if (GTK_WIDGET_REALIZED(m_widget))
+        {
+            gtk_widget_grab_focus( m_widget );
+            g_delayedFocus = NULL;
+        }
+    }
+
+    if (wxUpdateUIEvent::CanUpdate(this))
+        UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
+}
+
+wxSize wxTextCtrl::DoGetBestSize() const
+{
+    // FIXME should be different for multi-line controls...
+    wxSize ret( wxControl::DoGetBestSize() );
+    return wxSize(80, ret.y);
+}
+
+// ----------------------------------------------------------------------------
+// freeze/thaw
+// ----------------------------------------------------------------------------
+
+void wxTextCtrl::Freeze()
+{
+#ifndef __WXGTK20__
+    if ( HasFlag(wxTE_MULTILINE) )
+    {
+        gtk_text_freeze(GTK_TEXT(m_text));
+    }
+#endif
+}
+
+void wxTextCtrl::Thaw()
+{
+#ifndef __WXGTK20__
+    if ( HasFlag(wxTE_MULTILINE) )
+    {
+        GTK_TEXT(m_text)->vadj->value = 0.0;
+
+        gtk_text_thaw(GTK_TEXT(m_text));
+    }
+#endif
+}
+
+// ----------------------------------------------------------------------------
+// scrolling
+// ----------------------------------------------------------------------------
+
+GtkAdjustment *wxTextCtrl::GetVAdj() const
+{
+#ifdef __WXGTK20__
+    return NULL;
+#else
+    return HasFlag(wxTE_MULTILINE) ? GTK_TEXT(m_text)->vadj : NULL;
+#endif
+}
+
+bool wxTextCtrl::DoScroll(GtkAdjustment *adj, int diff)
+{
+#ifndef __WXGTK20__
+    float value = adj->value + diff;
+
+    if ( value < 0 )
+        value = 0;
+
+    float upper = adj->upper - adj->page_size;
+    if ( value > upper )
+        value = upper;
+
+    // did we noticeably change the scroll position?
+    if ( fabs(adj->value - value) < 0.2 )
+    {
+        // well, this is what Robert does in wxScrollBar, so it must be good...
+        return FALSE;
+    }
+
+    adj->value = value;
+
+    gtk_signal_emit_by_name(GTK_OBJECT(adj), "value_changed");
+
+#endif
+    return TRUE;
+}
+
+bool wxTextCtrl::ScrollLines(int lines)
+{
+#ifdef __WXGTK20__
+    return FALSE;
+#else
+    GtkAdjustment *adj = GetVAdj();
+    if ( !adj )
+        return FALSE;
+
+    // this is hardcoded to 10 in GTK+ 1.2 (great idea)
+    static const int KEY_SCROLL_PIXELS = 10;
+
+    return DoScroll(adj, lines*KEY_SCROLL_PIXELS);
+#endif
+}
+
+bool wxTextCtrl::ScrollPages(int pages)
+{
+#ifdef __WXGTK20__
+    return FALSE;
+#else
+    GtkAdjustment *adj = GetVAdj();
+    if ( !adj )
+        return FALSE;
+
+    return DoScroll(adj, (int)ceil(pages*adj->page_increment));
+#endif