1.question
It can works if implement the code in on_button_execute()
directly.
But it will throw error if create a thread and implement code in the thread entry.
What happened ? The rookie need your help, please.
2. error message
Gtk:ERROR:../../../gtk/gtktextview.c:4748:gtk_text_view_validate_onscreen: assertion failed: (priv->onscreen_validated)
Bail out! Gtk:ERROR:../../../gtk/gtktextview.c:4748:gtk_text_view_validate_onscreen: assertion failed: (priv->onscreen_validated)
And sometimes it may also be:
(main:23234): Gtk-WARNING **: 23:19:02.356: Invalid text buffer iterator: either the iterator is uninitialized, or the characters/paintables/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
**
Gtk:ERROR:../../../gtk/gtktextview.c:4748:gtk_text_view_validate_onscreen: assertion failed: (priv->onscreen_validated)
Bail out! Gtk:ERROR:../../../gtk/gtktextview.c:4748:gtk_text_view_validate_onscreen: assertion failed: (priv->onscreen_validated)
3. source code
Input apt search ls
and press Enter, which will output lots of text, then you can reproduce this error.
head.h:
#pragma once
#include <gtkmm.h>
#include <iostream>
#include <stdlib.h>
#include <pthread.h>
class TextEditor : public Gtk::Window {
public:
TextEditor();
protected:
void on_button_execute();
Gtk::Box m_vbox_top, m_hbox;
Gtk::TextView m_TextView_output;
Glib::RefPtr<Gtk::TextBuffer> m_refTextBuffer;
Gtk::ScrolledWindow m_ScrolledWindow_output;
Gtk::Entry m_Entry_cmdline;
Gtk::Button m_Button_execute;
pthread_t m_thread_execute;
pthread_mutex_t m_mutex_execute;
private:
static void *thread_entry (void *self_ptr);
};
TextEditor::TextEditor() :
m_vbox_top (Gtk::Orientation::VERTICAL),
m_hbox (Gtk::Orientation::HORIZONTAL),
m_Button_execute ("execute")
{
pthread_mutex_init (&m_mutex_execute, NULL);
set_default_size (640, 480);
set_child (m_vbox_top);
set_default_widget (m_Button_execute);
//m_vbox layout
m_vbox_top.append (m_hbox);
m_vbox_top.append (m_ScrolledWindow_output);
//m_ScrolledWindow_output
m_ScrolledWindow_output.set_child (m_TextView_output);
m_ScrolledWindow_output.set_expand();
//m_hbox layout
m_hbox.append (m_Entry_cmdline);
m_hbox.append (m_Button_execute);
//m_Button_execute
m_Button_execute.signal_clicked().connect (
sigc::mem_fun (*this, &TextEditor::on_button_execute)
);
//m_Entry
m_Entry_cmdline.set_margin (10);
m_Entry_cmdline.set_size_request (400, 20);
m_Entry_cmdline.set_activates_default();
//m_refTextBuffer
m_refTextBuffer = Gtk::TextBuffer::create();
//m_TextView_output
m_TextView_output.set_buffer (m_refTextBuffer);
m_TextView_output.set_expand();
m_TextView_output.set_margin (10);
m_TextView_output.set_editable (false);
}
void *TextEditor::thread_entry (void *self_ptr)
{
auto self = reinterpret_cast<TextEditor *> (self_ptr);
pthread_mutex_lock (&self->m_mutex_execute);
const Glib::ustring cmd = self->m_Entry_cmdline.get_text();
FILE *p_bash = popen (cmd.c_str(), "r");
if (p_bash == NULL) {
std:: cerr << "failed to create process\n";
pthread_exit (NULL);
}
auto text_buf = self->m_refTextBuffer;
text_buf->set_text ("");
char result[4096];
while (fgets (result, sizeof (result), p_bash) != NULL) {
text_buf->insert (text_buf->end(), result);
}
pclose (p_bash);
pthread_mutex_unlock (&self->m_mutex_execute);
return NULL;
}
void TextEditor::on_button_execute()
{
pthread_create (&m_thread_execute, NULL, TextEditor::thread_entry, this);
}
main.cpp:
#include "head.h"
#include <gtkmm/application.h>
int main (int argc, char **argv)
{
auto app = Gtk::Application::create();
return app->make_window_and_run<TextEditor> (argc, argv);
}
4. expectde results
change TextEditor::on_button_execute()
as below and it can work.
void TextEditor::on_button_execute()
{
// pthread_create (&m_thread_execute, NULL, TextEditor::thread_entry, this);
auto self = reinterpret_cast<TextEditor *> (this);
pthread_mutex_lock (&self->m_mutex_execute);
const Glib::ustring cmd = self->m_Entry_cmdline.get_text();
FILE *p_bash = popen (cmd.c_str(), "r");
if (p_bash == NULL) {
std:: cerr << "failed to create process\n";
pthread_exit (NULL);
}
auto text_buf = self->m_refTextBuffer;
text_buf->set_text ("");
char result[4096];
while (fgets (result, sizeof (result), p_bash) != NULL) {
text_buf->insert (text_buf->end(), result);
}
pclose (p_bash);
pthread_mutex_unlock (&self->m_mutex_execute);
}