]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/textctrl.cpp
don't handle orderly socket shutdown by the peer as an error (patch 1688222)
[wxWidgets.git] / src / gtk / textctrl.cpp
index 48dbbd95a28f6ba36e21988c620834c09e6b987f..4fc49796fb41df88ab1dc1899c154ba9b7f67770 100644 (file)
@@ -51,7 +51,6 @@ static void wxGtkOnRemoveTag(GtkTextBuffer *buffer,
 }
 }
 
-extern "C" {
 static void wxGtkTextApplyTagsFromAttr(GtkWidget *text,
                                        GtkTextBuffer *text_buffer,
                                        const wxTextAttr& attr,
@@ -260,9 +259,7 @@ static void wxGtkTextApplyTagsFromAttr(GtkWidget *text,
         gtk_text_buffer_apply_tag (text_buffer, tag, &para_start, &para_end);
     }
 }
-}
 
-extern "C" {
 static void wxGtkTextInsert(GtkWidget *text,
                             GtkTextBuffer *text_buffer,
                             const wxTextAttr& attr,
@@ -281,7 +278,6 @@ static void wxGtkTextInsert(GtkWidget *text,
 
     wxGtkTextApplyTagsFromAttr(text, text_buffer, attr, &start, &iter);
 }
-}
 
 // ----------------------------------------------------------------------------
 // "insert_text" for GtkEntry
@@ -651,7 +647,8 @@ void wxTextCtrl::Init()
     SetUpdateFont(false);
 
     m_text = NULL;
-    m_frozenness = 0;
+    m_freezeCount = 0;
+    m_showPositionOnThaw = NULL;
     m_gdkHandCursor = NULL;
     m_gdkXTermCursor = NULL;
 }
@@ -688,7 +685,6 @@ bool wxTextCtrl::Create( wxWindow *parent,
                          const wxString &name )
 {
     m_needParent = true;
-    m_acceptsFocus = true;
 
     if (!PreCreation( parent, pos, size ) ||
         !CreateBase( parent, id, pos, size, style, validator, name ))
@@ -706,38 +702,25 @@ bool wxTextCtrl::Create( wxWindow *parent,
 
         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, GTK_POLICY_AUTOMATIC );
+                                        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 );
 
-        // 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
-        {
-            // GTK_WRAP_WORD_CHAR seems to be new in GTK+ 2.4
-#ifdef __WXGTK24__
-            if ( !gtk_check_version(2,4,0) )
-            {
-                wrap = GTK_WRAP_WORD_CHAR;
-            }
-            else
-#endif
-            wrap = GTK_WRAP_WORD;
-        }
-
-        gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( m_text ), wrap );
+        GTKSetWrapMode();
 
         GtkScrolledWindowSetBorder(m_widget, style);
 
@@ -772,40 +755,14 @@ bool wxTextCtrl::Create( wxWindow *parent,
     }
 
     if (style & wxTE_PASSWORD)
-    {
-        if (!multi_line)
-            gtk_entry_set_visibility( GTK_ENTRY(m_text), FALSE );
-    }
+        GTKSetVisibility();
 
     if (style & wxTE_READONLY)
-    {
-        if (!multi_line)
-            gtk_editable_set_editable( GTK_EDITABLE(m_text), FALSE );
-        else
-            gtk_text_view_set_editable( GTK_TEXT_VIEW( m_text), FALSE);
-    }
+        GTKSetEditable();
 
-    if (multi_line)
-    {
-        if (style & wxTE_RIGHT)
-            gtk_text_view_set_justification( GTK_TEXT_VIEW(m_text), GTK_JUSTIFY_RIGHT );
-        else if (style & wxTE_CENTRE)
-            gtk_text_view_set_justification( GTK_TEXT_VIEW(m_text), GTK_JUSTIFY_CENTER );
-        // Left justify (alignment) is the default and we don't need to apply GTK_JUSTIFY_LEFT
-    }
-    else
-    {
-#ifdef __WXGTK24__
-        // gtk_entry_set_alignment was introduced in gtk+-2.3.5
-        if (!gtk_check_version(2,4,0))
-        {
-            if (style & wxTE_RIGHT)
-                gtk_entry_set_alignment( GTK_ENTRY(m_text), 1.0 );
-            else if (style & wxTE_CENTRE)
-                gtk_entry_set_alignment( GTK_ENTRY(m_text), 0.5 );
-        }
-#endif
-    }
+    // left justification (alignment) is the default anyhow
+    if ( style & (wxTE_RIGHT | wxTE_CENTRE) )
+        GTKSetJustification();
 
     // We want to be notified about text changes.
     if (multi_line)
@@ -870,11 +827,116 @@ bool wxTextCtrl::Create( wxWindow *parent,
     return true;
 }
 
+// ----------------------------------------------------------------------------
+// flags handling
+// ----------------------------------------------------------------------------
 
-void wxTextCtrl::CalculateScrollbar()
+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()
+{
+    // VZ: shouldn't we assert if wxTE_PASSWORD is set for multiline control?
+    if ( IsSingleLine() )
+        gtk_entry_set_visibility(GTK_ENTRY(m_text), !HasFlag(wxTE_PASSWORD));
+}
+
+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
+    {
+        // GTK_WRAP_WORD_CHAR seems to be new in GTK+ 2.4
+#ifdef __WXGTK24__
+        if ( !gtk_check_version(2,4,0) )
+        {
+            wrap = GTK_WRAP_WORD_CHAR;
+        }
+        else
+#endif // __WXGTK24__
+        wrap = GTK_WRAP_WORD;
+    }
+
+    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
+    {
+#ifdef __WXGTK24__
+        // gtk_entry_set_alignment was introduced in gtk+-2.3.5
+        if (!gtk_check_version(2,4,0))
+        {
+            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);
+        }
+#endif // __WXGTK24__
+    }
+
+}
+
+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();
+
+    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") );
@@ -940,7 +1002,13 @@ void wxTextCtrl::DoSetValue( const wxString &value, int flags )
     m_modified = false;
     DontMarkDirtyOnNextChange();
 
-    const wxCharBuffer buffer(wxGTK_CONV_ENC(value, GetTextEncoding()));
+    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
@@ -961,6 +1029,14 @@ void wxTextCtrl::DoSetValue( const wxString &value, int flags )
     if ( IsMultiLine() )
     {
         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);
+        }
     }
     else // single line
     {
@@ -1024,7 +1100,8 @@ void wxTextCtrl::WriteText( const wxString &text )
 
         GtkAdjustment *adj = gtk_scrolled_window_get_vadjustment( GTK_SCROLLED_WINDOW(m_widget) );
         // Scroll to cursor, but only if scrollbar thumb is at the very bottom
-        if ( wxIsSameDouble(adj->value, adj->upper - adj->page_size) )
+        // won't work when frozen, text view is not using m_buffer then
+        if (!IsFrozen() && wxIsSameDouble(adj->value, adj->upper - adj->page_size))
         {
             gtk_text_view_scroll_to_mark( GTK_TEXT_VIEW(m_text),
                     gtk_text_buffer_get_insert( m_buffer ), 0.0, FALSE, 0.0, 1.0 );
@@ -1170,11 +1247,12 @@ void wxTextCtrl::SetInsertionPoint( long pos )
         GtkTextIter iter;
         gtk_text_buffer_get_iter_at_offset( m_buffer, &iter, pos );
         gtk_text_buffer_place_cursor( m_buffer, &iter );
-        gtk_text_view_scroll_mark_onscreen
-        (
-            GTK_TEXT_VIEW(m_text),
-            gtk_text_buffer_get_insert( m_buffer )
-        );
+        GtkTextMark* mark = gtk_text_buffer_get_insert(m_buffer);
+        if (IsFrozen())
+            // defer until Thaw, text view is not using m_buffer now
+            m_showPositionOnThaw = mark;
+        else
+            gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(m_text), mark);
     }
     else
     {
@@ -1185,18 +1263,7 @@ void wxTextCtrl::SetInsertionPoint( long pos )
 
 void wxTextCtrl::SetInsertionPointEnd()
 {
-    wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
-
-    if ( IsMultiLine() )
-    {
-        GtkTextIter end;
-        gtk_text_buffer_get_end_iter( m_buffer, &end );
-        gtk_text_buffer_place_cursor( m_buffer, &end );
-    }
-    else
-    {
-        gtk_editable_set_position( GTK_EDITABLE(m_text), -1 );
-    }
+    SetInsertionPoint(-1);
 }
 
 void wxTextCtrl::SetEditable( bool editable )
@@ -1234,9 +1301,9 @@ bool wxTextCtrl::Enable( bool enable )
 }
 
 // wxGTK-specific: called recursively by Enable,
-// to give widgets an oppprtunity to correct their colours after they
+// to give widgets an opportunity to correct their colours after they
 // have been changed by Enable
-void wxTextCtrl::OnParentEnable( bool enable )
+void wxTextCtrl::OnEnabled( bool enable )
 {
     // If we have a custom background colour, we use this colour in both
     // disabled and enabled mode, or we end up with a different colour under the
@@ -1346,13 +1413,17 @@ void wxTextCtrl::SetSelection( long from, long to )
 
 void wxTextCtrl::ShowPosition( long pos )
 {
-    if ( IsMultiLine() )
+    if (IsMultiLine())
     {
         GtkTextIter iter;
-        gtk_text_buffer_get_start_iter( m_buffer, &iter );
-        gtk_text_iter_set_offset( &iter, pos );
-        GtkTextMark *mark = gtk_text_buffer_create_mark( m_buffer, NULL, &iter, TRUE );
-        gtk_text_view_scroll_to_mark( GTK_TEXT_VIEW(m_text), mark, 0.0, FALSE, 0.0, 0.0 );
+        gtk_text_buffer_get_iter_at_offset(m_buffer, &iter, int(pos));
+        GtkTextMark* mark = gtk_text_buffer_get_mark(m_buffer, "ShowPosition");
+        gtk_text_buffer_move_mark(m_buffer, mark, &iter);
+        if (IsFrozen())
+            // defer until Thaw, text view is not using m_buffer now
+            m_showPositionOnThaw = mark;
+        else
+            gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(m_text), mark);
     }
 }
 
@@ -1815,9 +1886,11 @@ wxSize wxTextCtrl::DoGetBestSize() const
 
 void wxTextCtrl::Freeze()
 {
+    wxCHECK_RET(m_text != NULL, wxT("invalid text ctrl"));
+
     if ( HasFlag(wxTE_MULTILINE) )
     {
-        if ( !m_frozenness++ )
+        if (m_freezeCount++ == 0)
         {
             // freeze textview updates and remove buffer
             g_signal_connect (m_text, "expose_event",
@@ -1827,9 +1900,16 @@ void wxTextCtrl::Freeze()
             gtk_widget_set_sensitive(m_widget, false);
             g_object_ref(m_buffer);
             GtkTextBuffer* buf_new = gtk_text_buffer_new(NULL);
+            GtkTextMark* mark = GTK_TEXT_VIEW(m_text)->first_para_mark;
             gtk_text_view_set_buffer(GTK_TEXT_VIEW(m_text), buf_new);
-            // FIXME: this leaks the new buffer, since gtk_text_view_set_buffer
-            // adds its own reference, but unrefing it here can cause a crash later
+            // gtk_text_view_set_buffer adds its own reference
+            g_object_unref(buf_new);
+            // This mark should be deleted when the buffer is changed,
+            // but it's not (in GTK+ up to at least 2.10.6).
+            // Otherwise these anonymous marks start to build up in the buffer,
+            // and Freeze takes longer and longer each time it is called.
+            if (GTK_IS_TEXT_MARK(mark) && !gtk_text_mark_get_deleted(mark))
+                gtk_text_buffer_delete_mark(m_buffer, mark);
         }
     }
 }
@@ -1838,9 +1918,9 @@ void wxTextCtrl::Thaw()
 {
     if ( HasFlag(wxTE_MULTILINE) )
     {
-        wxASSERT_MSG( m_frozenness > 0, _T("Thaw() without matching Freeze()") );
+        wxCHECK_RET(m_freezeCount != 0, _T("Thaw() without matching Freeze()"));
 
-        if ( !--m_frozenness )
+        if (--m_freezeCount == 0)
         {
             // Reattach buffer and thaw textview updates
             gtk_text_view_set_buffer(GTK_TEXT_VIEW(m_text), m_buffer);
@@ -1850,6 +1930,12 @@ void wxTextCtrl::Thaw()
                     (gpointer) gtk_text_exposed_callback, this);
             g_signal_handlers_disconnect_by_func (m_text,
                     (gpointer) gtk_text_exposed_callback, this);
+            if (m_showPositionOnThaw != NULL)
+            {
+                gtk_text_view_scroll_mark_onscreen(
+                    GTK_TEXT_VIEW(m_text), m_showPositionOnThaw);
+                m_showPositionOnThaw = NULL;
+            }
         }
     }
 }