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

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. Файлы с расширениями .hg и .ccg

Файлы исходного кода с расширениями .hg и .ccg очень похожи на файлы исходного кода языка программирования C++ с расширениями .h и .cc, но они содержат дополнительные макросы, такие, как _CLASS_GOBJECT() и _WRAP_METHOD(), с помощью которых утилита gmmproc генерирует соответствующий исходный код на языке C++ обычно с таким же расположением заголовочных файлов. Любой дополнительный код на языке C++ будет скопирован в неизменном виде в соответствующий файл с расширением .h или .cc.

В рамках файла с расширением .hg обычно осуществляется подключение некоторых заголовочных файлов с последующим объявлением класса, в котором используются некоторые макросы для описания API или поведения класса. Например, файл button.hg из исходного кода gtkmm выглядит примерно следующим образом:

В данном примере макросы выполняют следующие функции:
_DEFS()
Указывает целевую директорию для сгенерированных файлов исходного кода и имя основного файла с расширением .defs, который должен быть разобран с помощью утилиты gmmproc.
_PINCLUDE()
Сообщает утилите gmmproc о необходимости подключения заголовочного файла к сгенерированному файлу private/button_p.h.
_CLASS_GTKOBJECT()
Сообщает утилите gmmproc о необходимости добавления объявлений типов с использованием операторов typedef, конструкторов и стандартных методов для данного класса, характерных для оберток классов виджетов.
_IMPLEMENTS_INTERFACE()
Сообщает утилите gmmproc о необходимости добавления кода инициализации для интерфейса.
_CTOR_DEFAULT
Добавление стандартного конструктора.
_WRAP_METHOD(), _WRAP_SIGNAL() и _WRAP_PROPERTY()
Добавление методов для создания оберток над функциями API языка программирования C.
Файлы .h и .cc будут генерироваться на основе файлов .hg и .ccg путем обработки последних с помощью утилиты gmmproc, причем это будет делаться автоматически в случае использования описанной структуры директорий для сборки:
$ cd gtk/src
$ /usr/lib/glibmm-2.4/proc/gmmproc -I ../../tools/m4 --defs . button . ./../gtkmm

Обратите внимание на то, что мы передали утилите gmmproc путь к файлам преобразований с расширением .m4, путь к файлам с расширением .defs, имя файла с расширением .hg, путь к директории исходного кода, а также путь к директории для сохранения сгенерированных файлов.

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

Макросы будут описаны более подробно в следующих разделах.

G.3.1. Преобразования типов с использованием файлов преобразований с расширением .m4

При обработке использованных вами в файлах с расширениями .hg и .cgg макросов обычно требуется информация о том, как преобразовать тип языка C++ в тип языка C или наоборот. Утилита gmmproc получает эту информацию из файла преобразования с расширением .m4, находящегося в вашей директории tools/m4/. Эта информация позволяет вызвать функцию языка C с помощью метода языка C++, передавая соответствующие параметры данной функции языка C. Например, данный макрос сообщает утилите gmmproc о том, как преобразовать указатель типа GtkTreeView в указатель типа Gtk::TreeView:
_CONVERSION(`GtkTreeView*',`TreeView*',`Glib::wrap($3)')

Строка "$3" будет заменена на имя параметра в момент, когда этот макрос преобразования будет обработан утилитой gmmproc.

