Библиотека сайта rus-linux.net
Возможности тулкита GTK+ и сопутствующих библиотек
Автор: A. Панин
Дата публикации: 10 июня 2015 г.
Механизм загрузки ресурсов приложений
Дополнительные файлы ресурсов используются как приложениями с графическим интерфейсом, так и приложениями с интерфейсом командной строки. Примерами файлов ресурсов, используемых приложениями с графическим интерфейсом на основе тулкита GTK+, являются файлы изображений, звуковые файлы, файлы описания графического интерфейса и действий, файлы каскадных таблиц стилей с описаниями стилей элементов графического интерфейса, файлы с необходимыми для работы приложения данными и.т.д. Приложениям с интерфейсом командной строки для корректной работы также могут понадобиться файлы с данными. При разработке приложений, использующих файлы ресурсов, чаще всего либо предусматривают копирование этих файлов в директорию приложения, созданную в системной директории для хранения данных приложений (обычно /usr/share/), либо преобразовывают содержимое этих файлов в байтовые массивы, которые впоследствии размещаются в подключаемом к исходному коду приложения заголовочном файле. В последнем случае во-первых ускоряется загрузка приложения, а во-вторых снижается сложность кода, ведь в случае работы с байтовыми массивами больше не приходится обрабатывать ситуации с недоступностью файлов. В данной статье рассматривается третий вариант, а именно, механизм загрузки ресурсов приложений, реализованный в рамках библиотеки GIO.
1. Утилита для обработки ресурсов и файл описания ресурсов
Перед осуществлением доступа к данным ресурсов на уровне приложения необходимо произвести преобразование этих файлов в байтовый массив. Для выполнения этого действия должна использоваться утилита glib-compile-resources из комплекта поставки библиотеки GLib. В качестве исходных данных утилита принимает специально подготовленный файл формата XML со списком файлов ресурсов и описанием методов предварительной обработки/преобразования каждого из них. Файл должен иметь расширение .gresource.xml. Пример рассматриваемого файла приведен в Листинге 1.
Листинг 1 - Файл описания файлов ресурсов приложения
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gtk/GWhois">
<file preprocess="to-pixdata">alnilam-Stars-Pattern.png</file>
<file preprocess="xml-stripblanks">whois-server-list.xml</file>
<file compressed="true">gwhois.css</file>
</gresource>
</gresources>
Как вы наверняка поняли, в статье будет описываться процесс преобразования приложения gwhois из прошлой статьи серии, который вполне обоснован, так как данное приложение использует файл формата XML, содержащий информацию о серверах whois, с именем whois-server-list.xml. Кроме того, для демонстрации методики загрузки графических файлов и файлов каскадных таблиц стилей в файле описания ресурсов приложения приведены имена файлов alnilam-Stars-Pattern.png и gwhois.css. При преобразовании файлов ресурсов в байтовый массив каждый из этих файлов может быть сжат с помощью библиотеки ZLib в случае использования параметра "compressed" с значением "true" (очевидно, что в данном случае осуществляется сжатие файла каскадной таблицы стилей с именем gwhois.css). При доступе к сжатому файлу ресурса в процессе работы приложения будет автоматически осуществляться его декомпрессия. Перед преобразованием из файлов формата XML с помощью утилиты xmllint могут быть убраны лишние пробелы в случае использования параметра предварительной обработки "preprocess" с значением "xml-stripblanks" (в данном случае лишние пробелы удаляются из файла whois-server-list.xml). Кроме того, файлы изображений могут преобразовываться во внутренний формат хранения графических данных GDK с помощью утилиты gdk-pixbuf-pixdata в случае использовании параметра предварительной обработки "preprocess" с значением "to-pixdata" (в данном случае описанным образом преобразуется файл изображения alnilam-Stars-Pattern.png). Также следует обратить внимание на значение параметра "prefix", ведь при доступе к данным ресурсов на уровне приложения префикс должен записываться непосредственно перед именем каждого из файлов ресурсов.
Утилита glib-compile-resources может генерировать как бинарный файл, который впоследствии может загружаться с помощью специальных функций библиотеки GIO, так и набор из файла исходного кода языка программирования C с объявлением байтового массива с данными ресурсов и вызовами функций для инициализации и регистрации ресурсов в рамках приложения, а также соответствующего заголовочного файла для подключения к исходному коду приложения, разработанного с использованием языка программирования C. Для генерации бинарного файла следует использовать следующую команду:
В качестве имени бинарного файла ресурсов, имени идентификатора языка C и имени файла описания ресурсов чаще всего используется имя приложения, поэтому в случае генерации бинарного файла ресурсов для приложения gwhois команда будет выглядеть следующим образом:
glib-compile-resources --target=gwhois.resources --sourcedir=. --generate --c-name gwhois gwhois.gresource.xml
В результате в рабочей директории будет создан бинарный файл с именем gwhois.resources. Для генерации набора из файла исходного кода языка C и заголовочного файла следует использовать последовательность из двух команд, заменив параметр --generate на параметры --generate-source и --generate-header, а также указав имена файлов с соответствующими расширениями. В случае генерации описанного набора файлов для приложения gwhois последовательность команд будет выглядеть следующим образом:
glib-compile-resources --target=gwhois-resources.c --sourcedir=. --generate-source --c-name gwhois gwhois.gresource.xml glib-compile-resources --target=gwhois-resources.h --sourcedir=. --generate-header --c-name gwhois gwhois.gresource.xml
В результате в рабочей директории будут созданы файлы исходного кода gwhois-resources.c и gwhois-resources.h, причем последний файл предназначен для подключения к исходному коду приложения.
2. Класс набора ресурсов GResource и глобальное пространство ресурсов приложения
Ранее упоминалось, что данные файлов ресурсов могут быть размещены как в бинарном файле, так и в файле исходного кода языка программирования C. В случае использования бинарного файла (например, если используется отличный от C язык программирования) для работы с ресурсами должен создаваться объект набора ресурсов типа GResource, который впоследствии может быть зарегистрирован в глобальном пространстве ресурсов приложения. Для загрузки бинарного файла набора ресурсов может использоваться конструктор g_resource_load(), а также конструктор g_resource_new_from_data() в том случае, если уже имеется доступ к данным этого файла. С помощью обоих конструкторов создаются объекты наборов ресурсов типа GResource, которые могут либо использоваться для доступа к ресурсам приложения, либо регистрироваться в глобальном пространстве ресурсов приложения, что позволит отказаться от передачи указателя на упомянутый объект во все функции приложения, в которых осуществляется доступ к ресурсам.
GResource *
g_resource_load(const gchar *filename,
GError **error);
GResource *
g_resource_new_from_data(GBytes *data,
GError **error);
Регистрация объекта набора ресурсов типа GResource в глобальном пространстве ресурсов приложения осуществляется с помощью функции g_resources_register(), а отмена регистрации - с помощью функции g_resources_unregister(). В случае подключения к исходному коду приложения файлов исходного кода с данными ресурсов будет осуществляться автоматическая регистрация в глобальном пространстве ресурсов.
void g_resources_register(GResource *resource); void g_resources_unregister(GResource *resource);
Каждый из объектов наборов ресурсов типа GResource реализует механизм подсчета ссылок. Создание ссылки на объект осуществляется с помощью метода g_resource_ref(), а удаление - с помощью метода g_resource_unref(). При равенстве счетчика ссылок объекта нулю происходит его уничтожение с освобождением всей зарезервированной памяти. Оба метода являются потокобезопасными (могут вызываться из любого программного потока).
GResource * g_resource_ref(GResource *resource); void g_resource_unref(GResource *resource);
Доступ к данным ресурса может осуществляться как с помощью метода g_resource_lookup_data() в том случае, если объект набора ресурсов не зарегистрирован в глобальном пространстве ресурсов приложения, так и с помощью функции g_resources_lookup_data() в противном случае.
GBytes *
g_resource_lookup_data(GResource *resource,
const char *path,
GResourceLookupFlags lookup_flags,
GError **error);
GBytes *
g_resources_lookup_data(const char *path,
GResourceLookupFlags lookup_flags,
GError **error);
С помощью аргумента path передается имя файла из набора ресурсов приложения с префиксом (к примеру, в случае использования приведенного выше файла описания ресурсов для доступа к данным файла формата XML со списком серверов whois следует передать строку "/org/gtk/GWhois/whois-server-list.xml"). С помощью аргумента lookup_flags задаются флаги поиска данных ресурсов, причем на данный момент объявлена лишь константа G_RESOURCE_LOOKUP_FLAGS_NONE, обозначающая отсутствие флагов. В случае обнаружения данных ресурса будет возвращен объект ассоциированного байтового массива, в противном случае - значение NULL и объект ошибки с помощью аргумента error. Если же необходимо осуществлять последовательное чтение данных ресурса, следует использовать метод g_resource_open_stream() и функцию g_resources_open_stream().
GInputStream *
g_resource_open_stream(GResource *resource,
const char *path,
GResourceLookupFlags lookup_flags,
GError **error);
GInputStream *
g_resources_open_stream(const char *path,
GResourceLookupFlags lookup_flags,
GError **error);
Для получения списка доступных ресурсов следует использовать метод g_resource_enumerate_children() и функцию g_resources_enumerate_children().
char **
g_resource_enumerate_children(GResource *resource,
const char *path,
GResourceLookupFlags lookup_flags,
GError **error);
char **
g_resources_enumerate_children(const char *path,
GResourceLookupFlags lookup_flags,
GError **error);
В данном случае с помощью аргумента path следует передавать префикс, заданный в файле описания ресурсов приложения. Память, использованная для хранения возвращаемого массива строк, должна быть освобождена с помощью функции g_strfreev() из библиотеки GLib.
Для получения информации о ресурсе следует использовать метод g_resource_get_info() и функцию g_resources_get_info().
gboolean
g_resource_get_info(GResource *resource,
const char *path,
GResourceLookupFlags lookup_flags,
gsize *size,
guint32 *flags,
GError **error);
gboolean
g_resources_get_info(const char *path,
GResourceLookupFlags lookup_flags,
gsize *size,
guint32 *flags,
GError **error);
С помощью аргумента path следует передавать имя файла из набора ресурсов приложения с префиксом. Аргументы size и flags служат для получения информации о размере файла в байтах и флагах (атрибутах) этого файла соответственно (на данный момент единственным флагом является константа G_RESOURCE_FLAGS_COMPRESSED, указывающая на то, что файл был сжат).
Например, для получения информации о доступных приложению ресурсах может быть использован код из Листинга 2.
Листинг 2 - Пример использования функций g_resources_enumerate_children() и g_resources_get_info()
При условии использования приведенного ранее файла описания ресурсов приложенния в терминал будет выведен следующий список доступных ресурсов.
whois-server-list.xml, 583481 байт(а) alnilam-Stars-Pattern.png, 160024 байт(а) gwhois.css, 182 байт(а), сжат
В случае регистрации объекта набора ресурсов в глобальном пространстве ресурсов приложения могут использоваться вспомогательные методы, значительно упрощающие использование данных ресурсов приложения. Примерами таких методов являются:
-
Метод
gdk_pixbuf_new_from_resource(), предназначенный для создания объекта буфера пикселей изображения типаGdkPixbufна основе данных ресурса. -
Метод
gdk_pixbuf_new_from_resource_at_scale(), предназначенный для создания объекта буфера пикселей изображения типаGdkPixbufна основе данных ресурса с автоматическим масштабированием и возможностью сохранения соотношения длин сторон. -
Метод
gdk_pixbuf_animation_new_from_resource(), предназначенный для создания объекта буфера пикселей анимированного изображения типаGdkPixbufAnimationна основе данных ресурса. -
Метод
gtk_builder_new_from_resource(), являющийся конструктором объекта системы разбора описания графического интерфейса типаGtkBuilderи выполняющий загрузку и обработку данных описания графического интерфейса приложения из ресурса. -
Метод
gtk_builder_add_from_resource(), предназначенный для разбора представленного ресурсом описания графического интерфейса приложения и добавления созданных на его основе объектов к уже созданным в рамках существующего объекта разбора описания графического интерфейса типаGtkBuilderобъектам. -
Метод
gtk_builder_add_objects_from_resource(), предназначенный для разбора представленного ресурсом описания графического интерфейса приложения и добавления созданных на его основе объектов для виджетов с указанными именами к уже созданным в рамках существующего объекта разбора описания графического интерфейса типаGtkBuilderобъектам. -
Метод
gtk_css_provider_load_from_resource(), предназначенный для загрузки каскадной таблицы стилей из ресурса (введен в GTK+ 3.16).
GdkPixbuf *
gdk_pixbuf_new_from_resource(const char *resource_path,
GError **error);
GdkPixbuf *
gdk_pixbuf_new_from_resource_at_scale(const char *resource_path,
int width,
int height,
gboolean preserve_aspect_ratio,
GError **error);
GdkPixbufAnimation *
gdk_pixbuf_animation_new_from_resource(const char *resource_path,
GError **error);
GtkBuilder *
gtk_builder_new_from_resource(const gchar *resource_path);
guint
gtk_builder_add_from_resource(GtkBuilder *builder,
const gchar *resource_path,
GError **error);
guint
gtk_builder_add_objects_from_resource(GtkBuilder *builder,
const gchar *resource_path,
gchar **object_ids,
GError **error);
gboolean
gtk_css_provider_load_from_resource(GtkCssProvider *css_provider,
const gchar *resource_path,
GError **error);
Помимо использования описанных выше методов, на ресурсы можно ссылаться из описаний графических интерфейсов приложений и каскадных таблиц стилей. В случае описания графического интерфейса приложения ссылка на ресурс осуществляется с помощью описания свойства: <property name="resource">/путь/к/ресурсу</property>. В случае каскадной таблицы стилей используется следующий формат: url('resource:///путь/к/ресурсу').
Продолжение статьи : 3. Пример использования ресурсов в приложении.
