5

I've made a simple custom widget for GTK+3 in C, named AwLed, and added it to a custom Glade catalog. It works as expected inside Glade or when created using the aw_led_new() function. However, when I make a simple program that loads the Glade file and shows its widgets (calling the show_all() on the main window widget), the custom widgets don't show themselves. I added some printf-fflushs to debug and found out that the functions Realize, Allocate aren't even called. It would seem like the whole shared library is not loaded.

Now, what Glade does other than loading the widgets with GtkBuilder? Why these widgets are ignored? Am I suppose to write some boilerplate to implement the GtkBuildable interface?

Any help is well appreciated.

awled.c

#include <gtk/gtk.h>
#include "awled.h"

enum {
  PROP_0,
  PROP_ACTIVE,
};

static void      aw_led_set_property          (GObject        *object,
                                               guint           prop_id,
                                               const GValue   *value,
                                               GParamSpec     *pspec);
static void      aw_led_get_property          (GObject        *object,
                                               guint           prop_id,
                                               GValue         *value,
                                               GParamSpec     *pspec);
static void      aw_led_realize               (GtkWidget      *widget);
static void      aw_led_unrealize             (GtkWidget      *widget);
static void      aw_led_map                   (GtkWidget      *widget);
static void      aw_led_unmap                 (GtkWidget      *widget);
static void      aw_led_size_allocate         (GtkWidget      *widget,
                                               GtkAllocation  *allocation);
static void      aw_led_get_preferred_width (GtkWidget *widget,
                                              gint      *minimal_width,
                                              gint      *natural_width);
static void      aw_led_get_preferred_height (GtkWidget *widget,
                                              gint      *minimal_height,
                                              gint      *natural_height);
static gboolean  aw_led_draw                (GtkWidget      *widget,
                                             cairo_t *cr);

G_DEFINE_TYPE (AwLed, aw_led, GTK_TYPE_WIDGET)

#define parent_class aw_led_parent_class

static void
aw_led_class_init (AwLedClass *klass)
{
  GObjectClass   *object_class = G_OBJECT_CLASS (klass);
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);

  object_class->set_property         = aw_led_set_property;
  object_class->get_property         = aw_led_get_property;

  widget_class->realize              = aw_led_realize;
  widget_class->unrealize            = aw_led_unrealize;
  widget_class->map                  = aw_led_map;
  widget_class->unmap                = aw_led_unmap;
  widget_class->size_allocate        = aw_led_size_allocate;
  widget_class->get_preferred_width  = aw_led_get_preferred_width;
  widget_class->get_preferred_height = aw_led_get_preferred_height;
  widget_class->draw                 = aw_led_draw;

  GParamSpec* param_spec;
  param_spec = g_param_spec_boolean ("active", "Active", "LED State",
                                     FALSE, G_PARAM_READWRITE);
  g_object_class_install_property (object_class, PROP_ACTIVE, param_spec);
}


static void
aw_led_init (AwLed *led)
{
  gtk_widget_set_has_window (GTK_WIDGET (led), FALSE);

  led->state           = FALSE;
  led->color_on.red    = 0.0;
  led->color_on.green  = 0.6;
  led->color_on.blue   = 0.0;
  led->color_on.alpha  = 1.0;
  led->color_off.red   = 0.6;
  led->color_off.green = 0.0;
  led->color_off.blue  = 0.0;
  led->color_off.alpha = 1.0;
  /*priv->backing_store       = NULL; //what?? needed?
  priv->backing_store_valid = FALSE;
  priv->pos_redraw_idle_id   = 0;*/ 
}


