wxTextCtrl multiline/GTK implementing max length

104 views
Skip to first unread message

Zbigniew Zagórski

unread,
Oct 4, 2012, 3:04:24 AM10/4/12
to wx-u...@googlegroups.com
Hi,

I really need to implement "max length" in multiline wxTextCtrl on GTK.

Documentation says:
  Note that in wxGTK this function may only be used with single line 
  text controls.

I am wondering why, i can't find any mail thread from past that discusses why 
is complex/impossible.

So i've tried to implement First try:

    Bind(wxEVT_COMMAND_TEXT_UPDATED,
          &eagent_messenger_message_dlg::on_text_change, 
          this);
    (...)
    void on_text_change(wxCommandEvent& ev)
    {
        wxString s = this->main_text_ctrl->GetValue();
        if( s.size() > 100 ) {
            s = s.substr(0,100);
            this->main_text_ctrl->SetValue(s); HERE!!!
        }

    }

I've tried also with "Remove" (in same code): 

    this->main_text_ctrl->Remove(max, 
        this->main_text_ctrl->GetLastPosition());

I've tried also doing it directly via GTK in wxTextCtrl:

bool wxTextCtrl::Create( wxWindow *parent,...)
{
   (...)
    g_signal_connect(G_OBJECT( m_buffer ), "changed", 
        G_CALLBACK( textview_buffer_changed_callback ), this );
}

void textview_buffer_changed_callback (
   GtkTextBuffer  *buffer,
   gpointer        user_data)
{
   (...)
    if( current_buffer_length > MAX_BUFFER_LENGTH {
        GtkTextIter start;
        GtkTextIter end;
        gtk_text_buffer_get_iter_at_offset( buffer,
                                         &start,
                                         MAX_BUFFER_LENGTH  ); 
        gtk_text_buffer_get_iter_at_offset( buffer,
                                         &end,
                                         current_buffer_length );

        gtk_text_buffer_delete( buffer, &start, &end );
    }
}

Everything crashes in more or less same manner:

First, GTK asserts:

(messenger:10788): Gtk-WARNING **: Invalid text buffer iterator: either the 
iterator is 
uninitialized, or the characters/pixbufs/widgets in the buffer have been 
modified since the iterator was created.
You must use marks, character numbers, or line numbers to preserve a position
across buffer modifications.
You can apply tags and insert marks without invalidating your iterators,
but any mutation that affects 'indexable' buffer contents (contents that can
be referred to by character offset)
will invalidate all outstanding iterators

Then *au_insert_text_callback* tries to dereference invalid iterator:

Program received signal SIGSEGV, Segmentation fault.
0x003175af in ?? () from /usr/lib/libgtk-x11-2.0.so.0
(gdb) bt
#1  0x0031aa10 in gtk_text_iter_backward_chars () 
    from /usr/lib/libgtk-x11-2.0.so.0
#2  0x080e5590 in au_insert_text_callback (end=0xbfffeab8, text=0x8374d10 "this->
    main_text_ctrl->GetValue();", len=33, win=0x827adc0) at 
    ./src/gtk/textctrl.cpp:477
#3  0x002668b6 in ?? () from /usr/lib/libgtk-x11-2.0.so.0
(...)
#31 0x0095392b in g_main_loop_run () from /lib/i386-linux-gnu/libglib-2.0.so.0
#32 0x00261c39 in gtk_main () from /usr/lib/libgtk-x11-2.0.so.0
#33 0x08135e79 in wxGUIEventLoop::Run (this=0x83100f0) at 
    ./src/gtk/evtloop.cpp:60
#34 0x080e0915 in wxDialog::ShowModal (this=0x8241018) at 
    ./src/gtk/dialog.cpp:133
#35 0x0806a31f in eagent_messenger_app::OnInit (this=0x8206a38) at  
    messages/messenger.c


Now the issue: what i am missing here, i don't understand fully 
"wxGTK event architecture" but it looks like GTK "changed" and 
wxEVT_COMMAND_TEXT_UPDATED are spawned with queue full of other 
signals already queued. And moreover, those signals contain gtk text 
buffer iterators which are invalidated by my operation (be it SetValue, 
Remove, gtk_text_buffer_delete).

Any ideas where shall continue searching for solution ?

Now i will try randomly:
1) disabling URL highliht
2) trying to fix au_insert_text_callback, so it doesn't dereference received 
iterator
3) reorder/cancel queued signals ? is this possible ?

