9

I'm writing a custom widget using gtkmm, and I haven't been able to get it to work in glade. (The widget itself is barely functional; it does work, and I want to get it to work in glade before moving on to the next step.) Glade finds the widget, but when I try to place it in a window, glade crashes.

Based on hints I found during various searches, I added this bit of code to the main source file:

extern "C"
{
    GType date_chooser_get_type(void)
    {
        return DateChooser::get_type();
    }
}

I have a suspicion that the code above isn't right, but I can't find any gtkmm or glade documentation about what this function should do.

Based on the catalog documentation for glade, I created the following XML:

<?xml version="1.0" encoding="UTF-8"?>
<glade-catalog name="gtk-date-chooser" library="libgtkdatechooser-0.1.so" language="c++">
  <glade-widget-classes>
    <glade-widget-class name="DateChooser" generic-name="date-chooser" title="Date Chooser" />
  </glade-widget-classes>
  <glade-widget-group name="date" title="Date">
    <glade-widget-class-ref name="DateChooser"/>
  </glade-widget-group>
</glade-catalog>

This is in the root of my widget's source directory with the name gtk-date-chooser.xml. I run glade in that directory using:

GLADE_CATALOG_SEARCH_PATH=. GLADE_MODULE_SEARCH_PATH=./.libs glade

When the window comes up, my widget appears in a special "Date" group as specified in the catalog, with a default icon. If I place a window and then select the widget for placement in the window, glade crashes. I see the following on the console:

GladeUI-Message: 2 missing displayable value for GtkWidget::events
GladeUI-Message: No displayable values for property GtkTreeSelection::mode
GladeUI-Message: 1 missing displayable value for GtkCellRendererAccel::accel-mode
GladeUI-Message: 14 missing displayable value for GtkCellRendererAccel::accel-mods

(glade:23757): GladeUI-CRITICAL **: gwa_list_signals: assertion `real_type != 0' failed

(glade:23757): GLib-GObject-WARNING **: cannot retrieve class for invalid (unclassed) type `<invalid>'

(glade:23757): GLib-GObject-CRITICAL **: g_object_class_list_properties: assertion `G_IS_OBJECT_CLASS (class)' failed

(glade:23757): GLib-GObject-WARNING **: cannot retrieve class for invalid (unclassed) type `<invalid>'

