2

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

这将要求我在同一个程序上拥有多个 AppIndicator,因为我认为没有办法让一个 AppIndicator 具有多个图标,或者使用 gtk_container 来保存这些图标并将其附加到 AppIndicator。我实际上是在尝试为菜单使用 1 个 AppIndicator(带有“退出”选项),为每个 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

如有必要,我可以发布程序的代码,只是没有这样做,因为它会使问题变得更大。这就是我创建额外 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ç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 "+'\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));
}

编辑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));
4

2 回答 2

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期望 a const char *,意味着:它将只存储字符串的地址。

不仅内存将被重用于进一步的迭代,并且所有菜单在循环中都将具有相同的指标名称,而且退出循环,内存将被分配给其他变量并且名称将被丢弃 => 未定义的行为

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

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

(当然更好的方法是存储复制的字符串,以便在需要时释放它们)

于 2016-09-14T20:20:44.457 回答
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();

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

于 2016-09-14T22:34:16.690 回答