static void
aw_led_set_property (GObject      *object,
                     guint         prop_id,
                     const GValue *value,
                     GParamSpec   *pspec)
{
  AwLed *led = AW_LED (object);

  switch (prop_id)
  {
    case PROP_ACTIVE:
      led->state = g_value_get_boolean (value);
      gtk_widget_queue_resize (GTK_WIDGET (led));
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}


static void
aw_led_get_property (GObject    *object,
                     guint       prop_id,
                     GValue     *value,
                     GParamSpec *pspec)
{
 AwLed *led = AW_LED (object);

  switch (prop_id)
    {
    case PROP_ACTIVE:
      g_value_set_boolean (value, led->state);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}


GtkWidget *
aw_led_new ()
{
  return g_object_new (AW_TYPE_LED,
                       "active", FALSE,
                       NULL);
}


static void
aw_led_realize (GtkWidget *widget)
{
  AwLed         *led = AW_LED (widget);
  GtkAllocation allocation;
  GdkWindowAttr attributes;
  gint          attributes_mask;

  GTK_WIDGET_CLASS (aw_led_parent_class)->realize (widget);

  gtk_widget_get_allocation (widget, &allocation);

  attributes.window_type = GDK_WINDOW_CHILD;
  attributes.x           = allocation.x;
  attributes.y           = allocation.y;
  attributes.width       = allocation.width;
  attributes.height      = allocation.height;
  attributes.wclass      = GDK_INPUT_ONLY;
  attributes.event_mask  = (gtk_widget_get_events (widget) | 
                            GDK_EXPOSURE_MASK);

  attributes_mask = GDK_WA_X | GDK_WA_Y;

  led->input_window = gdk_window_new (gtk_widget_get_window (widget),
                                       &attributes, attributes_mask);
  gdk_window_set_user_data (led->input_window, led);

}


static void
aw_led_unrealize (GtkWidget *widget)
{
  AwLed *led = AW_LED (widget);

  if (led->input_window) {
      gdk_window_destroy (led->input_window);
      led->input_window = NULL;
  }

  GTK_WIDGET_CLASS (aw_led_parent_class)->unrealize (widget);
}


static void
aw_led_map (GtkWidget *widget)
{
  AwLed *led = AW_LED (widget);

  GTK_WIDGET_CLASS (parent_class)->map (widget);

  if (led->input_window)
    gdk_window_show (led->input_window);

}


static void
aw_led_unmap (GtkWidget *widget)
{
  AwLed *led = AW_LED (widget);
  if (led->input_window)
    gdk_window_hide (led->input_window);

  GTK_WIDGET_CLASS (parent_class)->unmap (widget);
}


static void
aw_led_size_allocate (GtkWidget     *widget,
                      GtkAllocation *allocation)
{
  AwLed *led = AW_LED (widget);

  gtk_widget_set_allocation (widget, allocation);

  if (gtk_widget_get_realized (widget)) {
      gdk_window_move_resize (led->input_window,
                              allocation->x, allocation->y,
                              allocation->width, allocation->height);
  }
}


static void
aw_led_get_preferred_width (GtkWidget *widget,
                            gint      *minimal_width,
                            gint      *natural_width)
{
  *minimal_width = 20;
  *natural_width = 35;
}


static void
aw_led_get_preferred_height (GtkWidget *widget,
                             gint      *minimal_height,
                             gint      *natural_height)
{
  *minimal_height = 20;
  *natural_height = 35;
}


static gboolean
aw_led_draw (GtkWidget *widget,
             cairo_t   *cr)
{
  gint width, height;
  AwLed* led = AW_LED(widget);

  width = gtk_widget_get_allocated_width (widget);
  height = gtk_widget_get_allocated_height (widget);

  GdkRGBA color = (led->state) ? led->color_on : led->color_off;

  cairo_arc (cr, width / 2.0, height / 2.0,
             MIN (width, height) / 2.0, 0, 2 * G_PI);

  gdk_cairo_set_source_rgba (cr, &color);

  cairo_fill (cr);

  return TRUE;
}

awled.h

#ifndef __AW_LED_H__
#define __AW_LED_H__

#include <gtk/gtk.h>

G_BEGIN_DECLS

#define AW_TYPE_LED             (aw_led_get_type ())
#define AW_LED(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), AW_TYPE_LED, AwLed))
#define AW_LED_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), AW_TYPE_LED, AwLedClass))
#define AW_IS_LED(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AW_TYPE_LED))
#define AW_IS_LED_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), AW_TYPE_LED))
#define AW_LED_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), AW_TYPE_LED, AwLedClass))

typedef struct _AwLed      AwLed;
typedef struct _AwLedClass AwLedClass;

typedef enum {
    OVAL,
    RECTANGULAR
} AwLedShape;

struct _AwLed {
    GtkWidget  parent_instance;
    //public members
    //@TODO Move these to .C file (AwLedPrivate structure)
    GdkRGBA    color_on;
    GdkRGBA    color_off;
    AwLedShape shape;
    gboolean   state;
    GdkWindow  *input_window;
};

struct _AwLedClass {
    GtkWidgetClass parent_class;
};

GType aw_led_get_type (void) G_GNUC_CONST;
GtkWidget* aw_led_new ();
gboolean aw_led_get_state (AwLed* led);
void aw_led_set_state (AwLed* led, gboolean state);

G_END_DECLS

#endif /* __AW_LED_H__ */

test_builder.c

#include <gtk/gtk.h>
#include <awled.h>

int main(int argc, char* argv[]) {
    GtkBuilder* builder;
    GtkWidget *window, *led, *led2, *box;

    gtk_init(&argc, &argv);

    builder = gtk_builder_new();
    gtk_builder_add_from_file(builder, "interface.ui", NULL);

    window = (GtkWidget*) gtk_builder_get_object(builder, "window1");
    led = (GtkWidget*) gtk_builder_get_object(builder, "led1");
    box = (GtkWidget*) gtk_builder_get_object(builder, "box1");

    //weird... if I create only one this way, all of them show themselves!
    //led2 = aw_led_new();
    //gtk_box_pack_end(GTK_BOX(box), led2, 0, 0, 0);

    gtk_widget_show_all(window);

    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);    

    gtk_main();
}
LRMAAX
  • 301
  • 3
  • 10
  • Can you try this without glade? – Iharob Al Asimi Jan 04 '16 at 13:46
  • What messages show up on stderr? – andlabs Jan 04 '16 at 14:46
  • 1
    Unfortunately, no error message. Works fine without Glade and without GtkBuilder. I just confirmed it's a problem of not loading the shared library: I created a dummy function aw_init(), which actually does nothing. However, by calling this function anywhere in my code, the widgets are correctly displayed. It's like the in my Glade file is ignored and the .so file isn't loaded automatically by GtkBuilder. – LRMAAX Jan 04 '16 at 17:06

0 Answers0