Си и libappindicator - создание нескольких индикаторов

Я программирую простой индикатор, который должен отображать значок для каждого ядра процессора на панели Unity, который будет менять цвет в зависимости от температурного диапазона.

Это потребовало бы от меня иметь более одного AppIndicator в одной и той же программе, поскольку я думаю, что нет способа иметь один AppIndicator с несколькими значками или использовать gtk_container для их хранения и добавления в AppIndicator. Я на самом деле пытаюсь использовать 1 AppIndicator для меню (с опцией "Quit") и 1 AppIndicator для каждого ядра процессора.

Программа не имела предупреждений Gtk только с одним AppIndicator (основным), но после того, как я добавил код для создания двух других AppIndicator для каждого ядра CPU (оба с разными уникальными идентификаторами), Gtk начал выдавать некоторые предупреждения и критические сообщения. Индикаторы отображаются на панели точно так, как они должны, но я не хочу просто игнорировать эти сообщения, поскольку они могут скрывать некоторые реальные проблемы под занавесом.

Проверка кода, единственное, что я думаю, может вызвать эти предупреждения и критические сообщения app_indicator_new() будучи вызванным несколько раз, я фактически удалил все подпрограммы создания menu и menu_item для этих дополнительных индикаторов, оставив только app_indicator_new() позвоните, и я все еще получаю эти сообщения (по одному на каждый дополнительный app_indicator_new() звони после первого):

(process:8040): Gtk-CRITICAL **: IA__gtk_icon_theme_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed

(process:8040): GLib-GObject-WARNING **: invalid (NULL) pointer instance

(process:8040): GLib-GObject-CRITICAL **: g_signal_connect_data: assertion 'G_TYPE_CHECK_INSTANCE (instance)' failed

Когда я добавляю код в создаваемое меню и связываю его с дополнительным AppIndicator, появляются некоторые дополнительные ошибки:

(process:8681): GLib-GObject-WARNING **: invalid (NULL) pointer instance

(process:8681): GLib-GObject-CRITICAL **: g_signal_connect_data: assertion 'G_TYPE_CHECK_INSTANCE (instance)' failed

(process:8681): Gtk-CRITICAL **: IA__gtk_icon_theme_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed

(process:8681): GLib-GObject-WARNING **: invalid (NULL) pointer instance

(process:8681): GLib-GObject-CRITICAL **: g_signal_connect_data: assertion 'G_TYPE_CHECK_INSTANCE (instance)' failed

(process:8681): Gtk-CRITICAL **: IA__gtk_settings_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed

(process:8681): GLib-GObject-CRITICAL **: g_object_ref: assertion 'G_IS_OBJECT (object)' failed

(process:8681): GLib-GObject-WARNING **: invalid (NULL) pointer instance

(process:8681): GLib-GObject-CRITICAL **: g_signal_connect_data: assertion 'G_TYPE_CHECK_INSTANCE (instance)' failed

(process:8681): Gtk-CRITICAL **: IA__gtk_settings_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed

(process:8681): GLib-GObject-WARNING **: invalid (NULL) pointer instance

(process:8681): GLib-GObject-CRITICAL **: g_signal_connect_data: assertion 'G_TYPE_CHECK_INSTANCE (instance)' failed

(process:8681): Gtk-CRITICAL **: IA__gtk_icon_theme_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed

(process:8681): GLib-GObject-WARNING **: invalid (NULL) pointer instance

(process:8681): GLib-GObject-CRITICAL **: g_signal_connect_data: assertion 'G_TYPE_CHECK_INSTANCE (instance)' failed

(process:8681): Gtk-CRITICAL **: IA__gtk_settings_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed

(process:8681): GLib-GObject-CRITICAL **: g_object_ref: assertion 'G_IS_OBJECT (object)' failed

(process:8681): GLib-GObject-WARNING **: invalid (NULL) pointer instance

(process:8681): GLib-GObject-CRITICAL **: g_signal_connect_data: assertion 'G_TYPE_CHECK_INSTANCE (instance)' failed

