TreeView with CellRendererText extended as (new class) CellRendererWidget: can't see widget...



Hello! I'm pasting a test file in below. I am trying to embed widgets in the TreeView. However, when I run the following file, I cannot see the widget.

I am using:
atk-1.10.1       glib-2.8.0        gtkmm-2.6.4       pango-1.10.0
cairo-0.9.2      glibmm-2.6.1      libiconv-1.9.2    pkg-config-0.19
freetype-2.1.10  gtk+-2.8.0        gettext-0.14.5   libsigc++-2.0.16

#include <gtk/gtk.h>

void maybe_update_text(GtkWidget * treeview, GtkWidget * widget,
                       const gchar * text)
{
}

typedef struct _GtkCellRendererWidget GtkCellRendererWidget;
struct _GtkCellRendererWidget
{
  GtkCellRendererText parent;

  GtkWidget * widget;
};

struct _GtkCellRendererWidgetClass
{
  GtkCellRendererTextClass parent_class;
};

static GType cell_renderer_widget_type;
static gpointer cell_renderer_widget_parent_class;

#define GTK_CELL_RENDERER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
                                       cell_renderer_widget_type, \
                                       GtkCellRendererWidget))

#define PROP_WIDGET 1

static void gtk_cell_renderer_widget_get_size(GtkCellRenderer * cr,
                                              GtkWidget * treeview,
                                              GdkRectangle * cell_area,
                                              gint * x_offset, gint * y_offset,
                                              gint * width, gint * height)
{
  GtkCellRendererWidget * crw = GTK_CELL_RENDERER_WIDGET(cr);
  if (crw->widget) {
    GtkRequisition req;
    gtk_widget_size_request(GTK_WIDGET(crw->widget), &req);
    if (x_offset) *x_offset = 0;
    if (y_offset) *y_offset = 0;
    if (width) *width = req.width;
    if (height) *height = req.height+50;
  }
  else GTK_CELL_RENDERER_CLASS(cell_renderer_widget_parent_class)->
      get_size(cr, treeview, cell_area, x_offset, y_offset, width, height);
}

static void gtk_cell_renderer_widget_render(GtkCellRenderer * cr,
                                            GdkWindow * bin_window,
                                            GtkWidget * treeview,
                                            GdkRectangle * background_area,
                                            GdkRectangle * cell_area,
                                            GdkRectangle * expose_area,
                                            GtkCellRendererState flags)
{
  GtkCellRendererWidget * crw = GTK_CELL_RENDERER_WIDGET(cr);
  if (crw->widget && (crw->widget->allocation.x!=cell_area->x ||
                      crw->widget->allocation.y!=cell_area->y ||
                      crw->widget->allocation.width!=cell_area->width ||
                      crw->widget->allocation.height!=cell_area->height)) {
    gtk_widget_size_allocate(crw->widget, cell_area);
  }
  maybe_update_text(treeview, crw->widget, GTK_CELL_RENDERER_TEXT(cr)->text);
  GTK_CELL_RENDERER_CLASS(cell_renderer_widget_parent_class)->
      render(cr, bin_window, treeview, background_area, cell_area, expose_area,
             flags);
}

static GtkCellEditable * gtk_cell_renderer_widget_start_editing(
                         GtkCellRenderer * cr, GdkEvent * event,
                         GtkWidget * treeview, const gchar * path,
                         GdkRectangle * background_area,
                         GdkRectangle * cell_area, GtkCellRendererState flags)
{
  GtkCellRendererWidget * crw = GTK_CELL_RENDERER_WIDGET(cr);
  if (crw->widget) {
    /* set focus to widget */
    return 0;
  }
  return GTK_CELL_RENDERER_CLASS(cell_renderer_widget_parent_class)->
      start_editing(cr, event, treeview, path, background_area, cell_area,
                    flags);
}

static void gtk_cell_renderer_widget_get_property(GObject * object,
                                                  guint paramid, GValue * value,
                                                  GParamSpec * pspec)
{
  GtkCellRendererWidget * crw = GTK_CELL_RENDERER_WIDGET(object);
  switch (paramid)
  {
  case PROP_WIDGET:
    g_value_set_object(value, (GObject *) crw->widget);
    break;
  default:
    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, paramid, pspec);
    break;
  }
}

