Create  Edit  FrontPage  Index  Search  Changes  History  RSS  Back  Login

How to Implement Ruby-GNOME2 - History

= How to implement Ruby-GNOME2
This document explains how to implement an extension for Ruby-GNOME2.

== Signals and Properties
Accessors methods (((*set*))/((*get*))) for properties are automatically generated.  Signals are also directly handled by GLib::Instantiatable#signal_connect.  So, you do not need to manually implement them anymore.

== Deprecated/Obsolete classes/methods
Don't implement them.

== Macros
You need to know that there are some macros which can help you to easily implement a new class/method.  
Almost all of these macros are in the header files glib/src/rbgobject.h, rbglib.h and gtk/src/rbgtk.h.

=== Define class/interface
These macros are used in Init_*() functions:

--- G_DEF_CLASS(gtype, name, module)
--- G_DEF_CLASS2(gtype, name, module, mark, free)
    Define a class. If you want to define mark and free functions by yourself, use G_DEF_CLASS2.
    This returns a new ruby class value.

--- G_DEF_CLASS3(gtype_name, name, module)
    Define a class dynamically. This is for private gtype classes such as GdkScreenX11, GdkWindowImplWin32.
    This returns nothing. These classes can't define the methods/constants by themselves. And these classes appear since a method which creates the private gtype has been called by ruby script.

--- G_DEF_INTERFACE(gtype, name, module)
--- G_DEF_INTERFACE2(gtype, name, module, mark, free)
    Define a module. If you want to define mark and free functions by yourself, use G_DEF_INTERFACE2.

--- G_DEF_ERROR(domain_quark, name, module, parent, enum_type)
--- G_DEF_ERROR2(domain_quark, name, module, parent)
    Define an error class which is called by RAISE_GERROR. 

--- void rbgobj_boxed_not_copy_obj(GType gtype)
    Use this method if the GBoxed object shouldn't be copied during its RVALUE conversion (for example in GBOXED2RVAL or G_INITIALIZE).

=== Initialize object
These macros are used in class constructors (methods ((*initialize*))):

--- G_INITIALIZE(obj, cobj)
--- RBGTK_INITIALIZE(obj,gtkobj)
--- RBGST_INITIALIZE(obj,gstobj)
    Initialize an object. If the class is a descendant of GtkObject, use RBGTK_INITIALIZE.  If the class in a descendant of GstObject, use RBGST_INITIALIZE.

=== Convert Ruby <-> GLib/GTK

--- RVAL2GOBJ(obj)
--- GOBJ2RVAL(gobj)
    VALUE(GLib::Object) <-> GObject

--- RVAL2BOXED(obj)
--- BOXED2RVAL(cobj, gtype)
    VALUE(GLib::Boxed) <-> GBoxed

--- RVAL2GENUM(obj, gtype)
--- GENUM2RVAL(gobj, gtype)
    VALUE(GLib::Enum) <-> GEnum

--- RVAL2GFLAGS(obj, gtype)
--- GFLAGS2RVAL(gobj, gtype)
    VALUE(GLib::Flags) <-> GFlags

--- RVAL2CSTR(v)
--- CSTR2RVAL(s)
    VALUE(String) <-> gchar*

--- CSTR2RVAL2(s)
    Convert gchar* s to VALUE(String) and then call g_free(s).

--- RVAL2CBOOL(v)
--- CBOOL2RVAL(b)
    VALUE(true or false) <-> gboolean

--- GVAL2RVAL(v)
    GValue(GLib::Value) -> RValue. 
    RVAL2GVAL(v) is not yet prepared. If you want to convert RValue to GValue, then use rbgobj_rvalue_to_gvalue():

  GValue gval = {0,};
  g_value_init(&gval, RVAL2GTYPE(value));
  
  rbgobj_rvalue_to_gvalue(value, &gval);
  /* then use gval... */

--- GEV2RVAL(ev)
--- RVAL2GEV(ev)
    VALUE(Gdk::Event) <-> GdkEvent

--- GLIST2ARY(list)
--- GSLIT2ARY(list)
    GList/GSList of GObject -> Array

--- GLIST2ARY2(list)
--- GSLIT2ARY2(list)
    GList/GSList of GBoxed -> Array

--- GLIST2ARYF(list)
--- GSLIST2ARYF(list)
--- GLIST2ARY2F(list)
--- GSLIST2ARY2F(list)
    Ditto. But call g_list_free() or g_slist_free() internal.

=== Convert RGObjClassInfo <-> GType,Ruby class/instance
--- CLASS2CINFO(klass)
    Class -> RGObjClassInfo
--- GTYPE2CINFO(gtype)
    GType -> RGObjClassInfo
--- RVAL2CINFO(obj)
    VALUE -> RGObjClassInfo

=== Convert GType <->Ruby class/instance
--- GTYPE2CLASS(gtype)
    GType -> Class