(process:8681): Gtk-CRITICAL **: IA__gtk_settings_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed

(TempI:8681): Gtk-WARNING **: Screen for GtkWindow not set; you must always set
a screen for a GtkWindow before using the window

(TempI:8681): Gdk-CRITICAL **: IA__gdk_screen_get_display: assertion 'GDK_IS_SCREEN (screen)' failed

(TempI:8681): Gdk-CRITICAL **: IA__gdk_keymap_get_for_display: assertion 'GDK_IS_DISPLAY (display)' failed

(TempI:8681): GLib-GObject-WARNING **: invalid (NULL) pointer instance

(TempI:8681): GLib-GObject-CRITICAL **: g_signal_connect_data: assertion 'G_TYPE_CHECK_INSTANCE (instance)' failed

(TempI:8681): Gtk-WARNING **: Screen for GtkWindow not set; you must always set
a screen for a GtkWindow before using the window

(TempI:8681): Gdk-CRITICAL **: IA__gdk_screen_get_display: assertion 'GDK_IS_SCREEN (screen)' failed

(TempI:8681): Gdk-CRITICAL **: IA__gdk_keymap_get_for_display: assertion 'GDK_IS_DISPLAY (display)' failed

(TempI:8681): GLib-GObject-WARNING **: invalid (NULL) pointer instance

(TempI:8681): GLib-GObject-CRITICAL **: g_signal_connect_data: assertion 'G_TYPE_CHECK_INSTANCE (instance)' failed

Я могу опубликовать код программы, если необходимо, просто не делал этого, потому что это сделало бы вопрос еще больше. Это блок, где я создаю дополнительные AppIndicators, хотя:

for(int i=0; i<TempI_Main.Cores_Counter; i++){
    TempI_Main.Core[i].Gtk_Menu_Root=gtk_menu_new();

    //The core name ("Core " + number)
    char IndicatorName[TEMPI_MAX_CHARS];
    snprintf(IndicatorName, TEMPI_MAX_CHARS,"TempI_Core %u",i);

    TempI_Main.Core[i].Gtk_Menu_Root_Description=gtk_menu_item_new_with_label(IndicatorName);
    gtk_menu_append(GTK_MENU(TempI_Main.Core[i].Gtk_Menu_Root),TempI_Main.Core[i].Gtk_Menu_Root_Description);
    gtk_widget_set_sensitive(GTK_WIDGET(TempI_Main.Core[i].Gtk_Menu_Root_Description),FALSE);
    gtk_widget_show(TempI_Main.Core[i].Gtk_Menu_Root_Description);

    TempI_Main.Core[i].Gtk_Indicator=app_indicator_new(IndicatorName,"indicator-messages",APP_INDICATOR_CATEGORY_APPLICATION_STATUS);
    app_indicator_set_status(TempI_Main.Core[i].Gtk_Indicator, APP_INDICATOR_STATUS_ACTIVE);
    //Need to set icon
    //Need to set attention icon

    app_indicator_set_menu(TempI_Main.Core[i].Gtk_Indicator,GTK_MENU(TempI_Main.Core[i].Gtk_Menu_Root));
}

Любые подсказки, что может быть причиной? Не поддерживаются ли несколько AppIndicators на программу?

РЕДАКТИРОВАТЬ:

Исправленный код после ответа @ Жан-Франсуа Фабр.

