Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

Программирование с использованием gtkmm 3. Создание с помощью утилиты gmmproc оберток для разработанных с использованием языка программирования C библиотек

Оригинал: Programming with gtkmm 3
Авторы: Murray Cumming, Bernhard Rieder, Jonathon Jongsma, Ole Laursen, Marko Anastasov, Daniel Elstner, Chris Vine, David King, Pedro Ferreira, Kjell Ahlstedt
Дата публикации: 15 Октября 2013 г.
Перевод: А.Панин
Дата перевода: 25 Апреля 2014 г.

Приложение G. Создание с помощью утилиты gmmproc оберток для разработанных с использованием языка программирования C библиотек

G.3.5. Макросы методов

G.3.5.1. _WRAP_METHOD

Данный макрос генерирует метод языка C++, который является оберткой для функции языка C.
_WRAP_METHOD( описание метода языка C++, имя функции языка C)
Пример из файла entry.hg:
_WRAP_METHOD(void set_text(const Glib::ustring& text), gtk_entry_set_text)

Приведенная выше функция языка C (т.е., gtk_entry_set_text) описана более подробно в файле с расширением .defs, при этом файлы преобразования convert*.m4 содержат информацию, необходимую для преобразования типов параметров языка C++ к типам параметров языка C. Данный макрос также генерирует комментарии для документации doxygen на основе информации из файлов файлов *_docs.xml и *_docs_override.xml.

Также имеется несколько дополнительных аргументов:
refreturn
Установка дополнительной ссылки на возвращаемое значение в том случае, если функция языка C не устанавливает ссылки.
errthrow
Использование последнего параметра типа GError** функции языка C для генерации исключения.
deprecated
Размещение сгенерированного кода внутри блоков условной компиляции #ifdef. Текст сообщения об устаревании метода может быть задан с помощью дополнительного параметра.
constversion
Использование простого вызова версии той же функции, возвращающей непостоянное значение, вместо генерации практически дублирующегося кода.
ifdef
Размещение сгенерированного кода внутри блоков условной компиляции #ifdef.
slot_name
Указание имени представленного слотом параметра метода в случае наличия такового. Оно позволяет утилите gmmproc генерировать код для копирования слота и передачи его с помощью последнего параметра функции языка C с именем user_data типа gpointer. Аргумент slot_callback должен также использоваться для указания имени связывающей функции обратного вызова с целью его передачи функции языка C.
slot_callback
Используется совместно с аргументом slot_name для указания имени связывающей функции обратного вызова, которая выполняет извлечение указателя на функцию из слота и вызов этой функции. Адрес данной функции обратного вызова также передается функции языка C, для которой создается обертка.
no_slot_copy
Указание утилите gmmproc на то, что не следует передавать копию слота функции языка C в том случае, если метод использует слот. Вместо этого будет осуществляться передача самого слота. Имя представленного слотом параметра а также имя связывающей функции обратного вызова должны быть указаны с помощью аргументов slot_name и slot_callback соответственно.
Правильный выбор типов языка C++ при создании оберток для API языка C является также достаточно важным. Хотя обычно и очевидно то, какие типы языка C++ должны использоваться в методе языка C++, ниже приведено несколько советов:
  • В том случае, если объекты используются посредством умного указателя типа Glib::RefPtr: следует передавать умный указатель типа Glib::RefPtr как неизменную ссылку. Например, const Glib::RefPtr<Gtk::FileFilter>& filter.
  • В том случае, если неизменные объекты используются посредством умного указателя типа Glib::RefPtr: если объект не должен изменяться с помощью функции, следует удостовериться в том, что объект объявлен как неизменный даже в том случае, если умный указатель типа Glib::RefPtr уже объявлен как неизменная ссылка. Например, const Glib::RefPtr<const Gtk::FileFilter>& filter.
  • Создание оберток для параметров в форме связанных списков типов GList* и GSList*: во-первых, вы должны узнать тип объекта, на который указывает поле данных каждого из элементов списка, причем обычно этот тип указывается в документации к функции языка C. После этого для списка может быть подготовлена обертка на основе контейнера типа std::vector. Например, std::vector< Glib::RefPtr<Gdk::Pixbuf> >. Вы также можете столкнуться с необходимостью указания свойств типа для установки способа преобразования типов языка C в типы языка C++.
  • Создание оберток для возвращаемых связанных списков типов GList* и GSList*: вы должны узнать о том, следует ли освобождать зарезервированную для списка память, а также о том, следует ли освобождать память, использованную для хранения элементов списка, также обратившись к документации функции языка C. Воспользовавшись этой информацией, вы сможете выбрать режим владения (none (без владения), shallow (частичное владение) или deep (полное владение)) для правила преобразования m4, которое вы, скорее всего, должны будете разместить непосредственно в файле с расширением .hg, так как режим владения зависит от функции, а не от типа данных. Пример макроса:
    #m4 _CONVERSION(`GSList*',`std::vector<Widget*>',`Glib::SListHandler<Widget*>::slist_to_vector($3, Glib::OWNERSHIP_SHALLOW)')

