]> Pileus Git - ~andy/gtk/blob - gtk/gtkiconview.c
Add buttons to select and unselect all nodes, make the popup menu actually
[~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                   ((icon_view->priv->selection_mode == GTK_SELECTION_SINGLE) && item->selected)) &&
976                   (event->state & GDK_CONTROL_MASK))
977                 {
978                   item->selected = !item->selected;
979                   gtk_icon_view_queue_draw_item (icon_view, item);
980                   dirty = TRUE;
981                 }
982               else
983                 {
984                   if (!item->selected)
985                     {
986                       gtk_icon_view_unselect_all_internal (icon_view);
987                       
988                       item->selected = TRUE;
989                       gtk_icon_view_queue_draw_item (icon_view, item);
990                       dirty = TRUE;
991                     }
992                 }
993               gtk_icon_view_set_cursor_item (icon_view, item);
994               icon_view->priv->anchor_item = item;
995             }
996 #ifdef DND_WORKS
997           /* Save press to possibly begin a drag */
998           if (icon_view->priv->pressed_button < 0)
999             {
1000               icon_view->priv->pressed_button = event->button;
1001               icon_view->priv->press_start_x = event->x;
1002               icon_view->priv->press_start_y = event->y;
1003             }
1004 #endif
1005           if (!icon_view->priv->last_single_clicked)
1006             icon_view->priv->last_single_clicked = item;
1007         }
1008       else
1009         {
1010           if (icon_view->priv->selection_mode != GTK_SELECTION_BROWSE &&
1011               !(event->state & GDK_CONTROL_MASK))
1012             {
1013               dirty = gtk_icon_view_unselect_all_internal (icon_view);
1014             }
1015           
1016           if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE)
1017             gtk_icon_view_start_rubberbanding (icon_view, event->x, event->y);
1018         }
1019
1020     }
1021
1022   if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
1023     {
1024       item = gtk_icon_view_get_item_at_pos (icon_view,
1025                                             event->x, event->y);
1026
1027       if (item && item == icon_view->priv->last_single_clicked)
1028         {
1029           GtkTreePath *path;
1030
1031           path = gtk_tree_path_new_from_indices (item->index, -1);
1032           gtk_icon_view_item_activated (icon_view, path);
1033           gtk_tree_path_free (path);
1034         }
1035
1036       icon_view->priv->last_single_clicked = NULL;
1037     }
1038   
1039   if (dirty)
1040     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
1041
1042   return event->button == 1;
1043 }
1044
1045 static gboolean
1046 gtk_icon_view_button_release (GtkWidget      *widget,
1047                               GdkEventButton *event)
1048 {
1049   GtkIconView *icon_view;
1050
1051   icon_view = GTK_ICON_VIEW (widget);
1052   
1053 #ifdef DND_WORKS
1054   if (icon_view->priv->pressed_button == event->button)
1055     icon_view->priv->pressed_button = -1;
1056 #endif
1057   gtk_icon_view_stop_rubberbanding (icon_view);
1058
1059   if (icon_view->priv->scroll_timeout_id != 0)
1060     {
1061       g_source_remove (icon_view->priv->scroll_timeout_id);
1062       icon_view->priv->scroll_timeout_id = 0;
1063     }
1064
1065   return TRUE;
1066 }
1067
1068 static void
1069 gtk_icon_view_update_rubberband (gpointer data)
1070 {
1071   GtkIconView *icon_view;
1072   gint x, y;
1073   GdkRectangle old_area;
1074   GdkRectangle new_area;
1075   GdkRectangle common;
1076   GdkRegion *invalid_region;
1077   
1078   icon_view = GTK_ICON_VIEW (data);
1079
1080   gdk_window_get_pointer (icon_view->priv->bin_window, &x, &y, NULL);
1081
1082   x = MAX (x, 0);
1083   y = MAX (y, 0);
1084
1085   old_area.x = MIN (icon_view->priv->rubberband_x1,
1086                     icon_view->priv->rubberband_x2);
1087   old_area.y = MIN (icon_view->priv->rubberband_y1,
1088                     icon_view->priv->rubberband_y2);
1089   old_area.width = ABS (icon_view->priv->rubberband_x2 -
1090                         icon_view->priv->rubberband_x1) + 1;
1091   old_area.height = ABS (icon_view->priv->rubberband_y2 -
1092                          icon_view->priv->rubberband_y1) + 1;
1093   
1094   new_area.x = MIN (icon_view->priv->rubberband_x1, x);
1095   new_area.y = MIN (icon_view->priv->rubberband_y1, y);
1096   new_area.width = ABS (x - icon_view->priv->rubberband_x1) + 1;
1097   new_area.height = ABS (y - icon_view->priv->rubberband_y1) + 1;
1098
1099   invalid_region = gdk_region_rectangle (&old_area);
1100   gdk_region_union_with_rect (invalid_region, &new_area);
1101
1102   gdk_rectangle_intersect (&old_area, &new_area, &common);
1103   if (common.width > 2 && common.height > 2)
1104     {
1105       GdkRegion *common_region;
1106
1107       /* make sure the border is invalidated */
1108       common.x += 1;
1109       common.y += 1;
1110       common.width -= 2;
1111       common.height -= 2;
1112       
1113       common_region = gdk_region_rectangle (&common);
1114
1115       gdk_region_subtract (invalid_region, common_region);
1116       gdk_region_destroy (common_region);
1117     }
1118   
1119   gdk_window_invalidate_region (icon_view->priv->bin_window, invalid_region, TRUE);
1120     
1121   gdk_region_destroy (invalid_region);
1122
1123   icon_view->priv->rubberband_x2 = x;
1124   icon_view->priv->rubberband_y2 = y;  
1125
1126   gtk_icon_view_update_rubberband_selection (icon_view);
1127 }
1128
1129 static void
1130 gtk_icon_view_start_rubberbanding (GtkIconView  *icon_view,
1131                                    gint          x,
1132                                    gint          y)
1133 {
1134   GList *items;
1135
1136   g_assert (!icon_view->priv->doing_rubberband);
1137
1138   for (items = icon_view->priv->items; items; items = items->next)
1139     {
1140       GtkIconViewItem *item = items->data;
1141
1142       item->selected_before_rubberbanding = item->selected;
1143     }
1144   
1145   icon_view->priv->rubberband_x1 = x;
1146   icon_view->priv->rubberband_y1 = y;
1147   icon_view->priv->rubberband_x2 = x;
1148   icon_view->priv->rubberband_y2 = y;
1149
1150   icon_view->priv->doing_rubberband = TRUE;
1151
1152   gtk_grab_add (GTK_WIDGET (icon_view));
1153 }
1154
1155 static void
1156 gtk_icon_view_stop_rubberbanding (GtkIconView *icon_view)
1157 {
1158   if (!icon_view->priv->doing_rubberband)
1159     return;
1160
1161   icon_view->priv->doing_rubberband = FALSE;
1162
1163   gtk_grab_remove (GTK_WIDGET (icon_view));
1164   
1165   gtk_widget_queue_draw (GTK_WIDGET (icon_view));
1166 }
1167
1168 static void
1169 gtk_icon_view_update_rubberband_selection (GtkIconView *icon_view)
1170 {
1171   GList *items;
1172   gint x, y, width, height;
1173   gboolean dirty = FALSE;
1174   
1175   x = MIN (icon_view->priv->rubberband_x1,
1176            icon_view->priv->rubberband_x2);
1177   y = MIN (icon_view->priv->rubberband_y1,
1178            icon_view->priv->rubberband_y2);
1179   width = ABS (icon_view->priv->rubberband_x1 - 
1180                icon_view->priv->rubberband_x2);
1181   height = ABS (icon_view->priv->rubberband_y1 - 
1182                 icon_view->priv->rubberband_y2);
1183   
1184   for (items = icon_view->priv->items; items; items = items->next)
1185     {
1186       GtkIconViewItem *item = items->data;
1187       gboolean is_in;
1188       gboolean selected;
1189       
1190       is_in = gtk_icon_view_item_hit_test (item, x, y, width, height);
1191
1192       selected = is_in ^ item->selected_before_rubberbanding;
1193
1194       if (item->selected != selected)
1195         {
1196           item->selected = selected;
1197           dirty = TRUE;
1198           gtk_icon_view_queue_draw_item (icon_view, item);
1199         }
1200     }
1201
1202   if (dirty)
1203     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
1204 }
1205
1206 static gboolean
1207 gtk_icon_view_item_hit_test (GtkIconViewItem  *item,
1208                              gint              x,
1209                              gint              y,
1210                              gint              width,
1211                              gint              height)
1212 {
1213   /* First try the pixbuf */
1214   if (MIN (x + width, item->pixbuf_x + item->pixbuf_width) - MAX (x, item->pixbuf_x) > 0 &&
1215       MIN (y + height, item->pixbuf_y + item->pixbuf_height) - MAX (y, item->pixbuf_y) > 0)
1216     return TRUE;
1217
1218   /* Then try the text */
1219   if (MIN (x + width, item->layout_x + item->layout_width) - MAX (x, item->layout_x) > 0 &&
1220       MIN (y + height, item->layout_y + item->layout_height) - MAX (y, item->layout_y) > 0)
1221     return TRUE;
1222   
1223   return FALSE;
1224 }
1225
1226 #ifdef DND_WORKS
1227 static gboolean
1228 gtk_icon_view_maybe_begin_dragging_items (GtkIconView     *icon_view,
1229                                           GdkEventMotion  *event)
1230 {
1231   gboolean retval = FALSE;
1232   gint button;
1233   if (icon_view->priv->pressed_button < 0)
1234     return retval;
1235
1236   if (!gtk_drag_check_threshold (GTK_WIDGET (icon_view),
1237                                  icon_view->priv->press_start_x,
1238                                  icon_view->priv->press_start_y,
1239                                  event->x, event->y))
1240     return retval;
1241
1242   button = icon_view->priv->pressed_button;
1243   icon_view->priv->pressed_button = -1;
1244   
1245   {
1246     static GtkTargetEntry row_targets[] = {
1247       { "GTK_ICON_VIEW_ITEMS", GTK_TARGET_SAME_APP, 0 }
1248     };
1249     GtkTargetList *target_list;
1250     GdkDragContext *context;
1251     GtkIconViewItem *item;
1252     
1253     retval = TRUE;
1254     
1255     target_list = gtk_target_list_new (row_targets, G_N_ELEMENTS (row_targets));
1256
1257     context = gtk_drag_begin (GTK_WIDGET (icon_view),
1258                               target_list, GDK_ACTION_MOVE,
1259                               button,
1260                               (GdkEvent *)event);
1261
1262     item = gtk_icon_view_get_item_at_pos (icon_view,
1263                                           icon_view->priv->press_start_x,
1264                                           icon_view->priv->press_start_y);
1265     g_assert (item != NULL);
1266     gtk_drag_set_icon_pixbuf (context, gtk_icon_view_get_item_icon (icon_view, item),
1267                               event->x - item->x,
1268                               event->y - item->y);
1269   }
1270   
1271   return retval;
1272 }
1273 #endif
1274
1275 static gboolean
1276 gtk_icon_view_unselect_all_internal (GtkIconView  *icon_view)
1277 {
1278   gboolean dirty = FALSE;
1279   GList *items;
1280
1281   if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
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   gtk_icon_view_unselect_all (icon_view);
1369 }
1370
1371 static void
1372 gtk_icon_view_real_select_cursor_item (GtkIconView *icon_view)
1373 {
1374   gtk_icon_view_unselect_all (icon_view);
1375   
1376   if (icon_view->priv->cursor_item != NULL)
1377     gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
1378 }
1379
1380 static gboolean
1381 gtk_icon_view_real_activate_cursor_item (GtkIconView *icon_view)
1382 {
1383   GtkTreePath *path;
1384   
1385   if (!icon_view->priv->cursor_item)
1386     return FALSE;
1387
1388   path = gtk_tree_path_new_from_indices (icon_view->priv->cursor_item->index, -1);
1389   
1390   gtk_icon_view_item_activated (icon_view, path);
1391
1392   gtk_tree_path_free (path);
1393
1394   return TRUE;
1395 }
1396
1397 static void
1398 gtk_icon_view_real_toggle_cursor_item (GtkIconView *icon_view)
1399 {
1400   if (!icon_view->priv->cursor_item)
1401     return;
1402
1403   switch (icon_view->priv->selection_mode)
1404     {
1405     case GTK_SELECTION_NONE:
1406       break;
1407     case GTK_SELECTION_BROWSE:
1408       gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
1409       break;
1410     case GTK_SELECTION_SINGLE:
1411       if (icon_view->priv->cursor_item->selected)
1412         gtk_icon_view_unselect_item (icon_view, icon_view->priv->cursor_item);
1413       else
1414         gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
1415       break;
1416     case GTK_SELECTION_MULTIPLE:
1417       icon_view->priv->cursor_item->selected = !icon_view->priv->cursor_item->selected;
1418       g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0); 
1419       
1420       gtk_icon_view_queue_draw_item (icon_view, icon_view->priv->cursor_item);
1421       break;
1422     }
1423 }
1424
1425 /* Internal functions */
1426 static void
1427 gtk_icon_view_adjustment_changed (GtkAdjustment *adjustment,
1428                                   GtkIconView   *icon_view)
1429 {
1430   if (GTK_WIDGET_REALIZED (icon_view))
1431     {
1432       gdk_window_move (icon_view->priv->bin_window,
1433                        - icon_view->priv->hadjustment->value,
1434                        - icon_view->priv->vadjustment->value);
1435
1436       if (icon_view->priv->doing_rubberband)
1437         gtk_icon_view_update_rubberband (GTK_WIDGET (icon_view));
1438
1439       gdk_window_process_updates (icon_view->priv->bin_window, TRUE);
1440     }
1441 }
1442
1443 static GList *
1444 gtk_icon_view_layout_single_row (GtkIconView *icon_view, GList *first_item, gint *y, gint *maximum_width, gint row)
1445 {
1446   gint focus_width, focus_pad;
1447   gint x, current_width, max_height, max_pixbuf_height;
1448   GList *items, *last_item;
1449   gint maximum_layout_width;
1450   gint col;
1451   gboolean rtl = gtk_widget_get_direction (GTK_WIDGET (icon_view)) == GTK_TEXT_DIR_RTL;
1452
1453   x = 0;
1454   col = 0;
1455   max_height = 0;
1456   max_pixbuf_height = 0;
1457   items = first_item;
1458   current_width = 0;
1459
1460   gtk_widget_style_get (GTK_WIDGET (icon_view),
1461                         "focus-line-width", &focus_width,
1462                         "focus-padding", &focus_pad,
1463                         NULL);
1464
1465   x += ICON_VIEW_LEFT_MARGIN;
1466   current_width += ICON_VIEW_LEFT_MARGIN + ICON_VIEW_RIGHT_MARGIN;
1467   items = first_item;
1468
1469   while (items)
1470     {
1471       GtkIconViewItem *item = items->data;
1472
1473       gtk_icon_view_calculate_item_size (icon_view, item);
1474
1475       current_width += MAX (item->width, MINIMUM_ICON_ITEM_WIDTH);
1476
1477       /* Don't add padding to the first or last icon */
1478       
1479       if (current_width > GTK_WIDGET (icon_view)->allocation.width &&
1480           items != first_item)
1481         break;
1482
1483       maximum_layout_width = MAX (item->pixbuf_width, MINIMUM_ICON_ITEM_WIDTH);
1484
1485       item->y = *y;
1486       item->x = rtl ? GTK_WIDGET (icon_view)->allocation.width - item->width - x : x;
1487       if (item->width < MINIMUM_ICON_ITEM_WIDTH) {
1488         if (rtl)
1489           item->x -= (MINIMUM_ICON_ITEM_WIDTH - item->width) / 2;
1490         else
1491           item->x += (MINIMUM_ICON_ITEM_WIDTH - item->width) / 2;
1492         x += (MINIMUM_ICON_ITEM_WIDTH - item->width);
1493       }
1494
1495       if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1496         {
1497           if (gtk_widget_get_direction (GTK_WIDGET (icon_view)) == GTK_TEXT_DIR_RTL)
1498             {
1499               item->layout_x = item->x + ICON_TEXT_PADDING + focus_width + focus_pad;
1500               item->pixbuf_x = item->x + 2 * (ICON_TEXT_PADDING + focus_width + focus_pad) + item->layout_width;
1501             }
1502           else 
1503             {
1504               item->pixbuf_x = item->x;
1505               item->layout_x = item->x + item->pixbuf_width + ICON_TEXT_PADDING + focus_width + focus_pad;
1506             }
1507         }
1508       else
1509         {
1510           item->pixbuf_x = item->x + (item->width - item->pixbuf_width) / 2;
1511           item->layout_x = item->x + (item->width - item->layout_width) / 2;
1512         }
1513
1514       x += item->width;
1515
1516       max_height = MAX (max_height, item->height);
1517       max_pixbuf_height = MAX (max_pixbuf_height, item->pixbuf_height);
1518       
1519       if (current_width > *maximum_width)
1520         *maximum_width = current_width;
1521
1522       item->row = row;
1523       item->col = col;
1524
1525       col++;
1526       items = items->next;
1527     }
1528
1529   last_item = items;
1530
1531   *y += max_height + ICON_VIEW_ICON_PADDING;
1532
1533   /* Now go through the row again and align the icons */
1534   for (items = first_item; items != last_item; items = items->next)
1535     {
1536       GtkIconViewItem *item = items->data;
1537
1538       if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1539         {
1540           item->pixbuf_y = item->y;
1541           item->layout_y = item->y + ICON_TEXT_PADDING + focus_width + focus_pad;
1542         }
1543       else 
1544         {
1545           item->pixbuf_y = item->y + (max_pixbuf_height - item->pixbuf_height);
1546           item->layout_y = item->pixbuf_y + item->pixbuf_height + ICON_TEXT_PADDING + focus_width + focus_pad;
1547       }
1548       /* Update the bounding box */
1549       item->y = item->pixbuf_y;
1550
1551       /* We may want to readjust the new y coordinate. */
1552       if (item->y + item->height > *y)
1553         *y = item->y + item->height;
1554
1555       if (rtl)
1556         item->col = col - 1 - item->col;
1557     }
1558   
1559   return last_item;
1560 }
1561
1562 static void
1563 gtk_icon_view_set_adjustment_upper (GtkAdjustment *adj,
1564                                     gdouble        upper)
1565 {
1566   if (upper != adj->upper)
1567     {
1568       gdouble min = MAX (0.0, upper - adj->page_size);
1569       gboolean value_changed = FALSE;
1570       
1571       adj->upper = upper;
1572
1573       if (adj->value > min)
1574         {
1575           adj->value = min;
1576           value_changed = TRUE;
1577         }
1578       
1579       gtk_adjustment_changed (adj);
1580       
1581       if (value_changed)
1582         gtk_adjustment_value_changed (adj);
1583     }
1584 }
1585
1586 static void
1587 gtk_icon_view_layout (GtkIconView *icon_view)
1588 {
1589   gint y = 0, maximum_width = 0;
1590   GList *icons;
1591   GtkWidget *widget;
1592   gint row;
1593
1594   if (!VALID_MODEL_AND_COLUMNS (icon_view))
1595     return;
1596
1597   widget = GTK_WIDGET (icon_view);
1598   icons = icon_view->priv->items;
1599
1600   y += ICON_VIEW_TOP_MARGIN;
1601   row = 0;
1602
1603   do
1604     {
1605       icons = gtk_icon_view_layout_single_row (icon_view, icons, &y, &maximum_width, row);
1606       row++;
1607     }
1608   while (icons != NULL);
1609
1610   if (maximum_width != icon_view->priv->width)
1611     {
1612       icon_view->priv->width = maximum_width;
1613     }
1614   y += ICON_VIEW_BOTTOM_MARGIN;
1615   
1616   if (y != icon_view->priv->height)
1617     {
1618       icon_view->priv->height = y;
1619     }
1620
1621   gtk_icon_view_set_adjustment_upper (icon_view->priv->hadjustment, icon_view->priv->width);
1622   gtk_icon_view_set_adjustment_upper (icon_view->priv->vadjustment, icon_view->priv->height);
1623
1624   if (GTK_WIDGET_REALIZED (icon_view))
1625     {
1626       gdk_window_resize (icon_view->priv->bin_window,
1627                          MAX (icon_view->priv->width, widget->allocation.width),
1628                          MAX (icon_view->priv->height, widget->allocation.height));
1629     }
1630
1631   if (icon_view->priv->layout_idle_id != 0)
1632     {
1633       g_source_remove (icon_view->priv->layout_idle_id);
1634       icon_view->priv->layout_idle_id = 0;
1635     }
1636
1637   gtk_widget_queue_draw (GTK_WIDGET (icon_view));
1638 }
1639
1640 /* Updates the pango layout and calculates the size */
1641 static void
1642 gtk_icon_view_calculate_item_size (GtkIconView *icon_view,
1643                                    GtkIconViewItem *item)
1644 {
1645   gint focus_width, focus_pad;
1646   gint layout_width, layout_height;
1647   gint maximum_layout_width;
1648   GdkPixbuf *pixbuf;
1649   
1650   if (item->width != -1 && item->width != -1) 
1651     return;
1652
1653   gtk_widget_style_get (GTK_WIDGET (icon_view),
1654                         "focus-line-width", &focus_width,
1655                         "focus-padding", &focus_pad,
1656                         NULL);
1657
1658   if (icon_view->priv->pixbuf_column != -1)
1659     {
1660       pixbuf = gtk_icon_view_get_item_icon (icon_view, item);
1661       item->pixbuf_width = gdk_pixbuf_get_width (pixbuf);
1662       item->pixbuf_height = gdk_pixbuf_get_height (pixbuf);
1663       g_object_unref (pixbuf);
1664     }
1665   else
1666     {
1667       item->pixbuf_width = 0;
1668       item->pixbuf_height = 0;
1669     }
1670   
1671   maximum_layout_width = MAX (item->pixbuf_width, MINIMUM_ICON_ITEM_WIDTH);
1672
1673   if (icon_view->priv->markup_column != 1 ||
1674       icon_view->priv->text_column != -1)
1675     {
1676       gtk_icon_view_update_item_text (icon_view, item);
1677
1678       pango_layout_set_alignment (icon_view->priv->layout, PANGO_ALIGN_CENTER);
1679       pango_layout_set_width (icon_view->priv->layout, maximum_layout_width * PANGO_SCALE);
1680       
1681       pango_layout_get_pixel_size (icon_view->priv->layout, &layout_width, &layout_height);
1682       
1683       item->layout_width = layout_width;
1684       item->layout_height = layout_height;
1685     }
1686   else
1687     {
1688       item->layout_width = 0;
1689       item->layout_height = 0;
1690     }
1691
1692   if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1693     {
1694       item->width = layout_width + 2 * (ICON_TEXT_PADDING + focus_width + focus_pad) + item->pixbuf_width;
1695       item->height = MAX (layout_height + 2 * (ICON_TEXT_PADDING + focus_width + focus_pad), item->pixbuf_height);
1696     }
1697   else
1698     {
1699       item->width = MAX (layout_width + 2 * (ICON_TEXT_PADDING + focus_width + focus_pad), item->pixbuf_width);
1700       item->height = layout_height + 2 * (ICON_TEXT_PADDING + focus_width + focus_pad) + item->pixbuf_height;
1701     }
1702 }
1703
1704 static void
1705 gtk_icon_view_invalidate_sizes (GtkIconView *icon_view)
1706 {
1707   g_list_foreach (icon_view->priv->items,
1708                   (GFunc)gtk_icon_view_item_invalidate_size, NULL);
1709 }
1710
1711 static void
1712 gtk_icon_view_item_invalidate_size (GtkIconViewItem *item)
1713 {
1714   item->width = -1;
1715   item->height = -1;
1716 }
1717
1718 static GdkPixbuf *
1719 create_colorized_pixbuf (GdkPixbuf *src, GdkColor *new_color)
1720 {
1721         gint i, j;
1722         gint width, height, has_alpha, src_row_stride, dst_row_stride;
1723         gint red_value, green_value, blue_value;
1724         guchar *target_pixels;
1725         guchar *original_pixels;
1726         guchar *pixsrc;
1727         guchar *pixdest;
1728         GdkPixbuf *dest;
1729
1730         red_value = new_color->red / 255.0;
1731         green_value = new_color->green / 255.0;
1732         blue_value = new_color->blue / 255.0;
1733
1734         dest = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src),
1735                                gdk_pixbuf_get_has_alpha (src),
1736                                gdk_pixbuf_get_bits_per_sample (src),
1737                                gdk_pixbuf_get_width (src),
1738                                gdk_pixbuf_get_height (src));
1739         
1740         has_alpha = gdk_pixbuf_get_has_alpha (src);
1741         width = gdk_pixbuf_get_width (src);
1742         height = gdk_pixbuf_get_height (src);
1743         src_row_stride = gdk_pixbuf_get_rowstride (src);
1744         dst_row_stride = gdk_pixbuf_get_rowstride (dest);
1745         target_pixels = gdk_pixbuf_get_pixels (dest);
1746         original_pixels = gdk_pixbuf_get_pixels (src);
1747
1748         for (i = 0; i < height; i++) {
1749                 pixdest = target_pixels + i*dst_row_stride;
1750                 pixsrc = original_pixels + i*src_row_stride;
1751                 for (j = 0; j < width; j++) {           
1752                         *pixdest++ = (*pixsrc++ * red_value) >> 8;
1753                         *pixdest++ = (*pixsrc++ * green_value) >> 8;
1754                         *pixdest++ = (*pixsrc++ * blue_value) >> 8;
1755                         if (has_alpha) {
1756                                 *pixdest++ = *pixsrc++;
1757                         }
1758                 }
1759         }
1760         return dest;
1761 }
1762
1763 static void
1764 gtk_icon_view_paint_item (GtkIconView     *icon_view,
1765                           GtkIconViewItem *item,
1766                           GdkRectangle    *area)
1767 {
1768   gint focus_width, focus_pad;
1769   GdkPixbuf *pixbuf, *tmp;
1770   GtkStateType state;
1771   
1772   if (!VALID_MODEL_AND_COLUMNS (icon_view))
1773     return;
1774   
1775   gtk_widget_style_get (GTK_WIDGET (icon_view),
1776                         "focus-line-width", &focus_width,
1777                         "focus-padding", &focus_pad,
1778                         NULL);
1779
1780   if (GTK_WIDGET_HAS_FOCUS (icon_view))
1781     state = GTK_STATE_SELECTED;
1782   else
1783     state = GTK_STATE_ACTIVE;
1784
1785   if (icon_view->priv->pixbuf_column != -1)
1786     {
1787       tmp = gtk_icon_view_get_item_icon (icon_view, item);
1788       if (item->selected)
1789         {
1790           pixbuf = create_colorized_pixbuf (tmp,
1791                                             &GTK_WIDGET (icon_view)->style->base[state]);
1792           g_object_unref (tmp);
1793         }
1794       else
1795         pixbuf = tmp;
1796       
1797       gdk_draw_pixbuf (icon_view->priv->bin_window, NULL, pixbuf,
1798                        0, 0,
1799                        item->pixbuf_x, item->pixbuf_y,
1800                        item->pixbuf_width, item->pixbuf_height,
1801                        GDK_RGB_DITHER_NORMAL,
1802                        item->pixbuf_width, item->pixbuf_height);
1803       g_object_unref (pixbuf);
1804     }
1805
1806   if (icon_view->priv->text_column != -1)
1807     {
1808       if (item->selected)
1809         {
1810           gdk_draw_rectangle (icon_view->priv->bin_window,
1811                               GTK_WIDGET (icon_view)->style->base_gc[state],
1812                               TRUE,
1813                               item->layout_x - ICON_TEXT_PADDING,
1814                               item->layout_y - ICON_TEXT_PADDING,
1815                               item->layout_width + 2 * ICON_TEXT_PADDING,
1816                               item->layout_height + 2 * ICON_TEXT_PADDING);
1817         }
1818
1819       gtk_icon_view_update_item_text (icon_view, item);
1820       gtk_paint_layout (GTK_WIDGET (icon_view)->style,
1821                         icon_view->priv->bin_window,
1822                         item->selected ? state : GTK_STATE_NORMAL,
1823                         TRUE, area, GTK_WIDGET (icon_view), "icon_view",
1824                         item->layout_x - ((item->width - item->layout_width) / 2) - (MAX (item->pixbuf_width, MINIMUM_ICON_ITEM_WIDTH) - item->width) / 2,
1825                         item->layout_y,
1826                         icon_view->priv->layout);
1827
1828       if (GTK_WIDGET_HAS_FOCUS (icon_view) &&
1829           item == icon_view->priv->cursor_item)
1830         gtk_paint_focus (GTK_WIDGET (icon_view)->style,
1831                          icon_view->priv->bin_window,
1832                          GTK_STATE_NORMAL,
1833                          area,
1834                          GTK_WIDGET (icon_view),
1835                          "icon_view",
1836                          item->layout_x - ICON_TEXT_PADDING - focus_width - focus_pad,
1837                          item->layout_y - ICON_TEXT_PADDING - focus_width - focus_pad,
1838                          item->layout_width + 2 * (ICON_TEXT_PADDING + focus_width + focus_pad),
1839                          item->layout_height + 2 * (ICON_TEXT_PADDING + focus_width + focus_pad));
1840     }
1841 }
1842
1843 static guint32
1844 gtk_gdk_color_to_rgb (const GdkColor *color)
1845 {
1846   guint32 result;
1847   result = (0xff0000 | (color->red & 0xff00));
1848   result <<= 8;
1849   result |= ((color->green & 0xff00) | (color->blue >> 8));
1850   return result;
1851 }
1852
1853 static void
1854 gtk_icon_view_paint_rubberband (GtkIconView     *icon_view,
1855                                 GdkRectangle    *area)
1856 {
1857   GdkRectangle rect;
1858   GdkPixbuf *pixbuf;
1859   GdkGC *gc;
1860   GdkRectangle rubber_rect;
1861   GdkColor *fill_color_gdk;
1862   guint fill_color;
1863   guchar fill_color_alpha;
1864
1865   rubber_rect.x = MIN (icon_view->priv->rubberband_x1, icon_view->priv->rubberband_x2);
1866   rubber_rect.y = MIN (icon_view->priv->rubberband_y1, icon_view->priv->rubberband_y2);
1867   rubber_rect.width = ABS (icon_view->priv->rubberband_x1 - icon_view->priv->rubberband_x2) + 1;
1868   rubber_rect.height = ABS (icon_view->priv->rubberband_y1 - icon_view->priv->rubberband_y2) + 1;
1869
1870   if (!gdk_rectangle_intersect (&rubber_rect, area, &rect))
1871     return;
1872
1873   gtk_widget_style_get (GTK_WIDGET (icon_view),
1874                         "selection_box_color", &fill_color_gdk,
1875                         "selection_box_alpha", &fill_color_alpha,
1876                         NULL);
1877
1878   if (!fill_color_gdk) {
1879     fill_color_gdk = gdk_color_copy (&GTK_WIDGET (icon_view)->style->base[GTK_STATE_SELECTED]);
1880   }
1881
1882   fill_color = gtk_gdk_color_to_rgb (fill_color_gdk) << 8 | fill_color_alpha;
1883
1884   if (!gdk_draw_rectangle_alpha_libgtk_only (icon_view->priv->bin_window,
1885                                              rect.x, rect.y, rect.width, rect.height,
1886                                              fill_color_gdk,
1887                                              fill_color_alpha << 8 | fill_color_alpha))
1888     {
1889       pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, rect.width, rect.height);
1890       gdk_pixbuf_fill (pixbuf, fill_color);
1891       
1892       gdk_draw_pixbuf (icon_view->priv->bin_window, NULL, pixbuf,
1893                        0, 0, 
1894                        rect.x,rect.y,
1895                        rect.width, rect.height,
1896                        GDK_RGB_DITHER_NONE,
1897                        0, 0);
1898       g_object_unref (pixbuf);
1899     }
1900
1901   gc = gdk_gc_new (icon_view->priv->bin_window);
1902   gdk_gc_set_rgb_fg_color (gc, fill_color_gdk);
1903   gdk_gc_set_clip_rectangle (gc, &rect);
1904   gdk_draw_rectangle (icon_view->priv->bin_window,
1905                       gc, FALSE,
1906                       rubber_rect.x, rubber_rect.y,
1907                       rubber_rect.width - 1, rubber_rect.height - 1);
1908   gdk_color_free (fill_color_gdk);
1909   g_object_unref (gc);
1910 }
1911
1912 static void
1913 gtk_icon_view_queue_draw_item (GtkIconView     *icon_view,
1914                                GtkIconViewItem *item)
1915 {
1916   GdkRectangle rect;
1917
1918   rect.x = item->x;
1919   rect.y = item->y;
1920   rect.width = item->width;
1921   rect.height = item->height;
1922
1923   if (icon_view->priv->bin_window)
1924     gdk_window_invalidate_rect (icon_view->priv->bin_window, &rect, TRUE);
1925 }
1926
1927 static gboolean
1928 layout_callback (gpointer user_data)
1929 {
1930   GtkIconView *icon_view;
1931
1932   icon_view = GTK_ICON_VIEW (user_data);
1933   
1934   icon_view->priv->layout_idle_id = 0;
1935
1936   gtk_icon_view_layout (icon_view);
1937   
1938   return FALSE;
1939 }
1940
1941 static void
1942 gtk_icon_view_queue_layout (GtkIconView *icon_view)
1943 {
1944   if (icon_view->priv->layout_idle_id != 0)
1945     return;
1946
1947   icon_view->priv->layout_idle_id = g_idle_add (layout_callback, icon_view);
1948 }
1949
1950 static void
1951 gtk_icon_view_set_cursor_item (GtkIconView     *icon_view,
1952                                GtkIconViewItem *item)
1953 {
1954   if (icon_view->priv->cursor_item == item)
1955     return;
1956
1957   if (icon_view->priv->cursor_item != NULL)
1958     gtk_icon_view_queue_draw_item (icon_view, icon_view->priv->cursor_item);
1959   
1960   icon_view->priv->cursor_item = item;
1961   gtk_icon_view_queue_draw_item (icon_view, item);
1962 }
1963
1964
1965 static GtkIconViewItem *
1966 gtk_icon_view_item_new (void)
1967 {
1968   GtkIconViewItem *item;
1969
1970   item = g_new0 (GtkIconViewItem, 1);
1971
1972   item->width = -1;
1973   item->height = -1;
1974   
1975   return item;
1976 }
1977
1978 static void
1979 gtk_icon_view_item_free (GtkIconViewItem *item)
1980 {
1981   g_return_if_fail (item != NULL);
1982
1983   g_free (item);
1984 }
1985
1986 static void
1987 gtk_icon_view_update_item_text (GtkIconView     *icon_view,
1988                                 GtkIconViewItem *item)
1989 {
1990   gboolean iters_persist;
1991   GtkTreeIter iter;
1992   GtkTreePath *path;
1993   gchar *text;
1994   
1995   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
1996   
1997   if (!iters_persist)
1998     {
1999       path = gtk_tree_path_new_from_indices (item->index, -1);
2000       gtk_tree_model_get_iter (icon_view->priv->model, &iter, path);
2001       gtk_tree_path_free (path);
2002     }
2003   else
2004     iter = item->iter;
2005
2006   if (icon_view->priv->markup_column != -1)
2007     {
2008       gtk_tree_model_get (icon_view->priv->model, &iter,
2009                           icon_view->priv->markup_column, &text,
2010                           -1);
2011       pango_layout_set_markup (icon_view->priv->layout, text, -1);
2012     }
2013   else
2014     {
2015       gtk_tree_model_get (icon_view->priv->model, &iter,
2016                           icon_view->priv->text_column, &text,
2017                           -1);
2018       pango_layout_set_text (icon_view->priv->layout, text, -1);
2019     }
2020
2021   g_free (text);        
2022 }
2023
2024 static GdkPixbuf *
2025 gtk_icon_view_get_item_icon (GtkIconView      *icon_view,
2026                              GtkIconViewItem  *item)
2027 {
2028   gboolean iters_persist;
2029   GtkTreeIter iter;
2030   GtkTreePath *path;
2031   GdkPixbuf *pixbuf;
2032   
2033   g_return_val_if_fail (item != NULL, NULL);
2034
2035   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
2036   
2037   if (!iters_persist)
2038     {
2039       path = gtk_tree_path_new_from_indices (item->index, -1);
2040       gtk_tree_model_get_iter (icon_view->priv->model, &iter, path);
2041       gtk_tree_path_free (path);
2042     }
2043   else
2044     iter = item->iter;
2045   
2046   gtk_tree_model_get (icon_view->priv->model, &iter,
2047                       icon_view->priv->pixbuf_column, &pixbuf,
2048                       -1);
2049
2050   return pixbuf;
2051 }
2052
2053
2054 static GtkIconViewItem *
2055 gtk_icon_view_get_item_at_pos (GtkIconView *icon_view,
2056                                gint         x,
2057                                gint         y)
2058 {
2059   GList *items;
2060   
2061   for (items = icon_view->priv->items; items; items = items->next)
2062     {
2063       GtkIconViewItem *item = items->data;
2064       
2065       if (x > item->x && x < item->x + item->width &&
2066           y > item->y && y < item->y + item->height)
2067         {
2068           gint layout_x = item->x + (item->width - item->layout_width) / 2;
2069           /* Check if the mouse is inside the icon or the label */
2070           if ((x > item->pixbuf_x && x < item->pixbuf_x + item->pixbuf_width &&
2071                y > item->pixbuf_y && y < item->pixbuf_y + item->pixbuf_height) ||
2072               (x > layout_x - ICON_TEXT_PADDING &&
2073                x < layout_x + item->layout_width + ICON_TEXT_PADDING * 2 &&
2074                y > item->layout_y - ICON_TEXT_PADDING
2075                && y < item->layout_y + item->layout_height + ICON_TEXT_PADDING * 2))
2076             return item;
2077         }
2078     }
2079
2080   return NULL;
2081 }
2082
2083 static void
2084 gtk_icon_view_select_item (GtkIconView      *icon_view,
2085                            GtkIconViewItem  *item)
2086 {
2087   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
2088   g_return_if_fail (item != NULL);
2089
2090   if (item->selected)
2091     return;
2092   
2093   if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
2094     return;
2095   else if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
2096     gtk_icon_view_unselect_all_internal (icon_view);
2097
2098   item->selected = TRUE;
2099
2100   gtk_icon_view_queue_draw_item (icon_view, item);
2101
2102   g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2103 }
2104
2105
2106 static void
2107 gtk_icon_view_unselect_item (GtkIconView      *icon_view,
2108                              GtkIconViewItem  *item)
2109 {
2110   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
2111   g_return_if_fail (item != NULL);
2112
2113   if (!item->selected)
2114     return;
2115   
2116   if (icon_view->priv->selection_mode == GTK_SELECTION_NONE ||
2117       icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
2118     return;
2119   
2120   item->selected = FALSE;
2121
2122   g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2123
2124   gtk_icon_view_queue_draw_item (icon_view, item);
2125 }
2126
2127 static void
2128 verify_items (GtkIconView *icon_view)
2129 {
2130   GList *items;
2131   int i = 0;
2132
2133   for (items = icon_view->priv->items; items; items = items->next)
2134     {
2135       GtkIconViewItem *item = items->data;
2136
2137       if (item->index != i)
2138         g_error ("List item does not match its index: item index %d and list index %d\n", item->index, i);
2139
2140       i++;
2141     }
2142 }
2143
2144 static void
2145 gtk_icon_view_row_changed (GtkTreeModel *model,
2146                            GtkTreePath  *path,
2147                            GtkTreeIter  *iter,
2148                            gpointer      data)
2149 {
2150   GtkIconViewItem *item;
2151   gint index;
2152   GtkIconView *icon_view;
2153
2154   icon_view = GTK_ICON_VIEW (data);
2155   
2156   index = gtk_tree_path_get_indices(path)[0];
2157   item = g_list_nth (icon_view->priv->items, index)->data;
2158
2159   gtk_icon_view_item_invalidate_size (item);
2160   gtk_icon_view_queue_layout (icon_view);
2161
2162   verify_items (icon_view);
2163 }
2164
2165 static void
2166 gtk_icon_view_row_inserted (GtkTreeModel *model,
2167                             GtkTreePath  *path,
2168                             GtkTreeIter  *iter,
2169                             gpointer      data)
2170 {
2171   gint length, index;
2172   GtkIconViewItem *item;
2173   gboolean iters_persist;
2174   GtkIconView *icon_view;
2175   GList *list;
2176   
2177   icon_view = GTK_ICON_VIEW (data);
2178   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
2179   
2180   length = gtk_tree_model_iter_n_children (model, NULL);
2181   index = gtk_tree_path_get_indices(path)[0];
2182
2183   item = gtk_icon_view_item_new ();
2184
2185   if (iters_persist)
2186     item->iter = *iter;
2187
2188   item->index = index;
2189
2190   /* FIXME: We can be more efficient here,
2191      we can store a tail pointer and use that when
2192      appending (which is a rather common operation)
2193   */
2194   icon_view->priv->items = g_list_insert (icon_view->priv->items,
2195                                          item, index);
2196   
2197   list = g_list_nth (icon_view->priv->items, index + 1);
2198   for (; list; list = list->next)
2199     {
2200       item = list->data;
2201
2202       item->index++;
2203     }
2204     
2205   verify_items (icon_view);
2206 }
2207
2208 static void
2209 gtk_icon_view_row_deleted (GtkTreeModel *model,
2210                            GtkTreePath  *path,
2211                            gpointer      data)
2212 {
2213   gint index;
2214   GtkIconView *icon_view;
2215   GtkIconViewItem *item;
2216   GList *list, *next;
2217   gboolean emit = FALSE;
2218   
2219   icon_view = GTK_ICON_VIEW (data);
2220
2221   index = gtk_tree_path_get_indices(path)[0];
2222
2223   list = g_list_nth (icon_view->priv->items, index);
2224   item = list->data;
2225
2226   if (item == icon_view->priv->anchor_item)
2227     icon_view->priv->anchor_item = NULL;
2228
2229   if (item == icon_view->priv->cursor_item)
2230     icon_view->priv->cursor_item = NULL;
2231
2232   if (item->selected)
2233     emit = TRUE;
2234   
2235   gtk_icon_view_item_free (item);
2236
2237   for (next = list->next; next; next = next->next)
2238     {
2239       item = next->data;
2240
2241       item->index--;
2242     }
2243   
2244   icon_view->priv->items = g_list_delete_link (icon_view->priv->items, list);
2245
2246   gtk_icon_view_queue_layout (icon_view);
2247
2248   verify_items (icon_view);  
2249   
2250   if (emit)
2251     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2252 }
2253
2254 static void
2255 gtk_icon_view_rows_reordered (GtkTreeModel *model,
2256                               GtkTreePath  *parent,
2257                               GtkTreeIter  *iter,
2258                               gint         *new_order,
2259                               gpointer      data)
2260 {
2261   int i;
2262   int length;
2263   GtkIconView *icon_view;
2264   GList *items = NULL, *list;
2265   gint *inverted_order;
2266   GtkIconViewItem **item_array;
2267   
2268   icon_view = GTK_ICON_VIEW (data);
2269
2270   length = gtk_tree_model_iter_n_children (model, NULL);
2271   inverted_order = g_new (gint, length);
2272
2273   /* Invert the array */
2274   for (i = 0; i < length; i++)
2275     inverted_order[new_order[i]] = i;
2276
2277   item_array = g_new (GtkIconViewItem *, length);
2278   for (i = 0, list = icon_view->priv->items; list != NULL; list = list->next, i++)
2279     item_array[inverted_order[i]] = list->data;
2280
2281   g_free (inverted_order);
2282   for (i = 0; i < length; i++)
2283     {
2284       item_array[i]->index = i;
2285       items = g_list_prepend (items, item_array[i]);
2286     }
2287   
2288   g_free (item_array);
2289   g_list_free (icon_view->priv->items);
2290   icon_view->priv->items = g_list_reverse (items);
2291
2292   verify_items (icon_view);  
2293 }
2294
2295 static void
2296 gtk_icon_view_build_items (GtkIconView *icon_view)
2297 {
2298   GtkTreeIter iter;
2299   int i;
2300   gboolean iters_persist;
2301   GList *items = NULL;
2302
2303   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
2304   
2305   if (!gtk_tree_model_get_iter_first (icon_view->priv->model,
2306                                       &iter))
2307     return;
2308
2309   i = 0;
2310   
2311   do
2312     {
2313       GtkIconViewItem *item = gtk_icon_view_item_new ();
2314
2315       if (iters_persist)
2316         item->iter = iter;
2317
2318       item->index = i;
2319       
2320       i++;
2321
2322       items = g_list_prepend (items, item);
2323       
2324     } while (gtk_tree_model_iter_next (icon_view->priv->model, &iter));
2325
2326   icon_view->priv->items = g_list_reverse (items);
2327 }
2328
2329 static void
2330 gtk_icon_view_add_move_binding (GtkBindingSet  *binding_set,
2331                                 guint           keyval,
2332                                 guint           modmask,
2333                                 GtkMovementStep step,
2334                                 gint            count)
2335 {
2336   
2337   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
2338                                 "move_cursor", 2,
2339                                 G_TYPE_ENUM, step,
2340                                 G_TYPE_INT, count);
2341
2342   gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
2343                                 "move_cursor", 2,
2344                                 G_TYPE_ENUM, step,
2345                                 G_TYPE_INT, count);
2346
2347   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2348    return;
2349
2350   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
2351                                 "move_cursor", 2,
2352                                 G_TYPE_ENUM, step,
2353                                 G_TYPE_INT, count);
2354
2355   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
2356                                 "move_cursor", 2,
2357                                 G_TYPE_ENUM, step,
2358                                 G_TYPE_INT, count);
2359 }
2360
2361 static gboolean
2362 gtk_icon_view_real_move_cursor (GtkIconView     *icon_view,
2363                                 GtkMovementStep  step,
2364                                 gint             count)
2365 {
2366   GdkModifierType state;
2367
2368   g_return_val_if_fail (GTK_ICON_VIEW (icon_view), FALSE);
2369   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
2370                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
2371                         step == GTK_MOVEMENT_DISPLAY_LINES ||
2372                         step == GTK_MOVEMENT_PAGES ||
2373                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
2374
2375   if (!GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (icon_view)))
2376     return FALSE;
2377
2378   gtk_widget_grab_focus (GTK_WIDGET (icon_view));
2379
2380   if (gtk_get_current_event_state (&state))
2381     {
2382       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2383         icon_view->priv->ctrl_pressed = TRUE;
2384       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2385         icon_view->priv->shift_pressed = TRUE;
2386     }
2387   /* else we assume not pressed */
2388
2389   switch (step)
2390     {
2391     case GTK_MOVEMENT_LOGICAL_POSITIONS:
2392     case GTK_MOVEMENT_VISUAL_POSITIONS:
2393       gtk_icon_view_move_cursor_left_right (icon_view, count);
2394       break;
2395     case GTK_MOVEMENT_DISPLAY_LINES:
2396       gtk_icon_view_move_cursor_up_down (icon_view, count);
2397       break;
2398     case GTK_MOVEMENT_PAGES:
2399       gtk_icon_view_move_cursor_page_up_down (icon_view, count);
2400       break;
2401     case GTK_MOVEMENT_BUFFER_ENDS:
2402       gtk_icon_view_move_cursor_start_end (icon_view, count);
2403       break;
2404     default:
2405       g_assert_not_reached ();
2406     }
2407
2408   icon_view->priv->ctrl_pressed = FALSE;
2409   icon_view->priv->shift_pressed = FALSE;
2410
2411   return TRUE;
2412 }
2413
2414 static GtkIconViewItem *
2415 find_item (GtkIconView     *icon_view,
2416            GtkIconViewItem *current,
2417            gint             row_ofs,
2418            gint             col_ofs)
2419 {
2420   gint row, col;
2421   GList *items;
2422   GtkIconViewItem *item;
2423
2424   /* FIXME: this could be more efficient 
2425    */
2426   row = current->row + row_ofs;
2427   col = current->col + col_ofs;
2428
2429   for (items = icon_view->priv->items; items; items = items->next)
2430     {
2431       item = items->data;
2432       if (item->row == row && item->col == col)
2433         return item;
2434     }
2435   
2436   return NULL;
2437 }
2438
2439
2440 static GtkIconViewItem *
2441 find_item_page_up_down (GtkIconView     *icon_view,
2442                         GtkIconViewItem *current,
2443                         gint             count)
2444 {
2445   GList *item, *next;
2446   gint y, col;
2447   
2448   col = current->col;
2449   y = current->y + count * icon_view->priv->vadjustment->page_size;
2450
2451   item = g_list_find (icon_view->priv->items, current);
2452   if (count > 0)
2453     {
2454       while (item)
2455         {
2456           for (next = item->next; next; next = next->next)
2457             {
2458               if (((GtkIconViewItem *)next->data)->col == col)
2459                 break;
2460             }
2461           if (!next || ((GtkIconViewItem *)next->data)->y > y)
2462             break;
2463
2464           item = next;
2465         }
2466     }
2467   else 
2468     {
2469       while (item)
2470         {
2471           for (next = item->prev; next; next = next->prev)
2472             {
2473               if (((GtkIconViewItem *)next->data)->col == col)
2474                 break;
2475             }
2476           if (!next || ((GtkIconViewItem *)next->data)->y < y)
2477             break;
2478
2479           item = next;
2480         }
2481     }
2482
2483   if (item)
2484     return item->data;
2485
2486   return NULL;
2487 }
2488
2489 static gboolean
2490 gtk_icon_view_select_all_between (GtkIconView     *icon_view,
2491                                   GtkIconViewItem *anchor,
2492                                   GtkIconViewItem *cursor)
2493 {
2494   GList *items;
2495   GtkIconViewItem *item;
2496   gint row1, row2, col1, col2;
2497   gboolean dirty = FALSE;
2498   
2499   if (anchor->row < cursor->row)
2500     {
2501       row1 = anchor->row;
2502       row2 = cursor->row;
2503     }
2504   else
2505     {
2506       row1 = cursor->row;
2507       row2 = anchor->row;
2508     }
2509
2510   if (anchor->col < cursor->col)
2511     {
2512       col1 = anchor->col;
2513       col2 = cursor->col;
2514     }
2515   else
2516     {
2517       col1 = cursor->col;
2518       col2 = anchor->col;
2519     }
2520
2521   for (items = icon_view->priv->items; items; items = items->next)
2522     {
2523       item = items->data;
2524
2525       if (row1 <= item->row && item->row <= row2 &&
2526           col1 <= item->col && item->col <= col2)
2527         {
2528           if (!item->selected)
2529             dirty = TRUE;
2530
2531           item->selected = TRUE;
2532           
2533           gtk_icon_view_queue_draw_item (icon_view, item);
2534         }
2535     }
2536
2537   return dirty;
2538 }
2539
2540 static void 
2541 gtk_icon_view_move_cursor_up_down (GtkIconView *icon_view,
2542                                    gint         count)
2543 {
2544   GtkIconViewItem *item;
2545   gboolean dirty = FALSE;
2546   
2547   if (!GTK_WIDGET_HAS_FOCUS (icon_view))
2548     return;
2549   
2550   if (!icon_view->priv->cursor_item)
2551     {
2552       GList *list;
2553
2554       if (count > 0)
2555         list = icon_view->priv->items;
2556       else
2557         list = g_list_last (icon_view->priv->items);
2558
2559       item = list->data;
2560     }
2561   else
2562     item = find_item (icon_view, 
2563                       icon_view->priv->cursor_item,
2564                       count, 0);
2565
2566   if (!item)
2567     return;
2568
2569   if (icon_view->priv->ctrl_pressed ||
2570       !icon_view->priv->shift_pressed ||
2571       !icon_view->priv->anchor_item ||
2572       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
2573     icon_view->priv->anchor_item = item;
2574
2575   gtk_icon_view_set_cursor_item (icon_view, item);
2576
2577   if (!icon_view->priv->ctrl_pressed &&
2578       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
2579     {
2580       gtk_icon_view_unselect_all_internal (icon_view);
2581       dirty = gtk_icon_view_select_all_between (icon_view, 
2582                                                 icon_view->priv->anchor_item,
2583                                                 item);
2584     }
2585
2586   gtk_icon_view_scroll_to_item (icon_view, item);
2587
2588   if (dirty)
2589     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2590 }
2591
2592 static void 
2593 gtk_icon_view_move_cursor_page_up_down (GtkIconView *icon_view,
2594                                         gint         count)
2595 {
2596   GtkIconViewItem *item;
2597   gboolean dirty = FALSE;
2598   
2599   if (!GTK_WIDGET_HAS_FOCUS (icon_view))
2600     return;
2601   
2602   if (!icon_view->priv->cursor_item)
2603     {
2604       GList *list;
2605
2606       if (count > 0)
2607         list = icon_view->priv->items;
2608       else
2609         list = g_list_last (icon_view->priv->items);
2610
2611       item = list->data;
2612     }
2613   else
2614     item = find_item_page_up_down (icon_view, 
2615                                    icon_view->priv->cursor_item,
2616                                    count);
2617
2618   if (!item)
2619     return;
2620
2621   if (icon_view->priv->ctrl_pressed ||
2622       !icon_view->priv->shift_pressed ||
2623       !icon_view->priv->anchor_item ||
2624       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
2625     icon_view->priv->anchor_item = item;
2626
2627   gtk_icon_view_set_cursor_item (icon_view, item);
2628
2629   if (!icon_view->priv->ctrl_pressed &&
2630       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
2631     {
2632       gtk_icon_view_unselect_all_internal (icon_view);
2633       dirty = gtk_icon_view_select_all_between (icon_view, 
2634                                                 icon_view->priv->anchor_item,
2635                                                 item);
2636     }
2637
2638   gtk_icon_view_scroll_to_item (icon_view, item);
2639
2640   if (dirty)
2641     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);  
2642 }
2643
2644 static void 
2645 gtk_icon_view_move_cursor_left_right (GtkIconView *icon_view,
2646                                       gint         count)
2647 {
2648   GtkIconViewItem *item;
2649   gboolean dirty = FALSE;
2650   
2651   if (!GTK_WIDGET_HAS_FOCUS (icon_view))
2652     return;
2653   
2654   if (!icon_view->priv->cursor_item)
2655     {
2656       GList *list;
2657
2658       if (count > 0)
2659         list = icon_view->priv->items;
2660       else
2661         list = g_list_last (icon_view->priv->items);
2662
2663       item = list->data;
2664     }
2665   else
2666     item = find_item (icon_view, 
2667                       icon_view->priv->cursor_item,
2668                       0, count);
2669
2670   if (!item)
2671     return;
2672
2673   if (icon_view->priv->ctrl_pressed ||
2674       !icon_view->priv->shift_pressed ||
2675       !icon_view->priv->anchor_item ||
2676       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
2677     icon_view->priv->anchor_item = item;
2678
2679   gtk_icon_view_set_cursor_item (icon_view, item);
2680
2681   if (!icon_view->priv->ctrl_pressed &&
2682       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
2683     {
2684       gtk_icon_view_unselect_all_internal (icon_view);
2685       dirty = gtk_icon_view_select_all_between (icon_view, 
2686                                                 icon_view->priv->anchor_item,
2687                                                 item);
2688     }
2689
2690   gtk_icon_view_scroll_to_item (icon_view, item);
2691
2692   if (dirty)
2693     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2694 }
2695
2696 static void 
2697 gtk_icon_view_move_cursor_start_end (GtkIconView *icon_view,
2698                                      gint         count)
2699 {
2700   GtkIconViewItem *item;
2701   GList *list;
2702   gboolean dirty = FALSE;
2703   
2704   if (!GTK_WIDGET_HAS_FOCUS (icon_view))
2705     return;
2706   
2707   if (count < 0)
2708     list = icon_view->priv->items;
2709   else
2710     list = g_list_last (icon_view->priv->items);
2711   
2712   item = list->data;
2713
2714   if (!item)
2715     return;
2716
2717   if (icon_view->priv->ctrl_pressed ||
2718       !icon_view->priv->shift_pressed ||
2719       !icon_view->priv->anchor_item ||
2720       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
2721     icon_view->priv->anchor_item = item;
2722
2723   gtk_icon_view_set_cursor_item (icon_view, item);
2724
2725   if (!icon_view->priv->ctrl_pressed &&
2726       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
2727     {
2728       gtk_icon_view_unselect_all (icon_view);
2729       dirty = gtk_icon_view_select_all_between (icon_view, 
2730                                                 icon_view->priv->anchor_item,
2731                                                 item);
2732     }
2733
2734   gtk_icon_view_scroll_to_item (icon_view, item);
2735
2736   if (dirty)
2737     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2738 }
2739
2740 static void     
2741 gtk_icon_view_scroll_to_item (GtkIconView     *icon_view, 
2742                               GtkIconViewItem *item)
2743 {
2744   gint y, height;
2745   gdouble value;
2746
2747   gdk_window_get_geometry (icon_view->priv->bin_window, NULL, &y, NULL, &height, NULL);
2748
2749   if (y + item->y < 0)
2750     {
2751       value = icon_view->priv->vadjustment->value + y + item->y;
2752       gtk_adjustment_set_value (icon_view->priv->vadjustment, value);
2753     }
2754   else if (y + item->y + item->height > GTK_WIDGET (icon_view)->allocation.height)
2755     {
2756       value = icon_view->priv->vadjustment->value + y + item->y + item->height 
2757         - GTK_WIDGET (icon_view)->allocation.height;
2758       gtk_adjustment_set_value (icon_view->priv->vadjustment, value);
2759     }
2760 }
2761
2762 /* Public API */
2763
2764
2765 /**
2766  * gtk_icon_view_new:
2767  * 
2768  * Creates a new #GtkIconView widget
2769  * 
2770  * Return value: A newly created #GtkIconView widget
2771  *
2772  * Since: 2.6
2773  **/
2774 GtkWidget *
2775 gtk_icon_view_new (void)
2776 {
2777   return g_object_new (GTK_TYPE_ICON_VIEW, NULL);
2778 }
2779
2780 /**
2781  * gtk_icon_view_new_with_model:
2782  * @model: The model.
2783  * 
2784  * Creates a new #GtkIconView widget with the model @model.
2785  * 
2786  * Return value: A newly created #GtkIconView widget.
2787  *
2788  * Since: 2.6 
2789  **/
2790 GtkWidget *
2791 gtk_icon_view_new_with_model (GtkTreeModel *model)
2792 {
2793   return g_object_new (GTK_TYPE_ICON_VIEW, "model", model, NULL);
2794 }
2795
2796
2797 /**
2798  * gtk_icon_view_get_path_at_pos:
2799  * @icon_view: A #GtkIconView.
2800  * @x: The x position to be identified
2801  * @y: The y position to be identified
2802  * 
2803  * Finds the path at the point (@x, @y), relative to widget coordinates.
2804  * 
2805  * Return value: The #GtkTreePath corresponding to the icon or %NULL
2806  * if no icon exists at that position.
2807  *
2808  * Since: 2.6 
2809  **/
2810 GtkTreePath *
2811 gtk_icon_view_get_path_at_pos (GtkIconView *icon_view,
2812                                gint         x,
2813                                gint         y)
2814 {
2815   GtkIconViewItem *item;
2816   GtkTreePath *path;
2817   
2818   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
2819
2820   item = gtk_icon_view_get_item_at_pos (icon_view, x, y);
2821
2822   if (!item)
2823     return NULL;
2824
2825   path = gtk_tree_path_new_from_indices (item->index, -1);
2826
2827   return path;
2828 }
2829
2830 /**
2831  * gtk_icon_view_selected_foreach:
2832  * @icon_view: A #GtkIconView.
2833  * @func: The funcion to call for each selected icon.
2834  * @data: User data to pass to the function.
2835  * 
2836  * Calls a function for each selected icon. Note that the model or
2837  * selection cannot be modified from within this function.
2838  *
2839  * Since: 2.6 
2840  **/
2841 void
2842 gtk_icon_view_selected_foreach (GtkIconView           *icon_view,
2843                                 GtkIconViewForeachFunc func,
2844                                 gpointer               data)
2845 {
2846   GList *list;
2847   
2848   for (list = icon_view->priv->items; list; list = list->next)
2849     {
2850       GtkIconViewItem *item = list->data;
2851       GtkTreePath *path = gtk_tree_path_new_from_indices (item->index, -1);
2852
2853       if (item->selected)
2854         (* func) (icon_view, path, data);
2855
2856       gtk_tree_path_free (path);
2857     }
2858 }
2859
2860 /**
2861  * gtk_icon_view_set_selection_mode:
2862  * @icon_view: A #GtkIconView.
2863  * @mode: The selection mode
2864  * 
2865  * Sets the selection mode of the @icon_view.
2866  *
2867  * Since: 2.6 
2868  **/
2869 void
2870 gtk_icon_view_set_selection_mode (GtkIconView      *icon_view,
2871                                   GtkSelectionMode  mode)
2872 {
2873   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
2874
2875   if (mode == icon_view->priv->selection_mode)
2876     return;
2877   
2878   if (mode == GTK_SELECTION_NONE ||
2879       icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE)
2880     gtk_icon_view_unselect_all (icon_view);
2881   
2882   icon_view->priv->selection_mode = mode;
2883
2884   g_object_notify (G_OBJECT (icon_view), "selection_mode");
2885 }
2886
2887 /**
2888  * gtk_icon_view_get_selection_mode:
2889  * @icon_view: A #GtkIconView.
2890  * 
2891  * Gets the selection mode of the @icon_view.
2892  *
2893  * Return value: the current selection mode
2894  *
2895  * Since: 2.6 
2896  **/
2897 GtkSelectionMode
2898 gtk_icon_view_get_selection_mode (GtkIconView *icon_view)
2899 {
2900   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), GTK_SELECTION_SINGLE);
2901
2902   return icon_view->priv->selection_mode;
2903 }
2904
2905 /**
2906  * gtk_icon_view_set_model:
2907  * @icon_view: A #GtkIconView.
2908  * @model: The model.
2909  *
2910  * Sets the model for a #GtkIconView.  
2911  * If the @icon_view already has a model set, it will remove 
2912  * it before setting the new model.  If @model is %NULL, then
2913  * it will unset the old model.
2914  *
2915  * Since: 2.6 
2916  **/
2917 void
2918 gtk_icon_view_set_model (GtkIconView *icon_view,
2919                          GtkTreeModel *model)
2920 {
2921   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
2922
2923   if (model != NULL)
2924     g_return_if_fail (GTK_IS_TREE_MODEL (model));
2925   
2926   if (icon_view->priv->model == model)
2927     return;
2928
2929   if (model)
2930     {
2931       GType pixbuf_column_type, text_column_type;
2932       
2933       g_return_if_fail (gtk_tree_model_get_flags (model) & GTK_TREE_MODEL_LIST_ONLY);
2934
2935       if (icon_view->priv->pixbuf_column != -1)
2936         {
2937           pixbuf_column_type = gtk_tree_model_get_column_type (icon_view->priv->model,
2938                                                                icon_view->priv->pixbuf_column);   
2939
2940           g_return_if_fail (pixbuf_column_type == GDK_TYPE_PIXBUF);
2941         }
2942
2943       if (icon_view->priv->text_column != -1)
2944         {
2945           text_column_type = gtk_tree_model_get_column_type (icon_view->priv->model,
2946                                                              icon_view->priv->pixbuf_column);     
2947
2948           g_return_if_fail (text_column_type == G_TYPE_STRING);
2949         }
2950       
2951     }
2952   
2953   if (icon_view->priv->model)
2954     {
2955       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
2956                                             gtk_icon_view_row_changed,
2957                                             icon_view);
2958       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
2959                                             gtk_icon_view_row_inserted,
2960                                             icon_view);
2961       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
2962                                             gtk_icon_view_row_deleted,
2963                                             icon_view);
2964       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
2965                                             gtk_icon_view_rows_reordered,
2966                                             icon_view);
2967
2968       g_object_unref (icon_view->priv->model);
2969       
2970       g_list_foreach (icon_view->priv->items, (GFunc)gtk_icon_view_item_free, NULL);
2971       g_list_free (icon_view->priv->items);
2972       icon_view->priv->items = NULL;
2973     }
2974
2975   icon_view->priv->model = model;
2976
2977   if (icon_view->priv->model)
2978     {
2979       g_object_ref (icon_view->priv->model);
2980       g_signal_connect (icon_view->priv->model,
2981                         "row_changed",
2982                         G_CALLBACK (gtk_icon_view_row_changed),
2983                         icon_view);
2984       g_signal_connect (icon_view->priv->model,
2985                         "row_inserted",
2986                         G_CALLBACK (gtk_icon_view_row_inserted),
2987                         icon_view);
2988       g_signal_connect (icon_view->priv->model,
2989                         "row_deleted",
2990                         G_CALLBACK (gtk_icon_view_row_deleted),
2991                         icon_view);
2992       g_signal_connect (icon_view->priv->model,
2993                         "rows_reordered",
2994                         G_CALLBACK (gtk_icon_view_rows_reordered),
2995                         icon_view);
2996
2997       gtk_icon_view_build_items (icon_view);
2998     }
2999
3000   g_object_notify (G_OBJECT (icon_view), "model");  
3001 }
3002
3003 /**
3004  * gtk_icon_view_get_model:
3005  * @icon_view: a #GtkIconView
3006  *
3007  * Returns the model the #GtkIconView is based on.  Returns %NULL if the
3008  * model is unset.
3009  *
3010  * Return value: A #GtkTreeModel, or %NULL if none is currently being used.
3011  *
3012  * Since: 2.6 
3013  **/
3014 GtkTreeModel *
3015 gtk_icon_view_get_model (GtkIconView *icon_view)
3016 {
3017   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
3018
3019   return icon_view->priv->model;
3020 }
3021
3022 /**
3023  * gtk_icon_view_set_text_column:
3024  * @icon_view: A #GtkIconView.
3025  * @column: A column in the currently used model.
3026  * 
3027  * Sets the column with text for @icon_view to be @column. The text
3028  * column must be of type #G_TYPE_STRING.
3029  *
3030  * Since: 2.6 
3031  **/
3032 void
3033 gtk_icon_view_set_text_column (GtkIconView *icon_view,
3034                                gint          column)
3035 {
3036   if (column == icon_view->priv->text_column)
3037     return;
3038   
3039   if (column == -1)
3040     icon_view->priv->text_column = -1;
3041   else
3042     {
3043       if (icon_view->priv->model != NULL)
3044         {
3045           GType column_type;
3046           
3047           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
3048
3049           g_return_if_fail (column_type == G_TYPE_STRING);
3050         }
3051       
3052       icon_view->priv->text_column = column;
3053     }
3054
3055   gtk_icon_view_invalidate_sizes (icon_view);
3056   gtk_icon_view_queue_layout (icon_view);
3057   
3058   g_object_notify (G_OBJECT (icon_view), "text_column");
3059 }
3060
3061 /**
3062  * gtk_icon_view_get_text_column:
3063  * @icon_view: A #GtkIconView.
3064  *
3065  * Returns the column with text for @icon_view.
3066  *
3067  * Returns: the text column, or -1 if it's unset.
3068  *
3069  * Since: 2.6
3070  */
3071 gint
3072 gtk_icon_view_get_text_column (GtkIconView  *icon_view)
3073 {
3074   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
3075
3076   return icon_view->priv->text_column;
3077 }
3078
3079 /**
3080  * gtk_icon_view_set_markup_column:
3081  * @icon_view: A #GtkIconView.
3082  * @column: A column in the currently used model.
3083  * 
3084  * Sets the column with markup information for @icon_view to be
3085  * @column. The markup column must be of type #G_TYPE_STRING.
3086  * If the markup column is set to something, it overrides
3087  * the text column set by gtk_icon_view_set_text_column().
3088  *
3089  * Since: 2.6
3090  **/
3091 void
3092 gtk_icon_view_set_markup_column (GtkIconView *icon_view,
3093                                  gint         column)
3094 {
3095   if (column == icon_view->priv->markup_column)
3096     return;
3097   
3098   if (column == -1)
3099     icon_view->priv->markup_column = -1;
3100   else
3101     {
3102       if (icon_view->priv->model != NULL)
3103         {
3104           GType column_type;
3105           
3106           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
3107
3108           g_return_if_fail (column_type == G_TYPE_STRING);
3109         }
3110       
3111       icon_view->priv->markup_column = column;
3112     }
3113
3114   gtk_icon_view_invalidate_sizes (icon_view);
3115   gtk_icon_view_queue_layout (icon_view);
3116   
3117   g_object_notify (G_OBJECT (icon_view), "markup_column");
3118 }
3119
3120 /**
3121  * gtk_icon_view_get_markup_column:
3122  * @icon_view: A #GtkIconView.
3123  *
3124  * Returns the column with markup text for @icon_view.
3125  *
3126  * Returns: the markup column, or -1 if it's unset.
3127  *
3128  * Since: 2.6
3129  */
3130 gint
3131 gtk_icon_view_get_markup_column (GtkIconView  *icon_view)
3132 {
3133   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
3134
3135   return icon_view->priv->markup_column;
3136 }
3137
3138 /**
3139  * gtk_icon_view_set_pixbuf_column:
3140  * @icon_view: A #GtkIconView.
3141  * @column: A column in the currently used model.
3142  * 
3143  * Sets the column with pixbufs for @icon_view to be @column. The pixbuf
3144  * column must be of type #GDK_TYPE_PIXBUF
3145  *
3146  * Since: 2.6 
3147  **/
3148 void
3149 gtk_icon_view_set_pixbuf_column (GtkIconView *icon_view,
3150                                  gint         column)
3151 {
3152   if (column == icon_view->priv->pixbuf_column)
3153     return;
3154   
3155   if (column == -1)
3156     icon_view->priv->pixbuf_column = -1;
3157   else
3158     {
3159       if (icon_view->priv->model != NULL)
3160         {
3161           GType column_type;
3162           
3163           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
3164
3165           g_return_if_fail (column_type == GDK_TYPE_PIXBUF);
3166         }
3167       
3168       icon_view->priv->pixbuf_column = column;
3169     }
3170
3171   gtk_icon_view_invalidate_sizes (icon_view);
3172   gtk_icon_view_queue_layout (icon_view);
3173   
3174   g_object_notify (G_OBJECT (icon_view), "pixbuf_column");
3175   
3176 }
3177
3178 /**
3179  * gtk_icon_view_get_pixbuf_column:
3180  * @icon_view: A #GtkIconView.
3181  *
3182  * Returns the column with pixbufs for @icon_view.
3183  *
3184  * Returns: the pixbuf column, or -1 if it's unset.
3185  *
3186  * Since: 2.6
3187  */
3188 gint
3189 gtk_icon_view_get_pixbuf_column (GtkIconView  *icon_view)
3190 {
3191   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
3192
3193   return icon_view->priv->pixbuf_column;
3194 }
3195
3196 /**
3197  * gtk_icon_view_select_path:
3198  * @icon_view: A #GtkIconView.
3199  * @path: The #GtkTreePath to be selected.
3200  * 
3201  * Selects the row at @path.
3202  *
3203  * Since: 2.6
3204  **/
3205 void
3206 gtk_icon_view_select_path (GtkIconView *icon_view,
3207                            GtkTreePath *path)
3208 {
3209   GtkIconViewItem *item;
3210   
3211   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3212   g_return_if_fail (icon_view->priv->model != NULL);
3213   g_return_if_fail (path != NULL);
3214
3215   item = g_list_nth (icon_view->priv->items,
3216                      gtk_tree_path_get_indices(path)[0])->data;
3217
3218   if (!item)
3219     return;
3220   
3221   gtk_icon_view_select_item (icon_view, item);
3222 }
3223
3224 /**
3225  * gtk_icon_view_unselect_path:
3226  * @icon_view: A #GtkIconView.
3227  * @path: The #GtkTreePath to be unselected.
3228  * 
3229  * Unselects the row at @path.
3230  *
3231  * Since: 2.6
3232  **/
3233 void
3234 gtk_icon_view_unselect_path (GtkIconView *icon_view,
3235                              GtkTreePath *path)
3236 {
3237   GtkIconViewItem *item;
3238   
3239   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3240   g_return_if_fail (icon_view->priv->model != NULL);
3241   g_return_if_fail (path != NULL);
3242
3243   item = g_list_nth (icon_view->priv->items,
3244                      gtk_tree_path_get_indices(path)[0])->data;
3245
3246   if (!item)
3247     return;
3248   
3249   gtk_icon_view_unselect_item (icon_view, item);
3250 }
3251
3252 /**
3253  * gtk_icon_view_get_selected_items:
3254  * @icon_view: A #GtkIconView.
3255  *
3256  * Creates a list of path of all selected items. Additionally, if you are
3257  * planning on modifying the model after calling this function, you may
3258  * want to convert the returned list into a list of #GtkTreeRowReference<!-- -->s.
3259  * To do this, you can use gtk_tree_row_reference_new().
3260  *
3261  * To free the return value, use:
3262  * <informalexample><programlisting>
3263  * g_list_foreach (list, gtk_tree_path_free, NULL);
3264  * g_list_free (list);
3265  * </programlisting></informalexample>
3266  *
3267  * Return value: A #GList containing a #GtkTreePath for each selected row.
3268  *
3269  * Since: 2.6
3270  **/
3271 GList *
3272 gtk_icon_view_get_selected_items (GtkIconView *icon_view)
3273 {
3274   GList *list;
3275   GList *selected = NULL;
3276   
3277   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
3278   
3279   for (list = icon_view->priv->items; list != NULL; list = list->next)
3280     {
3281       GtkIconViewItem *item = list->data;
3282
3283       if (item->selected)
3284         {
3285           GtkTreePath *path = gtk_tree_path_new_from_indices (item->index, -1);
3286
3287           selected = g_list_prepend (selected, path);
3288         }
3289     }
3290
3291   return selected;
3292 }
3293
3294 /**
3295  * gtk_icon_view_select_all:
3296  * @icon_view: A #GtkIconView.
3297  * 
3298  * Selects all the icons. @icon_view must has its selection mode set
3299  * to #GTK_SELECTION_MULTIPLE.
3300  *
3301  * Since: 2.6
3302  **/
3303 void
3304 gtk_icon_view_select_all (GtkIconView *icon_view)
3305 {
3306   GList *items;
3307   gboolean dirty = FALSE;
3308   
3309   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3310
3311   if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3312     return;
3313
3314   for (items = icon_view->priv->items; items; items = items->next)
3315     {
3316       GtkIconViewItem *item = items->data;
3317       
3318       if (!item->selected)
3319         {
3320           dirty = TRUE;
3321           item->selected = TRUE;
3322           gtk_icon_view_queue_draw_item (icon_view, item);
3323         }
3324     }
3325
3326   if (dirty)
3327     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3328 }
3329
3330 /**
3331  * gtk_icon_view_unselect_all:
3332  * @icon_view: A #GtkIconView.
3333  * 
3334  * Unselects all the icons.
3335  *
3336  * Since: 2.6
3337  **/
3338 void
3339 gtk_icon_view_unselect_all (GtkIconView *icon_view)
3340 {
3341   gboolean dirty = FALSE;
3342   
3343   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3344
3345   if (icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
3346     return;
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 }