exo-icon-view.c 290 KB
Newer Older
Benedikt Meurer's avatar
Benedikt Meurer committed
1
/*-
2
 * Copyright (c) 2008       Jannis Pohlmann <jannis@xfce.org>
3
 * Copyright (c) 2004-2006  os-cillation e.K.
4
5
6
 * Copyright (c) 2002,2004  Anders Carlsson <andersca@gnu.org>
 *
 * Written by Benedikt Meurer <benny@xfce.org>.
Benedikt Meurer's avatar
Benedikt Meurer committed
7
8
9
10
11
12
13
14
15
16
17
 *
 * 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.
 *
Nick Schermer's avatar
Nick Schermer committed
18
19
20
21
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA
Benedikt Meurer's avatar
Benedikt Meurer committed
22
23
24
25
26
27
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

28
29
30
#ifdef HAVE_MATH_H
#include <math.h>
#endif
31
32
33
34
35
36
37
38
39
40
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif

Benedikt Meurer's avatar
Benedikt Meurer committed
41
42
#include <gdk/gdkkeysyms.h>

43
#include <exo/exo-config.h>
44
#include <exo/exo-enum-types.h>
Benedikt Meurer's avatar
Benedikt Meurer committed
45
#include <exo/exo-icon-view.h>
46
#include <exo/exo-cell-renderer-icon.h>
Benedikt Meurer's avatar
Benedikt Meurer committed
47
#include <exo/exo-marshal.h>
48
#include <exo/exo-private.h>
49
#include <exo/exo-alias.h>
Yongha Hwang's avatar
Yongha Hwang committed
50
#include <libxfce4util/libxfce4util.h>
51

52
53
54
55
56
57
58
59
60
61
62
63
64
65
/**
 * SECTION: exo-icon-view
 * @title: ExoIconView
 * @short_description: A widget which displays a list of icons in a grid
 * @include: exo/exo.h
 *
 * #ExoIconView provides an alternative view on a list model.
 * It displays the model as a grid of icons with labels. Like
 * #GtkTreeView, it allows to select one or multiple items
 * (depending on the selection mode, see exo_icon_view_set_selection_mode()).
 * In addition to selection with the arrow keys, #ExoIconView supports
 * rubberband selection, which is controlled by dragging the pointer.
 **/

66
67
68
69
/* resurrect dead gdk apis for Gtk3
 * This is easier than using #ifs everywhere
 */

Sean Davis's avatar
Sean Davis committed
70
71
72
73
74
75
#define GdkRectangle cairo_rectangle_int_t
#define GdkRegion    cairo_region_t
#define gdk_region_rectangle(rect) cairo_region_create_rectangle (rect)
#define gdk_region_destroy(region) cairo_region_destroy (region)
#define gdk_region_subtract(dst, other) cairo_region_subtract (dst, other)
#define gdk_region_union_with_rect(dst, rect) cairo_region_union_rectangle (dst, rect)
76

Sean Davis's avatar
Sean Davis committed
77
78
79
80
#ifdef gdk_cursor_unref
#undef gdk_cursor_unref
#endif
#define gdk_cursor_unref(cursor) g_object_unref (cursor)
81

82
83
84
/* the search dialog timeout (in ms) */
#define EXO_ICON_VIEW_SEARCH_DIALOG_TIMEOUT (5000)

85
86
87
88
89
#define SCROLL_EDGE_SIZE 15



/* Property identifiers */
90
91
92
93
enum
{
  PROP_0,
  PROP_PIXBUF_COLUMN,
94
  PROP_ICON_COLUMN,
95
  PROP_TEXT_COLUMN,
Nick Schermer's avatar
Nick Schermer committed
96
  PROP_MARKUP_COLUMN,
97
  PROP_SELECTION_MODE,
98
  PROP_LAYOUT_MODE,
99
100
101
102
103
104
105
106
  PROP_ORIENTATION,
  PROP_MODEL,
  PROP_COLUMNS,
  PROP_ITEM_WIDTH,
  PROP_SPACING,
  PROP_ROW_SPACING,
  PROP_COLUMN_SPACING,
  PROP_MARGIN,
107
108
  PROP_REORDERABLE,
  PROP_SINGLE_CLICK,
109
  PROP_SINGLE_CLICK_TIMEOUT,
110
111
  PROP_ENABLE_SEARCH,
  PROP_SEARCH_COLUMN,
112
113
114
115
  PROP_HADJUSTMENT,
  PROP_VADJUSTMENT,
  PROP_VSCROLL_POLICY,
  PROP_HSCROLL_POLICY
116
117
};

118
/* Signal identifiers */
119
120
121
122
123
124
125
126
127
128
enum
{
  ITEM_ACTIVATED,
  SELECTION_CHANGED,
  SELECT_ALL,
  UNSELECT_ALL,
  SELECT_CURSOR_ITEM,
  TOGGLE_CURSOR_ITEM,
  MOVE_CURSOR,
  ACTIVATE_CURSOR_ITEM,
129
  START_INTERACTIVE_SEARCH,
130
131
132
  LAST_SIGNAL
};

133
134
135
136
137
138
/* Icon view flags */
typedef enum
{
  EXO_ICON_VIEW_DRAW_KEYFOCUS = (1l << 0),  /* whether to draw keyboard focus */
  EXO_ICON_VIEW_ITERS_PERSIST = (1l << 1),  /* whether current model provides persistent iterators */
} ExoIconViewFlags;
139

140
141
142
#define EXO_ICON_VIEW_SET_FLAG(icon_view, flag)   G_STMT_START{ (EXO_ICON_VIEW (icon_view)->priv->flags |= flag); }G_STMT_END
#define EXO_ICON_VIEW_UNSET_FLAG(icon_view, flag) G_STMT_START{ (EXO_ICON_VIEW (icon_view)->priv->flags &= ~(flag)); }G_STMT_END
#define EXO_ICON_VIEW_FLAG_SET(icon_view, flag)   ((EXO_ICON_VIEW (icon_view)->priv->flags & (flag)) == (flag))
143
144
145
146
147
148



typedef struct _ExoIconViewCellInfo ExoIconViewCellInfo;
typedef struct _ExoIconViewChild    ExoIconViewChild;
typedef struct _ExoIconViewItem     ExoIconViewItem;
Benedikt Meurer's avatar
Benedikt Meurer committed
149
150
151



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#define EXO_ICON_VIEW_CELL_INFO(obj)   ((ExoIconViewCellInfo *) (obj))
#define EXO_ICON_VIEW_CHILD(obj)       ((ExoIconViewChild *) (obj))
#define EXO_ICON_VIEW_ITEM(obj)        ((ExoIconViewItem *) (obj))



static void                 exo_icon_view_cell_layout_init               (GtkCellLayoutIface     *iface);
static void                 exo_icon_view_dispose                        (GObject                *object);
static void                 exo_icon_view_finalize                       (GObject                *object);
static void                 exo_icon_view_get_property                   (GObject                *object,
                                                                          guint                   prop_id,
                                                                          GValue                 *value,
                                                                          GParamSpec             *pspec);
static void                 exo_icon_view_set_property                   (GObject                *object,
                                                                          guint                   prop_id,
                                                                          const GValue           *value,
                                                                          GParamSpec             *pspec);
static void                 exo_icon_view_realize                        (GtkWidget              *widget);
static void                 exo_icon_view_unrealize                      (GtkWidget              *widget);
171
172
173
174
175
176
static void                 exo_icon_view_get_preferred_width            (GtkWidget              *widget,
                                                                          gint                   *minimal_width,
                                                                          gint                   *natural_width);
static void                 exo_icon_view_get_preferred_height           (GtkWidget              *widget,
                                                                          gint                   *minimal_height,
                                                                          gint                   *natural_height);
177
178
static void                 exo_icon_view_size_allocate                  (GtkWidget              *widget,
                                                                          GtkAllocation          *allocation);
179
180
static gboolean             exo_icon_view_draw                           (GtkWidget              *widget,
                                                                          cairo_t                *cr);
181
182
183
184
185
186
static gboolean             exo_icon_view_motion_notify_event            (GtkWidget              *widget,
                                                                          GdkEventMotion         *event);
static gboolean             exo_icon_view_button_press_event             (GtkWidget              *widget,
                                                                          GdkEventButton         *event);
