GNOME Bugzilla – Bug 327840
Provide GNOME_CALL_PARENT(_WITH_DEFAULT) equivalents
Last modified: 2013-02-05 04:19:23 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); \ }
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);
I think it makes the code slightly more readable. CCing Alex. Maybe you know why were these macros were used for years?
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.
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.
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=
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
P. Henrique: Regarding (2): You may want to use #define parent_class foo_parent_class
So can we resurrect this ticket if it's really a 3.0 blocker?
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));
(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.