Matthew
Matthew

Reputation: 3946

Update Gtk+2 text view widget from another thread

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

Answers (1)

Matthew
Matthew

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

Related Questions