Re: New 'GObject' as base for GtkObject?




> > > What is a virtual interface? (Isn't there some other
> > > term than 'virtual' that people could use occasionally?) 
> > 
> > I mean define some sub part of the object that can be
> > recovered to the whole.  If a sub piece doesn't at
> > least have a pointer to the base, where is this info
> > stored?
> 
> OK, that makes more sense, though the name virtual interface
> for this seems odd. (In a way, I'd call this a non-virtual
> interface). But I'd rather see interfaces used when
> there is a 1-1 relationship between the piece and the whole,
> which removes the need to pass around both, and use
> actual "objects" when I mean aggregation.

How about this then... I propose that the second pointer
in every gtk+ object be the pointer to the base of the object.

Thus to make sub pieces I do things like this

      ________________
     | (class C)      |
     | ______________ |
     || ____________ ||
     ||| TypePtr    |||\
     ||| BasePtr    ||| 
     ||| Refcount   |||  Gtk Object
     ||| DataPtr    |||/
     |||            |||
     ||| A Object   |||
     |||            |||
     |||____________|||
     ||  B Object    ||
     ||  __________  ||
     || | (Cont1)  | ||
     || |Type Ptr  | ||
     || |BasePtr   | ||
     || |__________| ||
     ||  __________  ||
     || | (Cont2)  | ||
     || |Type Ptr  | ||
     || |BasePtr   | ||
     || |__________| ||
     ||______________||
     |   C Object     |
     |                |
     |________________|

Now by passing the address of Cont1, Cont2 or the actual
base I can differentiate which is which.  And I can reference
the base or add data from any piece passed.

The cost is minimal and proxies are easy to set up including
dynamic proxies where the sub object isn't even in the base 
object.  (Great for button boxes which can be viewed as
a variable set of containers.)

> > This means passing around only the most basic object
> > defeating the cast checking system.  
> 
> As Tim and Havoc have pointed out, you probably want to
> make a GtkRadio opaque type which is just an alias
> for GtkObject so that the interfaces contain the correct
> type. But you are still effectively passing around
> the pointer to the base object.

Okay, how do you have 2 container interfaces in the frame?
(one up for the label, one for the main area.) 
I am not all that concerned with the naming conventions
that much.  (But I do feel that radio should be scraped
in favor of a Group concept.)  I just use Intr, Impl, Proto,
etc so that you can see what level I am referring to.    
  
> > (separate idea) How do you export
> > specific pieces of the interface?  For example, a frame
> > has 2 container interfaces.  I want to pass one of them
> > to something that is going to add a dialog in.  How would
> > I code that?  How would that reference so that it could
> > call signals? 
> 
> I don't see this as inheritance - the classic dictum
> is that inheritance models is_a relationships, not
> has_a relationships. gos couldn't handle this situation
> since it has only one copy of each base object, and
> trying to handle it with the C++ MI model would be,
> at best, a horrible kludge. The right way to do this
> is with aggregation or helper objects (more below)

No.  You are missing the point of the MI in the gos then.
Yes, I showed the classic C++ constructs, but being about
the substitute the very bottom of the class like gos allows,
means that I can just add an extra type in to make Proxies as
described above....


   Object+ Radio = RadioButton
   ObjectProxy + Radio = Radio Proxy.

I place radio proxies embedded in my class or I derive
from a radio button.  This allows sub interfaces with
HasA and wholes like IsA, just by switching the base 
pointer.  (And if I want to share implementation I 
need data stored in the interface as well.)


> >   void place_tic_tack_toe(GtkContainerIntf* w);  
> >    /* builds a tree interface in w */  
> > 
> > It can work with w if w is the window, a frame, or one side of
> > a paned.  Clearly, this is powerful abstraction as I don't
> > need special functions to export
> >   
> >   place_tic_tack_toe(paned.side1);
> 
> I've been working some with Python recently, and in
> a language like Python that has first class function objects,
> the way to do this is obvious:
> 
>  def place_tic_tack_toe (self, func):
>     func(self.thing_to_place)
> 
>  place_tic_tack_toe(paned.add1)
> 
> That just works right now. Almost like cheating, isn't it? I'd do the
> same thing in Scheme, and maybe even Perl, thoughj neither is as
> compact. Unfortunately, function pointers in C or C++ aren't as
> powerful, or as convenient, but you could pass in a function / closure
> data pair, or you could use helper objects. Helper objects is probably
> the way I'd do things in C++ or Java ... something like:

