gtkiconview.c 162 KB
Newer Older
Matthias Clasen's avatar
Matthias Clasen committed
1
/* gtkiconview.c
2
 * Copyright (C) 2002, 2004  Anders Carlsson <andersca@gnu.org>
Anders Carlsson's avatar
Anders Carlsson committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

20
#include <config.h>
Anders Carlsson's avatar
Anders Carlsson committed
21
22
#include <string.h>

23
24
#include <atk/atk.h>

25
#include <gdk/gdkkeysyms.h>
26

27
#include "gtkalias.h"
28
29
30
31
32
33
34
#include "gtkiconview.h"
#include "gtkmarshalers.h"
#include "gtkbindings.h"
#include "gtkdnd.h"
#include "gtkmain.h"
#include "gtksignal.h"
#include "gtkintl.h"
35
36
37
#include "gtkaccessible.h"
#include "gtkwindow.h"
#include "gtktextbuffer.h"
Anders Carlsson's avatar
Anders Carlsson committed
38
39
40
41

#define MINIMUM_ICON_ITEM_WIDTH 100
#define ICON_TEXT_PADDING 3

42
43
44
45
46
47
48
#define ICON_VIEW_TOP_MARGIN 6
#define ICON_VIEW_BOTTOM_MARGIN 6
#define ICON_VIEW_LEFT_MARGIN 6
#define ICON_VIEW_RIGHT_MARGIN 6
#define ICON_VIEW_ICON_PADDING 6

#define GTK_ICON_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ICON_VIEW, GtkIconViewPrivate))
49
50
51
52
#define VALID_MODEL_AND_COLUMNS(obj) ((obj)->priv->model != NULL && \
                                      ((obj)->priv->pixbuf_column != -1 || \
				       (obj)->priv->text_column != -1 || \
				       (obj)->priv->markup_column != -1))
Anders Carlsson's avatar
Anders Carlsson committed
53

Anders Carlsson's avatar
Anders Carlsson committed
54
typedef struct 
Anders Carlsson's avatar
Anders Carlsson committed
55
{
56
57
  GtkTreeIter iter;
  int index;
Anders Carlsson's avatar
Anders Carlsson committed
58
  
Matthias Clasen's avatar
Matthias Clasen committed
59
60
  gint row, col;

Anders Carlsson's avatar
Anders Carlsson committed
61
62
63
64
65
66
67
68
69
70
71
72
  /* Bounding boxes */
  gint x, y;
  gint width, height;

  gint pixbuf_x, pixbuf_y;
  gint pixbuf_height, pixbuf_width;

  gint layout_x, layout_y;
  gint layout_width, layout_height;

  guint selected : 1;
  guint selected_before_rubberbanding : 1;
Anders Carlsson's avatar
Anders Carlsson committed
73
} GtkIconViewItem;
Anders Carlsson's avatar
Anders Carlsson committed
74

75
struct _GtkIconViewPrivate
Anders Carlsson's avatar
Anders Carlsson committed
76
77
78
{
  gint width, height;

79
  gint text_column;
Anders Carlsson's avatar
Anders Carlsson committed
80
  gint markup_column;
81
82
  gint pixbuf_column;
  
Anders Carlsson's avatar
Anders Carlsson committed
83
84
85
86
  GtkSelectionMode selection_mode;

  GdkWindow *bin_window;

87
88
  GtkTreeModel *model;
  
Anders Carlsson's avatar
Anders Carlsson committed
89
90
91
92
93
94
95
  GList *items;
  
  GtkAdjustment *hadjustment;
  GtkAdjustment *vadjustment;

  guint layout_idle_id;
  
96
  gboolean doing_rubberband;
Anders Carlsson's avatar
Anders Carlsson committed
97
98
  gint rubberband_x1, rubberband_y1;
  gint rubberband_x2, rubberband_y2;
99
100
101
102
103

  guint scroll_timeout_id;
  gint scroll_value_diff;
  gint event_last_x, event_last_y;

104
105
  GtkIconViewItem *anchor_item;
  GtkIconViewItem *cursor_item;
Matthias Clasen's avatar
Matthias Clasen committed
106
107
108

  guint ctrl_pressed : 1;
  guint shift_pressed : 1;
Anders Carlsson's avatar
Anders Carlsson committed
109
  
110
  GtkIconViewItem *last_single_clicked;
Anders Carlsson's avatar
Anders Carlsson committed
111
112

#ifdef DND_WORKS
Anders Carlsson's avatar
Anders Carlsson committed
113
114
115
116
  /* Drag-and-drop. */
  gint pressed_button;
  gint press_start_x;
  gint press_start_y;
Anders Carlsson's avatar
Anders Carlsson committed
117
#endif
118

Anders Carlsson's avatar
Anders Carlsson committed
119
120
  /* Layout used to draw icon text */
  PangoLayout *layout;
121
122
  
  GtkOrientation orientation;
Anders Carlsson's avatar
Anders Carlsson committed
123
124
125
126
127
128
129
130
131
132
133
134
};

/* Signals */
enum
{
  ITEM_ACTIVATED,
  SELECTION_CHANGED,
  SELECT_ALL,
  UNSELECT_ALL,
  SELECT_CURSOR_ITEM,
  TOGGLE_CURSOR_ITEM,
  MOVE_CURSOR,
135
  ACTIVATE_CURSOR_ITEM,
Anders Carlsson's avatar
Anders Carlsson committed
136
137
138
139
140
141
142
  LAST_SIGNAL
};

/* Properties */
enum
{
  PROP_0,
143
144
  PROP_PIXBUF_COLUMN,
  PROP_TEXT_COLUMN,
Anders Carlsson's avatar
Anders Carlsson committed
145
  PROP_MARKUP_COLUMN,  
Anders Carlsson's avatar
Anders Carlsson committed
146
  PROP_SELECTION_MODE,
147
  PROP_ORIENTATION,
148
  PROP_MODEL,
Anders Carlsson's avatar
Anders Carlsson committed
149
150
151
};

/* GObject signals */
152
153
static void gtk_icon_view_finalize     (GObject      *object);
static void gtk_icon_view_set_property (GObject      *object,
Anders Carlsson's avatar
Anders Carlsson committed
154
155
156
					guint         prop_id,
					const GValue *value,
					GParamSpec   *pspec);