static void gtk_cell_renderer_widget_set_property(GObject * object,
                                                  guint paramid,
                                                  const GValue * value,
                                                  GParamSpec * pspec)
{
  GtkCellRendererWidget * crw = GTK_CELL_RENDERER_WIDGET(object);
  switch (paramid)
  {
  case PROP_WIDGET:
    if (crw->widget) g_object_unref(G_OBJECT(crw->widget));
    crw->widget = GTK_WIDGET(g_value_get_object(value));
    if (crw->widget) g_object_ref(G_OBJECT(crw->widget));
    break;
  default:
    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, paramid, pspec);
    break;
  }
}

static void gtk_cell_renderer_widget_destroy(GtkObject * object)
{
  GtkCellRendererWidget * crw = GTK_CELL_RENDERER_WIDGET(object);

  if (crw->widget) {
    printf("cell_r_widg widg=%08x refcount=%u: about to unref\n",
           (unsigned) crw->widget, G_OBJECT(crw->widget)->ref_count);
    g_object_unref(G_OBJECT(crw->widget));
  }

  (* GTK_OBJECT_CLASS(cell_renderer_widget_parent_class)->destroy)(object);
}

static void gtk_cell_renderer_widget_class_init(
            struct _GtkCellRendererWidgetClass * cl)
{
  GObjectClass * object_class = G_OBJECT_CLASS(cl);
  GtkObjectClass * gtk_object_class = GTK_OBJECT_CLASS(cl);
  GtkCellRendererClass * cell_r_class = GTK_CELL_RENDERER_CLASS(cl);

  cell_renderer_widget_parent_class = g_type_class_peek_parent(cl);

  object_class->get_property = gtk_cell_renderer_widget_get_property;
  object_class->set_property = gtk_cell_renderer_widget_set_property;

  gtk_object_class->destroy = gtk_cell_renderer_widget_destroy;

  cell_r_class->get_size = gtk_cell_renderer_widget_get_size;
  cell_r_class->render = gtk_cell_renderer_widget_render;
  cell_r_class->start_editing = gtk_cell_renderer_widget_start_editing;

  g_object_class_install_property(object_class, PROP_WIDGET,
                                  g_param_spec_object("widget", "Widget",
                                                      "Widget in cell",
                                                      GTK_TYPE_WIDGET,
                                                      G_PARAM_READWRITE |
                                                      G_PARAM_STATIC_NAME |
                                                      G_PARAM_STATIC_NICK |
                                                      G_PARAM_STATIC_BLURB));
}

static void gtk_cell_renderer_widget_init(GtkCellRendererWidget * crw)
{
  crw->widget = 0;
}

GType gtk_cell_renderer_widget_register_type()
{
  static const GTypeInfo renderer_widget_info =
  {
    sizeof(struct _GtkCellRendererWidgetClass),
    0,    /* base_init */
    0,    /* base_finalize */
    (GClassInitFunc) gtk_cell_renderer_widget_class_init,
    0,    /* class_finalize */
    0,    /* class_data */
    sizeof(GtkCellRendererWidget),
    0,    /* n_preallocs */
    (GInstanceInitFunc) gtk_cell_renderer_widget_init,
  };
  return g_type_register_static(GTK_TYPE_CELL_RENDERER_TEXT,
                                "GtkCellRendererWidget",
                                &renderer_widget_info, 0);
}

GtkCellRenderer * gtk_cell_renderer_widget_new()
{
  return g_object_new(cell_renderer_widget_type, 0);
}

GtkButton * the_button;

gboolean the_button_is_exposed(GtkWidget * widget, GdkEventExpose * event,
                               gpointer data)
{
  printf("the_button_is_exposed\n");
  return FALSE;  /* propagate the event to other handlers */
}

gboolean is_treeview_row_a_separator(GtkTreeModel * model, GtkTreeIter * iter,
                                     gpointer context)
{
  gboolean is_separator;
  gtk_tree_model_get(model, iter, 1, &is_separator, -1);
  return is_separator;
}

void the_button_destroyed(GtkObject * obj, gpointer data)
{
  if (obj!=GTK_OBJECT(the_button))
      printf("obj=%08x the_button=%08x ???\n",
             (unsigned) obj, (unsigned) the_button);
  printf("the_button destroyed\n");
}

struct treeview_expose_data
{
  GtkContainer * treeview;
  GdkEventExpose * event;
};

