Си и 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));
(конечно, лучшим способом было бы сохранить скопированную строку, чтобы иметь возможность освобождать их при необходимости)