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.
25 #include <gdk/gdkkeysyms.h>
28 #include "gtkiconview.h"
29 #include "gtkmarshalers.h"
30 #include "gtkbindings.h"
33 #include "gtksignal.h"
35 #include "gtkaccessible.h"
36 #include "gtkwindow.h"
37 #include "gtktextbuffer.h"
39 #undef DEBUG_ICON_VIEW
41 #define ICON_TEXT_PADDING 3
43 #define GTK_ICON_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ICON_VIEW, GtkIconViewPrivate))
44 #define VALID_MODEL_AND_COLUMNS(obj) ((obj)->priv->model != NULL && \
45 ((obj)->priv->pixbuf_column != -1 || \
46 (obj)->priv->text_column != -1 || \
47 (obj)->priv->markup_column != -1))
60 gint pixbuf_x, pixbuf_y;
61 gint pixbuf_height, pixbuf_width;
63 gint layout_x, layout_y;
64 gint layout_width, layout_height;
67 guint selected_before_rubberbanding : 1;
70 struct _GtkIconViewPrivate
78 GtkSelectionMode selection_mode;
80 GdkWindow *bin_window;
86 GtkAdjustment *hadjustment;
87 GtkAdjustment *vadjustment;
91 gboolean doing_rubberband;
92 gint rubberband_x1, rubberband_y1;
93 gint rubberband_x2, rubberband_y2;
95 guint scroll_timeout_id;
96 gint scroll_value_diff;
97 gint event_last_x, event_last_y;
99 GtkIconViewItem *anchor_item;
100 GtkIconViewItem *cursor_item;
102 guint ctrl_pressed : 1;
103 guint shift_pressed : 1;
105 GtkIconViewItem *last_single_clicked;
114 /* Layout used to draw icon text */
117 GtkOrientation orientation;
137 ACTIVATE_CURSOR_ITEM,
159 /* GObject signals */
160 static void gtk_icon_view_finalize (GObject *object);
161 static void gtk_icon_view_set_property (GObject *object,
165 static void gtk_icon_view_get_property (GObject *object,
171 /* GtkObject signals */
172 static void gtk_icon_view_destroy (GtkObject *object);
174 /* GtkWidget signals */
175 static void gtk_icon_view_realize (GtkWidget *widget);
176 static void gtk_icon_view_unrealize (GtkWidget *widget);
177 static void gtk_icon_view_map (GtkWidget *widget);
178 static void gtk_icon_view_size_request (GtkWidget *widget,
179 GtkRequisition *requisition);
180 static void gtk_icon_view_size_allocate (GtkWidget *widget,
181 GtkAllocation *allocation);
182 static gboolean gtk_icon_view_expose (GtkWidget *widget,
183 GdkEventExpose *expose);
184 static gboolean gtk_icon_view_motion (GtkWidget *widget,
185 GdkEventMotion *event);
186 static gboolean gtk_icon_view_button_press (GtkWidget *widget,
187 GdkEventButton *event);
188 static gboolean gtk_icon_view_button_release (GtkWidget *widget,
189 GdkEventButton *event);
190 /* GtkIconView signals */
191 static void gtk_icon_view_set_adjustments (GtkIconView *icon_view,
193 GtkAdjustment *vadj);
194 static void gtk_icon_view_real_select_all (GtkIconView *icon_view);
195 static void gtk_icon_view_real_unselect_all (GtkIconView *icon_view);
196 static void gtk_icon_view_real_select_cursor_item (GtkIconView *icon_view);
197 static void gtk_icon_view_real_toggle_cursor_item (GtkIconView *icon_view);
198 static gboolean gtk_icon_view_real_activate_cursor_item (GtkIconView *icon_view);
200 /* Internal functions */
201 static void gtk_icon_view_adjustment_changed (GtkAdjustment *adjustment,
202 GtkIconView *icon_view);
203 static void gtk_icon_view_layout (GtkIconView *icon_view);
204 static void gtk_icon_view_paint_item (GtkIconView *icon_view,
205 GtkIconViewItem *item,
207 static void gtk_icon_view_paint_rubberband (GtkIconView *icon_view,
209 static void gtk_icon_view_queue_draw_item (GtkIconView *icon_view,
210 GtkIconViewItem *item);
211 static void gtk_icon_view_queue_layout (GtkIconView *icon_view);
212 static void gtk_icon_view_set_cursor_item (GtkIconView *icon_view,
213 GtkIconViewItem *item);
214 static void gtk_icon_view_start_rubberbanding (GtkIconView *icon_view,
217 static void gtk_icon_view_stop_rubberbanding (GtkIconView *icon_view);
218 static void gtk_icon_view_update_rubberband_selection (GtkIconView *icon_view);
219 static gboolean gtk_icon_view_item_hit_test (GtkIconViewItem *item,
225 static gboolean gtk_icon_view_maybe_begin_dragging_items (GtkIconView *icon_view,
226 GdkEventMotion *event);
228 static gboolean gtk_icon_view_unselect_all_internal (GtkIconView *icon_view);
229 static void gtk_icon_view_calculate_item_size (GtkIconView *icon_view,
230 GtkIconViewItem *item,
232 static void gtk_icon_view_update_rubberband (gpointer data);
233 static void gtk_icon_view_item_invalidate_size (GtkIconViewItem *item);
234 static void gtk_icon_view_invalidate_sizes (GtkIconView *icon_view);
235 static void gtk_icon_view_add_move_binding (GtkBindingSet *binding_set,
238 GtkMovementStep step,
240 static gboolean gtk_icon_view_real_move_cursor (GtkIconView *icon_view,
241 GtkMovementStep step,
243 static void gtk_icon_view_move_cursor_up_down (GtkIconView *icon_view,
245 static void gtk_icon_view_move_cursor_page_up_down (GtkIconView *icon_view,
247 static void gtk_icon_view_move_cursor_left_right (GtkIconView *icon_view,
249 static void gtk_icon_view_move_cursor_start_end (GtkIconView *icon_view,
251 static void gtk_icon_view_scroll_to_item (GtkIconView *icon_view,
252 GtkIconViewItem *item);
253 static GdkPixbuf *gtk_icon_view_get_item_icon (GtkIconView *icon_view,
254 GtkIconViewItem *item);
255 static void gtk_icon_view_update_item_text (GtkIconView *icon_view,
256 GtkIconViewItem *item);
257 static void gtk_icon_view_select_item (GtkIconView *icon_view,
258 GtkIconViewItem *item);
259 static void gtk_icon_view_unselect_item (GtkIconView *icon_view,
260 GtkIconViewItem *item);
261 static gboolean gtk_icon_view_select_all_between (GtkIconView *icon_view,
262 GtkIconViewItem *anchor,
263 GtkIconViewItem *cursor);
265 static GtkIconViewItem *gtk_icon_view_get_item_at_pos (GtkIconView *icon_view,
270 /* Accessibility Support */
271 static AtkObject *gtk_icon_view_get_accessible (GtkWidget *widget);
273 static GtkContainerClass *parent_class = NULL;
274 static guint icon_view_signals[LAST_SIGNAL] = { 0 };
276 G_DEFINE_TYPE (GtkIconView, gtk_icon_view, GTK_TYPE_CONTAINER);
279 gtk_icon_view_class_init (GtkIconViewClass *klass)
281 GObjectClass *gobject_class;
282 GtkObjectClass *object_class;
283 GtkWidgetClass *widget_class;
284 GtkBindingSet *binding_set;
286 parent_class = g_type_class_peek_parent (klass);
287 binding_set = gtk_binding_set_by_class (klass);
289 g_type_class_add_private (klass, sizeof (GtkIconViewPrivate));
291 gobject_class = (GObjectClass *) klass;
292 object_class = (GtkObjectClass *) klass;
293 widget_class = (GtkWidgetClass *) klass;
295 gobject_class->finalize = gtk_icon_view_finalize;
296 gobject_class->set_property = gtk_icon_view_set_property;
297 gobject_class->get_property = gtk_icon_view_get_property;
299 object_class->destroy = gtk_icon_view_destroy;
301 widget_class->realize = gtk_icon_view_realize;
302 widget_class->unrealize = gtk_icon_view_unrealize;
303 widget_class->map = gtk_icon_view_map;
304 widget_class->size_request = gtk_icon_view_size_request;
305 widget_class->size_allocate = gtk_icon_view_size_allocate;
306 widget_class->expose_event = gtk_icon_view_expose;
307 widget_class->motion_notify_event = gtk_icon_view_motion;
308 widget_class->button_press_event = gtk_icon_view_button_press;
309 widget_class->button_release_event = gtk_icon_view_button_release;
310 widget_class->get_accessible = gtk_icon_view_get_accessible;
312 klass->set_scroll_adjustments = gtk_icon_view_set_adjustments;
313 klass->select_all = gtk_icon_view_real_select_all;
314 klass->unselect_all = gtk_icon_view_real_unselect_all;
315 klass->select_cursor_item = gtk_icon_view_real_select_cursor_item;
316 klass->toggle_cursor_item = gtk_icon_view_real_toggle_cursor_item;
317 klass->activate_cursor_item = gtk_icon_view_real_activate_cursor_item;
318 klass->move_cursor = gtk_icon_view_real_move_cursor;
322 * GtkIconView:selection-mode:
324 * The ::selection-mode property specifies the selection mode of
325 * icon view. If the mode is #GTK_SELECTION_MULTIPLE, rubberband selection
326 * is enabled, for the other modes, only keyboard selection is possible.
330 g_object_class_install_property (gobject_class,
332 g_param_spec_enum ("selection_mode",
333 P_("Selection mode"),
334 P_("The selection mode"),
335 GTK_TYPE_SELECTION_MODE,
336 GTK_SELECTION_SINGLE,
340 * GtkIconView:pixbuf-column:
342 * The ::pixbuf-column property contains the number of the model column
343 * containing the pixbufs which are displayed. The pixbuf column must be
344 * of type #GDK_TYPE_PIXBUF. Setting this property to -1 turns off the
345 * display of pixbufs.
349 g_object_class_install_property (gobject_class,
351 g_param_spec_int ("pixbuf_column",
353 P_("Model column used to retrieve the icon pixbuf from"),
358 * GtkIconView:text-column:
360 * The ::text-column property contains the number of the model column
361 * containing the texts which are displayed. The text column must be
362 * of type #G_TYPE_STRING. If this property and the :markup-column
363 * property are both set to -1, no texts are displayed.
367 g_object_class_install_property (gobject_class,
369 g_param_spec_int ("text_column",
371 P_("Model column used to retrieve the text from"),
377 * GtkIconView:markup-column:
379 * The ::markup-column property contains the number of the model column
380 * containing markup information to be displayed. The markup column must be
381 * of type #G_TYPE_STRING. If this property and the :text-column property
382 * are both set to column numbers, it overrides the text column.
383 * If both are set to -1, no texts are displayed.
387 g_object_class_install_property (gobject_class,
389 g_param_spec_int ("markup_column",
391 P_("Model column used to retrieve the text if using Pango markup"),
395 g_object_class_install_property (gobject_class,
397 g_param_spec_object ("model",
398 P_("Icon View Model"),
399 P_("The model for the icon view"),
404 * GtkIconView:columns:
406 * The columns property contains the number of the columns in which the
407 * items should be displayed. If it is -1, the number of columns will
408 * be chosen automatically to fill the available area.
412 g_object_class_install_property (gobject_class,
414 g_param_spec_int ("columns",
415 P_("Number of columns"),
416 P_("Number of columns to display"),
422 * GtkIconView::item-width:
424 * The item-width property specifies the width to use for each item.
425 * If it is set to -1, the icon view will automatically determine a
426 * suitable item size.
430 g_object_class_install_property (gobject_class,
432 g_param_spec_int ("item_width",
433 P_("Width for each item"),
434 P_("The width used for each item"),
439 * GtkIconView::spacing:
441 * The spacing property specifies the space which is inserted between
442 * the cells (i.e. the icon and the text) of an item.
446 g_object_class_install_property (gobject_class,
448 g_param_spec_int ("spacing",
450 P_("Space which is inserted between cells of an item"),
455 * GtkIconView::row-spacing:
457 * The row-spacing property specifies the space which is inserted between
458 * the rows of the icon view.
462 g_object_class_install_property (gobject_class,
464 g_param_spec_int ("row_spacing",
466 P_("Space which is inserted between grid rows"),
471 * GtkIconView::column-spacing:
473 * The column-spacing property specifies the space which is inserted between
474 * the columns of the icon view.
478 g_object_class_install_property (gobject_class,
480 g_param_spec_int ("column_spacing",
481 P_("Column Spacing"),
482 P_("Space which is inserted between grid column"),
487 * GtkIconView::margin:
489 * The margin property specifies the space which is inserted
490 * at the edges of the icon view.
494 g_object_class_install_property (gobject_class,
496 g_param_spec_int ("margin",
498 P_("Space which is inserted at the edges of the icon view"),
504 * GtkIconView::orientation:
506 * The orientation property specifies how the cells (i.e. the icon and
507 * the text) of the item are positioned relative to each other.
511 g_object_class_install_property (gobject_class,
513 g_param_spec_enum ("orientation",
515 P_("How the text and icon of each item are positioned relative to each other"),
516 GTK_TYPE_ORIENTATION,
517 GTK_ORIENTATION_VERTICAL,
520 /* Style properties */
521 gtk_widget_class_install_style_property (widget_class,
522 g_param_spec_boxed ("selection_box_color",
523 P_("Selection Box Color"),
524 P_("Color of the selection box"),
528 gtk_widget_class_install_style_property (widget_class,
529 g_param_spec_uchar ("selection_box_alpha",
530 P_("Selection Box Alpha"),
531 P_("Opacity of the selection box"),
537 widget_class->set_scroll_adjustments_signal =
538 g_signal_new ("set_scroll_adjustments",
539 G_TYPE_FROM_CLASS (gobject_class),
541 G_STRUCT_OFFSET (GtkIconViewClass, set_scroll_adjustments),
543 _gtk_marshal_VOID__OBJECT_OBJECT,
545 GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
547 icon_view_signals[ITEM_ACTIVATED] =
548 g_signal_new ("item_activated",
549 G_TYPE_FROM_CLASS (gobject_class),
551 G_STRUCT_OFFSET (GtkIconViewClass, item_activated),
553 g_cclosure_marshal_VOID__BOXED,
557 icon_view_signals[SELECTION_CHANGED] =
558 g_signal_new ("selection_changed",
559 G_TYPE_FROM_CLASS (gobject_class),
561 G_STRUCT_OFFSET (GtkIconViewClass, selection_changed),
563 g_cclosure_marshal_VOID__VOID,
566 icon_view_signals[SELECT_ALL] =
567 g_signal_new ("select_all",
568 G_TYPE_FROM_CLASS (gobject_class),
569 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
570 G_STRUCT_OFFSET (GtkIconViewClass, select_all),
572 g_cclosure_marshal_VOID__VOID,
575 icon_view_signals[UNSELECT_ALL] =
576 g_signal_new ("unselect_all",
577 G_TYPE_FROM_CLASS (gobject_class),
578 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
579 G_STRUCT_OFFSET (GtkIconViewClass, unselect_all),
581 g_cclosure_marshal_VOID__VOID,
584 icon_view_signals[SELECT_CURSOR_ITEM] =
585 g_signal_new ("select_cursor_item",
586 G_TYPE_FROM_CLASS (gobject_class),
587 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
588 G_STRUCT_OFFSET (GtkIconViewClass, select_cursor_item),
590 g_cclosure_marshal_VOID__VOID,
593 icon_view_signals[TOGGLE_CURSOR_ITEM] =
594 g_signal_new ("toggle_cursor_item",
595 G_TYPE_FROM_CLASS (gobject_class),
596 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
597 G_STRUCT_OFFSET (GtkIconViewClass, toggle_cursor_item),
599 g_cclosure_marshal_VOID__VOID,
602 icon_view_signals[ACTIVATE_CURSOR_ITEM] =
603 g_signal_new ("activate_cursor_item",
604 G_TYPE_FROM_CLASS (gobject_class),
605 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
606 G_STRUCT_OFFSET (GtkIconViewClass, activate_cursor_item),
608 _gtk_marshal_BOOLEAN__VOID,
611 icon_view_signals[MOVE_CURSOR] =
612 g_signal_new ("move_cursor",
613 G_TYPE_FROM_CLASS (gobject_class),
614 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
615 G_STRUCT_OFFSET (GtkIconViewClass, move_cursor),
617 _gtk_marshal_BOOLEAN__ENUM_INT,
619 GTK_TYPE_MOVEMENT_STEP,
623 gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, "select_all", 0);
624 gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect_all", 0);
625 gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select_cursor_item", 0);
626 gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, "toggle_cursor_item", 0);
628 gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, "activate_cursor_item", 0);
629 gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0, "activate_cursor_item", 0);
630 gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, "activate_cursor_item", 0);
632 gtk_icon_view_add_move_binding (binding_set, GDK_Up, 0,
633 GTK_MOVEMENT_DISPLAY_LINES, -1);
634 gtk_icon_view_add_move_binding (binding_set, GDK_KP_Up, 0,
635 GTK_MOVEMENT_DISPLAY_LINES, -1);
637 gtk_icon_view_add_move_binding (binding_set, GDK_Down, 0,
638 GTK_MOVEMENT_DISPLAY_LINES, 1);
639 gtk_icon_view_add_move_binding (binding_set, GDK_KP_Down, 0,
640 GTK_MOVEMENT_DISPLAY_LINES, 1);
642 gtk_icon_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK,
643 GTK_MOVEMENT_DISPLAY_LINES, -1);
645 gtk_icon_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK,
646 GTK_MOVEMENT_DISPLAY_LINES, 1);
648 gtk_icon_view_add_move_binding (binding_set, GDK_Home, 0,
649 GTK_MOVEMENT_BUFFER_ENDS, -1);
650 gtk_icon_view_add_move_binding (binding_set, GDK_KP_Home, 0,
651 GTK_MOVEMENT_BUFFER_ENDS, -1);
653 gtk_icon_view_add_move_binding (binding_set, GDK_End, 0,
654 GTK_MOVEMENT_BUFFER_ENDS, 1);
655 gtk_icon_view_add_move_binding (binding_set, GDK_KP_End, 0,
656 GTK_MOVEMENT_BUFFER_ENDS, 1);
658 gtk_icon_view_add_move_binding (binding_set, GDK_Page_Up, 0,
659 GTK_MOVEMENT_PAGES, -1);
660 gtk_icon_view_add_move_binding (binding_set, GDK_KP_Page_Up, 0,
661 GTK_MOVEMENT_PAGES, -1);
663 gtk_icon_view_add_move_binding (binding_set, GDK_Page_Down, 0,
664 GTK_MOVEMENT_PAGES, 1);
665 gtk_icon_view_add_move_binding (binding_set, GDK_KP_Page_Down, 0,
666 GTK_MOVEMENT_PAGES, 1);
668 gtk_icon_view_add_move_binding (binding_set, GDK_Right, 0,
669 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
670 gtk_icon_view_add_move_binding (binding_set, GDK_Left, 0,
671 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
673 gtk_icon_view_add_move_binding (binding_set, GDK_KP_Right, 0,
674 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
675 gtk_icon_view_add_move_binding (binding_set, GDK_KP_Left, 0,
676 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
680 gtk_icon_view_init (GtkIconView *icon_view)
682 icon_view->priv = GTK_ICON_VIEW_GET_PRIVATE (icon_view);
684 icon_view->priv->width = 0;
685 icon_view->priv->height = 0;
686 icon_view->priv->selection_mode = GTK_SELECTION_SINGLE;
688 icon_view->priv->pressed_button = -1;
689 icon_view->priv->press_start_x = -1;
690 icon_view->priv->press_start_y = -1;
692 icon_view->priv->text_column = -1;
693 icon_view->priv->markup_column = -1;
694 icon_view->priv->pixbuf_column = -1;
696 icon_view->priv->layout = gtk_widget_create_pango_layout (GTK_WIDGET (icon_view), NULL);
698 pango_layout_set_wrap (icon_view->priv->layout, PANGO_WRAP_WORD_CHAR);
700 GTK_WIDGET_SET_FLAGS (icon_view, GTK_CAN_FOCUS);
702 gtk_icon_view_set_adjustments (icon_view, NULL, NULL);
704 icon_view->priv->orientation = GTK_ORIENTATION_VERTICAL;
706 icon_view->priv->columns = -1;
707 icon_view->priv->item_width = -1;
708 icon_view->priv->spacing = 0;
709 icon_view->priv->row_spacing = 6;
710 icon_view->priv->column_spacing = 6;
711 icon_view->priv->margin = 6;
715 gtk_icon_view_destroy (GtkObject *object)
717 GtkIconView *icon_view;
719 icon_view = GTK_ICON_VIEW (object);
721 gtk_icon_view_set_model (icon_view, NULL);
723 if (icon_view->priv->layout_idle_id != 0)
724 g_source_remove (icon_view->priv->layout_idle_id);
726 if (icon_view->priv->scroll_timeout_id != 0)
727 g_source_remove (icon_view->priv->scroll_timeout_id);
729 (GTK_OBJECT_CLASS (parent_class)->destroy) (object);
732 /* GObject methods */
734 gtk_icon_view_finalize (GObject *object)
736 GtkIconView *icon_view;
738 icon_view = GTK_ICON_VIEW (object);
740 g_object_unref (icon_view->priv->layout);
742 (G_OBJECT_CLASS (parent_class)->finalize) (object);
747 gtk_icon_view_set_property (GObject *object,
752 GtkIconView *icon_view;
754 icon_view = GTK_ICON_VIEW (object);
758 case PROP_SELECTION_MODE:
759 gtk_icon_view_set_selection_mode (icon_view, g_value_get_enum (value));
761 case PROP_PIXBUF_COLUMN:
762 gtk_icon_view_set_pixbuf_column (icon_view, g_value_get_int (value));
764 case PROP_TEXT_COLUMN:
765 gtk_icon_view_set_text_column (icon_view, g_value_get_int (value));
767 case PROP_MARKUP_COLUMN:
768 gtk_icon_view_set_markup_column (icon_view, g_value_get_int (value));
771 gtk_icon_view_set_model (icon_view, g_value_get_object (value));
773 case PROP_ORIENTATION:
774 gtk_icon_view_set_orientation (icon_view, g_value_get_enum (value));
777 gtk_icon_view_set_columns (icon_view, g_value_get_int (value));
779 case PROP_ITEM_WIDTH:
780 gtk_icon_view_set_item_width (icon_view, g_value_get_int (value));
783 gtk_icon_view_set_spacing (icon_view, g_value_get_int (value));
785 case PROP_ROW_SPACING:
786 gtk_icon_view_set_row_spacing (icon_view, g_value_get_int (value));
788 case PROP_COLUMN_SPACING:
789 gtk_icon_view_set_column_spacing (icon_view, g_value_get_int (value));
792 gtk_icon_view_set_margin (icon_view, g_value_get_int (value));
796 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
802 gtk_icon_view_get_property (GObject *object,
807 GtkIconView *icon_view;
809 icon_view = GTK_ICON_VIEW (object);
813 case PROP_SELECTION_MODE:
814 g_value_set_enum (value, icon_view->priv->selection_mode);
816 case PROP_PIXBUF_COLUMN:
817 g_value_set_int (value, icon_view->priv->pixbuf_column);
819 case PROP_TEXT_COLUMN:
820 g_value_set_int (value, icon_view->priv->text_column);
822 case PROP_MARKUP_COLUMN:
823 g_value_set_int (value, icon_view->priv->markup_column);
826 g_value_set_object (value, icon_view->priv->model);
828 case PROP_ORIENTATION:
829 g_value_set_enum (value, icon_view->priv->orientation);
832 g_value_set_int (value, icon_view->priv->columns);
834 case PROP_ITEM_WIDTH:
835 g_value_set_int (value, icon_view->priv->item_width);
838 g_value_set_int (value, icon_view->priv->spacing);
840 case PROP_ROW_SPACING:
841 g_value_set_int (value, icon_view->priv->row_spacing);
843 case PROP_COLUMN_SPACING:
844 g_value_set_int (value, icon_view->priv->column_spacing);
847 g_value_set_int (value, icon_view->priv->margin);
851 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
856 /* GtkWidget signals */
858 gtk_icon_view_realize (GtkWidget *widget)
860 GtkIconView *icon_view;
861 GdkWindowAttr attributes;
862 gint attributes_mask;
864 icon_view = GTK_ICON_VIEW (widget);
866 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
868 /* Make the main, clipping window */
869 attributes.window_type = GDK_WINDOW_CHILD;
870 attributes.x = widget->allocation.x;
871 attributes.y = widget->allocation.y;
872 attributes.width = widget->allocation.width;
873 attributes.height = widget->allocation.height;
874 attributes.wclass = GDK_INPUT_OUTPUT;
875 attributes.visual = gtk_widget_get_visual (widget);
876 attributes.colormap = gtk_widget_get_colormap (widget);
877 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
879 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
881 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
882 &attributes, attributes_mask);
883 gdk_window_set_user_data (widget->window, widget);
885 /* Make the window for the icon view */
888 attributes.width = MAX (icon_view->priv->width, widget->allocation.width);
889 attributes.height = MAX (icon_view->priv->height, widget->allocation.height);
890 attributes.event_mask = (GDK_EXPOSURE_MASK |
892 GDK_POINTER_MOTION_MASK |
893 GDK_BUTTON_PRESS_MASK |
894 GDK_BUTTON_RELEASE_MASK |
896 GDK_KEY_RELEASE_MASK) |
897 gtk_widget_get_events (widget);
899 icon_view->priv->bin_window = gdk_window_new (widget->window,
900 &attributes, attributes_mask);
901 gdk_window_set_user_data (icon_view->priv->bin_window, widget);
903 widget->style = gtk_style_attach (widget->style, widget->window);
904 gdk_window_set_background (icon_view->priv->bin_window, &widget->style->base[widget->state]);
905 gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
909 gtk_icon_view_unrealize (GtkWidget *widget)
911 GtkIconView *icon_view;
913 icon_view = GTK_ICON_VIEW (widget);
915 gdk_window_set_user_data (icon_view->priv->bin_window, NULL);
916 gdk_window_destroy (icon_view->priv->bin_window);
917 icon_view->priv->bin_window = NULL;
919 /* GtkWidget::unrealize destroys children and widget->window */
920 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
921 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
925 gtk_icon_view_map (GtkWidget *widget)
927 GtkIconView *icon_view;
929 icon_view = GTK_ICON_VIEW (widget);
931 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
933 gdk_window_show (icon_view->priv->bin_window);
934 gdk_window_show (widget->window);
938 gtk_icon_view_size_request (GtkWidget *widget,
939 GtkRequisition *requisition)
941 GtkIconView *icon_view;
943 icon_view = GTK_ICON_VIEW (widget);
945 requisition->width = icon_view->priv->width;
946 requisition->height = icon_view->priv->height;
950 gtk_icon_view_size_allocate (GtkWidget *widget,
951 GtkAllocation *allocation)
953 GtkIconView *icon_view;
955 widget->allocation = *allocation;
957 icon_view = GTK_ICON_VIEW (widget);
959 if (GTK_WIDGET_REALIZED (widget))
961 gdk_window_move_resize (widget->window,
962 allocation->x, allocation->y,
963 allocation->width, allocation->height);
964 gdk_window_resize (icon_view->priv->bin_window,
965 MAX (icon_view->priv->width, allocation->width),
966 MAX (icon_view->priv->height, allocation->height));
969 icon_view->priv->hadjustment->page_size = allocation->width;
970 icon_view->priv->hadjustment->page_increment = allocation->width * 0.9;
971 icon_view->priv->hadjustment->step_increment = allocation->width * 0.1;
972 icon_view->priv->hadjustment->lower = 0;
973 icon_view->priv->hadjustment->upper = MAX (allocation->width, icon_view->priv->width);
974 gtk_adjustment_changed (icon_view->priv->hadjustment);
976 icon_view->priv->vadjustment->page_size = allocation->height;
977 icon_view->priv->vadjustment->page_increment = allocation->height * 0.9;
978 icon_view->priv->vadjustment->step_increment = allocation->width * 0.1;
979 icon_view->priv->vadjustment->lower = 0;
980 icon_view->priv->vadjustment->upper = MAX (allocation->height, icon_view->priv->height);
981 gtk_adjustment_changed (icon_view->priv->vadjustment);
983 gtk_icon_view_layout (icon_view);
987 gtk_icon_view_expose (GtkWidget *widget,
988 GdkEventExpose *expose)
990 GtkIconView *icon_view;
993 icon_view = GTK_ICON_VIEW (widget);
995 if (expose->window != icon_view->priv->bin_window)
998 for (icons = icon_view->priv->items; icons; icons = icons->next) {
999 GtkIconViewItem *item = icons->data;
1000 GdkRectangle item_rectangle;
1002 item_rectangle.x = item->x;
1003 item_rectangle.y = item->y;
1004 item_rectangle.width = item->width;
1005 item_rectangle.height = item->height;
1007 if (gdk_region_rect_in (expose->region, &item_rectangle) == GDK_OVERLAP_RECTANGLE_OUT)
1010 #ifdef DEBUG_ICON_VIEW
1011 gdk_draw_rectangle (icon_view->priv->bin_window,
1012 GTK_WIDGET (icon_view)->style->black_gc,
1015 item->width, item->height);
1016 gdk_draw_rectangle (icon_view->priv->bin_window,
1017 GTK_WIDGET (icon_view)->style->black_gc,
1019 item->pixbuf_x, item->pixbuf_y,
1020 item->pixbuf_width, item->pixbuf_height);
1021 gdk_draw_rectangle (icon_view->priv->bin_window,
1022 GTK_WIDGET (icon_view)->style->black_gc,
1024 item->layout_x, item->layout_y,
1025 item->layout_width, item->layout_height);
1027 gtk_icon_view_paint_item (icon_view, item, &expose->area);
1031 if (icon_view->priv->doing_rubberband)
1033 GdkRectangle *rectangles;
1036 gdk_region_get_rectangles (expose->region,
1040 while (n_rectangles--)
1041 gtk_icon_view_paint_rubberband (icon_view, &rectangles[n_rectangles]);
1043 g_free (rectangles);
1050 scroll_timeout (gpointer data)
1052 GtkIconView *icon_view;
1055 GDK_THREADS_ENTER ();
1059 value = MIN (icon_view->priv->vadjustment->value +
1060 icon_view->priv->scroll_value_diff,
1061 icon_view->priv->vadjustment->upper -
1062 icon_view->priv->vadjustment->page_size);
1064 gtk_adjustment_set_value (icon_view->priv->vadjustment,
1067 gtk_icon_view_update_rubberband (icon_view);
1069 GDK_THREADS_LEAVE ();
1075 gtk_icon_view_motion (GtkWidget *widget,
1076 GdkEventMotion *event)
1078 GtkIconView *icon_view;
1081 icon_view = GTK_ICON_VIEW (widget);
1083 gtk_icon_view_maybe_begin_dragging_items (icon_view, event);
1085 if (icon_view->priv->doing_rubberband)
1087 gtk_icon_view_update_rubberband (widget);
1089 abs_y = event->y - icon_view->priv->height *
1090 (icon_view->priv->vadjustment->value /
1091 (icon_view->priv->vadjustment->upper -
1092 icon_view->priv->vadjustment->lower));
1094 if (abs_y < 0 || abs_y > widget->allocation.height)
1096 if (icon_view->priv->scroll_timeout_id == 0)
1097 icon_view->priv->scroll_timeout_id = g_timeout_add (30, scroll_timeout, icon_view);
1100 icon_view->priv->scroll_value_diff = abs_y;
1102 icon_view->priv->scroll_value_diff = abs_y - widget->allocation.height;
1104 icon_view->priv->event_last_x = event->x;
1105 icon_view->priv->event_last_y = event->y;
1107 else if (icon_view->priv->scroll_timeout_id != 0)
1109 g_source_remove (icon_view->priv->scroll_timeout_id);
1111 icon_view->priv->scroll_timeout_id = 0;
1119 gtk_icon_view_button_press (GtkWidget *widget,
1120 GdkEventButton *event)
1122 GtkIconView *icon_view;
1123 GtkIconViewItem *item;
1124 gboolean dirty = FALSE;
1126 icon_view = GTK_ICON_VIEW (widget);
1128 if (event->window != icon_view->priv->bin_window)
1131 if (!GTK_WIDGET_HAS_FOCUS (widget))
1132 gtk_widget_grab_focus (widget);
1134 if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
1137 item = gtk_icon_view_get_item_at_pos (icon_view,
1138 event->x, event->y);
1142 gtk_icon_view_scroll_to_item (icon_view, item);
1144 if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
1146 gtk_icon_view_set_cursor_item (icon_view, item);
1148 else if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE &&
1149 (event->state & GDK_SHIFT_MASK))
1151 gtk_icon_view_unselect_all_internal (icon_view);
1153 gtk_icon_view_set_cursor_item (icon_view, item);
1154 if (!icon_view->priv->anchor_item)
1155 icon_view->priv->anchor_item = item;
1157 gtk_icon_view_select_all_between (icon_view,
1158 icon_view->priv->anchor_item,
1164 if ((icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE ||
1165 ((icon_view->priv->selection_mode == GTK_SELECTION_SINGLE) && item->selected)) &&
1166 (event->state & GDK_CONTROL_MASK))
1168 item->selected = !item->selected;
1169 gtk_icon_view_queue_draw_item (icon_view, item);
1174 if (!item->selected)
1176 gtk_icon_view_unselect_all_internal (icon_view);
1178 item->selected = TRUE;
1179 gtk_icon_view_queue_draw_item (icon_view, item);
1183 gtk_icon_view_set_cursor_item (icon_view, item);
1184 icon_view->priv->anchor_item = item;
1187 /* Save press to possibly begin a drag */
1188 if (icon_view->priv->pressed_button < 0)
1190 icon_view->priv->pressed_button = event->button;
1191 icon_view->priv->press_start_x = event->x;
1192 icon_view->priv->press_start_y = event->y;
1195 if (!icon_view->priv->last_single_clicked)
1196 icon_view->priv->last_single_clicked = item;
1200 if (icon_view->priv->selection_mode != GTK_SELECTION_BROWSE &&
1201 !(event->state & GDK_CONTROL_MASK))
1203 dirty = gtk_icon_view_unselect_all_internal (icon_view);
1206 if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE)
1207 gtk_icon_view_start_rubberbanding (icon_view, event->x, event->y);
1212 if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
1214 item = gtk_icon_view_get_item_at_pos (icon_view,
1215 event->x, event->y);
1217 if (item && item == icon_view->priv->last_single_clicked)
1221 path = gtk_tree_path_new_from_indices (item->index, -1);
1222 gtk_icon_view_item_activated (icon_view, path);
1223 gtk_tree_path_free (path);
1226 icon_view->priv->last_single_clicked = NULL;
1230 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
1232 return event->button == 1;
1236 gtk_icon_view_button_release (GtkWidget *widget,
1237 GdkEventButton *event)
1239 GtkIconView *icon_view;
1241 icon_view = GTK_ICON_VIEW (widget);
1244 if (icon_view->priv->pressed_button == event->button)
1245 icon_view->priv->pressed_button = -1;
1247 gtk_icon_view_stop_rubberbanding (icon_view);
1249 if (icon_view->priv->scroll_timeout_id != 0)
1251 g_source_remove (icon_view->priv->scroll_timeout_id);
1252 icon_view->priv->scroll_timeout_id = 0;
1259 gtk_icon_view_update_rubberband (gpointer data)
1261 GtkIconView *icon_view;
1263 GdkRectangle old_area;
1264 GdkRectangle new_area;
1265 GdkRectangle common;
1266 GdkRegion *invalid_region;
1268 icon_view = GTK_ICON_VIEW (data);
1270 gdk_window_get_pointer (icon_view->priv->bin_window, &x, &y, NULL);
1275 old_area.x = MIN (icon_view->priv->rubberband_x1,
1276 icon_view->priv->rubberband_x2);
1277 old_area.y = MIN (icon_view->priv->rubberband_y1,
1278 icon_view->priv->rubberband_y2);
1279 old_area.width = ABS (icon_view->priv->rubberband_x2 -
1280 icon_view->priv->rubberband_x1) + 1;
1281 old_area.height = ABS (icon_view->priv->rubberband_y2 -
1282 icon_view->priv->rubberband_y1) + 1;
1284 new_area.x = MIN (icon_view->priv->rubberband_x1, x);
1285 new_area.y = MIN (icon_view->priv->rubberband_y1, y);
1286 new_area.width = ABS (x - icon_view->priv->rubberband_x1) + 1;
1287 new_area.height = ABS (y - icon_view->priv->rubberband_y1) + 1;
1289 invalid_region = gdk_region_rectangle (&old_area);
1290 gdk_region_union_with_rect (invalid_region, &new_area);
1292 gdk_rectangle_intersect (&old_area, &new_area, &common);
1293 if (common.width > 2 && common.height > 2)
1295 GdkRegion *common_region;
1297 /* make sure the border is invalidated */
1303 common_region = gdk_region_rectangle (&common);
1305 gdk_region_subtract (invalid_region, common_region);
1306 gdk_region_destroy (common_region);
1309 gdk_window_invalidate_region (icon_view->priv->bin_window, invalid_region, TRUE);
1311 gdk_region_destroy (invalid_region);
1313 icon_view->priv->rubberband_x2 = x;
1314 icon_view->priv->rubberband_y2 = y;
1316 gtk_icon_view_update_rubberband_selection (icon_view);
1320 gtk_icon_view_start_rubberbanding (GtkIconView *icon_view,
1326 g_assert (!icon_view->priv->doing_rubberband);
1328 for (items = icon_view->priv->items; items; items = items->next)
1330 GtkIconViewItem *item = items->data;
1332 item->selected_before_rubberbanding = item->selected;
1335 icon_view->priv->rubberband_x1 = x;
1336 icon_view->priv->rubberband_y1 = y;
1337 icon_view->priv->rubberband_x2 = x;
1338 icon_view->priv->rubberband_y2 = y;
1340 icon_view->priv->doing_rubberband = TRUE;
1342 gtk_grab_add (GTK_WIDGET (icon_view));
1346 gtk_icon_view_stop_rubberbanding (GtkIconView *icon_view)
1348 if (!icon_view->priv->doing_rubberband)
1351 icon_view->priv->doing_rubberband = FALSE;
1353 gtk_grab_remove (GTK_WIDGET (icon_view));
1355 gtk_widget_queue_draw (GTK_WIDGET (icon_view));
1359 gtk_icon_view_update_rubberband_selection (GtkIconView *icon_view)
1362 gint x, y, width, height;
1363 gboolean dirty = FALSE;
1365 x = MIN (icon_view->priv->rubberband_x1,
1366 icon_view->priv->rubberband_x2);
1367 y = MIN (icon_view->priv->rubberband_y1,
1368 icon_view->priv->rubberband_y2);
1369 width = ABS (icon_view->priv->rubberband_x1 -
1370 icon_view->priv->rubberband_x2);
1371 height = ABS (icon_view->priv->rubberband_y1 -
1372 icon_view->priv->rubberband_y2);
1374 for (items = icon_view->priv->items; items; items = items->next)
1376 GtkIconViewItem *item = items->data;
1380 is_in = gtk_icon_view_item_hit_test (item, x, y, width, height);
1382 selected = is_in ^ item->selected_before_rubberbanding;
1384 if (item->selected != selected)
1386 item->selected = selected;
1388 gtk_icon_view_queue_draw_item (icon_view, item);
1393 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
1397 gtk_icon_view_item_hit_test (GtkIconViewItem *item,
1403 /* First try the pixbuf */
1404 if (MIN (x + width, item->pixbuf_x + item->pixbuf_width) - MAX (x, item->pixbuf_x) > 0 &&
1405 MIN (y + height, item->pixbuf_y + item->pixbuf_height) - MAX (y, item->pixbuf_y) > 0)
1408 /* Then try the text */
1409 if (MIN (x + width, item->layout_x + item->layout_width) - MAX (x, item->layout_x) > 0 &&
1410 MIN (y + height, item->layout_y + item->layout_height) - MAX (y, item->layout_y) > 0)
1418 gtk_icon_view_maybe_begin_dragging_items (GtkIconView *icon_view,
1419 GdkEventMotion *event)
1421 gboolean retval = FALSE;
1423 if (icon_view->priv->pressed_button < 0)
1426 if (!gtk_drag_check_threshold (GTK_WIDGET (icon_view),
1427 icon_view->priv->press_start_x,
1428 icon_view->priv->press_start_y,
1429 event->x, event->y))
1432 button = icon_view->priv->pressed_button;
1433 icon_view->priv->pressed_button = -1;
1436 static GtkTargetEntry row_targets[] = {
1437 { "GTK_ICON_VIEW_ITEMS", GTK_TARGET_SAME_APP, 0 }
1439 GtkTargetList *target_list;
1440 GdkDragContext *context;
1441 GtkIconViewItem *item;
1445 target_list = gtk_target_list_new (row_targets, G_N_ELEMENTS (row_targets));
1447 context = gtk_drag_begin (GTK_WIDGET (icon_view),
1448 target_list, GDK_ACTION_MOVE,
1452 item = gtk_icon_view_get_item_at_pos (icon_view,
1453 icon_view->priv->press_start_x,
1454 icon_view->priv->press_start_y);
1455 g_assert (item != NULL);
1456 gtk_drag_set_icon_pixbuf (context, gtk_icon_view_get_item_icon (icon_view, item),
1458 event->y - item->y);
1466 gtk_icon_view_unselect_all_internal (GtkIconView *icon_view)
1468 gboolean dirty = FALSE;
1471 if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
1474 for (items = icon_view->priv->items; items; items = items->next)
1476 GtkIconViewItem *item = items->data;
1480 item->selected = FALSE;
1482 gtk_icon_view_queue_draw_item (icon_view, item);
1490 /* GtkIconView signals */
1492 gtk_icon_view_set_adjustments (GtkIconView *icon_view,
1493 GtkAdjustment *hadj,
1494 GtkAdjustment *vadj)
1496 gboolean need_adjust = FALSE;
1499 g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
1501 hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
1503 g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
1505 vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
1507 if (icon_view->priv->hadjustment && (icon_view->priv->hadjustment != hadj))
1509 g_signal_handlers_disconnect_matched (icon_view->priv->hadjustment, G_SIGNAL_MATCH_DATA,
1510 0, 0, NULL, NULL, icon_view);
1511 g_object_unref (icon_view->priv->hadjustment);
1514 if (icon_view->priv->vadjustment && (icon_view->priv->vadjustment != vadj))
1516 g_signal_handlers_disconnect_matched (icon_view->priv->vadjustment, G_SIGNAL_MATCH_DATA,
1517 0, 0, NULL, NULL, icon_view);
1518 g_object_unref (icon_view->priv->vadjustment);
1521 if (icon_view->priv->hadjustment != hadj)
1523 icon_view->priv->hadjustment = hadj;
1524 g_object_ref (icon_view->priv->hadjustment);
1525 gtk_object_sink (GTK_OBJECT (icon_view->priv->hadjustment));
1527 g_signal_connect (icon_view->priv->hadjustment, "value_changed",
1528 G_CALLBACK (gtk_icon_view_adjustment_changed),
1533 if (icon_view->priv->vadjustment != vadj)
1535 icon_view->priv->vadjustment = vadj;
1536 g_object_ref (icon_view->priv->vadjustment);
1537 gtk_object_sink (GTK_OBJECT (icon_view->priv->vadjustment));
1539 g_signal_connect (icon_view->priv->vadjustment, "value_changed",
1540 G_CALLBACK (gtk_icon_view_adjustment_changed),
1546 gtk_icon_view_adjustment_changed (NULL, icon_view);
1550 gtk_icon_view_real_select_all (GtkIconView *icon_view)
1552 gtk_icon_view_select_all (icon_view);
1556 gtk_icon_view_real_unselect_all (GtkIconView *icon_view)
1558 gtk_icon_view_unselect_all (icon_view);
1562 gtk_icon_view_real_select_cursor_item (GtkIconView *icon_view)
1564 gtk_icon_view_unselect_all (icon_view);
1566 if (icon_view->priv->cursor_item != NULL)
1567 gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
1571 gtk_icon_view_real_activate_cursor_item (GtkIconView *icon_view)
1575 if (!icon_view->priv->cursor_item)
1578 path = gtk_tree_path_new_from_indices (icon_view->priv->cursor_item->index, -1);
1580 gtk_icon_view_item_activated (icon_view, path);
1582 gtk_tree_path_free (path);
1588 gtk_icon_view_real_toggle_cursor_item (GtkIconView *icon_view)
1590 if (!icon_view->priv->cursor_item)
1593 switch (icon_view->priv->selection_mode)
1595 case GTK_SELECTION_NONE:
1597 case GTK_SELECTION_BROWSE:
1598 gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
1600 case GTK_SELECTION_SINGLE:
1601 if (icon_view->priv->cursor_item->selected)
1602 gtk_icon_view_unselect_item (icon_view, icon_view->priv->cursor_item);
1604 gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
1606 case GTK_SELECTION_MULTIPLE:
1607 icon_view->priv->cursor_item->selected = !icon_view->priv->cursor_item->selected;
1608 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
1610 gtk_icon_view_queue_draw_item (icon_view, icon_view->priv->cursor_item);
1615 /* Internal functions */
1617 gtk_icon_view_adjustment_changed (GtkAdjustment *adjustment,
1618 GtkIconView *icon_view)
1620 if (GTK_WIDGET_REALIZED (icon_view))
1622 gdk_window_move (icon_view->priv->bin_window,
1623 - icon_view->priv->hadjustment->value,
1624 - icon_view->priv->vadjustment->value);
1626 if (icon_view->priv->doing_rubberband)
1627 gtk_icon_view_update_rubberband (GTK_WIDGET (icon_view));
1629 gdk_window_process_updates (icon_view->priv->bin_window, TRUE);
1634 gtk_icon_view_layout_single_row (GtkIconView *icon_view,
1639 gint *maximum_width)
1641 gint focus_width, focus_pad;
1642 gint x, current_width, max_height, max_pixbuf_height;
1643 GList *items, *last_item;
1646 gboolean rtl = gtk_widget_get_direction (GTK_WIDGET (icon_view)) == GTK_TEXT_DIR_RTL;
1651 max_pixbuf_height = 0;
1655 gtk_widget_style_get (GTK_WIDGET (icon_view),
1656 "focus-line-width", &focus_width,
1657 "focus-padding", &focus_pad,
1660 x += icon_view->priv->margin;
1661 current_width += 2 * icon_view->priv->margin;
1666 GtkIconViewItem *item = items->data;
1668 gtk_icon_view_calculate_item_size (icon_view, item, item_width);
1670 colspan = 1 + (item->width - 1) / (item_width + icon_view->priv->column_spacing);
1671 current_width += colspan * (item_width + icon_view->priv->column_spacing);
1673 if (items != first_item)
1675 if ((icon_view->priv->columns <= 0 && current_width > GTK_WIDGET (icon_view)->allocation.width) ||
1676 (icon_view->priv->columns > 0 && col >= icon_view->priv->columns))
1681 item->x = rtl ? GTK_WIDGET (icon_view)->allocation.width - MAX (item_width, item->width) - x : x;
1683 if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1687 item->layout_x = item->x + ICON_TEXT_PADDING + focus_width + focus_pad;
1688 if (icon_view->priv->text_column != -1 ||
1689 icon_view->priv->markup_column != -1)
1690 item->pixbuf_x = item->x + 2 * (ICON_TEXT_PADDING + focus_width + focus_pad) + icon_view->priv->spacing + item->layout_width;
1692 item->pixbuf_x = item->x;
1696 item->pixbuf_x = item->x;
1697 if (icon_view->priv->pixbuf_column != -1)
1698 item->layout_x = item->x + item->pixbuf_width + icon_view->priv->spacing + ICON_TEXT_PADDING + focus_width + focus_pad;
1700 item->layout_x = item->x + ICON_TEXT_PADDING + focus_width + focus_pad;
1705 if (item->width < colspan * item_width + (colspan - 1) * icon_view->priv->column_spacing)
1706 item->x += (colspan * item_width + (colspan - 1) * icon_view->priv->column_spacing - item->width) / 2;
1708 item->pixbuf_x = item->x + (item->width - item->pixbuf_width) / 2;
1709 item->layout_x = item->x + (item->width - item->layout_width) / 2;
1712 x = current_width - icon_view->priv->margin;
1714 max_height = MAX (max_height, item->height);
1715 max_pixbuf_height = MAX (max_pixbuf_height, item->pixbuf_height);
1717 if (current_width > *maximum_width)
1718 *maximum_width = current_width;
1724 items = items->next;
1729 *y += max_height + icon_view->priv->row_spacing;
1731 /* Now go through the row again and align the icons */
1732 for (items = first_item; items != last_item; items = items->next)
1734 GtkIconViewItem *item = items->data;
1736 if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1738 item->pixbuf_y = item->y;
1739 item->layout_y = item->y + ICON_TEXT_PADDING + focus_width + focus_pad;
1743 item->pixbuf_y = item->y + (max_pixbuf_height - item->pixbuf_height);
1744 if (icon_view->priv->pixbuf_column != -1)
1745 item->layout_y = item->pixbuf_y + item->pixbuf_height + icon_view->priv->spacing + ICON_TEXT_PADDING + focus_width + focus_pad;
1747 item->layout_y = item->y + ICON_TEXT_PADDING + focus_width + focus_pad;
1749 /* Update the bounding box */
1750 item->y = item->pixbuf_y;
1752 /* We may want to readjust the new y coordinate. */
1753 if (item->y + item->height > *y)
1754 *y = item->y + item->height;
1757 item->col = col - 1 - item->col;
1764 gtk_icon_view_set_adjustment_upper (GtkAdjustment *adj,
1767 if (upper != adj->upper)
1769 gdouble min = MAX (0.0, upper - adj->page_size);
1770 gboolean value_changed = FALSE;
1774 if (adj->value > min)
1777 value_changed = TRUE;
1780 gtk_adjustment_changed (adj);
1783 gtk_adjustment_value_changed (adj);
1788 gtk_icon_view_layout (GtkIconView *icon_view)
1790 gint y = 0, maximum_width = 0;
1796 if (!VALID_MODEL_AND_COLUMNS (icon_view))
1799 widget = GTK_WIDGET (icon_view);
1801 item_width = icon_view->priv->item_width;
1805 for (icons = icon_view->priv->items; icons; icons = icons->next)
1807 GtkIconViewItem *item = icons->data;
1808 gtk_icon_view_calculate_item_size (icon_view, item, -1);
1809 item_width = MAX (item_width, item->width);
1810 gtk_icon_view_item_invalidate_size (item);
1814 icons = icon_view->priv->items;
1815 y += icon_view->priv->margin;
1820 icons = gtk_icon_view_layout_single_row (icon_view, icons,
1822 &y, &maximum_width);
1825 while (icons != NULL);
1827 if (maximum_width != icon_view->priv->width)
1829 icon_view->priv->width = maximum_width;
1831 y += icon_view->priv->margin;
1833 if (y != icon_view->priv->height)
1835 icon_view->priv->height = y;
1838 gtk_icon_view_set_adjustment_upper (icon_view->priv->hadjustment, icon_view->priv->width);
1839 gtk_icon_view_set_adjustment_upper (icon_view->priv->vadjustment, icon_view->priv->height);
1841 if (GTK_WIDGET_REALIZED (icon_view))
1843 gdk_window_resize (icon_view->priv->bin_window,
1844 MAX (icon_view->priv->width, widget->allocation.width),
1845 MAX (icon_view->priv->height, widget->allocation.height));
1848 if (icon_view->priv->layout_idle_id != 0)
1850 g_source_remove (icon_view->priv->layout_idle_id);
1851 icon_view->priv->layout_idle_id = 0;
1854 gtk_widget_queue_draw (GTK_WIDGET (icon_view));
1857 /* Updates the pango layout and calculates the size */
1859 gtk_icon_view_calculate_item_size (GtkIconView *icon_view,
1860 GtkIconViewItem *item,
1863 gint focus_width, focus_pad;
1864 gint layout_width, layout_height;
1865 gint maximum_layout_width;
1866 gint spacing, padding;
1870 if (item->width != -1 && item->height != -1)
1873 gtk_widget_style_get (GTK_WIDGET (icon_view),
1874 "focus-line-width", &focus_width,
1875 "focus-padding", &focus_pad,
1878 spacing = icon_view->priv->spacing;
1880 if (icon_view->priv->pixbuf_column != -1)
1882 pixbuf = gtk_icon_view_get_item_icon (icon_view, item);
1883 item->pixbuf_width = gdk_pixbuf_get_width (pixbuf);
1884 item->pixbuf_height = gdk_pixbuf_get_height (pixbuf);
1885 g_object_unref (pixbuf);
1889 item->pixbuf_width = 0;
1890 item->pixbuf_height = 0;
1894 if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL &&
1897 colspan = item->pixbuf_width / item_width + 1;
1898 maximum_layout_width = MAX (colspan * item_width - item->pixbuf_width - icon_view->priv->spacing - 2 * (ICON_TEXT_PADDING + focus_width + focus_pad), 50);
1901 maximum_layout_width = MAX (item_width, item->pixbuf_width);
1903 if (icon_view->priv->markup_column != -1 ||
1904 icon_view->priv->text_column != -1)
1906 gtk_icon_view_update_item_text (icon_view, item);
1908 pango_layout_set_alignment (icon_view->priv->layout, PANGO_ALIGN_CENTER);
1909 pango_layout_set_width (icon_view->priv->layout, maximum_layout_width * PANGO_SCALE);
1911 pango_layout_get_pixel_size (icon_view->priv->layout, &layout_width, &layout_height);
1913 item->layout_width = layout_width;
1914 item->layout_height = layout_height;
1915 padding = 2 * (ICON_TEXT_PADDING + focus_width + focus_pad);
1919 item->layout_width = 0;
1920 item->layout_height = 0;
1925 if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1927 item->width = item->layout_width + padding + spacing + item->pixbuf_width;
1928 item->height = MAX (item->layout_height + padding, item->pixbuf_height);
1932 item->width = MAX (item->layout_width + padding, item->pixbuf_width);
1933 item->height = item->layout_height + padding + spacing + item->pixbuf_height;
1938 gtk_icon_view_invalidate_sizes (GtkIconView *icon_view)
1940 g_list_foreach (icon_view->priv->items,
1941 (GFunc)gtk_icon_view_item_invalidate_size, NULL);
1945 gtk_icon_view_item_invalidate_size (GtkIconViewItem *item)
1952 create_colorized_pixbuf (GdkPixbuf *src, GdkColor *new_color)
1955 gint width, height, has_alpha, src_row_stride, dst_row_stride;
1956 gint red_value, green_value, blue_value;
1957 guchar *target_pixels;
1958 guchar *original_pixels;
1963 red_value = new_color->red / 255.0;
1964 green_value = new_color->green / 255.0;
1965 blue_value = new_color->blue / 255.0;
1967 dest = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src),
1968 gdk_pixbuf_get_has_alpha (src),
1969 gdk_pixbuf_get_bits_per_sample (src),
1970 gdk_pixbuf_get_width (src),
1971 gdk_pixbuf_get_height (src));
1973 has_alpha = gdk_pixbuf_get_has_alpha (src);
1974 width = gdk_pixbuf_get_width (src);
1975 height = gdk_pixbuf_get_height (src);
1976 src_row_stride = gdk_pixbuf_get_rowstride (src);
1977 dst_row_stride = gdk_pixbuf_get_rowstride (dest);
1978 target_pixels = gdk_pixbuf_get_pixels (dest);
1979 original_pixels = gdk_pixbuf_get_pixels (src);
1981 for (i = 0; i < height; i++) {
1982 pixdest = target_pixels + i*dst_row_stride;
1983 pixsrc = original_pixels + i*src_row_stride;
1984 for (j = 0; j < width; j++) {
1985 *pixdest++ = (*pixsrc++ * red_value) >> 8;
1986 *pixdest++ = (*pixsrc++ * green_value) >> 8;
1987 *pixdest++ = (*pixsrc++ * blue_value) >> 8;
1989 *pixdest++ = *pixsrc++;
1997 gtk_icon_view_paint_item (GtkIconView *icon_view,
1998 GtkIconViewItem *item,
2001 gint focus_width, focus_pad;
2002 GdkPixbuf *pixbuf, *tmp;
2004 gboolean rtl = gtk_widget_get_direction (GTK_WIDGET (icon_view)) == GTK_TEXT_DIR_RTL;
2006 if (!VALID_MODEL_AND_COLUMNS (icon_view))
2009 gtk_widget_style_get (GTK_WIDGET (icon_view),
2010 "focus-line-width", &focus_width,
2011 "focus-padding", &focus_pad,
2014 if (GTK_WIDGET_HAS_FOCUS (icon_view))
2015 state = GTK_STATE_SELECTED;
2017 state = GTK_STATE_ACTIVE;
2019 if (icon_view->priv->pixbuf_column != -1)
2021 tmp = gtk_icon_view_get_item_icon (icon_view, item);
2024 pixbuf = create_colorized_pixbuf (tmp,
2025 >K_WIDGET (icon_view)->style->base[state]);
2026 g_object_unref (tmp);
2031 gdk_draw_pixbuf (icon_view->priv->bin_window, NULL, pixbuf,
2033 item->pixbuf_x, item->pixbuf_y,
2034 item->pixbuf_width, item->pixbuf_height,
2035 GDK_RGB_DITHER_NORMAL,
2036 item->pixbuf_width, item->pixbuf_height);
2037 g_object_unref (pixbuf);
2040 if (icon_view->priv->text_column != -1 ||
2041 icon_view->priv->markup_column != -1)
2045 gdk_draw_rectangle (icon_view->priv->bin_window,
2046 GTK_WIDGET (icon_view)->style->base_gc[state],
2048 item->layout_x - ICON_TEXT_PADDING,
2049 item->layout_y - ICON_TEXT_PADDING,
2050 item->layout_width + 2 * ICON_TEXT_PADDING,
2051 item->layout_height + 2 * ICON_TEXT_PADDING);
2054 gtk_icon_view_update_item_text (icon_view, item);
2055 pango_layout_set_alignment (icon_view->priv->layout, rtl ? PANGO_ALIGN_RIGHT: PANGO_ALIGN_LEFT);
2056 pango_layout_set_width (icon_view->priv->layout, item->layout_width * PANGO_SCALE);
2057 gtk_paint_layout (GTK_WIDGET (icon_view)->style,
2058 icon_view->priv->bin_window,
2059 item->selected ? state : GTK_STATE_NORMAL,
2060 TRUE, area, GTK_WIDGET (icon_view), "icon_view",
2063 icon_view->priv->layout);
2065 if (GTK_WIDGET_HAS_FOCUS (icon_view) &&
2066 item == icon_view->priv->cursor_item)
2067 gtk_paint_focus (GTK_WIDGET (icon_view)->style,
2068 icon_view->priv->bin_window,
2071 GTK_WIDGET (icon_view),
2073 item->layout_x - ICON_TEXT_PADDING - focus_width - focus_pad,
2074 item->layout_y - ICON_TEXT_PADDING - focus_width - focus_pad,
2075 item->layout_width + 2 * (ICON_TEXT_PADDING + focus_width + focus_pad),
2076 item->layout_height + 2 * (ICON_TEXT_PADDING + focus_width + focus_pad));
2081 gtk_gdk_color_to_rgb (const GdkColor *color)
2084 result = (0xff0000 | (color->red & 0xff00));
2086 result |= ((color->green & 0xff00) | (color->blue >> 8));
2091 gtk_icon_view_paint_rubberband (GtkIconView *icon_view,
2097 GdkRectangle rubber_rect;
2098 GdkColor *fill_color_gdk;
2100 guchar fill_color_alpha;
2102 rubber_rect.x = MIN (icon_view->priv->rubberband_x1, icon_view->priv->rubberband_x2);
2103 rubber_rect.y = MIN (icon_view->priv->rubberband_y1, icon_view->priv->rubberband_y2);
2104 rubber_rect.width = ABS (icon_view->priv->rubberband_x1 - icon_view->priv->rubberband_x2) + 1;
2105 rubber_rect.height = ABS (icon_view->priv->rubberband_y1 - icon_view->priv->rubberband_y2) + 1;
2107 if (!gdk_rectangle_intersect (&rubber_rect, area, &rect))
2110 gtk_widget_style_get (GTK_WIDGET (icon_view),
2111 "selection_box_color", &fill_color_gdk,
2112 "selection_box_alpha", &fill_color_alpha,
2115 if (!fill_color_gdk) {
2116 fill_color_gdk = gdk_color_copy (>K_WIDGET (icon_view)->style->base[GTK_STATE_SELECTED]);
2119 fill_color = gtk_gdk_color_to_rgb (fill_color_gdk) << 8 | fill_color_alpha;
2121 if (!gdk_draw_rectangle_alpha_libgtk_only (icon_view->priv->bin_window,
2122 rect.x, rect.y, rect.width, rect.height,
2124 fill_color_alpha << 8 | fill_color_alpha))
2126 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, rect.width, rect.height);
2127 gdk_pixbuf_fill (pixbuf, fill_color);
2129 gdk_draw_pixbuf (icon_view->priv->bin_window, NULL, pixbuf,
2132 rect.width, rect.height,
2133 GDK_RGB_DITHER_NONE,
2135 g_object_unref (pixbuf);
2138 gc = gdk_gc_new (icon_view->priv->bin_window);
2139 gdk_gc_set_rgb_fg_color (gc, fill_color_gdk);
2140 gdk_gc_set_clip_rectangle (gc, &rect);
2141 gdk_draw_rectangle (icon_view->priv->bin_window,
2143 rubber_rect.x, rubber_rect.y,
2144 rubber_rect.width - 1, rubber_rect.height - 1);
2145 gdk_color_free (fill_color_gdk);
2146 g_object_unref (gc);
2150 gtk_icon_view_queue_draw_item (GtkIconView *icon_view,
2151 GtkIconViewItem *item)
2157 rect.width = item->width;
2158 rect.height = item->height;
2160 if (icon_view->priv->bin_window)
2161 gdk_window_invalidate_rect (icon_view->priv->bin_window, &rect, TRUE);
2165 layout_callback (gpointer user_data)
2167 GtkIconView *icon_view;
2169 GDK_THREADS_ENTER ();
2171 icon_view = GTK_ICON_VIEW (user_data);
2173 icon_view->priv->layout_idle_id = 0;
2175 gtk_icon_view_layout (icon_view);
2177 GDK_THREADS_LEAVE();
2183 gtk_icon_view_queue_layout (GtkIconView *icon_view)
2185 if (icon_view->priv->layout_idle_id != 0)
2188 icon_view->priv->layout_idle_id = g_idle_add (layout_callback, icon_view);
2192 gtk_icon_view_set_cursor_item (GtkIconView *icon_view,
2193 GtkIconViewItem *item)
2196 AtkObject *item_obj;
2198 if (icon_view->priv->cursor_item == item)
2201 if (icon_view->priv->cursor_item != NULL)
2202 gtk_icon_view_queue_draw_item (icon_view, icon_view->priv->cursor_item);
2204 icon_view->priv->cursor_item = item;
2205 gtk_icon_view_queue_draw_item (icon_view, item);
2207 /* Notify that accessible focus object has changed */
2208 obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
2209 item_obj = atk_object_ref_accessible_child (obj, item->index);
2211 if (item_obj != NULL)
2213 atk_focus_tracker_notify (item_obj);
2214 g_object_unref (item_obj);
2219 static GtkIconViewItem *
2220 gtk_icon_view_item_new (void)
2222 GtkIconViewItem *item;
2224 item = g_new0 (GtkIconViewItem, 1);
2233 gtk_icon_view_item_free (GtkIconViewItem *item)
2235 g_return_if_fail (item != NULL);
2241 gtk_icon_view_update_item_text (GtkIconView *icon_view,
2242 GtkIconViewItem *item)
2244 gboolean iters_persist;
2249 iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
2253 path = gtk_tree_path_new_from_indices (item->index, -1);
2254 gtk_tree_model_get_iter (icon_view->priv->model, &iter, path);
2255 gtk_tree_path_free (path);
2260 if (icon_view->priv->markup_column != -1)
2262 gtk_tree_model_get (icon_view->priv->model, &iter,
2263 icon_view->priv->markup_column, &text,
2265 pango_layout_set_markup (icon_view->priv->layout, text, -1);
2268 else if (icon_view->priv->text_column != -1)
2270 gtk_tree_model_get (icon_view->priv->model, &iter,
2271 icon_view->priv->text_column, &text,
2273 pango_layout_set_text (icon_view->priv->layout, text, -1);
2277 pango_layout_set_text (icon_view->priv->layout, "", -1);
2281 gtk_icon_view_get_item_icon (GtkIconView *icon_view,
2282 GtkIconViewItem *item)
2284 gboolean iters_persist;
2289 g_return_val_if_fail (item != NULL, NULL);
2291 iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
2295 path = gtk_tree_path_new_from_indices (item->index, -1);
2296 gtk_tree_model_get_iter (icon_view->priv->model, &iter, path);
2297 gtk_tree_path_free (path);
2302 gtk_tree_model_get (icon_view->priv->model, &iter,
2303 icon_view->priv->pixbuf_column, &pixbuf,
2310 static GtkIconViewItem *
2311 gtk_icon_view_get_item_at_pos (GtkIconView *icon_view,
2317 for (items = icon_view->priv->items; items; items = items->next)
2319 GtkIconViewItem *item = items->data;
2321 if (x > item->x && x < item->x + item->width &&
2322 y > item->y && y < item->y + item->height)
2324 /* Check if the mouse is inside the icon or the label */
2325 if ((x > item->pixbuf_x && x < item->pixbuf_x + item->pixbuf_width &&
2326 y > item->pixbuf_y && y < item->pixbuf_y + item->pixbuf_height) ||
2327 (x > item->layout_x - ICON_TEXT_PADDING &&
2328 x < item->layout_x + item->layout_width + ICON_TEXT_PADDING &&
2329 y > item->layout_y - ICON_TEXT_PADDING &&
2330 y < item->layout_y + item->layout_height + ICON_TEXT_PADDING))
2339 gtk_icon_view_select_item (GtkIconView *icon_view,
2340 GtkIconViewItem *item)
2342 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
2343 g_return_if_fail (item != NULL);
2348 if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
2350 else if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
2351 gtk_icon_view_unselect_all_internal (icon_view);
2353 item->selected = TRUE;
2355 gtk_icon_view_queue_draw_item (icon_view, item);
2357 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2362 gtk_icon_view_unselect_item (GtkIconView *icon_view,
2363 GtkIconViewItem *item)
2365 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
2366 g_return_if_fail (item != NULL);
2368 if (!item->selected)
2371 if (icon_view->priv->selection_mode == GTK_SELECTION_NONE ||
2372 icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
2375 item->selected = FALSE;
2377 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2379 gtk_icon_view_queue_draw_item (icon_view, item);
2383 verify_items (GtkIconView *icon_view)
2388 for (items = icon_view->priv->items; items; items = items->next)
2390 GtkIconViewItem *item = items->data;
2392 if (item->index != i)
2393 g_error ("List item does not match its index: item index %d and list index %d\n", item->index, i);
2400 gtk_icon_view_row_changed (GtkTreeModel *model,
2405 GtkIconViewItem *item;
2407 GtkIconView *icon_view;
2409 icon_view = GTK_ICON_VIEW (data);
2411 index = gtk_tree_path_get_indices(path)[0];
2412 item = g_list_nth (icon_view->priv->items, index)->data;
2414 gtk_icon_view_item_invalidate_size (item);
2415 gtk_icon_view_queue_layout (icon_view);
2417 verify_items (icon_view);
2421 gtk_icon_view_row_inserted (GtkTreeModel *model,
2427 GtkIconViewItem *item;
2428 gboolean iters_persist;
2429 GtkIconView *icon_view;
2432 icon_view = GTK_ICON_VIEW (data);
2433 iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
2435 length = gtk_tree_model_iter_n_children (model, NULL);
2436 index = gtk_tree_path_get_indices(path)[0];
2438 item = gtk_icon_view_item_new ();
2443 item->index = index;
2445 /* FIXME: We can be more efficient here,
2446 we can store a tail pointer and use that when
2447 appending (which is a rather common operation)
2449 icon_view->priv->items = g_list_insert (icon_view->priv->items,
2452 list = g_list_nth (icon_view->priv->items, index + 1);
2453 for (; list; list = list->next)
2460 verify_items (icon_view);
2464 gtk_icon_view_row_deleted (GtkTreeModel *model,
2469 GtkIconView *icon_view;
2470 GtkIconViewItem *item;
2472 gboolean emit = FALSE;
2474 icon_view = GTK_ICON_VIEW (data);
2476 index = gtk_tree_path_get_indices(path)[0];
2478 list = g_list_nth (icon_view->priv->items, index);
2481 if (item == icon_view->priv->anchor_item)
2482 icon_view->priv->anchor_item = NULL;
2484 if (item == icon_view->priv->cursor_item)
2485 icon_view->priv->cursor_item = NULL;
2490 gtk_icon_view_item_free (item);
2492 for (next = list->next; next; next = next->next)
2499 icon_view->priv->items = g_list_delete_link (icon_view->priv->items, list);
2501 gtk_icon_view_queue_layout (icon_view);
2503 verify_items (icon_view);
2506 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2510 gtk_icon_view_rows_reordered (GtkTreeModel *model,
2511 GtkTreePath *parent,
2518 GtkIconView *icon_view;
2519 GList *items = NULL, *list;
2520 GtkIconViewItem **item_array;
2523 icon_view = GTK_ICON_VIEW (data);
2525 length = gtk_tree_model_iter_n_children (model, NULL);
2527 order = g_new (gint, length);
2528 for (i = 0; i < length; i++)
2529 order [new_order[i]] = i;
2531 item_array = g_new (GtkIconViewItem *, length);
2532 for (i = 0, list = icon_view->priv->items; list != NULL; list = list->next, i++)
2533 item_array[order[i]] = list->data;
2536 for (i = length - 1; i >= 0; i--)
2538 item_array[i]->index = i;
2539 items = g_list_prepend (items, item_array[i]);
2542 g_free (item_array);
2543 g_list_free (icon_view->priv->items);
2544 icon_view->priv->items = items;
2546 verify_items (icon_view);
2550 gtk_icon_view_build_items (GtkIconView *icon_view)
2554 gboolean iters_persist;
2555 GList *items = NULL;
2557 iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
2559 if (!gtk_tree_model_get_iter_first (icon_view->priv->model,
2567 GtkIconViewItem *item = gtk_icon_view_item_new ();
2576 items = g_list_prepend (items, item);
2578 } while (gtk_tree_model_iter_next (icon_view->priv->model, &iter));
2580 icon_view->priv->items = g_list_reverse (items);
2584 gtk_icon_view_add_move_binding (GtkBindingSet *binding_set,
2587 GtkMovementStep step,
2591 gtk_binding_entry_add_signal (binding_set, keyval, modmask,
2596 gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
2601 if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2604 gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
2609 gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
2616 gtk_icon_view_real_move_cursor (GtkIconView *icon_view,
2617 GtkMovementStep step,
2620 GdkModifierType state;
2622 g_return_val_if_fail (GTK_ICON_VIEW (icon_view), FALSE);
2623 g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
2624 step == GTK_MOVEMENT_VISUAL_POSITIONS ||
2625 step == GTK_MOVEMENT_DISPLAY_LINES ||
2626 step == GTK_MOVEMENT_PAGES ||
2627 step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
2629 if (!GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (icon_view)))
2632 gtk_widget_grab_focus (GTK_WIDGET (icon_view));
2634 if (gtk_get_current_event_state (&state))
2636 if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2637 icon_view->priv->ctrl_pressed = TRUE;
2638 if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2639 icon_view->priv->shift_pressed = TRUE;
2641 /* else we assume not pressed */
2645 case GTK_MOVEMENT_LOGICAL_POSITIONS:
2646 case GTK_MOVEMENT_VISUAL_POSITIONS:
2647 gtk_icon_view_move_cursor_left_right (icon_view, count);
2649 case GTK_MOVEMENT_DISPLAY_LINES:
2650 gtk_icon_view_move_cursor_up_down (icon_view, count);
2652 case GTK_MOVEMENT_PAGES:
2653 gtk_icon_view_move_cursor_page_up_down (icon_view, count);
2655 case GTK_MOVEMENT_BUFFER_ENDS:
2656 gtk_icon_view_move_cursor_start_end (icon_view, count);
2659 g_assert_not_reached ();
2662 icon_view->priv->ctrl_pressed = FALSE;
2663 icon_view->priv->shift_pressed = FALSE;
2668 static GtkIconViewItem *
2669 find_item (GtkIconView *icon_view,
2670 GtkIconViewItem *current,
2676 GtkIconViewItem *item;
2678 /* FIXME: this could be more efficient
2680 row = current->row + row_ofs;
2681 col = current->col + col_ofs;
2683 for (items = icon_view->priv->items; items; items = items->next)
2686 if (item->row == row && item->col == col)
2694 static GtkIconViewItem *
2695 find_item_page_up_down (GtkIconView *icon_view,
2696 GtkIconViewItem *current,
2703 y = current->y + count * icon_view->priv->vadjustment->page_size;
2705 item = g_list_find (icon_view->priv->items, current);
2710 for (next = item->next; next; next = next->next)
2712 if (((GtkIconViewItem *)next->data)->col == col)
2715 if (!next || ((GtkIconViewItem *)next->data)->y > y)
2725 for (next = item->prev; next; next = next->prev)
2727 if (((GtkIconViewItem *)next->data)->col == col)
2730 if (!next || ((GtkIconViewItem *)next->data)->y < y)
2744 gtk_icon_view_select_all_between (GtkIconView *icon_view,
2745 GtkIconViewItem *anchor,
2746 GtkIconViewItem *cursor)
2749 GtkIconViewItem *item;
2750 gint row1, row2, col1, col2;
2751 gboolean dirty = FALSE;
2753 if (anchor->row < cursor->row)
2764 if (anchor->col < cursor->col)
2775 for (items = icon_view->priv->items; items; items = items->next)
2779 if (row1 <= item->row && item->row <= row2 &&
2780 col1 <= item->col && item->col <= col2)
2782 if (!item->selected)
2785 item->selected = TRUE;
2787 gtk_icon_view_queue_draw_item (icon_view, item);
2795 gtk_icon_view_move_cursor_up_down (GtkIconView *icon_view,
2798 GtkIconViewItem *item;
2799 gboolean dirty = FALSE;
2801 if (!GTK_WIDGET_HAS_FOCUS (icon_view))
2804 if (!icon_view->priv->cursor_item)
2809 list = icon_view->priv->items;
2811 list = g_list_last (icon_view->priv->items);
2813 item = list ? list->data : NULL;
2816 item = find_item (icon_view,
2817 icon_view->priv->cursor_item,
2823 if (icon_view->priv->ctrl_pressed ||
2824 !icon_view->priv->shift_pressed ||
2825 !icon_view->priv->anchor_item ||
2826 icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
2827 icon_view->priv->anchor_item = item;
2829 gtk_icon_view_set_cursor_item (icon_view, item);
2831 if (!icon_view->priv->ctrl_pressed &&
2832 icon_view->priv->selection_mode != GTK_SELECTION_NONE)
2834 gtk_icon_view_unselect_all_internal (icon_view);
2835 dirty = gtk_icon_view_select_all_between (icon_view,
2836 icon_view->priv->anchor_item,
2840 gtk_icon_view_scroll_to_item (icon_view, item);
2843 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2847 gtk_icon_view_move_cursor_page_up_down (GtkIconView *icon_view,
2850 GtkIconViewItem *item;
2851 gboolean dirty = FALSE;
2853 if (!GTK_WIDGET_HAS_FOCUS (icon_view))
2856 if (!icon_view->priv->cursor_item)
2861 list = icon_view->priv->items;
2863 list = g_list_last (icon_view->priv->items);
2865 item = list ? list->data : NULL;
2868 item = find_item_page_up_down (icon_view,
2869 icon_view->priv->cursor_item,
2875 if (icon_view->priv->ctrl_pressed ||
2876 !icon_view->priv->shift_pressed ||
2877 !icon_view->priv->anchor_item ||
2878 icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
2879 icon_view->priv->anchor_item = item;
2881 gtk_icon_view_set_cursor_item (icon_view, item);
2883 if (!icon_view->priv->ctrl_pressed &&
2884 icon_view->priv->selection_mode != GTK_SELECTION_NONE)
2886 gtk_icon_view_unselect_all_internal (icon_view);
2887 dirty = gtk_icon_view_select_all_between (icon_view,
2888 icon_view->priv->anchor_item,
2892 gtk_icon_view_scroll_to_item (icon_view, item);
2895 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2899 gtk_icon_view_move_cursor_left_right (GtkIconView *icon_view,
2902 GtkIconViewItem *item;
2903 gboolean dirty = FALSE;
2905 if (!GTK_WIDGET_HAS_FOCUS (icon_view))
2908 if (!icon_view->priv->cursor_item)
2913 list = icon_view->priv->items;
2915 list = g_list_last (icon_view->priv->items);
2917 item = list ? list->data : NULL;
2920 item = find_item (icon_view,
2921 icon_view->priv->cursor_item,
2927 if (icon_view->priv->ctrl_pressed ||
2928 !icon_view->priv->shift_pressed ||
2929 !icon_view->priv->anchor_item ||
2930 icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
2931 icon_view->priv->anchor_item = item;
2933 gtk_icon_view_set_cursor_item (icon_view, item);
2935 if (!icon_view->priv->ctrl_pressed &&
2936 icon_view->priv->selection_mode != GTK_SELECTION_NONE)
2938 gtk_icon_view_unselect_all_internal (icon_view);
2939 dirty = gtk_icon_view_select_all_between (icon_view,
2940 icon_view->priv->anchor_item,
2944 gtk_icon_view_scroll_to_item (icon_view, item);
2947 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2951 gtk_icon_view_move_cursor_start_end (GtkIconView *icon_view,
2954 GtkIconViewItem *item;
2956 gboolean dirty = FALSE;
2958 if (!GTK_WIDGET_HAS_FOCUS (icon_view))
2962 list = icon_view->priv->items;
2964 list = g_list_last (icon_view->priv->items);
2966 item = list ? list->data : NULL;
2971 if (icon_view->priv->ctrl_pressed ||
2972 !icon_view->priv->shift_pressed ||
2973 !icon_view->priv->anchor_item ||
2974 icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
2975 icon_view->priv->anchor_item = item;
2977 gtk_icon_view_set_cursor_item (icon_view, item);
2979 if (!icon_view->priv->ctrl_pressed &&
2980 icon_view->priv->selection_mode != GTK_SELECTION_NONE)
2982 gtk_icon_view_unselect_all (icon_view);
2983 dirty = gtk_icon_view_select_all_between (icon_view,
2984 icon_view->priv->anchor_item,
2988 gtk_icon_view_scroll_to_item (icon_view, item);
2991 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2995 gtk_icon_view_scroll_to_item (GtkIconView *icon_view,
2996 GtkIconViewItem *item)
3001 gdk_drawable_get_size (GDK_DRAWABLE (icon_view->priv->bin_window), NULL, &height);
3002 gdk_window_get_position (icon_view->priv->bin_window, NULL, &y);
3004 if (y + item->y < 0)
3006 value = icon_view->priv->vadjustment->value + y + item->y;
3007 gtk_adjustment_set_value (icon_view->priv->vadjustment, value);
3009 else if (y + item->y + item->height > GTK_WIDGET (icon_view)->allocation.height)
3011 value = icon_view->priv->vadjustment->value + y + item->y + item->height
3012 - GTK_WIDGET (icon_view)->allocation.height;
3013 gtk_adjustment_set_value (icon_view->priv->vadjustment, value);
3021 * gtk_icon_view_new:
3023 * Creates a new #GtkIconView widget
3025 * Return value: A newly created #GtkIconView widget
3030 gtk_icon_view_new (void)
3032 return g_object_new (GTK_TYPE_ICON_VIEW, NULL);
3036 * gtk_icon_view_new_with_model:
3037 * @model: The model.
3039 * Creates a new #GtkIconView widget with the model @model.
3041 * Return value: A newly created #GtkIconView widget.
3046 gtk_icon_view_new_with_model (GtkTreeModel *model)
3048 return g_object_new (GTK_TYPE_ICON_VIEW, "model", model, NULL);
3053 * gtk_icon_view_get_path_at_pos:
3054 * @icon_view: A #GtkIconView.
3055 * @x: The x position to be identified
3056 * @y: The y position to be identified
3058 * Finds the path at the point (@x, @y), relative to widget coordinates.
3060 * Return value: The #GtkTreePath corresponding to the icon or %NULL
3061 * if no icon exists at that position.
3066 gtk_icon_view_get_path_at_pos (GtkIconView *icon_view,
3070 GtkIconViewItem *item;
3073 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
3075 item = gtk_icon_view_get_item_at_pos (icon_view, x, y);
3080 path = gtk_tree_path_new_from_indices (item->index, -1);
3086 * gtk_icon_view_selected_foreach:
3087 * @icon_view: A #GtkIconView.
3088 * @func: The funcion to call for each selected icon.
3089 * @data: User data to pass to the function.
3091 * Calls a function for each selected icon. Note that the model or
3092 * selection cannot be modified from within this function.
3097 gtk_icon_view_selected_foreach (GtkIconView *icon_view,
3098 GtkIconViewForeachFunc func,
3103 for (list = icon_view->priv->items; list; list = list->next)
3105 GtkIconViewItem *item = list->data;
3106 GtkTreePath *path = gtk_tree_path_new_from_indices (item->index, -1);
3109 (* func) (icon_view, path, data);
3111 gtk_tree_path_free (path);
3116 * gtk_icon_view_set_selection_mode:
3117 * @icon_view: A #GtkIconView.
3118 * @mode: The selection mode
3120 * Sets the selection mode of the @icon_view.
3125 gtk_icon_view_set_selection_mode (GtkIconView *icon_view,
3126 GtkSelectionMode mode)
3128 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3130 if (mode == icon_view->priv->selection_mode)
3133 if (mode == GTK_SELECTION_NONE ||
3134 icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE)
3135 gtk_icon_view_unselect_all (icon_view);
3137 icon_view->priv->selection_mode = mode;
3139 g_object_notify (G_OBJECT (icon_view), "selection_mode");
3143 * gtk_icon_view_get_selection_mode:
3144 * @icon_view: A #GtkIconView.
3146 * Gets the selection mode of the @icon_view.
3148 * Return value: the current selection mode
3153 gtk_icon_view_get_selection_mode (GtkIconView *icon_view)
3155 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), GTK_SELECTION_SINGLE);
3157 return icon_view->priv->selection_mode;
3161 * gtk_icon_view_set_model:
3162 * @icon_view: A #GtkIconView.
3163 * @model: The model.
3165 * Sets the model for a #GtkIconView.
3166 * If the @icon_view already has a model set, it will remove
3167 * it before setting the new model. If @model is %NULL, then
3168 * it will unset the old model.
3173 gtk_icon_view_set_model (GtkIconView *icon_view,
3174 GtkTreeModel *model)
3176 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3177 g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
3179 if (icon_view->priv->model == model)
3186 g_return_if_fail (gtk_tree_model_get_flags (model) & GTK_TREE_MODEL_LIST_ONLY);
3188 if (icon_view->priv->pixbuf_column != -1)
3190 column_type = gtk_tree_model_get_column_type (model,
3191 icon_view->priv->pixbuf_column);
3193 g_return_if_fail (column_type == GDK_TYPE_PIXBUF);
3196 if (icon_view->priv->text_column != -1)
3198 column_type = gtk_tree_model_get_column_type (model,
3199 icon_view->priv->text_column);
3201 g_return_if_fail (column_type == G_TYPE_STRING);
3204 if (icon_view->priv->markup_column != -1)
3206 column_type = gtk_tree_model_get_column_type (model,
3207 icon_view->priv->markup_column);
3209 g_return_if_fail (column_type == G_TYPE_STRING);
3214 if (icon_view->priv->model)
3216 g_signal_handlers_disconnect_by_func (icon_view->priv->model,
3217 gtk_icon_view_row_changed,
3219 g_signal_handlers_disconnect_by_func (icon_view->priv->model,
3220 gtk_icon_view_row_inserted,
3222 g_signal_handlers_disconnect_by_func (icon_view->priv->model,
3223 gtk_icon_view_row_deleted,
3225 g_signal_handlers_disconnect_by_func (icon_view->priv->model,
3226 gtk_icon_view_rows_reordered,
3229 g_object_unref (icon_view->priv->model);
3231 g_list_foreach (icon_view->priv->items, (GFunc)gtk_icon_view_item_free, NULL);
3232 g_list_free (icon_view->priv->items);
3233 icon_view->priv->items = NULL;
3234 icon_view->priv->anchor_item = NULL;
3235 icon_view->priv->cursor_item = NULL;
3236 icon_view->priv->last_single_clicked = NULL;
3239 icon_view->priv->model = model;
3241 if (icon_view->priv->model)
3243 g_object_ref (icon_view->priv->model);
3244 g_signal_connect (icon_view->priv->model,
3246 G_CALLBACK (gtk_icon_view_row_changed),
3248 g_signal_connect (icon_view->priv->model,
3250 G_CALLBACK (gtk_icon_view_row_inserted),
3252 g_signal_connect (icon_view->priv->model,
3254 G_CALLBACK (gtk_icon_view_row_deleted),
3256 g_signal_connect (icon_view->priv->model,
3258 G_CALLBACK (gtk_icon_view_rows_reordered),
3261 gtk_icon_view_build_items (icon_view);
3264 gtk_icon_view_queue_layout (icon_view);
3266 g_object_notify (G_OBJECT (icon_view), "model");
3270 * gtk_icon_view_get_model:
3271 * @icon_view: a #GtkIconView
3273 * Returns the model the #GtkIconView is based on. Returns %NULL if the
3276 * Return value: A #GtkTreeModel, or %NULL if none is currently being used.
3281 gtk_icon_view_get_model (GtkIconView *icon_view)
3283 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
3285 return icon_view->priv->model;
3289 * gtk_icon_view_set_text_column:
3290 * @icon_view: A #GtkIconView.
3291 * @column: A column in the currently used model.
3293 * Sets the column with text for @icon_view to be @column. The text
3294 * column must be of type #G_TYPE_STRING.
3299 gtk_icon_view_set_text_column (GtkIconView *icon_view,
3302 if (column == icon_view->priv->text_column)
3306 icon_view->priv->text_column = -1;
3309 if (icon_view->priv->model != NULL)
3313 column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
3315 g_return_if_fail (column_type == G_TYPE_STRING);
3318 icon_view->priv->text_column = column;
3321 gtk_icon_view_invalidate_sizes (icon_view);
3322 gtk_icon_view_queue_layout (icon_view);
3324 g_object_notify (G_OBJECT (icon_view), "text_column");
3328 * gtk_icon_view_get_text_column:
3329 * @icon_view: A #GtkIconView.
3331 * Returns the column with text for @icon_view.
3333 * Returns: the text column, or -1 if it's unset.
3338 gtk_icon_view_get_text_column (GtkIconView *icon_view)
3340 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
3342 return icon_view->priv->text_column;
3346 * gtk_icon_view_set_markup_column:
3347 * @icon_view: A #GtkIconView.
3348 * @column: A column in the currently used model.
3350 * Sets the column with markup information for @icon_view to be
3351 * @column. The markup column must be of type #G_TYPE_STRING.
3352 * If the markup column is set to something, it overrides
3353 * the text column set by gtk_icon_view_set_text_column().
3358 gtk_icon_view_set_markup_column (GtkIconView *icon_view,
3361 if (column == icon_view->priv->markup_column)
3365 icon_view->priv->markup_column = -1;
3368 if (icon_view->priv->model != NULL)
3372 column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
3374 g_return_if_fail (column_type == G_TYPE_STRING);
3377 icon_view->priv->markup_column = column;
3380 gtk_icon_view_invalidate_sizes (icon_view);
3381 gtk_icon_view_queue_layout (icon_view);
3383 g_object_notify (G_OBJECT (icon_view), "markup_column");
3387 * gtk_icon_view_get_markup_column:
3388 * @icon_view: A #GtkIconView.
3390 * Returns the column with markup text for @icon_view.
3392 * Returns: the markup column, or -1 if it's unset.
3397 gtk_icon_view_get_markup_column (GtkIconView *icon_view)
3399 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
3401 return icon_view->priv->markup_column;
3405 * gtk_icon_view_set_pixbuf_column:
3406 * @icon_view: A #GtkIconView.
3407 * @column: A column in the currently used model.
3409 * Sets the column with pixbufs for @icon_view to be @column. The pixbuf
3410 * column must be of type #GDK_TYPE_PIXBUF
3415 gtk_icon_view_set_pixbuf_column (GtkIconView *icon_view,
3418 if (column == icon_view->priv->pixbuf_column)
3422 icon_view->priv->pixbuf_column = -1;
3425 if (icon_view->priv->model != NULL)
3429 column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
3431 g_return_if_fail (column_type == GDK_TYPE_PIXBUF);
3434 icon_view->priv->pixbuf_column = column;
3437 gtk_icon_view_invalidate_sizes (icon_view);
3438 gtk_icon_view_queue_layout (icon_view);
3440 g_object_notify (G_OBJECT (icon_view), "pixbuf_column");
3445 * gtk_icon_view_get_pixbuf_column:
3446 * @icon_view: A #GtkIconView.
3448 * Returns the column with pixbufs for @icon_view.
3450 * Returns: the pixbuf column, or -1 if it's unset.
3455 gtk_icon_view_get_pixbuf_column (GtkIconView *icon_view)
3457 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
3459 return icon_view->priv->pixbuf_column;
3463 * gtk_icon_view_select_path:
3464 * @icon_view: A #GtkIconView.
3465 * @path: The #GtkTreePath to be selected.
3467 * Selects the row at @path.
3472 gtk_icon_view_select_path (GtkIconView *icon_view,
3475 GtkIconViewItem *item;
3477 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3478 g_return_if_fail (icon_view->priv->model != NULL);
3479 g_return_if_fail (path != NULL);
3481 item = g_list_nth (icon_view->priv->items,
3482 gtk_tree_path_get_indices(path)[0])->data;
3487 gtk_icon_view_select_item (icon_view, item);
3491 * gtk_icon_view_unselect_path:
3492 * @icon_view: A #GtkIconView.
3493 * @path: The #GtkTreePath to be unselected.
3495 * Unselects the row at @path.
3500 gtk_icon_view_unselect_path (GtkIconView *icon_view,
3503 GtkIconViewItem *item;
3505 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3506 g_return_if_fail (icon_view->priv->model != NULL);
3507 g_return_if_fail (path != NULL);
3509 item = g_list_nth (icon_view->priv->items,
3510 gtk_tree_path_get_indices(path)[0])->data;
3515 gtk_icon_view_unselect_item (icon_view, item);
3519 * gtk_icon_view_get_selected_items:
3520 * @icon_view: A #GtkIconView.
3522 * Creates a list of paths of all selected items. Additionally, if you are
3523 * planning on modifying the model after calling this function, you may
3524 * want to convert the returned list into a list of #GtkTreeRowReference<!-- -->s.
3525 * To do this, you can use gtk_tree_row_reference_new().
3527 * To free the return value, use:
3528 * <informalexample><programlisting>
3529 * g_list_foreach (list, gtk_tree_path_free, NULL);
3530 * g_list_free (list);
3531 * </programlisting></informalexample>
3533 * Return value: A #GList containing a #GtkTreePath for each selected row.
3538 gtk_icon_view_get_selected_items (GtkIconView *icon_view)
3541 GList *selected = NULL;
3543 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
3545 for (list = icon_view->priv->items; list != NULL; list = list->next)
3547 GtkIconViewItem *item = list->data;
3551 GtkTreePath *path = gtk_tree_path_new_from_indices (item->index, -1);
3553 selected = g_list_prepend (selected, path);
3561 * gtk_icon_view_select_all:
3562 * @icon_view: A #GtkIconView.
3564 * Selects all the icons. @icon_view must has its selection mode set
3565 * to #GTK_SELECTION_MULTIPLE.
3570 gtk_icon_view_select_all (GtkIconView *icon_view)
3573 gboolean dirty = FALSE;
3575 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3577 if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3580 for (items = icon_view->priv->items; items; items = items->next)
3582 GtkIconViewItem *item = items->data;
3584 if (!item->selected)
3587 item->selected = TRUE;
3588 gtk_icon_view_queue_draw_item (icon_view, item);
3593 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3597 * gtk_icon_view_unselect_all:
3598 * @icon_view: A #GtkIconView.
3600 * Unselects all the icons.
3605 gtk_icon_view_unselect_all (GtkIconView *icon_view)
3607 gboolean dirty = FALSE;
3609 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3611 if (icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
3614 dirty = gtk_icon_view_unselect_all_internal (icon_view);
3617 g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3621 * gtk_icon_view_path_is_selected:
3622 * @icon_view: A #GtkIconView.
3623 * @path: A #GtkTreePath to check selection on.
3625 * Returns %TRUE if the icon pointed to by @path is currently
3626 * selected. If @icon does not point to a valid location, %FALSE is returned.
3628 * Return value: %TRUE if @path is selected.
3633 gtk_icon_view_path_is_selected (GtkIconView *icon_view,
3636 GtkIconViewItem *item;
3638 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
3639 g_return_val_if_fail (icon_view->priv->model != NULL, FALSE);
3640 g_return_val_if_fail (path != NULL, FALSE);
3642 item = g_list_nth (icon_view->priv->items,
3643 gtk_tree_path_get_indices(path)[0])->data;
3648 return item->selected;
3652 * gtk_icon_view_item_activated:
3653 * @icon_view: A #GtkIconView
3654 * @path: The #GtkTreePath to be activated
3656 * Activates the item determined by @path.
3661 gtk_icon_view_item_activated (GtkIconView *icon_view,
3664 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3665 g_return_if_fail (path != NULL);
3667 g_signal_emit (icon_view, icon_view_signals[ITEM_ACTIVATED], 0, path);
3671 * gtk_icon_view_set_orientation:
3672 * @icon_view: a #GtkIconView
3673 * @orientation: the relative position of texts and icons
3675 * Sets the ::orientation property which determines whether the labels
3676 * are drawn beside the icons instead of below.
3681 gtk_icon_view_set_orientation (GtkIconView *icon_view,
3682 GtkOrientation orientation)
3684 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3686 if (icon_view->priv->orientation != orientation)
3688 icon_view->priv->orientation = orientation;
3690 gtk_icon_view_invalidate_sizes (icon_view);
3691 gtk_icon_view_queue_layout (icon_view);
3693 g_object_notify (G_OBJECT (icon_view), "orientation");
3698 * gtk_icon_view_get_orientation:
3699 * @icon_view: a #GtkIconView
3701 * Returns the value of the ::orientation property which determines
3702 * whether the labels are drawn beside the icons instead of below.
3704 * Return value: the relative position of texts and icons
3709 gtk_icon_view_get_orientation (GtkIconView *icon_view)
3711 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view),
3712 GTK_ORIENTATION_VERTICAL);
3714 return icon_view->priv->orientation;
3717 void gtk_icon_view_set_columns (GtkIconView *icon_view,
3720 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3722 if (icon_view->priv->columns != columns)
3724 icon_view->priv->columns = columns;
3726 gtk_icon_view_queue_layout (icon_view);
3728 g_object_notify (G_OBJECT (icon_view), "columns");
3733 gtk_icon_view_get_columns (GtkIconView *icon_view)
3735 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
3737 return icon_view->priv->columns;
3740 void gtk_icon_view_set_item_width (GtkIconView *icon_view,
3743 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3745 if (icon_view->priv->item_width != item_width)
3747 icon_view->priv->item_width = item_width;
3749 gtk_icon_view_invalidate_sizes (icon_view);
3750 gtk_icon_view_queue_layout (icon_view);
3752 g_object_notify (G_OBJECT (icon_view), "item-width");
3757 gtk_icon_view_get_item_width (GtkIconView *icon_view)
3759 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
3761 return icon_view->priv->item_width;
3765 void gtk_icon_view_set_spacing (GtkIconView *icon_view,
3768 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3770 if (icon_view->priv->spacing != spacing)
3772 icon_view->priv->spacing = spacing;
3774 gtk_icon_view_invalidate_sizes (icon_view);
3775 gtk_icon_view_queue_layout (icon_view);
3777 g_object_notify (G_OBJECT (icon_view), "spacing");
3782 gtk_icon_view_get_spacing (GtkIconView *icon_view)
3784 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
3786 return icon_view->priv->spacing;
3789 void gtk_icon_view_set_row_spacing (GtkIconView *icon_view,
3792 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3794 if (icon_view->priv->row_spacing != row_spacing)
3796 icon_view->priv->row_spacing = row_spacing;
3798 gtk_icon_view_invalidate_sizes (icon_view);
3799 gtk_icon_view_queue_layout (icon_view);
3801 g_object_notify (G_OBJECT (icon_view), "row-spacing");
3806 gtk_icon_view_get_row_spacing (GtkIconView *icon_view)
3808 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
3810 return icon_view->priv->row_spacing;
3813 void gtk_icon_view_set_column_spacing (GtkIconView *icon_view,
3814 gint column_spacing)
3816 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3818 if (icon_view->priv->column_spacing != column_spacing)
3820 icon_view->priv->column_spacing = column_spacing;
3822 gtk_icon_view_invalidate_sizes (icon_view);
3823 gtk_icon_view_queue_layout (icon_view);
3825 g_object_notify (G_OBJECT (icon_view), "column-spacing");
3830 gtk_icon_view_get_column_spacing (GtkIconView *icon_view)
3832 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
3834 return icon_view->priv->column_spacing;
3837 void gtk_icon_view_set_margin (GtkIconView *icon_view,
3840 g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3842 if (icon_view->priv->margin != margin)
3844 icon_view->priv->margin = margin;
3846 gtk_icon_view_invalidate_sizes (icon_view);
3847 gtk_icon_view_queue_layout (icon_view);
3849 g_object_notify (G_OBJECT (icon_view), "margin");
3854 gtk_icon_view_get_margin (GtkIconView *icon_view)
3856 g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
3858 return icon_view->priv->margin;
3862 /* Accessibility Support */
3864 static gpointer accessible_parent_class;
3865 static gpointer accessible_item_parent_class;
3866 static GQuark accessible_private_data_quark = 0;
3868 #define GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE (gtk_icon_view_item_accessible_get_type ())
3869 #define GTK_ICON_VIEW_ITEM_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE, GtkIconViewItemAccessible))
3870 #define GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE))
3872 static GType gtk_icon_view_item_accessible_get_type (void);
3883 GtkIconViewItem *item;
3887 AtkStateSet *state_set;
3891 GtkTextBuffer *text_buffer;
3893 gchar *action_descriptions[LAST_ACTION];
3894 gchar *image_description;
3895 guint action_idle_handler;
3896 } GtkIconViewItemAccessible;
3898 static const gchar *const gtk_icon_view_item_accessible_action_names[] =
3904 static const gchar *const gtk_icon_view_item_accessible_action_descriptions[] =
3909 typedef struct _GtkIconViewItemAccessibleClass
3911 AtkObjectClass parent_class;
3913 } GtkIconViewItemAccessibleClass;
3915 static gboolean gtk_icon_view_item_accessible_is_showing (GtkIconViewItemAccessible *item);
3918 gtk_icon_view_item_accessible_idle_do_action (gpointer data)
3920 GtkIconViewItemAccessible *item;
3921 GtkIconView *icon_view;
3924 GDK_THREADS_ENTER ();
3926 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (data);
3927 item->action_idle_handler = 0;
3929 if (item->widget != NULL)
3931 icon_view = GTK_ICON_VIEW (item->widget);
3932 path = gtk_tree_path_new_from_indices (item->item->index, -1);
3933 gtk_icon_view_item_activated (icon_view, path);
3934 gtk_tree_path_free (path);
3937 GDK_THREADS_LEAVE ();
3943 gtk_icon_view_item_accessible_action_do_action (AtkAction *action,
3946 GtkIconViewItemAccessible *item;
3947 GtkIconView *icon_view;
3949 if (i < 0 || i >= LAST_ACTION)
3952 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
3954 if (!GTK_IS_ICON_VIEW (item->widget))
3957 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
3960 icon_view = GTK_ICON_VIEW (item->widget);
3964 case ACTION_ACTIVATE:
3965 if (!item->action_idle_handler)
3966 item->action_idle_handler = g_idle_add (gtk_icon_view_item_accessible_idle_do_action, item);
3969 g_assert_not_reached ();
3977 gtk_icon_view_item_accessible_action_get_n_actions (AtkAction *action)
3982 static const gchar *
3983 gtk_icon_view_item_accessible_action_get_description (AtkAction *action,
3986 GtkIconViewItemAccessible *item;
3988 if (i < 0 || i >= LAST_ACTION)
3991 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
3993 if (item->action_descriptions[i])
3994 return item->action_descriptions[i];
3996 return gtk_icon_view_item_accessible_action_descriptions[i];
3999 static const gchar *
4000 gtk_icon_view_item_accessible_action_get_name (AtkAction *action,
4003 if (i < 0 || i >= LAST_ACTION)
4006 return gtk_icon_view_item_accessible_action_names[i];
4010 gtk_icon_view_item_accessible_action_set_description (AtkAction *action,
4012 const gchar *description)
4014 GtkIconViewItemAccessible *item;
4016 if (i < 0 || i >= LAST_ACTION)
4019 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
4021 if (item->action_descriptions[i])
4022 g_free (item->action_descriptions[i]);
4024 item->action_descriptions[i] = g_strdup (description);
4030 atk_action_item_interface_init (AtkActionIface *iface)
4032 iface->do_action = gtk_icon_view_item_accessible_action_do_action;
4033 iface->get_n_actions = gtk_icon_view_item_accessible_action_get_n_actions;
4034 iface->get_description = gtk_icon_view_item_accessible_action_get_description;
4035 iface->get_name = gtk_icon_view_item_accessible_action_get_name;
4036 iface->set_description = gtk_icon_view_item_accessible_action_set_description;
4039 static const gchar *
4040 gtk_icon_view_item_accessible_image_get_image_description (AtkImage *image)
4042 GtkIconViewItemAccessible *item;
4044 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
4046 return item->image_description;
4050 gtk_icon_view_item_accessible_image_set_image_description (AtkImage *image,
4051 const gchar *description)
4053 GtkIconViewItemAccessible *item;
4055 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
4057 g_free (item->image_description);
4058 item->image_description = g_strdup (item->image_description);
4064 gtk_icon_view_item_accessible_image_get_image_size (AtkImage *image,
4068 GtkIconViewItemAccessible *item;
4070 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
4072 if (!GTK_IS_ICON_VIEW (item->widget))
4075 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
4078 *width = item->item->pixbuf_width;
4079 *height = item->item->pixbuf_height;
4083 gtk_icon_view_item_accessible_image_get_image_position (AtkImage *image,
4086 AtkCoordType coord_type)
4088 GtkIconViewItemAccessible *item;
4090 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
4092 if (!GTK_IS_ICON_VIEW (item->widget))
4095 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
4098 atk_component_get_position (ATK_COMPONENT (image), x, y, coord_type);
4099 *x+= item->item->pixbuf_x - item->item->x;
4100 *y+= item->item->pixbuf_y - item->item->y;
4104 atk_image_item_interface_init (AtkImageIface *iface)
4106 iface->get_image_description = gtk_icon_view_item_accessible_image_get_image_description;
4107 iface->set_image_description = gtk_icon_view_item_accessible_image_set_image_description;
4108 iface->get_image_size = gtk_icon_view_item_accessible_image_get_image_size;
4109 iface->get_image_position = gtk_icon_view_item_accessible_image_get_image_position;
4113 gtk_icon_view_item_accessible_text_get_text (AtkText *text,
4117 GtkIconViewItemAccessible *item;
4118 GtkTextIter start, end;
4119 GtkTextBuffer *buffer;
4121 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
4123 if (!GTK_IS_ICON_VIEW (item->widget))
4126 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
4129 buffer = item->text_buffer;
4130 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
4132 gtk_text_buffer_get_end_iter (buffer, &end);
4134 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
4136 return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
4140 gtk_icon_view_item_accessible_text_get_character_at_offset (AtkText *text,
4143 GtkIconViewItemAccessible *item;
4144 GtkTextIter start, end;
4145 GtkTextBuffer *buffer;
4149 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
4151 if (!GTK_IS_ICON_VIEW (item->widget))
4154 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
4157 buffer = item->text_buffer;
4158 if (offset >= gtk_text_buffer_get_char_count (buffer))
4161 gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
4163 gtk_text_iter_forward_char (&end);
4164 string = gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
4165 unichar = g_utf8_get_char (string);
4172 get_pango_text_offsets (PangoLayout *layout,
4173 GtkTextBuffer *buffer,
4175 AtkTextBoundary boundary_type,
4179 GtkTextIter *start_iter,
4180 GtkTextIter *end_iter)
4182 PangoLayoutIter *iter;
4183 PangoLayoutLine *line, *prev_line = NULL, *prev_prev_line = NULL;
4184 gint index, start_index, end_index;
4186 gboolean found = FALSE;
4188 text = pango_layout_get_text (layout);
4189 index = g_utf8_offset_to_pointer (text, offset) - text;
4190 iter = pango_layout_get_iter (layout);
4193 line = pango_layout_iter_get_line (iter);
4194 start_index = line->start_index;
4195 end_index = start_index + line->length;
4197 if (index >= start_index && index <= end_index)
4200 * Found line for offset
4206 * We want the previous line
4210 switch (boundary_type)
4212 case ATK_TEXT_BOUNDARY_LINE_START:
4213 end_index = start_index;
4214 start_index = prev_line->start_index;
4216 case ATK_TEXT_BOUNDARY_LINE_END:
4218 start_index = prev_prev_line->start_index +
4219 prev_prev_line->length;
4220 end_index = prev_line->start_index + prev_line->length;
4223 g_assert_not_reached();
4227 start_index = end_index = 0;
4230 switch (boundary_type)
4232 case ATK_TEXT_BOUNDARY_LINE_START:
4233 if (pango_layout_iter_next_line (iter))
4234 end_index = pango_layout_iter_get_line (iter)->start_index;
4236 case ATK_TEXT_BOUNDARY_LINE_END:
4238 start_index = prev_line->start_index +
4242 g_assert_not_reached();
4247 * We want the next line
4249 if (pango_layout_iter_next_line (iter))
4251 line = pango_layout_iter_get_line (iter);
4252 switch (boundary_type)
4254 case ATK_TEXT_BOUNDARY_LINE_START:
4255 start_index = line->start_index;
4256 if (pango_layout_iter_next_line (iter))
4257 end_index = pango_layout_iter_get_line (iter)->start_index;
4259 end_index = start_index + line->length;
4261 case ATK_TEXT_BOUNDARY_LINE_END:
4262 start_index = end_index;
4263 end_index = line->start_index + line->length;
4266 g_assert_not_reached();
4270 start_index = end_index;
4276 prev_prev_line = prev_line;
4279 while (pango_layout_iter_next_line (iter));
4283 start_index = prev_line->start_index + prev_line->length;
4284 end_index = start_index;
4286 pango_layout_iter_free (iter);
4287 *start_offset = g_utf8_pointer_to_offset (text, text + start_index);
4288 *end_offset = g_utf8_pointer_to_offset (text, text + end_index);
4290 gtk_text_buffer_get_iter_at_offset (buffer, start_iter, *start_offset);
4291 gtk_text_buffer_get_iter_at_offset (buffer, end_iter, *end_offset);
4295 gtk_icon_view_item_accessible_text_get_text_before_offset (AtkText *text,
4297 AtkTextBoundary boundary_type,
4301 GtkIconViewItemAccessible *item;
4302 GtkTextIter start, end;
4303 GtkTextBuffer *buffer;
4304 GtkIconView *icon_view;
4306 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
4308 if (!GTK_IS_ICON_VIEW (item->widget))
4311 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
4314 buffer = item->text_buffer;
4316 if (!gtk_text_buffer_get_char_count (buffer))
4320 return g_strdup ("");
4322 gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
4326 switch (boundary_type)
4328 case ATK_TEXT_BOUNDARY_CHAR:
4329 gtk_text_iter_backward_char(&start);
4331 case ATK_TEXT_BOUNDARY_WORD_START:
4332 if (!gtk_text_iter_starts_word (&start))
4333 gtk_text_iter_backward_word_start (&start);
4335 gtk_text_iter_backward_word_start(&start);
4337 case ATK_TEXT_BOUNDARY_WORD_END:
4338 if (gtk_text_iter_inside_word (&start) &&
4339 !gtk_text_iter_starts_word (&start))
4340 gtk_text_iter_backward_word_start (&start);
4341 while (!gtk_text_iter_ends_word (&start))
4343 if (!gtk_text_iter_backward_char (&start))
4347 gtk_text_iter_backward_word_start(&start);
4348 while (!gtk_text_iter_ends_word (&start))
4350 if (!gtk_text_iter_backward_char (&start))
4354 case ATK_TEXT_BOUNDARY_SENTENCE_START:
4355 if (!gtk_text_iter_starts_sentence (&start))
4356 gtk_text_iter_backward_sentence_start (&start);
4358 gtk_text_iter_backward_sentence_start (&start);
4360 case ATK_TEXT_BOUNDARY_SENTENCE_END:
4361 if (gtk_text_iter_inside_sentence (&start) &&
4362 !gtk_text_iter_starts_sentence (&start))
4363 gtk_text_iter_backward_sentence_start (&start);
4364 while (!gtk_text_iter_ends_sentence (&start))
4366 if (!gtk_text_iter_backward_char (&start))
4370 gtk_text_iter_backward_sentence_start (&start);
4371 while (!gtk_text_iter_ends_sentence (&start))
4373 if (!gtk_text_iter_backward_char (&start))
4377 case ATK_TEXT_BOUNDARY_LINE_START:
4378 case ATK_TEXT_BOUNDARY_LINE_END:
4379 icon_view = GTK_ICON_VIEW (item->widget);
4380 gtk_icon_view_update_item_text (icon_view, item->item);
4381 get_pango_text_offsets (icon_view->priv->layout,
4393 *start_offset = gtk_text_iter_get_offset (&start);
4394 *end_offset = gtk_text_iter_get_offset (&end);
4396 return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
4400 gtk_icon_view_item_accessible_text_get_text_at_offset (AtkText *text,
4402 AtkTextBoundary boundary_type,
4406 GtkIconViewItemAccessible *item;
4407 GtkTextIter start, end;
4408 GtkTextBuffer *buffer;
4409 GtkIconView *icon_view;
4411 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
4413 if (!GTK_IS_ICON_VIEW (item->widget))
4416 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
4419 buffer = item->text_buffer;
4421 if (!gtk_text_buffer_get_char_count (buffer))
4425 return g_strdup ("");
4427 gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
4431 switch (boundary_type)
4433 case ATK_TEXT_BOUNDARY_CHAR:
4434 gtk_text_iter_forward_char (&end);
4436 case ATK_TEXT_BOUNDARY_WORD_START:
4437 if (!gtk_text_iter_starts_word (&start))
4438 gtk_text_iter_backward_word_start (&start);
4439 if (gtk_text_iter_inside_word (&end))
4440 gtk_text_iter_forward_word_end (&end);
4441 while (!gtk_text_iter_starts_word (&end))
4443 if (!gtk_text_iter_forward_char (&end))
4447 case ATK_TEXT_BOUNDARY_WORD_END:
4448 if (gtk_text_iter_inside_word (&start) &&
4449 !gtk_text_iter_starts_word (&start))
4450 gtk_text_iter_backward_word_start (&start);
4451 while (!gtk_text_iter_ends_word (&start))
4453 if (!gtk_text_iter_backward_char (&start))
4456 gtk_text_iter_forward_word_end (&end);
4458 case ATK_TEXT_BOUNDARY_SENTENCE_START:
4459 if (!gtk_text_iter_starts_sentence (&start))
4460 gtk_text_iter_backward_sentence_start (&start);
4461 if (gtk_text_iter_inside_sentence (&end))
4462 gtk_text_iter_forward_sentence_end (&end);
4463 while (!gtk_text_iter_starts_sentence (&end))
4465 if (!gtk_text_iter_forward_char (&end))
4469 case ATK_TEXT_BOUNDARY_SENTENCE_END:
4470 if (gtk_text_iter_inside_sentence (&start) &&
4471 !gtk_text_iter_starts_sentence (&start))
4472 gtk_text_iter_backward_sentence_start (&start);
4473 while (!gtk_text_iter_ends_sentence (&start))
4475 if (!gtk_text_iter_backward_char (&start))
4478 gtk_text_iter_forward_sentence_end (&end);
4480 case ATK_TEXT_BOUNDARY_LINE_START:
4481 case ATK_TEXT_BOUNDARY_LINE_END:
4482 icon_view = GTK_ICON_VIEW (item->widget);
4483 gtk_icon_view_update_item_text (icon_view, item->item);
4484 get_pango_text_offsets (icon_view->priv->layout,
4497 *start_offset = gtk_text_iter_get_offset (&start);
4498 *end_offset = gtk_text_iter_get_offset (&end);
4500 return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
4504 gtk_icon_view_item_accessible_text_get_text_after_offset (AtkText *text,
4506 AtkTextBoundary boundary_type,
4510 GtkIconViewItemAccessible *item;
4511 GtkTextIter start, end;
4512 GtkTextBuffer *buffer;
4513 GtkIconView *icon_view;
4515 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
4517 if (!GTK_IS_ICON_VIEW (item->widget))
4520 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
4523 buffer = item->text_buffer;
4525 if (!gtk_text_buffer_get_char_count (buffer))
4529 return g_strdup ("");
4531 gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
4535 switch (boundary_type)
4537 case ATK_TEXT_BOUNDARY_CHAR:
4538 gtk_text_iter_forward_char(&start);
4539 gtk_text_iter_forward_chars(&end, 2);
4541 case ATK_TEXT_BOUNDARY_WORD_START:
4542 if (gtk_text_iter_inside_word (&end))
4543 gtk_text_iter_forward_word_end (&end);
4544 while (!gtk_text_iter_starts_word (&end))
4546 if (!gtk_text_iter_forward_char (&end))
4550 if (!gtk_text_iter_is_end (&end))
4552 gtk_text_iter_forward_word_end (&end);
4553 while (!gtk_text_iter_starts_word (&end))
4555 if (!gtk_text_iter_forward_char (&end))
4560 case ATK_TEXT_BOUNDARY_WORD_END:
4561 gtk_text_iter_forward_word_end (&end);
4563 if (!gtk_text_iter_is_end (&end))
4564 gtk_text_iter_forward_word_end (&end);
4566 case ATK_TEXT_BOUNDARY_SENTENCE_START:
4567 if (gtk_text_iter_inside_sentence (&end))
4568 gtk_text_iter_forward_sentence_end (&end);
4569 while (!gtk_text_iter_starts_sentence (&end))
4571 if (!gtk_text_iter_forward_char (&end))
4575 if (!gtk_text_iter_is_end (&end))
4577 gtk_text_iter_forward_sentence_end (&end);
4578 while (!gtk_text_iter_starts_sentence (&end))
4580 if (!gtk_text_iter_forward_char (&end))
4585 case ATK_TEXT_BOUNDARY_SENTENCE_END:
4586 gtk_text_iter_forward_sentence_end (&end);
4588 if (!gtk_text_iter_is_end (&end))
4589 gtk_text_iter_forward_sentence_end (&end);
4591 case ATK_TEXT_BOUNDARY_LINE_START:
4592 case ATK_TEXT_BOUNDARY_LINE_END:
4593 icon_view = GTK_ICON_VIEW (item->widget);
4594 gtk_icon_view_update_item_text (icon_view, item->item);
4595 get_pango_text_offsets (icon_view->priv->layout,
4606 *start_offset = gtk_text_iter_get_offset (&start);
4607 *end_offset = gtk_text_iter_get_offset (&end);
4609 return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
4613 gtk_icon_view_item_accessible_text_get_character_count (AtkText *text)
4615 GtkIconViewItemAccessible *item;
4617 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
4619 if (!GTK_IS_ICON_VIEW (item->widget))
4622 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
4625 return gtk_text_buffer_get_char_count (item->text_buffer);
4629 gtk_icon_view_item_accessible_text_get_character_extents (AtkText *text,
4635 AtkCoordType coord_type)
4637 GtkIconViewItemAccessible *item;
4638 GtkIconView *icon_view;
4639 PangoRectangle char_rect;
4640 const gchar *item_text;
4643 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
4645 if (!GTK_IS_ICON_VIEW (item->widget))
4648 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
4651 icon_view = GTK_ICON_VIEW (item->widget);
4652 gtk_icon_view_update_item_text (icon_view, item->item);
4653 item_text = pango_layout_get_text (icon_view->priv->layout);
4654 index = g_utf8_offset_to_pointer (item_text, offset) - item_text;
4655 pango_layout_index_to_pos (icon_view->priv->layout, index, &char_rect);
4657 atk_component_get_position (ATK_COMPONENT (text), x, y, coord_type);
4658 *x += item->item->layout_x - item->item->x + char_rect.x / PANGO_SCALE;
4659 /* Look at gtk_icon_view_paint_item() to see where the text is. */
4660 *x -= ((item->item->width - item->item->layout_width) / 2) + (MAX (item->item->pixbuf_width, icon_view->priv->item_width) - item->item->width) / 2,
4661 *y += item->item->layout_y - item->item->y + char_rect.y / PANGO_SCALE;
4662 *width = char_rect.width / PANGO_SCALE;
4663 *height = char_rect.height / PANGO_SCALE;
4667 gtk_icon_view_item_accessible_text_get_offset_at_point (AtkText *text,
4670 AtkCoordType coord_type)
4672 GtkIconViewItemAccessible *item;
4673 GtkIconView *icon_view;
4674 const gchar *item_text;
4679 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
4681 if (!GTK_IS_ICON_VIEW (item->widget))
4684 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
4687 icon_view = GTK_ICON_VIEW (item->widget);
4688 gtk_icon_view_update_item_text (icon_view, item->item);
4689 atk_component_get_position (ATK_COMPONENT (text), &l_x, &l_y, coord_type);
4690 x -= l_x + item->item->layout_x - item->item->x;
4691 x += ((item->item->width - item->item->layout_width) / 2) + (MAX (item->item->pixbuf_width, icon_view->priv->item_width) - item->item->width) / 2,
4692 y -= l_y + item->item->layout_y - item->item->y;
4693 item_text = pango_layout_get_text (icon_view->priv->layout);
4694 if (!pango_layout_xy_to_index (icon_view->priv->layout,
4705 offset = g_utf8_strlen (item_text, -1);
4707 offset = g_utf8_pointer_to_offset (item_text, item_text + index);
4713 atk_text_item_interface_init (AtkTextIface *iface)
4715 iface->get_text = gtk_icon_view_item_accessible_text_get_text;
4716 iface->get_character_at_offset = gtk_icon_view_item_accessible_text_get_character_at_offset;
4717 iface->get_text_before_offset = gtk_icon_view_item_accessible_text_get_text_before_offset;
4718 iface->get_text_at_offset = gtk_icon_view_item_accessible_text_get_text_at_offset;
4719 iface->get_text_after_offset = gtk_icon_view_item_accessible_text_get_text_after_offset;
4720 iface->get_character_count = gtk_icon_view_item_accessible_text_get_character_count;
4721 iface->get_character_extents = gtk_icon_view_item_accessible_text_get_character_extents;
4722 iface->get_offset_at_point = gtk_icon_view_item_accessible_text_get_offset_at_point;
4726 gtk_icon_view_item_accessible_get_extents (AtkComponent *component,
4731 AtkCoordType coord_type)
4733 GtkIconViewItemAccessible *item;
4734 AtkObject *parent_obj;
4737 g_return_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (component));
4739 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (component);
4740 if (!GTK_IS_WIDGET (item->widget))
4743 if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
4746 *width = item->item->width;
4747 *height = item->item->height;
4748 if (gtk_icon_view_item_accessible_is_showing (item))
4750 parent_obj = gtk_widget_get_accessible (item->widget);
4751 atk_component_get_position (ATK_COMPONENT (parent_obj), &l_x, &l_y, coord_type);
4752 *x = l_x + item->item->x;
4753 *y = l_y + item->item->y;
4763 gtk_icon_view_item_accessible_grab_focus (AtkComponent *component)
4765 GtkIconViewItemAccessible *item;
4766 GtkWidget *toplevel;
4768 g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (component), FALSE);
4770 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (component);
4771 if (!GTK_IS_WIDGET (item->widget))
4774 gtk_widget_grab_focus (item->widget);
4775 gtk_icon_view_set_cursor_item (GTK_ICON_VIEW (item->widget), item->item);
4776 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (item->widget));
4777 if (GTK_WIDGET_TOPLEVEL (toplevel))
4778 gtk_window_present (GTK_WINDOW (toplevel));
4784 atk_component_item_interface_init (AtkComponentIface *iface)
4786 iface->get_extents = gtk_icon_view_item_accessible_get_extents;
4787 iface->grab_focus = gtk_icon_view_item_accessible_grab_focus;
4791 gtk_icon_view_item_accessible_add_state (GtkIconViewItemAccessible *item,
4792 AtkStateType state_type,
4793 gboolean emit_signal)
4797 rc = atk_state_set_add_state (item->state_set, state_type);
4799 * The signal should only be generated if the value changed,
4800 * not when the item is set up. So states that are set
4801 * initially should pass FALSE as the emit_signal argument.
4806 atk_object_notify_state_change (ATK_OBJECT (item), state_type, TRUE);
4807 /* If state_type is ATK_STATE_VISIBLE, additional notification */
4808 if (state_type == ATK_STATE_VISIBLE)
4809 g_signal_emit_by_name (item, "visible_data_changed");
4816 gtk_icon_view_item_accessible_remove_state (GtkIconViewItemAccessible *item,
4817 AtkStateType state_type,
4818 gboolean emit_signal)
4820 if (atk_state_set_contains_state (item->state_set, state_type))
4824 rc = atk_state_set_remove_state (item->state_set, state_type);
4826 * The signal should only be generated if the value changed,
4827 * not when the item is set up. So states that are set
4828 * initially should pass FALSE as the emit_signal argument.
4833 atk_object_notify_state_change (ATK_OBJECT (item), state_type, FALSE);
4834 /* If state_type is ATK_STATE_VISIBLE, additional notification */
4835 if (state_type == ATK_STATE_VISIBLE)
4836 g_signal_emit_by_name (item, "visible_data_changed");
4846 gtk_icon_view_item_accessible_is_showing (GtkIconViewItemAccessible *item)
4848 GtkIconView *icon_view;
4849 GdkRectangle visible_rect;
4850 gboolean is_showing;
4853 * An item is considered "SHOWING" if any part of the item is in the
4854 * visible rectangle.
4857 if (!GTK_IS_ICON_VIEW (item->widget))
4860 if (item->item == NULL)
4863 icon_view = GTK_ICON_VIEW (item->widget);
4865 if (icon_view->priv->hadjustment)
4866 visible_rect.x += icon_view->priv->hadjustment->value;
4868 if (icon_view->priv->hadjustment)
4869 visible_rect.y += icon_view->priv->vadjustment->value;
4870 visible_rect.width = item->widget->allocation.width;
4871 visible_rect.height = item->widget->allocation.height;
4873 if (((item->item->x + item->item->width) < visible_rect.x) ||
4874 ((item->item->y + item->item->height) < (visible_rect.y)) ||
4875 (item->item->x > (visible_rect.x + visible_rect.width)) ||
4876 (item->item->y > (visible_rect.y + visible_rect.height)))
4885 gtk_icon_view_item_accessible_set_visibility (GtkIconViewItemAccessible *item,
4886 gboolean emit_signal)
4888 if (gtk_icon_view_item_accessible_is_showing (item))
4889 return gtk_icon_view_item_accessible_add_state (item, ATK_STATE_SHOWING,
4892 return gtk_icon_view_item_accessible_remove_state (item, ATK_STATE_SHOWING,
4897 gtk_icon_view_item_accessible_object_init (GtkIconViewItemAccessible *item)
4901 item->state_set = atk_state_set_new ();
4903 atk_state_set_add_state (item->state_set, ATK_STATE_ENABLED);
4904 atk_state_set_add_state (item->state_set, ATK_STATE_FOCUSABLE);
4905 atk_state_set_add_state (item->state_set, ATK_STATE_SENSITIVE);
4906 atk_state_set_add_state (item->state_set, ATK_STATE_SELECTABLE);
4907 atk_state_set_add_state (item->state_set, ATK_STATE_VISIBLE);
4909 for (i = 0; i < LAST_ACTION; i++)
4910 item->action_descriptions[i] = NULL;
4912 item->image_description = NULL;
4914 item->action_idle_handler = 0;
4918 gtk_icon_view_item_accessible_finalize (GObject *object)
4920 GtkIconViewItemAccessible *item;
4923 g_return_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (object));
4925 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (object);
4928 g_object_remove_weak_pointer (G_OBJECT (item->widget), (gpointer) &item->widget);
4930 if (item->state_set)
4931 g_object_unref (item->state_set);
4933 if (item->text_buffer)
4934 g_object_unref (item->text_buffer);
4936 for (i = 0; i < LAST_ACTION; i++)
4937 g_free (item->action_descriptions[i]);
4939 g_free (item->image_description);
4941 if (item->action_idle_handler)
4943 g_source_remove (item->action_idle_handler);
4944 item->action_idle_handler = 0;
4947 G_OBJECT_CLASS (accessible_item_parent_class)->finalize (object);
4950 static G_CONST_RETURN gchar*
4951 gtk_icon_view_item_accessible_get_name (AtkObject *obj)
4957 GtkIconViewItemAccessible *item;
4958 GtkTextIter start_iter;
4959 GtkTextIter end_iter;
4961 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
4963 gtk_text_buffer_get_start_iter (item->text_buffer, &start_iter);
4964 gtk_text_buffer_get_end_iter (item->text_buffer, &end_iter);
4966 return gtk_text_buffer_get_text (item->text_buffer, &start_iter, &end_iter, FALSE);
4971 gtk_icon_view_item_accessible_get_parent (AtkObject *obj)
4973 GtkIconViewItemAccessible *item;
4975 g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (obj), NULL);
4976 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
4979 return gtk_widget_get_accessible (item->widget);
4985 gtk_icon_view_item_accessible_get_index_in_parent (AtkObject *obj)
4987 GtkIconViewItemAccessible *item;
4989 g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (obj), 0);
4990 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
4992 return item->item->index;
4995 static AtkStateSet *
4996 gtk_icon_view_item_accessible_ref_state_set (AtkObject *obj)
4998 GtkIconViewItemAccessible *item;
4999 GtkIconView *icon_view;
5001 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
5002 g_return_val_if_fail (item->state_set, NULL);
5007 icon_view = GTK_ICON_VIEW (item->widget);
5008 if (icon_view->priv->cursor_item == item->item)
5009 atk_state_set_add_state (item->state_set, ATK_STATE_FOCUSED);
5011 atk_state_set_remove_state (item->state_set, ATK_STATE_FOCUSED);
5013 return g_object_ref (item->state_set);
5017 gtk_icon_view_item_accessible_class_init (AtkObjectClass *klass)
5019 GObjectClass *gobject_class;
5021 accessible_item_parent_class = g_type_class_peek_parent (klass);
5023 gobject_class = (GObjectClass *)klass;
5025 gobject_class->finalize = gtk_icon_view_item_accessible_finalize;
5027 klass->get_index_in_parent = gtk_icon_view_item_accessible_get_index_in_parent;
5028 klass->get_name = gtk_icon_view_item_accessible_get_name;
5029 klass->get_parent = gtk_icon_view_item_accessible_get_parent;
5030 klass->ref_state_set = gtk_icon_view_item_accessible_ref_state_set;
5034 gtk_icon_view_item_accessible_get_type (void)
5036 static GType type = 0;
5040 static const GTypeInfo tinfo =
5042 sizeof (GtkIconViewItemAccessibleClass),
5043 (GBaseInitFunc) NULL, /* base init */
5044 (GBaseFinalizeFunc) NULL, /* base finalize */
5045 (GClassInitFunc) gtk_icon_view_item_accessible_class_init, /* class init */
5046 (GClassFinalizeFunc) NULL, /* class finalize */
5047 NULL, /* class data */
5048 sizeof (GtkIconViewItemAccessible), /* instance size */
5049 0, /* nb preallocs */
5050 (GInstanceInitFunc) gtk_icon_view_item_accessible_object_init, /* instance init */
5051 NULL /* value table */
5054 static const GInterfaceInfo atk_component_info =
5056 (GInterfaceInitFunc) atk_component_item_interface_init,
5057 (GInterfaceFinalizeFunc) NULL,
5060 static const GInterfaceInfo atk_action_info =
5062 (GInterfaceInitFunc) atk_action_item_interface_init,
5063 (GInterfaceFinalizeFunc) NULL,
5066 static const GInterfaceInfo atk_image_info =
5068 (GInterfaceInitFunc) atk_image_item_interface_init,
5069 (GInterfaceFinalizeFunc) NULL,
5072 static const GInterfaceInfo atk_text_info =
5074 (GInterfaceInitFunc) atk_text_item_interface_init,
5075 (GInterfaceFinalizeFunc) NULL,
5079 type = g_type_register_static (ATK_TYPE_OBJECT,
5080 "GtkIconViewItemAccessible", &tinfo, 0);
5081 g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
5082 &atk_component_info);
5083 g_type_add_interface_static (type, ATK_TYPE_ACTION,
5085 g_type_add_interface_static (type, ATK_TYPE_IMAGE,
5087 g_type_add_interface_static (type, ATK_TYPE_TEXT,
5094 #define GTK_TYPE_ICON_VIEW_ACCESSIBLE (gtk_icon_view_accessible_get_type ())
5095 #define GTK_ICON_VIEW_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ICON_VIEW_ACCESSIBLE, GtkIconViewAccessible))
5096 #define GTK_IS_ICON_VIEW_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ICON_VIEW_ACCESSIBLE))
5098 static GType gtk_icon_view_accessible_get_type (void);
5103 } GtkIconViewAccessible;
5109 } GtkIconViewItemAccessibleInfo;
5115 GtkAdjustment *old_hadj;
5116 GtkAdjustment *old_vadj;
5118 GtkTreeModel *model;
5120 } GtkIconViewAccessiblePrivate;
5122 static GtkIconViewAccessiblePrivate *
5123 gtk_icon_view_accessible_get_priv (AtkObject *accessible)
5125 return g_object_get_qdata (G_OBJECT (accessible),
5126 accessible_private_data_quark);
5130 gtk_icon_view_item_accessible_info_new (AtkObject *accessible,
5134 GtkIconViewItemAccessibleInfo *info;
5135 GtkIconViewItemAccessibleInfo *tmp_info;
5136 GtkIconViewAccessiblePrivate *priv;
5139 info = g_new (GtkIconViewItemAccessibleInfo, 1);
5141 info->index = index;
5143 priv = gtk_icon_view_accessible_get_priv (accessible);
5144 items = priv->items;
5147 tmp_info = items->data;
5148 if (tmp_info->index > index)
5150 items = items->next;
5152 priv->items = g_list_insert_before (priv->items, items, info);
5153 priv->old_hadj = NULL;
5154 priv->old_vadj = NULL;
5158 gtk_icon_view_accessible_get_n_children (AtkObject *accessible)
5160 GtkIconView *icon_view;
5163 widget = GTK_ACCESSIBLE (accessible)->widget;
5167 icon_view = GTK_ICON_VIEW (widget);
5169 return g_list_length (icon_view->priv->items);
5173 gtk_icon_view_accessible_find_child (AtkObject *accessible,
5176 GtkIconViewAccessiblePrivate *priv;
5177 GtkIconViewItemAccessibleInfo *info;
5180 priv = gtk_icon_view_accessible_get_priv (accessible);
5181 items = priv->items;
5186 if (info->index == index)
5188 items = items->next;
5194 gtk_icon_view_accessible_ref_child (AtkObject *accessible,
5197 GtkIconView *icon_view;
5201 GtkIconViewItemAccessible *a11y_item;
5203 widget = GTK_ACCESSIBLE (accessible)->widget;
5207 icon_view = GTK_ICON_VIEW (widget);
5208 icons = g_list_nth (icon_view->priv->items, index);
5212 GtkIconViewItem *item = icons->data;
5214 g_return_val_if_fail (item->index == index, NULL);
5215 obj = gtk_icon_view_accessible_find_child (accessible, index);
5218 obj = g_object_new (gtk_icon_view_item_accessible_get_type (), NULL);
5219 gtk_icon_view_item_accessible_info_new (accessible,
5222 obj->role = ATK_ROLE_ICON;
5223 a11y_item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
5224 a11y_item->item = item;
5225 a11y_item->widget = widget;
5226 a11y_item->text_buffer = gtk_text_buffer_new (NULL);
5227 gtk_icon_view_update_item_text (icon_view, item);
5228 gtk_text_buffer_set_text (a11y_item->text_buffer,
5229 pango_layout_get_text (icon_view->priv->layout),
5231 gtk_icon_view_item_accessible_set_visibility (a11y_item, FALSE);
5232 g_object_add_weak_pointer (G_OBJECT (widget), (gpointer) &(a11y_item->widget));
5240 gtk_icon_view_accessible_traverse_items (GtkIconViewAccessible *view,
5243 GtkIconViewAccessiblePrivate *priv;
5244 GtkIconViewItemAccessibleInfo *info;
5245 GtkIconViewItemAccessible *item;
5248 priv = gtk_icon_view_accessible_get_priv (ATK_OBJECT (view));
5252 gboolean act_on_item;
5254 widget = GTK_ACCESSIBLE (view)->widget;
5258 items = priv->items;
5260 act_on_item = (list == NULL);
5265 info = (GtkIconViewItemAccessibleInfo *)items->data;
5266 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
5268 if (act_on_item == FALSE && list == items)
5272 gtk_icon_view_item_accessible_set_visibility (item, TRUE);
5274 items = items->next;
5280 gtk_icon_view_accessible_adjustment_changed (GtkAdjustment *adjustment,
5281 GtkIconView *icon_view)
5284 GtkIconViewAccessible *view;
5287 * The scrollbars have changed
5289 obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
5290 view = GTK_ICON_VIEW_ACCESSIBLE (obj);
5292 gtk_icon_view_accessible_traverse_items (view, NULL);
5296 gtk_icon_view_accessible_set_scroll_adjustments (GtkWidget *widget,
5297 GtkAdjustment *hadj,
5298 GtkAdjustment *vadj)
5301 GtkIconViewAccessiblePrivate *priv;
5303 atk_obj = gtk_widget_get_accessible (widget);
5304 priv = gtk_icon_view_accessible_get_priv (atk_obj);
5306 if (priv->old_hadj != hadj)
5310 g_object_remove_weak_pointer (G_OBJECT (priv->old_hadj),
5311 (gpointer *)&priv->old_hadj);
5313 g_signal_handlers_disconnect_by_func (priv->old_hadj,
5314 (gpointer) gtk_icon_view_accessible_adjustment_changed,
5317 priv->old_hadj = hadj;
5320 g_object_add_weak_pointer (G_OBJECT (priv->old_hadj),
5321 (gpointer *)&priv->old_hadj);
5322 g_signal_connect (hadj,
5324 G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
5328 if (priv->old_vadj != vadj)
5332 g_object_remove_weak_pointer (G_OBJECT (priv->old_vadj),
5333 (gpointer *)&priv->old_vadj);
5335 g_signal_handlers_disconnect_by_func (priv->old_vadj,
5336 (gpointer) gtk_icon_view_accessible_adjustment_changed,
5339 priv->old_vadj = vadj;
5342 g_object_add_weak_pointer (G_OBJECT (priv->old_vadj),
5343 (gpointer *)&priv->old_vadj);
5344 g_signal_connect (vadj,
5346 G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
5353 gtk_icon_view_accessible_model_row_changed (GtkTreeModel *tree_model,
5360 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
5361 g_signal_emit_by_name (atk_obj, "visible-data-changed");
5367 gtk_icon_view_accessible_model_row_inserted (GtkTreeModel *tree_model,
5372 GtkIconViewAccessiblePrivate *priv;
5373 GtkIconViewItemAccessibleInfo *info;
5374 GtkIconViewAccessible *view;
5375 GtkIconViewItemAccessible *item;
5381 index = gtk_tree_path_get_indices(path)[0];
5382 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
5383 view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
5384 priv = gtk_icon_view_accessible_get_priv (atk_obj);
5386 items = priv->items;
5391 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
5392 if (info->index != item->item->index)
5394 if (info->index < index)
5395 g_warning ("Unexpected index value on insertion %d %d", index, info->index);
5397 if (tmp_list == NULL)
5400 info->index = item->item->index;
5403 items = items->next;
5405 gtk_icon_view_accessible_traverse_items (view, tmp_list);
5406 g_signal_emit_by_name (atk_obj, "children_changed::add",
5412 gtk_icon_view_accessible_model_row_deleted (GtkTreeModel *tree_model,
5416 GtkIconViewAccessiblePrivate *priv;
5417 GtkIconViewItemAccessibleInfo *info;
5418 GtkIconViewAccessible *view;
5419 GtkIconViewItemAccessible *item;
5422 GList *deleted_item;
5426 index = gtk_tree_path_get_indices(path)[0];
5427 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
5428 view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
5429 priv = gtk_icon_view_accessible_get_priv (atk_obj);
5431 items = priv->items;
5433 deleted_item = NULL;
5438 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
5439 if (info->index == index)
5441 deleted_item = items;
5443 if (info->index != item->item->index)
5445 if (tmp_list == NULL)
5448 info->index = item->item->index;
5451 items = items->next;
5453 gtk_icon_view_accessible_traverse_items (view, tmp_list);
5456 info = deleted_item->data;
5457 gtk_icon_view_item_accessible_add_state (GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item), ATK_STATE_DEFUNCT, TRUE);
5459 g_signal_emit_by_name (atk_obj, "children_changed::remove",
5463 priv->items = g_list_remove_link (priv->items, deleted_item);
5471 gtk_icon_view_accessible_item_compare (GtkIconViewItemAccessibleInfo *i1,
5472 GtkIconViewItemAccessibleInfo *i2)
5474 return i1->index - i2->index;
5478 gtk_icon_view_accessible_model_rows_reordered (GtkTreeModel *tree_model,
5484 GtkIconViewAccessiblePrivate *priv;
5485 GtkIconViewItemAccessibleInfo *info;
5486 GtkIconViewAccessible *view;
5487 GtkIconView *icon_view;
5488 GtkIconViewItemAccessible *item;
5493 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
5494 icon_view = GTK_ICON_VIEW (user_data);
5495 view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
5496 priv = gtk_icon_view_accessible_get_priv (atk_obj);
5498 items = priv->items;
5503 item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
5504 info->index = new_order[info->index];
5505 tmp_list = g_list_nth (icon_view->priv->items, info->index);
5506 item->item = tmp_list->data;
5507 items = items->next;
5509 priv->items = g_list_sort (priv->items,
5510 (GCompareFunc)gtk_icon_view_accessible_item_compare);
5516 gtk_icon_view_accessible_disconnect_model_signals (GtkTreeModel *model,
5521 obj = G_OBJECT (model);
5522 g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_changed, widget);
5523 g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_inserted, widget);
5524 g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_deleted, widget);
5525 g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_rows_reordered, widget);
5529 gtk_icon_view_accessible_connect_model_signals (GtkIconView *icon_view)
5533 obj = G_OBJECT (icon_view->priv->model);
5534 g_signal_connect_data (obj, "row-changed",
5535 (GCallback) gtk_icon_view_accessible_model_row_changed,
5536 icon_view, NULL, 0);
5537 g_signal_connect_data (obj, "row-inserted",
5538 (GCallback) gtk_icon_view_accessible_model_row_inserted,
5539 icon_view, NULL, G_CONNECT_AFTER);
5540 g_signal_connect_data (obj, "row-deleted",
5541 (GCallback) gtk_icon_view_accessible_model_row_deleted,
5542 icon_view, NULL, G_CONNECT_AFTER);
5543 g_signal_connect_data (obj, "rows-reordered",
5544 (GCallback) gtk_icon_view_accessible_model_rows_reordered,
5545 icon_view, NULL, G_CONNECT_AFTER);
5549 gtk_icon_view_accessible_clear_cache (GtkIconViewAccessiblePrivate *priv)
5551 GtkIconViewItemAccessibleInfo *info;
5554 items = priv->items;
5557 info = (GtkIconViewItemAccessibleInfo *) items->data;
5558 g_object_unref (info->item);
5559 g_free (items->data);
5560 items = items->next;
5562 g_list_free (priv->items);
5567 gtk_icon_view_accessible_notify_gtk (GObject *obj,
5570 GtkIconView *icon_view;
5573 GtkIconViewAccessible *view;
5574 GtkIconViewAccessiblePrivate *priv;
5576 if (strcmp (pspec->name, "model") == 0)
5578 widget = GTK_WIDGET (obj);
5579 atk_obj = gtk_widget_get_accessible (widget);
5580 view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
5581 priv = gtk_icon_view_accessible_get_priv (atk_obj);
5584 g_object_remove_weak_pointer (G_OBJECT (priv->model),
5585 (gpointer *)&priv->model);
5586 gtk_icon_view_accessible_disconnect_model_signals (priv->model, widget);
5588 gtk_icon_view_accessible_clear_cache (priv);
5590 icon_view = GTK_ICON_VIEW (obj);
5591 priv->model = icon_view->priv->model;
5592 /* If there is no model the GtkIconView is probably being destroyed */
5595 g_object_add_weak_pointer (G_OBJECT (priv->model), (gpointer *)&priv->model);
5596 gtk_icon_view_accessible_connect_model_signals (icon_view);
5604 gtk_icon_view_accessible_initialize (AtkObject *accessible,
5607 GtkIconViewAccessiblePrivate *priv;
5608 GtkIconView *icon_view;
5610 if (ATK_OBJECT_CLASS (accessible_parent_class)->initialize)
5611 ATK_OBJECT_CLASS (accessible_parent_class)->initialize (accessible, data);
5613 priv = g_new0 (GtkIconViewAccessiblePrivate, 1);
5614 g_object_set_qdata (G_OBJECT (accessible),
5615 accessible_private_data_quark,
5618 icon_view = GTK_ICON_VIEW (data);
5619 if (icon_view->priv->hadjustment)
5621 priv->old_hadj = icon_view->priv->hadjustment;
5622 g_object_add_weak_pointer (G_OBJECT (priv->old_hadj), (gpointer *)&priv->old_hadj);
5623 g_signal_connect (icon_view->priv->hadjustment,
5625 G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
5628 if (icon_view->priv->vadjustment)
5630 priv->old_vadj = icon_view->priv->vadjustment;
5631 g_object_add_weak_pointer (G_OBJECT (priv->old_vadj), (gpointer *)&priv->old_vadj);
5632 g_signal_connect (icon_view->priv->vadjustment,
5634 G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
5637 g_signal_connect_after (data,
5638 "set_scroll_adjustments",
5639 G_CALLBACK (gtk_icon_view_accessible_set_scroll_adjustments),
5641 g_signal_connect (data,
5643 G_CALLBACK (gtk_icon_view_accessible_notify_gtk),
5646 priv->model = icon_view->priv->model;
5649 g_object_add_weak_pointer (G_OBJECT (priv->model), (gpointer *)&priv->model);
5650 gtk_icon_view_accessible_connect_model_signals (icon_view);
5653 accessible->role = ATK_ROLE_LAYERED_PANE;
5657 gtk_icon_view_accessible_finalize (GObject *object)
5659 GtkIconViewAccessiblePrivate *priv;
5661 priv = gtk_icon_view_accessible_get_priv (ATK_OBJECT (object));
5662 gtk_icon_view_accessible_clear_cache (priv);
5666 G_OBJECT_CLASS (accessible_parent_class)->finalize (object);
5670 gtk_icon_view_accessible_destroyed (GtkWidget *widget,
5671 GtkAccessible *accessible)
5674 GtkIconViewAccessiblePrivate *priv;
5676 atk_obj = ATK_OBJECT (accessible);
5677 priv = gtk_icon_view_accessible_get_priv (atk_obj);
5680 g_object_remove_weak_pointer (G_OBJECT (priv->old_hadj),
5681 (gpointer *)&priv->old_hadj);
5683 g_signal_handlers_disconnect_by_func (priv->old_hadj,
5684 (gpointer) gtk_icon_view_accessible_adjustment_changed,
5686 priv->old_hadj = NULL;
5690 g_object_remove_weak_pointer (G_OBJECT (priv->old_vadj),
5691 (gpointer *)&priv->old_vadj);
5693 g_signal_handlers_disconnect_by_func (priv->old_vadj,
5694 (gpointer) gtk_icon_view_accessible_adjustment_changed,
5696 priv->old_vadj = NULL;
5701 gtk_icon_view_accessible_connect_widget_destroyed (GtkAccessible *accessible)
5703 if (accessible->widget)
5705 g_signal_connect_after (accessible->widget,
5707 G_CALLBACK (gtk_icon_view_accessible_destroyed),
5710 GTK_ACCESSIBLE_CLASS (accessible_parent_class)->connect_widget_destroyed (accessible);
5714 gtk_icon_view_accessible_class_init (AtkObjectClass *klass)
5716 GObjectClass *gobject_class;
5717 GtkAccessibleClass *accessible_class;
5719 accessible_parent_class = g_type_class_peek_parent (klass);
5721 gobject_class = (GObjectClass *)klass;
5722 accessible_class = (GtkAccessibleClass *)klass;
5724 gobject_class->finalize = gtk_icon_view_accessible_finalize;
5726 klass->get_n_children = gtk_icon_view_accessible_get_n_children;
5727 klass->ref_child = gtk_icon_view_accessible_ref_child;
5728 klass->initialize = gtk_icon_view_accessible_initialize;
5730 accessible_class->connect_widget_destroyed = gtk_icon_view_accessible_connect_widget_destroyed;
5732 accessible_private_data_quark = g_quark_from_static_string ("icon_view-accessible-private-data");
5736 gtk_icon_view_accessible_ref_accessible_at_point (AtkComponent *component,
5739 AtkCoordType coord_type)
5742 GtkIconView *icon_view;
5743 GtkIconViewItem *item;
5746 widget = GTK_ACCESSIBLE (component)->widget;
5748 /* State is defunct */
5751 icon_view = GTK_ICON_VIEW (widget);
5752 atk_component_get_extents (component, &x_pos, &y_pos, NULL, NULL, coord_type);
5753 item = gtk_icon_view_get_item_at_pos (icon_view, x - x_pos, y - y_pos);
5755 return gtk_icon_view_accessible_ref_child (ATK_OBJECT (component), item->index);
5761 atk_component_interface_init (AtkComponentIface *iface)
5763 iface->ref_accessible_at_point = gtk_icon_view_accessible_ref_accessible_at_point;
5767 gtk_icon_view_accessible_add_selection (AtkSelection *selection,
5771 GtkIconView *icon_view;
5772 GtkIconViewItem *item;
5775 widget = GTK_ACCESSIBLE (selection)->widget;
5779 icon_view = GTK_ICON_VIEW (widget);
5781 l = g_list_nth (icon_view->priv->items, i);
5786 gtk_icon_view_select_item (icon_view, item);
5792 gtk_icon_view_accessible_clear_selection (AtkSelection *selection)
5795 GtkIconView *icon_view;
5797 widget = GTK_ACCESSIBLE (selection)->widget;
5801 icon_view = GTK_ICON_VIEW (widget);
5802 gtk_icon_view_unselect_all (icon_view);
5808 gtk_icon_view_accessible_ref_selection (AtkSelection *selection,
5812 GtkIconView *icon_view;
5813 GtkIconViewItem *item;
5816 widget = GTK_ACCESSIBLE (selection)->widget;
5820 icon_view = GTK_ICON_VIEW (widget);
5822 l = icon_view->priv->items;
5829 return atk_object_ref_accessible_child (gtk_widget_get_accessible (widget), item->index);
5840 gtk_icon_view_accessible_get_selection_count (AtkSelection *selection)
5843 GtkIconView *icon_view;
5844 GtkIconViewItem *item;
5848 widget = GTK_ACCESSIBLE (selection)->widget;
5852 icon_view = GTK_ICON_VIEW (widget);
5854 l = icon_view->priv->items;
5870 gtk_icon_view_accessible_is_child_selected (AtkSelection *selection,
5874 GtkIconView *icon_view;
5875 GtkIconViewItem *item;
5878 widget = GTK_ACCESSIBLE (selection)->widget;
5882 icon_view = GTK_ICON_VIEW (widget);
5883 l = g_list_nth (icon_view->priv->items, i);
5889 return item->selected;
5893 gtk_icon_view_accessible_remove_selection (AtkSelection *selection,
5897 GtkIconView *icon_view;
5898 GtkIconViewItem *item;
5902 widget = GTK_ACCESSIBLE (selection)->widget;
5906 icon_view = GTK_ICON_VIEW (widget);
5907 l = icon_view->priv->items;
5916 gtk_icon_view_unselect_item (icon_view, item);
5928 gtk_icon_view_accessible_select_all_selection (AtkSelection *selection)
5931 GtkIconView *icon_view;
5933 widget = GTK_ACCESSIBLE (selection)->widget;
5937 icon_view = GTK_ICON_VIEW (widget);
5938 gtk_icon_view_select_all (icon_view);
5943 gtk_icon_view_accessible_selection_interface_init (AtkSelectionIface *iface)
5945 iface->add_selection = gtk_icon_view_accessible_add_selection;
5946 iface->clear_selection = gtk_icon_view_accessible_clear_selection;
5947 iface->ref_selection = gtk_icon_view_accessible_ref_selection;
5948 iface->get_selection_count = gtk_icon_view_accessible_get_selection_count;
5949 iface->is_child_selected = gtk_icon_view_accessible_is_child_selected;
5950 iface->remove_selection = gtk_icon_view_accessible_remove_selection;
5951 iface->select_all_selection = gtk_icon_view_accessible_select_all_selection;
5955 gtk_icon_view_accessible_get_type (void)
5957 static GType type = 0;
5961 static GTypeInfo tinfo =
5964 (GBaseInitFunc) NULL, /* base init */
5965 (GBaseFinalizeFunc) NULL, /* base finalize */
5966 (GClassInitFunc) gtk_icon_view_accessible_class_init,
5967 (GClassFinalizeFunc) NULL, /* class finalize */
5968 NULL, /* class data */
5969 0, /* instance size */
5970 0, /* nb preallocs */
5971 (GInstanceInitFunc) NULL, /* instance init */
5972 NULL /* value table */
5974 static const GInterfaceInfo atk_component_info =
5976 (GInterfaceInitFunc) atk_component_interface_init,
5977 (GInterfaceFinalizeFunc) NULL,
5980 static const GInterfaceInfo atk_selection_info =
5982 (GInterfaceInitFunc) gtk_icon_view_accessible_selection_interface_init,
5983 (GInterfaceFinalizeFunc) NULL,
5988 * Figure out the size of the class and instance
5989 * we are deriving from
5991 AtkObjectFactory *factory;
5994 GType derived_atk_type;
5996 derived_type = g_type_parent (GTK_TYPE_ICON_VIEW);
5997 factory = atk_registry_get_factory (atk_get_default_registry (),
5999 derived_atk_type = atk_object_factory_get_accessible_type (factory);
6000 g_type_query (derived_atk_type, &query);
6001 tinfo.class_size = query.class_size;
6002 tinfo.instance_size = query.instance_size;
6004 type = g_type_register_static (derived_atk_type,
6005 "GtkIconViewAccessible",
6007 g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
6008 &atk_component_info);
6009 g_type_add_interface_static (type, ATK_TYPE_SELECTION,
6010 &atk_selection_info);
6016 gtk_icon_view_accessible_new (GObject *obj)
6018 AtkObject *accessible;
6020 g_return_val_if_fail (GTK_IS_WIDGET (obj), NULL);
6022 accessible = g_object_new (gtk_icon_view_accessible_get_type (), NULL);
6023 atk_object_initialize (accessible, obj);
6029 gtk_icon_view_accessible_factory_get_accessible_type (void)
6031 return gtk_icon_view_accessible_get_type ();
6035 gtk_icon_view_accessible_factory_create_accessible (GObject *obj)
6037 return gtk_icon_view_accessible_new (obj);
6041 gtk_icon_view_accessible_factory_class_init (AtkObjectFactoryClass *klass)
6043 klass->create_accessible = gtk_icon_view_accessible_factory_create_accessible;
6044 klass->get_accessible_type = gtk_icon_view_accessible_factory_get_accessible_type;
6048 gtk_icon_view_accessible_factory_get_type (void)
6050 static GType type = 0;
6054 static const GTypeInfo tinfo =
6056 sizeof (AtkObjectFactoryClass),
6057 NULL, /* base_init */
6058 NULL, /* base_finalize */
6059 (GClassInitFunc) gtk_icon_view_accessible_factory_class_init,
6060 NULL, /* class_finalize */
6061 NULL, /* class_data */
6062 sizeof (AtkObjectFactory),
6063 0, /* n_preallocs */
6067 type = g_type_register_static (ATK_TYPE_OBJECT_FACTORY,
6068 "GtkIconViewAccessibleFactory",
6075 gtk_icon_view_get_accessible (GtkWidget *widget)
6077 static gboolean first_time = TRUE;
6081 AtkObjectFactory *factory;
6082 AtkRegistry *registry;
6084 GType derived_atk_type;
6087 * Figure out whether accessibility is enabled by looking at the
6088 * type of the accessible object which would be created for
6089 * the parent type of GtkIconView.
6091 derived_type = g_type_parent (GTK_TYPE_ICON_VIEW);
6093 registry = atk_get_default_registry ();
6094 factory = atk_registry_get_factory (registry,
6096 derived_atk_type = atk_object_factory_get_accessible_type (factory);
6097 if (g_type_is_a (derived_atk_type, GTK_TYPE_ACCESSIBLE))
6098 atk_registry_set_factory_type (registry,
6100 gtk_icon_view_accessible_factory_get_type ());
6103 return GTK_WIDGET_CLASS (parent_class)->get_accessible (widget);