gboolean treeview_expose_model_foreach(GtkTreeModel * model,
                                       GtkTreePath * path, GtkTreeIter * iter,
                                       gpointer data)
{
  struct treeview_expose_data * p = (struct treeview_expose_data *) data;
  GObject * widget;
  gtk_tree_model_get(model, iter, 5, &widget, -1);
  if (!widget) return FALSE;  /* continue on foreach walk */

  GdkWindow * tvw = gtk_tree_view_get_bin_window(GTK_TREE_VIEW(p->treeview));
  GtkWidget * w = GTK_WIDGET(widget);
  g_return_val_if_fail(!w->window || w->window==tvw, FALSE);
  if (!w->window) {
    printf("set parent of %08x\n", (unsigned) w);
    gtk_widget_set_parent_window(w, tvw);
    gtk_widget_set_parent(w, GTK_WIDGET(p->treeview));
    /* gtk_widget_set_parent() does us a "favor" and does a g_object_ref() */
    g_object_unref(widget);
    gtk_widget_show(w);
    gtk_widget_queue_resize(w);
  }
  gtk_container_propagate_expose(p->treeview, w, p->event);
  g_object_unref(widget);
  return FALSE;  /* continue on foreach walk */
}

gboolean treeview_expose_model_widgets(GtkWidget * treeview,
                                       GdkEventExpose * event, gpointer p)
{
  /* attached to expose-event in treeview: propagate expose to all widgets */
  struct treeview_expose_data data;
  if (event->window != gtk_tree_view_get_bin_window(GTK_TREE_VIEW(treeview)))
      return FALSE;  /* propagate the event to other handlers */
  data.treeview = GTK_CONTAINER(treeview);
  data.event = event;
  gtk_tree_model_foreach(gtk_tree_view_get_model(GTK_TREE_VIEW(treeview)),
                         treeview_expose_model_foreach, &data);
  return FALSE;  /* propagate the event to other handlers */
}

void treestore_set_widget(GtkTreeStore * tstore, GtkTreeIter * iter,
                          const char * label, GtkWidget * widget)
{
  gtk_tree_store_set(tstore, iter, 0, label, 1, FALSE, 3, TRUE, 4, TRUE,
                     5, widget, -1);
  gtk_object_sink(GTK_OBJECT(widget));
}

GtkCellRenderer * r2;