static gboolean             exo_icon_view_button_release_event           (GtkWidget              *widget,
                                                                          GdkEventButton         *event);
187
188
static gboolean             exo_icon_view_scroll_event                   (GtkWidget              *widget,
                                                                          GdkEventScroll         *event);
189
190
191
192
static gboolean             exo_icon_view_key_press_event                (GtkWidget              *widget,
                                                                          GdkEventKey            *event);
static gboolean             exo_icon_view_focus_out_event                (GtkWidget              *widget,
                                                                          GdkEventFocus          *event);
193
194
static gboolean             exo_icon_view_leave_notify_event             (GtkWidget              *widget,
                                                                          GdkEventCrossing       *event);
195
196
197
198
199
200
201
202
203
204
205
206
207
208
static void                 exo_icon_view_remove                         (GtkContainer           *container,
                                                                          GtkWidget              *widget);
static void                 exo_icon_view_forall                         (GtkContainer           *container,
                                                                          gboolean                include_internals,
                                                                          GtkCallback             callback,
                                                                          gpointer                callback_data);
static void                 exo_icon_view_set_adjustments                (ExoIconView            *icon_view,
                                                                          GtkAdjustment          *hadj,
                                                                          GtkAdjustment          *vadj);
static void                 exo_icon_view_real_select_all                (ExoIconView            *icon_view);
static void                 exo_icon_view_real_unselect_all              (ExoIconView            *icon_view);
static void                 exo_icon_view_real_select_cursor_item        (ExoIconView            *icon_view);
static void                 exo_icon_view_real_toggle_cursor_item        (ExoIconView            *icon_view);
static gboolean             exo_icon_view_real_activate_cursor_item      (ExoIconView            *icon_view);
209
static gboolean             exo_icon_view_real_start_interactive_search  (ExoIconView            *icon_view);
210
211
static void                 exo_icon_view_adjustment_changed             (GtkAdjustment          *adjustment,
                                                                          ExoIconView            *icon_view);
212
213
214
215
216
217
218
219
220
221
static gint                 exo_icon_view_layout_cols                    (ExoIconView            *icon_view,
                                                                          gint                    item_height,
                                                                          gint                   *x,
                                                                          gint                   *maximum_height,
                                                                          gint                    max_rows);
static gint                 exo_icon_view_layout_rows                    (ExoIconView            *icon_view,
                                                                          gint                    item_width,
                                                                          gint                   *y,
                                                                          gint                   *maximum_width,
                                                                          gint                    max_cols);
222
static void                 exo_icon_view_layout                         (ExoIconView            *icon_view);
223
224
225
226
227
228
static void                 exo_icon_view_paint_item                     (ExoIconView            *icon_view,
                                                                          ExoIconViewItem        *item,
                                                                          cairo_t                *cr,
                                                                          gint                    x,
                                                                          gint                    y,
                                                                          gboolean                draw_focus);
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
static void                 exo_icon_view_queue_draw_item                (ExoIconView            *icon_view,
                                                                          ExoIconViewItem        *item);
static void                 exo_icon_view_queue_layout                   (ExoIconView            *icon_view);
static void                 exo_icon_view_set_cursor_item                (ExoIconView            *icon_view,
                                                                          ExoIconViewItem        *item,
                                                                          gint                    cursor_cell);
static void                 exo_icon_view_start_rubberbanding            (ExoIconView            *icon_view,
                                                                          gint                    x,
                                                                          gint                    y);
static void                 exo_icon_view_stop_rubberbanding             (ExoIconView            *icon_view);
static void                 exo_icon_view_update_rubberband_selection    (ExoIconView            *icon_view);
static gboolean             exo_icon_view_item_hit_test                  (ExoIconView            *icon_view,
                                                                          ExoIconViewItem        *item,
                                                                          gint                    x,
                                                                          gint                    y,
                                                                          gint                    width,
                                                                          gint                    height);
static gboolean             exo_icon_view_unselect_all_internal          (ExoIconView            *icon_view);
static void                 exo_icon_view_calculate_item_size            (ExoIconView            *icon_view,
                                                                          ExoIconViewItem        *item);
static void                 exo_icon_view_calculate_item_size2           (ExoIconView            *icon_view,
                                                                          ExoIconViewItem        *item,
251
                                                                          gint                   *max_width,
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
                                                                          gint                   *max_height);
static void                 exo_icon_view_update_rubberband              (gpointer                data);
static void                 exo_icon_view_invalidate_sizes               (ExoIconView            *icon_view);
static void                 exo_icon_view_add_move_binding               (GtkBindingSet          *binding_set,
                                                                          guint                   keyval,
                                                                          guint                   modmask,
                                                                          GtkMovementStep         step,
                                                                          gint                    count);
static gboolean             exo_icon_view_real_move_cursor               (ExoIconView            *icon_view,
                                                                          GtkMovementStep         step,
                                                                          gint                    count);
static void                 exo_icon_view_move_cursor_up_down            (ExoIconView            *icon_view,
                                                                          gint                    count);
static void                 exo_icon_view_move_cursor_page_up_down       (ExoIconView            *icon_view,
                                                                          gint                    count);
static void                 exo_icon_view_move_cursor_left_right         (ExoIconView            *icon_view,
                                                                          gint                    count);
static void                 exo_icon_view_move_cursor_start_end          (ExoIconView            *icon_view,
                                                                          gint                    count);
static void                 exo_icon_view_scroll_to_item                 (ExoIconView            *icon_view,
                                                                          ExoIconViewItem        *item);
static void                 exo_icon_view_select_item                    (ExoIconView            *icon_view,
                                                                          ExoIconViewItem        *item);
static void                 exo_icon_view_unselect_item                  (ExoIconView            *icon_view,
                                                                          ExoIconViewItem        *item);
static gboolean             exo_icon_view_select_all_between             (ExoIconView            *icon_view,
                                                                          ExoIconViewItem        *anchor,
                                                                          ExoIconViewItem        *cursor);
static ExoIconViewItem *    exo_icon_view_get_item_at_coords             (const ExoIconView      *icon_view,
                                                                          gint                    x,
                                                                          gint                    y,
                                                                          gboolean                only_in_cell,
                                                                          ExoIconViewCellInfo   **cell_at_pos);
static void                 exo_icon_view_get_cell_area                  (ExoIconView            *icon_view,
                                                                          ExoIconViewItem        *item,
                                                                          ExoIconViewCellInfo    *cell_info,
                                                                          GdkRectangle           *cell_area);
static ExoIconViewCellInfo *exo_icon_view_get_cell_info                  (ExoIconView            *icon_view,
                                                                          GtkCellRenderer        *renderer);
static void                 exo_icon_view_set_cell_data                  (const ExoIconView      *icon_view,
                                                                          ExoIconViewItem        *item);
static void                 exo_icon_view_cell_layout_pack_start         (GtkCellLayout          *layout,
                                                                          GtkCellRenderer        *renderer,
                                                                          gboolean                expand);
static void                 exo_icon_view_cell_layout_pack_end           (GtkCellLayout          *layout,
                                                                          GtkCellRenderer        *renderer,
                                                                          gboolean                expand);
static void                 exo_icon_view_cell_layout_add_attribute      (GtkCellLayout          *layout,
                                                                          GtkCellRenderer        *renderer,
                                                                          const gchar            *attribute,
                                                                          gint                    column);
static void                 exo_icon_view_cell_layout_clear              (GtkCellLayout          *layout);
static void                 exo_icon_view_cell_layout_clear_attributes   (GtkCellLayout          *layout,
                                                                          GtkCellRenderer        *renderer);
static void                 exo_icon_view_cell_layout_set_cell_data_func (GtkCellLayout          *layout,
                                                                          GtkCellRenderer        *cell,
                                                                          GtkCellLayoutDataFunc   func,
                                                                          gpointer                func_data,
                                                                          GDestroyNotify          destroy);
static void                 exo_icon_view_cell_layout_reorder            (GtkCellLayout          *layout,
                                                                          GtkCellRenderer        *cell,
                                                                          gint                    position);
static void                 exo_icon_view_item_activate_cell             (ExoIconView            *icon_view,
                                                                          ExoIconViewItem        *item,
                                                                          ExoIconViewCellInfo    *cell_info,
                                                                          GdkEvent               *event);
