After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 327840 - Provide GNOME_CALL_PARENT(_WITH_DEFAULT) equivalents
Provide GNOME_CALL_PARENT(_WITH_DEFAULT) equivalents
Status: RESOLVED WONTFIX
Product: glib
Classification: Platform
Component: gobject
unspecified
Other All
: Normal enhancement
: ---
Assigned To: gtkdev
gtkdev
Depends on:
Blocks:
 
 
Reported: 2006-01-20 11:38 UTC by Christian Neumair
Modified: 2013-02-05 04:19 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description Christian Neumair 2006-01-20 11:38:36 UTC
As part of project ridley, we're trying to get rid of libgnome/eel class method invocation macros. I'm not sure which of them are suitable for providing glib equivalents, but they are used very much inside Nautilus which proves that they're useful if you're building complex object hierarchies with many handler invocations.

1. libbonobo/libgnome macros

/* Just call the parent handler.  This assumes that there is a variable
 * named parent_class that points to the (duh!) parent class.  Note that
 * this macro is not to be used with things that return something, use
 * the _WITH_DEFAULT version for that */
#define BONOBO_CALL_PARENT(parent_class_cast, name, args)               \
        ((parent_class_cast(parent_class)->name != NULL) ?              \
         parent_class_cast(parent_class)->name args : (void)0)

/* Same as above, but in case there is no implementation, it evaluates
 * to def_return */
#define BONOBO_CALL_PARENT_WITH_DEFAULT(parent_class_cast,              \
                                        name, args, def_return)         \
        ((parent_class_cast(parent_class)->name != NULL) ?              \
         parent_class_cast(parent_class)->name args : def_return)

2. eel macros

/* Call a parent class version of a virtual function (or default
 * signal handler since that's the same thing). Nice because it
 * documents what it's doing and there is less chance for a
 * typo. Depends on the parent class pointer having the conventional
 * name "parent_class" as the boilerplate macro above does it.
 */
#define EEL_CALL_PARENT(parent_class_cast_macro, signal, parameters)          \
                                                                              \
G_STMT_START {                                                                \
        if (parent_class_cast_macro (parent_class)->signal != NULL) {         \
                (* parent_class_cast_macro (parent_class)->signal) parameters;\
        }                                                                     \
} G_STMT_END

/* Same thing, for functions with a return value. */
#define EEL_CALL_PARENT_WITH_RETURN_VALUE(parent_class_cast_macro, signal,    \
                                          parameters)                         \
                                                                              \
(parent_class_cast_macro (parent_class)->signal == NULL)                      \
        ? 0                                                                   \
        : ((* parent_class_cast_macro (parent_class)->signal) parameters)

#endif /* EEL_DISABLE_DEPRECATED */

/* Call a virtual function. Useful when the virtual function is not a
 * signal, otherwise you want to gtk_signal emit. Nice because it
 * documents what it's doing and there is less chance for a typo.
 */
#define EEL_CALL_METHOD(class_cast_macro, object, signal, parameters)         \
                                                                              \
G_STMT_START {                                                                \
        if (class_cast_macro (G_OBJECT_GET_CLASS (object))->signal != NULL) { \
                (* class_cast_macro (G_OBJECT_GET_CLASS (object))->signal)    \
                parameters;                                                   \
        }                                                                     \
} G_STMT_END

/* Same thing, for functions with a return value. */
#define EEL_CALL_METHOD_WITH_RETURN_VALUE(class_cast_macro, object, signal,   \
                                          parameters)                         \
                                                                              \
(class_cast_macro (G_OBJECT_GET_CLASS (object))->signal == NULL)              \
        ? 0                                                                   \
        : ((* class_cast_macro (G_OBJECT_GET_CLASS (object))->signal)         \
           parameters)                                                        \

/* Define a signal that is not implemented by this class but must be
 * implemented by subclasses. This macro should be used inside the
 * class initialization function. The companion macro EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL
 * must be used earlier in the file. Called like this:
 *
 * EEL_ASSIGN_MUST_OVERRIDE_SIGNAL (klass,
 *                                       fm_directory_view,
 *                                       clear);
 */