Every language has cool tricks, but I am trying to get the same 
elegance down in C. 


(You do realize that after over a year of writing C++ bindings
for gtk+, I have proxies down to a practical science?  ;-)
I have proxied your glists, strings, argument interfaces,
signals, slots, timeouts, and key snooper.   Many of them
because common abstractions rather than disjoint ideas.)


> Interfaces:
> 
> class GtkSlot {

(Slot is a bit overloaded.  I would perfer Bin as
as that is what this really is.)

> public:
>     virtual void add (GtkWidget *child);
>     virtual void remove(GtkWidget *child);
> }
> 
> class GtkPaned {
>     [...]
>     GtkSlot get_slot (int side);
> }
> 
> Implemenation:
> 
> class GtkPanedSlot : GtkSlot {
> public:
>   GtkPanedSlot (GtkPaned *paned, int side) {
>     mPaned = paned;
>     side = side;
>   }
> 
>   void add (GtkWidget *child) {
>      if (mSide == 1)
>         mPaned.add1 (child);
>      else 
>         mPaned.add2 (child);
>   }
> 
> private:
>   GtkPaned_var mPaned;
>   int mSide;
> }
> 
> GtkSlot GtkPaned::get_slot (int side) 
> {  
>    return GtkPanedSlot (this, side);
> }

(Your C++ code looks okay, but you have serious object
slicing problems!)

This is fine for C++, but I would really like to see proxies
of this nature work in C with minimal set up on the user.
Ie.  The coder just feeds that they want this kind of
relationship to the object system (they don't hand construct 
tables of anything)  

    
> [ Taking the liberty to make up an imaginary C++ binding
>   with CORBA style smart pointers ]
> 
> In C, you could also use helper objects, or it might be easier just to
> require containers to number their slots (in some internal fashion),
> so you could have:
> 
>  int gtk_paned_get_slot_number (int side);
>  gtk_container_add_numbered (GtkContainer *container, int slot);
> 
> This could easily be wrapped into a slot object for C++.

indexing like that is great until some object combines several
of these together.  Then indexing by numbers when you have a
frame and a paned together becomes a pain.  Simple C object
that you pass pointers from are much better as you can select
to get them individually.

   GtkContainerIntf*  gtk_my_dialog_get_main_area(GtkMyDialog* w)
      {
        return w->paned->side1;
      }

Also I hope that we can come up with some way that a GnomeDialog
HasA window but the container interface points to the main
window and not the composite.  This would be done by
making Dialog HasA Window and redirects all events to that
window, but when it is used as a container to goes to the 
vbox.   

This means that things should derive from Widget
and a set of interfaces and then redirect to its internals
instead of deriving from some class and then redefining how
you add with gnome_dialog_add.  
 

> > > Of course multiple interfaces are a powerful tool for enabling
> > > aggregates while maintaining implementation independence (E.g, the
> > > GtkRadioGroup / GtkRadioMenuItem aggregate mentioned akbove) but I
> > > don't see such natural aggregates inducing hacks of the type you
> > > mention.
> > 
> > Well, I have other suggestions on radio groups.  It
> > would be better to make a group of toggles then build
> > a special radio for all these things.
>  
> Well, the GtkRadio interface could probably be called
> GtkToggle just as well. But appearance should be different
> for radio buttons so a separate class is necessary.

Why should that be?  All toggle buttons should have a
button drawing module that determines exactly how to draw
it.  This should be a plugin in class.  So if you want
a togglebutton with an indicator you could just do 

  gtk_button_set_button_style(GTK_BUTTON(b),ButtonWithIndicator);

were ButtonWithIndicator could be a vector of function pointers.
With gos this would just be to have the Button styles as
seperate implementations of a ButtonStyle and then 
inherit one of them or something similar. 

