]> Pileus Git - ~andy/gtk/blob - gtk/gtkiconview.c
Add a new :orientation property to determine whether text is positioned
[~andy/gtk] / gtk / gtkiconview.c
1 /* gtkiconview.c
2  * Copyright (C) 2002, 2004  Anders Carlsson <andersca@gnu.org>
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 #include <config.h>
21 #include <string.h>
22
23 #include <gdk/gdkkeysyms.h>
24
25 #include "gtkiconview.h"
26 #include "gtkmarshalers.h"
27 #include "gtkbindings.h"
28 #include "gtkdnd.h"
29 #include "gtkmain.h"
30 #include "gtksignal.h"
31 #include "gtkintl.h"
32
33 #define MINIMUM_ICON_ITEM_WIDTH 100
34 #define ICON_TEXT_PADDING 3
35
36 #define ICON_VIEW_TOP_MARGIN 6
37 #define ICON_VIEW_BOTTOM_MARGIN 6
38 #define ICON_VIEW_LEFT_MARGIN 6
39 #define ICON_VIEW_RIGHT_MARGIN 6
40 #define ICON_VIEW_ICON_PADDING 6
41
42 #define GTK_ICON_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ICON_VIEW, GtkIconViewPrivate))
43 #define VALID_MODEL_AND_COLUMNS(obj) ((obj)->priv->model != NULL && \
44                                       ((obj)->priv->pixbuf_column != -1 || \
45                                        (obj)->priv->text_column != -1 || \
46                                        (obj)->priv->markup_column != -1))
47
48 typedef struct 
49 {
50   GtkTreeIter iter;
51   int index;
52   
53   gint row, col;
54
55   /* Bounding boxes */
56   gint x, y;
57   gint width, height;
58
59   gint pixbuf_x, pixbuf_y;
60   gint pixbuf_height, pixbuf_width;
61
62   gint layout_x, layout_y;
63   gint layout_width, layout_height;
64
65   guint selected : 1;
66   guint selected_before_rubberbanding : 1;
67 } GtkIconViewItem;
68
69 struct _GtkIconViewPrivate
70 {
71   gint width, height;
72
73   gint text_column;
74   gint markup_column;
75   gint pixbuf_column;
76   
77   GtkSelectionMode selection_mode;
78
79   GdkWindow *bin_window;
80
81   GtkTreeModel *model;
82   
83   GList *items;
84   
85   GtkAdjustment *hadjustment;
86   GtkAdjustment *vadjustment;
87
88   guint layout_idle_id;
89   
90   gboolean doing_rubberband;
91   gint rubberband_x1, rubberband_y1;
92   gint rubberband_x2, rubberband_y2;
93
94   guint scroll_timeout_id;
95   gint scroll_value_diff;
96   gint event_last_x, event_last_y;
97
98   GtkIconViewItem *anchor_item;
99   GtkIconViewItem *cursor_item;
100
101   guint ctrl_pressed : 1;
102   guint shift_pressed : 1;
103   
104   GtkIconViewItem *last_single_clicked;
105
106 #ifdef DND_WORKS
107   /* Drag-and-drop. */
108   gint pressed_button;
109   gint press_start_x;
110   gint press_start_y;
111 #endif
112   
113   /* Layout used to draw icon text */
114   PangoLayout *layout;
115   
116   GtkOrientation orientation;
117 };
118
119 /* Signals */
120 enum
121 {
122   ITEM_ACTIVATED,
123   SELECTION_CHANGED,
124   SELECT_ALL,
125   UNSELECT_ALL,
126   SELECT_CURSOR_ITEM,
127   TOGGLE_CURSOR_ITEM,
128   MOVE_CURSOR,
129   ACTIVATE_CURSOR_ITEM,
130   LAST_SIGNAL
131 };
132
133 /* Properties */
134 enum
135 {
136   PROP_0,
137   PROP_PIXBUF_COLUMN,
138   PROP_TEXT_COLUMN,
139   PROP_MARKUP_COLUMN,  
140   PROP_SELECTION_MODE,
141   PROP_ORIENTATION,
142   PROP_MODEL,
143 };
144
145 /* GObject signals */
146 static void gtk_icon_view_finalize     (GObject      *object);
147 static void gtk_icon_view_set_property (GObject      *object,
148                                         guint         prop_id,
149                                         const GValue *value,
150                                         GParamSpec   *pspec);
151 static void gtk_icon_view_get_property (GObject      *object,
152                                         guint         prop_id,
153                                         GValue       *value,
154                                         GParamSpec   *pspec);
155
156
157 /* GtkObject signals */
158 static void gtk_icon_view_destroy (GtkObject *object);
159
160 /* GtkWidget signals */
161 static void     gtk_icon_view_realize        (GtkWidget      *widget);
162 static void     gtk_icon_view_unrealize      (GtkWidget      *widget);
163 static void     gtk_icon_view_map            (GtkWidget      *widget);
164 static void     gtk_icon_view_size_request   (GtkWidget      *widget,
165                                               GtkRequisition *requisition);
166 static void     gtk_icon_view_size_allocate  (GtkWidget      *widget,
167                                               GtkAllocation  *allocation);
168 static gboolean gtk_icon_view_expose         (GtkWidget      *widget,
169                                               GdkEventExpose *expose);
170 static gboolean gtk_icon_view_motion         (GtkWidget      *widget,
171                                               GdkEventMotion *event);
172 static gboolean gtk_icon_view_button_press   (GtkWidget      *widget,
173                                               GdkEventButton *event);
174 static gboolean gtk_icon_view_button_release (GtkWidget      *widget,
175                                               GdkEventButton *event);
176
177 /* GtkIconView signals */
178 static void     gtk_icon_view_set_adjustments           (GtkIconView   *icon_view,
179                                                          GtkAdjustment *hadj,
180                                                          GtkAdjustment *vadj);
181 static void     gtk_icon_view_real_select_all           (GtkIconView   *icon_view);
182 static void     gtk_icon_view_real_unselect_all         (GtkIconView   *icon_view);
183 static void     gtk_icon_view_real_select_cursor_item   (GtkIconView   *icon_view);
184 static void     gtk_icon_view_real_toggle_cursor_item   (GtkIconView   *icon_view);
185 static gboolean gtk_icon_view_real_activate_cursor_item (GtkIconView   *icon_view);
186
187 /* Internal functions */
188 static void       gtk_icon_view_adjustment_changed          (GtkAdjustment   *adjustment,
189                                                              GtkIconView     *icon_view);
190 static void       gtk_icon_view_layout                      (GtkIconView     *icon_view);
191 static void       gtk_icon_view_paint_item                  (GtkIconView     *icon_view,
192                                                              GtkIconViewItem *item,
193                                                              GdkRectangle    *area);
194 static void       gtk_icon_view_paint_rubberband            (GtkIconView     *icon_view,
195                                                              GdkRectangle    *area);
196 static void       gtk_icon_view_queue_draw_item             (GtkIconView     *icon_view,
197                                                              GtkIconViewItem *item);
198 static void       gtk_icon_view_queue_layout                (GtkIconView     *icon_view);
199 static void       gtk_icon_view_set_cursor_item             (GtkIconView     *icon_view,
200                                                              GtkIconViewItem *item);
201 static void       gtk_icon_view_start_rubberbanding         (GtkIconView     *icon_view,
202                                                              gint             x,
203                                                              gint             y);
204 static void       gtk_icon_view_stop_rubberbanding          (GtkIconView     *icon_view);
205 static void       gtk_icon_view_update_rubberband_selection (GtkIconView     *icon_view);
206 static gboolean   gtk_icon_view_item_hit_test               (GtkIconViewItem *item,
207                                                              gint             x,
208                                                              gint             y,
209                                                              gint             width,
210                                                              gint             height);
211 #ifdef DND_WORKS
212 static gboolean   gtk_icon_view_maybe_begin_dragging_items  (GtkIconView     *icon_view,
213                                                              GdkEventMotion  *event);
214 #endif
215 static gboolean   gtk_icon_view_unselect_all_internal       (GtkIconView     *icon_view);
216 static void       gtk_icon_view_calculate_item_size         (GtkIconView     *icon_view,
217                                                              GtkIconViewItem *item);
218 static void       gtk_icon_view_update_rubberband           (gpointer         data);
219 static void       gtk_icon_view_item_invalidate_size        (GtkIconViewItem *item);
220 static void       gtk_icon_view_invalidate_sizes            (GtkIconView     *icon_view);
221 static void       gtk_icon_view_add_move_binding            (GtkBindingSet   *binding_set,
222                                                              guint            keyval,
223                                                              guint            modmask,
224                                                              GtkMovementStep  step,
225                                                              gint             count);
226 static gboolean   gtk_icon_view_real_move_cursor            (GtkIconView     *icon_view,
227                                                              GtkMovementStep  step,
228                                                              gint             count);
229 static void       gtk_icon_view_move_cursor_up_down         (GtkIconView     *icon_view,
230                                                              gint             count);
231 static void       gtk_icon_view_move_cursor_page_up_down    (GtkIconView     *icon_view,
232                                                              gint             count);
233 static void       gtk_icon_view_move_cursor_left_right      (GtkIconView     *icon_view,
234                                                              gint             count);
235 static void       gtk_icon_view_move_cursor_start_end       (GtkIconView     *icon_view,
236                                                              gint             count);
237 static void       gtk_icon_view_scroll_to_item              (GtkIconView     *icon_view,
238                                                              GtkIconViewItem *item);
239 static GdkPixbuf *gtk_icon_view_get_item_icon               (GtkIconView     *icon_view,
240                                                              GtkIconViewItem *item);
241 static void       gtk_icon_view_update_item_text            (GtkIconView     *icon_view,
242                                                              GtkIconViewItem *item);
243 static void       gtk_icon_view_select_item                 (GtkIconView     *icon_view,
244                                                              GtkIconViewItem *item);
245 static void       gtk_icon_view_unselect_item               (GtkIconView     *icon_view,
246                                                              GtkIconViewItem *item);
247 static gboolean gtk_icon_view_select_all_between            (GtkIconView     *icon_view,
248                                                              GtkIconViewItem *anchor,
249                                                              GtkIconViewItem *cursor);
250
251 static GtkIconViewItem *gtk_icon_view_get_item_at_pos (GtkIconView *icon_view,
252                                                        gint         x,
253                                                        gint         y);
254
255
256
257
258
259 static GtkContainerClass *parent_class = NULL;
260 static guint icon_view_signals[LAST_SIGNAL] = { 0 };
261
262 G_DEFINE_TYPE (GtkIconView, gtk_icon_view, GTK_TYPE_CONTAINER);
263
264 static void
265 gtk_icon_view_class_init (GtkIconViewClass *klass)
266 {
267   GObjectClass *gobject_class;
268   GtkObjectClass *object_class;
269   GtkWidgetClass *widget_class;
270   GtkBindingSet *binding_set;
271   
272   parent_class = g_type_class_peek_parent (klass);
273   binding_set = gtk_binding_set_by_class (klass);
274
275   g_type_class_add_private (klass, sizeof (GtkIconViewPrivate));
276
277   gobject_class = (GObjectClass *) klass;
278   object_class = (GtkObjectClass *) klass;
279   widget_class = (GtkWidgetClass *) klass;
280
281   gobject_class->finalize = gtk_icon_view_finalize;
282   gobject_class->set_property = gtk_icon_view_set_property;
283   gobject_class->get_property = gtk_icon_view_get_property;
284
285   object_class->destroy = gtk_icon_view_destroy;
286   
287   widget_class->realize = gtk_icon_view_realize;
288   widget_class->unrealize = gtk_icon_view_unrealize;
289   widget_class->map = gtk_icon_view_map;
290   widget_class->size_request = gtk_icon_view_size_request;
291   widget_class->size_allocate = gtk_icon_view_size_allocate;
292   widget_class->expose_event = gtk_icon_view_expose;
293   widget_class->motion_notify_event = gtk_icon_view_motion;
294   widget_class->button_press_event = gtk_icon_view_button_press;
295   widget_class->button_release_event = gtk_icon_view_button_release;
296   
297   klass->set_scroll_adjustments = gtk_icon_view_set_adjustments;
298   klass->select_all = gtk_icon_view_real_select_all;
299   klass->unselect_all = gtk_icon_view_real_unselect_all;
300   klass->select_cursor_item = gtk_icon_view_real_select_cursor_item;
301   klass->toggle_cursor_item = gtk_icon_view_real_toggle_cursor_item;
302   klass->activate_cursor_item = gtk_icon_view_real_activate_cursor_item;  
303   klass->move_cursor = gtk_icon_view_real_move_cursor;
304   
305   /* Properties */
306   /**
307    * GtkIconView:selection-mode:
308    * 
309    * The ::selection-mode property specifies the selection mode of
310    * icon view. If the mode is #GTK_SELECTION_MULTIPLE, rubberband selection
311    * is enabled, for the other modes, only keyboard selection is possible.
312    *
313    * Since: 2.6
314    */
315   g_object_class_install_property (gobject_class,
316                                    PROP_SELECTION_MODE,
317                                    g_param_spec_enum ("selection_mode",
318                                                       P_("Selection mode"),
319                                                       P_("The selection mode"),
320                                                       GTK_TYPE_SELECTION_MODE,
321                                                       GTK_SELECTION_SINGLE,
322                                                       G_PARAM_READWRITE));
323
324   /**
325    * GtkIconView:pixbuf-column:
326    *
327    * The ::pixbuf-column property contains the number of the model column
328    * containing the pixbufs which are displayed. The pixbuf column must be 
329    * of type #GDK_TYPE_PIXBUF. Setting this property to -1 turns off the
330    * display of pixbufs.
331    *
332    * Since: 2.6
333    */
334   g_object_class_install_property (gobject_class,
335                                    PROP_PIXBUF_COLUMN,
336                                    g_param_spec_int ("pixbuf_column",
337                                                      P_("Pixbuf column"),
338                                                      P_("Model column used to retrieve the icon pixbuf from"),
339                                                      -1, G_MAXINT, -1,
340                                                      G_PARAM_READWRITE));
341
342   /**
343    * GtkIconView:text-column:
344    *
345    * The ::text-column property contains the number of the model column
346    * containing the texts which are displayed. The text column must be 
347    * of type #G_TYPE_STRING. If this property and the :markup-column 
348    * property are both set to -1, no texts are displayed.   
349    *
350    * Since: 2.6
351    */
352   g_object_class_install_property (gobject_class,
353                                    PROP_TEXT_COLUMN,
354                                    g_param_spec_int ("text_column",
355                                                      P_("Text column"),
356                                                      P_("Model column used to retrieve the text from"),
357                                                      -1, G_MAXINT, -1,
358                                                      G_PARAM_READWRITE));
359
360   
361   /**
362    * GtkIconView:markup-column:
363    *
364    * The ::markup-column property contains the number of the model column
365    * containing markup information to be displayed. The markup column must be 
366    * of type #G_TYPE_STRING. If this property and the :text-column property 
367    * are both set to column numbers, it overrides the text column.
368    * If both are set to -1, no texts are displayed.   
369    *
370    * Since: 2.6
371    */
372   g_object_class_install_property (gobject_class,
373                                    PROP_MARKUP_COLUMN,
374                                    g_param_spec_int ("markup_column",
375                                                      P_("Markup column"),
376                                                      P_("Model column used to retrieve the text if using Pango markup"),
377                                                      -1, G_MAXINT, -1,
378                                                      G_PARAM_READWRITE));
379   
380   g_object_class_install_property (gobject_class,
381                                    PROP_MODEL,
382                                    g_param_spec_object ("model",
383                                                         P_("Icon View Model"),
384                                                         P_("The model for the icon view"),
385                                                         GTK_TYPE_TREE_MODEL,
386                                                         G_PARAM_READWRITE));
387   
388   g_object_class_install_property (gobject_class,
389                                    PROP_ORIENTATION,
390                                    g_param_spec_enum ("orientation",
391                                                       P_("Orientation"),
392                                                       P_("How the text and icon of each item are positioned relative to each other"),
393                                                       GTK_TYPE_ORIENTATION,
394                                                       GTK_ORIENTATION_VERTICAL,
395                                                       G_PARAM_READWRITE));
396
397   /* Style properties */
398   gtk_widget_class_install_style_property (widget_class,
399                                            g_param_spec_boxed ("selection_box_color",
400                                                                P_("Selection Box Color"),
401                                                                P_("Color of the selection box"),
402                                                                GDK_TYPE_COLOR,
403                                                                G_PARAM_READABLE));
404
405   gtk_widget_class_install_style_property (widget_class,
406                                            g_param_spec_uchar ("selection_box_alpha",
407                                                                P_("Selection Box Alpha"),
408                                                                P_("Opacity of the selection box"),
409                                                                0, 0xff,
410                                                                0x40,
411                                                                G_PARAM_READABLE));
412
413   /* Signals */
414   widget_class->set_scroll_adjustments_signal =
415     g_signal_new ("set_scroll_adjustments",
416                   G_TYPE_FROM_CLASS (gobject_class),
417                   G_SIGNAL_RUN_LAST,
418                   G_STRUCT_OFFSET (GtkIconViewClass, set_scroll_adjustments),
419                   NULL, NULL, 
420                   _gtk_marshal_VOID__OBJECT_OBJECT,
421                   G_TYPE_NONE, 2,
422                   GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
423
424   icon_view_signals[ITEM_ACTIVATED] =
425     g_signal_new ("item_activated",
426                   G_TYPE_FROM_CLASS (gobject_class),
427                   G_SIGNAL_RUN_LAST,
428                   G_STRUCT_OFFSET (GtkIconViewClass, item_activated),
429                   NULL, NULL,
430                   g_cclosure_marshal_VOID__BOXED,
431                   G_TYPE_NONE, 1,
432                   GTK_TYPE_TREE_PATH);
433
434   icon_view_signals[SELECTION_CHANGED] =
435     g_signal_new ("selection_changed",
436                   G_TYPE_FROM_CLASS (gobject_class),
437                   G_SIGNAL_RUN_FIRST,
438                   G_STRUCT_OFFSET (GtkIconViewClass, selection_changed),
439                   NULL, NULL,
440                   g_cclosure_marshal_VOID__VOID,
441                   G_TYPE_NONE, 0);
442   
443   icon_view_signals[SELECT_ALL] =
444     g_signal_new ("select_all",
445                   G_TYPE_FROM_CLASS (gobject_class),
446                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
447                   G_STRUCT_OFFSET (GtkIconViewClass, select_all),
448                   NULL, NULL,
449                   g_cclosure_marshal_VOID__VOID,
450                   G_TYPE_NONE, 0);
451   
452   icon_view_signals[UNSELECT_ALL] =
453     g_signal_new ("unselect_all",
454                   G_TYPE_FROM_CLASS (gobject_class),
455                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
456                   G_STRUCT_OFFSET (GtkIconViewClass, unselect_all),
457                   NULL, NULL,
458                   g_cclosure_marshal_VOID__VOID,
459                   G_TYPE_NONE, 0);
460
461   icon_view_signals[SELECT_CURSOR_ITEM] =
462     g_signal_new ("select_cursor_item",
463                   G_TYPE_FROM_CLASS (gobject_class),
464                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
465                   G_STRUCT_OFFSET (GtkIconViewClass, select_cursor_item),
466                   NULL, NULL,
467                   g_cclosure_marshal_VOID__VOID,
468                   G_TYPE_NONE, 0);
469
470   icon_view_signals[TOGGLE_CURSOR_ITEM] =
471     g_signal_new ("toggle_cursor_item",
472                   G_TYPE_FROM_CLASS (gobject_class),
473                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
474                   G_STRUCT_OFFSET (GtkIconViewClass, toggle_cursor_item),
475                   NULL, NULL,
476                   g_cclosure_marshal_VOID__VOID,
477                   G_TYPE_NONE, 0);
478
479   icon_view_signals[ACTIVATE_CURSOR_ITEM] =
480     g_signal_new ("activate_cursor_item",
481                   G_TYPE_FROM_CLASS (gobject_class),
482                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
483                   G_STRUCT_OFFSET (GtkIconViewClass, activate_cursor_item),
484                   NULL, NULL,
485                   _gtk_marshal_BOOLEAN__VOID,
486                   G_TYPE_BOOLEAN, 0);
487   
488   icon_view_signals[MOVE_CURSOR] =
489     g_signal_new ("move_cursor",
490                   G_TYPE_FROM_CLASS (gobject_class),
491                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
492                   G_STRUCT_OFFSET (GtkIconViewClass, move_cursor),
493                   NULL, NULL,
494                   _gtk_marshal_BOOLEAN__ENUM_INT,
495                   G_TYPE_BOOLEAN, 2,
496                   GTK_TYPE_MOVEMENT_STEP,
497                   G_TYPE_INT);
498
499   /* Key bindings */
500   gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, "select_all", 0);
501   gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect_all", 0);
502   gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select_cursor_item", 0);
503   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, "toggle_cursor_item", 0);
504
505   gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, "activate_cursor_item", 0);
506   gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0, "activate_cursor_item", 0);
507   gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, "activate_cursor_item", 0);
508
509   gtk_icon_view_add_move_binding (binding_set, GDK_Up, 0,
510                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
511   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Up, 0,
512                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
513
514   gtk_icon_view_add_move_binding (binding_set, GDK_Down, 0,
515                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
516   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Down, 0,
517                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
518
519   gtk_icon_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK,
520                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
521
522   gtk_icon_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK,
523                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
524
525   gtk_icon_view_add_move_binding (binding_set, GDK_Home, 0,
526                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
527   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Home, 0,
528                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
529
530   gtk_icon_view_add_move_binding (binding_set, GDK_End, 0,
531                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
532   gtk_icon_view_add_move_binding (binding_set, GDK_KP_End, 0,
533                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
534
535   gtk_icon_view_add_move_binding (binding_set, GDK_Page_Up, 0,
536                                   GTK_MOVEMENT_PAGES, -1);
537   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Page_Up, 0,
538                                   GTK_MOVEMENT_PAGES, -1);
539
540   gtk_icon_view_add_move_binding (binding_set, GDK_Page_Down, 0,
541                                   GTK_MOVEMENT_PAGES, 1);
542   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Page_Down, 0,
543                                   GTK_MOVEMENT_PAGES, 1);
544
545   gtk_icon_view_add_move_binding (binding_set, GDK_Right, 0, 
546                                   GTK_MOVEMENT_VISUAL_POSITIONS, 1);
547   gtk_icon_view_add_move_binding (binding_set, GDK_Left, 0, 
548                                   GTK_MOVEMENT_VISUAL_POSITIONS, -1);
549
550   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Right, 0, 
551                                   GTK_MOVEMENT_VISUAL_POSITIONS, 1);
552   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Left, 0, 
553                                   GTK_MOVEMENT_VISUAL_POSITIONS, -1);
554 }
555
556 static void
557 gtk_icon_view_init (GtkIconView *icon_view)
558 {
559   icon_view->priv = GTK_ICON_VIEW_GET_PRIVATE (icon_view);
560   
561   icon_view->priv->width = 0;
562   icon_view->priv->height = 0;
563   icon_view->priv->selection_mode = GTK_SELECTION_SINGLE;
564 #ifdef DND_WORKS
565   icon_view->priv->pressed_button = -1;
566   icon_view->priv->press_start_x = -1;
567   icon_view->priv->press_start_y = -1;
568 #endif
569   icon_view->priv->text_column = -1;
570   icon_view->priv->markup_column = -1;  
571   icon_view->priv->pixbuf_column = -1;
572   
573   icon_view->priv->layout = gtk_widget_create_pango_layout (GTK_WIDGET (icon_view), NULL);
574
575   pango_layout_set_wrap (icon_view->priv->layout, PANGO_WRAP_WORD_CHAR);
576
577   GTK_WIDGET_SET_FLAGS (icon_view, GTK_CAN_FOCUS);
578   
579   gtk_icon_view_set_adjustments (icon_view, NULL, NULL);
580
581   icon_view->priv->orientation = GTK_ORIENTATION_VERTICAL;
582 }
583
584 static void
585 gtk_icon_view_destroy (GtkObject *object)
586 {
587   GtkIconView *icon_view;
588
589   icon_view = GTK_ICON_VIEW (object);
590   
591   gtk_icon_view_set_model (icon_view, NULL);
592   
593   if (icon_view->priv->layout_idle_id != 0)
594     g_source_remove (icon_view->priv->layout_idle_id);
595
596   if (icon_view->priv->scroll_timeout_id != 0)
597     g_source_remove (icon_view->priv->scroll_timeout_id);
598   
599   (GTK_OBJECT_CLASS (parent_class)->destroy) (object);
600 }
601
602 /* GObject methods */
603 static void
604 gtk_icon_view_finalize (GObject *object)
605 {
606   GtkIconView *icon_view;
607
608   icon_view = GTK_ICON_VIEW (object);
609
610   g_object_unref (icon_view->priv->layout);
611   
612   (G_OBJECT_CLASS (parent_class)->finalize) (object);
613 }
614
615
616 static void
617 gtk_icon_view_set_property (GObject      *object,
618                             guint         prop_id,
619                             const GValue *value,
620                             GParamSpec   *pspec)
621 {
622   GtkIconView *icon_view;
623
624   icon_view = GTK_ICON_VIEW (object);
625
626   switch (prop_id)
627     {
628     case PROP_SELECTION_MODE:
629       gtk_icon_view_set_selection_mode (icon_view, g_value_get_enum (value));
630       break;
631     case PROP_PIXBUF_COLUMN:
632       gtk_icon_view_set_pixbuf_column (icon_view, g_value_get_int (value));
633       break;
634     case PROP_TEXT_COLUMN:
635       gtk_icon_view_set_text_column (icon_view, g_value_get_int (value));
636       break;
637     case PROP_MARKUP_COLUMN:
638       gtk_icon_view_set_markup_column (icon_view, g_value_get_int (value));
639       break;
640     case PROP_MODEL:
641       gtk_icon_view_set_model (icon_view, g_value_get_object (value));
642       break;
643     case PROP_ORIENTATION:
644       gtk_icon_view_set_orientation (icon_view, g_value_get_enum (value));
645       break;
646       
647     default:
648       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
649       break;
650     }
651 }
652
653 static void
654 gtk_icon_view_get_property (GObject      *object,
655                             guint         prop_id,
656                             GValue       *value,
657                             GParamSpec   *pspec)
658 {
659   GtkIconView *icon_view;
660
661   icon_view = GTK_ICON_VIEW (object);
662
663   switch (prop_id)
664     {
665     case PROP_SELECTION_MODE:
666       g_value_set_enum (value, icon_view->priv->selection_mode);
667       break;
668     case PROP_PIXBUF_COLUMN:
669       g_value_set_int (value, icon_view->priv->pixbuf_column);
670       break;
671     case PROP_TEXT_COLUMN:
672       g_value_set_int (value, icon_view->priv->text_column);
673       break;
674     case PROP_MARKUP_COLUMN:
675       g_value_set_int (value, icon_view->priv->markup_column);
676       break;
677     case PROP_MODEL:
678       g_value_set_object (value, icon_view->priv->model);
679       break;
680     case PROP_ORIENTATION:
681       g_value_set_enum (value, icon_view->priv->orientation);
682       break;
683     default:
684       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
685       break;
686     }
687 }
688
689 /* GtkWidget signals */
690 static void
691 gtk_icon_view_realize (GtkWidget *widget)
692 {
693   GtkIconView *icon_view;
694   GdkWindowAttr attributes;
695   gint attributes_mask;
696   
697   icon_view = GTK_ICON_VIEW (widget);
698
699   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
700
701   /* Make the main, clipping window */
702   attributes.window_type = GDK_WINDOW_CHILD;
703   attributes.x = widget->allocation.x;
704   attributes.y = widget->allocation.y;
705   attributes.width = widget->allocation.width;
706   attributes.height = widget->allocation.height;
707   attributes.wclass = GDK_INPUT_OUTPUT;
708   attributes.visual = gtk_widget_get_visual (widget);
709   attributes.colormap = gtk_widget_get_colormap (widget);
710   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
711
712   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
713
714   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
715                                    &attributes, attributes_mask);
716   gdk_window_set_user_data (widget->window, widget);
717
718   /* Make the window for the icon view */
719   attributes.x = 0;
720   attributes.y = 0;
721   attributes.width = MAX (icon_view->priv->width, widget->allocation.width);
722   attributes.height = MAX (icon_view->priv->height, widget->allocation.height);
723   attributes.event_mask = (GDK_EXPOSURE_MASK |
724                            GDK_SCROLL_MASK |
725                            GDK_POINTER_MOTION_MASK |
726                            GDK_BUTTON_PRESS_MASK |
727                            GDK_BUTTON_RELEASE_MASK |
728                            GDK_KEY_PRESS_MASK |
729                            GDK_KEY_RELEASE_MASK) |
730     gtk_widget_get_events (widget);
731   
732   icon_view->priv->bin_window = gdk_window_new (widget->window,
733                                           &attributes, attributes_mask);
734   gdk_window_set_user_data (icon_view->priv->bin_window, widget);
735
736   widget->style = gtk_style_attach (widget->style, widget->window);
737   gdk_window_set_background (icon_view->priv->bin_window, &widget->style->base[widget->state]);
738   gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
739
740   
741 }
742
743 static void
744 gtk_icon_view_unrealize (GtkWidget *widget)
745 {
746   GtkIconView *icon_view;
747
748   icon_view = GTK_ICON_VIEW (widget);
749
750   gdk_window_set_user_data (icon_view->priv->bin_window, NULL);
751   gdk_window_destroy (icon_view->priv->bin_window);
752   icon_view->priv->bin_window = NULL;
753
754   /* GtkWidget::unrealize destroys children and widget->window */
755   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
756     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
757 }
758
759 static void
760 gtk_icon_view_map (GtkWidget *widget)
761 {
762   GtkIconView *icon_view;
763
764   icon_view = GTK_ICON_VIEW (widget);
765
766   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
767
768   gdk_window_show (icon_view->priv->bin_window);
769   gdk_window_show (widget->window);
770 }
771
772 static void
773 gtk_icon_view_size_request (GtkWidget      *widget,
774                             GtkRequisition *requisition)
775 {
776   GtkIconView *icon_view;
777
778   icon_view = GTK_ICON_VIEW (widget);
779
780   requisition->width = icon_view->priv->width;
781   requisition->height = icon_view->priv->height;
782 }
783
784 static void
785 gtk_icon_view_size_allocate (GtkWidget      *widget,
786                              GtkAllocation  *allocation)
787 {
788   GtkIconView *icon_view;
789
790   widget->allocation = *allocation;
791   
792   icon_view = GTK_ICON_VIEW (widget);
793   
794   if (GTK_WIDGET_REALIZED (widget))
795     {
796       gdk_window_move_resize (widget->window,
797                               allocation->x, allocation->y,
798                               allocation->width, allocation->height);
799       gdk_window_resize (icon_view->priv->bin_window,
800                          MAX (icon_view->priv->width, allocation->width),
801                          MAX (icon_view->priv->height, allocation->height));
802     }
803
804   icon_view->priv->hadjustment->page_size = allocation->width;
805   icon_view->priv->hadjustment->page_increment = allocation->width * 0.9;
806   icon_view->priv->hadjustment->step_increment = allocation->width * 0.1;
807   icon_view->priv->hadjustment->lower = 0;
808   icon_view->priv->hadjustment->upper = MAX (allocation->width, icon_view->priv->width);
809   gtk_adjustment_changed (icon_view->priv->hadjustment);
810
811   icon_view->priv->vadjustment->page_size = allocation->height;
812   icon_view->priv->vadjustment->page_increment = allocation->height * 0.9;
813   icon_view->priv->vadjustment->step_increment = allocation->width * 0.1;
814   icon_view->priv->vadjustment->lower = 0;
815   icon_view->priv->vadjustment->upper = MAX (allocation->height, icon_view->priv->height);
816   gtk_adjustment_changed (icon_view->priv->vadjustment);
817
818   gtk_icon_view_layout (icon_view);
819 }
820
821 static gboolean
822 gtk_icon_view_expose (GtkWidget *widget,
823                       GdkEventExpose *expose)
824 {
825   GtkIconView *icon_view;
826   GList *icons;
827
828   icon_view = GTK_ICON_VIEW (widget);
829
830   if (expose->window != icon_view->priv->bin_window)
831     return FALSE;
832
833   for (icons = icon_view->priv->items; icons; icons = icons->next) {
834     GtkIconViewItem *item = icons->data;
835     GdkRectangle item_rectangle;
836
837     item_rectangle.x = item->x;
838     item_rectangle.y = item->y;
839     item_rectangle.width = item->width;
840     item_rectangle.height = item->height;
841
842     if (gdk_region_rect_in (expose->region, &item_rectangle) == GDK_OVERLAP_RECTANGLE_OUT)
843       continue;
844
845     gtk_icon_view_paint_item (icon_view, item, &expose->area);
846   }
847
848   if (icon_view->priv->doing_rubberband)
849     {
850       GdkRectangle *rectangles;
851       gint n_rectangles;
852       
853       gdk_region_get_rectangles (expose->region,
854                                  &rectangles,
855                                  &n_rectangles);
856       
857       while (n_rectangles--)
858         gtk_icon_view_paint_rubberband (icon_view, &rectangles[n_rectangles]);
859
860       g_free (rectangles);
861     }
862
863   return TRUE;
864 }
865
866 static gboolean
867 scroll_timeout (gpointer data)
868 {
869   GtkIconView *icon_view;
870   gdouble value;
871   
872   icon_view = data;
873
874   value = MIN (icon_view->priv->vadjustment->value +
875                icon_view->priv->scroll_value_diff,
876                icon_view->priv->vadjustment->upper -
877                icon_view->priv->vadjustment->page_size);
878
879   gtk_adjustment_set_value (icon_view->priv->vadjustment,
880                             value);
881
882   gtk_icon_view_update_rubberband (icon_view);
883   
884   return TRUE;
885 }
886
887 static gboolean
888 gtk_icon_view_motion (GtkWidget      *widget,
889                       GdkEventMotion *event)
890 {
891   GtkIconView *icon_view;
892   gint abs_y;
893   
894   icon_view = GTK_ICON_VIEW (widget);
895 #ifdef DND_WORKS
896   gtk_icon_view_maybe_begin_dragging_items (icon_view, event);
897 #endif
898   if (icon_view->priv->doing_rubberband)
899     {
900       gtk_icon_view_update_rubberband (widget);
901       
902       abs_y = event->y - icon_view->priv->height *
903         (icon_view->priv->vadjustment->value /
904          (icon_view->priv->vadjustment->upper -
905           icon_view->priv->vadjustment->lower));
906
907       if (abs_y < 0 || abs_y > widget->allocation.height)
908         {
909           if (icon_view->priv->scroll_timeout_id == 0)
910             icon_view->priv->scroll_timeout_id = g_timeout_add (30, scroll_timeout, icon_view);
911
912           if (abs_y < 0)
913             icon_view->priv->scroll_value_diff = abs_y;
914           else
915             icon_view->priv->scroll_value_diff = abs_y - widget->allocation.height;
916
917           icon_view->priv->event_last_x = event->x;
918           icon_view->priv->event_last_y = event->y;
919         }
920       else if (icon_view->priv->scroll_timeout_id != 0)
921         {
922           g_source_remove (icon_view->priv->scroll_timeout_id);
923
924           icon_view->priv->scroll_timeout_id = 0;
925         }
926     }
927   
928   return TRUE;
929 }
930
931 static gboolean
932 gtk_icon_view_button_press (GtkWidget      *widget,
933                             GdkEventButton *event)
934 {
935   GtkIconView *icon_view;
936   GtkIconViewItem *item;
937   gboolean dirty = FALSE;
938
939   icon_view = GTK_ICON_VIEW (widget);
940
941   if (event->window != icon_view->priv->bin_window)
942     return FALSE;
943
944   if (!GTK_WIDGET_HAS_FOCUS (widget))
945     gtk_widget_grab_focus (widget);
946
947   if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
948     {
949
950       item = gtk_icon_view_get_item_at_pos (icon_view,
951                                             event->x, event->y);
952       
953       if (item != NULL)
954         {
955           gtk_icon_view_scroll_to_item (icon_view, item);
956           
957           if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
958             {
959               gtk_icon_view_set_cursor_item (icon_view, item);
960             }
961           else if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE &&
962                    (event->state & GDK_SHIFT_MASK))
963             {
964               gtk_icon_view_unselect_all_internal (icon_view);
965
966               gtk_icon_view_set_cursor_item (icon_view, item);
967               if (!icon_view->priv->anchor_item)
968                 icon_view->priv->anchor_item = item;
969               else 
970                 gtk_icon_view_select_all_between (icon_view,
971                                                   icon_view->priv->anchor_item,
972                                                   item);
973               dirty = TRUE;
974             }
975           else 
976             {
977               if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE &&
978                   (event->state & GDK_CONTROL_MASK))
979                 {
980                   item->selected = !item->selected;
981                   gtk_icon_view_queue_draw_item (icon_view, item);
982                   dirty = TRUE;
983                 }
984               else
985                 {
986                   if (!item->selected)
987                     {
988                       gtk_icon_view_unselect_all_internal (icon_view);
989                       
990                       item->selected = TRUE;
991                       gtk_icon_view_queue_draw_item (icon_view, item);
992                       dirty = TRUE;
993                     }
994                 }
995               gtk_icon_view_set_cursor_item (icon_view, item);
996               icon_view->priv->anchor_item = item;
997             }
998 #ifdef DND_WORKS
999           /* Save press to possibly begin a drag */
1000           if (icon_view->priv->pressed_button < 0)
1001             {
1002               icon_view->priv->pressed_button = event->button;
1003               icon_view->priv->press_start_x = event->x;
1004               icon_view->priv->press_start_y = event->y;
1005             }
1006 #endif
1007           if (!icon_view->priv->last_single_clicked)
1008             icon_view->priv->last_single_clicked = item;
1009         }
1010       else
1011         {
1012           if (icon_view->priv->selection_mode != GTK_SELECTION_BROWSE &&
1013               !(event->state & GDK_CONTROL_MASK))
1014             {
1015               dirty = gtk_icon_view_unselect_all_internal (icon_view);
1016             }
1017           
1018           if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE)
1019             gtk_icon_view_start_rubberbanding (icon_view, event->x, event->y);
1020         }
1021
1022     }
1023
1024   if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
1025     {
1026       item = gtk_icon_view_get_item_at_pos (icon_view,
1027                                             event->x, event->y);
1028
1029       if (item && item == icon_view->priv->last_single_clicked)
1030         {
1031           GtkTreePath *path;
1032
1033           path = gtk_tree_path_new_from_indices (item->index, -1);
1034           gtk_icon_view_item_activated (icon_view, path);
1035           gtk_tree_path_free (path);
1036         }
1037
1038       icon_view->priv->last_single_clicked = NULL;
1039     }
1040   
1041   if (dirty)
1042     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
1043
1044   return TRUE;
1045 }
1046
1047 static gboolean
1048 gtk_icon_view_button_release (GtkWidget      *widget,
1049                               GdkEventButton *event)
1050 {
1051   GtkIconView *icon_view;
1052
1053   icon_view = GTK_ICON_VIEW (widget);
1054   
1055 #ifdef DND_WORKS
1056   if (icon_view->priv->pressed_button == event->button)
1057     icon_view->priv->pressed_button = -1;
1058 #endif
1059   gtk_icon_view_stop_rubberbanding (icon_view);
1060
1061   if (icon_view->priv->scroll_timeout_id != 0)
1062     {
1063       g_source_remove (icon_view->priv->scroll_timeout_id);
1064       icon_view->priv->scroll_timeout_id = 0;
1065     }
1066
1067   return TRUE;
1068 }
1069
1070
1071 static void
1072 gtk_icon_view_update_rubberband (gpointer data)
1073 {
1074   GtkIconView *icon_view;
1075   gint x, y;
1076   GdkRectangle old_area;
1077   GdkRectangle new_area;
1078   GdkRectangle common;
1079   GdkRegion *invalid_region;
1080   
1081   icon_view = GTK_ICON_VIEW (data);
1082
1083   gdk_window_get_pointer (icon_view->priv->bin_window, &x, &y, NULL);
1084
1085   x = MAX (x, 0);
1086   y = MAX (y, 0);
1087
1088   old_area.x = MIN (icon_view->priv->rubberband_x1,
1089                     icon_view->priv->rubberband_x2);
1090   old_area.y = MIN (icon_view->priv->rubberband_y1,
1091                     icon_view->priv->rubberband_y2);
1092   old_area.width = ABS (icon_view->priv->rubberband_x2 -
1093                         icon_view->priv->rubberband_x1) + 1;
1094   old_area.height = ABS (icon_view->priv->rubberband_y2 -
1095                          icon_view->priv->rubberband_y1) + 1;
1096   
1097   new_area.x = MIN (icon_view->priv->rubberband_x1, x);
1098   new_area.y = MIN (icon_view->priv->rubberband_y1, y);
1099   new_area.width = ABS (x - icon_view->priv->rubberband_x1) + 1;
1100   new_area.height = ABS (y - icon_view->priv->rubberband_y1) + 1;
1101
1102   invalid_region = gdk_region_rectangle (&old_area);
1103   gdk_region_union_with_rect (invalid_region, &new_area);
1104
1105   gdk_rectangle_intersect (&old_area, &new_area, &common);
1106   if (common.width > 2 && common.height > 2)
1107     {
1108       GdkRegion *common_region;
1109
1110       /* make sure the border is invalidated */
1111       common.x += 1;
1112       common.y += 1;
1113       common.width -= 2;
1114       common.height -= 2;
1115       
1116       common_region = gdk_region_rectangle (&common);
1117
1118       gdk_region_subtract (invalid_region, common_region);
1119       gdk_region_destroy (common_region);
1120     }
1121   
1122   gdk_window_invalidate_region (icon_view->priv->bin_window, invalid_region, TRUE);
1123     
1124   gdk_region_destroy (invalid_region);
1125
1126   icon_view->priv->rubberband_x2 = x;
1127   icon_view->priv->rubberband_y2 = y;  
1128
1129   gtk_icon_view_update_rubberband_selection (icon_view);
1130 }
1131
1132 static void
1133 gtk_icon_view_start_rubberbanding (GtkIconView  *icon_view,
1134                                    gint          x,
1135                                    gint          y)
1136 {
1137   GList *items;
1138
1139   g_assert (!icon_view->priv->doing_rubberband);
1140
1141   for (items = icon_view->priv->items; items; items = items->next)
1142     {
1143       GtkIconViewItem *item = items->data;
1144
1145       item->selected_before_rubberbanding = item->selected;
1146     }
1147   
1148   icon_view->priv->rubberband_x1 = x;
1149   icon_view->priv->rubberband_y1 = y;
1150   icon_view->priv->rubberband_x2 = x;
1151   icon_view->priv->rubberband_y2 = y;
1152
1153   icon_view->priv->doing_rubberband = TRUE;
1154
1155   gtk_grab_add (GTK_WIDGET (icon_view));
1156 }
1157
1158 static void
1159 gtk_icon_view_stop_rubberbanding (GtkIconView *icon_view)
1160 {
1161   if (!icon_view->priv->doing_rubberband)
1162     return;
1163
1164   icon_view->priv->doing_rubberband = FALSE;
1165
1166   gtk_grab_remove (GTK_WIDGET (icon_view));
1167   
1168   gtk_widget_queue_draw (GTK_WIDGET (icon_view));
1169 }
1170
1171 static void
1172 gtk_icon_view_update_rubberband_selection (GtkIconView *icon_view)
1173 {
1174   GList *items;
1175   gint x, y, width, height;
1176   gboolean dirty = FALSE;
1177   
1178   x = MIN (icon_view->priv->rubberband_x1,
1179            icon_view->priv->rubberband_x2);
1180   y = MIN (icon_view->priv->rubberband_y1,
1181            icon_view->priv->rubberband_y2);
1182   width = ABS (icon_view->priv->rubberband_x1 - 
1183                icon_view->priv->rubberband_x2);
1184   height = ABS (icon_view->priv->rubberband_y1 - 
1185                 icon_view->priv->rubberband_y2);
1186   
1187   for (items = icon_view->priv->items; items; items = items->next)
1188     {
1189       GtkIconViewItem *item = items->data;
1190       gboolean is_in;
1191       gboolean selected;
1192       
1193       is_in = gtk_icon_view_item_hit_test (item, x, y, width, height);
1194
1195       selected = is_in ^ item->selected_before_rubberbanding;
1196
1197       if (item->selected != selected)
1198         {
1199           item->selected = selected;
1200           dirty = TRUE;
1201           gtk_icon_view_queue_draw_item (icon_view, item);
1202         }
1203     }
1204
1205   if (dirty)
1206     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
1207 }
1208
1209 static gboolean
1210 gtk_icon_view_item_hit_test (GtkIconViewItem  *item,
1211                              gint              x,
1212                              gint              y,
1213                              gint              width,
1214                              gint              height)
1215 {
1216   /* First try the pixbuf */
1217   if (MIN (x + width, item->pixbuf_x + item->pixbuf_width) - MAX (x, item->pixbuf_x) > 0 &&
1218       MIN (y + height, item->pixbuf_y + item->pixbuf_height) - MAX (y, item->pixbuf_y) > 0)
1219     return TRUE;
1220
1221   /* Then try the text */
1222   if (MIN (x + width, item->layout_x + item->layout_width) - MAX (x, item->layout_x) > 0 &&
1223       MIN (y + height, item->layout_y + item->layout_height) - MAX (y, item->layout_y) > 0)
1224     return TRUE;
1225   
1226   return FALSE;
1227 }
1228
1229 #ifdef DND_WORKS
1230 static gboolean
1231 gtk_icon_view_maybe_begin_dragging_items (GtkIconView     *icon_view,
1232                                           GdkEventMotion  *event)
1233 {
1234   gboolean retval = FALSE;
1235   gint button;
1236   if (icon_view->priv->pressed_button < 0)
1237     return retval;
1238
1239   if (!gtk_drag_check_threshold (GTK_WIDGET (icon_view),
1240                                  icon_view->priv->press_start_x,
1241                                  icon_view->priv->press_start_y,
1242                                  event->x, event->y))
1243     return retval;
1244
1245   button = icon_view->priv->pressed_button;
1246   icon_view->priv->pressed_button = -1;
1247   
1248   {
1249     static GtkTargetEntry row_targets[] = {
1250       { "GTK_ICON_VIEW_ITEMS", GTK_TARGET_SAME_APP, 0 }
1251     };
1252     GtkTargetList *target_list;
1253     GdkDragContext *context;
1254     GtkIconViewItem *item;
1255     
1256     retval = TRUE;
1257     
1258     target_list = gtk_target_list_new (row_targets, G_N_ELEMENTS (row_targets));
1259
1260     context = gtk_drag_begin (GTK_WIDGET (icon_view),
1261                               target_list, GDK_ACTION_MOVE,
1262                               button,
1263                               (GdkEvent *)event);
1264
1265     item = gtk_icon_view_get_item_at_pos (icon_view,
1266                                           icon_view->priv->press_start_x,
1267                                           icon_view->priv->press_start_y);
1268     g_assert (item != NULL);
1269     gtk_drag_set_icon_pixbuf (context, gtk_icon_view_get_item_icon (icon_view, item),
1270                               event->x - item->x,
1271                               event->y - item->y);
1272   }
1273   
1274   return retval;
1275 }
1276 #endif
1277
1278 static gboolean
1279 gtk_icon_view_unselect_all_internal (GtkIconView  *icon_view)
1280 {
1281   gboolean dirty = FALSE;
1282   GList *items;
1283
1284   if (icon_view->priv->selection_mode == GTK_SELECTION_NONE ||
1285       icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
1286     return FALSE;
1287   
1288   for (items = icon_view->priv->items; items; items = items->next)
1289     {
1290       GtkIconViewItem *item = items->data;
1291
1292       if (item->selected)
1293         {
1294           item->selected = FALSE;
1295           dirty = TRUE;
1296           gtk_icon_view_queue_draw_item (icon_view, item);
1297         }
1298     }
1299
1300   return dirty;
1301 }
1302
1303
1304 /* GtkIconView signals */
1305 static void
1306 gtk_icon_view_set_adjustments (GtkIconView   *icon_view,
1307                                GtkAdjustment *hadj,
1308                                GtkAdjustment *vadj)
1309 {
1310   gboolean need_adjust = FALSE;
1311
1312   if (hadj)
1313     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
1314   else
1315     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
1316   if (vadj)
1317     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
1318   else
1319     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
1320
1321   if (icon_view->priv->hadjustment && (icon_view->priv->hadjustment != hadj))
1322     {
1323       g_signal_handlers_disconnect_matched (icon_view->priv->hadjustment, G_SIGNAL_MATCH_DATA,
1324                                            0, 0, NULL, NULL, icon_view);
1325       g_object_unref (icon_view->priv->hadjustment);
1326     }
1327
1328   if (icon_view->priv->vadjustment && (icon_view->priv->vadjustment != vadj))
1329     {
1330       g_signal_handlers_disconnect_matched (icon_view->priv->vadjustment, G_SIGNAL_MATCH_DATA,
1331                                             0, 0, NULL, NULL, icon_view);
1332       g_object_unref (icon_view->priv->vadjustment);
1333     }
1334
1335   if (icon_view->priv->hadjustment != hadj)
1336     {
1337       icon_view->priv->hadjustment = hadj;
1338       g_object_ref (icon_view->priv->hadjustment);
1339       gtk_object_sink (GTK_OBJECT (icon_view->priv->hadjustment));
1340
1341       g_signal_connect (icon_view->priv->hadjustment, "value_changed",
1342                         G_CALLBACK (gtk_icon_view_adjustment_changed),
1343                         icon_view);
1344       need_adjust = TRUE;
1345     }
1346
1347   if (icon_view->priv->vadjustment != vadj)
1348     {
1349       icon_view->priv->vadjustment = vadj;
1350       g_object_ref (icon_view->priv->vadjustment);
1351       gtk_object_sink (GTK_OBJECT (icon_view->priv->vadjustment));
1352
1353       g_signal_connect (icon_view->priv->vadjustment, "value_changed",
1354                         G_CALLBACK (gtk_icon_view_adjustment_changed),
1355                         icon_view);
1356       need_adjust = TRUE;
1357     }
1358
1359   if (need_adjust)
1360     gtk_icon_view_adjustment_changed (NULL, icon_view);
1361 }
1362
1363 static void
1364 gtk_icon_view_real_select_all (GtkIconView *icon_view)
1365 {
1366   gtk_icon_view_select_all (icon_view);
1367 }
1368
1369 static void
1370 gtk_icon_view_real_unselect_all (GtkIconView *icon_view)
1371 {
1372   if (icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
1373     return;
1374
1375   gtk_icon_view_unselect_all (icon_view);
1376 }
1377
1378 static void
1379 gtk_icon_view_real_select_cursor_item (GtkIconView *icon_view)
1380 {
1381   gtk_icon_view_unselect_all (icon_view);
1382   
1383   if (icon_view->priv->cursor_item != NULL)
1384     gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
1385 }
1386
1387 static gboolean
1388 gtk_icon_view_real_activate_cursor_item (GtkIconView *icon_view)
1389 {
1390   GtkTreePath *path;
1391   
1392   if (!icon_view->priv->cursor_item)
1393     return FALSE;
1394
1395   path = gtk_tree_path_new_from_indices (icon_view->priv->cursor_item->index, -1);
1396   
1397   gtk_icon_view_item_activated (icon_view, path);
1398
1399   gtk_tree_path_free (path);
1400
1401   return TRUE;
1402 }
1403
1404 static void
1405 gtk_icon_view_real_toggle_cursor_item (GtkIconView *icon_view)
1406 {
1407   if (!icon_view->priv->cursor_item)
1408     return;
1409
1410   switch (icon_view->priv->selection_mode)
1411     {
1412     case GTK_SELECTION_NONE:
1413       break;
1414     case GTK_SELECTION_BROWSE:
1415       gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
1416       break;
1417     case GTK_SELECTION_SINGLE:
1418       if (icon_view->priv->cursor_item->selected)
1419         gtk_icon_view_unselect_item (icon_view, icon_view->priv->cursor_item);
1420       else
1421         gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
1422       break;
1423     case GTK_SELECTION_MULTIPLE:
1424       icon_view->priv->cursor_item->selected = !icon_view->priv->cursor_item->selected;
1425       g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0); 
1426       
1427       gtk_icon_view_queue_draw_item (icon_view, icon_view->priv->cursor_item);
1428       break;
1429     }
1430 }
1431
1432 /* Internal functions */
1433 static void
1434 gtk_icon_view_adjustment_changed (GtkAdjustment *adjustment,
1435                                   GtkIconView   *icon_view)
1436 {
1437   if (GTK_WIDGET_REALIZED (icon_view))
1438     {
1439       gdk_window_move (icon_view->priv->bin_window,
1440                        - icon_view->priv->hadjustment->value,
1441                        - icon_view->priv->vadjustment->value);
1442
1443       if (icon_view->priv->doing_rubberband)
1444         gtk_icon_view_update_rubberband (GTK_WIDGET (icon_view));
1445
1446       gdk_window_process_updates (icon_view->priv->bin_window, TRUE);
1447     }
1448 }
1449
1450 static GList *
1451 gtk_icon_view_layout_single_row (GtkIconView *icon_view, GList *first_item, gint *y, gint *maximum_width, gint row)
1452 {
1453   gint focus_width, focus_pad;
1454   gint x, current_width, max_height, max_pixbuf_height;
1455   GList *items, *last_item;
1456   gint maximum_layout_width;
1457   gint col;
1458   gboolean rtl = gtk_widget_get_direction (GTK_WIDGET (icon_view)) == GTK_TEXT_DIR_RTL;
1459
1460   x = 0;
1461   col = 0;
1462   max_height = 0;
1463   max_pixbuf_height = 0;
1464   items = first_item;
1465   current_width = 0;
1466
1467   gtk_widget_style_get (GTK_WIDGET (icon_view),
1468                         "focus-line-width", &focus_width,
1469                         "focus-padding", &focus_pad,
1470                         NULL);
1471
1472   x += ICON_VIEW_LEFT_MARGIN;
1473   current_width += ICON_VIEW_LEFT_MARGIN + ICON_VIEW_RIGHT_MARGIN;
1474   items = first_item;
1475
1476   while (items)
1477     {
1478       GtkIconViewItem *item = items->data;
1479
1480       gtk_icon_view_calculate_item_size (icon_view, item);
1481
1482       current_width += MAX (item->width, MINIMUM_ICON_ITEM_WIDTH);
1483
1484       /* Don't add padding to the first or last icon */
1485       
1486       if (current_width > GTK_WIDGET (icon_view)->allocation.width &&
1487           items != first_item)
1488         break;
1489
1490       maximum_layout_width = MAX (item->pixbuf_width, MINIMUM_ICON_ITEM_WIDTH);
1491
1492       item->y = *y;
1493       item->x = rtl ? GTK_WIDGET (icon_view)->allocation.width - item->width - x : x;
1494       if (item->width < MINIMUM_ICON_ITEM_WIDTH) {
1495         if (rtl)
1496           item->x -= (MINIMUM_ICON_ITEM_WIDTH - item->width) / 2;
1497         else
1498           item->x += (MINIMUM_ICON_ITEM_WIDTH - item->width) / 2;
1499         x += (MINIMUM_ICON_ITEM_WIDTH - item->width);
1500       }
1501
1502       if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1503         {
1504           if (gtk_widget_get_direction (GTK_WIDGET (icon_view)) == GTK_TEXT_DIR_RTL)
1505             {
1506               item->layout_x = item->x + ICON_TEXT_PADDING + focus_width + focus_pad;
1507               item->pixbuf_x = item->x + 2 * (ICON_TEXT_PADDING + focus_width + focus_pad) + item->layout_width;
1508             }
1509           else 
1510             {
1511               item->pixbuf_x = item->x;
1512               item->layout_x = item->x + item->pixbuf_width + ICON_TEXT_PADDING + focus_width + focus_pad;
1513             }
1514         }
1515       else
1516         {
1517           item->pixbuf_x = item->x + (item->width - item->pixbuf_width) / 2;
1518           item->layout_x = item->x + (item->width - item->layout_width) / 2;
1519         }
1520
1521       x += item->width;
1522
1523       max_height = MAX (max_height, item->height);
1524       max_pixbuf_height = MAX (max_pixbuf_height, item->pixbuf_height);
1525       
1526       if (current_width > *maximum_width)
1527         *maximum_width = current_width;
1528
1529       item->row = row;
1530       item->col = col;
1531
1532       col++;
1533       items = items->next;
1534     }
1535
1536   last_item = items;
1537
1538   *y += max_height + ICON_VIEW_ICON_PADDING;
1539
1540   /* Now go through the row again and align the icons */
1541   for (items = first_item; items != last_item; items = items->next)
1542     {
1543       GtkIconViewItem *item = items->data;
1544
1545       if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1546         {
1547           item->pixbuf_y = item->y;
1548           item->layout_y = item->y + ICON_TEXT_PADDING + focus_width + focus_pad;
1549         }
1550       else 
1551         {
1552           item->pixbuf_y = item->y + (max_pixbuf_height - item->pixbuf_height);
1553           item->layout_y = item->pixbuf_y + item->pixbuf_height + ICON_TEXT_PADDING + focus_width + focus_pad;
1554       }
1555       /* Update the bounding box */
1556       item->y = item->pixbuf_y;
1557
1558       /* We may want to readjust the new y coordinate. */
1559       if (item->y + item->height > *y)
1560         *y = item->y + item->height;
1561
1562       if (rtl)
1563         item->col = col - 1 - item->col;
1564     }
1565   
1566   return last_item;
1567 }
1568
1569 static void
1570 gtk_icon_view_set_adjustment_upper (GtkAdjustment *adj,
1571                                     gdouble        upper)
1572 {
1573   if (upper != adj->upper)
1574     {
1575       gdouble min = MAX (0.0, upper - adj->page_size);
1576       gboolean value_changed = FALSE;
1577       
1578       adj->upper = upper;
1579
1580       if (adj->value > min)
1581         {
1582           adj->value = min;
1583           value_changed = TRUE;
1584         }
1585       
1586       gtk_adjustment_changed (adj);
1587       
1588       if (value_changed)
1589         gtk_adjustment_value_changed (adj);
1590     }
1591 }
1592
1593 static void
1594 gtk_icon_view_layout (GtkIconView *icon_view)
1595 {
1596   gint y = 0, maximum_width = 0;
1597   GList *icons;
1598   GtkWidget *widget;
1599   gint row;
1600
1601   if (!VALID_MODEL_AND_COLUMNS (icon_view))
1602     return;
1603
1604   widget = GTK_WIDGET (icon_view);
1605   icons = icon_view->priv->items;
1606
1607   y += ICON_VIEW_TOP_MARGIN;
1608   row = 0;
1609
1610   do
1611     {
1612       icons = gtk_icon_view_layout_single_row (icon_view, icons, &y, &maximum_width, row);
1613       row++;
1614     }
1615   while (icons != NULL);
1616
1617   if (maximum_width != icon_view->priv->width)
1618     {
1619       icon_view->priv->width = maximum_width;
1620     }
1621   y += ICON_VIEW_BOTTOM_MARGIN;
1622   
1623   if (y != icon_view->priv->height)
1624     {
1625       icon_view->priv->height = y;
1626     }
1627
1628   gtk_icon_view_set_adjustment_upper (icon_view->priv->hadjustment, icon_view->priv->width);
1629   gtk_icon_view_set_adjustment_upper (icon_view->priv->vadjustment, icon_view->priv->height);
1630
1631   if (GTK_WIDGET_REALIZED (icon_view))
1632     {
1633       gdk_window_resize (icon_view->priv->bin_window,
1634                          MAX (icon_view->priv->width, widget->allocation.width),
1635                          MAX (icon_view->priv->height, widget->allocation.height));
1636     }
1637
1638   if (icon_view->priv->layout_idle_id != 0)
1639     {
1640       g_source_remove (icon_view->priv->layout_idle_id);
1641       icon_view->priv->layout_idle_id = 0;
1642     }
1643
1644   gtk_widget_queue_draw (GTK_WIDGET (icon_view));
1645 }
1646
1647 /* Updates the pango layout and calculates the size */
1648 static void
1649 gtk_icon_view_calculate_item_size (GtkIconView *icon_view,
1650                                    GtkIconViewItem *item)
1651 {
1652   gint focus_width, focus_pad;
1653   gint layout_width, layout_height;
1654   gint maximum_layout_width;
1655   GdkPixbuf *pixbuf;
1656   
1657   if (item->width != -1 && item->width != -1) 
1658     return;
1659
1660   gtk_widget_style_get (GTK_WIDGET (icon_view),
1661                         "focus-line-width", &focus_width,
1662                         "focus-padding", &focus_pad,
1663                         NULL);
1664
1665   if (icon_view->priv->pixbuf_column != -1)
1666     {
1667       pixbuf = gtk_icon_view_get_item_icon (icon_view, item);
1668       item->pixbuf_width = gdk_pixbuf_get_width (pixbuf);
1669       item->pixbuf_height = gdk_pixbuf_get_height (pixbuf);
1670       g_object_unref (pixbuf);
1671     }
1672   else
1673     {
1674       item->pixbuf_width = 0;
1675       item->pixbuf_height = 0;
1676     }
1677   
1678   maximum_layout_width = MAX (item->pixbuf_width, MINIMUM_ICON_ITEM_WIDTH);
1679
1680   if (icon_view->priv->markup_column != 1 ||
1681       icon_view->priv->text_column != -1)
1682     {
1683       gtk_icon_view_update_item_text (icon_view, item);
1684
1685       pango_layout_set_alignment (icon_view->priv->layout, PANGO_ALIGN_CENTER);
1686       pango_layout_set_width (icon_view->priv->layout, maximum_layout_width * PANGO_SCALE);
1687       
1688       pango_layout_get_pixel_size (icon_view->priv->layout, &layout_width, &layout_height);
1689       
1690       item->layout_width = layout_width;
1691       item->layout_height = layout_height;
1692     }
1693   else
1694     {
1695       item->layout_width = 0;
1696       item->layout_height = 0;
1697     }
1698
1699   if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1700     {
1701       item->width = layout_width + 2 * (ICON_TEXT_PADDING + focus_width + focus_pad) + item->pixbuf_width;
1702       item->height = MAX (layout_height + 2 * (ICON_TEXT_PADDING + focus_width + focus_pad), item->pixbuf_height);
1703     }
1704   else
1705     {
1706       item->width = MAX (layout_width + 2 * (ICON_TEXT_PADDING + focus_width + focus_pad), item->pixbuf_width);
1707       item->height = layout_height + 2 * (ICON_TEXT_PADDING + focus_width + focus_pad) + item->pixbuf_height;
1708     }
1709 }
1710
1711 static void
1712 gtk_icon_view_invalidate_sizes (GtkIconView *icon_view)
1713 {
1714   g_list_foreach (icon_view->priv->items,
1715                   (GFunc)gtk_icon_view_item_invalidate_size, NULL);
1716 }
1717
1718 static void
1719 gtk_icon_view_item_invalidate_size (GtkIconViewItem *item)
1720 {
1721   item->width = -1;
1722   item->height = -1;
1723 }
1724
1725 static GdkPixbuf *
1726 create_colorized_pixbuf (GdkPixbuf *src, GdkColor *new_color)
1727 {
1728         gint i, j;
1729         gint width, height, has_alpha, src_row_stride, dst_row_stride;
1730         gint red_value, green_value, blue_value;
1731         guchar *target_pixels;
1732         guchar *original_pixels;
1733         guchar *pixsrc;
1734         guchar *pixdest;
1735         GdkPixbuf *dest;
1736
1737         red_value = new_color->red / 255.0;
1738         green_value = new_color->green / 255.0;
1739         blue_value = new_color->blue / 255.0;
1740
1741         dest = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src),
1742                                gdk_pixbuf_get_has_alpha (src),
1743                                gdk_pixbuf_get_bits_per_sample (src),
1744                                gdk_pixbuf_get_width (src),
1745                                gdk_pixbuf_get_height (src));
1746         
1747         has_alpha = gdk_pixbuf_get_has_alpha (src);
1748         width = gdk_pixbuf_get_width (src);
1749         height = gdk_pixbuf_get_height (src);
1750         src_row_stride = gdk_pixbuf_get_rowstride (src);
1751         dst_row_stride = gdk_pixbuf_get_rowstride (dest);
1752         target_pixels = gdk_pixbuf_get_pixels (dest);
1753         original_pixels = gdk_pixbuf_get_pixels (src);
1754
1755         for (i = 0; i < height; i++) {
1756                 pixdest = target_pixels + i*dst_row_stride;
1757                 pixsrc = original_pixels + i*src_row_stride;
1758                 for (j = 0; j < width; j++) {           
1759                         *pixdest++ = (*pixsrc++ * red_value) >> 8;
1760                         *pixdest++ = (*pixsrc++ * green_value) >> 8;
1761                         *pixdest++ = (*pixsrc++ * blue_value) >> 8;
1762                         if (has_alpha) {
1763                                 *pixdest++ = *pixsrc++;
1764                         }
1765                 }
1766         }
1767         return dest;
1768 }
1769
1770 static void
1771 gtk_icon_view_paint_item (GtkIconView     *icon_view,
1772                           GtkIconViewItem *item,
1773                           GdkRectangle    *area)
1774 {
1775   gint focus_width, focus_pad;
1776   GdkPixbuf *pixbuf, *tmp;
1777   GtkStateType state;
1778   
1779   if (!VALID_MODEL_AND_COLUMNS (icon_view))
1780     return;
1781   
1782   gtk_widget_style_get (GTK_WIDGET (icon_view),
1783                         "focus-line-width", &focus_width,
1784                         "focus-padding", &focus_pad,
1785                         NULL);
1786
1787   if (GTK_WIDGET_HAS_FOCUS (icon_view))
1788     state = GTK_STATE_SELECTED;
1789   else
1790     state = GTK_STATE_ACTIVE;
1791
1792   if (icon_view->priv->pixbuf_column != -1)
1793     {
1794       tmp = gtk_icon_view_get_item_icon (icon_view, item);
1795       if (item->selected)
1796         {
1797           pixbuf = create_colorized_pixbuf (tmp,
1798                                             &GTK_WIDGET (icon_view)->style->base[state]);
1799           g_object_unref (tmp);
1800         }
1801       else
1802         pixbuf = tmp;
1803       
1804       gdk_draw_pixbuf (icon_view->priv->bin_window, NULL, pixbuf,
1805                        0, 0,
1806                        item->pixbuf_x, item->pixbuf_y,
1807                        item->pixbuf_width, item->pixbuf_height,
1808                        GDK_RGB_DITHER_NORMAL,
1809                        item->pixbuf_width, item->pixbuf_height);
1810       g_object_unref (pixbuf);
1811     }
1812
1813   if (icon_view->priv->text_column != -1)
1814     {
1815       if (item->selected)
1816         {
1817           gdk_draw_rectangle (icon_view->priv->bin_window,
1818                               GTK_WIDGET (icon_view)->style->base_gc[state],
1819                               TRUE,
1820                               item->layout_x - ICON_TEXT_PADDING,
1821                               item->layout_y - ICON_TEXT_PADDING,
1822                               item->layout_width + 2 * ICON_TEXT_PADDING,
1823                               item->layout_height + 2 * ICON_TEXT_PADDING);
1824         }
1825
1826       gtk_icon_view_update_item_text (icon_view, item);
1827       gtk_paint_layout (GTK_WIDGET (icon_view)->style,
1828                         icon_view->priv->bin_window,
1829                         item->selected ? state : GTK_STATE_NORMAL,
1830                         TRUE, area, GTK_WIDGET (icon_view), "icon_view",
1831                         item->layout_x - ((item->width - item->layout_width) / 2) - (MAX (item->pixbuf_width, MINIMUM_ICON_ITEM_WIDTH) - item->width) / 2,
1832                         item->layout_y,
1833                         icon_view->priv->layout);
1834
1835       if (GTK_WIDGET_HAS_FOCUS (icon_view) &&
1836           item == icon_view->priv->cursor_item)
1837         gtk_paint_focus (GTK_WIDGET (icon_view)->style,
1838                          icon_view->priv->bin_window,
1839                          GTK_STATE_NORMAL,
1840                          area,
1841                          GTK_WIDGET (icon_view),
1842                          "icon_view",
1843                          item->layout_x - ICON_TEXT_PADDING - focus_width - focus_pad,
1844                          item->layout_y - ICON_TEXT_PADDING - focus_width - focus_pad,
1845                          item->layout_width + 2 * (ICON_TEXT_PADDING + focus_width + focus_pad),
1846                          item->layout_height + 2 * (ICON_TEXT_PADDING + focus_width + focus_pad));
1847     }
1848 }
1849
1850 static guint32
1851 gtk_gdk_color_to_rgb (const GdkColor *color)
1852 {
1853   guint32 result;
1854   result = (0xff0000 | (color->red & 0xff00));
1855   result <<= 8;
1856   result |= ((color->green & 0xff00) | (color->blue >> 8));
1857   return result;
1858 }
1859
1860 static void
1861 gtk_icon_view_paint_rubberband (GtkIconView     *icon_view,
1862                                 GdkRectangle    *area)
1863 {
1864   GdkRectangle rect;
1865   GdkPixbuf *pixbuf;
1866   GdkGC *gc;
1867   GdkRectangle rubber_rect;
1868   GdkColor *fill_color_gdk;
1869   guint fill_color;
1870   guchar fill_color_alpha;
1871
1872   rubber_rect.x = MIN (icon_view->priv->rubberband_x1, icon_view->priv->rubberband_x2);
1873   rubber_rect.y = MIN (icon_view->priv->rubberband_y1, icon_view->priv->rubberband_y2);
1874   rubber_rect.width = ABS (icon_view->priv->rubberband_x1 - icon_view->priv->rubberband_x2) + 1;
1875   rubber_rect.height = ABS (icon_view->priv->rubberband_y1 - icon_view->priv->rubberband_y2) + 1;
1876
1877   if (!gdk_rectangle_intersect (&rubber_rect, area, &rect))
1878     return;
1879
1880   gtk_widget_style_get (GTK_WIDGET (icon_view),
1881                         "selection_box_color", &fill_color_gdk,
1882                         "selection_box_alpha", &fill_color_alpha,
1883                         NULL);
1884
1885   if (!fill_color_gdk) {
1886     fill_color_gdk = gdk_color_copy (&GTK_WIDGET (icon_view)->style->base[GTK_STATE_SELECTED]);
1887   }
1888
1889   fill_color = gtk_gdk_color_to_rgb (fill_color_gdk) << 8 | fill_color_alpha;
1890
1891   pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, rect.width, rect.height);
1892   gdk_pixbuf_fill (pixbuf, fill_color);
1893
1894   gdk_draw_pixbuf (icon_view->priv->bin_window, NULL, pixbuf,
1895                    0, 0, 
1896                    rect.x,rect.y,
1897                    rect.width, rect.height,
1898                    GDK_RGB_DITHER_NONE,
1899                    0, 0);
1900   g_object_unref (pixbuf);
1901   gc = gdk_gc_new (icon_view->priv->bin_window);
1902   gdk_gc_set_rgb_fg_color (gc, fill_color_gdk);
1903   gdk_gc_set_clip_rectangle (gc, &rect);
1904   gdk_draw_rectangle (icon_view->priv->bin_window,
1905                       gc, FALSE,
1906                       rubber_rect.x, rubber_rect.y,
1907                       rubber_rect.width - 1, rubber_rect.height - 1);
1908   gdk_color_free (fill_color_gdk);
1909   g_object_unref (gc);
1910 }
1911
1912 static void
1913 gtk_icon_view_queue_draw_item (GtkIconView     *icon_view,
1914                                GtkIconViewItem *item)
1915 {
1916   GdkRectangle rect;
1917
1918   rect.x = item->x;
1919   rect.y = item->y;
1920   rect.width = item->width;
1921   rect.height = item->height;
1922
1923   if (icon_view->priv->bin_window)
1924     gdk_window_invalidate_rect (icon_view->priv->bin_window, &rect, TRUE);
1925 }
1926
1927 static gboolean
1928 layout_callback (gpointer user_data)
1929 {
1930   GtkIconView *icon_view;
1931
1932   icon_view = GTK_ICON_VIEW (user_data);
1933   
1934   icon_view->priv->layout_idle_id = 0;
1935
1936   gtk_icon_view_layout (icon_view);
1937   
1938   return FALSE;
1939 }
1940
1941 static void
1942 gtk_icon_view_queue_layout (GtkIconView *icon_view)
1943 {
1944   if (icon_view->priv->layout_idle_id != 0)
1945     return;
1946
1947   icon_view->priv->layout_idle_id = g_idle_add (layout_callback, icon_view);
1948 }
1949
1950 static void
1951 gtk_icon_view_set_cursor_item (GtkIconView     *icon_view,
1952                                GtkIconViewItem *item)
1953 {
1954   if (icon_view->priv->cursor_item == item)
1955     return;
1956
1957   if (icon_view->priv->cursor_item != NULL)
1958     gtk_icon_view_queue_draw_item (icon_view, icon_view->priv->cursor_item);
1959   
1960   icon_view->priv->cursor_item = item;
1961   gtk_icon_view_queue_draw_item (icon_view, item);
1962 }
1963
1964
1965 static GtkIconViewItem *
1966 gtk_icon_view_item_new (void)
1967 {
1968   GtkIconViewItem *item;
1969
1970   item = g_new0 (GtkIconViewItem, 1);
1971
1972   item->width = -1;
1973   item->height = -1;
1974   
1975   return item;
1976 }
1977
1978 static void
1979 gtk_icon_view_item_free (GtkIconViewItem *item)
1980 {
1981   g_return_if_fail (item != NULL);
1982
1983   g_free (item);
1984 }
1985
1986 static void
1987 gtk_icon_view_update_item_text (GtkIconView     *icon_view,
1988                                 GtkIconViewItem *item)
1989 {
1990   gboolean iters_persist;
1991   GtkTreeIter iter;
1992   GtkTreePath *path;
1993   gchar *text;
1994   
1995   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
1996   
1997   if (!iters_persist)
1998     {
1999       path = gtk_tree_path_new_from_indices (item->index, -1);
2000       gtk_tree_model_get_iter (icon_view->priv->model, &iter, path);
2001       gtk_tree_path_free (path);
2002     }
2003   else
2004     iter = item->iter;
2005
2006   if (icon_view->priv->markup_column != -1)
2007     {
2008       gtk_tree_model_get (icon_view->priv->model, &iter,
2009                           icon_view->priv->markup_column, &text,
2010                           -1);
2011       pango_layout_set_markup (icon_view->priv->layout, text, -1);
2012     }
2013   else
2014     {
2015       gtk_tree_model_get (icon_view->priv->model, &iter,
2016                           icon_view->priv->text_column, &text,
2017                           -1);
2018       pango_layout_set_text (icon_view->priv->layout, text, -1);
2019     }
2020
2021   g_free (text);        
2022 }
2023
2024 static GdkPixbuf *
2025 gtk_icon_view_get_item_icon (GtkIconView      *icon_view,
2026                              GtkIconViewItem  *item)
2027 {
2028   gboolean iters_persist;
2029   GtkTreeIter iter;
2030   GtkTreePath *path;
2031   GdkPixbuf *pixbuf;
2032   
2033   g_return_val_if_fail (item != NULL, NULL);
2034
2035   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
2036   
2037   if (!iters_persist)
2038     {
2039       path = gtk_tree_path_new_from_indices (item->index, -1);
2040       gtk_tree_model_get_iter (icon_view->priv->model, &iter, path);
2041       gtk_tree_path_free (path);
2042     }
2043   else
2044     iter = item->iter;
2045   
2046   gtk_tree_model_get (icon_view->priv->model, &iter,
2047                       icon_view->priv->pixbuf_column, &pixbuf,
2048                       -1);
2049
2050   return pixbuf;
2051 }
2052
2053
2054 static GtkIconViewItem *
2055 gtk_icon_view_get_item_at_pos (GtkIconView *icon_view,
2056                                gint         x,
2057                                gint         y)
2058 {
2059   GList *items;
2060   
2061   for (items = icon_view->priv->items; items; items = items->next)
2062     {
2063       GtkIconViewItem *item = items->data;
2064       
2065       if (x > item->x && x < item->x + item->width &&
2066           y > item->y && y < item->y + item->height)
2067         {
2068           gint layout_x = item->x + (item->width - item->layout_width) / 2;
2069           /* Check if the mouse is inside the icon or the label */
2070           if ((x > item->pixbuf_x && x < item->pixbuf_x + item->pixbuf_width &&
2071                y > item->pixbuf_y && y < item->pixbuf_y + item->pixbuf_height) ||
2072               (x > layout_x - ICON_TEXT_PADDING &&
2073                x < layout_x + item->layout_width + ICON_TEXT_PADDING * 2 &&
2074                y > item->layout_y - ICON_TEXT_PADDING
2075                && y < item->layout_y + item->layout_height + ICON_TEXT_PADDING * 2))
2076             return item;
2077         }
2078     }
2079
2080   return NULL;
2081 }
2082
2083 static void
2084 gtk_icon_view_select_item (GtkIconView      *icon_view,
2085                            GtkIconViewItem  *item)
2086 {
2087   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
2088   g_return_if_fail (item != NULL);
2089
2090   if (item->selected)
2091     return;
2092   
2093   if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
2094     return;
2095   else if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
2096     gtk_icon_view_unselect_all_internal (icon_view);
2097
2098   item->selected = TRUE;
2099
2100   gtk_icon_view_queue_draw_item (icon_view, item);
2101
2102   g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2103 }
2104
2105
2106 static void
2107 gtk_icon_view_unselect_item (GtkIconView      *icon_view,
2108                              GtkIconViewItem  *item)
2109 {
2110   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
2111   g_return_if_fail (item != NULL);
2112
2113   if (!item->selected)
2114     return;
2115   
2116   if (icon_view->priv->selection_mode == GTK_SELECTION_NONE ||
2117       icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
2118     return;
2119   
2120   item->selected = FALSE;
2121
2122   g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2123
2124   gtk_icon_view_queue_draw_item (icon_view, item);
2125 }
2126
2127 static void
2128 verify_items (GtkIconView *icon_view)
2129 {
2130   GList *items;
2131   int i = 0;
2132
2133   for (items = icon_view->priv->items; items; items = items->next)
2134     {
2135       GtkIconViewItem *item = items->data;
2136
2137       if (item->index != i)
2138         g_error ("List item does not match its index: item index %d and list index %d\n", item->index, i);
2139
2140       i++;
2141     }
2142 }
2143
2144 static void
2145 gtk_icon_view_row_changed (GtkTreeModel *model,
2146                            GtkTreePath  *path,
2147                            GtkTreeIter  *iter,
2148                            gpointer      data)
2149 {
2150   GtkIconViewItem *item;
2151   gint index;
2152   GtkIconView *icon_view;
2153
2154   icon_view = GTK_ICON_VIEW (data);
2155   
2156   index = gtk_tree_path_get_indices(path)[0];
2157   item = g_list_nth (icon_view->priv->items, index)->data;
2158
2159   gtk_icon_view_item_invalidate_size (item);
2160   gtk_icon_view_queue_layout (icon_view);
2161
2162   verify_items (icon_view);
2163 }
2164
2165 static void
2166 gtk_icon_view_row_inserted (GtkTreeModel *model,
2167                             GtkTreePath  *path,
2168                             GtkTreeIter  *iter,
2169                             gpointer      data)
2170 {
2171   gint length, index;
2172   GtkIconViewItem *item;
2173   gboolean iters_persist;
2174   GtkIconView *icon_view;
2175   GList *list;
2176   
2177   icon_view = GTK_ICON_VIEW (data);
2178   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
2179   
2180   length = gtk_tree_model_iter_n_children (model, NULL);
2181   index = gtk_tree_path_get_indices(path)[0];
2182
2183   item = gtk_icon_view_item_new ();
2184
2185   if (iters_persist)
2186     item->iter = *iter;
2187
2188   item->index = index;
2189
2190   /* FIXME: We can be more efficient here,
2191      we can store a tail pointer and use that when
2192      appending (which is a rather common operation)
2193   */
2194   icon_view->priv->items = g_list_insert (icon_view->priv->items,
2195                                          item, index);
2196   
2197   list = g_list_nth (icon_view->priv->items, index + 1);
2198   for (; list; list = list->next)
2199     {
2200       item = list->data;
2201
2202       item->index++;
2203     }
2204     
2205   verify_items (icon_view);
2206 }
2207
2208 static void
2209 gtk_icon_view_row_deleted (GtkTreeModel *model,
2210                            GtkTreePath  *path,
2211                            gpointer      data)
2212 {
2213   gint index;
2214   GtkIconView *icon_view;
2215   GtkIconViewItem *item;
2216   GList *list, *next;
2217   gboolean emit = FALSE;
2218   
2219   icon_view = GTK_ICON_VIEW (data);
2220
2221   index = gtk_tree_path_get_indices(path)[0];
2222
2223   list = g_list_nth (icon_view->priv->items, index);
2224   item = list->data;
2225
2226   if (item == icon_view->priv->anchor_item)
2227     icon_view->priv->anchor_item = NULL;
2228
2229   if (item == icon_view->priv->cursor_item)
2230     icon_view->priv->cursor_item = NULL;
2231
2232   if (item->selected)
2233     emit = TRUE;
2234   
2235   gtk_icon_view_item_free (item);
2236
2237   for (next = list->next; next; next = next->next)
2238     {
2239       item = next->data;
2240
2241       item->index--;
2242     }
2243   
2244   icon_view->priv->items = g_list_delete_link (icon_view->priv->items, list);
2245
2246   gtk_icon_view_queue_layout (icon_view);
2247
2248   verify_items (icon_view);  
2249   
2250   if (emit)
2251     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2252 }
2253
2254 static void
2255 gtk_icon_view_rows_reordered (GtkTreeModel *model,
2256                               GtkTreePath  *parent,
2257                               GtkTreeIter  *iter,
2258                               gint         *new_order,
2259                               gpointer      data)
2260 {
2261   int i;
2262   int length;
2263   GtkIconView *icon_view;
2264   GList *items = NULL, *list;
2265   gint *inverted_order;
2266   GtkIconViewItem **item_array;
2267   
2268   icon_view = GTK_ICON_VIEW (data);
2269
2270   length = gtk_tree_model_iter_n_children (model, NULL);
2271   inverted_order = g_new (gint, length);
2272
2273   /* Invert the array */
2274   for (i = 0; i < length; i++)
2275     inverted_order[new_order[i]] = i;
2276
2277   item_array = g_new (GtkIconViewItem *, length);
2278   for (i = 0, list = icon_view->priv->items; list != NULL; list = list->next, i++)
2279     item_array[inverted_order[i]] = list->data;
2280
2281   g_free (inverted_order);
2282   for (i = 0; i < length; i++)
2283     {
2284       item_array[i]->index = i;
2285       items = g_list_prepend (items, item_array[i]);
2286     }
2287   
2288   g_free (item_array);
2289   g_list_free (icon_view->priv->items);
2290   icon_view->priv->items = g_list_reverse (items);
2291
2292   verify_items (icon_view);  
2293 }
2294
2295 static void
2296 gtk_icon_view_build_items (GtkIconView *icon_view)
2297 {
2298   GtkTreeIter iter;
2299   int i;
2300   gboolean iters_persist;
2301   GList *items = NULL;
2302
2303   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
2304   
2305   if (!gtk_tree_model_get_iter_first (icon_view->priv->model,
2306                                       &iter))
2307     return;
2308
2309   i = 0;
2310   
2311   do
2312     {
2313       GtkIconViewItem *item = gtk_icon_view_item_new ();
2314
2315       if (iters_persist)
2316         item->iter = iter;
2317
2318       item->index = i;
2319       
2320       i++;
2321
2322       items = g_list_prepend (items, item);
2323       
2324     } while (gtk_tree_model_iter_next (icon_view->priv->model, &iter));
2325
2326   icon_view->priv->items = g_list_reverse (items);
2327 }
2328
2329 static void
2330 gtk_icon_view_add_move_binding (GtkBindingSet  *binding_set,
2331                                 guint           keyval,
2332                                 guint           modmask,
2333                                 GtkMovementStep step,
2334                                 gint            count)
2335 {
2336   
2337   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
2338                                 "move_cursor", 2,
2339                                 G_TYPE_ENUM, step,
2340                                 G_TYPE_INT, count);
2341
2342   gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
2343                                 "move_cursor", 2,
2344                                 G_TYPE_ENUM, step,
2345                                 G_TYPE_INT, count);
2346
2347   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2348    return;
2349
2350   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
2351                                 "move_cursor", 2,
2352                                 G_TYPE_ENUM, step,
2353                                 G_TYPE_INT, count);
2354
2355   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
2356                                 "move_cursor", 2,
2357                                 G_TYPE_ENUM, step,
2358                                 G_TYPE_INT, count);
2359 }
2360
2361 static gboolean
2362 gtk_icon_view_real_move_cursor (GtkIconView     *icon_view,
2363                                 GtkMovementStep  step,
2364                                 gint             count)
2365 {
2366   GdkModifierType state;
2367
2368   g_return_val_if_fail (GTK_ICON_VIEW (icon_view), FALSE);
2369   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
2370                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
2371                         step == GTK_MOVEMENT_DISPLAY_LINES ||
2372                         step == GTK_MOVEMENT_PAGES ||
2373                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
2374
2375   if (!GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (icon_view)))
2376     return FALSE;
2377
2378   gtk_widget_grab_focus (GTK_WIDGET (icon_view));
2379
2380   if (gtk_get_current_event_state (&state))
2381     {
2382       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2383         icon_view->priv->ctrl_pressed = TRUE;
2384       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2385         icon_view->priv->shift_pressed = TRUE;
2386     }
2387   /* else we assume not pressed */
2388
2389   switch (step)
2390     {
2391     case GTK_MOVEMENT_LOGICAL_POSITIONS:
2392     case GTK_MOVEMENT_VISUAL_POSITIONS:
2393       gtk_icon_view_move_cursor_left_right (icon_view, count);
2394       break;
2395     case GTK_MOVEMENT_DISPLAY_LINES:
2396       gtk_icon_view_move_cursor_up_down (icon_view, count);
2397       break;
2398     case GTK_MOVEMENT_PAGES:
2399       gtk_icon_view_move_cursor_page_up_down (icon_view, count);
2400       break;
2401     case GTK_MOVEMENT_BUFFER_ENDS:
2402       gtk_icon_view_move_cursor_start_end (icon_view, count);
2403       break;
2404     default:
2405       g_assert_not_reached ();
2406     }
2407
2408   icon_view->priv->ctrl_pressed = FALSE;
2409   icon_view->priv->shift_pressed = FALSE;
2410
2411   return TRUE;
2412 }
2413
2414 static GtkIconViewItem *
2415 find_item (GtkIconView     *icon_view,
2416            GtkIconViewItem *current,
2417            gint             row_ofs,
2418            gint             col_ofs)
2419 {
2420   gint row, col;
2421   GList *items;
2422   GtkIconViewItem *item;
2423
2424   /* FIXME: this could be more efficient 
2425    */
2426   row = current->row + row_ofs;
2427   col = current->col + col_ofs;
2428
2429   for (items = icon_view->priv->items; items; items = items->next)
2430     {
2431       item = items->data;
2432       if (item->row == row && item->col == col)
2433         return item;
2434     }
2435   
2436   return NULL;
2437 }
2438
2439
2440 static GtkIconViewItem *
2441 find_item_page_up_down (GtkIconView     *icon_view,
2442                         GtkIconViewItem *current,
2443                         gint             count)
2444 {
2445   GList *item, *next;
2446   gint y, col;
2447   
2448   col = current->col;
2449   y = current->y + count * icon_view->priv->vadjustment->page_size;
2450
2451   item = g_list_find (icon_view->priv->items, current);
2452   if (count > 0)
2453     {
2454       while (item)
2455         {
2456           for (next = item->next; next; next = next->next)
2457             {
2458               if (((GtkIconViewItem *)next->data)->col == col)
2459                 break;
2460             }
2461           if (!next || ((GtkIconViewItem *)next->data)->y > y)
2462             break;
2463
2464           item = next;
2465         }
2466     }
2467   else 
2468     {
2469       while (item)
2470         {
2471           for (next = item->prev; next; next = next->prev)
2472             {
2473               if (((GtkIconViewItem *)next->data)->col == col)
2474                 break;
2475             }
2476           if (!next || ((GtkIconViewItem *)next->data)->y < y)
2477             break;
2478
2479           item = next;
2480         }
2481     }
2482
2483   if (item)
2484     return item->data;
2485
2486   return NULL;
2487 }
2488
2489 static gboolean
2490 gtk_icon_view_select_all_between (GtkIconView     *icon_view,
2491                                   GtkIconViewItem *anchor,
2492                                   GtkIconViewItem *cursor)
2493 {
2494   GList *items;
2495   GtkIconViewItem *item;
2496   gint row1, row2, col1, col2;
2497   gboolean dirty = FALSE;
2498   
2499   if (anchor->row < cursor->row)
2500     {
2501       row1 = anchor->row;
2502       row2 = cursor->row;
2503     }
2504   else
2505     {
2506       row1 = cursor->row;
2507       row2 = anchor->row;
2508     }
2509
2510   if (anchor->col < cursor->col)
2511     {
2512       col1 = anchor->col;
2513       col2 = cursor->col;
2514     }
2515   else
2516     {
2517       col1 = cursor->col;
2518       col2 = anchor->col;
2519     }
2520
2521   for (items = icon_view->priv->items; items; items = items->next)
2522     {
2523       item = items->data;
2524
2525       if (row1 <= item->row && item->row <= row2 &&
2526           col1 <= item->col && item->col <= col2)
2527         {
2528           if (!item->selected)
2529             dirty = TRUE;
2530
2531           item->selected = TRUE;
2532           
2533           gtk_icon_view_queue_draw_item (icon_view, item);
2534         }
2535     }
2536
2537   return dirty;
2538 }
2539
2540 static void 
2541 gtk_icon_view_move_cursor_up_down (GtkIconView *icon_view,
2542                                    gint         count)
2543 {
2544   GtkIconViewItem *item;
2545   gboolean dirty = FALSE;
2546   
2547   if (!GTK_WIDGET_HAS_FOCUS (icon_view))
2548     return;
2549   
2550   if (!icon_view->priv->cursor_item)
2551     {
2552       GList *list;
2553
2554       if (count > 0)
2555         list = icon_view->priv->items;
2556       else
2557         list = g_list_last (icon_view->priv->items);
2558
2559       item = list->data;
2560     }
2561   else
2562     item = find_item (icon_view, 
2563                       icon_view->priv->cursor_item,
2564                       count, 0);
2565
2566   if (!item)
2567     return;
2568
2569   if (icon_view->priv->ctrl_pressed ||
2570       !icon_view->priv->shift_pressed ||
2571       !icon_view->priv->anchor_item ||
2572       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
2573     icon_view->priv->anchor_item = item;
2574
2575   gtk_icon_view_set_cursor_item (icon_view, item);
2576
2577   if (!icon_view->priv->ctrl_pressed &&
2578       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
2579     {
2580       gtk_icon_view_unselect_all_internal (icon_view);
2581       dirty = gtk_icon_view_select_all_between (icon_view, 
2582                                                 icon_view->priv->anchor_item,
2583                                                 item);
2584     }
2585
2586   gtk_icon_view_scroll_to_item (icon_view, item);
2587
2588   if (dirty)
2589     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2590 }
2591
2592 static void 
2593 gtk_icon_view_move_cursor_page_up_down (GtkIconView *icon_view,
2594                                         gint         count)
2595 {
2596   GtkIconViewItem *item;
2597   gboolean dirty = FALSE;
2598   
2599   if (!GTK_WIDGET_HAS_FOCUS (icon_view))
2600     return;
2601   
2602   if (!icon_view->priv->cursor_item)
2603     {
2604       GList *list;
2605
2606       if (count > 0)
2607         list = icon_view->priv->items;
2608       else
2609         list = g_list_last (icon_view->priv->items);
2610
2611       item = list->data;
2612     }
2613   else
2614     item = find_item_page_up_down (icon_view, 
2615                                    icon_view->priv->cursor_item,
2616                                    count);
2617
2618   if (!item)
2619     return;
2620
2621   if (icon_view->priv->ctrl_pressed ||
2622       !icon_view->priv->shift_pressed ||
2623       !icon_view->priv->anchor_item ||
2624       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
2625     icon_view->priv->anchor_item = item;
2626
2627   gtk_icon_view_set_cursor_item (icon_view, item);
2628
2629   if (!icon_view->priv->ctrl_pressed &&
2630       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
2631     {
2632       gtk_icon_view_unselect_all_internal (icon_view);
2633       dirty = gtk_icon_view_select_all_between (icon_view, 
2634                                                 icon_view->priv->anchor_item,
2635                                                 item);
2636     }
2637
2638   gtk_icon_view_scroll_to_item (icon_view, item);
2639
2640   if (dirty)
2641     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);  
2642 }
2643
2644 static void 
2645 gtk_icon_view_move_cursor_left_right (GtkIconView *icon_view,
2646                                       gint         count)
2647 {
2648   GtkIconViewItem *item;
2649   gboolean dirty = FALSE;
2650   
2651   if (!GTK_WIDGET_HAS_FOCUS (icon_view))
2652     return;
2653   
2654   if (!icon_view->priv->cursor_item)
2655     {
2656       GList *list;
2657
2658       if (count > 0)
2659         list = icon_view->priv->items;
2660       else
2661         list = g_list_last (icon_view->priv->items);
2662
2663       item = list->data;
2664     }
2665   else
2666     item = find_item (icon_view, 
2667                       icon_view->priv->cursor_item,
2668                       0, count);
2669
2670   if (!item)
2671     return;
2672
2673   if (icon_view->priv->ctrl_pressed ||
2674       !icon_view->priv->shift_pressed ||
2675       !icon_view->priv->anchor_item ||
2676       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
2677     icon_view->priv->anchor_item = item;
2678
2679   gtk_icon_view_set_cursor_item (icon_view, item);
2680
2681   if (!icon_view->priv->ctrl_pressed &&
2682       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
2683     {
2684       gtk_icon_view_unselect_all_internal (icon_view);
2685       dirty = gtk_icon_view_select_all_between (icon_view, 
2686                                                 icon_view->priv->anchor_item,
2687                                                 item);
2688     }
2689
2690   gtk_icon_view_scroll_to_item (icon_view, item);
2691
2692   if (dirty)
2693     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2694 }
2695
2696 static void 
2697 gtk_icon_view_move_cursor_start_end (GtkIconView *icon_view,
2698                                      gint         count)
2699 {
2700   GtkIconViewItem *item;
2701   GList *list;
2702   gboolean dirty = FALSE;
2703   
2704   if (!GTK_WIDGET_HAS_FOCUS (icon_view))
2705     return;
2706   
2707   if (count < 0)
2708     list = icon_view->priv->items;
2709   else
2710     list = g_list_last (icon_view->priv->items);
2711   
2712   item = list->data;
2713
2714   if (!item)
2715     return;
2716
2717   if (icon_view->priv->ctrl_pressed ||
2718       !icon_view->priv->shift_pressed ||
2719       !icon_view->priv->anchor_item ||
2720       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
2721     icon_view->priv->anchor_item = item;
2722
2723   gtk_icon_view_set_cursor_item (icon_view, item);
2724
2725   if (!icon_view->priv->ctrl_pressed &&
2726       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
2727     {
2728       gtk_icon_view_unselect_all (icon_view);
2729       dirty = gtk_icon_view_select_all_between (icon_view, 
2730                                                 icon_view->priv->anchor_item,
2731                                                 item);
2732     }
2733
2734   gtk_icon_view_scroll_to_item (icon_view, item);
2735
2736   if (dirty)
2737     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2738 }
2739
2740 static void     
2741 gtk_icon_view_scroll_to_item (GtkIconView     *icon_view, 
2742                               GtkIconViewItem *item)
2743 {
2744   gint y, height;
2745   gdouble value;
2746
2747   gdk_window_get_geometry (icon_view->priv->bin_window, NULL, &y, NULL, &height, NULL);
2748
2749   if (y + item->y < 0)
2750     {
2751       value = icon_view->priv->vadjustment->value + y + item->y;
2752       gtk_adjustment_set_value (icon_view->priv->vadjustment, value);
2753     }
2754   else if (y + item->y + item->height > GTK_WIDGET (icon_view)->allocation.height)
2755     {
2756       value = icon_view->priv->vadjustment->value + y + item->y + item->height 
2757         - GTK_WIDGET (icon_view)->allocation.height;
2758       gtk_adjustment_set_value (icon_view->priv->vadjustment, value);
2759     }
2760 }
2761
2762 /* Public API */
2763
2764
2765 /**
2766  * gtk_icon_view_new:
2767  * 
2768  * Creates a new #GtkIconView widget
2769  * 
2770  * Return value: A newly created #GtkIconView widget
2771  *
2772  * Since: 2.6
2773  **/
2774 GtkWidget *
2775 gtk_icon_view_new (void)
2776 {
2777   return g_object_new (GTK_TYPE_ICON_VIEW, NULL);
2778 }
2779
2780 /**
2781  * gtk_icon_view_new_with_model:
2782  * @model: The model.
2783  * 
2784  * Creates a new #GtkIconView widget with the model @model.
2785  * 
2786  * Return value: A newly created #GtkIconView widget.
2787  *
2788  * Since: 2.6 
2789  **/
2790 GtkWidget *
2791 gtk_icon_view_new_with_model (GtkTreeModel *model)
2792 {
2793   return g_object_new (GTK_TYPE_ICON_VIEW, "model", model, NULL);
2794 }
2795
2796
2797 /**
2798  * gtk_icon_view_get_path_at_pos:
2799  * @icon_view: A #GtkIconView.
2800  * @x: The x position to be identified
2801  * @y: The y position to be identified
2802  * 
2803  * Finds the path at the point (@x, @y), relative to widget coordinates.
2804  * 
2805  * Return value: The #GtkTreePath corresponding to the icon or %NULL
2806  * if no icon exists at that position.
2807  *
2808  * Since: 2.6 
2809  **/
2810 GtkTreePath *
2811 gtk_icon_view_get_path_at_pos (GtkIconView *icon_view,
2812                                gint         x,
2813                                gint         y)
2814 {
2815   GtkIconViewItem *item;
2816   GtkTreePath *path;
2817   
2818   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
2819
2820   item = gtk_icon_view_get_item_at_pos (icon_view, x, y);
2821
2822   if (!item)
2823     return NULL;
2824
2825   path = gtk_tree_path_new_from_indices (item->index, -1);
2826
2827   return path;
2828 }
2829
2830 /**
2831  * gtk_icon_view_selected_foreach:
2832  * @icon_view: A #GtkIconView.
2833  * @func: The funcion to call for each selected icon.
2834  * @data: User data to pass to the function.
2835  * 
2836  * Calls a function for each selected icon. Note that the model or
2837  * selection cannot be modified from within this function.
2838  *
2839  * Since: 2.6 
2840  **/
2841 void
2842 gtk_icon_view_selected_foreach (GtkIconView           *icon_view,
2843                                 GtkIconViewForeachFunc func,
2844                                 gpointer               data)
2845 {
2846   GList *list;
2847   
2848   for (list = icon_view->priv->items; list; list = list->next)
2849     {
2850       GtkIconViewItem *item = list->data;
2851       GtkTreePath *path = gtk_tree_path_new_from_indices (item->index, -1);
2852
2853       if (item->selected)
2854         (* func) (icon_view, path, data);
2855
2856       gtk_tree_path_free (path);
2857     }
2858 }
2859
2860 /**
2861  * gtk_icon_view_set_selection_mode:
2862  * @icon_view: A #GtkIconView.
2863  * @mode: The selection mode
2864  * 
2865  * Sets the selection mode of the @icon_view.
2866  *
2867  * Since: 2.6 
2868  **/
2869 void
2870 gtk_icon_view_set_selection_mode (GtkIconView      *icon_view,
2871                                   GtkSelectionMode  mode)
2872 {
2873   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
2874
2875   if (mode == icon_view->priv->selection_mode)
2876     return;
2877   
2878   if (mode == GTK_SELECTION_NONE ||
2879       icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE)
2880     gtk_icon_view_unselect_all (icon_view);
2881   
2882   icon_view->priv->selection_mode = mode;
2883
2884   g_object_notify (G_OBJECT (icon_view), "selection_mode");
2885 }
2886
2887 /**
2888  * gtk_icon_view_get_selection_mode:
2889  * @icon_view: A #GtkIconView.
2890  * 
2891  * Gets the selection mode of the @icon_view.
2892  *
2893  * Return value: the current selection mode
2894  *
2895  * Since: 2.6 
2896  **/
2897 GtkSelectionMode
2898 gtk_icon_view_get_selection_mode (GtkIconView *icon_view)
2899 {
2900   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), GTK_SELECTION_SINGLE);
2901
2902   return icon_view->priv->selection_mode;
2903 }
2904
2905 /**
2906  * gtk_icon_view_set_model:
2907  * @icon_view: A #GtkIconView.
2908  * @model: The model.
2909  *
2910  * Sets the model for a #GtkIconView.  
2911  * If the @icon_view already has a model set, it will remove 
2912  * it before setting the new model.  If @model is %NULL, then
2913  * it will unset the old model.
2914  *
2915  * Since: 2.6 
2916  **/
2917 void
2918 gtk_icon_view_set_model (GtkIconView *icon_view,
2919                          GtkTreeModel *model)
2920 {
2921   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
2922
2923   if (model != NULL)
2924     g_return_if_fail (GTK_IS_TREE_MODEL (model));
2925   
2926   if (icon_view->priv->model == model)
2927     return;
2928
2929   if (model)
2930     {
2931       GType pixbuf_column_type, text_column_type;
2932       
2933       g_return_if_fail (gtk_tree_model_get_flags (model) & GTK_TREE_MODEL_LIST_ONLY);
2934
2935       if (icon_view->priv->pixbuf_column != -1)
2936         {
2937           pixbuf_column_type = gtk_tree_model_get_column_type (icon_view->priv->model,
2938                                                                icon_view->priv->pixbuf_column);   
2939
2940           g_return_if_fail (pixbuf_column_type == GDK_TYPE_PIXBUF);
2941         }
2942
2943       if (icon_view->priv->text_column != -1)
2944         {
2945           text_column_type = gtk_tree_model_get_column_type (icon_view->priv->model,
2946                                                              icon_view->priv->pixbuf_column);     
2947
2948           g_return_if_fail (text_column_type == G_TYPE_STRING);
2949         }
2950       
2951     }
2952   
2953   if (icon_view->priv->model)
2954     {
2955       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
2956                                             gtk_icon_view_row_changed,
2957                                             icon_view);
2958       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
2959                                             gtk_icon_view_row_inserted,
2960                                             icon_view);
2961       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
2962                                             gtk_icon_view_row_deleted,
2963                                             icon_view);
2964       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
2965                                             gtk_icon_view_rows_reordered,
2966                                             icon_view);
2967
2968       g_object_unref (icon_view->priv->model);
2969       
2970       g_list_foreach (icon_view->priv->items, (GFunc)gtk_icon_view_item_free, NULL);
2971       g_list_free (icon_view->priv->items);
2972       icon_view->priv->items = NULL;
2973     }
2974
2975   icon_view->priv->model = model;
2976
2977   if (icon_view->priv->model)
2978     {
2979       g_object_ref (icon_view->priv->model);
2980       g_signal_connect (icon_view->priv->model,
2981                         "row_changed",
2982                         G_CALLBACK (gtk_icon_view_row_changed),
2983                         icon_view);
2984       g_signal_connect (icon_view->priv->model,
2985                         "row_inserted",
2986                         G_CALLBACK (gtk_icon_view_row_inserted),
2987                         icon_view);
2988       g_signal_connect (icon_view->priv->model,
2989                         "row_deleted",
2990                         G_CALLBACK (gtk_icon_view_row_deleted),
2991                         icon_view);
2992       g_signal_connect (icon_view->priv->model,
2993                         "rows_reordered",
2994                         G_CALLBACK (gtk_icon_view_rows_reordered),
2995                         icon_view);
2996
2997       gtk_icon_view_build_items (icon_view);
2998     }
2999
3000   g_object_notify (G_OBJECT (icon_view), "model");  
3001 }
3002
3003 /**
3004  * gtk_icon_view_get_model:
3005  * @icon_view: a #GtkIconView
3006  *
3007  * Returns the model the #GtkIconView is based on.  Returns %NULL if the
3008  * model is unset.
3009  *
3010  * Return value: A #GtkTreeModel, or %NULL if none is currently being used.
3011  *
3012  * Since: 2.6 
3013  **/
3014 GtkTreeModel *
3015 gtk_icon_view_get_model (GtkIconView *icon_view)
3016 {
3017   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
3018
3019   return icon_view->priv->model;
3020 }
3021
3022 /**
3023  * gtk_icon_view_set_text_column:
3024  * @icon_view: A #GtkIconView.
3025  * @column: A column in the currently used model.
3026  * 
3027  * Sets the column with text for @icon_view to be @column. The text
3028  * column must be of type #G_TYPE_STRING.
3029  *
3030  * Since: 2.6 
3031  **/
3032 void
3033 gtk_icon_view_set_text_column (GtkIconView *icon_view,
3034                                gint          column)
3035 {
3036   if (column == icon_view->priv->text_column)
3037     return;
3038   
3039   if (column == -1)
3040     icon_view->priv->text_column = -1;
3041   else
3042     {
3043       if (icon_view->priv->model != NULL)
3044         {
3045           GType column_type;
3046           
3047           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
3048
3049           g_return_if_fail (column_type == G_TYPE_STRING);
3050         }
3051       
3052       icon_view->priv->text_column = column;
3053     }
3054
3055   gtk_icon_view_invalidate_sizes (icon_view);
3056   gtk_icon_view_queue_layout (icon_view);
3057   
3058   g_object_notify (G_OBJECT (icon_view), "text_column");
3059 }
3060
3061 /**
3062  * gtk_icon_view_get_text_column:
3063  * @icon_view: A #GtkIconView.
3064  *
3065  * Returns the column with text for @icon_view.
3066  *
3067  * Returns: the text column, or -1 if it's unset.
3068  *
3069  * Since: 2.6
3070  */
3071 gint
3072 gtk_icon_view_get_text_column (GtkIconView  *icon_view)
3073 {
3074   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
3075
3076   return icon_view->priv->text_column;
3077 }
3078
3079 /**
3080  * gtk_icon_view_set_markup_column:
3081  * @icon_view: A #GtkIconView.
3082  * @column: A column in the currently used model.
3083  * 
3084  * Sets the column with markup information for @icon_view to be
3085  * @column. The markup column must be of type #G_TYPE_STRING.
3086  * If the markup column is set to something, it overrides
3087  * the text column set by gtk_icon_view_set_text_column().
3088  *
3089  * Since: 2.6
3090  **/
3091 void
3092 gtk_icon_view_set_markup_column (GtkIconView *icon_view,
3093                                  gint         column)
3094 {
3095   if (column == icon_view->priv->markup_column)
3096     return;
3097   
3098   if (column == -1)
3099     icon_view->priv->markup_column = -1;
3100   else
3101     {
3102       if (icon_view->priv->model != NULL)
3103         {
3104           GType column_type;
3105           
3106           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
3107
3108           g_return_if_fail (column_type == G_TYPE_STRING);
3109         }
3110       
3111       icon_view->priv->markup_column = column;
3112     }
3113
3114   gtk_icon_view_invalidate_sizes (icon_view);
3115   gtk_icon_view_queue_layout (icon_view);
3116   
3117   g_object_notify (G_OBJECT (icon_view), "markup_column");
3118 }
3119
3120 /**
3121  * gtk_icon_view_get_markup_column:
3122  * @icon_view: A #GtkIconView.
3123  *
3124  * Returns the column with markup text for @icon_view.
3125  *
3126  * Returns: the markup column, or -1 if it's unset.
3127  *
3128  * Since: 2.6
3129  */
3130 gint
3131 gtk_icon_view_get_markup_column (GtkIconView  *icon_view)
3132 {
3133   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
3134
3135   return icon_view->priv->markup_column;
3136 }
3137
3138 /**
3139  * gtk_icon_view_set_pixbuf_column:
3140  * @icon_view: A #GtkIconView.
3141  * @column: A column in the currently used model.
3142  * 
3143  * Sets the column with pixbufs for @icon_view to be @column. The pixbuf
3144  * column must be of type #GDK_TYPE_PIXBUF
3145  *
3146  * Since: 2.6 
3147  **/
3148 void
3149 gtk_icon_view_set_pixbuf_column (GtkIconView *icon_view,
3150                                  gint         column)
3151 {
3152   if (column == icon_view->priv->pixbuf_column)
3153     return;
3154   
3155   if (column == -1)
3156     icon_view->priv->pixbuf_column = -1;
3157   else
3158     {
3159       if (icon_view->priv->model != NULL)
3160         {
3161           GType column_type;
3162           
3163           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
3164
3165           g_return_if_fail (column_type == GDK_TYPE_PIXBUF);
3166         }
3167       
3168       icon_view->priv->pixbuf_column = column;
3169     }
3170
3171   gtk_icon_view_invalidate_sizes (icon_view);
3172   gtk_icon_view_queue_layout (icon_view);
3173   
3174   g_object_notify (G_OBJECT (icon_view), "pixbuf_column");
3175   
3176 }
3177
3178 /**
3179  * gtk_icon_view_get_pixbuf_column:
3180  * @icon_view: A #GtkIconView.
3181  *
3182  * Returns the column with pixbufs for @icon_view.
3183  *
3184  * Returns: the pixbuf column, or -1 if it's unset.
3185  *
3186  * Since: 2.6
3187  */
3188 gint
3189 gtk_icon_view_get_pixbuf_column (GtkIconView  *icon_view)
3190 {
3191   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
3192
3193   return icon_view->priv->pixbuf_column;
3194 }
3195
3196 /**
3197  * gtk_icon_view_select_path:
3198  * @icon_view: A #GtkIconView.
3199  * @path: The #GtkTreePath to be selected.
3200  * 
3201  * Selects the row at @path.
3202  *
3203  * Since: 2.6
3204  **/
3205 void
3206 gtk_icon_view_select_path (GtkIconView *icon_view,
3207                            GtkTreePath *path)
3208 {
3209   GtkIconViewItem *item;
3210   
3211   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3212   g_return_if_fail (icon_view->priv->model != NULL);
3213   g_return_if_fail (path != NULL);
3214
3215   item = g_list_nth (icon_view->priv->items,
3216                      gtk_tree_path_get_indices(path)[0])->data;
3217
3218   if (!item)
3219     return;
3220   
3221   gtk_icon_view_select_item (icon_view, item);
3222 }
3223
3224 /**
3225  * gtk_icon_view_unselect_path:
3226  * @icon_view: A #GtkIconView.
3227  * @path: The #GtkTreePath to be unselected.
3228  * 
3229  * Unselects the row at @path.
3230  *
3231  * Since: 2.6
3232  **/
3233 void
3234 gtk_icon_view_unselect_path (GtkIconView *icon_view,
3235                              GtkTreePath *path)
3236 {
3237   GtkIconViewItem *item;
3238   
3239   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3240   g_return_if_fail (icon_view->priv->model != NULL);
3241   g_return_if_fail (path != NULL);
3242
3243   item = g_list_nth (icon_view->priv->items,
3244                      gtk_tree_path_get_indices(path)[0])->data;
3245
3246   if (!item)
3247     return;
3248   
3249   gtk_icon_view_unselect_item (icon_view, item);
3250 }
3251
3252 /**
3253  * gtk_icon_view_get_selected_items:
3254  * @icon_view: A #GtkIconView.
3255  *
3256  * Creates a list of path of all selected items. Additionally, if you are
3257  * planning on modifying the model after calling this function, you may
3258  * want to convert the returned list into a list of #GtkTreeRowReference<!-- -->s.
3259  * To do this, you can use gtk_tree_row_reference_new().
3260  *
3261  * To free the return value, use:
3262  * <informalexample><programlisting>
3263  * g_list_foreach (list, gtk_tree_path_free, NULL);
3264  * g_list_free (list);
3265  * </programlisting></informalexample>
3266  *
3267  * Return value: A #GList containing a #GtkTreePath for each selected row.
3268  *
3269  * Since: 2.6
3270  **/
3271 GList *
3272 gtk_icon_view_get_selected_items (GtkIconView *icon_view)
3273 {
3274   GList *list;
3275   GList *selected = NULL;
3276   
3277   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
3278   
3279   for (list = icon_view->priv->items; list != NULL; list = list->next)
3280     {
3281       GtkIconViewItem *item = list->data;
3282
3283       if (item->selected)
3284         {
3285           GtkTreePath *path = gtk_tree_path_new_from_indices (item->index, -1);
3286
3287           selected = g_list_prepend (selected, path);
3288         }
3289     }
3290
3291   return selected;
3292 }
3293
3294 /**
3295  * gtk_icon_view_select_all:
3296  * @icon_view: A #GtkIconView.
3297  * 
3298  * Selects all the icons. @icon_view must has its selection mode set
3299  * to #GTK_SELECTION_MULTIPLE.
3300  *
3301  * Since: 2.6
3302  **/
3303 void
3304 gtk_icon_view_select_all (GtkIconView *icon_view)
3305 {
3306   GList *items;
3307   gboolean dirty = FALSE;
3308   
3309   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3310
3311   if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3312     return;
3313
3314   for (items = icon_view->priv->items; items; items = items->next)
3315     {
3316       GtkIconViewItem *item = items->data;
3317       
3318       if (!item->selected)
3319         {
3320           dirty = TRUE;
3321           item->selected = TRUE;
3322           gtk_icon_view_queue_draw_item (icon_view, item);
3323         }
3324     }
3325
3326   if (dirty)
3327     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3328 }
3329
3330 /**
3331  * gtk_icon_view_unselect_all:
3332  * @icon_view: A #GtkIconView.
3333  * 
3334  * Unselects all the icons.
3335  *
3336  * Since: 2.6
3337  **/
3338 void
3339 gtk_icon_view_unselect_all (GtkIconView *icon_view)
3340 {
3341   gboolean dirty = FALSE;
3342   
3343   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3344
3345   dirty = gtk_icon_view_unselect_all_internal (icon_view);
3346
3347   if (dirty)
3348     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3349 }
3350
3351 /**
3352  * gtk_icon_view_path_is_selected:
3353  * @icon_view: A #GtkIconView.
3354  * @path: A #GtkTreePath to check selection on.
3355  * 
3356  * Returns %TRUE if the icon pointed to by @path is currently
3357  * selected. If @icon does not point to a valid location, %FALSE is returned.
3358  * 
3359  * Return value: %TRUE if @path is selected.
3360  *
3361  * Since: 2.6
3362  **/
3363 gboolean
3364 gtk_icon_view_path_is_selected (GtkIconView *icon_view,
3365                                 GtkTreePath *path)
3366 {
3367   GtkIconViewItem *item;
3368   
3369   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
3370   g_return_val_if_fail (icon_view->priv->model != NULL, FALSE);
3371   g_return_val_if_fail (path != NULL, FALSE);
3372   
3373   item = g_list_nth (icon_view->priv->items,
3374                      gtk_tree_path_get_indices(path)[0])->data;
3375
3376   if (!item)
3377     return FALSE;
3378   
3379   return item->selected;
3380 }
3381
3382 /**
3383  * gtk_icon_view_item_activated:
3384  * @icon_view: A #GtkIconView
3385  * @path: The #GtkTreePath to be activated
3386  * 
3387  * Activates the item determined by @path.
3388  *
3389  * Since: 2.6
3390  **/
3391 void
3392 gtk_icon_view_item_activated (GtkIconView      *icon_view,
3393                               GtkTreePath      *path)
3394 {
3395   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3396   g_return_if_fail (path != NULL);
3397   
3398   g_signal_emit (G_OBJECT (icon_view), icon_view_signals[ITEM_ACTIVATED], 0, path);
3399 }
3400
3401 /**
3402  * gtk_icon_view_set_orientation:
3403  * @icon_view: a #GtkIconView
3404  * @orientation: the relative position of texts and icons 
3405  * 
3406  * Sets the ::orientation property which determines whether the labels 
3407  * are drawn beside the icons instead of below.
3408  *
3409  * Since: 2.6
3410  **/
3411 void 
3412 gtk_icon_view_set_orientation (GtkIconView    *icon_view,
3413                                GtkOrientation  orientation)
3414 {
3415   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3416
3417   if (icon_view->priv->orientation != orientation)
3418     {
3419       icon_view->priv->orientation = orientation;
3420
3421       gtk_icon_view_invalidate_sizes (icon_view);
3422       gtk_icon_view_queue_layout (icon_view);
3423       
3424       g_object_notify (G_OBJECT (icon_view), "orientation");
3425     }
3426 }
3427
3428 /**
3429  * gtk_icon_view_get_orientation:
3430  * @icon_view: a #GtkIconView
3431  * 
3432  * Returns the value of the ::orientation property which determines 
3433  * whether the labels are drawn beside the icons instead of below. 
3434  * 
3435  * Return value: the relative position of texts and icons 
3436  *
3437  * Since: 2.6
3438  **/
3439 GtkOrientation
3440 gtk_icon_view_get_orientation (GtkIconView *icon_view)
3441 {
3442   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), 
3443                         GTK_ORIENTATION_VERTICAL);
3444
3445   return icon_view->priv->orientation;
3446 }