2011-09-14 64 views
0

我正在使用GTK编写一个非常简单的电池状态图标。 这是一个GtkStatusIcon,它显示工具提示中的当前电池状态。 为了获得电池的信息,我分析命令acpi是通常类似的输出: 暂停恢复时的分段错误

Battery 0: Discharging, 70%, 01:00:00 remaining

我的电池状态图标运行得很好,但在我中止我的电脑,然后我恢复它,我的程序与崩溃分段故障。

整个代码这个(我评论的话):

#include <gtk/gtk.h> 
#include <unistd.h> 
#include <string.h> 
#include <stdlib.h> 

#define DEFAULT_ARRAY_SIZE 3 
#define DEFAULT_TIME_UPDATE 5 

const gchar * acpi_command = "acpi"; 

typedef enum batteryState{ 
    CHARGING, 
    DISCHARGING, 
} BatteryState; 

typedef struct batteryTray { 
    GtkStatusIcon * tray_icon; 
    gchar * tooltip; 
    gchar * icon; 
} BatteryTray; 

typedef struct battery { 
    gchar * status; 
    gint percentage; 
    gchar * extra; 
     BatteryTray batteryTray; 
    BatteryState batteryState; 
} Battery; 

static void update_status_battery(Battery * battery); 
static gboolean update_status_tray(Battery * battery); 
static gchar * get_status_icon_name(Battery * battery); 
static void create_tray_icon(Battery * battery); 
static void parse_acpi_output(Battery * battery, gchar * acpi_output); 
static char * get_acpi_output(const gchar * acpi_command); 

static void update_status_battery(Battery * battery) 
{ 
    if(strcmp(battery->status, "Charging") == 0) 
     battery->batteryState = CHARGING; 
    else if(strcmp(battery->status, "Discharging") == 0) 
     battery->batteryState = DISCHARGING; 
} 

static gboolean update_status_tray(Battery * battery) 
{ 
    gchar * icon_name = get_status_icon_name(battery); 
    gchar * acpi_out = get_acpi_output(acpi_command); 

    parse_acpi_output(battery, acpi_out); 
    update_status_battery(battery); 

    battery->batteryTray.tooltip = g_strdup_printf("%s (%d%%) %s", 
     battery->status, 
     battery->percentage, 
     battery->extra); 

    gtk_status_icon_set_tooltip_text(battery->batteryTray.tray_icon, 
     battery->batteryTray.tooltip); 

    gtk_status_icon_set_from_icon_name(battery->batteryTray.tray_icon, 
     icon_name); 

    return TRUE; 
} 

static gchar * get_status_icon_name(Battery * battery) 
{ 

    GString * icon_name = g_string_new("notification-battery"); 

    if (battery->percentage < 20) 
     g_string_append(icon_name, "-low"); 
    else if (battery->percentage < 40) 
     g_string_append(icon_name, "-020"); 
    else if (battery->percentage < 80) 
     g_string_append(icon_name, "-060"); 
    else 
     g_string_append(icon_name, "-100"); 

    if(battery->batteryState == CHARGING) { 
     g_string_append(icon_name, "-plugged"); 
    } 

    return icon_name->str; 
} 

static void create_tray_icon(Battery * battery) 
{ 
     /* create the gtkstatusicon and call the function 
      `update_status_tray` every 5 seconds */ 

    battery->batteryTray.tray_icon = gtk_status_icon_new(); 
    battery->batteryTray.tooltip = "battery"; 
    gtk_status_icon_set_tooltip(battery->batteryTray.tray_icon, 
     battery->batteryTray.tooltip); 
    gtk_status_icon_set_visible(battery->batteryTray.tray_icon, 
     TRUE); 

    update_status_tray(battery); 
    g_timeout_add_seconds(DEFAULT_TIME_UPDATE, (GSourceFunc) update_status_tray, battery); 
} 

static void parse_acpi_output(Battery * battery, gchar * acpi_output) 
{ 
    /* acpi output is like: 
     Battery 0: Discharging, 70%, 01:00:00 remaining 

     In this function I assign "Discharging" to battery->status 
     70 to battery->percentage 
     and "01:00:00 remaining" to battery->extra 

     I use strtok to split the acpi output into tokens delimited by ',' and 
     then, if there's a blank character ' ' in front of a token, i 'remove' it. 
    */ 

    gint i = 0; 
    gchar * t; 
    gchar ** values_array; 

    /* find the position of ':' in the string */ 
    int pos = strchr(acpi_output, ':') - acpi_output; 
    t = strtok(acpi_output + pos + 1, ","); 

    values_array = malloc(DEFAULT_ARRAY_SIZE * sizeof(gchar)); 

    while(t != NULL) { 
     /* 'remove' the blank character */ 
     values_array[i++] = t[0] == ' ' ? t + 1 : t; 
     t = strtok(NULL, ","); 
    } 

    /* remove newline */ 
    if(values_array[2][strlen(values_array[2]) - 1] == '\n') { 
     values_array[2][strlen(values_array[2]) - 1] = '\0'; 
    } 

    battery->status = values_array[0]; 
    battery->percentage = atoi(values_array[1]); 
    battery->extra = values_array[2]; 

    free(values_array); 
} 

static gchar * get_acpi_output(const gchar * acpi_command) 
{ 
    gchar * output; 
    GError * error = NULL; 

    /* assign the output of the acpi command to 'output' */ 
    g_spawn_command_line_sync(acpi_command, &output, NULL, NULL, &error); 
    return output; 
} 

int main(int argc, char ** argv) 
{ 
    Battery battery; 

    gtk_init(&argc, &argv); 
    create_tray_icon(&battery); 
    gtk_main(); 

    return 0; 
} 

我希望有人能帮助我,因为我实在无法理解。

+0

这是很多代码。至少在你自己做一些工作 - 做一个核心转储,并用调试器检查它,看它在崩溃时做了什么。 –

回答

1

有很多地方你可以做更多的错误检查;也许你的代码之外的东西在唤醒期间失败。例如,您不检查g_spawn_command_line_sync的结果 - 您认为output在返回时指向有效的字符串,但可能并非总是如此。而且你假定,但是并没有确认,你运行的工具的输出中有一定数量的标记,但也许并不总是如此。