--- CLASS2GTYPE(klass)
    Class -> GType
--- RVAL2GTYPE(obj)
    VALUE -> GType

=== Relatives
This saves an object from the GC. Usually obj is self and rel is child widget/object or proc object.

--- G_RELATIVE(self, rel)
    Make a relation. Use this with proc object.
--- G_RELATIVE2(self, rel, id, hash_key)
    Make a removable relation.
--- G_REMOVE_RELATIVE(self, id, hash_key)
    Remove a relation.

--- G_CHILD_SET(self, id, child)
    Sets child to self with id(rb_intern value).
--- G_CHILD_UNSET(self, id)
    Unsets the child value of the id.
--- G_CHILD_ADD(self, child)
    Adds a child to self. This is equivalent with G_RELATIVE(self, child), but the name is obviously.
--- G_CHILD_REMOVE(self, child) 
    Remove child from self.

=== Setter methods
--- G_DEF_SETTER(klass, name)
--- G_DEF_SETTERS(klass)
    These macros can be used to implement automatically setters methods with operator ((*=*)).  
    You implement by yourself the method set_hoge(aValue), and then you call G_DEF_SETTER(klass, "hoge").

 set_hoge(a)          #return self (implemented by yourself)
 hoge=(a)             #return a    (created automatically from set_hoge)

If you have several set methods in a single class, then you can call G_DEF_SETTERS which will do the magic for all of them.

=== Define constants
--- G_DEF_CONSTANTS(mod, type, strip_prefix)
    Define constants of Module/Class from GType. G_DEF_CONSTANTS is used with G_DEF_CLASS.
    Here is a practical example from Gtk::Window source code:

  /* Define Gtk::Window::TOPLEVEL and 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)
    Rename constants which has been defined with G_DEF_CONSTANTS().

--- G_RENAME_NICK(orig, alt)
    Rename nick of GEnum/GFlags which start numerical character. 
    Ruby/GLib define the methods of GFlags from nick automatically. If nick starts numerical character, it causes a syntax error.

=== Block
--- G_BLOCK_PROC()
    This macro calls either rb_f_lambda() (Ruby <= 1.7.x) or rb_block_proc() (Ruby >= 1.8.x).
    You shouldn't use rb_f_lambda() or rb_block_proc() directly, if you want to produce portable code.

=== Argument of properties as hash
--- G_SET_PROPERTIES(self, properties)
    This macro will help you to implement set_hoge(a, {:foo => 0, :bar =>"hoge"}) for properties.

=== Symbol properties
--- G_SET_SYMBOL_PROPERTY(gtype, name)
    Define this in Init_*() for properties which use Symbol instead of String (e.g. Gtk::Stock).

=== Implement class which does not conform to GType system (no G*_TYPE_* macros)
You can either use traditional method, or implement the class as a GBoxed object.

Here is an example for the class ((*Foo*)):

(1) Create the following function, which will return a GLib type for our class:

      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;
      }
    
    If Foo has foo_ref/foo_unref, then use them instead of foo_copy, g_free.

(2) Create the following function, which will return a copy of an objet from our class:

      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;
      }
    
    Rarely, there are some objects which shouldn't make copy and shouldn't free them, you may need to write it as follows:

      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;
      }
     
    Furthermore, some objects may need to do g_free() there in this case.

(3) Define a G*_TYPE_* macro:

      #define G_TYPE_FOO         (foo_get_type())

(4) You can now call in your Init_*() function:

      void Init_foo(void) {
          VALUE cFoo = G_DEF_CLASS(G_TYPE_FOO, "Foo", aModule);
          /* ... */
      }

(5) And for conversions:

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

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

=== GError handling
--- RAISE_GERROR(GError* error)
    This macro will throw a Ruby exception according to the error code.

=== GLib::Object#signal_connect's block variables set manually
--- G_DEF_SIGNAL_FUNC(klass, signal_name, signal_g2r_func);
--- signal_g2r_func(guint num, const GValue* values);
    You can define with these macros block variables for signals by yourself.  
    These macros should be used only in special case (since signals are automatically handled).

=== Log handling from ruby scripts.
--- GLib::Log.set_error_domain(domain)
    This function improve log handling. See glib/src/lib/glib2.rb. 
    * Output GLib logs with -W, -d -v options of ruby.
    * Raise exception when GLib::Log::LEVEL_ERROR/CRITICAL.

=== Recommended editors
If you develop Ruby-GNOME2 with GNU Emacs, I recommend you to use ((<ruby-style.el|URL:http://svn.ruby-lang.org/repos/ruby/trunk/misc/ruby-style.el>)).
To use ruby-style.el, you need to customize your ~/.emacs file as follows:

 (add-to-list 'load-path "/path/to/ruby-style-el/directory")
 (require 'ruby-style)
Last modified:2019/10/23 00:34:20
Keyword(s):
References: