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