#include "gtkcellrenderer.h"
#include "gtkcellrenderertext.h"
#include "gtkcellrendererpixbuf.h"
-#include "gtkcellsizerequest.h"
#include "gtkmarshalers.h"
#include "gtkbindings.h"
#include "gtkdnd.h"
#include "gtkentry.h"
#include "gtkcombobox.h"
#include "gtktextbuffer.h"
+#include "gtkscrollable.h"
#include "gtksizerequest.h"
#include "gtktreednd.h"
#include "gtkprivate.h"
* @title: GtkIconView
* @short_description: A widget which displays a list of icons in a grid
*
- * #GtkIconView provides an alternative view on a list model.
+ * #GtkIconView provides an alternative view on a #GtkTreeModel.
* It displays the model as a grid of icons with labels. Like
* #GtkTreeView, it allows to select one or multiple items
* (depending on the selection mode, see gtk_icon_view_set_selection_mode()).
* In addition to selection with the arrow keys, #GtkIconView supports
* rubberband selection, which is controlled by dragging the pointer.
+ *
+ * Note that if the tree model is backed by an actual tree store (as
+ * opposed to a flat list where the mapping to icons is obvious),
+ * #GtkIconView will only display the first level of the tree and
+ * ignore the tree's branches.
*/
#define SCROLL_EDGE_SIZE 15
+#define GTK_ICON_VIEW_PRIORITY_LAYOUT (GDK_PRIORITY_REDRAW + 5)
+
typedef struct _GtkIconViewItem GtkIconViewItem;
struct _GtkIconViewItem
{
guint shift_pressed : 1;
guint draw_focus : 1;
+
+ /* GtkScrollablePolicy needs to be checked when
+ * driving the scrollable adjustment values */
+ guint hscroll_policy : 1;
+ guint vscroll_policy : 1;
};
/* Signals */
PROP_MARGIN,
PROP_REORDERABLE,
PROP_TOOLTIP_COLUMN,
- PROP_ITEM_PADDING
+ PROP_ITEM_PADDING,
+
+ /* For scrollable interface */
+ PROP_HADJUSTMENT,
+ PROP_VADJUSTMENT,
+ PROP_HSCROLL_POLICY,
+ PROP_VSCROLL_POLICY
};
/* GObject vfuncs */
guint prop_id,
GValue *value,
GParamSpec *pspec);
-
-/* GtkObject vfuncs */
-static void gtk_icon_view_destroy (GtkObject *object);
-
/* GtkWidget vfuncs */
+static void gtk_icon_view_destroy (GtkWidget *widget);
static void gtk_icon_view_realize (GtkWidget *widget);
static void gtk_icon_view_unrealize (GtkWidget *widget);
static void gtk_icon_view_style_set (GtkWidget *widget,
GtkStyle *previous_style);
static void gtk_icon_view_state_changed (GtkWidget *widget,
GtkStateType previous_state);
-static void gtk_icon_view_size_request (GtkWidget *widget,
- GtkRequisition *requisition);
+static void gtk_icon_view_get_preferred_width (GtkWidget *widget,
+ gint *minimum,
+ gint *natural);
+static void gtk_icon_view_get_preferred_height (GtkWidget *widget,
+ gint *minimum,
+ gint *natural);
static void gtk_icon_view_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
-static gboolean gtk_icon_view_expose (GtkWidget *widget,
- GdkEventExpose *expose);
+static gboolean gtk_icon_view_draw (GtkWidget *widget,
+ cairo_t *cr);
static gboolean gtk_icon_view_motion (GtkWidget *widget,
GdkEventMotion *event);
static gboolean gtk_icon_view_button_press (GtkWidget *widget,
gpointer callback_data);
/* GtkIconView vfuncs */
-static void gtk_icon_view_set_adjustments (GtkIconView *icon_view,
- GtkAdjustment *hadj,
- GtkAdjustment *vadj);
static void gtk_icon_view_real_select_all (GtkIconView *icon_view);
static void gtk_icon_view_real_unselect_all (GtkIconView *icon_view);
static void gtk_icon_view_real_select_cursor_item (GtkIconView *icon_view);
static gboolean gtk_icon_view_real_activate_cursor_item (GtkIconView *icon_view);
/* Internal functions */
+static void gtk_icon_view_set_hadjustment_values (GtkIconView *icon_view);
+static void gtk_icon_view_set_vadjustment_values (GtkIconView *icon_view);
+static void gtk_icon_view_set_hadjustment (GtkIconView *icon_view,
+ GtkAdjustment *adjustment);
+static void gtk_icon_view_set_vadjustment (GtkIconView *icon_view,
+ GtkAdjustment *adjustment);
+static void gtk_icon_view_accessible_set_adjustment (AtkObject *accessible,
+ GtkOrientation orientation,
+ GtkAdjustment *adjustment);
static void gtk_icon_view_adjustment_changed (GtkAdjustment *adjustment,
GtkIconView *icon_view);
static void gtk_icon_view_layout (GtkIconView *icon_view);
gint y,
gboolean draw_focus);
static void gtk_icon_view_paint_rubberband (GtkIconView *icon_view,
- cairo_t *cr,
- GdkRectangle *area);
+ cairo_t *cr);
static void gtk_icon_view_queue_draw_path (GtkIconView *icon_view,
GtkTreePath *path);
static void gtk_icon_view_queue_draw_item (GtkIconView *icon_view,
G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
gtk_icon_view_cell_layout_init)
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
- gtk_icon_view_buildable_init))
+ gtk_icon_view_buildable_init)
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
static void
gtk_icon_view_class_init (GtkIconViewClass *klass)
{
GObjectClass *gobject_class;
- GtkObjectClass *object_class;
GtkWidgetClass *widget_class;
GtkContainerClass *container_class;
GtkBindingSet *binding_set;
g_type_class_add_private (klass, sizeof (GtkIconViewPrivate));
gobject_class = (GObjectClass *) klass;
- object_class = (GtkObjectClass *) klass;
widget_class = (GtkWidgetClass *) klass;
container_class = (GtkContainerClass *) klass;
gobject_class->set_property = gtk_icon_view_set_property;
gobject_class->get_property = gtk_icon_view_get_property;
- object_class->destroy = gtk_icon_view_destroy;
-
+ widget_class->destroy = gtk_icon_view_destroy;
widget_class->realize = gtk_icon_view_realize;
widget_class->unrealize = gtk_icon_view_unrealize;
widget_class->style_set = gtk_icon_view_style_set;
widget_class->get_accessible = gtk_icon_view_get_accessible;
- widget_class->size_request = gtk_icon_view_size_request;
+ widget_class->get_preferred_width = gtk_icon_view_get_preferred_width;
+ widget_class->get_preferred_height = gtk_icon_view_get_preferred_height;
widget_class->size_allocate = gtk_icon_view_size_allocate;
- widget_class->expose_event = gtk_icon_view_expose;
+ widget_class->draw = gtk_icon_view_draw;
widget_class->motion_notify_event = gtk_icon_view_motion;
widget_class->button_press_event = gtk_icon_view_button_press;
widget_class->button_release_event = gtk_icon_view_button_release;
container_class->remove = gtk_icon_view_remove;
container_class->forall = gtk_icon_view_forall;
- klass->set_scroll_adjustments = gtk_icon_view_set_adjustments;
klass->select_all = gtk_icon_view_real_select_all;
klass->unselect_all = gtk_icon_view_real_unselect_all;
klass->select_cursor_item = gtk_icon_view_real_select_cursor_item;
0, G_MAXINT, 6,
GTK_PARAM_READWRITE));
-
+ /* Scrollable interface properties */
+ g_object_class_override_property (gobject_class, PROP_HADJUSTMENT, "hadjustment");
+ g_object_class_override_property (gobject_class, PROP_VADJUSTMENT, "vadjustment");
+ g_object_class_override_property (gobject_class, PROP_HSCROLL_POLICY, "hscroll-policy");
+ g_object_class_override_property (gobject_class, PROP_VSCROLL_POLICY, "vscroll-policy");
/* Style properties */
gtk_widget_class_install_style_property (widget_class,
GTK_PARAM_READABLE));
/* Signals */
- /**
- * GtkIconView::set-scroll-adjustments
- * @horizontal: the horizontal #GtkAdjustment
- * @vertical: the vertical #GtkAdjustment
- *
- * Set the scroll adjustments for the icon view. Usually scrolled containers
- * like #GtkScrolledWindow will emit this signal to connect two instances
- * of #GtkScrollbar to the scroll directions of the #GtkIconView.
- */
- widget_class->set_scroll_adjustments_signal =
- g_signal_new (I_("set-scroll-adjustments"),
- G_TYPE_FROM_CLASS (gobject_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GtkIconViewClass, set_scroll_adjustments),
- NULL, NULL,
- _gtk_marshal_VOID__OBJECT_OBJECT,
- G_TYPE_NONE, 2,
- GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
-
/**
* GtkIconView::item-activated:
* @iconview: the object on which the signal is emitted
gtk_widget_set_can_focus (GTK_WIDGET (icon_view), TRUE);
- gtk_icon_view_set_adjustments (icon_view, NULL, NULL);
-
icon_view->priv->cell_list = NULL;
icon_view->priv->n_cells = 0;
icon_view->priv->cursor_cell = -1;
icon_view->priv->draw_focus = TRUE;
}
-static void
-gtk_icon_view_destroy (GtkObject *object)
-{
- GtkIconView *icon_view;
-
- icon_view = GTK_ICON_VIEW (object);
-
- gtk_icon_view_stop_editing (icon_view, TRUE);
-
- gtk_icon_view_set_model (icon_view, NULL);
-
- if (icon_view->priv->layout_idle_id != 0)
- {
- g_source_remove (icon_view->priv->layout_idle_id);
- icon_view->priv->layout_idle_id = 0;
- }
-
- if (icon_view->priv->scroll_to_path != NULL)
- {
- gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
- icon_view->priv->scroll_to_path = NULL;
- }
-
- remove_scroll_timeout (icon_view);
-
- if (icon_view->priv->hadjustment != NULL)
- {
- g_object_unref (icon_view->priv->hadjustment);
- icon_view->priv->hadjustment = NULL;
- }
-
- if (icon_view->priv->vadjustment != NULL)
- {
- g_object_unref (icon_view->priv->vadjustment);
- icon_view->priv->vadjustment = NULL;
- }
-
- GTK_OBJECT_CLASS (gtk_icon_view_parent_class)->destroy (object);
-}
-
/* GObject methods */
static void
gtk_icon_view_finalize (GObject *object)
gtk_icon_view_set_item_padding (icon_view, g_value_get_int (value));
break;
+ case PROP_HADJUSTMENT:
+ gtk_icon_view_set_hadjustment (icon_view, g_value_get_object (value));
+ break;
+ case PROP_VADJUSTMENT:
+ gtk_icon_view_set_vadjustment (icon_view, g_value_get_object (value));
+ break;
+ case PROP_HSCROLL_POLICY:
+ icon_view->priv->hscroll_policy = g_value_get_enum (value);
+ gtk_widget_queue_resize (GTK_WIDGET (icon_view));
+ break;
+ case PROP_VSCROLL_POLICY:
+ icon_view->priv->vscroll_policy = g_value_get_enum (value);
+ gtk_widget_queue_resize (GTK_WIDGET (icon_view));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
g_value_set_int (value, icon_view->priv->item_padding);
break;
+ case PROP_HADJUSTMENT:
+ g_value_set_object (value, icon_view->priv->hadjustment);
+ break;
+ case PROP_VADJUSTMENT:
+ g_value_set_object (value, icon_view->priv->vadjustment);
+ break;
+ case PROP_HSCROLL_POLICY:
+ g_value_set_enum (value, icon_view->priv->hscroll_policy);
+ break;
+ case PROP_VSCROLL_POLICY:
+ g_value_set_enum (value, icon_view->priv->vscroll_policy);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
-/* GtkWidget signals */
+/* GtkWidget methods */
+static void
+gtk_icon_view_destroy (GtkWidget *widget)
+{
+ GtkIconView *icon_view = GTK_ICON_VIEW (widget);
+
+ gtk_icon_view_stop_editing (icon_view, TRUE);
+
+ gtk_icon_view_set_model (icon_view, NULL);
+
+ if (icon_view->priv->layout_idle_id != 0)
+ {
+ g_source_remove (icon_view->priv->layout_idle_id);
+ icon_view->priv->layout_idle_id = 0;
+ }
+
+ if (icon_view->priv->scroll_to_path != NULL)
+ {
+ gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
+ icon_view->priv->scroll_to_path = NULL;
+ }
+
+ remove_scroll_timeout (icon_view);
+
+ if (icon_view->priv->hadjustment != NULL)
+ {
+ g_object_unref (icon_view->priv->hadjustment);
+ icon_view->priv->hadjustment = NULL;
+ }
+
+ if (icon_view->priv->vadjustment != NULL)
+ {
+ g_object_unref (icon_view->priv->vadjustment);
+ icon_view->priv->vadjustment = NULL;
+ }
+
+ GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->destroy (widget);
+}
+
static void
gtk_icon_view_realize (GtkWidget *widget)
{
attributes.height = allocation.height;
attributes.wclass = GDK_INPUT_OUTPUT;
attributes.visual = gtk_widget_get_visual (widget);
- attributes.colormap = gtk_widget_get_colormap (widget);
attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
- attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+ attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
window = gdk_window_new (gtk_widget_get_parent_window (widget),
&attributes, attributes_mask);
}
static void
-gtk_icon_view_size_request (GtkWidget *widget,
- GtkRequisition *requisition)
+gtk_icon_view_get_preferred_width (GtkWidget *widget,
+ gint *minimum,
+ gint *natural)
{
- GtkIconView *icon_view = GTK_ICON_VIEW (widget);
- GList *tmp_list;
-
- requisition->width = icon_view->priv->width;
- requisition->height = icon_view->priv->height;
-
- tmp_list = icon_view->priv->children;
-
- while (tmp_list)
- {
- GtkIconViewChild *child = tmp_list->data;
- GtkRequisition child_requisition;
-
- tmp_list = tmp_list->next;
+ *minimum = *natural = GTK_ICON_VIEW (widget)->priv->width;
+}
- if (gtk_widget_get_visible (child->widget))
- gtk_size_request_get_size (GTK_SIZE_REQUEST (child->widget),
- &child_requisition, NULL);
- }
+static void
+gtk_icon_view_get_preferred_height (GtkWidget *widget,
+ gint *minimum,
+ gint *natural)
+{
+ *minimum = *natural = GTK_ICON_VIEW (widget)->priv->height;
}
static void
{
GtkIconView *icon_view = GTK_ICON_VIEW (widget);
- GtkAdjustment *hadjustment, *vadjustment;
-
gtk_widget_set_allocation (widget, allocation);
if (gtk_widget_get_realized (widget))
gtk_icon_view_allocate_children (icon_view);
- hadjustment = icon_view->priv->hadjustment;
- vadjustment = icon_view->priv->vadjustment;
-
- hadjustment->page_size = allocation->width;
- hadjustment->page_increment = allocation->width * 0.9;
- hadjustment->step_increment = allocation->width * 0.1;
- hadjustment->lower = 0;
- hadjustment->upper = MAX (allocation->width, icon_view->priv->width);
+ /* Delay signal emission */
+ g_object_freeze_notify (G_OBJECT (icon_view->priv->hadjustment));
+ g_object_freeze_notify (G_OBJECT (icon_view->priv->vadjustment));
- if (hadjustment->value > hadjustment->upper - hadjustment->page_size)
- gtk_adjustment_set_value (hadjustment, hadjustment->upper - hadjustment->page_size);
-
- vadjustment->page_size = allocation->height;
- vadjustment->page_increment = allocation->height * 0.9;
- vadjustment->step_increment = allocation->height * 0.1;
- vadjustment->lower = 0;
- vadjustment->upper = MAX (allocation->height, icon_view->priv->height);
-
- if (vadjustment->value > vadjustment->upper - vadjustment->page_size)
- gtk_adjustment_set_value (vadjustment, vadjustment->upper - vadjustment->page_size);
+ gtk_icon_view_set_hadjustment_values (icon_view);
+ gtk_icon_view_set_vadjustment_values (icon_view);
if (gtk_widget_get_realized (widget) &&
icon_view->priv->scroll_to_path)
icon_view->priv->scroll_to_col_align);
gtk_tree_path_free (path);
}
- else
- {
- gtk_adjustment_changed (hadjustment);
- gtk_adjustment_changed (vadjustment);
- }
+
+ /* Emit any pending signals now */
+ g_object_thaw_notify (G_OBJECT (icon_view->priv->hadjustment));
+ g_object_thaw_notify (G_OBJECT (icon_view->priv->vadjustment));
}
static gboolean
-gtk_icon_view_expose (GtkWidget *widget,
- GdkEventExpose *expose)
+gtk_icon_view_draw (GtkWidget *widget,
+ cairo_t *cr)
{
GtkIconView *icon_view;
GList *icons;
- cairo_t *cr;
GtkTreePath *path;
gint dest_index;
GtkIconViewDropPosition dest_pos;
icon_view = GTK_ICON_VIEW (widget);
- if (expose->window != icon_view->priv->bin_window)
+ if (!gtk_cairo_should_draw_window (cr, icon_view->priv->bin_window))
return FALSE;
- /* If a layout has been scheduled, do it now so that all
- * cell view items have valid sizes before we proceed. */
- if (icon_view->priv->layout_idle_id != 0)
- gtk_icon_view_layout (icon_view);
+ cairo_save (cr);
- cr = gdk_cairo_create (icon_view->priv->bin_window);
+ gtk_cairo_transform_to_window (cr, widget, icon_view->priv->bin_window);
+
cairo_set_line_width (cr, 1.);
gtk_icon_view_get_drag_dest_item (icon_view, &path, &dest_pos);
for (icons = icon_view->priv->items; icons; icons = icons->next)
{
GtkIconViewItem *item = icons->data;
- GdkRectangle area;
cairo_save (cr);
cairo_rectangle (cr, item->x, item->y, item->width, item->height);
cairo_clip (cr);
- area.x = item->x;
- area.y = item->y;
- area.width = item->width;
- area.height = item->height;
-
- if (cairo_region_contains_rectangle (expose->region, &area) != CAIRO_REGION_OVERLAP_OUT)
+ if (gdk_cairo_get_clip_rectangle (cr, NULL))
{
gtk_icon_view_paint_item (icon_view, cr, item,
item->x, item->y,
switch (dest_pos)
{
case GTK_ICON_VIEW_DROP_INTO:
- gtk_cairo_paint_focus (style,
+ gtk_paint_focus (style,
cr,
state,
widget,
dest_item->width, dest_item->height);
break;
case GTK_ICON_VIEW_DROP_ABOVE:
- gtk_cairo_paint_focus (style,
+ gtk_paint_focus (style,
cr,
state,
widget,
dest_item->width, 2);
break;
case GTK_ICON_VIEW_DROP_LEFT:
- gtk_cairo_paint_focus (style,
+ gtk_paint_focus (style,
cr,
state,
widget,
2, dest_item->height);
break;
case GTK_ICON_VIEW_DROP_BELOW:
- gtk_cairo_paint_focus (style,
+ gtk_paint_focus (style,
cr,
state,
widget,
dest_item->width, 2);
break;
case GTK_ICON_VIEW_DROP_RIGHT:
- gtk_cairo_paint_focus (style,
+ gtk_paint_focus (style,
cr,
state,
widget,
}
if (icon_view->priv->doing_rubberband)
- {
- cairo_rectangle_int_t rectangle;
- gint n_rectangles;
-
- n_rectangles = cairo_region_num_rectangles (expose->region);
-
- while (n_rectangles--)
- {
- cairo_region_get_rectangle (expose->region, n_rectangles, &rectangle);
- gtk_icon_view_paint_rubberband (icon_view, cr, &rectangle);
- }
- }
+ gtk_icon_view_paint_rubberband (icon_view, cr);
- cairo_destroy (cr);
+ cairo_restore (cr);
- GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->expose_event (widget, expose);
+ GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->draw (widget, cr);
return TRUE;
}
/* GtkIconView signals */
-static void
-gtk_icon_view_set_adjustments (GtkIconView *icon_view,
- GtkAdjustment *hadj,
- GtkAdjustment *vadj)
-{
- gboolean need_adjust = FALSE;
-
- if (hadj)
- g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
- else
- hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
- if (vadj)
- g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
- else
- vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
-
- if (icon_view->priv->hadjustment && (icon_view->priv->hadjustment != hadj))
- {
- g_signal_handlers_disconnect_matched (icon_view->priv->hadjustment, G_SIGNAL_MATCH_DATA,
- 0, 0, NULL, NULL, icon_view);
- g_object_unref (icon_view->priv->hadjustment);
- }
-
- if (icon_view->priv->vadjustment && (icon_view->priv->vadjustment != vadj))
- {
- g_signal_handlers_disconnect_matched (icon_view->priv->vadjustment, G_SIGNAL_MATCH_DATA,
- 0, 0, NULL, NULL, icon_view);
- g_object_unref (icon_view->priv->vadjustment);
- }
-
- if (icon_view->priv->hadjustment != hadj)
- {
- icon_view->priv->hadjustment = hadj;
- g_object_ref_sink (icon_view->priv->hadjustment);
-
- g_signal_connect (icon_view->priv->hadjustment, "value-changed",
- G_CALLBACK (gtk_icon_view_adjustment_changed),
- icon_view);
- need_adjust = TRUE;
- }
-
- if (icon_view->priv->vadjustment != vadj)
- {
- icon_view->priv->vadjustment = vadj;
- g_object_ref_sink (icon_view->priv->vadjustment);
-
- g_signal_connect (icon_view->priv->vadjustment, "value-changed",
- G_CALLBACK (gtk_icon_view_adjustment_changed),
- icon_view);
- need_adjust = TRUE;
- }
-
- if (need_adjust)
- gtk_icon_view_adjustment_changed (NULL, icon_view);
-}
-
static void
gtk_icon_view_real_select_all (GtkIconView *icon_view)
{
}
/* Internal functions */
+static void
+gtk_icon_view_process_updates (GtkIconView *icon_view)
+{
+ /* Prior to drawing, we check if a layout has been scheduled. If so,
+ * do it now that all cell view items have valid sizes before we proceeed
+ * (and resize the bin_window if required).
+ */
+ if (icon_view->priv->layout_idle_id != 0)
+ gtk_icon_view_layout (icon_view);
+
+ gdk_window_process_updates (icon_view->priv->bin_window, TRUE);
+}
+
+static void
+gtk_icon_view_set_hadjustment_values (GtkIconView *icon_view)
+{
+ GtkAllocation allocation;
+ GtkAdjustment *adj = icon_view->priv->hadjustment;
+ gdouble old_page_size;
+ gdouble old_upper;
+ gdouble old_value;
+ gdouble new_value;
+ gdouble new_upper;
+
+ gtk_widget_get_allocation (GTK_WIDGET (icon_view), &allocation);
+
+ old_value = gtk_adjustment_get_value (adj);
+ old_upper = gtk_adjustment_get_upper (adj);
+ old_page_size = gtk_adjustment_get_page_size (adj);
+ new_upper = MAX (allocation.width, icon_view->priv->width);
+
+ g_object_set (adj,
+ "lower", 0.0,
+ "upper", new_upper,
+ "page-size", (gdouble)allocation.width,
+ "step-increment", allocation.width * 0.1,
+ "page-increment", allocation.width * 0.9,
+ NULL);
+
+ if (gtk_widget_get_direction (GTK_WIDGET (icon_view)) == GTK_TEXT_DIR_RTL)
+ {
+ /* Make sure no scrolling occurs for RTL locales also (if possible) */
+ /* Quick explanation:
+ * In LTR locales, leftmost portion of visible rectangle should stay
+ * fixed, which means left edge of scrollbar thumb should remain fixed
+ * and thus adjustment's value should stay the same.
+ *
+ * In RTL locales, we want to keep rightmost portion of visible
+ * rectangle fixed. This means right edge of thumb should remain fixed.
+ * In this case, upper - value - page_size should remain constant.
+ */
+ new_value = (new_upper - allocation.width) -
+ (old_upper - old_value - old_page_size);
+ new_value = CLAMP (new_value, 0, new_upper - allocation.width);
+ }
+ else
+ new_value = CLAMP (old_value, 0, new_upper - allocation.width);
+
+ if (new_value != old_value)
+ gtk_adjustment_set_value (adj, new_value);
+}
+
+static void
+gtk_icon_view_set_vadjustment_values (GtkIconView *icon_view)
+{
+ GtkAllocation allocation;
+ GtkAdjustment *adj = icon_view->priv->vadjustment;
+ gdouble old_value;
+ gdouble new_value;
+ gdouble new_upper;
+
+ gtk_widget_get_allocation (GTK_WIDGET (icon_view), &allocation);
+
+ old_value = gtk_adjustment_get_value (adj);
+ new_upper = MAX (allocation.height, icon_view->priv->height);
+
+ g_object_set (adj,
+ "lower", 0.0,
+ "upper", new_upper,
+ "page-size", (gdouble)allocation.height,
+ "step-increment", allocation.height * 0.1,
+ "page-increment", allocation.height * 0.9,
+ NULL);
+
+ new_value = CLAMP (old_value, 0, new_upper - allocation.height);
+ if (new_value != old_value)
+ gtk_adjustment_set_value (adj, new_value);
+}
+
+static void
+gtk_icon_view_set_hadjustment (GtkIconView *icon_view,
+ GtkAdjustment *adjustment)
+{
+ GtkIconViewPrivate *priv = icon_view->priv;
+ AtkObject *atk_obj;
+
+ if (adjustment && priv->hadjustment == adjustment)
+ return;
+
+ if (priv->hadjustment != NULL)
+ {
+ g_signal_handlers_disconnect_matched (priv->hadjustment,
+ G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL, NULL, icon_view);
+ g_object_unref (priv->hadjustment);
+ }
+
+ if (!adjustment)
+ adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
+ 0.0, 0.0, 0.0);
+
+ g_signal_connect (adjustment, "value-changed",
+ G_CALLBACK (gtk_icon_view_adjustment_changed), icon_view);
+ priv->hadjustment = g_object_ref_sink (adjustment);
+ gtk_icon_view_set_hadjustment_values (icon_view);
+
+ atk_obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
+ gtk_icon_view_accessible_set_adjustment (atk_obj,
+ GTK_ORIENTATION_HORIZONTAL,
+ adjustment);
+
+ g_object_notify (G_OBJECT (icon_view), "hadjustment");
+}
+
+static void
+gtk_icon_view_set_vadjustment (GtkIconView *icon_view,
+ GtkAdjustment *adjustment)
+{
+ GtkIconViewPrivate *priv = icon_view->priv;
+ AtkObject *atk_obj;
+
+ if (adjustment && priv->vadjustment == adjustment)
+ return;
+
+ if (priv->vadjustment != NULL)
+ {
+ g_signal_handlers_disconnect_matched (priv->vadjustment,
+ G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL, NULL, icon_view);
+ g_object_unref (priv->vadjustment);
+ }
+
+ if (!adjustment)
+ adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
+ 0.0, 0.0, 0.0);
+
+ g_signal_connect (adjustment, "value-changed",
+ G_CALLBACK (gtk_icon_view_adjustment_changed), icon_view);
+ priv->vadjustment = g_object_ref_sink (adjustment);
+ gtk_icon_view_set_vadjustment_values (icon_view);
+
+ atk_obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
+ gtk_icon_view_accessible_set_adjustment (atk_obj,
+ GTK_ORIENTATION_VERTICAL,
+ adjustment);
+
+ g_object_notify (G_OBJECT (icon_view), "vadjustment");
+}
+
static void
gtk_icon_view_adjustment_changed (GtkAdjustment *adjustment,
- GtkIconView *icon_view)
+ GtkIconView *icon_view)
{
+ GtkIconViewPrivate *priv = icon_view->priv;
+
if (gtk_widget_get_realized (GTK_WIDGET (icon_view)))
{
- gdk_window_move (icon_view->priv->bin_window,
- - icon_view->priv->hadjustment->value,
- - icon_view->priv->vadjustment->value);
+ gdk_window_move (priv->bin_window,
+ - priv->hadjustment->value,
+ - priv->vadjustment->value);
if (icon_view->priv->doing_rubberband)
- gtk_icon_view_update_rubberband (GTK_WIDGET (icon_view));
+ gtk_icon_view_update_rubberband (GTK_WIDGET (icon_view));
- gdk_window_process_updates (icon_view->priv->bin_window, TRUE);
+ gtk_icon_view_process_updates (icon_view);
}
}
pixbuf_info = g_list_nth_data (icon_view->priv->cell_list,
icon_view->priv->pixbuf_cell);
- gtk_cell_size_request_get_size (GTK_CELL_SIZE_REQUEST (pixbuf_info->cell),
- GTK_WIDGET (icon_view),
- &min_size, NULL);
+ gtk_cell_renderer_get_preferred_size (pixbuf_info->cell,
+ GTK_WIDGET (icon_view),
+ &min_size, NULL);
if (icon_view->priv->item_width > 0)
item_width = icon_view->priv->item_width;
if (!gtk_cell_renderer_get_visible (info->cell))
continue;
- gtk_cell_size_request_get_size (GTK_CELL_SIZE_REQUEST (info->cell),
- GTK_WIDGET (icon_view),
- &min_size, NULL);
+ gtk_cell_renderer_get_preferred_size (info->cell,
+ GTK_WIDGET (icon_view),
+ &min_size, NULL);
item->box[info->position].width = min_size.width;
item->box[info->position].height = min_size.height;
cell_area.height = max_height[i];
}
- gtk_cell_size_request_get_size (GTK_CELL_SIZE_REQUEST (info->cell),
- GTK_WIDGET (icon_view),
- &min_size, NULL);
+ gtk_cell_renderer_get_preferred_size (info->cell,
+ GTK_WIDGET (icon_view),
+ &min_size, NULL);
item->box[info->position].width = min_size.width;
item->box[info->position].height = min_size.height;
if (item->selected)
{
- gtk_cairo_paint_flat_box (style,
+ gtk_paint_flat_box (style,
cr,
GTK_STATE_SELECTED,
GTK_SHADOW_NONE,
cell_area.x = x - item->x + cell_area.x;
cell_area.y = y - item->y + cell_area.y;
- gtk_cell_renderer_render_cairo (info->cell,
- cr,
- widget,
- &cell_area, &cell_area, flags);
+ gtk_cell_renderer_render (info->cell,
+ cr,
+ widget,
+ &cell_area, &cell_area, flags);
}
if (draw_focus &&
if (i == icon_view->priv->cursor_cell)
{
- gtk_cairo_paint_focus (style,
+ gtk_paint_focus (style,
cr,
GTK_STATE_NORMAL,
widget,
* around the whole item.
*/
if (icon_view->priv->cursor_cell < 0)
- gtk_cairo_paint_focus (style,
+ gtk_paint_focus (style,
cr,
GTK_STATE_NORMAL,
widget,
static void
gtk_icon_view_paint_rubberband (GtkIconView *icon_view,
- cairo_t *cr,
- GdkRectangle *area)
+ cairo_t *cr)
{
GdkRectangle rect;
- GdkRectangle rubber_rect;
GdkColor *fill_color_gdk;
guchar fill_color_alpha;
- rubber_rect.x = MIN (icon_view->priv->rubberband_x1, icon_view->priv->rubberband_x2);
- rubber_rect.y = MIN (icon_view->priv->rubberband_y1, icon_view->priv->rubberband_y2);
- rubber_rect.width = ABS (icon_view->priv->rubberband_x1 - icon_view->priv->rubberband_x2) + 1;
- rubber_rect.height = ABS (icon_view->priv->rubberband_y1 - icon_view->priv->rubberband_y2) + 1;
+ cairo_save (cr);
- if (!gdk_rectangle_intersect (&rubber_rect, area, &rect))
- return;
+ rect.x = MIN (icon_view->priv->rubberband_x1, icon_view->priv->rubberband_x2);
+ rect.y = MIN (icon_view->priv->rubberband_y1, icon_view->priv->rubberband_y2);
+ rect.width = ABS (icon_view->priv->rubberband_x1 - icon_view->priv->rubberband_x2) + 1;
+ rect.height = ABS (icon_view->priv->rubberband_y1 - icon_view->priv->rubberband_y2) + 1;
gtk_widget_style_get (GTK_WIDGET (icon_view),
"selection-box-color", &fill_color_gdk,
if (!fill_color_gdk)
fill_color_gdk = gdk_color_copy (>k_widget_get_style (GTK_WIDGET (icon_view))->base[GTK_STATE_SELECTED]);
- cairo_set_source_rgba (cr,
- fill_color_gdk->red / 65535.,
- fill_color_gdk->green / 65535.,
- fill_color_gdk->blue / 65535.,
- fill_color_alpha / 255.);
+ gdk_cairo_set_source_color (cr, fill_color_gdk);
- cairo_save (cr);
gdk_cairo_rectangle (cr, &rect);
cairo_clip (cr);
- cairo_paint (cr);
- /* Draw the border without alpha */
- cairo_set_source_rgb (cr,
- fill_color_gdk->red / 65535.,
- fill_color_gdk->green / 65535.,
- fill_color_gdk->blue / 65535.);
+ cairo_paint_with_alpha (cr, fill_color_alpha / 255.);
+
cairo_rectangle (cr,
- rubber_rect.x + 0.5, rubber_rect.y + 0.5,
- rubber_rect.width - 1, rubber_rect.height - 1);
+ rect.x + 0.5, rect.y + 0.5,
+ rect.width - 1, rect.height - 1);
cairo_stroke (cr);
- cairo_restore (cr);
gdk_color_free (fill_color_gdk);
+
+ cairo_restore (cr);
}
static void
if (icon_view->priv->layout_idle_id != 0)
return;
- icon_view->priv->layout_idle_id = gdk_threads_add_idle (layout_callback, icon_view);
+ icon_view->priv->layout_idle_id =
+ gdk_threads_add_idle_full (GTK_ICON_VIEW_PRIORITY_LAYOUT,
+ layout_callback, icon_view, NULL);
}
static void
GtkTreeIter *iter,
gpointer data)
{
+ GtkIconView *icon_view = GTK_ICON_VIEW (data);
GtkIconViewItem *item;
gint index;
- GtkIconView *icon_view;
- icon_view = GTK_ICON_VIEW (data);
+ /* ignore changes in branches */
+ if (gtk_tree_path_get_depth (path) > 1)
+ return;
gtk_icon_view_stop_editing (icon_view, TRUE);
GtkTreeIter *iter,
gpointer data)
{
+ GtkIconView *icon_view = GTK_ICON_VIEW (data);
gint index;
GtkIconViewItem *item;
gboolean iters_persist;
- GtkIconView *icon_view;
GList *list;
-
- icon_view = GTK_ICON_VIEW (data);
+
+ /* ignore changes in branches */
+ if (gtk_tree_path_get_depth (path) > 1)
+ return;
iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
GtkTreePath *path,
gpointer data)
{
+ GtkIconView *icon_view = GTK_ICON_VIEW (data);
gint index;
- GtkIconView *icon_view;
GtkIconViewItem *item;
GList *list, *next;
gboolean emit = FALSE;
-
- icon_view = GTK_ICON_VIEW (data);
+
+ /* ignore changes in branches */
+ if (gtk_tree_path_get_depth (path) > 1)
+ return;
index = gtk_tree_path_get_indices(path)[0];
gint *new_order,
gpointer data)
{
+ GtkIconView *icon_view = GTK_ICON_VIEW (data);
int i;
int length;
- GtkIconView *icon_view;
GList *items = NULL, *list;
GtkIconViewItem **item_array;
gint *order;
-
- icon_view = GTK_ICON_VIEW (data);
+
+ /* ignore changes in branches */
+ if (iter != NULL)
+ return;
gtk_icon_view_stop_editing (icon_view, TRUE);
"focus-line-width", &focus_width,
NULL);
- gdk_drawable_get_size (GDK_DRAWABLE (icon_view->priv->bin_window),
- &width, &height);
+ width = gdk_window_get_width (icon_view->priv->bin_window);
+ height = gdk_window_get_height (icon_view->priv->bin_window);
gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
gtk_widget_get_allocation (widget, &allocation);
* When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
* @icon_view will connect a #GtkWidget::query-tooltip signal handler.
*
+ * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
+ * so &, <, etc have to be escaped in the text.
+ *
* Since: 2.12
*/
void
if (model)
{
GType column_type;
-
- g_return_if_fail (gtk_tree_model_get_flags (model) & GTK_TREE_MODEL_LIST_ONLY);
if (icon_view->priv->pixbuf_column != -1)
{
g_object_set (info->cell,
"alignment", PANGO_ALIGN_CENTER,
"wrap-mode", PANGO_WRAP_WORD_CHAR,
- "xalign", 0.0,
+ "xalign", 0.5,
"yalign", 0.0,
NULL);
else
"alignment", PANGO_ALIGN_LEFT,
"wrap-mode", PANGO_WRAP_WORD_CHAR,
"xalign", 0.0,
- "yalign", 0.0,
+ "yalign", 0.5,
NULL);
}
}
window = gtk_widget_get_window (GTK_WIDGET (icon_view));
gdk_window_get_pointer (window, &px, &py, NULL);
- gdk_window_get_geometry (window, &x, &y, &width, &height, NULL);
+ gdk_window_get_geometry (window, &x, &y, &width, &height);
/* see if we are near the edge. */
voffset = py - (y + 2 * SCROLL_EDGE_SIZE);
{
GtkIconView *icon_view;
GtkIconViewItem *item;
- GdkPixmap *icon;
+ cairo_surface_t *icon;
gint x, y;
GtkTreePath *path;
icon = gtk_icon_view_create_drag_icon (icon_view, path);
gtk_tree_path_free (path);
- gtk_drag_set_icon_pixmap (context,
- gdk_drawable_get_colormap (icon),
- icon,
- NULL,
- x, y);
+ cairo_surface_set_device_offset (icon, -x, -y);
+
+ gtk_drag_set_icon_surface (context, icon);
- g_object_unref (icon);
+ cairo_surface_destroy (icon);
}
static void
* @icon_view: a #GtkIconView
* @path: a #GtkTreePath in @icon_view
*
- * Creates a #GdkPixmap representation of the item at @path.
+ * Creates a #cairo_surface_t representation of the item at @path.
* This image is used for a drag icon.
*
- * Return value: (transfer full): a newly-allocated pixmap of the drag icon.
+ * Return value: (transfer full) a newly-allocated surface of the drag icon.
*
* Since: 2.8
**/
-GdkPixmap *
+cairo_surface_t *
gtk_icon_view_create_drag_icon (GtkIconView *icon_view,
GtkTreePath *path)
{
GtkWidget *widget;
cairo_t *cr;
- GdkPixmap *drawable;
+ cairo_surface_t *surface;
GList *l;
gint index;
if (index == item->index)
{
- drawable = gdk_pixmap_new (icon_view->priv->bin_window,
- item->width + 2,
- item->height + 2,
- -1);
+ surface = gdk_window_create_similar_surface (icon_view->priv->bin_window,
+ CAIRO_CONTENT_COLOR,
+ item->width + 2,
+ item->height + 2);
- cr = gdk_cairo_create (drawable);
+ cr = cairo_create (surface);
cairo_set_line_width (cr, 1.);
gdk_cairo_set_source_color (cr, >k_widget_get_style (widget)->base[gtk_widget_get_state (widget)]);
cairo_destroy (cr);
- return drawable;
+ return surface;
}
}
}
static void
-gtk_icon_view_accessible_adjustment_changed (GtkAdjustment *adjustment,
- GtkIconView *icon_view)
+gtk_icon_view_accessible_adjustment_changed (GtkAdjustment *adjustment,
+ GtkIconViewAccessible *view)
{
- AtkObject *obj;
- GtkIconViewAccessible *view;
-
- /*
- * The scrollbars have changed
- */
- obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
- view = GTK_ICON_VIEW_ACCESSIBLE (obj);
-
gtk_icon_view_accessible_traverse_items (view, NULL);
}
static void
-gtk_icon_view_accessible_set_scroll_adjustments (GtkWidget *widget,
- GtkAdjustment *hadj,
- GtkAdjustment *vadj)
+gtk_icon_view_accessible_set_adjustment (AtkObject *accessible,
+ GtkOrientation orientation,
+ GtkAdjustment *adjustment)
{
- AtkObject *atk_obj;
GtkIconViewAccessiblePrivate *priv;
+ GtkAdjustment **old_adj_ptr;
- atk_obj = gtk_widget_get_accessible (widget);
- priv = gtk_icon_view_accessible_get_priv (atk_obj);
+ priv = gtk_icon_view_accessible_get_priv (accessible);
+
+ /* Adjustments are set for the first time in constructor and priv is not
+ * initialized at that time, so skip this first setting. */
+ if (!priv)
+ return;
- if (priv->old_hadj != hadj)
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
- if (priv->old_hadj)
- {
- g_object_remove_weak_pointer (G_OBJECT (priv->old_hadj),
- (gpointer *)&priv->old_hadj);
-
- g_signal_handlers_disconnect_by_func (priv->old_hadj,
- (gpointer) gtk_icon_view_accessible_adjustment_changed,
- widget);
- }
- priv->old_hadj = hadj;
- if (priv->old_hadj)
- {
- g_object_add_weak_pointer (G_OBJECT (priv->old_hadj),
- (gpointer *)&priv->old_hadj);
- g_signal_connect (hadj,
- "value-changed",
- G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
- widget);
- }
+ if (priv->old_hadj == adjustment)
+ return;
+
+ old_adj_ptr = &priv->old_hadj;
}
- if (priv->old_vadj != vadj)
+ else
{
- if (priv->old_vadj)
- {
- g_object_remove_weak_pointer (G_OBJECT (priv->old_vadj),
- (gpointer *)&priv->old_vadj);
-
- g_signal_handlers_disconnect_by_func (priv->old_vadj,
- (gpointer) gtk_icon_view_accessible_adjustment_changed,
- widget);
- }
- priv->old_vadj = vadj;
- if (priv->old_vadj)
- {
- g_object_add_weak_pointer (G_OBJECT (priv->old_vadj),
- (gpointer *)&priv->old_vadj);
- g_signal_connect (vadj,
- "value-changed",
- G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
- widget);
- }
+ if (priv->old_vadj == adjustment)
+ return;
+
+ old_adj_ptr = &priv->old_vadj;
}
+
+ /* Disconnect signal handlers */
+ if (*old_adj_ptr)
+ {
+ g_object_remove_weak_pointer (G_OBJECT (*old_adj_ptr),
+ (gpointer *)&priv->old_hadj);
+ g_signal_handlers_disconnect_by_func (*old_adj_ptr,
+ gtk_icon_view_accessible_adjustment_changed,
+ accessible);
+ }
+
+ /* Connect signal */
+ *old_adj_ptr = adjustment;
+ g_object_add_weak_pointer (G_OBJECT (adjustment), (gpointer *)old_adj_ptr);
+ g_signal_connect (adjustment, "value-changed",
+ G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
+ accessible);
}
static void
icon_view = GTK_ICON_VIEW (data);
if (icon_view->priv->hadjustment)
- {
- priv->old_hadj = icon_view->priv->hadjustment;
- g_object_add_weak_pointer (G_OBJECT (priv->old_hadj), (gpointer *)&priv->old_hadj);
- g_signal_connect (icon_view->priv->hadjustment,
- "value-changed",
- G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
- icon_view);
- }
+ gtk_icon_view_accessible_set_adjustment (accessible,
+ GTK_ORIENTATION_HORIZONTAL,
+ icon_view->priv->hadjustment);
if (icon_view->priv->vadjustment)
- {
- priv->old_vadj = icon_view->priv->vadjustment;
- g_object_add_weak_pointer (G_OBJECT (priv->old_vadj), (gpointer *)&priv->old_vadj);
- g_signal_connect (icon_view->priv->vadjustment,
- "value-changed",
- G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
- icon_view);
- }
- g_signal_connect_after (data,
- "set-scroll-adjustments",
- G_CALLBACK (gtk_icon_view_accessible_set_scroll_adjustments),
- NULL);
+ gtk_icon_view_accessible_set_adjustment (accessible,
+ GTK_ORIENTATION_VERTICAL,
+ icon_view->priv->vadjustment);
g_signal_connect (data,
"notify",
G_CALLBACK (gtk_icon_view_accessible_notify_gtk),
g_signal_handlers_disconnect_by_func (priv->old_hadj,
(gpointer) gtk_icon_view_accessible_adjustment_changed,
- widget);
+ accessible);
priv->old_hadj = NULL;
}
if (priv->old_vadj)
g_signal_handlers_disconnect_by_func (priv->old_vadj,
(gpointer) gtk_icon_view_accessible_adjustment_changed,
- widget);
+ accessible);
priv->old_vadj = NULL;
}
}