Gtk+ MIface implementation (was: New 'GObject' as base forGtkObject?)



On Tue, 21 Dec 1999, Karl Nelson wrote:

> Can you compose a demo of the system like the gos which shows
> and example with some simple use?  It would both help
> me see how easy it is to wrap in C++ and what design
> decisions are left to be ironed out. 

some long time ago ;), i.e. in april, i already outlined this on gtk-list,
at that point i had already the type system side implemented for BSE, and
that is currently sitting in beast cvs module, so you can always peek at
the actuall implementation.
the original mail is appended.

> 
> Regards,
> 
> --Karl  
> 

---
ciaoTJ

---------- Forwarded message ----------
Date: Thu, 15 Apr 1999 17:44:27 +0200 (CEST)
From: Tim Janik <timj@gtk.org>
Reply-To: gtk-list@redhat.com
To: gtk-list@redhat.com
Subject: [gtk-list] Re: Interfaces
Resent-Date: 15 Apr 1999 16:17:53 -0000
Resent-From: gtk-list@redhat.com

On Thu, 15 Apr 1999 rowe@excc.ex.ac.uk wrote:

> On Wed, 14 Apr 1999 14:44:52 -0700 (PDT), Bill Huey <billh@mag.ucsd.edu> wrote:
> >
> > With the recent announcement that GTK will have the notion of 
> > Java Interfaces (a form of multipule inheritance) in the next
> 
> This is *very* interesting. Where can we see some details about this? (Or
> even just a copy of the announcement.)

the interfaces are meant to follow much the c++ style of signatures, that is
for two given classes class A { int foo (int); } and class B { int foo (int); }
which both introduce int foo (int); but don't inherit from each other, you
can magically cast both of them into S, where S would be
signature S { int foo (int); }.

of course, this doesn't work as magically with gtk as well, for the purpose
of gtk, it'd be nice to be able to retrofit multiple interface onto
certain widget classes, e.g. to use
GSList*     gtk_radio_get_group       (GtkRadio *radio);
void        gtk_radio_set_group       (GtkRadio *radio,
                                       GSList   *group);
for GtkRadioButton and GtkRadioMenuItem at the same time.

this can be achived by defining the GtkRadio interface and retrofitting
that on GtkRadioButton and GtkRadioMenuItem, with e.g.

/* --- interface type macros --- */
#define GTK_TYPE_RADIO                  (gtk_radio_get_type ())
#define GTK_RADIO(object)               (GTK_CHECK_STRUCT_CAST ((object), GTK_TYPE_RADIO, GtkRadio))
#define GTK_IS_RADIO(object)            (GTK_CHECK_STRUCT_TYPE ((object), GTK_TYPE_RADIO))
#define GTK_RADIO_GET_INTERFACE(object) (GTK_OBJECT_GET_INTERFACE ((object), GTK_TYPE_RADIO, GtkRadioInterface))

/* --- GtkRadio interface --- */
typedef struct _GtkRadio          GtkRadio;  /* blind type definition */
typedef struct _GtkRadioInterface GtkRadioInterface;
struct _GtkRadioInterface
{
  GtkTypeInterfaceClass interface;
  
  GSList* (get_group) (GtkRadio *radio);
  void    (set_group) (GtkRadio *radio,
                       GSList   *group);
};

/* --- prototypes --- */
GSList*     gtk_radio_get_group       (GtkRadio *radio);
void        gtk_radio_set_group       (GtkRadio *radio,
                                       GSList   *group);


a possible implementation of gtk_radio_get_group() would look like:

GSList*
gtk_radio_get_group (GtkRadio *radio)
{
  GtkRadioInterface *iface;
  
  g_return_val_if_fail (GTK_IS_RADIO (radio), NULL);
  
  iface = GTK_RADIO_GET_INTERFACE (radio);

  return iface->get_group (radio);
}

and to retrofit this interface on say GtkRadioButton, you'd only need to
  GtkInterfaceInfo radio_button_iface_radio = {
    (GtkClassInitFunc) gtk_radio_button_init_iface_radio,
    [...]
  };
  gtk_type_add_interface (GTK_TYPE_RADIO_BUTTON,
                          GTK_TYPE_RADIO,
                          &radio_button_iface_radio);

static void
gtk_radio_button_init_iface_radio (GtkRadioInterface *iface)
{
  iface->get_group = gtk_radio_button_group;
  iface->set_group = gtk_radio_button_set_group;
}

whether a certain widget implements a certain interface, can be tested
with
gboolean gtk_type_conforms_to (GtkType type,
                               GtkType iface_type);
with it's semantics similar to gtk_type_is_a(). iface_type doesn't
neccessarily need to be an interface type, it can just as well be
GTK_TYPE_OBJECT or any other parent, since all objects "conform to"
the GtkObject interface or the interfaces implemented by their
parent types (with "interface" here i mean the API implemented by
a parent type).
on the other hand, interface types as such, only conform to themselves
and GTK_TYPE_OBJECT.

additionally to function pointers, the interface structures could hold
guints to store signal id's to emit certain class-specific signals.

this way, we can provide interfaces out of the box within gtk (e.g.
GtkRadio or GtkScrollable), and users can write new custom interfaces
and retrofit that on any given widget type (within the *_init_iface_*
functions, you can even provide default implementations for certain
widget types).

> > development, release only magnifies the replication of the OO
> > facilities by "hand" instead of by "compiler".
> >
> > This just magnifies the mistake that GTK was not built on top of an
> > strong OO language like Java, since more and more OO facilities are
> > being built by hand.
> >
> > What's happening here is that GTK is converging on having the same,
> > yet inferior capabilities, as a genuine OO language and replicating
> > the same OO facilities as an OO language by "hand", which is
> > completely ridiculous given the tedious error prone amount of work
> > that it takes to maintain the OO layer.
> 
> That depends a lot upon how it's done. There's no reason a well defined
> interface structure shouldn't be implemented in a reasonably automated
> manner provided it's done carefully with a realistic set of objectives.
> 
> What *is* important, without going into the usual C/C++ flame war, is
> to have a good idea of what the objectives of such a system would be
> including the system resource issues (speed, memory..).

the involved system resources shouldn't be much of an issue at least on the
class side, per class you retrofit an interface on, you'll have an
additional Gtk*Interface structure, holding the interface's vtable. interfaces 
get inherited, so say you retrofit GtkRadio on GtkRadioButton, you then have:

GtkObject
  GtkWidget
    GtkContainer
      GtkBin
        GtkButton
          GtkRadioButton[GtkRadio] + vtable for Radio->RadioButton mappings
            GtkSomethingDerivedFromRadioButton[GtkRadio]

to get this going on the type system side is a little more tricky, in order
to get fast GTK_*_GET_INTERFACE() lookups and to speedup gtk_type_conforms_to()
every type node implements an array to hold the interface types and vtables
it conforms to. upon gtk_type_add_interface(), the interface gets propagated
up the type node tree so that derived types, up to the leafs (in the above
example that would be GtkSomethingDerivedFromRadioButton) implement the
interface as well. to search the interface arrays on the type nodes, we
either use a sequential array lookup for small arrays, e.g. n_ifaces < 4 or
an ordered array lookup otherwise, which gives us O (MAX (3, log2 (n_ifaces)))
for worst case lookups (e.g. at maximum 6 lookups for a type that implements
64!!! interfaces), which should be sufficiently speedy.

> 
> John
> 

---
ciaoTJ

-- 
To unsubscribe: mail -s unsubscribe gtk-list-request@redhat.com < /dev/null





[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]