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 351810 - C++ bindings for GtkBinding*
C++ bindings for GtkBinding*
Status: RESOLVED OBSOLETE
Product: gtkmm
Classification: Bindings
Component: general
unspecified
Other Linux
: Normal enhancement
: ---
Assigned To: gtkmm-forge
gtkmm-forge
Depends on:
Blocks:
 
 
Reported: 2006-08-17 18:45 UTC by Chong Kai Xiong
Modified: 2018-05-22 12:08 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
header file (3.38 KB, text/x-c++hdr)
2006-08-25 18:47 UTC, Paul Pogonyshev
Details
source file (4.85 KB, text/x-c++src)
2006-08-25 18:48 UTC, Paul Pogonyshev
Details
somewhat cleaned up sources + example of usage (3.36 KB, application/x-compressed-tar )
2007-02-16 23:18 UTC, Paul Pogonyshev
Details

Description Chong Kai Xiong 2006-08-17 18:45:02 UTC
Gtkmm currently does not have language bindings for installing widget keybindings   with GtkBinding*.

GtkBinding* is documented here:
http://developer.gnome.org/doc/API/2.0/gtk/gtk-Bindings.html
Comment 1 Murray Cumming 2006-08-17 18:47:57 UTC
Is there any documentation about how this should be used. For instance, a C example?
Comment 2 Chong Kai Xiong 2006-08-17 19:57:01 UTC
Unfortunately I couldn't find any except GTK+'s code for e.g. GtkWidget, GtkWindow and GtkScale.

Here's a link to GtkScale's code:
http://cvs.gnome.org/viewcvs/gtk%2B/gtk/gtkscale.c?view=markup

In the class initializer, the code first creates a GtkBindingSet for the class using gtk_binding_set_by_class(). Then, key-signal entries are added to map keys to signal handlers using gtk_binding_entry_add_signal(), complete with arguments used to invoke them.

Then, in the key-press-event handler, the event struct is passed to gtk_bindings_activate_event() which looks up and emits the corresponding signal. Note that this is exactly what GtkWidget's handler does.

For GtkWidget-derived objects, there is no need to perform the last step as it is already taken care of by GtkWidget's handler.
Comment 3 Paul Pogonyshev 2006-08-21 19:16:22 UTC
Here is an example from my program:

static void
gtk_goban_class_init (GtkGobanClass *class)
{
  static GtkUtilsBindingInfo navigation_bindings[] = {
    {GDK_Left,		0,	GOBAN_NAVIGATE_BACK},
    {GDK_Page_Up,	0,	GOBAN_NAVIGATE_BACK_FAST},
    {GDK_Right,		0,	GOBAN_NAVIGATE_FORWARD},
    {GDK_Page_Down,	0,	GOBAN_NAVIGATE_FORWARD_FAST},
    {GDK_Up,		0,	GOBAN_NAVIGATE_PREVIOUS_VARIATION},
    {GDK_Down,		0,	GOBAN_NAVIGATE_NEXT_VARIATION},
    {GDK_Home,		0,	GOBAN_NAVIGATE_ROOT},
    {GDK_End,		0,	GOBAN_NAVIGATE_VARIATION_END}
  };

  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
  GtkBindingSet *binding_set;
  
  ...

  binding_set = gtk_binding_set_by_class (class);
  gtk_utils_add_similar_bindings (binding_set, "navigate", navigation_bindings,
				  (sizeof navigation_bindings
				   / sizeof (GtkUtilsBindingInfo)));
}

/* Elsewhere. */
void
gtk_utils_add_similar_bindings (GtkBindingSet *binding_set,
				const gchar *signal_name,
				GtkUtilsBindingInfo *bindings,
				int num_bindings)
{
  int k;

  g_return_if_fail (binding_set);
  g_return_if_fail (signal_name);
  g_return_if_fail (bindings);
  g_return_if_fail (num_bindings > 0);

  for (k = 0; k < num_bindings; k++) {
    gtk_binding_entry_add_signal (binding_set,
				  bindings[k].keyval, bindings[k].modifiers,
				  signal_name,
				  1, G_TYPE_INT, bindings[k].signal_parameter);
  }
}