G.3.5.2. _WRAP_METHOD_DOCS_ONLY

Данный макрос аналогичен макросу _WRAP_METHOD(), но он генерирует исключительно документацию для метода языка C++, который является оберткой для функции языка C. Используйте его тогда, когда вам приходится вручную разрабатывать метод, но вы хотите использовать документацию, которая будет сгенерирована в случае генерации метода.
_WRAP_METHOD_DOCS_ONLY(имя функции языка C)
Пример из файла container.hg:
_WRAP_METHOD_DOCS_ONLY(gtk_container_remove)

G.3.5.3. _IGNORE/_IGNORE_SIGNAL

Утилита gmmproc будет выводить предупреждения в стандартный поток вывода при обработке каждой функции и каждого сигнала, для которых вы забыли создать обертки, гарантируя создание завершенной обертки для всего API. Но в том случае, если вы не хотите создавать обертки для каких-либо функций и сигналов или в том случае, если вы решите самостоятельно разработать некоторые методы, вы можете использовать макрос _IGNORE() или _IGNORE_SIGNAL() для предотвращения вывода предупреждений утилитой gmmproc.
_IGNORE(имя функции 1 языка C, имя функции 2 языка C, и.т.д.)
_IGNORE_SIGNAL(имя сигнала 1 языка C, имя сигнала 2 языка C, и.т.д.)
Пример из файла buttonbox.hg:
_IGNORE(gtk_button_box_set_spacing, gtk_button_box_get_spacing)

G.3.5.4. _WRAP_SIGNAL

Данный макрос генерирует реализацию сигнала в стиле libsigc++ на языке C++, который является оберткой над сигналом системы GObject языка C. На самом деле он генерирует публичный метод доступа, такой, как signal_clicked(), который возвращает прокси-объект. Утилита gmmproc использует файл с расширением .defs для определения типов параметров функции сигнала для языка C, а также файлы преобразования с расширением .m4 для определения подходящих типов для преобразования.
_WRAP_SIGNAL( описание обработчика сигнала языка C++, имя сигнала языка C)
Пример из файла button.hg:
_WRAP_SIGNAL(void clicked(),"clicked")

Для реализации сигналов обычно используются указатели на функции во внутренней структуре GTK, а также соответствующее значение перечисления и функция g_signal_new() в файле с расширением .c.

Также имеется несколько дополнительных аргументов:
no_default_handler
Не генерировать виртуальный метод on_something(), позволяющий перекрыть стандартный обработчик сигналов. Используйте данный аргумент в том случае, когда добавление сигнала со стандартным обработчиком может привести к нарушению ABI из-за увеличения размера таблицы виртуальных функций класса.
custom_default_handler
Генерировать описание виртуального метода on_something() в заголовочном файле с расширением .h без генерации реализации в файле исходного кода с расширением .cc. Используйте данный аргумент тогда, когда вам нужно создать реализацию стандартного обработчика сигнала вручную.
custom_c_callback
Не генерировать функцию обратного вызова языка C для данного сигнала. Используйте данный аргумент тогда, когда вам нужно разработать функцию обратного вызова вручную.
refreturn
Установить дополнительную ссылку для возвращаемого виртуальным методом on_something() значения в том случае, если функция языка C не устанавливает ссылки.
ifdef
Поместить сгенерированный код в блоки условной компиляции #ifdef.