BR,
 Zbyszek 

Zbigniew Zagórski

unread,
Oct 4, 2012, 3:15:15 AM10/4/12
to wx-u...@googlegroups.com
On Thursday, October 4, 2012 9:04:24 AM UTC+2, Zbigniew Zagórski wrote:
Hi,

(...)
So i've tried to implement First try:

    Bind(wxEVT_COMMAND_TEXT_UPDATED,
          &eagent_messenger_message_dlg::on_text_change, 
          this);
    (...)
    void on_text_change(wxCommandEvent& ev)
    {
        wxString s = this->main_text_ctrl->GetValue();
        if( s.size() > 100 ) {
            s = s.substr(0,100);
            this->main_text_ctrl->SetValue(s); HERE!!!
        }

    }

(...)
First, GTK asserts:

(messenger:10788): Gtk-WARNING **: Invalid text buffer iterator: either the 
iterator is 
uninitialized, or the characters/pixbufs/widgets in the buffer have been 
modified since the iterator was created.
You must use marks, character numbers, or line numbers to preserve a position
across buffer modifications.
You can apply tags and insert marks without invalidating your iterators,
but any mutation that affects 'indexable' buffer contents (contents that can
be referred to by character offset)
will invalidate all outstanding iterators

Then *au_insert_text_callback* tries to dereference invalid iterator:

Program received signal SIGSEGV, Segmentation fault.
0x003175af in ?? () from /usr/lib/libgtk-x11-2.0.so.0
(...)
 
Now i will try randomly:
1) disabling URL highliht
2) trying to fix au_insert_text_callback, so it doesn't dereference received 
iterator
3) reorder/cancel queued signals ? is this possible ?


Quick update:
Disabling wxTE_AUTO_URL fixes the crash (both Remove(MAX, current_size) and ChangeValue() work and sucessfullly limit length of text in control.

(BTW, i am using wxWidgets-2.9.4, minimal (as minimal as it gets), gtk: 2.24.4-0ubuntu2)

Nevertheless the issue of queued "au_insert_text_callback" with created iterators remains ... :)

Best regards,
 Zbyszek
 

Vadim Zeitlin

unread,
Oct 4, 2012, 6:56:51 AM10/4/12
to wx-u...@googlegroups.com
On Thu, 4 Oct 2012 00:04:24 -0700 (PDT) Zbigniew Zagórski wrote:

ZZ> I really need to implement "max length" in multiline wxTextCtrl on GTK.
ZZ>
ZZ> Documentation says:
ZZ> Note that in wxGTK this function may only be used with single line
ZZ> text controls.
ZZ>
ZZ> I am wondering why, i can't find any mail thread from past that discusses
ZZ> why is complex/impossible.

Simply because gtk_entry_set_max_length() only works for GtkEntry, not
GtkTextView. And I don't think GtkTextView has insert-text signal neither.

ZZ> Any ideas where shall continue searching for solution ?

First of all, it definitely needs to be done inside wxGTK. Whatever you do
it in your program won't work 100% correctly. Although I think that the
crash in your approach is simply related to a stack overflow, because you
call SetValue() which generates wxEVT_COMMAND_TEXT_UPDATED, from the
handler for this event itself, it still wouldn't work well even if you used
ChangeValue().

As for how to do this at GtkTextView level, I'm not sure but a quick web
search finds a lot of suggestions. Here is one:

http://stackoverflow.com/questions/2791035/how-do-i-set-buffer-limit-for-gtk-text-view-in-c

Good luck,
VZ

--
TT-Solutions: wxWidgets consultancy and technical support
http://www.tt-solutions.com/
Reply all
Reply to author
Forward
0 new messages