static void                 exo_icon_view_put                            (ExoIconView            *icon_view,
                                                                          GtkWidget              *widget,
                                                                          ExoIconViewItem        *item,
                                                                          gint                    cell);
static void                 exo_icon_view_remove_widget                  (GtkCellEditable        *editable,
                                                                          ExoIconView            *icon_view);
static void                 exo_icon_view_start_editing                  (ExoIconView            *icon_view,
                                                                          ExoIconViewItem        *item,
                                                                          ExoIconViewCellInfo    *cell_info,
                                                                          GdkEvent               *event);
static void                 exo_icon_view_stop_editing                   (ExoIconView            *icon_view,
                                                                          gboolean                cancel_editing);
330
331
332
333
334
static void                 exo_icon_view_set_pixbuf_column              (ExoIconView            *icon_view,
                                                                          gint                    column);
static void                 exo_icon_view_set_icon_column                (ExoIconView            *icon_view,
                                                                          gint                    column);

335
336
static void                 exo_icon_view_get_work_area_dimensions       (GdkWindow              *window,
                                                                          GdkRectangle           *dimensions);
337
338
339
340
341
342
343
344
345
346

/* Source side drag signals */
static void exo_icon_view_drag_begin       (GtkWidget        *widget,
                                            GdkDragContext   *context);
static void exo_icon_view_drag_end         (GtkWidget        *widget,
                                            GdkDragContext   *context);
static void exo_icon_view_drag_data_get    (GtkWidget        *widget,
                                            GdkDragContext   *context,
                                            GtkSelectionData *selection_data,
                                            guint             info,
347
                                            guint             drag_time);
348
349
350
351
352
353
static void exo_icon_view_drag_data_delete (GtkWidget        *widget,
                                            GdkDragContext   *context);

/* Target side drag signals */
static void     exo_icon_view_drag_leave         (GtkWidget        *widget,
                                                  GdkDragContext   *context,
354
                                                  guint             drag_time);
355
356
357
358
static gboolean exo_icon_view_drag_motion        (GtkWidget        *widget,
                                                  GdkDragContext   *context,
                                                  gint              x,
                                                  gint              y,
359
                                                  guint             drag_time);
360
361
362
363
static gboolean exo_icon_view_drag_drop          (GtkWidget        *widget,
                                                  GdkDragContext   *context,
                                                  gint              x,
                                                  gint              y,
364
                                                  guint             drag_time);
365
366
367
368
369
370
static void     exo_icon_view_drag_data_received (GtkWidget        *widget,
                                                  GdkDragContext   *context,
                                                  gint              x,
                                                  gint              y,
                                                  GtkSelectionData *selection_data,
                                                  guint             info,
371
                                                  guint             drag_time);
372
373
static gboolean exo_icon_view_maybe_begin_drag   (ExoIconView      *icon_view,
                                                  GdkEventMotion   *event);
374
375
376

static void     remove_scroll_timeout            (ExoIconView *icon_view);

377
378
379
380
/* single-click autoselection support */
static gboolean exo_icon_view_single_click_timeout          (gpointer user_data);
static void     exo_icon_view_single_click_timeout_destroy  (gpointer user_data);

381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
/* Interactive search support */
static void     exo_icon_view_search_activate           (GtkEntry       *entry,
                                                         ExoIconView    *icon_view);
static void     exo_icon_view_search_dialog_hide        (GtkWidget      *search_dialog,
                                                         ExoIconView    *icon_view);
static void     exo_icon_view_search_ensure_directory   (ExoIconView    *icon_view);
static void     exo_icon_view_search_init               (GtkWidget      *search_entry,
                                                         ExoIconView    *icon_view);
static gboolean exo_icon_view_search_iter               (ExoIconView    *icon_view,
                                                         GtkTreeModel   *model,
                                                         GtkTreeIter    *iter,
                                                         const gchar    *text,
                                                         gint           *count,
                                                         gint            n);
static void     exo_icon_view_search_move               (GtkWidget      *widget,
                                                         ExoIconView    *icon_view,
                                                         gboolean        move_up);
static gboolean exo_icon_view_search_start              (ExoIconView    *icon_view,
                                                         gboolean        keybinding);
static gboolean exo_icon_view_search_equal_func         (GtkTreeModel   *model,
                                                         gint            column,
                                                         const gchar    *key,
                                                         GtkTreeIter    *iter,
                                                         gpointer        user_data);
static void     exo_icon_view_search_position_func      (ExoIconView    *icon_view,
                                                         GtkWidget      *search_dialog,
                                                         gpointer        user_data);
static gboolean exo_icon_view_search_button_press_event (GtkWidget      *widget,
                                                         GdkEventButton *event,
                                                         ExoIconView    *icon_view);
static gboolean exo_icon_view_search_delete_event       (GtkWidget      *widget,
                                                         GdkEventAny    *event,
                                                         ExoIconView    *icon_view);
static gboolean exo_icon_view_search_key_press_event    (GtkWidget      *widget,
                                                         GdkEventKey    *event,
                                                         ExoIconView    *icon_view);
static gboolean exo_icon_view_search_scroll_event       (GtkWidget      *widget,
                                                         GdkEventScroll *event,
                                                         ExoIconView    *icon_view);
static gboolean exo_icon_view_search_timeout            (gpointer        user_data);
static void     exo_icon_view_search_timeout_destroy    (gpointer        user_data);

423
424
425
426
427
428
429
430
431
432
433
434
435


struct _ExoIconViewCellInfo
{
  GtkCellRenderer      *cell;
  guint                 expand : 1;
  guint                 pack : 1;
  guint                 editing : 1;
  gint                  position;
  GSList               *attributes;
  GtkCellLayoutDataFunc func;
  gpointer              func_data;
  GDestroyNotify        destroy;
436
  gboolean              is_text;
437
438
439
440
441
442
443
444
};

struct _ExoIconViewChild
{
  ExoIconViewItem *item;
  GtkWidget       *widget;
  gint             cell;
};
Benedikt Meurer's avatar
Benedikt Meurer committed
445

446
struct _ExoIconViewItem
Benedikt Meurer's avatar
Benedikt Meurer committed
447
448
{
  GtkTreeIter iter;
Nick Schermer's avatar
Nick Schermer committed
449

450
451
452
  /* Bounding box (a value of -1 for width indicates
   * that the item needs to be layouted first)
   */
453
  GdkRectangle area;
Benedikt Meurer's avatar
Benedikt Meurer committed
454

455
456
  /* Individual cells.
   * box[i] is the actual area occupied by cell i,
Nick Schermer's avatar
Nick Schermer committed
457
458
   * before, after are used to calculate the cell
   * area relative to the box.
459
460
461
462
463
464
   * See exo_icon_view_get_cell_area().
   */
  gint n_cells;
  GdkRectangle *box;
  gint *before;
  gint *after;
Benedikt Meurer's avatar
Benedikt Meurer committed
465

466
467
  guint row : ((sizeof (guint) / 2) * 8) - 1;
  guint col : ((sizeof (guint) / 2) * 8) - 1;
Benedikt Meurer's avatar
Benedikt Meurer committed
468
469
  guint selected : 1;
  guint selected_before_rubberbanding : 1;
470
};
Benedikt Meurer's avatar
Benedikt Meurer committed
471
472
473
474

struct _ExoIconViewPrivate
{
  gint width, height;
475
  gint rows, cols;
Benedikt Meurer's avatar
Benedikt Meurer committed
476
477
478

  GtkSelectionMode selection_mode;

479
480
  ExoIconViewLayoutMode layout_mode;

Benedikt Meurer's avatar
Benedikt Meurer committed
481
482
  GdkWindow *bin_window;

483
484
  GList *children;

Benedikt Meurer's avatar
Benedikt Meurer committed
485
  GtkTreeModel *model;
Nick Schermer's avatar
Nick Schermer committed
486

Benedikt Meurer's avatar
Benedikt Meurer committed
487
  GList *items;
Nick Schermer's avatar
Nick Schermer committed
488

Benedikt Meurer's avatar
Benedikt Meurer committed
489
490
  GtkAdjustment *hadjustment;
  GtkAdjustment *vadjustment;
Sean Davis's avatar
Sean Davis committed
491

492
493
  GtkScrollablePolicy hscroll_policy;
  GtkScrollablePolicy vscroll_policy;
Benedikt Meurer's avatar
Benedikt Meurer committed
494

495
  guint layout_idle_id;
Nick Schermer's avatar
Nick Schermer committed
496

Benedikt Meurer's avatar
Benedikt Meurer committed
497
  gboolean doing_rubberband;
498
  gint rubberband_x_1, rubberband_y_1;
Benedikt Meurer's avatar
Benedikt Meurer committed
499
500
  gint rubberband_x2, rubberband_y2;

501
  guint scroll_timeout_id;
Benedikt Meurer's avatar
Benedikt Meurer committed
502
503
504
505
506
  gint scroll_value_diff;
  gint event_last_x, event_last_y;

