9.3. Getting the Cell Renderer a Click Event Happened On

It seems that in many cases when people want to know the cell renderer a click event happened on, they do not really need to know the cell renderer, but rather want to modify an individual cell in a particular column. For this you do not need to know the cell renderer. Use gtk_tree_view_get_path_at_pos to get a tree path from the x and y coordinates of the button event that is passed to you in a "button-press-event" signal callback (if you use the "row-activated" signal to catch double-clicks you get the tree path passed directly into the callback function). Then convert that tree path into an iter using gtk_tree_model_get_iter and modify the data in the cell you want to modify with gtk_list_store_set or gtk_tree_store_set.

If you really do need to know the cell renderer where a button press event happened, that is a bit more tricky. Here is a suggestion on how to approach this issue (the function has not been well-tested and might not work correctly if the content rendered by one renderer in different columns varies in width; please send suggestions on how to fix or improve this function to the author):


static gboolean
tree_view_get_cell_from_pos(GtkTreeView *view, guint x, guint y, GtkCellRenderer **cell)
{
	GtkTreeViewColumn *col = NULL;
	GList             *node, *columns, *cells;
	guint              colx = 0;

	g_return_val_if_fail ( view != NULL, FALSE );
	g_return_val_if_fail ( cell != NULL, FALSE );

	/* (1) find column and column x relative to tree view coordinates */

	columns = gtk_tree_view_get_columns(view);

	for (node = columns;  node != NULL && col == NULL;  node = node->next)
	{
		GtkTreeViewColumn *checkcol = (GtkTreeViewColumn*) node->data;

		if (x >= colx  &&  x < (colx + checkcol->width))
			col = checkcol;
		else
			colx += checkcol->width;
	}

	g_list_free(columns);

	if (col == NULL)
		return FALSE; /* not found */

	/* (2) find the cell renderer within the column */

	cells = gtk_tree_view_column_get_cell_renderers(col);

	for (node = cells;  node != NULL;  node = node->next)
	{
		GtkCellRenderer *checkcell = (GtkCellRenderer*) node->data;
		guint            width = 0, height = 0;

		/* Will this work for all packing modes? doesn't that
		 *  return a random width depending on the last content
		 * rendered? */
		gtk_cell_renderer_get_size(checkcell, GTK_WIDGET(view), NULL, NULL, NULL, &width, NULL);

		if (x >= colx && x < (colx + width))
		{
			*cell = checkcell;
			g_list_free(cells);
			return TRUE;
		}

		colx += width;
	}

	g_list_free(cells);
	return FALSE; /* not found */
}

static gboolean
onButtonPress (GtkWidget *view, GdkEventButton *bevent, gpointer data)
{
	GtkCellRenderer *renderer = NULL;

	if (tree_view_get_cell_from_pos(GTK_TREE_VIEW(view), bevent->x, bevent->y, &renderer))
		g_print ("Renderer found\n");
	else
		g_print ("Renderer not found!\n");
}