Créer  Editer  FrontPage  Index  Chercher  Changements  History  RSS  Login

Comment implementer Ruby-GNOME2

Comment implémenter Ruby-GNOME2

Ce document explique comment implémenter une extension Ruby-GNOME2.

Signaux, propriétés

Des méthodes accesseurs sont automatiquement générées pour les propriétés. Les signaux sont également supportés directement par GLib::Instantiatable#signal_connect. Vous n'avez donc plus besoin de les implémenter manuellement.

Macros

Vous devez savoir qu'il existe plusieurs macros qui peuvent vous aider à implémenter votre nouvelle classe/module plus facilement. La plupart de ces macros sont dans les fichiers d'entête glib/src/rbgobject.h, rbglib.h et gtk/src/rbgtk.h.

Définition d'une classe ou d'une interface

Ces macros sont utilisées dans les fonctions Init_*().

G_DEF_CLASS(gtype, name, module)
G_DEF_CLASS2(gtype, name, module, mark, free)
Définit une classe. La seconde macro vous permet de définir manuellement les fonctions de marquage et de libération de la mémoire, utilisées par le ramasse-miettes *1.
G_DEF_INTERFACE(gtype, name, module)
G_DEF_INTERFACE2(gtype, name, module, mark, free)
Définit un module. La seconde macro vous permet de définir manuellement les fonctions de marquage et de libération de la mémoire, utilisées par le ramasse-miettes.
void rbgobj_boxed_not_copy_obj(GType gtype)
Utilisez cette fonction si l'objet GBoxed ne doit pas être copié pendant une conversion vers une valeur Ruby (par exemple dans GBOXED2RVAL ou G_INITIALIZE).

Initialisation d'un objet

Ces macros sont utilisées dans les constructeurs de classes (méthodes initialize).

G_INITIALIZE(obj, cobj)
RBGTK_INITIALIZE(obj, gtkobj)
RBGST_INITIALIZE(obj, gstobj)
Initialise un objet. Si cette classe hérite de GtkObject, utilisez RBGTK_INITIALIZE. Si cette classe hérite de GstObject, utilisez RBGST_INITIALIZE.

Conversion Ruby <-> GLib

RVAL2GOBJ(obj)
GOBJ2RVAL(gobj)
VALUE(GLib::Object) <-> GObject
RVAL2BOXED(obj)
BOXED2RVAL(cobj, gtype)
VALUE(GLib::Boxed) <-> GBoxed
RVAL2CSTR(v)
CSTR2RVAL(s)
VALUE(String) <-> gchar*
RVAL2CBOOL(v)
CBOOL2RVAL(b)
VALUE(true or false) <-> gboolean
GVAL2RVAL(v)
GValue(GLib::Value?) -> RValue. RVAL2GVAL(v) n'est pas encore implémenté. Si vous désirez convertir une valeur Ruby en valeur GLib, utilisez alors rbgobj_rvalue_to_gvalue():
GValue gval = {0,};
g_value_init(&gval, RVAL2GTYPE(value));

rbgobj_rvalue_to_gvalue(value, &gval);
/* Ensuite, utilisez gval... */
GEV2RVAL(ev)
RVAL2GEV(ev)
VALUE(Gtk::Event?) <-> GtkEvent
GLIST2ARY(list)
GSLIT2ARY(list)
GList/GSList of GObject -> Array
GLIST2ARY2(list)
GSLIT2ARY2(list)
GList/GSList of GBoxed -> Array

Conversion RGObjClassInfo <-> GType, classe/instance Ruby

CLASS2CINFO(klass)
Class -> RGObjClassInfo
GTYPE2CINFO(gtype)
GType -> RGObjClassInfo
RVAL2CINFO(obj)
VALUE -> RGObjClassInfo

Conversion GType <-> Classe/instance Ruby

GTYPE2CLASS(gtype)
GType -> Class
CLASS2GTYPE(klass)
Class -> GType
RVAL2GTYPE(obj)
VALUE -> GType

Relations

Ces macros permettent d'interagir avec le ramasse-miettes. Dans ces macros, obj est généralement la variable self et rel est le widget/objet fils ou un objet proc.

G_RELATIVE(obj, rel)
Etabit une relation. L'objet ne sera pas détruit par le ramasse-miettes.
G_RELATIVE2(obj, rel, id, hash_key)
Etabit une relation. L'objet ne sera pas détruit par le ramasse-miettes. Cette relation peut-être retirée avec la macro suivante.
G_REMOVE_RELATIVE(obj, id, hash_key)
Retire une relation existante.

Méthodes set

G_DEF_SETTER(classe, nom)
G_DEF_SETTERS(classe)
Ces macros permettent d'implémenter automatiquement les méthodes d'affectation avec l'opérateur = à partir des méthodes set traditionelles. Voici comment ça fonctionne; vous implémentez par vous-même la méthode set_hoge(uneValeur), et ensuite vous appelez G_DEF_SETTER(classe, "hoge").
set_hoge(a)           #renvoie self (implémentée par vous-même)
hoge=(a)              #renvoie a    (crée automatiquement à partir de set_hoge)

