 | Добавление возможностей
Что дальше?
Теперь, когда у нас есть базовый интерфейс, позволяющий выполнять считывание данных, следующим вопросом будет - какие ещё данные могут быть полезны? Еще один доступный параметр - это свободное дисковое пространство. Узнать его можно несколькими способами.
Определение дискового пространства
Узнать размер свободного дискового пространства можно с помощью системного вызова statfs()
. Эта функция возвращает строку, содержащую текущую статистику использования дискового пространства:
Листинг 13. Определение свободного дискового пространства
static char *
diskfree(void)
{
static char capacity[16];
struct statfs buf;
if (statfs("/", &buf) < 0) {
strcpy(capacity, "unavailable");
} else {
double used = 1.0 - ((double) buf.f_bavail / buf.f_blocks);
sprintf(capacity, "%.1f%%", (used * 100));
}
return capacity;
}
|
Системный вызов statfs(), подобно stat(), возвращает информацию об указанном пути, за тем исключением, что он показывает не файловую статистику, а статистику файловой системы. В качестве некоторой странности, хотя все привыкли выражать занимаемое пространство в процентах, statfs() сообщает только доступный на данный момент объём. Этот код рассчитывает используемый объём (в диапазоне от 0 до 1) и преобразует его в проценты. Обратите внимание на то, что для проверки ошибок необходимо добавление заголовка <string.h> к strcpy().
Добавление информации
Теперь процедура нам хорошо знакома:
Листинг 14. Добавление меток
/* disk space */
label = gtk_label_new("Disk usage:");
gtk_table_attach(GTK_TABLE(table), label,
0, 1,
1, 2,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
0, 0);
label = gtk_label_new(diskfree());
gtk_table_attach(GTK_TABLE(table), label,
1, 3,
1, 2,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
0, 0);
|
На самом деле подобные вещи выглядят как шаблоны, которые можно использовать. Фактически здесь изменяются только номер строки таблицы и две строковые переменные.
Время реорганизации кода
Немного обобщая, мы можем создать функцию, которая выводит один из этих параметров в таблицу. Суть эффективного программирования лежит в творчестве; я творчески назвал функцию label_in_table(). Какие аргументы нужны для неё? Ей нужна таблица, строка, описательная метка (слева) и текст, который необходимо вывести (справа). Итак:
Листинг 15. Извлеченные параметры
static void
label_in_table(GtkWidget *table, int row, char *name, char *value)
{
GtkWidget *label;
label = gtk_label_new(name);
gtk_table_attach(GTK_TABLE(table), label,
0, 1,
row, row + 1,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
0, 0);
label = gtk_label_new(value);
gtk_table_attach(GTK_TABLE(table), label,
1, 3,
row, row + 1,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
0, 0);
}
|
Вызов label_in_table()
Давайте теперь упростим основную функцию. Теперь это намного проще, чем раньше:
Листинг 16. Исправленный и упрощённый код
/* uname */
uname(&u);
label_in_table(table, 0, "Kernel version:", u.release);
/* disk space */
label_in_table(table, 1, "Disk usage:", diskfree());
|
Этот пример указывает на несколько моментов. Первый состоит в том, что table может быть кандидатом в глобальные переменные; в конце концов это единственная такая таблица. Другой момент - вы можете подумать о том, что может иметь смысл использование статической или глобальной переменной для отслеживания номеров строк—и это так, за исключением того, что в будущем может понадобиться замена содержимого существующей строки, поэтому хорошо бы иметь возможность указания целевой строки.
Информация о памяти
На следующем шаге мы займемся информацией о памяти. Отправной точкой для этого служит вызов sysinfo(). Поскольку вызов sysinfo() возвращает несколько полезных элементов информации, способ, которым код будет обращаться с ним, будет посложнее—но только слегка. Подобно uname() и statfs(),
sysinfo() извлекает данные в структуру (struct sysinfo).
Из неё достаточно просто извлекается значение величины использованной памяти.
Листинг 17. Определение использования памяти
sprintf(buffer, "%.1f%%",
(100 * (1.0 - ((double) si.freeram / si.totalram))));
label_in_table(table, 2, "Memory usage:", buffer);
|
Загрузка системы
Получить значение загрузки системы очень просто; средние значения нагрузки за одну, пять и пятнадцать минут хранятся в struct sysinfo, как unsigned long. Однако традиционно средняя нагрузка показывается пользователю как средняя длина очереди задач, как правило, в виде числа с плавающей запятой. Средняя нагрузка 1,00 показывает, что система находится на нижнем пределе полной загрузки. Итак, как преобразовать значения unsigned long в более привычные? Это, хотя и не очень понятно, изложено на странице man sysinfo(). Секрет заключается в макросе SI_LOAD_SHIFT, в котором хранится коэффициент пересчёта; фактически unsigned long трактуются как дробные значения с фиксированной запятой. Чаще всего SI_LOAD_SHIFT равно 16, то означает, что средняя нагрузка 1,0 представляется как 65 536.
Этот тип расчетов вызывает функцию helper:
Листинг 18. Получение средней нагрузки
static double
scaled_load(long int unscaled) {
return (double) unscaled / (1 << SI_LOAD_SHIFT);
}
|
Полученные значения могут выводиться на печать так же, как остальные – на экран:
Листинг 19. Отобрвжение средней нагрузки
sprintf(buffer, "%.2f %.2f %.2f",
scaled_load(si.loads[0]), scaled_load(si.loads[1]),
scaled_load(si.loads[2]));
label_in_table(table, 3, "Load:", buffer);
|
На этом пока все.
Пора посмотреть на готовую программу Вот экран программы:
Рисунок 2. Апплет системной информации
|  |