for(int i=0; i<TempI_Main.Cores_Counter; i++){
    TempI_Main.Core[i].Gtk_Menu_Root=gtk_menu_new();

    //The core name ("Core " + number)
    char IndicatorName[TEMPI_MAX_CHARS];
    //MAX_CHARS - 6 ("Core "+'\0') is the limit for appending
    snprintf(IndicatorName, TEMPI_MAX_CHARS,"TempI_Core %u",i);

    TempI_Main.Core[i].Gtk_Indicator_Name=strdup(IndicatorName);

    TempI_Main.Core[i].Gtk_Menu_Root_Description=gtk_menu_item_new_with_label(TempI_Main.Core[i].Gtk_Indicator_Name);
    gtk_menu_append(GTK_MENU(TempI_Main.Core[i].Gtk_Menu_Root),TempI_Main.Core[i].Gtk_Menu_Root_Description);
    gtk_widget_set_sensitive(GTK_WIDGET(TempI_Main.Core[i].Gtk_Menu_Root_Description),FALSE);
    gtk_widget_show(TempI_Main.Core[i].Gtk_Menu_Root_Description);

    TempI_Main.Core[i].Gtk_Indicator=app_indicator_new(TempI_Main.Core[i].Gtk_Indicator_Name,"indicator-messages",APP_INDICATOR_CATEGORY_APPLICATION_STATUS);
    app_indicator_set_status(TempI_Main.Core[i].Gtk_Indicator, APP_INDICATOR_STATUS_ACTIVE);
    //Need to set icon
    //Need to set attention icon

    app_indicator_set_menu(TempI_Main.Core[i].Gtk_Indicator,GTK_MENU(TempI_Main.Core[i].Gtk_Menu_Root));
}

EDIT2:

Код для создания одного индикатора Core явно. По-прежнему бросать предупреждения и критические сообщения:

TempI_Main.Core[0].Gtk_Menu_Root=gtk_menu_new();

TempI_Main.Core[0].Gtk_Menu_Root_Description=gtk_menu_item_new_with_label("Core1");
gtk_menu_append(GTK_MENU(TempI_Main.Core[0].Gtk_Menu_Root),TempI_Main.Core[0].Gtk_Menu_Root_Description);
gtk_widget_set_sensitive(GTK_WIDGET(TempI_Main.Core[0].Gtk_Menu_Root_Description),FALSE);
gtk_widget_show(TempI_Main.Core[0].Gtk_Menu_Root_Description);

TempI_Main.Core[0].Gtk_Indicator=app_indicator_new("Core1","indicator-messages",APP_INDICATOR_CATEGORY_APPLICATION_STATUS);
app_indicator_set_status(TempI_Main.Core[0].Gtk_Indicator, APP_INDICATOR_STATUS_ACTIVE);
//Need to set icon
//Need to set attention icon

app_indicator_set_menu(TempI_Main.Core[0].Gtk_Indicator,GTK_MENU(TempI_Main.Core[0].Gtk_Menu_Root));

2 ответа

Решение

Я нашел корень проблемы, и мне стыдно сказать, но я просто потерял функцию, которая создала AppIndicator. Звонили раньше gtk_init() вот откуда все эти ошибки. Сначала я имел:

TempI_Set_Core_Indicator();

//Starts gtk
gtk_init(&argc,&argv);

TempI_Set_Main_Indicator();

и просто заменить его на:

//Starts gtk
gtk_init(&argc,&argv);

TempI_Set_Main_Indicator();
TempI_Set_Core_Indicator();

было достаточно, чтобы решить проблему. Я так сильно сосредоточился на самой функции, что не остановился, чтобы посмотреть, где она вызывается.

Это в цикле просто плохо

char IndicatorName[TEMPI_MAX_CHARS];
snprintf(IndicatorName, TEMPI_MAX_CHARS,"TempI_Core %u",i);
TempI_Main.Core[i].Gtk_Menu_Root_Description=gtk_menu_item_new_with_label(IndicatorName);
...
TempI_Main.Core[i].Gtk_Indicator=app_indicator_new(IndicatorName, ...

Вы декларируете IndicatorName в качестве автоматической переменной в цикле, но передать его gtk_menu_item_new_with_label который ожидает const char *, означает: он будет просто хранить адрес строки.

Мало того, что память будет использоваться повторно для дальнейших итераций, и все меню будут иметь одинаковое имя индикатора в цикле, но при выходе из цикла память будет выделена какой-то другой переменной, а имена будут выброшены => неопределенное поведение

Вы должны сделать копию строки следующим образом:

TempI_Main.Core[i].Gtk_Menu_Root_Description=gtk_menu_item_new_with_label(strdup(IndicatorName));

(конечно, лучшим способом было бы сохранить скопированную строку, чтобы иметь возможность освобождать их при необходимости)

Другие вопросы по тегам