Создание gtk-сигнала для редактирования GtkWidget, запущенного в другом потоке - PullRequest
0 голосов
/ 15 мая 2018

У меня есть приложение, которое в основном работает в режиме терминала, но оно может открыть свою часть графического интерфейса в другом потоке (простое окно с GtkTextView для распечатки некоторых сообщений).Мне нужно вручную обновить содержимое этого GtkTextView, когда в главном потоке происходит какое-то событие.Для этого я создал 'new-message-receive' сигнал, который должен передавать указатель на массив символов msg с сообщением для печати

Создание нового сигнала:

g_signal_new("new-message-received",
              G_TYPE_OBJECT, G_SIGNAL_RUN_FIRST,
              0, NULL, NULL,
              g_cclosure_marshal_VOID__POINTER,
              G_TYPE_NONE, 1, G_TYPE_POINTER);

Подключение к нему с помощью функции обработчика:

g_signal_connect(G_OBJECT(demo_window), "new-message-received", 
                 G_CALLBACK(print_demo_message),(gpointer)msg);

И испускание сигнала:

if (flag){
memset(msg, 0, 256);
g_signal_emit_by_name(G_OBJECT(demo_window), 
                     "new-message-received", 
                     (gpointer) msg);
...
}

Проблема в том, что обработчик сигнала получает некоторый сломанный указатель (я пытаюсьвыведите его на стандартный вывод - это всегда несколько случайных 4 символов вместо передаваемого сообщения.Обработчик:

void print_demo_message(gpointer *param)
{
    const gchar* message = (const gchar*)param;
    g_print("Got message: %s\n", message);
    ...
}

Выход выглядит так:

Got message: p���

Что я пробовал:

  1. Создание msgглобальная переменная, чтобы избежать повторной инициализации - без результата
  2. Использование универсального маршаллера при создании сигнала - без результата
  3. Передача ссылки на адрес msg вместо указателя на него,тоже никакого результата.

Вопрос - что я делаю не так?

Заранее спасибо.

1 Ответ

0 голосов
/ 22 мая 2018

Пришлось решать это самостоятельно, вообще не было необходимости использовать сигналы.

Основной поток для GTK - это поток, откуда вызывается gtk_main().Доступ к любому объекту GTK вне его основного потока запрещен.Итак, чтобы инициировать поток для графического интерфейса GTK, я использовал g_thread_new() и g_idle_add(print_demo_message, msg), чтобы «попросить» основной поток GTK вставить msg в GtkTextView.

Итак, теперь это выглядит так:

APP MAIN THREAD:

if(%some_condition%){
     msg = malloc(256);
     sprintf(msg, "Some text");
     g_idle_add(print_demo_message, msg);
}

GUI THREAD:

boolean print_demo_message(gpointer data)
{
    gchar* message = data;
    g_print("Got message: %s\n", message);
 ...
}

Сообщение передано нормально, работает как charm:)

...