G.3.3.5 _WRAP_PROPERTY

Данный макрос генерирует метод языка C++, являющийся оберткой свойства системы GObject языка C. Вы должны указать имя и желаемый тип данных языка C++ для рассматриваемого свойства. Утилита gmmproc использует файл с расширением .defs для установления типа данных языка C, а также файлы правил преобразования типов с расширением .m4 для установления соответствия между типами данных для преобразований.
_WRAP_PROPERTY(имя свойства языка C, тип данных языка C++)
Пример из файла button.hg:
_WRAP_PROPERTY("label", Glib::ustring)

G.3.5.6. _WRAP_VFUNC

Данный макрос генерирует виртуальный метод языка C++, являющийся оберткой для функции языка C.
_WRAP_VFUNC( описание метода языка C++, имя функции языка C)
Пример из файла widget.hg:
_WRAP_VFUNC(SizeRequestMode get_request_mode() const, get_request_mode)

Функция языка C (т.е., get_request_mode) более подробно описана в файле *_vfuncs.defs, а файлы *.m4 содержат необходимые правила преобразования типов параметров языка C++ к типам параметров языка C.

Также имеется несколько дополнительных аргументов:
refreturn
Установить дополнительную ссылку для возвращаемого функцией something_vfunc() значения в том случае, если функция, использующаяся в качестве виртуальной функции языка C, не устанавливает ссылки.
refreturn_ctype
Установить дополнительную ссылку для возвращаемого значения перекрытой функции something_vfunc() в рамках функции обратного вызова языка C в том случае, если вызывающая функция языка C ожидает ее для предоставления ссылки.
errthrow
Использовать последний параметр типа GError** (если такой существует) функции, использующейся в качестве виртуальной функции языка C, для генерации исключения.
custom_vfunc
Не генерировать объявление виртуальной функции в файле с расширением .cc. Используйте данный аргумент в том случае, если вам нужно разработать виртуальную функцию вручную.
custom_vfunc_callback
Не генерировать функцию обратного вызова языка C для виртуальной функции. Используйте данный аргумент в том случае, если вам нужно разработать функцию обратного вызова вручную.
ifdef
Разместить сгенерированный код в блоках условной компиляции #ifdef.
slot_name
Указание имени представленного слотом параметра метода в случае наличия такового. Оно позволяет утилите gmmproc генерировать код для копирования слота и передачи его с помощью последнего параметра функции языка C с именем user_data типа gpointer. Аргумент slot_callback должен также использоваться для указания имени связывающей функции обратного вызова с целью его передачи функции языка C.
slot_callback
Используется совместно с аргументом slot_name для указания имени связывающей функции обратного вызова, которая выполняет извлечение указателя на функцию из слота и вызов этой функции. Адрес данной функции обратного вызова также передается функции языка C, для которой создается обертка.
no_slot_copy
Указание утилите gmmproc на то, что не следует передавать копию слота функции языка C в том случае, если метод использует слот. Вместо этого будет осуществляться передача самого слота. Имя представленного слотом параметра а также имя связывающей функции обратного вызова должны быть указаны с помощью аргументов slot_name и slot_callback соответственно.

Правило, у которого могут быть исключения: если функция, выступающая в качестве виртуальной функции языка C, возвращает указатель на объект на основе GObject, т.е., на объект с подсчетом ссылок, виртуальная функция языка C++ должна возвращать объект типа Glib::RefPtr<>. При этом необходимо использовать один из следующих дополнительных аргументов макроса: либо refreturn, либо refreturn_ctype.

