Обновление Gtk + 2 виджета текстового представления из другого потока - PullRequest
0 голосов
/ 24 апреля 2019

Я пишу чат-клиент в GTK. У клиента есть основной цикл GTK, плюс порожденный поток, который сидит и блокирует функцию read(), ожидая ввода из файлового дескриптора, подключенного к сокету.

Как только функция чтения преодолевает блокировку, она имеет буфер текста, который я хотел бы добавить в виджет GTK Text View, однако он находится в потоке, который отличается от основного цикла GTK.

Как я могу наиболее быстро обновить GUI из этого другого потока? В Java я бы использовал метод SwingUtilities.invokeLater(new Runnable()), чтобы вызвать этот метод из основного потока. Я хочу подобное поведение в C и с использованием GTK.

Вот функция, которая вызывается из нового потока ...

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);

    }
}

1 Ответ

0 голосов
/ 27 апреля 2019

Решением, которое я придумал, является использование функции g_idle_add().Я не знаю, упускаю ли я что-то, потому что решение очень простое, но никто не определил его, поэтому меня это немного беспокоит.

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
}
...