157
static void gtk_icon_view_get_property (GObject      *object,
Anders Carlsson's avatar
Anders Carlsson committed
158
159
160
161
162
					guint         prop_id,
					GValue       *value,
					GParamSpec   *pspec);


163
/* GtkObject signals */
164
static void gtk_icon_view_destroy (GtkObject *object);
165

Anders Carlsson's avatar
Anders Carlsson committed
166
/* GtkWidget signals */
167
168
169
170
static void     gtk_icon_view_realize        (GtkWidget      *widget);
static void     gtk_icon_view_unrealize      (GtkWidget      *widget);
static void     gtk_icon_view_map            (GtkWidget      *widget);
static void     gtk_icon_view_size_request   (GtkWidget      *widget,
Anders Carlsson's avatar
Anders Carlsson committed
171
					      GtkRequisition *requisition);
172
static void     gtk_icon_view_size_allocate  (GtkWidget      *widget,
Anders Carlsson's avatar
Anders Carlsson committed
173
					      GtkAllocation  *allocation);
174
static gboolean gtk_icon_view_expose         (GtkWidget      *widget,
Anders Carlsson's avatar
Anders Carlsson committed
175
					      GdkEventExpose *expose);
176
static gboolean gtk_icon_view_motion         (GtkWidget      *widget,
Anders Carlsson's avatar
Anders Carlsson committed
177
					      GdkEventMotion *event);
178
static gboolean gtk_icon_view_button_press   (GtkWidget      *widget,
Anders Carlsson's avatar
Anders Carlsson committed
179
					      GdkEventButton *event);
180
static gboolean gtk_icon_view_button_release (GtkWidget      *widget,
Anders Carlsson's avatar
Anders Carlsson committed
181
					      GdkEventButton *event);
182
/* GtkIconView signals */
183
184
185
186
187
188
189
190
static void     gtk_icon_view_set_adjustments           (GtkIconView   *icon_view,
							 GtkAdjustment *hadj,
							 GtkAdjustment *vadj);
static void     gtk_icon_view_real_select_all           (GtkIconView   *icon_view);
static void     gtk_icon_view_real_unselect_all         (GtkIconView   *icon_view);
static void     gtk_icon_view_real_select_cursor_item   (GtkIconView   *icon_view);
static void     gtk_icon_view_real_toggle_cursor_item   (GtkIconView   *icon_view);
static gboolean gtk_icon_view_real_activate_cursor_item (GtkIconView   *icon_view);
Anders Carlsson's avatar
Anders Carlsson committed
191
192

/* Internal functions */
193
194
195
196
197
static void       gtk_icon_view_adjustment_changed          (GtkAdjustment   *adjustment,
							     GtkIconView     *icon_view);
static void       gtk_icon_view_layout                      (GtkIconView     *icon_view);
static void       gtk_icon_view_paint_item                  (GtkIconView     *icon_view,
							     GtkIconViewItem *item,
198
							     GdkRectangle    *area);
199
static void       gtk_icon_view_paint_rubberband            (GtkIconView     *icon_view,
200
							     GdkRectangle    *area);
201
202
203
204
205
206
static void       gtk_icon_view_queue_draw_item             (GtkIconView     *icon_view,
							     GtkIconViewItem *item);
static void       gtk_icon_view_queue_layout                (GtkIconView     *icon_view);
static void       gtk_icon_view_set_cursor_item             (GtkIconView     *icon_view,
							     GtkIconViewItem *item);
static void       gtk_icon_view_start_rubberbanding         (GtkIconView     *icon_view,
207
208
							     gint             x,
							     gint             y);
209
210
211
static void       gtk_icon_view_stop_rubberbanding          (GtkIconView     *icon_view);
static void       gtk_icon_view_update_rubberband_selection (GtkIconView     *icon_view);
static gboolean   gtk_icon_view_item_hit_test               (GtkIconViewItem *item,
212
213
214
215
							     gint             x,
							     gint             y,
							     gint             width,
							     gint             height);
Anders Carlsson's avatar
Anders Carlsson committed
216
#ifdef DND_WORKS
217
static gboolean   gtk_icon_view_maybe_begin_dragging_items  (GtkIconView     *icon_view,
218
							     GdkEventMotion  *event);
Anders Carlsson's avatar
Anders Carlsson committed
219
#endif
220
221
222
223
224
225
226
static gboolean   gtk_icon_view_unselect_all_internal       (GtkIconView     *icon_view);
static void       gtk_icon_view_calculate_item_size         (GtkIconView     *icon_view,
							     GtkIconViewItem *item);
static void       gtk_icon_view_update_rubberband           (gpointer         data);
static void       gtk_icon_view_item_invalidate_size        (GtkIconViewItem *item);
static void       gtk_icon_view_invalidate_sizes            (GtkIconView     *icon_view);
static void       gtk_icon_view_add_move_binding            (GtkBindingSet   *binding_set,
227
228
229
230
							     guint            keyval,
							     guint            modmask,
							     GtkMovementStep  step,
							     gint             count);
231
static gboolean   gtk_icon_view_real_move_cursor            (GtkIconView     *icon_view,
232
233
							     GtkMovementStep  step,
							     gint             count);
234
static void       gtk_icon_view_move_cursor_up_down         (GtkIconView     *icon_view,
235
							     gint             count);
236
static void       gtk_icon_view_move_cursor_page_up_down    (GtkIconView     *icon_view,
237
							     gint             count);
238
static void       gtk_icon_view_move_cursor_left_right      (GtkIconView     *icon_view,
239
							     gint             count);
240
static void       gtk_icon_view_move_cursor_start_end       (GtkIconView     *icon_view,
241
							     gint             count);
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
static void       gtk_icon_view_scroll_to_item              (GtkIconView     *icon_view,
							     GtkIconViewItem *item);
static GdkPixbuf *gtk_icon_view_get_item_icon               (GtkIconView     *icon_view,
							     GtkIconViewItem *item);
static void       gtk_icon_view_update_item_text            (GtkIconView     *icon_view,
							     GtkIconViewItem *item);
static void       gtk_icon_view_select_item                 (GtkIconView     *icon_view,
							     GtkIconViewItem *item);
static void       gtk_icon_view_unselect_item               (GtkIconView     *icon_view,
							     GtkIconViewItem *item);
static gboolean gtk_icon_view_select_all_between            (GtkIconView     *icon_view,
							     GtkIconViewItem *anchor,
							     GtkIconViewItem *cursor);