Si vous avez plusieurs cas de figure dans une même classe, appelez alors G_DEF_SETTERS, qui se chargera de faire le même travail pour toutes les méthodes set.

Definition de constantes

G_DEF_CONSTANTS(mod, type, strip_prefix)
Définit automatiquement les constantes d'une classe ou d'un module à partir d'un type GLib. Un exemple, tiré du code source de Gtk::Window:
/* Définit Gtk::Window::TOPLEVEL et Gtk::Window::POPUP. */
G_DEF_CLASS(GTK_TYPE_WINDOW_TYPE, "Type", gWindow);
G_DEF_CONSTANTS(gWindow, GTK_TYPE_WINDOW_TYPE, "GTK_WINDOW_");
G_RENAME_CONSTANT(orig, alt)
Renomme des constantes préalablement définies par G_DEF_CONSTANTS().

Blocs

G_BLOCK_PROC()
Il s'agit d'une macro qui appelle soit rb_f_lambda() (Yuby 1.7.x ou inférieur), soit rb_block_proc() (Ruby 1.8.x ou supérieur). Dans un soucis de portabilité, vous ne devriez pas appeler directement rb_f_lambda() ou rb_block_proc().

Utilisez un tableau de hachage comme argument pour une propriété

G_SET_PROPERTIES(self, properties)
Cette macro vous aidera à implémenter set_hoge(a, {:foo => 0, :bar =>"hoge"}).

Propriétés avec symboles

G_SET_SYMBOL_PROPERTY(gtype, name)
Utilisez cette macro dans votre fonction Init_*() pour les propriétés qui utilisent Symbol à la place de String (par exemple comme Gtk::Stock).

Implémenter une classe incompatible avec le système de type GLib (sans macros G*_TYPE_*)

Vous pouvez utiliser soit la méthode traditionnelle, soit implémenter la classe comme un objet GBoxed.

Voici un exemple pour la classe Foo:

  1. Créez la fonction suivante, qui se chargera de retourner un type GLib pour notre classe:

    GType foo_get_type(void) {
        static GType our_type = 0;
        if (our_type == 0) {
          our_type = g_boxed_type_register_static("Foo",
                                                  (GBoxedCopyFunc)foo_copy,
                                                  (GBoxedFreeFunc)g_free);
        }
        return our_type;
    }

    Si il existe déjà des fonctions foo_ref/foo_unref, utilisez-les à la place de foo_copy et de g_free.

  2. Créez la fonction suivante, qui se chargera de retourner une copie d'un objet issu de notre classe:

    Foo* foo_copy(const Foo* foo) {
        Foo* new_foo;
        g_return_val_if_fail (foo != NULL, NULL);
        new_foo = g_new(Foo, sizeof(Foo));
        *new_foo = *foo;
        return new_foo;
    }

    Plus rarement, il existe des objets qui ne devraient pas être copiés et libérés. Dans ce cas, utilisez la méthode suivante:

    Foo* foo_copy(const Foo* foo) {
        return (Foo*)foo;
    }
    void foo_free(gpointer foo) {
        /* do nothing */
    }
    GType foo_get_type(void) {
        static GType our_type = 0;
        if (our_type == 0) {
            our_type = g_boxed_type_register_static("Foo",
                                                    (GBoxedCopyFunc)foo_copy,
                                                    (GBoxedFreeFunc)foo_free);
        }
        return our_type;
    }
  3. Définissez une macro G*_TYPE_*:

    #define G_TYPE_FOO         (foo_get_type())
  4. Vous pouvez maintenant appelez dans votre fonction Init_*():

    void Init_foo(void) {
        VALUE cFoo = G_DEF_CLASS(G_TYPE_FOO, "Foo", unModule);
        /* ... */
    }
  5. Pour les conversions:

    /* Ruby -> GLib */
    RVAL2BOXED(objet, G_TYPE_FOO);
    
    /* GLib -> Ruby */
    BOXED2RVAL(objet, G_TYPE_FOO))

GError

RAISE_GERROR(GError* error)
Lance une exception Ruby en fonction du code d'erreur encapsulé dans la variable error.

GLib::Instantiatable#signal_connect: corriger manuellement les variables pour le bloc de code

G_DEF_SIGNAL_FUNC(klass, signal_name, signal_g2r_func);
signal_g2r_func(guint num, const GValue* values);
A l'aide de ces macros, vous pouvez définir par vous-même les variables pour les blocs de code relatifs aux signaux. Vous ne devriez les utiliser que dans des cas spéciaux (les signaux étant automatiquement gerés).

Editeurs

Si vous développez Ruby-GNOME2 avec GNU Emacs, nous vous recommandons de personaliser votre fichier .emacs comme ceci:

(c-add-style
 "ruby"
 '("bsd"
   (c-basic-offset . 4)
   (c-offsets-alist
    (case-label . 2)
    (label . 2)
     (statement-case-open . 2)
     (statement-case-intro . 2))))

(add-hook 'c-mode-common-hook
          '(lambda () (setq indent-tabs-mode nil)))

- Masao

Traduction de la page anglaise par Laurent Sansonetti.


*1 en anglais, garbage collector

Dernière modification:2011/06/09 11:31:30
Mots clef:
Références:[FrontPage]