Библиотека сайта 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/G
W
hois/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. Пример использования ресурсов в приложении.