static GtkIconViewItem *gtk_icon_view_get_item_at_pos (GtkIconView *icon_view,
257
258
						       gint         x,
						       gint         y);
Anders Carlsson's avatar
Anders Carlsson committed
259
260


261
262
/* Accessibility Support */
static AtkObject       *gtk_icon_view_get_accessible  (GtkWidget   *widget);
263
264

static GtkContainerClass *parent_class = NULL;
265
static guint icon_view_signals[LAST_SIGNAL] = { 0 };
Anders Carlsson's avatar
Anders Carlsson committed
266

267
G_DEFINE_TYPE (GtkIconView, gtk_icon_view, GTK_TYPE_CONTAINER);
Anders Carlsson's avatar
Anders Carlsson committed
268
269

static void
270
gtk_icon_view_class_init (GtkIconViewClass *klass)
Anders Carlsson's avatar
Anders Carlsson committed
271
272
{
  GObjectClass *gobject_class;
273
  GtkObjectClass *object_class;
Anders Carlsson's avatar
Anders Carlsson committed
274
275
276
277
278
  GtkWidgetClass *widget_class;
  GtkBindingSet *binding_set;
  
  parent_class = g_type_class_peek_parent (klass);
  binding_set = gtk_binding_set_by_class (klass);
279

280
  g_type_class_add_private (klass, sizeof (GtkIconViewPrivate));
281

Anders Carlsson's avatar
Anders Carlsson committed
282
  gobject_class = (GObjectClass *) klass;
283
  object_class = (GtkObjectClass *) klass;
Anders Carlsson's avatar
Anders Carlsson committed
284
285
  widget_class = (GtkWidgetClass *) klass;

286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
  gobject_class->finalize = gtk_icon_view_finalize;
  gobject_class->set_property = gtk_icon_view_set_property;
  gobject_class->get_property = gtk_icon_view_get_property;

  object_class->destroy = gtk_icon_view_destroy;
  
  widget_class->realize = gtk_icon_view_realize;
  widget_class->unrealize = gtk_icon_view_unrealize;
  widget_class->map = gtk_icon_view_map;
  widget_class->size_request = gtk_icon_view_size_request;
  widget_class->size_allocate = gtk_icon_view_size_allocate;
  widget_class->expose_event = gtk_icon_view_expose;
  widget_class->motion_notify_event = gtk_icon_view_motion;
  widget_class->button_press_event = gtk_icon_view_button_press;
  widget_class->button_release_event = gtk_icon_view_button_release;
301
  widget_class->get_accessible = gtk_icon_view_get_accessible;
302

303
304
305
306
307
  klass->set_scroll_adjustments = gtk_icon_view_set_adjustments;
  klass->select_all = gtk_icon_view_real_select_all;
  klass->unselect_all = gtk_icon_view_real_unselect_all;
  klass->select_cursor_item = gtk_icon_view_real_select_cursor_item;
  klass->toggle_cursor_item = gtk_icon_view_real_toggle_cursor_item;
308
  klass->activate_cursor_item = gtk_icon_view_real_activate_cursor_item;  
309
  klass->move_cursor = gtk_icon_view_real_move_cursor;
Anders Carlsson's avatar
Anders Carlsson committed
310
311
  
  /* Properties */
Matthias Clasen's avatar
Matthias Clasen committed
312
313
314
315
316
317
318
319
320
  /**
   * GtkIconView:selection-mode:
   * 
   * The ::selection-mode property specifies the selection mode of
   * icon view. If the mode is #GTK_SELECTION_MULTIPLE, rubberband selection
   * is enabled, for the other modes, only keyboard selection is possible.
   *
   * Since: 2.6
   */
Anders Carlsson's avatar
Anders Carlsson committed
321
322
323
  g_object_class_install_property (gobject_class,
				   PROP_SELECTION_MODE,
				   g_param_spec_enum ("selection_mode",
324
325
						      P_("Selection mode"),
						      P_("The selection mode"),
Anders Carlsson's avatar
Anders Carlsson committed
326
327
328
329
						      GTK_TYPE_SELECTION_MODE,
						      GTK_SELECTION_SINGLE,
						      G_PARAM_READWRITE));

Matthias Clasen's avatar
Matthias Clasen committed
330
331
332
333
334
335
336
337
338
339
  /**
   * GtkIconView:pixbuf-column:
   *
   * The ::pixbuf-column property contains the number of the model column
   * containing the pixbufs which are displayed. The pixbuf column must be 
   * of type #GDK_TYPE_PIXBUF. Setting this property to -1 turns off the
   * display of pixbufs.
   *
   * Since: 2.6
   */
Anders Carlsson's avatar
Anders Carlsson committed
340
  g_object_class_install_property (gobject_class,
341
342
				   PROP_PIXBUF_COLUMN,
				   g_param_spec_int ("pixbuf_column",
343
344
						     P_("Pixbuf column"),
						     P_("Model column used to retrieve the icon pixbuf from"),
345
346
347
						     -1, G_MAXINT, -1,
						     G_PARAM_READWRITE));

Matthias Clasen's avatar
Matthias Clasen committed
348
349
350
351
352
353
354
355
356
357
  /**
   * GtkIconView:text-column:
   *
   * The ::text-column property contains the number of the model column
   * containing the texts which are displayed. The text column must be 
   * of type #G_TYPE_STRING. If this property and the :markup-column 
   * property are both set to -1, no texts are displayed.   
   *
   * Since: 2.6
   */
Anders Carlsson's avatar
Anders Carlsson committed
358
  g_object_class_install_property (gobject_class,
359
360
				   PROP_TEXT_COLUMN,
				   g_param_spec_int ("text_column",
361
362
						     P_("Text column"),
						     P_("Model column used to retrieve the text from"),
363
364
						     -1, G_MAXINT, -1,
						     G_PARAM_READWRITE));
Anders Carlsson's avatar
Anders Carlsson committed
365

Matthias Clasen's avatar
Matthias Clasen committed
366
367
368
369
370
371
372
373
374
375
376
377
  
  /**
   * GtkIconView:markup-column:
   *
   * The ::markup-column property contains the number of the model column
   * containing markup information to be displayed. The markup column must be 
   * of type #G_TYPE_STRING. If this property and the :text-column property 
   * are both set to column numbers, it overrides the text column.
   * If both are set to -1, no texts are displayed.   
   *
   * Since: 2.6
   */
Anders Carlsson's avatar
Anders Carlsson committed
378
379
380
  g_object_class_install_property (gobject_class,
				   PROP_MARKUP_COLUMN,
				   g_param_spec_int ("markup_column",
381
						     P_("Markup column"),
Matthias Clasen's avatar
Matthias Clasen committed
382
						     P_("Model column used to retrieve the text if using Pango markup"),
Anders Carlsson's avatar
Anders Carlsson committed
383
384
385
						     -1, G_MAXINT, -1,
						     G_PARAM_READWRITE));
  
386
387
388
  g_object_class_install_property (gobject_class,
                                   PROP_MODEL,
                                   g_param_spec_object ("model",
Matthias Clasen's avatar
Matthias Clasen committed
389
390
							P_("Icon View Model"),
							P_("The model for the icon view"),
391
392
393
							GTK_TYPE_TREE_MODEL,
							G_PARAM_READWRITE));
  
394
395
396
397
398
399
400
401
  g_object_class_install_property (gobject_class,
				   PROP_ORIENTATION,
				   g_param_spec_enum ("orientation",
						      P_("Orientation"),
						      P_("How the text and icon of each item are positioned relative to each other"),
						      GTK_TYPE_ORIENTATION,
						      GTK_ORIENTATION_VERTICAL,
						      G_PARAM_READWRITE));
Anders Carlsson's avatar
Anders Carlsson committed
402

403
  /* Style properties */
404
405
  gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_boxed ("selection_box_color",
406
407
                                                               P_("Selection Box Color"),
                                                               P_("Color of the selection box"),
408
409
410
411
412
                                                               GDK_TYPE_COLOR,
                                                               G_PARAM_READABLE));

  gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_uchar ("selection_box_alpha",
413
414
                                                               P_("Selection Box Alpha"),
                                                               P_("Opacity of the selection box"),
415
416
417
418
                                                               0, 0xff,
                                                               0x40,
                                                               G_PARAM_READABLE));

