Question of Style [was Re: Conceptual Question on Signal Handling in Subclasses]



Havoc Pennington writes:

Write a custom object derived from GtkObject using the GTK
object/type system. See for example the source code for any widget
in GTK.  It involves knowing a lot about the GTK object/type
system, so you may not want to go there.

Okay, maybe I didn't explain things well in the first message.

I _am_ trying to use the GTK object/type system.  I _have_
successfully built multiple classes, some derived from GtkWidget and
some from GtkObject.  For the most part, they work great.

What I am trying to do is design a class in the GTK object system that
has something equivalent to virtual functions as non-default signal
handlers.  I want to do this in a way that other GTK programmers will
understand easily.

I know that I can create virtual-like functions by having something in
the class structure like:

    struct _MyGtkObjectClass
      {
        ...
        void (* my_gtk_object_virt_func) ( MyGtkObject *obj );
        ...
      }

The thing is, I've looked through many of the GTK class definitions
and I've never seen a virtual function that wasn't the default handler
for a signal.  This leads me to believe that in GTK virtual functions
are, by convention, only used for signal handling.  Is this true?

The task I'm trying to accomplish is to use gtk_signal_connect_object
to connect one object's signal to another object's handler that is a
virtual function (so that subclasses can choose how they handle the
signal).  I've thought of three ways:

1) Naked virtual functions.  This is what Havoc suggested in his first
   reply.

     struct _MyNakedObjectClass
       {
         ...
         void (* my_naked_object_virtual) ( MyNakedObject *obj, ... );
         ...
       }

     void
     connect_two_objects( GtkObject *x, MyNakedObject *y )
     {
       MyNakedObjectClass *y_class;

       y_class = MY_NAKED_OBJECT_CLASS( GTK_OBJECT( y )->klass );

       g_assert( IS_MY_GTK_OBJECT_CLASS( y_class ) );

       gtk_signal_connect_object_while_alive( GTK_OBJECT( x ), "my_signal",
                                              y_class->my_naked_object_virtual,
                                              GTK_OBJECT( y ) );
     }


2) Corresponding Signals.  Here I would have a signal in my object
   that corresponded to the signal in the other object.  Then I would
   have a function that would just emit that signal, like this:

     struct _MyCorrespondingObjectClass
       {
         ...
         void (* my_corresponding_object_virtual) ( MyCorrespondingObject *obj,
                                                    ... );
         ...
       }

     [ assume that my_corresponding_object_virtual is set up as the
       default signal handler for "my_corresponding_signal"         ]

     void
     connect_two_objects( GtkObject *x, MyCorrespondingObject *y )
     {
       MyCorrespondingObjectClass *y_class;

       gtk_signal_connect_object_while_alive( GTK_OBJECT( x ), "my_signal",
                                              my_corresponding_object_handler,
                                              GTK_OBJECT( y ) );
     }

     void
     my_corresponding_object_handler( MyCorrespondingObject *obj,
                                      GtkObject *other )
     {
       gtk_signal_emit_by_name( GTK_OBJECT( obj ),
                                "my_corresponding_signal",
                                other );
     }


3) Wrapped virtual functions.  Here I wrap the virtual function call
   with a static function.  That way the connect_two_objects function
   doesn't have to do anything fancy.

     struct _MyWrappedObjectClass
       {
         ...
         void (* my_wrapped_object_virtual) ( MyWrappedObject *obj, ... );
         ...
       }

     void
     connect_two_objects( GtkObject *x, MyWrappedObject *y )
     {
       gtk_signal_connect_object_while_alive( GTK_OBJECT( x ), "my_signal",
                                              my_wrapped_object_virtual_wrapper,
                                              GTK_OBJECT( y ) );
     }

     void
     my_wrapped_object_virtual_wrapper( MyWrappedObject *obj,
                                        GtkObject *other )
     {
       MyWrappedObjectClass *obj_class;

       obj_class = MY_WRAPPED_OBJECT_CLASS( GTK_OBJECT( obj )->klass );

       g_assert( IS_MY_GTK_OBJECT_CLASS( obj_class ) );

       obj_class->my_wrapped_object_virtual( obj, other );
     }


For the moment, I've implemented method 1 and it works fine.  I just
wonder if it's the way people will expect this kind of thing to be
done.

Any advice or comments are much appreciated.

Thanks,

Ian Flanigan




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