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 "gtkiconview.h"
27 #include "gtkcelllayout.h"
28 #include "gtkcellrenderer.h"
29 #include "gtkcellareabox.h"
30 #include "gtkcellareacontext.h"
31 #include "gtkcellrenderertext.h"
32 #include "gtkcellrendererpixbuf.h"
33 #include "gtkorientable.h"
34 #include "gtkmarshalers.h"
35 #include "gtkbindings.h"
39 #include "gtkaccessible.h"
40 #include "gtkwindow.h"
42 #include "gtkcombobox.h"
43 #include "gtktextbuffer.h"
44 #include "gtkscrollable.h"
45 #include "gtksizerequest.h"
46 #include "gtktreednd.h"
47 #include "gtktypebuiltins.h"
48 #include "gtkprivate.h"
53 * @short_description: A widget which displays a list of icons in a grid
55 * #GtkIconView provides an alternative view on a #GtkTreeModel.
56 * It displays the model as a grid of icons with labels. Like
57 * #GtkTreeView, it allows to select one or multiple items
58 * (depending on the selection mode, see gtk_icon_view_set_selection_mode()).
59 * In addition to selection with the arrow keys, #GtkIconView supports
60 * rubberband selection, which is controlled by dragging the pointer.
62 * Note that if the tree model is backed by an actual tree store (as
63 * opposed to a flat list where the mapping to icons is obvious),
64 * #GtkIconView will only display the first level of the tree and
65 * ignore the tree's branches.
68 #define SCROLL_EDGE_SIZE 15
70 #define GTK_ICON_VIEW_PRIORITY_LAYOUT (GDK_PRIORITY_REDRAW + 5)
72 typedef struct _GtkIconViewItem GtkIconViewItem;
73 struct _GtkIconViewItem
75 /* First member is always the rectangle so it
76 * can be cast to a rectangle. */
77 GdkRectangle cell_area;
85 guint selected_before_rubberbanding : 1;
89 typedef struct _GtkIconViewChild GtkIconViewChild;
90 struct _GtkIconViewChild
96 struct _GtkIconViewPrivate
98 GtkCellArea *cell_area;
99 GtkCellAreaContext *cell_area_context;
101 gulong add_editable_id;
102 gulong remove_editable_id;
103 gulong context_changed_id;
105 GPtrArray *row_contexts;
109 GtkSelectionMode selection_mode;
111 GdkWindow *bin_window;
119 GtkAdjustment *hadjustment;
120 GtkAdjustment *vadjustment;
122 guint layout_idle_id;
124 gint rubberband_x1, rubberband_y1;
125 gint rubberband_x2, rubberband_y2;
126 GdkDevice *rubberband_device;
128 guint scroll_timeout_id;
129 gint scroll_value_diff;
130 gint event_last_x, event_last_y;
132 GtkIconViewItem *anchor_item;
133 GtkIconViewItem *cursor_item;
135 GtkIconViewItem *last_single_clicked;
137 GtkOrientation item_orientation;
151 GtkCellRenderer *pixbuf_cell;
152 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_set (GtkWidget *widget,
254 GtkStyle *previous_style);
255 static void gtk_icon_view_state_changed (GtkWidget *widget,
256 GtkStateType previous_state);
257 static void gtk_icon_view_get_preferred_width (GtkWidget *widget,
260 static void gtk_icon_view_get_preferred_height (GtkWidget *widget,
263 static void gtk_icon_view_size_allocate (GtkWidget *widget,
264 GtkAllocation *allocation);
265 static gboolean gtk_icon_view_draw (GtkWidget *widget,
267 static gboolean gtk_icon_view_motion (GtkWidget *widget,
268 GdkEventMotion *event);
269 static gboolean gtk_icon_view_button_press (GtkWidget *widget,
270 GdkEventButton *event);
271 static gboolean gtk_icon_view_button_release (GtkWidget *widget,
272 GdkEventButton *event);
273 static gboolean gtk_icon_view_key_press (GtkWidget *widget,
275 static gboolean gtk_icon_view_key_release (GtkWidget *widget,
277 static AtkObject *gtk_icon_view_get_accessible (GtkWidget *widget);
280 /* GtkContainer vfuncs */
281 static void gtk_icon_view_remove (GtkContainer *container,
283 static void gtk_icon_view_forall (GtkContainer *container,
284 gboolean include_internals,
285 GtkCallback callback,
286 gpointer callback_data);
288 /* GtkIconView vfuncs */
289 static void gtk_icon_view_real_select_all (GtkIconView *icon_view);
290 static void gtk_icon_view_real_unselect_all (GtkIconView *icon_view);
291 static void gtk_icon_view_real_select_cursor_item (GtkIconView *icon_view);
292 static void gtk_icon_view_real_toggle_cursor_item (GtkIconView *icon_view);
293 static gboolean gtk_icon_view_real_activate_cursor_item (GtkIconView *icon_view);
295 /* Internal functions */
296 static void gtk_icon_view_set_hadjustment_values (GtkIconView *icon_view);
297 static void gtk_icon_view_set_vadjustment_values (GtkIconView *icon_view);
298 static void gtk_icon_view_set_hadjustment (GtkIconView *icon_view,
299 GtkAdjustment *adjustment);
300 static void gtk_icon_view_set_vadjustment (GtkIconView *icon_view,
301 GtkAdjustment *adjustment);
302 static void gtk_icon_view_accessible_set_adjustment (AtkObject *accessible,
303 GtkOrientation orientation,
304 GtkAdjustment *adjustment);
305 static void gtk_icon_view_adjustment_changed (GtkAdjustment *adjustment,
306 GtkIconView *icon_view);
307 static void gtk_icon_view_layout (GtkIconView *icon_view);
308 static void gtk_icon_view_paint_item (GtkIconView *icon_view,
310 GtkIconViewItem *item,
313 gboolean draw_focus);
314 static void gtk_icon_view_paint_rubberband (GtkIconView *icon_view,
316 static void gtk_icon_view_queue_draw_path (GtkIconView *icon_view,
318 static void gtk_icon_view_queue_draw_item (GtkIconView *icon_view,
319 GtkIconViewItem *item);
320 static void gtk_icon_view_queue_layout (GtkIconView *icon_view);
321 static void gtk_icon_view_set_cursor_item (GtkIconView *icon_view,
322 GtkIconViewItem *item,
323 GtkCellRenderer *cursor_cell);
324 static void gtk_icon_view_start_rubberbanding (GtkIconView *icon_view,
328 static void gtk_icon_view_stop_rubberbanding (GtkIconView *icon_view);
329 static void gtk_icon_view_update_rubberband_selection (GtkIconView *icon_view);
330 static gboolean gtk_icon_view_item_hit_test (GtkIconView *icon_view,
331 GtkIconViewItem *item,
336 static gboolean gtk_icon_view_unselect_all_internal (GtkIconView *icon_view);
337 static void gtk_icon_view_cache_widths (GtkIconView *icon_view);
338 static void gtk_icon_view_update_rubberband (gpointer data);
339 static void gtk_icon_view_item_invalidate_size (GtkIconViewItem *item);
340 static void gtk_icon_view_invalidate_sizes (GtkIconView *icon_view);
341 static void gtk_icon_view_add_move_binding (GtkBindingSet *binding_set,
344 GtkMovementStep step,
346 static gboolean gtk_icon_view_real_move_cursor (GtkIconView *icon_view,
347 GtkMovementStep step,
349 static void gtk_icon_view_move_cursor_up_down (GtkIconView *icon_view,
351 static void gtk_icon_view_move_cursor_page_up_down (GtkIconView *icon_view,
353 static void gtk_icon_view_move_cursor_left_right (GtkIconView *icon_view,
355 static void gtk_icon_view_move_cursor_start_end (GtkIconView *icon_view,
357 static void gtk_icon_view_scroll_to_item (GtkIconView *icon_view,
358 GtkIconViewItem *item);
359 static void gtk_icon_view_select_item (GtkIconView *icon_view,
360 GtkIconViewItem *item);
361 static void gtk_icon_view_unselect_item (GtkIconView *icon_view,
362 GtkIconViewItem *item);
363 static gboolean gtk_icon_view_select_all_between (GtkIconView *icon_view,
364 GtkIconViewItem *anchor,
365 GtkIconViewItem *cursor);
366 static GtkIconViewItem * gtk_icon_view_get_item_at_coords (GtkIconView *icon_view,
369 gboolean only_in_cell,
370 GtkCellRenderer **cell_at_pos);
371 static void gtk_icon_view_set_cell_data (GtkIconView *icon_view,
372 GtkIconViewItem *item);
374 static GtkCellArea *gtk_icon_view_cell_layout_get_area (GtkCellLayout *layout);
376 static void gtk_icon_view_item_selected_changed (GtkIconView *icon_view,
377 GtkIconViewItem *item);
379 static void gtk_icon_view_add_editable (GtkCellArea *area,
380 GtkCellRenderer *renderer,
381 GtkCellEditable *editable,
382 GdkRectangle *cell_area,
384 GtkIconView *icon_view);
385 static void gtk_icon_view_remove_editable (GtkCellArea *area,
386 GtkCellRenderer *renderer,
387 GtkCellEditable *editable,
388 GtkIconView *icon_view);
389 static void gtk_icon_view_context_changed (GtkCellAreaContext *context,
391 GtkIconView *icon_view);
393 /* Source side drag signals */
394 static void gtk_icon_view_drag_begin (GtkWidget *widget,
395 GdkDragContext *context);
396 static void gtk_icon_view_drag_end (GtkWidget *widget,
397 GdkDragContext *context);
398 static void gtk_icon_view_drag_data_get (GtkWidget *widget,
399 GdkDragContext *context,
400 GtkSelectionData *selection_data,
403 static void gtk_icon_view_drag_data_delete (GtkWidget *widget,
404 GdkDragContext *context);
406 /* Target side drag signals */
407 static void gtk_icon_view_drag_leave (GtkWidget *widget,
408 GdkDragContext *context,
410 static gboolean gtk_icon_view_drag_motion (GtkWidget *widget,
411 GdkDragContext *context,
415 static gboolean gtk_icon_view_drag_drop (GtkWidget *widget,
416 GdkDragContext *context,
420 static void gtk_icon_view_drag_data_received (GtkWidget *widget,
421 GdkDragContext *context,
424 GtkSelectionData *selection_data,
427 static gboolean gtk_icon_view_maybe_begin_drag (GtkIconView *icon_view,
428 GdkEventMotion *event);
430 static void remove_scroll_timeout (GtkIconView *icon_view);
433 static GtkBuildableIface *parent_buildable_iface;
434 static void gtk_icon_view_buildable_init (GtkBuildableIface *iface);
435 static gboolean gtk_icon_view_buildable_custom_tag_start (GtkBuildable *buildable,
438 const gchar *tagname,
439 GMarkupParser *parser,
441 static void gtk_icon_view_buildable_custom_tag_end (GtkBuildable *buildable,
444 const gchar *tagname,
447 static guint icon_view_signals[LAST_SIGNAL] = { 0 };
449 G_DEFINE_TYPE_WITH_CODE (GtkIconView, gtk_icon_view, GTK_TYPE_CONTAINER,
450 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
451 gtk_icon_view_cell_layout_init)
452 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
453 gtk_icon_view_buildable_init)
454 G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
457 gtk_icon_view_class_init (GtkIconViewClass *klass)
459 GObjectClass *gobject_class;
460 GtkWidgetClass *widget_class;
461 GtkContainerClass *container_class;
462 GtkBindingSet *binding_set;
464 binding_set = gtk_binding_set_by_class (klass);
466 g_type_class_add_private (klass, sizeof (GtkIconViewPrivate));
468 gobject_class = (GObjectClass *) klass;
469 widget_class = (GtkWidgetClass *) klass;
470 container_class = (GtkContainerClass *) klass;
472 gobject_class->constructor = gtk_icon_view_constructor;
473 gobject_class->dispose = gtk_icon_view_dispose;
474 gobject_class->set_property = gtk_icon_view_set_property;
475 gobject_class->get_property = gtk_icon_view_get_property;
477 widget_class->destroy = gtk_icon_view_destroy;
478 widget_class->realize = gtk_icon_view_realize;
479 widget_class->unrealize = gtk_icon_view_unrealize;
480 widget_class->style_set = gtk_icon_view_style_set;
481 widget_class->get_accessible = gtk_icon_view_get_accessible;
482 widget_class->get_preferred_width = gtk_icon_view_get_preferred_width;
483 widget_class->get_preferred_height = gtk_icon_view_get_preferred_height;
484 widget_class->size_allocate = gtk_icon_view_size_allocate;
485 widget_class->draw = gtk_icon_view_draw;
486 widget_class->motion_notify_event = gtk_icon_view_motion;
487 widget_class->button_press_event = gtk_icon_view_button_press;
488 widget_class->button_release_event = gtk_icon_view_button_release;
489 widget_class->key_press_event = gtk_icon_view_key_press;
490 widget_class->key_release_event = gtk_icon_view_key_release;
491 widget_class->drag_begin = gtk_icon_view_drag_begin;
492 widget_class->drag_end = gtk_icon_view_drag_end;
493 widget_class->drag_data_get = gtk_icon_view_drag_data_get;
494 widget_class->drag_data_delete = gtk_icon_view_drag_data_delete;
495 widget_class->drag_leave = gtk_icon_view_drag_leave;
496 widget_class->drag_motion = gtk_icon_view_drag_motion;
497 widget_class->drag_drop = gtk_icon_view_drag_drop;
498 widget_class->drag_data_received = gtk_icon_view_drag_data_received;
499 widget_class->state_changed = gtk_icon_view_state_changed;
501 container_class->remove = gtk_icon_view_remove;
502 container_class->forall = gtk_icon_view_forall;
504 klass->select_all = gtk_icon_view_real_select_all;
505 klass->unselect_all = gtk_icon_view_real_unselect_all;
506 klass->select_cursor_item = gtk_icon_view_real_select_cursor_item;
507 klass->toggle_cursor_item = gtk_icon_view_real_toggle_cursor_item;
508 klass->activate_cursor_item = gtk_icon_view_real_activate_cursor_item;
509 klass->move_cursor = gtk_icon_view_real_move_cursor;
513 * GtkIconView:selection-mode:
515 * The ::selection-mode property specifies the selection mode of
516 * icon view. If the mode is #GTK_SELECTION_MULTIPLE, rubberband selection
517 * is enabled, for the other modes, only keyboard selection is possible.
521 g_object_class_install_property (gobject_class,
523 g_param_spec_enum ("selection-mode",
524 P_("Selection mode"),
525 P_("The selection mode"),
526 GTK_TYPE_SELECTION_MODE,
527 GTK_SELECTION_SINGLE,
528 GTK_PARAM_READWRITE));
531 * GtkIconView:pixbuf-column:
533 * The ::pixbuf-column property contains the number of the model column
534 * containing the pixbufs which are displayed. The pixbuf column must be
535 * of type #GDK_TYPE_PIXBUF. Setting this property to -1 turns off the
536 * display of pixbufs.
540 g_object_class_install_property (gobject_class,
542 g_param_spec_int ("pixbuf-column",
544 P_("Model column used to retrieve the icon pixbuf from"),
546 GTK_PARAM_READWRITE));
549 * GtkIconView:text-column:
551 * The ::text-column property contains the number of the model column
552 * containing the texts which are displayed. The text column must be
553 * of type #G_TYPE_STRING. If this property and the :markup-column
554 * property are both set to -1, no texts are displayed.
558 g_object_class_install_property (gobject_class,
560 g_param_spec_int ("text-column",
562 P_("Model column used to retrieve the text from"),
564 GTK_PARAM_READWRITE));
568 * GtkIconView:markup-column:
570 * The ::markup-column property contains the number of the model column
571 * containing markup information to be displayed. The markup column must be
572 * of type #G_TYPE_STRING. If this property and the :text-column property
573 * are both set to column numbers, it overrides the text column.
574 * If both are set to -1, no texts are displayed.
578 g_object_class_install_property (gobject_class,
580 g_param_spec_int ("markup-column",
582 P_("Model column used to retrieve the text if using Pango markup"),
584 GTK_PARAM_READWRITE));
586 g_object_class_install_property (gobject_class,
588 g_param_spec_object ("model",
589 P_("Icon View Model"),
590 P_("The model for the icon view"),
592 GTK_PARAM_READWRITE));
595 * GtkIconView:columns:
597 * The columns property contains the number of the columns in which the
598 * items should be displayed. If it is -1, the number of columns will
599 * be chosen automatically to fill the available area.
603 g_object_class_install_property (gobject_class,
605 g_param_spec_int ("columns",
606 P_("Number of columns"),
607 P_("Number of columns to display"),
609 GTK_PARAM_READWRITE));
613 * GtkIconView:item-width:
615 * The item-width property specifies the width to use for each item.
616 * If it is set to -1, the icon view will automatically determine a
617 * suitable item size.
621 g_object_class_install_property (gobject_class,
623 g_param_spec_int ("item-width",
624 P_("Width for each item"),
625 P_("The width used for each item"),
627 GTK_PARAM_READWRITE));
630 * GtkIconView:spacing:
632 * The spacing property specifies the space which is inserted between
633 * the cells (i.e. the icon and the text) of an item.
637 g_object_class_install_property (gobject_class,
639 g_param_spec_int ("spacing",
641 P_("Space which is inserted between cells of an item"),
643 GTK_PARAM_READWRITE));
646 * GtkIconView:row-spacing:
648 * The row-spacing property specifies the space which is inserted between
649 * the rows of the icon view.
653 g_object_class_install_property (gobject_class,
655 g_param_spec_int ("row-spacing",
657 P_("Space which is inserted between grid rows"),
659 GTK_PARAM_READWRITE));
662 * GtkIconView:column-spacing:
664 * The column-spacing property specifies the space which is inserted between
665 * the columns of the icon view.
669 g_object_class_install_property (gobject_class,
671 g_param_spec_int ("column-spacing",
672 P_("Column Spacing"),
673 P_("Space which is inserted between grid columns"),
675 GTK_PARAM_READWRITE));
678 * GtkIconView:margin:
680 * The margin property specifies the space which is inserted
681 * at the edges of the icon view.
685 g_object_class_install_property (gobject_class,
687 g_param_spec_int ("margin",
689 P_("Space which is inserted at the edges of the icon view"),
691 GTK_PARAM_READWRITE));
694 * GtkIconView:item-orientation:
696 * The item-orientation property specifies how the cells (i.e. the icon and
697 * the text) of the item are positioned relative to each other.
701 g_object_class_install_property (gobject_class,
702 PROP_ITEM_ORIENTATION,
703 g_param_spec_enum ("item-orientation",
704 P_("Item Orientation"),
705 P_("How the text and icon of each item are positioned relative to each other"),
706 GTK_TYPE_ORIENTATION,
707 GTK_ORIENTATION_VERTICAL,
708 GTK_PARAM_READWRITE));
711 * GtkIconView:reorderable:
713 * The reorderable property specifies if the items can be reordered
718 g_object_class_install_property (gobject_class,
720 g_param_spec_boolean ("reorderable",
722 P_("View is reorderable"),
726 g_object_class_install_property (gobject_class,
728 g_param_spec_int ("tooltip-column",
729 P_("Tooltip Column"),
730 P_("The column in the model containing the tooltip texts for the items"),
734 GTK_PARAM_READWRITE));
737 * GtkIconView:item-padding:
739 * The item-padding property specifies the padding around each
740 * of the icon view's item.
744 g_object_class_install_property (gobject_class,
746 g_param_spec_int ("item-padding",
748 P_("Padding around icon view items"),
750 GTK_PARAM_READWRITE));
753 * GtkIconView:cell-area:
755 * The #GtkCellArea used to layout cell renderers for this view.
759 g_object_class_install_property (gobject_class,
761 g_param_spec_object ("cell-area",
763 P_("The GtkCellArea used to layout cells"),
765 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
767 /* Scrollable interface properties */
768 g_object_class_override_property (gobject_class, PROP_HADJUSTMENT, "hadjustment");
769 g_object_class_override_property (gobject_class, PROP_VADJUSTMENT, "vadjustment");
770 g_object_class_override_property (gobject_class, PROP_HSCROLL_POLICY, "hscroll-policy");
771 g_object_class_override_property (gobject_class, PROP_VSCROLL_POLICY, "vscroll-policy");
773 /* Style properties */
774 gtk_widget_class_install_style_property (widget_class,
775 g_param_spec_boxed ("selection-box-color",
776 P_("Selection Box Color"),
777 P_("Color of the selection box"),
779 GTK_PARAM_READABLE));
781 gtk_widget_class_install_style_property (widget_class,
782 g_param_spec_uchar ("selection-box-alpha",
783 P_("Selection Box Alpha"),
784 P_("Opacity of the selection box"),
787 GTK_PARAM_READABLE));
791 * GtkIconView::item-activated:
792 * @iconview: the object on which the signal is emitted
793 * @path: the #GtkTreePath for the activated item
795 * The ::item-activated signal is emitted when the method
796 * gtk_icon_view_item_activated() is called or the user double
797 * clicks an item. It is also emitted when a non-editable item
798 * is selected and one of the keys: Space, Return or Enter is
801 icon_view_signals[ITEM_ACTIVATED] =
802 g_signal_new (I_("item-activated"),
803 G_TYPE_FROM_CLASS (gobject_class),
805 G_STRUCT_OFFSET (GtkIconViewClass, item_activated),
807 g_cclosure_marshal_VOID__BOXED,
812 * GtkIconView::selection-changed:
813 * @iconview: the object on which the signal is emitted
815 * The ::selection-changed signal is emitted when the selection
816 * (i.e. the set of selected items) changes.
818 icon_view_signals[SELECTION_CHANGED] =
819 g_signal_new (I_("selection-changed"),
820 G_TYPE_FROM_CLASS (gobject_class),
822 G_STRUCT_OFFSET (GtkIconViewClass, selection_changed),
824 g_cclosure_marshal_VOID__VOID,
828 * GtkIconView::select-all:
829 * @iconview: the object on which the signal is emitted
831 * A <link linkend="keybinding-signals">keybinding signal</link>
832 * which gets emitted when the user selects all items.
834 * Applications should not connect to it, but may emit it with
835 * g_signal_emit_by_name() if they need to control selection
838 * The default binding for this signal is Ctrl-a.
840 icon_view_signals[SELECT_ALL] =
841 g_signal_new (I_("select-all"),
842 G_TYPE_FROM_CLASS (gobject_class),
843 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
844 G_STRUCT_OFFSET (GtkIconViewClass, select_all),
846 g_cclosure_marshal_VOID__VOID,
850 * GtkIconView::unselect-all:
851 * @iconview: the object on which the signal is emitted
853 * A <link linkend="keybinding-signals">keybinding signal</link>
854 * which gets emitted when the user unselects all items.
856 * Applications should not connect to it, but may emit it with
857 * g_signal_emit_by_name() if they need to control selection
860 * The default binding for this signal is Ctrl-Shift-a.
862 icon_view_signals[UNSELECT_ALL] =
863 g_signal_new (I_("unselect-all"),
864 G_TYPE_FROM_CLASS (gobject_class),
865 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
866 G_STRUCT_OFFSET (GtkIconViewClass, unselect_all),
868 g_cclosure_marshal_VOID__VOID,
872 * GtkIconView::select-cursor-item:
873 * @iconview: the object on which the signal is emitted
875 * A <link linkend="keybinding-signals">keybinding signal</link>
876 * which gets emitted when the user selects the item that is currently
879 * Applications should not connect to it, but may emit it with
880 * g_signal_emit_by_name() if they need to control selection
883 * There is no default binding for this signal.
885 icon_view_signals[SELECT_CURSOR_ITEM] =
886 g_signal_new (I_("select-cursor-item"),
887 G_TYPE_FROM_CLASS (gobject_class),
888 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
889 G_STRUCT_OFFSET (GtkIconViewClass, select_cursor_item),
891 g_cclosure_marshal_VOID__VOID,
895 * GtkIconView::toggle-cursor-item:
896 * @iconview: the object on which the signal is emitted
898 * A <link linkend="keybinding-signals">keybinding signal</link>
899 * which gets emitted when the user toggles whether the currently
900 * focused item is selected or not. The exact effect of this
901 * depend on the selection mode.
903 * Applications should not connect to it, but may emit it with
904 * g_signal_emit_by_name() if they need to control selection
907 * There is no default binding for this signal is Ctrl-Space.
909 icon_view_signals[TOGGLE_CURSOR_ITEM] =
910 g_signal_new (I_("toggle-cursor-item"),
911 G_TYPE_FROM_CLASS (gobject_class),
912 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
913 G_STRUCT_OFFSET (GtkIconViewClass, toggle_cursor_item),
915 g_cclosure_marshal_VOID__VOID,
919 * GtkIconView::activate-cursor-item:
920 * @iconview: the object on which the signal is emitted
922 * A <link linkend="keybinding-signals">keybinding signal</link>
923 * which gets emitted when the user activates the currently
926 * Applications should not connect to it, but may emit it with
927 * g_signal_emit_by_name() if they need to control activation
930 * The default bindings for this signal are Space, Return and Enter.
932 icon_view_signals[ACTIVATE_CURSOR_ITEM] =
933 g_signal_new (I_("activate-cursor-item"),
934 G_TYPE_FROM_CLASS (gobject_class),
935 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
936 G_STRUCT_OFFSET (GtkIconViewClass, activate_cursor_item),
938 _gtk_marshal_BOOLEAN__VOID,
942 * GtkIconView::move-cursor:
943 * @iconview: the object which received the signal
944 * @step: the granularity of the move, as a #GtkMovementStep
945 * @count: the number of @step units to move
947 * The ::move-cursor signal is a
948 * <link linkend="keybinding-signals">keybinding signal</link>
949 * which gets emitted when the user initiates a cursor movement.
951 * Applications should not connect to it, but may emit it with
952 * g_signal_emit_by_name() if they need to control the cursor
955 * The default bindings for this signal include
957 * <listitem>Arrow keys which move by individual steps</listitem>
958 * <listitem>Home/End keys which move to the first/last item</listitem>
959 * <listitem>PageUp/PageDown which move by "pages"</listitem>
962 * All of these will extend the selection when combined with
963 * the Shift modifier.
965 icon_view_signals[MOVE_CURSOR] =
966 g_signal_new (I_("move-cursor"),
967 G_TYPE_FROM_CLASS (gobject_class),
968 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
969 G_STRUCT_OFFSET (GtkIconViewClass, move_cursor),
971 _gtk_marshal_BOOLEAN__ENUM_INT,
973 GTK_TYPE_MOVEMENT_STEP,
977 gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK,
979 gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
981 gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_CONTROL_MASK,
982 "toggle-cursor-item", 0);
983 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_CONTROL_MASK,
984 "toggle-cursor-item", 0);
986 gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0,
987 "activate-cursor-item", 0);
988 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0,
989 "activate-cursor-item", 0);
990 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0,
991 "activate-cursor-item", 0);
992 gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0,
993 "activate-cursor-item", 0);
994 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0,
995 "activate-cursor-item", 0);
997 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_Up, 0,
998 GTK_MOVEMENT_DISPLAY_LINES, -1);
999 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_KP_Up, 0,
1000 GTK_MOVEMENT_DISPLAY_LINES, -1);
1002 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_Down, 0,
1003 GTK_MOVEMENT_DISPLAY_LINES, 1);
1004 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_KP_Down, 0,
1005 GTK_MOVEMENT_DISPLAY_LINES, 1);
1007 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_p, GDK_CONTROL_MASK,
1008 GTK_MOVEMENT_DISPLAY_LINES, -1);
1010 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_n, GDK_CONTROL_MASK,
1011 GTK_MOVEMENT_DISPLAY_LINES, 1);
1013 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_Home, 0,
1014 GTK_MOVEMENT_BUFFER_ENDS, -1);
1015 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_KP_Home, 0,
1016 GTK_MOVEMENT_BUFFER_ENDS, -1);
1018 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_End, 0,
1019 GTK_MOVEMENT_BUFFER_ENDS, 1);
1020 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_KP_End, 0,
1021 GTK_MOVEMENT_BUFFER_ENDS, 1);
1023 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_Page_Up, 0,
1024 GTK_MOVEMENT_PAGES, -1);
1025 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0,
1026 GTK_MOVEMENT_PAGES, -1);
1028 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_Page_Down, 0,
1029 GTK_MOVEMENT_PAGES, 1);
1030 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0,
1031 GTK_MOVEMENT_PAGES, 1);
1033 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_Right, 0,
1034 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
1035 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_Left, 0,
1036 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
1038 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_KP_Right, 0,
1039 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
1040 gtk_icon_view_add_move_binding (binding_set, GDK_KEY_KP_Left, 0,
1041 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
1045 gtk_icon_view_buildable_init (GtkBuildableIface *iface)
1047 parent_buildable_iface = g_type_interface_peek_parent (iface);
1048 iface->add_child = _gtk_cell_layout_buildable_add_child;
1049 iface->custom_tag_start = gtk_icon_view_buildable_custom_tag_start;
1050 iface->custom_tag_end = gtk_icon_view_buildable_custom_tag_end;
1054 gtk_icon_view_cell_layout_init (GtkCellLayoutIface *iface)
1056 iface->get_area = gtk_icon_view_cell_layout_get_area;
1060 gtk_icon_view_init (GtkIconView *icon_view)
1062 icon_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (icon_view,
1064 GtkIconViewPrivate);
1066 icon_view->priv->width = 0;
1067 icon_view->priv->height = 0;
1068 icon_view->priv->selection_mode = GTK_SELECTION_SINGLE;
1069 icon_view->priv->pressed_button = -1;
1070 icon_view->priv->press_start_x = -1;
1071 icon_view->priv->press_start_y = -1;
1072 icon_view->priv->text_column = -1;
1073 icon_view->priv->markup_column = -1;
1074 icon_view->priv->pixbuf_column = -1;
1075 icon_view->priv->text_cell = NULL;
1076 icon_view->priv->pixbuf_cell = NULL;
1077 icon_view->priv->tooltip_column = -1;
1079 gtk_widget_set_can_focus (GTK_WIDGET (icon_view), TRUE);
1081 icon_view->priv->item_orientation = GTK_ORIENTATION_VERTICAL;
1083 icon_view->priv->columns = -1;
1084 icon_view->priv->item_width = -1;
1085 icon_view->priv->spacing = 0;
1086 icon_view->priv->row_spacing = 6;
1087 icon_view->priv->column_spacing = 6;
1088 icon_view->priv->margin = 6;
1089 icon_view->priv->item_padding = 6;
1091 icon_view->priv->draw_focus = TRUE;
1093 icon_view->priv->row_contexts =
1094 g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
1097 /* GObject methods */
1099 gtk_icon_view_constructor (GType type,
1100 guint n_construct_properties,
1101 GObjectConstructParam *construct_properties)
1103 GtkIconView *icon_view;
1104 GtkIconViewPrivate *priv;
1107 object = G_OBJECT_CLASS (gtk_icon_view_parent_class)->constructor
1108 (type, n_construct_properties, construct_properties);
1110 icon_view = (GtkIconView *) object;
1111 priv = icon_view->priv;
1113 if (!priv->cell_area)
1115 priv->cell_area = gtk_cell_area_box_new ();
1116 g_object_ref_sink (priv->cell_area);
1119 if (GTK_IS_ORIENTABLE (priv->cell_area))
1120 gtk_orientable_set_orientation (GTK_ORIENTABLE (priv->cell_area), priv->item_orientation);
1122 priv->cell_area_context = gtk_cell_area_create_context (priv->cell_area);
1124 priv->add_editable_id =
1125 g_signal_connect (priv->cell_area, "add-editable",
1126 G_CALLBACK (gtk_icon_view_add_editable), icon_view);
1127 priv->remove_editable_id =
1128 g_signal_connect (priv->cell_area, "remove-editable",
1129 G_CALLBACK (gtk_icon_view_remove_editable), icon_view);
1130 priv->context_changed_id =
1131 g_signal_connect (priv->cell_area_context, "notify",
1132 G_CALLBACK (gtk_icon_view_context_changed), icon_view);
1138 gtk_icon_view_dispose (GObject *object)
1140 GtkIconView *icon_view;
1141 GtkIconViewPrivate *priv;
1143 icon_view = GTK_ICON_VIEW (object);
1144 priv = icon_view->priv;
1146 if (priv->cell_area_context)
1148 g_signal_handler_disconnect (priv->cell_area_context, priv->context_changed_id);
1149 priv->context_changed_id = 0;
1151 g_object_unref (priv->cell_area_context);
1152 priv->cell_area_context = NULL;
1155 if (priv->row_contexts)
1157 g_ptr_array_free (priv->row_contexts, TRUE);
1158 priv->row_contexts = NULL;
1161 if (priv->cell_area)
1163 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
1165 g_signal_handler_disconnect (priv->cell_area, priv->add_editable_id);
1166 g_signal_handler_disconnect (priv->cell_area, priv->remove_editable_id);
1167 priv->add_editable_id = 0;
1168 priv->remove_editable_id = 0;
1170 g_object_unref (priv->cell_area);
1171 priv->cell_area = NULL;
1174 G_OBJECT_CLASS (gtk_icon_view_parent_class)->dispose (object);
1178 gtk_icon_view_set_property (GObject *object,
1180 const GValue *value,
1183 GtkIconView *icon_view;
1186 icon_view = GTK_ICON_VIEW (object);
1190 case PROP_SELECTION_MODE:
1191 gtk_icon_view_set_selection_mode (icon_view, g_value_get_enum (value));
1193 case PROP_PIXBUF_COLUMN:
1194 gtk_icon_view_set_pixbuf_column (icon_view, g_value_get_int (value));
1196 case PROP_TEXT_COLUMN:
1197 gtk_icon_view_set_text_column (icon_view, g_value_get_int (value));
1199 case PROP_MARKUP_COLUMN:
1200 gtk_icon_view_set_markup_column (icon_view, g_value_get_int (value));
1203 gtk_icon_view_set_model (icon_view, g_value_get_object (value));
1205 case PROP_ITEM_ORIENTATION:
1206 gtk_icon_view_set_item_orientation (icon_view, g_value_get_enum (value));
1209 gtk_icon_view_set_columns (icon_view, g_value_get_int (value));
1211 case PROP_ITEM_WIDTH:
1212 gtk_icon_view_set_item_width (icon_view, g_value_get_int (value));
1215 gtk_icon_view_set_spacing (icon_view, g_value_get_int (value));
1217 case PROP_ROW_SPACING:
1218 gtk_icon_view_set_row_spacing (icon_view, g_value_get_int (value));
1220 case PROP_COLUMN_SPACING:
1221 gtk_icon_view_set_column_spacing (icon_view, g_value_get_int (value));
1224 gtk_icon_view_set_margin (icon_view, g_value_get_int (value));
1226 case PROP_REORDERABLE:
1227 gtk_icon_view_set_reorderable (icon_view, g_value_get_boolean (value));
1230 case PROP_TOOLTIP_COLUMN:
1231 gtk_icon_view_set_tooltip_column (icon_view, g_value_get_int (value));
1234 case PROP_ITEM_PADDING:
1235 gtk_icon_view_set_item_padding (icon_view, g_value_get_int (value));
1238 case PROP_CELL_AREA:
1239 /* Construct-only, can only be assigned once */
1240 area = g_value_get_object (value);
1243 icon_view->priv->cell_area = g_object_ref_sink (area);
1246 case PROP_HADJUSTMENT:
1247 gtk_icon_view_set_hadjustment (icon_view, g_value_get_object (value));
1249 case PROP_VADJUSTMENT:
1250 gtk_icon_view_set_vadjustment (icon_view, g_value_get_object (value));
1252 case PROP_HSCROLL_POLICY:
1253 icon_view->priv->hscroll_policy = g_value_get_enum (value);
1254 gtk_widget_queue_resize (GTK_WIDGET (icon_view));
1256 case PROP_VSCROLL_POLICY:
1257 icon_view->priv->vscroll_policy = g_value_get_enum (value);
1258 gtk_widget_queue_resize (GTK_WIDGET (icon_view));
1262 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1268 gtk_icon_view_get_property (GObject *object,
1273 GtkIconView *icon_view;
1275 icon_view = GTK_ICON_VIEW (object);
1279 case PROP_SELECTION_MODE:
1280 g_value_set_enum (value, icon_view->priv->selection_mode);
1282 case PROP_PIXBUF_COLUMN:
1283 g_value_set_int (value, icon_view->priv->pixbuf_column);
1285 case PROP_TEXT_COLUMN:
1286 g_value_set_int (value, icon_view->priv->text_column);
1288 case PROP_MARKUP_COLUMN:
1289 g_value_set_int (value, icon_view->priv->markup_column);
1292 g_value_set_object (value, icon_view->priv->model);
1294 case PROP_ITEM_ORIENTATION:
1295 g_value_set_enum (value, icon_view->priv->item_orientation);
1298 g_value_set_int (value, icon_view->priv->columns);
1300 case PROP_ITEM_WIDTH:
1301 g_value_set_int (value, icon_view->priv->item_width);
1304 g_value_set_int (value, icon_view->priv->spacing);
1306 case PROP_ROW_SPACING:
1307 g_value_set_int (value, icon_view->priv->row_spacing);
1309 case PROP_COLUMN_SPACING:
1310 g_value_set_int (value, icon_view->priv->column_spacing);
1313 g_value_set_int (value, icon_view->priv->margin);
1315 case PROP_REORDERABLE:
1316 g_value_set_boolean (value, icon_view->priv->reorderable);
1318 case PROP_TOOLTIP_COLUMN:
1319 g_value_set_int (value, icon_view->priv->tooltip_column);
1322 case PROP_ITEM_PADDING:
1323 g_value_set_int (value, icon_view->priv->item_padding);
1326 case PROP_CELL_AREA:
1327 g_value_set_object (value, icon_view->priv->cell_area);
1330 case PROP_HADJUSTMENT:
1331 g_value_set_object (value, icon_view->priv->hadjustment);
1333 case PROP_VADJUSTMENT:
1334 g_value_set_object (value, icon_view->priv->vadjustment);
1336 case PROP_HSCROLL_POLICY:
1337 g_value_set_enum (value, icon_view->priv->hscroll_policy);
1339 case PROP_VSCROLL_POLICY:
1340 g_value_set_enum (value, icon_view->priv->vscroll_policy);
1344 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1349 /* GtkWidget methods */
1351 gtk_icon_view_destroy (GtkWidget *widget)
1353 GtkIconView *icon_view = GTK_ICON_VIEW (widget);
1355 gtk_icon_view_set_model (icon_view, NULL);
1357 if (icon_view->priv->layout_idle_id != 0)
1359 g_source_remove (icon_view->priv->layout_idle_id);
1360 icon_view->priv->layout_idle_id = 0;
1363 if (icon_view->priv->scroll_to_path != NULL)
1365 gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
1366 icon_view->priv->scroll_to_path = NULL;
1369 remove_scroll_timeout (icon_view);
1371 if (icon_view->priv->hadjustment != NULL)
1373 g_object_unref (icon_view->priv->hadjustment);
1374 icon_view->priv->hadjustment = NULL;
1377 if (icon_view->priv->vadjustment != NULL)
1379 g_object_unref (icon_view->priv->vadjustment);
1380 icon_view->priv->vadjustment = NULL;
1383 GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->destroy (widget);
1387 gtk_icon_view_realize (GtkWidget *widget)
1389 GtkIconView *icon_view = GTK_ICON_VIEW (widget);
1390 GtkAllocation allocation;
1392 GdkWindowAttr attributes;
1393 gint attributes_mask;
1395 gtk_widget_set_realized (widget, TRUE);
1397 gtk_widget_get_allocation (widget, &allocation);
1399 /* Make the main, clipping window */
1400 attributes.window_type = GDK_WINDOW_CHILD;
1401 attributes.x = allocation.x;
1402 attributes.y = allocation.y;
1403 attributes.width = allocation.width;
1404 attributes.height = allocation.height;
1405 attributes.wclass = GDK_INPUT_OUTPUT;
1406 attributes.visual = gtk_widget_get_visual (widget);
1407 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1409 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
1411 window = gdk_window_new (gtk_widget_get_parent_window (widget),
1412 &attributes, attributes_mask);
1413 gtk_widget_set_window (widget, window);
1414 gdk_window_set_user_data (window, widget);
1416 gtk_widget_get_allocation (widget, &allocation);
1418 /* Make the window for the icon view */
1421 attributes.width = MAX (icon_view->priv->width, allocation.width);
1422 attributes.height = MAX (icon_view->priv->height, allocation.height);
1423 attributes.event_mask = (GDK_EXPOSURE_MASK |
1425 GDK_POINTER_MOTION_MASK |
1426 GDK_BUTTON_PRESS_MASK |
1427 GDK_BUTTON_RELEASE_MASK |
1428 GDK_KEY_PRESS_MASK |
1429 GDK_KEY_RELEASE_MASK) |
1430 gtk_widget_get_events (widget);
1432 icon_view->priv->bin_window = gdk_window_new (window,
1433 &attributes, attributes_mask);
1434 gdk_window_set_user_data (icon_view->priv->bin_window, widget);
1436 gtk_widget_style_attach (widget);
1437 gdk_window_set_background (icon_view->priv->bin_window,
1438 >k_widget_get_style (widget)->base[gtk_widget_get_state (widget)]);
1440 gdk_window_show (icon_view->priv->bin_window);
1444 gtk_icon_view_unrealize (GtkWidget *widget)
1446 GtkIconView *icon_view;
1448 icon_view = GTK_ICON_VIEW (widget);
1450 gdk_window_set_user_data (icon_view->priv->bin_window, NULL);
1451 gdk_window_destroy (icon_view->priv->bin_window);
1452 icon_view->priv->bin_window = NULL;
1454 GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->unrealize (widget);
1458 gtk_icon_view_state_changed (GtkWidget *widget,
1459 GtkStateType previous_state)
1461 GtkIconView *icon_view = GTK_ICON_VIEW (widget);
1465 if (gtk_widget_get_realized (widget))
1467 style = gtk_widget_get_style (widget);
1468 state = gtk_widget_get_state (widget);
1470 gdk_window_set_background (gtk_widget_get_window (widget), &style->base[state]);
1471 gdk_window_set_background (icon_view->priv->bin_window, &style->base[state]);
1474 gtk_widget_queue_draw (widget);
1478 gtk_icon_view_style_set (GtkWidget *widget,
1479 GtkStyle *previous_style)
1481 GtkIconView *icon_view = GTK_ICON_VIEW (widget);
1485 if (gtk_widget_get_realized (widget))
1487 style = gtk_widget_get_style (widget);
1488 state = gtk_widget_get_state (widget);
1490 gdk_window_set_background (gtk_widget_get_window (widget), &style->base[state]);
1491 gdk_window_set_background (icon_view->priv->bin_window, &style->base[state]);
1494 gtk_widget_queue_resize (widget);
1498 gtk_icon_view_get_preferred_width (GtkWidget *widget,
1502 *minimum = *natural = GTK_ICON_VIEW (widget)->priv->width;
1506 gtk_icon_view_get_preferred_height (GtkWidget *widget,
1510 *minimum = *natural = GTK_ICON_VIEW (widget)->priv->height;
1514 gtk_icon_view_allocate_children (GtkIconView *icon_view)
1518 for (list = icon_view->priv->children; list; list = list->next)
1520 GtkIconViewChild *child = list->data;
1522 /* totally ignore our child's requisition */
1523 gtk_widget_size_allocate (child->widget, &child->area);
1528 gtk_icon_view_size_allocate (GtkWidget *widget,
1529 GtkAllocation *allocation)
1531 GtkIconView *icon_view = GTK_ICON_VIEW (widget);
1533 gtk_widget_set_allocation (widget, allocation);
1535 if (gtk_widget_get_realized (widget))
1537 gdk_window_move_resize (gtk_widget_get_window (widget),
1538 allocation->x, allocation->y,
1539 allocation->width, allocation->height);
1540 gdk_window_resize (icon_view->priv->bin_window,
1541 MAX (icon_view->priv->width, allocation->width),
1542 MAX (icon_view->priv->height, allocation->height));
1545 gtk_icon_view_layout (icon_view);
1547 gtk_icon_view_allocate_children (icon_view);
1549 /* Delay signal emission */
1550 g_object_freeze_notify (G_OBJECT (icon_view->priv->hadjustment));
1551 g_object_freeze_notify (G_OBJECT (icon_view->priv->vadjustment));
1553 gtk_icon_view_set_hadjustment_values (icon_view);
1554 gtk_icon_view_set_vadjustment_values (icon_view);
1556 if (gtk_widget_get_realized (widget) &&
1557 icon_view->priv->scroll_to_path)
1560 path = gtk_tree_row_reference_get_path (icon_view->priv->scroll_to_path);
1561 gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
1562 icon_view->priv->scroll_to_path = NULL;
1564 gtk_icon_view_scroll_to_path (icon_view, path,
1565 icon_view->priv->scroll_to_use_align,
1566 icon_view->priv->scroll_to_row_align,
1567 icon_view->priv->scroll_to_col_align);
1568 gtk_tree_path_free (path);
1571 /* Emit any pending signals now */
1572 g_object_thaw_notify (G_OBJECT (icon_view->priv->hadjustment));
1573 g_object_thaw_notify (G_OBJECT (icon_view->priv->vadjustment));
1577 gtk_icon_view_draw (GtkWidget *widget,
1580 GtkIconView *icon_view;
1584 GtkIconViewDropPosition dest_pos;
1585 GtkIconViewItem *dest_item = NULL;
1587 icon_view = GTK_ICON_VIEW (widget);
1589 if (!gtk_cairo_should_draw_window (cr, icon_view->priv->bin_window))
1594 gtk_cairo_transform_to_window (cr, widget, icon_view->priv->bin_window);
1596 cairo_set_line_width (cr, 1.);
1598 gtk_icon_view_get_drag_dest_item (icon_view, &path, &dest_pos);
1602 dest_index = gtk_tree_path_get_indices (path)[0];
1603 gtk_tree_path_free (path);
1608 for (icons = icon_view->priv->items; icons; icons = icons->next)
1610 GtkIconViewItem *item = icons->data;
1611 GdkRectangle paint_area;
1613 paint_area.x = ((GdkRectangle *)item)->x - icon_view->priv->item_padding;
1614 paint_area.y = ((GdkRectangle *)item)->y - icon_view->priv->item_padding;
1615 paint_area.width = ((GdkRectangle *)item)->width + icon_view->priv->item_padding * 2;
1616 paint_area.height = ((GdkRectangle *)item)->height + icon_view->priv->item_padding * 2;
1620 cairo_rectangle (cr, paint_area.x, paint_area.y, paint_area.width, paint_area.height);
1623 if (gdk_cairo_get_clip_rectangle (cr, NULL))
1625 gtk_icon_view_paint_item (icon_view, cr, item,
1626 ((GdkRectangle *)item)->x, ((GdkRectangle *)item)->y,
1627 icon_view->priv->draw_focus);
1629 if (dest_index == item->index)
1641 style = gtk_widget_get_style (widget);
1642 state = gtk_widget_get_state (widget);
1646 case GTK_ICON_VIEW_DROP_INTO:
1647 gtk_paint_focus (style, cr, state, widget,
1648 "iconview-drop-indicator",
1649 dest_item->cell_area.x, dest_item->cell_area.y,
1650 dest_item->cell_area.width, dest_item->cell_area.height);
1652 case GTK_ICON_VIEW_DROP_ABOVE:
1653 gtk_paint_focus (style, cr, state, widget,
1654 "iconview-drop-indicator",
1655 dest_item->cell_area.x, dest_item->cell_area.y - 1,
1656 dest_item->cell_area.width, 2);
1658 case GTK_ICON_VIEW_DROP_LEFT:
1659 gtk_paint_focus (style, cr, state, widget,
1660 "iconview-drop-indicator",
1661 dest_item->cell_area.x - 1, dest_item->cell_area.y,
1662 2, dest_item->cell_area.height);
1664 case GTK_ICON_VIEW_DROP_BELOW:
1665 gtk_paint_focus (style, cr, state, widget,
1666 "iconview-drop-indicator",
1667 dest_item->cell_area.x,
1668 dest_item->cell_area.y + dest_item->cell_area.height - 1,
1669 dest_item->cell_area.width, 2);
1671 case GTK_ICON_VIEW_DROP_RIGHT:
1672 gtk_paint_focus (style, cr, state, widget,
1673 "iconview-drop-indicator",
1674 dest_item->cell_area.x + dest_item->cell_area.width - 1,
1675 dest_item->cell_area.y,
1676 2, dest_item->cell_area.height);
1677 case GTK_ICON_VIEW_NO_DROP: ;
1682 if (icon_view->priv->doing_rubberband)
1683 gtk_icon_view_paint_rubberband (icon_view, cr);
1687 GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->draw (widget, cr);
1693 rubberband_scroll_timeout (gpointer data)
1695 GtkIconView *icon_view = data;
1697 gtk_adjustment_set_value (icon_view->priv->vadjustment,
1698 gtk_adjustment_get_value (icon_view->priv->vadjustment) +
1699 icon_view->priv->scroll_value_diff);
1701 gtk_icon_view_update_rubberband (icon_view);
1707 gtk_icon_view_motion (GtkWidget *widget,
1708 GdkEventMotion *event)
1710 GtkAllocation allocation;
1711 GtkIconView *icon_view;
1714 icon_view = GTK_ICON_VIEW (widget);
1716 gtk_icon_view_maybe_begin_drag (icon_view, event);
1718 if (icon_view->priv->doing_rubberband)
1720 gtk_icon_view_update_rubberband (widget);
1722 abs_y = event->y - icon_view->priv->height *
1723 (gtk_adjustment_get_value (icon_view->priv->vadjustment) /
1724 (gtk_adjustment_get_upper (icon_view->priv->vadjustment) -
1725 gtk_adjustment_get_lower (icon_view->priv->vadjustment)));
1727 gtk_widget_get_allocation (widget, &allocation);
1729 if (abs_y < 0 || abs_y > allocation.height)
1732 icon_view->priv->scroll_value_diff = abs_y;
1734 icon_view->priv->scroll_value_diff = abs_y - allocation.height;
1736 icon_view->priv->event_last_x = event->x;
1737 icon_view->priv->event_last_y = event->y;
1739 if (icon_view->priv->scroll_timeout_id == 0)
1740 icon_view->priv->scroll_timeout_id = gdk_threads_add_timeout (30, rubberband_scroll_timeout,
1744 remove_scroll_timeout (icon_view);
1751 gtk_icon_view_remove (GtkContainer *container,
1754 GtkIconView *icon_view;
1755 GtkIconViewChild *child = NULL;
1758 icon_view = GTK_ICON_VIEW (container);
1760 tmp_list = icon_view->priv->children;
1763 child = tmp_list->data;
1764 if (child->widget == widget)
1766 gtk_widget_unparent (widget);
1768 icon_view->priv->children = g_list_remove_link (icon_view->priv->children, tmp_list);
1769 g_list_free_1 (tmp_list);
1774 tmp_list = tmp_list->next;
1779 gtk_icon_view_forall (GtkContainer *container,
1780 gboolean include_internals,
1781 GtkCallback callback,
1782 gpointer callback_data)
1784 GtkIconView *icon_view;
1785 GtkIconViewChild *child = NULL;
1788 icon_view = GTK_ICON_VIEW (container);
1790 tmp_list = icon_view->priv->children;
1793 child = tmp_list->data;
1794 tmp_list = tmp_list->next;
1796 (* callback) (child->widget, callback_data);
1801 gtk_icon_view_item_selected_changed (GtkIconView *icon_view,
1802 GtkIconViewItem *item)
1805 AtkObject *item_obj;
1807 obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
1810 item_obj = atk_object_ref_accessible_child (obj, item->index);
1811 if (item_obj != NULL)
1813 atk_object_notify_state_change (item_obj, ATK_STATE_SELECTED, item->selected);
1814 g_object_unref (item_obj);
1820 gtk_icon_view_add_editable (GtkCellArea *area,
1821 GtkCellRenderer *renderer,
1822 GtkCellEditable *editable,
1823 GdkRectangle *cell_area,
1825 GtkIconView *icon_view)
1827 GtkIconViewChild *child;
1828 GtkWidget *widget = GTK_WIDGET (editable);
1830 child = g_new (GtkIconViewChild, 1);
1832 child->widget = widget;
1833 child->area.x = cell_area->x;
1834 child->area.y = cell_area->y;
1835 child->area.width = cell_area->width;
1836 child->area.height = cell_area->height;
1838 icon_view->priv->children = g_list_append (icon_view->priv->children, child);
1840 if (gtk_widget_get_realized (GTK_WIDGET (icon_view)))
1841 gtk_widget_set_parent_window (child->widget, icon_view->priv->bin_window);
1843 gtk_widget_set_parent (widget, GTK_WIDGET (icon_view));
1847 gtk_icon_view_remove_editable (GtkCellArea *area,
1848 GtkCellRenderer *renderer,
1849 GtkCellEditable *editable,
1850 GtkIconView *icon_view)
1854 if (gtk_widget_has_focus (GTK_WIDGET (editable)))
1855 gtk_widget_grab_focus (GTK_WIDGET (icon_view));
1857 gtk_container_remove (GTK_CONTAINER (icon_view),
1858 GTK_WIDGET (editable));
1860 path = gtk_tree_path_new_from_string (gtk_cell_area_get_current_path_string (area));
1861 gtk_icon_view_queue_draw_path (icon_view, path);
1862 gtk_tree_path_free (path);
1866 gtk_icon_view_context_changed (GtkCellAreaContext *context,
1868 GtkIconView *icon_view)
1870 if (!strcmp (pspec->name, "minimum-width") ||
1871 !strcmp (pspec->name, "natural-width") ||
1872 !strcmp (pspec->name, "minimum-height") ||
1873 !strcmp (pspec->name, "natural-height"))
1874 gtk_icon_view_invalidate_sizes (icon_view);
1878 * gtk_icon_view_set_cursor:
1879 * @icon_view: A #GtkIconView
1880 * @path: A #GtkTreePath
1881 * @cell: (allow-none): One of the cell renderers of @icon_view, or %NULL
1882 * @start_editing: %TRUE if the specified cell should start being edited.
1884 * Sets the current keyboard focus to be at @path, and selects it. This is
1885 * useful when you want to focus the user's attention on a particular item.
1886 * If @cell is not %NULL, then focus is given to the cell specified by
1887 * it. Additionally, if @start_editing is %TRUE, then editing should be
1888 * started in the specified cell.
1890 * This function is often followed by <literal>gtk_widget_grab_focus
1891 * (icon_view)</literal> in order to give keyboard focus to the widget.
1892 * Please note that editing can only happen when the widget is realized.
1897 gtk_icon_view_set_cursor (GtkIconView *icon_view,
1899 GtkCellRenderer *cell,
1900 gboolean start_editing)
1902 GtkIconViewItem *item = NULL;
1904 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
1905 g_return_if_fail (path != NULL);
1906 g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
1908 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
1910 if (gtk_tree_path_get_depth (path) == 1)
1911 item = g_list_nth_data (icon_view->priv->items,
1912 gtk_tree_path_get_indices(path)[0]);
1917 gtk_icon_view_set_cursor_item (icon_view, item, cell);
1918 gtk_icon_view_scroll_to_path (icon_view, path, FALSE, 0.0, 0.0);
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)
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 g_signal_handler_block (icon_view->priv->cell_area_context,
2894 icon_view->priv->context_changed_id);
2895 gtk_cell_area_context_reset (icon_view->priv->cell_area_context);
2896 g_signal_handler_unblock (icon_view->priv->cell_area_context,
2897 icon_view->priv->context_changed_id);
2899 /* Re-layout the items */
2900 gtk_icon_view_queue_layout (icon_view);
2904 gtk_icon_view_item_invalidate_size (GtkIconViewItem *item)
2906 item->cell_area.width = -1;
2907 item->cell_area.height = -1;
2911 gtk_icon_view_paint_item (GtkIconView *icon_view,
2913 GtkIconViewItem *item,
2916 gboolean draw_focus)
2918 GdkRectangle cell_area;
2919 GtkCellRendererState flags;
2920 GtkWidget *widget = GTK_WIDGET (icon_view);
2921 GtkIconViewPrivate *priv = icon_view->priv;
2923 GtkCellAreaContext *context;
2925 if (priv->model == NULL)
2928 style = gtk_widget_get_style (widget);
2929 gtk_icon_view_set_cell_data (icon_view, item);
2933 gtk_paint_flat_box (style,
2937 GTK_WIDGET (icon_view),
2939 x - icon_view->priv->item_padding,
2940 y - icon_view->priv->item_padding,
2941 item->cell_area.width + icon_view->priv->item_padding * 2,
2942 item->cell_area.height + icon_view->priv->item_padding * 2);
2947 cell_area.width = item->cell_area.width;
2948 cell_area.height = item->cell_area.height;
2952 flags |= GTK_CELL_RENDERER_SELECTED;
2954 if (gtk_widget_has_focus (widget) && item == icon_view->priv->cursor_item)
2955 flags |= GTK_CELL_RENDERER_FOCUSED;
2957 context = g_ptr_array_index (priv->row_contexts, item->row);
2958 gtk_cell_area_render (priv->cell_area, context,
2959 widget, cr, &cell_area, &cell_area, flags,
2964 gtk_icon_view_paint_rubberband (GtkIconView *icon_view,
2968 GdkColor *fill_color_gdk;
2969 guchar fill_color_alpha;
2973 rect.x = MIN (icon_view->priv->rubberband_x1, icon_view->priv->rubberband_x2);
2974 rect.y = MIN (icon_view->priv->rubberband_y1, icon_view->priv->rubberband_y2);
2975 rect.width = ABS (icon_view->priv->rubberband_x1 - icon_view->priv->rubberband_x2) + 1;
2976 rect.height = ABS (icon_view->priv->rubberband_y1 - icon_view->priv->rubberband_y2) + 1;
2978 gtk_widget_style_get (GTK_WIDGET (icon_view),
2979 "selection-box-color", &fill_color_gdk,
2980 "selection-box-alpha", &fill_color_alpha,
2983 if (!fill_color_gdk)
2984 fill_color_gdk = gdk_color_copy (>k_widget_get_style (GTK_WIDGET (icon_view))->base[GTK_STATE_SELECTED]);
2986 gdk_cairo_set_source_color (cr, fill_color_gdk);
2988 gdk_cairo_rectangle (cr, &rect);
2991 cairo_paint_with_alpha (cr, fill_color_alpha / 255.);
2993 cairo_rectangle (cr,
2994 rect.x + 0.5, rect.y + 0.5,
2995 rect.width - 1, rect.height - 1);
2998 gdk_color_free (fill_color_gdk);
3004 gtk_icon_view_queue_draw_path (GtkIconView *icon_view,
3010 index = gtk_tree_path_get_indices (path)[0];
3012 for (l = icon_view->priv->items; l; l = l->next)
3014 GtkIconViewItem *item = l->data;
3016 if (item->index == index)
3018 gtk_icon_view_queue_draw_item (icon_view, item);
3025 gtk_icon_view_queue_draw_item (GtkIconView *icon_view,
3026 GtkIconViewItem *item)
3029 GdkRectangle *item_area = (GdkRectangle *)item;
3031 rect.x = item_area->x - icon_view->priv->item_padding;
3032 rect.y = item_area->y - icon_view->priv->item_padding;
3033 rect.width = item_area->width + icon_view->priv->item_padding * 2;
3034 rect.height = item_area->height + icon_view->priv->item_padding * 2;
3036 if (icon_view->priv->bin_window)
3037 gdk_window_invalidate_rect (icon_view->priv->bin_window, &rect, TRUE);
3041 layout_callback (gpointer user_data)
3043 GtkIconView *icon_view;
3045 icon_view = GTK_ICON_VIEW (user_data);
3047 icon_view->priv->layout_idle_id = 0;
3049 gtk_icon_view_layout (icon_view);
3055 gtk_icon_view_queue_layout (GtkIconView *icon_view)
3057 if (icon_view->priv->layout_idle_id != 0)
3060 icon_view->priv->layout_idle_id =
3061 gdk_threads_add_idle_full (GTK_ICON_VIEW_PRIORITY_LAYOUT,
3062 layout_callback, icon_view, NULL);
3066 gtk_icon_view_set_cursor_item (GtkIconView *icon_view,
3067 GtkIconViewItem *item,
3068 GtkCellRenderer *cursor_cell)
3071 AtkObject *item_obj;
3072 AtkObject *cursor_item_obj;
3074 /* When hitting this path from keynav, the focus cell is
3075 * already set, we dont need to notify the atk object
3076 * but we still need to queue the draw here (in the case
3077 * that the focus cell changes but not the cursor item).
3079 gtk_icon_view_queue_draw_item (icon_view, item);
3081 if (icon_view->priv->cursor_item == item &&
3082 (cursor_cell == NULL || cursor_cell == gtk_cell_area_get_focus_cell (icon_view->priv->cell_area)))
3085 obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
3086 if (icon_view->priv->cursor_item != NULL)
3088 gtk_icon_view_queue_draw_item (icon_view, icon_view->priv->cursor_item);
3091 cursor_item_obj = atk_object_ref_accessible_child (obj, icon_view->priv->cursor_item->index);
3092 if (cursor_item_obj != NULL)
3093 atk_object_notify_state_change (cursor_item_obj, ATK_STATE_FOCUSED, FALSE);
3096 icon_view->priv->cursor_item = item;
3099 gtk_cell_area_set_focus_cell (icon_view->priv->cell_area, cursor_cell);
3102 /* Make sure there is a cell in focus initially */
3103 if (!gtk_cell_area_get_focus_cell (icon_view->priv->cell_area))
3104 gtk_cell_area_focus (icon_view->priv->cell_area, GTK_DIR_TAB_FORWARD);
3107 /* Notify that accessible focus object has changed */
3108 item_obj = atk_object_ref_accessible_child (obj, item->index);
3110 if (item_obj != NULL)
3112 atk_focus_tracker_notify (item_obj);
3113 atk_object_notify_state_change (item_obj, ATK_STATE_FOCUSED, TRUE);
3114 g_object_unref (item_obj);
3119 static GtkIconViewItem *
3120 gtk_icon_view_item_new (void)
3122 GtkIconViewItem *item;
3124 item = g_slice_new0 (GtkIconViewItem);
3126 item->cell_area.width = -1;
3127 item->cell_area.height = -1;
3133 gtk_icon_view_item_free (GtkIconViewItem *item)
3135 g_return_if_fail (item != NULL);
3137 g_slice_free (GtkIconViewItem, item);
3140 static GtkIconViewItem *
3141 gtk_icon_view_get_item_at_coords (GtkIconView *icon_view,
3144 gboolean only_in_cell,
3145 GtkCellRenderer **cell_at_pos)
3150 *cell_at_pos = NULL;
3152 for (items = icon_view->priv->items; items; items = items->next)
3154 GtkIconViewItem *item = items->data;
3155 GdkRectangle *item_area = (GdkRectangle *)item;
3157 if (x >= item_area->x - icon_view->priv->column_spacing/2 &&
3158 x <= item_area->x + item_area->width + icon_view->priv->column_spacing/2 &&
3159 y >= item_area->y - icon_view->priv->row_spacing/2 &&
3160 y <= item_area->y + item_area->height + icon_view->priv->row_spacing/2)
3162 if (only_in_cell || cell_at_pos)
3164 GtkCellRenderer *cell = NULL;
3165 GtkCellAreaContext *context;
3167 context = g_ptr_array_index (icon_view->priv->row_contexts, item->row);
3168 gtk_icon_view_set_cell_data (icon_view, item);
3170 if (x >= item_area->x && x <= item_area->x + item_area->width &&
3171 y >= item_area->y && y <= item_area->y + item_area->height)
3172 cell = gtk_cell_area_get_cell_at_position (icon_view->priv->cell_area, context,
3173 GTK_WIDGET (icon_view),
3178 *cell_at_pos = cell;
3181 return cell != NULL ? item : NULL;
3192 gtk_icon_view_select_item (GtkIconView *icon_view,
3193 GtkIconViewItem *item)
3195 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3196 g_return_if_fail (item != NULL);
3201 if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
3203 else if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3204 gtk_icon_view_unselect_all_internal (icon_view);
3206 item->selected = TRUE;
3208 gtk_icon_view_item_selected_changed (icon_view, item);
3209 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3211 gtk_icon_view_queue_draw_item (icon_view, item);
3216 gtk_icon_view_unselect_item (GtkIconView *icon_view,
3217 GtkIconViewItem *item)
3219 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3220 g_return_if_fail (item != NULL);
3222 if (!item->selected)
3225 if (icon_view->priv->selection_mode == GTK_SELECTION_NONE ||
3226 icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
3229 item->selected = FALSE;
3231 gtk_icon_view_item_selected_changed (icon_view, item);
3232 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3234 gtk_icon_view_queue_draw_item (icon_view, item);
3238 verify_items (GtkIconView *icon_view)
3243 for (items = icon_view->priv->items; items; items = items->next)
3245 GtkIconViewItem *item = items->data;
3247 if (item->index != i)
3248 g_error ("List item does not match its index: "
3249 "item index %d and list index %d\n", item->index, i);
3256 gtk_icon_view_row_changed (GtkTreeModel *model,
3261 GtkIconView *icon_view = GTK_ICON_VIEW (data);
3263 /* ignore changes in branches */
3264 if (gtk_tree_path_get_depth (path) > 1)
3267 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
3269 /* Here we can use a "grow-only" strategy for optimization
3270 * and only invalidate a single item and queue a relayout
3271 * instead of invalidating the whole thing.
3273 * For now GtkIconView still cant deal with huge models
3274 * so just invalidate the whole thing when the model
3277 gtk_icon_view_invalidate_sizes (icon_view);
3279 verify_items (icon_view);
3283 gtk_icon_view_row_inserted (GtkTreeModel *model,
3288 GtkIconView *icon_view = GTK_ICON_VIEW (data);
3290 GtkIconViewItem *item;
3291 gboolean iters_persist;
3294 /* ignore changes in branches */
3295 if (gtk_tree_path_get_depth (path) > 1)
3298 iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
3300 index = gtk_tree_path_get_indices(path)[0];
3302 item = gtk_icon_view_item_new ();
3307 item->index = index;
3309 /* FIXME: We can be more efficient here,
3310 we can store a tail pointer and use that when
3311 appending (which is a rather common operation)
3313 icon_view->priv->items = g_list_insert (icon_view->priv->items,
3316 list = g_list_nth (icon_view->priv->items, index + 1);
3317 for (; list; list = list->next)
3324 verify_items (icon_view);
3326 gtk_icon_view_queue_layout (icon_view);
3330 gtk_icon_view_row_deleted (GtkTreeModel *model,
3334 GtkIconView *icon_view = GTK_ICON_VIEW (data);
3336 GtkIconViewItem *item;
3338 gboolean emit = FALSE;
3340 /* ignore changes in branches */
3341 if (gtk_tree_path_get_depth (path) > 1)
3344 index = gtk_tree_path_get_indices(path)[0];
3346 list = g_list_nth (icon_view->priv->items, index);
3349 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
3351 if (item == icon_view->priv->anchor_item)
3352 icon_view->priv->anchor_item = NULL;
3354 if (item == icon_view->priv->cursor_item)
3355 icon_view->priv->cursor_item = NULL;
3360 gtk_icon_view_item_free (item);
3362 for (next = list->next; next; next = next->next)
3369 icon_view->priv->items = g_list_delete_link (icon_view->priv->items, list);
3371 verify_items (icon_view);
3373 gtk_icon_view_queue_layout (icon_view);
3376 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3380 gtk_icon_view_rows_reordered (GtkTreeModel *model,
3381 GtkTreePath *parent,
3386 GtkIconView *icon_view = GTK_ICON_VIEW (data);
3389 GList *items = NULL, *list;
3390 GtkIconViewItem **item_array;
3393 /* ignore changes in branches */
3397 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
3399 length = gtk_tree_model_iter_n_children (model, NULL);
3401 order = g_new (gint, length);
3402 for (i = 0; i < length; i++)
3403 order [new_order[i]] = i;
3405 item_array = g_new (GtkIconViewItem *, length);
3406 for (i = 0, list = icon_view->priv->items; list != NULL; list = list->next, i++)
3407 item_array[order[i]] = list->data;
3410 for (i = length - 1; i >= 0; i--)
3412 item_array[i]->index = i;
3413 items = g_list_prepend (items, item_array[i]);
3416 g_free (item_array);
3417 g_list_free (icon_view->priv->items);
3418 icon_view->priv->items = items;
3420 gtk_icon_view_queue_layout (icon_view);
3422 verify_items (icon_view);
3426 gtk_icon_view_build_items (GtkIconView *icon_view)
3430 gboolean iters_persist;
3431 GList *items = NULL;
3433 iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
3435 if (!gtk_tree_model_get_iter_first (icon_view->priv->model,
3443 GtkIconViewItem *item = gtk_icon_view_item_new ();
3452 items = g_list_prepend (items, item);
3454 } while (gtk_tree_model_iter_next (icon_view->priv->model, &iter));
3456 icon_view->priv->items = g_list_reverse (items);
3460 gtk_icon_view_add_move_binding (GtkBindingSet *binding_set,
3463 GtkMovementStep step,
3467 gtk_binding_entry_add_signal (binding_set, keyval, modmask,
3468 I_("move-cursor"), 2,
3472 gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
3477 if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
3480 gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
3485 gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
3492 gtk_icon_view_real_move_cursor (GtkIconView *icon_view,
3493 GtkMovementStep step,
3496 GdkModifierType state;
3498 g_return_val_if_fail (GTK_ICON_VIEW (icon_view), FALSE);
3499 g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
3500 step == GTK_MOVEMENT_VISUAL_POSITIONS ||
3501 step == GTK_MOVEMENT_DISPLAY_LINES ||
3502 step == GTK_MOVEMENT_PAGES ||
3503 step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
3505 if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3508 gtk_cell_area_stop_editing (icon_view->priv->cell_area, FALSE);
3509 gtk_widget_grab_focus (GTK_WIDGET (icon_view));
3511 if (gtk_get_current_event_state (&state))
3513 if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
3514 icon_view->priv->ctrl_pressed = TRUE;
3515 if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
3516 icon_view->priv->shift_pressed = TRUE;
3518 /* else we assume not pressed */
3522 case GTK_MOVEMENT_LOGICAL_POSITIONS:
3523 case GTK_MOVEMENT_VISUAL_POSITIONS:
3524 gtk_icon_view_move_cursor_left_right (icon_view, count);
3526 case GTK_MOVEMENT_DISPLAY_LINES:
3527 gtk_icon_view_move_cursor_up_down (icon_view, count);
3529 case GTK_MOVEMENT_PAGES:
3530 gtk_icon_view_move_cursor_page_up_down (icon_view, count);
3532 case GTK_MOVEMENT_BUFFER_ENDS:
3533 gtk_icon_view_move_cursor_start_end (icon_view, count);
3536 g_assert_not_reached ();
3539 icon_view->priv->ctrl_pressed = FALSE;
3540 icon_view->priv->shift_pressed = FALSE;
3542 icon_view->priv->draw_focus = TRUE;
3547 static GtkIconViewItem *
3548 find_item (GtkIconView *icon_view,
3549 GtkIconViewItem *current,
3555 GtkIconViewItem *item;
3557 /* FIXME: this could be more efficient
3559 row = current->row + row_ofs;
3560 col = current->col + col_ofs;
3562 for (items = icon_view->priv->items; items; items = items->next)
3565 if (item->row == row && item->col == col)
3572 static GtkIconViewItem *
3573 find_item_page_up_down (GtkIconView *icon_view,
3574 GtkIconViewItem *current,
3581 y = current->cell_area.y + count * gtk_adjustment_get_page_size (icon_view->priv->vadjustment);
3583 item = g_list_find (icon_view->priv->items, current);
3588 for (next = item->next; next; next = next->next)
3590 if (((GtkIconViewItem *)next->data)->col == col)
3593 if (!next || ((GtkIconViewItem *)next->data)->cell_area.y > y)
3603 for (next = item->prev; next; next = next->prev)
3605 if (((GtkIconViewItem *)next->data)->col == col)
3608 if (!next || ((GtkIconViewItem *)next->data)->cell_area.y < y)
3622 gtk_icon_view_select_all_between (GtkIconView *icon_view,
3623 GtkIconViewItem *anchor,
3624 GtkIconViewItem *cursor)
3627 GtkIconViewItem *item;
3628 gint row1, row2, col1, col2;
3629 gboolean dirty = FALSE;
3631 if (anchor->row < cursor->row)
3642 if (anchor->col < cursor->col)
3653 for (items = icon_view->priv->items; items; items = items->next)
3657 if (row1 <= item->row && item->row <= row2 &&
3658 col1 <= item->col && item->col <= col2)
3660 if (!item->selected)
3663 item->selected = TRUE;
3664 gtk_icon_view_item_selected_changed (icon_view, item);
3666 gtk_icon_view_queue_draw_item (icon_view, item);
3674 gtk_icon_view_move_cursor_up_down (GtkIconView *icon_view,
3677 GtkIconViewItem *item;
3678 GtkCellRenderer *cell;
3679 gboolean dirty = FALSE;
3681 GtkDirectionType direction;
3683 if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3686 direction = count < 0 ? GTK_DIR_UP : GTK_DIR_DOWN;
3688 if (!icon_view->priv->cursor_item)
3693 list = icon_view->priv->items;
3695 list = g_list_last (icon_view->priv->items);
3697 item = list ? list->data : NULL;
3699 /* Give focus to the first cell initially */
3700 gtk_icon_view_set_cell_data (icon_view, item);
3701 gtk_cell_area_focus (icon_view->priv->cell_area, direction);
3705 item = icon_view->priv->cursor_item;
3706 step = count > 0 ? 1 : -1;
3708 /* Save the current focus cell in case we hit the edge */
3709 cell = gtk_cell_area_get_focus_cell (icon_view->priv->cell_area);
3713 gtk_icon_view_set_cell_data (icon_view, item);
3715 if (gtk_cell_area_focus (icon_view->priv->cell_area, direction))
3718 item = find_item (icon_view, item, step, 0);
3724 if (!gtk_widget_keynav_failed (GTK_WIDGET (icon_view), direction))
3726 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (icon_view));
3728 gtk_widget_child_focus (toplevel,
3729 direction == GTK_DIR_UP ?
3730 GTK_DIR_TAB_BACKWARD :
3731 GTK_DIR_TAB_FORWARD);
3735 gtk_cell_area_set_focus_cell (icon_view->priv->cell_area, cell);
3739 if (icon_view->priv->ctrl_pressed ||
3740 !icon_view->priv->shift_pressed ||
3741 !icon_view->priv->anchor_item ||
3742 icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3743 icon_view->priv->anchor_item = item;
3745 cell = gtk_cell_area_get_focus_cell (icon_view->priv->cell_area);
3746 gtk_icon_view_set_cursor_item (icon_view, item, cell);
3748 if (!icon_view->priv->ctrl_pressed &&
3749 icon_view->priv->selection_mode != GTK_SELECTION_NONE)
3751 dirty = gtk_icon_view_unselect_all_internal (icon_view);
3752 dirty = gtk_icon_view_select_all_between (icon_view,
3753 icon_view->priv->anchor_item,
3757 gtk_icon_view_scroll_to_item (icon_view, item);
3760 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3764 gtk_icon_view_move_cursor_page_up_down (GtkIconView *icon_view,
3767 GtkIconViewItem *item;
3768 gboolean dirty = FALSE;
3770 if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3773 if (!icon_view->priv->cursor_item)
3778 list = icon_view->priv->items;
3780 list = g_list_last (icon_view->priv->items);
3782 item = list ? list->data : NULL;
3785 item = find_item_page_up_down (icon_view,
3786 icon_view->priv->cursor_item,
3789 if (item == icon_view->priv->cursor_item)
3790 gtk_widget_error_bell (GTK_WIDGET (icon_view));
3795 if (icon_view->priv->ctrl_pressed ||
3796 !icon_view->priv->shift_pressed ||
3797 !icon_view->priv->anchor_item ||
3798 icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3799 icon_view->priv->anchor_item = item;
3801 gtk_icon_view_set_cursor_item (icon_view, item, NULL);
3803 if (!icon_view->priv->ctrl_pressed &&
3804 icon_view->priv->selection_mode != GTK_SELECTION_NONE)
3806 dirty = gtk_icon_view_unselect_all_internal (icon_view);
3807 dirty = gtk_icon_view_select_all_between (icon_view,
3808 icon_view->priv->anchor_item,
3812 gtk_icon_view_scroll_to_item (icon_view, item);
3815 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3819 gtk_icon_view_move_cursor_left_right (GtkIconView *icon_view,
3822 GtkIconViewItem *item;
3823 GtkCellRenderer *cell = NULL;
3824 gboolean dirty = FALSE;
3826 GtkDirectionType direction;
3828 if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3831 direction = count < 0 ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
3833 if (!icon_view->priv->cursor_item)
3838 list = icon_view->priv->items;
3840 list = g_list_last (icon_view->priv->items);
3842 item = list ? list->data : NULL;
3844 /* Give focus to the first cell initially */
3845 gtk_icon_view_set_cell_data (icon_view, item);
3846 gtk_cell_area_focus (icon_view->priv->cell_area, direction);
3850 item = icon_view->priv->cursor_item;
3851 step = count > 0 ? 1 : -1;
3853 /* Save the current focus cell in case we hit the edge */
3854 cell = gtk_cell_area_get_focus_cell (icon_view->priv->cell_area);
3858 gtk_icon_view_set_cell_data (icon_view, item);
3860 if (gtk_cell_area_focus (icon_view->priv->cell_area, direction))
3863 item = find_item (icon_view, item, 0, step);
3869 if (!gtk_widget_keynav_failed (GTK_WIDGET (icon_view), direction))
3871 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (icon_view));
3873 gtk_widget_child_focus (toplevel,
3874 direction == GTK_DIR_LEFT ?
3875 GTK_DIR_TAB_BACKWARD :
3876 GTK_DIR_TAB_FORWARD);
3880 gtk_cell_area_set_focus_cell (icon_view->priv->cell_area, cell);
3884 if (icon_view->priv->ctrl_pressed ||
3885 !icon_view->priv->shift_pressed ||
3886 !icon_view->priv->anchor_item ||
3887 icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3888 icon_view->priv->anchor_item = item;
3890 cell = gtk_cell_area_get_focus_cell (icon_view->priv->cell_area);
3891 gtk_icon_view_set_cursor_item (icon_view, item, cell);
3893 if (!icon_view->priv->ctrl_pressed &&
3894 icon_view->priv->selection_mode != GTK_SELECTION_NONE)
3896 dirty = gtk_icon_view_unselect_all_internal (icon_view);
3897 dirty = gtk_icon_view_select_all_between (icon_view,
3898 icon_view->priv->anchor_item,
3902 gtk_icon_view_scroll_to_item (icon_view, item);
3905 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3909 gtk_icon_view_move_cursor_start_end (GtkIconView *icon_view,
3912 GtkIconViewItem *item;
3914 gboolean dirty = FALSE;
3916 if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3920 list = icon_view->priv->items;
3922 list = g_list_last (icon_view->priv->items);
3924 item = list ? list->data : NULL;
3926 if (item == icon_view->priv->cursor_item)
3927 gtk_widget_error_bell (GTK_WIDGET (icon_view));
3932 if (icon_view->priv->ctrl_pressed ||
3933 !icon_view->priv->shift_pressed ||
3934 !icon_view->priv->anchor_item ||
3935 icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3936 icon_view->priv->anchor_item = item;
3938 gtk_icon_view_set_cursor_item (icon_view, item, NULL);
3940 if (!icon_view->priv->ctrl_pressed &&
3941 icon_view->priv->selection_mode != GTK_SELECTION_NONE)
3943 dirty = gtk_icon_view_unselect_all_internal (icon_view);
3944 dirty = gtk_icon_view_select_all_between (icon_view,
3945 icon_view->priv->anchor_item,
3949 gtk_icon_view_scroll_to_item (icon_view, item);
3952 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3956 * gtk_icon_view_scroll_to_path:
3957 * @icon_view: A #GtkIconView.
3958 * @path: The path of the item to move to.
3959 * @use_align: whether to use alignment arguments, or %FALSE.
3960 * @row_align: The vertical alignment of the item specified by @path.
3961 * @col_align: The horizontal alignment of the item specified by @path.
3963 * Moves the alignments of @icon_view to the position specified by @path.
3964 * @row_align determines where the row is placed, and @col_align determines
3965 * where @column is placed. Both are expected to be between 0.0 and 1.0.
3966 * 0.0 means left/top alignment, 1.0 means right/bottom alignment, 0.5 means
3969 * If @use_align is %FALSE, then the alignment arguments are ignored, and the
3970 * tree does the minimum amount of work to scroll the item onto the screen.
3971 * This means that the item will be scrolled to the edge closest to its current
3972 * position. If the item is currently visible on the screen, nothing is done.
3974 * This function only works if the model is set, and @path is a valid row on
3975 * the model. If the model changes before the @icon_view is realized, the
3976 * centered path will be modified to reflect this change.
3981 gtk_icon_view_scroll_to_path (GtkIconView *icon_view,
3987 GtkIconViewItem *item = NULL;
3990 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3991 g_return_if_fail (path != NULL);
3992 g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
3993 g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
3995 widget = GTK_WIDGET (icon_view);
3997 if (gtk_tree_path_get_depth (path) > 0)
3998 item = g_list_nth_data (icon_view->priv->items,
3999 gtk_tree_path_get_indices(path)[0]);
4001 if (!item || item->cell_area.width < 0 ||
4002 !gtk_widget_get_realized (widget))
4004 if (icon_view->priv->scroll_to_path)
4005 gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
4007 icon_view->priv->scroll_to_path = NULL;
4010 icon_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (icon_view), icon_view->priv->model, path);
4012 icon_view->priv->scroll_to_use_align = use_align;
4013 icon_view->priv->scroll_to_row_align = row_align;
4014 icon_view->priv->scroll_to_col_align = col_align;
4021 GtkAllocation allocation;
4024 GdkRectangle item_area =
4026 item->cell_area.x - icon_view->priv->item_padding,
4027 item->cell_area.y - icon_view->priv->item_padding,
4028 item->cell_area.width + icon_view->priv->item_padding * 2,
4029 item->cell_area.height + icon_view->priv->item_padding * 2
4032 gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4034 gtk_widget_get_allocation (widget, &allocation);
4036 offset = y + item_area.y - row_align * (allocation.height - item_area.height);
4038 gtk_adjustment_set_value (icon_view->priv->vadjustment,
4039 gtk_adjustment_get_value (icon_view->priv->vadjustment) + offset);
4041 offset = x + item_area.x - col_align * (allocation.width - item_area.width);
4043 gtk_adjustment_set_value (icon_view->priv->hadjustment,
4044 gtk_adjustment_get_value (icon_view->priv->hadjustment) + offset);
4046 gtk_adjustment_changed (icon_view->priv->hadjustment);
4047 gtk_adjustment_changed (icon_view->priv->vadjustment);
4050 gtk_icon_view_scroll_to_item (icon_view, item);
4055 gtk_icon_view_scroll_to_item (GtkIconView *icon_view,
4056 GtkIconViewItem *item)
4058 GtkIconViewPrivate *priv = icon_view->priv;
4059 GtkWidget *widget = GTK_WIDGET (icon_view);
4060 GtkAdjustment *hadj, *vadj;
4061 GtkAllocation allocation;
4063 GdkRectangle item_area;
4065 item_area.x = item->cell_area.x - priv->item_padding;
4066 item_area.y = item->cell_area.y - priv->item_padding;
4067 item_area.width = item->cell_area.width + priv->item_padding * 2;
4068 item_area.height = item->cell_area.height + priv->item_padding * 2;
4070 gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4071 gtk_widget_get_allocation (widget, &allocation);
4073 hadj = icon_view->priv->hadjustment;
4074 vadj = icon_view->priv->vadjustment;
4076 if (y + item_area.y < 0)
4077 gtk_adjustment_set_value (vadj,
4078 gtk_adjustment_get_value (vadj)
4080 else if (y + item_area.y + item_area.height > allocation.height)
4081 gtk_adjustment_set_value (vadj,
4082 gtk_adjustment_get_value (vadj)
4083 + y + item_area.y + item_area.height - allocation.height);
4085 if (x + item_area.x < 0)
4086 gtk_adjustment_set_value (hadj,
4087 gtk_adjustment_get_value (hadj)
4089 else if (x + item_area.x + item_area.width > allocation.width)
4090 gtk_adjustment_set_value (hadj,
4091 gtk_adjustment_get_value (hadj)
4092 + x + item_area.x + item_area.width - allocation.width);
4094 gtk_adjustment_changed (hadj);
4095 gtk_adjustment_changed (vadj);
4098 /* GtkCellLayout implementation */
4099 static GtkCellArea *
4100 gtk_icon_view_cell_layout_get_area (GtkCellLayout *cell_layout)
4102 GtkIconView *icon_view = GTK_ICON_VIEW (cell_layout);
4104 return icon_view->priv->cell_area;
4108 gtk_icon_view_set_cell_data (GtkIconView *icon_view,
4109 GtkIconViewItem *item)
4111 gboolean iters_persist;
4114 iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
4120 path = gtk_tree_path_new_from_indices (item->index, -1);
4121 if (!gtk_tree_model_get_iter (icon_view->priv->model, &iter, path))
4123 gtk_tree_path_free (path);
4128 gtk_cell_area_apply_attributes (icon_view->priv->cell_area,
4129 icon_view->priv->model,
4130 &iter, FALSE, FALSE);
4139 * gtk_icon_view_new:
4141 * Creates a new #GtkIconView widget
4143 * Return value: A newly created #GtkIconView widget
4148 gtk_icon_view_new (void)
4150 return g_object_new (GTK_TYPE_ICON_VIEW, NULL);
4154 * gtk_icon_view_new_with_area:
4155 * @area: the #GtkCellArea to use to layout cells
4157 * Creates a new #GtkIconView widget using the
4158 * specified @area to layout cells inside the icons.
4160 * Return value: A newly created #GtkIconView widget
4165 gtk_icon_view_new_with_area (GtkCellArea *area)
4167 return g_object_new (GTK_TYPE_ICON_VIEW, "cell-area", area, NULL);
4171 * gtk_icon_view_new_with_model:
4172 * @model: The model.
4174 * Creates a new #GtkIconView widget with the model @model.
4176 * Return value: A newly created #GtkIconView widget.
4181 gtk_icon_view_new_with_model (GtkTreeModel *model)
4183 return g_object_new (GTK_TYPE_ICON_VIEW, "model", model, NULL);
4187 * gtk_icon_view_convert_widget_to_bin_window_coords:
4188 * @icon_view: a #GtkIconView
4189 * @wx: X coordinate relative to the widget
4190 * @wy: Y coordinate relative to the widget
4191 * @bx: (out): return location for bin_window X coordinate
4192 * @by: (out): return location for bin_window Y coordinate
4194 * Converts widget coordinates to coordinates for the bin_window,
4195 * as expected by e.g. gtk_icon_view_get_path_at_pos().
4200 gtk_icon_view_convert_widget_to_bin_window_coords (GtkIconView *icon_view,
4208 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4210 if (icon_view->priv->bin_window)
4211 gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4222 * gtk_icon_view_get_path_at_pos:
4223 * @icon_view: A #GtkIconView.
4224 * @x: The x position to be identified
4225 * @y: The y position to be identified
4227 * Finds the path at the point (@x, @y), relative to bin_window coordinates.
4228 * See gtk_icon_view_get_item_at_pos(), if you are also interested in
4229 * the cell at the specified position.
4230 * See gtk_icon_view_convert_widget_to_bin_window_coords() for converting
4231 * widget coordinates to bin_window coordinates.
4233 * Return value: The #GtkTreePath corresponding to the icon or %NULL
4234 * if no icon exists at that position.
4239 gtk_icon_view_get_path_at_pos (GtkIconView *icon_view,
4243 GtkIconViewItem *item;
4246 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
4248 item = gtk_icon_view_get_item_at_coords (icon_view, x, y, TRUE, NULL);
4253 path = gtk_tree_path_new_from_indices (item->index, -1);
4259 * gtk_icon_view_get_item_at_pos:
4260 * @icon_view: A #GtkIconView.
4261 * @x: The x position to be identified
4262 * @y: The y position to be identified
4263 * @path: (out) (allow-none): Return location for the path, or %NULL
4264 * @cell: (out) (allow-none): Return location for the renderer
4265 * responsible for the cell at (@x, @y), or %NULL
4267 * Finds the path at the point (@x, @y), relative to bin_window coordinates.
4268 * In contrast to gtk_icon_view_get_path_at_pos(), this function also
4269 * obtains the cell at the specified position. The returned path should
4270 * be freed with gtk_tree_path_free().
4271 * See gtk_icon_view_convert_widget_to_bin_window_coords() for converting
4272 * widget coordinates to bin_window coordinates.
4274 * Return value: %TRUE if an item exists at the specified position
4279 gtk_icon_view_get_item_at_pos (GtkIconView *icon_view,
4283 GtkCellRenderer **cell)
4285 GtkIconViewItem *item;
4286 GtkCellRenderer *renderer = NULL;
4288 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
4290 item = gtk_icon_view_get_item_at_coords (icon_view, x, y, TRUE, &renderer);
4295 *path = gtk_tree_path_new_from_indices (item->index, -1);
4303 return (item != NULL);
4307 * gtk_icon_view_set_tooltip_item:
4308 * @icon_view: a #GtkIconView
4309 * @tooltip: a #GtkTooltip
4310 * @path: a #GtkTreePath
4312 * Sets the tip area of @tooltip to be the area covered by the item at @path.
4313 * See also gtk_icon_view_set_tooltip_column() for a simpler alternative.
4314 * See also gtk_tooltip_set_tip_area().
4319 gtk_icon_view_set_tooltip_item (GtkIconView *icon_view,
4320 GtkTooltip *tooltip,
4323 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4324 g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
4326 gtk_icon_view_set_tooltip_cell (icon_view, tooltip, path, NULL);
4330 * gtk_icon_view_set_tooltip_cell:
4331 * @icon_view: a #GtkIconView
4332 * @tooltip: a #GtkTooltip
4333 * @path: a #GtkTreePath
4334 * @cell: (allow-none): a #GtkCellRenderer or %NULL
4336 * Sets the tip area of @tooltip to the area which @cell occupies in
4337 * the item pointed to by @path. See also gtk_tooltip_set_tip_area().
4339 * See also gtk_icon_view_set_tooltip_column() for a simpler alternative.
4344 gtk_icon_view_set_tooltip_cell (GtkIconView *icon_view,
4345 GtkTooltip *tooltip,
4347 GtkCellRenderer *cell)
4350 GtkIconViewItem *item = NULL;
4353 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4354 g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
4355 g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
4357 if (gtk_tree_path_get_depth (path) > 0)
4358 item = g_list_nth_data (icon_view->priv->items,
4359 gtk_tree_path_get_indices(path)[0]);
4366 GtkCellAreaContext *context;
4368 context = g_ptr_array_index (icon_view->priv->row_contexts, item->row);
4369 gtk_icon_view_set_cell_data (icon_view, item);
4370 gtk_cell_area_get_cell_allocation (icon_view->priv->cell_area, context,
4371 GTK_WIDGET (icon_view),
4372 cell, (GdkRectangle *)item, &rect);
4376 rect.x = item->cell_area.x - icon_view->priv->item_padding;
4377 rect.y = item->cell_area.y - icon_view->priv->item_padding;
4378 rect.width = item->cell_area.width + icon_view->priv->item_padding * 2;
4379 rect.height = item->cell_area.height + icon_view->priv->item_padding * 2;
4382 if (icon_view->priv->bin_window)
4384 gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4389 gtk_tooltip_set_tip_area (tooltip, &rect);
4394 * gtk_icon_view_get_tooltip_context:
4395 * @icon_view: an #GtkIconView
4396 * @x: (inout): the x coordinate (relative to widget coordinates)
4397 * @y: (inout): the y coordinate (relative to widget coordinates)
4398 * @keyboard_tip: whether this is a keyboard tooltip or not
4399 * @model: (out) (allow-none): a pointer to receive a #GtkTreeModel or %NULL
4400 * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
4401 * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
4403 * This function is supposed to be used in a #GtkWidget::query-tooltip
4404 * signal handler for #GtkIconView. The @x, @y and @keyboard_tip values
4405 * which are received in the signal handler, should be passed to this
4406 * function without modification.
4408 * The return value indicates whether there is an icon view item at the given
4409 * coordinates (%TRUE) or not (%FALSE) for mouse tooltips. For keyboard
4410 * tooltips the item returned will be the cursor item. When %TRUE, then any of
4411 * @model, @path and @iter which have been provided will be set to point to
4412 * that row and the corresponding model. @x and @y will always be converted
4413 * to be relative to @icon_view's bin_window if @keyboard_tooltip is %FALSE.
4415 * Return value: whether or not the given tooltip context points to a item
4420 gtk_icon_view_get_tooltip_context (GtkIconView *icon_view,
4423 gboolean keyboard_tip,
4424 GtkTreeModel **model,
4428 GtkTreePath *tmppath = NULL;
4430 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
4431 g_return_val_if_fail (x != NULL, FALSE);
4432 g_return_val_if_fail (y != NULL, FALSE);
4436 gtk_icon_view_get_cursor (icon_view, &tmppath, NULL);
4443 gtk_icon_view_convert_widget_to_bin_window_coords (icon_view, *x, *y,
4446 if (!gtk_icon_view_get_item_at_pos (icon_view, *x, *y, &tmppath, NULL))
4451 *model = gtk_icon_view_get_model (icon_view);
4454 gtk_tree_model_get_iter (gtk_icon_view_get_model (icon_view),
4460 gtk_tree_path_free (tmppath);
4466 gtk_icon_view_set_tooltip_query_cb (GtkWidget *widget,
4469 gboolean keyboard_tip,
4470 GtkTooltip *tooltip,
4476 GtkTreeModel *model;
4477 GtkIconView *icon_view = GTK_ICON_VIEW (widget);
4479 if (!gtk_icon_view_get_tooltip_context (GTK_ICON_VIEW (widget),
4482 &model, &path, &iter))
4485 gtk_tree_model_get (model, &iter, icon_view->priv->tooltip_column, &str, -1);
4489 gtk_tree_path_free (path);
4493 gtk_tooltip_set_markup (tooltip, str);
4494 gtk_icon_view_set_tooltip_item (icon_view, tooltip, path);
4496 gtk_tree_path_free (path);
4504 * gtk_icon_view_set_tooltip_column:
4505 * @icon_view: a #GtkIconView
4506 * @column: an integer, which is a valid column number for @icon_view's model
4508 * If you only plan to have simple (text-only) tooltips on full items, you
4509 * can use this function to have #GtkIconView handle these automatically
4510 * for you. @column should be set to the column in @icon_view's model
4511 * containing the tooltip texts, or -1 to disable this feature.
4513 * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
4514 * @icon_view will connect a #GtkWidget::query-tooltip signal handler.
4516 * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
4517 * so &, <, etc have to be escaped in the text.
4522 gtk_icon_view_set_tooltip_column (GtkIconView *icon_view,
4525 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4527 if (column == icon_view->priv->tooltip_column)
4532 g_signal_handlers_disconnect_by_func (icon_view,
4533 gtk_icon_view_set_tooltip_query_cb,
4535 gtk_widget_set_has_tooltip (GTK_WIDGET (icon_view), FALSE);
4539 if (icon_view->priv->tooltip_column == -1)
4541 g_signal_connect (icon_view, "query-tooltip",
4542 G_CALLBACK (gtk_icon_view_set_tooltip_query_cb), NULL);
4543 gtk_widget_set_has_tooltip (GTK_WIDGET (icon_view), TRUE);
4547 icon_view->priv->tooltip_column = column;
4548 g_object_notify (G_OBJECT (icon_view), "tooltip-column");
4552 * gtk_icon_view_get_tooltip_column:
4553 * @icon_view: a #GtkIconView
4555 * Returns the column of @icon_view's model which is being used for
4556 * displaying tooltips on @icon_view's rows.
4558 * Return value: the index of the tooltip column that is currently being
4559 * used, or -1 if this is disabled.
4564 gtk_icon_view_get_tooltip_column (GtkIconView *icon_view)
4566 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), 0);
4568 return icon_view->priv->tooltip_column;
4572 * gtk_icon_view_get_visible_range:
4573 * @icon_view: A #GtkIconView
4574 * @start_path: (out) (allow-none): Return location for start of region,
4576 * @end_path: (out) (allow-none): Return location for end of region, or %NULL
4578 * Sets @start_path and @end_path to be the first and last visible path.
4579 * Note that there may be invisible paths in between.
4581 * Both paths should be freed with gtk_tree_path_free() after use.
4583 * Return value: %TRUE, if valid paths were placed in @start_path and @end_path
4588 gtk_icon_view_get_visible_range (GtkIconView *icon_view,
4589 GtkTreePath **start_path,
4590 GtkTreePath **end_path)
4592 gint start_index = -1;
4593 gint end_index = -1;
4596 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
4598 if (icon_view->priv->hadjustment == NULL ||
4599 icon_view->priv->vadjustment == NULL)
4602 if (start_path == NULL && end_path == NULL)
4605 for (icons = icon_view->priv->items; icons; icons = icons->next)
4607 GtkIconViewItem *item = icons->data;
4608 GdkRectangle *item_area = (GdkRectangle *)item;
4610 if ((item_area->x + item_area->width >= (int)gtk_adjustment_get_value (icon_view->priv->hadjustment)) &&
4611 (item_area->y + item_area->height >= (int)gtk_adjustment_get_value (icon_view->priv->vadjustment)) &&
4613 (int) (gtk_adjustment_get_value (icon_view->priv->hadjustment) +
4614 gtk_adjustment_get_page_size (icon_view->priv->hadjustment))) &&
4616 (int) (gtk_adjustment_get_value (icon_view->priv->vadjustment) +
4617 gtk_adjustment_get_page_size (icon_view->priv->vadjustment))))
4619 if (start_index == -1)
4620 start_index = item->index;
4621 end_index = item->index;
4625 if (start_path && start_index != -1)
4626 *start_path = gtk_tree_path_new_from_indices (start_index, -1);
4627 if (end_path && end_index != -1)
4628 *end_path = gtk_tree_path_new_from_indices (end_index, -1);
4630 return start_index != -1;
4634 * gtk_icon_view_selected_foreach:
4635 * @icon_view: A #GtkIconView.
4636 * @func: (scope call): The function to call for each selected icon.
4637 * @data: User data to pass to the function.
4639 * Calls a function for each selected icon. Note that the model or
4640 * selection cannot be modified from within this function.
4645 gtk_icon_view_selected_foreach (GtkIconView *icon_view,
4646 GtkIconViewForeachFunc func,
4651 for (list = icon_view->priv->items; list; list = list->next)
4653 GtkIconViewItem *item = list->data;
4654 GtkTreePath *path = gtk_tree_path_new_from_indices (item->index, -1);
4657 (* func) (icon_view, path, data);
4659 gtk_tree_path_free (path);
4664 * gtk_icon_view_set_selection_mode:
4665 * @icon_view: A #GtkIconView.
4666 * @mode: The selection mode
4668 * Sets the selection mode of the @icon_view.
4673 gtk_icon_view_set_selection_mode (GtkIconView *icon_view,
4674 GtkSelectionMode mode)
4676 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4678 if (mode == icon_view->priv->selection_mode)
4681 if (mode == GTK_SELECTION_NONE ||
4682 icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE)
4683 gtk_icon_view_unselect_all (icon_view);
4685 icon_view->priv->selection_mode = mode;
4687 g_object_notify (G_OBJECT (icon_view), "selection-mode");
4691 * gtk_icon_view_get_selection_mode:
4692 * @icon_view: A #GtkIconView.
4694 * Gets the selection mode of the @icon_view.
4696 * Return value: the current selection mode
4701 gtk_icon_view_get_selection_mode (GtkIconView *icon_view)
4703 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), GTK_SELECTION_SINGLE);
4705 return icon_view->priv->selection_mode;
4709 * gtk_icon_view_set_model:
4710 * @icon_view: A #GtkIconView.
4711 * @model: (allow-none): The model.
4713 * Sets the model for a #GtkIconView.
4714 * If the @icon_view already has a model set, it will remove
4715 * it before setting the new model. If @model is %NULL, then
4716 * it will unset the old model.
4721 gtk_icon_view_set_model (GtkIconView *icon_view,
4722 GtkTreeModel *model)
4724 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4725 g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
4727 if (icon_view->priv->model == model)
4730 if (icon_view->priv->scroll_to_path)
4732 gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
4733 icon_view->priv->scroll_to_path = NULL;
4736 /* The area can be NULL while disposing */
4737 if (icon_view->priv->cell_area)
4738 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
4744 if (icon_view->priv->pixbuf_column != -1)
4746 column_type = gtk_tree_model_get_column_type (model,
4747 icon_view->priv->pixbuf_column);
4749 g_return_if_fail (column_type == GDK_TYPE_PIXBUF);
4752 if (icon_view->priv->text_column != -1)
4754 column_type = gtk_tree_model_get_column_type (model,
4755 icon_view->priv->text_column);
4757 g_return_if_fail (column_type == G_TYPE_STRING);
4760 if (icon_view->priv->markup_column != -1)
4762 column_type = gtk_tree_model_get_column_type (model,
4763 icon_view->priv->markup_column);
4765 g_return_if_fail (column_type == G_TYPE_STRING);
4770 if (icon_view->priv->model)
4772 g_signal_handlers_disconnect_by_func (icon_view->priv->model,
4773 gtk_icon_view_row_changed,
4775 g_signal_handlers_disconnect_by_func (icon_view->priv->model,
4776 gtk_icon_view_row_inserted,
4778 g_signal_handlers_disconnect_by_func (icon_view->priv->model,
4779 gtk_icon_view_row_deleted,
4781 g_signal_handlers_disconnect_by_func (icon_view->priv->model,
4782 gtk_icon_view_rows_reordered,
4785 g_object_unref (icon_view->priv->model);
4787 g_list_foreach (icon_view->priv->items, (GFunc)gtk_icon_view_item_free, NULL);
4788 g_list_free (icon_view->priv->items);
4789 icon_view->priv->items = NULL;
4790 icon_view->priv->anchor_item = NULL;
4791 icon_view->priv->cursor_item = NULL;
4792 icon_view->priv->last_single_clicked = NULL;
4793 icon_view->priv->width = 0;
4794 icon_view->priv->height = 0;
4797 icon_view->priv->model = model;
4799 if (icon_view->priv->model)
4801 g_object_ref (icon_view->priv->model);
4802 g_signal_connect (icon_view->priv->model,
4804 G_CALLBACK (gtk_icon_view_row_changed),
4806 g_signal_connect (icon_view->priv->model,
4808 G_CALLBACK (gtk_icon_view_row_inserted),
4810 g_signal_connect (icon_view->priv->model,
4812 G_CALLBACK (gtk_icon_view_row_deleted),
4814 g_signal_connect (icon_view->priv->model,
4816 G_CALLBACK (gtk_icon_view_rows_reordered),
4819 gtk_icon_view_build_items (icon_view);
4821 gtk_icon_view_queue_layout (icon_view);
4824 g_object_notify (G_OBJECT (icon_view), "model");
4826 if (gtk_widget_get_realized (GTK_WIDGET (icon_view)))
4827 gtk_widget_queue_resize (GTK_WIDGET (icon_view));
4831 * gtk_icon_view_get_model:
4832 * @icon_view: a #GtkIconView
4834 * Returns the model the #GtkIconView is based on. Returns %NULL if the
4837 * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is
4838 * currently being used.
4843 gtk_icon_view_get_model (GtkIconView *icon_view)
4845 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
4847 return icon_view->priv->model;
4851 update_text_cell (GtkIconView *icon_view)
4853 if (icon_view->priv->text_column == -1 &&
4854 icon_view->priv->markup_column == -1)
4856 if (icon_view->priv->text_cell != NULL)
4858 gtk_cell_area_remove (icon_view->priv->cell_area,
4859 icon_view->priv->text_cell);
4860 icon_view->priv->text_cell = NULL;
4865 if (icon_view->priv->text_cell == NULL)
4867 icon_view->priv->text_cell = gtk_cell_renderer_text_new ();
4869 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (icon_view), icon_view->priv->text_cell, FALSE);
4872 if (icon_view->priv->markup_column != -1)
4873 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
4874 icon_view->priv->text_cell,
4875 "markup", icon_view->priv->markup_column,
4878 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
4879 icon_view->priv->text_cell,
4880 "text", icon_view->priv->text_column,
4883 if (icon_view->priv->item_orientation == GTK_ORIENTATION_VERTICAL)
4884 g_object_set (icon_view->priv->text_cell,
4885 "alignment", PANGO_ALIGN_CENTER,
4886 "wrap-mode", PANGO_WRAP_WORD_CHAR,
4891 g_object_set (icon_view->priv->text_cell,
4892 "alignment", PANGO_ALIGN_LEFT,
4893 "wrap-mode", PANGO_WRAP_WORD_CHAR,
4901 update_pixbuf_cell (GtkIconView *icon_view)
4903 if (icon_view->priv->pixbuf_column == -1)
4905 if (icon_view->priv->pixbuf_cell != NULL)
4907 gtk_cell_area_remove (icon_view->priv->cell_area,
4908 icon_view->priv->pixbuf_cell);
4910 icon_view->priv->pixbuf_cell = NULL;
4915 if (icon_view->priv->pixbuf_cell == NULL)
4917 icon_view->priv->pixbuf_cell = gtk_cell_renderer_pixbuf_new ();
4919 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (icon_view), icon_view->priv->pixbuf_cell, FALSE);
4922 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
4923 icon_view->priv->pixbuf_cell,
4924 "pixbuf", icon_view->priv->pixbuf_column,
4927 if (icon_view->priv->item_orientation == GTK_ORIENTATION_VERTICAL)
4928 g_object_set (icon_view->priv->pixbuf_cell,
4933 g_object_set (icon_view->priv->pixbuf_cell,
4941 * gtk_icon_view_set_text_column:
4942 * @icon_view: A #GtkIconView.
4943 * @column: A column in the currently used model, or -1 to display no text
4945 * Sets the column with text for @icon_view to be @column. The text
4946 * column must be of type #G_TYPE_STRING.
4951 gtk_icon_view_set_text_column (GtkIconView *icon_view,
4954 if (column == icon_view->priv->text_column)
4958 icon_view->priv->text_column = -1;
4961 if (icon_view->priv->model != NULL)
4965 column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
4967 g_return_if_fail (column_type == G_TYPE_STRING);
4970 icon_view->priv->text_column = column;
4974 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
4976 update_text_cell (icon_view);
4978 gtk_icon_view_invalidate_sizes (icon_view);
4980 g_object_notify (G_OBJECT (icon_view), "text-column");
4984 * gtk_icon_view_get_text_column:
4985 * @icon_view: A #GtkIconView.
4987 * Returns the column with text for @icon_view.
4989 * Returns: the text column, or -1 if it's unset.
4994 gtk_icon_view_get_text_column (GtkIconView *icon_view)
4996 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
4998 return icon_view->priv->text_column;
5002 * gtk_icon_view_set_markup_column:
5003 * @icon_view: A #GtkIconView.
5004 * @column: A column in the currently used model, or -1 to display no text
5006 * Sets the column with markup information for @icon_view to be
5007 * @column. The markup column must be of type #G_TYPE_STRING.
5008 * If the markup column is set to something, it overrides
5009 * the text column set by gtk_icon_view_set_text_column().
5014 gtk_icon_view_set_markup_column (GtkIconView *icon_view,
5017 if (column == icon_view->priv->markup_column)
5021 icon_view->priv->markup_column = -1;
5024 if (icon_view->priv->model != NULL)
5028 column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
5030 g_return_if_fail (column_type == G_TYPE_STRING);
5033 icon_view->priv->markup_column = column;
5036 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5038 update_text_cell (icon_view);
5040 gtk_icon_view_invalidate_sizes (icon_view);
5042 g_object_notify (G_OBJECT (icon_view), "markup-column");
5046 * gtk_icon_view_get_markup_column:
5047 * @icon_view: A #GtkIconView.
5049 * Returns the column with markup text for @icon_view.
5051 * Returns: the markup column, or -1 if it's unset.
5056 gtk_icon_view_get_markup_column (GtkIconView *icon_view)
5058 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5060 return icon_view->priv->markup_column;
5064 * gtk_icon_view_set_pixbuf_column:
5065 * @icon_view: A #GtkIconView.
5066 * @column: A column in the currently used model, or -1 to disable
5068 * Sets the column with pixbufs for @icon_view to be @column. The pixbuf
5069 * column must be of type #GDK_TYPE_PIXBUF
5074 gtk_icon_view_set_pixbuf_column (GtkIconView *icon_view,
5077 if (column == icon_view->priv->pixbuf_column)
5081 icon_view->priv->pixbuf_column = -1;
5084 if (icon_view->priv->model != NULL)
5088 column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
5090 g_return_if_fail (column_type == GDK_TYPE_PIXBUF);
5093 icon_view->priv->pixbuf_column = column;
5096 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5098 update_pixbuf_cell (icon_view);
5100 gtk_icon_view_invalidate_sizes (icon_view);
5102 g_object_notify (G_OBJECT (icon_view), "pixbuf-column");
5107 * gtk_icon_view_get_pixbuf_column:
5108 * @icon_view: A #GtkIconView.
5110 * Returns the column with pixbufs for @icon_view.
5112 * Returns: the pixbuf column, or -1 if it's unset.
5117 gtk_icon_view_get_pixbuf_column (GtkIconView *icon_view)
5119 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5121 return icon_view->priv->pixbuf_column;
5125 * gtk_icon_view_select_path:
5126 * @icon_view: A #GtkIconView.
5127 * @path: The #GtkTreePath to be selected.
5129 * Selects the row at @path.
5134 gtk_icon_view_select_path (GtkIconView *icon_view,
5137 GtkIconViewItem *item = NULL;
5139 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5140 g_return_if_fail (icon_view->priv->model != NULL);
5141 g_return_if_fail (path != NULL);
5143 if (gtk_tree_path_get_depth (path) > 0)
5144 item = g_list_nth_data (icon_view->priv->items,
5145 gtk_tree_path_get_indices(path)[0]);
5148 gtk_icon_view_select_item (icon_view, item);
5152 * gtk_icon_view_unselect_path:
5153 * @icon_view: A #GtkIconView.
5154 * @path: The #GtkTreePath to be unselected.
5156 * Unselects the row at @path.
5161 gtk_icon_view_unselect_path (GtkIconView *icon_view,
5164 GtkIconViewItem *item;
5166 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5167 g_return_if_fail (icon_view->priv->model != NULL);
5168 g_return_if_fail (path != NULL);
5170 item = g_list_nth_data (icon_view->priv->items,
5171 gtk_tree_path_get_indices(path)[0]);
5176 gtk_icon_view_unselect_item (icon_view, item);
5180 * gtk_icon_view_get_selected_items:
5181 * @icon_view: A #GtkIconView.
5183 * Creates a list of paths of all selected items. Additionally, if you are
5184 * planning on modifying the model after calling this function, you may
5185 * want to convert the returned list into a list of #GtkTreeRowReference<!-- -->s.
5186 * To do this, you can use gtk_tree_row_reference_new().
5188 * To free the return value, use:
5190 * g_list_foreach (list, (GFunc)gtk_tree_path_free, NULL);
5191 * g_list_free (list);
5194 * Return value: (element-type GtkTreePath) (transfer full): A #GList containing a #GtkTreePath for each selected row.
5199 gtk_icon_view_get_selected_items (GtkIconView *icon_view)
5202 GList *selected = NULL;
5204 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
5206 for (list = icon_view->priv->items; list != NULL; list = list->next)
5208 GtkIconViewItem *item = list->data;
5212 GtkTreePath *path = gtk_tree_path_new_from_indices (item->index, -1);
5214 selected = g_list_prepend (selected, path);
5222 * gtk_icon_view_select_all:
5223 * @icon_view: A #GtkIconView.
5225 * Selects all the icons. @icon_view must has its selection mode set
5226 * to #GTK_SELECTION_MULTIPLE.
5231 gtk_icon_view_select_all (GtkIconView *icon_view)
5234 gboolean dirty = FALSE;
5236 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5238 if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
5241 for (items = icon_view->priv->items; items; items = items->next)
5243 GtkIconViewItem *item = items->data;
5245 if (!item->selected)
5248 item->selected = TRUE;
5249 gtk_icon_view_queue_draw_item (icon_view, item);
5254 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
5258 * gtk_icon_view_unselect_all:
5259 * @icon_view: A #GtkIconView.
5261 * Unselects all the icons.
5266 gtk_icon_view_unselect_all (GtkIconView *icon_view)
5268 gboolean dirty = FALSE;
5270 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5272 if (icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
5275 dirty = gtk_icon_view_unselect_all_internal (icon_view);
5278 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
5282 * gtk_icon_view_path_is_selected:
5283 * @icon_view: A #GtkIconView.
5284 * @path: A #GtkTreePath to check selection on.
5286 * Returns %TRUE if the icon pointed to by @path is currently
5287 * selected. If @path does not point to a valid location, %FALSE is returned.
5289 * Return value: %TRUE if @path is selected.
5294 gtk_icon_view_path_is_selected (GtkIconView *icon_view,
5297 GtkIconViewItem *item;
5299 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
5300 g_return_val_if_fail (icon_view->priv->model != NULL, FALSE);
5301 g_return_val_if_fail (path != NULL, FALSE);
5303 item = g_list_nth_data (icon_view->priv->items,
5304 gtk_tree_path_get_indices(path)[0]);
5309 return item->selected;
5313 * gtk_icon_view_get_item_row:
5314 * @icon_view: a #GtkIconView
5315 * @path: the #GtkTreePath of the item
5317 * Gets the row in which the item @path is currently
5318 * displayed. Row numbers start at 0.
5320 * Returns: The row in which the item is displayed
5325 gtk_icon_view_get_item_row (GtkIconView *icon_view,
5328 GtkIconViewItem *item;
5330 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5331 g_return_val_if_fail (icon_view->priv->model != NULL, -1);
5332 g_return_val_if_fail (path != NULL, -1);
5334 item = g_list_nth_data (icon_view->priv->items,
5335 gtk_tree_path_get_indices(path)[0]);
5344 * gtk_icon_view_get_item_column:
5345 * @icon_view: a #GtkIconView
5346 * @path: the #GtkTreePath of the item
5348 * Gets the column in which the item @path is currently
5349 * displayed. Column numbers start at 0.
5351 * Returns: The column in which the item is displayed
5356 gtk_icon_view_get_item_column (GtkIconView *icon_view,
5359 GtkIconViewItem *item;
5361 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5362 g_return_val_if_fail (icon_view->priv->model != NULL, -1);
5363 g_return_val_if_fail (path != NULL, -1);
5365 item = g_list_nth_data (icon_view->priv->items,
5366 gtk_tree_path_get_indices(path)[0]);
5375 * gtk_icon_view_item_activated:
5376 * @icon_view: A #GtkIconView
5377 * @path: The #GtkTreePath to be activated
5379 * Activates the item determined by @path.
5384 gtk_icon_view_item_activated (GtkIconView *icon_view,
5387 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5388 g_return_if_fail (path != NULL);
5390 g_signal_emit (icon_view, icon_view_signals[ITEM_ACTIVATED], 0, path);
5394 * gtk_icon_view_set_item_orientation:
5395 * @icon_view: a #GtkIconView
5396 * @orientation: the relative position of texts and icons
5398 * Sets the ::item-orientation property which determines whether the labels
5399 * are drawn beside the icons instead of below.
5404 gtk_icon_view_set_item_orientation (GtkIconView *icon_view,
5405 GtkOrientation orientation)
5407 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5409 if (icon_view->priv->item_orientation != orientation)
5411 icon_view->priv->item_orientation = orientation;
5413 if (GTK_IS_ORIENTABLE (icon_view->priv->cell_area))
5414 gtk_orientable_set_orientation (GTK_ORIENTABLE (icon_view->priv->cell_area),
5415 icon_view->priv->item_orientation);
5417 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5418 gtk_icon_view_invalidate_sizes (icon_view);
5420 update_text_cell (icon_view);
5421 update_pixbuf_cell (icon_view);
5423 g_object_notify (G_OBJECT (icon_view), "item-orientation");
5428 * gtk_icon_view_get_item_orientation:
5429 * @icon_view: a #GtkIconView
5431 * Returns the value of the ::item-orientation property which determines
5432 * whether the labels are drawn beside the icons instead of below.
5434 * Return value: the relative position of texts and icons
5439 gtk_icon_view_get_item_orientation (GtkIconView *icon_view)
5441 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view),
5442 GTK_ORIENTATION_VERTICAL);
5444 return icon_view->priv->item_orientation;
5448 * gtk_icon_view_set_columns:
5449 * @icon_view: a #GtkIconView
5450 * @columns: the number of columns
5452 * Sets the ::columns property which determines in how
5453 * many columns the icons are arranged. If @columns is
5454 * -1, the number of columns will be chosen automatically
5455 * to fill the available area.
5460 gtk_icon_view_set_columns (GtkIconView *icon_view,
5463 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5465 if (icon_view->priv->columns != columns)
5467 icon_view->priv->columns = columns;
5469 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5470 gtk_icon_view_queue_layout (icon_view);
5472 g_object_notify (G_OBJECT (icon_view), "columns");
5477 * gtk_icon_view_get_columns:
5478 * @icon_view: a #GtkIconView
5480 * Returns the value of the ::columns property.
5482 * Return value: the number of columns, or -1
5487 gtk_icon_view_get_columns (GtkIconView *icon_view)
5489 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5491 return icon_view->priv->columns;
5495 * gtk_icon_view_set_item_width:
5496 * @icon_view: a #GtkIconView
5497 * @item_width: the width for each item
5499 * Sets the ::item-width property which specifies the width
5500 * to use for each item. If it is set to -1, the icon view will
5501 * automatically determine a suitable item size.
5506 gtk_icon_view_set_item_width (GtkIconView *icon_view,
5509 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5511 if (icon_view->priv->item_width != item_width)
5513 icon_view->priv->item_width = item_width;
5515 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5516 gtk_icon_view_invalidate_sizes (icon_view);
5518 update_text_cell (icon_view);
5520 g_object_notify (G_OBJECT (icon_view), "item-width");
5525 * gtk_icon_view_get_item_width:
5526 * @icon_view: a #GtkIconView
5528 * Returns the value of the ::item-width property.
5530 * Return value: the width of a single item, or -1
5535 gtk_icon_view_get_item_width (GtkIconView *icon_view)
5537 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5539 return icon_view->priv->item_width;
5544 * gtk_icon_view_set_spacing:
5545 * @icon_view: a #GtkIconView
5546 * @spacing: the spacing
5548 * Sets the ::spacing property which specifies the space
5549 * which is inserted between the cells (i.e. the icon and
5550 * the text) of an item.
5555 gtk_icon_view_set_spacing (GtkIconView *icon_view,
5558 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5560 if (icon_view->priv->spacing != spacing)
5562 icon_view->priv->spacing = spacing;
5564 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5565 gtk_icon_view_invalidate_sizes (icon_view);
5567 g_object_notify (G_OBJECT (icon_view), "spacing");
5572 * gtk_icon_view_get_spacing:
5573 * @icon_view: a #GtkIconView
5575 * Returns the value of the ::spacing property.
5577 * Return value: the space between cells
5582 gtk_icon_view_get_spacing (GtkIconView *icon_view)
5584 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5586 return icon_view->priv->spacing;
5590 * gtk_icon_view_set_row_spacing:
5591 * @icon_view: a #GtkIconView
5592 * @row_spacing: the row spacing
5594 * Sets the ::row-spacing property which specifies the space
5595 * which is inserted between the rows of the icon view.
5600 gtk_icon_view_set_row_spacing (GtkIconView *icon_view,
5603 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5605 if (icon_view->priv->row_spacing != row_spacing)
5607 icon_view->priv->row_spacing = row_spacing;
5609 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5610 gtk_icon_view_invalidate_sizes (icon_view);
5612 g_object_notify (G_OBJECT (icon_view), "row-spacing");
5617 * gtk_icon_view_get_row_spacing:
5618 * @icon_view: a #GtkIconView
5620 * Returns the value of the ::row-spacing property.
5622 * Return value: the space between rows
5627 gtk_icon_view_get_row_spacing (GtkIconView *icon_view)
5629 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5631 return icon_view->priv->row_spacing;
5635 * gtk_icon_view_set_column_spacing:
5636 * @icon_view: a #GtkIconView
5637 * @column_spacing: the column spacing
5639 * Sets the ::column-spacing property which specifies the space
5640 * which is inserted between the columns of the icon view.
5645 gtk_icon_view_set_column_spacing (GtkIconView *icon_view,
5646 gint column_spacing)
5648 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5650 if (icon_view->priv->column_spacing != column_spacing)
5652 icon_view->priv->column_spacing = column_spacing;
5654 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5655 gtk_icon_view_invalidate_sizes (icon_view);
5657 g_object_notify (G_OBJECT (icon_view), "column-spacing");
5662 * gtk_icon_view_get_column_spacing:
5663 * @icon_view: a #GtkIconView
5665 * Returns the value of the ::column-spacing property.
5667 * Return value: the space between columns
5672 gtk_icon_view_get_column_spacing (GtkIconView *icon_view)
5674 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5676 return icon_view->priv->column_spacing;
5680 * gtk_icon_view_set_margin:
5681 * @icon_view: a #GtkIconView
5682 * @margin: the margin
5684 * Sets the ::margin property which specifies the space
5685 * which is inserted at the top, bottom, left and right
5691 gtk_icon_view_set_margin (GtkIconView *icon_view,
5694 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5696 if (icon_view->priv->margin != margin)
5698 icon_view->priv->margin = margin;
5700 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5701 gtk_icon_view_invalidate_sizes (icon_view);
5703 g_object_notify (G_OBJECT (icon_view), "margin");
5708 * gtk_icon_view_get_margin:
5709 * @icon_view: a #GtkIconView
5711 * Returns the value of the ::margin property.
5713 * Return value: the space at the borders
5718 gtk_icon_view_get_margin (GtkIconView *icon_view)
5720 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5722 return icon_view->priv->margin;
5726 * gtk_icon_view_set_item_padding:
5727 * @icon_view: a #GtkIconView
5728 * @item_padding: the item padding
5730 * Sets the #GtkIconView:item-padding property which specifies the padding
5731 * around each of the icon view's items.
5736 gtk_icon_view_set_item_padding (GtkIconView *icon_view,
5739 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5741 if (icon_view->priv->item_padding != item_padding)
5743 icon_view->priv->item_padding = item_padding;
5745 gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5746 gtk_icon_view_invalidate_sizes (icon_view);
5748 g_object_notify (G_OBJECT (icon_view), "item-padding");
5753 * gtk_icon_view_get_item_padding:
5754 * @icon_view: a #GtkIconView
5756 * Returns the value of the ::item-padding property.
5758 * Return value: the padding around items
5763 gtk_icon_view_get_item_padding (GtkIconView *icon_view)
5765 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5767 return icon_view->priv->item_padding;
5770 /* Get/set whether drag_motion requested the drag data and
5771 * drag_data_received should thus not actually insert the data,
5772 * since the data doesn't result from a drop.
5775 set_status_pending (GdkDragContext *context,
5776 GdkDragAction suggested_action)
5778 g_object_set_data (G_OBJECT (context),
5779 I_("gtk-icon-view-status-pending"),
5780 GINT_TO_POINTER (suggested_action));
5783 static GdkDragAction
5784 get_status_pending (GdkDragContext *context)
5786 return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
5787 "gtk-icon-view-status-pending"));
5791 unset_reorderable (GtkIconView *icon_view)
5793 if (icon_view->priv->reorderable)
5795 icon_view->priv->reorderable = FALSE;
5796 g_object_notify (G_OBJECT (icon_view), "reorderable");
5801 set_source_row (GdkDragContext *context,
5802 GtkTreeModel *model,
5803 GtkTreePath *source_row)
5806 g_object_set_data_full (G_OBJECT (context),
5807 I_("gtk-icon-view-source-row"),
5808 gtk_tree_row_reference_new (model, source_row),
5809 (GDestroyNotify) gtk_tree_row_reference_free);
5811 g_object_set_data_full (G_OBJECT (context),
5812 I_("gtk-icon-view-source-row"),
5817 get_source_row (GdkDragContext *context)
5819 GtkTreeRowReference *ref;
5821 ref = g_object_get_data (G_OBJECT (context), "gtk-icon-view-source-row");
5824 return gtk_tree_row_reference_get_path (ref);
5831 GtkTreeRowReference *dest_row;
5832 gboolean empty_view_drop;
5833 gboolean drop_append_mode;
5837 dest_row_free (gpointer data)
5839 DestRow *dr = (DestRow *)data;
5841 gtk_tree_row_reference_free (dr->dest_row);
5846 set_dest_row (GdkDragContext *context,
5847 GtkTreeModel *model,
5848 GtkTreePath *dest_row,
5849 gboolean empty_view_drop,
5850 gboolean drop_append_mode)
5856 g_object_set_data_full (G_OBJECT (context),
5857 I_("gtk-icon-view-dest-row"),
5862 dr = g_new0 (DestRow, 1);
5864 dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
5865 dr->empty_view_drop = empty_view_drop;
5866 dr->drop_append_mode = drop_append_mode;
5867 g_object_set_data_full (G_OBJECT (context),
5868 I_("gtk-icon-view-dest-row"),
5869 dr, (GDestroyNotify) dest_row_free);
5873 get_dest_row (GdkDragContext *context)
5877 dr = g_object_get_data (G_OBJECT (context), "gtk-icon-view-dest-row");
5881 GtkTreePath *path = NULL;
5884 path = gtk_tree_row_reference_get_path (dr->dest_row);
5885 else if (dr->empty_view_drop)
5886 path = gtk_tree_path_new_from_indices (0, -1);
5890 if (path && dr->drop_append_mode)
5891 gtk_tree_path_next (path);
5900 check_model_dnd (GtkTreeModel *model,
5901 GType required_iface,
5902 const gchar *signal)
5904 if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
5906 g_warning ("You must override the default '%s' handler "
5907 "on GtkIconView when using models that don't support "
5908 "the %s interface and enabling drag-and-drop. The simplest way to do this "
5909 "is to connect to '%s' and call "
5910 "g_signal_stop_emission_by_name() in your signal handler to prevent "
5911 "the default handler from running. Look at the source code "
5912 "for the default handler in gtkiconview.c to get an idea what "
5913 "your handler should do. (gtkiconview.c is in the GTK+ source "
5914 "code.) If you're using GTK+ from a language other than C, "
5915 "there may be a more natural way to override default handlers, e.g. via derivation.",
5916 signal, g_type_name (required_iface), signal);
5924 remove_scroll_timeout (GtkIconView *icon_view)
5926 if (icon_view->priv->scroll_timeout_id != 0)
5928 g_source_remove (icon_view->priv->scroll_timeout_id);
5930 icon_view->priv->scroll_timeout_id = 0;
5935 gtk_icon_view_autoscroll (GtkIconView *icon_view)
5938 gint px, py, x, y, width, height;
5939 gint hoffset, voffset;
5941 window = gtk_widget_get_window (GTK_WIDGET (icon_view));
5943 gdk_window_get_pointer (window, &px, &py, NULL);
5944 gdk_window_get_geometry (window, &x, &y, &width, &height);
5946 /* see if we are near the edge. */
5947 voffset = py - (y + 2 * SCROLL_EDGE_SIZE);
5949 voffset = MAX (py - (y + height - 2 * SCROLL_EDGE_SIZE), 0);
5951 hoffset = px - (x + 2 * SCROLL_EDGE_SIZE);
5953 hoffset = MAX (px - (x + width - 2 * SCROLL_EDGE_SIZE), 0);
5956 gtk_adjustment_set_value (icon_view->priv->vadjustment,
5957 gtk_adjustment_get_value (icon_view->priv->vadjustment) + voffset);
5960 gtk_adjustment_set_value (icon_view->priv->hadjustment,
5961 gtk_adjustment_get_value (icon_view->priv->hadjustment) + hoffset);
5966 drag_scroll_timeout (gpointer data)
5968 GtkIconView *icon_view = GTK_ICON_VIEW (data);
5970 gtk_icon_view_autoscroll (icon_view);
5977 set_destination (GtkIconView *icon_view,
5978 GdkDragContext *context,
5981 GdkDragAction *suggested_action,
5985 GtkTreePath *path = NULL;
5986 GtkIconViewDropPosition pos;
5987 GtkIconViewDropPosition old_pos;
5988 GtkTreePath *old_dest_path = NULL;
5989 gboolean can_drop = FALSE;
5991 widget = GTK_WIDGET (icon_view);
5993 *suggested_action = 0;
5996 if (!icon_view->priv->dest_set)
5998 /* someone unset us as a drag dest, note that if
5999 * we return FALSE drag_leave isn't called
6002 gtk_icon_view_set_drag_dest_item (icon_view,
6004 GTK_ICON_VIEW_DROP_LEFT);
6006 remove_scroll_timeout (GTK_ICON_VIEW (widget));
6008 return FALSE; /* no longer a drop site */
6011 *target = gtk_drag_dest_find_target (widget, context,
6012 gtk_drag_dest_get_target_list (widget));
6013 if (*target == GDK_NONE)
6016 if (!gtk_icon_view_get_dest_item_at_pos (icon_view, x, y, &path, &pos))
6019 GtkTreeModel *model;
6021 /* the row got dropped on empty space, let's setup a special case
6025 gtk_tree_path_free (path);
6027 model = gtk_icon_view_get_model (icon_view);
6029 n_children = gtk_tree_model_iter_n_children (model, NULL);
6032 pos = GTK_ICON_VIEW_DROP_BELOW;
6033 path = gtk_tree_path_new_from_indices (n_children - 1, -1);
6037 pos = GTK_ICON_VIEW_DROP_ABOVE;
6038 path = gtk_tree_path_new_from_indices (0, -1);
6048 gtk_icon_view_get_drag_dest_item (icon_view,
6053 gtk_tree_path_free (old_dest_path);
6055 if (TRUE /* FIXME if the location droppable predicate */)
6063 GtkWidget *source_widget;
6065 *suggested_action = gdk_drag_context_get_suggested_action (context);
6066 source_widget = gtk_drag_get_source_widget (context);
6068 if (source_widget == widget)
6070 /* Default to MOVE, unless the user has
6071 * pressed ctrl or shift to affect available actions
6073 if ((gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) != 0)
6074 *suggested_action = GDK_ACTION_MOVE;
6077 gtk_icon_view_set_drag_dest_item (GTK_ICON_VIEW (widget),
6082 /* can't drop here */
6083 gtk_icon_view_set_drag_dest_item (GTK_ICON_VIEW (widget),
6085 GTK_ICON_VIEW_DROP_LEFT);
6089 gtk_tree_path_free (path);
6095 get_logical_destination (GtkIconView *icon_view,
6096 gboolean *drop_append_mode)
6098 /* adjust path to point to the row the drop goes in front of */
6099 GtkTreePath *path = NULL;
6100 GtkIconViewDropPosition pos;
6102 *drop_append_mode = FALSE;
6104 gtk_icon_view_get_drag_dest_item (icon_view, &path, &pos);
6109 if (pos == GTK_ICON_VIEW_DROP_RIGHT ||
6110 pos == GTK_ICON_VIEW_DROP_BELOW)
6113 GtkTreeModel *model = icon_view->priv->model;
6115 if (!gtk_tree_model_get_iter (model, &iter, path) ||
6116 !gtk_tree_model_iter_next (model, &iter))
6117 *drop_append_mode = TRUE;
6120 *drop_append_mode = FALSE;
6121 gtk_tree_path_next (path);
6129 gtk_icon_view_maybe_begin_drag (GtkIconView *icon_view,
6130 GdkEventMotion *event)
6132 GtkWidget *widget = GTK_WIDGET (icon_view);
6133 GdkDragContext *context;
6134 GtkTreePath *path = NULL;
6136 GtkTreeModel *model;
6137 gboolean retval = FALSE;
6139 if (!icon_view->priv->source_set)
6142 if (icon_view->priv->pressed_button < 0)
6145 if (!gtk_drag_check_threshold (GTK_WIDGET (icon_view),
6146 icon_view->priv->press_start_x,
6147 icon_view->priv->press_start_y,
6148 event->x, event->y))
6151 model = gtk_icon_view_get_model (icon_view);
6156 button = icon_view->priv->pressed_button;
6157 icon_view->priv->pressed_button = -1;
6159 path = gtk_icon_view_get_path_at_pos (icon_view,
6160 icon_view->priv->press_start_x,
6161 icon_view->priv->press_start_y);
6166 if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
6167 !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
6171 /* FIXME Check whether we're a start button, if not return FALSE and
6175 /* Now we can begin the drag */
6179 context = gtk_drag_begin (widget,
6180 gtk_drag_source_get_target_list (widget),
6181 icon_view->priv->source_actions,
6185 set_source_row (context, model, path);
6189 gtk_tree_path_free (path);
6194 /* Source side drag signals */
6196 gtk_icon_view_drag_begin (GtkWidget *widget,
6197 GdkDragContext *context)
6199 GtkIconView *icon_view;
6200 GtkIconViewItem *item;
6201 cairo_surface_t *icon;
6205 icon_view = GTK_ICON_VIEW (widget);
6207 /* if the user uses a custom DnD impl, we don't set the icon here */
6208 if (!icon_view->priv->dest_set && !icon_view->priv->source_set)
6211 item = gtk_icon_view_get_item_at_coords (icon_view,
6212 icon_view->priv->press_start_x,
6213 icon_view->priv->press_start_y,
6217 g_return_if_fail (item != NULL);
6219 x = icon_view->priv->press_start_x - item->cell_area.x + 1;
6220 y = icon_view->priv->press_start_y - item->cell_area.y + 1;
6222 path = gtk_tree_path_new_from_indices (item->index, -1);
6223 icon = gtk_icon_view_create_drag_icon (icon_view, path);
6224 gtk_tree_path_free (path);
6226 cairo_surface_set_device_offset (icon, -x, -y);
6228 gtk_drag_set_icon_surface (context, icon);
6230 cairo_surface_destroy (icon);
6234 gtk_icon_view_drag_end (GtkWidget *widget,
6235 GdkDragContext *context)
6241 gtk_icon_view_drag_data_get (GtkWidget *widget,
6242 GdkDragContext *context,
6243 GtkSelectionData *selection_data,
6247 GtkIconView *icon_view;
6248 GtkTreeModel *model;
6249 GtkTreePath *source_row;
6251 icon_view = GTK_ICON_VIEW (widget);
6252 model = gtk_icon_view_get_model (icon_view);
6257 if (!icon_view->priv->source_set)
6260 source_row = get_source_row (context);
6262 if (source_row == NULL)
6265 /* We can implement the GTK_TREE_MODEL_ROW target generically for
6266 * any model; for DragSource models there are some other targets
6270 if (GTK_IS_TREE_DRAG_SOURCE (model) &&
6271 gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
6276 /* If drag_data_get does nothing, try providing row data. */
6277 if (gtk_selection_data_get_target (selection_data) == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
6278 gtk_tree_set_row_drag_data (selection_data,
6283 gtk_tree_path_free (source_row);
6287 gtk_icon_view_drag_data_delete (GtkWidget *widget,
6288 GdkDragContext *context)
6290 GtkTreeModel *model;
6291 GtkIconView *icon_view;
6292 GtkTreePath *source_row;
6294 icon_view = GTK_ICON_VIEW (widget);
6295 model = gtk_icon_view_get_model (icon_view);
6297 if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag-data-delete"))
6300 if (!icon_view->priv->source_set)
6303 source_row = get_source_row (context);
6305 if (source_row == NULL)
6308 gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
6311 gtk_tree_path_free (source_row);
6313 set_source_row (context, NULL, NULL);
6316 /* Target side drag signals */
6318 gtk_icon_view_drag_leave (GtkWidget *widget,
6319 GdkDragContext *context,
6322 GtkIconView *icon_view;
6324 icon_view = GTK_ICON_VIEW (widget);
6326 /* unset any highlight row */
6327 gtk_icon_view_set_drag_dest_item (icon_view,
6329 GTK_ICON_VIEW_DROP_LEFT);
6331 remove_scroll_timeout (icon_view);
6335 gtk_icon_view_drag_motion (GtkWidget *widget,
6336 GdkDragContext *context,
6341 GtkTreePath *path = NULL;
6342 GtkIconViewDropPosition pos;
6343 GtkIconView *icon_view;
6344 GdkDragAction suggested_action = 0;
6348 icon_view = GTK_ICON_VIEW (widget);
6350 if (!set_destination (icon_view, context, x, y, &suggested_action, &target))
6353 gtk_icon_view_get_drag_dest_item (icon_view, &path, &pos);
6355 /* we only know this *after* set_desination_row */
6356 empty = icon_view->priv->empty_view_drop;
6358 if (path == NULL && !empty)
6360 /* Can't drop here. */
6361 gdk_drag_status (context, 0, time);
6365 if (icon_view->priv->scroll_timeout_id == 0)
6367 icon_view->priv->scroll_timeout_id =
6368 gdk_threads_add_timeout (50, drag_scroll_timeout, icon_view);
6371 if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
6373 /* Request data so we can use the source row when
6374 * determining whether to accept the drop
6376 set_status_pending (context, suggested_action);
6377 gtk_drag_get_data (widget, context, target, time);
6381 set_status_pending (context, 0);
6382 gdk_drag_status (context, suggested_action, time);
6387 gtk_tree_path_free (path);
6393 gtk_icon_view_drag_drop (GtkWidget *widget,
6394 GdkDragContext *context,
6399 GtkIconView *icon_view;
6401 GdkDragAction suggested_action = 0;
6402 GdkAtom target = GDK_NONE;
6403 GtkTreeModel *model;
6404 gboolean drop_append_mode;
6406 icon_view = GTK_ICON_VIEW (widget);
6407 model = gtk_icon_view_get_model (icon_view);
6409 remove_scroll_timeout (GTK_ICON_VIEW (widget));
6411 if (!icon_view->priv->dest_set)
6414 if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag-drop"))
6417 if (!set_destination (icon_view, context, x, y, &suggested_action, &target))
6420 path = get_logical_destination (icon_view, &drop_append_mode);
6422 if (target != GDK_NONE && path != NULL)
6424 /* in case a motion had requested drag data, change things so we
6425 * treat drag data receives as a drop.
6427 set_status_pending (context, 0);
6428 set_dest_row (context, model, path,
6429 icon_view->priv->empty_view_drop, drop_append_mode);
6433 gtk_tree_path_free (path);
6435 /* Unset this thing */
6436 gtk_icon_view_set_drag_dest_item (icon_view, NULL, GTK_ICON_VIEW_DROP_LEFT);
6438 if (target != GDK_NONE)
6440 gtk_drag_get_data (widget, context, target, time);
6448 gtk_icon_view_drag_data_received (GtkWidget *widget,
6449 GdkDragContext *context,
6452 GtkSelectionData *selection_data,
6457 gboolean accepted = FALSE;
6458 GtkTreeModel *model;
6459 GtkIconView *icon_view;
6460 GtkTreePath *dest_row;
6461 GdkDragAction suggested_action;
6462 gboolean drop_append_mode;
6464 icon_view = GTK_ICON_VIEW (widget);
6465 model = gtk_icon_view_get_model (icon_view);
6467 if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag-data-received"))
6470 if (!icon_view->priv->dest_set)
6473 suggested_action = get_status_pending (context);
6475 if (suggested_action)
6477 /* We are getting this data due to a request in drag_motion,
6478 * rather than due to a request in drag_drop, so we are just
6479 * supposed to call drag_status, not actually paste in the
6482 path = get_logical_destination (icon_view, &drop_append_mode);
6485 suggested_action = 0;
6487 if (suggested_action)
6489 if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
6492 suggested_action = 0;
6495 gdk_drag_status (context, suggested_action, time);
6498 gtk_tree_path_free (path);
6500 /* If you can't drop, remove user drop indicator until the next motion */
6501 if (suggested_action == 0)
6502 gtk_icon_view_set_drag_dest_item (icon_view,
6504 GTK_ICON_VIEW_DROP_LEFT);
6509 dest_row = get_dest_row (context);
6511 if (dest_row == NULL)
6514 if (gtk_selection_data_get_length (selection_data) >= 0)
6516 if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
6522 gtk_drag_finish (context,
6524 (gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE),
6527 gtk_tree_path_free (dest_row);
6530 set_dest_row (context, NULL, NULL, FALSE, FALSE);
6533 /* Drag-and-Drop support */
6535 * gtk_icon_view_enable_model_drag_source:
6536 * @icon_view: a #GtkIconTreeView
6537 * @start_button_mask: Mask of allowed buttons to start drag
6538 * @targets: (array length=n_targets): the table of targets that the drag will
6540 * @n_targets: the number of items in @targets
6541 * @actions: the bitmask of possible actions for a drag from this
6544 * Turns @icon_view into a drag source for automatic DND. Calling this
6545 * method sets #GtkIconView:reorderable to %FALSE.
6550 gtk_icon_view_enable_model_drag_source (GtkIconView *icon_view,
6551 GdkModifierType start_button_mask,
6552 const GtkTargetEntry *targets,
6554 GdkDragAction actions)
6556 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6558 gtk_drag_source_set (GTK_WIDGET (icon_view), 0, targets, n_targets, actions);
6560 icon_view->priv->start_button_mask = start_button_mask;
6561 icon_view->priv->source_actions = actions;
6563 icon_view->priv->source_set = TRUE;
6565 unset_reorderable (icon_view);
6569 * gtk_icon_view_enable_model_drag_dest:
6570 * @icon_view: a #GtkIconView
6571 * @targets: (array length=n_targets): the table of targets that the drag will
6573 * @n_targets: the number of items in @targets
6574 * @actions: the bitmask of possible actions for a drag to this
6577 * Turns @icon_view into a drop destination for automatic DND. Calling this
6578 * method sets #GtkIconView:reorderable to %FALSE.
6583 gtk_icon_view_enable_model_drag_dest (GtkIconView *icon_view,
6584 const GtkTargetEntry *targets,
6586 GdkDragAction actions)
6588 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6590 gtk_drag_dest_set (GTK_WIDGET (icon_view), 0, targets, n_targets, actions);
6592 icon_view->priv->dest_actions = actions;
6594 icon_view->priv->dest_set = TRUE;
6596 unset_reorderable (icon_view);
6600 * gtk_icon_view_unset_model_drag_source:
6601 * @icon_view: a #GtkIconView
6603 * Undoes the effect of gtk_icon_view_enable_model_drag_source(). Calling this
6604 * method sets #GtkIconView:reorderable to %FALSE.
6609 gtk_icon_view_unset_model_drag_source (GtkIconView *icon_view)
6611 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6613 if (icon_view->priv->source_set)
6615 gtk_drag_source_unset (GTK_WIDGET (icon_view));
6616 icon_view->priv->source_set = FALSE;
6619 unset_reorderable (icon_view);
6623 * gtk_icon_view_unset_model_drag_dest:
6624 * @icon_view: a #GtkIconView
6626 * Undoes the effect of gtk_icon_view_enable_model_drag_dest(). Calling this
6627 * method sets #GtkIconView:reorderable to %FALSE.
6632 gtk_icon_view_unset_model_drag_dest (GtkIconView *icon_view)
6634 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6636 if (icon_view->priv->dest_set)
6638 gtk_drag_dest_unset (GTK_WIDGET (icon_view));
6639 icon_view->priv->dest_set = FALSE;
6642 unset_reorderable (icon_view);
6645 /* These are useful to implement your own custom stuff. */
6647 * gtk_icon_view_set_drag_dest_item:
6648 * @icon_view: a #GtkIconView
6649 * @path: (allow-none): The path of the item to highlight, or %NULL.
6650 * @pos: Specifies where to drop, relative to the item
6652 * Sets the item that is highlighted for feedback.
6657 gtk_icon_view_set_drag_dest_item (GtkIconView *icon_view,
6659 GtkIconViewDropPosition pos)
6661 /* Note; this function is exported to allow a custom DND
6662 * implementation, so it can't touch TreeViewDragInfo
6665 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6667 if (icon_view->priv->dest_item)
6669 GtkTreePath *current_path;
6670 current_path = gtk_tree_row_reference_get_path (icon_view->priv->dest_item);
6671 gtk_tree_row_reference_free (icon_view->priv->dest_item);
6672 icon_view->priv->dest_item = NULL;
6674 gtk_icon_view_queue_draw_path (icon_view, current_path);
6675 gtk_tree_path_free (current_path);
6678 /* special case a drop on an empty model */
6679 icon_view->priv->empty_view_drop = FALSE;
6680 if (pos == GTK_ICON_VIEW_DROP_ABOVE && path
6681 && gtk_tree_path_get_depth (path) == 1
6682 && gtk_tree_path_get_indices (path)[0] == 0)
6686 n_children = gtk_tree_model_iter_n_children (icon_view->priv->model,
6689 if (n_children == 0)
6690 icon_view->priv->empty_view_drop = TRUE;
6693 icon_view->priv->dest_pos = pos;
6697 icon_view->priv->dest_item =
6698 gtk_tree_row_reference_new_proxy (G_OBJECT (icon_view),
6699 icon_view->priv->model, path);
6701 gtk_icon_view_queue_draw_path (icon_view, path);
6706 * gtk_icon_view_get_drag_dest_item:
6707 * @icon_view: a #GtkIconView
6708 * @path: (out) (allow-none): Return location for the path of
6709 * the highlighted item, or %NULL.
6710 * @pos: (out) (allow-none): Return location for the drop position, or %NULL
6712 * Gets information about the item that is highlighted for feedback.
6717 gtk_icon_view_get_drag_dest_item (GtkIconView *icon_view,
6719 GtkIconViewDropPosition *pos)
6721 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6725 if (icon_view->priv->dest_item)
6726 *path = gtk_tree_row_reference_get_path (icon_view->priv->dest_item);
6732 *pos = icon_view->priv->dest_pos;
6736 * gtk_icon_view_get_dest_item_at_pos:
6737 * @icon_view: a #GtkIconView
6738 * @drag_x: the position to determine the destination item for
6739 * @drag_y: the position to determine the destination item for
6740 * @path: (out) (allow-none): Return location for the path of the item,
6742 * @pos: (out) (allow-none): Return location for the drop position, or %NULL
6744 * Determines the destination item for a given position.
6746 * Return value: whether there is an item at the given position.
6751 gtk_icon_view_get_dest_item_at_pos (GtkIconView *icon_view,
6755 GtkIconViewDropPosition *pos)
6757 GtkIconViewItem *item;
6759 /* Note; this function is exported to allow a custom DND
6760 * implementation, so it can't touch TreeViewDragInfo
6763 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
6764 g_return_val_if_fail (drag_x >= 0, FALSE);
6765 g_return_val_if_fail (drag_y >= 0, FALSE);
6766 g_return_val_if_fail (icon_view->priv->bin_window != NULL, FALSE);
6772 item = gtk_icon_view_get_item_at_coords (icon_view,
6773 drag_x + gtk_adjustment_get_value (icon_view->priv->hadjustment),
6774 drag_y + gtk_adjustment_get_value (icon_view->priv->vadjustment),
6781 *path = gtk_tree_path_new_from_indices (item->index, -1);
6785 if (drag_x < item->cell_area.x + item->cell_area.width / 4)
6786 *pos = GTK_ICON_VIEW_DROP_LEFT;
6787 else if (drag_x > item->cell_area.x + item->cell_area.width * 3 / 4)
6788 *pos = GTK_ICON_VIEW_DROP_RIGHT;
6789 else if (drag_y < item->cell_area.y + item->cell_area.height / 4)
6790 *pos = GTK_ICON_VIEW_DROP_ABOVE;
6791 else if (drag_y > item->cell_area.y + item->cell_area.height * 3 / 4)
6792 *pos = GTK_ICON_VIEW_DROP_BELOW;
6794 *pos = GTK_ICON_VIEW_DROP_INTO;
6801 * gtk_icon_view_create_drag_icon:
6802 * @icon_view: a #GtkIconView
6803 * @path: a #GtkTreePath in @icon_view
6805 * Creates a #cairo_surface_t representation of the item at @path.
6806 * This image is used for a drag icon.
6808 * Return value: (transfer full): a newly-allocated surface of the drag icon.
6813 gtk_icon_view_create_drag_icon (GtkIconView *icon_view,
6818 cairo_surface_t *surface;
6822 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
6823 g_return_val_if_fail (path != NULL, NULL);
6825 widget = GTK_WIDGET (icon_view);
6827 if (!gtk_widget_get_realized (widget))
6830 index = gtk_tree_path_get_indices (path)[0];
6832 for (l = icon_view->priv->items; l; l = l->next)
6834 GtkIconViewItem *item = l->data;
6836 if (index == item->index)
6838 GdkRectangle rect = {
6839 item->cell_area.x - icon_view->priv->item_padding,
6840 item->cell_area.y - icon_view->priv->item_padding,
6841 item->cell_area.width + icon_view->priv->item_padding * 2,
6842 item->cell_area.height + icon_view->priv->item_padding * 2
6845 surface = gdk_window_create_similar_surface (icon_view->priv->bin_window,
6846 CAIRO_CONTENT_COLOR,
6850 cr = cairo_create (surface);
6851 cairo_set_line_width (cr, 1.);
6853 gdk_cairo_set_source_color (cr, >k_widget_get_style (widget)->base[gtk_widget_get_state (widget)]);
6854 cairo_rectangle (cr, 0, 0, rect.width + 2, rect.height + 2);
6859 cairo_rectangle (cr, 1, 1, rect.width, rect.height);
6862 gtk_icon_view_paint_item (icon_view, cr, item,
6863 icon_view->priv->item_padding + 1,
6864 icon_view->priv->item_padding + 1, FALSE);
6868 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
6869 cairo_rectangle (cr, 0.5, 0.5, rect.width + 1, rect.height + 1);
6882 * gtk_icon_view_get_reorderable:
6883 * @icon_view: a #GtkIconView
6885 * Retrieves whether the user can reorder the list via drag-and-drop.
6886 * See gtk_icon_view_set_reorderable().
6888 * Return value: %TRUE if the list can be reordered.
6893 gtk_icon_view_get_reorderable (GtkIconView *icon_view)
6895 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
6897 return icon_view->priv->reorderable;
6900 static const GtkTargetEntry item_targets[] = {
6901 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
6906 * gtk_icon_view_set_reorderable:
6907 * @icon_view: A #GtkIconView.
6908 * @reorderable: %TRUE, if the list of items can be reordered.
6910 * This function is a convenience function to allow you to reorder models that
6911 * support the #GtkTreeDragSourceIface and the #GtkTreeDragDestIface. Both
6912 * #GtkTreeStore and #GtkListStore support these. If @reorderable is %TRUE, then
6913 * the user can reorder the model by dragging and dropping rows. The
6914 * developer can listen to these changes by connecting to the model's
6915 * row_inserted and row_deleted signals. The reordering is implemented by setting up
6916 * the icon view as a drag source and destination. Therefore, drag and
6917 * drop can not be used in a reorderable view for any other purpose.
6919 * This function does not give you any degree of control over the order -- any
6920 * reordering is allowed. If more control is needed, you should probably
6921 * handle drag and drop manually.
6926 gtk_icon_view_set_reorderable (GtkIconView *icon_view,
6927 gboolean reorderable)
6929 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6931 reorderable = reorderable != FALSE;
6933 if (icon_view->priv->reorderable == reorderable)
6938 gtk_icon_view_enable_model_drag_source (icon_view,
6941 G_N_ELEMENTS (item_targets),
6943 gtk_icon_view_enable_model_drag_dest (icon_view,
6945 G_N_ELEMENTS (item_targets),
6950 gtk_icon_view_unset_model_drag_source (icon_view);
6951 gtk_icon_view_unset_model_drag_dest (icon_view);
6954 icon_view->priv->reorderable = reorderable;
6956 g_object_notify (G_OBJECT (icon_view), "reorderable");
6960 /* Accessibility Support */
6962 static gpointer accessible_parent_class;
6963 static gpointer accessible_item_parent_class;
6964 static GQuark accessible_private_data_quark = 0;
6966 #define GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE (gtk_icon_view_item_accessible_get_type ())
6967 #define GTK_ICON_VIEW_ITEM_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE, GtkIconViewItemAccessible))
6968 #define GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE))
6970 static GType gtk_icon_view_item_accessible_get_type (void);
6981 GtkIconViewItem *item;
6985 AtkStateSet *state_set;
6989 GtkTextBuffer *text_buffer;
6991 gchar *action_descriptions[LAST_ACTION];
6992 gchar *image_description;
6993 guint action_idle_handler;
6994 } GtkIconViewItemAccessible;
6996 static const gchar *const gtk_icon_view_item_accessible_action_names[] =
7002 static const gchar *const gtk_icon_view_item_accessible_action_descriptions[] =
7007 typedef struct _GtkIconViewItemAccessibleClass
7009 AtkObjectClass parent_class;
7011 } GtkIconViewItemAccessibleClass;
7013 static gboolean gtk_icon_view_item_accessible_is_showing (GtkIconViewItemAccessible *item);
7016 gtk_icon_view_item_accessible_idle_do_action (gpointer data)
7018 GtkIconViewItemAccessible *item;
7019 GtkIconView *icon_view;
7022 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (data);
7023 item->action_idle_handler = 0;
7025 if (item->widget != NULL)
7027 icon_view = GTK_ICON_VIEW (item->widget);
7028 path = gtk_tree_path_new_from_indices (item->item->index, -1);
7029 gtk_icon_view_item_activated (icon_view, path);
7030 gtk_tree_path_free (path);
7037 gtk_icon_view_item_accessible_action_do_action (AtkAction *action,
7040 GtkIconViewItemAccessible *item;
7042 if (i < 0 || i >= LAST_ACTION)
7045 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
7047 if (!GTK_IS_ICON_VIEW (item->widget))
7050 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7055 case ACTION_ACTIVATE:
7056 if (!item->action_idle_handler)
7057 item->action_idle_handler = gdk_threads_add_idle (gtk_icon_view_item_accessible_idle_do_action, item);
7060 g_assert_not_reached ();
7068 gtk_icon_view_item_accessible_action_get_n_actions (AtkAction *action)
7073 static const gchar *
7074 gtk_icon_view_item_accessible_action_get_description (AtkAction *action,
7077 GtkIconViewItemAccessible *item;
7079 if (i < 0 || i >= LAST_ACTION)
7082 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
7084 if (item->action_descriptions[i])
7085 return item->action_descriptions[i];
7087 return gtk_icon_view_item_accessible_action_descriptions[i];
7090 static const gchar *
7091 gtk_icon_view_item_accessible_action_get_name (AtkAction *action,
7094 if (i < 0 || i >= LAST_ACTION)
7097 return gtk_icon_view_item_accessible_action_names[i];
7101 gtk_icon_view_item_accessible_action_set_description (AtkAction *action,
7103 const gchar *description)
7105 GtkIconViewItemAccessible *item;
7107 if (i < 0 || i >= LAST_ACTION)
7110 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
7112 g_free (item->action_descriptions[i]);
7114 item->action_descriptions[i] = g_strdup (description);
7120 atk_action_item_interface_init (AtkActionIface *iface)
7122 iface->do_action = gtk_icon_view_item_accessible_action_do_action;
7123 iface->get_n_actions = gtk_icon_view_item_accessible_action_get_n_actions;
7124 iface->get_description = gtk_icon_view_item_accessible_action_get_description;
7125 iface->get_name = gtk_icon_view_item_accessible_action_get_name;
7126 iface->set_description = gtk_icon_view_item_accessible_action_set_description;
7129 static const gchar *
7130 gtk_icon_view_item_accessible_image_get_image_description (AtkImage *image)
7132 GtkIconViewItemAccessible *item;
7134 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7136 return item->image_description;
7140 gtk_icon_view_item_accessible_image_set_image_description (AtkImage *image,
7141 const gchar *description)
7143 GtkIconViewItemAccessible *item;
7145 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7147 g_free (item->image_description);
7148 item->image_description = g_strdup (description);
7155 gboolean pixbuf_found;
7159 get_pixbuf_foreach (GtkCellRenderer *renderer,
7160 const GdkRectangle *cell_area,
7161 const GdkRectangle *cell_background,
7162 GetPixbufBoxData *data)
7164 if (GTK_IS_CELL_RENDERER_PIXBUF (renderer))
7166 data->box = *cell_area;
7167 data->pixbuf_found = TRUE;
7169 return (data->pixbuf_found != FALSE);
7173 get_pixbuf_box (GtkIconView *icon_view,
7174 GtkIconViewItem *item,
7177 GetPixbufBoxData data = { { 0, }, FALSE };
7178 GtkCellAreaContext *context;
7180 context = g_ptr_array_index (icon_view->priv->row_contexts, item->row);
7182 gtk_icon_view_set_cell_data (icon_view, item);
7183 gtk_cell_area_foreach_alloc (icon_view->priv->cell_area, context,
7184 GTK_WIDGET (icon_view),
7185 (GdkRectangle *)item, (GdkRectangle *)item,
7186 (GtkCellAllocCallback)get_pixbuf_foreach, &data);
7188 return data.pixbuf_found;
7192 get_text_foreach (GtkCellRenderer *renderer,
7195 if (GTK_IS_CELL_RENDERER_TEXT (renderer))
7197 g_object_get (renderer, "text", text, NULL);
7205 get_text (GtkIconView *icon_view,
7206 GtkIconViewItem *item)
7210 gtk_icon_view_set_cell_data (icon_view, item);
7211 gtk_cell_area_foreach (icon_view->priv->cell_area,
7212 (GtkCellCallback)get_text_foreach, &text);
7218 gtk_icon_view_item_accessible_image_get_image_size (AtkImage *image,
7222 GtkIconViewItemAccessible *item;
7225 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7227 if (!GTK_IS_ICON_VIEW (item->widget))
7230 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7233 if (get_pixbuf_box (GTK_ICON_VIEW (item->widget), item->item, &box))
7236 *height = box.height;
7241 gtk_icon_view_item_accessible_image_get_image_position (AtkImage *image,
7244 AtkCoordType coord_type)
7246 GtkIconViewItemAccessible *item;
7249 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7251 if (!GTK_IS_ICON_VIEW (item->widget))
7254 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7257 atk_component_get_position (ATK_COMPONENT (image), x, y, coord_type);
7259 if (get_pixbuf_box (GTK_ICON_VIEW (item->widget), item->item, &box))
7261 *x+= box.x - item->item->cell_area.x;
7262 *y+= box.y - item->item->cell_area.y;
7268 atk_image_item_interface_init (AtkImageIface *iface)
7270 iface->get_image_description = gtk_icon_view_item_accessible_image_get_image_description;
7271 iface->set_image_description = gtk_icon_view_item_accessible_image_set_image_description;
7272 iface->get_image_size = gtk_icon_view_item_accessible_image_get_image_size;
7273 iface->get_image_position = gtk_icon_view_item_accessible_image_get_image_position;
7277 gtk_icon_view_item_accessible_text_get_text (AtkText *text,
7281 GtkIconViewItemAccessible *item;
7282 GtkTextIter start, end;
7283 GtkTextBuffer *buffer;
7285 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7287 if (!GTK_IS_ICON_VIEW (item->widget))
7290 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7293 buffer = item->text_buffer;
7294 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
7296 gtk_text_buffer_get_end_iter (buffer, &end);
7298 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
7300 return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
7304 gtk_icon_view_item_accessible_text_get_character_at_offset (AtkText *text,
7307 GtkIconViewItemAccessible *item;
7308 GtkTextIter start, end;
7309 GtkTextBuffer *buffer;
7313 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7315 if (!GTK_IS_ICON_VIEW (item->widget))
7318 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7321 buffer = item->text_buffer;
7322 if (offset >= gtk_text_buffer_get_char_count (buffer))
7325 gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
7327 gtk_text_iter_forward_char (&end);
7328 string = gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
7329 unichar = g_utf8_get_char (string);
7337 get_pango_text_offsets (PangoLayout *layout,
7338 GtkTextBuffer *buffer,
7340 AtkTextBoundary boundary_type,
7344 GtkTextIter *start_iter,
7345 GtkTextIter *end_iter)
7347 PangoLayoutIter *iter;
7348 PangoLayoutLine *line, *prev_line = NULL, *prev_prev_line = NULL;
7349 gint index, start_index, end_index;
7351 gboolean found = FALSE;
7353 text = pango_layout_get_text (layout);
7354 index = g_utf8_offset_to_pointer (text, offset) - text;
7355 iter = pango_layout_get_iter (layout);
7358 line = pango_layout_iter_get_line_readonly (iter);
7359 start_index = line->start_index;
7360 end_index = start_index + line->length;
7362 if (index >= start_index && index <= end_index)
7365 * Found line for offset
7371 * We want the previous line
7375 switch (boundary_type)
7377 case ATK_TEXT_BOUNDARY_LINE_START:
7378 end_index = start_index;
7379 start_index = prev_line->start_index;
7381 case ATK_TEXT_BOUNDARY_LINE_END:
7383 start_index = prev_prev_line->start_index +
7384 prev_prev_line->length;
7385 end_index = prev_line->start_index + prev_line->length;
7388 g_assert_not_reached();
7392 start_index = end_index = 0;
7395 switch (boundary_type)
7397 case ATK_TEXT_BOUNDARY_LINE_START:
7398 if (pango_layout_iter_next_line (iter))
7399 end_index = pango_layout_iter_get_line_readonly (iter)->start_index;
7401 case ATK_TEXT_BOUNDARY_LINE_END:
7403 start_index = prev_line->start_index +
7407 g_assert_not_reached();
7412 * We want the next line
7414 if (pango_layout_iter_next_line (iter))
7416 line = pango_layout_iter_get_line_readonly (iter);
7417 switch (boundary_type)
7419 case ATK_TEXT_BOUNDARY_LINE_START:
7420 start_index = line->start_index;
7421 if (pango_layout_iter_next_line (iter))
7422 end_index = pango_layout_iter_get_line_readonly (iter)->start_index;
7424 end_index = start_index + line->length;
7426 case ATK_TEXT_BOUNDARY_LINE_END:
7427 start_index = end_index;
7428 end_index = line->start_index + line->length;
7431 g_assert_not_reached();
7435 start_index = end_index;
7441 prev_prev_line = prev_line;
7444 while (pango_layout_iter_next_line (iter));
7448 start_index = prev_line->start_index + prev_line->length;
7449 end_index = start_index;
7451 pango_layout_iter_free (iter);
7452 *start_offset = g_utf8_pointer_to_offset (text, text + start_index);
7453 *end_offset = g_utf8_pointer_to_offset (text, text + end_index);
7455 gtk_text_buffer_get_iter_at_offset (buffer, start_iter, *start_offset);
7456 gtk_text_buffer_get_iter_at_offset (buffer, end_iter, *end_offset);
7461 gtk_icon_view_item_accessible_text_get_text_before_offset (AtkText *text,
7463 AtkTextBoundary boundary_type,
7467 GtkIconViewItemAccessible *item;
7468 GtkTextIter start, end;
7469 GtkTextBuffer *buffer;
7471 GtkIconView *icon_view;
7474 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7476 if (!GTK_IS_ICON_VIEW (item->widget))
7479 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7482 buffer = item->text_buffer;
7484 if (!gtk_text_buffer_get_char_count (buffer))
7488 return g_strdup ("");
7490 gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
7494 switch (boundary_type)
7496 case ATK_TEXT_BOUNDARY_CHAR:
7497 gtk_text_iter_backward_char(&start);
7499 case ATK_TEXT_BOUNDARY_WORD_START:
7500 if (!gtk_text_iter_starts_word (&start))
7501 gtk_text_iter_backward_word_start (&start);
7503 gtk_text_iter_backward_word_start(&start);
7505 case ATK_TEXT_BOUNDARY_WORD_END:
7506 if (gtk_text_iter_inside_word (&start) &&
7507 !gtk_text_iter_starts_word (&start))
7508 gtk_text_iter_backward_word_start (&start);
7509 while (!gtk_text_iter_ends_word (&start))
7511 if (!gtk_text_iter_backward_char (&start))
7515 gtk_text_iter_backward_word_start(&start);
7516 while (!gtk_text_iter_ends_word (&start))
7518 if (!gtk_text_iter_backward_char (&start))
7522 case ATK_TEXT_BOUNDARY_SENTENCE_START:
7523 if (!gtk_text_iter_starts_sentence (&start))
7524 gtk_text_iter_backward_sentence_start (&start);
7526 gtk_text_iter_backward_sentence_start (&start);
7528 case ATK_TEXT_BOUNDARY_SENTENCE_END:
7529 if (gtk_text_iter_inside_sentence (&start) &&
7530 !gtk_text_iter_starts_sentence (&start))
7531 gtk_text_iter_backward_sentence_start (&start);
7532 while (!gtk_text_iter_ends_sentence (&start))
7534 if (!gtk_text_iter_backward_char (&start))
7538 gtk_text_iter_backward_sentence_start (&start);
7539 while (!gtk_text_iter_ends_sentence (&start))
7541 if (!gtk_text_iter_backward_char (&start))
7545 case ATK_TEXT_BOUNDARY_LINE_START:
7546 case ATK_TEXT_BOUNDARY_LINE_END:
7548 icon_view = GTK_ICON_VIEW (item->widget);
7549 /* FIXME we probably have to use GailTextCell to salvage this */
7550 gtk_icon_view_update_item_text (icon_view, item->item);
7551 get_pango_text_offsets (icon_view->priv->layout,
7564 *start_offset = gtk_text_iter_get_offset (&start);
7565 *end_offset = gtk_text_iter_get_offset (&end);
7567 return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
7571 gtk_icon_view_item_accessible_text_get_text_at_offset (AtkText *text,
7573 AtkTextBoundary boundary_type,
7577 GtkIconViewItemAccessible *item;
7578 GtkTextIter start, end;
7579 GtkTextBuffer *buffer;
7581 GtkIconView *icon_view;
7584 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7586 if (!GTK_IS_ICON_VIEW (item->widget))
7589 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7592 buffer = item->text_buffer;
7594 if (!gtk_text_buffer_get_char_count (buffer))
7598 return g_strdup ("");
7600 gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
7604 switch (boundary_type)
7606 case ATK_TEXT_BOUNDARY_CHAR:
7607 gtk_text_iter_forward_char (&end);
7609 case ATK_TEXT_BOUNDARY_WORD_START:
7610 if (!gtk_text_iter_starts_word (&start))
7611 gtk_text_iter_backward_word_start (&start);
7612 if (gtk_text_iter_inside_word (&end))
7613 gtk_text_iter_forward_word_end (&end);
7614 while (!gtk_text_iter_starts_word (&end))
7616 if (!gtk_text_iter_forward_char (&end))
7620 case ATK_TEXT_BOUNDARY_WORD_END:
7621 if (gtk_text_iter_inside_word (&start) &&
7622 !gtk_text_iter_starts_word (&start))
7623 gtk_text_iter_backward_word_start (&start);
7624 while (!gtk_text_iter_ends_word (&start))
7626 if (!gtk_text_iter_backward_char (&start))
7629 gtk_text_iter_forward_word_end (&end);
7631 case ATK_TEXT_BOUNDARY_SENTENCE_START:
7632 if (!gtk_text_iter_starts_sentence (&start))
7633 gtk_text_iter_backward_sentence_start (&start);
7634 if (gtk_text_iter_inside_sentence (&end))
7635 gtk_text_iter_forward_sentence_end (&end);
7636 while (!gtk_text_iter_starts_sentence (&end))
7638 if (!gtk_text_iter_forward_char (&end))
7642 case ATK_TEXT_BOUNDARY_SENTENCE_END:
7643 if (gtk_text_iter_inside_sentence (&start) &&
7644 !gtk_text_iter_starts_sentence (&start))
7645 gtk_text_iter_backward_sentence_start (&start);
7646 while (!gtk_text_iter_ends_sentence (&start))
7648 if (!gtk_text_iter_backward_char (&start))
7651 gtk_text_iter_forward_sentence_end (&end);
7653 case ATK_TEXT_BOUNDARY_LINE_START:
7654 case ATK_TEXT_BOUNDARY_LINE_END:
7656 icon_view = GTK_ICON_VIEW (item->widget);
7657 /* FIXME we probably have to use GailTextCell to salvage this */
7658 gtk_icon_view_update_item_text (icon_view, item->item);
7659 get_pango_text_offsets (icon_view->priv->layout,
7673 *start_offset = gtk_text_iter_get_offset (&start);
7674 *end_offset = gtk_text_iter_get_offset (&end);
7676 return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
7680 gtk_icon_view_item_accessible_text_get_text_after_offset (AtkText *text,
7682 AtkTextBoundary boundary_type,
7686 GtkIconViewItemAccessible *item;
7687 GtkTextIter start, end;
7688 GtkTextBuffer *buffer;
7690 GtkIconView *icon_view;
7693 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7695 if (!GTK_IS_ICON_VIEW (item->widget))
7698 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7701 buffer = item->text_buffer;
7703 if (!gtk_text_buffer_get_char_count (buffer))
7707 return g_strdup ("");
7709 gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
7713 switch (boundary_type)
7715 case ATK_TEXT_BOUNDARY_CHAR:
7716 gtk_text_iter_forward_char(&start);
7717 gtk_text_iter_forward_chars(&end, 2);
7719 case ATK_TEXT_BOUNDARY_WORD_START:
7720 if (gtk_text_iter_inside_word (&end))
7721 gtk_text_iter_forward_word_end (&end);
7722 while (!gtk_text_iter_starts_word (&end))
7724 if (!gtk_text_iter_forward_char (&end))
7728 if (!gtk_text_iter_is_end (&end))
7730 gtk_text_iter_forward_word_end (&end);
7731 while (!gtk_text_iter_starts_word (&end))
7733 if (!gtk_text_iter_forward_char (&end))
7738 case ATK_TEXT_BOUNDARY_WORD_END:
7739 gtk_text_iter_forward_word_end (&end);
7741 if (!gtk_text_iter_is_end (&end))
7742 gtk_text_iter_forward_word_end (&end);
7744 case ATK_TEXT_BOUNDARY_SENTENCE_START:
7745 if (gtk_text_iter_inside_sentence (&end))
7746 gtk_text_iter_forward_sentence_end (&end);
7747 while (!gtk_text_iter_starts_sentence (&end))
7749 if (!gtk_text_iter_forward_char (&end))
7753 if (!gtk_text_iter_is_end (&end))
7755 gtk_text_iter_forward_sentence_end (&end);
7756 while (!gtk_text_iter_starts_sentence (&end))
7758 if (!gtk_text_iter_forward_char (&end))
7763 case ATK_TEXT_BOUNDARY_SENTENCE_END:
7764 gtk_text_iter_forward_sentence_end (&end);
7766 if (!gtk_text_iter_is_end (&end))
7767 gtk_text_iter_forward_sentence_end (&end);
7769 case ATK_TEXT_BOUNDARY_LINE_START:
7770 case ATK_TEXT_BOUNDARY_LINE_END:
7772 icon_view = GTK_ICON_VIEW (item->widget);
7773 /* FIXME we probably have to use GailTextCell to salvage this */
7774 gtk_icon_view_update_item_text (icon_view, item->item);
7775 get_pango_text_offsets (icon_view->priv->layout,
7787 *start_offset = gtk_text_iter_get_offset (&start);
7788 *end_offset = gtk_text_iter_get_offset (&end);
7790 return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
7794 gtk_icon_view_item_accessible_text_get_character_count (AtkText *text)
7796 GtkIconViewItemAccessible *item;
7798 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7800 if (!GTK_IS_ICON_VIEW (item->widget))
7803 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7806 return gtk_text_buffer_get_char_count (item->text_buffer);
7810 gtk_icon_view_item_accessible_text_get_character_extents (AtkText *text,
7816 AtkCoordType coord_type)
7818 GtkIconViewItemAccessible *item;
7820 GtkIconView *icon_view;
7821 PangoRectangle char_rect;
7822 const gchar *item_text;
7826 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7828 if (!GTK_IS_ICON_VIEW (item->widget))
7831 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7835 icon_view = GTK_ICON_VIEW (item->widget);
7836 /* FIXME we probably have to use GailTextCell to salvage this */
7837 gtk_icon_view_update_item_text (icon_view, item->item);
7838 item_text = pango_layout_get_text (icon_view->priv->layout);
7839 index = g_utf8_offset_to_pointer (item_text, offset) - item_text;
7840 pango_layout_index_to_pos (icon_view->priv->layout, index, &char_rect);
7842 atk_component_get_position (ATK_COMPONENT (text), x, y, coord_type);
7843 *x += item->item->layout_x - item->item->x + char_rect.x / PANGO_SCALE;
7844 /* Look at gtk_icon_view_paint_item() to see where the text is. */
7845 *x -= ((item->item->width - item->item->layout_width) / 2) + (MAX (item->item->pixbuf_width, icon_view->priv->item_width) - item->item->width) / 2,
7846 *y += item->item->layout_y - item->item->y + char_rect.y / PANGO_SCALE;
7847 *width = char_rect.width / PANGO_SCALE;
7848 *height = char_rect.height / PANGO_SCALE;
7853 gtk_icon_view_item_accessible_text_get_offset_at_point (AtkText *text,
7856 AtkCoordType coord_type)
7858 GtkIconViewItemAccessible *item;
7861 GtkIconView *icon_view;
7862 const gchar *item_text;
7867 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7869 if (!GTK_IS_ICON_VIEW (item->widget))
7872 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7876 icon_view = GTK_ICON_VIEW (item->widget);
7877 /* FIXME we probably have to use GailTextCell to salvage this */
7878 gtk_icon_view_update_item_text (icon_view, item->item);
7879 atk_component_get_position (ATK_COMPONENT (text), &l_x, &l_y, coord_type);
7880 x -= l_x + item->item->layout_x - item->item->x;
7881 x += ((item->item->width - item->item->layout_width) / 2) + (MAX (item->item->pixbuf_width, icon_view->priv->item_width) - item->item->width) / 2,
7882 y -= l_y + item->item->layout_y - item->item->y;
7883 item_text = pango_layout_get_text (icon_view->priv->layout);
7884 if (!pango_layout_xy_to_index (icon_view->priv->layout,
7895 offset = g_utf8_strlen (item_text, -1);
7897 offset = g_utf8_pointer_to_offset (item_text, item_text + index);
7903 atk_text_item_interface_init (AtkTextIface *iface)
7905 iface->get_text = gtk_icon_view_item_accessible_text_get_text;
7906 iface->get_character_at_offset = gtk_icon_view_item_accessible_text_get_character_at_offset;
7907 iface->get_text_before_offset = gtk_icon_view_item_accessible_text_get_text_before_offset;
7908 iface->get_text_at_offset = gtk_icon_view_item_accessible_text_get_text_at_offset;
7909 iface->get_text_after_offset = gtk_icon_view_item_accessible_text_get_text_after_offset;
7910 iface->get_character_count = gtk_icon_view_item_accessible_text_get_character_count;
7911 iface->get_character_extents = gtk_icon_view_item_accessible_text_get_character_extents;
7912 iface->get_offset_at_point = gtk_icon_view_item_accessible_text_get_offset_at_point;
7916 gtk_icon_view_item_accessible_get_extents (AtkComponent *component,
7921 AtkCoordType coord_type)
7923 GtkIconViewItemAccessible *item;
7924 AtkObject *parent_obj;
7927 g_return_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (component));
7929 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (component);
7930 if (!GTK_IS_WIDGET (item->widget))
7933 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7936 *width = item->item->cell_area.width;
7937 *height = item->item->cell_area.height;
7938 if (gtk_icon_view_item_accessible_is_showing (item))
7940 parent_obj = gtk_widget_get_accessible (item->widget);
7941 atk_component_get_position (ATK_COMPONENT (parent_obj), &l_x, &l_y, coord_type);
7942 *x = l_x + item->item->cell_area.x;
7943 *y = l_y + item->item->cell_area.y;
7953 gtk_icon_view_item_accessible_grab_focus (AtkComponent *component)
7955 GtkIconViewItemAccessible *item;
7956 GtkWidget *toplevel;
7958 g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (component), FALSE);
7960 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (component);
7961 if (!GTK_IS_WIDGET (item->widget))
7964 gtk_widget_grab_focus (item->widget);
7965 gtk_icon_view_set_cursor_item (GTK_ICON_VIEW (item->widget), item->item, NULL);
7966 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (item->widget));
7967 if (gtk_widget_is_toplevel (toplevel))
7968 gtk_window_present (GTK_WINDOW (toplevel));
7974 atk_component_item_interface_init (AtkComponentIface *iface)
7976 iface->get_extents = gtk_icon_view_item_accessible_get_extents;
7977 iface->grab_focus = gtk_icon_view_item_accessible_grab_focus;
7981 gtk_icon_view_item_accessible_add_state (GtkIconViewItemAccessible *item,
7982 AtkStateType state_type,
7983 gboolean emit_signal)
7987 rc = atk_state_set_add_state (item->state_set, state_type);
7989 * The signal should only be generated if the value changed,
7990 * not when the item is set up. So states that are set
7991 * initially should pass FALSE as the emit_signal argument.
7996 atk_object_notify_state_change (ATK_OBJECT (item), state_type, TRUE);
7997 /* If state_type is ATK_STATE_VISIBLE, additional notification */
7998 if (state_type == ATK_STATE_VISIBLE)
7999 g_signal_emit_by_name (item, "visible-data-changed");
8006 gtk_icon_view_item_accessible_remove_state (GtkIconViewItemAccessible *item,
8007 AtkStateType state_type,
8008 gboolean emit_signal)
8010 if (atk_state_set_contains_state (item->state_set, state_type))
8014 rc = atk_state_set_remove_state (item->state_set, state_type);
8016 * The signal should only be generated if the value changed,
8017 * not when the item is set up. So states that are set
8018 * initially should pass FALSE as the emit_signal argument.
8023 atk_object_notify_state_change (ATK_OBJECT (item), state_type, FALSE);
8024 /* If state_type is ATK_STATE_VISIBLE, additional notification */
8025 if (state_type == ATK_STATE_VISIBLE)
8026 g_signal_emit_by_name (item, "visible-data-changed");
8036 gtk_icon_view_item_accessible_is_showing (GtkIconViewItemAccessible *item)
8038 GtkAllocation allocation;
8039 GtkIconView *icon_view;
8040 GdkRectangle visible_rect;
8041 gboolean is_showing;
8044 * An item is considered "SHOWING" if any part of the item is in the
8045 * visible rectangle.
8048 if (!GTK_IS_ICON_VIEW (item->widget))
8051 if (item->item == NULL)
8054 gtk_widget_get_allocation (item->widget, &allocation);
8056 icon_view = GTK_ICON_VIEW (item->widget);
8058 if (icon_view->priv->hadjustment)
8059 visible_rect.x += gtk_adjustment_get_value (icon_view->priv->hadjustment);
8061 if (icon_view->priv->hadjustment)
8062 visible_rect.y += gtk_adjustment_get_value (icon_view->priv->vadjustment);
8063 visible_rect.width = allocation.width;
8064 visible_rect.height = allocation.height;
8066 if (((item->item->cell_area.x + item->item->cell_area.width) < visible_rect.x) ||
8067 ((item->item->cell_area.y + item->item->cell_area.height) < (visible_rect.y)) ||
8068 (item->item->cell_area.x > (visible_rect.x + visible_rect.width)) ||
8069 (item->item->cell_area.y > (visible_rect.y + visible_rect.height)))
8078 gtk_icon_view_item_accessible_set_visibility (GtkIconViewItemAccessible *item,
8079 gboolean emit_signal)
8081 if (gtk_icon_view_item_accessible_is_showing (item))
8082 return gtk_icon_view_item_accessible_add_state (item, ATK_STATE_SHOWING,
8085 return gtk_icon_view_item_accessible_remove_state (item, ATK_STATE_SHOWING,
8090 gtk_icon_view_item_accessible_object_init (GtkIconViewItemAccessible *item)
8094 item->state_set = atk_state_set_new ();
8096 atk_state_set_add_state (item->state_set, ATK_STATE_ENABLED);
8097 atk_state_set_add_state (item->state_set, ATK_STATE_FOCUSABLE);
8098 atk_state_set_add_state (item->state_set, ATK_STATE_SENSITIVE);
8099 atk_state_set_add_state (item->state_set, ATK_STATE_SELECTABLE);
8100 atk_state_set_add_state (item->state_set, ATK_STATE_VISIBLE);
8102 for (i = 0; i < LAST_ACTION; i++)
8103 item->action_descriptions[i] = NULL;
8105 item->image_description = NULL;
8107 item->action_idle_handler = 0;
8111 gtk_icon_view_item_accessible_finalize (GObject *object)
8113 GtkIconViewItemAccessible *item;
8116 g_return_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (object));
8118 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (object);
8121 g_object_remove_weak_pointer (G_OBJECT (item->widget), (gpointer) &item->widget);
8123 if (item->state_set)
8124 g_object_unref (item->state_set);
8126 if (item->text_buffer)
8127 g_object_unref (item->text_buffer);
8129 for (i = 0; i < LAST_ACTION; i++)
8130 g_free (item->action_descriptions[i]);
8132 g_free (item->image_description);
8134 if (item->action_idle_handler)
8136 g_source_remove (item->action_idle_handler);
8137 item->action_idle_handler = 0;
8140 G_OBJECT_CLASS (accessible_item_parent_class)->finalize (object);
8143 static G_CONST_RETURN gchar*
8144 gtk_icon_view_item_accessible_get_name (AtkObject *obj)
8150 GtkIconViewItemAccessible *item;
8151 GtkTextIter start_iter;
8152 GtkTextIter end_iter;
8154 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8156 gtk_text_buffer_get_start_iter (item->text_buffer, &start_iter);
8157 gtk_text_buffer_get_end_iter (item->text_buffer, &end_iter);
8159 return gtk_text_buffer_get_text (item->text_buffer, &start_iter, &end_iter, FALSE);
8164 gtk_icon_view_item_accessible_get_parent (AtkObject *obj)
8166 GtkIconViewItemAccessible *item;
8168 g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (obj), NULL);
8169 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8172 return gtk_widget_get_accessible (item->widget);
8178 gtk_icon_view_item_accessible_get_index_in_parent (AtkObject *obj)
8180 GtkIconViewItemAccessible *item;
8182 g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (obj), 0);
8183 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8185 return item->item->index;
8188 static AtkStateSet *
8189 gtk_icon_view_item_accessible_ref_state_set (AtkObject *obj)
8191 GtkIconViewItemAccessible *item;
8192 GtkIconView *icon_view;
8194 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8195 g_return_val_if_fail (item->state_set, NULL);
8200 icon_view = GTK_ICON_VIEW (item->widget);
8201 if (icon_view->priv->cursor_item == item->item)
8202 atk_state_set_add_state (item->state_set, ATK_STATE_FOCUSED);
8204 atk_state_set_remove_state (item->state_set, ATK_STATE_FOCUSED);
8205 if (item->item->selected)
8206 atk_state_set_add_state (item->state_set, ATK_STATE_SELECTED);
8208 atk_state_set_remove_state (item->state_set, ATK_STATE_SELECTED);
8210 return g_object_ref (item->state_set);
8214 gtk_icon_view_item_accessible_class_init (AtkObjectClass *klass)
8216 GObjectClass *gobject_class;
8218 accessible_item_parent_class = g_type_class_peek_parent (klass);
8220 gobject_class = (GObjectClass *)klass;
8222 gobject_class->finalize = gtk_icon_view_item_accessible_finalize;
8224 klass->get_index_in_parent = gtk_icon_view_item_accessible_get_index_in_parent;
8225 klass->get_name = gtk_icon_view_item_accessible_get_name;
8226 klass->get_parent = gtk_icon_view_item_accessible_get_parent;
8227 klass->ref_state_set = gtk_icon_view_item_accessible_ref_state_set;
8231 gtk_icon_view_item_accessible_get_type (void)
8233 static GType type = 0;
8237 const GTypeInfo tinfo =
8239 sizeof (GtkIconViewItemAccessibleClass),
8240 (GBaseInitFunc) NULL, /* base init */
8241 (GBaseFinalizeFunc) NULL, /* base finalize */
8242 (GClassInitFunc) gtk_icon_view_item_accessible_class_init, /* class init */
8243 (GClassFinalizeFunc) NULL, /* class finalize */
8244 NULL, /* class data */
8245 sizeof (GtkIconViewItemAccessible), /* instance size */
8246 0, /* nb preallocs */
8247 (GInstanceInitFunc) gtk_icon_view_item_accessible_object_init, /* instance init */
8248 NULL /* value table */
8251 const GInterfaceInfo atk_component_info =
8253 (GInterfaceInitFunc) atk_component_item_interface_init,
8254 (GInterfaceFinalizeFunc) NULL,
8257 const GInterfaceInfo atk_action_info =
8259 (GInterfaceInitFunc) atk_action_item_interface_init,
8260 (GInterfaceFinalizeFunc) NULL,
8263 const GInterfaceInfo atk_image_info =
8265 (GInterfaceInitFunc) atk_image_item_interface_init,
8266 (GInterfaceFinalizeFunc) NULL,
8269 const GInterfaceInfo atk_text_info =
8271 (GInterfaceInitFunc) atk_text_item_interface_init,
8272 (GInterfaceFinalizeFunc) NULL,
8276 type = g_type_register_static (ATK_TYPE_OBJECT,
8277 I_("GtkIconViewItemAccessible"), &tinfo, 0);
8278 g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
8279 &atk_component_info);
8280 g_type_add_interface_static (type, ATK_TYPE_ACTION,
8282 g_type_add_interface_static (type, ATK_TYPE_IMAGE,
8284 g_type_add_interface_static (type, ATK_TYPE_TEXT,
8291 #define GTK_TYPE_ICON_VIEW_ACCESSIBLE (gtk_icon_view_accessible_get_type ())
8292 #define GTK_ICON_VIEW_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ICON_VIEW_ACCESSIBLE, GtkIconViewAccessible))
8293 #define GTK_IS_ICON_VIEW_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ICON_VIEW_ACCESSIBLE))
8295 static GType gtk_icon_view_accessible_get_type (void);
8300 } GtkIconViewAccessible;
8306 } GtkIconViewItemAccessibleInfo;
8312 GtkAdjustment *old_hadj;
8313 GtkAdjustment *old_vadj;
8315 GtkTreeModel *model;
8317 } GtkIconViewAccessiblePrivate;
8319 static GtkIconViewAccessiblePrivate *
8320 gtk_icon_view_accessible_get_priv (AtkObject *accessible)
8322 return g_object_get_qdata (G_OBJECT (accessible),
8323 accessible_private_data_quark);
8327 gtk_icon_view_item_accessible_info_new (AtkObject *accessible,
8331 GtkIconViewItemAccessibleInfo *info;
8332 GtkIconViewItemAccessibleInfo *tmp_info;
8333 GtkIconViewAccessiblePrivate *priv;
8336 info = g_new (GtkIconViewItemAccessibleInfo, 1);
8338 info->index = index;
8340 priv = gtk_icon_view_accessible_get_priv (accessible);
8341 items = priv->items;
8344 tmp_info = items->data;
8345 if (tmp_info->index > index)
8347 items = items->next;
8349 priv->items = g_list_insert_before (priv->items, items, info);
8350 priv->old_hadj = NULL;
8351 priv->old_vadj = NULL;
8355 gtk_icon_view_accessible_get_n_children (AtkObject *accessible)
8357 GtkIconView *icon_view;
8360 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8364 icon_view = GTK_ICON_VIEW (widget);
8366 return g_list_length (icon_view->priv->items);
8370 gtk_icon_view_accessible_find_child (AtkObject *accessible,
8373 GtkIconViewAccessiblePrivate *priv;
8374 GtkIconViewItemAccessibleInfo *info;
8377 priv = gtk_icon_view_accessible_get_priv (accessible);
8378 items = priv->items;
8383 if (info->index == index)
8385 items = items->next;
8391 gtk_icon_view_accessible_ref_child (AtkObject *accessible,
8394 GtkIconView *icon_view;
8398 GtkIconViewItemAccessible *a11y_item;
8400 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8404 icon_view = GTK_ICON_VIEW (widget);
8405 icons = g_list_nth (icon_view->priv->items, index);
8409 GtkIconViewItem *item = icons->data;
8411 g_return_val_if_fail (item->index == index, NULL);
8412 obj = gtk_icon_view_accessible_find_child (accessible, index);
8417 obj = g_object_new (gtk_icon_view_item_accessible_get_type (), NULL);
8418 gtk_icon_view_item_accessible_info_new (accessible,
8421 obj->role = ATK_ROLE_ICON;
8422 a11y_item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8423 a11y_item->item = item;
8424 a11y_item->widget = widget;
8425 a11y_item->text_buffer = gtk_text_buffer_new (NULL);
8427 text = get_text (icon_view, item);
8430 gtk_text_buffer_set_text (a11y_item->text_buffer, text, -1);
8434 gtk_icon_view_item_accessible_set_visibility (a11y_item, FALSE);
8435 g_object_add_weak_pointer (G_OBJECT (widget), (gpointer) &(a11y_item->widget));
8443 gtk_icon_view_accessible_traverse_items (GtkIconViewAccessible *view,
8446 GtkIconViewAccessiblePrivate *priv;
8447 GtkIconViewItemAccessibleInfo *info;
8448 GtkIconViewItemAccessible *item;
8451 priv = gtk_icon_view_accessible_get_priv (ATK_OBJECT (view));
8455 gboolean act_on_item;
8457 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (view));
8461 items = priv->items;
8463 act_on_item = (list == NULL);
8468 info = (GtkIconViewItemAccessibleInfo *)items->data;
8469 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
8471 if (act_on_item == FALSE && list == items)
8475 gtk_icon_view_item_accessible_set_visibility (item, TRUE);
8477 items = items->next;
8483 gtk_icon_view_accessible_adjustment_changed (GtkAdjustment *adjustment,
8484 GtkIconViewAccessible *view)
8486 gtk_icon_view_accessible_traverse_items (view, NULL);
8490 gtk_icon_view_accessible_set_adjustment (AtkObject *accessible,
8491 GtkOrientation orientation,
8492 GtkAdjustment *adjustment)
8494 GtkIconViewAccessiblePrivate *priv;
8495 GtkAdjustment **old_adj_ptr;
8497 priv = gtk_icon_view_accessible_get_priv (accessible);
8499 /* Adjustments are set for the first time in constructor and priv is not
8500 * initialized at that time, so skip this first setting. */
8504 if (orientation == GTK_ORIENTATION_HORIZONTAL)
8506 if (priv->old_hadj == adjustment)
8509 old_adj_ptr = &priv->old_hadj;
8513 if (priv->old_vadj == adjustment)
8516 old_adj_ptr = &priv->old_vadj;
8519 /* Disconnect signal handlers */
8522 g_object_remove_weak_pointer (G_OBJECT (*old_adj_ptr),
8523 (gpointer *)&priv->old_hadj);
8524 g_signal_handlers_disconnect_by_func (*old_adj_ptr,
8525 gtk_icon_view_accessible_adjustment_changed,
8529 /* Connect signal */
8530 *old_adj_ptr = adjustment;
8531 g_object_add_weak_pointer (G_OBJECT (adjustment), (gpointer *)old_adj_ptr);
8532 g_signal_connect (adjustment, "value-changed",
8533 G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
8538 gtk_icon_view_accessible_model_row_changed (GtkTreeModel *tree_model,
8546 GtkIconView *icon_view;
8547 GtkIconViewItem *item;
8548 GtkIconViewItemAccessible *a11y_item;
8552 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
8553 index = gtk_tree_path_get_indices(path)[0];
8554 a11y_item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (
8555 gtk_icon_view_accessible_find_child (atk_obj, index));
8559 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_obj));
8560 icon_view = GTK_ICON_VIEW (widget);
8561 item = a11y_item->item;
8563 name = gtk_icon_view_item_accessible_get_name (ATK_OBJECT (a11y_item));
8565 if (!name || strcmp (name, "") == 0)
8567 text = get_text (icon_view, item);
8570 gtk_text_buffer_set_text (a11y_item->text_buffer, text, -1);
8576 g_signal_emit_by_name (atk_obj, "visible-data-changed");
8582 gtk_icon_view_accessible_model_row_inserted (GtkTreeModel *tree_model,
8587 GtkIconViewAccessiblePrivate *priv;
8588 GtkIconViewItemAccessibleInfo *info;
8589 GtkIconViewAccessible *view;
8590 GtkIconViewItemAccessible *item;
8596 index = gtk_tree_path_get_indices(path)[0];
8597 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
8598 view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
8599 priv = gtk_icon_view_accessible_get_priv (atk_obj);
8601 items = priv->items;
8606 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
8607 if (info->index != item->item->index)
8609 if (info->index < index)
8610 g_warning ("Unexpected index value on insertion %d %d", index, info->index);
8612 if (tmp_list == NULL)
8615 info->index = item->item->index;
8618 items = items->next;
8620 gtk_icon_view_accessible_traverse_items (view, tmp_list);
8621 g_signal_emit_by_name (atk_obj, "children-changed::add",
8627 gtk_icon_view_accessible_model_row_deleted (GtkTreeModel *tree_model,
8631 GtkIconViewAccessiblePrivate *priv;
8632 GtkIconViewItemAccessibleInfo *info;
8633 GtkIconViewAccessible *view;
8634 GtkIconViewItemAccessible *item;
8637 GList *deleted_item;
8641 index = gtk_tree_path_get_indices(path)[0];
8642 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
8643 view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
8644 priv = gtk_icon_view_accessible_get_priv (atk_obj);
8646 items = priv->items;
8648 deleted_item = NULL;
8653 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
8654 if (info->index == index)
8656 deleted_item = items;
8658 if (info->index != item->item->index)
8660 if (tmp_list == NULL)
8663 info->index = item->item->index;
8666 items = items->next;
8668 gtk_icon_view_accessible_traverse_items (view, tmp_list);
8671 info = deleted_item->data;
8672 gtk_icon_view_item_accessible_add_state (GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item), ATK_STATE_DEFUNCT, TRUE);
8673 g_signal_emit_by_name (atk_obj, "children-changed::remove",
8675 priv->items = g_list_remove_link (priv->items, deleted_item);
8683 gtk_icon_view_accessible_item_compare (GtkIconViewItemAccessibleInfo *i1,
8684 GtkIconViewItemAccessibleInfo *i2)
8686 return i1->index - i2->index;
8690 gtk_icon_view_accessible_model_rows_reordered (GtkTreeModel *tree_model,
8696 GtkIconViewAccessiblePrivate *priv;
8697 GtkIconViewItemAccessibleInfo *info;
8698 GtkIconView *icon_view;
8699 GtkIconViewItemAccessible *item;
8705 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
8706 icon_view = GTK_ICON_VIEW (user_data);
8707 priv = gtk_icon_view_accessible_get_priv (atk_obj);
8709 length = gtk_tree_model_iter_n_children (tree_model, NULL);
8711 order = g_new (gint, length);
8712 for (i = 0; i < length; i++)
8713 order [new_order[i]] = i;
8715 items = priv->items;
8719 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
8720 info->index = order[info->index];
8721 item->item = g_list_nth_data (icon_view->priv->items, info->index);
8722 items = items->next;
8725 priv->items = g_list_sort (priv->items,
8726 (GCompareFunc)gtk_icon_view_accessible_item_compare);
8732 gtk_icon_view_accessible_disconnect_model_signals (GtkTreeModel *model,
8737 obj = G_OBJECT (model);
8738 g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_changed, widget);
8739 g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_inserted, widget);
8740 g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_deleted, widget);
8741 g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_rows_reordered, widget);
8745 gtk_icon_view_accessible_connect_model_signals (GtkIconView *icon_view)
8749 obj = G_OBJECT (icon_view->priv->model);
8750 g_signal_connect_data (obj, "row-changed",
8751 (GCallback) gtk_icon_view_accessible_model_row_changed,
8752 icon_view, NULL, 0);
8753 g_signal_connect_data (obj, "row-inserted",
8754 (GCallback) gtk_icon_view_accessible_model_row_inserted,
8755 icon_view, NULL, G_CONNECT_AFTER);
8756 g_signal_connect_data (obj, "row-deleted",
8757 (GCallback) gtk_icon_view_accessible_model_row_deleted,
8758 icon_view, NULL, G_CONNECT_AFTER);
8759 g_signal_connect_data (obj, "rows-reordered",
8760 (GCallback) gtk_icon_view_accessible_model_rows_reordered,
8761 icon_view, NULL, G_CONNECT_AFTER);
8765 gtk_icon_view_accessible_clear_cache (GtkIconViewAccessiblePrivate *priv)
8767 GtkIconViewItemAccessibleInfo *info;
8770 items = priv->items;
8773 info = (GtkIconViewItemAccessibleInfo *) items->data;
8774 g_object_unref (info->item);
8775 g_free (items->data);
8776 items = items->next;
8778 g_list_free (priv->items);
8783 gtk_icon_view_accessible_notify_gtk (GObject *obj,
8786 GtkIconView *icon_view;
8789 GtkIconViewAccessiblePrivate *priv;
8791 if (strcmp (pspec->name, "model") == 0)
8793 widget = GTK_WIDGET (obj);
8794 atk_obj = gtk_widget_get_accessible (widget);
8795 priv = gtk_icon_view_accessible_get_priv (atk_obj);
8798 g_object_remove_weak_pointer (G_OBJECT (priv->model),
8799 (gpointer *)&priv->model);
8800 gtk_icon_view_accessible_disconnect_model_signals (priv->model, widget);
8802 gtk_icon_view_accessible_clear_cache (priv);
8804 icon_view = GTK_ICON_VIEW (obj);
8805 priv->model = icon_view->priv->model;
8806 /* If there is no model the GtkIconView is probably being destroyed */
8809 g_object_add_weak_pointer (G_OBJECT (priv->model), (gpointer *)&priv->model);
8810 gtk_icon_view_accessible_connect_model_signals (icon_view);
8818 gtk_icon_view_accessible_initialize (AtkObject *accessible,
8821 GtkIconViewAccessiblePrivate *priv;
8822 GtkIconView *icon_view;
8824 if (ATK_OBJECT_CLASS (accessible_parent_class)->initialize)
8825 ATK_OBJECT_CLASS (accessible_parent_class)->initialize (accessible, data);
8827 priv = g_new0 (GtkIconViewAccessiblePrivate, 1);
8828 g_object_set_qdata (G_OBJECT (accessible),
8829 accessible_private_data_quark,
8832 icon_view = GTK_ICON_VIEW (data);
8833 if (icon_view->priv->hadjustment)
8834 gtk_icon_view_accessible_set_adjustment (accessible,
8835 GTK_ORIENTATION_HORIZONTAL,
8836 icon_view->priv->hadjustment);
8837 if (icon_view->priv->vadjustment)
8838 gtk_icon_view_accessible_set_adjustment (accessible,
8839 GTK_ORIENTATION_VERTICAL,
8840 icon_view->priv->vadjustment);
8841 g_signal_connect (data,
8843 G_CALLBACK (gtk_icon_view_accessible_notify_gtk),
8846 priv->model = icon_view->priv->model;
8849 g_object_add_weak_pointer (G_OBJECT (priv->model), (gpointer *)&priv->model);
8850 gtk_icon_view_accessible_connect_model_signals (icon_view);
8853 accessible->role = ATK_ROLE_LAYERED_PANE;
8857 gtk_icon_view_accessible_finalize (GObject *object)
8859 GtkIconViewAccessiblePrivate *priv;
8861 priv = gtk_icon_view_accessible_get_priv (ATK_OBJECT (object));
8862 gtk_icon_view_accessible_clear_cache (priv);
8866 G_OBJECT_CLASS (accessible_parent_class)->finalize (object);
8870 gtk_icon_view_accessible_destroyed (GtkWidget *widget,
8871 GtkAccessible *accessible)
8874 GtkIconViewAccessiblePrivate *priv;
8876 atk_obj = ATK_OBJECT (accessible);
8877 priv = gtk_icon_view_accessible_get_priv (atk_obj);
8880 g_object_remove_weak_pointer (G_OBJECT (priv->old_hadj),
8881 (gpointer *)&priv->old_hadj);
8883 g_signal_handlers_disconnect_by_func (priv->old_hadj,
8884 (gpointer) gtk_icon_view_accessible_adjustment_changed,
8886 priv->old_hadj = NULL;
8890 g_object_remove_weak_pointer (G_OBJECT (priv->old_vadj),
8891 (gpointer *)&priv->old_vadj);
8893 g_signal_handlers_disconnect_by_func (priv->old_vadj,
8894 (gpointer) gtk_icon_view_accessible_adjustment_changed,
8896 priv->old_vadj = NULL;
8901 gtk_icon_view_accessible_connect_widget_destroyed (GtkAccessible *accessible)
8905 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8908 g_signal_connect_after (widget,
8910 G_CALLBACK (gtk_icon_view_accessible_destroyed),
8913 GTK_ACCESSIBLE_CLASS (accessible_parent_class)->connect_widget_destroyed (accessible);
8917 gtk_icon_view_accessible_class_init (AtkObjectClass *klass)
8919 GObjectClass *gobject_class;
8920 GtkAccessibleClass *accessible_class;
8922 accessible_parent_class = g_type_class_peek_parent (klass);
8924 gobject_class = (GObjectClass *)klass;
8925 accessible_class = (GtkAccessibleClass *)klass;
8927 gobject_class->finalize = gtk_icon_view_accessible_finalize;
8929 klass->get_n_children = gtk_icon_view_accessible_get_n_children;
8930 klass->ref_child = gtk_icon_view_accessible_ref_child;
8931 klass->initialize = gtk_icon_view_accessible_initialize;
8933 accessible_class->connect_widget_destroyed = gtk_icon_view_accessible_connect_widget_destroyed;
8935 accessible_private_data_quark = g_quark_from_static_string ("icon_view-accessible-private-data");
8939 gtk_icon_view_accessible_ref_accessible_at_point (AtkComponent *component,
8942 AtkCoordType coord_type)
8945 GtkIconView *icon_view;
8946 GtkIconViewItem *item;
8949 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
8951 /* State is defunct */
8954 icon_view = GTK_ICON_VIEW (widget);
8955 atk_component_get_extents (component, &x_pos, &y_pos, NULL, NULL, coord_type);
8956 item = gtk_icon_view_get_item_at_coords (icon_view, x - x_pos, y - y_pos, TRUE, NULL);
8958 return gtk_icon_view_accessible_ref_child (ATK_OBJECT (component), item->index);
8964 atk_component_interface_init (AtkComponentIface *iface)
8966 iface->ref_accessible_at_point = gtk_icon_view_accessible_ref_accessible_at_point;
8970 gtk_icon_view_accessible_add_selection (AtkSelection *selection,
8974 GtkIconView *icon_view;
8975 GtkIconViewItem *item;
8977 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
8981 icon_view = GTK_ICON_VIEW (widget);
8983 item = g_list_nth_data (icon_view->priv->items, i);
8988 gtk_icon_view_select_item (icon_view, item);
8994 gtk_icon_view_accessible_clear_selection (AtkSelection *selection)
8997 GtkIconView *icon_view;
8999 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9003 icon_view = GTK_ICON_VIEW (widget);
9004 gtk_icon_view_unselect_all (icon_view);
9010 gtk_icon_view_accessible_ref_selection (AtkSelection *selection,
9015 GtkIconView *icon_view;
9016 GtkIconViewItem *item;
9018 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9022 icon_view = GTK_ICON_VIEW (widget);
9024 l = icon_view->priv->items;
9031 return atk_object_ref_accessible_child (gtk_widget_get_accessible (widget), item->index);
9042 gtk_icon_view_accessible_get_selection_count (AtkSelection *selection)
9045 GtkIconView *icon_view;
9046 GtkIconViewItem *item;
9050 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9054 icon_view = GTK_ICON_VIEW (widget);
9056 l = icon_view->priv->items;
9072 gtk_icon_view_accessible_is_child_selected (AtkSelection *selection,
9076 GtkIconView *icon_view;
9077 GtkIconViewItem *item;
9079 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9083 icon_view = GTK_ICON_VIEW (widget);
9085 item = g_list_nth_data (icon_view->priv->items, i);
9089 return item->selected;
9093 gtk_icon_view_accessible_remove_selection (AtkSelection *selection,
9097 GtkIconView *icon_view;
9098 GtkIconViewItem *item;
9102 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9106 icon_view = GTK_ICON_VIEW (widget);
9107 l = icon_view->priv->items;
9116 gtk_icon_view_unselect_item (icon_view, item);
9128 gtk_icon_view_accessible_select_all_selection (AtkSelection *selection)
9131 GtkIconView *icon_view;
9133 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9137 icon_view = GTK_ICON_VIEW (widget);
9138 gtk_icon_view_select_all (icon_view);
9143 gtk_icon_view_accessible_selection_interface_init (AtkSelectionIface *iface)
9145 iface->add_selection = gtk_icon_view_accessible_add_selection;
9146 iface->clear_selection = gtk_icon_view_accessible_clear_selection;
9147 iface->ref_selection = gtk_icon_view_accessible_ref_selection;
9148 iface->get_selection_count = gtk_icon_view_accessible_get_selection_count;
9149 iface->is_child_selected = gtk_icon_view_accessible_is_child_selected;
9150 iface->remove_selection = gtk_icon_view_accessible_remove_selection;
9151 iface->select_all_selection = gtk_icon_view_accessible_select_all_selection;
9155 gtk_icon_view_accessible_get_type (void)
9157 static GType type = 0;
9164 (GBaseInitFunc) NULL, /* base init */
9165 (GBaseFinalizeFunc) NULL, /* base finalize */
9166 (GClassInitFunc) gtk_icon_view_accessible_class_init,
9167 (GClassFinalizeFunc) NULL, /* class finalize */
9168 NULL, /* class data */
9169 0, /* instance size */
9170 0, /* nb preallocs */
9171 (GInstanceInitFunc) NULL, /* instance init */
9172 NULL /* value table */
9174 const GInterfaceInfo atk_component_info =
9176 (GInterfaceInitFunc) atk_component_interface_init,
9177 (GInterfaceFinalizeFunc) NULL,
9180 const GInterfaceInfo atk_selection_info =
9182 (GInterfaceInitFunc) gtk_icon_view_accessible_selection_interface_init,
9183 (GInterfaceFinalizeFunc) NULL,
9188 * Figure out the size of the class and instance
9189 * we are deriving from
9191 AtkObjectFactory *factory;
9194 GType derived_atk_type;
9196 derived_type = g_type_parent (GTK_TYPE_ICON_VIEW);
9197 factory = atk_registry_get_factory (atk_get_default_registry (),
9199 derived_atk_type = atk_object_factory_get_accessible_type (factory);
9200 g_type_query (derived_atk_type, &query);
9201 tinfo.class_size = query.class_size;
9202 tinfo.instance_size = query.instance_size;
9204 type = g_type_register_static (derived_atk_type,
9205 I_("GtkIconViewAccessible"),
9207 g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
9208 &atk_component_info);
9209 g_type_add_interface_static (type, ATK_TYPE_SELECTION,
9210 &atk_selection_info);
9216 gtk_icon_view_accessible_new (GObject *obj)
9218 AtkObject *accessible;
9220 g_return_val_if_fail (GTK_IS_WIDGET (obj), NULL);
9222 accessible = g_object_new (gtk_icon_view_accessible_get_type (), NULL);
9223 atk_object_initialize (accessible, obj);
9229 gtk_icon_view_accessible_factory_get_accessible_type (void)
9231 return gtk_icon_view_accessible_get_type ();
9235 gtk_icon_view_accessible_factory_create_accessible (GObject *obj)
9237 return gtk_icon_view_accessible_new (obj);
9241 gtk_icon_view_accessible_factory_class_init (AtkObjectFactoryClass *klass)
9243 klass->create_accessible = gtk_icon_view_accessible_factory_create_accessible;
9244 klass->get_accessible_type = gtk_icon_view_accessible_factory_get_accessible_type;
9248 gtk_icon_view_accessible_factory_get_type (void)
9250 static GType type = 0;
9254 const GTypeInfo tinfo =
9256 sizeof (AtkObjectFactoryClass),
9257 NULL, /* base_init */
9258 NULL, /* base_finalize */
9259 (GClassInitFunc) gtk_icon_view_accessible_factory_class_init,
9260 NULL, /* class_finalize */
9261 NULL, /* class_data */
9262 sizeof (AtkObjectFactory),
9263 0, /* n_preallocs */
9267 type = g_type_register_static (ATK_TYPE_OBJECT_FACTORY,
9268 I_("GtkIconViewAccessibleFactory"),
9276 gtk_icon_view_get_accessible (GtkWidget *widget)
9278 static gboolean first_time = TRUE;
9282 AtkObjectFactory *factory;
9283 AtkRegistry *registry;
9285 GType derived_atk_type;
9288 * Figure out whether accessibility is enabled by looking at the
9289 * type of the accessible object which would be created for
9290 * the parent type of GtkIconView.
9292 derived_type = g_type_parent (GTK_TYPE_ICON_VIEW);
9294 registry = atk_get_default_registry ();
9295 factory = atk_registry_get_factory (registry,
9297 derived_atk_type = atk_object_factory_get_accessible_type (factory);
9298 if (g_type_is_a (derived_atk_type, GTK_TYPE_ACCESSIBLE))
9299 atk_registry_set_factory_type (registry,
9301 gtk_icon_view_accessible_factory_get_type ());
9304 return GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->get_accessible (widget);
9308 gtk_icon_view_buildable_custom_tag_start (GtkBuildable *buildable,
9309 GtkBuilder *builder,
9311 const gchar *tagname,
9312 GMarkupParser *parser,
9315 if (parent_buildable_iface->custom_tag_start (buildable, builder, child,
9316 tagname, parser, data))
9319 return _gtk_cell_layout_buildable_custom_tag_start (buildable, builder, child,
9320 tagname, parser, data);
9324 gtk_icon_view_buildable_custom_tag_end (GtkBuildable *buildable,
9325 GtkBuilder *builder,
9327 const gchar *tagname,
9330 if (!_gtk_cell_layout_buildable_custom_tag_end (buildable, builder,
9331 child, tagname, data))
9332 parent_buildable_iface->custom_tag_end (buildable, builder, child, tagname,