(glade:23757): Gtk-CRITICAL **: gtk_container_class_list_child_properties: assertion `GTK_IS_CONTAINER_CLASS (cclass)' failed
GladeUI-Message: Glade needs artwork; a default icon will be used for the following classes:
    DateChooser needs an icon named 'widget-gtk-date-chooser-date-chooser'
**
GladeUI:ERROR:glade-signal-model.c:800:glade_signal_model_iter_n_children: code should not be reached

It seems like the answer to this (unanswered) question might provide a clue, but I haven't been able to find any answer for that question or clues that will help with my problem.

Versions I'm using:

  • Ubuntu: 12.04
  • gtkmm: 3.4.0-0ubuntu1
  • glade: 3.12.0-0ubuntu1

(I'd be willing to test solutions based on trunk versions, or on Centos 6 or Fedora 16.)

Community
  • 1
  • 1
bstpierre
  • 30,042
  • 15
  • 70
  • 103
  • Is your custom widget a Gtk::DrawingArea (or could be implemented as that)? – higuaro Jun 06 '12 at 13:37
  • I have the same problem. It seems to be happening because the new type is not being properly registered. This in turn depends on calling `Gtk::Main::init_gtkmm_internals()` in a library initialisation function, and doing so prevents glade from starting up properly. Haven't figured out why yet, though. – Tom Jun 06 '12 at 14:05
  • @h3nr1x: No. Take a peek at the code linked above -- it's very simple. – bstpierre Jun 06 '12 at 14:13
  • There is also a longish discussion of this topic at https://mail.gnome.org/archives/gtkmm-list/2006-November/msg00132.html but it never comes to a conclusion of how to include Gtk-- widgets in a catalog. The best I've managed is to leave an empty container and add the widget programmatically. – Tom Jun 06 '12 at 14:49
  • @Tom: Thanks for the pointer. I don't know why I hadn't stumbled across that thread in my searches. Have you followed Oliver Nittka's example in [this message](https://mail.gnome.org/archives/gtkmm-list/2006-November/msg00182.html)? I'm going to test it out tonight. – bstpierre Jun 08 '12 at 13:35
  • 1
    I've found this one of the most frustrating problems I've come across to try to hunt down, because the documentation seems to have been reorganised and move to a different server three or four times in the past couple of years. So almost every article you find on the subject says, "read the documentation," complete with a dead link. – Tom Jun 10 '12 at 13:05
  • I've tried the example you linked - it doesn't work, at least not using the Ubuntu 12.04 versions of the libraries. The call to init_gtkmm_internals never returns. – Tom Jun 10 '12 at 13:13
  • I second your comment about the documentation. I finally had a chance to compile the example linked above, and it seems to work for me on Ubuntu 12.04 after I tweaked the Makefile to use `-fPIC` in `CXXFLAGS` and `-L. -lsimpledraw` at the end of the link lines instead of explicitly naming libsimpledraw.so near the beginning. (And then running with `LD_LIBRARY_PATH=. ./simpledraw_ctortest`.) – bstpierre Jun 12 '12 at 03:01
  • Doh! I wrote that too soon -- the examples compile and run fine, but glade does not work at all. – bstpierre Jun 12 '12 at 03:03
  • @Tom: Your link to the thread above has been the most helpful thing I've found. If you post it as an answer with a bit of commentary, the +200 is yours unless someone swoops in with a solution... – bstpierre Jun 12 '12 at 11:55
  • I'm writing a blog post about the topic, I hope it can help solve your problem. I'll be back with it as an answer. – Szilárd Pfeiffer Jun 12 '12 at 12:02
  • @Tom: See Szilárd Pfeiffer's answer -- it fixes the type registration piece of the puzzle. – bstpierre Jun 13 '12 at 12:50
  • I had a look but haven't had a chance to try it yet. I couldn't see what was different to what we'd already tried. – Tom Jun 14 '12 at 10:25
  • I tried it and it works. Haven't done a close comparison yet, but there's some detail in the type creation that I wasn't doing right, and the example linked above was doing either. – bstpierre Jun 14 '12 at 15:37

1 Answers1

6

The followings are required to add a custom gtkmm widget to Glade:

  1. at least one pure custom widget implementation
  2. some Glade-related extra functions to the custom widgets
  3. a catalog file which describes the custom widgets to Glade
  4. a library contains the custom widgets and some Glade-related functions

The most important thing is the fact that Glade is written in C not in C++, so we have to be able to wrap a plan C widget to a C++ one and we have to register this wrap function to the GType related to the custom widget. It looks something like the followings:

#include "custom_widget.h"

GType CustomWidget::gtype = 0;

CustomWidget::CustomWidget (GtkEntry *gobj) :
  Gtk::Entry (gobj)
{
}

CustomWidget::CustomWidget () :
  Glib::ObjectBase ("customwidget")
{
}

Glib::ObjectBase *
CustomWidget::wrap_new (GObject *o)
{
  if (gtk_widget_is_toplevel (GTK_WIDGET (o)))
    {
      return new CustomWidget (GTK_ENTRY (o));
    }
  else
    {
      return Gtk::manage(new CustomWidget (GTK_ENTRY (o)));
    }
}

void
CustomWidget::register_type ()
{
  if (gtype)
    return;

  CustomWidget dummy;

  GtkWidget *widget = GTK_WIDGET (dummy.gobj ());

  gtype = G_OBJECT_TYPE (widget);

  Glib::wrap_register (gtype, CustomWidget::wrap_new);
}

You should write the catalog file very carefully. Names must be correct (especially glade-widget-class) for the proper work.

<?xml version="1.0" encoding="UTF-8" ?>
<glade-catalog name="customwidgets" library="customwidgetsglade" depends="gtk+">

  <init-function>custom_widgets_glade_init</init-function>

  <glade-widget-classes>
    <glade-widget-class name="gtkmm__CustomObject_customwidget" generic-name="customwidget" icon-name="widget-gtk-entry" title="Custom Widget">
    </glade-widget-class>
  </glade-widget-classes>

  <glade-widget-group name="customwidgets" title="Custom Widgets" >
    <glade-widget-class-ref name="gtkmm__CustomObject_customwidget" />
  </glade-widget-group>

</glade-catalog>

There is nothing to do, but implement the function, which registers our widget as the part of the initialization of our Glade library.

extern "C" void
custom_widgets_glade_init ()
{
  Gtk::Main::init_gtkmm_internals ();
  custom_widgets_register ();
}

Initializing gtkmm internals is a must, because custom_widgets_glade_init is called from Glade, which is written in C not in C++ so it initializes only the GTK+.

If you are interested in the topic you can find my blog post here with more the details.

Szilárd Pfeiffer
  • 1,636
  • 1
  • 12
  • 6
  • Sigh. After a *long* time beating my head against this, realised that the example given only works with gtk-- 3.0, not with 2.4. – Tom Jul 12 '12 at 15:19
  • As far as I know it works with _gtkmm_ 2.x. I completed [my blog post](http://szilard.blogs.balabit.com/en/2012/06/how-to-add-custom-gtkmm-widget-to-glade/) with the appropriate commands (code compilation, _Glade_ related environment variables) and notes. – Szilárd Pfeiffer Jan 26 '13 at 12:55
  • 2
    @SzilárdPfeiffer, do you still have the link? The one in your comment is broken... – Mateus Terra Feb 03 '20 at 15:34