Note that you are done with using gtk_binding_set_by_class() and gtk_binding_entry_add_signal().  Everything else is just utility for my own use.
No special handling of the created binding set is required, it is automatic in the sense that it is handled by GTK+ itself.
Comment 4 Paul Pogonyshev 2006-08-21 19:29:31 UTC
However, there are two difficulties I can see for a C++ implementation.  First is that standard usage of GtkBindingSet relies on GType and, as far as I understand, all Gtk::Widget descendants will have one GType in a Gtkmm program.  This may be solved with `typeid'.

Second is that GtkBindingSet uses C-level signals and I'm not sure how to use C++-level (sigc++) signals instead.
Comment 5 Chong Kai Xiong 2006-08-24 15:16:48 UTC
Another problem is that user-defined libsigc++ signals are not registered with the GObject system, and gtk_binding_activate_event() needs to look them up by name to emit the right signals.
Comment 6 Paul Pogonyshev 2006-08-24 18:27:33 UTC
I thing Gtkmm can use a proxy object to relay C-level signal emissions to C++ signals.  In other words, I propose to use a somewhat different syntax for C++ that doesn't expect signal names, but rather uses sigc++ slots, for instance signal emission slots, but those could be anything.
Comment 7 Paul Pogonyshev 2006-08-25 18:46:40 UTC
OK, I have a working implementation, see below.  It uses some internal utilities, but those are in no way critical.  Please let me know if you are interested.
Comment 8 Paul Pogonyshev 2006-08-25 18:47:46 UTC
Created attachment 71612 [details]
header file
Comment 9 Paul Pogonyshev 2006-08-25 18:48:30 UTC
Created attachment 71613 [details]
source file
Comment 10 Murray Cumming 2007-02-10 15:21:23 UTC
Let's take a look at this when we branch for gtkmm 2.12. Among other things, this should follow existing conventions, such as capitalized class names without _ underscores.

We'll need an example to show how to use this. That could be an addition to the custom widget example, I guess.

Comment 11 Paul Pogonyshev 2007-02-16 23:18:53 UTC
Created attachment 82710 [details]
somewhat cleaned up sources + example of usage

I stripped the sources of all dependency on my program (which is now written in PyGTK anyway.)  Also added a quick example.  It features two widgets of same class and cursor keys work in the one which is focused at the moment (to demonstrate difference from window-global accelerators.)

I would appreciate if someone in Gtkmm team could take over this code, since I don't plan to work on Gtkmm myself.  I'm willing to provide help, though.
Comment 12 Paul Pogonyshev 2007-02-16 23:25:36 UTC
I also took the latest version of the files from my program.  No idea if they differ from what I posted before.

A nice idea that would make usage simpler is to implement something like C-level function gtk_binding_set_by_class ().  So, user-derived classes wouldn't have to define specific on_key_press/on_key_release handlers, but just add bindings to result of Gtk::BindingSet <...>::by_class().  Then all Gtkmm classes would call by_class() itself in default handlers and if it returns an existing object, would call activate_event() on it.  I'm not sure if that is difficult to implement, but since it requires changing existing Gtkmm code, I don't volunteer.
Comment 13 Murray Cumming 2010-11-18 08:49:29 UTC
Note to self: Don't ignore this.
http://library.gnome.org/devel/gtk/unstable/gtk3-Bindings.html
Comment 14 Murray Cumming 2011-02-22 09:58:35 UTC
I'm still interesting in this if someone wants to create a git patch for gtkmm 3. Time is running out though.
Comment 15 Murray Cumming 2011-03-09 13:08:23 UTC
Last chance for a patch.
Comment 16 Murray Cumming 2011-03-19 12:06:54 UTC
Punted to gtkmm 3.2 then.
Comment 17 Daniel Boles 2017-08-13 15:42:36 UTC
(In reply to Chong Kai Xiong from comment #2)
> In the class initializer, the code first creates a GtkBindingSet for the
> class using gtk_binding_set_by_class(). Then, key-signal entries are added
> to map keys to signal handlers using gtk_binding_entry_add_signal(),
> complete with arguments used to invoke them.

As you've seen, gtkmm 3 doesn't support any custom code in class initialisers. So, you had to approximate it using a static member and having the first instance constructed populate said member. This presumably works for you but is not ideal from a design POV.

gtkmm 4/master does support custom class init methods, so that might be better suited to wrapping GtkBindings.


(In reply to Paul Pogonyshev from comment #4)
> However, there are two difficulties I can see for a C++ implementation. 
> First is that standard usage of GtkBindingSet relies on GType and, as far as
> I understand, all Gtk::Widget descendants will have one GType in a Gtkmm
> program.  This may be solved with `typeid'.

No, each glibmm/gtkmm class will have the GType of the C class it wrapps.


> Second is that GtkBindingSet uses C-level signals and I'm not sure how to
> use C++-level (sigc++) signals instead.

Is that why you convert between int/long/pointer, as if these are interchangeable, when they're really not? That whole pattern seems like a timebomb waiting to go off and probably a bad idea for including in any library. GLib itself warns about this:

    Remember, you may not store pointers in integers. This is not portable in any way, shape or form. These macros only allow storing integers in pointers, and only preserve 32 bits of the integer; values outside the range of a 32-bit integer will be mangled.
Comment 18 Kjell Ahlstedt 2017-08-14 13:25:59 UTC
>> as far as I understand, all Gtk::Widget descendants will have one GType in a
>> Gtkmm program.
>
> No, each glibmm/gtkmm class will have the GType of the C class it wraps.

The connection between the GType class hierarchy and the C++ hierarchy is
somewhat curious. Let's take part of a hierarchy as an example.

In C++/gtkmm:
  class Gtk::Widget : public ...
  class Gtk::Container : public Gtk::Widget
  class Gtk::Box : public Gtk::Container

In GType/gtk+:
  class GtkWidget : public ...
  class GtkContainer : public GtkWidget
  class GtkBox : public GtkContainer

In GType/gtkmm add:
  class gtkmm__GtkWidget : public GtkWidget       // Gtk::Widget
  class gtkmm__GtkContainer : public GtkContainer // Gtk::Container
  class gtkmm__GtkBox : public GtkBox             // Gtk::Box

If a user of gtkmm derives a class such as
  class MyBox : public Gtk::Box
in the usual way, implicitly calling Glib::ObjectBase's default constructor,
then MyBox will have the same GType as Gtk::Box.
Comment 19 Daniel Boles 2017-10-09 12:37:03 UTC
Interesting, thanks. So, if a new name is needed, we call Glib::ObjectBase("name") manually passing it? Which is always possible because we need virtual inheritance, and that makes us responsible for calling all base constructors.

Related to this is Bug 546220: "Maybe all derived classes should get their own GType automatically."
Comment 20 GNOME Infrastructure Team 2018-05-22 12:08:14 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to GNOME's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/gtkmm/issues/3.