Anders Carlsson's avatar
Anders Carlsson committed
419
420
421
422
423
  /* Signals */
  widget_class->set_scroll_adjustments_signal =
    g_signal_new ("set_scroll_adjustments",
		  G_TYPE_FROM_CLASS (gobject_class),
		  G_SIGNAL_RUN_LAST,
424
		  G_STRUCT_OFFSET (GtkIconViewClass, set_scroll_adjustments),
Anders Carlsson's avatar
Anders Carlsson committed
425
		  NULL, NULL, 
426
		  _gtk_marshal_VOID__OBJECT_OBJECT,
Anders Carlsson's avatar
Anders Carlsson committed
427
428
429
		  G_TYPE_NONE, 2,
		  GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);

430
  icon_view_signals[ITEM_ACTIVATED] =
Anders Carlsson's avatar
Anders Carlsson committed
431
432
433
    g_signal_new ("item_activated",
		  G_TYPE_FROM_CLASS (gobject_class),
		  G_SIGNAL_RUN_LAST,
434
		  G_STRUCT_OFFSET (GtkIconViewClass, item_activated),
Anders Carlsson's avatar
Anders Carlsson committed
435
		  NULL, NULL,
Anders Carlsson's avatar
Anders Carlsson committed
436
		  g_cclosure_marshal_VOID__BOXED,
Anders Carlsson's avatar
Anders Carlsson committed
437
		  G_TYPE_NONE, 1,
438
		  GTK_TYPE_TREE_PATH);
Anders Carlsson's avatar
Anders Carlsson committed
439

440
  icon_view_signals[SELECTION_CHANGED] =
Anders Carlsson's avatar
Anders Carlsson committed
441
442
443
    g_signal_new ("selection_changed",
		  G_TYPE_FROM_CLASS (gobject_class),
		  G_SIGNAL_RUN_FIRST,
444
		  G_STRUCT_OFFSET (GtkIconViewClass, selection_changed),
Anders Carlsson's avatar
Anders Carlsson committed
445
446
447
448
		  NULL, NULL,
		  g_cclosure_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);
  
449
  icon_view_signals[SELECT_ALL] =
Anders Carlsson's avatar
Anders Carlsson committed
450
451
452
    g_signal_new ("select_all",
		  G_TYPE_FROM_CLASS (gobject_class),
		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
453
		  G_STRUCT_OFFSET (GtkIconViewClass, select_all),
Anders Carlsson's avatar
Anders Carlsson committed
454
455
456
457
		  NULL, NULL,
		  g_cclosure_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);
  
458
  icon_view_signals[UNSELECT_ALL] =
Anders Carlsson's avatar
Anders Carlsson committed
459
460
461
    g_signal_new ("unselect_all",
		  G_TYPE_FROM_CLASS (gobject_class),
		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
462
		  G_STRUCT_OFFSET (GtkIconViewClass, unselect_all),
Anders Carlsson's avatar
Anders Carlsson committed
463
464
465
466
		  NULL, NULL,
		  g_cclosure_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);

467
  icon_view_signals[SELECT_CURSOR_ITEM] =
Anders Carlsson's avatar
Anders Carlsson committed
468
469
470
    g_signal_new ("select_cursor_item",
		  G_TYPE_FROM_CLASS (gobject_class),
		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
471
		  G_STRUCT_OFFSET (GtkIconViewClass, select_cursor_item),
Anders Carlsson's avatar
Anders Carlsson committed
472
473
474
475
		  NULL, NULL,
		  g_cclosure_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);

476
  icon_view_signals[TOGGLE_CURSOR_ITEM] =
Anders Carlsson's avatar
Anders Carlsson committed
477
478
479
    g_signal_new ("toggle_cursor_item",
		  G_TYPE_FROM_CLASS (gobject_class),
		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
480
		  G_STRUCT_OFFSET (GtkIconViewClass, toggle_cursor_item),
Anders Carlsson's avatar
Anders Carlsson committed
481
482
483
484
		  NULL, NULL,
		  g_cclosure_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);

485
486
487
488
489
490
491
492
493
  icon_view_signals[ACTIVATE_CURSOR_ITEM] =
    g_signal_new ("activate_cursor_item",
		  G_TYPE_FROM_CLASS (gobject_class),
		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
		  G_STRUCT_OFFSET (GtkIconViewClass, activate_cursor_item),
		  NULL, NULL,
		  _gtk_marshal_BOOLEAN__VOID,
		  G_TYPE_BOOLEAN, 0);
  
