Les fichiers .hg et .ccg

Les fichiers sources .hg et .ccg ressemblent tout à fait aux fichiers sources .h et .cc du C++, mais il comportent des macros supplémentaires, telles que _CLASS_GOBJECT() et _WRAP_METHOD(), à partir desquelles gmmproc génére le code source C++ approprié, habituellement à la même position dans l'en-tête. Tout code source C++ sera copié mot pour mot dans le fichier .h ou .cc correspondant.

Un fichier .hg inclut habituellement certains fichiers d'en-tête, puis déclare une classe en utilisant certaines macros pour ajouter l'API ou certains comportements pour cette classe. Par exemple, button.hg de gtkmm ressemble grossièrement à ceci :

#include <gtkmm/bin.h>
#include <gtkmm/stockid.h>
_DEFS(gtkmm,gtk)
_PINCLUDE(gtkmm/private/bin_p.h)

namespace Gtk
{

class Button : public Bin
{
  _CLASS_GTKOBJECT(Button,GtkButton,GTK_BUTTON,Gtk::Bin,GtkBin)
public:

  _CTOR_DEFAULT
  explicit Button(const Glib::ustring& label, bool mnemonic = false);
  explicit Button(const StockID& stock_id);

  _WRAP_METHOD(void set_label(const Glib::ustring& label), gtk_button_set_label)

  ...

  _WRAP_SIGNAL(void clicked(), "clicked")

  ...

  _WRAP_PROPERTY("label", Glib::ustring)
};

} // espace de nom Gtk

Les macros employées dans cet exemple effectuent les tâches suivantes :

_DEFS()

précise le répertoire de destination pour les sources générées et le nom des principaux fichiers .defs que gmmproc doit analyser.

_PINCLUDE()

indique à gmmproc d'inclure un en-tête à partir du fichier private/button_p.h.

_CLASS_GTKOBJECT()

demande à gmmproc d'ajouter de manière appropriée quelques définitions de types, constructeurs et fonctions membres standard à cette classe lors de l'habillage d'un type dérivé de GtkObject.

_WRAP_METHOD(), _WRAP_SIGNAL() et _WRAP_PROPERTY()

ajoute des fonctions membres pour habiller des parties de l'API C.

Les fichiers .h et .cc sont générées à partir des fichiers .hg et .ccg en les traitant de la sorte avec gmmproc, bien que ceci se fasse automatiquement en utilisant la structure de construction suivante :

$ cd gtk/src
$ /usr/lib/glibmm-2.4/proc/gmmproc -I ../../tools/m4 --defs . button . ./../gtkmm

Notez que nous appelons gmmproc avec comme paramètre le chemin vers les fichiers .m4 convertis, le chemin vers les fichiers .defs, le nom du fichier .hg, le répertoire source et le répertoire destination.

Nous nous abstenons d'inclure le fichier d'en-tête C à partir de l'en-tête C++ pour éviter de polluer l'espace de noms global et pour éviter d'exporter des API publiques non nécessaires. Mais vous aurez besoin d'inclure les en-têtes C nécessaires à partir de votre fichier .ccg.

Les macros sont expliquées plus en détail dans les paragraphes suivants.

G.III.I. Conversions m4

Les macros utilisées dans les fichiers .hg et .ccg ont souvent besoin de savoir comment convertir un type C++ en type C ou vice-versa. gmmproc prend cette information dans un fichier .m4 du répertoire tools/m4/. Celle-ci lui permet d'appeler une fonction C dans l'implémentation de votre fonction membre C++, en passant les paramètres appropriés à cette fonction C. Par exemple, cette macro indique à gmmproc comment convertir un pointeur GtkTreeView en pointeur Gtk::TreeView :

_CONVERSION(`GtkTreeView*',`TreeView*',`Glib::wrap($3)')

$3 sera remplacé par le nom du paramètre lorsque cette conversion est utilisée par gmmproc.

Quelques macros supplémentaires rendent ceci plus facile et plus cohérent. Regardez dans les fichiers .m4 pour des exemples. Ainsi :