void test_treeview(GtkScrolledWindow * sw)
{
  the_button = GTK_BUTTON(gtk_button_new_with_label("Test"));
  /*gtk_widget_show(GTK_WIDGET(the_button));*/
  printf("new the_button = %08x\n", (unsigned) the_button);
  g_signal_connect(G_OBJECT(the_button), "destroy",
                   G_CALLBACK(the_button_destroyed), 0);
  g_signal_connect(G_OBJECT(the_button), "expose-event",
                   G_CALLBACK(the_button_is_exposed), 0);

  GtkTreeStore * tstore = gtk_tree_store_new(6,
                          G_TYPE_STRING,  /* label */
                          G_TYPE_BOOLEAN, /* is_separator */
                          G_TYPE_STRING,  /* contents */
                          G_TYPE_BOOLEAN, /* contents.visible */
                          G_TYPE_BOOLEAN, /* contents.editable */
                          G_TYPE_OBJECT   /* contents.widget */);
  GtkWidget * treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(tstore));
  g_signal_connect(G_OBJECT(treeview), "expose-event",
                   G_CALLBACK(treeview_expose_model_widgets), 0);
  gtk_tree_view_set_row_separator_func(GTK_TREE_VIEW(treeview),
                                       is_treeview_row_a_separator, 0, 0);

  GtkCellRenderer * r1 = gtk_cell_renderer_text_new();
  GtkTreeViewColumn * col1 = gtk_tree_view_column_new_with_attributes(
                             "Label", r1, "text", 0, NULL);
  gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), col1);

  r2 = gtk_cell_renderer_widget_new();
  GtkTreeViewColumn * col2 = gtk_tree_view_column_new_with_attributes(
                             "Contents", r2, "text", 2, "visible", 3,
                             "editable", 4, "widget", 5, NULL);
  gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), col2);

  gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
  gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
  gtk_container_add(GTK_CONTAINER(sw), treeview);

  GtkTreeIter pi, ci, gi;
  gtk_tree_store_append(tstore, &pi, 0);
  gtk_tree_store_set(tstore, &pi, 0, "Parent 1", 1, FALSE,
                     2, "Value 1", 3, FALSE, 4, TRUE, -1);

  gtk_tree_store_append(tstore, &ci, &pi);
  gtk_tree_store_set(tstore, &ci, 0, "Child 1.1", 1, FALSE,
                     2, "Value 1.1", 3, TRUE, 4, TRUE, -1);

  gtk_tree_store_append(tstore, &ci, &pi);
  gtk_tree_store_set(tstore, &ci, 0, "Child 1.2", 1, FALSE,
                     2, "Value 1.2", 3, TRUE, 4, TRUE, -1);

  gtk_tree_store_append(tstore, &ci, &pi);
  gtk_tree_store_set(tstore, &ci, 0, "Child 1.3", 1, FALSE,
                     2, "Value 1.3", 3, TRUE, 4, TRUE, -1);

  gtk_tree_store_append(tstore, &pi, 0);
  gtk_tree_store_set(tstore, &pi, 0, "Parent 2", 1, FALSE,
                     2, "Value 2", 3, FALSE, 4, TRUE, -1);

  gtk_tree_store_append(tstore, &ci, &pi);
  gtk_tree_store_set(tstore, &ci, 0, "Child 2.1", 1, FALSE,
                     2, "Value 2.1", 3, FALSE, 4, TRUE, -1);

  gtk_tree_store_append(tstore, &gi, &ci);
  gtk_tree_store_set(tstore, &gi, 0, "Grandchild 2.1.1", 1, FALSE,
                     2, "Value 2.1.1", 3, TRUE, 4, TRUE, -1);

  gtk_tree_store_append(tstore, &gi, &ci);
  treestore_set_widget(tstore, &gi, "Grandchild 2.1.2", GTK_WIDGET(the_button));

  gtk_tree_store_append(tstore, &gi, &ci);
  gtk_tree_store_set(tstore, &gi, 0, "Grandchild 2.1.3", 1, FALSE,
                     2, "Value 2.1.3", 3, TRUE, 4, TRUE, -1);

  gtk_tree_store_append(tstore, &ci, &pi);
  gtk_tree_store_set(tstore, &ci, 0, "Child 2.2", 1, FALSE,
                     2, "Value 2.2", 3, TRUE, 4, TRUE, -1);

  gtk_tree_store_append(tstore, &ci, &pi);
  gtk_tree_store_set(tstore, &ci, 0, "Child 2.3", 1, FALSE,
                     2, "Value 2.3", 3, TRUE, 4, TRUE, -1);

  gtk_tree_view_expand_row(GTK_TREE_VIEW(treeview),
                           gtk_tree_model_get_path(GTK_TREE_MODEL(tstore), &pi),
                           TRUE /*open_all*/);

  gtk_tree_store_append(tstore, &pi, 0);
  gtk_tree_store_set(tstore, &pi, 0, "Separator", 1, TRUE,
                     2, "(separator)", 3, FALSE, 4, TRUE, -1);

  gtk_tree_store_append(tstore, &pi, 0);
  gtk_tree_store_set(tstore, &pi, 0, "Parent 3", 1, FALSE,
                     2, "Value 3", 3, FALSE, 4, TRUE, -1);

  gtk_tree_store_append(tstore, &ci, &pi);
  gtk_tree_store_set(tstore, &ci, 0, "Child 3.1", 1, FALSE,
                     2, "Value 3.1", 3, TRUE, 4, TRUE, -1);

  gtk_tree_store_append(tstore, &ci, &pi);
  gtk_tree_store_set(tstore, &ci, 0, "Child 3.2", 1, FALSE,
                     2, "Value 3.2", 3, TRUE, 4, TRUE, -1);

  gtk_tree_store_append(tstore, &ci, &pi);
  gtk_tree_store_set(tstore, &ci, 0, "Child 3.3", 1, FALSE,
                     2, "Value 3.3", 3, TRUE, 4, TRUE, -1);

  g_object_unref(G_OBJECT(tstore));
}

int main(int argc, char ** argv)
{
  gtk_init(&argc, &argv);
  cell_renderer_widget_type = gtk_cell_renderer_widget_register_type();

  GtkWidget * window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_default_size(GTK_WINDOW(window), 500, 300);
  g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), 0);
  g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(gtk_main_quit),
                   0);
  GtkWidget * sw = gtk_scrolled_window_new(0, 0);
  test_treeview(GTK_SCROLLED_WINDOW(sw));
  gtk_container_add(GTK_CONTAINER(window), sw);
  gtk_widget_show_all(window);

  gtk_main();
  gtk_widget_destroy(sw);
  return 0;
}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]