C和libappindicator - 创建多个指标

时间:2016-09-14 20:16:21

标签: c gtk appindicator

我正在编写一个简单的指示器,它应该在Unity面板中显示每个CPU Core的图标,这将根据温度范围改变颜色。

这需要我在同一个程序上有多个AppIndicator,因为我认为没有办法让一个AppIndicator有多个图标或使用gtk_container来保存它们并将它附加到AppIndicator。我实际上尝试使用1个AppIndicator作为菜单(使用“Quit”选项)和1个AppIndicator用于每个CPU核心。

该程序只有一个AppIndicator(主要的)没有Gtk警告,但在我添加了为每个CPU Core创建其他2个AppIndicator的代码(两者都有不同的唯一ID)后,Gtk开始抛出一些警告和关键消息。指标显示在面板中就像它们应该的那样,但我不想简单地忽略这些消息,因为它们可能隐藏了一些真正的问题。

检查代码,我认为唯一可以触发这些警告和关键消息的是app_indicator_new()不止一次被调用,实际上我删除了所有菜单和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));
}

任何线索可能是什么原因? 每个程序不支持多个AppIndicator

修改

在@ Jean-FrançoisFabre回答之后更正了代码。

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:

明确创建单个核心指标的代码。仍在抛出警告和关键信息:

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 个答案:

答案 0 :(得分:1)

循环中的那个很糟糕:

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的{​​{1}},意味着:它只会存储字符串的地址。

不仅内存将被重复用于进一步的迭代,并且所有菜单在循环内都具有相同的指示符名称,但是退出循环,内存将被分配给其他变量并且名称将被删除=&gt;未定义的行为

你应该像这样制作字符串的副本

const char *

(当然更好的方法是存储复制的字符串,以便在需要时能够解除分配)

答案 1 :(得分:0)

我找到了问题的根源,并且很难说,但我只是错放了创建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();

足以解决问题。我非常关注功能本身,我没有停下来看它被调用的地方。