_CONVERSION(`PrintSettings&',`GtkPrintSettings*',__FR2P)
_CONVERSION(`const PrintSettings&',`GtkPrintSettings*',__FCR2P)
_CONVERSION(`const Glib::RefPtr<Printer>&',`GtkPrinter*',__CONVERT_REFPTR_TO_P($3))

G.III.II. Macros de classes

La macro de classe déclare la classe elle-même et ses relations avec le type C sous-jacent. Elle génère certains constructeurs internes, la variable membre gobject_, des définitions de types, les mécanismes d'accès aux gobj(), l'enregistrement du type et la fonction membre Glib::wrap(), entre autres choses.

D'autres macros, telles que _WRAP_METHOD() et _SIGNAL() ne peuvent être utilisées qu'après un appel de la macro _CLASS_*.

G.III.II.I. _CLASS_GOBJECT

Cette macro déclare un habillage pour un type dérivé de GObject, mais non-dérivé de GtkObject.

_CLASS_GOBJECT( C++ class, C class, C casting macro, C++ base class, C base class )

Par exemple, à partir de accelgroup.hg :

_CLASS_GOBJECT(AccelGroup, GtkAccelGroup, GTK_ACCEL_GROUP, Glib::Object, GObject)

G.III.II.II. _CLASS_GTKOBJECT

Cette macro déclare un habillage pour un type dérivé de GtkObject, tel un élément graphique ou une boîte de dialogue.

_CLASS_GTKOBJECT( C++ class, C class, C casting macro, C++ base class, C base class )

Par exemple, à partir de button.hg :

_CLASS_GTKOBJECT(Button, GtkButton, GTK_BUTTON, Gtk::Bin, GtkBin)

G.III.II.III. _CLASS_BOXEDTYPE

Cette macro déclare un habillage pour une structure non-GObject, enregistrée avec g_boxed_type_register_static().

_CLASS_BOXEDTYPE( C++ class, C class, new function, copy function, free function )

Par exemple, pour Gdk::Color :

_CLASS_BOXEDTYPE(Color, GdkColor, NONE, gdk_color_copy, gdk_color_free)

G.III.II.IV. _CLASS_BOXEDTYPE_STATIC

Cette macro déclare un habillage pour une simple structure assignable comme un GdkRectangle. Elle est semblable à _CLASS_BOXEDTYPE, mais la structure C n'est pas allouée dynamiquement.

_CLASS_BOXEDTYPE_STATIC( C++ class, C class )

Par exemple, pour Gdk::Rectangle :

_CLASS_BOXEDTYPE_STATIC(Rectangle, GdkRectangle)

G.III.II.V. _CLASS_OPAQUE_COPYABLE

Cette macro déclare un habillage pour une structure opaque possédant des fonctions de copie et de libération. Les fonctions new, copy et free seront utilisées pour instancier le constructeur par défaut, le constructeur de copie et le destructeur.

_CLASS_OPAQUE_COPYABLE( C++ class, C class, new function, copy function, free function )

Par exemple, pour Gdk::Region :

_CLASS_OPAQUE_COPYABLE(Region, 
                       GdkRegion,
                       gdk_region_new,
                       gdk_region_copy,
                       gdk_region_destroy)

G.III.II.VI. _CLASS_OPAQUE_REFCOUNTED

Cette macro déclare un habillage pour une structure opaque à décompte de références. L'habillage C++ ne peut pas être directement instancié et ne peut être utilisé qu'avec un pointeur intelligent Glib::RefPtr.

_CLASS_OPAQUE_COPYABLE( C++ class, C class, new function, ref function, unref function )

Par exemple, pour Pango::Coverage :

_CLASS_OPAQUE_REFCOUNTED(Coverage, 
                         PangoCoverage, 
                         pango_coverage_new, 
                         pango_coverage_ref, 
                         pango_coverage_unref)

G.III.II.VII. _CLASS_GENERIC

Cette macro peut être utilisée pour habiller les structures n'entrant pas dans une catégorie particulière.

_CLASS_GENERIC( C++ class, C class )

Par exemple, pour Pango::AttrIter :

_CLASS_GENERIC(AttrIter, PangoAttrIterator)

G.III.II.VIII. _CLASS_INTERFACE

Cette macro déclare un habillage pour un type dérivé de GObject, mais non-dérivé de GtkObject.

_CLASS_INTERFACE( C++ class, C class, C casting macro, C interface struct, Base C++ class (optional), Base C class (optional) )

Par exemple, pour celleditable.hg :

  _CLASS_INTERFACE(CellEditable,
                   GtkCellEditable,
                   GTK_CELL_EDITABLE,
                   GtkCellEditableIface)

Deux paramètres sont optionnels, dans le cas où l'interface dérive d'une autre interface, ce qui doit être le cas quand la GInterface a une autre GInterface prérequise. Par exemple, pour loadableicon.hg :

  _CLASS_INTERFACE(LoadableIcon,
                   GLoadableIcon,
                   G_LOADABLE_ICON,
                   GLoadableIconIface,
                   Icon,
                   GIcon)

G.III.III. Macros de constructeurs

Les macros _CTOR_DEFAULT() et _WRAP_CTOR() ajoutent des constructeurs, habillant les fonctions C *_new() spécifiées. Ces macros supposent que l'objet C a des propriétés de même nom que les paramètres de la fonction, ce qui est habituellement le cas ; ainsi il peut fournir les paramètres directement pour l'appel de g_object_new(). Ces constructeurs en réalité n'appellent jamais les fonctions C *_new(), car gtkmm doit en fait instancier des types GTypes dérivés et les fonctions C *_new() ne sont conçues que comme fonctions de commodité pour les programmeurs C.

Quand on utilise _CLASS_GOBJECT(), il faut que les constructeurs soient protégés (plutôt que publics) et chaque constructeur doit posséder une fonction correspondante _WRAP_CREATE() dans la section public. Ceci empêche l'instanciation de la classe sans utiliser de RefPtr. Par exemple :

class ActionGroup : public Glib::Object
{
  _CLASS_GOBJECT(ActionGroup, GtkActionGroup,
                 GTK_ACTION_GROUP, Glib::Object, GObject)

protected:
  _WRAP_CTOR(ActionGroup(const Glib::ustring& name = Glib::ustring()),
             gtk_action_group_new)

public:
  _WRAP_CREATE(const Glib::ustring& name = Glib::ustring())

G.III.III.I. _CTOR_DEFAULT

Cette macro crée un constructeur par défaut sans paramètre.

G.III.III.II. _WRAP_CTOR

Cette macro crée un constructeur avec paramètres, équivalent à la fonction C *_new(). Elle n'appelle pas réellement la fonction *_new(), mais elle crée simplement un constructeur équivalent avec les mêmes types de paramètres. Elle prend en paramètres la signature d'un constructeur C++ et un nom de fonction C.

G.III.III.III. Constructeurs codés à la main

Quand un constructeur doit être partiellement écrit à la main parce que, par exemple, les paramètres de la fonction C *_new() ne correspondent pas directement aux propriétés de l'objet ou parce que la fonction C *_new() fait plus qu'appeler g_object_new(), la macro _CONSTRUCT() peut s'utiliser dans le fichier .ccg pour s'économiser un peu de travail. La macro _CONSTRUCT prend comme paramètres une série de noms de propriétés et de valeurs. Par exemple, pour button.ccg :

Button::Button(const Glib::ustring& label, bool mnemonic)
:
  _CONSTRUCT("label", label.c_str(), "use_underline", gboolean(mnemonic))
{}

G.III.IV. Macros pour fonctions membres

G.III.IV.I. _WRAP_METHOD

Cette macro génère une fonction membre C++ habillant une fonction C.

_WRAP_METHOD( C++ method signature, C function name)

Par exemple, pour entry.hg :

_WRAP_METHOD(void set_text(const Glib::ustring& text), gtk_entry_set_text)

La fonction C (par exemple, gtk_entry_set_text) est décrite plus précisément dans les fichiers .defs et les fichiers convert*.m4 contiennent la conversion nécessaire des types de paramètres C++ vers les paramètres de type C. Cette macro génère également des commentaires pour la documentation doxygen à partir des fichiers *_docs.xml et *_docs_override.xml.

Il y a quelques paramètres optionnels supplémentaires :

refreturn

effectue un appel supplémentaire à reference() sur la valeur de retour au cas où la fonction C ne fournirait pas de référence.

errthrow

utilise le dernier paramètre GError* de la fonction C pour déclencher une exception.

deprecated

place le code généré dans un bloc #ifdef. Le texte concernant l'abandon peut être précisé en tant que paramètre optionnel.

constversion

appelle simplement la version non-const de la même fonction au lieu de générer du code dupliqué.

Même s'il est généralement évident que les types C++ devraient être utilisés dans les fonctions membres C++, voici quelques astuces :

  • Objets utilisés par l'intermédiaire d'un RefPtr : passez le RefPtr en tant que référence const, par exemple, const Glib::RefPtr<Gtk::Action>& action.
  • Objets const utilisés par l'intermédiaire d'un RefPtr : si l'objet ne doit pas être modifié par la fonction, assurez-vous que l'objet est const, même si le RefPtr est déjà const, par exemple, const Glib::RefPtr<const Gtk::Action>& action.
  • Wrapping GList* and GSList* parameters: First, you need to discover what objects are contained in the list's data field for each item, usually by reading the documentation for the C function. The list can then be wrapped by a std::vector type. For instance, std::vector< Glib::RefPtr<Action> >. You may need to define a Traits type to specify how the C and C++ types should be converted.
  • Habillage des types de retour des GList* et GSList* : vous devez découvrir comment l'appelant libère la liste et comment il libère les éléments de la liste, à nouveau en lisant la documentation de la fonction C. Avec ces informations vous pouvez choisir le type de propriété (aucun (none), superficiel (shallow), profond (deep)) pour la règle de conversion m4, règle que vous placerez probablement directement dans le fichier .hg parce que le type de propriété dépend plutôt de la fonction que du type, par exemple :
    #m4 _CONVERSION(`GSList*',`std::vector<Widget*>',`Glib::SListHandler<Widget*>::slist_to_vector($3, Glib::OWNERSHIP_SHALLOW)')

G.III.IV.II. _WRAP_METHOD_DOCS_ONLY

Cette macro est comparable à la macro _WRAP_METHOD(), mais elle ne génère la documentation que dans le cas d'une fonction membre C++ habillant une fonction C. Utilisez-la si vous devez coder à la main la fonction membre, mais vous voulez utiliser la documentation qui serait générée si la fonction membre était générée.

_WRAP_METHOD_DOCS_ONLY(C function name)

Par exemple, pour container.hg :

_WRAP_METHOD_DOCS_ONLY(gtk_container_remove)

G.III.IV.III. _IGNORE()

gmmproc émet un avertissement sur stdout à propos des fonctions que vous avez oubliées d'habiller, pour vous aider à être sûr d'avoir bien habillé la totalité de l'API. Mais si vous ne voulez pas habiller certaines fonctions ou si vous avez choisi de coder à la main certaines fonctions membres, vous pouvez alors utiliser la macro _IGNORE() pour que gmmproc arrête de se plaindre.

_IGNORE(C function name 1, C function name2, etc)

Par exemple, pour buttonbox.hg :

_IGNORE(gtk_button_box_set_spacing, gtk_button_box_get_spacing,

G.III.IV.IV. _WRAP_SIGNAL

Cette macro génère le signal C++ de style libsigc++ habillant un signal C GObject. Il génère en fait un mécanisme d'accès public, comme signal_clicked(), qui renvoie un objet mandataire. gmmproc utilise le fichier .defs pour découvrir le type des paramètres du C et les fichiers de conversion .m4 pour découvrir les types de conversion appropriés.

_WRAP_SIGNAL( C++ signal handler signature, C signal name)

Par exemple, à partir de button.hg :

_WRAP_SIGNAL(void clicked(),"clicked")

Les signaux ont généralement des pointeurs de fonction dans la structure GTK, avec une valeur d'énumération correspondante, et une fonction g_signal_new() dans le fichier .c.

Il y a quelques paramètres optionnels supplémentaires :

no_default_handler

ne pas générer une fonction membre virtuelle on_something() pour faciliter la surdéfinition du gestionnaire de signal par défaut. Ce paramètre est à utiliser quand l'ajout d'un signal avec son gestionnaire par défaut casserait l'ABI (Application Binary Interface) en augmentant la taille de la table des fonctions virtuelles de la classe.

G.III.IV.V. _WRAP_PROPERTY

Cette macro génère une fonction membre C++ habillant une propriété d'un GObject C. Vous devez indiquer le nom de la propriété et le type C++ souhaité pour la propriété. gmmproc utilise le fichier .defs pour connaître le type C et les fichiers de conversion .m4 pour découvrir les types appropriés de conversion.

_WRAP_PROPERTY(C property name, C++ type)

Par exemple, à partir de button.hg :

_WRAP_PROPERTY("label", Glib::ustring)

G.III.V. Autres macros :

G.III.V.I. _WRAP_ENUM

Cette macro génère une énumération C++ pour habiller une énumération C. Vous devez préciser le nom C++ et le nom de l'énumération C subjacente.

Par exemple, pour widget.hg :

_WRAP_ENUM(WindowType, GdkWindowType)

Si l'énumération n'est pas du type GType, vous devrez passer comme troisième paramètre NO_GTYPE. C'est le cas lorsqu'il n'existe pas de fonction *_get_type() pour l'énumération C ; mais, faites attention au fait qu'il n'est pas suffisant d'inclure un en-tête supplémentaire pour cette fonction. Vous devez également faire un rapport d'anomalie concernant l'API C étant donné que toutes les énumérations doivent être enregistrées en tant que GTypes.

Par exemple :

_WRAP_ENUM(IconLookupFlags, GtkIconLookupFlags)

G.III.V.II. _WRAP_GERROR

Cette macro génère une classe d'exception C++, dérivée de Glib::Error, avec un Code enum et une fonction membre code(). Vous devez préciser le nom C++ souhaité, le nom de l'énumération correspondante C et le préfixe pour les valeurs d'énumération C.

Cette exception peut alors être déclenchée par des fonctions membres générées par _WRAP_METHOD() avec l'option errthrow.

Par exemple, pour pixbuf.hg :

_WRAP_GERROR(PixbufError, GdkPixbufError, GDK_PIXBUF_ERROR)

G.III.V.III. _MEMBER_GET / _MEMBER_SET

Si vous habillez une simple structure ou un type de boîte qui autorise un accès direct à ses données membres, utilisez ces macros pour créer les obtenteurs (get) et mutateurs (set) des données membres.

_MEMBER_GET(C++ name, C name, C++ type, C type)

_MEMBER_SET(C++ name, C name, C++ type, C type)

Par exemple, dans rectangle.hg :

_MEMBER_GET(x, x, int, int)

G.III.V.IV. _MEMBER_GET_PTR / _MEMBER_SET_PTR

Utilisez ces macros pour créer automatiquement des obtenteurs (get) et des mutateurs (set) pour une donnée membre du type pointeur. Pour le mécanisme d'obtention, elle créera deux fonctions membres, une qualifiée const et une non-const.

_MEMBER_GET_PTR(C++ name, C name, C++ type, C type)

_MEMBER_SET_PTR(C++ name, C name, C++ type, C type)

Par exemple, dans dialog.hg :

_MEMBER_GET_PTR(vbox, vbox, VBox*, GtkWidget*)

G.III.V.V. _MEMBER_GET_GOBJECT / _MEMBER_SET_GOBJECT

Utilisez cette macro pour fournir des obtenteurs (get) et des mutateurs (set) pour une donnée membre du type GObject nécessitant un référencement avant renvoi.

_MEMBER_GET_GOBJECT(C++ name, C name, C++ type, C type)

_MEMBER_SET_GOBJECT(C++ name, C name, C++ type, C type)

Par exemple, dans progress.hg :

_MEMBER_GET_GOBJECT(offscreen_pixmap, offscreen_pixmap, Gdk::Pixmap, GdkPixmap*)

G.III.VI. Types de base

Certains types de base utilisés dans les API C possèdent une meilleure typologie en C++. Par exemple, il n'est pas nécessaire d'avoir un type gboolean puisque le C++ dispose du type bool. La liste suivante montre quelques types couramment utilisés dans les API C, types que vous pouvez convertir dans la bibliothèque d'habillage C++.

Équivalents des types de base

Types C: gboolean

Types C++: bool

Types C: gint

Types C++: int

Types C: guint

Types C++: guint

Types C: gdouble

Types C++: double

Types C: gunichar

Types C++: gunichar

Types C: gchar*

Types C++: Glib::ustring (ou std::string pour les noms de fichiers)