G.3.6. Другие макросы

G.3.6.1. _IMPLEMENTS_INTERFACE

Данный макрос генерирует код инициализации для интерфейса.
_IMPLEMENTS_INTERFACE(имя интерфейса языка C++)
Пример из файла button.hg:
_IMPLEMENTS_INTERFACE(Activatable)
Также имеется дополнительный аргумент:
ifdef
Разместить сгенерированный код с блоках условной компиляции #ifdef.

G.3.6.2. _WRAP_ENUM

Данный макрос генерирует перечисление языка C++, являющееся оберткой для перечисления языка C. Вы должны указать желаемое имя перечисления языка C++, а также имя лежащего в его основе перечисления языка C.

Пример из фала enums.hg:
_WRAP_ENUM(WindowType, GtkWindowType)

В том случае, если перечисление не относится к типу GType системы типов, вы должны передать третий параметр NO_GTYPE. Это именно тот случай, когда для перечисления языка C не реализована функция *_get_type(), поэтому следует проявлять осторожность и не подключать дополнительный заголовочный файл для этой функции. Вам также следует отправить сообщение об ошибке в API языка C, так как все перечисления должны быть зарегистрированы в системе типов и иметь тип GType.

Пример из файла icontheme.hg:
_WRAP_ENUM(IconLookupFlags, GtkIconLookupFlags, NO_GTYPE)

G.3.6.3. _WRAP_ENUM_DOCS_ONLY

Данный макрос генерирует блок документации Doxygen для рассматриваемого перечисления. Он полезен при работе с перечислениями, обертки для которых не могут быть созданы с помощью макроса _WRAP_ENUM() ввиду их сложного объявления (возможно, с использованием макросов языка C), но добавление сгенерированной документации для перечисления все же желательно. Данный макрос использует такой же синтаксис, как и макрос _WRAP_ENUM() и принимает те же параметры (хотя аргумент NO_GTYPE просто игнорируется из-за того, что регистрация в системе типов не оказывает влияния на генерацию документации перечисления).

G.3.6.4. _WRAP_GERROR

Данный макрос генерирует класс исключения языка C++, унаследованный от класса Glib::Error с перечислением Code и методом code(). Вы должны указать желаемое имя класса языка C++, имя соответствующего перечисления языка C и префикс для значений перечисления языка C.

Это исключение впоследствии может генерироваться методами, которые были сгенерированы с помощью макроса _WRAP_METHOD() с аргументом errthrow.

Пример из файла pixbuf.hg:
_WRAP_GERROR(PixbufError, GdkPixbufError, GDK_PIXBUF_ERROR)

G.3.6.5. _MEMBER_GET / _MEMBER_SET

Используйте эти макросы в том случае, если вы генерируете обертку для простой структуры или специализированной структуры (boxed type), которая предоставляет прямой доступ к своим полям данных, с целью создания методов получения и установки значений полей.
_MEMBER_GET(имя поля языка C++, имя поля языка C, тип поля языка C++, тип поля зыка C)
_MEMBER_SET(имя поля языка C++, имя поля языка C, тип поля зыка C++, тип поля языка C)
Пример из файла rectangle.hg:
_MEMBER_GET(x, x, int, int)

G.3.6.6. _MEMBER_GET_PTR / _MEMBER_SET_PTR

Используйте эти макросы для автоматической генерации методов получения и установки значений для полей данных, представленных указателями. Для получения значения на самом деле будут созданы два метода: один метод для получения неизменного значения и один метод для получения изменяемого значения.
_MEMBER_GET_PTR(имя поля языка C++, имя поля языка C, тип поля языка C++, тип поля языка C)
_MEMBER_SET_PTR(имя поля языка C++, имя поля языка C, тип поля языка C++, тип поля языка C)
Пример для класса Pango::Analysis из файла item.hg:
// _MEMBER_GET_PTR(engine_lang, lang_engine, EngineLang*, PangoEngineLang*)
// Это всего лишь комментарий. На самом деле сложно найти реальный пример использования данного макроса.

G.3.6.7. _MEMBER_GET_GOBJECT / _MEMBER_SET_GOBJECT

Используйте эти макросы для генерации методов получения и установки значений для полей данных, представленных объектами типа GObject, на которые должны устанавливаться ссылки перед получением.
_MEMBER_GET_GOBJECT(имя поля языка C++, имя поля языка C, тип поля языка C++, тип поля языка C)
_MEMBER_SET_GOBJECT(имя поля языка C++, имя поля языка C, тип поля языка C++, тип поля языка C)
Пример для Pangomm из файла layoutline.hg:
_MEMBER_GET_GOBJECT(layout, layout, Pango::Layout, PangoLayout*)

G.3.7. Обработка параметров утилитой gmmproc

Утилита gmmproc может обрабатывать параметры объявлений методов в макросах, которые принимают объявления методов (таких, как _WRAP_METHOD(), _WRAP_CTOR() и _WRAP_CREATE()) различными способами.

G.3.7.1. Изменение порядка следования параметров

Во всех обрабатывающих объявления методов макросах для языка C++ может быть использован порядок следования параметров, отличающийся от порядка следования параметров функции языка C, виртуальной функции или функции обработчика сигналов. Например, предположим, что для следующей функции языка C в качестве обертки был создан метод класса Gtk::Widget языка C++:
void gtk_widget_set_device_events(GtkWidget* widget, GdkDevice* device, GdkEventMask events);
Однако, необходимо изменение порядка следования двух параметров метода языка C++. Макрос, аналогичный следующему, может использоваться для создания обертки в форме метода языка C++ с измененным порядком следования двух параметров:
_WRAP_METHOD(void set_device_events(Gdk::EventMask events{events}, const Glib::RefPtr<const Gdk::Device>& device{device}), gtk_widget_set_device_events)
Директива, использованная после имен параметров метода, сообщает утилите gmmproc о том, что следует поставить в соответствие параметру языка C++ указанный в скобках {} параметр языка C. Так как имена параметров языка C++ соответствуют именам параметров языка C, приведенный выше макрос может быть переписан следующим образом:
_WRAP_METHOD(void set_device_events(Gdk::EventMask events{.}, const Glib::RefPtr<const Gdk::Device>& device{.}), gtk_widget_set_device_events)
Пожалуйста учтите, что при изменении порядка следования параметров описания метода в макросе _WRAP_SIGNAL() имена параметров языка C всегда должны быть p0, p1, и.т.д., так как утилита generate_extra_defs использует такие имена параметров вне зависимости от того, какие имена параметров могут использоваться в API языка C. На данный момент упомянутая утилита работает именно так.

G.3.7.2. Обработка дополнительных параметров

При использовании всех принимающих описания методов макросов за исключением _WRAP_SIGNAL() и _WRAP_VFUNC() имеется возможность сделать параметры необязательными, что приведет к генерации дополнительных методов языка C++ без каждого из указанных необязательных параметров. Например, предположим, что конструктор класса Gtk::ToolButton является оберткой для следующей функции *_new():
GtkToolItem* gtk_tool_button_new(GtkWidget* icon_widget, const gchar* label);
Также предположим, что API языка C позволяет использовать значение NULL для параметра label, поэтому данный параметр является необязательным. Утилита gmmproc должна генерировать оригинальный конструктор (со всеми параметрами) наряду с дополнительным конструктором, не использующим данный параметр, после добавления директивы {?} к имени необязательного параметра таким образом, как показано ниже:
_WRAP_CTOR(ToolButton(Widget& icon_widget, const Glib::ustring& label{?}), gtk_tool_button_new)

В данном случае будут сгенерированы два конструктора: один конструктор с дополнительным параметром и один конструктор без него.

G.3.7.3. Обработка выходных параметров