Well, you get the idea.  I would like for gtk+ to boil down
to simple classes with plug in pieces rather than hardwired
classes.  It is the flexibility that not having a Button,
ButtonPixmap, and ButtonLabel that drew me to gtk+ in the first
place.  Breaking down widgets so that we have just a very
simple set with Styles would make it even better.

  
> > I intend to solve that by introducing proxies.  They
> > are an addition to the gos type system were if it can't
> > find something it goes to the base object to get it.  Thus
> > exporting interfaces is as easy as deriving from a ProxyObject
> > instead of a real one.
>    
> Can you give an example?

Actually you gave one!  The C++ example above could be translated
directly to gos as perfect example of proxies in C.

You define a base class 

  struct _GtkSlotClass
    {
      GosBaseClass base;
      void (*add)(GtkSlot*,GtkWidget*);
      void (*remove)(GtkSlot*);  /* slots hold only 1, no need to name it */
    };

  struct _GtkSlot  /* pure virtual interface */
    {
      GosBase base;
    };

  void gtk_slot_add(GtkSlot*,GtkWidget*);
  void gtk_slot_remove(GtkSlot*);

/************************************************/

  struct _GtkPanedSlotClass
    {
      GosBaseClass base;  /* this will derive from a GtkObjectProxy
                             and a GtkSlot in the get_type */
    };

  struct _GtkPanedSlot
    {
      GosBase base;
      GtkPaned* paned;
      gint side;
    };

/* we point the virtual methods to work with Paned methods and 
the ObjectProxy to use the paned reference/unreference and set_data/get_data.
*/

  struct _GtkPaned
     { /* .... */

       GtkPanedSlot side1;
       GtkPanedSlot side2;
     };

   GtkObject* gtk_paned_new()
      { /*...*/

        gtk_paned_slot_ctor(w->side1, w, 0);
        gtk_paned_slot_ctor(w->side2, w, 1);
      };
    

Tada! we now have the exact same power that we have in making proxies
in gtk--.  And the sides because they are proxies can have data set
and reference, but they now work to the base object instead of the
mini ones.

Also is shows why our proxies need some type of data they can access.


> > I was just saying that if there was data associated with
> > an interface (for example, some drag interface may need 
> > to store scratch info).  Otherwise, this means that 
> > every thing that uses the interface may have to code
> > the method.  I was hoping that we can make the interface
> > then some implementations that use it (perhaps in abstract)
> > so that we don't need to do all this copy/paste/modify stuff.
> 
> Well, in the rare case where a) you need to store data
> and b) the data is too private to add accessors to the
> interfaces for the purposes of stroing it, I don't
> see using object data as harmful. Most likely better
> than adding multiple inheritance of implementation to
> cover this rare case.

I suppose you could face having the data in the base class
with lots of get_data/set_data keys.  However, as there
is not a unique address associated with parts of the interface
calling up this data would be a mess.  How do I know if it
is one interface of many what is its name if it doesn't have
a unique address or data to tell its name?  (This is a very
serious problem we faced in Gtk--.  We ended up using templates
to compile a different class for each proxy with an index.  It
is not an option here!)

As the example above showed there was some need for data in
the proxy to tell which part I am.  And we are still missing
the full reuse that may be achieved.  
 

> > thing that acts like a radio group.  I have been fighting
> > for days now because RadioMenuItems and RadioButtons work
> > differently!  (Boy, won't that simplify the Packer demo a
> > bit as the toggles could all be grouped.)
> 
> The natural way to do this is to have a RadioGroup object
> that interracts with Radio interfaces (ok, Toggle interfaces).
> Which is exactly the example Tim and I have been using.
> But the point I would make is that the state lives in
> the GtkRadioGroup  object, not in the GtkRadio interfaces.

Yes, I agree.  So long as the Group interface can be
used so that I can place any Toggle in it (buttons, menu_items
etc.)  then it will be more flexible.


Side note:

I know that my ideas are a radical departure from the current
SI ideas in gtk+, but I think that if some of them come to play
the interface will get much better.  I also hope that we can
come up with something that doesn't require so much overhead
of table construction on the user.  Hiding the objects internals
to prevent misuse should be the goal of any object rewrite.

I am being careful to avoid turning this into a language war
or something similar (which side thread already appear to have
become) because I think that if we can get something practical
out of these discussions: our wrappers will be better, our system
will be more compact, and our users (programmers) will be more
productive.  

--Karl



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