2016-09-14 49 views
2

我正在編程一個簡單的指示器,它應該顯示Unity面板中每個CPU Core的圖標,它將根據溫度範圍改變顏色。C和libappindicator - 創建多個指示器

這將需要我在同一個程序上有多個AppIndicator,因爲我認爲沒有辦法讓一個AppIndicator具有多個圖標或使用gtk_container來保存這些圖標並將其附加到AppIndicator。實際上,我嘗試使用1個AppIndicator作爲菜單(帶有「退出」選項)和1個AppIndicator用於每個CPU核心。

該程序沒有Gtk警告只有一個AppIndicator(主要的),但是當我添加了用於爲每個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

編輯:

更正代碼之後@讓 - 弗朗索瓦·法布爾的答案。

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

回答

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

就足以解決問題。我非常關注功能本身,所以我沒有停下來看看它被調用的地方。

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一個希望將const char *,意思是:它只會存儲字符串的地址。

不僅內存將被重複用於進一步的迭代,並且所有菜單將在循環中具有相同的指示器名稱,但退出循環內存將被分配給其他變量並且名稱將被丟棄=>未定義行爲

你應該讓字符串的副本這樣的:

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

(當然是一個更好的方式是存儲複製的字符串能夠取消分配這些如果需要的話)

+0

男人,我做了什麼?!? :o感謝您指出了這一點!我爲名稱「TempI_Main.Core [i] .Gtk_Indicator_Name」創建了一個額外的字段,並用它來代替。儘管如此,我仍然收到警告和重要信息。我將以編輯的形式在問題中發佈新的循環代碼! – IanC

+0

難道問題是堆是動態的,在程序執行期間字符串可能會改變位置? libappindicator仍然會有舊的地址並導致相同的未定義行爲?我會嘗試使用字符串文字並查看結果是什麼。 – IanC

+0

與strdup它應該是確定的。你確定'TEMPI_MAX_CHARS'足夠大嗎?我會減少循環到1次迭代:容易做到,可能會減少一些光... –