494
  icon_view_signals[MOVE_CURSOR] =
Matthias Clasen's avatar
Matthias Clasen committed
495
496
497
    g_signal_new ("move_cursor",
		  G_TYPE_FROM_CLASS (gobject_class),
		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
498
		  G_STRUCT_OFFSET (GtkIconViewClass, move_cursor),
Matthias Clasen's avatar
Matthias Clasen committed
499
		  NULL, NULL,
500
		  _gtk_marshal_BOOLEAN__ENUM_INT,
Matthias Clasen's avatar
Matthias Clasen committed
501
502
503
504
		  G_TYPE_BOOLEAN, 2,
		  GTK_TYPE_MOVEMENT_STEP,
		  G_TYPE_INT);

Anders Carlsson's avatar
Anders Carlsson committed
505
506
507
508
509
510
  /* Key bindings */
  gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, "select_all", 0);
  gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect_all", 0);
  gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select_cursor_item", 0);
  gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, "toggle_cursor_item", 0);

511
512
513
514
  gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, "activate_cursor_item", 0);
  gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0, "activate_cursor_item", 0);
  gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, "activate_cursor_item", 0);

515
  gtk_icon_view_add_move_binding (binding_set, GDK_Up, 0,
Matthias Clasen's avatar
Matthias Clasen committed
516
				  GTK_MOVEMENT_DISPLAY_LINES, -1);
517
  gtk_icon_view_add_move_binding (binding_set, GDK_KP_Up, 0,
Matthias Clasen's avatar
Matthias Clasen committed
518
519
				  GTK_MOVEMENT_DISPLAY_LINES, -1);

520
  gtk_icon_view_add_move_binding (binding_set, GDK_Down, 0,
Matthias Clasen's avatar
Matthias Clasen committed
521
				  GTK_MOVEMENT_DISPLAY_LINES, 1);
522
  gtk_icon_view_add_move_binding (binding_set, GDK_KP_Down, 0,
Matthias Clasen's avatar
Matthias Clasen committed
523
524
				  GTK_MOVEMENT_DISPLAY_LINES, 1);

525
  gtk_icon_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK,
Matthias Clasen's avatar
Matthias Clasen committed
526
527
				  GTK_MOVEMENT_DISPLAY_LINES, -1);

528
  gtk_icon_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK,
Matthias Clasen's avatar
Matthias Clasen committed
529
530
				  GTK_MOVEMENT_DISPLAY_LINES, 1);

531
  gtk_icon_view_add_move_binding (binding_set, GDK_Home, 0,
Matthias Clasen's avatar
Matthias Clasen committed
532
				  GTK_MOVEMENT_BUFFER_ENDS, -1);
533
  gtk_icon_view_add_move_binding (binding_set, GDK_KP_Home, 0,
Matthias Clasen's avatar
Matthias Clasen committed
534
535
				  GTK_MOVEMENT_BUFFER_ENDS, -1);

536
  gtk_icon_view_add_move_binding (binding_set, GDK_End, 0,
Matthias Clasen's avatar
Matthias Clasen committed
537
				  GTK_MOVEMENT_BUFFER_ENDS, 1);
538
  gtk_icon_view_add_move_binding (binding_set, GDK_KP_End, 0,
Matthias Clasen's avatar
Matthias Clasen committed
539
540
				  GTK_MOVEMENT_BUFFER_ENDS, 1);

541
  gtk_icon_view_add_move_binding (binding_set, GDK_Page_Up, 0,
Matthias Clasen's avatar
Matthias Clasen committed
542
				  GTK_MOVEMENT_PAGES, -1);
543
  gtk_icon_view_add_move_binding (binding_set, GDK_KP_Page_Up, 0,
Matthias Clasen's avatar
Matthias Clasen committed
544
545
				  GTK_MOVEMENT_PAGES, -1);

546
  gtk_icon_view_add_move_binding (binding_set, GDK_Page_Down, 0,
Matthias Clasen's avatar
Matthias Clasen committed
547
				  GTK_MOVEMENT_PAGES, 1);
548
  gtk_icon_view_add_move_binding (binding_set, GDK_KP_Page_Down, 0,
Matthias Clasen's avatar
Matthias Clasen committed
549
550
				  GTK_MOVEMENT_PAGES, 1);

551
  gtk_icon_view_add_move_binding (binding_set, GDK_Right, 0, 
Matthias Clasen's avatar
Matthias Clasen committed
552
				  GTK_MOVEMENT_VISUAL_POSITIONS, 1);
553
  gtk_icon_view_add_move_binding (binding_set, GDK_Left, 0, 
Matthias Clasen's avatar
Matthias Clasen committed
554
555
				  GTK_MOVEMENT_VISUAL_POSITIONS, -1);

556
  gtk_icon_view_add_move_binding (binding_set, GDK_KP_Right, 0, 
Matthias Clasen's avatar
Matthias Clasen committed
557
				  GTK_MOVEMENT_VISUAL_POSITIONS, 1);
558
  gtk_icon_view_add_move_binding (binding_set, GDK_KP_Left, 0, 
Matthias Clasen's avatar
Matthias Clasen committed
559
560
				  GTK_MOVEMENT_VISUAL_POSITIONS, -1);
}
Anders Carlsson's avatar
Anders Carlsson committed
561
562

static void
563
gtk_icon_view_init (GtkIconView *icon_view)
Anders Carlsson's avatar
Anders Carlsson committed
564
{
565
  icon_view->priv = GTK_ICON_VIEW_GET_PRIVATE (icon_view);
566
  
567
568
569
  icon_view->priv->width = 0;
  icon_view->priv->height = 0;
  icon_view->priv->selection_mode = GTK_SELECTION_SINGLE;
Anders Carlsson's avatar
Anders Carlsson committed
570
#ifdef DND_WORKS
571
572
573
  icon_view->priv->pressed_button = -1;
  icon_view->priv->press_start_x = -1;
  icon_view->priv->press_start_y = -1;
Anders Carlsson's avatar
Anders Carlsson committed
574
#endif
575
576
577
  icon_view->priv->text_column = -1;
  icon_view->priv->markup_column = -1;  
  icon_view->priv->pixbuf_column = -1;
578
  
579
  icon_view->priv->layout = gtk_widget_create_pango_layout (GTK_WIDGET (icon_view), NULL);
580

581
  pango_layout_set_wrap (icon_view->priv->layout, PANGO_WRAP_WORD_CHAR);
582

583
  GTK_WIDGET_SET_FLAGS (icon_view, GTK_CAN_FOCUS);
Anders Carlsson's avatar
Anders Carlsson committed
584
  
585
  gtk_icon_view_set_adjustments (icon_view, NULL, NULL);
586
587

  icon_view->priv->orientation = GTK_ORIENTATION_VERTICAL;
Anders Carlsson's avatar
Anders Carlsson committed
588
589
590
}

