How do I add a custom gtkmm widget to glade?
Asked Answered
T

1

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

Tact answered 31/5, 2012 at 1:40 Comment(14)
Is your custom widget a Gtk::DrawingArea (or could be implemented as that)?Earley
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.Summerville
@h3nr1x: No. Take a peek at the code linked above -- it's very simple.Tact
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.Summerville
@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? I'm going to test it out tonight.Tact
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.Summerville
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.Summerville
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.)Tact
Doh! I wrote that too soon -- the examples compile and run fine, but glade does not work at all.Tact
@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...Tact
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.Borman
@Tom: See Szilárd Pfeiffer's answer -- it fixes the type registration piece of the puzzle.Tact
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.Summerville
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.Tact
S
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.

Sellars answered 13/6, 2012 at 9:30 Comment(3)
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.Summerville
As far as I know it works with gtkmm 2.x. I completed my blog post with the appropriate commands (code compilation, Glade related environment variables) and notes.Borman
@SzilárdPfeiffer, do you still have the link? The one in your comment is broken...Rebekah

© 2022 - 2024 — McMap. All rights reserved.