2 * Copyright (C) 2002, 2004 Anders Carlsson <andersca@gnu.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
26 #include "gtkaccessibleprivate.h"
27 #include "gtkiconview.h"
28 #include "gtkcelllayout.h"
29 #include "gtkcellrenderer.h"
30 #include "gtkcellareabox.h"
31 #include "gtkcellareacontext.h"
32 #include "gtkcellrenderertext.h"
33 #include "gtkcellrendererpixbuf.h"
34 #include "gtkorientable.h"
35 #include "gtkmarshalers.h"
36 #include "gtkbindings.h"
40 #include "gtkaccessible.h"
41 #include "gtkwindow.h"
43 #include "gtkcombobox.h"
44 #include "gtktextbuffer.h"
45 #include "gtkscrollable.h"
46 #include "gtksizerequest.h"
47 #include "gtktreednd.h"
48 #include "gtktypebuiltins.h"
49 #include "gtkprivate.h"
54 * @short_description: A widget which displays a list of icons in a grid
56 * #GtkIconView provides an alternative view on a #GtkTreeModel.
57 * It displays the model as a grid of icons with labels. Like
58 * #GtkTreeView, it allows to select one or multiple items
59 * (depending on the selection mode, see gtk_icon_view_set_selection_mode()).
60 * In addition to selection with the arrow keys, #GtkIconView supports
61 * rubberband selection, which is controlled by dragging the pointer.
63 * Note that if the tree model is backed by an actual tree store (as
64 * opposed to a flat list where the mapping to icons is obvious),
65 * #GtkIconView will only display the first level of the tree and
66 * ignore the tree's branches.
69 #define SCROLL_EDGE_SIZE 15
71 #define GTK_ICON_VIEW_PRIORITY_LAYOUT (GDK_PRIORITY_REDRAW + 5)
73 typedef struct _GtkIconViewItem GtkIconViewItem;
74 struct _GtkIconViewItem
76 /* First member is always the rectangle so it
77 * can be cast to a rectangle. */
78 GdkRectangle cell_area;
86 guint selected_before_rubberbanding : 1;
90 typedef struct _GtkIconViewChild GtkIconViewChild;
91 struct _GtkIconViewChild
97 struct _GtkIconViewPrivate
99 GtkCellArea *cell_area;
100 GtkCellAreaContext *cell_area_context;
102 gulong add_editable_id;
103 gulong remove_editable_id;
104 gulong context_changed_id;
106 GPtrArray *row_contexts;
110 GtkSelectionMode selection_mode;
112 guint layout_idle_id;
114 GdkWindow *bin_window;
122 GtkAdjustment *hadjustment;
123 GtkAdjustment *vadjustment;
125 gint rubberband_x1, rubberband_y1;
126 gint rubberband_x2, rubberband_y2;
127 GdkDevice *rubberband_device;
129 guint scroll_timeout_id;
130 gint scroll_value_diff;
131 gint event_last_x, event_last_y;
133 GtkIconViewItem *anchor_item;
134 GtkIconViewItem *cursor_item;
136 GtkIconViewItem *last_single_clicked;
138 GtkOrientation item_orientation;
153 GtkCellRenderer *pixbuf_cell;
154 GtkCellRenderer *text_cell;
157 GdkModifierType start_button_mask;
162 GdkDragAction source_actions;
163 GdkDragAction dest_actions;
165 GtkTreeRowReference *dest_item;
166 GtkIconViewDropPosition dest_pos;
169 GtkTreeRowReference *scroll_to_path;
170 gfloat scroll_to_row_align;
171 gfloat scroll_to_col_align;
172 guint scroll_to_use_align : 1;
174 guint source_set : 1;
176 guint reorderable : 1;
177 guint empty_view_drop :1;
179 guint ctrl_pressed : 1;
180 guint shift_pressed : 1;
182 guint draw_focus : 1;
184 /* GtkScrollablePolicy needs to be checked when
185 * driving the scrollable adjustment values */
186 guint hscroll_policy : 1;
187 guint vscroll_policy : 1;
189 guint doing_rubberband : 1;
203 ACTIVATE_CURSOR_ITEM,
215 PROP_ITEM_ORIENTATION,
228 /* For scrollable interface */
236 static void gtk_icon_view_cell_layout_init (GtkCellLayoutIface *iface);
237 static void gtk_icon_view_dispose (GObject *object);
238 static GObject *gtk_icon_view_constructor (GType type,
239 guint n_construct_properties,
240 GObjectConstructParam *construct_properties);
241 static void gtk_icon_view_set_property (GObject *object,
245 static void gtk_icon_view_get_property (GObject *object,
249 /* GtkWidget vfuncs */
250 static void gtk_icon_view_destroy (GtkWidget *widget);
251 static void gtk_icon_view_realize (GtkWidget *widget);
252 static void gtk_icon_view_unrealize (GtkWidget *widget);
253 static void gtk_icon_view_style_updated (GtkWidget *widget);
254 static void gtk_icon_view_state_flags_changed (GtkWidget *widget,
255 GtkStateFlags previous_state);
256 static void gtk_icon_view_get_preferred_width (GtkWidget *widget,
259 static void gtk_icon_view_get_preferred_height (GtkWidget *widget,
262 static void gtk_icon_view_size_allocate (GtkWidget *widget,
263 GtkAllocation *allocation);
264 static gboolean gtk_icon_view_draw (GtkWidget *widget,
266 static gboolean gtk_icon_view_motion (GtkWidget *widget,
267 GdkEventMotion *event);
268 static gboolean gtk_icon_view_button_press (GtkWidget *widget,
269 GdkEventButton *event);
270 static gboolean gtk_icon_view_button_release (GtkWidget *widget,
271 GdkEventButton *event);
272 static gboolean gtk_icon_view_key_press (GtkWidget *widget,
274 static gboolean gtk_icon_view_key_release (GtkWidget *widget,
276 static AtkObject *gtk_icon_view_get_accessible (GtkWidget *widget);
279 /* GtkContainer vfuncs */
280 static void gtk_icon_view_remove (GtkContainer *container,
282 static void gtk_icon_view_forall (GtkContainer *container,
283 gboolean include_internals,
284 GtkCallback callback,
285 gpointer callback_data);
287 /* GtkIconView vfuncs */
288 static void gtk_icon_view_real_select_all (GtkIconView *icon_view);
289 static void gtk_icon_view_real_unselect_all (GtkIconView *icon_view);
290 static void gtk_icon_view_real_select_cursor_item (GtkIconView *icon_view);
291 static void gtk_icon_view_real_toggle_cursor_item (GtkIconView *icon_view);
292 static gboolean gtk_icon_view_real_activate_cursor_item (GtkIconView *icon_view);
294 /* Internal functions */
295 static void gtk_icon_view_set_hadjustment_values (GtkIconView *icon_view);
296 static void gtk_icon_view_set_vadjustment_values (GtkIconView *icon_view);
297 static void gtk_icon_view_set_hadjustment (GtkIconView *icon_view,
298 GtkAdjustment *adjustment);
299 static void gtk_icon_view_set_vadjustment (GtkIconView *icon_view,
300 GtkAdjustment *adjustment);
301 static void gtk_icon_view_accessible_set_adjustment (AtkObject *accessible,
302 GtkOrientation orientation,
303 GtkAdjustment *adjustment);
304 static void gtk_icon_view_adjustment_changed (GtkAdjustment *adjustment,
305 GtkIconView *icon_view);
306 static void gtk_icon_view_layout (GtkIconView *icon_view);
307 static void gtk_icon_view_paint_item (GtkIconView *icon_view,
309 GtkIconViewItem *item,
312 gboolean draw_focus);
313 static void gtk_icon_view_paint_rubberband (GtkIconView *icon_view,
315 static void gtk_icon_view_queue_draw_path (GtkIconView *icon_view,
317 static void gtk_icon_view_queue_draw_item (GtkIconView *icon_view,
318 GtkIconViewItem *item);
319 static void gtk_icon_view_queue_layout (GtkIconView *icon_view);
320 static void gtk_icon_view_set_cursor_item (GtkIconView *icon_view,
321 GtkIconViewItem *item,
322 GtkCellRenderer *cursor_cell);
323 static void gtk_icon_view_start_rubberbanding (GtkIconView *icon_view,
327 static void gtk_icon_view_stop_rubberbanding (GtkIconView *icon_view);
328 static void gtk_icon_view_update_rubberband_selection (GtkIconView *icon_view);
329 static gboolean gtk_icon_view_item_hit_test (GtkIconView *icon_view,
330 GtkIconViewItem *item,
335 static gboolean gtk_icon_view_unselect_all_internal (GtkIconView *icon_view);
336 static void gtk_icon_view_cache_widths (GtkIconView *icon_view);
337 static void gtk_icon_view_update_rubberband (gpointer data);
338 static void gtk_icon_view_item_invalidate_size (GtkIconViewItem *item);
339 static void gtk_icon_view_invalidate_sizes (GtkIconView *icon_view);
340 static void gtk_icon_view_add_move_binding (GtkBindingSet *binding_set,
343 GtkMovementStep step,
345 static gboolean gtk_icon_view_real_move_cursor (GtkIconView *icon_view,
346 GtkMovementStep step,
348 static void gtk_icon_view_move_cursor_up_down (GtkIconView *icon_view,
350 static void gtk_icon_view_move_cursor_page_up_down (GtkIconView *icon_view,
352 static void gtk_icon_view_move_cursor_left_right (GtkIconView *icon_view,
354 static void gtk_icon_view_move_cursor_start_end (GtkIconView *icon_view,
356 static void gtk_icon_view_scroll_to_item (GtkIconView *icon_view,
357 GtkIconViewItem *item);
358 static void gtk_icon_view_select_item (GtkIconView *icon_view,
359 GtkIconViewItem *item);
360 static void gtk_icon_view_unselect_item (GtkIconView *icon_view,
361 GtkIconViewItem *item);
362 static gboolean gtk_icon_view_select_all_between (GtkIconView *icon_view,
363 GtkIconViewItem *anchor,
364 GtkIconViewItem *cursor);
365 static GtkIconViewItem * gtk_icon_view_get_item_at_coords (GtkIconView *icon_view,
368 gboolean only_in_cell,
369 GtkCellRenderer **cell_at_pos);
370 static void gtk_icon_view_set_cell_data (GtkIconView *icon_view,
371 GtkIconViewItem *item);
373 static void gtk_icon_view_ensure_cell_area (GtkIconView *icon_view,
374 GtkCellArea *cell_area);
376 static GtkCellArea *gtk_icon_view_cell_layout_get_area (GtkCellLayout *layout);
378 static void gtk_icon_view_item_selected_changed (GtkIconView *icon_view,
379 GtkIconViewItem *item);
381 static void gtk_icon_view_add_editable (GtkCellArea *area,
382 GtkCellRenderer *renderer,
383 GtkCellEditable *editable,
384 GdkRectangle *cell_area,
386 GtkIconView *icon_view);
387 static void gtk_icon_view_remove_editable (GtkCellArea *area,
388 GtkCellRenderer *renderer,
389 GtkCellEditable *editable,
390 GtkIconView *icon_view);
391 static void gtk_icon_view_context_changed (GtkCellAreaContext *context,
393 GtkIconView *icon_view);
394 static void update_text_cell (GtkIconView *icon_view);
395 static void update_pixbuf_cell (GtkIconView *icon_view);
397 /* Source side drag signals */
398 static void gtk_icon_view_drag_begin (GtkWidget *widget,
399 GdkDragContext *context);
400 static void gtk_icon_view_drag_end (GtkWidget *widget,
401 GdkDragContext *context);
402 static void gtk_icon_view_drag_data_get (GtkWidget *widget,
403 GdkDragContext *context,
404 GtkSelectionData *selection_data,
407 static void gtk_icon_view_drag_data_delete (GtkWidget *widget,
408 GdkDragContext *context);
410 /* Target side drag signals */
411 static void gtk_icon_view_drag_leave (GtkWidget *widget,
412 GdkDragContext *context,
414 static gboolean gtk_icon_view_drag_motion (GtkWidget *widget,
415 GdkDragContext *context,
419 static gboolean gtk_icon_view_drag_drop (GtkWidget *widget,
420 GdkDragContext *context,
424 static void gtk_icon_view_drag_data_received (GtkWidget *widget,
425 GdkDragContext *context,
428 GtkSelectionData *selection_data,
431 static gboolean gtk_icon_view_maybe_begin_drag (GtkIconView *icon_view,
432 GdkEventMotion *event);
434 static void remove_scroll_timeout (GtkIconView *icon_view);
437 static GtkBuildableIface *parent_buildable_iface;
438 static void gtk_icon_view_buildable_init (GtkBuildableIface *iface);
439 static gboolean gtk_icon_view_buildable_custom_tag_start (GtkBuildable *buildable,
442 const gchar *tagname,
443 GMarkupParser *parser,
445 static void gtk_icon_view_buildable_custom_tag_end (GtkBuildable *buildable,
448 const gchar *tagname,
451 static guint icon_view_signals[LAST_SIGNAL] = { 0 };
453 G_DEFINE_TYPE_WITH_CODE (GtkIconView, gtk_icon_view, GTK_TYPE_CONTAINER,
454 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
455 gtk_icon_view_cell_layout_init)
456 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
457 gtk_icon_view_buildable_init)
458 G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
461 gtk_icon_view_class_init (GtkIconViewClass *klass)
463 GObjectClass *gobject_class;
464 GtkWidgetClass *widget_class;
465 GtkContainerClass *container_class;
466 GtkBindingSet *binding_set;
468 binding_set = gtk_binding_set_by_class (klass);
470 g_type_class_add_private (klass, sizeof (GtkIconViewPrivate));
472 gobject_class = (GObjectClass *) klass;
473 widget_class = (GtkWidgetClass *) klass;
474 container_class = (GtkContainerClass *) klass;
476 gobject_class->constructor = gtk_icon_view_constructor;
477 gobject_class->dispose = gtk_icon_view_dispose;
478 gobject_class->set_property = gtk_icon_view_set_property;
479 gobject_class->get_property = gtk_icon_view_get_property;
481 widget_class->destroy = gtk_icon_view_destroy;
482 widget_class->realize = gtk_icon_view_realize;
483 widget_class->unrealize = gtk_icon_view_unrealize;
484 widget_class->style_updated = gtk_icon_view_style_updated;
485 widget_class->get_accessible = gtk_icon_view_get_accessible;
486 widget_class->get_preferred_width = gtk_icon_view_get_preferred_width;
487 widget_class->get_preferred_height = gtk_icon_view_get_preferred_height;
488 widget_class->size_allocate = gtk_icon_view_size_allocate;
489 widget_class->draw = gtk_icon_view_draw;
490 widget_class->motion_notify_event = gtk_icon_view_motion;
491 widget_class->button_press_event = gtk_icon_view_button_press;
492 widget_class->button_release_event = gtk_icon_view_button_release;
493 widget_class->key_press_event = gtk_icon_view_key_press;
494 widget_class->key_release_event = gtk_icon_view_key_release;
495 widget_class->drag_begin = gtk_icon_view_drag_begin;
496 widget_class->drag_end = gtk_icon_view_drag_end;
497 widget_class->drag_data_get = gtk_icon_view_drag_data_get;
498 widget_class->drag_data_delete = gtk_icon_view_drag_data_delete;
499 widget_class->drag_leave = gtk_icon_view_drag_leave;
500 widget_class->drag_motion = gtk_icon_view_drag_motion;
501 widget_class->drag_drop = gtk_icon_view_drag_drop;
502 widget_class->drag_data_received = gtk_icon_view_drag_data_received;
503 widget_class->state_flags_changed = gtk_icon_view_state_flags_changed;
505 container_class->remove = gtk_icon_view_remove;
506 container_class->forall = gtk_icon_view_forall;
508 klass->select_all = gtk_icon_view_real_select_all;
509 klass->unselect_all = gtk_icon_view_real_unselect_all;
510 klass->select_cursor_item = gtk_icon_view_real_select_cursor_item;
511 klass->toggle_cursor_item = gtk_icon_view_real_toggle_cursor_item;
512 klass->activate_cursor_item = gtk_icon_view_real_activate_cursor_item;
513 klass->move_cursor = gtk_icon_view_real_move_cursor;
517 * GtkIconView:selection-mode:
519 * The ::selection-mode property specifies the selection mode of
520 * icon view. If the mode is #GTK_SELECTION_MULTIPLE, rubberband selection
521 * is enabled, for the other modes, only keyboard selection is possible.
525 g_object_class_install_property (gobject_class,
527 g_param_spec_enum ("selection-mode",
528 P_("Selection mode"),
529 P_("The selection mode"),
530 GTK_TYPE_SELECTION_MODE,
531 GTK_SELECTION_SINGLE,
532 GTK_PARAM_READWRITE));
535 * GtkIconView:pixbuf-column:
537 * The ::pixbuf-column property contains the number of the model column
538 * containing the pixbufs which are displayed. The pixbuf column must be
539 * of type #GDK_TYPE_PIXBUF. Setting this property to -1 turns off the
540 * display of pixbufs.
544 g_object_class_install_property (gobject_class,
546 g_param_spec_int ("pixbuf-column",
548 P_("Model column used to retrieve the icon pixbuf from"),
550 GTK_PARAM_READWRITE));
553 * GtkIconView:text-column:
555 * The ::text-column property contains the number of the model column
556 * containing the texts which are displayed. The text column must be
557 * of type #G_TYPE_STRING. If this property and the :markup-column
558 * property are both set to -1, no texts are displayed.
562 g_object_class_install_property (gobject_class,
564 g_param_spec_int ("text-column",
566 P_("Model column used to retrieve the text from"),
568 GTK_PARAM_READWRITE));
572 * GtkIconView:markup-column:
574 * The ::markup-column property contains the number of the model column
575 * containing markup information to be displayed. The markup column must be
576 * of type #G_TYPE_STRING. If this property and the :text-column property
577 * are both set to column numbers, it overrides the text column.
578 * If both are set to -1, no texts are displayed.
582 g_object_class_install_property (gobject_class,
584 g_param_spec_int ("markup-column",
586 P_("Model column used to retrieve the text if using Pango markup"),
588 GTK_PARAM_READWRITE));
590 g_object_class_install_property (gobject_class,
592 g_param_spec_object ("model",
593 P_("Icon View Model"),
594 P_("The model for the icon view"),
596 GTK_PARAM_READWRITE));
599 * GtkIconView:columns:
601 * The columns property contains the number of the columns in which the
602 * items should be displayed. If it is -1, the number of columns will
603 * be chosen automatically to fill the available area.
607 g_object_class_install_property (gobject_class,
609 g_param_spec_int ("columns",
610 P_("Number of columns"),
611 P_("Number of columns to display"),
613 GTK_PARAM_READWRITE));
617 * GtkIconView:item-width:
619 * The item-width property specifies the width to use for each item.
620 * If it is set to -1, the icon view will automatically determine a
621 * suitable item size.
625 g_object_class_install_property (gobject_class,
627 g_param_spec_int ("item-width",
628 P_("Width for each item"),
629 P_("The width used for each item"),
631 GTK_PARAM_READWRITE));
634 * GtkIconView:spacing:
636 * The spacing property specifies the space which is inserted between
637 * the cells (i.e. the icon and the text) of an item.
641 g_object_class_install_property (gobject_class,
643 g_param_spec_int ("spacing",
645 P_("Space which is inserted between cells of an item"),
647 GTK_PARAM_READWRITE));
650 * GtkIconView:row-spacing:
652 * The row-spacing property specifies the space which is inserted between
653 * the rows of the icon view.
657 g_object_class_install_property (gobject_class,
659 g_param_spec_int ("row-spacing",
661 P_("Space which is inserted between grid rows"),
663 GTK_PARAM_READWRITE));
666 * GtkIconView:column-spacing:
668 * The column-spacing property specifies the space which is inserted between
669 * the columns of the icon view.
673 g_object_class_install_property (gobject_class,
675 g_param_spec_int ("column-spacing",
676 P_("Column Spacing"),
677 P_("Space which is inserted between grid columns"),
679 GTK_PARAM_READWRITE));
682 * GtkIconView:margin:
684 * The margin property specifies the space which is inserted
685 * at the edges of the icon view.
689 g_object_class_install_property (gobject_class,
691 g_param_spec_int ("margin",
693 P_("Space which is inserted at the edges of the icon view"),
695 GTK_PARAM_READWRITE));
698 * GtkIconView:item-orientation:
700 * The item-orientation property specifies how the cells (i.e. the icon and
701 * the text) of the item are positioned relative to each other.
705 g_object_class_install_property (gobject_class,
706 PROP_ITEM_ORIENTATION,
707 g_param_spec_enum ("item-orientation",
708 P_("Item Orientation"),
709 P_("How the text and icon of each item are positioned relative to each other"),
710 GTK_TYPE_ORIENTATION,
711 GTK_ORIENTATION_VERTICAL,
712 GTK_PARAM_READWRITE));
715 * GtkIconView:reorderable:
717 * The reorderable property specifies if the items can be reordered
722 g_object_class_install_property (gobject_class,
724 g_param_spec_boolean ("reorderable",
726 P_("View is reorderable"),
730 g_object_class_install_property (gobject_class,
732 g_param_spec_int ("tooltip-column",
733 P_("Tooltip Column"),
734 P_("The column in the model containing the tooltip texts for the items"),
738 GTK_PARAM_READWRITE));
741 * GtkIconView:item-padding:
743 * The item-padding property specifies the padding around each
744 * of the icon view's item.
748 g_object_class_install_property (gobject_class,
750 g_param_spec_int ("item-padding",
752 P_("Padding around icon view items"),
754 GTK_PARAM_READWRITE));
757 * GtkIconView:cell-area:
759 * The #GtkCellArea used to layout cell renderers for this view.
761 * If no area is specified when creating the icon view with gtk_icon_view_new_with_area()
762 * a #GtkCellAreaBox will be used.
766 g_object_class_install_property (gobject_class,
768 g_param_spec_object ("cell-area",
770 P_("The GtkCellArea used to layout cells"),
772 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
774 /* Scrollable interface properties */
775 g_object_class_override_property (gobject_class, PROP_HADJUSTMENT, "hadjustment");
776 g_object_class_override_property (gobject_class, PROP_VADJUSTMENT, "vadjustment");
777 g_object_class_override_property (gobject_class, PROP_HSCROLL_POLICY, "hscroll-policy");
778 g_object_class_override_property (gobject_class, PROP_VSCROLL_POLICY, "vscroll-policy");
780 /* Style properties */
781 gtk_widget_class_install_style_property (widget_class,
782 g_param_spec_boxed ("selection-box-color",
783 P_("Selection Box Color"),
784 P_("Color of the selection box"),
786 GTK_PARAM_READABLE));
788 gtk_widget_class_install_style_property (widget_class,
789 g_param_spec_uchar ("selection-box-alpha",
790 P_("Selection Box Alpha"),
791 P_("Opacity of the selection box"),
794 GTK_PARAM_READABLE));
798 * GtkIconView::item-activated:
799 * @iconview: the object on which the signal is emitted
800 * @path: the #GtkTreePath for the activated item
802 * The ::item-activated signal is emitted when the method
803 * gtk_icon_view_item_activated() is called or the user double
804 * clicks an item. It is also emitted when a non-editable item
805 * is selected and one of the keys: Space, Return or Enter is
808 icon_view_signals[ITEM_ACTIVATED] =
809 g_signal_new (I_("item-activated"),
810 G_TYPE_FROM_CLASS (gobject_class),
812 G_STRUCT_OFFSET (GtkIconViewClass, item_activated),
814 g_cclosure_marshal_VOID__BOXED,
819 * GtkIconView::selection-changed:
820 * @iconview: the object on which the signal is emitted
822 * The ::selection-changed signal is emitted when the selection
823 * (i.e. the set of selected items) changes.
825 icon_view_signals[SELECTION_CHANGED] =
826 g_signal_new (I_("selection-changed"),
827 G_TYPE_FROM_CLASS (gobject_class),
829 G_STRUCT_OFFSET (GtkIconViewClass, selection_changed),
831 g_cclosure_marshal_VOID__VOID,
835 * GtkIconView::select-all:
836 * @iconview: the object on which the signal is emitted
838 * A <link linkend="keybinding-signals">keybinding signal</link>
839 * which gets emitted when the user selects all items.
841 * Applications should not connect to it, but may emit it with
842 * g_signal_emit_by_name() if they need to control selection
845 * The default binding for this signal is Ctrl-a.
847 icon_view_signals[SELECT_ALL] =
848 g_signal_new (I_("select-all"),
849 G_TYPE_FROM_CLASS (gobject_class),
850 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
851 G_STRUCT_OFFSET (GtkIconViewClass, select_all),
853 g_cclosure_marshal_VOID__VOID,
857 * GtkIconView::unselect-all:
858 * @iconview: the object on which the signal is emitted
860 * A <link linkend="keybinding-signals">keybinding signal</link>
861 * which gets emitted when the user unselects all items.
863 * Applications should not connect to it, but may emit it with
864 * g_signal_emit_by_name() if they need to control selection
867 * The default binding for this signal is Ctrl-Shift-a.
869 icon_view_signals[UNSELECT_ALL] =
870 g_signal_new (I_("unselect-all"),
871 G_TYPE_FROM_CLASS (gobject_class),
872 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
873 G_STRUCT_OFFSET (GtkIconViewClass, unselect_all),
875 g_cclosure_marshal_VOID__VOID,
879 * GtkIconView::select-cursor-item:
880 * @iconview: the object on which the signal is emitted
882 * A <link linkend="keybinding-signals">keybinding signal</link>
883 * which gets emitted when the user selects the item that is currently
886 * Applications should not connect to it, but may emit it with
887 * g_signal_emit_by_name() if they need to control selection
890 * There is no default binding for this signal.
892 icon_view_signals[SELECT_CURSOR_ITEM] =
893 g_signal_new (I_("select-cursor-item"),
894 G_TYPE_FROM_CLASS (gobject_class),
895 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
896 G_STRUCT_OFFSET (GtkIconViewClass, select_cursor_item),
898 g_cclosure_marshal_VOID__VOID,
902 * GtkIconView::toggle-cursor-item:
903 * @iconview: the object on which the signal is emitted
905 * A <link linkend="keybinding-signals">keybinding signal</link>
906 * which gets emitted when the user toggles whether the currently
907 * focused item is selected or not. The exact effect of this
908 * depend on the selection mode.
910 * Applications should not connect to it, but may emit it with
911 * g_signal_emit_by_name() if they need to control selection
914 * There is no default binding for this signal is Ctrl-Space.
916 icon_view_signals[TOGGLE_CURSOR_ITEM] =
917 g_signal_new (I_("toggle-cursor-item"),
918 G_TYPE_FROM_CLASS (gobject_class),
919 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
920 G_STRUCT_OFFSET (GtkIconViewClass, toggle_cursor_item),
922 g_cclosure_marshal_VOID__VOID,
926 * GtkIconView::activate-cursor-item:
927 * @iconview: the object on which the signal is emitted
929 * A <link linkend="keybinding-signals">keybinding signal</link>
930 * which gets emitted when the user activates the currently
933 * Applications should not connect to it, but may emit it with
934 * g_signal_emit_by_name() if they need to control activation
937 * The default bindings for this signal are Space, Return and Enter.
939 icon_view_signals[ACTIVATE_CURSOR_ITEM] =
940 g_signal_new (I_("activate-cursor-item"),
941 G_TYPE_FROM_CLASS (gobject_class),
942 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
943 G_STRUCT_OFFSET (GtkIconViewClass, activate_cursor_item),
945 _gtk_marshal_BOOLEAN__VOID,
949 * GtkIconView::move-cursor:
950 * @iconview: the object which received the signal
951 * @step: the granularity of the move, as a #GtkMovementStep
952 * @count: the number of @step units to move
954 * The ::move-cursor signal is a
955 * <link linkend="keybinding-signals">keybinding signal</link>
956 * which gets emitted when the user initiates a cursor movement.
958 * Applications should not connect to it, but may emit it with
959 * g_signal_emit_by_name() if they need to control the cursor
962 * The default bindings for this signal include
964 * <listitem>Arrow keys which move by individual steps</listitem>
965 * <listitem>Home/End keys which move to the first/last item</listitem>
966 * <listitem>PageUp/PageDown which move by "pages"</listitem>
969 * All of these will extend the selection when combined with
970 * the Shift modifier.
972 icon_view_signals[MOVE_CURSOR] =
973 g_signal_new (I_("move-cursor"),
974 G_TYPE_FROM_CLASS (gobject_class),
975 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
976 G_STRUCT_OFFSET (GtkIconViewClass, move_cursor),
978 _gtk_marshal_BOOLEAN__ENUM_INT,
980 GTK_TYPE_MOVEMENT_STEP,
984 gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK,
986 gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
988 gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_CONTROL_MASK,
989 "toggle-cursor-item", 0);
990 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_CONTROL_MASK,
991 "toggle-cursor-item", 0);
993 gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0,
994 "activate-cursor-item", 0);
995 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0,
996 "activate-cursor-item", 0);
997 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0,
998 "activate-cursor-item", 0);
999 gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0,
1000 "activate-cursor-item", 0);
1001 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0,
1002 "activate-cursor-item", 0);
1004 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_Up, 0,
1005 GTK_MOVEMENT_DISPLAY_LINES, -1);
1006 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_KP_Up, 0,
1007 GTK_MOVEMENT_DISPLAY_LINES, -1);
1009 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_Down, 0,
1010 GTK_MOVEMENT_DISPLAY_LINES, 1);
1011 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_KP_Down, 0,
1012 GTK_MOVEMENT_DISPLAY_LINES, 1);
1014 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_p, GDK_CONTROL_MASK,
1015 GTK_MOVEMENT_DISPLAY_LINES, -1);
1017 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_n, GDK_CONTROL_MASK,
1018 GTK_MOVEMENT_DISPLAY_LINES, 1);
1020 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_Home, 0,
1021 GTK_MOVEMENT_BUFFER_ENDS, -1);
1022 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_KP_Home, 0,
1023 GTK_MOVEMENT_BUFFER_ENDS, -1);
1025 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_End, 0,
1026 GTK_MOVEMENT_BUFFER_ENDS, 1);
1027 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_KP_End, 0,
1028 GTK_MOVEMENT_BUFFER_ENDS, 1);
1030 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_Page_Up, 0,
1031 GTK_MOVEMENT_PAGES, -1);
1032 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0,
1033 GTK_MOVEMENT_PAGES, -1);
1035 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_Page_Down, 0,
1036 GTK_MOVEMENT_PAGES, 1);
1037 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0,
1038 GTK_MOVEMENT_PAGES, 1);
1040 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_Right, 0,
1041 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
1042 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_Left, 0,
1043 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
1045 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_KP_Right, 0,
1046 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
1047 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_KP_Left, 0,
1048 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
1052 gtk_icon_view_buildable_init (GtkBuildableIface *iface)
1054 parent_buildable_iface = g_type_interface_peek_parent (iface);
1055 iface->add_child = _gtk_cell_layout_buildable_add_child;
1056 iface->custom_tag_start = gtk_icon_view_buildable_custom_tag_start;
1057 iface->custom_tag_end = gtk_icon_view_buildable_custom_tag_end;
1061 gtk_icon_view_cell_layout_init (GtkCellLayoutIface *iface)
1063 iface->get_area = gtk_icon_view_cell_layout_get_area;
1067 gtk_icon_view_init (GtkIconView *icon_view)
1069 icon_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (icon_view,
1071 GtkIconViewPrivate);
1073 icon_view->priv->width = 0;
1074 icon_view->priv->height = 0;
1075 icon_view->priv->selection_mode = GTK_SELECTION_SINGLE;
1076 icon_view->priv->pressed_button = -1;
1077 icon_view->priv->press_start_x = -1;
1078 icon_view->priv->press_start_y = -1;
1079 icon_view->priv->text_column = -1;
1080 icon_view->priv->markup_column = -1;
1081 icon_view->priv->pixbuf_column = -1;
1082 icon_view->priv->text_cell = NULL;
1083 icon_view->priv->pixbuf_cell = NULL;
1084 icon_view->priv->tooltip_column = -1;
1086 gtk_widget_set_can_focus (GTK_WIDGET (icon_view), TRUE);
1088 icon_view->priv->item_orientation = GTK_ORIENTATION_VERTICAL;
1090 icon_view->priv->columns = -1;
1091 icon_view->priv->item_width = -1;
1092 icon_view->priv->spacing = 0;
1093 icon_view->priv->row_spacing = 6;
1094 icon_view->priv->column_spacing = 6;
1095 icon_view->priv->margin = 6;
1096 icon_view->priv->item_padding = 6;
1098 icon_view->priv->draw_focus = TRUE;
1100 icon_view->priv->row_contexts =
1101 g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
1104 /* GObject methods */
1106 gtk_icon_view_constructor (GType type,
1107 guint n_construct_properties,
1108 GObjectConstructParam *construct_properties)
1110 GtkIconView *icon_view;
1113 object = G_OBJECT_CLASS (gtk_icon_view_parent_class)->constructor
1114 (type, n_construct_properties, construct_properties);
1116 icon_view = (GtkIconView *) object;
1118 gtk_icon_view_ensure_cell_area (icon_view, NULL);
1124 gtk_icon_view_dispose (GObject *object)
1126 GtkIconView *icon_view;
1127 GtkIconViewPrivate *priv;
1129 icon_view = GTK_ICON_VIEW (object);
1130 priv = icon_view->priv;
1132 if (priv->cell_area_context)
1134 g_signal_handler_disconnect (priv->cell_area_context, priv->context_changed_id);
1135 priv->context_changed_id = 0;
1137 g_object_unref (priv->cell_area_context);
1138 priv->cell_area_context = NULL;
1141 if (priv->row_contexts)
1143 g_ptr_array_free (priv->row_contexts, TRUE);
1144 priv->row_contexts = NULL;
1147 if (priv->cell_area)
1149 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
1151 g_signal_handler_disconnect (priv->cell_area, priv->add_editable_id);
1152 g_signal_handler_disconnect (priv->cell_area, priv->remove_editable_id);
1153 priv->add_editable_id = 0;
1154 priv->remove_editable_id = 0;
1156 g_object_unref (priv->cell_area);
1157 priv->cell_area = NULL;
1160 G_OBJECT_CLASS (gtk_icon_view_parent_class)->dispose (object);
1164 gtk_icon_view_set_property (GObject *object,
1166 const GValue *value,
1169 GtkIconView *icon_view;
1172 icon_view = GTK_ICON_VIEW (object);
1176 case PROP_SELECTION_MODE:
1177 gtk_icon_view_set_selection_mode (icon_view, g_value_get_enum (value));
1179 case PROP_PIXBUF_COLUMN:
1180 gtk_icon_view_set_pixbuf_column (icon_view, g_value_get_int (value));
1182 case PROP_TEXT_COLUMN:
1183 gtk_icon_view_set_text_column (icon_view, g_value_get_int (value));
1185 case PROP_MARKUP_COLUMN:
1186 gtk_icon_view_set_markup_column (icon_view, g_value_get_int (value));
1189 gtk_icon_view_set_model (icon_view, g_value_get_object (value));
1191 case PROP_ITEM_ORIENTATION:
1192 gtk_icon_view_set_item_orientation (icon_view, g_value_get_enum (value));
1195 gtk_icon_view_set_columns (icon_view, g_value_get_int (value));
1197 case PROP_ITEM_WIDTH:
1198 gtk_icon_view_set_item_width (icon_view, g_value_get_int (value));
1201 gtk_icon_view_set_spacing (icon_view, g_value_get_int (value));
1203 case PROP_ROW_SPACING:
1204 gtk_icon_view_set_row_spacing (icon_view, g_value_get_int (value));
1206 case PROP_COLUMN_SPACING:
1207 gtk_icon_view_set_column_spacing (icon_view, g_value_get_int (value));
1210 gtk_icon_view_set_margin (icon_view, g_value_get_int (value));
1212 case PROP_REORDERABLE:
1213 gtk_icon_view_set_reorderable (icon_view, g_value_get_boolean (value));
1216 case PROP_TOOLTIP_COLUMN:
1217 gtk_icon_view_set_tooltip_column (icon_view, g_value_get_int (value));
1220 case PROP_ITEM_PADDING:
1221 gtk_icon_view_set_item_padding (icon_view, g_value_get_int (value));
1224 case PROP_CELL_AREA:
1225 /* Construct-only, can only be assigned once */
1226 area = g_value_get_object (value);
1229 if (icon_view->priv->cell_area != NULL)
1231 g_warning ("cell-area has already been set, ignoring construct property");
1232 g_object_ref_sink (area);
1233 g_object_unref (area);
1236 gtk_icon_view_ensure_cell_area (icon_view, area);
1240 case PROP_HADJUSTMENT:
1241 gtk_icon_view_set_hadjustment (icon_view, g_value_get_object (value));
1243 case PROP_VADJUSTMENT:
1244 gtk_icon_view_set_vadjustment (icon_view, g_value_get_object (value));
1246 case PROP_HSCROLL_POLICY:
1247 icon_view->priv->hscroll_policy = g_value_get_enum (value);
1248 gtk_widget_queue_resize (GTK_WIDGET (icon_view));
1250 case PROP_VSCROLL_POLICY:
1251 icon_view->priv->vscroll_policy = g_value_get_enum (value);
1252 gtk_widget_queue_resize (GTK_WIDGET (icon_view));
1256 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1262 gtk_icon_view_get_property (GObject *object,
1267 GtkIconView *icon_view;
1269 icon_view = GTK_ICON_VIEW (object);
1273 case PROP_SELECTION_MODE:
1274 g_value_set_enum (value, icon_view->priv->selection_mode);
1276 case PROP_PIXBUF_COLUMN:
1277 g_value_set_int (value, icon_view->priv->pixbuf_column);
1279 case PROP_TEXT_COLUMN:
1280 g_value_set_int (value, icon_view->priv->text_column);
1282 case PROP_MARKUP_COLUMN:
1283 g_value_set_int (value, icon_view->priv->markup_column);
1286 g_value_set_object (value, icon_view->priv->model);
1288 case PROP_ITEM_ORIENTATION:
1289 g_value_set_enum (value, icon_view->priv->item_orientation);
1292 g_value_set_int (value, icon_view->priv->columns);
1294 case PROP_ITEM_WIDTH:
1295 g_value_set_int (value, icon_view->priv->item_width);
1298 g_value_set_int (value, icon_view->priv->spacing);
1300 case PROP_ROW_SPACING:
1301 g_value_set_int (value, icon_view->priv->row_spacing);
1303 case PROP_COLUMN_SPACING:
1304 g_value_set_int (value, icon_view->priv->column_spacing);
1307 g_value_set_int (value, icon_view->priv->margin);
1309 case PROP_REORDERABLE:
1310 g_value_set_boolean (value, icon_view->priv->reorderable);
1312 case PROP_TOOLTIP_COLUMN:
1313 g_value_set_int (value, icon_view->priv->tooltip_column);
1316 case PROP_ITEM_PADDING:
1317 g_value_set_int (value, icon_view->priv->item_padding);
1320 case PROP_CELL_AREA:
1321 g_value_set_object (value, icon_view->priv->cell_area);
1324 case PROP_HADJUSTMENT:
1325 g_value_set_object (value, icon_view->priv->hadjustment);
1327 case PROP_VADJUSTMENT:
1328 g_value_set_object (value, icon_view->priv->vadjustment);
1330 case PROP_HSCROLL_POLICY:
1331 g_value_set_enum (value, icon_view->priv->hscroll_policy);
1333 case PROP_VSCROLL_POLICY:
1334 g_value_set_enum (value, icon_view->priv->vscroll_policy);
1338 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1343 /* GtkWidget methods */
1345 gtk_icon_view_destroy (GtkWidget *widget)
1347 GtkIconView *icon_view = GTK_ICON_VIEW (widget);
1349 gtk_icon_view_set_model (icon_view, NULL);
1351 if (icon_view->priv->layout_idle_id != 0)
1353 g_source_remove (icon_view->priv->layout_idle_id);
1354 icon_view->priv->layout_idle_id = 0;
1357 if (icon_view->priv->scroll_to_path != NULL)
1359 gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
1360 icon_view->priv->scroll_to_path = NULL;
1363 remove_scroll_timeout (icon_view);
1365 if (icon_view->priv->hadjustment != NULL)
1367 g_object_unref (icon_view->priv->hadjustment);
1368 icon_view->priv->hadjustment = NULL;
1371 if (icon_view->priv->vadjustment != NULL)
1373 g_object_unref (icon_view->priv->vadjustment);
1374 icon_view->priv->vadjustment = NULL;
1377 GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->destroy (widget);
1381 gtk_icon_view_realize (GtkWidget *widget)
1383 GtkIconView *icon_view = GTK_ICON_VIEW (widget);
1384 GtkAllocation allocation;
1386 GdkWindowAttr attributes;
1387 gint attributes_mask;
1388 GtkStyleContext *context;
1390 gtk_widget_set_realized (widget, TRUE);
1392 gtk_widget_get_allocation (widget, &allocation);
1394 /* Make the main, clipping window */
1395 attributes.window_type = GDK_WINDOW_CHILD;
1396 attributes.x = allocation.x;
1397 attributes.y = allocation.y;
1398 attributes.width = allocation.width;
1399 attributes.height = allocation.height;
1400 attributes.wclass = GDK_INPUT_OUTPUT;
1401 attributes.visual = gtk_widget_get_visual (widget);
1402 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1404 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
1406 window = gdk_window_new (gtk_widget_get_parent_window (widget),
1407 &attributes, attributes_mask);
1408 gtk_widget_set_window (widget, window);
1409 gdk_window_set_user_data (window, widget);
1411 gtk_widget_get_allocation (widget, &allocation);
1413 /* Make the window for the icon view */
1416 attributes.width = MAX (icon_view->priv->width, allocation.width);
1417 attributes.height = MAX (icon_view->priv->height, allocation.height);
1418 attributes.event_mask = (GDK_EXPOSURE_MASK |
1420 GDK_POINTER_MOTION_MASK |
1421 GDK_BUTTON_PRESS_MASK |
1422 GDK_BUTTON_RELEASE_MASK |
1423 GDK_KEY_PRESS_MASK |
1424 GDK_KEY_RELEASE_MASK) |
1425 gtk_widget_get_events (widget);
1427 icon_view->priv->bin_window = gdk_window_new (window,
1428 &attributes, attributes_mask);
1429 gdk_window_set_user_data (icon_view->priv->bin_window, widget);
1431 context = gtk_widget_get_style_context (widget);
1433 gtk_style_context_save (context);
1434 gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
1435 gtk_style_context_set_background (context, icon_view->priv->bin_window);
1436 gtk_style_context_restore (context);
1438 gdk_window_show (icon_view->priv->bin_window);
1442 gtk_icon_view_unrealize (GtkWidget *widget)
1444 GtkIconView *icon_view;
1446 icon_view = GTK_ICON_VIEW (widget);
1448 gdk_window_set_user_data (icon_view->priv->bin_window, NULL);
1449 gdk_window_destroy (icon_view->priv->bin_window);
1450 icon_view->priv->bin_window = NULL;
1452 GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->unrealize (widget);
1456 _gtk_icon_view_update_background (GtkIconView *icon_view)
1458 GtkWidget *widget = GTK_WIDGET (icon_view);
1460 if (gtk_widget_get_realized (widget))
1462 GtkStyleContext *context;
1464 context = gtk_widget_get_style_context (widget);
1466 gtk_style_context_save (context);
1467 gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
1469 gtk_style_context_set_background (context, gtk_widget_get_window (widget));
1470 gtk_style_context_set_background (context, icon_view->priv->bin_window);
1472 gtk_style_context_restore (context);
1477 gtk_icon_view_state_flags_changed (GtkWidget *widget,
1478 GtkStateFlags previous_state)
1480 _gtk_icon_view_update_background (GTK_ICON_VIEW (widget));
1481 gtk_widget_queue_draw (widget);
1485 gtk_icon_view_style_updated (GtkWidget *widget)
1487 GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->style_updated (widget);
1489 _gtk_icon_view_update_background (GTK_ICON_VIEW (widget));
1490 gtk_widget_queue_resize (widget);
1494 gtk_icon_view_get_preferred_width (GtkWidget *widget,
1498 *minimum = *natural = GTK_ICON_VIEW (widget)->priv->width;
1502 gtk_icon_view_get_preferred_height (GtkWidget *widget,
1506 *minimum = *natural = GTK_ICON_VIEW (widget)->priv->height;
1510 gtk_icon_view_allocate_children (GtkIconView *icon_view)
1514 for (list = icon_view->priv->children; list; list = list->next)
1516 GtkIconViewChild *child = list->data;
1518 /* totally ignore our child's requisition */
1519 gtk_widget_size_allocate (child->widget, &child->area);
1524 gtk_icon_view_size_allocate (GtkWidget *widget,
1525 GtkAllocation *allocation)
1527 GtkIconView *icon_view = GTK_ICON_VIEW (widget);
1529 gtk_widget_set_allocation (widget, allocation);
1531 if (gtk_widget_get_realized (widget))
1533 gdk_window_move_resize (gtk_widget_get_window (widget),
1534 allocation->x, allocation->y,
1535 allocation->width, allocation->height);
1536 gdk_window_resize (icon_view->priv->bin_window,
1537 MAX (icon_view->priv->width, allocation->width),
1538 MAX (icon_view->priv->height, allocation->height));
1541 gtk_icon_view_layout (icon_view);
1543 gtk_icon_view_allocate_children (icon_view);
1545 /* Delay signal emission */
1546 g_object_freeze_notify (G_OBJECT (icon_view->priv->hadjustment));
1547 g_object_freeze_notify (G_OBJECT (icon_view->priv->vadjustment));
1549 gtk_icon_view_set_hadjustment_values (icon_view);
1550 gtk_icon_view_set_vadjustment_values (icon_view);
1552 if (gtk_widget_get_realized (widget) &&
1553 icon_view->priv->scroll_to_path)
1556 path = gtk_tree_row_reference_get_path (icon_view->priv->scroll_to_path);
1557 gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
1558 icon_view->priv->scroll_to_path = NULL;
1560 gtk_icon_view_scroll_to_path (icon_view, path,
1561 icon_view->priv->scroll_to_use_align,
1562 icon_view->priv->scroll_to_row_align,
1563 icon_view->priv->scroll_to_col_align);
1564 gtk_tree_path_free (path);
1567 /* Emit any pending signals now */
1568 g_object_thaw_notify (G_OBJECT (icon_view->priv->hadjustment));
1569 g_object_thaw_notify (G_OBJECT (icon_view->priv->vadjustment));
1573 gtk_icon_view_draw (GtkWidget *widget,
1576 GtkIconView *icon_view;
1580 GtkIconViewDropPosition dest_pos;
1581 GtkIconViewItem *dest_item = NULL;
1583 icon_view = GTK_ICON_VIEW (widget);
1585 if (!gtk_cairo_should_draw_window (cr, icon_view->priv->bin_window))
1590 gtk_cairo_transform_to_window (cr, widget, icon_view->priv->bin_window);
1592 cairo_set_line_width (cr, 1.);
1594 gtk_icon_view_get_drag_dest_item (icon_view, &path, &dest_pos);
1598 dest_index = gtk_tree_path_get_indices (path)[0];
1599 gtk_tree_path_free (path);
1604 for (icons = icon_view->priv->items; icons; icons = icons->next)
1606 GtkIconViewItem *item = icons->data;
1607 GdkRectangle paint_area;
1609 paint_area.x = ((GdkRectangle *)item)->x - icon_view->priv->item_padding;
1610 paint_area.y = ((GdkRectangle *)item)->y - icon_view->priv->item_padding;
1611 paint_area.width = ((GdkRectangle *)item)->width + icon_view->priv->item_padding * 2;
1612 paint_area.height = ((GdkRectangle *)item)->height + icon_view->priv->item_padding * 2;
1616 cairo_rectangle (cr, paint_area.x, paint_area.y, paint_area.width, paint_area.height);
1619 if (gdk_cairo_get_clip_rectangle (cr, NULL))
1621 gtk_icon_view_paint_item (icon_view, cr, item,
1622 ((GdkRectangle *)item)->x, ((GdkRectangle *)item)->y,
1623 icon_view->priv->draw_focus);
1625 if (dest_index == item->index)
1633 dest_pos != GTK_ICON_VIEW_NO_DROP)
1635 GtkStyleContext *context;
1636 GtkStateFlags state;
1637 GdkRectangle rect = { 0 };
1639 context = gtk_widget_get_style_context (widget);
1640 state = gtk_widget_get_state_flags (widget);
1644 case GTK_ICON_VIEW_DROP_INTO:
1645 rect = dest_item->cell_area;
1647 case GTK_ICON_VIEW_DROP_ABOVE:
1648 rect.x = dest_item->cell_area.x;
1649 rect.y = dest_item->cell_area.y - 1;
1650 rect.width = dest_item->cell_area.width;
1653 case GTK_ICON_VIEW_DROP_LEFT:
1654 rect.x = dest_item->cell_area.x - 1;
1655 rect.y = dest_item->cell_area.y;
1657 rect.height = dest_item->cell_area.height;
1659 case GTK_ICON_VIEW_DROP_BELOW:
1660 rect.x = dest_item->cell_area.x;
1661 rect.y = dest_item->cell_area.y + dest_item->cell_area.height - 1;
1662 rect.width = dest_item->cell_area.width;
1665 case GTK_ICON_VIEW_DROP_RIGHT:
1666 rect.x = dest_item->cell_area.x + dest_item->cell_area.width - 1;
1667 rect.y = dest_item->cell_area.y;
1669 rect.height = dest_item->cell_area.height;
1670 case GTK_ICON_VIEW_NO_DROP: ;
1674 gtk_style_context_set_state (context, state);
1675 gtk_render_focus (context, cr,
1677 rect.width, rect.height);
1680 if (icon_view->priv->doing_rubberband)
1681 gtk_icon_view_paint_rubberband (icon_view, cr);
1685 GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->draw (widget, cr);
1691 rubberband_scroll_timeout (gpointer data)
1693 GtkIconView *icon_view = data;
1695 gtk_adjustment_set_value (icon_view->priv->vadjustment,
1696 gtk_adjustment_get_value (icon_view->priv->vadjustment) +
1697 icon_view->priv->scroll_value_diff);
1699 gtk_icon_view_update_rubberband (icon_view);
1705 gtk_icon_view_motion (GtkWidget *widget,
1706 GdkEventMotion *event)
1708 GtkAllocation allocation;
1709 GtkIconView *icon_view;
1712 icon_view = GTK_ICON_VIEW (widget);
1714 gtk_icon_view_maybe_begin_drag (icon_view, event);
1716 if (icon_view->priv->doing_rubberband)
1718 gtk_icon_view_update_rubberband (widget);
1720 abs_y = event->y - icon_view->priv->height *
1721 (gtk_adjustment_get_value (icon_view->priv->vadjustment) /
1722 (gtk_adjustment_get_upper (icon_view->priv->vadjustment) -
1723 gtk_adjustment_get_lower (icon_view->priv->vadjustment)));
1725 gtk_widget_get_allocation (widget, &allocation);
1727 if (abs_y < 0 || abs_y > allocation.height)
1730 icon_view->priv->scroll_value_diff = abs_y;
1732 icon_view->priv->scroll_value_diff = abs_y - allocation.height;
1734 icon_view->priv->event_last_x = event->x;
1735 icon_view->priv->event_last_y = event->y;
1737 if (icon_view->priv->scroll_timeout_id == 0)
1738 icon_view->priv->scroll_timeout_id = gdk_threads_add_timeout (30, rubberband_scroll_timeout,
1742 remove_scroll_timeout (icon_view);
1749 gtk_icon_view_remove (GtkContainer *container,
1752 GtkIconView *icon_view;
1753 GtkIconViewChild *child = NULL;
1756 icon_view = GTK_ICON_VIEW (container);
1758 tmp_list = icon_view->priv->children;
1761 child = tmp_list->data;
1762 if (child->widget == widget)
1764 gtk_widget_unparent (widget);
1766 icon_view->priv->children = g_list_remove_link (icon_view->priv->children, tmp_list);
1767 g_list_free_1 (tmp_list);
1772 tmp_list = tmp_list->next;
1777 gtk_icon_view_forall (GtkContainer *container,
1778 gboolean include_internals,
1779 GtkCallback callback,
1780 gpointer callback_data)
1782 GtkIconView *icon_view;
1783 GtkIconViewChild *child = NULL;
1786 icon_view = GTK_ICON_VIEW (container);
1788 tmp_list = icon_view->priv->children;
1791 child = tmp_list->data;
1792 tmp_list = tmp_list->next;
1794 (* callback) (child->widget, callback_data);
1799 gtk_icon_view_item_selected_changed (GtkIconView *icon_view,
1800 GtkIconViewItem *item)
1803 AtkObject *item_obj;
1805 obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
1808 item_obj = atk_object_ref_accessible_child (obj, item->index);
1809 if (item_obj != NULL)
1811 atk_object_notify_state_change (item_obj, ATK_STATE_SELECTED, item->selected);
1812 g_object_unref (item_obj);
1818 gtk_icon_view_add_editable (GtkCellArea *area,
1819 GtkCellRenderer *renderer,
1820 GtkCellEditable *editable,
1821 GdkRectangle *cell_area,
1823 GtkIconView *icon_view)
1825 GtkIconViewChild *child;
1826 GtkWidget *widget = GTK_WIDGET (editable);
1828 child = g_new (GtkIconViewChild, 1);
1830 child->widget = widget;
1831 child->area.x = cell_area->x;
1832 child->area.y = cell_area->y;
1833 child->area.width = cell_area->width;
1834 child->area.height = cell_area->height;
1836 icon_view->priv->children = g_list_append (icon_view->priv->children, child);
1838 if (gtk_widget_get_realized (GTK_WIDGET (icon_view)))
1839 gtk_widget_set_parent_window (child->widget, icon_view->priv->bin_window);
1841 gtk_widget_set_parent (widget, GTK_WIDGET (icon_view));
1845 gtk_icon_view_remove_editable (GtkCellArea *area,
1846 GtkCellRenderer *renderer,
1847 GtkCellEditable *editable,
1848 GtkIconView *icon_view)
1852 if (gtk_widget_has_focus (GTK_WIDGET (editable)))
1853 gtk_widget_grab_focus (GTK_WIDGET (icon_view));
1855 gtk_container_remove (GTK_CONTAINER (icon_view),
1856 GTK_WIDGET (editable));
1858 path = gtk_tree_path_new_from_string (gtk_cell_area_get_current_path_string (area));
1859 gtk_icon_view_queue_draw_path (icon_view, path);
1860 gtk_tree_path_free (path);
1864 gtk_icon_view_context_changed (GtkCellAreaContext *context,
1866 GtkIconView *icon_view)
1868 if (!strcmp (pspec->name, "minimum-width") ||
1869 !strcmp (pspec->name, "natural-width") ||
1870 !strcmp (pspec->name, "minimum-height") ||
1871 !strcmp (pspec->name, "natural-height"))
1872 gtk_icon_view_invalidate_sizes (icon_view);
1876 * gtk_icon_view_set_cursor:
1877 * @icon_view: A #GtkIconView
1878 * @path: A #GtkTreePath
1879 * @cell: (allow-none): One of the cell renderers of @icon_view, or %NULL
1880 * @start_editing: %TRUE if the specified cell should start being edited.
1882 * Sets the current keyboard focus to be at @path, and selects it. This is
1883 * useful when you want to focus the user's attention on a particular item.
1884 * If @cell is not %NULL, then focus is given to the cell specified by
1885 * it. Additionally, if @start_editing is %TRUE, then editing should be
1886 * started in the specified cell.
1888 * This function is often followed by <literal>gtk_widget_grab_focus
1889 * (icon_view)</literal> in order to give keyboard focus to the widget.
1890 * Please note that editing can only happen when the widget is realized.
1895 gtk_icon_view_set_cursor (GtkIconView *icon_view,
1897 GtkCellRenderer *cell,
1898 gboolean start_editing)
1900 GtkIconViewItem *item = NULL;
1902 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
1903 g_return_if_fail (path != NULL);
1904 g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
1906 if (icon_view->priv->cell_area)
1907 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
1909 if (gtk_tree_path_get_depth (path) == 1)
1910 item = g_list_nth_data (icon_view->priv->items,
1911 gtk_tree_path_get_indices(path)[0]);
1916 gtk_icon_view_set_cursor_item (icon_view, item, cell);
1917 gtk_icon_view_scroll_to_path (icon_view, path, FALSE, 0.0, 0.0);
1919 if (start_editing &&
1920 icon_view->priv->cell_area)
1922 GtkCellAreaContext *context;
1924 context = g_ptr_array_index (icon_view->priv->row_contexts, item->row);
1925 gtk_icon_view_set_cell_data (icon_view, item);
1926 gtk_cell_area_activate (icon_view->priv->cell_area, context,
1927 GTK_WIDGET (icon_view), (GdkRectangle *)item,
1928 0 /* XXX flags */, TRUE);
1933 * gtk_icon_view_get_cursor:
1934 * @icon_view: A #GtkIconView
1935 * @path: (out) (allow-none): Return location for the current cursor path,
1937 * @cell: (out) (allow-none): Return location the current focus cell, or %NULL
1939 * Fills in @path and @cell with the current cursor path and cell.
1940 * If the cursor isn't currently set, then *@path will be %NULL.
1941 * If no cell currently has focus, then *@cell will be %NULL.
1943 * The returned #GtkTreePath must be freed with gtk_tree_path_free().
1945 * Return value: %TRUE if the cursor is set.
1950 gtk_icon_view_get_cursor (GtkIconView *icon_view,
1952 GtkCellRenderer **cell)
1954 GtkIconViewItem *item;
1956 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
1958 item = icon_view->priv->cursor_item;
1963 *path = gtk_tree_path_new_from_indices (item->index, -1);
1968 if (cell != NULL && item != NULL && icon_view->priv->cell_area != NULL)
1969 *cell = gtk_cell_area_get_focus_cell (icon_view->priv->cell_area);
1971 return (item != NULL);
1975 gtk_icon_view_button_press (GtkWidget *widget,
1976 GdkEventButton *event)
1978 GtkIconView *icon_view;
1979 GtkIconViewItem *item;
1980 gboolean dirty = FALSE;
1981 GtkCellRenderer *cell = NULL, *cursor_cell = NULL;
1983 icon_view = GTK_ICON_VIEW (widget);
1985 if (event->window != icon_view->priv->bin_window)
1988 if (!gtk_widget_has_focus (widget))
1989 gtk_widget_grab_focus (widget);
1991 if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
1993 item = gtk_icon_view_get_item_at_coords (icon_view,
1999 * We consider only the the cells' area as the item area if the
2000 * item is not selected, but if it *is* selected, the complete
2001 * selection rectangle is considered to be part of the item.
2003 if (item != NULL && (cell != NULL || item->selected))
2007 if (gtk_cell_renderer_is_activatable (cell))
2011 gtk_icon_view_scroll_to_item (icon_view, item);
2013 if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
2015 gtk_icon_view_set_cursor_item (icon_view, item, cursor_cell);
2017 else if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE &&
2018 (event->state & GDK_SHIFT_MASK))
2020 gtk_icon_view_unselect_all_internal (icon_view);
2022 gtk_icon_view_set_cursor_item (icon_view, item, cursor_cell);
2023 if (!icon_view->priv->anchor_item)
2024 icon_view->priv->anchor_item = item;
2026 gtk_icon_view_select_all_between (icon_view,
2027 icon_view->priv->anchor_item,
2033 if ((icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE ||
2034 ((icon_view->priv->selection_mode == GTK_SELECTION_SINGLE) && item->selected)) &&
2035 (event->state & GDK_CONTROL_MASK))
2037 item->selected = !item->selected;
2038 gtk_icon_view_queue_draw_item (icon_view, item);
2043 gtk_icon_view_unselect_all_internal (icon_view);
2045 item->selected = TRUE;
2046 gtk_icon_view_queue_draw_item (icon_view, item);
2049 gtk_icon_view_set_cursor_item (icon_view, item, cursor_cell);
2050 icon_view->priv->anchor_item = item;
2053 /* Save press to possibly begin a drag */
2054 if (icon_view->priv->pressed_button < 0)
2056 icon_view->priv->pressed_button = event->button;
2057 icon_view->priv->press_start_x = event->x;
2058 icon_view->priv->press_start_y = event->y;
2061 if (!icon_view->priv->last_single_clicked)
2062 icon_view->priv->last_single_clicked = item;
2064 /* cancel the current editing, if it exists */
2065 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
2067 if (cell != NULL && gtk_cell_renderer_is_activatable (cell))
2069 GtkCellAreaContext *context;
2071 context = g_ptr_array_index (icon_view->priv->row_contexts, item->row);
2073 gtk_icon_view_set_cell_data (icon_view, item);
2074 gtk_cell_area_activate (icon_view->priv->cell_area, context,
2075 GTK_WIDGET (icon_view),
2076 (GdkRectangle *)item, 0/* XXX flags */, FALSE);
2081 if (icon_view->priv->selection_mode != GTK_SELECTION_BROWSE &&
2082 !(event->state & GDK_CONTROL_MASK))
2084 dirty = gtk_icon_view_unselect_all_internal (icon_view);
2087 if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE)
2088 gtk_icon_view_start_rubberbanding (icon_view, event->device, event->x, event->y);
2091 /* don't draw keyboard focus around an clicked-on item */
2092 icon_view->priv->draw_focus = FALSE;
2095 if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
2097 item = gtk_icon_view_get_item_at_coords (icon_view,
2102 if (item && item == icon_view->priv->last_single_clicked)
2106 path = gtk_tree_path_new_from_indices (item->index, -1);
2107 gtk_icon_view_item_activated (icon_view, path);
2108 gtk_tree_path_free (path);
2111 icon_view->priv->last_single_clicked = NULL;
2112 icon_view->priv->pressed_button = -1;
2116 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2118 return event->button == 1;
2122 gtk_icon_view_button_release (GtkWidget *widget,
2123 GdkEventButton *event)
2125 GtkIconView *icon_view;
2127 icon_view = GTK_ICON_VIEW (widget);
2129 if (icon_view->priv->pressed_button == event->button)
2130 icon_view->priv->pressed_button = -1;
2132 gtk_icon_view_stop_rubberbanding (icon_view);
2134 remove_scroll_timeout (icon_view);
2140 gtk_icon_view_key_press (GtkWidget *widget,
2143 GtkIconView *icon_view = GTK_ICON_VIEW (widget);
2145 if (icon_view->priv->doing_rubberband)
2147 if (event->keyval == GDK_KEY_Escape)
2148 gtk_icon_view_stop_rubberbanding (icon_view);
2153 return GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->key_press_event (widget, event);
2157 gtk_icon_view_key_release (GtkWidget *widget,
2160 GtkIconView *icon_view = GTK_ICON_VIEW (widget);
2162 if (icon_view->priv->doing_rubberband)
2165 return GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->key_press_event (widget, event);
2169 gtk_icon_view_update_rubberband (gpointer data)
2171 GtkIconView *icon_view;
2173 GdkRectangle old_area;
2174 GdkRectangle new_area;
2175 GdkRectangle common;
2176 cairo_region_t *invalid_region;
2178 icon_view = GTK_ICON_VIEW (data);
2180 gdk_window_get_device_position (icon_view->priv->bin_window,
2181 icon_view->priv->rubberband_device,
2187 old_area.x = MIN (icon_view->priv->rubberband_x1,
2188 icon_view->priv->rubberband_x2);
2189 old_area.y = MIN (icon_view->priv->rubberband_y1,
2190 icon_view->priv->rubberband_y2);
2191 old_area.width = ABS (icon_view->priv->rubberband_x2 -
2192 icon_view->priv->rubberband_x1) + 1;
2193 old_area.height = ABS (icon_view->priv->rubberband_y2 -
2194 icon_view->priv->rubberband_y1) + 1;
2196 new_area.x = MIN (icon_view->priv->rubberband_x1, x);
2197 new_area.y = MIN (icon_view->priv->rubberband_y1, y);
2198 new_area.width = ABS (x - icon_view->priv->rubberband_x1) + 1;
2199 new_area.height = ABS (y - icon_view->priv->rubberband_y1) + 1;
2201 invalid_region = cairo_region_create_rectangle (&old_area);
2202 cairo_region_union_rectangle (invalid_region, &new_area);
2204 gdk_rectangle_intersect (&old_area, &new_area, &common);
2205 if (common.width > 2 && common.height > 2)
2207 cairo_region_t *common_region;
2209 /* make sure the border is invalidated */
2215 common_region = cairo_region_create_rectangle (&common);
2217 cairo_region_subtract (invalid_region, common_region);
2218 cairo_region_destroy (common_region);
2221 gdk_window_invalidate_region (icon_view->priv->bin_window, invalid_region, TRUE);
2223 cairo_region_destroy (invalid_region);
2225 icon_view->priv->rubberband_x2 = x;
2226 icon_view->priv->rubberband_y2 = y;
2228 gtk_icon_view_update_rubberband_selection (icon_view);
2232 gtk_icon_view_start_rubberbanding (GtkIconView *icon_view,
2239 if (icon_view->priv->rubberband_device)
2242 for (items = icon_view->priv->items; items; items = items->next)
2244 GtkIconViewItem *item = items->data;
2246 item->selected_before_rubberbanding = item->selected;
2249 icon_view->priv->rubberband_x1 = x;
2250 icon_view->priv->rubberband_y1 = y;
2251 icon_view->priv->rubberband_x2 = x;
2252 icon_view->priv->rubberband_y2 = y;
2254 icon_view->priv->doing_rubberband = TRUE;
2255 icon_view->priv->rubberband_device = device;
2257 gtk_device_grab_add (GTK_WIDGET (icon_view), device, TRUE);
2261 gtk_icon_view_stop_rubberbanding (GtkIconView *icon_view)
2263 if (!icon_view->priv->doing_rubberband)
2266 gtk_device_grab_remove (GTK_WIDGET (icon_view),
2267 icon_view->priv->rubberband_device);
2269 icon_view->priv->doing_rubberband = FALSE;
2270 icon_view->priv->rubberband_device = NULL;
2272 gtk_widget_queue_draw (GTK_WIDGET (icon_view));
2276 gtk_icon_view_update_rubberband_selection (GtkIconView *icon_view)
2279 gint x, y, width, height;
2280 gboolean dirty = FALSE;
2282 x = MIN (icon_view->priv->rubberband_x1,
2283 icon_view->priv->rubberband_x2);
2284 y = MIN (icon_view->priv->rubberband_y1,
2285 icon_view->priv->rubberband_y2);
2286 width = ABS (icon_view->priv->rubberband_x1 -
2287 icon_view->priv->rubberband_x2);
2288 height = ABS (icon_view->priv->rubberband_y1 -
2289 icon_view->priv->rubberband_y2);
2291 for (items = icon_view->priv->items; items; items = items->next)
2293 GtkIconViewItem *item = items->data;
2297 is_in = gtk_icon_view_item_hit_test (icon_view, item,
2298 x, y, width, height);
2300 selected = is_in ^ item->selected_before_rubberbanding;
2302 if (item->selected != selected)
2304 item->selected = selected;
2306 gtk_icon_view_queue_draw_item (icon_view, item);
2311 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2316 GdkRectangle hit_rect;
2321 hit_test (GtkCellRenderer *renderer,
2322 const GdkRectangle *cell_area,
2323 const GdkRectangle *cell_background,
2326 if (MIN (data->hit_rect.x + data->hit_rect.width, cell_area->x + cell_area->width) -
2327 MAX (data->hit_rect.x, cell_area->x) > 0 &&
2328 MIN (data->hit_rect.y + data->hit_rect.height, cell_area->y + cell_area->height) -
2329 MAX (data->hit_rect.y, cell_area->y) > 0)
2332 return (data->hit != FALSE);
2336 gtk_icon_view_item_hit_test (GtkIconView *icon_view,
2337 GtkIconViewItem *item,
2343 HitTestData data = { { x, y, width, height }, FALSE };
2344 GtkCellAreaContext *context;
2345 GdkRectangle *item_area = (GdkRectangle *)item;
2347 if (MIN (x + width, item_area->x + item_area->width) - MAX (x, item_area->x) <= 0 ||
2348 MIN (y + height, item_area->y + item_area->height) - MAX (y, item_area->y) <= 0)
2351 context = g_ptr_array_index (icon_view->priv->row_contexts, item->row);
2353 gtk_icon_view_set_cell_data (icon_view, item);
2354 gtk_cell_area_foreach_alloc (icon_view->priv->cell_area, context,
2355 GTK_WIDGET (icon_view),
2356 item_area, item_area,
2357 (GtkCellAllocCallback)hit_test, &data);
2363 gtk_icon_view_unselect_all_internal (GtkIconView *icon_view)
2365 gboolean dirty = FALSE;
2368 if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
2371 for (items = icon_view->priv->items; items; items = items->next)
2373 GtkIconViewItem *item = items->data;
2377 item->selected = FALSE;
2379 gtk_icon_view_queue_draw_item (icon_view, item);
2380 gtk_icon_view_item_selected_changed (icon_view, item);
2388 /* GtkIconView signals */
2390 gtk_icon_view_real_select_all (GtkIconView *icon_view)
2392 gtk_icon_view_select_all (icon_view);
2396 gtk_icon_view_real_unselect_all (GtkIconView *icon_view)
2398 gtk_icon_view_unselect_all (icon_view);
2402 gtk_icon_view_real_select_cursor_item (GtkIconView *icon_view)
2404 gtk_icon_view_unselect_all (icon_view);
2406 if (icon_view->priv->cursor_item != NULL)
2407 gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
2411 gtk_icon_view_real_activate_cursor_item (GtkIconView *icon_view)
2414 GtkCellAreaContext *context;
2416 if (!icon_view->priv->cursor_item)
2419 context = g_ptr_array_index (icon_view->priv->row_contexts, icon_view->priv->cursor_item->row);
2421 gtk_icon_view_set_cell_data (icon_view, icon_view->priv->cursor_item);
2422 gtk_cell_area_activate (icon_view->priv->cell_area, context,
2423 GTK_WIDGET (icon_view),
2424 (GdkRectangle *)icon_view->priv->cursor_item,
2428 path = gtk_tree_path_new_from_indices (icon_view->priv->cursor_item->index, -1);
2429 gtk_icon_view_item_activated (icon_view, path);
2430 gtk_tree_path_free (path);
2436 gtk_icon_view_real_toggle_cursor_item (GtkIconView *icon_view)
2438 if (!icon_view->priv->cursor_item)
2441 switch (icon_view->priv->selection_mode)
2443 case GTK_SELECTION_NONE:
2445 case GTK_SELECTION_BROWSE:
2446 gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
2448 case GTK_SELECTION_SINGLE:
2449 if (icon_view->priv->cursor_item->selected)
2450 gtk_icon_view_unselect_item (icon_view, icon_view->priv->cursor_item);
2452 gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
2454 case GTK_SELECTION_MULTIPLE:
2455 icon_view->priv->cursor_item->selected = !icon_view->priv->cursor_item->selected;
2456 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2458 gtk_icon_view_item_selected_changed (icon_view, icon_view->priv->cursor_item);
2459 gtk_icon_view_queue_draw_item (icon_view, icon_view->priv->cursor_item);
2464 /* Internal functions */
2466 gtk_icon_view_process_updates (GtkIconView *icon_view)
2468 /* Prior to drawing, we check if a layout has been scheduled. If so,
2469 * do it now that all cell view items have valid sizes before we proceeed
2470 * (and resize the bin_window if required).
2472 if (icon_view->priv->layout_idle_id != 0)
2473 gtk_icon_view_layout (icon_view);
2475 gdk_window_process_updates (icon_view->priv->bin_window, TRUE);
2479 gtk_icon_view_set_hadjustment_values (GtkIconView *icon_view)
2481 GtkAllocation allocation;
2482 GtkAdjustment *adj = icon_view->priv->hadjustment;
2483 gdouble old_page_size;
2489 gtk_widget_get_allocation (GTK_WIDGET (icon_view), &allocation);
2491 old_value = gtk_adjustment_get_value (adj);
2492 old_upper = gtk_adjustment_get_upper (adj);
2493 old_page_size = gtk_adjustment_get_page_size (adj);
2494 new_upper = MAX (allocation.width, icon_view->priv->width);
2496 if (gtk_widget_get_direction (GTK_WIDGET (icon_view)) == GTK_TEXT_DIR_RTL)
2498 /* Make sure no scrolling occurs for RTL locales also (if possible) */
2499 /* Quick explanation:
2500 * In LTR locales, leftmost portion of visible rectangle should stay
2501 * fixed, which means left edge of scrollbar thumb should remain fixed
2502 * and thus adjustment's value should stay the same.
2504 * In RTL locales, we want to keep rightmost portion of visible
2505 * rectangle fixed. This means right edge of thumb should remain fixed.
2506 * In this case, upper - value - page_size should remain constant.
2508 new_value = (new_upper - allocation.width) -
2509 (old_upper - old_value - old_page_size);
2510 new_value = CLAMP (new_value, 0, new_upper - allocation.width);
2513 new_value = CLAMP (old_value, 0, new_upper - allocation.width);
2515 gtk_adjustment_configure (adj,
2519 allocation.width * 0.1,
2520 allocation.width * 0.9,
2525 gtk_icon_view_set_vadjustment_values (GtkIconView *icon_view)
2527 GtkAllocation allocation;
2528 GtkAdjustment *adj = icon_view->priv->vadjustment;
2530 gtk_widget_get_allocation (GTK_WIDGET (icon_view), &allocation);
2532 gtk_adjustment_configure (adj,
2533 gtk_adjustment_get_value (adj),
2535 MAX (allocation.height, icon_view->priv->height),
2536 allocation.height * 0.1,
2537 allocation.height * 0.9,
2542 gtk_icon_view_set_hadjustment (GtkIconView *icon_view,
2543 GtkAdjustment *adjustment)
2545 GtkIconViewPrivate *priv = icon_view->priv;
2548 if (adjustment && priv->hadjustment == adjustment)
2551 if (priv->hadjustment != NULL)
2553 g_signal_handlers_disconnect_matched (priv->hadjustment,
2554 G_SIGNAL_MATCH_DATA,
2555 0, 0, NULL, NULL, icon_view);
2556 g_object_unref (priv->hadjustment);
2560 adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
2563 g_signal_connect (adjustment, "value-changed",
2564 G_CALLBACK (gtk_icon_view_adjustment_changed), icon_view);
2565 priv->hadjustment = g_object_ref_sink (adjustment);
2566 gtk_icon_view_set_hadjustment_values (icon_view);
2568 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
2569 gtk_icon_view_accessible_set_adjustment (atk_obj,
2570 GTK_ORIENTATION_HORIZONTAL,
2573 g_object_notify (G_OBJECT (icon_view), "hadjustment");
2577 gtk_icon_view_set_vadjustment (GtkIconView *icon_view,
2578 GtkAdjustment *adjustment)
2580 GtkIconViewPrivate *priv = icon_view->priv;
2583 if (adjustment && priv->vadjustment == adjustment)
2586 if (priv->vadjustment != NULL)
2588 g_signal_handlers_disconnect_matched (priv->vadjustment,
2589 G_SIGNAL_MATCH_DATA,
2590 0, 0, NULL, NULL, icon_view);
2591 g_object_unref (priv->vadjustment);
2595 adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
2598 g_signal_connect (adjustment, "value-changed",
2599 G_CALLBACK (gtk_icon_view_adjustment_changed), icon_view);
2600 priv->vadjustment = g_object_ref_sink (adjustment);
2601 gtk_icon_view_set_vadjustment_values (icon_view);
2603 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
2604 gtk_icon_view_accessible_set_adjustment (atk_obj,
2605 GTK_ORIENTATION_VERTICAL,
2608 g_object_notify (G_OBJECT (icon_view), "vadjustment");
2612 gtk_icon_view_adjustment_changed (GtkAdjustment *adjustment,
2613 GtkIconView *icon_view)
2615 GtkIconViewPrivate *priv = icon_view->priv;
2617 if (gtk_widget_get_realized (GTK_WIDGET (icon_view)))
2619 gdk_window_move (priv->bin_window,
2620 - gtk_adjustment_get_value (priv->hadjustment),
2621 - gtk_adjustment_get_value (priv->vadjustment));
2623 if (icon_view->priv->doing_rubberband)
2624 gtk_icon_view_update_rubberband (GTK_WIDGET (icon_view));
2626 gtk_icon_view_process_updates (icon_view);
2631 gtk_icon_view_layout_single_row (GtkIconView *icon_view,
2636 gint *maximum_width)
2638 GtkAllocation allocation;
2639 GtkCellAreaContext *context;
2640 GtkIconViewPrivate *priv = icon_view->priv;
2641 GtkWidget *widget = GTK_WIDGET (icon_view);
2642 gint x, current_width;
2643 GList *items, *last_item;
2645 gint max_height = 0;
2648 rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2656 current_width += 2 * priv->margin;
2658 gtk_widget_get_allocation (widget, &allocation);
2660 context = gtk_cell_area_copy_context (priv->cell_area, priv->cell_area_context);
2661 g_ptr_array_add (priv->row_contexts, context);
2663 /* In the first loop we iterate horizontally until we hit allocation width
2664 * and collect the aligned height-for-width */
2668 GtkIconViewItem *item = items->data;
2669 GdkRectangle *item_area = (GdkRectangle *)item;
2671 item_area->width = item_width;
2673 current_width += item_area->width + icon_view->priv->item_padding * 2;
2675 if (items != first_item)
2677 if ((icon_view->priv->columns <= 0 && current_width > allocation.width) ||
2678 (icon_view->priv->columns > 0 && col >= icon_view->priv->columns))
2682 /* Get this item's particular width & height (all alignments are cached by now) */
2683 gtk_icon_view_set_cell_data (icon_view, item);
2684 gtk_cell_area_get_preferred_height_for_width (priv->cell_area,
2689 current_width += icon_view->priv->column_spacing;
2691 item_area->y = *y + icon_view->priv->item_padding;
2692 item_area->x = x + icon_view->priv->item_padding;
2694 x = current_width - icon_view->priv->margin;
2696 if (current_width > *maximum_width)
2697 *maximum_width = current_width;
2703 items = items->next;
2708 gtk_cell_area_context_get_preferred_height_for_width (context, item_width, &max_height, NULL);
2709 gtk_cell_area_context_allocate (context, item_width, max_height);
2711 /* In the second loop the item height has been aligned and derived and
2712 * we just set the height and handle rtl layout */
2713 for (items = first_item; items != last_item; items = items->next)
2715 GtkIconViewItem *item = items->data;
2716 GdkRectangle *item_area = (GdkRectangle *)item;
2720 item_area->x = *maximum_width - item_area->width - item_area->x;
2721 item->col = col - 1 - item->col;
2724 /* All items in the same row get the same height */
2725 item_area->height = max_height;
2728 /* Adjust the new y coordinate. */
2729 *y += max_height + icon_view->priv->row_spacing + icon_view->priv->item_padding * 2;
2735 adjust_wrap_width (GtkIconView *icon_view)
2737 if (icon_view->priv->text_cell)
2739 gint wrap_width = 50;
2741 /* Here we go with the same old guess, try the icon size and set double
2742 * the size of the first icon found in the list, naive but works much
2744 if (icon_view->priv->items && icon_view->priv->pixbuf_cell)
2746 gtk_icon_view_set_cell_data (icon_view, icon_view->priv->items->data);
2747 gtk_cell_renderer_get_preferred_width (icon_view->priv->pixbuf_cell,
2748 GTK_WIDGET (icon_view),
2751 wrap_width = MAX (wrap_width * 2, 50);
2754 g_object_set (icon_view->priv->text_cell, "wrap-width", wrap_width, NULL);
2755 g_object_set (icon_view->priv->text_cell, "width", wrap_width, NULL);
2760 gtk_icon_view_layout (GtkIconView *icon_view)
2762 GtkAllocation allocation;
2765 gint y = 0, maximum_width = 0;
2768 gboolean size_changed = FALSE;
2770 if (icon_view->priv->layout_idle_id != 0)
2772 g_source_remove (icon_view->priv->layout_idle_id);
2773 icon_view->priv->layout_idle_id = 0;
2776 if (icon_view->priv->model == NULL)
2779 widget = GTK_WIDGET (icon_view);
2781 item_width = icon_view->priv->item_width;
2783 /* Update the wrap width for the text cell before going and requesting sizes */
2784 adjust_wrap_width (icon_view);
2786 /* Update the context widths for any invalidated items */
2787 gtk_icon_view_cache_widths (icon_view);
2789 /* Fetch the new item width if needed */
2791 gtk_cell_area_context_get_preferred_width (icon_view->priv->cell_area_context,
2794 gtk_cell_area_context_allocate (icon_view->priv->cell_area_context, item_width, -1);
2796 icons = icon_view->priv->items;
2797 y += icon_view->priv->margin;
2800 /* Clear the per row contexts */
2801 g_ptr_array_set_size (icon_view->priv->row_contexts, 0);
2805 icons = gtk_icon_view_layout_single_row (icon_view, icons,
2807 &y, &maximum_width);
2810 while (icons != NULL);
2812 if (maximum_width != icon_view->priv->width)
2814 icon_view->priv->width = maximum_width;
2815 size_changed = TRUE;
2818 y += icon_view->priv->margin;
2820 if (y != icon_view->priv->height)
2822 icon_view->priv->height = y;
2823 size_changed = TRUE;
2826 gtk_icon_view_set_hadjustment_values (icon_view);
2827 gtk_icon_view_set_vadjustment_values (icon_view);
2830 gtk_widget_queue_resize_no_redraw (widget);
2832 gtk_widget_get_allocation (widget, &allocation);
2833 if (gtk_widget_get_realized (GTK_WIDGET (icon_view)))
2834 gdk_window_resize (icon_view->priv->bin_window,
2835 MAX (icon_view->priv->width, allocation.width),
2836 MAX (icon_view->priv->height, allocation.height));
2838 if (icon_view->priv->scroll_to_path)
2842 path = gtk_tree_row_reference_get_path (icon_view->priv->scroll_to_path);
2843 gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
2844 icon_view->priv->scroll_to_path = NULL;
2846 gtk_icon_view_scroll_to_path (icon_view, path,
2847 icon_view->priv->scroll_to_use_align,
2848 icon_view->priv->scroll_to_row_align,
2849 icon_view->priv->scroll_to_col_align);
2850 gtk_tree_path_free (path);
2853 gtk_widget_queue_draw (widget);
2856 /* This ensures that all widths have been cached in the
2857 * context and we have proper alignments to go on.
2860 gtk_icon_view_cache_widths (GtkIconView *icon_view)
2864 g_signal_handler_block (icon_view->priv->cell_area_context,
2865 icon_view->priv->context_changed_id);
2867 for (items = icon_view->priv->items; items; items = items->next)
2869 GtkIconViewItem *item = items->data;
2871 /* Only fetch the width of items with invalidated sizes */
2872 if (item->cell_area.width < 0)
2874 gtk_icon_view_set_cell_data (icon_view, item);
2875 gtk_cell_area_get_preferred_width (icon_view->priv->cell_area,
2876 icon_view->priv->cell_area_context,
2877 GTK_WIDGET (icon_view), NULL, NULL);
2881 g_signal_handler_unblock (icon_view->priv->cell_area_context,
2882 icon_view->priv->context_changed_id);
2886 gtk_icon_view_invalidate_sizes (GtkIconView *icon_view)
2888 /* Clear all item sizes */
2889 g_list_foreach (icon_view->priv->items,
2890 (GFunc)gtk_icon_view_item_invalidate_size, NULL);
2892 /* Reset the context */
2893 if (icon_view->priv->cell_area_context)
2895 g_signal_handler_block (icon_view->priv->cell_area_context,
2896 icon_view->priv->context_changed_id);
2897 gtk_cell_area_context_reset (icon_view->priv->cell_area_context);
2898 g_signal_handler_unblock (icon_view->priv->cell_area_context,
2899 icon_view->priv->context_changed_id);
2902 /* Re-layout the items */
2903 gtk_icon_view_queue_layout (icon_view);
2907 gtk_icon_view_item_invalidate_size (GtkIconViewItem *item)
2909 item->cell_area.width = -1;
2910 item->cell_area.height = -1;
2914 gtk_icon_view_paint_item (GtkIconView *icon_view,
2916 GtkIconViewItem *item,
2919 gboolean draw_focus)
2921 GdkRectangle cell_area;
2922 GtkStateFlags state = 0;
2923 GtkCellRendererState flags = 0;
2924 GtkStyleContext *style_context;
2925 GtkWidget *widget = GTK_WIDGET (icon_view);
2926 GtkIconViewPrivate *priv = icon_view->priv;
2927 GtkCellAreaContext *context;
2929 if (priv->model == NULL)
2932 gtk_icon_view_set_cell_data (icon_view, item);
2934 style_context = gtk_widget_get_style_context (widget);
2936 gtk_style_context_save (style_context);
2937 gtk_style_context_add_class (style_context, GTK_STYLE_CLASS_VIEW);
2938 gtk_style_context_add_class (style_context, GTK_STYLE_CLASS_CELL);
2942 if (gtk_widget_has_focus (widget) &&
2943 item == icon_view->priv->cursor_item)
2945 state |= GTK_STATE_FLAG_FOCUSED;
2946 flags |= GTK_CELL_RENDERER_FOCUSED;
2949 state |= GTK_STATE_FLAG_SELECTED;
2950 flags |= GTK_CELL_RENDERER_SELECTED;
2952 gtk_style_context_set_state (style_context, state);
2953 gtk_render_background (style_context, cr,
2954 x - icon_view->priv->item_padding,
2955 y - icon_view->priv->item_padding,
2956 item->cell_area.width + icon_view->priv->item_padding * 2,
2957 item->cell_area.height + icon_view->priv->item_padding * 2);
2962 cell_area.width = item->cell_area.width;
2963 cell_area.height = item->cell_area.height;
2965 context = g_ptr_array_index (priv->row_contexts, item->row);
2966 gtk_cell_area_render (priv->cell_area, context,
2967 widget, cr, &cell_area, &cell_area, flags,
2970 gtk_style_context_restore (style_context);
2974 gtk_icon_view_paint_rubberband (GtkIconView *icon_view,
2977 GtkStyleContext *context;
2982 rect.x = MIN (icon_view->priv->rubberband_x1, icon_view->priv->rubberband_x2);
2983 rect.y = MIN (icon_view->priv->rubberband_y1, icon_view->priv->rubberband_y2);
2984 rect.width = ABS (icon_view->priv->rubberband_x1 - icon_view->priv->rubberband_x2) + 1;
2985 rect.height = ABS (icon_view->priv->rubberband_y1 - icon_view->priv->rubberband_y2) + 1;
2987 context = gtk_widget_get_style_context (GTK_WIDGET (icon_view));
2989 gtk_style_context_save (context);
2990 gtk_style_context_add_class (context, GTK_STYLE_CLASS_RUBBERBAND);
2992 gdk_cairo_rectangle (cr, &rect);
2995 gtk_render_background (context, cr,
2997 rect.width, rect.height);
2998 gtk_render_frame (context, cr,
3000 rect.width, rect.height);
3002 gtk_style_context_restore (context);
3007 gtk_icon_view_queue_draw_path (GtkIconView *icon_view,
3013 index = gtk_tree_path_get_indices (path)[0];
3015 for (l = icon_view->priv->items; l; l = l->next)
3017 GtkIconViewItem *item = l->data;
3019 if (item->index == index)
3021 gtk_icon_view_queue_draw_item (icon_view, item);
3028 gtk_icon_view_queue_draw_item (GtkIconView *icon_view,
3029 GtkIconViewItem *item)
3032 GdkRectangle *item_area = (GdkRectangle *)item;
3034 rect.x = item_area->x - icon_view->priv->item_padding;
3035 rect.y = item_area->y - icon_view->priv->item_padding;
3036 rect.width = item_area->width + icon_view->priv->item_padding * 2;
3037 rect.height = item_area->height + icon_view->priv->item_padding * 2;
3039 if (icon_view->priv->bin_window)
3040 gdk_window_invalidate_rect (icon_view->priv->bin_window, &rect, TRUE);
3044 layout_callback (gpointer user_data)
3046 GtkIconView *icon_view;
3048 icon_view = GTK_ICON_VIEW (user_data);
3050 icon_view->priv->layout_idle_id = 0;
3052 gtk_icon_view_layout (icon_view);
3058 gtk_icon_view_queue_layout (GtkIconView *icon_view)
3060 if (icon_view->priv->layout_idle_id != 0)
3063 icon_view->priv->layout_idle_id =
3064 gdk_threads_add_idle_full (GTK_ICON_VIEW_PRIORITY_LAYOUT,
3065 layout_callback, icon_view, NULL);
3069 gtk_icon_view_set_cursor_item (GtkIconView *icon_view,
3070 GtkIconViewItem *item,
3071 GtkCellRenderer *cursor_cell)
3074 AtkObject *item_obj;
3075 AtkObject *cursor_item_obj;
3077 /* When hitting this path from keynav, the focus cell is
3078 * already set, we dont need to notify the atk object
3079 * but we still need to queue the draw here (in the case
3080 * that the focus cell changes but not the cursor item).
3082 gtk_icon_view_queue_draw_item (icon_view, item);
3084 if (icon_view->priv->cursor_item == item &&
3085 (cursor_cell == NULL || cursor_cell == gtk_cell_area_get_focus_cell (icon_view->priv->cell_area)))
3088 obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
3089 if (icon_view->priv->cursor_item != NULL)
3091 gtk_icon_view_queue_draw_item (icon_view, icon_view->priv->cursor_item);
3094 cursor_item_obj = atk_object_ref_accessible_child (obj, icon_view->priv->cursor_item->index);
3095 if (cursor_item_obj != NULL)
3096 atk_object_notify_state_change (cursor_item_obj, ATK_STATE_FOCUSED, FALSE);
3099 icon_view->priv->cursor_item = item;
3102 gtk_cell_area_set_focus_cell (icon_view->priv->cell_area, cursor_cell);
3105 /* Make sure there is a cell in focus initially */
3106 if (!gtk_cell_area_get_focus_cell (icon_view->priv->cell_area))
3107 gtk_cell_area_focus (icon_view->priv->cell_area, GTK_DIR_TAB_FORWARD);
3110 /* Notify that accessible focus object has changed */
3111 item_obj = atk_object_ref_accessible_child (obj, item->index);
3113 if (item_obj != NULL)
3115 atk_focus_tracker_notify (item_obj);
3116 atk_object_notify_state_change (item_obj, ATK_STATE_FOCUSED, TRUE);
3117 g_object_unref (item_obj);
3122 static GtkIconViewItem *
3123 gtk_icon_view_item_new (void)
3125 GtkIconViewItem *item;
3127 item = g_slice_new0 (GtkIconViewItem);
3129 item->cell_area.width = -1;
3130 item->cell_area.height = -1;
3136 gtk_icon_view_item_free (GtkIconViewItem *item)
3138 g_return_if_fail (item != NULL);
3140 g_slice_free (GtkIconViewItem, item);
3143 static GtkIconViewItem *
3144 gtk_icon_view_get_item_at_coords (GtkIconView *icon_view,
3147 gboolean only_in_cell,
3148 GtkCellRenderer **cell_at_pos)
3153 *cell_at_pos = NULL;
3155 for (items = icon_view->priv->items; items; items = items->next)
3157 GtkIconViewItem *item = items->data;
3158 GdkRectangle *item_area = (GdkRectangle *)item;
3160 if (x >= item_area->x - icon_view->priv->column_spacing/2 &&
3161 x <= item_area->x + item_area->width + icon_view->priv->column_spacing/2 &&
3162 y >= item_area->y - icon_view->priv->row_spacing/2 &&
3163 y <= item_area->y + item_area->height + icon_view->priv->row_spacing/2)
3165 if (only_in_cell || cell_at_pos)
3167 GtkCellRenderer *cell = NULL;
3168 GtkCellAreaContext *context;
3170 context = g_ptr_array_index (icon_view->priv->row_contexts, item->row);
3171 gtk_icon_view_set_cell_data (icon_view, item);
3173 if (x >= item_area->x && x <= item_area->x + item_area->width &&
3174 y >= item_area->y && y <= item_area->y + item_area->height)
3175 cell = gtk_cell_area_get_cell_at_position (icon_view->priv->cell_area, context,
3176 GTK_WIDGET (icon_view),
3181 *cell_at_pos = cell;
3184 return cell != NULL ? item : NULL;
3195 gtk_icon_view_select_item (GtkIconView *icon_view,
3196 GtkIconViewItem *item)
3198 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3199 g_return_if_fail (item != NULL);
3204 if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
3206 else if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3207 gtk_icon_view_unselect_all_internal (icon_view);
3209 item->selected = TRUE;
3211 gtk_icon_view_item_selected_changed (icon_view, item);
3212 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3214 gtk_icon_view_queue_draw_item (icon_view, item);
3219 gtk_icon_view_unselect_item (GtkIconView *icon_view,
3220 GtkIconViewItem *item)
3222 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3223 g_return_if_fail (item != NULL);
3225 if (!item->selected)
3228 if (icon_view->priv->selection_mode == GTK_SELECTION_NONE ||
3229 icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
3232 item->selected = FALSE;
3234 gtk_icon_view_item_selected_changed (icon_view, item);
3235 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3237 gtk_icon_view_queue_draw_item (icon_view, item);
3241 verify_items (GtkIconView *icon_view)
3246 for (items = icon_view->priv->items; items; items = items->next)
3248 GtkIconViewItem *item = items->data;
3250 if (item->index != i)
3251 g_error ("List item does not match its index: "
3252 "item index %d and list index %d\n", item->index, i);
3259 gtk_icon_view_row_changed (GtkTreeModel *model,
3264 GtkIconView *icon_view = GTK_ICON_VIEW (data);
3266 /* ignore changes in branches */
3267 if (gtk_tree_path_get_depth (path) > 1)
3270 /* An icon view subclass might add it's own model and populate
3271 * things at init() time instead of waiting for the constructor()
3274 if (icon_view->priv->cell_area)
3275 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
3277 /* Here we can use a "grow-only" strategy for optimization
3278 * and only invalidate a single item and queue a relayout
3279 * instead of invalidating the whole thing.
3281 * For now GtkIconView still cant deal with huge models
3282 * so just invalidate the whole thing when the model
3285 gtk_icon_view_invalidate_sizes (icon_view);
3287 verify_items (icon_view);
3291 gtk_icon_view_row_inserted (GtkTreeModel *model,
3296 GtkIconView *icon_view = GTK_ICON_VIEW (data);
3298 GtkIconViewItem *item;
3299 gboolean iters_persist;
3302 /* ignore changes in branches */
3303 if (gtk_tree_path_get_depth (path) > 1)
3306 iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
3308 index = gtk_tree_path_get_indices(path)[0];
3310 item = gtk_icon_view_item_new ();
3315 item->index = index;
3317 /* FIXME: We can be more efficient here,
3318 we can store a tail pointer and use that when
3319 appending (which is a rather common operation)
3321 icon_view->priv->items = g_list_insert (icon_view->priv->items,
3324 list = g_list_nth (icon_view->priv->items, index + 1);
3325 for (; list; list = list->next)
3332 verify_items (icon_view);
3334 gtk_icon_view_queue_layout (icon_view);
3338 gtk_icon_view_row_deleted (GtkTreeModel *model,
3342 GtkIconView *icon_view = GTK_ICON_VIEW (data);
3344 GtkIconViewItem *item;
3346 gboolean emit = FALSE;
3348 /* ignore changes in branches */
3349 if (gtk_tree_path_get_depth (path) > 1)
3352 index = gtk_tree_path_get_indices(path)[0];
3354 list = g_list_nth (icon_view->priv->items, index);
3357 if (icon_view->priv->cell_area)
3358 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
3360 if (item == icon_view->priv->anchor_item)
3361 icon_view->priv->anchor_item = NULL;
3363 if (item == icon_view->priv->cursor_item)
3364 icon_view->priv->cursor_item = NULL;
3369 gtk_icon_view_item_free (item);
3371 for (next = list->next; next; next = next->next)
3378 icon_view->priv->items = g_list_delete_link (icon_view->priv->items, list);
3380 verify_items (icon_view);
3382 gtk_icon_view_queue_layout (icon_view);
3385 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3389 gtk_icon_view_rows_reordered (GtkTreeModel *model,
3390 GtkTreePath *parent,
3395 GtkIconView *icon_view = GTK_ICON_VIEW (data);
3398 GList *items = NULL, *list;
3399 GtkIconViewItem **item_array;
3402 /* ignore changes in branches */
3406 if (icon_view->priv->cell_area)
3407 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
3409 length = gtk_tree_model_iter_n_children (model, NULL);
3411 order = g_new (gint, length);
3412 for (i = 0; i < length; i++)
3413 order [new_order[i]] = i;
3415 item_array = g_new (GtkIconViewItem *, length);
3416 for (i = 0, list = icon_view->priv->items; list != NULL; list = list->next, i++)
3417 item_array[order[i]] = list->data;
3420 for (i = length - 1; i >= 0; i--)
3422 item_array[i]->index = i;
3423 items = g_list_prepend (items, item_array[i]);
3426 g_free (item_array);
3427 g_list_free (icon_view->priv->items);
3428 icon_view->priv->items = items;
3430 gtk_icon_view_queue_layout (icon_view);
3432 verify_items (icon_view);
3436 gtk_icon_view_build_items (GtkIconView *icon_view)
3440 gboolean iters_persist;
3441 GList *items = NULL;
3443 iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
3445 if (!gtk_tree_model_get_iter_first (icon_view->priv->model,
3453 GtkIconViewItem *item = gtk_icon_view_item_new ();
3462 items = g_list_prepend (items, item);
3464 } while (gtk_tree_model_iter_next (icon_view->priv->model, &iter));
3466 icon_view->priv->items = g_list_reverse (items);
3470 gtk_icon_view_add_move_binding (GtkBindingSet *binding_set,
3473 GtkMovementStep step,
3477 gtk_binding_entry_add_signal (binding_set, keyval, modmask,
3478 I_("move-cursor"), 2,
3482 gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
3487 if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
3490 gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
3495 gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
3502 gtk_icon_view_real_move_cursor (GtkIconView *icon_view,
3503 GtkMovementStep step,
3506 GdkModifierType state;
3508 g_return_val_if_fail (GTK_ICON_VIEW (icon_view), FALSE);
3509 g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
3510 step == GTK_MOVEMENT_VISUAL_POSITIONS ||
3511 step == GTK_MOVEMENT_DISPLAY_LINES ||
3512 step == GTK_MOVEMENT_PAGES ||
3513 step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
3515 if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3518 gtk_cell_area_stop_editing (icon_view->priv->cell_area, FALSE);
3519 gtk_widget_grab_focus (GTK_WIDGET (icon_view));
3521 if (gtk_get_current_event_state (&state))
3523 if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
3524 icon_view->priv->ctrl_pressed = TRUE;
3525 if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
3526 icon_view->priv->shift_pressed = TRUE;
3528 /* else we assume not pressed */
3532 case GTK_MOVEMENT_LOGICAL_POSITIONS:
3533 case GTK_MOVEMENT_VISUAL_POSITIONS:
3534 gtk_icon_view_move_cursor_left_right (icon_view, count);
3536 case GTK_MOVEMENT_DISPLAY_LINES:
3537 gtk_icon_view_move_cursor_up_down (icon_view, count);
3539 case GTK_MOVEMENT_PAGES:
3540 gtk_icon_view_move_cursor_page_up_down (icon_view, count);
3542 case GTK_MOVEMENT_BUFFER_ENDS:
3543 gtk_icon_view_move_cursor_start_end (icon_view, count);
3546 g_assert_not_reached ();
3549 icon_view->priv->ctrl_pressed = FALSE;
3550 icon_view->priv->shift_pressed = FALSE;
3552 icon_view->priv->draw_focus = TRUE;
3557 static GtkIconViewItem *
3558 find_item (GtkIconView *icon_view,
3559 GtkIconViewItem *current,
3565 GtkIconViewItem *item;
3567 /* FIXME: this could be more efficient
3569 row = current->row + row_ofs;
3570 col = current->col + col_ofs;
3572 for (items = icon_view->priv->items; items; items = items->next)
3575 if (item->row == row && item->col == col)
3582 static GtkIconViewItem *
3583 find_item_page_up_down (GtkIconView *icon_view,
3584 GtkIconViewItem *current,
3591 y = current->cell_area.y + count * gtk_adjustment_get_page_size (icon_view->priv->vadjustment);
3593 item = g_list_find (icon_view->priv->items, current);
3598 for (next = item->next; next; next = next->next)
3600 if (((GtkIconViewItem *)next->data)->col == col)
3603 if (!next || ((GtkIconViewItem *)next->data)->cell_area.y > y)
3613 for (next = item->prev; next; next = next->prev)
3615 if (((GtkIconViewItem *)next->data)->col == col)
3618 if (!next || ((GtkIconViewItem *)next->data)->cell_area.y < y)
3632 gtk_icon_view_select_all_between (GtkIconView *icon_view,
3633 GtkIconViewItem *anchor,
3634 GtkIconViewItem *cursor)
3637 GtkIconViewItem *item;
3638 gint row1, row2, col1, col2;
3639 gboolean dirty = FALSE;
3641 if (anchor->row < cursor->row)
3652 if (anchor->col < cursor->col)
3663 for (items = icon_view->priv->items; items; items = items->next)
3667 if (row1 <= item->row && item->row <= row2 &&
3668 col1 <= item->col && item->col <= col2)
3670 if (!item->selected)
3673 item->selected = TRUE;
3674 gtk_icon_view_item_selected_changed (icon_view, item);
3676 gtk_icon_view_queue_draw_item (icon_view, item);
3684 gtk_icon_view_move_cursor_up_down (GtkIconView *icon_view,
3687 GtkIconViewItem *item;
3688 GtkCellRenderer *cell;
3689 gboolean dirty = FALSE;
3691 GtkDirectionType direction;
3693 if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3696 direction = count < 0 ? GTK_DIR_UP : GTK_DIR_DOWN;
3698 if (!icon_view->priv->cursor_item)
3703 list = icon_view->priv->items;
3705 list = g_list_last (icon_view->priv->items);
3707 item = list ? list->data : NULL;
3709 /* Give focus to the first cell initially */
3710 gtk_icon_view_set_cell_data (icon_view, item);
3711 gtk_cell_area_focus (icon_view->priv->cell_area, direction);
3715 item = icon_view->priv->cursor_item;
3716 step = count > 0 ? 1 : -1;
3718 /* Save the current focus cell in case we hit the edge */
3719 cell = gtk_cell_area_get_focus_cell (icon_view->priv->cell_area);
3723 gtk_icon_view_set_cell_data (icon_view, item);
3725 if (gtk_cell_area_focus (icon_view->priv->cell_area, direction))
3728 item = find_item (icon_view, item, step, 0);
3734 if (!gtk_widget_keynav_failed (GTK_WIDGET (icon_view), direction))
3736 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (icon_view));
3738 gtk_widget_child_focus (toplevel,
3739 direction == GTK_DIR_UP ?
3740 GTK_DIR_TAB_BACKWARD :
3741 GTK_DIR_TAB_FORWARD);
3745 gtk_cell_area_set_focus_cell (icon_view->priv->cell_area, cell);
3749 if (icon_view->priv->ctrl_pressed ||
3750 !icon_view->priv->shift_pressed ||
3751 !icon_view->priv->anchor_item ||
3752 icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3753 icon_view->priv->anchor_item = item;
3755 cell = gtk_cell_area_get_focus_cell (icon_view->priv->cell_area);
3756 gtk_icon_view_set_cursor_item (icon_view, item, cell);
3758 if (!icon_view->priv->ctrl_pressed &&
3759 icon_view->priv->selection_mode != GTK_SELECTION_NONE)
3761 dirty = gtk_icon_view_unselect_all_internal (icon_view);
3762 dirty = gtk_icon_view_select_all_between (icon_view,
3763 icon_view->priv->anchor_item,
3767 gtk_icon_view_scroll_to_item (icon_view, item);
3770 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3774 gtk_icon_view_move_cursor_page_up_down (GtkIconView *icon_view,
3777 GtkIconViewItem *item;
3778 gboolean dirty = FALSE;
3780 if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3783 if (!icon_view->priv->cursor_item)
3788 list = icon_view->priv->items;
3790 list = g_list_last (icon_view->priv->items);
3792 item = list ? list->data : NULL;
3795 item = find_item_page_up_down (icon_view,
3796 icon_view->priv->cursor_item,
3799 if (item == icon_view->priv->cursor_item)
3800 gtk_widget_error_bell (GTK_WIDGET (icon_view));
3805 if (icon_view->priv->ctrl_pressed ||
3806 !icon_view->priv->shift_pressed ||
3807 !icon_view->priv->anchor_item ||
3808 icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3809 icon_view->priv->anchor_item = item;
3811 gtk_icon_view_set_cursor_item (icon_view, item, NULL);
3813 if (!icon_view->priv->ctrl_pressed &&
3814 icon_view->priv->selection_mode != GTK_SELECTION_NONE)
3816 dirty = gtk_icon_view_unselect_all_internal (icon_view);
3817 dirty = gtk_icon_view_select_all_between (icon_view,
3818 icon_view->priv->anchor_item,
3822 gtk_icon_view_scroll_to_item (icon_view, item);
3825 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3829 gtk_icon_view_move_cursor_left_right (GtkIconView *icon_view,
3832 GtkIconViewItem *item;
3833 GtkCellRenderer *cell = NULL;
3834 gboolean dirty = FALSE;
3836 GtkDirectionType direction;
3838 if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3841 direction = count < 0 ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
3843 if (!icon_view->priv->cursor_item)
3848 list = icon_view->priv->items;
3850 list = g_list_last (icon_view->priv->items);
3852 item = list ? list->data : NULL;
3854 /* Give focus to the first cell initially */
3855 gtk_icon_view_set_cell_data (icon_view, item);
3856 gtk_cell_area_focus (icon_view->priv->cell_area, direction);
3860 item = icon_view->priv->cursor_item;
3861 step = count > 0 ? 1 : -1;
3863 /* Save the current focus cell in case we hit the edge */
3864 cell = gtk_cell_area_get_focus_cell (icon_view->priv->cell_area);
3868 gtk_icon_view_set_cell_data (icon_view, item);
3870 if (gtk_cell_area_focus (icon_view->priv->cell_area, direction))
3873 item = find_item (icon_view, item, 0, step);
3879 if (!gtk_widget_keynav_failed (GTK_WIDGET (icon_view), direction))
3881 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (icon_view));
3883 gtk_widget_child_focus (toplevel,
3884 direction == GTK_DIR_LEFT ?
3885 GTK_DIR_TAB_BACKWARD :
3886 GTK_DIR_TAB_FORWARD);
3890 gtk_cell_area_set_focus_cell (icon_view->priv->cell_area, cell);
3894 if (icon_view->priv->ctrl_pressed ||
3895 !icon_view->priv->shift_pressed ||
3896 !icon_view->priv->anchor_item ||
3897 icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3898 icon_view->priv->anchor_item = item;
3900 cell = gtk_cell_area_get_focus_cell (icon_view->priv->cell_area);
3901 gtk_icon_view_set_cursor_item (icon_view, item, cell);
3903 if (!icon_view->priv->ctrl_pressed &&
3904 icon_view->priv->selection_mode != GTK_SELECTION_NONE)
3906 dirty = gtk_icon_view_unselect_all_internal (icon_view);
3907 dirty = gtk_icon_view_select_all_between (icon_view,
3908 icon_view->priv->anchor_item,
3912 gtk_icon_view_scroll_to_item (icon_view, item);
3915 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3919 gtk_icon_view_move_cursor_start_end (GtkIconView *icon_view,
3922 GtkIconViewItem *item;
3924 gboolean dirty = FALSE;
3926 if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3930 list = icon_view->priv->items;
3932 list = g_list_last (icon_view->priv->items);
3934 item = list ? list->data : NULL;
3936 if (item == icon_view->priv->cursor_item)
3937 gtk_widget_error_bell (GTK_WIDGET (icon_view));
3942 if (icon_view->priv->ctrl_pressed ||
3943 !icon_view->priv->shift_pressed ||
3944 !icon_view->priv->anchor_item ||
3945 icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3946 icon_view->priv->anchor_item = item;
3948 gtk_icon_view_set_cursor_item (icon_view, item, NULL);
3950 if (!icon_view->priv->ctrl_pressed &&
3951 icon_view->priv->selection_mode != GTK_SELECTION_NONE)
3953 dirty = gtk_icon_view_unselect_all_internal (icon_view);
3954 dirty = gtk_icon_view_select_all_between (icon_view,
3955 icon_view->priv->anchor_item,
3959 gtk_icon_view_scroll_to_item (icon_view, item);
3962 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3966 * gtk_icon_view_scroll_to_path:
3967 * @icon_view: A #GtkIconView.
3968 * @path: The path of the item to move to.
3969 * @use_align: whether to use alignment arguments, or %FALSE.
3970 * @row_align: The vertical alignment of the item specified by @path.
3971 * @col_align: The horizontal alignment of the item specified by @path.
3973 * Moves the alignments of @icon_view to the position specified by @path.
3974 * @row_align determines where the row is placed, and @col_align determines
3975 * where @column is placed. Both are expected to be between 0.0 and 1.0.
3976 * 0.0 means left/top alignment, 1.0 means right/bottom alignment, 0.5 means
3979 * If @use_align is %FALSE, then the alignment arguments are ignored, and the
3980 * tree does the minimum amount of work to scroll the item onto the screen.
3981 * This means that the item will be scrolled to the edge closest to its current
3982 * position. If the item is currently visible on the screen, nothing is done.
3984 * This function only works if the model is set, and @path is a valid row on
3985 * the model. If the model changes before the @icon_view is realized, the
3986 * centered path will be modified to reflect this change.
3991 gtk_icon_view_scroll_to_path (GtkIconView *icon_view,
3997 GtkIconViewItem *item = NULL;
4000 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4001 g_return_if_fail (path != NULL);
4002 g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
4003 g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
4005 widget = GTK_WIDGET (icon_view);
4007 if (gtk_tree_path_get_depth (path) > 0)
4008 item = g_list_nth_data (icon_view->priv->items,
4009 gtk_tree_path_get_indices(path)[0]);
4011 if (!item || item->cell_area.width < 0 ||
4012 !gtk_widget_get_realized (widget))
4014 if (icon_view->priv->scroll_to_path)
4015 gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
4017 icon_view->priv->scroll_to_path = NULL;
4020 icon_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (icon_view), icon_view->priv->model, path);
4022 icon_view->priv->scroll_to_use_align = use_align;
4023 icon_view->priv->scroll_to_row_align = row_align;
4024 icon_view->priv->scroll_to_col_align = col_align;
4031 GtkAllocation allocation;
4034 GdkRectangle item_area =
4036 item->cell_area.x - icon_view->priv->item_padding,
4037 item->cell_area.y - icon_view->priv->item_padding,
4038 item->cell_area.width + icon_view->priv->item_padding * 2,
4039 item->cell_area.height + icon_view->priv->item_padding * 2
4042 gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4044 gtk_widget_get_allocation (widget, &allocation);
4046 offset = y + item_area.y - row_align * (allocation.height - item_area.height);
4048 gtk_adjustment_set_value (icon_view->priv->vadjustment,
4049 gtk_adjustment_get_value (icon_view->priv->vadjustment) + offset);
4051 offset = x + item_area.x - col_align * (allocation.width - item_area.width);
4053 gtk_adjustment_set_value (icon_view->priv->hadjustment,
4054 gtk_adjustment_get_value (icon_view->priv->hadjustment) + offset);
4056 gtk_adjustment_changed (icon_view->priv->hadjustment);
4057 gtk_adjustment_changed (icon_view->priv->vadjustment);
4060 gtk_icon_view_scroll_to_item (icon_view, item);
4065 gtk_icon_view_scroll_to_item (GtkIconView *icon_view,
4066 GtkIconViewItem *item)
4068 GtkIconViewPrivate *priv = icon_view->priv;
4069 GtkWidget *widget = GTK_WIDGET (icon_view);
4070 GtkAdjustment *hadj, *vadj;
4071 GtkAllocation allocation;
4073 GdkRectangle item_area;
4075 item_area.x = item->cell_area.x - priv->item_padding;
4076 item_area.y = item->cell_area.y - priv->item_padding;
4077 item_area.width = item->cell_area.width + priv->item_padding * 2;
4078 item_area.height = item->cell_area.height + priv->item_padding * 2;
4080 gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4081 gtk_widget_get_allocation (widget, &allocation);
4083 hadj = icon_view->priv->hadjustment;
4084 vadj = icon_view->priv->vadjustment;
4086 if (y + item_area.y < 0)
4087 gtk_adjustment_set_value (vadj,
4088 gtk_adjustment_get_value (vadj)
4090 else if (y + item_area.y + item_area.height > allocation.height)
4091 gtk_adjustment_set_value (vadj,
4092 gtk_adjustment_get_value (vadj)
4093 + y + item_area.y + item_area.height - allocation.height);
4095 if (x + item_area.x < 0)
4096 gtk_adjustment_set_value (hadj,
4097 gtk_adjustment_get_value (hadj)
4099 else if (x + item_area.x + item_area.width > allocation.width)
4100 gtk_adjustment_set_value (hadj,
4101 gtk_adjustment_get_value (hadj)
4102 + x + item_area.x + item_area.width - allocation.width);
4104 gtk_adjustment_changed (hadj);
4105 gtk_adjustment_changed (vadj);
4108 /* GtkCellLayout implementation */
4111 gtk_icon_view_ensure_cell_area (GtkIconView *icon_view,
4112 GtkCellArea *cell_area)
4114 GtkIconViewPrivate *priv = icon_view->priv;
4116 if (priv->cell_area)
4120 priv->cell_area = cell_area;
4122 priv->cell_area = gtk_cell_area_box_new ();
4124 g_object_ref_sink (priv->cell_area);
4126 if (GTK_IS_ORIENTABLE (priv->cell_area))
4127 gtk_orientable_set_orientation (GTK_ORIENTABLE (priv->cell_area), priv->item_orientation);
4129 priv->cell_area_context = gtk_cell_area_create_context (priv->cell_area);
4131 priv->add_editable_id =
4132 g_signal_connect (priv->cell_area, "add-editable",
4133 G_CALLBACK (gtk_icon_view_add_editable), icon_view);
4134 priv->remove_editable_id =
4135 g_signal_connect (priv->cell_area, "remove-editable",
4136 G_CALLBACK (gtk_icon_view_remove_editable), icon_view);
4137 priv->context_changed_id =
4138 g_signal_connect (priv->cell_area_context, "notify",
4139 G_CALLBACK (gtk_icon_view_context_changed), icon_view);
4141 update_text_cell (icon_view);
4142 update_pixbuf_cell (icon_view);
4145 static GtkCellArea *
4146 gtk_icon_view_cell_layout_get_area (GtkCellLayout *cell_layout)
4148 GtkIconView *icon_view = GTK_ICON_VIEW (cell_layout);
4149 GtkIconViewPrivate *priv = icon_view->priv;
4151 if (G_UNLIKELY (!priv->cell_area))
4152 gtk_icon_view_ensure_cell_area (icon_view, NULL);
4154 return icon_view->priv->cell_area;
4158 gtk_icon_view_set_cell_data (GtkIconView *icon_view,
4159 GtkIconViewItem *item)
4161 gboolean iters_persist;
4164 iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
4170 path = gtk_tree_path_new_from_indices (item->index, -1);
4171 if (!gtk_tree_model_get_iter (icon_view->priv->model, &iter, path))
4173 gtk_tree_path_free (path);
4178 gtk_cell_area_apply_attributes (icon_view->priv->cell_area,
4179 icon_view->priv->model,
4180 &iter, FALSE, FALSE);
4189 * gtk_icon_view_new:
4191 * Creates a new #GtkIconView widget
4193 * Return value: A newly created #GtkIconView widget
4198 gtk_icon_view_new (void)
4200 return g_object_new (GTK_TYPE_ICON_VIEW, NULL);
4204 * gtk_icon_view_new_with_area:
4205 * @area: the #GtkCellArea to use to layout cells
4207 * Creates a new #GtkIconView widget using the
4208 * specified @area to layout cells inside the icons.
4210 * Return value: A newly created #GtkIconView widget
4215 gtk_icon_view_new_with_area (GtkCellArea *area)
4217 return g_object_new (GTK_TYPE_ICON_VIEW, "cell-area", area, NULL);
4221 * gtk_icon_view_new_with_model:
4222 * @model: The model.
4224 * Creates a new #GtkIconView widget with the model @model.
4226 * Return value: A newly created #GtkIconView widget.
4231 gtk_icon_view_new_with_model (GtkTreeModel *model)
4233 return g_object_new (GTK_TYPE_ICON_VIEW, "model", model, NULL);
4237 * gtk_icon_view_convert_widget_to_bin_window_coords:
4238 * @icon_view: a #GtkIconView
4239 * @wx: X coordinate relative to the widget
4240 * @wy: Y coordinate relative to the widget
4241 * @bx: (out): return location for bin_window X coordinate
4242 * @by: (out): return location for bin_window Y coordinate
4244 * Converts widget coordinates to coordinates for the bin_window,
4245 * as expected by e.g. gtk_icon_view_get_path_at_pos().
4250 gtk_icon_view_convert_widget_to_bin_window_coords (GtkIconView *icon_view,
4258 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4260 if (icon_view->priv->bin_window)
4261 gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4272 * gtk_icon_view_get_path_at_pos:
4273 * @icon_view: A #GtkIconView.
4274 * @x: The x position to be identified
4275 * @y: The y position to be identified
4277 * Finds the path at the point (@x, @y), relative to bin_window coordinates.
4278 * See gtk_icon_view_get_item_at_pos(), if you are also interested in
4279 * the cell at the specified position.
4280 * See gtk_icon_view_convert_widget_to_bin_window_coords() for converting
4281 * widget coordinates to bin_window coordinates.
4283 * Return value: The #GtkTreePath corresponding to the icon or %NULL
4284 * if no icon exists at that position.
4289 gtk_icon_view_get_path_at_pos (GtkIconView *icon_view,
4293 GtkIconViewItem *item;
4296 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
4298 item = gtk_icon_view_get_item_at_coords (icon_view, x, y, TRUE, NULL);
4303 path = gtk_tree_path_new_from_indices (item->index, -1);
4309 * gtk_icon_view_get_item_at_pos:
4310 * @icon_view: A #GtkIconView.
4311 * @x: The x position to be identified
4312 * @y: The y position to be identified
4313 * @path: (out) (allow-none): Return location for the path, or %NULL
4314 * @cell: (out) (allow-none): Return location for the renderer
4315 * responsible for the cell at (@x, @y), or %NULL
4317 * Finds the path at the point (@x, @y), relative to bin_window coordinates.
4318 * In contrast to gtk_icon_view_get_path_at_pos(), this function also
4319 * obtains the cell at the specified position. The returned path should
4320 * be freed with gtk_tree_path_free().
4321 * See gtk_icon_view_convert_widget_to_bin_window_coords() for converting
4322 * widget coordinates to bin_window coordinates.
4324 * Return value: %TRUE if an item exists at the specified position
4329 gtk_icon_view_get_item_at_pos (GtkIconView *icon_view,
4333 GtkCellRenderer **cell)
4335 GtkIconViewItem *item;
4336 GtkCellRenderer *renderer = NULL;
4338 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
4340 item = gtk_icon_view_get_item_at_coords (icon_view, x, y, TRUE, &renderer);
4345 *path = gtk_tree_path_new_from_indices (item->index, -1);
4353 return (item != NULL);
4357 * gtk_icon_view_set_tooltip_item:
4358 * @icon_view: a #GtkIconView
4359 * @tooltip: a #GtkTooltip
4360 * @path: a #GtkTreePath
4362 * Sets the tip area of @tooltip to be the area covered by the item at @path.
4363 * See also gtk_icon_view_set_tooltip_column() for a simpler alternative.
4364 * See also gtk_tooltip_set_tip_area().
4369 gtk_icon_view_set_tooltip_item (GtkIconView *icon_view,
4370 GtkTooltip *tooltip,
4373 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4374 g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
4376 gtk_icon_view_set_tooltip_cell (icon_view, tooltip, path, NULL);
4380 * gtk_icon_view_set_tooltip_cell:
4381 * @icon_view: a #GtkIconView
4382 * @tooltip: a #GtkTooltip
4383 * @path: a #GtkTreePath
4384 * @cell: (allow-none): a #GtkCellRenderer or %NULL
4386 * Sets the tip area of @tooltip to the area which @cell occupies in
4387 * the item pointed to by @path. See also gtk_tooltip_set_tip_area().
4389 * See also gtk_icon_view_set_tooltip_column() for a simpler alternative.
4394 gtk_icon_view_set_tooltip_cell (GtkIconView *icon_view,
4395 GtkTooltip *tooltip,
4397 GtkCellRenderer *cell)
4400 GtkIconViewItem *item = NULL;
4403 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4404 g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
4405 g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
4407 if (gtk_tree_path_get_depth (path) > 0)
4408 item = g_list_nth_data (icon_view->priv->items,
4409 gtk_tree_path_get_indices(path)[0]);
4416 GtkCellAreaContext *context;
4418 context = g_ptr_array_index (icon_view->priv->row_contexts, item->row);
4419 gtk_icon_view_set_cell_data (icon_view, item);
4420 gtk_cell_area_get_cell_allocation (icon_view->priv->cell_area, context,
4421 GTK_WIDGET (icon_view),
4422 cell, (GdkRectangle *)item, &rect);
4426 rect.x = item->cell_area.x - icon_view->priv->item_padding;
4427 rect.y = item->cell_area.y - icon_view->priv->item_padding;
4428 rect.width = item->cell_area.width + icon_view->priv->item_padding * 2;
4429 rect.height = item->cell_area.height + icon_view->priv->item_padding * 2;
4432 if (icon_view->priv->bin_window)
4434 gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4439 gtk_tooltip_set_tip_area (tooltip, &rect);
4444 * gtk_icon_view_get_tooltip_context:
4445 * @icon_view: an #GtkIconView
4446 * @x: (inout): the x coordinate (relative to widget coordinates)
4447 * @y: (inout): the y coordinate (relative to widget coordinates)
4448 * @keyboard_tip: whether this is a keyboard tooltip or not
4449 * @model: (out) (allow-none): a pointer to receive a #GtkTreeModel or %NULL
4450 * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
4451 * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
4453 * This function is supposed to be used in a #GtkWidget::query-tooltip
4454 * signal handler for #GtkIconView. The @x, @y and @keyboard_tip values
4455 * which are received in the signal handler, should be passed to this
4456 * function without modification.
4458 * The return value indicates whether there is an icon view item at the given
4459 * coordinates (%TRUE) or not (%FALSE) for mouse tooltips. For keyboard
4460 * tooltips the item returned will be the cursor item. When %TRUE, then any of
4461 * @model, @path and @iter which have been provided will be set to point to
4462 * that row and the corresponding model. @x and @y will always be converted
4463 * to be relative to @icon_view's bin_window if @keyboard_tooltip is %FALSE.
4465 * Return value: whether or not the given tooltip context points to a item
4470 gtk_icon_view_get_tooltip_context (GtkIconView *icon_view,
4473 gboolean keyboard_tip,
4474 GtkTreeModel **model,
4478 GtkTreePath *tmppath = NULL;
4480 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
4481 g_return_val_if_fail (x != NULL, FALSE);
4482 g_return_val_if_fail (y != NULL, FALSE);
4486 gtk_icon_view_get_cursor (icon_view, &tmppath, NULL);
4493 gtk_icon_view_convert_widget_to_bin_window_coords (icon_view, *x, *y,
4496 if (!gtk_icon_view_get_item_at_pos (icon_view, *x, *y, &tmppath, NULL))
4501 *model = gtk_icon_view_get_model (icon_view);
4504 gtk_tree_model_get_iter (gtk_icon_view_get_model (icon_view),
4510 gtk_tree_path_free (tmppath);
4516 gtk_icon_view_set_tooltip_query_cb (GtkWidget *widget,
4519 gboolean keyboard_tip,
4520 GtkTooltip *tooltip,
4526 GtkTreeModel *model;
4527 GtkIconView *icon_view = GTK_ICON_VIEW (widget);
4529 if (!gtk_icon_view_get_tooltip_context (GTK_ICON_VIEW (widget),
4532 &model, &path, &iter))
4535 gtk_tree_model_get (model, &iter, icon_view->priv->tooltip_column, &str, -1);
4539 gtk_tree_path_free (path);
4543 gtk_tooltip_set_markup (tooltip, str);
4544 gtk_icon_view_set_tooltip_item (icon_view, tooltip, path);
4546 gtk_tree_path_free (path);
4554 * gtk_icon_view_set_tooltip_column:
4555 * @icon_view: a #GtkIconView
4556 * @column: an integer, which is a valid column number for @icon_view's model
4558 * If you only plan to have simple (text-only) tooltips on full items, you
4559 * can use this function to have #GtkIconView handle these automatically
4560 * for you. @column should be set to the column in @icon_view's model
4561 * containing the tooltip texts, or -1 to disable this feature.
4563 * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
4564 * @icon_view will connect a #GtkWidget::query-tooltip signal handler.
4566 * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
4567 * so &, <, etc have to be escaped in the text.
4572 gtk_icon_view_set_tooltip_column (GtkIconView *icon_view,
4575 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4577 if (column == icon_view->priv->tooltip_column)
4582 g_signal_handlers_disconnect_by_func (icon_view,
4583 gtk_icon_view_set_tooltip_query_cb,
4585 gtk_widget_set_has_tooltip (GTK_WIDGET (icon_view), FALSE);
4589 if (icon_view->priv->tooltip_column == -1)
4591 g_signal_connect (icon_view, "query-tooltip",
4592 G_CALLBACK (gtk_icon_view_set_tooltip_query_cb), NULL);
4593 gtk_widget_set_has_tooltip (GTK_WIDGET (icon_view), TRUE);
4597 icon_view->priv->tooltip_column = column;
4598 g_object_notify (G_OBJECT (icon_view), "tooltip-column");
4602 * gtk_icon_view_get_tooltip_column:
4603 * @icon_view: a #GtkIconView
4605 * Returns the column of @icon_view's model which is being used for
4606 * displaying tooltips on @icon_view's rows.
4608 * Return value: the index of the tooltip column that is currently being
4609 * used, or -1 if this is disabled.
4614 gtk_icon_view_get_tooltip_column (GtkIconView *icon_view)
4616 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), 0);
4618 return icon_view->priv->tooltip_column;
4622 * gtk_icon_view_get_visible_range:
4623 * @icon_view: A #GtkIconView
4624 * @start_path: (out) (allow-none): Return location for start of region,
4626 * @end_path: (out) (allow-none): Return location for end of region, or %NULL
4628 * Sets @start_path and @end_path to be the first and last visible path.
4629 * Note that there may be invisible paths in between.
4631 * Both paths should be freed with gtk_tree_path_free() after use.
4633 * Return value: %TRUE, if valid paths were placed in @start_path and @end_path
4638 gtk_icon_view_get_visible_range (GtkIconView *icon_view,
4639 GtkTreePath **start_path,
4640 GtkTreePath **end_path)
4642 gint start_index = -1;
4643 gint end_index = -1;
4646 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
4648 if (icon_view->priv->hadjustment == NULL ||
4649 icon_view->priv->vadjustment == NULL)
4652 if (start_path == NULL && end_path == NULL)
4655 for (icons = icon_view->priv->items; icons; icons = icons->next)
4657 GtkIconViewItem *item = icons->data;
4658 GdkRectangle *item_area = (GdkRectangle *)item;
4660 if ((item_area->x + item_area->width >= (int)gtk_adjustment_get_value (icon_view->priv->hadjustment)) &&
4661 (item_area->y + item_area->height >= (int)gtk_adjustment_get_value (icon_view->priv->vadjustment)) &&
4663 (int) (gtk_adjustment_get_value (icon_view->priv->hadjustment) +
4664 gtk_adjustment_get_page_size (icon_view->priv->hadjustment))) &&
4666 (int) (gtk_adjustment_get_value (icon_view->priv->vadjustment) +
4667 gtk_adjustment_get_page_size (icon_view->priv->vadjustment))))
4669 if (start_index == -1)
4670 start_index = item->index;
4671 end_index = item->index;
4675 if (start_path && start_index != -1)
4676 *start_path = gtk_tree_path_new_from_indices (start_index, -1);
4677 if (end_path && end_index != -1)
4678 *end_path = gtk_tree_path_new_from_indices (end_index, -1);
4680 return start_index != -1;
4684 * gtk_icon_view_selected_foreach:
4685 * @icon_view: A #GtkIconView.
4686 * @func: (scope call): The function to call for each selected icon.
4687 * @data: User data to pass to the function.
4689 * Calls a function for each selected icon. Note that the model or
4690 * selection cannot be modified from within this function.
4695 gtk_icon_view_selected_foreach (GtkIconView *icon_view,
4696 GtkIconViewForeachFunc func,
4701 for (list = icon_view->priv->items; list; list = list->next)
4703 GtkIconViewItem *item = list->data;
4704 GtkTreePath *path = gtk_tree_path_new_from_indices (item->index, -1);
4707 (* func) (icon_view, path, data);
4709 gtk_tree_path_free (path);
4714 * gtk_icon_view_set_selection_mode:
4715 * @icon_view: A #GtkIconView.
4716 * @mode: The selection mode
4718 * Sets the selection mode of the @icon_view.
4723 gtk_icon_view_set_selection_mode (GtkIconView *icon_view,
4724 GtkSelectionMode mode)
4726 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4728 if (mode == icon_view->priv->selection_mode)
4731 if (mode == GTK_SELECTION_NONE ||
4732 icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE)
4733 gtk_icon_view_unselect_all (icon_view);
4735 icon_view->priv->selection_mode = mode;
4737 g_object_notify (G_OBJECT (icon_view), "selection-mode");
4741 * gtk_icon_view_get_selection_mode:
4742 * @icon_view: A #GtkIconView.
4744 * Gets the selection mode of the @icon_view.
4746 * Return value: the current selection mode
4751 gtk_icon_view_get_selection_mode (GtkIconView *icon_view)
4753 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), GTK_SELECTION_SINGLE);
4755 return icon_view->priv->selection_mode;
4759 * gtk_icon_view_set_model:
4760 * @icon_view: A #GtkIconView.
4761 * @model: (allow-none): The model.
4763 * Sets the model for a #GtkIconView.
4764 * If the @icon_view already has a model set, it will remove
4765 * it before setting the new model. If @model is %NULL, then
4766 * it will unset the old model.
4771 gtk_icon_view_set_model (GtkIconView *icon_view,
4772 GtkTreeModel *model)
4774 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4775 g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
4777 if (icon_view->priv->model == model)
4780 if (icon_view->priv->scroll_to_path)
4782 gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
4783 icon_view->priv->scroll_to_path = NULL;
4786 /* The area can be NULL while disposing */
4787 if (icon_view->priv->cell_area)
4788 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
4794 if (icon_view->priv->pixbuf_column != -1)
4796 column_type = gtk_tree_model_get_column_type (model,
4797 icon_view->priv->pixbuf_column);
4799 g_return_if_fail (column_type == GDK_TYPE_PIXBUF);
4802 if (icon_view->priv->text_column != -1)
4804 column_type = gtk_tree_model_get_column_type (model,
4805 icon_view->priv->text_column);
4807 g_return_if_fail (column_type == G_TYPE_STRING);
4810 if (icon_view->priv->markup_column != -1)
4812 column_type = gtk_tree_model_get_column_type (model,
4813 icon_view->priv->markup_column);
4815 g_return_if_fail (column_type == G_TYPE_STRING);
4820 if (icon_view->priv->model)
4822 g_signal_handlers_disconnect_by_func (icon_view->priv->model,
4823 gtk_icon_view_row_changed,
4825 g_signal_handlers_disconnect_by_func (icon_view->priv->model,
4826 gtk_icon_view_row_inserted,
4828 g_signal_handlers_disconnect_by_func (icon_view->priv->model,
4829 gtk_icon_view_row_deleted,
4831 g_signal_handlers_disconnect_by_func (icon_view->priv->model,
4832 gtk_icon_view_rows_reordered,
4835 g_object_unref (icon_view->priv->model);
4837 g_list_foreach (icon_view->priv->items, (GFunc)gtk_icon_view_item_free, NULL);
4838 g_list_free (icon_view->priv->items);
4839 icon_view->priv->items = NULL;
4840 icon_view->priv->anchor_item = NULL;
4841 icon_view->priv->cursor_item = NULL;
4842 icon_view->priv->last_single_clicked = NULL;
4843 icon_view->priv->width = 0;
4844 icon_view->priv->height = 0;
4847 icon_view->priv->model = model;
4849 if (icon_view->priv->model)
4851 g_object_ref (icon_view->priv->model);
4852 g_signal_connect (icon_view->priv->model,
4854 G_CALLBACK (gtk_icon_view_row_changed),
4856 g_signal_connect (icon_view->priv->model,
4858 G_CALLBACK (gtk_icon_view_row_inserted),
4860 g_signal_connect (icon_view->priv->model,
4862 G_CALLBACK (gtk_icon_view_row_deleted),
4864 g_signal_connect (icon_view->priv->model,
4866 G_CALLBACK (gtk_icon_view_rows_reordered),
4869 gtk_icon_view_build_items (icon_view);
4871 gtk_icon_view_queue_layout (icon_view);
4874 g_object_notify (G_OBJECT (icon_view), "model");
4876 if (gtk_widget_get_realized (GTK_WIDGET (icon_view)))
4877 gtk_widget_queue_resize (GTK_WIDGET (icon_view));
4881 * gtk_icon_view_get_model:
4882 * @icon_view: a #GtkIconView
4884 * Returns the model the #GtkIconView is based on. Returns %NULL if the
4887 * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is
4888 * currently being used.
4893 gtk_icon_view_get_model (GtkIconView *icon_view)
4895 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
4897 return icon_view->priv->model;
4901 update_text_cell (GtkIconView *icon_view)
4903 if (!icon_view->priv->cell_area)
4906 if (icon_view->priv->text_column == -1 &&
4907 icon_view->priv->markup_column == -1)
4909 if (icon_view->priv->text_cell != NULL)
4911 gtk_cell_area_remove (icon_view->priv->cell_area,
4912 icon_view->priv->text_cell);
4913 icon_view->priv->text_cell = NULL;
4918 if (icon_view->priv->text_cell == NULL)
4920 icon_view->priv->text_cell = gtk_cell_renderer_text_new ();
4922 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (icon_view), icon_view->priv->text_cell, FALSE);
4925 if (icon_view->priv->markup_column != -1)
4926 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
4927 icon_view->priv->text_cell,
4928 "markup", icon_view->priv->markup_column,
4931 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
4932 icon_view->priv->text_cell,
4933 "text", icon_view->priv->text_column,
4936 if (icon_view->priv->item_orientation == GTK_ORIENTATION_VERTICAL)
4937 g_object_set (icon_view->priv->text_cell,
4938 "alignment", PANGO_ALIGN_CENTER,
4939 "wrap-mode", PANGO_WRAP_WORD_CHAR,
4944 g_object_set (icon_view->priv->text_cell,
4945 "alignment", PANGO_ALIGN_LEFT,
4946 "wrap-mode", PANGO_WRAP_WORD_CHAR,
4954 update_pixbuf_cell (GtkIconView *icon_view)
4956 if (!icon_view->priv->cell_area)
4959 if (icon_view->priv->pixbuf_column == -1)
4961 if (icon_view->priv->pixbuf_cell != NULL)
4963 gtk_cell_area_remove (icon_view->priv->cell_area,
4964 icon_view->priv->pixbuf_cell);
4966 icon_view->priv->pixbuf_cell = NULL;
4971 if (icon_view->priv->pixbuf_cell == NULL)
4973 icon_view->priv->pixbuf_cell = gtk_cell_renderer_pixbuf_new ();
4975 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (icon_view), icon_view->priv->pixbuf_cell, FALSE);
4978 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
4979 icon_view->priv->pixbuf_cell,
4980 "pixbuf", icon_view->priv->pixbuf_column,
4983 if (icon_view->priv->item_orientation == GTK_ORIENTATION_VERTICAL)
4984 g_object_set (icon_view->priv->pixbuf_cell,
4989 g_object_set (icon_view->priv->pixbuf_cell,
4997 * gtk_icon_view_set_text_column:
4998 * @icon_view: A #GtkIconView.
4999 * @column: A column in the currently used model, or -1 to display no text
5001 * Sets the column with text for @icon_view to be @column. The text
5002 * column must be of type #G_TYPE_STRING.
5007 gtk_icon_view_set_text_column (GtkIconView *icon_view,
5010 if (column == icon_view->priv->text_column)
5014 icon_view->priv->text_column = -1;
5017 if (icon_view->priv->model != NULL)
5021 column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
5023 g_return_if_fail (column_type == G_TYPE_STRING);
5026 icon_view->priv->text_column = column;
5029 if (icon_view->priv->cell_area)
5030 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5032 update_text_cell (icon_view);
5034 gtk_icon_view_invalidate_sizes (icon_view);
5036 g_object_notify (G_OBJECT (icon_view), "text-column");
5040 * gtk_icon_view_get_text_column:
5041 * @icon_view: A #GtkIconView.
5043 * Returns the column with text for @icon_view.
5045 * Returns: the text column, or -1 if it's unset.
5050 gtk_icon_view_get_text_column (GtkIconView *icon_view)
5052 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5054 return icon_view->priv->text_column;
5058 * gtk_icon_view_set_markup_column:
5059 * @icon_view: A #GtkIconView.
5060 * @column: A column in the currently used model, or -1 to display no text
5062 * Sets the column with markup information for @icon_view to be
5063 * @column. The markup column must be of type #G_TYPE_STRING.
5064 * If the markup column is set to something, it overrides
5065 * the text column set by gtk_icon_view_set_text_column().
5070 gtk_icon_view_set_markup_column (GtkIconView *icon_view,
5073 if (column == icon_view->priv->markup_column)
5077 icon_view->priv->markup_column = -1;
5080 if (icon_view->priv->model != NULL)
5084 column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
5086 g_return_if_fail (column_type == G_TYPE_STRING);
5089 icon_view->priv->markup_column = column;
5092 if (icon_view->priv->cell_area)
5093 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5095 update_text_cell (icon_view);
5097 gtk_icon_view_invalidate_sizes (icon_view);
5099 g_object_notify (G_OBJECT (icon_view), "markup-column");
5103 * gtk_icon_view_get_markup_column:
5104 * @icon_view: A #GtkIconView.
5106 * Returns the column with markup text for @icon_view.
5108 * Returns: the markup column, or -1 if it's unset.
5113 gtk_icon_view_get_markup_column (GtkIconView *icon_view)
5115 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5117 return icon_view->priv->markup_column;
5121 * gtk_icon_view_set_pixbuf_column:
5122 * @icon_view: A #GtkIconView.
5123 * @column: A column in the currently used model, or -1 to disable
5125 * Sets the column with pixbufs for @icon_view to be @column. The pixbuf
5126 * column must be of type #GDK_TYPE_PIXBUF
5131 gtk_icon_view_set_pixbuf_column (GtkIconView *icon_view,
5134 if (column == icon_view->priv->pixbuf_column)
5138 icon_view->priv->pixbuf_column = -1;
5141 if (icon_view->priv->model != NULL)
5145 column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
5147 g_return_if_fail (column_type == GDK_TYPE_PIXBUF);
5150 icon_view->priv->pixbuf_column = column;
5153 if (icon_view->priv->cell_area)
5154 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5156 update_pixbuf_cell (icon_view);
5158 gtk_icon_view_invalidate_sizes (icon_view);
5160 g_object_notify (G_OBJECT (icon_view), "pixbuf-column");
5165 * gtk_icon_view_get_pixbuf_column:
5166 * @icon_view: A #GtkIconView.
5168 * Returns the column with pixbufs for @icon_view.
5170 * Returns: the pixbuf column, or -1 if it's unset.
5175 gtk_icon_view_get_pixbuf_column (GtkIconView *icon_view)
5177 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5179 return icon_view->priv->pixbuf_column;
5183 * gtk_icon_view_select_path:
5184 * @icon_view: A #GtkIconView.
5185 * @path: The #GtkTreePath to be selected.
5187 * Selects the row at @path.
5192 gtk_icon_view_select_path (GtkIconView *icon_view,
5195 GtkIconViewItem *item = NULL;
5197 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5198 g_return_if_fail (icon_view->priv->model != NULL);
5199 g_return_if_fail (path != NULL);
5201 if (gtk_tree_path_get_depth (path) > 0)
5202 item = g_list_nth_data (icon_view->priv->items,
5203 gtk_tree_path_get_indices(path)[0]);
5206 gtk_icon_view_select_item (icon_view, item);
5210 * gtk_icon_view_unselect_path:
5211 * @icon_view: A #GtkIconView.
5212 * @path: The #GtkTreePath to be unselected.
5214 * Unselects the row at @path.
5219 gtk_icon_view_unselect_path (GtkIconView *icon_view,
5222 GtkIconViewItem *item;
5224 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5225 g_return_if_fail (icon_view->priv->model != NULL);
5226 g_return_if_fail (path != NULL);
5228 item = g_list_nth_data (icon_view->priv->items,
5229 gtk_tree_path_get_indices(path)[0]);
5234 gtk_icon_view_unselect_item (icon_view, item);
5238 * gtk_icon_view_get_selected_items:
5239 * @icon_view: A #GtkIconView.
5241 * Creates a list of paths of all selected items. Additionally, if you are
5242 * planning on modifying the model after calling this function, you may
5243 * want to convert the returned list into a list of #GtkTreeRowReference<!-- -->s.
5244 * To do this, you can use gtk_tree_row_reference_new().
5246 * To free the return value, use:
5248 * g_list_foreach (list, (GFunc)gtk_tree_path_free, NULL);
5249 * g_list_free (list);
5252 * Return value: (element-type GtkTreePath) (transfer full): A #GList containing a #GtkTreePath for each selected row.
5257 gtk_icon_view_get_selected_items (GtkIconView *icon_view)
5260 GList *selected = NULL;
5262 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
5264 for (list = icon_view->priv->items; list != NULL; list = list->next)
5266 GtkIconViewItem *item = list->data;
5270 GtkTreePath *path = gtk_tree_path_new_from_indices (item->index, -1);
5272 selected = g_list_prepend (selected, path);
5280 * gtk_icon_view_select_all:
5281 * @icon_view: A #GtkIconView.
5283 * Selects all the icons. @icon_view must has its selection mode set
5284 * to #GTK_SELECTION_MULTIPLE.
5289 gtk_icon_view_select_all (GtkIconView *icon_view)
5292 gboolean dirty = FALSE;
5294 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5296 if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
5299 for (items = icon_view->priv->items; items; items = items->next)
5301 GtkIconViewItem *item = items->data;
5303 if (!item->selected)
5306 item->selected = TRUE;
5307 gtk_icon_view_queue_draw_item (icon_view, item);
5312 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
5316 * gtk_icon_view_unselect_all:
5317 * @icon_view: A #GtkIconView.
5319 * Unselects all the icons.
5324 gtk_icon_view_unselect_all (GtkIconView *icon_view)
5326 gboolean dirty = FALSE;
5328 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5330 if (icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
5333 dirty = gtk_icon_view_unselect_all_internal (icon_view);
5336 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
5340 * gtk_icon_view_path_is_selected:
5341 * @icon_view: A #GtkIconView.
5342 * @path: A #GtkTreePath to check selection on.
5344 * Returns %TRUE if the icon pointed to by @path is currently
5345 * selected. If @path does not point to a valid location, %FALSE is returned.
5347 * Return value: %TRUE if @path is selected.
5352 gtk_icon_view_path_is_selected (GtkIconView *icon_view,
5355 GtkIconViewItem *item;
5357 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
5358 g_return_val_if_fail (icon_view->priv->model != NULL, FALSE);
5359 g_return_val_if_fail (path != NULL, FALSE);
5361 item = g_list_nth_data (icon_view->priv->items,
5362 gtk_tree_path_get_indices(path)[0]);
5367 return item->selected;
5371 * gtk_icon_view_get_item_row:
5372 * @icon_view: a #GtkIconView
5373 * @path: the #GtkTreePath of the item
5375 * Gets the row in which the item @path is currently
5376 * displayed. Row numbers start at 0.
5378 * Returns: The row in which the item is displayed
5383 gtk_icon_view_get_item_row (GtkIconView *icon_view,
5386 GtkIconViewItem *item;
5388 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5389 g_return_val_if_fail (icon_view->priv->model != NULL, -1);
5390 g_return_val_if_fail (path != NULL, -1);
5392 item = g_list_nth_data (icon_view->priv->items,
5393 gtk_tree_path_get_indices(path)[0]);
5402 * gtk_icon_view_get_item_column:
5403 * @icon_view: a #GtkIconView
5404 * @path: the #GtkTreePath of the item
5406 * Gets the column in which the item @path is currently
5407 * displayed. Column numbers start at 0.
5409 * Returns: The column in which the item is displayed
5414 gtk_icon_view_get_item_column (GtkIconView *icon_view,
5417 GtkIconViewItem *item;
5419 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5420 g_return_val_if_fail (icon_view->priv->model != NULL, -1);
5421 g_return_val_if_fail (path != NULL, -1);
5423 item = g_list_nth_data (icon_view->priv->items,
5424 gtk_tree_path_get_indices(path)[0]);
5433 * gtk_icon_view_item_activated:
5434 * @icon_view: A #GtkIconView
5435 * @path: The #GtkTreePath to be activated
5437 * Activates the item determined by @path.
5442 gtk_icon_view_item_activated (GtkIconView *icon_view,
5445 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5446 g_return_if_fail (path != NULL);
5448 g_signal_emit (icon_view, icon_view_signals[ITEM_ACTIVATED], 0, path);
5452 * gtk_icon_view_set_item_orientation:
5453 * @icon_view: a #GtkIconView
5454 * @orientation: the relative position of texts and icons
5456 * Sets the ::item-orientation property which determines whether the labels
5457 * are drawn beside the icons instead of below.
5462 gtk_icon_view_set_item_orientation (GtkIconView *icon_view,
5463 GtkOrientation orientation)
5465 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5467 if (icon_view->priv->item_orientation != orientation)
5469 icon_view->priv->item_orientation = orientation;
5471 if (icon_view->priv->cell_area)
5473 if (GTK_IS_ORIENTABLE (icon_view->priv->cell_area))
5474 gtk_orientable_set_orientation (GTK_ORIENTABLE (icon_view->priv->cell_area),
5475 icon_view->priv->item_orientation);
5477 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5480 gtk_icon_view_invalidate_sizes (icon_view);
5482 update_text_cell (icon_view);
5483 update_pixbuf_cell (icon_view);
5485 g_object_notify (G_OBJECT (icon_view), "item-orientation");
5490 * gtk_icon_view_get_item_orientation:
5491 * @icon_view: a #GtkIconView
5493 * Returns the value of the ::item-orientation property which determines
5494 * whether the labels are drawn beside the icons instead of below.
5496 * Return value: the relative position of texts and icons
5501 gtk_icon_view_get_item_orientation (GtkIconView *icon_view)
5503 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view),
5504 GTK_ORIENTATION_VERTICAL);
5506 return icon_view->priv->item_orientation;
5510 * gtk_icon_view_set_columns:
5511 * @icon_view: a #GtkIconView
5512 * @columns: the number of columns
5514 * Sets the ::columns property which determines in how
5515 * many columns the icons are arranged. If @columns is
5516 * -1, the number of columns will be chosen automatically
5517 * to fill the available area.
5522 gtk_icon_view_set_columns (GtkIconView *icon_view,
5525 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5527 if (icon_view->priv->columns != columns)
5529 icon_view->priv->columns = columns;
5531 if (icon_view->priv->cell_area)
5532 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5534 gtk_icon_view_queue_layout (icon_view);
5536 g_object_notify (G_OBJECT (icon_view), "columns");
5541 * gtk_icon_view_get_columns:
5542 * @icon_view: a #GtkIconView
5544 * Returns the value of the ::columns property.
5546 * Return value: the number of columns, or -1
5551 gtk_icon_view_get_columns (GtkIconView *icon_view)
5553 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5555 return icon_view->priv->columns;
5559 * gtk_icon_view_set_item_width:
5560 * @icon_view: a #GtkIconView
5561 * @item_width: the width for each item
5563 * Sets the ::item-width property which specifies the width
5564 * to use for each item. If it is set to -1, the icon view will
5565 * automatically determine a suitable item size.
5570 gtk_icon_view_set_item_width (GtkIconView *icon_view,
5573 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5575 if (icon_view->priv->item_width != item_width)
5577 icon_view->priv->item_width = item_width;
5579 if (icon_view->priv->cell_area)
5580 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5582 gtk_icon_view_invalidate_sizes (icon_view);
5584 update_text_cell (icon_view);
5586 g_object_notify (G_OBJECT (icon_view), "item-width");
5591 * gtk_icon_view_get_item_width:
5592 * @icon_view: a #GtkIconView
5594 * Returns the value of the ::item-width property.
5596 * Return value: the width of a single item, or -1
5601 gtk_icon_view_get_item_width (GtkIconView *icon_view)
5603 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5605 return icon_view->priv->item_width;
5610 * gtk_icon_view_set_spacing:
5611 * @icon_view: a #GtkIconView
5612 * @spacing: the spacing
5614 * Sets the ::spacing property which specifies the space
5615 * which is inserted between the cells (i.e. the icon and
5616 * the text) of an item.
5621 gtk_icon_view_set_spacing (GtkIconView *icon_view,
5624 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5626 if (icon_view->priv->spacing != spacing)
5628 icon_view->priv->spacing = spacing;
5630 if (icon_view->priv->cell_area)
5631 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5633 gtk_icon_view_invalidate_sizes (icon_view);
5635 g_object_notify (G_OBJECT (icon_view), "spacing");
5640 * gtk_icon_view_get_spacing:
5641 * @icon_view: a #GtkIconView
5643 * Returns the value of the ::spacing property.
5645 * Return value: the space between cells
5650 gtk_icon_view_get_spacing (GtkIconView *icon_view)
5652 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5654 return icon_view->priv->spacing;
5658 * gtk_icon_view_set_row_spacing:
5659 * @icon_view: a #GtkIconView
5660 * @row_spacing: the row spacing
5662 * Sets the ::row-spacing property which specifies the space
5663 * which is inserted between the rows of the icon view.
5668 gtk_icon_view_set_row_spacing (GtkIconView *icon_view,
5671 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5673 if (icon_view->priv->row_spacing != row_spacing)
5675 icon_view->priv->row_spacing = row_spacing;
5677 if (icon_view->priv->cell_area)
5678 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5680 gtk_icon_view_invalidate_sizes (icon_view);
5682 g_object_notify (G_OBJECT (icon_view), "row-spacing");
5687 * gtk_icon_view_get_row_spacing:
5688 * @icon_view: a #GtkIconView
5690 * Returns the value of the ::row-spacing property.
5692 * Return value: the space between rows
5697 gtk_icon_view_get_row_spacing (GtkIconView *icon_view)
5699 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5701 return icon_view->priv->row_spacing;
5705 * gtk_icon_view_set_column_spacing:
5706 * @icon_view: a #GtkIconView
5707 * @column_spacing: the column spacing
5709 * Sets the ::column-spacing property which specifies the space
5710 * which is inserted between the columns of the icon view.
5715 gtk_icon_view_set_column_spacing (GtkIconView *icon_view,
5716 gint column_spacing)
5718 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5720 if (icon_view->priv->column_spacing != column_spacing)
5722 icon_view->priv->column_spacing = column_spacing;
5724 if (icon_view->priv->cell_area)
5725 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5727 gtk_icon_view_invalidate_sizes (icon_view);
5729 g_object_notify (G_OBJECT (icon_view), "column-spacing");
5734 * gtk_icon_view_get_column_spacing:
5735 * @icon_view: a #GtkIconView
5737 * Returns the value of the ::column-spacing property.
5739 * Return value: the space between columns
5744 gtk_icon_view_get_column_spacing (GtkIconView *icon_view)
5746 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5748 return icon_view->priv->column_spacing;
5752 * gtk_icon_view_set_margin:
5753 * @icon_view: a #GtkIconView
5754 * @margin: the margin
5756 * Sets the ::margin property which specifies the space
5757 * which is inserted at the top, bottom, left and right
5763 gtk_icon_view_set_margin (GtkIconView *icon_view,
5766 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5768 if (icon_view->priv->margin != margin)
5770 icon_view->priv->margin = margin;
5772 if (icon_view->priv->cell_area)
5773 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5775 gtk_icon_view_invalidate_sizes (icon_view);
5777 g_object_notify (G_OBJECT (icon_view), "margin");
5782 * gtk_icon_view_get_margin:
5783 * @icon_view: a #GtkIconView
5785 * Returns the value of the ::margin property.
5787 * Return value: the space at the borders
5792 gtk_icon_view_get_margin (GtkIconView *icon_view)
5794 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5796 return icon_view->priv->margin;
5800 * gtk_icon_view_set_item_padding:
5801 * @icon_view: a #GtkIconView
5802 * @item_padding: the item padding
5804 * Sets the #GtkIconView:item-padding property which specifies the padding
5805 * around each of the icon view's items.
5810 gtk_icon_view_set_item_padding (GtkIconView *icon_view,
5813 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5815 if (icon_view->priv->item_padding != item_padding)
5817 icon_view->priv->item_padding = item_padding;
5819 if (icon_view->priv->cell_area)
5820 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5822 gtk_icon_view_invalidate_sizes (icon_view);
5824 g_object_notify (G_OBJECT (icon_view), "item-padding");
5829 * gtk_icon_view_get_item_padding:
5830 * @icon_view: a #GtkIconView
5832 * Returns the value of the ::item-padding property.
5834 * Return value: the padding around items
5839 gtk_icon_view_get_item_padding (GtkIconView *icon_view)
5841 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5843 return icon_view->priv->item_padding;
5846 /* Get/set whether drag_motion requested the drag data and
5847 * drag_data_received should thus not actually insert the data,
5848 * since the data doesn't result from a drop.
5851 set_status_pending (GdkDragContext *context,
5852 GdkDragAction suggested_action)
5854 g_object_set_data (G_OBJECT (context),
5855 I_("gtk-icon-view-status-pending"),
5856 GINT_TO_POINTER (suggested_action));
5859 static GdkDragAction
5860 get_status_pending (GdkDragContext *context)
5862 return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
5863 "gtk-icon-view-status-pending"));
5867 unset_reorderable (GtkIconView *icon_view)
5869 if (icon_view->priv->reorderable)
5871 icon_view->priv->reorderable = FALSE;
5872 g_object_notify (G_OBJECT (icon_view), "reorderable");
5877 set_source_row (GdkDragContext *context,
5878 GtkTreeModel *model,
5879 GtkTreePath *source_row)
5882 g_object_set_data_full (G_OBJECT (context),
5883 I_("gtk-icon-view-source-row"),
5884 gtk_tree_row_reference_new (model, source_row),
5885 (GDestroyNotify) gtk_tree_row_reference_free);
5887 g_object_set_data_full (G_OBJECT (context),
5888 I_("gtk-icon-view-source-row"),
5893 get_source_row (GdkDragContext *context)
5895 GtkTreeRowReference *ref;
5897 ref = g_object_get_data (G_OBJECT (context), "gtk-icon-view-source-row");
5900 return gtk_tree_row_reference_get_path (ref);
5907 GtkTreeRowReference *dest_row;
5908 gboolean empty_view_drop;
5909 gboolean drop_append_mode;
5913 dest_row_free (gpointer data)
5915 DestRow *dr = (DestRow *)data;
5917 gtk_tree_row_reference_free (dr->dest_row);
5922 set_dest_row (GdkDragContext *context,
5923 GtkTreeModel *model,
5924 GtkTreePath *dest_row,
5925 gboolean empty_view_drop,
5926 gboolean drop_append_mode)
5932 g_object_set_data_full (G_OBJECT (context),
5933 I_("gtk-icon-view-dest-row"),
5938 dr = g_new0 (DestRow, 1);
5940 dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
5941 dr->empty_view_drop = empty_view_drop;
5942 dr->drop_append_mode = drop_append_mode;
5943 g_object_set_data_full (G_OBJECT (context),
5944 I_("gtk-icon-view-dest-row"),
5945 dr, (GDestroyNotify) dest_row_free);
5949 get_dest_row (GdkDragContext *context)
5953 dr = g_object_get_data (G_OBJECT (context), "gtk-icon-view-dest-row");
5957 GtkTreePath *path = NULL;
5960 path = gtk_tree_row_reference_get_path (dr->dest_row);
5961 else if (dr->empty_view_drop)
5962 path = gtk_tree_path_new_from_indices (0, -1);
5966 if (path && dr->drop_append_mode)
5967 gtk_tree_path_next (path);
5976 check_model_dnd (GtkTreeModel *model,
5977 GType required_iface,
5978 const gchar *signal)
5980 if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
5982 g_warning ("You must override the default '%s' handler "
5983 "on GtkIconView when using models that don't support "
5984 "the %s interface and enabling drag-and-drop. The simplest way to do this "
5985 "is to connect to '%s' and call "
5986 "g_signal_stop_emission_by_name() in your signal handler to prevent "
5987 "the default handler from running. Look at the source code "
5988 "for the default handler in gtkiconview.c to get an idea what "
5989 "your handler should do. (gtkiconview.c is in the GTK+ source "
5990 "code.) If you're using GTK+ from a language other than C, "
5991 "there may be a more natural way to override default handlers, e.g. via derivation.",
5992 signal, g_type_name (required_iface), signal);
6000 remove_scroll_timeout (GtkIconView *icon_view)
6002 if (icon_view->priv->scroll_timeout_id != 0)
6004 g_source_remove (icon_view->priv->scroll_timeout_id);
6006 icon_view->priv->scroll_timeout_id = 0;
6011 gtk_icon_view_autoscroll (GtkIconView *icon_view)
6014 gint px, py, x, y, width, height;
6015 gint hoffset, voffset;
6017 window = gtk_widget_get_window (GTK_WIDGET (icon_view));
6019 gdk_window_get_pointer (window, &px, &py, NULL);
6020 gdk_window_get_geometry (window, &x, &y, &width, &height);
6022 /* see if we are near the edge. */
6023 voffset = py - (y + 2 * SCROLL_EDGE_SIZE);
6025 voffset = MAX (py - (y + height - 2 * SCROLL_EDGE_SIZE), 0);
6027 hoffset = px - (x + 2 * SCROLL_EDGE_SIZE);
6029 hoffset = MAX (px - (x + width - 2 * SCROLL_EDGE_SIZE), 0);
6032 gtk_adjustment_set_value (icon_view->priv->vadjustment,
6033 gtk_adjustment_get_value (icon_view->priv->vadjustment) + voffset);
6036 gtk_adjustment_set_value (icon_view->priv->hadjustment,
6037 gtk_adjustment_get_value (icon_view->priv->hadjustment) + hoffset);
6042 drag_scroll_timeout (gpointer data)
6044 GtkIconView *icon_view = GTK_ICON_VIEW (data);
6046 gtk_icon_view_autoscroll (icon_view);
6053 set_destination (GtkIconView *icon_view,
6054 GdkDragContext *context,
6057 GdkDragAction *suggested_action,
6061 GtkTreePath *path = NULL;
6062 GtkIconViewDropPosition pos;
6063 GtkIconViewDropPosition old_pos;
6064 GtkTreePath *old_dest_path = NULL;
6065 gboolean can_drop = FALSE;
6067 widget = GTK_WIDGET (icon_view);
6069 *suggested_action = 0;
6072 if (!icon_view->priv->dest_set)
6074 /* someone unset us as a drag dest, note that if
6075 * we return FALSE drag_leave isn't called
6078 gtk_icon_view_set_drag_dest_item (icon_view,
6080 GTK_ICON_VIEW_DROP_LEFT);
6082 remove_scroll_timeout (GTK_ICON_VIEW (widget));
6084 return FALSE; /* no longer a drop site */
6087 *target = gtk_drag_dest_find_target (widget, context,
6088 gtk_drag_dest_get_target_list (widget));
6089 if (*target == GDK_NONE)
6092 if (!gtk_icon_view_get_dest_item_at_pos (icon_view, x, y, &path, &pos))
6095 GtkTreeModel *model;
6097 /* the row got dropped on empty space, let's setup a special case
6101 gtk_tree_path_free (path);
6103 model = gtk_icon_view_get_model (icon_view);
6105 n_children = gtk_tree_model_iter_n_children (model, NULL);
6108 pos = GTK_ICON_VIEW_DROP_BELOW;
6109 path = gtk_tree_path_new_from_indices (n_children - 1, -1);
6113 pos = GTK_ICON_VIEW_DROP_ABOVE;
6114 path = gtk_tree_path_new_from_indices (0, -1);
6124 gtk_icon_view_get_drag_dest_item (icon_view,
6129 gtk_tree_path_free (old_dest_path);
6131 if (TRUE /* FIXME if the location droppable predicate */)
6139 GtkWidget *source_widget;
6141 *suggested_action = gdk_drag_context_get_suggested_action (context);
6142 source_widget = gtk_drag_get_source_widget (context);
6144 if (source_widget == widget)
6146 /* Default to MOVE, unless the user has
6147 * pressed ctrl or shift to affect available actions
6149 if ((gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) != 0)
6150 *suggested_action = GDK_ACTION_MOVE;
6153 gtk_icon_view_set_drag_dest_item (GTK_ICON_VIEW (widget),
6158 /* can't drop here */
6159 gtk_icon_view_set_drag_dest_item (GTK_ICON_VIEW (widget),
6161 GTK_ICON_VIEW_DROP_LEFT);
6165 gtk_tree_path_free (path);
6171 get_logical_destination (GtkIconView *icon_view,
6172 gboolean *drop_append_mode)
6174 /* adjust path to point to the row the drop goes in front of */
6175 GtkTreePath *path = NULL;
6176 GtkIconViewDropPosition pos;
6178 *drop_append_mode = FALSE;
6180 gtk_icon_view_get_drag_dest_item (icon_view, &path, &pos);
6185 if (pos == GTK_ICON_VIEW_DROP_RIGHT ||
6186 pos == GTK_ICON_VIEW_DROP_BELOW)
6189 GtkTreeModel *model = icon_view->priv->model;
6191 if (!gtk_tree_model_get_iter (model, &iter, path) ||
6192 !gtk_tree_model_iter_next (model, &iter))
6193 *drop_append_mode = TRUE;
6196 *drop_append_mode = FALSE;
6197 gtk_tree_path_next (path);
6205 gtk_icon_view_maybe_begin_drag (GtkIconView *icon_view,
6206 GdkEventMotion *event)
6208 GtkWidget *widget = GTK_WIDGET (icon_view);
6209 GdkDragContext *context;
6210 GtkTreePath *path = NULL;
6212 GtkTreeModel *model;
6213 gboolean retval = FALSE;
6215 if (!icon_view->priv->source_set)
6218 if (icon_view->priv->pressed_button < 0)
6221 if (!gtk_drag_check_threshold (GTK_WIDGET (icon_view),
6222 icon_view->priv->press_start_x,
6223 icon_view->priv->press_start_y,
6224 event->x, event->y))
6227 model = gtk_icon_view_get_model (icon_view);
6232 button = icon_view->priv->pressed_button;
6233 icon_view->priv->pressed_button = -1;
6235 path = gtk_icon_view_get_path_at_pos (icon_view,
6236 icon_view->priv->press_start_x,
6237 icon_view->priv->press_start_y);
6242 if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
6243 !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
6247 /* FIXME Check whether we're a start button, if not return FALSE and
6251 /* Now we can begin the drag */
6255 context = gtk_drag_begin (widget,
6256 gtk_drag_source_get_target_list (widget),
6257 icon_view->priv->source_actions,
6261 set_source_row (context, model, path);
6265 gtk_tree_path_free (path);
6270 /* Source side drag signals */
6272 gtk_icon_view_drag_begin (GtkWidget *widget,
6273 GdkDragContext *context)
6275 GtkIconView *icon_view;
6276 GtkIconViewItem *item;
6277 cairo_surface_t *icon;
6281 icon_view = GTK_ICON_VIEW (widget);
6283 /* if the user uses a custom DnD impl, we don't set the icon here */
6284 if (!icon_view->priv->dest_set && !icon_view->priv->source_set)
6287 item = gtk_icon_view_get_item_at_coords (icon_view,
6288 icon_view->priv->press_start_x,
6289 icon_view->priv->press_start_y,
6293 g_return_if_fail (item != NULL);
6295 x = icon_view->priv->press_start_x - item->cell_area.x + 1;
6296 y = icon_view->priv->press_start_y - item->cell_area.y + 1;
6298 path = gtk_tree_path_new_from_indices (item->index, -1);
6299 icon = gtk_icon_view_create_drag_icon (icon_view, path);
6300 gtk_tree_path_free (path);
6302 cairo_surface_set_device_offset (icon, -x, -y);
6304 gtk_drag_set_icon_surface (context, icon);
6306 cairo_surface_destroy (icon);
6310 gtk_icon_view_drag_end (GtkWidget *widget,
6311 GdkDragContext *context)
6317 gtk_icon_view_drag_data_get (GtkWidget *widget,
6318 GdkDragContext *context,
6319 GtkSelectionData *selection_data,
6323 GtkIconView *icon_view;
6324 GtkTreeModel *model;
6325 GtkTreePath *source_row;
6327 icon_view = GTK_ICON_VIEW (widget);
6328 model = gtk_icon_view_get_model (icon_view);
6333 if (!icon_view->priv->source_set)
6336 source_row = get_source_row (context);
6338 if (source_row == NULL)
6341 /* We can implement the GTK_TREE_MODEL_ROW target generically for
6342 * any model; for DragSource models there are some other targets
6346 if (GTK_IS_TREE_DRAG_SOURCE (model) &&
6347 gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
6352 /* If drag_data_get does nothing, try providing row data. */
6353 if (gtk_selection_data_get_target (selection_data) == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
6354 gtk_tree_set_row_drag_data (selection_data,
6359 gtk_tree_path_free (source_row);
6363 gtk_icon_view_drag_data_delete (GtkWidget *widget,
6364 GdkDragContext *context)
6366 GtkTreeModel *model;
6367 GtkIconView *icon_view;
6368 GtkTreePath *source_row;
6370 icon_view = GTK_ICON_VIEW (widget);
6371 model = gtk_icon_view_get_model (icon_view);
6373 if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag-data-delete"))
6376 if (!icon_view->priv->source_set)
6379 source_row = get_source_row (context);
6381 if (source_row == NULL)
6384 gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
6387 gtk_tree_path_free (source_row);
6389 set_source_row (context, NULL, NULL);
6392 /* Target side drag signals */
6394 gtk_icon_view_drag_leave (GtkWidget *widget,
6395 GdkDragContext *context,
6398 GtkIconView *icon_view;
6400 icon_view = GTK_ICON_VIEW (widget);
6402 /* unset any highlight row */
6403 gtk_icon_view_set_drag_dest_item (icon_view,
6405 GTK_ICON_VIEW_DROP_LEFT);
6407 remove_scroll_timeout (icon_view);
6411 gtk_icon_view_drag_motion (GtkWidget *widget,
6412 GdkDragContext *context,
6417 GtkTreePath *path = NULL;
6418 GtkIconViewDropPosition pos;
6419 GtkIconView *icon_view;
6420 GdkDragAction suggested_action = 0;
6424 icon_view = GTK_ICON_VIEW (widget);
6426 if (!set_destination (icon_view, context, x, y, &suggested_action, &target))
6429 gtk_icon_view_get_drag_dest_item (icon_view, &path, &pos);
6431 /* we only know this *after* set_desination_row */
6432 empty = icon_view->priv->empty_view_drop;
6434 if (path == NULL && !empty)
6436 /* Can't drop here. */
6437 gdk_drag_status (context, 0, time);
6441 if (icon_view->priv->scroll_timeout_id == 0)
6443 icon_view->priv->scroll_timeout_id =
6444 gdk_threads_add_timeout (50, drag_scroll_timeout, icon_view);
6447 if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
6449 /* Request data so we can use the source row when
6450 * determining whether to accept the drop
6452 set_status_pending (context, suggested_action);
6453 gtk_drag_get_data (widget, context, target, time);
6457 set_status_pending (context, 0);
6458 gdk_drag_status (context, suggested_action, time);
6463 gtk_tree_path_free (path);
6469 gtk_icon_view_drag_drop (GtkWidget *widget,
6470 GdkDragContext *context,
6475 GtkIconView *icon_view;
6477 GdkDragAction suggested_action = 0;
6478 GdkAtom target = GDK_NONE;
6479 GtkTreeModel *model;
6480 gboolean drop_append_mode;
6482 icon_view = GTK_ICON_VIEW (widget);
6483 model = gtk_icon_view_get_model (icon_view);
6485 remove_scroll_timeout (GTK_ICON_VIEW (widget));
6487 if (!icon_view->priv->dest_set)
6490 if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag-drop"))
6493 if (!set_destination (icon_view, context, x, y, &suggested_action, &target))
6496 path = get_logical_destination (icon_view, &drop_append_mode);
6498 if (target != GDK_NONE && path != NULL)
6500 /* in case a motion had requested drag data, change things so we
6501 * treat drag data receives as a drop.
6503 set_status_pending (context, 0);
6504 set_dest_row (context, model, path,
6505 icon_view->priv->empty_view_drop, drop_append_mode);
6509 gtk_tree_path_free (path);
6511 /* Unset this thing */
6512 gtk_icon_view_set_drag_dest_item (icon_view, NULL, GTK_ICON_VIEW_DROP_LEFT);
6514 if (target != GDK_NONE)
6516 gtk_drag_get_data (widget, context, target, time);
6524 gtk_icon_view_drag_data_received (GtkWidget *widget,
6525 GdkDragContext *context,
6528 GtkSelectionData *selection_data,
6533 gboolean accepted = FALSE;
6534 GtkTreeModel *model;
6535 GtkIconView *icon_view;
6536 GtkTreePath *dest_row;
6537 GdkDragAction suggested_action;
6538 gboolean drop_append_mode;
6540 icon_view = GTK_ICON_VIEW (widget);
6541 model = gtk_icon_view_get_model (icon_view);
6543 if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag-data-received"))
6546 if (!icon_view->priv->dest_set)
6549 suggested_action = get_status_pending (context);
6551 if (suggested_action)
6553 /* We are getting this data due to a request in drag_motion,
6554 * rather than due to a request in drag_drop, so we are just
6555 * supposed to call drag_status, not actually paste in the
6558 path = get_logical_destination (icon_view, &drop_append_mode);
6561 suggested_action = 0;
6563 if (suggested_action)
6565 if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
6568 suggested_action = 0;
6571 gdk_drag_status (context, suggested_action, time);
6574 gtk_tree_path_free (path);
6576 /* If you can't drop, remove user drop indicator until the next motion */
6577 if (suggested_action == 0)
6578 gtk_icon_view_set_drag_dest_item (icon_view,
6580 GTK_ICON_VIEW_DROP_LEFT);
6585 dest_row = get_dest_row (context);
6587 if (dest_row == NULL)
6590 if (gtk_selection_data_get_length (selection_data) >= 0)
6592 if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
6598 gtk_drag_finish (context,
6600 (gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE),
6603 gtk_tree_path_free (dest_row);
6606 set_dest_row (context, NULL, NULL, FALSE, FALSE);
6609 /* Drag-and-Drop support */
6611 * gtk_icon_view_enable_model_drag_source:
6612 * @icon_view: a #GtkIconTreeView
6613 * @start_button_mask: Mask of allowed buttons to start drag
6614 * @targets: (array length=n_targets): the table of targets that the drag will
6616 * @n_targets: the number of items in @targets
6617 * @actions: the bitmask of possible actions for a drag from this
6620 * Turns @icon_view into a drag source for automatic DND. Calling this
6621 * method sets #GtkIconView:reorderable to %FALSE.
6626 gtk_icon_view_enable_model_drag_source (GtkIconView *icon_view,
6627 GdkModifierType start_button_mask,
6628 const GtkTargetEntry *targets,
6630 GdkDragAction actions)
6632 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6634 gtk_drag_source_set (GTK_WIDGET (icon_view), 0, targets, n_targets, actions);
6636 icon_view->priv->start_button_mask = start_button_mask;
6637 icon_view->priv->source_actions = actions;
6639 icon_view->priv->source_set = TRUE;
6641 unset_reorderable (icon_view);
6645 * gtk_icon_view_enable_model_drag_dest:
6646 * @icon_view: a #GtkIconView
6647 * @targets: (array length=n_targets): the table of targets that the drag will
6649 * @n_targets: the number of items in @targets
6650 * @actions: the bitmask of possible actions for a drag to this
6653 * Turns @icon_view into a drop destination for automatic DND. Calling this
6654 * method sets #GtkIconView:reorderable to %FALSE.
6659 gtk_icon_view_enable_model_drag_dest (GtkIconView *icon_view,
6660 const GtkTargetEntry *targets,
6662 GdkDragAction actions)
6664 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6666 gtk_drag_dest_set (GTK_WIDGET (icon_view), 0, targets, n_targets, actions);
6668 icon_view->priv->dest_actions = actions;
6670 icon_view->priv->dest_set = TRUE;
6672 unset_reorderable (icon_view);
6676 * gtk_icon_view_unset_model_drag_source:
6677 * @icon_view: a #GtkIconView
6679 * Undoes the effect of gtk_icon_view_enable_model_drag_source(). Calling this
6680 * method sets #GtkIconView:reorderable to %FALSE.
6685 gtk_icon_view_unset_model_drag_source (GtkIconView *icon_view)
6687 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6689 if (icon_view->priv->source_set)
6691 gtk_drag_source_unset (GTK_WIDGET (icon_view));
6692 icon_view->priv->source_set = FALSE;
6695 unset_reorderable (icon_view);
6699 * gtk_icon_view_unset_model_drag_dest:
6700 * @icon_view: a #GtkIconView
6702 * Undoes the effect of gtk_icon_view_enable_model_drag_dest(). Calling this
6703 * method sets #GtkIconView:reorderable to %FALSE.
6708 gtk_icon_view_unset_model_drag_dest (GtkIconView *icon_view)
6710 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6712 if (icon_view->priv->dest_set)
6714 gtk_drag_dest_unset (GTK_WIDGET (icon_view));
6715 icon_view->priv->dest_set = FALSE;
6718 unset_reorderable (icon_view);
6721 /* These are useful to implement your own custom stuff. */
6723 * gtk_icon_view_set_drag_dest_item:
6724 * @icon_view: a #GtkIconView
6725 * @path: (allow-none): The path of the item to highlight, or %NULL.
6726 * @pos: Specifies where to drop, relative to the item
6728 * Sets the item that is highlighted for feedback.
6733 gtk_icon_view_set_drag_dest_item (GtkIconView *icon_view,
6735 GtkIconViewDropPosition pos)
6737 /* Note; this function is exported to allow a custom DND
6738 * implementation, so it can't touch TreeViewDragInfo
6741 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6743 if (icon_view->priv->dest_item)
6745 GtkTreePath *current_path;
6746 current_path = gtk_tree_row_reference_get_path (icon_view->priv->dest_item);
6747 gtk_tree_row_reference_free (icon_view->priv->dest_item);
6748 icon_view->priv->dest_item = NULL;
6750 gtk_icon_view_queue_draw_path (icon_view, current_path);
6751 gtk_tree_path_free (current_path);
6754 /* special case a drop on an empty model */
6755 icon_view->priv->empty_view_drop = FALSE;
6756 if (pos == GTK_ICON_VIEW_DROP_ABOVE && path
6757 && gtk_tree_path_get_depth (path) == 1
6758 && gtk_tree_path_get_indices (path)[0] == 0)
6762 n_children = gtk_tree_model_iter_n_children (icon_view->priv->model,
6765 if (n_children == 0)
6766 icon_view->priv->empty_view_drop = TRUE;
6769 icon_view->priv->dest_pos = pos;
6773 icon_view->priv->dest_item =
6774 gtk_tree_row_reference_new_proxy (G_OBJECT (icon_view),
6775 icon_view->priv->model, path);
6777 gtk_icon_view_queue_draw_path (icon_view, path);
6782 * gtk_icon_view_get_drag_dest_item:
6783 * @icon_view: a #GtkIconView
6784 * @path: (out) (allow-none): Return location for the path of
6785 * the highlighted item, or %NULL.
6786 * @pos: (out) (allow-none): Return location for the drop position, or %NULL
6788 * Gets information about the item that is highlighted for feedback.
6793 gtk_icon_view_get_drag_dest_item (GtkIconView *icon_view,
6795 GtkIconViewDropPosition *pos)
6797 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6801 if (icon_view->priv->dest_item)
6802 *path = gtk_tree_row_reference_get_path (icon_view->priv->dest_item);
6808 *pos = icon_view->priv->dest_pos;
6812 * gtk_icon_view_get_dest_item_at_pos:
6813 * @icon_view: a #GtkIconView
6814 * @drag_x: the position to determine the destination item for
6815 * @drag_y: the position to determine the destination item for
6816 * @path: (out) (allow-none): Return location for the path of the item,
6818 * @pos: (out) (allow-none): Return location for the drop position, or %NULL
6820 * Determines the destination item for a given position.
6822 * Return value: whether there is an item at the given position.
6827 gtk_icon_view_get_dest_item_at_pos (GtkIconView *icon_view,
6831 GtkIconViewDropPosition *pos)
6833 GtkIconViewItem *item;
6835 /* Note; this function is exported to allow a custom DND
6836 * implementation, so it can't touch TreeViewDragInfo
6839 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
6840 g_return_val_if_fail (drag_x >= 0, FALSE);
6841 g_return_val_if_fail (drag_y >= 0, FALSE);
6842 g_return_val_if_fail (icon_view->priv->bin_window != NULL, FALSE);
6848 item = gtk_icon_view_get_item_at_coords (icon_view,
6849 drag_x + gtk_adjustment_get_value (icon_view->priv->hadjustment),
6850 drag_y + gtk_adjustment_get_value (icon_view->priv->vadjustment),
6857 *path = gtk_tree_path_new_from_indices (item->index, -1);
6861 if (drag_x < item->cell_area.x + item->cell_area.width / 4)
6862 *pos = GTK_ICON_VIEW_DROP_LEFT;
6863 else if (drag_x > item->cell_area.x + item->cell_area.width * 3 / 4)
6864 *pos = GTK_ICON_VIEW_DROP_RIGHT;
6865 else if (drag_y < item->cell_area.y + item->cell_area.height / 4)
6866 *pos = GTK_ICON_VIEW_DROP_ABOVE;
6867 else if (drag_y > item->cell_area.y + item->cell_area.height * 3 / 4)
6868 *pos = GTK_ICON_VIEW_DROP_BELOW;
6870 *pos = GTK_ICON_VIEW_DROP_INTO;
6877 * gtk_icon_view_create_drag_icon:
6878 * @icon_view: a #GtkIconView
6879 * @path: a #GtkTreePath in @icon_view
6881 * Creates a #cairo_surface_t representation of the item at @path.
6882 * This image is used for a drag icon.
6884 * Return value: (transfer full): a newly-allocated surface of the drag icon.
6889 gtk_icon_view_create_drag_icon (GtkIconView *icon_view,
6893 GtkStyleContext *context;
6895 cairo_surface_t *surface;
6899 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
6900 g_return_val_if_fail (path != NULL, NULL);
6902 widget = GTK_WIDGET (icon_view);
6903 context = gtk_widget_get_style_context (widget);
6905 if (!gtk_widget_get_realized (widget))
6908 index = gtk_tree_path_get_indices (path)[0];
6910 for (l = icon_view->priv->items; l; l = l->next)
6912 GtkIconViewItem *item = l->data;
6914 if (index == item->index)
6916 GdkRectangle rect = {
6917 item->cell_area.x - icon_view->priv->item_padding,
6918 item->cell_area.y - icon_view->priv->item_padding,
6919 item->cell_area.width + icon_view->priv->item_padding * 2,
6920 item->cell_area.height + icon_view->priv->item_padding * 2
6923 surface = gdk_window_create_similar_surface (icon_view->priv->bin_window,
6924 CAIRO_CONTENT_COLOR,
6928 cr = cairo_create (surface);
6929 cairo_set_line_width (cr, 1.);
6931 gtk_render_background (context, cr, 0, 0,
6932 rect.width + 2, rect.height + 2);
6936 cairo_rectangle (cr, 1, 1, rect.width, rect.height);
6939 gtk_icon_view_paint_item (icon_view, cr, item,
6940 icon_view->priv->item_padding + 1,
6941 icon_view->priv->item_padding + 1, FALSE);
6945 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
6946 cairo_rectangle (cr, 0.5, 0.5, rect.width + 1, rect.height + 1);
6959 * gtk_icon_view_get_reorderable:
6960 * @icon_view: a #GtkIconView
6962 * Retrieves whether the user can reorder the list via drag-and-drop.
6963 * See gtk_icon_view_set_reorderable().
6965 * Return value: %TRUE if the list can be reordered.
6970 gtk_icon_view_get_reorderable (GtkIconView *icon_view)
6972 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
6974 return icon_view->priv->reorderable;
6977 static const GtkTargetEntry item_targets[] = {
6978 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
6983 * gtk_icon_view_set_reorderable:
6984 * @icon_view: A #GtkIconView.
6985 * @reorderable: %TRUE, if the list of items can be reordered.
6987 * This function is a convenience function to allow you to reorder models that
6988 * support the #GtkTreeDragSourceIface and the #GtkTreeDragDestIface. Both
6989 * #GtkTreeStore and #GtkListStore support these. If @reorderable is %TRUE, then
6990 * the user can reorder the model by dragging and dropping rows. The
6991 * developer can listen to these changes by connecting to the model's
6992 * row_inserted and row_deleted signals. The reordering is implemented by setting up
6993 * the icon view as a drag source and destination. Therefore, drag and
6994 * drop can not be used in a reorderable view for any other purpose.
6996 * This function does not give you any degree of control over the order -- any
6997 * reordering is allowed. If more control is needed, you should probably
6998 * handle drag and drop manually.
7003 gtk_icon_view_set_reorderable (GtkIconView *icon_view,
7004 gboolean reorderable)
7006 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
7008 reorderable = reorderable != FALSE;
7010 if (icon_view->priv->reorderable == reorderable)
7015 gtk_icon_view_enable_model_drag_source (icon_view,
7018 G_N_ELEMENTS (item_targets),
7020 gtk_icon_view_enable_model_drag_dest (icon_view,
7022 G_N_ELEMENTS (item_targets),
7027 gtk_icon_view_unset_model_drag_source (icon_view);
7028 gtk_icon_view_unset_model_drag_dest (icon_view);
7031 icon_view->priv->reorderable = reorderable;
7033 g_object_notify (G_OBJECT (icon_view), "reorderable");
7037 /* Accessibility Support */
7039 static gpointer accessible_parent_class;
7040 static gpointer accessible_item_parent_class;
7041 static GQuark accessible_private_data_quark = 0;
7043 #define GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE (gtk_icon_view_item_accessible_get_type ())
7044 #define GTK_ICON_VIEW_ITEM_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE, GtkIconViewItemAccessible))
7045 #define GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE))
7047 static GType gtk_icon_view_item_accessible_get_type (void);
7058 GtkIconViewItem *item;
7062 AtkStateSet *state_set;
7066 GtkTextBuffer *text_buffer;
7068 gchar *action_descriptions[LAST_ACTION];
7069 gchar *image_description;
7070 guint action_idle_handler;
7071 } GtkIconViewItemAccessible;
7073 static const gchar *const gtk_icon_view_item_accessible_action_names[] =
7079 static const gchar *const gtk_icon_view_item_accessible_action_descriptions[] =
7084 typedef struct _GtkIconViewItemAccessibleClass
7086 AtkObjectClass parent_class;
7088 } GtkIconViewItemAccessibleClass;
7090 static gboolean gtk_icon_view_item_accessible_is_showing (GtkIconViewItemAccessible *item);
7093 gtk_icon_view_item_accessible_idle_do_action (gpointer data)
7095 GtkIconViewItemAccessible *item;
7096 GtkIconView *icon_view;
7099 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (data);
7100 item->action_idle_handler = 0;
7102 if (item->widget != NULL)
7104 icon_view = GTK_ICON_VIEW (item->widget);
7105 path = gtk_tree_path_new_from_indices (item->item->index, -1);
7106 gtk_icon_view_item_activated (icon_view, path);
7107 gtk_tree_path_free (path);
7114 gtk_icon_view_item_accessible_action_do_action (AtkAction *action,
7117 GtkIconViewItemAccessible *item;
7119 if (i < 0 || i >= LAST_ACTION)
7122 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
7124 if (!GTK_IS_ICON_VIEW (item->widget))
7127 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7132 case ACTION_ACTIVATE:
7133 if (!item->action_idle_handler)
7134 item->action_idle_handler = gdk_threads_add_idle (gtk_icon_view_item_accessible_idle_do_action, item);
7137 g_assert_not_reached ();
7145 gtk_icon_view_item_accessible_action_get_n_actions (AtkAction *action)
7150 static const gchar *
7151 gtk_icon_view_item_accessible_action_get_description (AtkAction *action,
7154 GtkIconViewItemAccessible *item;
7156 if (i < 0 || i >= LAST_ACTION)
7159 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
7161 if (item->action_descriptions[i])
7162 return item->action_descriptions[i];
7164 return gtk_icon_view_item_accessible_action_descriptions[i];
7167 static const gchar *
7168 gtk_icon_view_item_accessible_action_get_name (AtkAction *action,
7171 if (i < 0 || i >= LAST_ACTION)
7174 return gtk_icon_view_item_accessible_action_names[i];
7178 gtk_icon_view_item_accessible_action_set_description (AtkAction *action,
7180 const gchar *description)
7182 GtkIconViewItemAccessible *item;
7184 if (i < 0 || i >= LAST_ACTION)
7187 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
7189 g_free (item->action_descriptions[i]);
7191 item->action_descriptions[i] = g_strdup (description);
7197 atk_action_item_interface_init (AtkActionIface *iface)
7199 iface->do_action = gtk_icon_view_item_accessible_action_do_action;
7200 iface->get_n_actions = gtk_icon_view_item_accessible_action_get_n_actions;
7201 iface->get_description = gtk_icon_view_item_accessible_action_get_description;
7202 iface->get_name = gtk_icon_view_item_accessible_action_get_name;
7203 iface->set_description = gtk_icon_view_item_accessible_action_set_description;
7206 static const gchar *
7207 gtk_icon_view_item_accessible_image_get_image_description (AtkImage *image)
7209 GtkIconViewItemAccessible *item;
7211 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7213 return item->image_description;
7217 gtk_icon_view_item_accessible_image_set_image_description (AtkImage *image,
7218 const gchar *description)
7220 GtkIconViewItemAccessible *item;
7222 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7224 g_free (item->image_description);
7225 item->image_description = g_strdup (description);
7232 gboolean pixbuf_found;
7236 get_pixbuf_foreach (GtkCellRenderer *renderer,
7237 const GdkRectangle *cell_area,
7238 const GdkRectangle *cell_background,
7239 GetPixbufBoxData *data)
7241 if (GTK_IS_CELL_RENDERER_PIXBUF (renderer))
7243 data->box = *cell_area;
7244 data->pixbuf_found = TRUE;
7246 return (data->pixbuf_found != FALSE);
7250 get_pixbuf_box (GtkIconView *icon_view,
7251 GtkIconViewItem *item,
7254 GetPixbufBoxData data = { { 0, }, FALSE };
7255 GtkCellAreaContext *context;
7257 context = g_ptr_array_index (icon_view->priv->row_contexts, item->row);
7259 gtk_icon_view_set_cell_data (icon_view, item);
7260 gtk_cell_area_foreach_alloc (icon_view->priv->cell_area, context,
7261 GTK_WIDGET (icon_view),
7262 (GdkRectangle *)item, (GdkRectangle *)item,
7263 (GtkCellAllocCallback)get_pixbuf_foreach, &data);
7265 return data.pixbuf_found;
7269 get_text_foreach (GtkCellRenderer *renderer,
7272 if (GTK_IS_CELL_RENDERER_TEXT (renderer))
7274 g_object_get (renderer, "text", text, NULL);
7282 get_text (GtkIconView *icon_view,
7283 GtkIconViewItem *item)
7287 gtk_icon_view_set_cell_data (icon_view, item);
7288 gtk_cell_area_foreach (icon_view->priv->cell_area,
7289 (GtkCellCallback)get_text_foreach, &text);
7295 gtk_icon_view_item_accessible_image_get_image_size (AtkImage *image,
7299 GtkIconViewItemAccessible *item;
7302 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7304 if (!GTK_IS_ICON_VIEW (item->widget))
7307 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7310 if (get_pixbuf_box (GTK_ICON_VIEW (item->widget), item->item, &box))
7313 *height = box.height;
7318 gtk_icon_view_item_accessible_image_get_image_position (AtkImage *image,
7321 AtkCoordType coord_type)
7323 GtkIconViewItemAccessible *item;
7326 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7328 if (!GTK_IS_ICON_VIEW (item->widget))
7331 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7334 atk_component_get_position (ATK_COMPONENT (image), x, y, coord_type);
7336 if (get_pixbuf_box (GTK_ICON_VIEW (item->widget), item->item, &box))
7338 *x+= box.x - item->item->cell_area.x;
7339 *y+= box.y - item->item->cell_area.y;
7345 atk_image_item_interface_init (AtkImageIface *iface)
7347 iface->get_image_description = gtk_icon_view_item_accessible_image_get_image_description;
7348 iface->set_image_description = gtk_icon_view_item_accessible_image_set_image_description;
7349 iface->get_image_size = gtk_icon_view_item_accessible_image_get_image_size;
7350 iface->get_image_position = gtk_icon_view_item_accessible_image_get_image_position;
7354 gtk_icon_view_item_accessible_text_get_text (AtkText *text,
7358 GtkIconViewItemAccessible *item;
7359 GtkTextIter start, end;
7360 GtkTextBuffer *buffer;
7362 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7364 if (!GTK_IS_ICON_VIEW (item->widget))
7367 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7370 buffer = item->text_buffer;
7371 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
7373 gtk_text_buffer_get_end_iter (buffer, &end);
7375 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
7377 return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
7381 gtk_icon_view_item_accessible_text_get_character_at_offset (AtkText *text,
7384 GtkIconViewItemAccessible *item;
7385 GtkTextIter start, end;
7386 GtkTextBuffer *buffer;
7390 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7392 if (!GTK_IS_ICON_VIEW (item->widget))
7395 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7398 buffer = item->text_buffer;
7399 if (offset >= gtk_text_buffer_get_char_count (buffer))
7402 gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
7404 gtk_text_iter_forward_char (&end);
7405 string = gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
7406 unichar = g_utf8_get_char (string);
7414 get_pango_text_offsets (PangoLayout *layout,
7415 GtkTextBuffer *buffer,
7417 AtkTextBoundary boundary_type,
7421 GtkTextIter *start_iter,
7422 GtkTextIter *end_iter)
7424 PangoLayoutIter *iter;
7425 PangoLayoutLine *line, *prev_line = NULL, *prev_prev_line = NULL;
7426 gint index, start_index, end_index;
7428 gboolean found = FALSE;
7430 text = pango_layout_get_text (layout);
7431 index = g_utf8_offset_to_pointer (text, offset) - text;
7432 iter = pango_layout_get_iter (layout);
7435 line = pango_layout_iter_get_line_readonly (iter);
7436 start_index = line->start_index;
7437 end_index = start_index + line->length;
7439 if (index >= start_index && index <= end_index)
7442 * Found line for offset
7448 * We want the previous line
7452 switch (boundary_type)
7454 case ATK_TEXT_BOUNDARY_LINE_START:
7455 end_index = start_index;
7456 start_index = prev_line->start_index;
7458 case ATK_TEXT_BOUNDARY_LINE_END:
7460 start_index = prev_prev_line->start_index +
7461 prev_prev_line->length;
7462 end_index = prev_line->start_index + prev_line->length;
7465 g_assert_not_reached();
7469 start_index = end_index = 0;
7472 switch (boundary_type)
7474 case ATK_TEXT_BOUNDARY_LINE_START:
7475 if (pango_layout_iter_next_line (iter))
7476 end_index = pango_layout_iter_get_line_readonly (iter)->start_index;
7478 case ATK_TEXT_BOUNDARY_LINE_END:
7480 start_index = prev_line->start_index +
7484 g_assert_not_reached();
7489 * We want the next line
7491 if (pango_layout_iter_next_line (iter))
7493 line = pango_layout_iter_get_line_readonly (iter);
7494 switch (boundary_type)
7496 case ATK_TEXT_BOUNDARY_LINE_START:
7497 start_index = line->start_index;
7498 if (pango_layout_iter_next_line (iter))
7499 end_index = pango_layout_iter_get_line_readonly (iter)->start_index;
7501 end_index = start_index + line->length;
7503 case ATK_TEXT_BOUNDARY_LINE_END:
7504 start_index = end_index;
7505 end_index = line->start_index + line->length;
7508 g_assert_not_reached();
7512 start_index = end_index;
7518 prev_prev_line = prev_line;
7521 while (pango_layout_iter_next_line (iter));
7525 start_index = prev_line->start_index + prev_line->length;
7526 end_index = start_index;
7528 pango_layout_iter_free (iter);
7529 *start_offset = g_utf8_pointer_to_offset (text, text + start_index);
7530 *end_offset = g_utf8_pointer_to_offset (text, text + end_index);
7532 gtk_text_buffer_get_iter_at_offset (buffer, start_iter, *start_offset);
7533 gtk_text_buffer_get_iter_at_offset (buffer, end_iter, *end_offset);
7538 gtk_icon_view_item_accessible_text_get_text_before_offset (AtkText *text,
7540 AtkTextBoundary boundary_type,
7544 GtkIconViewItemAccessible *item;
7545 GtkTextIter start, end;
7546 GtkTextBuffer *buffer;
7548 GtkIconView *icon_view;
7551 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7553 if (!GTK_IS_ICON_VIEW (item->widget))
7556 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7559 buffer = item->text_buffer;
7561 if (!gtk_text_buffer_get_char_count (buffer))
7565 return g_strdup ("");
7567 gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
7571 switch (boundary_type)
7573 case ATK_TEXT_BOUNDARY_CHAR:
7574 gtk_text_iter_backward_char(&start);
7576 case ATK_TEXT_BOUNDARY_WORD_START:
7577 if (!gtk_text_iter_starts_word (&start))
7578 gtk_text_iter_backward_word_start (&start);
7580 gtk_text_iter_backward_word_start(&start);
7582 case ATK_TEXT_BOUNDARY_WORD_END:
7583 if (gtk_text_iter_inside_word (&start) &&
7584 !gtk_text_iter_starts_word (&start))
7585 gtk_text_iter_backward_word_start (&start);
7586 while (!gtk_text_iter_ends_word (&start))
7588 if (!gtk_text_iter_backward_char (&start))
7592 gtk_text_iter_backward_word_start(&start);
7593 while (!gtk_text_iter_ends_word (&start))
7595 if (!gtk_text_iter_backward_char (&start))
7599 case ATK_TEXT_BOUNDARY_SENTENCE_START:
7600 if (!gtk_text_iter_starts_sentence (&start))
7601 gtk_text_iter_backward_sentence_start (&start);
7603 gtk_text_iter_backward_sentence_start (&start);
7605 case ATK_TEXT_BOUNDARY_SENTENCE_END:
7606 if (gtk_text_iter_inside_sentence (&start) &&
7607 !gtk_text_iter_starts_sentence (&start))
7608 gtk_text_iter_backward_sentence_start (&start);
7609 while (!gtk_text_iter_ends_sentence (&start))
7611 if (!gtk_text_iter_backward_char (&start))
7615 gtk_text_iter_backward_sentence_start (&start);
7616 while (!gtk_text_iter_ends_sentence (&start))
7618 if (!gtk_text_iter_backward_char (&start))
7622 case ATK_TEXT_BOUNDARY_LINE_START:
7623 case ATK_TEXT_BOUNDARY_LINE_END:
7625 icon_view = GTK_ICON_VIEW (item->widget);
7626 /* FIXME we probably have to use GailTextCell to salvage this */
7627 gtk_icon_view_update_item_text (icon_view, item->item);
7628 get_pango_text_offsets (icon_view->priv->layout,
7641 *start_offset = gtk_text_iter_get_offset (&start);
7642 *end_offset = gtk_text_iter_get_offset (&end);
7644 return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
7648 gtk_icon_view_item_accessible_text_get_text_at_offset (AtkText *text,
7650 AtkTextBoundary boundary_type,
7654 GtkIconViewItemAccessible *item;
7655 GtkTextIter start, end;
7656 GtkTextBuffer *buffer;
7658 GtkIconView *icon_view;
7661 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7663 if (!GTK_IS_ICON_VIEW (item->widget))
7666 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7669 buffer = item->text_buffer;
7671 if (!gtk_text_buffer_get_char_count (buffer))
7675 return g_strdup ("");
7677 gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
7681 switch (boundary_type)
7683 case ATK_TEXT_BOUNDARY_CHAR:
7684 gtk_text_iter_forward_char (&end);
7686 case ATK_TEXT_BOUNDARY_WORD_START:
7687 if (!gtk_text_iter_starts_word (&start))
7688 gtk_text_iter_backward_word_start (&start);
7689 if (gtk_text_iter_inside_word (&end))
7690 gtk_text_iter_forward_word_end (&end);
7691 while (!gtk_text_iter_starts_word (&end))
7693 if (!gtk_text_iter_forward_char (&end))
7697 case ATK_TEXT_BOUNDARY_WORD_END:
7698 if (gtk_text_iter_inside_word (&start) &&
7699 !gtk_text_iter_starts_word (&start))
7700 gtk_text_iter_backward_word_start (&start);
7701 while (!gtk_text_iter_ends_word (&start))
7703 if (!gtk_text_iter_backward_char (&start))
7706 gtk_text_iter_forward_word_end (&end);
7708 case ATK_TEXT_BOUNDARY_SENTENCE_START:
7709 if (!gtk_text_iter_starts_sentence (&start))
7710 gtk_text_iter_backward_sentence_start (&start);
7711 if (gtk_text_iter_inside_sentence (&end))
7712 gtk_text_iter_forward_sentence_end (&end);
7713 while (!gtk_text_iter_starts_sentence (&end))
7715 if (!gtk_text_iter_forward_char (&end))
7719 case ATK_TEXT_BOUNDARY_SENTENCE_END:
7720 if (gtk_text_iter_inside_sentence (&start) &&
7721 !gtk_text_iter_starts_sentence (&start))
7722 gtk_text_iter_backward_sentence_start (&start);
7723 while (!gtk_text_iter_ends_sentence (&start))
7725 if (!gtk_text_iter_backward_char (&start))
7728 gtk_text_iter_forward_sentence_end (&end);
7730 case ATK_TEXT_BOUNDARY_LINE_START:
7731 case ATK_TEXT_BOUNDARY_LINE_END:
7733 icon_view = GTK_ICON_VIEW (item->widget);
7734 /* FIXME we probably have to use GailTextCell to salvage this */
7735 gtk_icon_view_update_item_text (icon_view, item->item);
7736 get_pango_text_offsets (icon_view->priv->layout,
7750 *start_offset = gtk_text_iter_get_offset (&start);
7751 *end_offset = gtk_text_iter_get_offset (&end);
7753 return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
7757 gtk_icon_view_item_accessible_text_get_text_after_offset (AtkText *text,
7759 AtkTextBoundary boundary_type,
7763 GtkIconViewItemAccessible *item;
7764 GtkTextIter start, end;
7765 GtkTextBuffer *buffer;
7767 GtkIconView *icon_view;
7770 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7772 if (!GTK_IS_ICON_VIEW (item->widget))
7775 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7778 buffer = item->text_buffer;
7780 if (!gtk_text_buffer_get_char_count (buffer))
7784 return g_strdup ("");
7786 gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
7790 switch (boundary_type)
7792 case ATK_TEXT_BOUNDARY_CHAR:
7793 gtk_text_iter_forward_char(&start);
7794 gtk_text_iter_forward_chars(&end, 2);
7796 case ATK_TEXT_BOUNDARY_WORD_START:
7797 if (gtk_text_iter_inside_word (&end))
7798 gtk_text_iter_forward_word_end (&end);
7799 while (!gtk_text_iter_starts_word (&end))
7801 if (!gtk_text_iter_forward_char (&end))
7805 if (!gtk_text_iter_is_end (&end))
7807 gtk_text_iter_forward_word_end (&end);
7808 while (!gtk_text_iter_starts_word (&end))
7810 if (!gtk_text_iter_forward_char (&end))
7815 case ATK_TEXT_BOUNDARY_WORD_END:
7816 gtk_text_iter_forward_word_end (&end);
7818 if (!gtk_text_iter_is_end (&end))
7819 gtk_text_iter_forward_word_end (&end);
7821 case ATK_TEXT_BOUNDARY_SENTENCE_START:
7822 if (gtk_text_iter_inside_sentence (&end))
7823 gtk_text_iter_forward_sentence_end (&end);
7824 while (!gtk_text_iter_starts_sentence (&end))
7826 if (!gtk_text_iter_forward_char (&end))
7830 if (!gtk_text_iter_is_end (&end))
7832 gtk_text_iter_forward_sentence_end (&end);
7833 while (!gtk_text_iter_starts_sentence (&end))
7835 if (!gtk_text_iter_forward_char (&end))
7840 case ATK_TEXT_BOUNDARY_SENTENCE_END:
7841 gtk_text_iter_forward_sentence_end (&end);
7843 if (!gtk_text_iter_is_end (&end))
7844 gtk_text_iter_forward_sentence_end (&end);
7846 case ATK_TEXT_BOUNDARY_LINE_START:
7847 case ATK_TEXT_BOUNDARY_LINE_END:
7849 icon_view = GTK_ICON_VIEW (item->widget);
7850 /* FIXME we probably have to use GailTextCell to salvage this */
7851 gtk_icon_view_update_item_text (icon_view, item->item);
7852 get_pango_text_offsets (icon_view->priv->layout,
7864 *start_offset = gtk_text_iter_get_offset (&start);
7865 *end_offset = gtk_text_iter_get_offset (&end);
7867 return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
7871 gtk_icon_view_item_accessible_text_get_character_count (AtkText *text)
7873 GtkIconViewItemAccessible *item;
7875 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7877 if (!GTK_IS_ICON_VIEW (item->widget))
7880 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7883 return gtk_text_buffer_get_char_count (item->text_buffer);
7887 gtk_icon_view_item_accessible_text_get_character_extents (AtkText *text,
7893 AtkCoordType coord_type)
7895 GtkIconViewItemAccessible *item;
7897 GtkIconView *icon_view;
7898 PangoRectangle char_rect;
7899 const gchar *item_text;
7903 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7905 if (!GTK_IS_ICON_VIEW (item->widget))
7908 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7912 icon_view = GTK_ICON_VIEW (item->widget);
7913 /* FIXME we probably have to use GailTextCell to salvage this */
7914 gtk_icon_view_update_item_text (icon_view, item->item);
7915 item_text = pango_layout_get_text (icon_view->priv->layout);
7916 index = g_utf8_offset_to_pointer (item_text, offset) - item_text;
7917 pango_layout_index_to_pos (icon_view->priv->layout, index, &char_rect);
7919 atk_component_get_position (ATK_COMPONENT (text), x, y, coord_type);
7920 *x += item->item->layout_x - item->item->x + char_rect.x / PANGO_SCALE;
7921 /* Look at gtk_icon_view_paint_item() to see where the text is. */
7922 *x -= ((item->item->width - item->item->layout_width) / 2) + (MAX (item->item->pixbuf_width, icon_view->priv->item_width) - item->item->width) / 2,
7923 *y += item->item->layout_y - item->item->y + char_rect.y / PANGO_SCALE;
7924 *width = char_rect.width / PANGO_SCALE;
7925 *height = char_rect.height / PANGO_SCALE;
7930 gtk_icon_view_item_accessible_text_get_offset_at_point (AtkText *text,
7933 AtkCoordType coord_type)
7935 GtkIconViewItemAccessible *item;
7938 GtkIconView *icon_view;
7939 const gchar *item_text;
7944 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7946 if (!GTK_IS_ICON_VIEW (item->widget))
7949 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7953 icon_view = GTK_ICON_VIEW (item->widget);
7954 /* FIXME we probably have to use GailTextCell to salvage this */
7955 gtk_icon_view_update_item_text (icon_view, item->item);
7956 atk_component_get_position (ATK_COMPONENT (text), &l_x, &l_y, coord_type);
7957 x -= l_x + item->item->layout_x - item->item->x;
7958 x += ((item->item->width - item->item->layout_width) / 2) + (MAX (item->item->pixbuf_width, icon_view->priv->item_width) - item->item->width) / 2,
7959 y -= l_y + item->item->layout_y - item->item->y;
7960 item_text = pango_layout_get_text (icon_view->priv->layout);
7961 if (!pango_layout_xy_to_index (icon_view->priv->layout,
7972 offset = g_utf8_strlen (item_text, -1);
7974 offset = g_utf8_pointer_to_offset (item_text, item_text + index);
7980 atk_text_item_interface_init (AtkTextIface *iface)
7982 iface->get_text = gtk_icon_view_item_accessible_text_get_text;
7983 iface->get_character_at_offset = gtk_icon_view_item_accessible_text_get_character_at_offset;
7984 iface->get_text_before_offset = gtk_icon_view_item_accessible_text_get_text_before_offset;
7985 iface->get_text_at_offset = gtk_icon_view_item_accessible_text_get_text_at_offset;
7986 iface->get_text_after_offset = gtk_icon_view_item_accessible_text_get_text_after_offset;
7987 iface->get_character_count = gtk_icon_view_item_accessible_text_get_character_count;
7988 iface->get_character_extents = gtk_icon_view_item_accessible_text_get_character_extents;
7989 iface->get_offset_at_point = gtk_icon_view_item_accessible_text_get_offset_at_point;
7993 gtk_icon_view_item_accessible_get_extents (AtkComponent *component,
7998 AtkCoordType coord_type)
8000 GtkIconViewItemAccessible *item;
8001 AtkObject *parent_obj;
8004 g_return_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (component));
8006 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (component);
8007 if (!GTK_IS_WIDGET (item->widget))
8010 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
8013 *width = item->item->cell_area.width;
8014 *height = item->item->cell_area.height;
8015 if (gtk_icon_view_item_accessible_is_showing (item))
8017 parent_obj = gtk_widget_get_accessible (item->widget);
8018 atk_component_get_position (ATK_COMPONENT (parent_obj), &l_x, &l_y, coord_type);
8019 *x = l_x + item->item->cell_area.x;
8020 *y = l_y + item->item->cell_area.y;
8030 gtk_icon_view_item_accessible_grab_focus (AtkComponent *component)
8032 GtkIconViewItemAccessible *item;
8033 GtkWidget *toplevel;
8035 g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (component), FALSE);
8037 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (component);
8038 if (!GTK_IS_WIDGET (item->widget))
8041 gtk_widget_grab_focus (item->widget);
8042 gtk_icon_view_set_cursor_item (GTK_ICON_VIEW (item->widget), item->item, NULL);
8043 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (item->widget));
8044 if (gtk_widget_is_toplevel (toplevel))
8045 gtk_window_present (GTK_WINDOW (toplevel));
8051 atk_component_item_interface_init (AtkComponentIface *iface)
8053 iface->get_extents = gtk_icon_view_item_accessible_get_extents;
8054 iface->grab_focus = gtk_icon_view_item_accessible_grab_focus;
8058 gtk_icon_view_item_accessible_add_state (GtkIconViewItemAccessible *item,
8059 AtkStateType state_type,
8060 gboolean emit_signal)
8064 rc = atk_state_set_add_state (item->state_set, state_type);
8066 * The signal should only be generated if the value changed,
8067 * not when the item is set up. So states that are set
8068 * initially should pass FALSE as the emit_signal argument.
8073 atk_object_notify_state_change (ATK_OBJECT (item), state_type, TRUE);
8074 /* If state_type is ATK_STATE_VISIBLE, additional notification */
8075 if (state_type == ATK_STATE_VISIBLE)
8076 g_signal_emit_by_name (item, "visible-data-changed");
8083 gtk_icon_view_item_accessible_remove_state (GtkIconViewItemAccessible *item,
8084 AtkStateType state_type,
8085 gboolean emit_signal)
8087 if (atk_state_set_contains_state (item->state_set, state_type))
8091 rc = atk_state_set_remove_state (item->state_set, state_type);
8093 * The signal should only be generated if the value changed,
8094 * not when the item is set up. So states that are set
8095 * initially should pass FALSE as the emit_signal argument.
8100 atk_object_notify_state_change (ATK_OBJECT (item), state_type, FALSE);
8101 /* If state_type is ATK_STATE_VISIBLE, additional notification */
8102 if (state_type == ATK_STATE_VISIBLE)
8103 g_signal_emit_by_name (item, "visible-data-changed");
8113 gtk_icon_view_item_accessible_is_showing (GtkIconViewItemAccessible *item)
8115 GtkAllocation allocation;
8116 GtkIconView *icon_view;
8117 GdkRectangle visible_rect;
8118 gboolean is_showing;
8121 * An item is considered "SHOWING" if any part of the item is in the
8122 * visible rectangle.
8125 if (!GTK_IS_ICON_VIEW (item->widget))
8128 if (item->item == NULL)
8131 gtk_widget_get_allocation (item->widget, &allocation);
8133 icon_view = GTK_ICON_VIEW (item->widget);
8135 if (icon_view->priv->hadjustment)
8136 visible_rect.x += gtk_adjustment_get_value (icon_view->priv->hadjustment);
8138 if (icon_view->priv->hadjustment)
8139 visible_rect.y += gtk_adjustment_get_value (icon_view->priv->vadjustment);
8140 visible_rect.width = allocation.width;
8141 visible_rect.height = allocation.height;
8143 if (((item->item->cell_area.x + item->item->cell_area.width) < visible_rect.x) ||
8144 ((item->item->cell_area.y + item->item->cell_area.height) < (visible_rect.y)) ||
8145 (item->item->cell_area.x > (visible_rect.x + visible_rect.width)) ||
8146 (item->item->cell_area.y > (visible_rect.y + visible_rect.height)))
8155 gtk_icon_view_item_accessible_set_visibility (GtkIconViewItemAccessible *item,
8156 gboolean emit_signal)
8158 if (gtk_icon_view_item_accessible_is_showing (item))
8159 return gtk_icon_view_item_accessible_add_state (item, ATK_STATE_SHOWING,
8162 return gtk_icon_view_item_accessible_remove_state (item, ATK_STATE_SHOWING,
8167 gtk_icon_view_item_accessible_object_init (GtkIconViewItemAccessible *item)
8171 item->state_set = atk_state_set_new ();
8173 atk_state_set_add_state (item->state_set, ATK_STATE_ENABLED);
8174 atk_state_set_add_state (item->state_set, ATK_STATE_FOCUSABLE);
8175 atk_state_set_add_state (item->state_set, ATK_STATE_SENSITIVE);
8176 atk_state_set_add_state (item->state_set, ATK_STATE_SELECTABLE);
8177 atk_state_set_add_state (item->state_set, ATK_STATE_VISIBLE);
8179 for (i = 0; i < LAST_ACTION; i++)
8180 item->action_descriptions[i] = NULL;
8182 item->image_description = NULL;
8184 item->action_idle_handler = 0;
8188 gtk_icon_view_item_accessible_finalize (GObject *object)
8190 GtkIconViewItemAccessible *item;
8193 g_return_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (object));
8195 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (object);
8198 g_object_remove_weak_pointer (G_OBJECT (item->widget), (gpointer) &item->widget);
8200 if (item->state_set)
8201 g_object_unref (item->state_set);
8203 if (item->text_buffer)
8204 g_object_unref (item->text_buffer);
8206 for (i = 0; i < LAST_ACTION; i++)
8207 g_free (item->action_descriptions[i]);
8209 g_free (item->image_description);
8211 if (item->action_idle_handler)
8213 g_source_remove (item->action_idle_handler);
8214 item->action_idle_handler = 0;
8217 G_OBJECT_CLASS (accessible_item_parent_class)->finalize (object);
8221 gtk_icon_view_item_accessible_get_parent (AtkObject *obj)
8223 GtkIconViewItemAccessible *item;
8225 g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (obj), NULL);
8226 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8229 return gtk_widget_get_accessible (item->widget);
8235 gtk_icon_view_item_accessible_get_index_in_parent (AtkObject *obj)
8237 GtkIconViewItemAccessible *item;
8239 g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (obj), 0);
8240 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8242 return item->item->index;
8245 static AtkStateSet *
8246 gtk_icon_view_item_accessible_ref_state_set (AtkObject *obj)
8248 GtkIconViewItemAccessible *item;
8249 GtkIconView *icon_view;
8251 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8252 g_return_val_if_fail (item->state_set, NULL);
8257 icon_view = GTK_ICON_VIEW (item->widget);
8258 if (icon_view->priv->cursor_item == item->item)
8259 atk_state_set_add_state (item->state_set, ATK_STATE_FOCUSED);
8261 atk_state_set_remove_state (item->state_set, ATK_STATE_FOCUSED);
8262 if (item->item->selected)
8263 atk_state_set_add_state (item->state_set, ATK_STATE_SELECTED);
8265 atk_state_set_remove_state (item->state_set, ATK_STATE_SELECTED);
8267 return g_object_ref (item->state_set);
8271 gtk_icon_view_item_accessible_class_init (AtkObjectClass *klass)
8273 GObjectClass *gobject_class;
8275 accessible_item_parent_class = g_type_class_peek_parent (klass);
8277 gobject_class = (GObjectClass *)klass;
8279 gobject_class->finalize = gtk_icon_view_item_accessible_finalize;
8281 klass->get_index_in_parent = gtk_icon_view_item_accessible_get_index_in_parent;
8282 klass->get_parent = gtk_icon_view_item_accessible_get_parent;
8283 klass->ref_state_set = gtk_icon_view_item_accessible_ref_state_set;
8287 gtk_icon_view_item_accessible_get_type (void)
8289 static GType type = 0;
8293 const GTypeInfo tinfo =
8295 sizeof (GtkIconViewItemAccessibleClass),
8296 (GBaseInitFunc) NULL, /* base init */
8297 (GBaseFinalizeFunc) NULL, /* base finalize */
8298 (GClassInitFunc) gtk_icon_view_item_accessible_class_init, /* class init */
8299 (GClassFinalizeFunc) NULL, /* class finalize */
8300 NULL, /* class data */
8301 sizeof (GtkIconViewItemAccessible), /* instance size */
8302 0, /* nb preallocs */
8303 (GInstanceInitFunc) gtk_icon_view_item_accessible_object_init, /* instance init */
8304 NULL /* value table */
8307 const GInterfaceInfo atk_component_info =
8309 (GInterfaceInitFunc) atk_component_item_interface_init,
8310 (GInterfaceFinalizeFunc) NULL,
8313 const GInterfaceInfo atk_action_info =
8315 (GInterfaceInitFunc) atk_action_item_interface_init,
8316 (GInterfaceFinalizeFunc) NULL,
8319 const GInterfaceInfo atk_image_info =
8321 (GInterfaceInitFunc) atk_image_item_interface_init,
8322 (GInterfaceFinalizeFunc) NULL,
8325 const GInterfaceInfo atk_text_info =
8327 (GInterfaceInitFunc) atk_text_item_interface_init,
8328 (GInterfaceFinalizeFunc) NULL,
8332 type = g_type_register_static (ATK_TYPE_OBJECT,
8333 I_("GtkIconViewItemAccessible"), &tinfo, 0);
8334 g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
8335 &atk_component_info);
8336 g_type_add_interface_static (type, ATK_TYPE_ACTION,
8338 g_type_add_interface_static (type, ATK_TYPE_IMAGE,
8340 g_type_add_interface_static (type, ATK_TYPE_TEXT,
8347 #define GTK_TYPE_ICON_VIEW_ACCESSIBLE (gtk_icon_view_accessible_get_type ())
8348 #define GTK_ICON_VIEW_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ICON_VIEW_ACCESSIBLE, GtkIconViewAccessible))
8349 #define GTK_IS_ICON_VIEW_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ICON_VIEW_ACCESSIBLE))
8351 static GType gtk_icon_view_accessible_get_type (void);
8356 } GtkIconViewAccessible;
8362 } GtkIconViewItemAccessibleInfo;
8368 GtkAdjustment *old_hadj;
8369 GtkAdjustment *old_vadj;
8371 GtkTreeModel *model;
8373 } GtkIconViewAccessiblePrivate;
8375 static GtkIconViewAccessiblePrivate *
8376 gtk_icon_view_accessible_get_priv (AtkObject *accessible)
8378 return g_object_get_qdata (G_OBJECT (accessible),
8379 accessible_private_data_quark);
8383 gtk_icon_view_item_accessible_info_new (AtkObject *accessible,
8387 GtkIconViewItemAccessibleInfo *info;
8388 GtkIconViewItemAccessibleInfo *tmp_info;
8389 GtkIconViewAccessiblePrivate *priv;
8392 info = g_new (GtkIconViewItemAccessibleInfo, 1);
8394 info->index = index;
8396 priv = gtk_icon_view_accessible_get_priv (accessible);
8397 items = priv->items;
8400 tmp_info = items->data;
8401 if (tmp_info->index > index)
8403 items = items->next;
8405 priv->items = g_list_insert_before (priv->items, items, info);
8406 priv->old_hadj = NULL;
8407 priv->old_vadj = NULL;
8411 gtk_icon_view_accessible_get_n_children (AtkObject *accessible)
8413 GtkIconView *icon_view;
8416 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8420 icon_view = GTK_ICON_VIEW (widget);
8422 return g_list_length (icon_view->priv->items);
8426 gtk_icon_view_accessible_find_child (AtkObject *accessible,
8429 GtkIconViewAccessiblePrivate *priv;
8430 GtkIconViewItemAccessibleInfo *info;
8433 priv = gtk_icon_view_accessible_get_priv (accessible);
8434 items = priv->items;
8439 if (info->index == index)
8441 items = items->next;
8447 gtk_icon_view_accessible_ref_child (AtkObject *accessible,
8450 GtkIconView *icon_view;
8454 GtkIconViewItemAccessible *a11y_item;
8456 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8460 icon_view = GTK_ICON_VIEW (widget);
8461 icons = g_list_nth (icon_view->priv->items, index);
8465 GtkIconViewItem *item = icons->data;
8467 g_return_val_if_fail (item->index == index, NULL);
8468 obj = gtk_icon_view_accessible_find_child (accessible, index);
8473 obj = g_object_new (gtk_icon_view_item_accessible_get_type (), NULL);
8474 gtk_icon_view_item_accessible_info_new (accessible,
8477 obj->role = ATK_ROLE_ICON;
8478 a11y_item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8479 a11y_item->item = item;
8480 a11y_item->widget = widget;
8481 a11y_item->text_buffer = gtk_text_buffer_new (NULL);
8483 text = get_text (icon_view, item);
8486 gtk_text_buffer_set_text (a11y_item->text_buffer, text, -1);
8490 gtk_icon_view_item_accessible_set_visibility (a11y_item, FALSE);
8491 g_object_add_weak_pointer (G_OBJECT (widget), (gpointer) &(a11y_item->widget));
8499 gtk_icon_view_accessible_traverse_items (GtkIconViewAccessible *view,
8502 GtkIconViewAccessiblePrivate *priv;
8503 GtkIconViewItemAccessibleInfo *info;
8504 GtkIconViewItemAccessible *item;
8507 priv = gtk_icon_view_accessible_get_priv (ATK_OBJECT (view));
8511 gboolean act_on_item;
8513 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (view));
8517 items = priv->items;
8519 act_on_item = (list == NULL);
8524 info = (GtkIconViewItemAccessibleInfo *)items->data;
8525 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
8527 if (act_on_item == FALSE && list == items)
8531 gtk_icon_view_item_accessible_set_visibility (item, TRUE);
8533 items = items->next;
8539 gtk_icon_view_accessible_adjustment_changed (GtkAdjustment *adjustment,
8540 GtkIconViewAccessible *view)
8542 gtk_icon_view_accessible_traverse_items (view, NULL);
8546 gtk_icon_view_accessible_set_adjustment (AtkObject *accessible,
8547 GtkOrientation orientation,
8548 GtkAdjustment *adjustment)
8550 GtkIconViewAccessiblePrivate *priv;
8551 GtkAdjustment **old_adj_ptr;
8553 priv = gtk_icon_view_accessible_get_priv (accessible);
8555 /* Adjustments are set for the first time in constructor and priv is not
8556 * initialized at that time, so skip this first setting. */
8560 if (orientation == GTK_ORIENTATION_HORIZONTAL)
8562 if (priv->old_hadj == adjustment)
8565 old_adj_ptr = &priv->old_hadj;
8569 if (priv->old_vadj == adjustment)
8572 old_adj_ptr = &priv->old_vadj;
8575 /* Disconnect signal handlers */
8578 g_object_remove_weak_pointer (G_OBJECT (*old_adj_ptr),
8579 (gpointer *)&priv->old_hadj);
8580 g_signal_handlers_disconnect_by_func (*old_adj_ptr,
8581 gtk_icon_view_accessible_adjustment_changed,
8585 /* Connect signal */
8586 *old_adj_ptr = adjustment;
8587 g_object_add_weak_pointer (G_OBJECT (adjustment), (gpointer *)old_adj_ptr);
8588 g_signal_connect (adjustment, "value-changed",
8589 G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
8594 gtk_icon_view_accessible_model_row_changed (GtkTreeModel *tree_model,
8602 GtkIconView *icon_view;
8603 GtkIconViewItem *item;
8604 GtkIconViewItemAccessible *a11y_item;
8608 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
8609 index = gtk_tree_path_get_indices(path)[0];
8610 a11y_item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (
8611 gtk_icon_view_accessible_find_child (atk_obj, index));
8615 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_obj));
8616 icon_view = GTK_ICON_VIEW (widget);
8617 item = a11y_item->item;
8619 name = atk_object_get_name (ATK_OBJECT (a11y_item));
8621 if (!name || strcmp (name, "") == 0)
8623 text = get_text (icon_view, item);
8626 gtk_text_buffer_set_text (a11y_item->text_buffer, text, -1);
8632 g_signal_emit_by_name (atk_obj, "visible-data-changed");
8638 gtk_icon_view_accessible_model_row_inserted (GtkTreeModel *tree_model,
8643 GtkIconViewAccessiblePrivate *priv;
8644 GtkIconViewItemAccessibleInfo *info;
8645 GtkIconViewAccessible *view;
8646 GtkIconViewItemAccessible *item;
8652 index = gtk_tree_path_get_indices(path)[0];
8653 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
8654 view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
8655 priv = gtk_icon_view_accessible_get_priv (atk_obj);
8657 items = priv->items;
8662 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
8663 if (info->index != item->item->index)
8665 if (info->index < index)
8666 g_warning ("Unexpected index value on insertion %d %d", index, info->index);
8668 if (tmp_list == NULL)
8671 info->index = item->item->index;
8674 items = items->next;
8676 gtk_icon_view_accessible_traverse_items (view, tmp_list);
8677 g_signal_emit_by_name (atk_obj, "children-changed::add",
8683 gtk_icon_view_accessible_model_row_deleted (GtkTreeModel *tree_model,
8687 GtkIconViewAccessiblePrivate *priv;
8688 GtkIconViewItemAccessibleInfo *info;
8689 GtkIconViewAccessible *view;
8690 GtkIconViewItemAccessible *item;
8693 GList *deleted_item;
8697 index = gtk_tree_path_get_indices(path)[0];
8698 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
8699 view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
8700 priv = gtk_icon_view_accessible_get_priv (atk_obj);
8702 items = priv->items;
8704 deleted_item = NULL;
8709 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
8710 if (info->index == index)
8712 deleted_item = items;
8714 if (info->index != item->item->index)
8716 if (tmp_list == NULL)
8719 info->index = item->item->index;
8722 items = items->next;
8724 gtk_icon_view_accessible_traverse_items (view, tmp_list);
8727 info = deleted_item->data;
8728 gtk_icon_view_item_accessible_add_state (GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item), ATK_STATE_DEFUNCT, TRUE);
8729 g_signal_emit_by_name (atk_obj, "children-changed::remove",
8731 priv->items = g_list_remove_link (priv->items, deleted_item);
8739 gtk_icon_view_accessible_item_compare (GtkIconViewItemAccessibleInfo *i1,
8740 GtkIconViewItemAccessibleInfo *i2)
8742 return i1->index - i2->index;
8746 gtk_icon_view_accessible_model_rows_reordered (GtkTreeModel *tree_model,
8752 GtkIconViewAccessiblePrivate *priv;
8753 GtkIconViewItemAccessibleInfo *info;
8754 GtkIconView *icon_view;
8755 GtkIconViewItemAccessible *item;
8761 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
8762 icon_view = GTK_ICON_VIEW (user_data);
8763 priv = gtk_icon_view_accessible_get_priv (atk_obj);
8765 length = gtk_tree_model_iter_n_children (tree_model, NULL);
8767 order = g_new (gint, length);
8768 for (i = 0; i < length; i++)
8769 order [new_order[i]] = i;
8771 items = priv->items;
8775 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
8776 info->index = order[info->index];
8777 item->item = g_list_nth_data (icon_view->priv->items, info->index);
8778 items = items->next;
8781 priv->items = g_list_sort (priv->items,
8782 (GCompareFunc)gtk_icon_view_accessible_item_compare);
8788 gtk_icon_view_accessible_disconnect_model_signals (GtkTreeModel *model,
8793 obj = G_OBJECT (model);
8794 g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_changed, widget);
8795 g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_inserted, widget);
8796 g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_deleted, widget);
8797 g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_rows_reordered, widget);
8801 gtk_icon_view_accessible_connect_model_signals (GtkIconView *icon_view)
8805 obj = G_OBJECT (icon_view->priv->model);
8806 g_signal_connect_data (obj, "row-changed",
8807 (GCallback) gtk_icon_view_accessible_model_row_changed,
8808 icon_view, NULL, 0);
8809 g_signal_connect_data (obj, "row-inserted",
8810 (GCallback) gtk_icon_view_accessible_model_row_inserted,
8811 icon_view, NULL, G_CONNECT_AFTER);
8812 g_signal_connect_data (obj, "row-deleted",
8813 (GCallback) gtk_icon_view_accessible_model_row_deleted,
8814 icon_view, NULL, G_CONNECT_AFTER);
8815 g_signal_connect_data (obj, "rows-reordered",
8816 (GCallback) gtk_icon_view_accessible_model_rows_reordered,
8817 icon_view, NULL, G_CONNECT_AFTER);
8821 gtk_icon_view_accessible_clear_cache (GtkIconViewAccessiblePrivate *priv)
8823 GtkIconViewItemAccessibleInfo *info;
8826 items = priv->items;
8829 info = (GtkIconViewItemAccessibleInfo *) items->data;
8830 g_object_unref (info->item);
8831 g_free (items->data);
8832 items = items->next;
8834 g_list_free (priv->items);
8839 gtk_icon_view_accessible_notify_gtk (GObject *obj,
8842 GtkIconView *icon_view;
8845 GtkIconViewAccessiblePrivate *priv;
8847 if (strcmp (pspec->name, "model") == 0)
8849 widget = GTK_WIDGET (obj);
8850 atk_obj = gtk_widget_get_accessible (widget);
8851 priv = gtk_icon_view_accessible_get_priv (atk_obj);
8854 g_object_remove_weak_pointer (G_OBJECT (priv->model),
8855 (gpointer *)&priv->model);
8856 gtk_icon_view_accessible_disconnect_model_signals (priv->model, widget);
8858 gtk_icon_view_accessible_clear_cache (priv);
8860 icon_view = GTK_ICON_VIEW (obj);
8861 priv->model = icon_view->priv->model;
8862 /* If there is no model the GtkIconView is probably being destroyed */
8865 g_object_add_weak_pointer (G_OBJECT (priv->model), (gpointer *)&priv->model);
8866 gtk_icon_view_accessible_connect_model_signals (icon_view);
8874 gtk_icon_view_accessible_initialize (AtkObject *accessible,
8877 GtkIconViewAccessiblePrivate *priv;
8878 GtkIconView *icon_view;
8880 if (ATK_OBJECT_CLASS (accessible_parent_class)->initialize)
8881 ATK_OBJECT_CLASS (accessible_parent_class)->initialize (accessible, data);
8883 priv = g_new0 (GtkIconViewAccessiblePrivate, 1);
8884 g_object_set_qdata (G_OBJECT (accessible),
8885 accessible_private_data_quark,
8888 icon_view = GTK_ICON_VIEW (data);
8889 if (icon_view->priv->hadjustment)
8890 gtk_icon_view_accessible_set_adjustment (accessible,
8891 GTK_ORIENTATION_HORIZONTAL,
8892 icon_view->priv->hadjustment);
8893 if (icon_view->priv->vadjustment)
8894 gtk_icon_view_accessible_set_adjustment (accessible,
8895 GTK_ORIENTATION_VERTICAL,
8896 icon_view->priv->vadjustment);
8897 g_signal_connect (data,
8899 G_CALLBACK (gtk_icon_view_accessible_notify_gtk),
8902 priv->model = icon_view->priv->model;
8905 g_object_add_weak_pointer (G_OBJECT (priv->model), (gpointer *)&priv->model);
8906 gtk_icon_view_accessible_connect_model_signals (icon_view);
8909 accessible->role = ATK_ROLE_LAYERED_PANE;
8913 gtk_icon_view_accessible_finalize (GObject *object)
8915 GtkIconViewAccessiblePrivate *priv;
8917 priv = gtk_icon_view_accessible_get_priv (ATK_OBJECT (object));
8918 gtk_icon_view_accessible_clear_cache (priv);
8922 G_OBJECT_CLASS (accessible_parent_class)->finalize (object);
8926 gtk_icon_view_accessible_destroyed (GtkWidget *widget,
8927 GtkAccessible *accessible)
8930 GtkIconViewAccessiblePrivate *priv;
8932 atk_obj = ATK_OBJECT (accessible);
8933 priv = gtk_icon_view_accessible_get_priv (atk_obj);
8936 g_object_remove_weak_pointer (G_OBJECT (priv->old_hadj),
8937 (gpointer *)&priv->old_hadj);
8939 g_signal_handlers_disconnect_by_func (priv->old_hadj,
8940 (gpointer) gtk_icon_view_accessible_adjustment_changed,
8942 priv->old_hadj = NULL;
8946 g_object_remove_weak_pointer (G_OBJECT (priv->old_vadj),
8947 (gpointer *)&priv->old_vadj);
8949 g_signal_handlers_disconnect_by_func (priv->old_vadj,
8950 (gpointer) gtk_icon_view_accessible_adjustment_changed,
8952 priv->old_vadj = NULL;
8957 gtk_icon_view_accessible_connect_widget_destroyed (GtkAccessible *accessible)
8961 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8964 g_signal_connect_after (widget,
8966 G_CALLBACK (gtk_icon_view_accessible_destroyed),
8969 GTK_ACCESSIBLE_CLASS (accessible_parent_class)->connect_widget_destroyed (accessible);
8973 gtk_icon_view_accessible_class_init (AtkObjectClass *klass)
8975 GObjectClass *gobject_class;
8976 GtkAccessibleClass *accessible_class;
8978 accessible_parent_class = g_type_class_peek_parent (klass);
8980 gobject_class = (GObjectClass *)klass;
8981 accessible_class = (GtkAccessibleClass *)klass;
8983 gobject_class->finalize = gtk_icon_view_accessible_finalize;
8985 klass->get_n_children = gtk_icon_view_accessible_get_n_children;
8986 klass->ref_child = gtk_icon_view_accessible_ref_child;
8987 klass->initialize = gtk_icon_view_accessible_initialize;
8989 accessible_class->connect_widget_destroyed = gtk_icon_view_accessible_connect_widget_destroyed;
8991 accessible_private_data_quark = g_quark_from_static_string ("icon_view-accessible-private-data");
8995 gtk_icon_view_accessible_ref_accessible_at_point (AtkComponent *component,
8998 AtkCoordType coord_type)
9001 GtkIconView *icon_view;
9002 GtkIconViewItem *item;
9005 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
9007 /* State is defunct */
9010 icon_view = GTK_ICON_VIEW (widget);
9011 atk_component_get_extents (component, &x_pos, &y_pos, NULL, NULL, coord_type);
9012 item = gtk_icon_view_get_item_at_coords (icon_view, x - x_pos, y - y_pos, TRUE, NULL);
9014 return gtk_icon_view_accessible_ref_child (ATK_OBJECT (component), item->index);
9020 atk_component_interface_init (AtkComponentIface *iface)
9022 iface->ref_accessible_at_point = gtk_icon_view_accessible_ref_accessible_at_point;
9026 gtk_icon_view_accessible_add_selection (AtkSelection *selection,
9030 GtkIconView *icon_view;
9031 GtkIconViewItem *item;
9033 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9037 icon_view = GTK_ICON_VIEW (widget);
9039 item = g_list_nth_data (icon_view->priv->items, i);
9044 gtk_icon_view_select_item (icon_view, item);
9050 gtk_icon_view_accessible_clear_selection (AtkSelection *selection)
9053 GtkIconView *icon_view;
9055 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9059 icon_view = GTK_ICON_VIEW (widget);
9060 gtk_icon_view_unselect_all (icon_view);
9066 gtk_icon_view_accessible_ref_selection (AtkSelection *selection,
9071 GtkIconView *icon_view;
9072 GtkIconViewItem *item;
9074 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9078 icon_view = GTK_ICON_VIEW (widget);
9080 l = icon_view->priv->items;
9087 return atk_object_ref_accessible_child (gtk_widget_get_accessible (widget), item->index);
9098 gtk_icon_view_accessible_get_selection_count (AtkSelection *selection)
9101 GtkIconView *icon_view;
9102 GtkIconViewItem *item;
9106 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9110 icon_view = GTK_ICON_VIEW (widget);
9112 l = icon_view->priv->items;
9128 gtk_icon_view_accessible_is_child_selected (AtkSelection *selection,
9132 GtkIconView *icon_view;
9133 GtkIconViewItem *item;
9135 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9139 icon_view = GTK_ICON_VIEW (widget);
9141 item = g_list_nth_data (icon_view->priv->items, i);
9145 return item->selected;
9149 gtk_icon_view_accessible_remove_selection (AtkSelection *selection,
9153 GtkIconView *icon_view;
9154 GtkIconViewItem *item;
9158 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9162 icon_view = GTK_ICON_VIEW (widget);
9163 l = icon_view->priv->items;
9172 gtk_icon_view_unselect_item (icon_view, item);
9184 gtk_icon_view_accessible_select_all_selection (AtkSelection *selection)
9187 GtkIconView *icon_view;
9189 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9193 icon_view = GTK_ICON_VIEW (widget);
9194 gtk_icon_view_select_all (icon_view);
9199 gtk_icon_view_accessible_selection_interface_init (AtkSelectionIface *iface)
9201 iface->add_selection = gtk_icon_view_accessible_add_selection;
9202 iface->clear_selection = gtk_icon_view_accessible_clear_selection;
9203 iface->ref_selection = gtk_icon_view_accessible_ref_selection;
9204 iface->get_selection_count = gtk_icon_view_accessible_get_selection_count;
9205 iface->is_child_selected = gtk_icon_view_accessible_is_child_selected;
9206 iface->remove_selection = gtk_icon_view_accessible_remove_selection;
9207 iface->select_all_selection = gtk_icon_view_accessible_select_all_selection;
9211 gtk_icon_view_accessible_get_type (void)
9213 static GType type = 0;
9220 (GBaseInitFunc) NULL, /* base init */
9221 (GBaseFinalizeFunc) NULL, /* base finalize */
9222 (GClassInitFunc) gtk_icon_view_accessible_class_init,
9223 (GClassFinalizeFunc) NULL, /* class finalize */
9224 NULL, /* class data */
9225 0, /* instance size */
9226 0, /* nb preallocs */
9227 (GInstanceInitFunc) NULL, /* instance init */
9228 NULL /* value table */
9230 const GInterfaceInfo atk_component_info =
9232 (GInterfaceInitFunc) atk_component_interface_init,
9233 (GInterfaceFinalizeFunc) NULL,
9236 const GInterfaceInfo atk_selection_info =
9238 (GInterfaceInitFunc) gtk_icon_view_accessible_selection_interface_init,
9239 (GInterfaceFinalizeFunc) NULL,
9244 * Figure out the size of the class and instance
9245 * we are deriving from
9247 AtkObjectFactory *factory;
9250 GType derived_atk_type;
9252 derived_type = g_type_parent (GTK_TYPE_ICON_VIEW);
9253 factory = atk_registry_get_factory (atk_get_default_registry (),
9255 derived_atk_type = atk_object_factory_get_accessible_type (factory);
9256 g_type_query (derived_atk_type, &query);
9257 tinfo.class_size = query.class_size;
9258 tinfo.instance_size = query.instance_size;
9260 type = g_type_register_static (derived_atk_type,
9261 I_("GtkIconViewAccessible"),
9263 g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
9264 &atk_component_info);
9265 g_type_add_interface_static (type, ATK_TYPE_SELECTION,
9266 &atk_selection_info);
9272 gtk_icon_view_accessible_new (GObject *obj)
9274 AtkObject *accessible;
9276 g_return_val_if_fail (GTK_IS_WIDGET (obj), NULL);
9278 accessible = g_object_new (gtk_icon_view_accessible_get_type (), NULL);
9279 atk_object_initialize (accessible, obj);
9285 gtk_icon_view_accessible_factory_get_accessible_type (void)
9287 return gtk_icon_view_accessible_get_type ();
9291 gtk_icon_view_accessible_factory_create_accessible (GObject *obj)
9293 return gtk_icon_view_accessible_new (obj);
9297 gtk_icon_view_accessible_factory_class_init (AtkObjectFactoryClass *klass)
9299 klass->create_accessible = gtk_icon_view_accessible_factory_create_accessible;
9300 klass->get_accessible_type = gtk_icon_view_accessible_factory_get_accessible_type;
9304 gtk_icon_view_accessible_factory_get_type (void)
9306 static GType type = 0;
9310 const GTypeInfo tinfo =
9312 sizeof (AtkObjectFactoryClass),
9313 NULL, /* base_init */
9314 NULL, /* base_finalize */
9315 (GClassInitFunc) gtk_icon_view_accessible_factory_class_init,
9316 NULL, /* class_finalize */
9317 NULL, /* class_data */
9318 sizeof (AtkObjectFactory),
9319 0, /* n_preallocs */
9323 type = g_type_register_static (ATK_TYPE_OBJECT_FACTORY,
9324 I_("GtkIconViewAccessibleFactory"),
9332 gtk_icon_view_get_accessible (GtkWidget *widget)
9334 static gboolean first_time = TRUE;
9338 _gtk_accessible_set_factory_type (GTK_TYPE_ICON_VIEW,
9339 gtk_icon_view_accessible_factory_get_type ());
9342 return GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->get_accessible (widget);
9346 gtk_icon_view_buildable_custom_tag_start (GtkBuildable *buildable,
9347 GtkBuilder *builder,
9349 const gchar *tagname,
9350 GMarkupParser *parser,
9353 if (parent_buildable_iface->custom_tag_start (buildable, builder, child,
9354 tagname, parser, data))
9357 return _gtk_cell_layout_buildable_custom_tag_start (buildable, builder, child,
9358 tagname, parser, data);
9362 gtk_icon_view_buildable_custom_tag_end (GtkBuildable *buildable,
9363 GtkBuilder *builder,
9365 const gchar *tagname,
9368 if (!_gtk_cell_layout_buildable_custom_tag_end (buildable, builder,
9369 child, tagname, data))
9370 parent_buildable_iface->custom_tag_end (buildable, builder, child, tagname,