static void
591
gtk_icon_view_destroy (GtkObject *object)
Anders Carlsson's avatar
Anders Carlsson committed
592
{
593
  GtkIconView *icon_view;
Anders Carlsson's avatar
Anders Carlsson committed
594

595
  icon_view = GTK_ICON_VIEW (object);
596
  
597
  gtk_icon_view_set_model (icon_view, NULL);
598
  
599
600
  if (icon_view->priv->layout_idle_id != 0)
    g_source_remove (icon_view->priv->layout_idle_id);
Anders Carlsson's avatar
Anders Carlsson committed
601

602
603
  if (icon_view->priv->scroll_timeout_id != 0)
    g_source_remove (icon_view->priv->scroll_timeout_id);
604
605
606
607
608
609
  
  (GTK_OBJECT_CLASS (parent_class)->destroy) (object);
}

/* GObject methods */
static void
610
gtk_icon_view_finalize (GObject *object)
611
{
612
  GtkIconView *icon_view;
613

614
  icon_view = GTK_ICON_VIEW (object);
615

616
  g_object_unref (icon_view->priv->layout);
Anders Carlsson's avatar
Anders Carlsson committed
617
618
619
620
621
622
  
  (G_OBJECT_CLASS (parent_class)->finalize) (object);
}


static void
623
gtk_icon_view_set_property (GObject      *object,
Anders Carlsson's avatar
Anders Carlsson committed
624
625
626
627
			    guint         prop_id,
			    const GValue *value,
			    GParamSpec   *pspec)
{
628
  GtkIconView *icon_view;
Anders Carlsson's avatar
Anders Carlsson committed
629

630
  icon_view = GTK_ICON_VIEW (object);
Anders Carlsson's avatar
Anders Carlsson committed
631
632
633
634

  switch (prop_id)
    {
    case PROP_SELECTION_MODE:
635
      gtk_icon_view_set_selection_mode (icon_view, g_value_get_enum (value));
Anders Carlsson's avatar
Anders Carlsson committed
636
      break;
637
    case PROP_PIXBUF_COLUMN:
638
      gtk_icon_view_set_pixbuf_column (icon_view, g_value_get_int (value));
639
640
      break;
    case PROP_TEXT_COLUMN:
641
      gtk_icon_view_set_text_column (icon_view, g_value_get_int (value));
Anders Carlsson's avatar
Anders Carlsson committed
642
      break;
Anders Carlsson's avatar
Anders Carlsson committed
643
    case PROP_MARKUP_COLUMN:
644
      gtk_icon_view_set_markup_column (icon_view, g_value_get_int (value));
Anders Carlsson's avatar
Anders Carlsson committed
645
      break;
646
    case PROP_MODEL:
647
      gtk_icon_view_set_model (icon_view, g_value_get_object (value));
Anders Carlsson's avatar
Anders Carlsson committed
648
      break;
649
650
651
    case PROP_ORIENTATION:
      gtk_icon_view_set_orientation (icon_view, g_value_get_enum (value));
      break;
652
      
Anders Carlsson's avatar
Anders Carlsson committed
653
654
655
656
657
658
659
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
660
gtk_icon_view_get_property (GObject      *object,
Anders Carlsson's avatar
Anders Carlsson committed
661
662
663
664
			    guint         prop_id,
			    GValue       *value,
			    GParamSpec   *pspec)
{
665
  GtkIconView *icon_view;
Anders Carlsson's avatar
Anders Carlsson committed
666

667
  icon_view = GTK_ICON_VIEW (object);
Anders Carlsson's avatar
Anders Carlsson committed
668
669
670
671

  switch (prop_id)
    {
    case PROP_SELECTION_MODE:
672
      g_value_set_enum (value, icon_view->priv->selection_mode);
Anders Carlsson's avatar
Anders Carlsson committed
673
      break;
674
    case PROP_PIXBUF_COLUMN:
675
      g_value_set_int (value, icon_view->priv->pixbuf_column);
676
677
      break;
    case PROP_TEXT_COLUMN:
678
      g_value_set_int (value, icon_view->priv->text_column);
Anders Carlsson's avatar
Anders Carlsson committed
679
      break;
Anders Carlsson's avatar
Anders Carlsson committed
680
    case PROP_MARKUP_COLUMN:
681
      g_value_set_int (value, icon_view->priv->markup_column);
Anders Carlsson's avatar
Anders Carlsson committed
682
      break;
683
    case PROP_MODEL:
684
      g_value_set_object (value, icon_view->priv->model);
Anders Carlsson's avatar
Anders Carlsson committed
685
      break;
686
687
688
    case PROP_ORIENTATION:
      g_value_set_enum (value, icon_view->priv->orientation);
      break;
Anders Carlsson's avatar
Anders Carlsson committed
689
690
691
692
693
694
695
696
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

/* GtkWidget signals */
static void
697
gtk_icon_view_realize (GtkWidget *widget)
Anders Carlsson's avatar
Anders Carlsson committed
698
{
699
  GtkIconView *icon_view;
Anders Carlsson's avatar
Anders Carlsson committed
700
701
702
  GdkWindowAttr attributes;
  gint attributes_mask;
  
703
  icon_view = GTK_ICON_VIEW (widget);
Anders Carlsson's avatar
Anders Carlsson committed
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723

  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);

  /* Make the main, clipping window */
  attributes.window_type = GDK_WINDOW_CHILD;
  attributes.x = widget->allocation.x;
  attributes.y = widget->allocation.y;
  attributes.width = widget->allocation.width;
  attributes.height = widget->allocation.height;
  attributes.wclass = GDK_INPUT_OUTPUT;
  attributes.visual = gtk_widget_get_visual (widget);
  attributes.colormap = gtk_widget_get_colormap (widget);
  attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;

  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;

  widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
				   &attributes, attributes_mask);
  gdk_window_set_user_data (widget->window, widget);

Matthias Clasen's avatar
Matthias Clasen committed
724
  /* Make the window for the icon view */
Anders Carlsson's avatar
Anders Carlsson committed
725
726
  attributes.x = 0;
  attributes.y = 0;
727
728
  attributes.width = MAX (icon_view->priv->width, widget->allocation.width);
  attributes.height = MAX (icon_view->priv->height, widget->allocation.height);
Anders Carlsson's avatar
Anders Carlsson committed
729
730
731
732
733
734
735
736
737
  attributes.event_mask = (GDK_EXPOSURE_MASK |
			   GDK_SCROLL_MASK |
			   GDK_POINTER_MOTION_MASK |
			   GDK_BUTTON_PRESS_MASK |
			   GDK_BUTTON_RELEASE_MASK |
			   GDK_KEY_PRESS_MASK |
			   GDK_KEY_RELEASE_MASK) |
    gtk_widget_get_events (widget);
  
738
  icon_view->priv->bin_window = gdk_window_new (widget->window,
739
						&attributes, attributes_mask);
740
  gdk_window_set_user_data (icon_view->priv->bin_window, widget);
Anders Carlsson's avatar
Anders Carlsson committed
741
742

  widget->style = gtk_style_attach (widget->style, widget->window);
743
  gdk_window_set_background (icon_view->priv->bin_window, &widget->style->base[widget->state]);
Anders Carlsson's avatar
Anders Carlsson committed
744
745
746
747
  gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
}

static void
748
gtk_icon_view_unrealize (GtkWidget *widget)
Anders Carlsson's avatar
Anders Carlsson committed
749
{
750
  GtkIconView *icon_view;
Anders Carlsson's avatar
Anders Carlsson committed
751

752
  icon_view = GTK_ICON_VIEW (widget);
Anders Carlsson's avatar
Anders Carlsson committed
753

754
755
756
  gdk_window_set_user_data (icon_view->priv->bin_window, NULL);
  gdk_window_destroy (icon_view->priv->bin_window);
  icon_view->priv->bin_window = NULL;
Anders Carlsson's avatar
Anders Carlsson committed
757
758
759
760
761
762
763

  /* GtkWidget::unrealize destroys children and widget->window */
  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
}

static void
764
gtk_icon_view_map (GtkWidget *widget)
Anders Carlsson's avatar
Anders Carlsson committed
765
{
766
  GtkIconView *icon_view;
Anders Carlsson's avatar
Anders Carlsson committed
767

768
  icon_view = GTK_ICON_VIEW (widget);
Anders Carlsson's avatar
Anders Carlsson committed
769
770
771

  GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);

772
  gdk_window_show (icon_view->priv->bin_window);
Anders Carlsson's avatar
Anders Carlsson committed
773
774
775
776
  gdk_window_show (widget->window);
}

static void
777
gtk_icon_view_size_request (GtkWidget      *widget,
Anders Carlsson's avatar
Anders Carlsson committed
778
779
			    GtkRequisition *requisition)
{
780
  GtkIconView *icon_view;
Anders Carlsson's avatar
Anders Carlsson committed
781

782
  icon_view = GTK_ICON_VIEW (widget);
Anders Carlsson's avatar
Anders Carlsson committed
783

784
785
  requisition->width = icon_view->priv->width;
  requisition->height = icon_view->priv->height;
Anders Carlsson's avatar
Anders Carlsson committed
786
787
788
}

static void
789
gtk_icon_view_size_allocate (GtkWidget      *widget,
Anders Carlsson's avatar
Anders Carlsson committed
790
791
			     GtkAllocation  *allocation)
{
792
  GtkIconView *icon_view;
Anders Carlsson's avatar
Anders Carlsson committed
793
794
795

  widget->allocation = *allocation;
  
796
  icon_view = GTK_ICON_VIEW (widget);
Anders Carlsson's avatar
Anders Carlsson committed
797
798
799
800
801
802
  
  if (GTK_WIDGET_REALIZED (widget))
    {
      gdk_window_move_resize (widget->window,
			      allocation->x, allocation->y,
			      allocation->width, allocation->height);
803
804
805
      gdk_window_resize (icon_view->priv->bin_window,
			 MAX (icon_view->priv->width, allocation->width),
			 MAX (icon_view->priv->height, allocation->height));
Anders Carlsson's avatar
Anders Carlsson committed
806
807
    }

808
809
810
811
812
813
  icon_view->priv->hadjustment->page_size = allocation->width;
  icon_view->priv->hadjustment->page_increment = allocation->width * 0.9;
  icon_view->priv->hadjustment->step_increment = allocation->width * 0.1;
  icon_view->priv->hadjustment->lower = 0;
  icon_view->priv->hadjustment->upper = MAX (allocation->width, icon_view->priv->width);
  gtk_adjustment_changed (icon_view->priv->hadjustment);
Anders Carlsson's avatar
Anders Carlsson committed
814

815
816
817
818
819
820
  icon_view->priv->vadjustment->page_size = allocation->height;
  icon_view->priv->vadjustment->page_increment = allocation->height * 0.9;
  icon_view->priv->vadjustment->step_increment = allocation->width * 0.1;
  icon_view->priv->vadjustment->lower = 0;
  icon_view->priv->vadjustment->upper = MAX (allocation->height, icon_view->priv->height);
  gtk_adjustment_changed (icon_view->priv->vadjustment);
Anders Carlsson's avatar
Anders Carlsson committed
821

822
  gtk_icon_view_layout (icon_view);
Anders Carlsson's avatar
Anders Carlsson committed
823
824
825
}

static gboolean
826
gtk_icon_view_expose (GtkWidget *widget,
Anders Carlsson's avatar
Anders Carlsson committed
827
828
		      GdkEventExpose *expose)
{
829
  GtkIconView *icon_view;
Anders Carlsson's avatar
Anders Carlsson committed
830
831
  GList *icons;

832
  icon_view = GTK_ICON_VIEW (widget);
Anders Carlsson's avatar
Anders Carlsson committed
833

834
  if (expose->window != icon_view->priv->bin_window)
Anders Carlsson's avatar
Anders Carlsson committed
835
836
    return FALSE;

837
838
  for (icons = icon_view->priv->items; icons; icons = icons->next) {
    GtkIconViewItem *item = icons->data;
Anders Carlsson's avatar
Anders Carlsson committed
839
840
841
842
843
844
845
846
847
848
    GdkRectangle item_rectangle;

    item_rectangle.x = item->x;
    item_rectangle.y = item->y;
    item_rectangle.width = item->width;
    item_rectangle.height = item->height;

    if (gdk_region_rect_in (expose->region, &item_rectangle) == GDK_OVERLAP_RECTANGLE_OUT)
      continue;

849
    gtk_icon_view_paint_item (icon_view, item, &expose->area);
Anders Carlsson's avatar
Anders Carlsson committed
850
851
  }

852
  if (icon_view->priv->doing_rubberband)
Anders Carlsson's avatar
Anders Carlsson committed
853
854
855
856
857
858
859
860
861
    {
      GdkRectangle *rectangles;
      gint n_rectangles;
      
      gdk_region_get_rectangles (expose->region,
				 &rectangles,
				 &n_rectangles);
      
      while (n_rectangles--)
862
	gtk_icon_view_paint_rubberband (icon_view, &rectangles[n_rectangles]);
Anders Carlsson's avatar
Anders Carlsson committed
863
864
865
866
867
868
869

      g_free (rectangles);
    }

  return TRUE;
}

870
871
872
static gboolean
scroll_timeout (gpointer data)
{
873
  GtkIconView *icon_view;
874
  gdouble value;
Matthias Clasen's avatar
Matthias Clasen committed
875
876

  GDK_THREADS_ENTER ();
877
  
878
  icon_view = data;
879

880
881
882
883
  value = MIN (icon_view->priv->vadjustment->value +
	       icon_view->priv->scroll_value_diff,
	       icon_view->priv->vadjustment->upper -
	       icon_view->priv->vadjustment->page_size);
884

885
  gtk_adjustment_set_value (icon_view->priv->vadjustment,
886
887
			    value);

888
  gtk_icon_view_update_rubberband (icon_view);
889
  
Matthias Clasen's avatar
Matthias Clasen committed
890
891
  GDK_THREADS_LEAVE ();

892
893
894
  return TRUE;
}

Anders Carlsson's avatar
Anders Carlsson committed
895
static gboolean
896
gtk_icon_view_motion (GtkWidget      *widget,
Anders Carlsson's avatar
Anders Carlsson committed
897
898
		      GdkEventMotion *event)
{
899
  GtkIconView *icon_view;
900
901
  gint abs_y;
  
902
  icon_view = GTK_ICON_VIEW (widget);
Anders Carlsson's avatar
Anders Carlsson committed
903
#ifdef DND_WORKS
904
  gtk_icon_view_maybe_begin_dragging_items (icon_view, event);
Anders Carlsson's avatar
Anders Carlsson committed
905
#endif
906
  if (icon_view->priv->doing_rubberband)
907
    {
908
      gtk_icon_view_update_rubberband (widget);
909
      
910
911
912
913
      abs_y = event->y - icon_view->priv->height *
	(icon_view->priv->vadjustment->value /
	 (icon_view->priv->vadjustment->upper -
	  icon_view->priv->vadjustment->lower));
914
915
916

      if (abs_y < 0 || abs_y > widget->allocation.height)
	{
917
918
	  if (icon_view->priv->scroll_timeout_id == 0)
	    icon_view->priv->scroll_timeout_id = g_timeout_add (30, scroll_timeout, icon_view);
919
920

	  if (abs_y < 0)
921
	    icon_view->priv->scroll_value_diff = abs_y;
922
	  else
923
	    icon_view->priv->scroll_value_diff = abs_y - widget->allocation.height;
924

925
926
	  icon_view->priv->event_last_x = event->x;
	  icon_view->priv->event_last_y = event->y;
927
	}
928
      else if (icon_view->priv->scroll_timeout_id != 0)
929
	{
930
	  g_source_remove (icon_view->priv->scroll_timeout_id);
931

932
	  icon_view->priv->scroll_timeout_id = 0;
933
934
	}
    }
Anders Carlsson's avatar
Anders Carlsson committed
935
936
937
938
939
  
  return TRUE;
}

static gboolean
940
gtk_icon_view_button_press (GtkWidget      *widget,
Anders Carlsson's avatar
Anders Carlsson committed
941
942
			    GdkEventButton *event)
{
943
944
  GtkIconView *icon_view;
  GtkIconViewItem *item;
Anders Carlsson's avatar
Anders Carlsson committed
945
  gboolean dirty = FALSE;
946

947
  icon_view = GTK_ICON_VIEW (widget);
Anders Carlsson's avatar
Anders Carlsson committed
948

949
  if (event->window != icon_view->priv->bin_window)
Anders Carlsson's avatar
Anders Carlsson committed
950
951
952
953
954
955
956
957
    return FALSE;

  if (!GTK_WIDGET_HAS_FOCUS (widget))
    gtk_widget_grab_focus (widget);

  if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
    {

958
      item = gtk_icon_view_get_item_at_pos (icon_view,
Anders Carlsson's avatar
Anders Carlsson committed
959
					    event->x, event->y);
Matthias Clasen's avatar
Matthias Clasen committed
960
      
Anders Carlsson's avatar
Anders Carlsson committed
961
962
      if (item != NULL)
	{
963
	  gtk_icon_view_scroll_to_item (icon_view, item);
964
	  
965
	  if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
966
	    {
967
	      gtk_icon_view_set_cursor_item (icon_view, item);
968
	    }
969
	  else if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE &&
970
		   (event->state & GDK_SHIFT_MASK))
Anders Carlsson's avatar
Anders Carlsson committed
971
	    {
972
	      gtk_icon_view_unselect_all_internal (icon_view);
Matthias Clasen's avatar
Matthias Clasen committed
973

974
975
976
	      gtk_icon_view_set_cursor_item (icon_view, item);
	      if (!icon_view->priv->anchor_item)
		icon_view->priv->anchor_item = item;
Matthias Clasen's avatar
Matthias Clasen committed
977
	      else 
978
979
		gtk_icon_view_select_all_between (icon_view,
						  icon_view->priv->anchor_item,
980
						  item);
Anders Carlsson's avatar
Anders Carlsson committed
981
982
	      dirty = TRUE;
	    }
Matthias Clasen's avatar
Matthias Clasen committed
983
	  else 
Anders Carlsson's avatar
Anders Carlsson committed
984
	    {
985