#define EEL_ASSIGN_MUST_OVERRIDE_SIGNAL(class_pointer, prefix, signal)        \
                                                                              \
* (void (**)(void)) & (class_pointer)->signal = prefix##_unimplemented_##signal

/* Provide a debug-only implementation of a signal that must be implemented
 * by subclasses. The debug-only implementation fires a warning if it is called.
 * This macro should be placed as if it were a function, earlier in the file
 * than the class initialization function. Called like this:
 *
 * EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, clear);
 */
#define EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL(prefix, signal)                    \
                                                                              \
static void                                                                   \
prefix##_unimplemented_##signal (void)                                        \
{                                                                             \
        g_warning ("failed to override signal " #prefix "->" #signal);        \
}
Comment 1 Matthias Clasen 2006-01-20 16:28:17 UTC
I must admit that I don't see the big benefit over

 if (parent_class->func)
    parent_class->func (args);

its just two lines, and if you know that function is implemented above,
you can optimize it to just

   parent_class->func (args);

Comment 2 Christian Neumair 2006-01-20 20:31:29 UTC
I think it makes the code slightly more readable.

CCing Alex. Maybe you know why were these macros were used for years?
Comment 3 Matthias Clasen 2006-01-20 20:43:16 UTC
I don't agree with the readability aspect at all. 
Either you need varargs macros, which are not portable, or you need
wierd double-parenting.
Comment 4 Alexander Larsson 2006-01-23 08:37:27 UTC
christian: Its all a question on what you think is most readable. The initial developers of nautilus that set the styleguides etc thought it was more readable that way. Others disagree.
Comment 5 Christian Neumair 2006-01-23 19:02:21 UTC
I think it is likely that these macros will be used by many people. According to google [1], at least eog, evolution, the panel and ghex use these GNOME/BONOBO macros.

[1] http://www.google.com/search?num=100&hl=&q=BONOBO_CALL_PARENT+OR+GNOME_CALL_PARENT&btnG=&meta=
Comment 6 P. Henrique Silva 2006-12-09 09:09:02 UTC
gnome-macros was just deprecated and I created a patch to [1]. I replaced GNOME_CALL_PARENT with the simple PARENT_TYPE_CAST(type_name_parent_class)->do (arg).

As I said in [1] there was a lot of places in libbonoboui that use this pattern and ignores the GNOME_CALL_PARENT macro.

I just observed two points when GNOME_CALL_PARENT was remove together with GNOME_CLASS_BOILERPLATE (also deprecated):

1. G_DEFINE_TYPE uses a different name convention for instance init method, so these methods should be renamed.

2. the names used by G_DEFINE_TYPE to the parent class (type_name_parent_class) becames too long sometimes to write over and over (a bit error prone);

[1] http://bugzilla.gnome.org/show_bug.cgi?id=383497
Comment 7 Christian Neumair 2006-12-10 11:20:44 UTC
P. Henrique: Regarding (2): You may want to use
#define parent_class foo_parent_class
Comment 8 André Klapper 2009-04-24 09:32:19 UTC
So can we resurrect this ticket if it's really a 3.0 blocker?
Comment 9 André Klapper 2009-04-24 11:03:50 UTC
I can only see anjuta and gnome-mag here in an updated list:

./libgnome/libgnome/gnome-macros.h:	
   BONOBO_CALL_PARENT (parent_class_cast, name, args)
   BONOBO_CALL_PARENT_WITH_DEFAULT (				\
./gnome-mag/magnifier/zoom-region.c:
   BONOBO_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
   BONOBO_CALL_PARENT (G_OBJECT_CLASS, finalize, (region));
./gnome-mag/magnifier/magnifier.c:
   BONOBO_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
./libbonobo/bonobo/bonobo-macros.h:	
   #define BONOBO_CALL_PARENT(parent_class_cast, name, args)		\
   #define BONOBO_CALL_PARENT_WITH_DEFAULT(parent_class_cast,		\


./anjuta/plugins/project-manager/gbf-project-view.c:
	event_handled = GNOME_CALL_PARENT_WITH_DEFAULT (
./anjuta/plugins/gbf-am/gbf-am-project.c:
	GNOME_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
./anjuta/plugins/file-manager.old/plugin.c:
	GNOME_CALL_PARENT (G_OBJECT_CLASS, dispose, (obj));
./anjuta/plugins/gbf-mkfile/gbf-mkfile-project.c:
	GNOME_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
./libgnome/libgnome/gnome-macros.h:
	#define GNOME_CALL_PARENT(parent_class_cast, name, args)	\
	#define GNOME_CALL_PARENT_WITH_DEFAULT(parent_class_cast,	\
./libgnome/libgnome/gnome-program.c:
	GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
./libgnomeui/libgnomeui/gnome-dateedit.c:
	GNOME_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
	GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
./libgnomeui/libgnomeui/gnome-about.c:
	GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
./libgnomeui/libgnomeui/gnome-druid-page-edge.c:
	GNOME_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
	GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
	GNOME_CALL_PARENT (GTK_WIDGET_CLASS, style_set, (widget, old_style));
	GNOME_CALL_PARENT (GTK_WIDGET_CLASS, realize, (widget));
./libgnomeui/libgnomeui/gnome-appbar.c:
	GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
./libgnomeui/libgnomeui/gnome-icon-list.c:
	GNOME_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
	GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
./libgnomeui/libgnomeui/gnome-href.c:
	GNOME_CALL_PARENT (GTK_BUTTON_CLASS, clicked, (button));
	GNOME_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
	GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
	GNOME_CALL_PARENT (GTK_WIDGET_CLASS, realize, (widget));
./libgnomeui/libgnomeui/gnome-entry.c:
	GNOME_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
	GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
./libgnomeui/libgnomeui/gnome-color-picker.c:
	GNOME_CALL_PARENT (GTK_WIDGET_CLASS, realize, (widget));
	GNOME_CALL_PARENT (GTK_WIDGET_CLASS, style_set,
	GNOME_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
	GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
./libgnomeui/libgnomeui/gnome-druid-page.c:
	return GNOME_CALL_PARENT_WITH_DEFAULT
./libgnomeui/libgnomeui/gnome-app.c:
	GNOME_CALL_PARENT (GTK_WIDGET_CLASS, show, (widget));
	GNOME_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
	GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
./libgnomeui/libgnomeui/gnome-file-entry.c:
	GNOME_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
	GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
./libgnomeui/libgnomeui/gnome-client.c:
	GNOME_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
	GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
./libgnomeui/libgnomeui/gnome-druid.c:
	GNOME_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
	GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
./libgnomeui/libgnomeui/gnome-druid-page-standard.c:
	GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
	GNOME_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
	GNOME_CALL_PARENT (GTK_WIDGET_CLASS, realize, (widget));
	GNOME_CALL_PARENT (GTK_WIDGET_CLASS, style_set, (widget, old_style));
./libgnomeui/libgnomeui/gnome-icon-entry.c:
	GNOME_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
	GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
./libgnomeui/libgnomeui/gnome-icon-item.c:
	GNOME_CALL_PARENT (GNOME_CANVAS_ITEM_CLASS, realize, (item));
	GNOME_CALL_PARENT (GNOME_CANVAS_ITEM_CLASS, unrealize, (item));
	GNOME_CALL_PARENT (GNOME_CANVAS_ITEM_CLASS, update, (item, affine,
                           clip_path, flags));
	GNOME_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
./libgnomeui/libgnomeui/gnome-font-picker.c:
	GNOME_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
	GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
./libgnomeui/libgnomeui/gnome-pixmap-entry.c:
	GNOME_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
	GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
./libgnomeui/libgnomeui/gnome-scores.c:
	GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
./libgnomeui/libgnomeui/gnome-icon-sel.c:
	GNOME_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
	GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
Comment 10 Matthias Clasen 2009-04-24 13:50:46 UTC
(In reply to comment #8)
> So can we resurrect this ticket if it's really a 3.0 blocker?
> 

Nothing here is a blocker in any way. 

We are talking about a macro that would replace 3 lines of code.