-wxTextCtrl::wxTextCtrl(void) : streambuf()
-{
-  m_modified = FALSE;
-};
-
-wxTextCtrl::wxTextCtrl( wxWindow *parent, const wxWindowID id, const wxString &value,
-      const wxPoint &pos, const wxSize &size,
-      const int style, const wxString &name ) : streambuf()
-{
-  m_modified = FALSE;
-  Create( parent, id, value, pos, size, style, name );
-};
-
-bool wxTextCtrl::Create( wxWindow *parent, const wxWindowID id, const wxString &value,
-      const wxPoint &pos, const wxSize &size,
-      const int style, const wxString &name )
-{
-  m_needParent = TRUE;
-
-  PreCreation( parent, id, pos, size, style, name );
-
-  if (style & wxTE_MULTILINE)
-    m_widget = gtk_text_new( NULL, NULL );
-  else
-    m_widget = gtk_entry_new();
-
-  wxSize newSize = size;
-  if (newSize.x == -1) newSize.x = 80;
-  if (newSize.y == -1) newSize.y = 26;
-  SetSize( newSize.x, newSize.y );
-
-  PostCreation();
-
-  // we want to be notified about text changes
-  gtk_signal_connect(GTK_OBJECT(m_widget), "changed",
-                     GTK_SIGNAL_FUNC(gtk_text_changed_callback),
-                     (gpointer)this);
-
-  if (!value.IsNull())
-  {
-    gint tmp = 0;
-    gtk_editable_insert_text( GTK_EDITABLE(m_widget), value, value.Length(), &tmp );
-  };
-
-  if (style & wxREADONLY)
-  {
-  }
-  else
-  {
-    if (style & wxTE_MULTILINE) gtk_text_set_editable( GTK_TEXT(m_widget), 1 );
-  };
-
-  Show( TRUE );
-
-  return TRUE;
-};
-
-wxString wxTextCtrl::GetValue(void) const
-{
-  wxString tmp;
-  if (m_windowStyle & wxTE_MULTILINE)
-  {
-    gint len = gtk_text_get_length( GTK_TEXT(m_widget) );
-    tmp = gtk_editable_get_chars( GTK_EDITABLE(m_widget), 0, len );
-  }
-  else
-  {
-    tmp = gtk_entry_get_text( GTK_ENTRY(m_widget) );
-  };
-  return tmp;
-};
-
-void wxTextCtrl::SetValue( const wxString &value )
-{
-  wxString tmp = "";
-  if (!value.IsNull()) tmp = value;
-  if (m_windowStyle & wxTE_MULTILINE)
-  {
-    gint len = gtk_text_get_length( GTK_TEXT(m_widget) );
-    gtk_editable_delete_text( GTK_EDITABLE(m_widget), 0, len );
-    len = 0;
-    gtk_editable_insert_text( GTK_EDITABLE(m_widget), tmp, tmp.Length(), &len );
-  }
-  else
-  {
-    gtk_entry_set_text( GTK_ENTRY(m_widget), tmp );
-  };
-};
+void wxTextCtrl::Init()
+{
+    m_dontMarkDirty =
+    m_modified = false;
+
+    m_countUpdatesToIgnore = 0;
+
+    SetUpdateFont(false);
+
+    m_text = NULL;
+    m_showPositionOnThaw = NULL;
+    m_gdkHandCursor = NULL;
+    m_gdkXTermCursor = NULL;
+}
+
+wxTextCtrl::~wxTextCtrl()
+{
+    if(m_gdkHandCursor)
+        gdk_cursor_unref(m_gdkHandCursor);
+    if(m_gdkXTermCursor)
+        gdk_cursor_unref(m_gdkXTermCursor);
+}
+
+wxTextCtrl::wxTextCtrl( wxWindow *parent,
+                        wxWindowID id,
+                        const wxString &value,
+                        const wxPoint &pos,
+                        const wxSize &size,
+                        long style,
+                        const wxValidator& validator,
+                        const wxString &name )
+{
+    Init();
+
+    Create( parent, id, value, pos, size, style, validator, name );
+}
+
+bool wxTextCtrl::Create( wxWindow *parent,
+                         wxWindowID id,
+                         const wxString &value,
+                         const wxPoint &pos,
+                         const wxSize &size,
+                         long style,
+                         const wxValidator& validator,
+                         const wxString &name )
+{
+    if (!PreCreation( parent, pos, size ) ||
+        !CreateBase( parent, id, pos, size, style, validator, name ))
+    {
+        wxFAIL_MSG( wxT("wxTextCtrl creation failed") );
+        return false;
+    }
+
+    bool multi_line = (style & wxTE_MULTILINE) != 0;
+
+    if (multi_line)
+    {
+        // Create view
+        m_text = gtk_text_view_new();
+
+        m_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(m_text) );
+
+        // create "ShowPosition" marker
+        GtkTextIter iter;
+        gtk_text_buffer_get_start_iter(m_buffer, &iter);
+        gtk_text_buffer_create_mark(m_buffer, "ShowPosition", &iter, true);
+
+        // create scrolled window
+        m_widget = gtk_scrolled_window_new( NULL, NULL );
+        gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( m_widget ),
+                                        GTK_POLICY_AUTOMATIC,
+                                        style & wxTE_NO_VSCROLL
+                                            ? GTK_POLICY_NEVER
+                                            : GTK_POLICY_AUTOMATIC );
+        // for ScrollLines/Pages
+        m_scrollBar[1] = (GtkRange*)((GtkScrolledWindow*)m_widget)->vscrollbar;
+
+        // Insert view into scrolled window
+        gtk_container_add( GTK_CONTAINER(m_widget), m_text );
+
+        GTKSetWrapMode();
+
+        GtkScrolledWindowSetBorder(m_widget, style);
+
+        gtk_widget_add_events( GTK_WIDGET(m_text), GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK );
+
+        GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
+    }
+    else
+    {
+        // a single-line text control: no need for scrollbars
+        m_widget =
+        m_text = gtk_entry_new();
+
+        if (style & wxNO_BORDER)
+            g_object_set (m_text, "has-frame", FALSE, NULL);
+            
+    }
+
+    m_parent->DoAddChild( this );
+
+    m_focusWidget = m_text;
+
+    PostCreation(size);
+
+    if (multi_line)
+    {
+        gtk_widget_show(m_text);
+    }
+
+    // We want to be notified about text changes.
+    if (multi_line)
+    {
+        g_signal_connect (m_buffer, "changed",
+                          G_CALLBACK (gtk_text_changed_callback), this);
+    }
+    else
+    {
+        g_signal_connect (m_text, "changed",
+                          G_CALLBACK (gtk_text_changed_callback), this);
+    }
+
+    if (!value.empty())
+    {
+        SetValue( value );
+    }
+
+    if (style & wxTE_PASSWORD)
+        GTKSetVisibility();
+
+    if (style & wxTE_READONLY)
+        GTKSetEditable();
+
+    // left justification (alignment) is the default anyhow
+    if ( style & (wxTE_RIGHT | wxTE_CENTRE) )
+        GTKSetJustification();
+
+    if (multi_line)
+    {
+        // Handle URLs on multi-line controls with wxTE_AUTO_URL style
+        if (style & wxTE_AUTO_URL)
+        {
+            GtkTextIter start, end;
+            m_gdkHandCursor = gdk_cursor_new(GDK_HAND2);
+            m_gdkXTermCursor = gdk_cursor_new(GDK_XTERM);
+
+            // We create our wxUrl tag here for slight efficiency gain - we
+            // don't have to check for the tag existance in callbacks,
+            // hereby it's guaranteed to exist.
+            gtk_text_buffer_create_tag(m_buffer, "wxUrl",
+                                       "foreground", "blue",
+                                       "underline", PANGO_UNDERLINE_SINGLE,
+                                       NULL);
+
+            // Check for URLs after each text change
+            g_signal_connect_after (m_buffer, "insert_text",
+                                    G_CALLBACK (au_insert_text_callback), this);
+            g_signal_connect_after (m_buffer, "delete_range",
+                                    G_CALLBACK (au_delete_range_callback), this);
+
+            // Block all wxUrl tag applying unless we do it ourselves, in which case we
+            // block this callback temporarily. This takes care of gtk+ internal
+            // gtk_text_buffer_insert_range* calls that would copy our URL tag otherwise,
+            // which is undesired because only a part of the URL might be copied.
+            // The insert-text signal emitted inside it will take care of newly formed
+            // or wholly copied URLs.
+            g_signal_connect (m_buffer, "apply_tag",
+                              G_CALLBACK (au_apply_tag_callback), NULL);
+
+            // Check for URLs in the initial string passed to Create
+            gtk_text_buffer_get_start_iter(m_buffer, &start);
+            gtk_text_buffer_get_end_iter(m_buffer, &end);
+            au_check_range(&start, &end);
+        }
+    }
+    else // single line
+    {
+        // do the right thing with Enter presses depending on whether we have
+        // wxTE_PROCESS_ENTER or not
+        GTKSetActivatesDefault();
+    }
+
+
+    g_signal_connect (m_text, "copy-clipboard",
+                      G_CALLBACK (gtk_copy_clipboard_callback), this);
+    g_signal_connect (m_text, "cut-clipboard",
+                      G_CALLBACK (gtk_cut_clipboard_callback), this);
+    g_signal_connect (m_text, "paste-clipboard",
+                      G_CALLBACK (gtk_paste_clipboard_callback), this);
+
+    m_cursor = wxCursor( wxCURSOR_IBEAM );
+
+    return true;
+}
+
+GtkEditable *wxTextCtrl::GetEditable() const
+{
+    wxCHECK_MSG( IsSingleLine(), NULL, "shouldn't be called for multiline" );
+
+    return GTK_EDITABLE(m_text);
+}
+
+// ----------------------------------------------------------------------------
+// flags handling
+// ----------------------------------------------------------------------------
+
+void wxTextCtrl::GTKSetEditable()
+{
+    gboolean editable = !HasFlag(wxTE_READONLY);
+    if ( IsSingleLine() )
+        gtk_editable_set_editable(GTK_EDITABLE(m_text), editable);
+    else
+        gtk_text_view_set_editable(GTK_TEXT_VIEW(m_text), editable);
+}
+
+void wxTextCtrl::GTKSetVisibility()
+{
+    wxCHECK_RET( IsSingleLine(),
+                 "wxTE_PASSWORD is for single line text controls only" );
+
+    gtk_entry_set_visibility(GTK_ENTRY(m_text), !HasFlag(wxTE_PASSWORD));
+}
+
+void wxTextCtrl::GTKSetActivatesDefault()
+{
+    wxCHECK_RET( IsSingleLine(),
+                 "wxTE_PROCESS_ENTER is for single line text controls only" );
+
+    gtk_entry_set_activates_default(GTK_ENTRY(m_text),
+                                    !HasFlag(wxTE_PROCESS_ENTER));
+}
+
+void wxTextCtrl::GTKSetWrapMode()
+{
+    // no wrapping in single line controls
+    if ( !IsMultiLine() )
+        return;
+
+    // translate wx wrapping style to GTK+
+    GtkWrapMode wrap;
+    if ( HasFlag( wxTE_DONTWRAP ) )
+        wrap = GTK_WRAP_NONE;
+    else if ( HasFlag( wxTE_CHARWRAP ) )
+        wrap = GTK_WRAP_CHAR;
+    else if ( HasFlag( wxTE_WORDWRAP ) )
+        wrap = GTK_WRAP_WORD;
+    else // HasFlag(wxTE_BESTWRAP) always true as wxTE_BESTWRAP == 0
+        wrap = GTK_WRAP_WORD_CHAR;
+
+    gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( m_text ), wrap );
+}
+
+void wxTextCtrl::GTKSetJustification()
+{
+    if ( IsMultiLine() )
+    {
+        GtkJustification just;
+        if ( HasFlag(wxTE_RIGHT) )
+            just = GTK_JUSTIFY_RIGHT;
+        else if ( HasFlag(wxTE_CENTRE) )
+            just = GTK_JUSTIFY_CENTER;
+        else // wxTE_LEFT == 0
+            just = GTK_JUSTIFY_LEFT;
+
+        gtk_text_view_set_justification(GTK_TEXT_VIEW(m_text), just);
+    }
+    else // single line
+    {
+        gfloat align;
+        if ( HasFlag(wxTE_RIGHT) )
+            align = 1.0;
+        else if ( HasFlag(wxTE_CENTRE) )
+            align = 0.5;
+        else // single line
+            align = 0.0;
+
+        gtk_entry_set_alignment(GTK_ENTRY(m_text), align);
+    }
+}
+
+void wxTextCtrl::SetWindowStyleFlag(long style)
+{
+    long styleOld = GetWindowStyleFlag();
+
+    wxTextCtrlBase::SetWindowStyleFlag(style);
+
+    if ( (style & wxTE_READONLY) != (styleOld & wxTE_READONLY) )
+        GTKSetEditable();
+
+    if ( (style & wxTE_PASSWORD) != (styleOld & wxTE_PASSWORD) )
+        GTKSetVisibility();
+
+    if ( (style & wxTE_PROCESS_ENTER) != (styleOld & wxTE_PROCESS_ENTER) )
+        GTKSetActivatesDefault();
+
+    static const long flagsWrap = wxTE_WORDWRAP | wxTE_CHARWRAP | wxTE_DONTWRAP;
+    if ( (style & flagsWrap) != (styleOld & flagsWrap) )
+        GTKSetWrapMode();
+
+    static const long flagsAlign = wxTE_LEFT | wxTE_CENTRE | wxTE_RIGHT;
+    if ( (style & flagsAlign) != (styleOld & flagsAlign) )
+        GTKSetJustification();
+}
+
+// ----------------------------------------------------------------------------
+// control value
+// ----------------------------------------------------------------------------
+
+wxString wxTextCtrl::GetValue() const
+{
+    wxCHECK_MSG( m_text != NULL, wxEmptyString, wxT("invalid text ctrl") );
+
+    if ( IsMultiLine() )
+    {
+        GtkTextIter start;
+        gtk_text_buffer_get_start_iter( m_buffer, &start );
+        GtkTextIter end;
+        gtk_text_buffer_get_end_iter( m_buffer, &end );
+        wxGtkString text(gtk_text_buffer_get_text(m_buffer, &start, &end, true));
+
+        return wxGTK_CONV_BACK(text);
+    }
+    else // single line
+    {
+        return wxTextEntry::GetValue();
+    }
+}
+
+wxFontEncoding wxTextCtrl::GetTextEncoding() const
+{
+    // GTK+ uses UTF-8 internally, we need to convert to it but from which
+    // encoding?
+
+    // first check the default text style (we intentionally don't check the
+    // style for the current position as it doesn't make sense for SetValue())
+    const wxTextAttr& style = GetDefaultStyle();
+    wxFontEncoding enc = style.HasFontEncoding() ? style.GetFontEncoding()
+                                         : wxFONTENCODING_SYSTEM;
+
+    // fall back to the controls font if no style
+    if ( enc == wxFONTENCODING_SYSTEM && m_hasFont )
+        enc = GetFont().GetEncoding();
+
+    return enc;
+}
+
+bool wxTextCtrl::IsEmpty() const
+{
+    if ( IsMultiLine() )
+        return gtk_text_buffer_get_char_count(m_buffer) == 0;
+
+    return wxTextEntry::IsEmpty();
+}
+
+void wxTextCtrl::DoSetValue( const wxString &value, int flags )
+{
+    wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
+
+    m_modified = false;
+
+    if ( !IsMultiLine() )
+    {
+        wxTextEntry::DoSetValue(value, flags);
+        return;
+    }
+
+    wxFontEncoding enc = m_defaultStyle.HasFont()
+                            ? m_defaultStyle.GetFont().GetEncoding()
+                            : wxFONTENCODING_SYSTEM;
+    if ( enc == wxFONTENCODING_SYSTEM )
+        enc = GetTextEncoding();
+
+    const wxCharBuffer buffer(wxGTK_CONV_ENC(value, enc));
+    if ( !buffer )
+    {
+        // see comment in WriteText() as to why we must warn the user about
+        // this
+        wxLogWarning(_("Failed to set text in the text control."));
+        return;
+    }
+
+    if ( !(flags & SetValue_SendEvent) )
+    {
+        EnableTextChangedEvents(false);
+    }
+
+    gtk_text_buffer_set_text( m_buffer, buffer, strlen(buffer) );
+
+    if ( !m_defaultStyle.IsDefault() )
+    {
+        GtkTextIter start, end;
+        gtk_text_buffer_get_bounds( m_buffer, &start, &end );
+        wxGtkTextApplyTagsFromAttr(m_widget, m_buffer, m_defaultStyle,
+                                   &start, &end);
+    }
+
+    if ( !(flags & SetValue_SendEvent) )
+    {
+        EnableTextChangedEvents(true);
+    }
+
+    // This was added after discussion on the list
+    SetInsertionPoint(0);
+}