  ExoIconViewItem *anchor_item;
  ExoIconViewItem *cursor_item;
507
508
509
  ExoIconViewItem *edited_item;
  GtkCellEditable *editable;
  ExoIconViewItem *prelit_item;
Benedikt Meurer's avatar
Benedikt Meurer committed
510
511
512

  ExoIconViewItem *last_single_clicked;

513
  GList *cell_list;
514
  gint n_cells;
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529

  gint cursor_cell;

  GtkOrientation orientation;

  gint columns;
  gint item_width;
  gint spacing;
  gint row_spacing;
  gint column_spacing;
  gint margin;

  gint text_column;
  gint markup_column;
  gint pixbuf_column;
530
  gint icon_column;
531
532
533
534

  gint pixbuf_cell;
  gint text_cell;

Benedikt Meurer's avatar
Benedikt Meurer committed
535
  /* Drag-and-drop. */
536
  GdkModifierType start_button_mask;
Benedikt Meurer's avatar
Benedikt Meurer committed
537
538
539
540
  gint pressed_button;
  gint press_start_x;
  gint press_start_y;

541
542
  GtkTargetList *source_targets;
  GdkDragAction source_actions;
Benedikt Meurer's avatar
Benedikt Meurer committed
543

544
545
  GtkTargetList *dest_targets;
  GdkDragAction dest_actions;
Benedikt Meurer's avatar
Benedikt Meurer committed
546

547
548
549
  GtkTreeRowReference *dest_item;
  ExoIconViewDropPosition dest_pos;

550
551
552
553
554
555
556
557
558
559
560
561
562
563
  /* delayed scrolling */
  GtkTreeRowReference          *scroll_to_path;
  gfloat                        scroll_to_row_align;
  gfloat                        scroll_to_col_align;
  guint                         scroll_to_use_align : 1;

  /* misc flags */
  guint                         source_set : 1;
  guint                         dest_set : 1;
  guint                         reorderable : 1;
  guint                         empty_view_drop :1;

  guint                         ctrl_pressed : 1;
  guint                         shift_pressed : 1;
564

565
566
567
568
569
570
571
  /* Single-click support
   * The single_click_timeout is the timeout after which the
   * prelited item will be automatically selected in single
   * click mode (0 to disable).
   */
  guint                         single_click : 1;
  guint                         single_click_timeout;
572
  guint                         single_click_timeout_id;
573
574
  guint                         single_click_timeout_state;

575
576
577
578
  /* Interactive search support */
  guint                         enable_search : 1;
  gint                          search_column;
  gint                          search_selected_iter;
579
  guint                         search_timeout_id;
580
581
582
583
584
585
586
587
588
589
590
  gboolean                      search_disable_popdown;
  ExoIconViewSearchEqualFunc    search_equal_func;
  gpointer                      search_equal_data;
  GDestroyNotify                search_equal_destroy;
  ExoIconViewSearchPositionFunc search_position_func;
  gpointer                      search_position_data;
  GDestroyNotify                search_position_destroy;
  gint                          search_entry_changed_id;
  GtkWidget                    *search_entry;
  GtkWidget                    *search_window;

591
592
  /* ExoIconViewFlags */
  guint flags;
Benedikt Meurer's avatar
Benedikt Meurer committed
593
594
};

595
596


597
598
599
600
#include <exo/exo-icon-view-accessible.c>



Nick Schermer's avatar
Nick Schermer committed
601
static guint icon_view_signals[LAST_SIGNAL];
602
603
604



Nick Schermer's avatar
Nick Schermer committed
605
G_DEFINE_TYPE_WITH_CODE (ExoIconView, exo_icon_view, GTK_TYPE_CONTAINER,
606
607
    G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT, exo_icon_view_cell_layout_init)
    G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL)
608
    G_ADD_PRIVATE (ExoIconView))
609

610
611
612
613
static AtkObject *
exo_icon_view_get_accessible (GtkWidget *widget)
{
  static gboolean initited = FALSE;
614
  GType derived_type;
615
616
617
  AtkObjectFactory *factory;
  AtkRegistry *registry;
  GType derived_atk_type;
618

619
620
621
622
623
624
625
  if (!initited)
    {
      derived_type = g_type_parent (EXO_TYPE_ICON_VIEW);

      registry = atk_get_default_registry ();
      factory = atk_registry_get_factory (registry, derived_type);
      derived_atk_type = atk_object_factory_get_accessible_type (factory);
626

627
628
629
630
631
632
633
634
635
636
637
      if (g_type_is_a (derived_atk_type, GTK_TYPE_ACCESSIBLE))
        {
          atk_registry_set_factory_type (registry, EXO_TYPE_ICON_VIEW,
                                         exo_icon_view_accessible_factory_get_type ());
        }

      initited = TRUE;
    }

  return GTK_WIDGET_CLASS (exo_icon_view_parent_class)->get_accessible (widget);
}
Benedikt Meurer's avatar
Benedikt Meurer committed
638

639
static void
640
exo_icon_view_get_work_area_dimensions (GdkWindow *window, GdkRectangle *dimensions)
641
642
643
644
{
  GdkDisplay   *display;
  GdkRectangle  geometry;

645
  GdkMonitor   *monitor;
646

647
648
649
  display = gdk_window_get_display (window);
  monitor = gdk_display_get_monitor_at_window (display, window);
  gdk_monitor_get_workarea (monitor, &geometry);
650

651
652
653
654
655
656
657
  if (dimensions != NULL)
    {
       dimensions->x = geometry.x;
       dimensions->y = geometry.y;
       dimensions->width = geometry.width;
       dimensions->height = geometry.height;
    }
658
659
660
661
}



