summaryrefslogtreecommitdiff
path: root/gtk/gtktreeview.c
diff options
context:
space:
mode:
Diffstat (limited to 'gtk/gtktreeview.c')
-rw-r--r--gtk/gtktreeview.c653
1 files changed, 439 insertions, 214 deletions
diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c
index 464842ea09..0c43d366f7 100644
--- a/gtk/gtktreeview.c
+++ b/gtk/gtktreeview.c
@@ -27,6 +27,7 @@
#include "gtktreednd.h"
#include "gtktreeprivate.h"
#include "gtkcellrenderer.h"
+#include "gtksizerequest.h"
#include "gtkmain.h"
#include "gtkmarshalers.h"
#include "gtkbuildable.h"
@@ -43,6 +44,7 @@
#include "gtkframe.h"
#include "gtktreemodelsort.h"
#include "gtktooltip.h"
+#include "gtkscrolledwindow.h"
#include "gtkprivate.h"
#define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
@@ -164,8 +166,6 @@ static void gtk_tree_view_destroy (GtkObject *object);
static void gtk_tree_view_realize (GtkWidget *widget);
static void gtk_tree_view_unrealize (GtkWidget *widget);
static void gtk_tree_view_map (GtkWidget *widget);
-static void gtk_tree_view_size_request (GtkWidget *widget,
- GtkRequisition *requisition);
static void gtk_tree_view_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static gboolean gtk_tree_view_expose (GtkWidget *widget,
@@ -298,7 +298,8 @@ static gboolean do_validate_rows (GtkTreeView *tree_view,
gboolean size_request);
static gboolean validate_rows (GtkTreeView *tree_view);
static gboolean presize_handler_callback (gpointer data);
-static void install_presize_handler (GtkTreeView *tree_view);
+static void install_presize_handler (GtkTreeView *tree_view,
+ gboolean content_dirty);
static void install_scroll_sync_handler (GtkTreeView *tree_view);
static void gtk_tree_view_set_top_row (GtkTreeView *tree_view,
GtkTreePath *path,
@@ -464,6 +465,15 @@ static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView *tree
GtkTreeViewColumn *column,
gint drop_position);
+/* GtkSizeRequest */
+static void gtk_tree_view_size_request_init (GtkSizeRequestIface *iface);
+static void gtk_tree_view_get_width (GtkSizeRequest *widget,
+ gint *minimum_size,
+ gint *natural_size);
+static void gtk_tree_view_get_height (GtkSizeRequest *widget,
+ gint *minimum_size,
+ gint *natural_size);
+
/* GtkBuildable */
static void gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
GtkBuilder *builder,
@@ -488,7 +498,10 @@ static guint tree_view_signals [LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
- gtk_tree_view_buildable_init))
+ gtk_tree_view_buildable_init)
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_SIZE_REQUEST,
+ gtk_tree_view_size_request_init))
+
static void
gtk_tree_view_class_init (GtkTreeViewClass *class)
@@ -518,7 +531,6 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
widget_class->map = gtk_tree_view_map;
widget_class->realize = gtk_tree_view_realize;
widget_class->unrealize = gtk_tree_view_unrealize;
- widget_class->size_request = gtk_tree_view_size_request;
widget_class->size_allocate = gtk_tree_view_size_allocate;
widget_class->button_press_event = gtk_tree_view_button_press;
widget_class->button_release_event = gtk_tree_view_button_release;
@@ -1865,7 +1877,7 @@ gtk_tree_view_realize (GtkWidget *widget)
gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
- install_presize_handler (tree_view);
+ install_presize_handler (tree_view, TRUE);
}
static void
@@ -2033,37 +2045,6 @@ gtk_tree_view_update_size (GtkTreeView *tree_view)
tree_view->priv->height = tree_view->priv->tree->root->offset;
}
-static void
-gtk_tree_view_size_request (GtkWidget *widget,
- GtkRequisition *requisition)
-{
- GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
- GList *tmp_list;
-
- /* we validate some rows initially just to make sure we have some size.
- * In practice, with a lot of static lists, this should get a good width.
- */
- do_validate_rows (tree_view, FALSE);
- gtk_tree_view_size_request_columns (tree_view);
- gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
-
- requisition->width = tree_view->priv->width;
- requisition->height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
-
- tmp_list = tree_view->priv->children;
-
- while (tmp_list)
- {
- GtkTreeViewChild *child = tmp_list->data;
- GtkRequisition child_requisition;
-
- tmp_list = tmp_list->next;
-
- if (gtk_widget_get_visible (child->widget))
- gtk_widget_size_request (child->widget, &child_requisition);
- }
-}
-
static int
gtk_tree_view_calculate_width_before_expander (GtkTreeView *tree_view)
{
@@ -2172,6 +2153,28 @@ gtk_tree_view_get_real_requested_width_from_column (GtkTreeView *tree_view
return real_requested_width;
}
+static gint
+gtk_tree_view_get_real_natural_width_from_column (GtkTreeView *tree_view,
+ GtkTreeViewColumn *column)
+{
+ GtkTreeViewColumnPrivate *column_priv;
+ gint button_natural_width;
+ gint column_natural_width;
+
+ column_priv = GTK_TREE_VIEW_COLUMN_GET_PRIVATE (column);
+ column_natural_width = column_priv->natural_width;
+
+ if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
+ {
+ gtk_size_request_get_width (GTK_SIZE_REQUEST (column->button),
+ NULL, &button_natural_width);
+
+ column_natural_width = MAX (column_natural_width, button_natural_width);
+ }
+
+ return column_natural_width;
+}
+
/* GtkWidget::size_allocate helper */
static void
gtk_tree_view_size_allocate_columns (GtkWidget *widget,
@@ -2182,15 +2185,23 @@ gtk_tree_view_size_allocate_columns (GtkWidget *widget,
GtkTreeViewColumn *column;
GtkAllocation allocation;
gint width = 0;
- gint extra, extra_per_column, extra_for_last;
- gint full_requested_width = 0;
+ gint extra, extra_per_column;
+ gint column_width, i, horizontal_separator;
+ gint grid_line_width, draw_vgrid_lines;
gint number_of_expand_columns = 0;
gboolean column_changed = FALSE;
gboolean rtl;
gboolean update_expand;
+ GArray *array;
+ GtkRequestedSize *sizes;
tree_view = GTK_TREE_VIEW (widget);
+ gtk_widget_style_get (widget,
+ "horizontal-separator", &horizontal_separator,
+ "grid-line-width", &grid_line_width,
+ NULL);
+
for (last_column = g_list_last (tree_view->priv->columns);
last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
last_column = last_column->prev)
@@ -2203,25 +2214,56 @@ gtk_tree_view_size_allocate_columns (GtkWidget *widget,
first_column = first_column->next)
;
+ draw_vgrid_lines =
+ tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
+ || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
+
allocation.y = 0;
allocation.height = tree_view->priv->header_height;
rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
- /* find out how many extra space and expandable columns we have */
+ extra = widget->allocation.width;
+
+ array = g_array_new (0, TRUE, sizeof (GtkRequestedSize));
+
for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
{
+ GtkRequestedSize requested;
+ gint padding;
+
column = (GtkTreeViewColumn *)list->data;
if (!column->visible)
continue;
- full_requested_width += gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
+ /* Calculate padding for this column and store it in our client pointer for the next loop */
+ padding = horizontal_separator;
+ if (draw_vgrid_lines)
+ {
+ if (list == first_column || list == last_column)
+ padding += grid_line_width / 2.0;
+ else
+ padding += grid_line_width;
+ }
+
+ requested.data = GINT_TO_POINTER (padding);
+ requested.minimum_size = gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
+ requested.natural_size = gtk_tree_view_get_real_natural_width_from_column (tree_view, column);
+ g_array_append_val (array, requested);
+
+ /* Subtract each column's request and padding from the remaining allocation */
+ extra -= requested.minimum_size;
+ extra -= padding;
if (column->expand)
number_of_expand_columns++;
}
+ /* Distribute as much of remaining 'size' as possible before sharing expand space */
+ sizes = (GtkRequestedSize *)array->data;
+ extra = gtk_distribute_natural_allocation (MAX (extra, 0), array->len, sizes);
+
/* Only update the expand value if the width of the widget has changed,
* or the number of expand columns has changed, or if there are no expand
* columns, or if we didn't have an size-allocation yet after the
@@ -2234,21 +2276,8 @@ gtk_tree_view_size_allocate_columns (GtkWidget *widget,
tree_view->priv->post_validation_flag = FALSE;
- if (!update_expand)
- {
- extra = tree_view->priv->last_extra_space;
- extra_for_last = MAX (widget->allocation.width - full_requested_width - extra, 0);
- }
- else
- {
- extra = MAX (widget->allocation.width - full_requested_width, 0);
- extra_for_last = 0;
-
- tree_view->priv->last_extra_space = extra;
- }
-
if (number_of_expand_columns > 0)
- extra_per_column = extra/number_of_expand_columns;
+ extra_per_column = extra / number_of_expand_columns;
else
extra_per_column = 0;
@@ -2258,12 +2287,12 @@ gtk_tree_view_size_allocate_columns (GtkWidget *widget,
tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
}
- for (list = (rtl ? last_column : first_column);
+ for (list = (rtl ? last_column : first_column), i = 0;
list != (rtl ? first_column->prev : last_column->next);
list = (rtl ? list->prev : list->next))
{
- gint real_requested_width = 0;
gint old_width;
+ gint padding;
column = list->data;
old_width = column->width;
@@ -2284,56 +2313,43 @@ gtk_tree_view_size_allocate_columns (GtkWidget *widget,
gtk_widget_size_allocate (tree_view->priv->drag_column->button,
&drag_allocation);
width += drag_allocation.width;
+
+ i++;
continue;
}
- real_requested_width = gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
-
- allocation.x = width;
- column->width = real_requested_width;
+ column_width = sizes[i].minimum_size;
+ padding = GPOINTER_TO_INT (sizes[i].data);
if (column->expand)
{
- if (number_of_expand_columns == 1)
- {
- /* We add the remander to the last column as
- * */
- column->width += extra;
- }
- else
- {
- column->width += extra_per_column;
- extra -= extra_per_column;
- number_of_expand_columns --;
- }
+ column_width += extra_per_column;
}
- else if (number_of_expand_columns == 0 &&
- list == last_column)
+ /* If no columns expand, the last one takes the remaining space */
+ else if (number_of_expand_columns == 0 && list == last_column)
{
- column->width += extra;
+ column_width += extra;
}
- /* In addition to expand, the last column can get even more
- * extra space so all available space is filled up.
- */
- if (extra_for_last > 0 && list == last_column)
- column->width += extra_for_last;
+ gtk_tree_view_column_allocate_width (column, column_width);
- g_object_notify (G_OBJECT (column), "width");
+ /* Add padding between columns and allocate the buttons... */
+ allocation.x = width;
+ allocation.width = column_width + padding;
+ width += allocation.width;
- allocation.width = column->width;
- width += column->width;
+ gtk_widget_size_allocate (column->button, &allocation);
- if (column->width > old_width)
+ if (column_width > old_width)
column_changed = TRUE;
- gtk_widget_size_allocate (column->button, &allocation);
-
if (column->window)
gdk_window_move_resize (column->window,
allocation.x + (rtl ? 0 : allocation.width) - TREE_VIEW_DRAG_WIDTH/2,
allocation.y,
TREE_VIEW_DRAG_WIDTH, allocation.height);
+
+ i++; // itterate through visible columns
}
/* We change the width here. The user might have been resizing columns,
@@ -2342,7 +2358,7 @@ gtk_tree_view_size_allocate_columns (GtkWidget *widget,
tree_view->priv->width = width;
if (width_changed)
*width_changed = TRUE;
-
+
if (column_changed)
gtk_widget_queue_draw (GTK_WIDGET (tree_view));
}
@@ -2356,6 +2372,7 @@ gtk_tree_view_size_allocate (GtkWidget *widget,
GList *tmp_list;
gboolean width_changed = FALSE;
gint old_width = widget->allocation.width;
+ gboolean scroll_window_feedback = FALSE;
if (allocation->width != widget->allocation.width)
width_changed = TRUE;
@@ -2379,11 +2396,49 @@ gtk_tree_view_size_allocate (GtkWidget *widget,
gtk_widget_size_allocate (child->widget, &allocation);
}
+ /* If we get various width allocations while our content did not change
+ * and the parent is a scrolled window and it's own allocation has not
+ * changed:
+ *
+ * Stop setting the adjustments until
+ * a.) Treeview content size changes
+ * b.) Parent's allocation changes
+ */
+ if (GTK_IS_SCROLLED_WINDOW (gtk_widget_get_parent (widget)))
+ {
+ GtkWidget *swindow = gtk_widget_get_parent (widget);
+ GtkAllocation salloc;
+
+ gtk_widget_get_allocation (swindow, &salloc);
+
+ if (!tree_view->priv->content_size_dirty &&
+ tree_view->priv->prev_parent_width == salloc.width &&
+ tree_view->priv->prev_parent_height == salloc.height)
+ {
+ /* Feedback detected */
+ if (tree_view->priv->consecutive_allocations >= 3)
+ scroll_window_feedback = TRUE;
+ else
+ tree_view->priv->consecutive_allocations++;
+ }
+ else
+ tree_view->priv->consecutive_allocations = 0;
+
+ tree_view->priv->content_size_dirty = FALSE;
+ tree_view->priv->prev_parent_width = salloc.width;
+ tree_view->priv->prev_parent_height = salloc.height;
+ }
+ else
+ tree_view->priv->consecutive_allocations = 0;
+
+
/* We size-allocate the columns first because the width of the
* tree view (used in updating the adjustments below) might change.
*/
gtk_tree_view_size_allocate_columns (widget, &width_changed);
+ if (!scroll_window_feedback)
+ {
tree_view->priv->hadjustment->page_size = allocation->width;
tree_view->priv->hadjustment->page_increment = allocation->width * 0.9;
tree_view->priv->hadjustment->step_increment = allocation->width * 0.1;
@@ -2425,6 +2480,7 @@ gtk_tree_view_size_allocate (GtkWidget *widget,
tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->page_size, tree_view->priv->height);
gtk_adjustment_changed (tree_view->priv->vadjustment);
+ }
/* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
@@ -2500,6 +2556,32 @@ gtk_tree_view_size_allocate (GtkWidget *widget,
gtk_widget_queue_draw (widget);
}
}
+
+ /* Need to do this when the real allocated width changes
+ * and upon the first allocation */
+ if (allocation->width != old_width &&
+ !tree_view->priv->fixed_height_mode)
+ {
+ /* Have the tree recalculate height-for-width of all rows when the width changes
+ */
+ _gtk_rbtree_mark_invalid (tree_view->priv->tree);
+ for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
+ {
+ GtkTreeViewColumn *column;
+
+ column = tmp_list->data;
+ if (! column->visible)
+ continue;
+
+ if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE ||
+ column->column_type == GTK_TREE_VIEW_COLUMN_GROW_ONLY)
+ _gtk_tree_view_column_cell_set_dirty (column, FALSE, FALSE);
+ }
+
+ install_presize_handler (tree_view, FALSE);
+
+ gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+ }
}
/* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
@@ -4460,11 +4542,12 @@ gtk_tree_view_bin_expose (GtkWidget *widget,
max_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
- cell_offset = 0;
- highlight_x = 0; /* should match x coord of first cell */
+ cell_offset = 0;
+ highlight_x = 0; /* should match x coord of first cell */
expander_cell_width = 0;
- background_area.y = y_offset + event->area.y;
+ /* 'background_area' itterates vertically over rows in the exposed area */
+ background_area.y = y_offset + event->area.y;
background_area.height = max_height;
flags = 0;
@@ -4506,62 +4589,68 @@ gtk_tree_view_bin_expose (GtkWidget *widget,
if (!column->visible)
continue;
- if (cell_offset > event->area.x + event->area.width ||
- cell_offset + column->width < event->area.x)
- {
- cell_offset += column->width;
- continue;
- }
-
- if (column->show_sort_indicator)
- flags |= GTK_CELL_RENDERER_SORTED;
- else
- flags &= ~GTK_CELL_RENDERER_SORTED;
-
- if (cursor == node)
- flags |= GTK_CELL_RENDERER_FOCUSED;
- else
- flags &= ~GTK_CELL_RENDERER_FOCUSED;
-
- background_area.x = cell_offset;
+ /* Adjust 'background_area' for this column's portion of this row */
+ background_area.x = cell_offset;
background_area.width = column->width;
- cell_area = background_area;
- cell_area.y += vertical_separator / 2;
- cell_area.x += horizontal_separator / 2;
+ /* Create 'cell_area' to render this column inside this row */
+ cell_area = background_area;
+ cell_area.y += vertical_separator / 2;
+ cell_area.x += horizontal_separator / 2;
cell_area.height -= vertical_separator;
- cell_area.width -= horizontal_separator;
+ /* Calculate padding */
if (draw_vgrid_lines)
{
if (list == first_column)
{
- cell_area.width -= grid_line_width / 2;
+ background_area.width += grid_line_width / 2;
}
else if (list == last_column)
{
cell_area.x += grid_line_width / 2;
- cell_area.width -= grid_line_width / 2;
+ background_area.width += grid_line_width / 2;
}
else
{
cell_area.x += grid_line_width / 2;
- cell_area.width -= grid_line_width;
+ background_area.width += grid_line_width;
}
}
-
+
if (draw_hgrid_lines)
{
cell_area.y += grid_line_width / 2;
cell_area.height -= grid_line_width;
}
+ /* Now that we've deduced the real rendering area,
+ * do a couple of assertions to make sure we're rendereing
+ * a relevant area.
+ */
+ if (cell_offset > event->area.x + event->area.width ||
+ cell_offset + column->width < event->area.x)
+ {
+ cell_offset += background_area.width;
+ continue;
+ }
+
if (cairo_region_contains_rectangle (event->region, &background_area) == CAIRO_REGION_OVERLAP_OUT)
{
- cell_offset += column->width;
+ cell_offset += background_area.width;
continue;
}
+ if (column->show_sort_indicator)
+ flags |= GTK_CELL_RENDERER_SORTED;
+ else
+ flags &= ~GTK_CELL_RENDERER_SORTED;
+
+ if (cursor == node)
+ flags |= GTK_CELL_RENDERER_FOCUSED;
+ else
+ flags &= ~GTK_CELL_RENDERER_FOCUSED;
+
gtk_tree_view_column_cell_set_cell_data (column,
tree_view->priv->model,
&iter,
@@ -4684,59 +4773,42 @@ gtk_tree_view_bin_expose (GtkWidget *widget,
*/
highlight_x = cell_area.x;
expander_cell_width = cell_area.width;
-
- if (is_separator)
- gtk_paint_hline (widget->style,
- event->window,
- state,
- &cell_area,
- widget,
- NULL,
- cell_area.x,
- cell_area.x + cell_area.width,
- cell_area.y + cell_area.height / 2);
- else
- _gtk_tree_view_column_cell_render (column,
- event->window,
- &background_area,
- &cell_area,
- &event->area,
- flags);
- if (TREE_VIEW_DRAW_EXPANDERS(tree_view)
- && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
- {
- if (!got_pointer)
- {
- gdk_window_get_pointer (tree_view->priv->bin_window,
- &pointer_x, &pointer_y, NULL);
- got_pointer = TRUE;
- }
-
- gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
- tree,
- node,
- pointer_x, pointer_y);
- }
}
+
+ /* Do the actual rendering */
+ if (is_separator)
+ gtk_paint_hline (widget->style,
+ event->window,
+ state,
+ &cell_area,
+ widget,
+ NULL,
+ cell_area.x,
+ cell_area.x + cell_area.width,
+ cell_area.y + cell_area.height / 2);
else
+ _gtk_tree_view_column_cell_render (column,
+ event->window,
+ &background_area,
+ &cell_area,
+ &event->area,
+ flags);
+
+ if (gtk_tree_view_is_expander_column (tree_view, column) &&
+ TREE_VIEW_DRAW_EXPANDERS(tree_view) &&
+ (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
{
- if (is_separator)
- gtk_paint_hline (widget->style,
- event->window,
- state,
- &cell_area,
- widget,
- NULL,
- cell_area.x,
- cell_area.x + cell_area.width,
- cell_area.y + cell_area.height / 2);
- else
- _gtk_tree_view_column_cell_render (column,
- event->window,
- &background_area,
- &cell_area,
- &event->area,
- flags);
+ if (!got_pointer)
+ {
+ gdk_window_get_pointer (tree_view->priv->bin_window,
+ &pointer_x, &pointer_y, NULL);
+ got_pointer = TRUE;
+ }
+
+ gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
+ tree,
+ node,
+ pointer_x, pointer_y);
}
if (draw_hgrid_lines)
@@ -4842,7 +4914,7 @@ gtk_tree_view_bin_expose (GtkWidget *widget,
flags);
}
- cell_offset += column->width;
+ cell_offset += background_area.width;
}
if (node == drag_highlight)
@@ -4964,6 +5036,10 @@ gtk_tree_view_bin_expose (GtkWidget *widget,
width, tmp_height);
}
+ /* This remaining portion of the loop finds the appropriate next GtkTreeIter
+ * to render and increments the render offset (top down row-by-row inside
+ * the dirty exposed area).
+ */
y_offset += max_height;
if (node->children)
{
@@ -5716,7 +5792,7 @@ validate_row (GtkTreeView *tree_view,
gint focus_pad;
gint grid_line_width;
gboolean wide_separators;
- gint separator_height;
+ gint separator_height, bin_window_width = -1;
/* double check the row needs validating */
if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
@@ -5725,6 +5801,9 @@ validate_row (GtkTreeView *tree_view,
is_separator = row_is_separator (tree_view, iter, NULL);
+ if (tree_view->priv->bin_window)
+ gdk_drawable_get_size (tree_view->priv->bin_window, &bin_window_width, NULL);
+
gtk_widget_style_get (GTK_WIDGET (tree_view),
"focus-padding", &focus_pad,
"focus-line-width", &focus_line_width,
@@ -5752,12 +5831,15 @@ validate_row (GtkTreeView *tree_view,
first_column = first_column->next)
;
+ /* Start by calculating the overall width of the row */
for (list = tree_view->priv->columns; list; list = list->next)
{
- gint tmp_width;
- gint tmp_height;
+ GtkTreeViewColumnPrivate *column_priv;
+ gint minimum_width, natural_width;
+ gint padding;
column = list->data;
+ column_priv = GTK_TREE_VIEW_COLUMN_GET_PRIVATE (column);
if (! column->visible)
continue;
@@ -5765,51 +5847,84 @@ validate_row (GtkTreeView *tree_view,
if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
continue;
+ /* First time around setup the cell data for each column */
gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
node->children?TRUE:FALSE);
- gtk_tree_view_column_cell_get_size (column,
- NULL, NULL, NULL,
- &tmp_width, &tmp_height);
- if (!is_separator)
- {
- tmp_height += vertical_separator;
- height = MAX (height, tmp_height);
- height = MAX (height, tree_view->priv->expander_size);
- }
- else
- {
- if (wide_separators)
- height = separator_height + 2 * focus_pad;
- else
- height = 2 + 2 * focus_pad;
- }
+ gtk_tree_view_column_get_natural_width (column, &minimum_width, &natural_width);
if (gtk_tree_view_is_expander_column (tree_view, column))
{
- tmp_width = tmp_width + horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
+ padding = horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
- tmp_width += depth * tree_view->priv->expander_size;
+ padding += depth * tree_view->priv->expander_size;
}
else
- tmp_width = tmp_width + horizontal_separator;
+ padding = horizontal_separator;
if (draw_vgrid_lines)
{
- if (list->data == first_column || list->data == last_column)
- tmp_width += grid_line_width / 2.0;
+ if (list->data == first_column || list == last_column)
+ padding += grid_line_width / 2.0;
else
- tmp_width += grid_line_width;
+ padding += grid_line_width;
}
- if (tmp_width > column->requested_width)
+ minimum_width += padding;
+ natural_width += padding;
+
+ if (minimum_width > column->requested_width ||
+ natural_width > column_priv->natural_width)
{
retval = TRUE;
- column->requested_width = tmp_width;
+ column->requested_width = MAX (column->requested_width, minimum_width);
+ column_priv->natural_width = MAX (column_priv->natural_width, natural_width);
}
}
+
+ /* Finished calculating width of row, now get the height for the collective width */
+ if (!is_separator)
+ {
+ for (list = tree_view->priv->columns; list; list = list->next)
+ {
+ GtkTreeViewColumnPrivate *column_priv;
+ gint column_height;
+
+ column = list->data;
+ column_priv = GTK_TREE_VIEW_COLUMN_GET_PRIVATE (column);
+
+ if (!column->visible)
+ continue;
+
+ if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
+ continue;
+
+
+ /* If we have an allocation then we need to fetch the row height for the
+ * allocated width of the column, otherwise we'll settle for the
+ * height for the minimum width for the initial request phase.
+ */
+ if (column->width > 0)
+ gtk_tree_view_column_get_height_for_width (column, column->width,
+ &column_height, NULL);
+ else
+ gtk_tree_view_column_get_height_for_width (column, column->requested_width,
+ &column_height, NULL);
+
+ column_height += vertical_separator;
+ height = MAX (height, column_height);
+ height = MAX (height, tree_view->priv->expander_size);
+ }
+ }
+ else /* row is a separator */
+ {
+ if (wide_separators)
+ height = separator_height + 2 * focus_pad;
+ else
+ height = 2 + 2 * focus_pad;
+ }
if (draw_hgrid_lines)
height += grid_line_width;
@@ -6443,8 +6558,12 @@ presize_handler_callback (gpointer data)
}
static void
-install_presize_handler (GtkTreeView *tree_view)
+install_presize_handler (GtkTreeView *tree_view,
+ gboolean content_dirty)
{
+ if (content_dirty)
+ tree_view->priv->content_size_dirty = TRUE;
+
if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
return;
@@ -6604,7 +6723,7 @@ _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view)
{
tree_view->priv->mark_rows_col_dirty = TRUE;
- install_presize_handler (tree_view);
+ install_presize_handler (tree_view, FALSE);
}
/*
@@ -6621,7 +6740,7 @@ _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
- _gtk_tree_view_column_cell_set_dirty (column, FALSE);
+ _gtk_tree_view_column_cell_set_dirty (column, TRUE, FALSE);
do_presize_handler (tree_view);
while (validate_rows (tree_view));
@@ -7749,7 +7868,7 @@ gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
tree_view->priv->fixed_height = -1;
/* force a revalidation */
- install_presize_handler (tree_view);
+ install_presize_handler (tree_view, TRUE);
}
else
{
@@ -7771,6 +7890,8 @@ gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
if (tree_view->priv->tree)
initialize_fixed_height_mode (tree_view);
+
+ tree_view->priv->content_size_dirty = TRUE;
}
g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
@@ -8079,7 +8200,7 @@ gtk_tree_view_style_set (GtkWidget *widget,
for (list = tree_view->priv->columns; list; list = list->next)
{
column = list->data;
- _gtk_tree_view_column_cell_set_dirty (column, TRUE);
+ _gtk_tree_view_column_cell_set_dirty (column, TRUE, TRUE);
}
tree_view->priv->fixed_height = -1;
@@ -8362,7 +8483,7 @@ gtk_tree_view_row_changed (GtkTreeModel *model,
if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
{
- _gtk_tree_view_column_cell_set_dirty (column, TRUE);
+ _gtk_tree_view_column_cell_set_dirty (column, TRUE, TRUE);
}
}
}
@@ -8370,9 +8491,12 @@ gtk_tree_view_row_changed (GtkTreeModel *model,
done:
if (!tree_view->priv->fixed_height_mode &&
gtk_widget_get_realized (GTK_WIDGET (tree_view)))
- install_presize_handler (tree_view);
+ install_presize_handler (tree_view, TRUE);
+
if (free_path)
gtk_tree_path_free (path);
+
+ tree_view->priv->content_size_dirty = TRUE;
}
static void
@@ -8485,9 +8609,11 @@ gtk_tree_view_row_inserted (GtkTreeModel *model,
gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
}
else
- install_presize_handler (tree_view);
+ install_presize_handler (tree_view, TRUE);
if (free_path)
gtk_tree_path_free (path);
+
+ tree_view->priv->content_size_dirty = TRUE;
}
static void
@@ -8547,8 +8673,7 @@ gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
for (list = tree_view->priv->columns; list; list = list->next)
if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
{
- GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
- _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
+ _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE, TRUE);
break;
}
}
@@ -8615,7 +8740,7 @@ gtk_tree_view_row_deleted (GtkTreeModel *model,
for (list = tree_view->priv->columns; list; list = list->next)
if (((GtkTreeViewColumn *)list->data)->visible &&
((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
- _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
+ _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE, TRUE);
/* Ensure we don't have a dangling pointer to a dead node */
ensure_unprelighted (tree_view);
@@ -10883,7 +11008,7 @@ gtk_tree_view_set_model (GtkTreeView *tree_view,
gtk_tree_path_free (path);
/* FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
- install_presize_handler (tree_view);
+ install_presize_handler (tree_view, TRUE);
}
g_object_notify (G_OBJECT (tree_view), "model");
@@ -10893,6 +11018,8 @@ gtk_tree_view_set_model (GtkTreeView *tree_view,
if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+
+ tree_view->priv->content_size_dirty = TRUE;
}
/**
@@ -11091,7 +11218,7 @@ gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
column = list->data;
if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
continue;
- _gtk_tree_view_column_cell_set_dirty (column, TRUE);
+ _gtk_tree_view_column_cell_set_dirty (column, TRUE, TRUE);
dirty = TRUE;
}
@@ -11274,7 +11401,7 @@ gtk_tree_view_remove_column (GtkTreeView *tree_view,
tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
if (tmp_column->visible)
- _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
+ _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE, TRUE);
}
if (tree_view->priv->n_columns == 0 &&
@@ -11344,7 +11471,7 @@ gtk_tree_view_insert_column (GtkTreeView *tree_view,
{
column = GTK_TREE_VIEW_COLUMN (list->data);
if (column->visible)
- _gtk_tree_view_column_cell_set_dirty (column, TRUE);
+ _gtk_tree_view_column_cell_set_dirty (column, TRUE, TRUE);
}
gtk_widget_queue_resize (GTK_WIDGET (tree_view));
}
@@ -11752,7 +11879,7 @@ gtk_tree_view_scroll_to_cell (GtkTreeView *tree_view,
tree_view->priv->scroll_to_row_align = row_align;
tree_view->priv->scroll_to_col_align = col_align;
- install_presize_handler (tree_view);
+ install_presize_handler (tree_view, FALSE);
}
else
{
@@ -12165,7 +12292,7 @@ gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
if (animate)
add_expand_collapse_timeout (tree_view, tree, node, TRUE);
- install_presize_handler (tree_view);
+ install_presize_handler (tree_view, TRUE);
g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
if (open_all && node->children)
@@ -12276,7 +12403,7 @@ gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
if (column->visible == FALSE)
continue;
if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
- _gtk_tree_view_column_cell_set_dirty (column, TRUE);
+ _gtk_tree_view_column_cell_set_dirty (column, TRUE, TRUE);
}
if (tree_view->priv->destroy_count_func)
@@ -15708,3 +15835,101 @@ gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
return tree_view->priv->tooltip_column;
}
+
+
+static void
+gtk_tree_view_get_minimum_size (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
+ GList *tmp_list;
+
+ /* we validate some rows initially just to make sure we have some size.
+ * In practice, with a lot of static lists, this should get a good width.
+ */
+ do_validate_rows (tree_view, FALSE);
+ gtk_tree_view_size_request_columns (tree_view);
+ gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
+
+ requisition->width = tree_view->priv->width;
+ requisition->height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
+
+ tmp_list = tree_view->priv->children;
+
+ while (tmp_list)
+ {
+ GtkTreeViewChild *child = tmp_list->data;
+ GtkRequisition child_requisition;
+
+ tmp_list = tmp_list->next;
+
+ if (gtk_widget_get_visible (child->widget))
+ gtk_widget_size_request (child->widget, &child_requisition);
+ }
+}
+
+static void
+gtk_tree_view_size_request_init (GtkSizeRequestIface *iface)
+{
+ iface->get_width = gtk_tree_view_get_width;
+ iface->get_height = gtk_tree_view_get_height;
+}
+
+static void
+gtk_tree_view_get_size (GtkSizeRequest *widget,
+ GtkOrientation orientation,
+ gint *minimum_size,
+ gint *natural_size)
+{
+ GtkTreeView *tree_view;
+ gint natural_width = 0;
+ GList *column_iter;
+ GtkRequisition requisition;
+
+ tree_view = GTK_TREE_VIEW (widget);
+
+ gtk_tree_view_get_minimum_size (GTK_WIDGET (widget), &requisition);
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ for (column_iter = tree_view->priv->columns; column_iter; column_iter = column_iter->next)
+ {
+ GtkTreeViewColumn *column = column_iter->data;
+
+ if (!column->visible)
+ continue;
+
+ natural_width += gtk_tree_view_get_real_natural_width_from_column (tree_view, column);
+ }
+
+ if (minimum_size)
+ *minimum_size = requisition.width;
+
+ if (natural_size)
+ *natural_size = MAX (requisition.width, natural_width);
+ }
+ else
+ {
+ if (minimum_size)
+ *minimum_size = requisition.height;
+
+ if (natural_size)
+ *natural_size = requisition.height;
+ }
+}
+
+static void
+gtk_tree_view_get_width (GtkSizeRequest *widget,
+ gint *minimum_size,
+ gint *natural_size)
+{
+ gtk_tree_view_get_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
+}
+
+static void
+gtk_tree_view_get_height (GtkSizeRequest *widget,
+ gint *minimum_size,
+ gint *natural_size)
+{
+ gtk_tree_view_get_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
+}