我正在使用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
在返回时指向有效的字符串,但可能并非总是如此。你假设,但实际上没有确认,你运行的工具的输出中有一定数量的标记,但也许并非总是如此。