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 774778 - gtk+4, gtkwidget.c: get_render_mode() is problematic for gtkmm
gtk+4, gtkwidget.c: get_render_mode() is problematic for gtkmm
Status: RESOLVED NOTABUG
Product: gtk+
Classification: Platform
Component: Language Bindings
3.22.x
Other All
: Normal normal
: ---
Assigned To: gtk-bugs
gtk-bugs
Depends on:
Blocks:
 
 
Reported: 2016-11-21 09:56 UTC by Kjell Ahlstedt
Modified: 2017-02-15 10:20 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
patch: widget: Make get_render_mode() virtual (4.63 KB, patch)
2016-11-22 15:09 UTC, Kjell Ahlstedt
none Details | Review

Description Kjell Ahlstedt 2016-11-21 09:56:42 UTC
Gtk+ now has two ways of rendering a widget. The local get_render_mode()
determines which mode to use for a specific widget. It is not compatible with
the way gtkmm overrides virtual functions and default signal handlers.

An example, to show what gtkmm does:
Let's look at a fictitious widget, called GtkAbc. It's wrapped in C++ code in
gtkmm. Gtkmm then registers a class, gtkmm__GtkAbc, derived from GtkAbc.
In its class init() function, it overrides all vfuncs and default signal
handlers which shall be available to C++ application programmers. That has so
far included GtkWidget::draw. In the future I suppose it will also include the
GtkWidget::snapshot vfunc. Most of the overridden signal handlers and vfuncs do
nothing. When they are called, they just chain the call up to the base class,
GtkAbc.

So what are these overridden functions good for?
A C++ programmer, using the C++ class Gtk::Abc (as it's called in C++ code), can
derive from class Gtk::Abc, making e.g.
  class MyAbc : public Gtk::Abc
With very few exceptions, such a derived class is not registered in the GType
system. To glib and gtk+, instances of both MyAbc and Gtk::Abc look like
instances of gtkmm__GtkAbc. Signal handlers and vfuncs can be overridden (in a
C++ way) in MyAbc. Some instances of gtkmm__GtkAbc may chain a call to ::draw
up to GtkAbc, while other instances may do the drawing in the derived class.
What will happen is determined when the signal handler or vfunc is called.

Summary: get_render_mode() determines which render mode to use by looking at
which signal handlers and vfuncs are overridden. Gtkmm overrides almost
everything and determines what to do when a signal is emitted or a vfunc is
called.

What can we do? I'm not sure. Perhaps add a gtk_widget_set_render_mode() that
can be called by every widget? Not very attractive, I admit.
If you do add such a function, please don't require that it must be called in
the class init() or instance init() function. C++ programmers using gtkmm can't
add anything to those functions. It ought to be enough that a set_render_mode()
function is called before the widget is rendered. And it must be set per
instance, not just per GType class.


An unrelated comment: gtkwidget.h says "@snapshot: Signal emitted ...". But
snapshot is not a signal, it's a vfunc.
Comment 1 Kjell Ahlstedt 2016-11-21 14:21:12 UTC
s/Most of the overridden signal handlers/Most of the overriding signal handlers/
s/these overridden functions good for?/these overriding functions good for?/
Comment 2 Emmanuele Bassi (:ebassi) 2016-11-21 14:43:45 UTC
> such a derived class is not registered in the GType
system.

Now I'm left wondering how *anything* in GTKmm even works.

Subclassing without notifying the GType type system is a surefire way to break something.

GObject does not know anything about C++ types, if those types are not shared with the underlying type system.

In any case, the real problem is:

> get_render_mode() determines which render mode to use by
> looking at which signal handlers and vfuncs are overridden.

which is the result, as you say, of C++ overriding everything up front.

Sadly, we don't have any other way to determine if something is effectively overriding things at the C level, which is needed to determine whether or not we can call into compatibility API.

Adding a gtk_widget_class_set_render_mode() may work, since it's a per-class issue, not a per-instance once; but few language bindings even support the ability to get to the GTypeClass pointer, and, as you say, it's still a non-starter for GTKmm:

> If you do add such a function, please don't require that it must
> be called in the class init() or instance init() function.

I'm sorry, but calling random GObject/GTK API into random places does not guarantee any plausible behaviour that the toolkit itself can rely on.

We've already been here with the C++ bindings adding random interfaces and properties to types long after the GType class init has been called.
Comment 3 Kjell Ahlstedt 2016-11-22 15:09:42 UTC
Created attachment 340522 [details] [review]
patch: widget: Make get_render_mode() virtual

Is this patch unacceptable or only disgusting?

It would work with gtkmm. I understand that it looks strange. Here's how it
works:

1. For a gtk+ widget such as GtkAbc the result is just like calling the
   present non-virtual get_render_mode().
2. For a gtkmm widget such as gtkmm__GtkAbc, get_render_mode() is overridden in
   gtkmm__GtkAbc. Gtkmm tries to figure out what mode to use. If code in gtkmm
   or user code that derives from a gtkmm widget will render the widget,
   GTK_RENDER_DRAW or GTK_RENDER_SNAPSHOT is returned. If, as is usually the
   case, it's left to gtk+ to do the rendering, gtkmm__GtkAbc.get_render_mode()
   chains up to GtkAbc.get_render_mode() with GtkWidgetClass* klass set to the
   class of GtkAbc.

Even if you accept such a strange solution, the patch needs some refinement
before it's pushed. E.g. some documentation and a better commit message.


> Now I'm left wondering how *anything* in GTKmm even works.

Usually it works well.

> Subclassing without notifying the GType type system is a surefire way to break
> something.

It makes subclassing in C++ code much much easier.

> GObject does not know anything about C++ types, if those types are not shared
> with the underlying type system.

Often it need not know. At least up until now.

> We've already been here with the C++ bindings adding random interfaces and
> properties to types long after the GType class init has been called.

At long last we managed to add interfaces (but not properties) in the class
init() function.
When restrictions are added after several years, it's no wonder it can cause
problems somewhere.
Comment 4 Kjell Ahlstedt 2017-02-15 10:20:05 UTC
I've implemented a reasonable way of handling this problem in gtkmm.
No need for a fix in gtk+. See gtkmm bug 775348.