C 和 libappindicator - 创建多个指标

C and libappindicator - Creating multiple indicators

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

这将要求我在同一个程序上有多个 AppIndicator,因为我认为没有办法让一个 AppIndicator 具有多个图标或使用 gtk_container 来保存这些图标并将其附加到 AppIndicator .我实际上正在尝试为菜单使用 1 个 AppIndicator(使用 "Quit" 选项),为每个 CPU 核心使用 1 个 AppIndicator。

该程序只有一个 AppIndicator(主要的)没有 Gtk 警告,但是在我添加了为每个 CPU 核心(均具有不同的唯一 ID)创建其他 2 个 AppIndicator 的代码后,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

如有必要,我可以post程序代码,只是没有这样做,因为这会使问题变得更大。这就是我创建额外 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

编辑:

@Jean-François Fabre 回答后更正了代码。

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 "+'[=13=]') 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));
}

编辑2:

用于显式创建单个核心指标的代码。仍然抛出警告和关键消息:

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

在一个循环中很糟糕:

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 *,这意味着:它将仅存储字符串的地址。

不仅内存将被重新用于进一步的迭代,而且所有菜单在循环内将具有相同的指示器名称,但退出循环时内存将被分配给其他一些变量,名称将被丢弃 => undefined行为

您应该像这样 复制 字符串:

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

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

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

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