]> Pileus Git - ~andy/gtk/blob - gtk/gtkiconview.c
Internalize some strings, pointed out by Damon Chaplin.
[~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 <atk/atk.h>
24
25 #include <gdk/gdkkeysyms.h>
26
27 #include "gtkiconview.h"
28 #include "gtkcelllayout.h"
29 #include "gtkcellrenderer.h"
30 #include "gtkcellrenderertext.h"
31 #include "gtkcellrendererpixbuf.h"
32 #include "gtkmarshalers.h"
33 #include "gtkbindings.h"
34 #include "gtkdnd.h"
35 #include "gtkmain.h"
36 #include "gtksignal.h"
37 #include "gtkintl.h"
38 #include "gtkaccessible.h"
39 #include "gtkwindow.h"
40 #include "gtkentry.h"
41 #include "gtkcombobox.h"
42 #include "gtktextbuffer.h"
43 #include "gtktreednd.h"
44 #include "gtkprivate.h"
45 #include "gtkalias.h"
46
47 #undef DEBUG_ICON_VIEW
48
49 #define SCROLL_EDGE_SIZE 15
50
51 #define GTK_ICON_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ICON_VIEW, GtkIconViewPrivate))
52
53 typedef struct _GtkIconViewItem GtkIconViewItem;
54 struct _GtkIconViewItem
55 {
56   GtkTreeIter iter;
57   gint index;
58   
59   gint row, col;
60
61   /* Bounding box */
62   gint x, y, width, height;
63
64   /* Individual cells.
65    * box[i] is the actual area occupied by cell i,
66    * before, after are used to calculate the cell 
67    * area relative to the box. 
68    * See gtk_icon_view_get_cell_area().
69    */
70   gint n_cells;
71   GdkRectangle *box;
72   gint *before;
73   gint *after;
74
75   guint selected : 1;
76   guint selected_before_rubberbanding : 1;
77
78 };
79
80 typedef struct _GtkIconViewCellInfo GtkIconViewCellInfo;
81 struct _GtkIconViewCellInfo
82 {
83   GtkCellRenderer *cell;
84
85   guint expand : 1;
86   guint pack : 1;
87   guint editing : 1;
88
89   gint position;
90
91   GSList *attributes;
92
93   GtkCellLayoutDataFunc func;
94   gpointer func_data;
95   GDestroyNotify destroy;
96 };
97
98 typedef struct _GtkIconViewChild GtkIconViewChild;
99 struct _GtkIconViewChild
100 {
101   GtkWidget *widget;
102   GtkIconViewItem *item;
103   gint cell;
104 };
105
106 struct _GtkIconViewPrivate
107 {
108   gint width, height;
109
110   GtkSelectionMode selection_mode;
111
112   GdkWindow *bin_window;
113
114   GList *children;
115
116   GtkTreeModel *model;
117   
118   GList *items;
119   
120   GtkAdjustment *hadjustment;
121   GtkAdjustment *vadjustment;
122
123   guint layout_idle_id;
124   
125   gboolean doing_rubberband;
126   gint rubberband_x1, rubberband_y1;
127   gint rubberband_x2, rubberband_y2;
128
129   guint scroll_timeout_id;
130   gint scroll_value_diff;
131   gint event_last_x, event_last_y;
132
133   GtkIconViewItem *anchor_item;
134   GtkIconViewItem *cursor_item;
135   GtkIconViewItem *edited_item;
136   GtkCellEditable *editable;
137
138   GtkIconViewItem *last_single_clicked;
139
140   GList *cell_list;
141   guint n_cells;
142
143   gint cursor_cell;
144
145   GtkOrientation orientation;
146
147   gint columns;
148   gint item_width;
149   gint spacing;
150   gint row_spacing;
151   gint column_spacing;
152   gint margin;
153
154   gint text_column;
155   gint markup_column;
156   gint pixbuf_column;
157
158   gint pixbuf_cell;
159   gint text_cell;
160
161   /* Drag-and-drop. */
162   GdkModifierType start_button_mask;
163   gint pressed_button;
164   gint press_start_x;
165   gint press_start_y;
166
167   GtkTargetList *source_targets;
168   GdkDragAction source_actions;
169
170   GtkTargetList *dest_targets;
171   GdkDragAction dest_actions;
172
173   GtkTreeRowReference *dest_item;
174   GtkIconViewDropPosition dest_pos;
175
176   /* scroll to */
177   GtkTreeRowReference *scroll_to_path;
178   gfloat scroll_to_row_align;
179   gfloat scroll_to_col_align;
180   guint scroll_to_use_align : 1;
181
182   guint source_set : 1;
183   guint dest_set : 1;
184   guint reorderable : 1;
185   guint empty_view_drop :1;
186
187   guint ctrl_pressed : 1;
188   guint shift_pressed : 1;  
189 };
190
191 /* Signals */
192 enum
193 {
194   ITEM_ACTIVATED,
195   SELECTION_CHANGED,
196   SELECT_ALL,
197   UNSELECT_ALL,
198   SELECT_CURSOR_ITEM,
199   TOGGLE_CURSOR_ITEM,
200   MOVE_CURSOR,
201   ACTIVATE_CURSOR_ITEM,
202   LAST_SIGNAL
203 };
204
205 /* Properties */
206 enum
207 {
208   PROP_0,
209   PROP_PIXBUF_COLUMN,
210   PROP_TEXT_COLUMN,
211   PROP_MARKUP_COLUMN,  
212   PROP_SELECTION_MODE,
213   PROP_ORIENTATION,
214   PROP_MODEL,
215   PROP_COLUMNS,
216   PROP_ITEM_WIDTH,
217   PROP_SPACING,
218   PROP_ROW_SPACING,
219   PROP_COLUMN_SPACING,
220   PROP_MARGIN,
221   PROP_REORDERABLE
222 };
223
224 /* GObject vfuncs */
225 static void             gtk_icon_view_cell_layout_init          (GtkCellLayoutIface *iface);
226 static void             gtk_icon_view_finalize                  (GObject            *object);
227 static void             gtk_icon_view_set_property              (GObject            *object,
228                                                                  guint               prop_id,
229                                                                  const GValue       *value,
230                                                                  GParamSpec         *pspec);
231 static void             gtk_icon_view_get_property              (GObject            *object,
232                                                                  guint               prop_id,
233                                                                  GValue             *value,
234                                                                  GParamSpec         *pspec);
235
236 /* GtkObject vfuncs */
237 static void             gtk_icon_view_destroy                   (GtkObject          *object);
238
239 /* GtkWidget vfuncs */
240 static void             gtk_icon_view_realize                   (GtkWidget          *widget);
241 static void             gtk_icon_view_unrealize                 (GtkWidget          *widget);
242 static void             gtk_icon_view_style_set                 (GtkWidget        *widget,
243                                                                  GtkStyle         *previous_style);
244 static void             gtk_icon_view_state_changed             (GtkWidget        *widget,
245                                                                  GtkStateType      previous_state);
246 static void             gtk_icon_view_size_request              (GtkWidget          *widget,
247                                                                  GtkRequisition     *requisition);
248 static void             gtk_icon_view_size_allocate             (GtkWidget          *widget,
249                                                                  GtkAllocation      *allocation);
250 static gboolean         gtk_icon_view_expose                    (GtkWidget          *widget,
251                                                                  GdkEventExpose     *expose);
252 static gboolean         gtk_icon_view_motion                    (GtkWidget          *widget,
253                                                                  GdkEventMotion     *event);
254 static gboolean         gtk_icon_view_button_press              (GtkWidget          *widget,
255                                                                  GdkEventButton     *event);
256 static gboolean         gtk_icon_view_button_release            (GtkWidget          *widget,
257                                                                  GdkEventButton     *event);
258 static AtkObject       *gtk_icon_view_get_accessible            (GtkWidget          *widget);
259
260
261 /* GtkContainer vfuncs */
262 static void             gtk_icon_view_remove                    (GtkContainer       *container,
263                                                                  GtkWidget          *widget);
264 static void             gtk_icon_view_forall                    (GtkContainer       *container,
265                                                                  gboolean            include_internals,
266                                                                  GtkCallback         callback,
267                                                                  gpointer            callback_data);
268
269 /* GtkIconView vfuncs */
270 static void             gtk_icon_view_set_adjustments           (GtkIconView        *icon_view,
271                                                                  GtkAdjustment      *hadj,
272                                                                  GtkAdjustment      *vadj);
273 static void             gtk_icon_view_real_select_all           (GtkIconView        *icon_view);
274 static void             gtk_icon_view_real_unselect_all         (GtkIconView        *icon_view);
275 static void             gtk_icon_view_real_select_cursor_item   (GtkIconView        *icon_view);
276 static void             gtk_icon_view_real_toggle_cursor_item   (GtkIconView        *icon_view);
277 static gboolean         gtk_icon_view_real_activate_cursor_item (GtkIconView        *icon_view);
278
279  /* Internal functions */
280 static void                 gtk_icon_view_adjustment_changed             (GtkAdjustment          *adjustment,
281                                                                           GtkIconView            *icon_view);
282 static void                 gtk_icon_view_layout                         (GtkIconView            *icon_view);
283 static void                 gtk_icon_view_paint_item                     (GtkIconView            *icon_view,
284                                                                           cairo_t *cr,
285
286                                                                           GtkIconViewItem        *item,
287                                                                           GdkRectangle           *area,
288                                                                           GdkDrawable *drawable,
289                                                                           gint         x,
290                                                                           gint         y,
291                                                                           gboolean     draw_focus);
292 static void                 gtk_icon_view_paint_rubberband               (GtkIconView            *icon_view,
293                                                                           cairo_t *cr,
294                                                                           GdkRectangle           *area);
295 static void                 gtk_icon_view_queue_draw_path                (GtkIconView *icon_view,
296                                                                           GtkTreePath *path);
297 static void                 gtk_icon_view_queue_draw_item                (GtkIconView            *icon_view,
298                                                                           GtkIconViewItem        *item);
299 static void                 gtk_icon_view_queue_layout                   (GtkIconView            *icon_view);
300 static void                 gtk_icon_view_set_cursor_item                (GtkIconView            *icon_view,
301                                                                           GtkIconViewItem        *item,
302                                                                           gint                    cursor_cell);
303 static void                 gtk_icon_view_start_rubberbanding            (GtkIconView            *icon_view,
304                                                                           gint                    x,
305                                                                           gint                    y);
306 static void                 gtk_icon_view_stop_rubberbanding             (GtkIconView            *icon_view);
307 static void                 gtk_icon_view_update_rubberband_selection    (GtkIconView            *icon_view);
308 static gboolean             gtk_icon_view_item_hit_test                  (GtkIconView            *icon_view,
309                                                                           GtkIconViewItem        *item,
310                                                                           gint                    x,
311                                                                           gint                    y,
312                                                                           gint                    width,
313                                                                           gint                    height);
314 static gboolean             gtk_icon_view_unselect_all_internal          (GtkIconView            *icon_view);
315 static void                 gtk_icon_view_calculate_item_size            (GtkIconView            *icon_view,
316                                                                           GtkIconViewItem        *item);
317 static void                 gtk_icon_view_calculate_item_size2           (GtkIconView            *icon_view,
318                                                                           GtkIconViewItem        *item,
319                                                                           gint                   *max_height);
320 static void                 gtk_icon_view_update_rubberband              (gpointer                data);
321 static void                 gtk_icon_view_item_invalidate_size           (GtkIconViewItem        *item);
322 static void                 gtk_icon_view_invalidate_sizes               (GtkIconView            *icon_view);
323 static void                 gtk_icon_view_add_move_binding               (GtkBindingSet          *binding_set,
324                                                                           guint                   keyval,
325                                                                           guint                   modmask,
326                                                                           GtkMovementStep         step,
327                                                                           gint                    count);
328 static gboolean             gtk_icon_view_real_move_cursor               (GtkIconView            *icon_view,
329                                                                           GtkMovementStep         step,
330                                                                           gint                    count);
331 static void                 gtk_icon_view_move_cursor_up_down            (GtkIconView            *icon_view,
332                                                                           gint                    count);
333 static void                 gtk_icon_view_move_cursor_page_up_down       (GtkIconView            *icon_view,
334                                                                           gint                    count);
335 static void                 gtk_icon_view_move_cursor_left_right         (GtkIconView            *icon_view,
336                                                                           gint                    count);
337 static void                 gtk_icon_view_move_cursor_start_end          (GtkIconView            *icon_view,
338                                                                           gint                    count);
339 static void                 gtk_icon_view_scroll_to_item                 (GtkIconView            *icon_view,
340                                                                           GtkIconViewItem        *item);
341 static void                 gtk_icon_view_select_item                    (GtkIconView            *icon_view,
342                                                                           GtkIconViewItem        *item);
343 static void                 gtk_icon_view_unselect_item                  (GtkIconView            *icon_view,
344                                                                           GtkIconViewItem        *item);
345 static gboolean             gtk_icon_view_select_all_between             (GtkIconView            *icon_view,
346                                                                           GtkIconViewItem        *anchor,
347                                                                           GtkIconViewItem        *cursor);
348 static GtkIconViewItem *    gtk_icon_view_get_item_at_coords             (GtkIconView            *icon_view,
349                                                                           gint                    x,
350                                                                           gint                    y,
351                                                                           gboolean                only_in_cell,
352                                                                           GtkIconViewCellInfo   **cell_at_pos);
353 static void                 gtk_icon_view_get_cell_area                  (GtkIconView            *icon_view,
354                                                                           GtkIconViewItem        *item,
355                                                                           GtkIconViewCellInfo    *cell_info,
356                                                                           GdkRectangle           *cell_area);
357 static void                 gtk_icon_view_get_cell_box                   (GtkIconView            *icon_view,
358                                                                           GtkIconViewItem        *item,
359                                                                           GtkIconViewCellInfo    *info,
360                                                                           GdkRectangle           *box);
361 static GtkIconViewCellInfo *gtk_icon_view_get_cell_info                  (GtkIconView            *icon_view,
362                                                                           GtkCellRenderer        *renderer);
363 static void                 gtk_icon_view_set_cell_data                  (GtkIconView            *icon_view,
364                                                                           GtkIconViewItem        *item);
365 static void                 gtk_icon_view_cell_layout_pack_start         (GtkCellLayout          *layout,
366                                                                           GtkCellRenderer        *renderer,
367                                                                           gboolean                expand);
368 static void                 gtk_icon_view_cell_layout_pack_end           (GtkCellLayout          *layout,
369                                                                           GtkCellRenderer        *renderer,
370                                                                           gboolean                expand);
371 static void                 gtk_icon_view_cell_layout_add_attribute      (GtkCellLayout          *layout,
372                                                                           GtkCellRenderer        *renderer,
373                                                                           const gchar            *attribute,
374                                                                           gint                    column);
375 static void                 gtk_icon_view_cell_layout_clear              (GtkCellLayout          *layout);
376 static void                 gtk_icon_view_cell_layout_clear_attributes   (GtkCellLayout          *layout,
377                                                                           GtkCellRenderer        *renderer);
378 static void                 gtk_icon_view_cell_layout_set_cell_data_func (GtkCellLayout          *layout,
379                                                                           GtkCellRenderer        *cell,
380                                                                           GtkCellLayoutDataFunc   func,
381                                                                           gpointer                func_data,
382                                                                           GDestroyNotify          destroy);
383 static void                 gtk_icon_view_cell_layout_reorder            (GtkCellLayout          *layout,
384                                                                           GtkCellRenderer        *cell,
385                                                                           gint                    position);
386 static GList *              gtk_icon_view_cell_layout_get_cells          (GtkCellLayout          *layout);
387
388 static void                 gtk_icon_view_item_activate_cell             (GtkIconView            *icon_view,
389                                                                           GtkIconViewItem        *item,
390                                                                           GtkIconViewCellInfo    *cell_info,
391                                                                           GdkEvent               *event);
392 static void                 gtk_icon_view_put                            (GtkIconView            *icon_view,
393                                                                           GtkWidget              *widget,
394                                                                           GtkIconViewItem        *item,
395                                                                           gint                    cell);
396 static void                 gtk_icon_view_remove_widget                  (GtkCellEditable        *editable,
397                                                                           GtkIconView            *icon_view);
398 static void                 gtk_icon_view_start_editing                  (GtkIconView            *icon_view,
399                                                                           GtkIconViewItem        *item,
400                                                                           GtkIconViewCellInfo    *cell_info,
401                                                                           GdkEvent               *event);
402 static void                 gtk_icon_view_stop_editing                   (GtkIconView            *icon_view,
403                                                                           gboolean                cancel_editing);
404
405 /* Source side drag signals */
406 static void gtk_icon_view_drag_begin       (GtkWidget        *widget,
407                                             GdkDragContext   *context);
408 static void gtk_icon_view_drag_end         (GtkWidget        *widget,
409                                             GdkDragContext   *context);
410 static void gtk_icon_view_drag_data_get    (GtkWidget        *widget,
411                                             GdkDragContext   *context,
412                                             GtkSelectionData *selection_data,
413                                             guint             info,
414                                             guint             time);
415 static void gtk_icon_view_drag_data_delete (GtkWidget        *widget,
416                                             GdkDragContext   *context);
417
418 /* Target side drag signals */
419 static void     gtk_icon_view_drag_leave         (GtkWidget        *widget,
420                                                   GdkDragContext   *context,
421                                                   guint             time);
422 static gboolean gtk_icon_view_drag_motion        (GtkWidget        *widget,
423                                                   GdkDragContext   *context,
424                                                   gint              x,
425                                                   gint              y,
426                                                   guint             time);
427 static gboolean gtk_icon_view_drag_drop          (GtkWidget        *widget,
428                                                   GdkDragContext   *context,
429                                                   gint              x,
430                                                   gint              y,
431                                                   guint             time);
432 static void     gtk_icon_view_drag_data_received (GtkWidget        *widget,
433                                                   GdkDragContext   *context,
434                                                   gint              x,
435                                                   gint              y,
436                                                   GtkSelectionData *selection_data,
437                                                   guint             info,
438                                                   guint             time);
439 static gboolean gtk_icon_view_maybe_begin_drag   (GtkIconView             *icon_view,
440                                                   GdkEventMotion          *event);
441
442 static void     remove_scroll_timeout            (GtkIconView *icon_view);
443 static void     clear_dest_info                  (GtkIconView *icon_view);
444 static void     clear_source_info                (GtkIconView *icon_view);
445
446
447 static guint icon_view_signals[LAST_SIGNAL] = { 0 };
448
449 G_DEFINE_TYPE_WITH_CODE (GtkIconView, gtk_icon_view, GTK_TYPE_CONTAINER,
450                          G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
451                                                 gtk_icon_view_cell_layout_init))
452
453 static void
454 gtk_icon_view_class_init (GtkIconViewClass *klass)
455 {
456   GObjectClass *gobject_class;
457   GtkObjectClass *object_class;
458   GtkWidgetClass *widget_class;
459   GtkContainerClass *container_class;
460   GtkBindingSet *binding_set;
461   
462   binding_set = gtk_binding_set_by_class (klass);
463
464   g_type_class_add_private (klass, sizeof (GtkIconViewPrivate));
465
466   gobject_class = (GObjectClass *) klass;
467   object_class = (GtkObjectClass *) klass;
468   widget_class = (GtkWidgetClass *) klass;
469   container_class = (GtkContainerClass *) klass;
470
471   gobject_class->finalize = gtk_icon_view_finalize;
472   gobject_class->set_property = gtk_icon_view_set_property;
473   gobject_class->get_property = gtk_icon_view_get_property;
474
475   object_class->destroy = gtk_icon_view_destroy;
476   
477   widget_class->realize = gtk_icon_view_realize;
478   widget_class->unrealize = gtk_icon_view_unrealize;
479   widget_class->style_set = gtk_icon_view_style_set;
480   widget_class->get_accessible = gtk_icon_view_get_accessible;
481   widget_class->size_request = gtk_icon_view_size_request;
482   widget_class->size_allocate = gtk_icon_view_size_allocate;
483   widget_class->expose_event = gtk_icon_view_expose;
484   widget_class->motion_notify_event = gtk_icon_view_motion;
485   widget_class->button_press_event = gtk_icon_view_button_press;
486   widget_class->button_release_event = gtk_icon_view_button_release;
487   widget_class->drag_begin = gtk_icon_view_drag_begin;
488   widget_class->drag_end = gtk_icon_view_drag_end;
489   widget_class->drag_data_get = gtk_icon_view_drag_data_get;
490   widget_class->drag_data_delete = gtk_icon_view_drag_data_delete;
491   widget_class->drag_leave = gtk_icon_view_drag_leave;
492   widget_class->drag_motion = gtk_icon_view_drag_motion;
493   widget_class->drag_drop = gtk_icon_view_drag_drop;
494   widget_class->drag_data_received = gtk_icon_view_drag_data_received;
495   widget_class->state_changed = gtk_icon_view_state_changed;
496
497   container_class->remove = gtk_icon_view_remove;
498   container_class->forall = gtk_icon_view_forall;
499
500   klass->set_scroll_adjustments = gtk_icon_view_set_adjustments;
501   klass->select_all = gtk_icon_view_real_select_all;
502   klass->unselect_all = gtk_icon_view_real_unselect_all;
503   klass->select_cursor_item = gtk_icon_view_real_select_cursor_item;
504   klass->toggle_cursor_item = gtk_icon_view_real_toggle_cursor_item;
505   klass->activate_cursor_item = gtk_icon_view_real_activate_cursor_item;  
506   klass->move_cursor = gtk_icon_view_real_move_cursor;
507   
508   /* Properties */
509   /**
510    * GtkIconView:selection-mode:
511    * 
512    * The ::selection-mode property specifies the selection mode of
513    * icon view. If the mode is #GTK_SELECTION_MULTIPLE, rubberband selection
514    * is enabled, for the other modes, only keyboard selection is possible.
515    *
516    * Since: 2.6
517    */
518   g_object_class_install_property (gobject_class,
519                                    PROP_SELECTION_MODE,
520                                    g_param_spec_enum ("selection-mode",
521                                                       P_("Selection mode"),
522                                                       P_("The selection mode"),
523                                                       GTK_TYPE_SELECTION_MODE,
524                                                       GTK_SELECTION_SINGLE,
525                                                       GTK_PARAM_READWRITE));
526
527   /**
528    * GtkIconView:pixbuf-column:
529    *
530    * The ::pixbuf-column property contains the number of the model column
531    * containing the pixbufs which are displayed. The pixbuf column must be 
532    * of type #GDK_TYPE_PIXBUF. Setting this property to -1 turns off the
533    * display of pixbufs.
534    *
535    * Since: 2.6
536    */
537   g_object_class_install_property (gobject_class,
538                                    PROP_PIXBUF_COLUMN,
539                                    g_param_spec_int ("pixbuf-column",
540                                                      P_("Pixbuf column"),
541                                                      P_("Model column used to retrieve the icon pixbuf from"),
542                                                      -1, G_MAXINT, -1,
543                                                      GTK_PARAM_READWRITE));
544
545   /**
546    * GtkIconView:text-column:
547    *
548    * The ::text-column property contains the number of the model column
549    * containing the texts which are displayed. The text column must be 
550    * of type #G_TYPE_STRING. If this property and the :markup-column 
551    * property are both set to -1, no texts are displayed.   
552    *
553    * Since: 2.6
554    */
555   g_object_class_install_property (gobject_class,
556                                    PROP_TEXT_COLUMN,
557                                    g_param_spec_int ("text-column",
558                                                      P_("Text column"),
559                                                      P_("Model column used to retrieve the text from"),
560                                                      -1, G_MAXINT, -1,
561                                                      GTK_PARAM_READWRITE));
562
563   
564   /**
565    * GtkIconView:markup-column:
566    *
567    * The ::markup-column property contains the number of the model column
568    * containing markup information to be displayed. The markup column must be 
569    * of type #G_TYPE_STRING. If this property and the :text-column property 
570    * are both set to column numbers, it overrides the text column.
571    * If both are set to -1, no texts are displayed.   
572    *
573    * Since: 2.6
574    */
575   g_object_class_install_property (gobject_class,
576                                    PROP_MARKUP_COLUMN,
577                                    g_param_spec_int ("markup-column",
578                                                      P_("Markup column"),
579                                                      P_("Model column used to retrieve the text if using Pango markup"),
580                                                      -1, G_MAXINT, -1,
581                                                      GTK_PARAM_READWRITE));
582   
583   g_object_class_install_property (gobject_class,
584                                    PROP_MODEL,
585                                    g_param_spec_object ("model",
586                                                         P_("Icon View Model"),
587                                                         P_("The model for the icon view"),
588                                                         GTK_TYPE_TREE_MODEL,
589                                                         GTK_PARAM_READWRITE));
590   
591   /**
592    * GtkIconView:columns:
593    *
594    * The columns property contains the number of the columns in which the
595    * items should be displayed. If it is -1, the number of columns will
596    * be chosen automatically to fill the available area.
597    *
598    * Since: 2.6
599    */
600   g_object_class_install_property (gobject_class,
601                                    PROP_COLUMNS,
602                                    g_param_spec_int ("columns",
603                                                      P_("Number of columns"),
604                                                      P_("Number of columns to display"),
605                                                      -1, G_MAXINT, -1,
606                                                      GTK_PARAM_READWRITE));
607   
608
609   /**
610    * GtkIconView:item-width:
611    *
612    * The item-width property specifies the width to use for each item. 
613    * If it is set to -1, the icon view will automatically determine a 
614    * suitable item size.
615    *
616    * Since: 2.6
617    */
618   g_object_class_install_property (gobject_class,
619                                    PROP_ITEM_WIDTH,
620                                    g_param_spec_int ("item-width",
621                                                      P_("Width for each item"),
622                                                      P_("The width used for each item"),
623                                                      -1, G_MAXINT, -1,
624                                                      GTK_PARAM_READWRITE));  
625
626   /**
627    * GtkIconView:spacing:
628    *
629    * The spacing property specifies the space which is inserted between
630    * the cells (i.e. the icon and the text) of an item.
631    *
632    * Since: 2.6
633    */
634   g_object_class_install_property (gobject_class,
635                                    PROP_SPACING,
636                                    g_param_spec_int ("spacing",
637                                                      P_("Spacing"),
638                                                      P_("Space which is inserted between cells of an item"),
639                                                      0, G_MAXINT, 0,
640                                                      GTK_PARAM_READWRITE));
641
642   /**
643    * GtkIconView:row-spacing:
644    *
645    * The row-spacing property specifies the space which is inserted between
646    * the rows of the icon view.
647    *
648    * Since: 2.6
649    */
650   g_object_class_install_property (gobject_class,
651                                    PROP_ROW_SPACING,
652                                    g_param_spec_int ("row-spacing",
653                                                      P_("Row Spacing"),
654                                                      P_("Space which is inserted between grid rows"),
655                                                      0, G_MAXINT, 6,
656                                                      GTK_PARAM_READWRITE));
657
658   /**
659    * GtkIconView:column-spacing:
660    *
661    * The column-spacing property specifies the space which is inserted between
662    * the columns of the icon view.
663    *
664    * Since: 2.6
665    */
666   g_object_class_install_property (gobject_class,
667                                    PROP_COLUMN_SPACING,
668                                    g_param_spec_int ("column-spacing",
669                                                      P_("Column Spacing"),
670                                                      P_("Space which is inserted between grid columns"),
671                                                      0, G_MAXINT, 6,
672                                                      GTK_PARAM_READWRITE));
673
674   /**
675    * GtkIconView:margin:
676    *
677    * The margin property specifies the space which is inserted 
678    * at the edges of the icon view.
679    *
680    * Since: 2.6
681    */
682   g_object_class_install_property (gobject_class,
683                                    PROP_MARGIN,
684                                    g_param_spec_int ("margin",
685                                                      P_("Margin"),
686                                                      P_("Space which is inserted at the edges of the icon view"),
687                                                      0, G_MAXINT, 6,
688                                                      GTK_PARAM_READWRITE));
689
690
691   /**
692    * GtkIconView:orientation:
693    *
694    * The orientation property specifies how the cells (i.e. the icon and 
695    * the text) of the item are positioned relative to each other.
696    *
697    * Since: 2.6
698    */
699   g_object_class_install_property (gobject_class,
700                                    PROP_ORIENTATION,
701                                    g_param_spec_enum ("orientation",
702                                                       P_("Orientation"),
703                                                       P_("How the text and icon of each item are positioned relative to each other"),
704                                                       GTK_TYPE_ORIENTATION,
705                                                       GTK_ORIENTATION_VERTICAL,
706                                                       GTK_PARAM_READWRITE));
707
708   /**
709    * GtkIconView:reorderable:
710    *
711    * The reorderable property specifies if the items can be reordered
712    * by DND.
713    *
714    * Since: 2.8
715    */
716   g_object_class_install_property (gobject_class,
717                                    PROP_REORDERABLE,
718                                    g_param_spec_boolean ("reorderable",
719                                                          P_("Reorderable"),
720                                                          P_("View is reorderable"),
721                                                          FALSE,
722                                                          G_PARAM_READWRITE));
723
724   /* Style properties */
725   gtk_widget_class_install_style_property (widget_class,
726                                            g_param_spec_boxed ("selection-box-color",
727                                                                P_("Selection Box Color"),
728                                                                P_("Color of the selection box"),
729                                                                GDK_TYPE_COLOR,
730                                                                GTK_PARAM_READABLE));
731
732   gtk_widget_class_install_style_property (widget_class,
733                                            g_param_spec_uchar ("selection-box-alpha",
734                                                                P_("Selection Box Alpha"),
735                                                                P_("Opacity of the selection box"),
736                                                                0, 0xff,
737                                                                0x40,
738                                                                GTK_PARAM_READABLE));
739
740   /* Signals */
741   widget_class->set_scroll_adjustments_signal =
742     g_signal_new (I_("set_scroll_adjustments"),
743                   G_TYPE_FROM_CLASS (gobject_class),
744                   G_SIGNAL_RUN_LAST,
745                   G_STRUCT_OFFSET (GtkIconViewClass, set_scroll_adjustments),
746                   NULL, NULL, 
747                   _gtk_marshal_VOID__OBJECT_OBJECT,
748                   G_TYPE_NONE, 2,
749                   GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
750
751   icon_view_signals[ITEM_ACTIVATED] =
752     g_signal_new (I_("item_activated"),
753                   G_TYPE_FROM_CLASS (gobject_class),
754                   G_SIGNAL_RUN_LAST,
755                   G_STRUCT_OFFSET (GtkIconViewClass, item_activated),
756                   NULL, NULL,
757                   g_cclosure_marshal_VOID__BOXED,
758                   G_TYPE_NONE, 1,
759                   GTK_TYPE_TREE_PATH);
760
761   icon_view_signals[SELECTION_CHANGED] =
762     g_signal_new (I_("selection-changed"),
763                   G_TYPE_FROM_CLASS (gobject_class),
764                   G_SIGNAL_RUN_FIRST,
765                   G_STRUCT_OFFSET (GtkIconViewClass, selection_changed),
766                   NULL, NULL,
767                   g_cclosure_marshal_VOID__VOID,
768                   G_TYPE_NONE, 0);
769   
770   icon_view_signals[SELECT_ALL] =
771     g_signal_new (I_("select_all"),
772                   G_TYPE_FROM_CLASS (gobject_class),
773                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
774                   G_STRUCT_OFFSET (GtkIconViewClass, select_all),
775                   NULL, NULL,
776                   g_cclosure_marshal_VOID__VOID,
777                   G_TYPE_NONE, 0);
778   
779   icon_view_signals[UNSELECT_ALL] =
780     g_signal_new (I_("unselect_all"),
781                   G_TYPE_FROM_CLASS (gobject_class),
782                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
783                   G_STRUCT_OFFSET (GtkIconViewClass, unselect_all),
784                   NULL, NULL,
785                   g_cclosure_marshal_VOID__VOID,
786                   G_TYPE_NONE, 0);
787
788   icon_view_signals[SELECT_CURSOR_ITEM] =
789     g_signal_new (I_("select_cursor_item"),
790                   G_TYPE_FROM_CLASS (gobject_class),
791                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
792                   G_STRUCT_OFFSET (GtkIconViewClass, select_cursor_item),
793                   NULL, NULL,
794                   g_cclosure_marshal_VOID__VOID,
795                   G_TYPE_NONE, 0);
796
797   icon_view_signals[TOGGLE_CURSOR_ITEM] =
798     g_signal_new (I_("toggle_cursor_item"),
799                   G_TYPE_FROM_CLASS (gobject_class),
800                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
801                   G_STRUCT_OFFSET (GtkIconViewClass, toggle_cursor_item),
802                   NULL, NULL,
803                   g_cclosure_marshal_VOID__VOID,
804                   G_TYPE_NONE, 0);
805
806   icon_view_signals[ACTIVATE_CURSOR_ITEM] =
807     g_signal_new (I_("activate_cursor_item"),
808                   G_TYPE_FROM_CLASS (gobject_class),
809                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
810                   G_STRUCT_OFFSET (GtkIconViewClass, activate_cursor_item),
811                   NULL, NULL,
812                   _gtk_marshal_BOOLEAN__VOID,
813                   G_TYPE_BOOLEAN, 0);
814   
815   icon_view_signals[MOVE_CURSOR] =
816     g_signal_new (I_("move_cursor"),
817                   G_TYPE_FROM_CLASS (gobject_class),
818                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
819                   G_STRUCT_OFFSET (GtkIconViewClass, move_cursor),
820                   NULL, NULL,
821                   _gtk_marshal_BOOLEAN__ENUM_INT,
822                   G_TYPE_BOOLEAN, 2,
823                   GTK_TYPE_MOVEMENT_STEP,
824                   G_TYPE_INT);
825
826   /* Key bindings */
827   gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, 
828                                 "select_all", 0);
829   gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK | GDK_SHIFT_MASK, 
830                                 "unselect_all", 0);
831   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, 
832                                 "toggle_cursor_item", 0);
833
834   gtk_binding_entry_add_signal (binding_set, GDK_space, 0, 
835                                 "activate_cursor_item", 0);
836   gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, 
837                                 "activate_cursor_item", 0);
838   gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0, 
839                                 "activate_cursor_item", 0);
840   gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, 
841                                 "activate_cursor_item", 0);
842
843   gtk_icon_view_add_move_binding (binding_set, GDK_Up, 0,
844                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
845   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Up, 0,
846                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
847
848   gtk_icon_view_add_move_binding (binding_set, GDK_Down, 0,
849                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
850   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Down, 0,
851                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
852
853   gtk_icon_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK,
854                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
855
856   gtk_icon_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK,
857                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
858
859   gtk_icon_view_add_move_binding (binding_set, GDK_Home, 0,
860                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
861   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Home, 0,
862                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
863
864   gtk_icon_view_add_move_binding (binding_set, GDK_End, 0,
865                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
866   gtk_icon_view_add_move_binding (binding_set, GDK_KP_End, 0,
867                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
868
869   gtk_icon_view_add_move_binding (binding_set, GDK_Page_Up, 0,
870                                   GTK_MOVEMENT_PAGES, -1);
871   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Page_Up, 0,
872                                   GTK_MOVEMENT_PAGES, -1);
873
874   gtk_icon_view_add_move_binding (binding_set, GDK_Page_Down, 0,
875                                   GTK_MOVEMENT_PAGES, 1);
876   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Page_Down, 0,
877                                   GTK_MOVEMENT_PAGES, 1);
878
879   gtk_icon_view_add_move_binding (binding_set, GDK_Right, 0, 
880                                   GTK_MOVEMENT_VISUAL_POSITIONS, 1);
881   gtk_icon_view_add_move_binding (binding_set, GDK_Left, 0, 
882                                   GTK_MOVEMENT_VISUAL_POSITIONS, -1);
883
884   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Right, 0, 
885                                   GTK_MOVEMENT_VISUAL_POSITIONS, 1);
886   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Left, 0, 
887                                   GTK_MOVEMENT_VISUAL_POSITIONS, -1);
888 }
889
890 static void
891 gtk_icon_view_cell_layout_init (GtkCellLayoutIface *iface)
892 {
893   iface->pack_start = gtk_icon_view_cell_layout_pack_start;
894   iface->pack_end = gtk_icon_view_cell_layout_pack_end;
895   iface->clear = gtk_icon_view_cell_layout_clear;
896   iface->add_attribute = gtk_icon_view_cell_layout_add_attribute;
897   iface->set_cell_data_func = gtk_icon_view_cell_layout_set_cell_data_func;
898   iface->clear_attributes = gtk_icon_view_cell_layout_clear_attributes;
899   iface->reorder = gtk_icon_view_cell_layout_reorder;
900   iface->get_cells = gtk_icon_view_cell_layout_get_cells;
901 }
902
903 static void
904 gtk_icon_view_init (GtkIconView *icon_view)
905 {
906   icon_view->priv = GTK_ICON_VIEW_GET_PRIVATE (icon_view);
907   
908   icon_view->priv->width = 0;
909   icon_view->priv->height = 0;
910   icon_view->priv->selection_mode = GTK_SELECTION_SINGLE;
911   icon_view->priv->pressed_button = -1;
912   icon_view->priv->press_start_x = -1;
913   icon_view->priv->press_start_y = -1;
914   icon_view->priv->text_column = -1;
915   icon_view->priv->markup_column = -1;  
916   icon_view->priv->pixbuf_column = -1;
917   icon_view->priv->text_cell = -1;
918   icon_view->priv->pixbuf_cell = -1;  
919
920   GTK_WIDGET_SET_FLAGS (icon_view, GTK_CAN_FOCUS);
921   
922   gtk_icon_view_set_adjustments (icon_view, NULL, NULL);
923
924   icon_view->priv->cell_list = NULL;
925   icon_view->priv->n_cells = 0;
926   icon_view->priv->cursor_cell = -1;
927
928   icon_view->priv->orientation = GTK_ORIENTATION_VERTICAL;
929
930   icon_view->priv->columns = -1;
931   icon_view->priv->item_width = -1;
932   icon_view->priv->spacing = 0;
933   icon_view->priv->row_spacing = 6;
934   icon_view->priv->column_spacing = 6;
935   icon_view->priv->margin = 6;
936 }
937
938 static void
939 gtk_icon_view_destroy (GtkObject *object)
940 {
941   GtkIconView *icon_view;
942
943   icon_view = GTK_ICON_VIEW (object);
944   
945   gtk_icon_view_stop_editing (icon_view, TRUE);
946
947   gtk_icon_view_set_model (icon_view, NULL);
948   
949   if (icon_view->priv->layout_idle_id != 0)
950     {
951       g_source_remove (icon_view->priv->layout_idle_id);
952       icon_view->priv->layout_idle_id = 0;
953     }
954
955   if (icon_view->priv->scroll_to_path != NULL)
956     {
957       gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
958       icon_view->priv->scroll_to_path = NULL;
959     }
960
961   remove_scroll_timeout (icon_view);
962
963   if (icon_view->priv->hadjustment != NULL)
964     {
965       g_object_unref (icon_view->priv->hadjustment);
966       icon_view->priv->hadjustment = NULL;
967     }
968
969   if (icon_view->priv->vadjustment != NULL)
970     {
971       g_object_unref (icon_view->priv->vadjustment);
972       icon_view->priv->vadjustment = NULL;
973     }
974   
975   clear_dest_info (icon_view);
976   clear_source_info (icon_view);
977
978   (* GTK_OBJECT_CLASS (gtk_icon_view_parent_class)->destroy) (object);
979 }
980
981 /* GObject methods */
982 static void
983 gtk_icon_view_finalize (GObject *object)
984 {
985   gtk_icon_view_cell_layout_clear (GTK_CELL_LAYOUT (object));
986
987   (* G_OBJECT_CLASS (gtk_icon_view_parent_class)->finalize) (object);
988 }
989
990
991 static void
992 gtk_icon_view_set_property (GObject      *object,
993                             guint         prop_id,
994                             const GValue *value,
995                             GParamSpec   *pspec)
996 {
997   GtkIconView *icon_view;
998
999   icon_view = GTK_ICON_VIEW (object);
1000
1001   switch (prop_id)
1002     {
1003     case PROP_SELECTION_MODE:
1004       gtk_icon_view_set_selection_mode (icon_view, g_value_get_enum (value));
1005       break;
1006     case PROP_PIXBUF_COLUMN:
1007       gtk_icon_view_set_pixbuf_column (icon_view, g_value_get_int (value));
1008       break;
1009     case PROP_TEXT_COLUMN:
1010       gtk_icon_view_set_text_column (icon_view, g_value_get_int (value));
1011       break;
1012     case PROP_MARKUP_COLUMN:
1013       gtk_icon_view_set_markup_column (icon_view, g_value_get_int (value));
1014       break;
1015     case PROP_MODEL:
1016       gtk_icon_view_set_model (icon_view, g_value_get_object (value));
1017       break;
1018     case PROP_ORIENTATION:
1019       gtk_icon_view_set_orientation (icon_view, g_value_get_enum (value));
1020       break;
1021     case PROP_COLUMNS:
1022       gtk_icon_view_set_columns (icon_view, g_value_get_int (value));
1023       break;
1024     case PROP_ITEM_WIDTH:
1025       gtk_icon_view_set_item_width (icon_view, g_value_get_int (value));
1026       break;
1027     case PROP_SPACING:
1028       gtk_icon_view_set_spacing (icon_view, g_value_get_int (value));
1029       break;
1030     case PROP_ROW_SPACING:
1031       gtk_icon_view_set_row_spacing (icon_view, g_value_get_int (value));
1032       break;
1033     case PROP_COLUMN_SPACING:
1034       gtk_icon_view_set_column_spacing (icon_view, g_value_get_int (value));
1035       break;
1036     case PROP_MARGIN:
1037       gtk_icon_view_set_margin (icon_view, g_value_get_int (value));
1038       break;
1039     case PROP_REORDERABLE:
1040       gtk_icon_view_set_reorderable (icon_view, g_value_get_boolean (value));
1041       break;
1042       
1043     default:
1044       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1045       break;
1046     }
1047 }
1048
1049 static void
1050 gtk_icon_view_get_property (GObject      *object,
1051                             guint         prop_id,
1052                             GValue       *value,
1053                             GParamSpec   *pspec)
1054 {
1055   GtkIconView *icon_view;
1056
1057   icon_view = GTK_ICON_VIEW (object);
1058
1059   switch (prop_id)
1060     {
1061     case PROP_SELECTION_MODE:
1062       g_value_set_enum (value, icon_view->priv->selection_mode);
1063       break;
1064     case PROP_PIXBUF_COLUMN:
1065       g_value_set_int (value, icon_view->priv->pixbuf_column);
1066       break;
1067     case PROP_TEXT_COLUMN:
1068       g_value_set_int (value, icon_view->priv->text_column);
1069       break;
1070     case PROP_MARKUP_COLUMN:
1071       g_value_set_int (value, icon_view->priv->markup_column);
1072       break;
1073     case PROP_MODEL:
1074       g_value_set_object (value, icon_view->priv->model);
1075       break;
1076     case PROP_ORIENTATION:
1077       g_value_set_enum (value, icon_view->priv->orientation);
1078       break;
1079     case PROP_COLUMNS:
1080       g_value_set_int (value, icon_view->priv->columns);
1081       break;
1082     case PROP_ITEM_WIDTH:
1083       g_value_set_int (value, icon_view->priv->item_width);
1084       break;
1085     case PROP_SPACING:
1086       g_value_set_int (value, icon_view->priv->spacing);
1087       break;
1088     case PROP_ROW_SPACING:
1089       g_value_set_int (value, icon_view->priv->row_spacing);
1090       break;
1091     case PROP_COLUMN_SPACING:
1092       g_value_set_int (value, icon_view->priv->column_spacing);
1093       break;
1094     case PROP_MARGIN:
1095       g_value_set_int (value, icon_view->priv->margin);
1096       break;
1097     case PROP_REORDERABLE:
1098       g_value_set_boolean (value, icon_view->priv->reorderable);
1099       break;
1100
1101     default:
1102       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1103       break;
1104     }
1105 }
1106
1107 /* GtkWidget signals */
1108 static void
1109 gtk_icon_view_realize (GtkWidget *widget)
1110 {
1111   GtkIconView *icon_view;
1112   GdkWindowAttr attributes;
1113   gint attributes_mask;
1114   
1115   icon_view = GTK_ICON_VIEW (widget);
1116
1117   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1118
1119   /* Make the main, clipping window */
1120   attributes.window_type = GDK_WINDOW_CHILD;
1121   attributes.x = widget->allocation.x;
1122   attributes.y = widget->allocation.y;
1123   attributes.width = widget->allocation.width;
1124   attributes.height = widget->allocation.height;
1125   attributes.wclass = GDK_INPUT_OUTPUT;
1126   attributes.visual = gtk_widget_get_visual (widget);
1127   attributes.colormap = gtk_widget_get_colormap (widget);
1128   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1129
1130   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1131
1132   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1133                                    &attributes, attributes_mask);
1134   gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
1135   gdk_window_set_user_data (widget->window, widget);
1136
1137   /* Make the window for the icon view */
1138   attributes.x = 0;
1139   attributes.y = 0;
1140   attributes.width = MAX (icon_view->priv->width, widget->allocation.width);
1141   attributes.height = MAX (icon_view->priv->height, widget->allocation.height);
1142   attributes.event_mask = (GDK_EXPOSURE_MASK |
1143                            GDK_SCROLL_MASK |
1144                            GDK_POINTER_MOTION_MASK |
1145                            GDK_BUTTON_PRESS_MASK |
1146                            GDK_BUTTON_RELEASE_MASK |
1147                            GDK_KEY_PRESS_MASK |
1148                            GDK_KEY_RELEASE_MASK) |
1149     gtk_widget_get_events (widget);
1150   
1151   icon_view->priv->bin_window = gdk_window_new (widget->window,
1152                                                 &attributes, attributes_mask);
1153   gdk_window_set_user_data (icon_view->priv->bin_window, widget);
1154
1155   widget->style = gtk_style_attach (widget->style, widget->window);
1156   gdk_window_set_background (icon_view->priv->bin_window, &widget->style->base[widget->state]);
1157
1158   gdk_window_show (icon_view->priv->bin_window);
1159 }
1160
1161 static void
1162 gtk_icon_view_unrealize (GtkWidget *widget)
1163 {
1164   GtkIconView *icon_view;
1165
1166   icon_view = GTK_ICON_VIEW (widget);
1167
1168   gdk_window_set_user_data (icon_view->priv->bin_window, NULL);
1169   gdk_window_destroy (icon_view->priv->bin_window);
1170   icon_view->priv->bin_window = NULL;
1171
1172   /* GtkWidget::unrealize destroys children and widget->window */
1173   if (GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->unrealize)
1174     (* GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->unrealize) (widget);
1175 }
1176
1177 static void
1178 gtk_icon_view_state_changed (GtkWidget      *widget,
1179                              GtkStateType    previous_state)
1180 {
1181   GtkIconView *icon_view = GTK_ICON_VIEW (widget);
1182
1183   if (GTK_WIDGET_REALIZED (widget))
1184     {
1185       gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
1186       gdk_window_set_background (icon_view->priv->bin_window, &widget->style->base[widget->state]);
1187     }
1188
1189   gtk_widget_queue_draw (widget);
1190 }
1191
1192 static void
1193 gtk_icon_view_style_set (GtkWidget *widget,
1194                          GtkStyle *previous_style)
1195 {
1196   GtkIconView *icon_view;
1197
1198   g_return_if_fail (GTK_IS_ICON_VIEW (widget));
1199
1200   icon_view = GTK_ICON_VIEW (widget);
1201
1202   if (GTK_WIDGET_REALIZED (widget))
1203     {
1204       gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
1205       gdk_window_set_background (icon_view->priv->bin_window, &widget->style->base[widget->state]);
1206     }
1207
1208   gtk_widget_queue_resize (widget);
1209 }
1210
1211 static void
1212 gtk_icon_view_size_request (GtkWidget      *widget,
1213                             GtkRequisition *requisition)
1214 {
1215   GtkIconView *icon_view;
1216   GList *tmp_list;
1217
1218   icon_view = GTK_ICON_VIEW (widget);
1219
1220   requisition->width = icon_view->priv->width;
1221   requisition->height = icon_view->priv->height;
1222
1223   tmp_list = icon_view->priv->children;
1224
1225   while (tmp_list)
1226     {
1227       GtkIconViewChild *child = tmp_list->data;
1228       GtkRequisition child_requisition;
1229
1230       tmp_list = tmp_list->next;
1231
1232       if (GTK_WIDGET_VISIBLE (child->widget))
1233         gtk_widget_size_request (child->widget, &child_requisition);
1234     }  
1235 }
1236
1237 static void
1238 gtk_icon_view_allocate_children (GtkIconView *icon_view)
1239 {
1240   GList *list;
1241
1242   for (list = icon_view->priv->children; list; list = list->next)
1243     {
1244       GtkIconViewChild *child = list->data;
1245       GtkAllocation allocation;
1246
1247       /* totally ignore our child's requisition */
1248       if (child->cell < 0)
1249         {
1250           allocation.x = child->item->x;
1251           allocation.y = child->item->y;
1252           allocation.width = child->item->width;
1253           allocation.height = child->item->height;
1254         }
1255       else
1256         {
1257           GdkRectangle *box = &child->item->box[child->cell];
1258
1259           allocation.x = box->x;
1260           allocation.y = box->y;
1261           allocation.width = box->width;
1262           allocation.height = box->height;
1263         }
1264
1265       gtk_widget_size_allocate (child->widget, &allocation);
1266     }
1267 }
1268
1269 static void
1270 gtk_icon_view_size_allocate (GtkWidget      *widget,
1271                              GtkAllocation  *allocation)
1272 {
1273   GtkIconView *icon_view = GTK_ICON_VIEW (widget);
1274
1275   GtkAdjustment *hadjustment, *vadjustment;
1276
1277   widget->allocation = *allocation;
1278   
1279   if (GTK_WIDGET_REALIZED (widget))
1280     {
1281       gdk_window_move_resize (widget->window,
1282                               allocation->x, allocation->y,
1283                               allocation->width, allocation->height);
1284       gdk_window_resize (icon_view->priv->bin_window,
1285                          MAX (icon_view->priv->width, allocation->width),
1286                          MAX (icon_view->priv->height, allocation->height));
1287     }
1288
1289   gtk_icon_view_layout (icon_view);
1290   
1291   gtk_icon_view_allocate_children (icon_view);
1292
1293   hadjustment = icon_view->priv->hadjustment;
1294   vadjustment = icon_view->priv->vadjustment;
1295
1296   hadjustment->page_size = allocation->width;
1297   hadjustment->page_increment = allocation->width * 0.9;
1298   hadjustment->step_increment = allocation->width * 0.1;
1299   hadjustment->lower = 0;
1300   hadjustment->upper = MAX (allocation->width, icon_view->priv->width);
1301
1302   if (hadjustment->value > hadjustment->upper - hadjustment->page_size)
1303     gtk_adjustment_set_value (hadjustment, MAX (0, hadjustment->upper - hadjustment->page_size));
1304
1305   vadjustment->page_size = allocation->height;
1306   vadjustment->page_increment = allocation->height * 0.9;
1307   vadjustment->step_increment = allocation->height * 0.1;
1308   vadjustment->lower = 0;
1309   vadjustment->upper = MAX (allocation->height, icon_view->priv->height);
1310
1311   if (vadjustment->value > vadjustment->upper - vadjustment->page_size)
1312     gtk_adjustment_set_value (vadjustment, MAX (0, vadjustment->upper - vadjustment->page_size));
1313
1314   if (GTK_WIDGET_REALIZED (widget) &&
1315       icon_view->priv->scroll_to_path)
1316     {
1317       GtkTreePath *path;
1318       path = gtk_tree_row_reference_get_path (icon_view->priv->scroll_to_path);
1319       gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
1320       icon_view->priv->scroll_to_path = NULL;
1321
1322       gtk_icon_view_scroll_to_path (icon_view, path,
1323                                     icon_view->priv->scroll_to_use_align,
1324                                     icon_view->priv->scroll_to_row_align,
1325                                     icon_view->priv->scroll_to_col_align);
1326       gtk_tree_path_free (path);
1327     }
1328   else
1329     {
1330       gtk_adjustment_changed (hadjustment);
1331       gtk_adjustment_changed (vadjustment);
1332     }
1333 }
1334
1335 static gboolean
1336 gtk_icon_view_expose (GtkWidget *widget,
1337                       GdkEventExpose *expose)
1338 {
1339   GtkIconView *icon_view;
1340   GList *icons;
1341   cairo_t *cr;
1342   GtkTreePath *path;
1343   gint dest_index;
1344   GtkIconViewDropPosition dest_pos;
1345   GtkIconViewItem *dest_item = NULL;
1346
1347   icon_view = GTK_ICON_VIEW (widget);
1348
1349   if (expose->window != icon_view->priv->bin_window)
1350     return FALSE;
1351
1352   cr = gdk_cairo_create (icon_view->priv->bin_window);
1353   cairo_set_line_width (cr, 1.);
1354
1355   gtk_icon_view_get_drag_dest_item (icon_view, &path, &dest_pos);
1356
1357   if (path)
1358     {
1359       dest_index = gtk_tree_path_get_indices (path)[0];
1360       gtk_tree_path_free (path);
1361     }
1362   else
1363     dest_index = -1;
1364
1365   for (icons = icon_view->priv->items; icons; icons = icons->next) 
1366     {
1367       GtkIconViewItem *item = icons->data;
1368       GdkRectangle area;
1369       
1370       area.x = item->x;
1371       area.y = item->y;
1372       area.width = item->width;
1373       area.height = item->height;
1374         
1375       if (gdk_region_rect_in (expose->region, &area) == GDK_OVERLAP_RECTANGLE_OUT)
1376         continue;
1377       
1378       gtk_icon_view_paint_item (icon_view, cr, item, &expose->area, 
1379                                 icon_view->priv->bin_window,
1380                                 item->x, item->y, TRUE); 
1381  
1382       if (dest_index == item->index)
1383         dest_item = item;
1384     }
1385
1386   if (dest_item)
1387     {
1388       switch (dest_pos)
1389         {
1390         case GTK_ICON_VIEW_DROP_INTO:
1391           gtk_paint_focus (widget->style,
1392                            icon_view->priv->bin_window,
1393                            GTK_WIDGET_STATE (widget),
1394                            NULL,
1395                            widget,
1396                            "iconview-drop-indicator",
1397                            dest_item->x, dest_item->y,
1398                            dest_item->width, dest_item->height);
1399           break;
1400         case GTK_ICON_VIEW_DROP_ABOVE:
1401           gtk_paint_focus (widget->style,
1402                            icon_view->priv->bin_window,
1403                            GTK_WIDGET_STATE (widget),
1404                            NULL,
1405                            widget,
1406                            "iconview-drop-indicator",
1407                            dest_item->x, dest_item->y - 1,
1408                            dest_item->width, 2);
1409           break;
1410         case GTK_ICON_VIEW_DROP_LEFT:
1411           gtk_paint_focus (widget->style,
1412                            icon_view->priv->bin_window,
1413                            GTK_WIDGET_STATE (widget),
1414                            NULL,
1415                            widget,
1416                            "iconview-drop-indicator",
1417                            dest_item->x - 1, dest_item->y,
1418                            2, dest_item->height);
1419           break;
1420         case GTK_ICON_VIEW_DROP_BELOW:
1421           gtk_paint_focus (widget->style,
1422                            icon_view->priv->bin_window,
1423                            GTK_WIDGET_STATE (widget),
1424                            NULL,
1425                            widget,
1426                            "iconview-drop-indicator",
1427                            dest_item->x, dest_item->y + dest_item->height - 1,
1428                            dest_item->width, 2);
1429           break;
1430         case GTK_ICON_VIEW_DROP_RIGHT:
1431           gtk_paint_focus (widget->style,
1432                            icon_view->priv->bin_window,
1433                            GTK_WIDGET_STATE (widget),
1434                            NULL,
1435                            widget,
1436                            "iconview-drop-indicator",
1437                            dest_item->x + dest_item->width - 1, dest_item->y,
1438                            2, dest_item->height);
1439         case GTK_ICON_VIEW_NO_DROP: ;
1440           break;
1441         }
1442     }
1443   
1444   if (icon_view->priv->doing_rubberband)
1445     {
1446       GdkRectangle *rectangles;
1447       gint n_rectangles;
1448       
1449       gdk_region_get_rectangles (expose->region,
1450                                  &rectangles,
1451                                  &n_rectangles);
1452       
1453       while (n_rectangles--)
1454         gtk_icon_view_paint_rubberband (icon_view, cr, &rectangles[n_rectangles]);
1455
1456       g_free (rectangles);
1457     }
1458
1459   cairo_destroy (cr);
1460
1461   (* GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->expose_event) (widget, expose);
1462
1463   return TRUE;
1464 }
1465
1466 static gboolean
1467 rubberband_scroll_timeout (gpointer data)
1468 {
1469   GtkIconView *icon_view;
1470   gdouble value;
1471
1472   icon_view = data;
1473
1474   value = MIN (icon_view->priv->vadjustment->value +
1475                icon_view->priv->scroll_value_diff,
1476                icon_view->priv->vadjustment->upper -
1477                icon_view->priv->vadjustment->page_size);
1478
1479   gtk_adjustment_set_value (icon_view->priv->vadjustment, value);
1480
1481   gtk_icon_view_update_rubberband (icon_view);
1482   
1483   return TRUE;
1484 }
1485
1486 static gboolean
1487 gtk_icon_view_motion (GtkWidget      *widget,
1488                       GdkEventMotion *event)
1489 {
1490   GtkIconView *icon_view;
1491   gint abs_y;
1492   
1493   icon_view = GTK_ICON_VIEW (widget);
1494
1495   gtk_icon_view_maybe_begin_drag (icon_view, event);
1496
1497   if (icon_view->priv->doing_rubberband)
1498     {
1499       gtk_icon_view_update_rubberband (widget);
1500       
1501       abs_y = event->y - icon_view->priv->height *
1502         (icon_view->priv->vadjustment->value /
1503          (icon_view->priv->vadjustment->upper -
1504           icon_view->priv->vadjustment->lower));
1505
1506       if (abs_y < 0 || abs_y > widget->allocation.height)
1507         {
1508           if (abs_y < 0)
1509             icon_view->priv->scroll_value_diff = abs_y;
1510           else
1511             icon_view->priv->scroll_value_diff = abs_y - widget->allocation.height;
1512
1513           icon_view->priv->event_last_x = event->x;
1514           icon_view->priv->event_last_y = event->y;
1515
1516           if (icon_view->priv->scroll_timeout_id == 0)
1517             icon_view->priv->scroll_timeout_id = gdk_threads_add_timeout (30, rubberband_scroll_timeout, 
1518                                                                 icon_view);
1519         }
1520       else 
1521         remove_scroll_timeout (icon_view);
1522     }
1523   
1524   return TRUE;
1525 }
1526
1527 static void
1528 gtk_icon_view_remove (GtkContainer *container,
1529                       GtkWidget    *widget)
1530 {
1531   GtkIconView *icon_view;
1532   GtkIconViewChild *child = NULL;
1533   GList *tmp_list;
1534
1535   icon_view = GTK_ICON_VIEW (container);
1536   
1537   tmp_list = icon_view->priv->children;
1538   while (tmp_list)
1539     {
1540       child = tmp_list->data;
1541       if (child->widget == widget)
1542         {
1543           gtk_widget_unparent (widget);
1544
1545           icon_view->priv->children = g_list_remove_link (icon_view->priv->children, tmp_list);
1546           g_list_free_1 (tmp_list);
1547           g_free (child);
1548           return;
1549         }
1550
1551       tmp_list = tmp_list->next;
1552     }
1553 }
1554
1555 static void
1556 gtk_icon_view_forall (GtkContainer *container,
1557                       gboolean      include_internals,
1558                       GtkCallback   callback,
1559                       gpointer      callback_data)
1560 {
1561   GtkIconView *icon_view;
1562   GtkIconViewChild *child = NULL;
1563   GList *tmp_list;
1564
1565   icon_view = GTK_ICON_VIEW (container);
1566
1567   tmp_list = icon_view->priv->children;
1568   while (tmp_list)
1569     {
1570       child = tmp_list->data;
1571       tmp_list = tmp_list->next;
1572
1573       (* callback) (child->widget, callback_data);
1574     }
1575 }
1576
1577 static void
1578 gtk_icon_view_item_activate_cell (GtkIconView         *icon_view, 
1579                                   GtkIconViewItem     *item, 
1580                                   GtkIconViewCellInfo *info,
1581                                   GdkEvent            *event)
1582 {
1583   GtkTreePath *path;  
1584   gchar *path_string;
1585   GdkRectangle cell_area;
1586   gboolean visible, mode;
1587
1588   gtk_icon_view_set_cell_data (icon_view, item);
1589
1590   g_object_get (info->cell,
1591                 "visible", &visible,
1592                 "mode", &mode,
1593                 NULL);
1594
1595   if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
1596     {
1597       gtk_icon_view_get_cell_area (icon_view, item, info, &cell_area);
1598
1599       path = gtk_tree_path_new_from_indices (item->index, -1);
1600       path_string = gtk_tree_path_to_string (path);
1601       gtk_tree_path_free (path);
1602
1603       gtk_cell_renderer_activate (info->cell, 
1604                                   event, 
1605                                   GTK_WIDGET (icon_view),
1606                                   path_string, 
1607                                   &cell_area, 
1608                                   &cell_area, 
1609                                   0);
1610
1611       g_free (path_string);      
1612     }
1613 }
1614
1615 static void 
1616 gtk_icon_view_put (GtkIconView     *icon_view,
1617                    GtkWidget       *widget,
1618                    GtkIconViewItem *item,
1619                    gint             cell)
1620 {
1621   GtkIconViewChild *child;
1622   
1623   child = g_new (GtkIconViewChild, 1);
1624   
1625   child->widget = widget;
1626   child->item = item;
1627   child->cell = cell;
1628
1629   icon_view->priv->children = g_list_append (icon_view->priv->children, child);
1630
1631   if (GTK_WIDGET_REALIZED (icon_view))
1632     gtk_widget_set_parent_window (child->widget, icon_view->priv->bin_window);
1633   
1634   gtk_widget_set_parent (widget, GTK_WIDGET (icon_view));
1635 }
1636
1637 static void
1638 gtk_icon_view_remove_widget (GtkCellEditable *editable,
1639                              GtkIconView     *icon_view)
1640 {
1641   GList *l;
1642   GtkIconViewItem *item;
1643
1644   if (icon_view->priv->edited_item == NULL)
1645     return;
1646
1647   item = icon_view->priv->edited_item;
1648   icon_view->priv->edited_item = NULL;
1649   icon_view->priv->editable = NULL;
1650   for (l = icon_view->priv->cell_list; l; l = l->next)
1651     {
1652       GtkIconViewCellInfo *info = l->data;
1653
1654       info->editing = FALSE;
1655     }
1656
1657   if (GTK_WIDGET_HAS_FOCUS (editable))
1658     gtk_widget_grab_focus (GTK_WIDGET (icon_view));
1659   
1660   g_signal_handlers_disconnect_by_func (editable,
1661                                         gtk_icon_view_remove_widget,
1662                                         icon_view);
1663
1664   gtk_container_remove (GTK_CONTAINER (icon_view),
1665                         GTK_WIDGET (editable));  
1666
1667   gtk_icon_view_queue_draw_item (icon_view, item);
1668 }
1669
1670
1671 static void
1672 gtk_icon_view_start_editing (GtkIconView         *icon_view, 
1673                              GtkIconViewItem     *item, 
1674                              GtkIconViewCellInfo *info,
1675                              GdkEvent            *event)
1676 {
1677   GtkTreePath *path;  
1678   gchar *path_string;
1679   GdkRectangle cell_area;
1680   gboolean visible, mode;
1681   GtkCellEditable *editable;
1682
1683   gtk_icon_view_set_cell_data (icon_view, item);
1684
1685   g_object_get (info->cell,
1686                 "visible", &visible,
1687                 "mode", &mode,
1688                 NULL);
1689   if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
1690     {
1691       gtk_icon_view_get_cell_area (icon_view, item, info, &cell_area);
1692
1693       path = gtk_tree_path_new_from_indices (item->index, -1);
1694       path_string = gtk_tree_path_to_string (path);
1695       gtk_tree_path_free (path);
1696
1697       editable = gtk_cell_renderer_start_editing (info->cell, 
1698                                                   event, 
1699                                                   GTK_WIDGET (icon_view),
1700                                                   path_string, 
1701                                                   &cell_area, 
1702                                                   &cell_area, 
1703                                                   0);
1704       g_free (path_string);      
1705
1706       /* FIXME ugly special case */ 
1707       if (GTK_IS_ENTRY (editable) || GTK_IS_COMBO_BOX (editable))
1708         g_object_set (editable, "has-frame", TRUE, NULL);
1709
1710       /* the rest corresponds to tree_view_real_start_editing... */
1711       icon_view->priv->edited_item = item;
1712       icon_view->priv->editable = editable;
1713       info->editing = TRUE;
1714
1715       gtk_icon_view_put (icon_view, GTK_WIDGET (editable), item, 
1716                          info->position);
1717       gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (editable), 
1718                                        (GdkEvent *)event);
1719       gtk_widget_grab_focus (GTK_WIDGET (editable));
1720       g_signal_connect (editable, "remove_widget",
1721                         G_CALLBACK (gtk_icon_view_remove_widget), 
1722                         icon_view);
1723
1724     }
1725 }
1726
1727 static void
1728 gtk_icon_view_stop_editing (GtkIconView *icon_view,
1729                             gboolean     cancel_editing)
1730 {
1731   GtkCellRenderer *cell = NULL;
1732   GtkIconViewItem *item;
1733   GList *l;
1734
1735   if (icon_view->priv->edited_item == NULL)
1736     return;
1737
1738   /*
1739    * This is very evil. We need to do this, because
1740    * gtk_cell_editable_editing_done may trigger gtk_icon_view_row_changed
1741    * later on. If gtk_icon_view_row_changed notices
1742    * icon_view->priv->edited_item != NULL, it'll call
1743    * gtk_icon_view_stop_editing again. Bad things will happen then.
1744    *
1745    * Please read that again if you intend to modify anything here.
1746    */
1747
1748   item = icon_view->priv->edited_item;
1749   icon_view->priv->edited_item = NULL;
1750
1751   for (l = icon_view->priv->cell_list; l; l = l->next)
1752     {
1753       GtkIconViewCellInfo *info = l->data;
1754
1755       if (info->editing)
1756         {
1757           cell = info->cell;
1758           break;
1759         }
1760     }
1761
1762   if (cell == NULL)
1763     return;
1764
1765   gtk_cell_renderer_stop_editing (cell, cancel_editing);
1766   if (!cancel_editing)
1767     gtk_cell_editable_editing_done (icon_view->priv->editable);
1768
1769   icon_view->priv->edited_item = item;
1770
1771   gtk_cell_editable_remove_widget (icon_view->priv->editable);
1772 }
1773
1774 /**
1775  * gtk_icon_view_set_cursor:
1776  * @icon_view: A #GtkIconView
1777  * @path: A #GtkTreePath
1778  * @cell: One of the cell renderers of @icon_view, or %NULL
1779  * @start_editing: %TRUE if the specified cell should start being edited.
1780  *
1781  * Sets the current keyboard focus to be at @path, and selects it.  This is
1782  * useful when you want to focus the user's attention on a particular item.  
1783  * If @cell is not %NULL, then focus is given to the cell specified by 
1784  * it. Additionally, if @start_editing is %TRUE, then editing should be 
1785  * started in the specified cell.  
1786  *
1787  * This function is often followed by <literal>gtk_widget_grab_focus 
1788  * (icon_view)</literal> in order to give keyboard focus to the widget.  
1789  * Please note that editing can only happen when the widget is realized.
1790  *
1791  * Since: 2.8
1792  **/
1793 void
1794 gtk_icon_view_set_cursor (GtkIconView     *icon_view,
1795                           GtkTreePath     *path,
1796                           GtkCellRenderer *cell,
1797                           gboolean         start_editing)
1798 {
1799   GtkIconViewItem *item = NULL;
1800   GtkIconViewCellInfo *info =  NULL;
1801   GList *l;
1802   gint i, cell_pos;
1803
1804   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
1805   g_return_if_fail (path != NULL);
1806   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
1807
1808   gtk_icon_view_stop_editing (icon_view, TRUE);
1809
1810   if (gtk_tree_path_get_depth (path) == 1)
1811     item = g_list_nth_data (icon_view->priv->items,
1812                             gtk_tree_path_get_indices(path)[0]);
1813   
1814   if (!item)
1815     return;
1816
1817   cell_pos = -1;
1818   for (l = icon_view->priv->cell_list, i = 0; l; l = l->next, i++)
1819     {
1820       info = l->data;
1821       
1822       if (info->cell == cell)
1823         {
1824           cell_pos = i;
1825           break;
1826         }
1827           
1828       info = NULL;
1829     }
1830   
1831   g_return_if_fail (cell == NULL || info != NULL);
1832
1833   gtk_icon_view_set_cursor_item (icon_view, item, cell_pos);
1834   gtk_icon_view_scroll_to_path (icon_view, path, FALSE, 0.0, 0.0);
1835   
1836   if (info && start_editing)
1837     gtk_icon_view_start_editing (icon_view, item, info, NULL);
1838 }
1839
1840 /**
1841  * gtk_icon_view_get_cursor:
1842  * @icon_view: A #GtkIconView
1843  * @path: Return location for the current cursor path, or %NULL
1844  * @cell: Return location the current focus cell, or %NULL
1845  *
1846  * Fills in @path and @cell with the current cursor path and cell. 
1847  * If the cursor isn't currently set, then *@path will be %NULL.  
1848  * If no cell currently has focus, then *@cell will be %NULL.
1849  *
1850  * The returned #GtkTreePath must be freed with gtk_tree_path_free().
1851  *
1852  * Return value: %TRUE if the cursor is set.
1853  *
1854  * Since: 2.8
1855  **/
1856 gboolean
1857 gtk_icon_view_get_cursor (GtkIconView      *icon_view,
1858                           GtkTreePath     **path,
1859                           GtkCellRenderer **cell)
1860 {
1861   GtkIconViewItem *item;
1862   GtkIconViewCellInfo *info;
1863
1864   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
1865
1866   item = icon_view->priv->cursor_item;
1867   if (icon_view->priv->cursor_cell < 0)
1868     info = NULL;
1869   else
1870     info = g_list_nth_data (icon_view->priv->cell_list, 
1871                             icon_view->priv->cursor_cell);
1872
1873   if (path != NULL)
1874     {
1875       if (item != NULL)
1876         *path = gtk_tree_path_new_from_indices (item->index, -1);
1877       else
1878         *path = NULL;
1879     }
1880
1881   if (cell != NULL)
1882     {
1883       if (info != NULL)
1884         *cell = info->cell;
1885       else 
1886         *cell = NULL;
1887     }
1888
1889   return (item != NULL);
1890 }
1891
1892 static gboolean
1893 gtk_icon_view_button_press (GtkWidget      *widget,
1894                             GdkEventButton *event)
1895 {
1896   GtkIconView *icon_view;
1897   GtkIconViewItem *item;
1898   GtkIconViewCellInfo *info = NULL;
1899   gboolean dirty = FALSE;
1900   GtkCellRendererMode mode;
1901   gint cursor_cell;
1902
1903   icon_view = GTK_ICON_VIEW (widget);
1904
1905   if (event->window != icon_view->priv->bin_window)
1906     return FALSE;
1907
1908   if (!GTK_WIDGET_HAS_FOCUS (widget))
1909     gtk_widget_grab_focus (widget);
1910
1911   if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
1912     {
1913       item = gtk_icon_view_get_item_at_coords (icon_view, 
1914                                                event->x, event->y,
1915                                                TRUE,
1916                                                &info);      
1917       if (item != NULL)
1918         {
1919           g_object_get (info->cell, "mode", &mode, NULL);
1920           
1921           if (mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE ||
1922               mode == GTK_CELL_RENDERER_MODE_EDITABLE)
1923             cursor_cell = g_list_index (icon_view->priv->cell_list, info);
1924           else
1925             cursor_cell = -1;
1926           
1927           gtk_icon_view_scroll_to_item (icon_view, item);
1928           
1929           if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
1930             {
1931               gtk_icon_view_set_cursor_item (icon_view, item, cursor_cell);
1932             }
1933           else if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE &&
1934                    (event->state & GDK_SHIFT_MASK))
1935             {
1936               gtk_icon_view_unselect_all_internal (icon_view);
1937
1938               gtk_icon_view_set_cursor_item (icon_view, item, cursor_cell);
1939               if (!icon_view->priv->anchor_item)
1940                 icon_view->priv->anchor_item = item;
1941               else 
1942                 gtk_icon_view_select_all_between (icon_view,
1943                                                   icon_view->priv->anchor_item,
1944                                                   item);
1945               dirty = TRUE;
1946             }
1947           else 
1948             {
1949               if ((icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE ||
1950                   ((icon_view->priv->selection_mode == GTK_SELECTION_SINGLE) && item->selected)) &&
1951                   (event->state & GDK_CONTROL_MASK))
1952                 {
1953                   item->selected = !item->selected;
1954                   gtk_icon_view_queue_draw_item (icon_view, item);
1955                   dirty = TRUE;
1956                 }
1957               else
1958                 {
1959                   if (!item->selected)
1960                     {
1961                       gtk_icon_view_unselect_all_internal (icon_view);
1962                       
1963                       item->selected = TRUE;
1964                       gtk_icon_view_queue_draw_item (icon_view, item);
1965                       dirty = TRUE;
1966                     }
1967                 }
1968               gtk_icon_view_set_cursor_item (icon_view, item, cursor_cell);
1969               icon_view->priv->anchor_item = item;
1970             }
1971
1972           /* Save press to possibly begin a drag */
1973           if (icon_view->priv->pressed_button < 0)
1974             {
1975               icon_view->priv->pressed_button = event->button;
1976               icon_view->priv->press_start_x = event->x;
1977               icon_view->priv->press_start_y = event->y;
1978             }
1979
1980           if (!icon_view->priv->last_single_clicked)
1981             icon_view->priv->last_single_clicked = item;
1982
1983           /* cancel the current editing, if it exists */
1984           gtk_icon_view_stop_editing (icon_view, TRUE);
1985           
1986           if (mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
1987             gtk_icon_view_item_activate_cell (icon_view, item, info, 
1988                                               (GdkEvent *)event);
1989           else if (mode == GTK_CELL_RENDERER_MODE_EDITABLE)
1990             gtk_icon_view_start_editing (icon_view, item, info, 
1991                                          (GdkEvent *)event);      
1992         }
1993       else
1994         {
1995           if (icon_view->priv->selection_mode != GTK_SELECTION_BROWSE &&
1996               !(event->state & GDK_CONTROL_MASK))
1997             {
1998               dirty = gtk_icon_view_unselect_all_internal (icon_view);
1999             }
2000           
2001           if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE)
2002             gtk_icon_view_start_rubberbanding (icon_view, event->x, event->y);
2003         }
2004
2005     }
2006
2007   if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
2008     {
2009       item = gtk_icon_view_get_item_at_coords (icon_view,
2010                                                event->x, event->y,
2011                                                TRUE,
2012                                                NULL);
2013
2014       if (item && item == icon_view->priv->last_single_clicked)
2015         {
2016           GtkTreePath *path;
2017
2018           path = gtk_tree_path_new_from_indices (item->index, -1);
2019           gtk_icon_view_item_activated (icon_view, path);
2020           gtk_tree_path_free (path);
2021         }
2022
2023       icon_view->priv->last_single_clicked = NULL;
2024       icon_view->priv->pressed_button = -1;
2025     }
2026   
2027   if (dirty)
2028     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2029
2030   return event->button == 1;
2031 }
2032
2033 static gboolean
2034 gtk_icon_view_button_release (GtkWidget      *widget,
2035                               GdkEventButton *event)
2036 {
2037   GtkIconView *icon_view;
2038
2039   icon_view = GTK_ICON_VIEW (widget);
2040   
2041   if (icon_view->priv->pressed_button == event->button)
2042     icon_view->priv->pressed_button = -1;
2043
2044   gtk_icon_view_stop_rubberbanding (icon_view);
2045
2046   remove_scroll_timeout (icon_view);
2047
2048   return TRUE;
2049 }
2050
2051 static void
2052 gtk_icon_view_update_rubberband (gpointer data)
2053 {
2054   GtkIconView *icon_view;
2055   gint x, y;
2056   GdkRectangle old_area;
2057   GdkRectangle new_area;
2058   GdkRectangle common;
2059   GdkRegion *invalid_region;
2060   
2061   icon_view = GTK_ICON_VIEW (data);
2062
2063   gdk_window_get_pointer (icon_view->priv->bin_window, &x, &y, NULL);
2064
2065   x = MAX (x, 0);
2066   y = MAX (y, 0);
2067
2068   old_area.x = MIN (icon_view->priv->rubberband_x1,
2069                     icon_view->priv->rubberband_x2);
2070   old_area.y = MIN (icon_view->priv->rubberband_y1,
2071                     icon_view->priv->rubberband_y2);
2072   old_area.width = ABS (icon_view->priv->rubberband_x2 -
2073                         icon_view->priv->rubberband_x1) + 1;
2074   old_area.height = ABS (icon_view->priv->rubberband_y2 -
2075                          icon_view->priv->rubberband_y1) + 1;
2076   
2077   new_area.x = MIN (icon_view->priv->rubberband_x1, x);
2078   new_area.y = MIN (icon_view->priv->rubberband_y1, y);
2079   new_area.width = ABS (x - icon_view->priv->rubberband_x1) + 1;
2080   new_area.height = ABS (y - icon_view->priv->rubberband_y1) + 1;
2081
2082   invalid_region = gdk_region_rectangle (&old_area);
2083   gdk_region_union_with_rect (invalid_region, &new_area);
2084
2085   gdk_rectangle_intersect (&old_area, &new_area, &common);
2086   if (common.width > 2 && common.height > 2)
2087     {
2088       GdkRegion *common_region;
2089
2090       /* make sure the border is invalidated */
2091       common.x += 1;
2092       common.y += 1;
2093       common.width -= 2;
2094       common.height -= 2;
2095       
2096       common_region = gdk_region_rectangle (&common);
2097
2098       gdk_region_subtract (invalid_region, common_region);
2099       gdk_region_destroy (common_region);
2100     }
2101   
2102   gdk_window_invalidate_region (icon_view->priv->bin_window, invalid_region, TRUE);
2103     
2104   gdk_region_destroy (invalid_region);
2105
2106   icon_view->priv->rubberband_x2 = x;
2107   icon_view->priv->rubberband_y2 = y;  
2108
2109   gtk_icon_view_update_rubberband_selection (icon_view);
2110 }
2111
2112 static void
2113 gtk_icon_view_start_rubberbanding (GtkIconView  *icon_view,
2114                                    gint          x,
2115                                    gint          y)
2116 {
2117   GList *items;
2118
2119   g_assert (!icon_view->priv->doing_rubberband);
2120
2121   for (items = icon_view->priv->items; items; items = items->next)
2122     {
2123       GtkIconViewItem *item = items->data;
2124
2125       item->selected_before_rubberbanding = item->selected;
2126     }
2127   
2128   icon_view->priv->rubberband_x1 = x;
2129   icon_view->priv->rubberband_y1 = y;
2130   icon_view->priv->rubberband_x2 = x;
2131   icon_view->priv->rubberband_y2 = y;
2132
2133   icon_view->priv->doing_rubberband = TRUE;
2134
2135   gtk_grab_add (GTK_WIDGET (icon_view));
2136 }
2137
2138 static void
2139 gtk_icon_view_stop_rubberbanding (GtkIconView *icon_view)
2140 {
2141   if (!icon_view->priv->doing_rubberband)
2142     return;
2143
2144   icon_view->priv->doing_rubberband = FALSE;
2145
2146   gtk_grab_remove (GTK_WIDGET (icon_view));
2147   
2148   gtk_widget_queue_draw (GTK_WIDGET (icon_view));
2149 }
2150
2151 static void
2152 gtk_icon_view_update_rubberband_selection (GtkIconView *icon_view)
2153 {
2154   GList *items;
2155   gint x, y, width, height;
2156   gboolean dirty = FALSE;
2157   
2158   x = MIN (icon_view->priv->rubberband_x1,
2159            icon_view->priv->rubberband_x2);
2160   y = MIN (icon_view->priv->rubberband_y1,
2161            icon_view->priv->rubberband_y2);
2162   width = ABS (icon_view->priv->rubberband_x1 - 
2163                icon_view->priv->rubberband_x2);
2164   height = ABS (icon_view->priv->rubberband_y1 - 
2165                 icon_view->priv->rubberband_y2);
2166   
2167   for (items = icon_view->priv->items; items; items = items->next)
2168     {
2169       GtkIconViewItem *item = items->data;
2170       gboolean is_in;
2171       gboolean selected;
2172       
2173       is_in = gtk_icon_view_item_hit_test (icon_view, item, 
2174                                            x, y, width, height);
2175
2176       selected = is_in ^ item->selected_before_rubberbanding;
2177
2178       if (item->selected != selected)
2179         {
2180           item->selected = selected;
2181           dirty = TRUE;
2182           gtk_icon_view_queue_draw_item (icon_view, item);
2183         }
2184     }
2185
2186   if (dirty)
2187     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2188 }
2189
2190 static gboolean
2191 gtk_icon_view_item_hit_test (GtkIconView      *icon_view,
2192                              GtkIconViewItem  *item,
2193                              gint              x,
2194                              gint              y,
2195                              gint              width,
2196                              gint              height)
2197 {
2198   GList *l;
2199   GdkRectangle box;
2200  
2201   for (l = icon_view->priv->cell_list; l; l = l->next)
2202     {
2203       GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
2204       
2205       if (!info->cell->visible)
2206         continue;
2207       
2208       gtk_icon_view_get_cell_box (icon_view, item, info, &box);
2209
2210       if (MIN (x + width, box.x + box.width) - MAX (x, box.x) > 0 &&
2211         MIN (y + height, box.y + box.height) - MAX (y, box.y) > 0)
2212         return TRUE;
2213     }
2214
2215   return FALSE;
2216 }
2217
2218 static gboolean
2219 gtk_icon_view_unselect_all_internal (GtkIconView  *icon_view)
2220 {
2221   gboolean dirty = FALSE;
2222   GList *items;
2223
2224   if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
2225     return FALSE;
2226
2227   for (items = icon_view->priv->items; items; items = items->next)
2228     {
2229       GtkIconViewItem *item = items->data;
2230
2231       if (item->selected)
2232         {
2233           item->selected = FALSE;
2234           dirty = TRUE;
2235           gtk_icon_view_queue_draw_item (icon_view, item);
2236         }
2237     }
2238
2239   return dirty;
2240 }
2241
2242
2243 /* GtkIconView signals */
2244 static void
2245 gtk_icon_view_set_adjustments (GtkIconView   *icon_view,
2246                                GtkAdjustment *hadj,
2247                                GtkAdjustment *vadj)
2248 {
2249   gboolean need_adjust = FALSE;
2250
2251   if (hadj)
2252     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
2253   else
2254     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
2255   if (vadj)
2256     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
2257   else
2258     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
2259
2260   if (icon_view->priv->hadjustment && (icon_view->priv->hadjustment != hadj))
2261     {
2262       g_signal_handlers_disconnect_matched (icon_view->priv->hadjustment, G_SIGNAL_MATCH_DATA,
2263                                            0, 0, NULL, NULL, icon_view);
2264       g_object_unref (icon_view->priv->hadjustment);
2265     }
2266
2267   if (icon_view->priv->vadjustment && (icon_view->priv->vadjustment != vadj))
2268     {
2269       g_signal_handlers_disconnect_matched (icon_view->priv->vadjustment, G_SIGNAL_MATCH_DATA,
2270                                             0, 0, NULL, NULL, icon_view);
2271       g_object_unref (icon_view->priv->vadjustment);
2272     }
2273
2274   if (icon_view->priv->hadjustment != hadj)
2275     {
2276       icon_view->priv->hadjustment = hadj;
2277       g_object_ref_sink (icon_view->priv->hadjustment);
2278
2279       g_signal_connect (icon_view->priv->hadjustment, "value_changed",
2280                         G_CALLBACK (gtk_icon_view_adjustment_changed),
2281                         icon_view);
2282       need_adjust = TRUE;
2283     }
2284
2285   if (icon_view->priv->vadjustment != vadj)
2286     {
2287       icon_view->priv->vadjustment = vadj;
2288       g_object_ref_sink (icon_view->priv->vadjustment);
2289
2290       g_signal_connect (icon_view->priv->vadjustment, "value_changed",
2291                         G_CALLBACK (gtk_icon_view_adjustment_changed),
2292                         icon_view);
2293       need_adjust = TRUE;
2294     }
2295
2296   if (need_adjust)
2297     gtk_icon_view_adjustment_changed (NULL, icon_view);
2298 }
2299
2300 static void
2301 gtk_icon_view_real_select_all (GtkIconView *icon_view)
2302 {
2303   gtk_icon_view_select_all (icon_view);
2304 }
2305
2306 static void
2307 gtk_icon_view_real_unselect_all (GtkIconView *icon_view)
2308 {
2309   gtk_icon_view_unselect_all (icon_view);
2310 }
2311
2312 static void
2313 gtk_icon_view_real_select_cursor_item (GtkIconView *icon_view)
2314 {
2315   gtk_icon_view_unselect_all (icon_view);
2316   
2317   if (icon_view->priv->cursor_item != NULL)
2318     gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
2319 }
2320
2321 static gboolean
2322 gtk_icon_view_real_activate_cursor_item (GtkIconView *icon_view)
2323 {
2324   GtkTreePath *path;
2325   GtkCellRendererMode mode;
2326   GtkIconViewCellInfo *info = NULL;
2327   
2328   if (!icon_view->priv->cursor_item)
2329     return FALSE;
2330
2331   info = g_list_nth_data (icon_view->priv->cell_list, 
2332                           icon_view->priv->cursor_cell);
2333
2334   if (info) 
2335     {  
2336       g_object_get (info->cell, "mode", &mode, NULL);
2337
2338       if (mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
2339         {
2340           gtk_icon_view_item_activate_cell (icon_view, 
2341                                             icon_view->priv->cursor_item, 
2342                                             info, NULL);
2343           return TRUE;
2344         }
2345       else if (mode == GTK_CELL_RENDERER_MODE_EDITABLE)
2346         {
2347           gtk_icon_view_start_editing (icon_view, 
2348                                        icon_view->priv->cursor_item, 
2349                                        info, NULL);
2350           return TRUE;
2351         }
2352     }
2353   
2354   path = gtk_tree_path_new_from_indices (icon_view->priv->cursor_item->index, -1);
2355   gtk_icon_view_item_activated (icon_view, path);
2356   gtk_tree_path_free (path);
2357
2358   return TRUE;
2359 }
2360
2361 static void
2362 gtk_icon_view_real_toggle_cursor_item (GtkIconView *icon_view)
2363 {
2364   if (!icon_view->priv->cursor_item)
2365     return;
2366
2367   switch (icon_view->priv->selection_mode)
2368     {
2369     case GTK_SELECTION_NONE:
2370       break;
2371     case GTK_SELECTION_BROWSE:
2372       gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
2373       break;
2374     case GTK_SELECTION_SINGLE:
2375       if (icon_view->priv->cursor_item->selected)
2376         gtk_icon_view_unselect_item (icon_view, icon_view->priv->cursor_item);
2377       else
2378         gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
2379       break;
2380     case GTK_SELECTION_MULTIPLE:
2381       icon_view->priv->cursor_item->selected = !icon_view->priv->cursor_item->selected;
2382       g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0); 
2383       
2384       gtk_icon_view_queue_draw_item (icon_view, icon_view->priv->cursor_item);
2385       break;
2386     }
2387 }
2388
2389 /* Internal functions */
2390 static void
2391 gtk_icon_view_adjustment_changed (GtkAdjustment *adjustment,
2392                                   GtkIconView   *icon_view)
2393 {
2394   if (GTK_WIDGET_REALIZED (icon_view))
2395     {
2396       gdk_window_move (icon_view->priv->bin_window,
2397                        - icon_view->priv->hadjustment->value,
2398                        - icon_view->priv->vadjustment->value);
2399
2400       if (icon_view->priv->doing_rubberband)
2401         gtk_icon_view_update_rubberband (GTK_WIDGET (icon_view));
2402
2403       gdk_window_process_updates (icon_view->priv->bin_window, TRUE);
2404     }
2405 }
2406
2407 static GList *
2408 gtk_icon_view_layout_single_row (GtkIconView *icon_view, 
2409                                  GList       *first_item, 
2410                                  gint         item_width,
2411                                  gint         row,
2412                                  gint        *y, 
2413                                  gint        *maximum_width)
2414 {
2415   gint focus_width;
2416   gint x, current_width;
2417   GList *items, *last_item;
2418   gint col;
2419   gint colspan;
2420   gint *max_height;
2421   gint i;
2422   gboolean rtl;
2423
2424   rtl = gtk_widget_get_direction (GTK_WIDGET (icon_view)) == GTK_TEXT_DIR_RTL;
2425   max_height = g_new0 (gint, icon_view->priv->n_cells);
2426
2427   x = 0;
2428   col = 0;
2429   items = first_item;
2430   current_width = 0;
2431
2432   gtk_widget_style_get (GTK_WIDGET (icon_view),
2433                         "focus-line-width", &focus_width,
2434                         NULL);
2435
2436   x += icon_view->priv->margin + focus_width;
2437   current_width += 2 * (icon_view->priv->margin + focus_width);
2438
2439   items = first_item;
2440   while (items)
2441     {
2442       GtkIconViewItem *item = items->data;
2443
2444       gtk_icon_view_calculate_item_size (icon_view, item);
2445       colspan = 1 + (item->width - 1) / (item_width + icon_view->priv->column_spacing);
2446
2447       item->width = colspan * item_width + (colspan - 1) * icon_view->priv->column_spacing;
2448
2449       current_width += item->width;
2450
2451       if (items != first_item)
2452         {
2453           if ((icon_view->priv->columns <= 0 && current_width > GTK_WIDGET (icon_view)->allocation.width) ||
2454               (icon_view->priv->columns > 0 && col >= icon_view->priv->columns))
2455             break;
2456         }
2457
2458       current_width += icon_view->priv->column_spacing + 2 * focus_width;
2459
2460       item->y = *y + focus_width;
2461       item->x = rtl ? GTK_WIDGET (icon_view)->allocation.width - item->width - x : x;
2462
2463       x = current_width - (icon_view->priv->margin + focus_width); 
2464
2465       for (i = 0; i < icon_view->priv->n_cells; i++)
2466         max_height[i] = MAX (max_height[i], item->box[i].height);
2467               
2468       if (current_width > *maximum_width)
2469         *maximum_width = current_width;
2470
2471       item->row = row;
2472       item->col = col;
2473
2474       col += colspan;
2475       items = items->next;
2476     }
2477
2478   last_item = items;
2479
2480   /* Now go through the row again and align the icons */
2481   for (items = first_item; items != last_item; items = items->next)
2482     {
2483       GtkIconViewItem *item = items->data;
2484
2485       gtk_icon_view_calculate_item_size2 (icon_view, item, max_height);
2486
2487       /* We may want to readjust the new y coordinate. */
2488       if (item->y + item->height + focus_width + icon_view->priv->row_spacing > *y)
2489         *y = item->y + item->height + focus_width + icon_view->priv->row_spacing;
2490
2491       if (rtl)
2492         item->col = col - 1 - item->col;
2493     }
2494
2495   g_free (max_height);
2496   
2497   return last_item;
2498 }
2499
2500 static void
2501 gtk_icon_view_set_adjustment_upper (GtkAdjustment *adj,
2502                                     gdouble        upper)
2503 {
2504   if (upper != adj->upper)
2505     {
2506       gdouble min = MAX (0.0, upper - adj->page_size);
2507       gboolean value_changed = FALSE;
2508       
2509       adj->upper = upper;
2510
2511       if (adj->value > min)
2512         {
2513           adj->value = min;
2514           value_changed = TRUE;
2515         }
2516       
2517       gtk_adjustment_changed (adj);
2518       
2519       if (value_changed)
2520         gtk_adjustment_value_changed (adj);
2521     }
2522 }
2523
2524 static void
2525 gtk_icon_view_layout (GtkIconView *icon_view)
2526 {
2527   gint y = 0, maximum_width = 0;
2528   GList *icons;
2529   GtkWidget *widget;
2530   gint row;
2531   gint item_width;
2532
2533   if (icon_view->priv->layout_idle_id != 0)
2534     {
2535       g_source_remove (icon_view->priv->layout_idle_id);
2536       icon_view->priv->layout_idle_id = 0;
2537     }
2538   
2539   if (icon_view->priv->model == NULL)
2540     return;
2541
2542   widget = GTK_WIDGET (icon_view);
2543
2544   item_width = icon_view->priv->item_width;
2545
2546   if (item_width < 0)
2547     {
2548       for (icons = icon_view->priv->items; icons; icons = icons->next)
2549         {
2550           GtkIconViewItem *item = icons->data;
2551           gtk_icon_view_calculate_item_size (icon_view, item);
2552           item_width = MAX (item_width, item->width);
2553         }
2554     }
2555
2556   icons = icon_view->priv->items;
2557   y += icon_view->priv->margin;
2558   row = 0;
2559   
2560   do
2561     {
2562       icons = gtk_icon_view_layout_single_row (icon_view, icons, 
2563                                                item_width, row,
2564                                                &y, &maximum_width);
2565       row++;
2566     }
2567   while (icons != NULL);
2568
2569   if (maximum_width != icon_view->priv->width)
2570     icon_view->priv->width = maximum_width;
2571
2572   y += icon_view->priv->margin;
2573   
2574   if (y != icon_view->priv->height)
2575     icon_view->priv->height = y;
2576
2577   gtk_icon_view_set_adjustment_upper (icon_view->priv->hadjustment, 
2578                                       icon_view->priv->width);
2579   gtk_icon_view_set_adjustment_upper (icon_view->priv->vadjustment, 
2580                                       icon_view->priv->height);
2581
2582   if (GTK_WIDGET_REALIZED (icon_view))
2583     gdk_window_resize (icon_view->priv->bin_window,
2584                        MAX (icon_view->priv->width, widget->allocation.width),
2585                        MAX (icon_view->priv->height, widget->allocation.height));
2586
2587   if (icon_view->priv->scroll_to_path)
2588     {
2589       GtkTreePath *path;
2590
2591       path = gtk_tree_row_reference_get_path (icon_view->priv->scroll_to_path);
2592       gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
2593       icon_view->priv->scroll_to_path = NULL;
2594       
2595       gtk_icon_view_scroll_to_path (icon_view, path,
2596                                     icon_view->priv->scroll_to_use_align,
2597                                     icon_view->priv->scroll_to_row_align,
2598                                     icon_view->priv->scroll_to_col_align);
2599       gtk_tree_path_free (path);
2600     }
2601   
2602   gtk_widget_queue_draw (GTK_WIDGET (icon_view));
2603 }
2604
2605 static void 
2606 gtk_icon_view_get_cell_area (GtkIconView         *icon_view,
2607                              GtkIconViewItem     *item,
2608                              GtkIconViewCellInfo *info,
2609                              GdkRectangle        *cell_area)
2610 {
2611   if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
2612     {
2613       cell_area->x = item->box[info->position].x - item->before[info->position];
2614       cell_area->y = item->y;
2615       cell_area->width = item->box[info->position].width + 
2616         item->before[info->position] + item->after[info->position];
2617       cell_area->height = item->height;
2618     }
2619   else
2620     {
2621       cell_area->x = item->x;
2622       cell_area->y = item->box[info->position].y - item->before[info->position];
2623       cell_area->width = item->width;
2624       cell_area->height = item->box[info->position].height + 
2625         item->before[info->position] + item->after[info->position];
2626     }
2627 }
2628
2629 static void 
2630 gtk_icon_view_get_cell_box (GtkIconView         *icon_view,
2631                             GtkIconViewItem     *item,
2632                             GtkIconViewCellInfo *info,
2633                             GdkRectangle        *box)
2634 {
2635   *box = item->box[info->position];
2636 }
2637
2638 /* try to guess a reasonable wrap width for an implicit text cell renderer
2639  */
2640 static void
2641 adjust_wrap_width (GtkIconView     *icon_view,
2642                    GtkIconViewItem *item)
2643 {
2644   GtkIconViewCellInfo *text_info;
2645   GtkIconViewCellInfo *pixbuf_info;
2646   gint pixbuf_width, wrap_width;
2647       
2648   if (icon_view->priv->text_cell != -1 &&
2649       icon_view->priv->pixbuf_cell != -1)
2650     {
2651       text_info = g_list_nth_data (icon_view->priv->cell_list,
2652                                    icon_view->priv->text_cell);
2653       pixbuf_info = g_list_nth_data (icon_view->priv->cell_list,
2654                                      icon_view->priv->pixbuf_cell);
2655       
2656       gtk_cell_renderer_get_size (pixbuf_info->cell, 
2657                                   GTK_WIDGET (icon_view), 
2658                                   NULL, NULL, NULL,
2659                                   &pixbuf_width, 
2660                                   NULL);
2661           
2662       if (item->width == -1)
2663         wrap_width = MAX (2 * pixbuf_width, 50);
2664       else if (icon_view->priv->orientation == GTK_ORIENTATION_VERTICAL)
2665         wrap_width = item->width;
2666       else
2667         wrap_width = item->width - pixbuf_width - icon_view->priv->spacing;
2668
2669       g_object_set (text_info->cell, "wrap-width", wrap_width, NULL);
2670       g_object_set (text_info->cell, "width", wrap_width, NULL);
2671     }
2672 }
2673
2674 static void
2675 gtk_icon_view_calculate_item_size (GtkIconView     *icon_view,
2676                                    GtkIconViewItem *item)
2677 {
2678   gint spacing;
2679   GList *l;
2680
2681   if (item->width != -1 && item->height != -1) 
2682     return;
2683
2684   if (item->n_cells != icon_view->priv->n_cells)
2685     {
2686       g_free (item->before);
2687       g_free (item->after);
2688       g_free (item->box);
2689       
2690       item->before = g_new0 (gint, icon_view->priv->n_cells);
2691       item->after = g_new0 (gint, icon_view->priv->n_cells);
2692       item->box = g_new0 (GdkRectangle, icon_view->priv->n_cells);
2693
2694       item->n_cells = icon_view->priv->n_cells;
2695     }
2696
2697   gtk_icon_view_set_cell_data (icon_view, item);
2698
2699   spacing = icon_view->priv->spacing;
2700
2701   item->width = 0;
2702   item->height = 0;
2703   for (l = icon_view->priv->cell_list; l; l = l->next)
2704     {
2705       GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
2706       
2707       if (!info->cell->visible)
2708         continue;
2709       
2710       gtk_cell_renderer_get_size (info->cell, GTK_WIDGET (icon_view), 
2711                                   NULL, NULL, NULL,
2712                                   &item->box[info->position].width, 
2713                                   &item->box[info->position].height);
2714
2715       if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
2716         {
2717           item->width += item->box[info->position].width 
2718             + (info->position > 0 ? spacing : 0);
2719           item->height = MAX (item->height, item->box[info->position].height);
2720         }
2721       else
2722         {
2723           item->width = MAX (item->width, item->box[info->position].width);
2724           item->height += item->box[info->position].height + (info->position > 0 ? spacing : 0);
2725         }
2726     }
2727 }
2728
2729 static void
2730 gtk_icon_view_calculate_item_size2 (GtkIconView     *icon_view,
2731                                     GtkIconViewItem *item,
2732                                     gint            *max_height)
2733 {
2734   GdkRectangle cell_area;
2735   gint spacing;
2736   GList *l;
2737   gint i, k;
2738   gboolean rtl;
2739
2740   rtl = gtk_widget_get_direction (GTK_WIDGET (icon_view)) == GTK_TEXT_DIR_RTL;
2741
2742   gtk_icon_view_set_cell_data (icon_view, item);
2743
2744   spacing = icon_view->priv->spacing;
2745
2746   item->height = 0;
2747   for (i = 0; i < icon_view->priv->n_cells; i++)
2748     {
2749       if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
2750         item->height = MAX (item->height, max_height[i]);
2751       else
2752         item->height += max_height[i] + (i > 0 ? spacing : 0);
2753     }
2754
2755   cell_area.x = item->x;
2756   cell_area.y = item->y;
2757       
2758   for (k = 0; k < 2; k++)
2759     for (l = icon_view->priv->cell_list, i = 0; l; l = l->next, i++)
2760       {
2761         GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
2762         
2763         if (info->pack == (k ? GTK_PACK_START : GTK_PACK_END))
2764           continue;
2765
2766         if (!info->cell->visible)
2767           continue;
2768
2769         if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
2770           {
2771             cell_area.width = item->box[info->position].width;
2772             cell_area.height = item->height;
2773           }
2774         else
2775           {
2776             cell_area.width = item->width;
2777             cell_area.height = max_height[i];
2778           }
2779         
2780         gtk_cell_renderer_get_size (info->cell, GTK_WIDGET (icon_view), 
2781                                     &cell_area,
2782                                     &item->box[info->position].x, &item->box[info->position].y,
2783                                     &item->box[info->position].width, &item->box[info->position].height);
2784         
2785         item->box[info->position].x += cell_area.x;
2786         item->box[info->position].y += cell_area.y;
2787         if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
2788           {
2789             item->before[info->position] = item->box[info->position].x - cell_area.x;
2790             item->after[info->position] = cell_area.width - item->box[info->position].width - item->before[info->position];
2791             cell_area.x += cell_area.width + spacing;
2792           }
2793         else
2794           {
2795             if (item->box[info->position].width > item->width)
2796               {
2797                 item->width = item->box[info->position].width;
2798                 cell_area.width = item->width;
2799               }
2800             item->before[info->position] = item->box[info->position].y - cell_area.y;
2801             item->after[info->position] = cell_area.height - item->box[info->position].height - item->before[info->position];
2802             cell_area.y += cell_area.height + spacing;
2803           }
2804       }
2805   
2806   if (rtl && icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
2807     {
2808       for (i = 0; i < icon_view->priv->n_cells; i++)
2809         {
2810           item->box[i].x = item->x + item->width - 
2811             (item->box[i].x + item->box[i].width - item->x);
2812         }      
2813     }   
2814 }
2815
2816 static void
2817 gtk_icon_view_invalidate_sizes (GtkIconView *icon_view)
2818 {
2819   g_list_foreach (icon_view->priv->items,
2820                   (GFunc)gtk_icon_view_item_invalidate_size, NULL);
2821 }
2822
2823 static void
2824 gtk_icon_view_item_invalidate_size (GtkIconViewItem *item)
2825 {
2826   item->width = -1;
2827   item->height = -1;
2828 }
2829
2830 static void
2831 gtk_icon_view_paint_item (GtkIconView     *icon_view,
2832                           cairo_t         *cr,
2833                           GtkIconViewItem *item,
2834                           GdkRectangle    *area,
2835                           GdkDrawable     *drawable,
2836                           gint             x,
2837                           gint             y,
2838                           gboolean         draw_focus)
2839 {
2840   gint focus_width, focus_pad;
2841   gint padding;
2842   GdkRectangle cell_area, box;
2843   GList *l;
2844   gint i;
2845   GtkStateType state;
2846   GtkCellRendererState flags;
2847       
2848   if (icon_view->priv->model == NULL)
2849     return;
2850   
2851   gtk_icon_view_set_cell_data (icon_view, item);
2852
2853   gtk_widget_style_get (GTK_WIDGET (icon_view),
2854                         "focus-line-width", &focus_width,
2855                         "focus-padding", &focus_pad,
2856                         NULL);
2857   
2858   padding = focus_width; 
2859   
2860   if (item->selected)
2861     {
2862       flags = GTK_CELL_RENDERER_SELECTED;
2863       if (GTK_WIDGET_HAS_FOCUS (icon_view))
2864         state = GTK_STATE_SELECTED;
2865       else
2866         state = GTK_STATE_ACTIVE;
2867     }
2868   else
2869     {
2870       flags = 0;
2871       state = GTK_STATE_NORMAL;
2872     }
2873   
2874 #ifdef DEBUG_ICON_VIEW
2875   gdk_draw_rectangle (drawable,
2876                       GTK_WIDGET (icon_view)->style->black_gc,
2877                       FALSE,
2878                       x, y, 
2879                       item->width, item->height);
2880 #endif
2881
2882   if (item->selected)
2883     for (l = icon_view->priv->cell_list; l; l = l->next)
2884       {
2885         GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
2886         
2887         if (!info->cell->visible)
2888           continue;
2889         
2890         gtk_icon_view_get_cell_box (icon_view, item, info, &box);
2891
2892         /* FIXME we hardwire background drawing behind text
2893          * cell renderers here 
2894          */
2895         if (GTK_IS_CELL_RENDERER_TEXT (info->cell))
2896           {
2897             gdk_cairo_set_source_color (cr, &GTK_WIDGET (icon_view)->style->base[state]);
2898             cairo_rectangle (cr,
2899                              x - item->x + box.x, 
2900                              y - item->y + box.y,
2901                              box.width, box.height);
2902             cairo_fill (cr);
2903           }
2904       }
2905   
2906   for (l = icon_view->priv->cell_list; l; l = l->next)
2907     {
2908       GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
2909       
2910       if (!info->cell->visible)
2911         continue;
2912       
2913       gtk_icon_view_get_cell_area (icon_view, item, info, &cell_area);
2914       
2915 #ifdef DEBUG_ICON_VIEW
2916       gdk_draw_rectangle (drawable,
2917                           GTK_WIDGET (icon_view)->style->black_gc,
2918                           FALSE,
2919                           x - item->x + cell_area.x, 
2920                           y - item->y + cell_area.y, 
2921                           cell_area.width, cell_area.height);
2922
2923       gtk_icon_view_get_cell_box (icon_view, item, info, &box);
2924           
2925       gdk_draw_rectangle (drawable,
2926                           GTK_WIDGET (icon_view)->style->black_gc,
2927                           FALSE,
2928                           x - item->x + box.x, 
2929                           y - item->y + box.y, 
2930                           box.width, box.height);
2931 #endif
2932
2933       cell_area.x = x - item->x + cell_area.x;
2934       cell_area.y = y - item->y + cell_area.y;
2935
2936       gtk_cell_renderer_render (info->cell,
2937                                 drawable,
2938                                 GTK_WIDGET (icon_view),
2939                                 &cell_area, &cell_area, area, flags);
2940       
2941     }
2942
2943   /* FIXME where to draw the focus with generic cell renderers ? */
2944   if (draw_focus && 
2945       GTK_WIDGET_HAS_FOCUS (icon_view) &&
2946       item == icon_view->priv->cursor_item)
2947     for (l = icon_view->priv->cell_list, i = 0; l; l = l->next, i++)
2948       {
2949         GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
2950         
2951         if (!info->cell->visible)
2952           continue;
2953         
2954         if (icon_view->priv->cursor_cell < 0 &&
2955             (info->cell->mode != GTK_CELL_RENDERER_MODE_INERT ||
2956              GTK_IS_CELL_RENDERER_TEXT (info->cell)))
2957           icon_view->priv->cursor_cell = i;
2958         
2959         if (i == icon_view->priv->cursor_cell)
2960           {
2961             gtk_icon_view_get_cell_box (icon_view, item, info, &box);
2962
2963             gtk_paint_focus (GTK_WIDGET (icon_view)->style,
2964                              drawable,
2965                              GTK_STATE_NORMAL,
2966                              area,
2967                              GTK_WIDGET (icon_view),
2968                              "icon_view",
2969                              x - item->x + box.x - padding,
2970                              y - item->y + box.y - padding,
2971                              box.width + 2 * padding,
2972                              box.height + 2 * padding);
2973             break;
2974           }
2975       }
2976 }
2977
2978 static void
2979 gtk_icon_view_paint_rubberband (GtkIconView     *icon_view,
2980                                 cairo_t         *cr,
2981                                 GdkRectangle    *area)
2982 {
2983   GdkRectangle rect;
2984   GdkRectangle rubber_rect;
2985   GdkColor *fill_color_gdk;
2986   guchar fill_color_alpha;
2987
2988   rubber_rect.x = MIN (icon_view->priv->rubberband_x1, icon_view->priv->rubberband_x2);
2989   rubber_rect.y = MIN (icon_view->priv->rubberband_y1, icon_view->priv->rubberband_y2);
2990   rubber_rect.width = ABS (icon_view->priv->rubberband_x1 - icon_view->priv->rubberband_x2) + 1;
2991   rubber_rect.height = ABS (icon_view->priv->rubberband_y1 - icon_view->priv->rubberband_y2) + 1;
2992
2993   if (!gdk_rectangle_intersect (&rubber_rect, area, &rect))
2994     return;
2995
2996   gtk_widget_style_get (GTK_WIDGET (icon_view),
2997                         "selection-box-color", &fill_color_gdk,
2998                         "selection-box-alpha", &fill_color_alpha,
2999                         NULL);
3000
3001   if (!fill_color_gdk)
3002     fill_color_gdk = gdk_color_copy (&GTK_WIDGET (icon_view)->style->base[GTK_STATE_SELECTED]);
3003
3004   cairo_set_source_rgba (cr,
3005                          fill_color_gdk->red / 65535.,
3006                          fill_color_gdk->green / 65535.,
3007                          fill_color_gdk->blue / 65535.,
3008                          fill_color_alpha / 255.);
3009
3010   cairo_save (cr);
3011   gdk_cairo_rectangle (cr, &rect);
3012   cairo_clip (cr);
3013   cairo_paint (cr);
3014
3015   /* Draw the border without alpha */
3016   cairo_set_source_rgb (cr,
3017                         fill_color_gdk->red / 65535.,
3018                         fill_color_gdk->green / 65535.,
3019                         fill_color_gdk->blue / 65535.);
3020   cairo_rectangle (cr, 
3021                    rubber_rect.x + 0.5, rubber_rect.y + 0.5,
3022                    rubber_rect.width - 1, rubber_rect.height - 1);
3023   cairo_stroke (cr);
3024   cairo_restore (cr);
3025
3026   gdk_color_free (fill_color_gdk);
3027 }
3028
3029 static void
3030 gtk_icon_view_queue_draw_path (GtkIconView *icon_view,
3031                                GtkTreePath *path)
3032 {
3033   GList *l;
3034   gint index;
3035
3036   index = gtk_tree_path_get_indices (path)[0];
3037
3038   for (l = icon_view->priv->items; l; l = l->next) 
3039     {
3040       GtkIconViewItem *item = l->data;
3041
3042       if (item->index == index)
3043         {
3044           gtk_icon_view_queue_draw_item (icon_view, item);
3045           break;
3046         }
3047     }
3048 }
3049
3050 static void
3051 gtk_icon_view_queue_draw_item (GtkIconView     *icon_view,
3052                                GtkIconViewItem *item)
3053 {
3054   gint focus_width;
3055   GdkRectangle rect;
3056
3057   gtk_widget_style_get (GTK_WIDGET (icon_view),
3058                         "focus-line-width", &focus_width,
3059                         NULL);
3060
3061   rect.x = item->x - focus_width;
3062   rect.y = item->y - focus_width;
3063   rect.width = item->width + 2 * focus_width;
3064   rect.height = item->height + 2 * focus_width;
3065
3066   if (icon_view->priv->bin_window)
3067     gdk_window_invalidate_rect (icon_view->priv->bin_window, &rect, TRUE);
3068 }
3069
3070 static gboolean
3071 layout_callback (gpointer user_data)
3072 {
3073   GtkIconView *icon_view;
3074
3075   icon_view = GTK_ICON_VIEW (user_data);
3076   
3077   icon_view->priv->layout_idle_id = 0;
3078
3079   gtk_icon_view_layout (icon_view);
3080   
3081   return FALSE;
3082 }
3083
3084 static void
3085 gtk_icon_view_queue_layout (GtkIconView *icon_view)
3086 {
3087   if (icon_view->priv->layout_idle_id != 0)
3088     return;
3089
3090   icon_view->priv->layout_idle_id = gdk_threads_add_idle (layout_callback, icon_view);
3091 }
3092
3093 static void
3094 gtk_icon_view_set_cursor_item (GtkIconView     *icon_view,
3095                                GtkIconViewItem *item,
3096                                gint             cursor_cell)
3097 {
3098   AtkObject *obj;
3099   AtkObject *item_obj;
3100
3101   if (icon_view->priv->cursor_item == item &&
3102       (cursor_cell < 0 || cursor_cell == icon_view->priv->cursor_cell))
3103     return;
3104
3105   if (icon_view->priv->cursor_item != NULL)
3106     gtk_icon_view_queue_draw_item (icon_view, icon_view->priv->cursor_item);
3107   
3108   icon_view->priv->cursor_item = item;
3109   if (cursor_cell >= 0)
3110     icon_view->priv->cursor_cell = cursor_cell;
3111
3112   gtk_icon_view_queue_draw_item (icon_view, item);
3113   
3114   /* Notify that accessible focus object has changed */
3115   obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
3116   item_obj = atk_object_ref_accessible_child (obj, item->index);
3117
3118   if (item_obj != NULL)
3119     {
3120       atk_focus_tracker_notify (item_obj);
3121       g_object_unref (item_obj); 
3122     }
3123 }
3124
3125
3126 static GtkIconViewItem *
3127 gtk_icon_view_item_new (void)
3128 {
3129   GtkIconViewItem *item;
3130
3131   item = g_new0 (GtkIconViewItem, 1);
3132
3133   item->width = -1;
3134   item->height = -1;
3135   
3136   return item;
3137 }
3138
3139 static void
3140 gtk_icon_view_item_free (GtkIconViewItem *item)
3141 {
3142   g_return_if_fail (item != NULL);
3143
3144   g_free (item->before);
3145   g_free (item->after);
3146   g_free (item->box);
3147
3148   g_free (item);
3149 }
3150
3151
3152 static GtkIconViewItem *
3153 gtk_icon_view_get_item_at_coords (GtkIconView          *icon_view,
3154                                   gint                  x,
3155                                   gint                  y,
3156                                   gboolean              only_in_cell,
3157                                   GtkIconViewCellInfo **cell_at_pos)
3158 {
3159   GList *items, *l;
3160   GdkRectangle box;
3161
3162   for (items = icon_view->priv->items; items; items = items->next)
3163     {
3164       GtkIconViewItem *item = items->data;
3165
3166       if (x >= item->x - icon_view->priv->column_spacing/2 && x <= item->x + item->width + icon_view->priv->column_spacing/2 &&
3167           y >= item->y - icon_view->priv->row_spacing/2 && y <= item->y + item->height + icon_view->priv->row_spacing/2)
3168         {
3169           if (only_in_cell || cell_at_pos)
3170             {
3171               gtk_icon_view_set_cell_data (icon_view, item);
3172
3173               for (l = icon_view->priv->cell_list; l; l = l->next)
3174                 {
3175                   GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
3176                   
3177                   if (!info->cell->visible)
3178                     continue;
3179                   
3180                   gtk_icon_view_get_cell_box (icon_view, item, info, &box);
3181                   
3182                   if ((x >= box.x && x <= box.x + box.width &&
3183                        y >= box.y && y <= box.y + box.height) ||
3184                       (x >= box.x  &&
3185                        x <= box.x + box.width &&
3186                        y >= box.y &&
3187                        y <= box.y + box.height))
3188                     {
3189                       if (cell_at_pos)
3190                         *cell_at_pos = info;
3191                       
3192                       return item;
3193                     }
3194                 }
3195
3196               if (only_in_cell)
3197                 return NULL;
3198               
3199               if (cell_at_pos)
3200                 *cell_at_pos = NULL;
3201             }
3202
3203           return item;
3204         }
3205     }
3206
3207   return NULL;
3208 }
3209
3210 static void
3211 gtk_icon_view_select_item (GtkIconView      *icon_view,
3212                            GtkIconViewItem  *item)
3213 {
3214   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3215   g_return_if_fail (item != NULL);
3216
3217   if (item->selected)
3218     return;
3219   
3220   if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
3221     return;
3222   else if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3223     gtk_icon_view_unselect_all_internal (icon_view);
3224
3225   item->selected = TRUE;
3226
3227   gtk_icon_view_queue_draw_item (icon_view, item);
3228
3229   g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3230 }
3231
3232
3233 static void
3234 gtk_icon_view_unselect_item (GtkIconView      *icon_view,
3235                              GtkIconViewItem  *item)
3236 {
3237   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3238   g_return_if_fail (item != NULL);
3239
3240   if (!item->selected)
3241     return;
3242   
3243   if (icon_view->priv->selection_mode == GTK_SELECTION_NONE ||
3244       icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
3245     return;
3246   
3247   item->selected = FALSE;
3248
3249   g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3250
3251   gtk_icon_view_queue_draw_item (icon_view, item);
3252 }
3253
3254 static void
3255 verify_items (GtkIconView *icon_view)
3256 {
3257   GList *items;
3258   int i = 0;
3259
3260   for (items = icon_view->priv->items; items; items = items->next)
3261     {
3262       GtkIconViewItem *item = items->data;
3263
3264       if (item->index != i)
3265         g_error ("List item does not match its index: "
3266                  "item index %d and list index %d\n", item->index, i);
3267
3268       i++;
3269     }
3270 }
3271
3272 static void
3273 gtk_icon_view_row_changed (GtkTreeModel *model,
3274                            GtkTreePath  *path,
3275                            GtkTreeIter  *iter,
3276                            gpointer      data)
3277 {
3278   GtkIconViewItem *item;
3279   gint index;
3280   GtkIconView *icon_view;
3281
3282   icon_view = GTK_ICON_VIEW (data);
3283
3284   gtk_icon_view_stop_editing (icon_view, TRUE);
3285   
3286   index = gtk_tree_path_get_indices(path)[0];
3287   item = g_list_nth_data (icon_view->priv->items, index);
3288
3289   gtk_icon_view_item_invalidate_size (item);
3290   gtk_icon_view_queue_layout (icon_view);
3291
3292   verify_items (icon_view);
3293 }
3294
3295 static void
3296 gtk_icon_view_row_inserted (GtkTreeModel *model,
3297                             GtkTreePath  *path,
3298                             GtkTreeIter  *iter,
3299                             gpointer      data)
3300 {
3301   gint index;
3302   GtkIconViewItem *item;
3303   gboolean iters_persist;
3304   GtkIconView *icon_view;
3305   GList *list;
3306   
3307   icon_view = GTK_ICON_VIEW (data);
3308
3309   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
3310   
3311   index = gtk_tree_path_get_indices(path)[0];
3312
3313   item = gtk_icon_view_item_new ();
3314
3315   if (iters_persist)
3316     item->iter = *iter;
3317
3318   item->index = index;
3319
3320   /* FIXME: We can be more efficient here,
3321      we can store a tail pointer and use that when
3322      appending (which is a rather common operation)
3323   */
3324   icon_view->priv->items = g_list_insert (icon_view->priv->items,
3325                                          item, index);
3326   
3327   list = g_list_nth (icon_view->priv->items, index + 1);
3328   for (; list; list = list->next)
3329     {
3330       item = list->data;
3331
3332       item->index++;
3333     }
3334     
3335   verify_items (icon_view);
3336
3337   gtk_icon_view_queue_layout (icon_view);
3338 }
3339
3340 static void
3341 gtk_icon_view_row_deleted (GtkTreeModel *model,
3342                            GtkTreePath  *path,
3343                            gpointer      data)
3344 {
3345   gint index;
3346   GtkIconView *icon_view;
3347   GtkIconViewItem *item;
3348   GList *list, *next;
3349   gboolean emit = FALSE;
3350   
3351   icon_view = GTK_ICON_VIEW (data);
3352
3353   index = gtk_tree_path_get_indices(path)[0];
3354
3355   list = g_list_nth (icon_view->priv->items, index);
3356   item = list->data;
3357
3358   gtk_icon_view_stop_editing (icon_view, TRUE);
3359
3360   if (item == icon_view->priv->anchor_item)
3361     icon_view->priv->anchor_item = NULL;
3362
3363   if (item == icon_view->priv->cursor_item)
3364     icon_view->priv->cursor_item = NULL;
3365
3366   if (item->selected)
3367     emit = TRUE;
3368   
3369   gtk_icon_view_item_free (item);
3370
3371   for (next = list->next; next; next = next->next)
3372     {
3373       item = next->data;
3374
3375       item->index--;
3376     }
3377   
3378   icon_view->priv->items = g_list_delete_link (icon_view->priv->items, list);
3379
3380   verify_items (icon_view);  
3381   
3382   gtk_icon_view_queue_layout (icon_view);
3383
3384   if (emit)
3385     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3386 }
3387
3388 static void
3389 gtk_icon_view_rows_reordered (GtkTreeModel *model,
3390                               GtkTreePath  *parent,
3391                               GtkTreeIter  *iter,
3392                               gint         *new_order,
3393                               gpointer      data)
3394 {
3395   int i;
3396   int length;
3397   GtkIconView *icon_view;
3398   GList *items = NULL, *list;
3399   GtkIconViewItem **item_array;
3400   gint *order;
3401   
3402   icon_view = GTK_ICON_VIEW (data);
3403
3404   gtk_icon_view_stop_editing (icon_view, TRUE);
3405
3406   length = gtk_tree_model_iter_n_children (model, NULL);
3407
3408   order = g_new (gint, length);
3409   for (i = 0; i < length; i++)
3410     order [new_order[i]] = i;
3411
3412   item_array = g_new (GtkIconViewItem *, length);
3413   for (i = 0, list = icon_view->priv->items; list != NULL; list = list->next, i++)
3414     item_array[order[i]] = list->data;
3415   g_free (order);
3416
3417   for (i = length - 1; i >= 0; i--)
3418     {
3419       item_array[i]->index = i;
3420       items = g_list_prepend (items, item_array[i]);
3421     }
3422   
3423   g_free (item_array);
3424   g_list_free (icon_view->priv->items);
3425   icon_view->priv->items = items;
3426
3427   gtk_icon_view_queue_layout (icon_view);
3428
3429   verify_items (icon_view);  
3430 }
3431
3432 static void
3433 gtk_icon_view_build_items (GtkIconView *icon_view)
3434 {
3435   GtkTreeIter iter;
3436   int i;
3437   gboolean iters_persist;
3438   GList *items = NULL;
3439
3440   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
3441   
3442   if (!gtk_tree_model_get_iter_first (icon_view->priv->model,
3443                                       &iter))
3444     return;
3445
3446   i = 0;
3447   
3448   do
3449     {
3450       GtkIconViewItem *item = gtk_icon_view_item_new ();
3451
3452       if (iters_persist)
3453         item->iter = iter;
3454
3455       item->index = i;
3456       
3457       i++;
3458
3459       items = g_list_prepend (items, item);
3460       
3461     } while (gtk_tree_model_iter_next (icon_view->priv->model, &iter));
3462
3463   icon_view->priv->items = g_list_reverse (items);
3464 }
3465
3466 static void
3467 gtk_icon_view_add_move_binding (GtkBindingSet  *binding_set,
3468                                 guint           keyval,
3469                                 guint           modmask,
3470                                 GtkMovementStep step,
3471                                 gint            count)
3472 {
3473   
3474   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
3475                                 I_("move_cursor"), 2,
3476                                 G_TYPE_ENUM, step,
3477                                 G_TYPE_INT, count);
3478
3479   gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
3480                                 "move_cursor", 2,
3481                                 G_TYPE_ENUM, step,
3482                                 G_TYPE_INT, count);
3483
3484   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
3485    return;
3486
3487   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
3488                                 "move_cursor", 2,
3489                                 G_TYPE_ENUM, step,
3490                                 G_TYPE_INT, count);
3491
3492   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
3493                                 "move_cursor", 2,
3494                                 G_TYPE_ENUM, step,
3495                                 G_TYPE_INT, count);
3496 }
3497
3498 static gboolean
3499 gtk_icon_view_real_move_cursor (GtkIconView     *icon_view,
3500                                 GtkMovementStep  step,
3501                                 gint             count)
3502 {
3503   GdkModifierType state;
3504
3505   g_return_val_if_fail (GTK_ICON_VIEW (icon_view), FALSE);
3506   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
3507                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
3508                         step == GTK_MOVEMENT_DISPLAY_LINES ||
3509                         step == GTK_MOVEMENT_PAGES ||
3510                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
3511
3512   if (!GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (icon_view)))
3513     return FALSE;
3514
3515   gtk_icon_view_stop_editing (icon_view, FALSE);
3516   gtk_widget_grab_focus (GTK_WIDGET (icon_view));
3517
3518   if (gtk_get_current_event_state (&state))
3519     {
3520       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
3521         icon_view->priv->ctrl_pressed = TRUE;
3522       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
3523         icon_view->priv->shift_pressed = TRUE;
3524     }
3525   /* else we assume not pressed */
3526
3527   switch (step)
3528     {
3529     case GTK_MOVEMENT_LOGICAL_POSITIONS:
3530     case GTK_MOVEMENT_VISUAL_POSITIONS:
3531       gtk_icon_view_move_cursor_left_right (icon_view, count);
3532       break;
3533     case GTK_MOVEMENT_DISPLAY_LINES:
3534       gtk_icon_view_move_cursor_up_down (icon_view, count);
3535       break;
3536     case GTK_MOVEMENT_PAGES:
3537       gtk_icon_view_move_cursor_page_up_down (icon_view, count);
3538       break;
3539     case GTK_MOVEMENT_BUFFER_ENDS:
3540       gtk_icon_view_move_cursor_start_end (icon_view, count);
3541       break;
3542     default:
3543       g_assert_not_reached ();
3544     }
3545
3546   icon_view->priv->ctrl_pressed = FALSE;
3547   icon_view->priv->shift_pressed = FALSE;
3548
3549   return TRUE;
3550 }
3551
3552 static GtkIconViewItem *
3553 find_item (GtkIconView     *icon_view,
3554            GtkIconViewItem *current,
3555            gint             row_ofs,
3556            gint             col_ofs)
3557 {
3558   gint row, col;
3559   GList *items;
3560   GtkIconViewItem *item;
3561
3562   /* FIXME: this could be more efficient 
3563    */
3564   row = current->row + row_ofs;
3565   col = current->col + col_ofs;
3566
3567   for (items = icon_view->priv->items; items; items = items->next)
3568     {
3569       item = items->data;
3570       if (item->row == row && item->col == col)
3571         return item;
3572     }
3573   
3574   return NULL;
3575 }
3576
3577 static gint
3578 find_cell (GtkIconView     *icon_view,
3579            GtkIconViewItem *item,
3580            gint             cell,
3581            GtkOrientation   orientation,
3582            gint             step,
3583            gint            *count)
3584 {
3585   gint n_focusable;
3586   gint *focusable;
3587   gint first_text;
3588   gint current;
3589   gint i, k;
3590   GList *l;
3591
3592   if (icon_view->priv->orientation != orientation)
3593     return cell;
3594
3595   gtk_icon_view_set_cell_data (icon_view, item);
3596
3597   focusable = g_new0 (gint, icon_view->priv->n_cells);
3598   n_focusable = 0;
3599
3600   first_text = 0;
3601   current = 0;
3602   for (k = 0; k < 2; k++)
3603     for (l = icon_view->priv->cell_list, i = 0; l; l = l->next, i++)
3604       {
3605         GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
3606         
3607         if (info->pack == (k ? GTK_PACK_START : GTK_PACK_END))
3608           continue;
3609         
3610         if (!info->cell->visible)
3611           continue;
3612         
3613         if (GTK_IS_CELL_RENDERER_TEXT (info->cell))
3614           first_text = i;
3615
3616         if (info->cell->mode != GTK_CELL_RENDERER_MODE_INERT)
3617           {
3618             if (cell == i)
3619               current = n_focusable;
3620
3621             focusable[n_focusable] = i;
3622
3623             n_focusable++;
3624           }
3625       }
3626   
3627   if (n_focusable == 0)
3628     focusable[n_focusable++] = first_text;
3629
3630   if (cell < 0)
3631     {
3632       current = step > 0 ? 0 : n_focusable - 1;
3633       cell = focusable[current];
3634     }
3635
3636   if (current + *count < 0)
3637     {
3638       cell = -1;
3639       *count = current + *count;
3640     }
3641   else if (current + *count > n_focusable - 1)
3642     {
3643       cell = -1;
3644       *count = current + *count - (n_focusable - 1);
3645     }
3646   else
3647     {
3648       cell = focusable[current + *count];
3649       *count = 0;
3650     }
3651   
3652   g_free (focusable);
3653   
3654   return cell;
3655 }
3656
3657 static GtkIconViewItem *
3658 find_item_page_up_down (GtkIconView     *icon_view,
3659                         GtkIconViewItem *current,
3660                         gint             count)
3661 {
3662   GList *item, *next;
3663   gint y, col;
3664   
3665   col = current->col;
3666   y = current->y + count * icon_view->priv->vadjustment->page_size;
3667
3668   item = g_list_find (icon_view->priv->items, current);
3669   if (count > 0)
3670     {
3671       while (item)
3672         {
3673           for (next = item->next; next; next = next->next)
3674             {
3675               if (((GtkIconViewItem *)next->data)->col == col)
3676                 break;
3677             }
3678           if (!next || ((GtkIconViewItem *)next->data)->y > y)
3679             break;
3680
3681           item = next;
3682         }
3683     }
3684   else 
3685     {
3686       while (item)
3687         {
3688           for (next = item->prev; next; next = next->prev)
3689             {
3690               if (((GtkIconViewItem *)next->data)->col == col)
3691                 break;
3692             }
3693           if (!next || ((GtkIconViewItem *)next->data)->y < y)
3694             break;
3695
3696           item = next;
3697         }
3698     }
3699
3700   if (item)
3701     return item->data;
3702
3703   return NULL;
3704 }
3705
3706 static gboolean
3707 gtk_icon_view_select_all_between (GtkIconView     *icon_view,
3708                                   GtkIconViewItem *anchor,
3709                                   GtkIconViewItem *cursor)
3710 {
3711   GList *items;
3712   GtkIconViewItem *item;
3713   gint row1, row2, col1, col2;
3714   gboolean dirty = FALSE;
3715   
3716   if (anchor->row < cursor->row)
3717     {
3718       row1 = anchor->row;
3719       row2 = cursor->row;
3720     }
3721   else
3722     {
3723       row1 = cursor->row;
3724       row2 = anchor->row;
3725     }
3726
3727   if (anchor->col < cursor->col)
3728     {
3729       col1 = anchor->col;
3730       col2 = cursor->col;
3731     }
3732   else
3733     {
3734       col1 = cursor->col;
3735       col2 = anchor->col;
3736     }
3737
3738   for (items = icon_view->priv->items; items; items = items->next)
3739     {
3740       item = items->data;
3741
3742       if (row1 <= item->row && item->row <= row2 &&
3743           col1 <= item->col && item->col <= col2)
3744         {
3745           if (!item->selected)
3746             dirty = TRUE;
3747
3748           item->selected = TRUE;
3749           
3750           gtk_icon_view_queue_draw_item (icon_view, item);
3751         }
3752     }
3753
3754   return dirty;
3755 }
3756
3757 static void 
3758 gtk_icon_view_move_cursor_up_down (GtkIconView *icon_view,
3759                                    gint         count)
3760 {
3761   GtkIconViewItem *item;
3762   gint cell;
3763   gboolean dirty = FALSE;
3764   gint step;
3765   
3766   if (!GTK_WIDGET_HAS_FOCUS (icon_view))
3767     return;
3768   
3769   if (!icon_view->priv->cursor_item)
3770     {
3771       GList *list;
3772
3773       if (count > 0)
3774         list = icon_view->priv->items;
3775       else
3776         list = g_list_last (icon_view->priv->items);
3777
3778       item = list ? list->data : NULL;
3779       cell = -1;
3780     }
3781   else
3782     {
3783       item = icon_view->priv->cursor_item;
3784       cell = icon_view->priv->cursor_cell;
3785       step = count > 0 ? 1 : -1;      
3786       while (item)
3787         {
3788           cell = find_cell (icon_view, item, cell,
3789                             GTK_ORIENTATION_VERTICAL, 
3790                             step, &count);
3791           if (count == 0)
3792             break;
3793
3794           item = find_item (icon_view, item, step, 0);
3795           count = count - step;
3796         }
3797     }
3798
3799   if (!item)
3800     {
3801       gtk_widget_error_bell (GTK_WIDGET (icon_view));
3802       return;
3803     }
3804
3805   if (icon_view->priv->ctrl_pressed ||
3806       !icon_view->priv->shift_pressed ||
3807       !icon_view->priv->anchor_item ||
3808       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3809     icon_view->priv->anchor_item = item;
3810
3811   gtk_icon_view_set_cursor_item (icon_view, item, cell);
3812
3813   if (!icon_view->priv->ctrl_pressed &&
3814       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
3815     {
3816       dirty = gtk_icon_view_unselect_all_internal (icon_view);
3817       dirty = gtk_icon_view_select_all_between (icon_view, 
3818                                                 icon_view->priv->anchor_item,
3819                                                 item) || dirty;
3820     }
3821
3822   gtk_icon_view_scroll_to_item (icon_view, item);
3823
3824   if (dirty)
3825     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3826 }
3827
3828 static void 
3829 gtk_icon_view_move_cursor_page_up_down (GtkIconView *icon_view,
3830                                         gint         count)
3831 {
3832   GtkIconViewItem *item;
3833   gboolean dirty = FALSE;
3834   
3835   if (!GTK_WIDGET_HAS_FOCUS (icon_view))
3836     return;
3837   
3838   if (!icon_view->priv->cursor_item)
3839     {
3840       GList *list;
3841
3842       if (count > 0)
3843         list = icon_view->priv->items;
3844       else
3845         list = g_list_last (icon_view->priv->items);
3846
3847       item = list ? list->data : NULL;
3848     }
3849   else
3850     item = find_item_page_up_down (icon_view, 
3851                                    icon_view->priv->cursor_item,
3852                                    count);
3853
3854   if (item == icon_view->priv->cursor_item)
3855     gtk_widget_error_bell (GTK_WIDGET (icon_view));
3856
3857   if (!item)
3858     return;
3859
3860   if (icon_view->priv->ctrl_pressed ||
3861       !icon_view->priv->shift_pressed ||
3862       !icon_view->priv->anchor_item ||
3863       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3864     icon_view->priv->anchor_item = item;
3865
3866   gtk_icon_view_set_cursor_item (icon_view, item, -1);
3867
3868   if (!icon_view->priv->ctrl_pressed &&
3869       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
3870     {
3871       dirty = gtk_icon_view_unselect_all_internal (icon_view);
3872       dirty = gtk_icon_view_select_all_between (icon_view, 
3873                                                 icon_view->priv->anchor_item,
3874                                                 item) || dirty;
3875     }
3876
3877   gtk_icon_view_scroll_to_item (icon_view, item);
3878
3879   if (dirty)
3880     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);  
3881 }
3882
3883 static void 
3884 gtk_icon_view_move_cursor_left_right (GtkIconView *icon_view,
3885                                       gint         count)
3886 {
3887   GtkIconViewItem *item;
3888   gint cell = -1;
3889   gboolean dirty = FALSE;
3890   gint step;
3891   
3892   if (!GTK_WIDGET_HAS_FOCUS (icon_view))
3893     return;
3894   
3895   if (!icon_view->priv->cursor_item)
3896     {
3897       GList *list;
3898
3899       if (count > 0)
3900         list = icon_view->priv->items;
3901       else
3902         list = g_list_last (icon_view->priv->items);
3903
3904       item = list ? list->data : NULL;
3905     }
3906   else
3907     {
3908       item = icon_view->priv->cursor_item;
3909       cell = icon_view->priv->cursor_cell;
3910       step = count > 0 ? 1 : -1;
3911       while (item)
3912         {
3913           cell = find_cell (icon_view, item, cell,
3914                             GTK_ORIENTATION_HORIZONTAL, 
3915                             step, &count);
3916           if (count == 0)
3917             break;
3918           
3919           item = find_item (icon_view, item, 0, step);
3920           count = count - step;
3921         }
3922     }
3923
3924   if (!item)
3925     {
3926       gtk_widget_error_bell (GTK_WIDGET (icon_view));
3927       return;
3928     }
3929
3930   if (icon_view->priv->ctrl_pressed ||
3931       !icon_view->priv->shift_pressed ||
3932       !icon_view->priv->anchor_item ||
3933       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3934     icon_view->priv->anchor_item = item;
3935
3936   gtk_icon_view_set_cursor_item (icon_view, item, cell);
3937
3938   if (!icon_view->priv->ctrl_pressed &&
3939       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
3940     {
3941       dirty = gtk_icon_view_unselect_all_internal (icon_view);
3942       dirty = gtk_icon_view_select_all_between (icon_view, 
3943                                                 icon_view->priv->anchor_item,
3944                                                 item) || dirty;
3945     }
3946
3947   gtk_icon_view_scroll_to_item (icon_view, item);
3948
3949   if (dirty)
3950     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3951 }
3952
3953 static void 
3954 gtk_icon_view_move_cursor_start_end (GtkIconView *icon_view,
3955                                      gint         count)
3956 {
3957   GtkIconViewItem *item;
3958   GList *list;
3959   gboolean dirty = FALSE;
3960   
3961   if (!GTK_WIDGET_HAS_FOCUS (icon_view))
3962     return;
3963   
3964   if (count < 0)
3965     list = icon_view->priv->items;
3966   else
3967     list = g_list_last (icon_view->priv->items);
3968   
3969   item = list ? list->data : NULL;
3970
3971   if (item == icon_view->priv->cursor_item)
3972     gtk_widget_error_bell (GTK_WIDGET (icon_view));
3973
3974   if (!item)
3975     return;
3976
3977   if (icon_view->priv->ctrl_pressed ||
3978       !icon_view->priv->shift_pressed ||
3979       !icon_view->priv->anchor_item ||
3980       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3981     icon_view->priv->anchor_item = item;
3982
3983   gtk_icon_view_set_cursor_item (icon_view, item, -1);
3984
3985   if (!icon_view->priv->ctrl_pressed &&
3986       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
3987     {
3988       dirty = gtk_icon_view_unselect_all_internal (icon_view);
3989       dirty = gtk_icon_view_select_all_between (icon_view, 
3990                                                 icon_view->priv->anchor_item,
3991                                                 item) || dirty;
3992     }
3993
3994   gtk_icon_view_scroll_to_item (icon_view, item);
3995
3996   if (dirty)
3997     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3998 }
3999
4000 /**
4001  * gtk_icon_view_scroll_to_path:
4002  * @icon_view: A #GtkIconView.
4003  * @path: The path of the item to move to.
4004  * @use_align: whether to use alignment arguments, or %FALSE.
4005  * @row_align: The vertical alignment of the item specified by @path.
4006  * @col_align: The horizontal alignment of the item specified by @path.
4007  *
4008  * Moves the alignments of @icon_view to the position specified by @path.  
4009  * @row_align determines where the row is placed, and @col_align determines 
4010  * where @column is placed.  Both are expected to be between 0.0 and 1.0. 
4011  * 0.0 means left/top alignment, 1.0 means right/bottom alignment, 0.5 means 
4012  * center.
4013  *
4014  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
4015  * tree does the minimum amount of work to scroll the item onto the screen.
4016  * This means that the item will be scrolled to the edge closest to its current
4017  * position.  If the item is currently visible on the screen, nothing is done.
4018  *
4019  * This function only works if the model is set, and @path is a valid row on 
4020  * the model. If the model changes before the @icon_view is realized, the 
4021  * centered path will be modified to reflect this change.
4022  *
4023  * Since: 2.8
4024  **/
4025 void
4026 gtk_icon_view_scroll_to_path (GtkIconView *icon_view,
4027                               GtkTreePath *path,
4028                               gboolean     use_align,
4029                               gfloat       row_align,
4030                               gfloat       col_align)
4031 {
4032   GtkIconViewItem *item = NULL;
4033
4034   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4035   g_return_if_fail (path != NULL);
4036   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
4037   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
4038
4039   if (gtk_tree_path_get_depth (path) > 0)
4040     item = g_list_nth_data (icon_view->priv->items,
4041                             gtk_tree_path_get_indices(path)[0]);
4042   
4043   if (!GTK_WIDGET_REALIZED (icon_view) || !item || item->width < 0)
4044     {
4045       if (icon_view->priv->scroll_to_path)
4046         gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
4047
4048       icon_view->priv->scroll_to_path = NULL;
4049
4050       if (path)
4051         icon_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (icon_view), icon_view->priv->model, path);
4052
4053       icon_view->priv->scroll_to_use_align = use_align;
4054       icon_view->priv->scroll_to_row_align = row_align;
4055       icon_view->priv->scroll_to_col_align = col_align;
4056
4057       return;
4058     }
4059
4060   if (use_align)
4061     {
4062       gint x, y;
4063       gint focus_width;
4064       gfloat offset, value;
4065
4066       gtk_widget_style_get (GTK_WIDGET (icon_view),
4067                             "focus-line-width", &focus_width,
4068                             NULL);
4069       
4070       gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4071       
4072       offset =  y + item->y - focus_width - 
4073         row_align * (GTK_WIDGET (icon_view)->allocation.height - item->height);
4074       value = CLAMP (icon_view->priv->vadjustment->value + offset, 
4075                      icon_view->priv->vadjustment->lower,
4076                      icon_view->priv->vadjustment->upper - icon_view->priv->vadjustment->page_size);
4077       gtk_adjustment_set_value (icon_view->priv->vadjustment, value);
4078
4079       offset = x + item->x - focus_width - 
4080         col_align * (GTK_WIDGET (icon_view)->allocation.width - item->width);
4081       value = CLAMP (icon_view->priv->hadjustment->value + offset, 
4082                      icon_view->priv->hadjustment->lower,
4083                      icon_view->priv->hadjustment->upper - icon_view->priv->hadjustment->page_size);
4084       gtk_adjustment_set_value (icon_view->priv->hadjustment, value);
4085
4086       gtk_adjustment_changed (icon_view->priv->hadjustment);
4087       gtk_adjustment_changed (icon_view->priv->vadjustment);
4088     }
4089   else
4090     gtk_icon_view_scroll_to_item (icon_view, item);
4091 }
4092
4093
4094 static void     
4095 gtk_icon_view_scroll_to_item (GtkIconView     *icon_view, 
4096                               GtkIconViewItem *item)
4097 {
4098   gint x, y, width, height;
4099   gint focus_width;
4100
4101   gtk_widget_style_get (GTK_WIDGET (icon_view),
4102                         "focus-line-width", &focus_width,
4103                         NULL);
4104
4105   gdk_drawable_get_size (GDK_DRAWABLE (icon_view->priv->bin_window), 
4106                          &width, &height);
4107   gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4108   
4109   if (y + item->y - focus_width < 0)
4110     gtk_adjustment_set_value (icon_view->priv->vadjustment, 
4111                               icon_view->priv->vadjustment->value + y + item->y - focus_width);
4112   else if (y + item->y + item->height + focus_width > GTK_WIDGET (icon_view)->allocation.height)
4113     gtk_adjustment_set_value (icon_view->priv->vadjustment, 
4114                               icon_view->priv->vadjustment->value + y + item->y + item->height 
4115                               + focus_width - GTK_WIDGET (icon_view)->allocation.height);
4116
4117   if (x + item->x - focus_width < 0)
4118     gtk_adjustment_set_value (icon_view->priv->hadjustment, 
4119                               icon_view->priv->hadjustment->value + x + item->x - focus_width);
4120   else if (x + item->x + item->width + focus_width > GTK_WIDGET (icon_view)->allocation.width)
4121     gtk_adjustment_set_value (icon_view->priv->hadjustment, 
4122                               icon_view->priv->hadjustment->value + x + item->x + item->width 
4123                               + focus_width - GTK_WIDGET (icon_view)->allocation.width);
4124
4125   gtk_adjustment_changed (icon_view->priv->hadjustment);
4126   gtk_adjustment_changed (icon_view->priv->vadjustment);
4127 }
4128
4129 /* GtkCellLayout implementation */
4130 static GtkIconViewCellInfo *
4131 gtk_icon_view_get_cell_info (GtkIconView     *icon_view,
4132                              GtkCellRenderer *renderer)
4133 {
4134   GList *i;
4135
4136   for (i = icon_view->priv->cell_list; i; i = i->next)
4137     {
4138       GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)i->data;
4139
4140       if (info->cell == renderer)
4141         return info;
4142     }
4143
4144   return NULL;
4145 }
4146
4147 static void
4148 gtk_icon_view_set_cell_data (GtkIconView     *icon_view, 
4149                              GtkIconViewItem *item)
4150 {
4151   GList *i;
4152   gboolean iters_persist;
4153   GtkTreeIter iter;
4154   
4155   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
4156   
4157   if (!iters_persist)
4158     {
4159       GtkTreePath *path;
4160
4161       path = gtk_tree_path_new_from_indices (item->index, -1);
4162       if (!gtk_tree_model_get_iter (icon_view->priv->model, &iter, path))
4163         return;
4164       gtk_tree_path_free (path);
4165     }
4166   else
4167     iter = item->iter;
4168   
4169   for (i = icon_view->priv->cell_list; i; i = i->next)
4170     {
4171       GSList *j;
4172       GtkIconViewCellInfo *info = i->data;
4173
4174       g_object_freeze_notify (G_OBJECT (info->cell));
4175
4176       for (j = info->attributes; j && j->next; j = j->next->next)
4177         {
4178           gchar *property = j->data;
4179           gint column = GPOINTER_TO_INT (j->next->data);
4180           GValue value = {0, };
4181
4182           gtk_tree_model_get_value (icon_view->priv->model, &iter,
4183                                     column, &value);
4184           g_object_set_property (G_OBJECT (info->cell),
4185                                  property, &value);
4186           g_value_unset (&value);
4187         }
4188
4189       if (info->func)
4190         (* info->func) (GTK_CELL_LAYOUT (icon_view),
4191                         info->cell,
4192                         icon_view->priv->model,
4193                         &iter,
4194                         info->func_data);
4195       
4196       g_object_thaw_notify (G_OBJECT (info->cell));
4197     }  
4198   
4199   adjust_wrap_width (icon_view, item);
4200 }
4201
4202 static void 
4203 free_cell_attributes (GtkIconViewCellInfo *info)
4204
4205   GSList *list;
4206
4207   list = info->attributes;
4208   while (list && list->next)
4209     {
4210       g_free (list->data);
4211       list = list->next->next;
4212     }
4213   
4214   g_slist_free (info->attributes);
4215   info->attributes = NULL;
4216 }
4217
4218 static void
4219 free_cell_info (GtkIconViewCellInfo *info)
4220 {
4221   free_cell_attributes (info);
4222
4223   g_object_unref (info->cell);
4224   
4225   if (info->destroy)
4226     (* info->destroy) (info->func_data);
4227
4228   g_free (info);
4229 }
4230
4231 static void
4232 gtk_icon_view_cell_layout_pack_start (GtkCellLayout   *layout,
4233                                       GtkCellRenderer *renderer,
4234                                       gboolean         expand)
4235 {
4236   GtkIconViewCellInfo *info;
4237   GtkIconView *icon_view = GTK_ICON_VIEW (layout);
4238
4239   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
4240   g_return_if_fail (!gtk_icon_view_get_cell_info (icon_view, renderer));
4241
4242   g_object_ref_sink (renderer);
4243
4244   info = g_new0 (GtkIconViewCellInfo, 1);
4245   info->cell = renderer;
4246   info->expand = expand ? TRUE : FALSE;
4247   info->pack = GTK_PACK_START;
4248   info->position = icon_view->priv->n_cells;
4249   
4250   icon_view->priv->cell_list = g_list_append (icon_view->priv->cell_list, info);
4251   icon_view->priv->n_cells++;
4252 }
4253
4254 static void
4255 gtk_icon_view_cell_layout_pack_end (GtkCellLayout   *layout,
4256                                     GtkCellRenderer *renderer,
4257                                     gboolean         expand)
4258 {
4259   GtkIconViewCellInfo *info;
4260   GtkIconView *icon_view = GTK_ICON_VIEW (layout);
4261
4262   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
4263   g_return_if_fail (!gtk_icon_view_get_cell_info (icon_view, renderer));
4264
4265   g_object_ref_sink (renderer);
4266
4267   info = g_new0 (GtkIconViewCellInfo, 1);
4268   info->cell = renderer;
4269   info->expand = expand ? TRUE : FALSE;
4270   info->pack = GTK_PACK_END;
4271   info->position = icon_view->priv->n_cells;
4272
4273   icon_view->priv->cell_list = g_list_append (icon_view->priv->cell_list, info);
4274   icon_view->priv->n_cells++;
4275 }
4276
4277 static void
4278 gtk_icon_view_cell_layout_add_attribute (GtkCellLayout   *layout,
4279                                          GtkCellRenderer *renderer,
4280                                          const gchar     *attribute,
4281                                          gint             column)
4282 {
4283   GtkIconViewCellInfo *info;
4284   GtkIconView *icon_view = GTK_ICON_VIEW (layout);
4285
4286   info = gtk_icon_view_get_cell_info (icon_view, renderer);
4287   g_return_if_fail (info != NULL);
4288
4289   info->attributes = g_slist_prepend (info->attributes,
4290                                       GINT_TO_POINTER (column));
4291   info->attributes = g_slist_prepend (info->attributes,
4292                                       g_strdup (attribute));
4293 }
4294
4295 static void
4296 gtk_icon_view_cell_layout_clear (GtkCellLayout *layout)
4297 {
4298   GtkIconView *icon_view = GTK_ICON_VIEW (layout);
4299
4300   while (icon_view->priv->cell_list)
4301     {
4302       GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)icon_view->priv->cell_list->data;
4303       free_cell_info (info);
4304       icon_view->priv->cell_list = g_list_delete_link (icon_view->priv->cell_list, 
4305                                                        icon_view->priv->cell_list);
4306     }
4307
4308   icon_view->priv->n_cells = 0;
4309 }
4310
4311 static void
4312 gtk_icon_view_cell_layout_set_cell_data_func (GtkCellLayout         *layout,
4313                                               GtkCellRenderer       *cell,
4314                                               GtkCellLayoutDataFunc  func,
4315                                               gpointer               func_data,
4316                                               GDestroyNotify         destroy)
4317 {
4318   GtkIconViewCellInfo *info;
4319   GtkIconView *icon_view = GTK_ICON_VIEW (layout);
4320
4321   info = gtk_icon_view_get_cell_info (icon_view, cell);
4322   g_return_if_fail (info != NULL);
4323
4324   if (info->destroy)
4325     {
4326       GDestroyNotify d = info->destroy;
4327
4328       info->destroy = NULL;
4329       d (info->func_data);
4330     }
4331
4332   info->func = func;
4333   info->func_data = func_data;
4334   info->destroy = destroy;
4335 }
4336
4337 static void
4338 gtk_icon_view_cell_layout_clear_attributes (GtkCellLayout   *layout,
4339                                             GtkCellRenderer *renderer)
4340 {
4341   GtkIconViewCellInfo *info;
4342
4343   info = gtk_icon_view_get_cell_info (GTK_ICON_VIEW (layout), renderer);
4344   if (info != NULL)
4345     free_cell_attributes (info);
4346 }
4347
4348 static void
4349 gtk_icon_view_cell_layout_reorder (GtkCellLayout   *layout,
4350                                    GtkCellRenderer *cell,
4351                                    gint             position)
4352 {
4353   GtkIconView *icon_view;
4354   GList *link, *l;
4355   GtkIconViewCellInfo *info;
4356   gint i;
4357
4358   icon_view = GTK_ICON_VIEW (layout);
4359
4360   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
4361
4362   info = gtk_icon_view_get_cell_info (icon_view, cell);
4363
4364   g_return_if_fail (info != NULL);
4365   g_return_if_fail (position >= 0);
4366
4367   link = g_list_find (icon_view->priv->cell_list, info);
4368
4369   g_return_if_fail (link != NULL);
4370
4371   icon_view->priv->cell_list = g_list_remove_link (icon_view->priv->cell_list,
4372                                                   link);
4373   icon_view->priv->cell_list = g_list_insert (icon_view->priv->cell_list,
4374                                              info, position);
4375
4376   for (l = icon_view->priv->cell_list, i = 0; l; l = l->next, i++)
4377     {
4378       info = l->data;
4379
4380       info->position = i;
4381     }
4382
4383   gtk_widget_queue_draw (GTK_WIDGET (icon_view));
4384 }
4385
4386 static GList *
4387 gtk_icon_view_cell_layout_get_cells (GtkCellLayout *layout)
4388 {
4389   GtkIconView *icon_view = (GtkIconView *)layout;
4390   GList *retval = NULL, *l;
4391
4392   for (l = icon_view->priv->cell_list; l; l = l->next)
4393     {
4394       GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
4395
4396       retval = g_list_prepend (retval, info->cell);
4397     }
4398
4399   return g_list_reverse (retval);
4400 }
4401
4402 /* Public API */
4403
4404
4405 /**
4406  * gtk_icon_view_new:
4407  * 
4408  * Creates a new #GtkIconView widget
4409  * 
4410  * Return value: A newly created #GtkIconView widget
4411  *
4412  * Since: 2.6
4413  **/
4414 GtkWidget *
4415 gtk_icon_view_new (void)
4416 {
4417   return g_object_new (GTK_TYPE_ICON_VIEW, NULL);
4418 }
4419
4420 /**
4421  * gtk_icon_view_new_with_model:
4422  * @model: The model.
4423  * 
4424  * Creates a new #GtkIconView widget with the model @model.
4425  * 
4426  * Return value: A newly created #GtkIconView widget.
4427  *
4428  * Since: 2.6 
4429  **/
4430 GtkWidget *
4431 gtk_icon_view_new_with_model (GtkTreeModel *model)
4432 {
4433   return g_object_new (GTK_TYPE_ICON_VIEW, "model", model, NULL);
4434 }
4435
4436
4437 /**
4438  * gtk_icon_view_get_path_at_pos:
4439  * @icon_view: A #GtkIconView.
4440  * @x: The x position to be identified
4441  * @y: The y position to be identified
4442  * 
4443  * Finds the path at the point (@x, @y), relative to widget coordinates.
4444  * See gtk_icon_view_get_item_at_pos(), if you are also interested in
4445  * the cell at the specified position.
4446  * 
4447  * Return value: The #GtkTreePath corresponding to the icon or %NULL
4448  * if no icon exists at that position.
4449  *
4450  * Since: 2.6 
4451  **/
4452 GtkTreePath *
4453 gtk_icon_view_get_path_at_pos (GtkIconView *icon_view,
4454                                gint         x,
4455                                gint         y)
4456 {
4457   GtkIconViewItem *item;
4458   GtkTreePath *path;
4459   
4460   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
4461
4462   item = gtk_icon_view_get_item_at_coords (icon_view, x, y, TRUE, NULL);
4463
4464   if (!item)
4465     return NULL;
4466
4467   path = gtk_tree_path_new_from_indices (item->index, -1);
4468
4469   return path;
4470 }
4471
4472 /**
4473  * gtk_icon_view_get_item_at_pos:
4474  * @icon_view: A #GtkIconView.
4475  * @x: The x position to be identified
4476  * @y: The y position to be identified
4477  * @path: Return location for the path, or %NULL
4478  * @cell: Return location for the renderer responsible for the cell
4479  *   at (@x, @y), or %NULL
4480  * 
4481  * Finds the path at the point (@x, @y), relative to widget coordinates.
4482  * In contrast to gtk_icon_view_get_path_at_pos(), this function also 
4483  * obtains the cell at the specified position. The returned path should
4484  * be freed with gtk_tree_path_free().
4485  * 
4486  * Return value: %TRUE if an item exists at the specified position
4487  *
4488  * Since: 2.8
4489  **/
4490 gboolean 
4491 gtk_icon_view_get_item_at_pos (GtkIconView      *icon_view,
4492                                gint              x,
4493                                gint              y,
4494                                GtkTreePath     **path,
4495                                GtkCellRenderer **cell)
4496 {
4497   GtkIconViewItem *item;
4498   GtkIconViewCellInfo *info;
4499   
4500   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
4501
4502   item = gtk_icon_view_get_item_at_coords (icon_view, x, y, TRUE, &info);
4503
4504   if (path != NULL)
4505     {
4506       if (item != NULL)
4507         *path = gtk_tree_path_new_from_indices (item->index, -1);
4508       else
4509         *path = NULL;
4510     }
4511
4512   if (cell != NULL)
4513     {
4514       if (info != NULL)
4515         *cell = info->cell;
4516       else 
4517         *cell = NULL;
4518     }
4519
4520   return (item != NULL);
4521 }
4522
4523
4524 /**
4525  * gtk_icon_view_get_visible_range:
4526  * @icon_view: A #GtkIconView
4527  * @start_path: Return location for start of region, or %NULL
4528  * @end_path: Return location for end of region, or %NULL
4529  * 
4530  * Sets @start_path and @end_path to be the first and last visible path. 
4531  * Note that there may be invisible paths in between.
4532  * 
4533  * Both paths should be freed with gtk_tree_path_free() after use.
4534  * 
4535  * Return value: %TRUE, if valid paths were placed in @start_path and @end_path
4536  *
4537  * Since: 2.8
4538  **/
4539 gboolean
4540 gtk_icon_view_get_visible_range (GtkIconView  *icon_view,
4541                                  GtkTreePath **start_path,
4542                                  GtkTreePath **end_path)
4543 {
4544   gint start_index = -1;
4545   gint end_index = -1;
4546   GList *icons;
4547
4548   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
4549
4550   if (icon_view->priv->hadjustment == NULL ||
4551       icon_view->priv->vadjustment == NULL)
4552     return FALSE;
4553
4554   if (start_path == NULL && end_path == NULL)
4555     return FALSE;
4556   
4557   for (icons = icon_view->priv->items; icons; icons = icons->next) 
4558     {
4559       GtkIconViewItem *item = icons->data;
4560
4561       if ((item->x + item->width >= (int)icon_view->priv->hadjustment->value) &&
4562           (item->y + item->height >= (int)icon_view->priv->vadjustment->value) &&
4563           (item->x <= (int) (icon_view->priv->hadjustment->value + icon_view->priv->hadjustment->page_size)) &&
4564           (item->y <= (int) (icon_view->priv->vadjustment->value + icon_view->priv->vadjustment->page_size)))
4565         {
4566           if (start_index == -1)
4567             start_index = item->index;
4568           end_index = item->index;
4569         }
4570     }
4571
4572   if (start_path && start_index != -1)
4573     *start_path = gtk_tree_path_new_from_indices (start_index, -1);
4574   if (end_path && end_index != -1)
4575     *end_path = gtk_tree_path_new_from_indices (end_index, -1);
4576   
4577   return start_index != -1;
4578 }
4579
4580 /**
4581  * gtk_icon_view_selected_foreach:
4582  * @icon_view: A #GtkIconView.
4583  * @func: The funcion to call for each selected icon.
4584  * @data: User data to pass to the function.
4585  * 
4586  * Calls a function for each selected icon. Note that the model or
4587  * selection cannot be modified from within this function.
4588  *
4589  * Since: 2.6 
4590  **/
4591 void
4592 gtk_icon_view_selected_foreach (GtkIconView           *icon_view,
4593                                 GtkIconViewForeachFunc func,
4594                                 gpointer               data)
4595 {
4596   GList *list;
4597   
4598   for (list = icon_view->priv->items; list; list = list->next)
4599     {
4600       GtkIconViewItem *item = list->data;
4601       GtkTreePath *path = gtk_tree_path_new_from_indices (item->index, -1);
4602
4603       if (item->selected)
4604         (* func) (icon_view, path, data);
4605
4606       gtk_tree_path_free (path);
4607     }
4608 }
4609
4610 /**
4611  * gtk_icon_view_set_selection_mode:
4612  * @icon_view: A #GtkIconView.
4613  * @mode: The selection mode
4614  * 
4615  * Sets the selection mode of the @icon_view.
4616  *
4617  * Since: 2.6 
4618  **/
4619 void
4620 gtk_icon_view_set_selection_mode (GtkIconView      *icon_view,
4621                                   GtkSelectionMode  mode)
4622 {
4623   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4624
4625   if (mode == icon_view->priv->selection_mode)
4626     return;
4627   
4628   if (mode == GTK_SELECTION_NONE ||
4629       icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE)
4630     gtk_icon_view_unselect_all (icon_view);
4631   
4632   icon_view->priv->selection_mode = mode;
4633
4634   g_object_notify (G_OBJECT (icon_view), "selection-mode");
4635 }
4636
4637 /**
4638  * gtk_icon_view_get_selection_mode:
4639  * @icon_view: A #GtkIconView.
4640  * 
4641  * Gets the selection mode of the @icon_view.
4642  *
4643  * Return value: the current selection mode
4644  *
4645  * Since: 2.6 
4646  **/
4647 GtkSelectionMode
4648 gtk_icon_view_get_selection_mode (GtkIconView *icon_view)
4649 {
4650   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), GTK_SELECTION_SINGLE);
4651
4652   return icon_view->priv->selection_mode;
4653 }
4654
4655 /**
4656  * gtk_icon_view_set_model:
4657  * @icon_view: A #GtkIconView.
4658  * @model: The model.
4659  *
4660  * Sets the model for a #GtkIconView.  
4661  * If the @icon_view already has a model set, it will remove 
4662  * it before setting the new model.  If @model is %NULL, then
4663  * it will unset the old model.
4664  *
4665  * Since: 2.6 
4666  **/
4667 void
4668 gtk_icon_view_set_model (GtkIconView *icon_view,
4669                          GtkTreeModel *model)
4670 {
4671   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4672   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
4673   
4674   if (icon_view->priv->model == model)
4675     return;
4676
4677   if (icon_view->priv->scroll_to_path)
4678     {
4679       gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
4680       icon_view->priv->scroll_to_path = NULL;
4681     }
4682
4683   gtk_icon_view_stop_editing (icon_view, TRUE);
4684
4685   if (model)
4686     {
4687       GType column_type;
4688       
4689       g_return_if_fail (gtk_tree_model_get_flags (model) & GTK_TREE_MODEL_LIST_ONLY);
4690
4691       if (icon_view->priv->pixbuf_column != -1)
4692         {
4693           column_type = gtk_tree_model_get_column_type (model,
4694                                                         icon_view->priv->pixbuf_column);          
4695
4696           g_return_if_fail (column_type == GDK_TYPE_PIXBUF);
4697         }
4698
4699       if (icon_view->priv->text_column != -1)
4700         {
4701           column_type = gtk_tree_model_get_column_type (model,
4702                                                         icon_view->priv->text_column);    
4703
4704           g_return_if_fail (column_type == G_TYPE_STRING);
4705         }
4706
4707       if (icon_view->priv->markup_column != -1)
4708         {
4709           column_type = gtk_tree_model_get_column_type (model,
4710                                                         icon_view->priv->markup_column);          
4711
4712           g_return_if_fail (column_type == G_TYPE_STRING);
4713         }
4714       
4715     }
4716   
4717   if (icon_view->priv->model)
4718     {
4719       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
4720                                             gtk_icon_view_row_changed,
4721                                             icon_view);
4722       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
4723                                             gtk_icon_view_row_inserted,
4724                                             icon_view);
4725       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
4726                                             gtk_icon_view_row_deleted,
4727                                             icon_view);
4728       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
4729                                             gtk_icon_view_rows_reordered,
4730                                             icon_view);
4731
4732       g_object_unref (icon_view->priv->model);
4733       
4734       g_list_foreach (icon_view->priv->items, (GFunc)gtk_icon_view_item_free, NULL);
4735       g_list_free (icon_view->priv->items);
4736       icon_view->priv->items = NULL;
4737       icon_view->priv->anchor_item = NULL;
4738       icon_view->priv->cursor_item = NULL;
4739       icon_view->priv->last_single_clicked = NULL;
4740       icon_view->priv->width = 0;
4741       icon_view->priv->height = 0;
4742     }
4743
4744   icon_view->priv->model = model;
4745
4746   if (icon_view->priv->model)
4747     {
4748       g_object_ref (icon_view->priv->model);
4749       g_signal_connect (icon_view->priv->model,
4750                         "row_changed",
4751                         G_CALLBACK (gtk_icon_view_row_changed),
4752                         icon_view);
4753       g_signal_connect (icon_view->priv->model,
4754                         "row_inserted",
4755                         G_CALLBACK (gtk_icon_view_row_inserted),
4756                         icon_view);
4757       g_signal_connect (icon_view->priv->model,
4758                         "row_deleted",
4759                         G_CALLBACK (gtk_icon_view_row_deleted),
4760                         icon_view);
4761       g_signal_connect (icon_view->priv->model,
4762                         "rows_reordered",
4763                         G_CALLBACK (gtk_icon_view_rows_reordered),
4764                         icon_view);
4765
4766       gtk_icon_view_build_items (icon_view);
4767
4768       gtk_icon_view_queue_layout (icon_view);
4769     }
4770
4771   g_object_notify (G_OBJECT (icon_view), "model");  
4772
4773   if (GTK_WIDGET_REALIZED (icon_view))
4774     gtk_widget_queue_resize (GTK_WIDGET (icon_view));
4775 }
4776
4777 /**
4778  * gtk_icon_view_get_model:
4779  * @icon_view: a #GtkIconView
4780  *
4781  * Returns the model the #GtkIconView is based on.  Returns %NULL if the
4782  * model is unset.
4783  *
4784  * Return value: A #GtkTreeModel, or %NULL if none is currently being used.
4785  *
4786  * Since: 2.6 
4787  **/
4788 GtkTreeModel *
4789 gtk_icon_view_get_model (GtkIconView *icon_view)
4790 {
4791   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
4792
4793   return icon_view->priv->model;
4794 }
4795
4796 static void
4797 update_text_cell (GtkIconView *icon_view)
4798 {
4799   GtkIconViewCellInfo *info;
4800   GList *l;
4801   gint i;
4802           
4803   if (icon_view->priv->text_column == -1 &&
4804       icon_view->priv->markup_column == -1)
4805     {
4806       if (icon_view->priv->text_cell != -1)
4807         {
4808           if (icon_view->priv->pixbuf_cell > icon_view->priv->text_cell)
4809             icon_view->priv->pixbuf_cell--;
4810
4811           info = g_list_nth_data (icon_view->priv->cell_list, 
4812                                   icon_view->priv->text_cell);
4813           
4814           icon_view->priv->cell_list = g_list_remove (icon_view->priv->cell_list, info);
4815           
4816           free_cell_info (info);
4817           
4818           icon_view->priv->n_cells--;
4819           icon_view->priv->text_cell = -1;
4820         }
4821     }
4822   else 
4823     {
4824       if (icon_view->priv->text_cell == -1)
4825         {
4826           GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
4827           gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (icon_view), cell, FALSE);
4828           for (l = icon_view->priv->cell_list, i = 0; l; l = l->next, i++)
4829             {
4830               info = l->data;
4831               if (info->cell == cell)
4832                 {
4833                   icon_view->priv->text_cell = i;
4834                   break;
4835                 }
4836             }
4837         }
4838       
4839       info = g_list_nth_data (icon_view->priv->cell_list,
4840                               icon_view->priv->text_cell);
4841
4842       if (icon_view->priv->markup_column != -1)
4843         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
4844                                         info->cell, 
4845                                         "markup", icon_view->priv->markup_column, 
4846                                         NULL);
4847       else
4848         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
4849                                         info->cell, 
4850                                         "text", icon_view->priv->text_column, 
4851                                         NULL);
4852
4853       if (icon_view->priv->orientation == GTK_ORIENTATION_VERTICAL)
4854         g_object_set (info->cell,
4855                       "alignment", PANGO_ALIGN_CENTER,
4856                       "wrap-mode", PANGO_WRAP_WORD,
4857                       "wrap-width", icon_view->priv->item_width,
4858                       "xalign", 0.0,
4859                       "yalign", 0.0,
4860                       NULL);
4861       else
4862         g_object_set (info->cell,
4863                       "alignment", PANGO_ALIGN_LEFT,
4864                       "wrap-mode", PANGO_WRAP_WORD,
4865                       "wrap-width", icon_view->priv->item_width,
4866                       "xalign", 0.0,
4867                       "yalign", 0.0,
4868                       NULL);
4869     }
4870 }
4871
4872 static void
4873 update_pixbuf_cell (GtkIconView *icon_view)
4874 {
4875   GtkIconViewCellInfo *info;
4876   GList *l;
4877   gint i;
4878
4879   if (icon_view->priv->pixbuf_column == -1)
4880     {
4881       if (icon_view->priv->pixbuf_cell != -1)
4882         {
4883           if (icon_view->priv->text_cell > icon_view->priv->pixbuf_cell)
4884             icon_view->priv->text_cell--;
4885
4886           info = g_list_nth_data (icon_view->priv->cell_list, 
4887                                   icon_view->priv->pixbuf_cell);
4888           
4889           icon_view->priv->cell_list = g_list_remove (icon_view->priv->cell_list, info);
4890           
4891           free_cell_info (info);
4892           
4893           icon_view->priv->n_cells--;
4894           icon_view->priv->pixbuf_cell = -1;
4895         }
4896     }
4897   else 
4898     {
4899       if (icon_view->priv->pixbuf_cell == -1)
4900         {
4901           GtkCellRenderer *cell = gtk_cell_renderer_pixbuf_new ();
4902           
4903           gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (icon_view), cell, FALSE);
4904           for (l = icon_view->priv->cell_list, i = 0; l; l = l->next, i++)
4905             {
4906               info = l->data;
4907               if (info->cell == cell)
4908                 {
4909                   icon_view->priv->pixbuf_cell = i;
4910                   break;
4911                 }
4912             }
4913         }
4914       
4915         info = g_list_nth_data (icon_view->priv->cell_list, 
4916                                 icon_view->priv->pixbuf_cell);
4917         
4918         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
4919                                         info->cell, 
4920                                         "pixbuf", icon_view->priv->pixbuf_column, 
4921                                         NULL);
4922
4923         if (icon_view->priv->orientation == GTK_ORIENTATION_VERTICAL)
4924           g_object_set (info->cell,
4925                         "follow-state", TRUE, 
4926                         "xalign", 0.5,
4927                         "yalign", 1.0,
4928                         NULL);
4929         else
4930           g_object_set (info->cell,
4931                         "follow-state", TRUE, 
4932                         "xalign", 0.0,
4933                         "yalign", 0.0,
4934                         NULL);
4935     }
4936 }
4937
4938 /**
4939  * gtk_icon_view_set_text_column:
4940  * @icon_view: A #GtkIconView.
4941  * @column: A column in the currently used model, or -1 to display no text
4942  * 
4943  * Sets the column with text for @icon_view to be @column. The text
4944  * column must be of type #G_TYPE_STRING.
4945  *
4946  * Since: 2.6 
4947  **/
4948 void
4949 gtk_icon_view_set_text_column (GtkIconView *icon_view,
4950                                gint          column)
4951 {
4952   if (column == icon_view->priv->text_column)
4953     return;
4954   
4955   if (column == -1)
4956     icon_view->priv->text_column = -1;
4957   else
4958     {
4959       if (icon_view->priv->model != NULL)
4960         {
4961           GType column_type;
4962           
4963           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
4964
4965           g_return_if_fail (column_type == G_TYPE_STRING);
4966         }
4967       
4968       icon_view->priv->text_column = column;
4969     }
4970
4971   gtk_icon_view_stop_editing (icon_view, TRUE);
4972
4973   update_text_cell (icon_view);
4974
4975   gtk_icon_view_invalidate_sizes (icon_view);
4976   gtk_icon_view_queue_layout (icon_view);
4977   
4978   g_object_notify (G_OBJECT (icon_view), "text-column");
4979 }
4980
4981 /**
4982  * gtk_icon_view_get_text_column:
4983  * @icon_view: A #GtkIconView.
4984  *
4985  * Returns the column with text for @icon_view.
4986  *
4987  * Returns: the text column, or -1 if it's unset.
4988  *
4989  * Since: 2.6
4990  */
4991 gint
4992 gtk_icon_view_get_text_column (GtkIconView  *icon_view)
4993 {
4994   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
4995
4996   return icon_view->priv->text_column;
4997 }
4998
4999 /**
5000  * gtk_icon_view_set_markup_column:
5001  * @icon_view: A #GtkIconView.
5002  * @column: A column in the currently used model, or -1 to display no text
5003  * 
5004  * Sets the column with markup information for @icon_view to be
5005  * @column. The markup column must be of type #G_TYPE_STRING.
5006  * If the markup column is set to something, it overrides
5007  * the text column set by gtk_icon_view_set_text_column().
5008  *
5009  * Since: 2.6
5010  **/
5011 void
5012 gtk_icon_view_set_markup_column (GtkIconView *icon_view,
5013                                  gint         column)
5014 {
5015   if (column == icon_view->priv->markup_column)
5016     return;
5017   
5018   if (column == -1)
5019     icon_view->priv->markup_column = -1;
5020   else
5021     {
5022       if (icon_view->priv->model != NULL)
5023         {
5024           GType column_type;
5025           
5026           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
5027
5028           g_return_if_fail (column_type == G_TYPE_STRING);
5029         }
5030       
5031       icon_view->priv->markup_column = column;
5032     }
5033
5034   gtk_icon_view_stop_editing (icon_view, TRUE);
5035
5036   update_text_cell (icon_view);
5037
5038   gtk_icon_view_invalidate_sizes (icon_view);
5039   gtk_icon_view_queue_layout (icon_view);
5040   
5041   g_object_notify (G_OBJECT (icon_view), "markup-column");
5042 }
5043
5044 /**
5045  * gtk_icon_view_get_markup_column:
5046  * @icon_view: A #GtkIconView.
5047  *
5048  * Returns the column with markup text for @icon_view.
5049  *
5050  * Returns: the markup column, or -1 if it's unset.
5051  *
5052  * Since: 2.6
5053  */
5054 gint
5055 gtk_icon_view_get_markup_column (GtkIconView  *icon_view)
5056 {
5057   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5058
5059   return icon_view->priv->markup_column;
5060 }
5061
5062 /**
5063  * gtk_icon_view_set_pixbuf_column:
5064  * @icon_view: A #GtkIconView.
5065  * @column: A column in the currently used model, or -1 to disable
5066  * 
5067  * Sets the column with pixbufs for @icon_view to be @column. The pixbuf
5068  * column must be of type #GDK_TYPE_PIXBUF
5069  *
5070  * Since: 2.6 
5071  **/
5072 void
5073 gtk_icon_view_set_pixbuf_column (GtkIconView *icon_view,
5074                                  gint         column)
5075 {
5076   if (column == icon_view->priv->pixbuf_column)
5077     return;
5078   
5079   if (column == -1)
5080     icon_view->priv->pixbuf_column = -1;
5081   else
5082     {
5083       if (icon_view->priv->model != NULL)
5084         {
5085           GType column_type;
5086           
5087           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
5088
5089           g_return_if_fail (column_type == GDK_TYPE_PIXBUF);
5090         }
5091       
5092       icon_view->priv->pixbuf_column = column;
5093     }
5094
5095   gtk_icon_view_stop_editing (icon_view, TRUE);
5096
5097   update_pixbuf_cell (icon_view);
5098
5099   gtk_icon_view_invalidate_sizes (icon_view);
5100   gtk_icon_view_queue_layout (icon_view);
5101   
5102   g_object_notify (G_OBJECT (icon_view), "pixbuf-column");
5103   
5104 }
5105
5106 /**
5107  * gtk_icon_view_get_pixbuf_column:
5108  * @icon_view: A #GtkIconView.
5109  *
5110  * Returns the column with pixbufs for @icon_view.
5111  *
5112  * Returns: the pixbuf column, or -1 if it's unset.
5113  *
5114  * Since: 2.6
5115  */
5116 gint
5117 gtk_icon_view_get_pixbuf_column (GtkIconView  *icon_view)
5118 {
5119   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5120
5121   return icon_view->priv->pixbuf_column;
5122 }
5123
5124 /**
5125  * gtk_icon_view_select_path:
5126  * @icon_view: A #GtkIconView.
5127  * @path: The #GtkTreePath to be selected.
5128  * 
5129  * Selects the row at @path.
5130  *
5131  * Since: 2.6
5132  **/
5133 void
5134 gtk_icon_view_select_path (GtkIconView *icon_view,
5135                            GtkTreePath *path)
5136 {
5137   GtkIconViewItem *item = NULL;
5138
5139   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5140   g_return_if_fail (icon_view->priv->model != NULL);
5141   g_return_if_fail (path != NULL);
5142
5143   if (gtk_tree_path_get_depth (path) > 0)
5144     item = g_list_nth_data (icon_view->priv->items,
5145                             gtk_tree_path_get_indices(path)[0]);
5146
5147   if (item)
5148     gtk_icon_view_select_item (icon_view, item);
5149 }
5150
5151 /**
5152  * gtk_icon_view_unselect_path:
5153  * @icon_view: A #GtkIconView.
5154  * @path: The #GtkTreePath to be unselected.
5155  * 
5156  * Unselects the row at @path.
5157  *
5158  * Since: 2.6
5159  **/
5160 void
5161 gtk_icon_view_unselect_path (GtkIconView *icon_view,
5162                              GtkTreePath *path)
5163 {
5164   GtkIconViewItem *item;
5165   
5166   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5167   g_return_if_fail (icon_view->priv->model != NULL);
5168   g_return_if_fail (path != NULL);
5169
5170   item = g_list_nth_data (icon_view->priv->items,
5171                           gtk_tree_path_get_indices(path)[0]);
5172
5173   if (!item)
5174     return;
5175   
5176   gtk_icon_view_unselect_item (icon_view, item);
5177 }
5178
5179 /**
5180  * gtk_icon_view_get_selected_items:
5181  * @icon_view: A #GtkIconView.
5182  *
5183  * Creates a list of paths of all selected items. Additionally, if you are
5184  * planning on modifying the model after calling this function, you may
5185  * want to convert the returned list into a list of #GtkTreeRowReference<!-- -->s.
5186  * To do this, you can use gtk_tree_row_reference_new().
5187  *
5188  * To free the return value, use:
5189  * <informalexample><programlisting>
5190  * g_list_foreach (list, gtk_tree_path_free, NULL);
5191  * g_list_free (list);
5192  * </programlisting></informalexample>
5193  *
5194  * Return value: A #GList containing a #GtkTreePath for each selected row.
5195  *
5196  * Since: 2.6
5197  **/
5198 GList *
5199 gtk_icon_view_get_selected_items (GtkIconView *icon_view)
5200 {
5201   GList *list;
5202   GList *selected = NULL;
5203   
5204   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
5205   
5206   for (list = icon_view->priv->items; list != NULL; list = list->next)
5207     {
5208       GtkIconViewItem *item = list->data;
5209
5210       if (item->selected)
5211         {
5212           GtkTreePath *path = gtk_tree_path_new_from_indices (item->index, -1);
5213
5214           selected = g_list_prepend (selected, path);
5215         }
5216     }
5217
5218   return selected;
5219 }
5220
5221 /**
5222  * gtk_icon_view_select_all:
5223  * @icon_view: A #GtkIconView.
5224  * 
5225  * Selects all the icons. @icon_view must has its selection mode set
5226  * to #GTK_SELECTION_MULTIPLE.
5227  *
5228  * Since: 2.6
5229  **/
5230 void
5231 gtk_icon_view_select_all (GtkIconView *icon_view)
5232 {
5233   GList *items;
5234   gboolean dirty = FALSE;
5235   
5236   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5237
5238   if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
5239     return;
5240
5241   for (items = icon_view->priv->items; items; items = items->next)
5242     {
5243       GtkIconViewItem *item = items->data;
5244       
5245       if (!item->selected)
5246         {
5247           dirty = TRUE;
5248           item->selected = TRUE;
5249           gtk_icon_view_queue_draw_item (icon_view, item);
5250         }
5251     }
5252
5253   if (dirty)
5254     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
5255 }
5256
5257 /**
5258  * gtk_icon_view_unselect_all:
5259  * @icon_view: A #GtkIconView.
5260  * 
5261  * Unselects all the icons.
5262  *
5263  * Since: 2.6
5264  **/
5265 void
5266 gtk_icon_view_unselect_all (GtkIconView *icon_view)
5267 {
5268   gboolean dirty = FALSE;
5269   
5270   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5271
5272   if (icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
5273     return;
5274
5275   dirty = gtk_icon_view_unselect_all_internal (icon_view);
5276
5277   if (dirty)
5278     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
5279 }
5280
5281 /**
5282  * gtk_icon_view_path_is_selected:
5283  * @icon_view: A #GtkIconView.
5284  * @path: A #GtkTreePath to check selection on.
5285  * 
5286  * Returns %TRUE if the icon pointed to by @path is currently
5287  * selected. If @path does not point to a valid location, %FALSE is returned.
5288  * 
5289  * Return value: %TRUE if @path is selected.
5290  *
5291  * Since: 2.6
5292  **/
5293 gboolean
5294 gtk_icon_view_path_is_selected (GtkIconView *icon_view,
5295                                 GtkTreePath *path)
5296 {
5297   GtkIconViewItem *item;
5298   
5299   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
5300   g_return_val_if_fail (icon_view->priv->model != NULL, FALSE);
5301   g_return_val_if_fail (path != NULL, FALSE);
5302   
5303   item = g_list_nth_data (icon_view->priv->items,
5304                           gtk_tree_path_get_indices(path)[0]);
5305
5306   if (!item)
5307     return FALSE;
5308   
5309   return item->selected;
5310 }
5311
5312 /**
5313  * gtk_icon_view_item_activated:
5314  * @icon_view: A #GtkIconView
5315  * @path: The #GtkTreePath to be activated
5316  * 
5317  * Activates the item determined by @path.
5318  *
5319  * Since: 2.6
5320  **/
5321 void
5322 gtk_icon_view_item_activated (GtkIconView      *icon_view,
5323                               GtkTreePath      *path)
5324 {
5325   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5326   g_return_if_fail (path != NULL);
5327   
5328   g_signal_emit (icon_view, icon_view_signals[ITEM_ACTIVATED], 0, path);
5329 }
5330
5331 /**
5332  * gtk_icon_view_set_orientation:
5333  * @icon_view: a #GtkIconView
5334  * @orientation: the relative position of texts and icons 
5335  * 
5336  * Sets the ::orientation property which determines whether the labels 
5337  * are drawn beside the icons instead of below.
5338  *
5339  * Since: 2.6
5340  **/
5341 void 
5342 gtk_icon_view_set_orientation (GtkIconView    *icon_view,
5343                                GtkOrientation  orientation)
5344 {
5345   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5346
5347   if (icon_view->priv->orientation != orientation)
5348     {
5349       icon_view->priv->orientation = orientation;
5350
5351       gtk_icon_view_stop_editing (icon_view, TRUE);
5352       gtk_icon_view_invalidate_sizes (icon_view);
5353       gtk_icon_view_queue_layout (icon_view);
5354
5355       update_text_cell (icon_view);
5356       update_pixbuf_cell (icon_view);
5357       
5358       g_object_notify (G_OBJECT (icon_view), "orientation");
5359     }
5360 }
5361
5362 /**
5363  * gtk_icon_view_get_orientation:
5364  * @icon_view: a #GtkIconView
5365  * 
5366  * Returns the value of the ::orientation property which determines 
5367  * whether the labels are drawn beside the icons instead of below. 
5368  * 
5369  * Return value: the relative position of texts and icons 
5370  *
5371  * Since: 2.6
5372  **/
5373 GtkOrientation
5374 gtk_icon_view_get_orientation (GtkIconView *icon_view)
5375 {
5376   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), 
5377                         GTK_ORIENTATION_VERTICAL);
5378
5379   return icon_view->priv->orientation;
5380 }
5381
5382 /**
5383  * gtk_icon_view_set_columns:
5384  * @icon_view: a #GtkIconView
5385  * @columns: the number of columns
5386  * 
5387  * Sets the ::columns property which determines in how
5388  * many columns the icons are arranged. If @columns is
5389  * -1, the number of columns will be chosen automatically 
5390  * to fill the available area. 
5391  *
5392  * Since: 2.6
5393  */
5394 void 
5395 gtk_icon_view_set_columns (GtkIconView *icon_view,
5396                            gint         columns)
5397 {
5398   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5399   
5400   if (icon_view->priv->columns != columns)
5401     {
5402       icon_view->priv->columns = columns;
5403
5404       gtk_icon_view_stop_editing (icon_view, TRUE);
5405       gtk_icon_view_queue_layout (icon_view);
5406       
5407       g_object_notify (G_OBJECT (icon_view), "columns");
5408     }  
5409 }
5410
5411 /**
5412  * gtk_icon_view_get_columns:
5413  * @icon_view: a #GtkIconView
5414  * 
5415  * Returns the value of the ::columns property.
5416  * 
5417  * Return value: the number of columns, or -1
5418  *
5419  * Since: 2.6
5420  */
5421 gint
5422 gtk_icon_view_get_columns (GtkIconView *icon_view)
5423 {
5424   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5425
5426   return icon_view->priv->columns;
5427 }
5428
5429 /**
5430  * gtk_icon_view_set_item_width:
5431  * @icon_view: a #GtkIconView
5432  * @item_width: the width for each item
5433  * 
5434  * Sets the ::item-width property which specifies the width 
5435  * to use for each item. If it is set to -1, the icon view will 
5436  * automatically determine a suitable item size.
5437  *
5438  * Since: 2.6
5439  */
5440 void 
5441 gtk_icon_view_set_item_width (GtkIconView *icon_view,
5442                               gint         item_width)
5443 {
5444   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5445   
5446   if (icon_view->priv->item_width != item_width)
5447     {
5448       icon_view->priv->item_width = item_width;
5449       
5450       gtk_icon_view_stop_editing (icon_view, TRUE);
5451       gtk_icon_view_invalidate_sizes (icon_view);
5452       gtk_icon_view_queue_layout (icon_view);
5453       
5454       update_text_cell (icon_view);
5455
5456       g_object_notify (G_OBJECT (icon_view), "item-width");
5457     }  
5458 }
5459
5460 /**
5461  * gtk_icon_view_get_item_width:
5462  * @icon_view: a #GtkIconView
5463  * 
5464  * Returns the value of the ::item-width property.
5465  * 
5466  * Return value: the width of a single item, or -1
5467  *
5468  * Since: 2.6
5469  */
5470 gint
5471 gtk_icon_view_get_item_width (GtkIconView *icon_view)
5472 {
5473   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5474
5475   return icon_view->priv->item_width;
5476 }
5477
5478
5479 /**
5480  * gtk_icon_view_set_spacing:
5481  * @icon_view: a #GtkIconView
5482  * @spacing: the spacing
5483  * 
5484  * Sets the ::spacing property which specifies the space 
5485  * which is inserted between the cells (i.e. the icon and 
5486  * the text) of an item.
5487  *
5488  * Since: 2.6
5489  */
5490 void 
5491 gtk_icon_view_set_spacing (GtkIconView *icon_view,
5492                            gint         spacing)
5493 {
5494   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5495   
5496   if (icon_view->priv->spacing != spacing)
5497     {
5498       icon_view->priv->spacing = spacing;
5499
5500       gtk_icon_view_stop_editing (icon_view, TRUE);
5501       gtk_icon_view_invalidate_sizes (icon_view);
5502       gtk_icon_view_queue_layout (icon_view);
5503       
5504       g_object_notify (G_OBJECT (icon_view), "spacing");
5505     }  
5506 }
5507
5508 /**
5509  * gtk_icon_view_get_spacing:
5510  * @icon_view: a #GtkIconView
5511  * 
5512  * Returns the value of the ::spacing property.
5513  * 
5514  * Return value: the space between cells 
5515  *
5516  * Since: 2.6
5517  */
5518 gint
5519 gtk_icon_view_get_spacing (GtkIconView *icon_view)
5520 {
5521   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5522
5523   return icon_view->priv->spacing;
5524 }
5525
5526 /**
5527  * gtk_icon_view_set_row_spacing:
5528  * @icon_view: a #GtkIconView
5529  * @row_spacing: the row spacing
5530  * 
5531  * Sets the ::row-spacing property which specifies the space 
5532  * which is inserted between the rows of the icon view.
5533  *
5534  * Since: 2.6
5535  */
5536 void 
5537 gtk_icon_view_set_row_spacing (GtkIconView *icon_view,
5538                                gint         row_spacing)
5539 {
5540   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5541   
5542   if (icon_view->priv->row_spacing != row_spacing)
5543     {
5544       icon_view->priv->row_spacing = row_spacing;
5545
5546       gtk_icon_view_stop_editing (icon_view, TRUE);
5547       gtk_icon_view_invalidate_sizes (icon_view);
5548       gtk_icon_view_queue_layout (icon_view);
5549       
5550       g_object_notify (G_OBJECT (icon_view), "row-spacing");
5551     }  
5552 }
5553
5554 /**
5555  * gtk_icon_view_get_row_spacing:
5556  * @icon_view: a #GtkIconView
5557  * 
5558  * Returns the value of the ::row-spacing property.
5559  * 
5560  * Return value: the space between rows
5561  *
5562  * Since: 2.6
5563  */
5564 gint
5565 gtk_icon_view_get_row_spacing (GtkIconView *icon_view)
5566 {
5567   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5568
5569   return icon_view->priv->row_spacing;
5570 }
5571
5572 /**
5573  * gtk_icon_view_set_column_spacing:
5574  * @icon_view: a #GtkIconView
5575  * @column_spacing: the column spacing
5576  * 
5577  * Sets the ::column-spacing property which specifies the space 
5578  * which is inserted between the columns of the icon view.
5579  *
5580  * Since: 2.6
5581  */
5582 void 
5583 gtk_icon_view_set_column_spacing (GtkIconView *icon_view,
5584                                   gint         column_spacing)
5585 {
5586   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5587   
5588   if (icon_view->priv->column_spacing != column_spacing)
5589     {
5590       icon_view->priv->column_spacing = column_spacing;
5591
5592       gtk_icon_view_stop_editing (icon_view, TRUE);
5593       gtk_icon_view_invalidate_sizes (icon_view);
5594       gtk_icon_view_queue_layout (icon_view);
5595       
5596       g_object_notify (G_OBJECT (icon_view), "column-spacing");
5597     }  
5598 }
5599
5600 /**
5601  * gtk_icon_view_get_column_spacing:
5602  * @icon_view: a #GtkIconView
5603  * 
5604  * Returns the value of the ::column-spacing property.
5605  * 
5606  * Return value: the space between columns
5607  *
5608  * Since: 2.6
5609  */
5610 gint
5611 gtk_icon_view_get_column_spacing (GtkIconView *icon_view)
5612 {
5613   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5614
5615   return icon_view->priv->column_spacing;
5616 }
5617
5618 /**
5619  * gtk_icon_view_set_margin:
5620  * @icon_view: a #GtkIconView
5621  * @margin: the margin
5622  * 
5623  * Sets the ::margin property which specifies the space 
5624  * which is inserted at the top, bottom, left and right 
5625  * of the icon view.
5626  *
5627  * Since: 2.6
5628  */
5629 void 
5630 gtk_icon_view_set_margin (GtkIconView *icon_view,
5631                           gint         margin)
5632 {
5633   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5634   
5635   if (icon_view->priv->margin != margin)
5636     {
5637       icon_view->priv->margin = margin;
5638
5639       gtk_icon_view_stop_editing (icon_view, TRUE);
5640       gtk_icon_view_invalidate_sizes (icon_view);
5641       gtk_icon_view_queue_layout (icon_view);
5642       
5643       g_object_notify (G_OBJECT (icon_view), "margin");
5644     }  
5645 }
5646
5647 /**
5648  * gtk_icon_view_get_margin:
5649  * @icon_view: a #GtkIconView
5650  * 
5651  * Returns the value of the ::margin property.
5652  * 
5653  * Return value: the space at the borders 
5654  *
5655  * Since: 2.6
5656  */
5657 gint
5658 gtk_icon_view_get_margin (GtkIconView *icon_view)
5659 {
5660   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5661
5662   return icon_view->priv->margin;
5663 }
5664
5665
5666 /* Get/set whether drag_motion requested the drag data and
5667  * drag_data_received should thus not actually insert the data,
5668  * since the data doesn't result from a drop.
5669  */
5670 static void
5671 set_status_pending (GdkDragContext *context,
5672                     GdkDragAction   suggested_action)
5673 {
5674   g_object_set_data (G_OBJECT (context),
5675                      I_("gtk-icon-view-status-pending"),
5676                      GINT_TO_POINTER (suggested_action));
5677 }
5678
5679 static GdkDragAction
5680 get_status_pending (GdkDragContext *context)
5681 {
5682   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
5683                                              "gtk-icon-view-status-pending"));
5684 }
5685
5686 static void
5687 unset_reorderable (GtkIconView *icon_view)
5688 {
5689   if (icon_view->priv->reorderable)
5690     {
5691       icon_view->priv->reorderable = FALSE;
5692       g_object_notify (G_OBJECT (icon_view), "reorderable");
5693     }
5694 }
5695
5696 static void
5697 clear_source_info (GtkIconView *icon_view)
5698 {
5699   if (icon_view->priv->source_targets)
5700     gtk_target_list_unref (icon_view->priv->source_targets);
5701   icon_view->priv->source_targets = NULL;
5702
5703   icon_view->priv->source_set = FALSE;
5704 }
5705
5706 static void
5707 clear_dest_info (GtkIconView *icon_view)
5708 {
5709   if (icon_view->priv->dest_targets)
5710     gtk_target_list_unref (icon_view->priv->dest_targets);
5711   icon_view->priv->dest_targets = NULL;
5712
5713   icon_view->priv->dest_set = FALSE;
5714 }
5715
5716 static void
5717 set_source_row (GdkDragContext *context,
5718                 GtkTreeModel   *model,
5719                 GtkTreePath    *source_row)
5720 {
5721   if (source_row)
5722     g_object_set_data_full (G_OBJECT (context),
5723                             I_("gtk-icon-view-source-row"),
5724                             gtk_tree_row_reference_new (model, source_row),
5725                             (GDestroyNotify) gtk_tree_row_reference_free);
5726   else
5727     g_object_set_data_full (G_OBJECT (context),
5728                             I_("gtk-icon-view-source-row"),
5729                             NULL, NULL);
5730 }
5731
5732 static GtkTreePath*
5733 get_source_row (GdkDragContext *context)
5734 {
5735   GtkTreeRowReference *ref;
5736
5737   ref = g_object_get_data (G_OBJECT (context), "gtk-icon-view-source-row");
5738
5739   if (ref)
5740     return gtk_tree_row_reference_get_path (ref);
5741   else
5742     return NULL;
5743 }
5744
5745 typedef struct
5746 {
5747   GtkTreeRowReference *dest_row;
5748   gboolean             empty_view_drop;
5749   gboolean             drop_append_mode;
5750 } DestRow;
5751
5752 static void
5753 dest_row_free (gpointer data)
5754 {
5755   DestRow *dr = (DestRow *)data;
5756
5757   gtk_tree_row_reference_free (dr->dest_row);
5758   g_free (dr);
5759 }
5760
5761 static void
5762 set_dest_row (GdkDragContext *context,
5763               GtkTreeModel   *model,
5764               GtkTreePath    *dest_row,
5765               gboolean        empty_view_drop,
5766               gboolean        drop_append_mode)
5767 {
5768   DestRow *dr;
5769
5770   if (!dest_row)
5771     {
5772       g_object_set_data_full (G_OBJECT (context),
5773                               I_("gtk-icon-view-dest-row"),
5774                               NULL, NULL);
5775       return;
5776     }
5777   
5778   dr = g_new0 (DestRow, 1);
5779      
5780   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
5781   dr->empty_view_drop = empty_view_drop;
5782   dr->drop_append_mode = drop_append_mode;
5783   g_object_set_data_full (G_OBJECT (context),
5784                           I_("gtk-icon-view-dest-row"),
5785                           dr, (GDestroyNotify) dest_row_free);
5786 }
5787
5788 static GtkTreePath*
5789 get_dest_row (GdkDragContext *context)
5790 {
5791   DestRow *dr;
5792
5793   dr = g_object_get_data (G_OBJECT (context), "gtk-icon-view-dest-row");
5794
5795   if (dr)
5796     {
5797       GtkTreePath *path = NULL;
5798       
5799       if (dr->dest_row)
5800         path = gtk_tree_row_reference_get_path (dr->dest_row);
5801       else if (dr->empty_view_drop)
5802         path = gtk_tree_path_new_from_indices (0, -1);
5803       else
5804         path = NULL;
5805
5806       if (path && dr->drop_append_mode)
5807         gtk_tree_path_next (path);
5808
5809       return path;
5810     }
5811   else
5812     return NULL;
5813 }
5814
5815 static gboolean
5816 check_model_dnd (GtkTreeModel *model,
5817                  GType         required_iface,
5818                  const gchar  *signal)
5819 {
5820   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
5821     {
5822       g_warning ("You must override the default '%s' handler "
5823                  "on GtkIconView when using models that don't support "
5824                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
5825                  "is to connect to '%s' and call "
5826                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
5827                  "the default handler from running. Look at the source code "
5828                  "for the default handler in gtkiconview.c to get an idea what "
5829                  "your handler should do. (gtkiconview.c is in the GTK+ source "
5830                  "code.) If you're using GTK+ from a language other than C, "
5831                  "there may be a more natural way to override default handlers, e.g. via derivation.",
5832                  signal, g_type_name (required_iface), signal);
5833       return FALSE;
5834     }
5835   else
5836     return TRUE;
5837 }
5838
5839 static void
5840 remove_scroll_timeout (GtkIconView *icon_view)
5841 {
5842   if (icon_view->priv->scroll_timeout_id != 0)
5843     {
5844       g_source_remove (icon_view->priv->scroll_timeout_id);
5845
5846       icon_view->priv->scroll_timeout_id = 0;
5847     }
5848 }
5849
5850 static void
5851 gtk_icon_view_autoscroll (GtkIconView *icon_view)
5852 {
5853   gint px, py, x, y, width, height;
5854   gint hoffset, voffset;
5855   gfloat value;
5856
5857   gdk_window_get_pointer (GTK_WIDGET (icon_view)->window, &px, &py, NULL);
5858   gdk_window_get_geometry (GTK_WIDGET (icon_view)->window, &x, &y, &width, &height, NULL);
5859
5860   /* see if we are near the edge. */
5861   voffset = py - (y + 2 * SCROLL_EDGE_SIZE);
5862   if (voffset > 0)
5863     voffset = MAX (py - (y + height - 2 * SCROLL_EDGE_SIZE), 0);
5864
5865   hoffset = px - (x + 2 * SCROLL_EDGE_SIZE);
5866   if (hoffset > 0)
5867     hoffset = MAX (px - (x + width - 2 * SCROLL_EDGE_SIZE), 0);
5868
5869   if (voffset != 0)
5870     {
5871       value = CLAMP (icon_view->priv->vadjustment->value + voffset, 
5872                      icon_view->priv->vadjustment->lower,
5873                      icon_view->priv->vadjustment->upper - icon_view->priv->vadjustment->page_size);
5874       gtk_adjustment_set_value (icon_view->priv->vadjustment, value);
5875     }
5876   if (hoffset != 0)
5877     {
5878       value = CLAMP (icon_view->priv->hadjustment->value + hoffset, 
5879                      icon_view->priv->hadjustment->lower,
5880                      icon_view->priv->hadjustment->upper - icon_view->priv->hadjustment->page_size);
5881       gtk_adjustment_set_value (icon_view->priv->hadjustment, value);
5882     }
5883 }
5884
5885
5886 static gboolean
5887 drag_scroll_timeout (gpointer data)
5888 {
5889   GtkIconView *icon_view = GTK_ICON_VIEW (data);
5890
5891   gtk_icon_view_autoscroll (icon_view);
5892
5893   return TRUE;
5894 }
5895
5896
5897 static gboolean
5898 set_destination (GtkIconView    *icon_view,
5899                  GdkDragContext *context,
5900                  gint            x,
5901                  gint            y,
5902                  GdkDragAction  *suggested_action,
5903                  GdkAtom        *target)
5904 {
5905   GtkWidget *widget;
5906   GtkTreePath *path = NULL;
5907   GtkIconViewDropPosition pos;
5908   GtkIconViewDropPosition old_pos;
5909   GtkTreePath *old_dest_path = NULL;
5910   gboolean can_drop = FALSE;
5911
5912   widget = GTK_WIDGET (icon_view);
5913
5914   *suggested_action = 0;
5915   *target = GDK_NONE;
5916
5917   if (!icon_view->priv->dest_set)
5918     {
5919       /* someone unset us as a drag dest, note that if
5920        * we return FALSE drag_leave isn't called
5921        */
5922
5923       gtk_icon_view_set_drag_dest_item (icon_view,
5924                                         NULL,
5925                                         GTK_ICON_VIEW_DROP_LEFT);
5926
5927       remove_scroll_timeout (GTK_ICON_VIEW (widget));
5928
5929       return FALSE; /* no longer a drop site */
5930     }
5931
5932   *target = gtk_drag_dest_find_target (widget, context, icon_view->priv->dest_targets);
5933   if (*target == GDK_NONE)
5934     return FALSE;
5935
5936   if (!gtk_icon_view_get_dest_item_at_pos (icon_view, x, y, &path, &pos)) 
5937     {
5938       gint n_children;
5939       GtkTreeModel *model;
5940       
5941       /* the row got dropped on empty space, let's setup a special case
5942        */
5943
5944       if (path)
5945         gtk_tree_path_free (path);
5946
5947       model = gtk_icon_view_get_model (icon_view);
5948
5949       n_children = gtk_tree_model_iter_n_children (model, NULL);
5950       if (n_children)
5951         {
5952           pos = GTK_ICON_VIEW_DROP_BELOW;
5953           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
5954         }
5955       else
5956         {
5957           pos = GTK_ICON_VIEW_DROP_ABOVE;
5958           path = gtk_tree_path_new_from_indices (0, -1);
5959         }
5960
5961       can_drop = TRUE;
5962
5963       goto out;
5964     }
5965
5966   g_assert (path);
5967
5968   gtk_icon_view_get_drag_dest_item (icon_view,
5969                                     &old_dest_path,
5970                                     &old_pos);
5971   
5972   if (old_dest_path)
5973     gtk_tree_path_free (old_dest_path);
5974   
5975   if (TRUE /* FIXME if the location droppable predicate */)
5976     {
5977       can_drop = TRUE;
5978     }
5979
5980 out:
5981   if (can_drop)
5982     {
5983       GtkWidget *source_widget;
5984
5985       *suggested_action = context->suggested_action;
5986       source_widget = gtk_drag_get_source_widget (context);
5987
5988       if (source_widget == widget)
5989         {
5990           /* Default to MOVE, unless the user has
5991            * pressed ctrl or shift to affect available actions
5992            */
5993           if ((context->actions & GDK_ACTION_MOVE) != 0)
5994             *suggested_action = GDK_ACTION_MOVE;
5995         }
5996
5997       gtk_icon_view_set_drag_dest_item (GTK_ICON_VIEW (widget),
5998                                         path, pos);
5999     }
6000   else
6001     {
6002       /* can't drop here */
6003       gtk_icon_view_set_drag_dest_item (GTK_ICON_VIEW (widget),
6004                                         NULL,
6005                                         GTK_ICON_VIEW_DROP_LEFT);
6006     }
6007   
6008   if (path)
6009     gtk_tree_path_free (path);
6010   
6011   return TRUE;
6012 }
6013
6014 static GtkTreePath*
6015 get_logical_destination (GtkIconView *icon_view,
6016                          gboolean    *drop_append_mode)
6017 {
6018   /* adjust path to point to the row the drop goes in front of */
6019   GtkTreePath *path = NULL;
6020   GtkIconViewDropPosition pos;
6021   
6022   *drop_append_mode = FALSE;
6023
6024   gtk_icon_view_get_drag_dest_item (icon_view, &path, &pos);
6025
6026   if (path == NULL)
6027     return NULL;
6028
6029   if (pos == GTK_ICON_VIEW_DROP_RIGHT || 
6030       pos == GTK_ICON_VIEW_DROP_BELOW)
6031     {
6032       GtkTreeIter iter;
6033       GtkTreeModel *model = icon_view->priv->model;
6034
6035       if (!gtk_tree_model_get_iter (model, &iter, path) ||
6036           !gtk_tree_model_iter_next (model, &iter))
6037         *drop_append_mode = TRUE;
6038       else
6039         {
6040           *drop_append_mode = FALSE;
6041           gtk_tree_path_next (path);
6042         }      
6043     }
6044
6045   return path;
6046 }
6047
6048 static gboolean
6049 gtk_icon_view_maybe_begin_drag (GtkIconView    *icon_view,
6050                                 GdkEventMotion *event)
6051 {
6052   GdkDragContext *context;
6053   GtkTreePath *path = NULL;
6054   gint button;
6055   GtkTreeModel *model;
6056   gboolean retval = FALSE;
6057
6058   if (!icon_view->priv->source_set)
6059     goto out;
6060
6061   if (icon_view->priv->pressed_button < 0)
6062     goto out;
6063
6064   if (!gtk_drag_check_threshold (GTK_WIDGET (icon_view),
6065                                  icon_view->priv->press_start_x,
6066                                  icon_view->priv->press_start_y,
6067                                  event->x, event->y))
6068     goto out;
6069
6070   model = gtk_icon_view_get_model (icon_view);
6071
6072   if (model == NULL)
6073     goto out;
6074
6075   button = icon_view->priv->pressed_button;
6076   icon_view->priv->pressed_button = -1;
6077
6078   path = gtk_icon_view_get_path_at_pos (icon_view,
6079                                         icon_view->priv->press_start_x,
6080                                         icon_view->priv->press_start_y);
6081
6082   if (path == NULL)
6083     goto out;
6084
6085   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
6086       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
6087                                            path))
6088     goto out;
6089
6090   /* FIXME Check whether we're a start button, if not return FALSE and
6091    * free path
6092    */
6093
6094   /* Now we can begin the drag */
6095   
6096   retval = TRUE;
6097
6098   context = gtk_drag_begin (GTK_WIDGET (icon_view),
6099                             icon_view->priv->source_targets,
6100                             icon_view->priv->source_actions,
6101                             button,
6102                             (GdkEvent*)event);
6103
6104   set_source_row (context, model, path);
6105   
6106  out:
6107   if (path)
6108     gtk_tree_path_free (path);
6109
6110   return retval;
6111 }
6112
6113 /* Source side drag signals */
6114 static void 
6115 gtk_icon_view_drag_begin (GtkWidget      *widget,
6116                           GdkDragContext *context)
6117 {
6118   GtkIconView *icon_view;
6119   GtkIconViewItem *item;
6120   GdkPixmap *icon;
6121   gint x, y;
6122   GtkTreePath *path;
6123
6124   icon_view = GTK_ICON_VIEW (widget);
6125
6126   /* if the user uses a custom DnD impl, we don't set the icon here */
6127   if (!icon_view->priv->dest_set && !icon_view->priv->source_set)
6128     return;
6129
6130   item = gtk_icon_view_get_item_at_coords (icon_view,
6131                                            icon_view->priv->press_start_x,
6132                                            icon_view->priv->press_start_y,
6133                                            TRUE,
6134                                            NULL);
6135
6136   g_return_if_fail (item != NULL);
6137
6138   x = icon_view->priv->press_start_x - item->x + 1;
6139   y = icon_view->priv->press_start_y - item->y + 1;
6140   
6141   path = gtk_tree_path_new_from_indices (item->index, -1);
6142   icon = gtk_icon_view_create_drag_icon (icon_view, path);
6143   gtk_tree_path_free (path);
6144
6145   gtk_drag_set_icon_pixmap (context, 
6146                             gdk_drawable_get_colormap (icon),
6147                             icon, 
6148                             NULL, 
6149                             x, y);
6150
6151   g_object_unref (icon);
6152 }
6153
6154 static void 
6155 gtk_icon_view_drag_end (GtkWidget      *widget,
6156                         GdkDragContext *context)
6157 {
6158   /* do nothing */
6159 }
6160
6161 static void 
6162 gtk_icon_view_drag_data_get (GtkWidget        *widget,
6163                              GdkDragContext   *context,
6164                              GtkSelectionData *selection_data,
6165                              guint             info,
6166                              guint             time)
6167 {
6168   GtkIconView *icon_view;
6169   GtkTreeModel *model;
6170   GtkTreePath *source_row;
6171
6172   icon_view = GTK_ICON_VIEW (widget);
6173   model = gtk_icon_view_get_model (icon_view);
6174
6175   if (model == NULL)
6176     return;
6177
6178   if (!icon_view->priv->dest_set)
6179     return;
6180
6181   source_row = get_source_row (context);
6182
6183   if (source_row == NULL)
6184     return;
6185
6186   /* We can implement the GTK_TREE_MODEL_ROW target generically for
6187    * any model; for DragSource models there are some other targets
6188    * we also support.
6189    */
6190
6191   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
6192       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
6193                                           source_row,
6194                                           selection_data))
6195     goto done;
6196
6197   /* If drag_data_get does nothing, try providing row data. */
6198   if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
6199     gtk_tree_set_row_drag_data (selection_data,
6200                                 model,
6201                                 source_row);
6202
6203  done:
6204   gtk_tree_path_free (source_row);
6205 }
6206
6207 static void 
6208 gtk_icon_view_drag_data_delete (GtkWidget      *widget,
6209                                 GdkDragContext *context)
6210 {
6211   GtkTreeModel *model;
6212   GtkIconView *icon_view;
6213   GtkTreePath *source_row;
6214
6215   icon_view = GTK_ICON_VIEW (widget);
6216   model = gtk_icon_view_get_model (icon_view);
6217
6218   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
6219     return;
6220
6221   if (!icon_view->priv->dest_set)
6222     return;
6223
6224   source_row = get_source_row (context);
6225
6226   if (source_row == NULL)
6227     return;
6228
6229   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
6230                                          source_row);
6231
6232   gtk_tree_path_free (source_row);
6233
6234   set_source_row (context, NULL, NULL);
6235 }
6236
6237 /* Target side drag signals */
6238 static void
6239 gtk_icon_view_drag_leave (GtkWidget      *widget,
6240                           GdkDragContext *context,
6241                           guint           time)
6242 {
6243   GtkIconView *icon_view;
6244
6245   icon_view = GTK_ICON_VIEW (widget);
6246
6247   /* unset any highlight row */
6248   gtk_icon_view_set_drag_dest_item (icon_view,
6249                                     NULL,
6250                                     GTK_ICON_VIEW_DROP_LEFT);
6251
6252   remove_scroll_timeout (icon_view);
6253 }
6254
6255 static gboolean 
6256 gtk_icon_view_drag_motion (GtkWidget      *widget,
6257                            GdkDragContext *context,
6258                            gint            x,
6259                            gint            y,
6260                            guint           time)
6261 {
6262   GtkTreePath *path = NULL;
6263   GtkIconViewDropPosition pos;
6264   GtkIconView *icon_view;
6265   GdkDragAction suggested_action = 0;
6266   GdkAtom target;
6267   gboolean empty;
6268
6269   icon_view = GTK_ICON_VIEW (widget);
6270
6271   if (!set_destination (icon_view, context, x, y, &suggested_action, &target))
6272     return FALSE;
6273
6274   gtk_icon_view_get_drag_dest_item (icon_view, &path, &pos);
6275
6276   /* we only know this *after* set_desination_row */
6277   empty = icon_view->priv->empty_view_drop;
6278
6279   if (path == NULL && !empty)
6280     {
6281       /* Can't drop here. */
6282       gdk_drag_status (context, 0, time);
6283     }
6284   else
6285     {
6286       if (icon_view->priv->scroll_timeout_id == 0)
6287         {
6288           icon_view->priv->scroll_timeout_id =
6289             gdk_threads_add_timeout (50, drag_scroll_timeout, icon_view);
6290         }
6291
6292       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
6293         {
6294           /* Request data so we can use the source row when
6295            * determining whether to accept the drop
6296            */
6297           set_status_pending (context, suggested_action);
6298           gtk_drag_get_data (widget, context, target, time);
6299         }
6300       else
6301         {
6302           set_status_pending (context, 0);
6303           gdk_drag_status (context, suggested_action, time);
6304         }
6305     }
6306
6307   if (path)
6308     gtk_tree_path_free (path);
6309
6310   return TRUE;
6311 }
6312
6313 static gboolean 
6314 gtk_icon_view_drag_drop (GtkWidget      *widget,
6315                          GdkDragContext *context,
6316                          gint            x,
6317                          gint            y,
6318                          guint           time)
6319 {
6320   GtkIconView *icon_view;
6321   GtkTreePath *path;
6322   GdkDragAction suggested_action = 0;
6323   GdkAtom target = GDK_NONE;
6324   GtkTreeModel *model;
6325   gboolean drop_append_mode;
6326
6327   icon_view = GTK_ICON_VIEW (widget);
6328   model = gtk_icon_view_get_model (icon_view);
6329
6330   remove_scroll_timeout (GTK_ICON_VIEW (widget));
6331
6332   if (!icon_view->priv->dest_set)
6333     return FALSE;
6334
6335   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
6336     return FALSE;
6337
6338   if (!set_destination (icon_view, context, x, y, &suggested_action, &target))
6339     return FALSE;
6340   
6341   path = get_logical_destination (icon_view, &drop_append_mode);
6342
6343   if (target != GDK_NONE && path != NULL)
6344     {
6345       /* in case a motion had requested drag data, change things so we
6346        * treat drag data receives as a drop.
6347        */
6348       set_status_pending (context, 0);
6349       set_dest_row (context, model, path, 
6350                     icon_view->priv->empty_view_drop, drop_append_mode);
6351     }
6352
6353   if (path)
6354     gtk_tree_path_free (path);
6355
6356   /* Unset this thing */
6357   gtk_icon_view_set_drag_dest_item (icon_view, NULL, GTK_ICON_VIEW_DROP_LEFT);
6358
6359   if (target != GDK_NONE)
6360     {
6361       gtk_drag_get_data (widget, context, target, time);
6362       return TRUE;
6363     }
6364   else
6365     return FALSE;
6366 }
6367
6368 static void
6369 gtk_icon_view_drag_data_received (GtkWidget        *widget,
6370                                   GdkDragContext   *context,
6371                                   gint              x,
6372                                   gint              y,
6373                                   GtkSelectionData *selection_data,
6374                                   guint             info,
6375                                   guint             time)
6376 {
6377   GtkTreePath *path;
6378   gboolean accepted = FALSE;
6379   GtkTreeModel *model;
6380   GtkIconView *icon_view;
6381   GtkTreePath *dest_row;
6382   GdkDragAction suggested_action;
6383   gboolean drop_append_mode;
6384   
6385   icon_view = GTK_ICON_VIEW (widget);  
6386   model = gtk_icon_view_get_model (icon_view);
6387
6388   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
6389     return;
6390
6391   if (!icon_view->priv->dest_set)
6392     return;
6393
6394   suggested_action = get_status_pending (context);
6395
6396   if (suggested_action)
6397     {
6398       /* We are getting this data due to a request in drag_motion,
6399        * rather than due to a request in drag_drop, so we are just
6400        * supposed to call drag_status, not actually paste in the
6401        * data.
6402        */
6403       path = get_logical_destination (icon_view, &drop_append_mode);
6404
6405       if (path == NULL)
6406         suggested_action = 0;
6407
6408       if (suggested_action)
6409         {
6410           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
6411                                                      path,
6412                                                      selection_data))
6413             suggested_action = 0;
6414         }
6415
6416       gdk_drag_status (context, suggested_action, time);
6417
6418       if (path)
6419         gtk_tree_path_free (path);
6420
6421       /* If you can't drop, remove user drop indicator until the next motion */
6422       if (suggested_action == 0)
6423         gtk_icon_view_set_drag_dest_item (icon_view,
6424                                           NULL,
6425                                           GTK_ICON_VIEW_DROP_LEFT);
6426       return;
6427     }
6428   
6429
6430   dest_row = get_dest_row (context);
6431
6432   if (dest_row == NULL)
6433     return;
6434
6435   if (selection_data->length >= 0)
6436     {
6437       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
6438                                                  dest_row,
6439                                                  selection_data))
6440         accepted = TRUE;
6441     }
6442
6443   gtk_drag_finish (context,
6444                    accepted,
6445                    (context->action == GDK_ACTION_MOVE),
6446                    time);
6447
6448   gtk_tree_path_free (dest_row);
6449
6450   /* drop dest_row */
6451   set_dest_row (context, NULL, NULL, FALSE, FALSE);
6452 }
6453
6454 /* Drag-and-Drop support */
6455 /**
6456  * gtk_icon_view_enable_model_drag_source:
6457  * @icon_view: a #GtkIconTreeView
6458  * @start_button_mask: Mask of allowed buttons to start drag
6459  * @targets: the table of targets that the drag will support
6460  * @n_targets: the number of items in @targets
6461  * @actions: the bitmask of possible actions for a drag from this
6462  *    widget
6463  * 
6464  * Turns @icon_view into a drag source for automatic DND.
6465  *
6466  * Since: 2.8
6467  **/
6468 void
6469 gtk_icon_view_enable_model_drag_source (GtkIconView              *icon_view,
6470                                         GdkModifierType           start_button_mask,
6471                                         const GtkTargetEntry     *targets,
6472                                         gint                      n_targets,
6473                                         GdkDragAction             actions)
6474 {
6475   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6476
6477   gtk_drag_source_set (GTK_WIDGET (icon_view), 0, NULL, 0, actions);
6478
6479   clear_source_info (icon_view);
6480   icon_view->priv->start_button_mask = start_button_mask;
6481   icon_view->priv->source_targets = gtk_target_list_new (targets, n_targets);
6482   icon_view->priv->source_actions = actions;
6483
6484   icon_view->priv->source_set = TRUE;
6485
6486   unset_reorderable (icon_view);
6487 }
6488
6489 /**
6490  * gtk_icon_view_enable_model_drag_dest:
6491  * @icon_view: a #GtkIconView
6492  * @targets: the table of targets that the drag will support
6493  * @n_targets: the number of items in @targets
6494  * @actions: the bitmask of possible actions for a drag to this
6495  *    widget
6496  * 
6497  * Turns @icon_view into a drop destination for automatic DND.
6498  *
6499  * Since: 2.8
6500  **/
6501 void 
6502 gtk_icon_view_enable_model_drag_dest (GtkIconView          *icon_view,
6503                                       const GtkTargetEntry *targets,
6504                                       gint                  n_targets,
6505                                       GdkDragAction         actions)
6506 {
6507   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6508
6509   gtk_drag_dest_set (GTK_WIDGET (icon_view), 0, NULL, 0, actions);
6510
6511   clear_dest_info (icon_view);
6512
6513   icon_view->priv->dest_targets = gtk_target_list_new (targets, n_targets);
6514   icon_view->priv->dest_actions = actions;
6515
6516   icon_view->priv->dest_set = TRUE;
6517
6518   unset_reorderable (icon_view);  
6519 }
6520
6521 /**
6522  * gtk_icon_view_unset_model_drag_source:
6523  * @icon_view: a #GtkIconView
6524  * 
6525  * Undoes the effect of gtk_icon_view_enable_model_drag_source().
6526  *
6527  * Since: 2.8
6528  **/
6529 void
6530 gtk_icon_view_unset_model_drag_source (GtkIconView *icon_view)
6531 {
6532   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6533
6534   if (icon_view->priv->source_set)
6535     {
6536       gtk_drag_source_unset (GTK_WIDGET (icon_view));
6537       clear_source_info (icon_view);
6538     }
6539
6540   unset_reorderable (icon_view);
6541 }
6542
6543 /**
6544  * gtk_icon_view_unset_model_drag_dest:
6545  * @icon_view: a #GtkIconView
6546  * 
6547  * Undoes the effect of gtk_icon_view_enable_model_drag_dest().
6548  *
6549  * Since: 2.8
6550  **/
6551 void
6552 gtk_icon_view_unset_model_drag_dest (GtkIconView *icon_view)
6553 {
6554   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6555
6556   if (icon_view->priv->dest_set)
6557     {
6558       gtk_drag_dest_unset (GTK_WIDGET (icon_view));
6559       clear_dest_info (icon_view);
6560     }
6561
6562   unset_reorderable (icon_view);
6563 }
6564
6565 /* These are useful to implement your own custom stuff. */
6566 /**
6567  * gtk_icon_view_set_drag_dest_item:
6568  * @icon_view: a #GtkIconView
6569  * @path: The path of the item to highlight, or %NULL.
6570  * @pos: Specifies where to drop, relative to the item
6571  * 
6572  * Sets the item that is highlighted for feedback.
6573  *
6574  * Since: 2.8
6575  */
6576 void
6577 gtk_icon_view_set_drag_dest_item (GtkIconView              *icon_view,
6578                                   GtkTreePath              *path,
6579                                   GtkIconViewDropPosition   pos)
6580 {
6581   /* Note; this function is exported to allow a custom DND
6582    * implementation, so it can't touch TreeViewDragInfo
6583    */
6584
6585   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6586
6587   if (icon_view->priv->dest_item)
6588     {
6589       GtkTreePath *current_path;
6590       current_path = gtk_tree_row_reference_get_path (icon_view->priv->dest_item);
6591       gtk_tree_row_reference_free (icon_view->priv->dest_item);
6592       icon_view->priv->dest_item = NULL;      
6593
6594       gtk_icon_view_queue_draw_path (icon_view, current_path);
6595       gtk_tree_path_free (current_path);
6596     }
6597   
6598   /* special case a drop on an empty model */
6599   icon_view->priv->empty_view_drop = FALSE;
6600   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
6601       && gtk_tree_path_get_depth (path) == 1
6602       && gtk_tree_path_get_indices (path)[0] == 0)
6603     {
6604       gint n_children;
6605
6606       n_children = gtk_tree_model_iter_n_children (icon_view->priv->model,
6607                                                    NULL);
6608
6609       if (n_children == 0)
6610         icon_view->priv->empty_view_drop = TRUE;
6611     }
6612
6613   icon_view->priv->dest_pos = pos;
6614
6615   if (path)
6616     {
6617       icon_view->priv->dest_item =
6618         gtk_tree_row_reference_new_proxy (G_OBJECT (icon_view), 
6619                                           icon_view->priv->model, path);
6620       
6621       gtk_icon_view_queue_draw_path (icon_view, path);
6622     }
6623 }
6624
6625 /**
6626  * gtk_icon_view_get_drag_dest_item:
6627  * @icon_view: a #GtkIconView
6628  * @path: Return location for the path of the highlighted item, or %NULL.
6629  * @pos: Return location for the drop position, or %NULL
6630  * 
6631  * Gets information about the item that is highlighted for feedback.
6632  *
6633  * Since: 2.8
6634  **/
6635 void
6636 gtk_icon_view_get_drag_dest_item (GtkIconView              *icon_view,
6637                                   GtkTreePath             **path,
6638                                   GtkIconViewDropPosition  *pos)
6639 {
6640   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6641
6642   if (path)
6643     {
6644       if (icon_view->priv->dest_item)
6645         *path = gtk_tree_row_reference_get_path (icon_view->priv->dest_item);
6646       else
6647         *path = NULL;
6648     }
6649
6650   if (pos)
6651     *pos = icon_view->priv->dest_pos;
6652 }
6653
6654 /**
6655  * gtk_icon_view_get_dest_item_at_pos:
6656  * @icon_view: a #GtkIconView
6657  * @drag_x: the position to determine the destination item for
6658  * @drag_y: the position to determine the destination item for
6659  * @path: Return location for the path of the item, or %NULL.
6660  * @pos: Return location for the drop position, or %NULL
6661  * 
6662  * Determines the destination item for a given position.
6663  * 
6664  * Return value: whether there is an item at the given position.
6665  *
6666  * Since: 2.8
6667  **/
6668 gboolean
6669 gtk_icon_view_get_dest_item_at_pos (GtkIconView              *icon_view,
6670                                     gint                      drag_x,
6671                                     gint                      drag_y,
6672                                     GtkTreePath             **path,
6673                                     GtkIconViewDropPosition  *pos)
6674 {
6675   GtkIconViewItem *item;
6676
6677   /* Note; this function is exported to allow a custom DND
6678    * implementation, so it can't touch TreeViewDragInfo
6679    */
6680
6681   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
6682   g_return_val_if_fail (drag_x >= 0, FALSE);
6683   g_return_val_if_fail (drag_y >= 0, FALSE);
6684   g_return_val_if_fail (icon_view->priv->bin_window != NULL, FALSE);
6685
6686
6687   if (path)
6688     *path = NULL;
6689
6690   item = gtk_icon_view_get_item_at_coords (icon_view, 
6691                                            drag_x + icon_view->priv->hadjustment->value, 
6692                                            drag_y + icon_view->priv->vadjustment->value,
6693                                            FALSE, NULL);
6694
6695   if (item == NULL)
6696     return FALSE;
6697
6698   if (path)
6699     *path = gtk_tree_path_new_from_indices (item->index, -1);
6700
6701   if (pos)
6702     {
6703       if (drag_x < item->x + item->width / 4)
6704         *pos = GTK_ICON_VIEW_DROP_LEFT;
6705       else if (drag_x > item->x + item->width * 3 / 4)
6706         *pos = GTK_ICON_VIEW_DROP_RIGHT;
6707       else if (drag_y < item->y + item->height / 4)
6708         *pos = GTK_ICON_VIEW_DROP_ABOVE;
6709       else if (drag_y > item->y + item->height * 3 / 4)
6710         *pos = GTK_ICON_VIEW_DROP_BELOW;
6711       else
6712         *pos = GTK_ICON_VIEW_DROP_INTO;
6713     }
6714
6715   return TRUE;
6716 }
6717
6718 /**
6719  * gtk_icon_view_create_drag_icon:
6720  * @icon_view: a #GtkIconView
6721  * @path: a #GtkTreePath in @icon_view
6722  *
6723  * Creates a #GdkPixmap representation of the item at @path.  
6724  * This image is used for a drag icon.
6725  *
6726  * Return value: a newly-allocated pixmap of the drag icon.
6727  * 
6728  * Since: 2.8
6729  **/
6730 GdkPixmap *
6731 gtk_icon_view_create_drag_icon (GtkIconView *icon_view,
6732                                 GtkTreePath *path)
6733 {
6734   GtkWidget *widget;
6735   cairo_t *cr;
6736   GdkPixmap *drawable;
6737   GList *l;
6738   gint index;
6739   GdkRectangle area;
6740
6741   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
6742   g_return_val_if_fail (path != NULL, NULL);
6743
6744   widget = GTK_WIDGET (icon_view);
6745
6746   if (!GTK_WIDGET_REALIZED (widget))
6747     return NULL;
6748
6749   index = gtk_tree_path_get_indices (path)[0];
6750
6751   for (l = icon_view->priv->items; l; l = l->next) 
6752     {
6753       GtkIconViewItem *item = l->data;
6754       
6755       if (index == item->index)
6756         {
6757           drawable = gdk_pixmap_new (icon_view->priv->bin_window,
6758                                      item->width + 2,
6759                                      item->height + 2,
6760                                      -1);
6761
6762           cr = gdk_cairo_create (drawable);
6763           cairo_set_line_width (cr, 1.);
6764
6765           gdk_cairo_set_source_color
6766             (cr, &widget->style->base[GTK_WIDGET_STATE (widget)]);
6767           cairo_rectangle (cr, 0, 0, item->width + 2, item->height + 2);
6768           cairo_fill (cr);
6769
6770           area.x = 0;
6771           area.y = 0;
6772           area.width = item->width;
6773           area.height = item->height;
6774
6775           gtk_icon_view_paint_item (icon_view, cr, item, &area, 
6776                                     drawable, 1, 1, FALSE); 
6777
6778           cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
6779           cairo_rectangle (cr, 0.5, 0.5, item->width + 1, item->height + 1);
6780           cairo_stroke (cr);
6781
6782           cairo_destroy (cr);
6783
6784           return drawable;
6785         }
6786     }
6787   
6788   return NULL;
6789 }
6790
6791 /**
6792  * gtk_icon_view_get_reorderable:
6793  * @icon_view: a #GtkIconView
6794  *
6795  * Retrieves whether the user can reorder the list via drag-and-drop. 
6796  * See gtk_icon_view_set_reorderable().
6797  *
6798  * Return value: %TRUE if the list can be reordered.
6799  *
6800  * Since: 2.8
6801  **/
6802 gboolean
6803 gtk_icon_view_get_reorderable (GtkIconView *icon_view)
6804 {
6805   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
6806
6807   return icon_view->priv->reorderable;
6808 }
6809
6810 static const GtkTargetEntry item_targets[] = {
6811   { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
6812 };
6813
6814
6815 /**
6816  * gtk_icon_view_set_reorderable:
6817  * @icon_view: A #GtkIconView.
6818  * @reorderable: %TRUE, if the list of items can be reordered.
6819  *
6820  * This function is a convenience function to allow you to reorder models that
6821  * support the #GtkTreeDragSourceIface and the #GtkTreeDragDestIface.  Both
6822  * #GtkTreeStore and #GtkListStore support these.  If @reorderable is %TRUE, then
6823  * the user can reorder the model by dragging and dropping rows.  The
6824  * developer can listen to these changes by connecting to the model's
6825  * row_inserted and row_deleted signals.
6826  *
6827  * This function does not give you any degree of control over the order -- any
6828  * reordering is allowed.  If more control is needed, you should probably
6829  * handle drag and drop manually.
6830  *
6831  * Since: 2.8
6832  **/
6833 void
6834 gtk_icon_view_set_reorderable (GtkIconView *icon_view,
6835                                gboolean     reorderable)
6836 {
6837   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6838
6839   reorderable = reorderable != FALSE;
6840
6841   if (icon_view->priv->reorderable == reorderable)
6842     return;
6843
6844   if (reorderable)
6845     {
6846       gtk_icon_view_enable_model_drag_source (icon_view,
6847                                               GDK_BUTTON1_MASK,
6848                                               item_targets,
6849                                               G_N_ELEMENTS (item_targets),
6850                                               GDK_ACTION_MOVE);
6851       gtk_icon_view_enable_model_drag_dest (icon_view,
6852                                             item_targets,
6853                                             G_N_ELEMENTS (item_targets),
6854                                             GDK_ACTION_MOVE);
6855     }
6856   else
6857     {
6858       gtk_icon_view_unset_model_drag_source (icon_view);
6859       gtk_icon_view_unset_model_drag_dest (icon_view);
6860     }
6861
6862   icon_view->priv->reorderable = reorderable;
6863
6864   g_object_notify (G_OBJECT (icon_view), "reorderable");
6865 }
6866
6867
6868 /* Accessibility Support */
6869
6870 static gpointer accessible_parent_class;
6871 static gpointer accessible_item_parent_class;
6872 static GQuark accessible_private_data_quark = 0;
6873
6874 #define GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE      (gtk_icon_view_item_accessible_get_type ())
6875 #define GTK_ICON_VIEW_ITEM_ACCESSIBLE(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE, GtkIconViewItemAccessible))
6876 #define GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE(obj)   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE))
6877
6878 static GType gtk_icon_view_item_accessible_get_type (void);
6879
6880 enum {
6881     ACTION_ACTIVATE,
6882     LAST_ACTION
6883 };
6884
6885 typedef struct
6886 {
6887   AtkObject parent;
6888
6889   GtkIconViewItem *item;
6890
6891   GtkWidget *widget;
6892
6893   AtkStateSet *state_set;
6894
6895   gchar *text;
6896
6897   GtkTextBuffer *text_buffer;
6898
6899   gchar *action_descriptions[LAST_ACTION];
6900   gchar *image_description;
6901   guint action_idle_handler;
6902 } GtkIconViewItemAccessible;
6903
6904 static const gchar *const gtk_icon_view_item_accessible_action_names[] = 
6905 {
6906   "activate",
6907   NULL
6908 };
6909
6910 static const gchar *const gtk_icon_view_item_accessible_action_descriptions[] =
6911 {
6912   "Activate item",
6913   NULL
6914 };
6915 typedef struct _GtkIconViewItemAccessibleClass
6916 {
6917   AtkObjectClass parent_class;
6918
6919 } GtkIconViewItemAccessibleClass;
6920
6921 static gboolean gtk_icon_view_item_accessible_is_showing (GtkIconViewItemAccessible *item);
6922
6923 static gboolean
6924 gtk_icon_view_item_accessible_idle_do_action (gpointer data)
6925 {
6926   GtkIconViewItemAccessible *item;
6927   GtkIconView *icon_view;
6928   GtkTreePath *path;
6929
6930   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (data);
6931   item->action_idle_handler = 0;
6932
6933   if (item->widget != NULL)
6934     {
6935       icon_view = GTK_ICON_VIEW (item->widget);
6936       path = gtk_tree_path_new_from_indices (item->item->index, -1);
6937       gtk_icon_view_item_activated (icon_view, path);
6938       gtk_tree_path_free (path);
6939     }
6940
6941   return FALSE;
6942 }
6943
6944 static gboolean
6945 gtk_icon_view_item_accessible_action_do_action (AtkAction *action,
6946                                                 gint       i)
6947 {
6948   GtkIconViewItemAccessible *item;
6949
6950   if (i < 0 || i >= LAST_ACTION) 
6951     return FALSE;
6952
6953   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
6954
6955   if (!GTK_IS_ICON_VIEW (item->widget))
6956     return FALSE;
6957
6958   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
6959     return FALSE;
6960
6961   switch (i)
6962     {
6963     case ACTION_ACTIVATE:
6964       if (!item->action_idle_handler)
6965         item->action_idle_handler = gdk_threads_add_idle (gtk_icon_view_item_accessible_idle_do_action, item);
6966       break;
6967     default:
6968       g_assert_not_reached ();
6969       return FALSE;
6970
6971     }        
6972   return TRUE;
6973 }
6974
6975 static gint
6976 gtk_icon_view_item_accessible_action_get_n_actions (AtkAction *action)
6977 {
6978         return LAST_ACTION;
6979 }
6980
6981 static const gchar *
6982 gtk_icon_view_item_accessible_action_get_description (AtkAction *action,
6983                                                       gint       i)
6984 {
6985   GtkIconViewItemAccessible *item;
6986
6987   if (i < 0 || i >= LAST_ACTION) 
6988     return NULL;
6989
6990   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
6991
6992   if (item->action_descriptions[i])
6993     return item->action_descriptions[i];
6994   else
6995     return gtk_icon_view_item_accessible_action_descriptions[i];
6996 }
6997
6998 static const gchar *
6999 gtk_icon_view_item_accessible_action_get_name (AtkAction *action,
7000                                                gint       i)
7001 {
7002   if (i < 0 || i >= LAST_ACTION) 
7003     return NULL;
7004
7005   return gtk_icon_view_item_accessible_action_names[i];
7006 }
7007
7008 static gboolean
7009 gtk_icon_view_item_accessible_action_set_description (AtkAction   *action,
7010                                                       gint         i,
7011                                                       const gchar *description)
7012 {
7013   GtkIconViewItemAccessible *item;
7014
7015   if (i < 0 || i >= LAST_ACTION) 
7016     return FALSE;
7017
7018   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
7019
7020   g_free (item->action_descriptions[i]);
7021
7022   item->action_descriptions[i] = g_strdup (description);
7023
7024   return TRUE;
7025 }
7026
7027 static void
7028 atk_action_item_interface_init (AtkActionIface *iface)
7029 {
7030   iface->do_action = gtk_icon_view_item_accessible_action_do_action;
7031   iface->get_n_actions = gtk_icon_view_item_accessible_action_get_n_actions;
7032   iface->get_description = gtk_icon_view_item_accessible_action_get_description;
7033   iface->get_name = gtk_icon_view_item_accessible_action_get_name;
7034   iface->set_description = gtk_icon_view_item_accessible_action_set_description;
7035 }
7036
7037 static const gchar *
7038 gtk_icon_view_item_accessible_image_get_image_description (AtkImage *image)
7039 {
7040   GtkIconViewItemAccessible *item;
7041
7042   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7043
7044   return item->image_description;
7045 }
7046
7047 static gboolean
7048 gtk_icon_view_item_accessible_image_set_image_description (AtkImage    *image,
7049                                                            const gchar *description)
7050 {
7051   GtkIconViewItemAccessible *item;
7052
7053   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7054
7055   g_free (item->image_description);
7056   item->image_description = g_strdup (item->image_description);
7057
7058   return TRUE;
7059 }
7060
7061 static gboolean
7062 get_pixbuf_box (GtkIconView     *icon_view,
7063                 GtkIconViewItem *item,
7064                 GdkRectangle    *box)
7065 {
7066   GList *l;
7067
7068   for (l = icon_view->priv->cell_list; l; l = l->next)
7069     {
7070       GtkIconViewCellInfo *info = l->data;
7071       
7072       if (GTK_IS_CELL_RENDERER_PIXBUF (info->cell))
7073         {
7074           gtk_icon_view_get_cell_box (icon_view, item, info, box);
7075
7076           return TRUE;
7077         }
7078     }
7079
7080   return FALSE;
7081 }
7082
7083 static gchar *
7084 get_text (GtkIconView     *icon_view,
7085           GtkIconViewItem *item)
7086 {
7087   GList *l;
7088   gchar *text;
7089
7090   for (l = icon_view->priv->cell_list; l; l = l->next)
7091     {
7092       GtkIconViewCellInfo *info = l->data;
7093       
7094       if (GTK_IS_CELL_RENDERER_TEXT (info->cell))
7095         {
7096           g_object_get (info->cell, "text", &text, NULL);
7097           
7098           return text;
7099         }
7100     }
7101
7102   return NULL;
7103 }
7104
7105 static void
7106 gtk_icon_view_item_accessible_image_get_image_size (AtkImage *image,
7107                                                     gint     *width,
7108                                                     gint     *height)
7109 {
7110   GtkIconViewItemAccessible *item;
7111   GdkRectangle box;
7112
7113   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7114
7115   if (!GTK_IS_ICON_VIEW (item->widget))
7116     return;
7117
7118   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7119     return;
7120
7121   if (get_pixbuf_box (GTK_ICON_VIEW (item->widget), item->item, &box))
7122     {
7123       *width = box.width;
7124       *height = box.height;  
7125     }
7126 }
7127
7128 static void
7129 gtk_icon_view_item_accessible_image_get_image_position (AtkImage    *image,
7130                                                         gint        *x,
7131                                                         gint        *y,
7132                                                         AtkCoordType coord_type)
7133 {
7134   GtkIconViewItemAccessible *item;
7135   GdkRectangle box;
7136
7137   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7138
7139   if (!GTK_IS_ICON_VIEW (item->widget))
7140     return;
7141
7142   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7143     return;
7144
7145   atk_component_get_position (ATK_COMPONENT (image), x, y, coord_type);
7146
7147   if (get_pixbuf_box (GTK_ICON_VIEW (item->widget), item->item, &box))
7148     {
7149       *x+= box.x - item->item->x;
7150       *y+= box.y - item->item->y;
7151     }
7152
7153 }
7154
7155 static void
7156 atk_image_item_interface_init (AtkImageIface *iface)
7157 {
7158   iface->get_image_description = gtk_icon_view_item_accessible_image_get_image_description;
7159   iface->set_image_description = gtk_icon_view_item_accessible_image_set_image_description;
7160   iface->get_image_size = gtk_icon_view_item_accessible_image_get_image_size;
7161   iface->get_image_position = gtk_icon_view_item_accessible_image_get_image_position;
7162 }
7163
7164 static gchar *
7165 gtk_icon_view_item_accessible_text_get_text (AtkText *text,
7166                                              gint     start_pos,
7167                                              gint     end_pos)
7168 {
7169   GtkIconViewItemAccessible *item;
7170   GtkTextIter start, end;
7171   GtkTextBuffer *buffer;
7172
7173   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7174
7175   if (!GTK_IS_ICON_VIEW (item->widget))
7176     return NULL;
7177
7178   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7179     return NULL;
7180
7181   buffer = item->text_buffer;
7182   gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
7183   if (end_pos < 0)
7184     gtk_text_buffer_get_end_iter (buffer, &end);
7185   else
7186     gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
7187
7188   return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
7189 }
7190
7191 static gunichar
7192 gtk_icon_view_item_accessible_text_get_character_at_offset (AtkText *text,
7193                                                             gint     offset)
7194 {
7195   GtkIconViewItemAccessible *item;
7196   GtkTextIter start, end;
7197   GtkTextBuffer *buffer;
7198   gchar *string;
7199   gunichar unichar;
7200
7201   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7202
7203   if (!GTK_IS_ICON_VIEW (item->widget))
7204     return '\0';
7205
7206   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7207     return '\0';
7208
7209   buffer = item->text_buffer;
7210   if (offset >= gtk_text_buffer_get_char_count (buffer))
7211     return '\0';
7212
7213   gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
7214   end = start;
7215   gtk_text_iter_forward_char (&end);
7216   string = gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
7217   unichar = g_utf8_get_char (string);
7218   g_free(string);
7219
7220   return unichar;
7221 }
7222
7223 #if 0
7224 static void
7225 get_pango_text_offsets (PangoLayout     *layout,
7226                         GtkTextBuffer   *buffer,
7227                         gint             function,
7228                         AtkTextBoundary  boundary_type,
7229                         gint             offset,
7230                         gint            *start_offset,
7231                         gint            *end_offset,
7232                         GtkTextIter     *start_iter,
7233                         GtkTextIter     *end_iter)
7234 {
7235   PangoLayoutIter *iter;
7236   PangoLayoutLine *line, *prev_line = NULL, *prev_prev_line = NULL;
7237   gint index, start_index, end_index;
7238   const gchar *text;
7239   gboolean found = FALSE;
7240
7241   text = pango_layout_get_text (layout);
7242   index = g_utf8_offset_to_pointer (text, offset) - text;
7243   iter = pango_layout_get_iter (layout);
7244   do
7245     {
7246       line = pango_layout_iter_get_line_readonly (iter);
7247       start_index = line->start_index;
7248       end_index = start_index + line->length;
7249
7250       if (index >= start_index && index <= end_index)
7251         {
7252           /*
7253            * Found line for offset
7254            */
7255           switch (function)
7256             {
7257             case 0:
7258                   /*
7259                    * We want the previous line
7260                    */
7261               if (prev_line)
7262                 {
7263                   switch (boundary_type)
7264                     {
7265                     case ATK_TEXT_BOUNDARY_LINE_START:
7266                       end_index = start_index;
7267                       start_index = prev_line->start_index;
7268                       break;
7269                     case ATK_TEXT_BOUNDARY_LINE_END:
7270                       if (prev_prev_line)
7271                         start_index = prev_prev_line->start_index + 
7272                                   prev_prev_line->length;
7273                       end_index = prev_line->start_index + prev_line->length;
7274                       break;
7275                     default:
7276                       g_assert_not_reached();
7277                     }
7278                 }
7279               else
7280                 start_index = end_index = 0;
7281               break;
7282             case 1:
7283               switch (boundary_type)
7284                 {
7285                 case ATK_TEXT_BOUNDARY_LINE_START:
7286                   if (pango_layout_iter_next_line (iter))
7287                     end_index = pango_layout_iter_get_line_readonly (iter)->start_index;
7288                   break;
7289                 case ATK_TEXT_BOUNDARY_LINE_END:
7290                   if (prev_line)
7291                     start_index = prev_line->start_index + 
7292                                   prev_line->length;
7293                   break;
7294                 default:
7295                   g_assert_not_reached();
7296                 }
7297               break;
7298             case 2:
7299                /*
7300                 * We want the next line
7301                 */
7302               if (pango_layout_iter_next_line (iter))
7303                 {
7304                   line = pango_layout_iter_get_line_readonly (iter);
7305                   switch (boundary_type)
7306                     {
7307                     case ATK_TEXT_BOUNDARY_LINE_START:
7308                       start_index = line->start_index;
7309                       if (pango_layout_iter_next_line (iter))
7310                         end_index = pango_layout_iter_get_line_readonly (iter)->start_index;
7311                       else
7312                         end_index = start_index + line->length;
7313                       break;
7314                     case ATK_TEXT_BOUNDARY_LINE_END:
7315                       start_index = end_index;
7316                       end_index = line->start_index + line->length;
7317                       break;
7318                     default:
7319                       g_assert_not_reached();
7320                     }
7321                 }
7322               else
7323                 start_index = end_index;
7324               break;
7325             }
7326           found = TRUE;
7327           break;
7328         }
7329       prev_prev_line = prev_line; 
7330       prev_line = line; 
7331     }
7332   while (pango_layout_iter_next_line (iter));
7333
7334   if (!found)
7335     {
7336       start_index = prev_line->start_index + prev_line->length;
7337       end_index = start_index;
7338     }
7339   pango_layout_iter_free (iter);
7340   *start_offset = g_utf8_pointer_to_offset (text, text + start_index);
7341   *end_offset = g_utf8_pointer_to_offset (text, text + end_index);
7342  
7343   gtk_text_buffer_get_iter_at_offset (buffer, start_iter, *start_offset);
7344   gtk_text_buffer_get_iter_at_offset (buffer, end_iter, *end_offset);
7345 }
7346 #endif
7347
7348 static gchar*
7349 gtk_icon_view_item_accessible_text_get_text_before_offset (AtkText         *text,
7350                                                            gint            offset,
7351                                                            AtkTextBoundary boundary_type,
7352                                                            gint            *start_offset,
7353                                                            gint            *end_offset)
7354 {
7355   GtkIconViewItemAccessible *item;
7356   GtkTextIter start, end;
7357   GtkTextBuffer *buffer;
7358 #if 0
7359   GtkIconView *icon_view;
7360 #endif
7361
7362   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7363
7364   if (!GTK_IS_ICON_VIEW (item->widget))
7365     return NULL;
7366
7367   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7368     return NULL;
7369
7370   buffer = item->text_buffer;
7371
7372   if (!gtk_text_buffer_get_char_count (buffer))
7373     {
7374       *start_offset = 0;
7375       *end_offset = 0;
7376       return g_strdup ("");
7377     }
7378   gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
7379    
7380   end = start;
7381
7382   switch (boundary_type)
7383     {
7384     case ATK_TEXT_BOUNDARY_CHAR:
7385       gtk_text_iter_backward_char(&start);
7386       break;
7387     case ATK_TEXT_BOUNDARY_WORD_START:
7388       if (!gtk_text_iter_starts_word (&start))
7389         gtk_text_iter_backward_word_start (&start);
7390       end = start;
7391       gtk_text_iter_backward_word_start(&start);
7392       break;
7393     case ATK_TEXT_BOUNDARY_WORD_END:
7394       if (gtk_text_iter_inside_word (&start) &&
7395           !gtk_text_iter_starts_word (&start))
7396         gtk_text_iter_backward_word_start (&start);
7397       while (!gtk_text_iter_ends_word (&start))
7398         {
7399           if (!gtk_text_iter_backward_char (&start))
7400             break;
7401         }
7402       end = start;
7403       gtk_text_iter_backward_word_start(&start);
7404       while (!gtk_text_iter_ends_word (&start))
7405         {
7406           if (!gtk_text_iter_backward_char (&start))
7407             break;
7408         }
7409       break;
7410     case ATK_TEXT_BOUNDARY_SENTENCE_START:
7411       if (!gtk_text_iter_starts_sentence (&start))
7412         gtk_text_iter_backward_sentence_start (&start);
7413       end = start;
7414       gtk_text_iter_backward_sentence_start (&start);
7415       break;
7416     case ATK_TEXT_BOUNDARY_SENTENCE_END:
7417       if (gtk_text_iter_inside_sentence (&start) &&
7418           !gtk_text_iter_starts_sentence (&start))
7419         gtk_text_iter_backward_sentence_start (&start);
7420       while (!gtk_text_iter_ends_sentence (&start))
7421         {
7422           if (!gtk_text_iter_backward_char (&start))
7423             break;
7424         }
7425       end = start;
7426       gtk_text_iter_backward_sentence_start (&start);
7427       while (!gtk_text_iter_ends_sentence (&start))
7428         {
7429           if (!gtk_text_iter_backward_char (&start))
7430             break;
7431         }
7432       break;
7433    case ATK_TEXT_BOUNDARY_LINE_START:
7434    case ATK_TEXT_BOUNDARY_LINE_END:
7435 #if 0
7436       icon_view = GTK_ICON_VIEW (item->widget);
7437       /* FIXME we probably have to use GailTextCell to salvage this */
7438       gtk_icon_view_update_item_text (icon_view, item->item);
7439       get_pango_text_offsets (icon_view->priv->layout,
7440                               buffer,
7441                               0,
7442                               boundary_type,
7443                               offset,
7444                               start_offset,
7445                               end_offset,
7446                               &start,
7447                               &end);
7448 #endif
7449       break;
7450     }
7451
7452   *start_offset = gtk_text_iter_get_offset (&start);
7453   *end_offset = gtk_text_iter_get_offset (&end);
7454
7455   return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
7456 }
7457
7458 static gchar*
7459 gtk_icon_view_item_accessible_text_get_text_at_offset (AtkText         *text,
7460                                                        gint            offset,
7461                                                        AtkTextBoundary boundary_type,
7462                                                        gint            *start_offset,
7463                                                        gint            *end_offset)
7464 {
7465   GtkIconViewItemAccessible *item;
7466   GtkTextIter start, end;
7467   GtkTextBuffer *buffer;
7468 #if 0
7469   GtkIconView *icon_view;
7470 #endif
7471
7472   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7473
7474   if (!GTK_IS_ICON_VIEW (item->widget))
7475     return NULL;
7476
7477   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7478     return NULL;
7479
7480   buffer = item->text_buffer;
7481
7482   if (!gtk_text_buffer_get_char_count (buffer))
7483     {
7484       *start_offset = 0;
7485       *end_offset = 0;
7486       return g_strdup ("");
7487     }
7488   gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
7489    
7490   end = start;
7491
7492   switch (boundary_type)
7493     {
7494     case ATK_TEXT_BOUNDARY_CHAR:
7495       gtk_text_iter_forward_char (&end);
7496       break;
7497     case ATK_TEXT_BOUNDARY_WORD_START:
7498       if (!gtk_text_iter_starts_word (&start))
7499         gtk_text_iter_backward_word_start (&start);
7500       if (gtk_text_iter_inside_word (&end))
7501         gtk_text_iter_forward_word_end (&end);
7502       while (!gtk_text_iter_starts_word (&end))
7503         {
7504           if (!gtk_text_iter_forward_char (&end))
7505             break;
7506         }
7507       break;
7508     case ATK_TEXT_BOUNDARY_WORD_END:
7509       if (gtk_text_iter_inside_word (&start) &&
7510           !gtk_text_iter_starts_word (&start))
7511         gtk_text_iter_backward_word_start (&start);
7512       while (!gtk_text_iter_ends_word (&start))
7513         {
7514           if (!gtk_text_iter_backward_char (&start))
7515             break;
7516         }
7517       gtk_text_iter_forward_word_end (&end);
7518       break;
7519     case ATK_TEXT_BOUNDARY_SENTENCE_START:
7520       if (!gtk_text_iter_starts_sentence (&start))
7521         gtk_text_iter_backward_sentence_start (&start);
7522       if (gtk_text_iter_inside_sentence (&end))
7523         gtk_text_iter_forward_sentence_end (&end);
7524       while (!gtk_text_iter_starts_sentence (&end))
7525         {
7526           if (!gtk_text_iter_forward_char (&end))
7527             break;
7528         }
7529       break;
7530     case ATK_TEXT_BOUNDARY_SENTENCE_END:
7531       if (gtk_text_iter_inside_sentence (&start) &&
7532           !gtk_text_iter_starts_sentence (&start))
7533         gtk_text_iter_backward_sentence_start (&start);
7534       while (!gtk_text_iter_ends_sentence (&start))
7535         {
7536           if (!gtk_text_iter_backward_char (&start))
7537             break;
7538         }
7539       gtk_text_iter_forward_sentence_end (&end);
7540       break;
7541    case ATK_TEXT_BOUNDARY_LINE_START:
7542    case ATK_TEXT_BOUNDARY_LINE_END:
7543 #if 0
7544       icon_view = GTK_ICON_VIEW (item->widget);
7545       /* FIXME we probably have to use GailTextCell to salvage this */
7546       gtk_icon_view_update_item_text (icon_view, item->item);
7547       get_pango_text_offsets (icon_view->priv->layout,
7548                               buffer,
7549                               1,
7550                               boundary_type,
7551                               offset,
7552                               start_offset,
7553                               end_offset,
7554                               &start,
7555                               &end);
7556 #endif
7557       break;
7558     }
7559
7560
7561   *start_offset = gtk_text_iter_get_offset (&start);
7562   *end_offset = gtk_text_iter_get_offset (&end);
7563
7564   return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
7565 }
7566
7567 static gchar*
7568 gtk_icon_view_item_accessible_text_get_text_after_offset (AtkText         *text,
7569                                                           gint            offset,
7570                                                           AtkTextBoundary boundary_type,
7571                                                           gint            *start_offset,
7572                                                           gint            *end_offset)
7573 {
7574   GtkIconViewItemAccessible *item;
7575   GtkTextIter start, end;
7576   GtkTextBuffer *buffer;
7577 #if 0
7578   GtkIconView *icon_view;
7579 #endif
7580
7581   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7582
7583   if (!GTK_IS_ICON_VIEW (item->widget))
7584     return NULL;
7585
7586   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7587     return NULL;
7588
7589   buffer = item->text_buffer;
7590
7591   if (!gtk_text_buffer_get_char_count (buffer))
7592     {
7593       *start_offset = 0;
7594       *end_offset = 0;
7595       return g_strdup ("");
7596     }
7597   gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
7598    
7599   end = start;
7600
7601   switch (boundary_type)
7602     {
7603     case ATK_TEXT_BOUNDARY_CHAR:
7604       gtk_text_iter_forward_char(&start);
7605       gtk_text_iter_forward_chars(&end, 2);
7606       break;
7607     case ATK_TEXT_BOUNDARY_WORD_START:
7608       if (gtk_text_iter_inside_word (&end))
7609         gtk_text_iter_forward_word_end (&end);
7610       while (!gtk_text_iter_starts_word (&end))
7611         {
7612           if (!gtk_text_iter_forward_char (&end))
7613             break;
7614         }
7615       start = end;
7616       if (!gtk_text_iter_is_end (&end))
7617         {
7618           gtk_text_iter_forward_word_end (&end);
7619           while (!gtk_text_iter_starts_word (&end))
7620             {
7621               if (!gtk_text_iter_forward_char (&end))
7622                 break;
7623             }
7624         }
7625       break;
7626     case ATK_TEXT_BOUNDARY_WORD_END:
7627       gtk_text_iter_forward_word_end (&end);
7628       start = end;
7629       if (!gtk_text_iter_is_end (&end))
7630         gtk_text_iter_forward_word_end (&end);
7631       break;
7632     case ATK_TEXT_BOUNDARY_SENTENCE_START:
7633       if (gtk_text_iter_inside_sentence (&end))
7634         gtk_text_iter_forward_sentence_end (&end);
7635       while (!gtk_text_iter_starts_sentence (&end))
7636         {
7637           if (!gtk_text_iter_forward_char (&end))
7638             break;
7639         }
7640       start = end;
7641       if (!gtk_text_iter_is_end (&end))
7642         {
7643           gtk_text_iter_forward_sentence_end (&end);
7644           while (!gtk_text_iter_starts_sentence (&end))
7645             {
7646               if (!gtk_text_iter_forward_char (&end))
7647                 break;
7648             }
7649         }
7650       break;
7651     case ATK_TEXT_BOUNDARY_SENTENCE_END:
7652       gtk_text_iter_forward_sentence_end (&end);
7653       start = end;
7654       if (!gtk_text_iter_is_end (&end))
7655         gtk_text_iter_forward_sentence_end (&end);
7656       break;
7657    case ATK_TEXT_BOUNDARY_LINE_START:
7658    case ATK_TEXT_BOUNDARY_LINE_END:
7659 #if 0
7660       icon_view = GTK_ICON_VIEW (item->widget);
7661       /* FIXME we probably have to use GailTextCell to salvage this */
7662       gtk_icon_view_update_item_text (icon_view, item->item);
7663       get_pango_text_offsets (icon_view->priv->layout,
7664                               buffer,
7665                               2,
7666                               boundary_type,
7667                               offset,
7668                               start_offset,
7669                               end_offset,
7670                               &start,
7671                               &end);
7672 #endif
7673       break;
7674     }
7675   *start_offset = gtk_text_iter_get_offset (&start);
7676   *end_offset = gtk_text_iter_get_offset (&end);
7677
7678   return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
7679 }
7680
7681 static gint
7682 gtk_icon_view_item_accessible_text_get_character_count (AtkText *text)
7683 {
7684   GtkIconViewItemAccessible *item;
7685
7686   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7687
7688   if (!GTK_IS_ICON_VIEW (item->widget))
7689     return 0;
7690
7691   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7692     return 0;
7693
7694   return gtk_text_buffer_get_char_count (item->text_buffer);
7695 }
7696
7697 static void
7698 gtk_icon_view_item_accessible_text_get_character_extents (AtkText      *text,
7699                                                           gint         offset,
7700                                                           gint         *x,
7701                                                           gint         *y,
7702                                                           gint         *width,
7703                                                           gint         *height,
7704                                                           AtkCoordType coord_type)
7705 {
7706   GtkIconViewItemAccessible *item;
7707 #if 0
7708   GtkIconView *icon_view;
7709   PangoRectangle char_rect;
7710   const gchar *item_text;
7711   gint index;
7712 #endif
7713
7714   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7715
7716   if (!GTK_IS_ICON_VIEW (item->widget))
7717     return;
7718
7719   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7720     return;
7721
7722 #if 0
7723   icon_view = GTK_ICON_VIEW (item->widget);
7724       /* FIXME we probably have to use GailTextCell to salvage this */
7725   gtk_icon_view_update_item_text (icon_view, item->item);
7726   item_text = pango_layout_get_text (icon_view->priv->layout);
7727   index = g_utf8_offset_to_pointer (item_text, offset) - item_text;
7728   pango_layout_index_to_pos (icon_view->priv->layout, index, &char_rect);
7729
7730   atk_component_get_position (ATK_COMPONENT (text), x, y, coord_type);
7731   *x += item->item->layout_x - item->item->x + char_rect.x / PANGO_SCALE;
7732   /* Look at gtk_icon_view_paint_item() to see where the text is. */
7733   *x -=  ((item->item->width - item->item->layout_width) / 2) + (MAX (item->item->pixbuf_width, icon_view->priv->item_width) - item->item->width) / 2,
7734   *y += item->item->layout_y - item->item->y + char_rect.y / PANGO_SCALE;
7735   *width = char_rect.width / PANGO_SCALE;
7736   *height = char_rect.height / PANGO_SCALE;
7737 #endif
7738 }
7739
7740 static gint
7741 gtk_icon_view_item_accessible_text_get_offset_at_point (AtkText      *text,
7742                                                         gint          x,
7743                                                         gint          y,
7744                                                         AtkCoordType coord_type)
7745 {
7746   GtkIconViewItemAccessible *item;
7747   gint offset = 0;
7748 #if 0
7749   GtkIconView *icon_view;
7750   const gchar *item_text;
7751   gint index;
7752   gint l_x, l_y;
7753 #endif
7754
7755   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7756
7757   if (!GTK_IS_ICON_VIEW (item->widget))
7758     return -1;
7759
7760   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7761     return -1;
7762
7763 #if 0
7764   icon_view = GTK_ICON_VIEW (item->widget);
7765       /* FIXME we probably have to use GailTextCell to salvage this */
7766   gtk_icon_view_update_item_text (icon_view, item->item);
7767   atk_component_get_position (ATK_COMPONENT (text), &l_x, &l_y, coord_type);
7768   x -= l_x + item->item->layout_x - item->item->x;
7769   x +=  ((item->item->width - item->item->layout_width) / 2) + (MAX (item->item->pixbuf_width, icon_view->priv->item_width) - item->item->width) / 2,
7770   y -= l_y + item->item->layout_y - item->item->y;
7771   item_text = pango_layout_get_text (icon_view->priv->layout);
7772   if (!pango_layout_xy_to_index (icon_view->priv->layout, 
7773                                 x * PANGO_SCALE,
7774                                 y * PANGO_SCALE,
7775                                 &index, NULL))
7776     {
7777       if (x < 0 || y < 0)
7778         index = 0;
7779       else
7780         index = -1;
7781     } 
7782   if (index == -1)
7783     offset = g_utf8_strlen (item_text, -1);
7784   else
7785     offset = g_utf8_pointer_to_offset (item_text, item_text + index);
7786 #endif
7787   return offset;
7788 }
7789
7790 static void
7791 atk_text_item_interface_init (AtkTextIface *iface)
7792 {
7793   iface->get_text = gtk_icon_view_item_accessible_text_get_text;
7794   iface->get_character_at_offset = gtk_icon_view_item_accessible_text_get_character_at_offset;
7795   iface->get_text_before_offset = gtk_icon_view_item_accessible_text_get_text_before_offset;
7796   iface->get_text_at_offset = gtk_icon_view_item_accessible_text_get_text_at_offset;
7797   iface->get_text_after_offset = gtk_icon_view_item_accessible_text_get_text_after_offset;
7798   iface->get_character_count = gtk_icon_view_item_accessible_text_get_character_count;
7799   iface->get_character_extents = gtk_icon_view_item_accessible_text_get_character_extents;
7800   iface->get_offset_at_point = gtk_icon_view_item_accessible_text_get_offset_at_point;
7801 }
7802
7803 static void
7804 gtk_icon_view_item_accessible_get_extents (AtkComponent *component,
7805                                            gint         *x,
7806                                            gint         *y,
7807                                            gint         *width,
7808                                            gint         *height,
7809                                            AtkCoordType  coord_type)
7810 {
7811   GtkIconViewItemAccessible *item;
7812   AtkObject *parent_obj;
7813   gint l_x, l_y;
7814
7815   g_return_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (component));
7816
7817   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (component);
7818   if (!GTK_IS_WIDGET (item->widget))
7819     return;
7820
7821   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7822     return;
7823
7824   *width = item->item->width;
7825   *height = item->item->height;
7826   if (gtk_icon_view_item_accessible_is_showing (item))
7827     {
7828       parent_obj = gtk_widget_get_accessible (item->widget);
7829       atk_component_get_position (ATK_COMPONENT (parent_obj), &l_x, &l_y, coord_type);
7830       *x = l_x + item->item->x;
7831       *y = l_y + item->item->y;
7832     }
7833   else
7834     {
7835       *x = G_MININT;
7836       *y = G_MININT;
7837     }
7838 }
7839
7840 static gboolean
7841 gtk_icon_view_item_accessible_grab_focus (AtkComponent *component)
7842 {
7843   GtkIconViewItemAccessible *item;
7844   GtkWidget *toplevel;
7845
7846   g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (component), FALSE);
7847
7848   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (component);
7849   if (!GTK_IS_WIDGET (item->widget))
7850     return FALSE;
7851
7852   gtk_widget_grab_focus (item->widget);
7853   gtk_icon_view_set_cursor_item (GTK_ICON_VIEW (item->widget), item->item, -1);
7854   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (item->widget));
7855   if (GTK_WIDGET_TOPLEVEL (toplevel))
7856     gtk_window_present (GTK_WINDOW (toplevel));
7857
7858   return TRUE;
7859 }
7860
7861 static void
7862 atk_component_item_interface_init (AtkComponentIface *iface)
7863 {
7864   iface->get_extents = gtk_icon_view_item_accessible_get_extents;
7865   iface->grab_focus = gtk_icon_view_item_accessible_grab_focus;
7866 }
7867
7868 static gboolean
7869 gtk_icon_view_item_accessible_add_state (GtkIconViewItemAccessible *item,
7870                                          AtkStateType               state_type,
7871                                          gboolean                   emit_signal)
7872 {
7873   gboolean rc;
7874
7875   rc = atk_state_set_add_state (item->state_set, state_type);
7876   /*
7877    * The signal should only be generated if the value changed,
7878    * not when the item is set up.  So states that are set
7879    * initially should pass FALSE as the emit_signal argument.
7880    */
7881
7882   if (emit_signal)
7883     {
7884       atk_object_notify_state_change (ATK_OBJECT (item), state_type, TRUE);
7885       /* If state_type is ATK_STATE_VISIBLE, additional notification */
7886       if (state_type == ATK_STATE_VISIBLE)
7887         g_signal_emit_by_name (item, "visible_data_changed");
7888     }
7889
7890   return rc;
7891 }
7892
7893 static gboolean
7894 gtk_icon_view_item_accessible_remove_state (GtkIconViewItemAccessible *item,
7895                                             AtkStateType               state_type,
7896                                             gboolean                   emit_signal)
7897 {
7898   if (atk_state_set_contains_state (item->state_set, state_type))
7899     {
7900       gboolean rc;
7901
7902       rc = atk_state_set_remove_state (item->state_set, state_type);
7903       /*
7904        * The signal should only be generated if the value changed,
7905        * not when the item is set up.  So states that are set
7906        * initially should pass FALSE as the emit_signal argument.
7907        */
7908
7909       if (emit_signal)
7910         {
7911           atk_object_notify_state_change (ATK_OBJECT (item), state_type, FALSE);
7912           /* If state_type is ATK_STATE_VISIBLE, additional notification */
7913           if (state_type == ATK_STATE_VISIBLE)
7914             g_signal_emit_by_name (item, "visible_data_changed");
7915         }
7916
7917       return rc;
7918     }
7919   else
7920     return FALSE;
7921 }
7922
7923 static gboolean
7924 gtk_icon_view_item_accessible_is_showing (GtkIconViewItemAccessible *item)
7925 {
7926   GtkIconView *icon_view;
7927   GdkRectangle visible_rect;
7928   gboolean is_showing;
7929
7930   /*
7931    * An item is considered "SHOWING" if any part of the item is in the
7932    * visible rectangle.
7933    */
7934
7935   if (!GTK_IS_ICON_VIEW (item->widget))
7936     return FALSE;
7937
7938   if (item->item == NULL)
7939     return FALSE;
7940
7941   icon_view = GTK_ICON_VIEW (item->widget);
7942   visible_rect.x = 0;
7943   if (icon_view->priv->hadjustment)
7944     visible_rect.x += icon_view->priv->hadjustment->value;
7945   visible_rect.y = 0;
7946   if (icon_view->priv->hadjustment)
7947     visible_rect.y += icon_view->priv->vadjustment->value;
7948   visible_rect.width = item->widget->allocation.width;
7949   visible_rect.height = item->widget->allocation.height;
7950
7951   if (((item->item->x + item->item->width) < visible_rect.x) ||
7952      ((item->item->y + item->item->height) < (visible_rect.y)) ||
7953      (item->item->x > (visible_rect.x + visible_rect.width)) ||
7954      (item->item->y > (visible_rect.y + visible_rect.height)))
7955     is_showing =  FALSE;
7956   else
7957     is_showing = TRUE;
7958
7959   return is_showing;
7960 }
7961
7962 static gboolean
7963 gtk_icon_view_item_accessible_set_visibility (GtkIconViewItemAccessible *item,
7964                                               gboolean                   emit_signal)
7965 {
7966   if (gtk_icon_view_item_accessible_is_showing (item))
7967     return gtk_icon_view_item_accessible_add_state (item, ATK_STATE_SHOWING,
7968                                                     emit_signal);
7969   else
7970     return gtk_icon_view_item_accessible_remove_state (item, ATK_STATE_SHOWING,
7971                                                        emit_signal);
7972 }
7973
7974 static void
7975 gtk_icon_view_item_accessible_object_init (GtkIconViewItemAccessible *item)
7976 {
7977   gint i;
7978
7979   item->state_set = atk_state_set_new ();
7980
7981   atk_state_set_add_state (item->state_set, ATK_STATE_ENABLED);
7982   atk_state_set_add_state (item->state_set, ATK_STATE_FOCUSABLE);
7983   atk_state_set_add_state (item->state_set, ATK_STATE_SENSITIVE);
7984   atk_state_set_add_state (item->state_set, ATK_STATE_SELECTABLE);
7985   atk_state_set_add_state (item->state_set, ATK_STATE_VISIBLE);
7986
7987   for (i = 0; i < LAST_ACTION; i++)
7988     item->action_descriptions[i] = NULL;
7989
7990   item->image_description = NULL;
7991
7992   item->action_idle_handler = 0;
7993 }
7994
7995 static void
7996 gtk_icon_view_item_accessible_finalize (GObject *object)
7997 {
7998   GtkIconViewItemAccessible *item;
7999   gint i;
8000
8001   g_return_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (object));
8002
8003   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (object);
8004
8005   if (item->widget)
8006     g_object_remove_weak_pointer (G_OBJECT (item->widget), (gpointer) &item->widget);
8007
8008   if (item->state_set)
8009     g_object_unref (item->state_set);
8010
8011   if (item->text_buffer)
8012      g_object_unref (item->text_buffer);
8013
8014   for (i = 0; i < LAST_ACTION; i++)
8015     g_free (item->action_descriptions[i]);
8016
8017   g_free (item->image_description);
8018
8019   if (item->action_idle_handler)
8020     {
8021       g_source_remove (item->action_idle_handler);
8022       item->action_idle_handler = 0;
8023     }
8024
8025   G_OBJECT_CLASS (accessible_item_parent_class)->finalize (object);
8026 }
8027
8028 static G_CONST_RETURN gchar*
8029 gtk_icon_view_item_accessible_get_name (AtkObject *obj)
8030 {
8031   if (obj->name)
8032     return obj->name;
8033   else
8034     {
8035       GtkIconViewItemAccessible *item;
8036       GtkTextIter start_iter;
8037       GtkTextIter end_iter;
8038
8039       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8040  
8041       gtk_text_buffer_get_start_iter (item->text_buffer, &start_iter); 
8042       gtk_text_buffer_get_end_iter (item->text_buffer, &end_iter); 
8043
8044       return gtk_text_buffer_get_text (item->text_buffer, &start_iter, &end_iter, FALSE);
8045     }
8046 }
8047
8048 static AtkObject*
8049 gtk_icon_view_item_accessible_get_parent (AtkObject *obj)
8050 {
8051   GtkIconViewItemAccessible *item;
8052
8053   g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (obj), NULL);
8054   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8055
8056   if (item->widget)
8057     return gtk_widget_get_accessible (item->widget);
8058   else
8059     return NULL;
8060 }
8061
8062 static gint
8063 gtk_icon_view_item_accessible_get_index_in_parent (AtkObject *obj)
8064 {
8065   GtkIconViewItemAccessible *item;
8066
8067   g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (obj), 0);
8068   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8069
8070   return item->item->index; 
8071 }
8072
8073 static AtkStateSet *
8074 gtk_icon_view_item_accessible_ref_state_set (AtkObject *obj)
8075 {
8076   GtkIconViewItemAccessible *item;
8077   GtkIconView *icon_view;
8078
8079   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8080   g_return_val_if_fail (item->state_set, NULL);
8081
8082   if (!item->widget)
8083     return NULL;
8084
8085   icon_view = GTK_ICON_VIEW (item->widget);
8086   if (icon_view->priv->cursor_item == item->item)
8087     atk_state_set_add_state (item->state_set, ATK_STATE_FOCUSED);
8088   else
8089     atk_state_set_remove_state (item->state_set, ATK_STATE_FOCUSED);
8090
8091   return g_object_ref (item->state_set);
8092 }
8093
8094 static void
8095 gtk_icon_view_item_accessible_class_init (AtkObjectClass *klass)
8096 {
8097   GObjectClass *gobject_class;
8098
8099   accessible_item_parent_class = g_type_class_peek_parent (klass);
8100
8101   gobject_class = (GObjectClass *)klass;
8102
8103   gobject_class->finalize = gtk_icon_view_item_accessible_finalize;
8104
8105   klass->get_index_in_parent = gtk_icon_view_item_accessible_get_index_in_parent; 
8106   klass->get_name = gtk_icon_view_item_accessible_get_name; 
8107   klass->get_parent = gtk_icon_view_item_accessible_get_parent; 
8108   klass->ref_state_set = gtk_icon_view_item_accessible_ref_state_set; 
8109 }
8110
8111 static GType
8112 gtk_icon_view_item_accessible_get_type (void)
8113 {
8114   static GType type = 0;
8115
8116   if (!type)
8117     {
8118       const GTypeInfo tinfo =
8119       {
8120         sizeof (GtkIconViewItemAccessibleClass),
8121         (GBaseInitFunc) NULL, /* base init */
8122         (GBaseFinalizeFunc) NULL, /* base finalize */
8123         (GClassInitFunc) gtk_icon_view_item_accessible_class_init, /* class init */
8124         (GClassFinalizeFunc) NULL, /* class finalize */
8125         NULL, /* class data */
8126         sizeof (GtkIconViewItemAccessible), /* instance size */
8127         0, /* nb preallocs */
8128         (GInstanceInitFunc) gtk_icon_view_item_accessible_object_init, /* instance init */
8129         NULL /* value table */
8130       };
8131
8132       static const GInterfaceInfo atk_component_info =
8133       {
8134         (GInterfaceInitFunc) atk_component_item_interface_init,
8135         (GInterfaceFinalizeFunc) NULL,
8136         NULL
8137       };
8138       static const GInterfaceInfo atk_action_info =
8139       {
8140         (GInterfaceInitFunc) atk_action_item_interface_init,
8141         (GInterfaceFinalizeFunc) NULL,
8142         NULL
8143       };
8144       static const GInterfaceInfo atk_image_info =
8145       {
8146         (GInterfaceInitFunc) atk_image_item_interface_init,
8147         (GInterfaceFinalizeFunc) NULL,
8148         NULL
8149       };
8150       static const GInterfaceInfo atk_text_info =
8151       {
8152         (GInterfaceInitFunc) atk_text_item_interface_init,
8153         (GInterfaceFinalizeFunc) NULL,
8154         NULL
8155       };
8156
8157       type = g_type_register_static (ATK_TYPE_OBJECT,
8158                                      I_("GtkIconViewItemAccessible"), &tinfo, 0);
8159       g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
8160                                    &atk_component_info);
8161       g_type_add_interface_static (type, ATK_TYPE_ACTION,
8162                                    &atk_action_info);
8163       g_type_add_interface_static (type, ATK_TYPE_IMAGE,
8164                                    &atk_image_info);
8165       g_type_add_interface_static (type, ATK_TYPE_TEXT,
8166                                    &atk_text_info);
8167     }
8168
8169   return type;
8170 }
8171
8172 #define GTK_TYPE_ICON_VIEW_ACCESSIBLE      (gtk_icon_view_accessible_get_type ())
8173 #define GTK_ICON_VIEW_ACCESSIBLE(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ICON_VIEW_ACCESSIBLE, GtkIconViewAccessible))
8174 #define GTK_IS_ICON_VIEW_ACCESSIBLE(obj)   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ICON_VIEW_ACCESSIBLE))
8175
8176 static GType gtk_icon_view_accessible_get_type (void);
8177
8178 typedef struct
8179 {
8180    AtkObject parent;
8181 } GtkIconViewAccessible;
8182
8183 typedef struct
8184 {
8185   AtkObject *item;
8186   gint       index;
8187 } GtkIconViewItemAccessibleInfo;
8188
8189 typedef struct
8190 {
8191   GList *items;
8192
8193   GtkAdjustment *old_hadj;
8194   GtkAdjustment *old_vadj;
8195
8196   GtkTreeModel *model;
8197
8198 } GtkIconViewAccessiblePrivate;
8199
8200 static GtkIconViewAccessiblePrivate *
8201 gtk_icon_view_accessible_get_priv (AtkObject *accessible)
8202 {
8203   return g_object_get_qdata (G_OBJECT (accessible),
8204                              accessible_private_data_quark);
8205 }
8206
8207 static void
8208 gtk_icon_view_item_accessible_info_new (AtkObject *accessible,
8209                                         AtkObject *item,
8210                                         gint       index)
8211 {
8212   GtkIconViewItemAccessibleInfo *info;
8213   GtkIconViewItemAccessibleInfo *tmp_info;
8214   GtkIconViewAccessiblePrivate *priv;
8215   GList *items;
8216
8217   info = g_new (GtkIconViewItemAccessibleInfo, 1);
8218   info->item = item;
8219   info->index = index;
8220
8221   priv = gtk_icon_view_accessible_get_priv (accessible);
8222   items = priv->items;
8223   while (items)
8224     {
8225       tmp_info = items->data;
8226       if (tmp_info->index > index)
8227         break;
8228       items = items->next;
8229     }
8230   priv->items = g_list_insert_before (priv->items, items, info);
8231   priv->old_hadj = NULL;
8232   priv->old_vadj = NULL;
8233 }
8234
8235 static gint
8236 gtk_icon_view_accessible_get_n_children (AtkObject *accessible)
8237 {
8238   GtkIconView *icon_view;
8239   GtkWidget *widget;
8240
8241   widget = GTK_ACCESSIBLE (accessible)->widget;
8242   if (!widget)
8243       return 0;
8244
8245   icon_view = GTK_ICON_VIEW (widget);
8246
8247   return g_list_length (icon_view->priv->items);
8248 }
8249
8250 static AtkObject *
8251 gtk_icon_view_accessible_find_child (AtkObject *accessible,
8252                                      gint       index)
8253 {
8254   GtkIconViewAccessiblePrivate *priv;
8255   GtkIconViewItemAccessibleInfo *info;
8256   GList *items;
8257
8258   priv = gtk_icon_view_accessible_get_priv (accessible);
8259   items = priv->items;
8260
8261   while (items)
8262     {
8263       info = items->data;
8264       if (info->index == index)
8265         return info->item;
8266       items = items->next; 
8267     }
8268   return NULL;
8269 }
8270
8271 static AtkObject *
8272 gtk_icon_view_accessible_ref_child (AtkObject *accessible,
8273                                     gint       index)
8274 {
8275   GtkIconView *icon_view;
8276   GtkWidget *widget;
8277   GList *icons;
8278   AtkObject *obj;
8279   GtkIconViewItemAccessible *a11y_item;
8280
8281   widget = GTK_ACCESSIBLE (accessible)->widget;
8282   if (!widget)
8283     return NULL;
8284
8285   icon_view = GTK_ICON_VIEW (widget);
8286   icons = g_list_nth (icon_view->priv->items, index);
8287   obj = NULL;
8288   if (icons)
8289     {
8290       GtkIconViewItem *item = icons->data;
8291    
8292       g_return_val_if_fail (item->index == index, NULL);
8293       obj = gtk_icon_view_accessible_find_child (accessible, index);
8294       if (!obj)
8295         {
8296           obj = g_object_new (gtk_icon_view_item_accessible_get_type (), NULL);
8297           gtk_icon_view_item_accessible_info_new (accessible,
8298                                                   obj,
8299                                                   index);
8300           obj->role = ATK_ROLE_ICON;
8301           a11y_item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8302           a11y_item->item = item;
8303           a11y_item->widget = widget;
8304           a11y_item->text_buffer = gtk_text_buffer_new (NULL);
8305
8306           gtk_icon_view_set_cell_data (icon_view, item);
8307           gtk_text_buffer_set_text (a11y_item->text_buffer, 
8308                                     get_text (icon_view, item), -1);
8309
8310           gtk_icon_view_item_accessible_set_visibility (a11y_item, FALSE);
8311           g_object_add_weak_pointer (G_OBJECT (widget), (gpointer) &(a11y_item->widget));
8312        }
8313       g_object_ref (obj);
8314     }
8315   return obj;
8316 }
8317
8318 static void
8319 gtk_icon_view_accessible_traverse_items (GtkIconViewAccessible *view,
8320                                          GList                 *list)
8321 {
8322   GtkIconViewAccessiblePrivate *priv;
8323   GtkIconViewItemAccessibleInfo *info;
8324   GtkIconViewItemAccessible *item;
8325   GList *items;
8326   
8327   priv =  gtk_icon_view_accessible_get_priv (ATK_OBJECT (view));
8328   if (priv->items)
8329     {
8330       GtkWidget *widget;
8331       gboolean act_on_item;
8332
8333       widget = GTK_ACCESSIBLE (view)->widget;
8334       if (widget == NULL)
8335         return;
8336
8337       items = priv->items;
8338
8339       act_on_item = (list == NULL);
8340
8341       while (items)
8342         {
8343
8344           info = (GtkIconViewItemAccessibleInfo *)items->data;
8345           item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
8346
8347           if (act_on_item == FALSE && list == items)
8348             act_on_item = TRUE;
8349
8350           if (act_on_item)
8351             gtk_icon_view_item_accessible_set_visibility (item, TRUE);
8352
8353           items = items->next;
8354        }
8355    }
8356 }
8357
8358 static void
8359 gtk_icon_view_accessible_adjustment_changed (GtkAdjustment *adjustment,
8360                                              GtkIconView   *icon_view)
8361 {
8362   AtkObject *obj;
8363   GtkIconViewAccessible *view;
8364
8365   /*
8366    * The scrollbars have changed
8367    */
8368   obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
8369   view = GTK_ICON_VIEW_ACCESSIBLE (obj);
8370
8371   gtk_icon_view_accessible_traverse_items (view, NULL);
8372 }
8373
8374 static void
8375 gtk_icon_view_accessible_set_scroll_adjustments (GtkWidget      *widget,
8376                                                  GtkAdjustment *hadj,
8377                                                  GtkAdjustment *vadj)
8378 {
8379   AtkObject *atk_obj;
8380   GtkIconViewAccessiblePrivate *priv;
8381
8382   atk_obj = gtk_widget_get_accessible (widget);
8383   priv = gtk_icon_view_accessible_get_priv (atk_obj);
8384
8385   if (priv->old_hadj != hadj)
8386     {
8387       if (priv->old_hadj)
8388         {
8389           g_object_remove_weak_pointer (G_OBJECT (priv->old_hadj),
8390                                         (gpointer *)&priv->old_hadj);
8391           
8392           g_signal_handlers_disconnect_by_func (priv->old_hadj,
8393                                                 (gpointer) gtk_icon_view_accessible_adjustment_changed,
8394                                                 widget);
8395         }
8396       priv->old_hadj = hadj;
8397       if (priv->old_hadj)
8398         {
8399           g_object_add_weak_pointer (G_OBJECT (priv->old_hadj),
8400                                      (gpointer *)&priv->old_hadj);
8401           g_signal_connect (hadj,
8402                             "value-changed",
8403                             G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
8404                             widget);
8405         }
8406     }
8407   if (priv->old_vadj != vadj)
8408     {
8409       if (priv->old_vadj)
8410         {
8411           g_object_remove_weak_pointer (G_OBJECT (priv->old_vadj),
8412                                         (gpointer *)&priv->old_vadj);
8413           
8414           g_signal_handlers_disconnect_by_func (priv->old_vadj,
8415                                                 (gpointer) gtk_icon_view_accessible_adjustment_changed,
8416                                                 widget);
8417         }
8418       priv->old_vadj = vadj;
8419       if (priv->old_vadj)
8420         {
8421           g_object_add_weak_pointer (G_OBJECT (priv->old_vadj),
8422                                      (gpointer *)&priv->old_vadj);
8423           g_signal_connect (vadj,
8424                             "value-changed",
8425                             G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
8426                             widget);
8427         }
8428     }
8429 }
8430
8431 static void
8432 gtk_icon_view_accessible_model_row_changed (GtkTreeModel *tree_model,
8433                                             GtkTreePath  *path,
8434                                             GtkTreeIter  *iter,
8435                                             gpointer     user_data)
8436 {
8437   AtkObject *atk_obj;
8438
8439   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
8440   g_signal_emit_by_name (atk_obj, "visible_data_changed");
8441
8442   return;
8443 }
8444
8445 static void
8446 gtk_icon_view_accessible_model_row_inserted (GtkTreeModel *tree_model,
8447                                              GtkTreePath  *path,
8448                                              GtkTreeIter  *iter,
8449                                              gpointer     user_data)
8450 {
8451   GtkIconViewAccessiblePrivate *priv;
8452   GtkIconViewItemAccessibleInfo *info;
8453   GtkIconViewAccessible *view;
8454   GtkIconViewItemAccessible *item;
8455   GList *items;
8456   GList *tmp_list;
8457   AtkObject *atk_obj;
8458   gint index;
8459
8460   index = gtk_tree_path_get_indices(path)[0];
8461   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
8462   view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
8463   priv = gtk_icon_view_accessible_get_priv (atk_obj);
8464
8465   items = priv->items;
8466   tmp_list = NULL;
8467   while (items)
8468     {
8469       info = items->data;
8470       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
8471       if (info->index != item->item->index)
8472         {
8473           if (info->index < index)
8474             g_warning ("Unexpected index value on insertion %d %d", index, info->index);
8475  
8476           if (tmp_list == NULL)
8477             tmp_list = items;
8478    
8479           info->index = item->item->index;
8480         }
8481
8482       items = items->next;
8483     }
8484   gtk_icon_view_accessible_traverse_items (view, tmp_list);
8485   g_signal_emit_by_name (atk_obj, "children_changed::add",
8486                          index, NULL, NULL);
8487   return;
8488 }
8489
8490 static void
8491 gtk_icon_view_accessible_model_row_deleted (GtkTreeModel *tree_model,
8492                                             GtkTreePath  *path,
8493                                             gpointer     user_data)
8494 {
8495   GtkIconViewAccessiblePrivate *priv;
8496   GtkIconViewItemAccessibleInfo *info;
8497   GtkIconViewAccessible *view;
8498   GtkIconViewItemAccessible *item;
8499   GList *items;
8500   GList *tmp_list;
8501   GList *deleted_item;
8502   AtkObject *atk_obj;
8503   gint index;
8504
8505   index = gtk_tree_path_get_indices(path)[0];
8506   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
8507   view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
8508   priv = gtk_icon_view_accessible_get_priv (atk_obj);
8509
8510   items = priv->items;
8511   tmp_list = NULL;
8512   deleted_item = NULL;
8513   info = NULL;
8514   while (items)
8515     {
8516       info = items->data;
8517       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
8518       if (info->index == index)
8519         {
8520           deleted_item = items;
8521         }
8522       if (info->index != item->item->index)
8523         {
8524           if (tmp_list == NULL)
8525             tmp_list = items;
8526           else    
8527             info->index = item->item->index;
8528         }
8529
8530       items = items->next;
8531     }
8532   gtk_icon_view_accessible_traverse_items (view, tmp_list);
8533   if (deleted_item)
8534     {
8535       info = deleted_item->data;
8536       gtk_icon_view_item_accessible_add_state (GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item), ATK_STATE_DEFUNCT, TRUE);
8537     }
8538   g_signal_emit_by_name (atk_obj, "children_changed::remove",
8539                          index, NULL, NULL);
8540   if (deleted_item)
8541     {
8542       priv->items = g_list_remove_link (priv->items, deleted_item);
8543       g_free (info);
8544     }
8545
8546   return;
8547 }
8548
8549 static gint
8550 gtk_icon_view_accessible_item_compare (GtkIconViewItemAccessibleInfo *i1,
8551                                        GtkIconViewItemAccessibleInfo *i2)
8552 {
8553   return i1->index - i2->index;
8554 }
8555
8556 static void
8557 gtk_icon_view_accessible_model_rows_reordered (GtkTreeModel *tree_model,
8558                                                GtkTreePath  *path,
8559                                                GtkTreeIter  *iter,
8560                                                gint         *new_order,
8561                                                gpointer     user_data)
8562 {
8563   GtkIconViewAccessiblePrivate *priv;
8564   GtkIconViewItemAccessibleInfo *info;
8565   GtkIconView *icon_view;
8566   GtkIconViewItemAccessible *item;
8567   GList *items;
8568   AtkObject *atk_obj;
8569
8570   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
8571   icon_view = GTK_ICON_VIEW (user_data);
8572   priv = gtk_icon_view_accessible_get_priv (atk_obj);
8573
8574   items = priv->items;
8575   while (items)
8576     {
8577       info = items->data;
8578       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
8579       info->index = new_order[info->index];
8580       item->item = g_list_nth_data (icon_view->priv->items, info->index);
8581       items = items->next;
8582     }
8583   priv->items = g_list_sort (priv->items, 
8584                              (GCompareFunc)gtk_icon_view_accessible_item_compare);
8585
8586   return;
8587 }
8588
8589 static void
8590 gtk_icon_view_accessible_disconnect_model_signals (GtkTreeModel *model,
8591                                                    GtkWidget *widget)
8592 {
8593   GObject *obj;
8594
8595   obj = G_OBJECT (model);
8596   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_changed, widget);
8597   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_inserted, widget);
8598   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_deleted, widget);
8599   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_rows_reordered, widget);
8600 }
8601
8602 static void
8603 gtk_icon_view_accessible_connect_model_signals (GtkIconView *icon_view)
8604 {
8605   GObject *obj;
8606
8607   obj = G_OBJECT (icon_view->priv->model);
8608   g_signal_connect_data (obj, "row_changed",
8609                          (GCallback) gtk_icon_view_accessible_model_row_changed,
8610                          icon_view, NULL, 0);
8611   g_signal_connect_data (obj, "row_inserted",
8612                          (GCallback) gtk_icon_view_accessible_model_row_inserted, 
8613                          icon_view, NULL, G_CONNECT_AFTER);
8614   g_signal_connect_data (obj, "row_deleted",
8615                          (GCallback) gtk_icon_view_accessible_model_row_deleted, 
8616                          icon_view, NULL, G_CONNECT_AFTER);
8617   g_signal_connect_data (obj, "rows_reordered",
8618                          (GCallback) gtk_icon_view_accessible_model_rows_reordered, 
8619                          icon_view, NULL, G_CONNECT_AFTER);
8620 }
8621
8622 static void
8623 gtk_icon_view_accessible_clear_cache (GtkIconViewAccessiblePrivate *priv)
8624 {
8625   GtkIconViewItemAccessibleInfo *info;
8626   GList *items;
8627
8628   items = priv->items;
8629   while (items)
8630     {
8631       info = (GtkIconViewItemAccessibleInfo *) items->data;
8632       g_object_unref (info->item);
8633       g_free (items->data);
8634       items = items->next;
8635     }
8636   g_list_free (priv->items);
8637   priv->items = NULL;
8638 }
8639
8640 static void
8641 gtk_icon_view_accessible_notify_gtk (GObject *obj,
8642                                      GParamSpec *pspec)
8643 {
8644   GtkIconView *icon_view;
8645   GtkWidget *widget;
8646   AtkObject *atk_obj;
8647   GtkIconViewAccessiblePrivate *priv;
8648
8649   if (strcmp (pspec->name, "model") == 0)
8650     {
8651       widget = GTK_WIDGET (obj); 
8652       atk_obj = gtk_widget_get_accessible (widget);
8653       priv = gtk_icon_view_accessible_get_priv (atk_obj);
8654       if (priv->model)
8655         {
8656           g_object_remove_weak_pointer (G_OBJECT (priv->model),
8657                                         (gpointer *)&priv->model);
8658           gtk_icon_view_accessible_disconnect_model_signals (priv->model, widget);
8659         }
8660       gtk_icon_view_accessible_clear_cache (priv);
8661
8662       icon_view = GTK_ICON_VIEW (obj);
8663       priv->model = icon_view->priv->model;
8664       /* If there is no model the GtkIconView is probably being destroyed */
8665       if (priv->model)
8666         {
8667           g_object_add_weak_pointer (G_OBJECT (priv->model), (gpointer *)&priv->model);
8668           gtk_icon_view_accessible_connect_model_signals (icon_view);
8669         }
8670     }
8671
8672   return;
8673 }
8674
8675 static void
8676 gtk_icon_view_accessible_initialize (AtkObject *accessible,
8677                                      gpointer   data)
8678 {
8679   GtkIconViewAccessiblePrivate *priv;
8680   GtkIconView *icon_view;
8681
8682   if (ATK_OBJECT_CLASS (accessible_parent_class)->initialize)
8683     ATK_OBJECT_CLASS (accessible_parent_class)->initialize (accessible, data);
8684
8685   priv = g_new0 (GtkIconViewAccessiblePrivate, 1);
8686   g_object_set_qdata (G_OBJECT (accessible),
8687                       accessible_private_data_quark,
8688                       priv);
8689
8690   icon_view = GTK_ICON_VIEW (data);
8691   if (icon_view->priv->hadjustment)
8692     {
8693       priv->old_hadj = icon_view->priv->hadjustment;
8694       g_object_add_weak_pointer (G_OBJECT (priv->old_hadj), (gpointer *)&priv->old_hadj);
8695       g_signal_connect (icon_view->priv->hadjustment,
8696                         "value-changed",
8697                         G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
8698                         icon_view);
8699     } 
8700   if (icon_view->priv->vadjustment)
8701     {
8702       priv->old_vadj = icon_view->priv->vadjustment;
8703       g_object_add_weak_pointer (G_OBJECT (priv->old_vadj), (gpointer *)&priv->old_vadj);
8704       g_signal_connect (icon_view->priv->vadjustment,
8705                         "value-changed",
8706                         G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
8707                         icon_view);
8708     }
8709   g_signal_connect_after (data,
8710                           "set_scroll_adjustments",
8711                           G_CALLBACK (gtk_icon_view_accessible_set_scroll_adjustments),
8712                           NULL);
8713   g_signal_connect (data,
8714                     "notify",
8715                     G_CALLBACK (gtk_icon_view_accessible_notify_gtk),
8716                     NULL);
8717
8718   priv->model = icon_view->priv->model;
8719   if (priv->model)
8720     {
8721       g_object_add_weak_pointer (G_OBJECT (priv->model), (gpointer *)&priv->model);
8722       gtk_icon_view_accessible_connect_model_signals (icon_view);
8723     }
8724                           
8725   accessible->role = ATK_ROLE_LAYERED_PANE;
8726 }
8727
8728 static void
8729 gtk_icon_view_accessible_finalize (GObject *object)
8730 {
8731   GtkIconViewAccessiblePrivate *priv;
8732
8733   priv = gtk_icon_view_accessible_get_priv (ATK_OBJECT (object));
8734   gtk_icon_view_accessible_clear_cache (priv);
8735
8736   g_free (priv);
8737
8738   G_OBJECT_CLASS (accessible_parent_class)->finalize (object);
8739 }
8740
8741 static void
8742 gtk_icon_view_accessible_destroyed (GtkWidget *widget,
8743                                     GtkAccessible *accessible)
8744 {
8745   AtkObject *atk_obj;
8746   GtkIconViewAccessiblePrivate *priv;
8747
8748   atk_obj = ATK_OBJECT (accessible);
8749   priv = gtk_icon_view_accessible_get_priv (atk_obj);
8750   if (priv->old_hadj)
8751     {
8752       g_object_remove_weak_pointer (G_OBJECT (priv->old_hadj),
8753                                     (gpointer *)&priv->old_hadj);
8754           
8755       g_signal_handlers_disconnect_by_func (priv->old_hadj,
8756                                             (gpointer) gtk_icon_view_accessible_adjustment_changed,
8757                                             widget);
8758       priv->old_hadj = NULL;
8759     }
8760   if (priv->old_vadj)
8761     {
8762       g_object_remove_weak_pointer (G_OBJECT (priv->old_vadj),
8763                                     (gpointer *)&priv->old_vadj);
8764           
8765       g_signal_handlers_disconnect_by_func (priv->old_vadj,
8766                                             (gpointer) gtk_icon_view_accessible_adjustment_changed,
8767                                             widget);
8768       priv->old_vadj = NULL;
8769     }
8770 }
8771
8772 static void
8773 gtk_icon_view_accessible_connect_widget_destroyed (GtkAccessible *accessible)
8774 {
8775   if (accessible->widget)
8776     {
8777       g_signal_connect_after (accessible->widget,
8778                               "destroy",
8779                               G_CALLBACK (gtk_icon_view_accessible_destroyed),
8780                               accessible);
8781     }
8782   GTK_ACCESSIBLE_CLASS (accessible_parent_class)->connect_widget_destroyed (accessible);
8783 }
8784
8785 static void
8786 gtk_icon_view_accessible_class_init (AtkObjectClass *klass)
8787 {
8788   GObjectClass *gobject_class;
8789   GtkAccessibleClass *accessible_class;
8790
8791   accessible_parent_class = g_type_class_peek_parent (klass);
8792
8793   gobject_class = (GObjectClass *)klass;
8794   accessible_class = (GtkAccessibleClass *)klass;
8795
8796   gobject_class->finalize = gtk_icon_view_accessible_finalize;
8797
8798   klass->get_n_children = gtk_icon_view_accessible_get_n_children;
8799   klass->ref_child = gtk_icon_view_accessible_ref_child;
8800   klass->initialize = gtk_icon_view_accessible_initialize;
8801
8802   accessible_class->connect_widget_destroyed = gtk_icon_view_accessible_connect_widget_destroyed;
8803
8804   accessible_private_data_quark = g_quark_from_static_string ("icon_view-accessible-private-data");
8805 }
8806
8807 static AtkObject*
8808 gtk_icon_view_accessible_ref_accessible_at_point (AtkComponent *component,
8809                                                   gint          x,
8810                                                   gint          y,
8811                                                   AtkCoordType  coord_type)
8812 {
8813   GtkWidget *widget;
8814   GtkIconView *icon_view;
8815   GtkIconViewItem *item;
8816   gint x_pos, y_pos;
8817
8818   widget = GTK_ACCESSIBLE (component)->widget;
8819   if (widget == NULL)
8820   /* State is defunct */
8821     return NULL;
8822
8823   icon_view = GTK_ICON_VIEW (widget);
8824   atk_component_get_extents (component, &x_pos, &y_pos, NULL, NULL, coord_type);
8825   item = gtk_icon_view_get_item_at_coords (icon_view, x - x_pos, y - y_pos, TRUE, NULL);
8826   if (item)
8827     return gtk_icon_view_accessible_ref_child (ATK_OBJECT (component), item->index);
8828
8829   return NULL;
8830 }
8831
8832 static void
8833 atk_component_interface_init (AtkComponentIface *iface)
8834 {
8835   iface->ref_accessible_at_point = gtk_icon_view_accessible_ref_accessible_at_point;
8836 }
8837
8838 static gboolean
8839 gtk_icon_view_accessible_add_selection (AtkSelection *selection,
8840                                         gint i)
8841 {
8842   GtkWidget *widget;
8843   GtkIconView *icon_view;
8844   GtkIconViewItem *item;
8845
8846   widget = GTK_ACCESSIBLE (selection)->widget;
8847   if (widget == NULL)
8848     return FALSE;
8849
8850   icon_view = GTK_ICON_VIEW (widget);
8851
8852   item = g_list_nth_data (icon_view->priv->items, i);
8853
8854   if (!item)
8855     return FALSE;
8856
8857   gtk_icon_view_select_item (icon_view, item);
8858
8859   return TRUE;
8860 }
8861
8862 static gboolean
8863 gtk_icon_view_accessible_clear_selection (AtkSelection *selection)
8864 {
8865   GtkWidget *widget;
8866   GtkIconView *icon_view;
8867
8868   widget = GTK_ACCESSIBLE (selection)->widget;
8869   if (widget == NULL)
8870     return FALSE;
8871
8872   icon_view = GTK_ICON_VIEW (widget);
8873   gtk_icon_view_unselect_all (icon_view);
8874
8875   return TRUE;
8876 }
8877
8878 static AtkObject*
8879 gtk_icon_view_accessible_ref_selection (AtkSelection *selection,
8880                                         gint          i)
8881 {
8882   GList *l;
8883   GtkWidget *widget;
8884   GtkIconView *icon_view;
8885   GtkIconViewItem *item;
8886
8887   widget = GTK_ACCESSIBLE (selection)->widget;
8888   if (widget == NULL)
8889     return NULL;
8890
8891   icon_view = GTK_ICON_VIEW (widget);
8892
8893   l = icon_view->priv->items;
8894   while (l)
8895     {
8896       item = l->data;
8897       if (item->selected)
8898         {
8899           if (i == 0)
8900             return atk_object_ref_accessible_child (gtk_widget_get_accessible (widget), item->index);
8901           else
8902             i--;
8903         }
8904       l = l->next;
8905     }
8906
8907   return NULL;
8908 }
8909
8910 static gint
8911 gtk_icon_view_accessible_get_selection_count (AtkSelection *selection)
8912 {
8913   GtkWidget *widget;
8914   GtkIconView *icon_view;
8915   GtkIconViewItem *item;
8916   GList *l;
8917   gint count;
8918
8919   widget = GTK_ACCESSIBLE (selection)->widget;
8920   if (widget == NULL)
8921     return 0;
8922
8923   icon_view = GTK_ICON_VIEW (widget);
8924
8925   l = icon_view->priv->items;
8926   count = 0;
8927   while (l)
8928     {
8929       item = l->data;
8930
8931       if (item->selected)
8932         count++;
8933
8934       l = l->next;
8935     }
8936
8937   return count;
8938 }
8939
8940 static gboolean
8941 gtk_icon_view_accessible_is_child_selected (AtkSelection *selection,
8942                                             gint          i)
8943 {
8944   GtkWidget *widget;
8945   GtkIconView *icon_view;
8946   GtkIconViewItem *item;
8947
8948   widget = GTK_ACCESSIBLE (selection)->widget;
8949   if (widget == NULL)
8950     return FALSE;
8951
8952   icon_view = GTK_ICON_VIEW (widget);
8953
8954   item = g_list_nth_data (icon_view->priv->items, i);
8955   if (!item)
8956     return FALSE;
8957
8958   return item->selected;
8959 }
8960
8961 static gboolean
8962 gtk_icon_view_accessible_remove_selection (AtkSelection *selection,
8963                                            gint          i)
8964 {
8965   GtkWidget *widget;
8966   GtkIconView *icon_view;
8967   GtkIconViewItem *item;
8968   GList *l;
8969   gint count;
8970
8971   widget = GTK_ACCESSIBLE (selection)->widget;
8972   if (widget == NULL)
8973     return FALSE;
8974
8975   icon_view = GTK_ICON_VIEW (widget);
8976   l = icon_view->priv->items;
8977   count = 0;
8978   while (l)
8979     {
8980       item = l->data;
8981       if (item->selected)
8982         {
8983           if (count == i)
8984             {
8985               gtk_icon_view_unselect_item (icon_view, item);
8986               return TRUE;
8987             }
8988           count++;
8989         }
8990       l = l->next;
8991     }
8992
8993   return FALSE;
8994 }
8995  
8996 static gboolean
8997 gtk_icon_view_accessible_select_all_selection (AtkSelection *selection)
8998 {
8999   GtkWidget *widget;
9000   GtkIconView *icon_view;
9001
9002   widget = GTK_ACCESSIBLE (selection)->widget;
9003   if (widget == NULL)
9004     return FALSE;
9005
9006   icon_view = GTK_ICON_VIEW (widget);
9007   gtk_icon_view_select_all (icon_view);
9008   return TRUE;
9009 }
9010
9011 static void
9012 gtk_icon_view_accessible_selection_interface_init (AtkSelectionIface *iface)
9013 {
9014   iface->add_selection = gtk_icon_view_accessible_add_selection;
9015   iface->clear_selection = gtk_icon_view_accessible_clear_selection;
9016   iface->ref_selection = gtk_icon_view_accessible_ref_selection;
9017   iface->get_selection_count = gtk_icon_view_accessible_get_selection_count;
9018   iface->is_child_selected = gtk_icon_view_accessible_is_child_selected;
9019   iface->remove_selection = gtk_icon_view_accessible_remove_selection;
9020   iface->select_all_selection = gtk_icon_view_accessible_select_all_selection;
9021 }
9022
9023 static GType
9024 gtk_icon_view_accessible_get_type (void)
9025 {
9026   static GType type = 0;
9027
9028   if (!type)
9029     {
9030       static GTypeInfo tinfo =
9031       {
9032         0, /* class size */
9033         (GBaseInitFunc) NULL, /* base init */
9034         (GBaseFinalizeFunc) NULL, /* base finalize */
9035         (GClassInitFunc) gtk_icon_view_accessible_class_init,
9036         (GClassFinalizeFunc) NULL, /* class finalize */
9037         NULL, /* class data */
9038         0, /* instance size */
9039         0, /* nb preallocs */
9040         (GInstanceInitFunc) NULL, /* instance init */
9041         NULL /* value table */
9042       };
9043       static const GInterfaceInfo atk_component_info =
9044       {
9045         (GInterfaceInitFunc) atk_component_interface_init,
9046         (GInterfaceFinalizeFunc) NULL,
9047         NULL
9048       };
9049       static const GInterfaceInfo atk_selection_info = 
9050       {
9051         (GInterfaceInitFunc) gtk_icon_view_accessible_selection_interface_init,
9052         (GInterfaceFinalizeFunc) NULL,
9053         NULL
9054       };
9055
9056       /*
9057        * Figure out the size of the class and instance
9058        * we are deriving from
9059        */
9060       AtkObjectFactory *factory;
9061       GType derived_type;
9062       GTypeQuery query;
9063       GType derived_atk_type;
9064
9065       derived_type = g_type_parent (GTK_TYPE_ICON_VIEW);
9066       factory = atk_registry_get_factory (atk_get_default_registry (), 
9067                                           derived_type);
9068       derived_atk_type = atk_object_factory_get_accessible_type (factory);
9069       g_type_query (derived_atk_type, &query);
9070       tinfo.class_size = query.class_size;
9071       tinfo.instance_size = query.instance_size;
9072  
9073       type = g_type_register_static (derived_atk_type, 
9074                                      I_("GtkIconViewAccessible"), 
9075                                      &tinfo, 0);
9076       g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
9077                                    &atk_component_info);
9078       g_type_add_interface_static (type, ATK_TYPE_SELECTION,
9079                                    &atk_selection_info);
9080     }
9081   return type;
9082 }
9083
9084 static AtkObject *
9085 gtk_icon_view_accessible_new (GObject *obj)
9086 {
9087   AtkObject *accessible;
9088
9089   g_return_val_if_fail (GTK_IS_WIDGET (obj), NULL);
9090
9091   accessible = g_object_new (gtk_icon_view_accessible_get_type (), NULL);
9092   atk_object_initialize (accessible, obj);
9093
9094   return accessible;
9095 }
9096
9097 static GType
9098 gtk_icon_view_accessible_factory_get_accessible_type (void)
9099 {
9100   return gtk_icon_view_accessible_get_type ();
9101 }
9102
9103 static AtkObject*
9104 gtk_icon_view_accessible_factory_create_accessible (GObject *obj)
9105 {
9106   return gtk_icon_view_accessible_new (obj);
9107 }
9108
9109 static void
9110 gtk_icon_view_accessible_factory_class_init (AtkObjectFactoryClass *klass)
9111 {
9112   klass->create_accessible = gtk_icon_view_accessible_factory_create_accessible;
9113   klass->get_accessible_type = gtk_icon_view_accessible_factory_get_accessible_type;
9114 }
9115
9116 static GType
9117 gtk_icon_view_accessible_factory_get_type (void)
9118 {
9119   static GType type = 0;
9120
9121   if (!type)
9122     {
9123       const GTypeInfo tinfo =
9124       {
9125         sizeof (AtkObjectFactoryClass),
9126         NULL,           /* base_init */
9127         NULL,           /* base_finalize */
9128         (GClassInitFunc) gtk_icon_view_accessible_factory_class_init,
9129         NULL,           /* class_finalize */
9130         NULL,           /* class_data */
9131         sizeof (AtkObjectFactory),
9132         0,             /* n_preallocs */
9133         NULL, NULL
9134       };
9135
9136       type = g_type_register_static (ATK_TYPE_OBJECT_FACTORY, 
9137                                     I_("GtkIconViewAccessibleFactory"),
9138                                     &tinfo, 0);
9139     }
9140   return type;
9141 }
9142
9143
9144 static AtkObject *
9145 gtk_icon_view_get_accessible (GtkWidget *widget)
9146 {
9147   static gboolean first_time = TRUE;
9148
9149   if (first_time)
9150     {
9151       AtkObjectFactory *factory;
9152       AtkRegistry *registry;
9153       GType derived_type; 
9154       GType derived_atk_type; 
9155
9156       /*
9157        * Figure out whether accessibility is enabled by looking at the
9158        * type of the accessible object which would be created for
9159        * the parent type of GtkIconView.
9160        */
9161       derived_type = g_type_parent (GTK_TYPE_ICON_VIEW);
9162
9163       registry = atk_get_default_registry ();
9164       factory = atk_registry_get_factory (registry,
9165                                           derived_type);
9166       derived_atk_type = atk_object_factory_get_accessible_type (factory);
9167       if (g_type_is_a (derived_atk_type, GTK_TYPE_ACCESSIBLE)) 
9168         atk_registry_set_factory_type (registry, 
9169                                        GTK_TYPE_ICON_VIEW,
9170                                        gtk_icon_view_accessible_factory_get_type ());
9171       first_time = FALSE;
9172     } 
9173   return (* GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->get_accessible) (widget);
9174 }
9175
9176 #define __GTK_ICON_VIEW_C__
9177 #include "gtkaliasdef.c"