Reputation: 3946
I am writing a chat client in GTK. The client has the main GTK loop, plus a spawned thread that sits and blocks at the read()
function waiting for input from a file descriptor connected to a socket.
Once the read function gets past the blocking, it has a char buffer of text that I would like to append to the GTK Text View widget, however, this is in a thread that is different than the main GTK loop.
How can I most quickly update the GUI from that other thread? In Java, I would have used the SwingUtilities.invokeLater(new Runnable())
method to cause that method to be called from the main thread. I want similar behavior in C and using GTK.
Here is the function that is called from the new thread...
void* messageReceived(void* data)
{
struct ClientWindow* localVar = (struct ClientWindow*)data;
while(TRUE)
{
char buf[256];
int bytesRead = read(localVar->socketFileDescriptor, buf, 256);
GtkTextBuffer* tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(localVar->chatHistoryTextView));
GtkTextIter end;
//This code needs to execute in the main thread
gtk_text_buffer_get_end_iter(tb, &end);
gtk_text_buffer_insert(tb, &end, buf, -1);
}
}
Upvotes: 3
Views: 380
Reputation: 3946
The solution I came up with is using the g_idle_add()
function. I don't know if I am missing something because the solution is very simple but no one else identified it, so it makes me a bit worried.
void* messageReceived(void* data)
{
struct ClientWindow* localVar = (struct ClientWindow*)data;
char* message = NULL;
int bytesRead = 0;
do
{
message = bufferedRead(localVar->socketFileDescriptor, 4, &bytesRead);
struct UpdateGUIMessage* updateGui = malloc(sizeof(struct UpdateGUIMessage));
memset(updateGui, 0, sizeof(struct UpdateGUIMessage));
updateGui->clientWindow = localVar;
updateGui->message = message;
updateGui->bytesRead = bytesRead;
g_idle_add(G_SOURCE_FUNC(updateGUI), updateGui);
}while(message != NULL);
}
bool updateGUI(void* data)
{
struct UpdateGUIMessage* localVar = (struct UpdateGUIMessage*)data;
GtkTextBuffer* tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(localVar->clientWindow->chatHistoryTextView));
GtkTextIter end;
gtk_text_buffer_get_end_iter(tb, &end);
gtk_text_buffer_insert(tb, &end, localVar->message, localVar->bytesRead);
free(localVar->message);
free(data);
return FALSE; //So it only gets called once and then is removed
}
Upvotes: 3