При использовании макроса _WRAP_METHOD() имеется возможность передачи возвращаемого функцией языка C значения (если оно возвращается) посредством выходного параметра метода языка C++ вместо возврата методом языка C++ значения аналогично функции языка C. Для этого следует просто включить выходной параметр в список параметров метода языка C++ и добавить директиву {OUT} к имени этого параметра. Например, в том случае, если функция gtk_widget_get_request_mode() объявлена следующим образом:
GtkSizeRequestMode gtk_widget_get_request_mode(GtkWidget* widget);
И желательно использовать выходной параметр метода языка C++ вместо возврата значения типа SizeRequestMode, может быть применен аналогичный следующему макрос:
_WRAP_METHOD(void get_request_mode(SizeRequestMode& mode{OUT}) const, gtk_widget_get_request_mode)
Параметр {OUT}, добавленный к имени выходного параметра mode, сообщает утилите gmmproc о том, что следует поместить возвращаемое функцией языка С значение в этот выходной параметр. В данном случае, однако, также должен быть использован необходимый макрос инициализации, аналогичный следующему:
_INITIALIZATION(`SizeRequestMode&',`GtkSizeRequestMode',`$3 = (SizeRequestMode)($4)')
Причем он также может быть записан в следующей форме:
_INITIALIZATION(`SizeRequestMode&',`GtkSizeRequestMode',`$3 = ($1)($4)')
Макрос _WRAP_METHOD() также позволяет использовать в методах языка C++ выходные параметры, связанные с выходными параметрами функций языка C, разумеется, в тех случаях, когда функции языка C имеют такие параметры. Например, предположим, что мы хотим создать обертку для следующей функции языка C, возвращающей значение с помощью выходного параметра rect:
gboolean gtk_icon_view_get_cell_rect(GtkIconView* icon_view, GtkTreePath* path, GtkCellRenderer* cell, GdkRectangle* rect);
Для того, чтобы утилита gmmproc разместила возвращенное значение в выходном параметре rect метода языка C++, должна быть использована аналогичная следующей форма записи директивы в рамках макроса _WRAP_METHOD():
_WRAP_METHOD(bool get_cell_rect(const TreeModel::Path& path, const CellRenderer& cell, Gdk::Rectangle& rect{>>}) const, gtk_icon_view_get_cell_rect)
Директива {>>} после имени параметра rect указывает на то, что значение выходного параметра языка C++ должно быть установлено на основе значения, возвращенного с помощью параметра функции языка C. Утилита gmmproc сгенерирует объявление временной переменной, в которой будет храниться значение, преданное с помощью выходного параметра, а также код для установки значения выходного параметра метода языка C++ на основе значения временной переменной. В этом случае может оказаться необходимым макрос инициализации _INITIALIZATION(), описывающий метод получения типа Gdk::Rectangle& из типа GdkRectangle* и аналогичный следующему макросу:
_INITIALIZATION(`Gdk::Rectangle&',`GdkRectangle', `$3 = Glib::wrap(&($4))')

G.3.8. Базовые типы данных

Некоторые из базовых типов данных, используемых в рамках API языка C, имеют лучшие альтернативы в рамках языка C++. Например, нет необходимости в использовании логического типа данных gboolean, так как язык C++ предлагает аналогичный тип данных bool. В списке ниже представлены некоторые часто используемые в рамках API языка С типы данных, а также те типы данных, в которые вы можете преобразовать их для использования в рамках обертки библиотеки для языка C++.

Эквиваленты базовых типов данных

Тип данных языка C: gboolean

Тип данных языка C++: bool

Тип данных языка C: gint

Тип данных языка C++: int

Тип данных языка C: guint

Тип данных языка C++: guint

Тип данных языка C: gdouble

Тип данных языка C++: double

Тип данных языка C: gunichar

Тип данных языка C++: gunichar

Тип данных языка C: gchar *

Тип данных языка C++: Glib::ustring (или std::string для имен файлов)


Следующий раздел : Приложение G.4. Создаваемые вручную файлы исходного кода.