9
votes

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.)

1
Is your custom widget a Gtk::DrawingArea (or could be implemented as that)?higuaro
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
@h3nr1x: No. Take a peek at the code linked above -- it's very simple.bstpierre
There is also a longish discussion of this topic at 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
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

1 Answers

5
votes

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.