Некоторые дополнительные макросы позволяют сделать это проще и понятнее. Для ознакомления с их примерами вы можете использовать файлы преобразования с расширением .m4 из исходного кода gtkmm. Некоторые из упомянутых макросов:
_CONVERSION(`PrintSettings&',`GtkPrintSettings*',__FR2P)
_CONVERSION(`const PrintSettings&',`GtkPrintSettings*',__FCR2P)
_CONVERSION(`const Glib::RefPtr<Printer>&',`GtkPrinter*',__CONVERT_REFPTR_TO_P($3))

G.3.2. Инициализации с использованием файлов преобразований с расширением .m4

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

Например, в том случае, если имеется функция языка С, возвращающая указатель типа GtkWidget* и по какой-либо причине вместо метода языка C++, который возвращает объект виджета, желательно создать метод языка С++, который будет возвращать объект виджета с помощью указанного параметра, потребуется аналогичный приведенному ниже макрос инициализации:
_INITIALIZATION(`Gtk::Widget&',`GtkWidget*',`$3 = Glib::wrap($4)')

Строка "$3" будет заменена на имя выходного параметра метода C++, а строка "$4" - на возвращаемое значение функции языка C в момент обработки данного макроса с помощью утилиты gmmproc. Для удобства строка "$1" также заменяется на тип языка C++ без амперсанта (&), а строка "$2" - на тип языка C.

G.3.3. Макрос класса

Макрос класса описывает сам класс, а также способ его взаимодействия с лежащим в основе типом языка C. Он позволяет генерировать некоторые внутренние конструкторы, методы gobject_, объявления типов с использованием оператора typedef, методы доступа gobj(), производить регистрацию типов, а также генерировать реализацию метода Glib::wrap() помимо других вещей.

Другие макросы, такие, как _WRAP_METHOD() и _WRAP_SIGNAL() могут использоваться исключительно после использования макроса _CLASS_*.

G.3.3.1. _CLASS_GOBJECT

Данный макрос описывает обертку для типа, унаследованного от типа GObject, причем класс этой обертки не наследуется от класса Gtk::Object.
_CLASS_GOBJECT_CLASS_GOBJECT( класс языка C++, класс языка C, макрос преобразования языка C, базовый класс языка C++, базовый класс языка C )
Пример использования макроса из файла accelgroup.hg:
_CLASS_GOBJECT(AccelGroup, GtkAccelGroup, GTK_ACCEL_GROUP, Glib::Object, GObject)

G.3.3.2. _CLASS_GTKOBJECT

Данный макрос описывает обертку для типа, причем класс этой обертки унаследован от класса Gtk::Object, как класс виджета или диалога.
_CLASS_GTKOBJECT( класс языка C++, класс языка C, макрос преобразования языка C, базовый класс языка C++, базовый класс языка C )
Пример использования макроса из файла button.hg:
_CLASS_GTKOBJECT(Button, GtkButton, GTK_BUTTON, Gtk::Bin, GtkBin)

Обычно вы будете использовать данный макрос в том случае, если класс уже унаследован от класса Gtk::Object. Например, вы будете использовать его при создании обертки для виджета из состава GTK+, так как класс Gtk::Widget наследуется от класса Gtk::Object.

Вы также можете наследовать классы, не имеющие отношения к виджетам, от класса Gtk::Object, причем в этом случае они смогут использоваться без умного указателя типа Glib::RefPtr. К примеру, экземпляры данных классов могут создаваться с помощью метода Gtk::manage() или в стеке с использованием переменной класса. Работать с подобными объектами достаточно удобно, но вы должны использовать описанный подход только тогда, когда уверены в том, что реальный подсчет ссылок не требуется. Мы считаем данный подход полезным для работы с виджетами.

G.3.3.3. _CLASS_BOXEDTYPE

Данный макрос описывает обертку для структуры, не имеющей отношения к системе типов GObject и регистрируемой с помощью функции g_boxed_type_register_static().
_CLASS_BOXEDTYPE( класс языка C++, класс языка C, функция создания, функция копирования, функция освобождения зарезервированной для хранения памяти )
Пример из файла для класса Gdk::RGBA:
_CLASS_BOXEDTYPE(RGBA, GdkRGBA, NONE, gdk_rgba_copy, gdk_rgba_free)

G.3.3.4. _CLASS_BOXEDTYPE_STATIC

Данный макрос описывает обертку для простой структуры с поддержкой операции присваивания значения, такой, как GdkRectangle. Он аналогичен макросу _CLASS_BOXEDTYPE, но в данном случае структура языка C не создается динамически.
_CLASS_BOXEDTYPE_STATIC( класс языка C++, класс языка C )
Пример из файла для класса Gdk::Rectangle:
_CLASS_BOXEDTYPE_STATIC(Rectangle, GdkRectangle)

G.3.3.5. _CLASS_OPAQUE_COPYABLE

Данный макрос описывает обертку для специализированной структуры, для которой существуют функции копирования и освобождения зарезервированной для ее хранения памяти. Функции создания структуры, ее копирования и освобождения зарезервированной для ее хранения памяти будут использоваться для создания стандартного конструктора, конструктора копирования и деструктора соответственно.
_CLASS_OPAQUE_COPYABLE( класс языка C++, класс языка C, функция создания, функция копирования, функция освобождения зарезервированной для хранения памяти )
Пример из файла для класса Gdk::Checksum:
_CLASS_OPAQUE_COPYABLE(Checksum, GChecksum, NONE, g_checksum_copy, g_checksum_free)

G.3.3.6. _CLASS_OPAQUE_REFCOUNTED

Данный макрос описывает обертку для специализированной структуры с подсчетом ссылок. Экземпляр класса обертки для языка C++ не может непосредственно создаваться и должен использоваться исключительно посредством умного указателя типа Glib::RefPtr.
_CLASS_OPAQUE_REFCOUNTED( класс языка C++, класс языка C, функция создания структуры, функция создания ссылки, функция удаления ссылки )
Пример из файла для класса Pango::Coverage:
_CLASS_OPAQUE_REFCOUNTED(Coverage, PangoCoverage, pango_coverage_new, pango_coverage_ref, pango_coverage_unref)

G.3.3.7. _CLASS_GENERIC

Данный макрос может использоваться при создании оберток для структур, которые нельзя отнести ни к одной из перечисленных выше категорий.
_CLASS_GENERIC( класс языка C++, класс языка C )
Пример из файла для класса Pango::AttrIter:
_CLASS_GENERIC(AttrIter, PangoAttrIterator)

G.3.3.8. _CLASS_INTERFACE

Данный макрос описывает обертку для типа, который наследуется от типа GTypeInterface.
_CLASS_INTERFACE( класс языка C++, класс языка C, макрос преобразования языка C, структура интерфейса языка C, базовый класс языка C++ (необязательно), базовый класс языка C (необязательно) )
Пример из файла celleditable.hg:
_CLASS_INTERFACE(CellEditable, GtkCellEditable, GTK_CELL_EDITABLE, GtkCellEditableIface)

Два последних параметра являются необязательными и предназначены для тех случаев, когда описываемый интерфейс наследуется от другого интерфейса, что происходит тогда, когда класс на основе класса GInterface наследуется от другого класса на основе класса GInterface.

Пример из файла loadableicon.hg:
_CLASS_INTERFACE(LoadableIcon, GLoadableIcon, G_LOADABLE_ICON, GLoadableIconIface, Icon, Gicon)

G.3.4. Макросы конструктора

Макросы _CTOR_DEFAULT() и _WRAP_CTOR() добавляют конструкторы, создавая обертки над указанным функциями *_new() языка C. Эти макросы предполагают, что объект языка C имеет свойства с теми же именами, что и параметры функции, как обычно и бывает, поэтому он может непосредственно передавать параметры функции g_object_new(). Эти конструкторы на самом деле никогда не вызывают функции *_new() языка C, так как в реальности gtkmm приходится создавать экземпляры классов, соответствующих унаследованным от типа GType типам, а функции *_new() языка C являются всего лишь вспомогательными функциями для разработчиков, использующих язык программирования C.

При использовании макроса _CLASS_GOBJECT() конструкторы должны быть объявлены как защищенные (protected) (а не как публичные (public)) члены класса, причем каждый конструктор должен иметь соответствующий макрос _WRAP_CREATE() в секции для публичных объявлений. Такой подход предотвращает создание экземпляра класса без использования умного указателя типа Glib::RefPtr. Пример такого объявления:
class TextMark : public Glib::Object
{
  _CLASS_GOBJECT(TextMark, GtkTextMark, GTK_TEXT_MARK, Glib::Object, GObject)

protected:
  _WRAP_CTOR(TextMark(const Glib::ustring& name, bool left_gravity = true), gtk_text_mark_new)

public:
  _WRAP_CREATE(const Glib::ustring& name, bool left_gravity = true)

G.3.4.1. _CTOR_DEFAULT

Данный макрос создает стандартный конструктор без аргументов.

G.3.4.2. _WRAP_CTOR

Данный макрос создает конструктор с аргументами, эквивалентный функции *_new() языка C. На самом деле этот макрос не будет использовать функцию *_new(), а просто создаст эквивалентный конструктор с такими же типами аргументов. Он принимает описание конструктора языка C++ и имя функции языка C.

Также он принимает один дополнительный необязательный аргумент:
errthrow
Данный аргумент сообщает утилите gmmproc о том, что функция *_new() языка C имеет последний параметр типа GError**, который должен игнорироваться.

G.3.4.3. Создание конструкторов вручную

В том случае, если конструктор должен быть частично создан вручную, что бывает, к примеру, тогда, когда параметры функции *_new() языка C в точности не соответствуют свойствам объекта или тогда, когда функция *_new() языка C выполняет дополнительные действия помимо вызова функции g_object_new(), в файле с расширением .ccg также может быть использован макрос _CONSTRUCT() для сокращения объема работы. Макрос _CONSTRUCT принимает наборы имен свойств и значений. Пример из файла button.ccg:
Button::Button(const Glib::ustring& label, bool mnemonic)
:
  _CONSTRUCT("label", label.c_str(), "use_underline", gboolean(mnemonic))
{}

Следующий раздел : Приложение G.3.5. Макросы методов.