Benedikt Meurer's avatar
Benedikt Meurer committed
662
663
664
static void
exo_icon_view_class_init (ExoIconViewClass *klass)
{
665
666
667
668
  GtkContainerClass *gtkcontainer_class;
  GtkWidgetClass    *gtkwidget_class;
  GtkBindingSet     *gtkbinding_set;
  GObjectClass      *gobject_class;
Benedikt Meurer's avatar
Benedikt Meurer committed
669

670
671
  gobject_class = G_OBJECT_CLASS (klass);
  gobject_class->dispose = exo_icon_view_dispose;
Benedikt Meurer's avatar
Benedikt Meurer committed
672
673
674
675
  gobject_class->finalize = exo_icon_view_finalize;
  gobject_class->set_property = exo_icon_view_set_property;
  gobject_class->get_property = exo_icon_view_get_property;

676
677
678
  gtkwidget_class = GTK_WIDGET_CLASS (klass);
  gtkwidget_class->realize = exo_icon_view_realize;
  gtkwidget_class->unrealize = exo_icon_view_unrealize;
679
680
  gtkwidget_class->get_preferred_width = exo_icon_view_get_preferred_width;
  gtkwidget_class->get_preferred_height = exo_icon_view_get_preferred_height;
681
  gtkwidget_class->size_allocate = exo_icon_view_size_allocate;
682
  gtkwidget_class->get_accessible = exo_icon_view_get_accessible;
683
  gtkwidget_class->draw = exo_icon_view_draw;
684
685
686
  gtkwidget_class->motion_notify_event = exo_icon_view_motion_notify_event;
  gtkwidget_class->button_press_event = exo_icon_view_button_press_event;
  gtkwidget_class->button_release_event = exo_icon_view_button_release_event;
687
  gtkwidget_class->scroll_event = exo_icon_view_scroll_event;
688
689
  gtkwidget_class->key_press_event = exo_icon_view_key_press_event;
  gtkwidget_class->focus_out_event = exo_icon_view_focus_out_event;
690
  gtkwidget_class->leave_notify_event = exo_icon_view_leave_notify_event;
691
692
693
694
695
696
697
698
699
700
701
702
  gtkwidget_class->drag_begin = exo_icon_view_drag_begin;
  gtkwidget_class->drag_end = exo_icon_view_drag_end;
  gtkwidget_class->drag_data_get = exo_icon_view_drag_data_get;
  gtkwidget_class->drag_data_delete = exo_icon_view_drag_data_delete;
  gtkwidget_class->drag_leave = exo_icon_view_drag_leave;
  gtkwidget_class->drag_motion = exo_icon_view_drag_motion;
  gtkwidget_class->drag_drop = exo_icon_view_drag_drop;
  gtkwidget_class->drag_data_received = exo_icon_view_drag_data_received;

  gtkcontainer_class = GTK_CONTAINER_CLASS (klass);
  gtkcontainer_class->remove = exo_icon_view_remove;
  gtkcontainer_class->forall = exo_icon_view_forall;
Benedikt Meurer's avatar
Benedikt Meurer committed
703
704
705
706
707
708
709

  klass->set_scroll_adjustments = exo_icon_view_set_adjustments;
  klass->select_all = exo_icon_view_real_select_all;
  klass->unselect_all = exo_icon_view_real_unselect_all;
  klass->select_cursor_item = exo_icon_view_real_select_cursor_item;
  klass->toggle_cursor_item = exo_icon_view_real_toggle_cursor_item;
  klass->move_cursor = exo_icon_view_real_move_cursor;
Nick Schermer's avatar
Nick Schermer committed
710
  klass->activate_cursor_item = exo_icon_view_real_activate_cursor_item;
711
  klass->start_interactive_search = exo_icon_view_real_start_interactive_search;
Nick Schermer's avatar
Nick Schermer committed
712

Benedikt Meurer's avatar
Benedikt Meurer committed
713
  /**
714
   * ExoIconView:column-spacing:
715
716
717
718
719
720
   *
   * The column-spacing property specifies the space which is inserted between
   * the columns of the icon view.
   *
   * Since: 0.3.1
   **/
Benedikt Meurer's avatar
Benedikt Meurer committed
721
  g_object_class_install_property (gobject_class,
722
723
724
725
726
727
                                   PROP_COLUMN_SPACING,
                                   g_param_spec_int ("column-spacing",
                                                     _("Column Spacing"),
                                                     _("Space which is inserted between grid column"),
                                                     0, G_MAXINT, 6,
                                                     EXO_PARAM_READWRITE));
Benedikt Meurer's avatar
Benedikt Meurer committed
728
729

  /**
730
   * ExoIconView:columns:
Benedikt Meurer's avatar
Benedikt Meurer committed
731
   *
732
733
734
735
736
737
   * The columns property contains the number of the columns in which the
   * items should be displayed. If it is -1, the number of columns will
   * be chosen automatically to fill the available area.
   *
   * Since: 0.3.1
   **/
Benedikt Meurer's avatar
Benedikt Meurer committed
738
  g_object_class_install_property (gobject_class,
739
740
741
742
                                   PROP_COLUMNS,
                                   g_param_spec_int ("columns",
                                                     _("Number of columns"),
                                                     _("Number of columns to display"),
Benedikt Meurer's avatar
Benedikt Meurer committed
743
                                                     -1, G_MAXINT, -1,
744
                                                     EXO_PARAM_READWRITE));
Nick Schermer's avatar
Nick Schermer committed
745

746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
  /**
   * ExoIconView:enable-search:
   *
   * View allows user to search through columns interactively.
   *
   * Since: 0.3.1.3
   **/
  g_object_class_install_property (gobject_class,
                                   PROP_ENABLE_SEARCH,
                                   g_param_spec_boolean ("enable-search",
                                                         _("Enable Search"),
                                                         _("View allows user to search through columns interactively"),
                                                         TRUE,
                                                         EXO_PARAM_READWRITE));

Benedikt Meurer's avatar
Benedikt Meurer committed
761
762

  /**
763
   * ExoIconView:item-width:
Benedikt Meurer's avatar
Benedikt Meurer committed
764
   *
Nick Schermer's avatar
Nick Schermer committed
765
766
   * The item-width property specifies the width to use for each item.
   * If it is set to -1, the icon view will automatically determine a
767
768
769
770
   * suitable item size.
   *
   * Since: 0.3.1
   **/
Benedikt Meurer's avatar
Benedikt Meurer committed
771
  g_object_class_install_property (gobject_class,
772
773
774
775
                                   PROP_ITEM_WIDTH,
                                   g_param_spec_int ("item-width",
                                                     _("Width for each item"),
                                                     _("The width used for each item"),
776
                                                     -1, G_MAXINT, -1,
Nick Schermer's avatar
Nick Schermer committed
777
                                                     EXO_PARAM_READWRITE));
778

779
780
781
782
783
784
785
786
  /**
   * ExoIconView:layout-mode:
   *
   * The layout-mode property specifies the way items are layed out in
   * the #ExoIconView. This can be either %EXO_ICON_VIEW_LAYOUT_ROWS,
   * which is the default, where items are layed out horizontally in
   * rows from top to bottom, or %EXO_ICON_VIEW_LAYOUT_COLS, where items
   * are layed out vertically in columns from left to right.
Nick Schermer's avatar
Nick Schermer committed
787
   *
788
789
790
791
792
793
794
795
796
797
798
   * Since: 0.3.1.5
   **/
  g_object_class_install_property (gobject_class,
                                   PROP_LAYOUT_MODE,
                                   g_param_spec_enum ("layout-mode",
                                                      _("Layout mode"),
                                                      _("The layout mode"),
                                                      EXO_TYPE_ICON_VIEW_LAYOUT_MODE,
                                                      EXO_ICON_VIEW_LAYOUT_ROWS,
                                                      EXO_PARAM_READWRITE));

799
  /**
800
   * ExoIconView:margin:
801
   *
Nick Schermer's avatar
Nick Schermer committed
802
   * The margin property specifies the space which is inserted
803
804
805
806
807
808
809
810
811
812
813
   * at the edges of the icon view.
   *
   * Since: 0.3.1
   **/
  g_object_class_install_property (gobject_class,
                                   PROP_MARGIN,
                                   g_param_spec_int ("margin",
                                                     _("Margin"),
                                                     _("Space which is inserted at the edges of the icon view"),
                                                     0, G_MAXINT, 6,
                                                     EXO_PARAM_READWRITE));
Benedikt Meurer's avatar
Benedikt Meurer committed
814
815

  /**
816
   * ExoIconView:markup-column:
Benedikt Meurer's avatar
Benedikt Meurer committed
817
   *
818
   * The markup-column property contains the number of the model column
Nick Schermer's avatar
Nick Schermer committed
819
820
   * containing markup information to be displayed. The markup column must be
   * of type #G_TYPE_STRING. If this property and the text-column property
Benedikt Meurer's avatar
Benedikt Meurer committed
821
   * are both set to column numbers, it overrides the text column.
Nick Schermer's avatar
Nick Schermer committed
822
   * If both are set to -1, no texts are displayed.
823
   **/
Benedikt Meurer's avatar
Benedikt Meurer committed
824
  g_object_class_install_property (gobject_class,
825
                                   PROP_MARKUP_COLUMN,
826
                                   g_param_spec_int ("markup-column",
827
828
829
                                                     _("Markup column"),
                                                     _("Model column used to retrieve the text if using Pango markup"),
                                                     -1, G_MAXINT, -1,
830
831
832
                                                     EXO_PARAM_READWRITE));

  /**
833
   * ExoIconView:model:
834
   *
835
   * The model property contains the #GtkTreeModel, which should be
836
837
838
   * display by this icon view. Setting this property to %NULL turns
   * off the display of anything.
   **/
Benedikt Meurer's avatar
Benedikt Meurer committed
839
840
841
  g_object_class_install_property (gobject_class,
                                   PROP_MODEL,
                                   g_param_spec_object ("model",
842
843
844
                                                        _("Icon View Model"),
                                                        _("The model for the icon view"),
                                                        GTK_TYPE_TREE_MODEL,
845
                                                        EXO_PARAM_READWRITE));
Nick Schermer's avatar
Nick Schermer committed
846

847
  /**
848
   * ExoIconView:orientation:
849
   *
Nick Schermer's avatar
Nick Schermer committed
850
   * The orientation property specifies how the cells (i.e. the icon and
851
852
   * the text) of the item are positioned relative to each other.
   **/
Benedikt Meurer's avatar
Benedikt Meurer committed
853
  g_object_class_install_property (gobject_class,
854
855
856
857
858
859
                                   PROP_ORIENTATION,
                                   g_param_spec_enum ("orientation",
                                                      _("Orientation"),
                                                      _("How the text and icon of each item are positioned relative to each other"),
                                                      GTK_TYPE_ORIENTATION,
                                                      GTK_ORIENTATION_VERTICAL,
860
861
862
                                                      EXO_PARAM_READWRITE));

  /**
863
   * ExoIconView:pixbuf-column:
864
865
   *
   * The ::pixbuf-column property contains the number of the model column
Nick Schermer's avatar
Nick Schermer committed
866
   * containing the pixbufs which are displayed. The pixbuf column must be
867
868
869
870
871
872
873
874
875
876
877
   * of type #GDK_TYPE_PIXBUF. Setting this property to -1 turns off the
   * display of pixbufs.
   **/
  g_object_class_install_property (gobject_class,
                                   PROP_PIXBUF_COLUMN,
                                   g_param_spec_int ("pixbuf-column",
                                                     _("Pixbuf column"),
                                                     _("Model column used to retrieve the icon pixbuf from"),
                                                     -1, G_MAXINT, -1,
                                                     EXO_PARAM_READWRITE));

878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
  /**
   * ExoIconView:icon-column:
   *
   * The ::icon-column property contains the number of the model column
   * containing an absolute path to an image file to render. The icon column
   * must be of type #G_TYPE_STRING. Setting this property to -1 turns off
   * the display of icons.
   *
   * Since: 0.10.2
   **/
  g_object_class_install_property (gobject_class,
                                   PROP_ICON_COLUMN,
                                   g_param_spec_int ("icon-column",
                                                     _("Icon column"),
                                                     _("Model column used to retrieve the absolute path of an image file to render"),
                                                     -1, G_MAXINT, -1,
                                                     EXO_PARAM_READWRITE));

896
  /**
897
   * ExoIconView:reorderable:
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
   *
   * The reorderable property specifies if the items can be reordered
   * by Drag and Drop.
   *
   * Since: 0.3.1
   **/
  g_object_class_install_property (gobject_class,
                                   PROP_REORDERABLE,
                                   g_param_spec_boolean ("reorderable",
                                                         _("Reorderable"),
                                                         _("View is reorderable"),
                                                         FALSE,
                                                         EXO_PARAM_READWRITE));

  /**
913
   * ExoIconView:row-spacing:
914
915
916
917
918
919
920
921
922
923
924
925
926
927
   *
   * The row-spacing property specifies the space which is inserted between
   * the rows of the icon view.
   *
   * Since: 0.3.1
   **/
  g_object_class_install_property (gobject_class,
                                   PROP_ROW_SPACING,
                                   g_param_spec_int ("row-spacing",
                                                     _("Row Spacing"),
                                                     _("Space which is inserted between grid rows"),
                                                     0, G_MAXINT, 6,
                                                     EXO_PARAM_READWRITE));

928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
  /**
   * ExoIconView:search-column:
   *
   * Model column to search through when searching through code.
   *
   * Since: 0.3.1.3
   **/
  g_object_class_install_property (gobject_class,
                                   PROP_SEARCH_COLUMN,
                                   g_param_spec_int ("search-column",
                                                     _("Search Column"),
                                                     _("Model column to search through when searching through item"),
                                                     -1, G_MAXINT, -1,
                                                     EXO_PARAM_READWRITE));

943
  /**
944
   * ExoIconView:selection-mode:
Nick Schermer's avatar
Nick Schermer committed
945
   *
946
   * The selection-mode property specifies the selection mode of
947
948
949
950
951
952
953
954
955
956
957
958
959
   * icon view. If the mode is #GTK_SELECTION_MULTIPLE, rubberband selection
   * is enabled, for the other modes, only keyboard selection is possible.
   **/
  g_object_class_install_property (gobject_class,
                                   PROP_SELECTION_MODE,
                                   g_param_spec_enum ("selection-mode",
                                                      _("Selection mode"),
                                                      _("The selection mode"),
                                                      GTK_TYPE_SELECTION_MODE,
                                                      GTK_SELECTION_SINGLE,
                                                      EXO_PARAM_READWRITE));

  /**
960
961
962
963
964
965
966
967
968
969
970
971
972
973
   * ExoIconView:single-click:
   *
   * Determines whether items can be activated by single or double clicks.
   *
   * Since: 0.3.1.3
   **/
  g_object_class_install_property (gobject_class,
                                   PROP_SINGLE_CLICK,
                                   g_param_spec_boolean ("single-click",
                                                         _("Single Click"),
                                                         _("Whether the items in the view can be activated with single clicks"),
                                                         FALSE,
                                                         EXO_PARAM_READWRITE));

974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
  /**
   * ExoIconView:single-click-timeout:
   *
   * The amount of time in milliseconds after which a prelited item (an item
   * which is hovered by the mouse cursor) will be selected automatically in
   * single click mode. A value of %0 disables the automatic selection.
   *
   * Since: 0.3.1.5
   **/
  g_object_class_install_property (gobject_class,
                                   PROP_SINGLE_CLICK_TIMEOUT,
                                   g_param_spec_uint ("single-click-timeout",
                                                      _("Single Click Timeout"),
                                                      _("The amount of time after which the item under the mouse cursor will be selected automatically in single click mode"),
                                                      0, G_MAXUINT, 0,
                                                      EXO_PARAM_READWRITE));

991
992
  /**
   * ExoIconView:spacing:
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
   *
   * The spacing property specifies the space which is inserted between
   * the cells (i.e. the icon and the text) of an item.
   *
   * Since: 0.3.1
   **/
  g_object_class_install_property (gobject_class,
                                   PROP_SPACING,
                                   g_param_spec_int ("spacing",
                                                     _("Spacing"),
                                                     _("Space which is inserted between cells of an item"),
                                                     0, G_MAXINT, 0,
                                                     EXO_PARAM_READWRITE));

  /**
1008
   * ExoIconView:text-column:
1009
   *
1010
   * The text-column property contains the number of the model column
Nick Schermer's avatar
Nick Schermer committed
1011
1012
1013
   * 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.
1014
1015
1016
1017
1018
1019
1020
1021
   **/
  g_object_class_install_property (gobject_class,
                                   PROP_TEXT_COLUMN,
                                   g_param_spec_int ("text-column",
                                                     _("Text column"),
                                                     _("Model column used to retrieve the text from"),
                                                     -1, G_MAXINT, -1,
                                                     EXO_PARAM_READWRITE));
Benedikt Meurer's avatar
Benedikt Meurer committed
1022

1023
1024
1025
1026
1027
  g_object_class_override_property (gobject_class, PROP_HADJUSTMENT, "hadjustment");
  g_object_class_override_property (gobject_class, PROP_VADJUSTMENT, "vadjustment");
  g_object_class_override_property (gobject_class, PROP_HSCROLL_POLICY, "hscroll-policy");
  g_object_class_override_property (gobject_class, PROP_VSCROLL_POLICY, "vscroll-policy");

1028
1029
1030
  /**
   * ExoIconView::item-activated:
   * @icon_view : a #ExoIconView.
1031
   * @path      : the #GtkTreePath of the activated item.
1032
1033
1034
1035
1036
1037
1038
   *
   * The ::item-activated signal is emitted when the method
   * exo_icon_view_item_activated() is called, when the user double clicks
   * an item with the "activate-on-single-click" property set to %FALSE, or
   * when the user single clicks an item when the "activate-on-single-click"
   * property set to %TRUE. It is also emitted when a non-editable item is
   * selected and one of the keys: Space, Return or Enter is pressed.
1039
   **/
Benedikt Meurer's avatar
Benedikt Meurer committed
1040
  icon_view_signals[ITEM_ACTIVATED] =
1041
    g_signal_new (I_("item-activated"),
1042
1043
1044
1045
1046
1047
1048
                  G_TYPE_FROM_CLASS (gobject_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (ExoIconViewClass, item_activated),
                  NULL, NULL,
                  g_cclosure_marshal_VOID__BOXED,
                  G_TYPE_NONE, 1,
                  GTK_TYPE_TREE_PATH);
Benedikt Meurer's avatar
Benedikt Meurer committed
1049

1050
1051
1052
  /**
   * ExoIconView::selection-changed:
   * @icon_view : a #ExoIconView.
1053
1054
1055
   *
   * The ::selection-changed signal is emitted when the selection
   * (i.e. the set of selected items) changes.
1056
   **/
Benedikt Meurer's avatar
Benedikt Meurer committed
1057
  icon_view_signals[SELECTION_CHANGED] =
1058
    g_signal_new (I_("selection-changed"),
1059
1060
1061
1062
1063
1064
                  G_TYPE_FROM_CLASS (gobject_class),
                  G_SIGNAL_RUN_FIRST,
                  G_STRUCT_OFFSET (ExoIconViewClass, selection_changed),
                  NULL, NULL,
                  g_cclosure_marshal_VOID__VOID,
                  G_TYPE_NONE, 0);
1065
1066
1067
1068

  /**
   * ExoIconView::select-all:
   * @icon_view : a #ExoIconView.
1069
1070
1071
1072
1073
1074
1075
1076
   *
   * A #GtkBindingSignal which gets emitted when the user selects all items.
   *
   * Applications should not connect to it, but may emit it with
   * g_signal_emit_by_name() if they need to control selection
   * programmatically.
   *
   * The default binding for this signal is Ctrl-a.
1077
   **/
Benedikt Meurer's avatar
Benedikt Meurer committed
1078
  icon_view_signals[SELECT_ALL] =
1079
    g_signal_new (I_("select-all"),
1080
1081
1082
1083
1084
1085
                  G_TYPE_FROM_CLASS (gobject_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (ExoIconViewClass, select_all),
                  NULL, NULL,
                  g_cclosure_marshal_VOID__VOID,
                  G_TYPE_NONE, 0);
Nick Schermer's avatar
Nick Schermer committed
1086

1087
1088
1089
  /**
   * ExoIconView::unselect-all:
   * @icon_view : a #ExoIconView.
1090
1091
1092
1093
1094
1095
1096
1097
   *
   * A #GtkBindingSignal which gets emitted when the user unselects all items.
   *
   * Applications should not connect to it, but may emit it with
   * g_signal_emit_by_name() if they need to control selection
   * programmatically.
   *
   * The default binding for this signal is Ctrl-Shift-a.
1098
   **/
Benedikt Meurer's avatar
Benedikt Meurer committed
1099
  icon_view_signals[UNSELECT_ALL] =
1100
    g_signal_new (I_("unselect-all"),
1101
1102
1103
1104
1105
1106
                  G_TYPE_FROM_CLASS (gobject_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (ExoIconViewClass, unselect_all),
                  NULL, NULL,
                  g_cclosure_marshal_VOID__VOID,
                  G_TYPE_NONE, 0);
Benedikt Meurer's avatar
Benedikt Meurer committed
1107

1108
1109
1110
  /**
   * ExoIconView::select-cursor-item:
   * @icon_view : a #ExoIconView.
1111
1112
1113
1114
1115
1116
1117
1118
1119
   *
   * A #GtkBindingSignal which gets emitted when the user selects the item
   * that is currently focused.
   *
   * Applications should not connect to it, but may emit it with
   * g_signal_emit_by_name() if they need to control selection
   * programmatically.
   *
   * There is no default binding for this signal.
1120
   **/
Benedikt Meurer's avatar
Benedikt Meurer committed
1121
  icon_view_signals[SELECT_CURSOR_ITEM] =
1122
    g_signal_new (I_("select-cursor-item"),
1123
1124
1125
1126
1127
1128
                  G_TYPE_FROM_CLASS (gobject_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (ExoIconViewClass, select_cursor_item),
                  NULL, NULL,
                  g_cclosure_marshal_VOID__VOID,
                  G_TYPE_NONE, 0);
Benedikt Meurer's avatar
Benedikt Meurer committed
1129

1130
1131
1132
  /**
   * ExoIconView::toggle-cursor-item:
   * @icon_view : a #ExoIconView.
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
   *
   * A #GtkBindingSignal which gets emitted when the user toggles whether
   * the currently focused item is selected or not. The exact effect of
   * this depend on the selection mode.
   *
   * Applications should not connect to it, but may emit it with
   * g_signal_emit_by_name() if they need to control selection
   * programmatically.
   *
   * There is no default binding for this signal is Ctrl-Space.
1143
   **/
Benedikt Meurer's avatar
Benedikt Meurer committed
1144
  icon_view_signals[TOGGLE_CURSOR_ITEM] =
1145
    g_signal_new (I_("toggle-cursor-item"),
1146
1147
1148
1149
1150
1151
                  G_TYPE_FROM_CLASS (gobject_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (ExoIconViewClass, toggle_cursor_item),
                  NULL, NULL,
                  g_cclosure_marshal_VOID__VOID,
                  G_TYPE_NONE, 0);
Benedikt Meurer's avatar
Benedikt Meurer committed
1152

1153
1154
1155
  /**
   * ExoIconView::activate-cursor-item:
   * @icon_view : a #ExoIconView.
Nick Schermer's avatar
Nick Schermer committed
1156
   *
1157
1158
1159
1160
1161
1162
1163
1164
   * A #GtkBindingSignal which gets emitted when the user activates the
   * currently focused item.
   *
   * Applications should not connect to it, but may emit it with
   * g_signal_emit_by_name() if they need to control activation
   * programmatically.
   *
   * The default bindings for this signal are Space, Return and Enter.
1165
   **/
Benedikt Meurer's avatar
Benedikt Meurer committed
1166
  icon_view_signals[ACTIVATE_CURSOR_ITEM] =
1167
    g_signal_new (I_("activate-cursor-item"),
1168
1169
1170
1171
1172
1173
                  G_TYPE_FROM_CLASS (gobject_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (ExoIconViewClass, activate_cursor_item),
                  NULL, NULL,
                  _exo_marshal_BOOLEAN__VOID,
                  G_TYPE_BOOLEAN, 0);
1174
1175
1176

  /**
   * ExoIconView::start-interactive-search:
1177
   * @icon_view : a #ExoIconView.
1178
   *
1179
1180
   * The ::start-interative-search signal is emitted when the user starts
   * typing to jump to an item in the icon view.
1181
1182
1183
1184
1185
1186
1187
1188
1189
   **/
  icon_view_signals[START_INTERACTIVE_SEARCH] =
    g_signal_new (I_("start-interactive-search"),
                  G_TYPE_FROM_CLASS (gobject_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (ExoIconViewClass, start_interactive_search),
                  NULL, NULL,
                  _exo_marshal_BOOLEAN__VOID,
                  G_TYPE_BOOLEAN, 0);
Nick Schermer's avatar
Nick Schermer committed
1190

1191
1192
1193
  /**
   * ExoIconView::move-cursor:
   * @icon_view : a #ExoIconView.
1194
1195
1196
1197
1198
1199
1200
1201
1202
   * @step      : the granularity of the move, as a #GtkMovementStep
   * @count     : the number of @step units to move
   *
   * The ::move-cursor signal is a keybinding signal which gets emitted when
   * the user initiates a cursor movement.
   *
   * Applications should not connect to it, but may emit it with
   * g_signal_emit_by_name() if they need to control the cursor
   * programmatically.
1203
   *
1204
1205
1206
1207
1208
   * The default bindings for this signal include
   * * Arrow keys which move by individual steps
   * * Home/End keys which move to the first/last item
   * * PageUp/PageDown which move by "pages" All of these will extend the
   * selection when combined with the Shift modifier.
1209
   **/
Benedikt Meurer's avatar
Benedikt Meurer committed
1210
  icon_view_signals[MOVE_CURSOR] =
1211
    g_signal_new (I_("move-cursor"),
1212
1213
1214
1215
1216
1217
1218
1219
                  G_TYPE_FROM_CLASS (gobject_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (ExoIconViewClass, move_cursor),
                  NULL, NULL,
                  _exo_marshal_BOOLEAN__ENUM_INT,
                  G_TYPE_BOOLEAN, 2,
                  GTK_TYPE_MOVEMENT_STEP,
                  G_TYPE_INT);
Benedikt Meurer's avatar
Benedikt Meurer committed
1220
1221

  /* Key bindings */
1222
  gtkbinding_set = gtk_binding_set_by_class (klass);
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
  gtk_binding_entry_add_signal (gtkbinding_set, GDK_KEY_a, GDK_CONTROL_MASK, "select-all", 0);
  gtk_binding_entry_add_signal (gtkbinding_set, GDK_KEY_a, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
  gtk_binding_entry_add_signal (gtkbinding_set, GDK_KEY_space, GDK_CONTROL_MASK, "toggle-cursor-item", 0);
  gtk_binding_entry_add_signal (gtkbinding_set, GDK_KEY_space, 0, "activate-cursor-item", 0);
  gtk_binding_entry_add_signal (gtkbinding_set, GDK_KEY_Return, 0, "activate-cursor-item", 0);
  gtk_binding_entry_add_signal (gtkbinding_set, GDK_KEY_ISO_Enter, 0, "activate-cursor-item", 0);
  gtk_binding_entry_add_signal (gtkbinding_set, GDK_KEY_KP_Enter, 0, "activate-cursor-item", 0);
  gtk_binding_entry_add_signal (gtkbinding_set, GDK_KEY_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
  gtk_binding_entry_add_signal (gtkbinding_set, GDK_KEY_F, GDK_CONTROL_MASK, "start-interactive-search", 0);

  exo_icon_view_add_move_binding (gtkbinding_set, GDK_KEY_Up, 0, GTK_MOVEMENT_DISPLAY_LINES, -1);
  exo_icon_view_add_move_binding (gtkbinding_set, GDK_KEY_KP_Up, 0, GTK_MOVEMENT_DISPLAY_LINES, -1);
  exo_icon_view_add_move_binding (gtkbinding_set, GDK_KEY_Down, 0, GTK_MOVEMENT_DISPLAY_LINES, 1);
  exo_icon_view_add_move_binding (gtkbinding_set, GDK_KEY_KP_Down, 0, GTK_MOVEMENT_DISPLAY_LINES, 1);
  exo_icon_view_add_move_binding (gtkbinding_set, GDK_KEY_p, GDK_CONTROL_MASK, GTK_MOVEMENT_DISPLAY_LINES, -1);
  exo_icon_view_add_move_binding (gtkbinding_set, GDK_KEY_n, GDK_CONTROL_MASK, GTK_MOVEMENT_DISPLAY_LINES, 1);
  exo_icon_view_add_move_binding (gtkbinding_set, GDK_KEY_Home, 0, GTK_MOVEMENT_BUFFER_ENDS, -1);
  exo_icon_view_add_move_binding (gtkbinding_set, GDK_KEY_KP_Home, 0, GTK_MOVEMENT_BUFFER_ENDS, -1);
  exo_icon_view_add_move_binding (gtkbinding_set, GDK_KEY_End, 0, GTK_MOVEMENT_BUFFER_ENDS, 1);
  exo_icon_view_add_move_binding (gtkbinding_set, GDK_KEY_KP_End, 0, GTK_MOVEMENT_BUFFER_ENDS, 1);
  exo_icon_view_add_move_binding (gtkbinding_set, GDK_KEY_Page_Up, 0, GTK_MOVEMENT_PAGES, -1);
  exo_icon_view_add_move_binding (gtkbinding_set, GDK_KEY_KP_Page_Up, 0, GTK_MOVEMENT_PAGES, -1);
  exo_icon_view_add_move_binding (gtkbinding_set, GDK_KEY_Page_Down, 0, GTK_MOVEMENT_PAGES, 1);
  exo_icon_view_add_move_binding (gtkbinding_set, GDK_KEY_KP_Page_Down, 0, GTK_MOVEMENT_PAGES, 1);
  exo_icon_view_add_move_binding (gtkbinding_set, GDK_KEY_Right, 0, GTK_MOVEMENT_VISUAL_POSITIONS, 1);
  exo_icon_view_add_move_binding (gtkbinding_set, GDK_KEY_Left, 0, GTK_MOVEMENT_VISUAL_POSITIONS, -1);
  exo_icon_view_add_move_binding (gtkbinding_set, GDK_KEY_KP_Right, 0, GTK_MOVEMENT_VISUAL_POSITIONS, 1);
  exo_icon_view_add_move_binding (gtkbinding_set, GDK_KEY_KP_Left, 0, GTK_MOVEMENT_VISUAL_POSITIONS, -1);
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
}



static void
exo_icon_view_cell_layout_init (GtkCellLayoutIface *iface)
{
  iface->pack_start = exo_icon_view_cell_layout_pack_start;
  iface->pack_end = exo_icon_view_cell_layout_pack_end;
  iface->clear = exo_icon_view_cell_layout_clear;
  iface->add_attribute = exo_icon_view_cell_layout_add_attribute;
  iface->set_cell_data_func = exo_icon_view_cell_layout_set_cell_data_func;
  iface->clear_attributes = exo_icon_view_cell_layout_clear_attributes;
  iface->reorder = exo_icon_view_cell_layout_reorder;
Benedikt Meurer's avatar
Benedikt Meurer committed
1265
1266
}

1267
1268


Benedikt Meurer's avatar
Benedikt Meurer committed
1269
1270
1271
static void
exo_icon_view_init (ExoIconView *icon_view)
{
1272
1273
1274
  gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (icon_view)),
                               GTK_STYLE_CLASS_VIEW);

Andre Miranda's avatar
Andre Miranda committed
1275
  icon_view->priv = exo_icon_view_get_instance_private (icon_view);
Nick Schermer's avatar
Nick Schermer committed
1276

Benedikt Meurer's avatar
Benedikt Meurer committed
1277
1278
1279
1280
1281
  icon_view->priv->selection_mode = GTK_SELECTION_SINGLE;
  icon_view->priv->pressed_button = -1;
  icon_view->priv->press_start_x = -1;
  icon_view->priv->press_start_y = -1;
  icon_view->priv->text_column = -1;
Nick Schermer's avatar
Nick Schermer committed
1282
  icon_view->priv->markup_column = -1;
Benedikt Meurer's avatar
Benedikt Meurer committed
1283
  icon_view->priv->pixbuf_column = -1;
1284
  icon_view->priv->icon_column = -1;
1285
  icon_view->priv->text_cell = -1;
Nick Schermer's avatar
Nick Schermer committed
1286
  icon_view->priv->pixbuf_cell = -1;
Benedikt Meurer's avatar
Benedikt Meurer committed
1287

1288
  gtk_widget_set_can_focus (GTK_WIDGET (icon_view), TRUE);
Nick Schermer's avatar
Nick Schermer committed
1289

Benedikt Meurer's avatar
Benedikt Meurer committed
1290
1291
  exo_icon_view_set_adjustments (icon_view, NULL, NULL);

1292
1293
  icon_view->priv->cursor_cell = -1;

Benedikt Meurer's avatar
Benedikt Meurer committed
1294
  icon_view->priv->orientation = GTK_ORIENTATION_VERTICAL;
1295
1296
1297
1298
1299
1300
1301

  icon_view->priv->columns = -1;
  icon_view->priv->item_width = -1;
  icon_view->priv->row_spacing = 6;
  icon_view->priv->column_spacing = 6;
  icon_view->priv->margin = 6;

1302
1303
1304
1305
1306
  icon_view->priv->enable_search = TRUE;
  icon_view->priv->search_column = -1;
  icon_view->priv->search_equal_func = exo_icon_view_search_equal_func;
  icon_view->priv->search_position_func = exo_icon_view_search_position_func;

1307
  icon_view->priv->flags = EXO_ICON_VIEW_DRAW_KEYFOCUS;
Benedikt Meurer's avatar
Benedikt Meurer committed
1308
1309
}

1310
1311


Benedikt Meurer's avatar
Benedikt Meurer committed
1312
static void
1313
exo_icon_view_dispose (GObject *object)
Benedikt Meurer's avatar
Benedikt Meurer committed
1314
{
1315
  ExoIconView *icon_view = EXO_ICON_VIEW (object);
1316

1317
  /* cancel any pending search timeout */
1318
  if (G_UNLIKELY (icon_view->priv->search_timeout_id != 0))
1319