Gtk +3 TextView application crashes

1.4k Views Asked by At

I have an application using a GtkTextView and GtkTextBuffer. Lines are added to the buffer with the following python code which runs in a separate thread from the main process:

    while True:     
        if aLogQueue.qsize() > 0:
            aBuffer = aLogTextView.get_buffer()
            try:
                newLogMessage = aLogQueue.get_nowait()
                ipri = int(newLogMessage[0])                    
                if(ipri>=self.ListenLogMinPr):
                    aniter = aBuffer.get_iter_at_line(0)
                    aBuffer.insert(aniter, newLogMessage) 
                    #mark = aBuffer.get_mark('insert') 
                    #aniter = aBuffer.get_iter_at_mark(mark)
                    #aBuffer.place_cursor(aniter)
                pass
            except:
                print('threw exception in message loop')  
                self.gui_shutdown()  

aLogQueue is a queue of one-line ASCII text messages.

The application works for a while, but then invariably crashes with the following error

Gtk:ERROR:gtktextview.c:4328:gtk_text_view_validate_onscreen: assertion failed: (priv->onscreen_validated)

Note that I am inserting at line 0, so the fact that iterators are destroyed by the insert call should have no effect.

It writes between 20 and 200 lines before failing. It does not appear to be related to writing off the edge of the text buffer and scroll bars appear when expected.

Any suggestions?

2

There are 2 best solutions below

0
On

You cannot access the GtkTextBuffer — or any part of GTK+, for that matter — from a separate thread. You must access it from the GUI thread. You will need to use GLib.idle_add() to queue the buffer update on the GUI thread.

0
On

I was confused by the doc I found for GLib because GLib.idle_add does not accept an timeout. http://lazka.github.io/pgi-docs/index.html#GLib-2.0/functions.html#GLib.idle_add

But without timeout it is working for me using Python 2.7.12 and Gtk 3.20

Create a function for text insert:

   def set_text(self, text):
    textbuffer = self.textview.get_buffer()
    textbuffer.set_text(text, len(text))

   def append_text(self, text:
    oldtext = self.get_text()
    newtext = "{}\n{}".format(oldtext, text)
    self.set_text(newtext)

Then you can set new text with:

GLib.idle_add(self.textbox.append_text, "I am the new text line)  

Additional Info:

While the script is running I also check sensitivity of button with:

def on_search_button_clicked(self, widget)
    widget.set_sensitive(False)
    thread = Thread(target=self.run_search_script)
    thread.start()
    GObject.timeout_add(200, self.sensi, thread, widget)

def sensi(self, thread, widget):
    return True if thread.is_alive() else widget.set_sensitive(True)