1 /*
2  *  xfdesktop - xfce4's desktop manager
3  *
4  *  Copyright (c) 2006-2009 Brian Tarricone, <bjt23@cornell.edu>
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU Library General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software Foundation,
18  *  Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 
25 #ifdef HAVE_STRING_H
26 #include <string.h>
27 #endif
28 
29 #ifdef HAVE_MATH_H
30 #include <math.h>
31 #endif
32 
33 #include <glib-object.h>
34 
35 #include <X11/Xlib.h>
36 #include <X11/Xatom.h>
37 
38 #include <gdk/gdk.h>
39 #include <gdk/gdkx.h>
40 #include <gdk/gdkkeysyms.h>
41 #include <gtk/gtk.h>
42 #include <exo/exo.h>
43 
44 #include "xfdesktop-icon-view.h"
45 #include "xfdesktop-file-icon-manager.h"
46 #include "xfdesktop-window-icon-manager.h"
47 #include "xfdesktop-marshal.h"
48 #include "xfce-desktop.h"
49 #include "xfdesktop-volume-icon.h"
50 #include "xfdesktop-common.h"
51 
52 #include <libwnck/libwnck.h>
53 #include <libxfce4ui/libxfce4ui.h>
54 #include <xfconf/xfconf.h>
55 
56 #define DEFAULT_FONT_SIZE     12
57 #define DEFAULT_TOOLTIP_SIZE 128
58 #define MAX_TOOLTIP_SIZE     512
59 
60 #define GRAVITY_HORIZONTAL     1
61 #define GRAVITY_RIGHT          2
62 #define GRAVITY_BOTTOM         4
63 
64 #define ICON_SIZE         (icon_view->priv->icon_size)
65 #define TEXT_WIDTH        ((icon_view->priv->cell_text_width_proportion) * ICON_SIZE)
66 #define ICON_WIDTH        (TEXT_WIDTH)
67 #define CELL_PADDING      (icon_view->priv->cell_padding)
68 #define CELL_SIZE         (TEXT_WIDTH + CELL_PADDING * 2)
69 #define SPACING           (icon_view->priv->cell_spacing)
70 #define LABEL_RADIUS      (icon_view->priv->label_radius)
71 #define SHADOW_EXTENTS    (icon_view->priv->shadow_extents)
72 #define SHADOW_X_OFFSET   MAX(icon_view->priv->shadow_x_offset, icon_view->priv->selected_shadow_x_offset)
73 #define SHADOW_Y_OFFSET   MAX(icon_view->priv->shadow_y_offset, icon_view->priv->selected_shadow_y_offset)
74 #define TEXT_HEIGHT       (CELL_SIZE - ICON_SIZE - SPACING - (CELL_PADDING * 2) - LABEL_RADIUS)
75 #define MIN_MARGIN        8
76 
77 #if defined(DEBUG) && DEBUG > 0
78 #define DUMP_GRID_LAYOUT(icon_view) \
79 {\
80     gint my_i, my_maxi;\
81     \
82     DBG("grid layout dump:"); \
83     my_maxi = icon_view->priv->nrows * icon_view->priv->ncols;\
84     for(my_i = 0; my_i < my_maxi; my_i++)\
85         g_printerr("%c ", icon_view->priv->grid_layout[my_i] ? '1' : '0');\
86     g_printerr("\n\n");\
87 }
88 #else
89 #define DUMP_GRID_LAYOUT(icon_view)
90 #endif
91 
92 enum
93 {
94     SIG_ICON_SELECTION_CHANGED = 0,
95     SIG_ICON_ACTIVATED,
96     SIG_SELECT_ALL,
97     SIG_UNSELECT_ALL,
98     SIG_SELECT_CURSOR_ITEM,
99     SIG_TOGGLE_CURSOR_ITEM,
100     SIG_MOVE_CURSOR,
101     SIG_ACTIVATE_SELECTED_ITEMS,
102     SIG_RESIZE_EVENT,
103     SIG_N_SIGNALS,
104 };
105 
106 typedef struct
107 {
108     XfdesktopIconView *icon_view;
109     XfdesktopIcon *icon;
110     GdkRectangle area;
111     guint source_id;
112 } XfdesktopIdleRepaintData;
113 
114 struct _XfdesktopIconViewPrivate
115 {
116     XfdesktopIconViewManager *manager;
117 
118     GtkWidget *parent_window;
119 
120     guint icon_size;
121     gboolean primary;
122     gdouble font_size;
123     gboolean center_text;
124 
125     WnckScreen *wnck_screen;
126     PangoLayout *playout;
127 
128     GList *pending_icons;
129     GList *icons;
130     GList *selected_icons;
131 
132     gint xorigin;
133     gint yorigin;
134     gint width;
135     gint height;
136 
137     gint xmargin;
138     gint ymargin;
139     gint xspacing;
140     gint yspacing;
141 
142     gint16 nrows;
143     gint16 ncols;
144     XfdesktopIcon **grid_layout;
145 
146     guint grid_resize_timeout;
147 
148     GtkSelectionMode sel_mode;
149     guint maybe_begin_drag:1,
150           definitely_dragging:1,
151           allow_rubber_banding:1,
152           definitely_rubber_banding:1,
153           control_click:1,
154           double_click:1;
155     gint press_start_x;
156     gint press_start_y;
157     GdkRectangle band_rect;
158 
159     XfconfChannel *channel;
160 
161     XfdesktopIcon *cursor;
162     XfdesktopIcon *first_clicked_item;
163     XfdesktopIcon *item_under_pointer;
164 
165     GtkTargetList *native_targets;
166     GtkTargetList *source_targets;
167     GtkTargetList *dest_targets;
168 
169     gboolean drag_source_set;
170     GdkDragAction foreign_source_actions;
171     GdkModifierType foreign_source_mask;
172 
173     gboolean drag_dest_set;
174     GdkDragAction foreign_dest_actions;
175 
176     gboolean dropped;
177     GdkDragAction proposed_drop_action;
178     gint16 hover_row, hover_col;
179 
180     gint cell_padding;
181     gint cell_spacing;
182     gdouble label_radius;
183     gdouble cell_text_width_proportion;
184     gint shadow_extents;
185 
186     gboolean ellipsize_icon_labels;
187 
188     /* tooltip options - There's a style and an xfconf property.
189      * The order is xfconf, style, with a fall back of DEFAULT_TOOLTIP_SIZE.
190      * xfdesktop_icon_view_get_tooltip_size will return the correct size. */
191     gboolean show_tooltips;
192     gint   tooltip_size_from_style;
193     double tooltip_size_from_xfconf;
194 
195     gboolean single_click;
196     gint gravity;
197 };
198 
199 static void xfce_icon_view_set_property(GObject *object,
200                                         guint property_id,
201                                         const GValue *value,
202                                         GParamSpec *pspec);
203 static void xfce_icon_view_get_property(GObject *object,
204                                         guint property_id,
205                                         GValue *value,
206                                         GParamSpec *pspec);
207 
208 static gboolean xfdesktop_icon_view_button_press(GtkWidget *widget,
209                                                  GdkEventButton *evt,
210                                                  gpointer user_data);
211 static gboolean xfdesktop_icon_view_button_release(GtkWidget *widget,
212                                                    GdkEventButton *evt,
213                                                    gpointer user_data);
214 static gboolean xfdesktop_icon_view_key_press(GtkWidget *widget,
215                                               GdkEventKey *evt,
216                                               gpointer user_data);
217 static gboolean xfdesktop_icon_view_focus_in(GtkWidget *widget,
218                                              GdkEventFocus *evt,
219                                              gpointer user_data);
220 static gboolean xfdesktop_icon_view_focus_out(GtkWidget *widget,
221                                               GdkEventFocus *evt,
222                                               gpointer user_data);
223 static gboolean xfdesktop_icon_view_motion_notify(GtkWidget *widget,
224                                                   GdkEventMotion *evt,
225                                                   gpointer user_data);
226 static gboolean xfdesktop_icon_view_leave_notify(GtkWidget *widget,
227                                                  GdkEventCrossing *evt,
228                                                  gpointer user_data);
229 static void xfdesktop_icon_view_style_updated(GtkWidget *widget);
230 static void xfdesktop_icon_view_realize(GtkWidget *widget);
231 static void xfdesktop_icon_view_unrealize(GtkWidget *widget);
232 static gboolean xfdesktop_icon_view_draw(GtkWidget *widget,
233                                          cairo_t *cr);
234 static void xfdesktop_icon_view_drag_begin(GtkWidget *widget,
235                                            GdkDragContext *contest);
236 static gboolean xfdesktop_icon_view_drag_motion(GtkWidget *widget,
237                                                 GdkDragContext *context,
238                                                 gint x,
239                                                 gint y,
240                                                 guint time_);
241 static void xfdesktop_icon_view_drag_leave(GtkWidget *widget,
242                                            GdkDragContext *context,
243                                            guint time_);
244 static gboolean xfdesktop_icon_view_drag_drop(GtkWidget *widget,
245                                               GdkDragContext *context,
246                                               gint x,
247                                               gint y,
248                                               guint time_);
249 static void xfdesktop_icon_view_drag_data_get(GtkWidget *widget,
250                                               GdkDragContext *context,
251                                               GtkSelectionData *data,
252                                               guint info,
253                                               guint time_);
254 static void xfdesktop_icon_view_drag_data_received(GtkWidget *widget,
255                                                    GdkDragContext *context,
256                                                    gint x,
257                                                    gint y,
258                                                    GtkSelectionData *data,
259                                                    guint info,
260                                                    guint time_);
261 
262 static void xfdesktop_icon_view_finalize(GObject *obj);
263 
264 static void xfdesktop_icon_view_add_move_binding(GtkBindingSet *binding_set,
265                                                  guint keyval,
266                                                  guint modmask,
267                                                  GtkMovementStep step,
268                                                  gint count);
269 
270 static gboolean xfdesktop_icon_view_update_icon_extents(XfdesktopIconView *icon_view,
271                                                         XfdesktopIcon *icon,
272                                                         GdkRectangle *pixbuf_extents,
273                                                         GdkRectangle *text_extents,
274                                                         GdkRectangle *box_extents,
275                                                         GdkRectangle *total_extents);
276 static void xfdesktop_icon_view_invalidate_icon(XfdesktopIconView *icon_view,
277                                                 XfdesktopIcon *icon,
278                                                 gboolean recalc_extents);
279 static void xfdesktop_icon_view_icon_changed(XfdesktopIcon *icon,
280                                              gpointer user_data);
281 
282 static void xfdesktop_icon_view_invalidate_icon_pixbuf(XfdesktopIconView *icon_view,
283                                                        XfdesktopIcon *icon);
284 
285 static void xfdesktop_icon_view_paint_icon(XfdesktopIconView *icon_view,
286                                            XfdesktopIcon *icon,
287                                            GdkRectangle *area,
288                                            cairo_t *cr);
289 static void xfdesktop_icon_view_repaint_icons(XfdesktopIconView *icon_view,
290                                               GdkRectangle *area,
291                                               cairo_t *cr);
292 
293 static void xfdesktop_setup_grids(XfdesktopIconView *icon_view);
294 static gboolean xfdesktop_grid_get_next_free_position(XfdesktopIconView *icon_view,
295                                                       gint16 *row,
296                                                       gint16 *col);
297 static inline gboolean xfdesktop_grid_is_free_position(XfdesktopIconView *icon_view,
298                                                        gint16 row,
299                                                        gint16 col);
300 static inline void xfdesktop_grid_set_position_free(XfdesktopIconView *icon_view,
301                                                     gint16 row,
302                                                     gint16 col);
303 static inline gboolean xfdesktop_grid_unset_position_free_raw(XfdesktopIconView *icon_view,
304                                                               gint16 row,
305                                                               gint16 col,
306                                                               gpointer data);
307 static inline gboolean xfdesktop_grid_unset_position_free(XfdesktopIconView *icon_view,
308                                                           XfdesktopIcon *icon);
309 static inline XfdesktopIcon *xfdesktop_icon_view_icon_in_cell_raw(XfdesktopIconView *icon_view,
310                                                                   gint idx);
311 static inline XfdesktopIcon *xfdesktop_icon_view_icon_in_cell(XfdesktopIconView *icon_view,
312                                                               gint16 row,
313                                                               gint16 col);
314 static gint xfdesktop_check_icon_clicked(gconstpointer data,
315                                          gconstpointer user_data);
316 static void xfdesktop_list_foreach_invalidate(gpointer data,
317                                               gpointer user_data);
318 
319 static inline void xfdesktop_xy_to_rowcol(XfdesktopIconView *icon_view,
320                                           gint x,
321                                           gint y,
322                                           gint16 *row,
323                                           gint16 *col);
324 static gboolean xfdesktop_grid_resize_timeout(gpointer user_data);
325 static void xfdesktop_monitors_changed_cb(GdkScreen *gscreen,
326                                           gpointer user_data);
327 static void xfdesktop_screen_size_changed_cb(GdkScreen *gscreen,
328                                             gpointer user_data);
329 static GdkFilterReturn xfdesktop_rootwin_watch_workarea(GdkXEvent *gxevent,
330                                                         GdkEvent *event,
331                                                         gpointer user_data);
332 static void xfdesktop_move_all_icons_to_pending_icons_list(XfdesktopIconView *icon_view);
333 static void xfdesktop_move_all_pending_icons_to_desktop(XfdesktopIconView* icon_view);
334 static void xfdesktop_grid_do_resize(XfdesktopIconView *icon_view);
335 static inline gboolean xfdesktop_rectangle_contains_point(GdkRectangle *rect,
336                                                           gint x,
337                                                           gint y);
338 static void xfdesktop_icon_view_modify_font_size(XfdesktopIconView *icon_view,
339                                                  gdouble size);
340 static void xfdesktop_icon_view_add_item_internal(XfdesktopIconView *icon_view,
341                                                   XfdesktopIcon *icon);
342 static gboolean xfdesktop_icon_view_icon_find_position(XfdesktopIconView *icon_view,
343                                                        XfdesktopIcon *icon);
344 static gboolean xfdesktop_icon_view_shift_area_to_cell(XfdesktopIconView *icon_view,
345                                                        XfdesktopIcon *icon,
346                                                        GdkRectangle *text_area);
347 static gint xfdesktop_icon_view_get_tooltip_size(XfdesktopIconView *icon_view);
348 static gboolean xfdesktop_icon_view_show_tooltip(GtkWidget *widget,
349                                                  gint x,
350                                                  gint y,
351                                                  gboolean keyboard_tooltip,
352                                                  GtkTooltip *tooltip,
353                                                  gpointer user_data);
354 
355 static gboolean xfdesktop_icon_view_is_icon_selected(XfdesktopIconView *icon_view,
356                                                      XfdesktopIcon *icon);
357 static void xfdesktop_icon_view_real_select_all(XfdesktopIconView *icon_view);
358 static void xfdesktop_icon_view_real_unselect_all(XfdesktopIconView *icon_view);
359 static void xfdesktop_icon_view_real_select_cursor_item(XfdesktopIconView *icon_view);
360 static void xfdesktop_icon_view_real_toggle_cursor_item(XfdesktopIconView *icon_view);
361 static gboolean xfdesktop_icon_view_real_activate_selected_items(XfdesktopIconView *icon_view);
362 static gboolean xfdesktop_icon_view_real_move_cursor(XfdesktopIconView *icon_view,
363                                                      GtkMovementStep step,
364                                                      gint count);
365 
366 static void xfdesktop_icon_view_move_cursor_left_right(XfdesktopIconView *icon_view,
367                                                        gint count,
368                                                        GdkModifierType modmask);
369 static void xfdesktop_icon_view_select_between(XfdesktopIconView *icon_view,
370                                                XfdesktopIcon *start_icon,
371                                                XfdesktopIcon *end_icon);
372 
373 enum
374 {
375     TARGET_XFDESKTOP_ICON = 9999,
376 };
377 
378 enum
379 {
380     PROP_0 = 0,
381     PROP_SINGLE_CLICK,
382     PROP_SHOW_TOOLTIPS,
383     PROP_TOOLTIP_SIZE,
384     PROP_GRAVITY,
385 };
386 
387 
388 static const GtkTargetEntry icon_view_targets[] = {
389     { "XFDESKTOP_ICON", GTK_TARGET_SAME_APP, TARGET_XFDESKTOP_ICON }
390 };
391 static const gint icon_view_n_targets = 1;
392 
393 static guint __signals[SIG_N_SIGNALS] = { 0, };
394 
395 
G_DEFINE_TYPE_WITH_PRIVATE(XfdesktopIconView,xfdesktop_icon_view,GTK_TYPE_WIDGET)396 G_DEFINE_TYPE_WITH_PRIVATE(XfdesktopIconView, xfdesktop_icon_view, GTK_TYPE_WIDGET)
397 
398 
399 static void
400 xfdesktop_icon_view_class_init(XfdesktopIconViewClass *klass)
401 {
402     GObjectClass *gobject_class = (GObjectClass *)klass;
403     GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
404     GtkBindingSet *binding_set;
405 
406     binding_set = gtk_binding_set_by_class(klass);
407 
408     gobject_class->finalize = xfdesktop_icon_view_finalize;
409     gobject_class->set_property = xfce_icon_view_set_property;
410     gobject_class->get_property = xfce_icon_view_get_property;
411 
412     widget_class->style_updated = xfdesktop_icon_view_style_updated;
413     widget_class->realize = xfdesktop_icon_view_realize;
414     widget_class->unrealize = xfdesktop_icon_view_unrealize;
415     widget_class->draw = xfdesktop_icon_view_draw;
416     widget_class->drag_begin = xfdesktop_icon_view_drag_begin;
417     widget_class->drag_motion = xfdesktop_icon_view_drag_motion;
418     widget_class->drag_leave = xfdesktop_icon_view_drag_leave;
419     widget_class->drag_drop = xfdesktop_icon_view_drag_drop;
420     widget_class->drag_data_get = xfdesktop_icon_view_drag_data_get;
421     widget_class->drag_data_received = xfdesktop_icon_view_drag_data_received;
422 
423     klass->select_all = xfdesktop_icon_view_real_select_all;
424     klass->unselect_all = xfdesktop_icon_view_real_unselect_all;
425     klass->select_cursor_item = xfdesktop_icon_view_real_select_cursor_item;
426     klass->toggle_cursor_item = xfdesktop_icon_view_real_toggle_cursor_item;
427     klass->activate_selected_items = xfdesktop_icon_view_real_activate_selected_items;
428     klass->move_cursor = xfdesktop_icon_view_real_move_cursor;
429 
430     __signals[SIG_ICON_SELECTION_CHANGED] = g_signal_new("icon-selection-changed",
431                                                          XFDESKTOP_TYPE_ICON_VIEW,
432                                                          G_SIGNAL_RUN_LAST,
433                                                          G_STRUCT_OFFSET(XfdesktopIconViewClass,
434                                                                          icon_selection_changed),
435                                                          NULL, NULL,
436                                                          g_cclosure_marshal_VOID__VOID,
437                                                          G_TYPE_NONE, 0);
438 
439     __signals[SIG_ICON_ACTIVATED] = g_signal_new("icon-activated",
440                                                  XFDESKTOP_TYPE_ICON_VIEW,
441                                                  G_SIGNAL_RUN_LAST,
442                                                  G_STRUCT_OFFSET(XfdesktopIconViewClass,
443                                                                  icon_activated),
444                                                  NULL, NULL,
445                                                  g_cclosure_marshal_VOID__VOID,
446                                                  G_TYPE_NONE, 0);
447 
448     __signals[SIG_SELECT_ALL] = g_signal_new(I_("select-all"),
449                                              XFDESKTOP_TYPE_ICON_VIEW,
450                                              G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
451                                              G_STRUCT_OFFSET(XfdesktopIconViewClass,
452                                                              select_all),
453                                              NULL, NULL,
454                                              g_cclosure_marshal_VOID__VOID,
455                                              G_TYPE_NONE, 0);
456 
457     __signals[SIG_UNSELECT_ALL] = g_signal_new(I_("unselect-all"),
458                                                XFDESKTOP_TYPE_ICON_VIEW,
459                                                G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
460                                                G_STRUCT_OFFSET(XfdesktopIconViewClass,
461                                                                unselect_all),
462                                                NULL, NULL,
463                                                g_cclosure_marshal_VOID__VOID,
464                                                G_TYPE_NONE, 0);
465 
466     __signals[SIG_SELECT_CURSOR_ITEM] = g_signal_new(I_("select-cursor-item"),
467                                                      XFDESKTOP_TYPE_ICON_VIEW,
468                                                      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
469                                                      G_STRUCT_OFFSET(XfdesktopIconViewClass,
470                                                                      select_cursor_item),
471                                                      NULL, NULL,
472                                                      g_cclosure_marshal_VOID__VOID,
473                                                      G_TYPE_NONE, 0);
474 
475     __signals[SIG_TOGGLE_CURSOR_ITEM] = g_signal_new(I_("toggle-cursor-item"),
476                                                      XFDESKTOP_TYPE_ICON_VIEW,
477                                                      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
478                                                      G_STRUCT_OFFSET(XfdesktopIconViewClass,
479                                                                      toggle_cursor_item),
480                                                      NULL, NULL,
481                                                      g_cclosure_marshal_VOID__VOID,
482                                                      G_TYPE_NONE, 0);
483 
484     __signals[SIG_ACTIVATE_SELECTED_ITEMS] = g_signal_new(I_("activate-selected-items"),
485                                                        XFDESKTOP_TYPE_ICON_VIEW,
486                                                        G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
487                                                        G_STRUCT_OFFSET(XfdesktopIconViewClass,
488                                                                        activate_selected_items),
489                                                        NULL, NULL,
490                                                        xfdesktop_marshal_BOOLEAN__VOID,
491                                                        G_TYPE_BOOLEAN, 0);
492 
493     __signals[SIG_MOVE_CURSOR] = g_signal_new(I_("move-cursor"),
494                                               XFDESKTOP_TYPE_ICON_VIEW,
495                                               G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
496                                               G_STRUCT_OFFSET(XfdesktopIconViewClass,
497                                                               move_cursor),
498                                               NULL, NULL,
499                                               xfdesktop_marshal_BOOLEAN__ENUM_INT,
500                                               G_TYPE_BOOLEAN, 2,
501                                               GTK_TYPE_MOVEMENT_STEP,
502                                               G_TYPE_INT);
503 
504     __signals[SIG_RESIZE_EVENT] = g_signal_new(I_("resize-event"),
505                                                XFDESKTOP_TYPE_ICON_VIEW,
506                                                G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
507                                                G_STRUCT_OFFSET(XfdesktopIconViewClass,
508                                                                resize_event),
509                                                NULL, NULL,
510                                                g_cclosure_marshal_VOID__VOID,
511                                                G_TYPE_NONE, 0);
512 
513 
514     gtk_widget_class_install_style_property(widget_class,
515                                             g_param_spec_int("cell-spacing",
516                                                              "Cell spacing",
517                                                              "Spacing between desktop icon cells",
518                                                              0, 255, 2,
519                                                              G_PARAM_READABLE));
520 
521     gtk_widget_class_install_style_property(widget_class,
522                                             g_param_spec_int("cell-padding",
523                                                              "Cell padding",
524                                                              "Padding in desktop icon cell",
525                                                              0, 255, 6,
526                                                              G_PARAM_READABLE));
527 
528     gtk_widget_class_install_style_property(widget_class,
529                                             g_param_spec_double("cell-text-width-proportion",
530                                                                 "Cell text width proportion",
531                                                                 "Width of text in desktop icon cell, "
532                                                                 "calculated as multiplier of the icon size",
533                                                                 1.0, 10.0, 1.9,
534                                                                 G_PARAM_READABLE));
535     gtk_widget_class_install_style_property(widget_class,
536                                             g_param_spec_boolean("ellipsize-icon-labels",
537                                                                  "Ellipsize Icon Labels",
538                                                                  "Ellipzize labels of unselected icons on desktop",
539                                                                  TRUE,
540                                                                  G_PARAM_READABLE));
541     gtk_widget_class_install_style_property(widget_class,
542                                             g_param_spec_double("label-radius",
543                                                                 "Label radius",
544                                                                 "The radius of the rounded corners of the text background",
545                                                                 0.0, 50.0, 4.0,
546                                                                 G_PARAM_READABLE));
547 
548     gtk_widget_class_install_style_property(widget_class,
549                                             g_param_spec_int("tooltip-size",
550                                                              "Tooltip Image Size",
551                                                              "The size of the tooltip image preview",
552                                                              -1, MAX_TOOLTIP_SIZE, -1,
553                                                              G_PARAM_READABLE));
554 
555 #define XFDESKTOP_PARAM_FLAGS  (G_PARAM_READWRITE \
556                                 | G_PARAM_CONSTRUCT \
557                                 | G_PARAM_STATIC_NAME \
558                                 | G_PARAM_STATIC_NICK \
559                                 | G_PARAM_STATIC_BLURB)
560 
561     g_object_class_install_property(gobject_class, PROP_SINGLE_CLICK,
562                                     g_param_spec_boolean("single-click",
563                                                          "single-click",
564                                                          "single-click",
565                                                          FALSE,
566                                                          XFDESKTOP_PARAM_FLAGS));
567 
568     g_object_class_install_property(gobject_class, PROP_GRAVITY,
569                                     g_param_spec_int("gravity",
570                                                      "gravity",
571                                                      "set gravity of icons placement",
572                                                      0, 7, 0,
573                                                      XFDESKTOP_PARAM_FLAGS));
574 
575     g_object_class_install_property(gobject_class, PROP_SHOW_TOOLTIPS,
576                                     g_param_spec_boolean("show-tooltips",
577                                                          "show tooltips",
578                                                          "show tooltips for icons on the desktop",
579                                                          TRUE,
580                                                          XFDESKTOP_PARAM_FLAGS));
581 
582     g_object_class_install_property(gobject_class, PROP_TOOLTIP_SIZE,
583                                     g_param_spec_double("tooltip-size",
584                                                         "tooltip size",
585                                                         "size of the tooltip image preview",
586                                                         -1, MAX_TOOLTIP_SIZE, -1,
587                                                         XFDESKTOP_PARAM_FLAGS));
588 
589 #undef XFDESKTOP_PARAM_FLAGS
590 
591     /* same binding entries as GtkIconView */
592     gtk_binding_entry_add_signal(binding_set, GDK_KEY_a, GDK_CONTROL_MASK,
593                                  "select-all", 0);
594     gtk_binding_entry_add_signal(binding_set, GDK_KEY_a,
595                                  GDK_CONTROL_MASK | GDK_SHIFT_MASK,
596                                  "unselect-all", 0);
597     gtk_binding_entry_add_signal(binding_set, GDK_KEY_space, GDK_CONTROL_MASK,
598                                  "toggle-cursor-item", 0);
599     gtk_binding_entry_add_signal(binding_set, GDK_KEY_KP_Space, GDK_CONTROL_MASK,
600                                  "toggle-cursor-item", 0);
601 
602     gtk_binding_entry_add_signal(binding_set, GDK_KEY_space, 0,
603                                  "activate-selected-items", 0);
604     gtk_binding_entry_add_signal(binding_set, GDK_KEY_KP_Space, 0,
605                                  "activate-selected-items", 0);
606     gtk_binding_entry_add_signal(binding_set, GDK_KEY_Return, 0,
607                                  "activate-selected-items", 0);
608     gtk_binding_entry_add_signal(binding_set, GDK_KEY_ISO_Enter, 0,
609                                  "activate-selected-items", 0);
610     gtk_binding_entry_add_signal(binding_set, GDK_KEY_KP_Enter, 0,
611                                  "activate-selected-items", 0);
612 
613     xfdesktop_icon_view_add_move_binding(binding_set, GDK_KEY_Up, 0,
614                                          GTK_MOVEMENT_DISPLAY_LINES, -1);
615     xfdesktop_icon_view_add_move_binding(binding_set, GDK_KEY_KP_Up, 0,
616                                          GTK_MOVEMENT_DISPLAY_LINES, -1);
617 
618     xfdesktop_icon_view_add_move_binding(binding_set, GDK_KEY_Down, 0,
619                                          GTK_MOVEMENT_DISPLAY_LINES, 1);
620     xfdesktop_icon_view_add_move_binding(binding_set, GDK_KEY_KP_Down, 0,
621                                          GTK_MOVEMENT_DISPLAY_LINES, 1);
622 
623     xfdesktop_icon_view_add_move_binding(binding_set, GDK_KEY_p, GDK_CONTROL_MASK,
624                                          GTK_MOVEMENT_DISPLAY_LINES, -1);
625 
626     xfdesktop_icon_view_add_move_binding(binding_set, GDK_KEY_n, GDK_CONTROL_MASK,
627                                          GTK_MOVEMENT_DISPLAY_LINES, 1);
628 
629     xfdesktop_icon_view_add_move_binding(binding_set, GDK_KEY_Home, 0,
630                                          GTK_MOVEMENT_BUFFER_ENDS, -1);
631     xfdesktop_icon_view_add_move_binding(binding_set, GDK_KEY_KP_Home, 0,
632                                          GTK_MOVEMENT_BUFFER_ENDS, -1);
633 
634     xfdesktop_icon_view_add_move_binding(binding_set, GDK_KEY_End, 0,
635                                          GTK_MOVEMENT_BUFFER_ENDS, 1);
636     xfdesktop_icon_view_add_move_binding(binding_set, GDK_KEY_KP_End, 0,
637                                          GTK_MOVEMENT_BUFFER_ENDS, 1);
638 
639     xfdesktop_icon_view_add_move_binding(binding_set, GDK_KEY_Right, 0,
640                                          GTK_MOVEMENT_VISUAL_POSITIONS, 1);
641     xfdesktop_icon_view_add_move_binding(binding_set, GDK_KEY_Left, 0,
642                                          GTK_MOVEMENT_VISUAL_POSITIONS, -1);
643 
644     xfdesktop_icon_view_add_move_binding(binding_set, GDK_KEY_KP_Right, 0,
645                                          GTK_MOVEMENT_VISUAL_POSITIONS, 1);
646     xfdesktop_icon_view_add_move_binding(binding_set, GDK_KEY_KP_Left, 0,
647                                          GTK_MOVEMENT_VISUAL_POSITIONS, -1);
648 
649     gtk_widget_class_set_css_name (widget_class, "XfdesktopIconView");
650 }
651 
652 static void
xfdesktop_icon_view_init(XfdesktopIconView * icon_view)653 xfdesktop_icon_view_init(XfdesktopIconView *icon_view)
654 {
655     GtkStyleContext *context;
656 
657     icon_view->priv = xfdesktop_icon_view_get_instance_private(icon_view);
658 
659     icon_view->priv->icon_size = DEFAULT_ICON_SIZE;
660     icon_view->priv->font_size = DEFAULT_FONT_SIZE;
661 
662     icon_view->priv->allow_rubber_banding = TRUE;
663 
664     icon_view->priv->native_targets = gtk_target_list_new(icon_view_targets,
665                                                           icon_view_n_targets);
666 
667     icon_view->priv->source_targets = gtk_target_list_new(icon_view_targets,
668                                                           icon_view_n_targets);
669     gtk_drag_source_set(GTK_WIDGET(icon_view), 0, NULL, 0, GDK_ACTION_MOVE);
670 
671     icon_view->priv->dest_targets = gtk_target_list_new(icon_view_targets,
672                                                         icon_view_n_targets);
673     gtk_drag_dest_set(GTK_WIDGET(icon_view), 0, NULL, 0, GDK_ACTION_MOVE);
674 
675     g_object_set(G_OBJECT(icon_view), "has-tooltip", TRUE, NULL);
676     g_signal_connect(G_OBJECT(icon_view), "query-tooltip",
677                      G_CALLBACK(xfdesktop_icon_view_show_tooltip), NULL);
678 
679     gtk_widget_set_has_window(GTK_WIDGET(icon_view), FALSE);
680     gtk_widget_set_can_focus(GTK_WIDGET(icon_view), FALSE);
681 
682     context = gtk_widget_get_style_context(GTK_WIDGET(icon_view));
683     gtk_style_context_add_class(context, GTK_STYLE_CLASS_VIEW);
684 }
685 
686 static void
xfdesktop_icon_view_finalize(GObject * obj)687 xfdesktop_icon_view_finalize(GObject *obj)
688 {
689     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(obj);
690 
691     if(icon_view->priv->manager) {
692         xfdesktop_icon_view_manager_fini(icon_view->priv->manager);
693         g_object_unref(G_OBJECT(icon_view->priv->manager));
694     }
695 
696     gtk_target_list_unref(icon_view->priv->native_targets);
697     gtk_target_list_unref(icon_view->priv->source_targets);
698     gtk_target_list_unref(icon_view->priv->dest_targets);
699 
700     g_list_foreach(icon_view->priv->pending_icons, (GFunc)g_object_unref, NULL);
701     g_list_free(icon_view->priv->pending_icons);
702     /* icon_view->priv->icons should be cleared in _unrealize() */
703 
704     if (icon_view->priv->channel)
705         icon_view->priv->channel = NULL;
706 
707     G_OBJECT_CLASS(xfdesktop_icon_view_parent_class)->finalize(obj);
708 }
709 
710 static void
xfce_icon_view_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)711 xfce_icon_view_set_property(GObject *object,
712                             guint property_id,
713                             const GValue *value,
714                             GParamSpec *pspec)
715 {
716     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(object);
717 
718     switch(property_id) {
719         case PROP_SINGLE_CLICK:
720             icon_view->priv->single_click = g_value_get_boolean (value);
721             break;
722 
723         case PROP_SHOW_TOOLTIPS:
724             icon_view->priv->show_tooltips = g_value_get_boolean(value);
725             break;
726 
727         case PROP_TOOLTIP_SIZE:
728             icon_view->priv->tooltip_size_from_xfconf = g_value_get_double(value);
729             break;
730 
731         case PROP_GRAVITY:
732             icon_view->priv->gravity = g_value_get_int(value);
733             break;
734 
735         default:
736             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
737             break;
738     }
739 }
740 
741 static void
xfce_icon_view_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)742 xfce_icon_view_get_property(GObject *object,
743                            guint property_id,
744                            GValue *value,
745                            GParamSpec *pspec)
746 {
747     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(object);
748 
749     switch(property_id) {
750         case PROP_SINGLE_CLICK:
751             g_value_set_boolean(value, icon_view->priv->single_click);
752             break;
753 
754         case PROP_GRAVITY:
755             g_value_set_int(value, icon_view->priv->gravity);
756             break;
757 
758         case PROP_SHOW_TOOLTIPS:
759             g_value_set_boolean(value, icon_view->priv->show_tooltips);
760             break;
761 
762         case PROP_TOOLTIP_SIZE:
763             g_value_set_double(value, icon_view->priv->tooltip_size_from_xfconf);
764             break;
765 
766         default:
767             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
768             break;
769     }
770 }
771 
772 static void
xfdesktop_icon_view_add_move_binding(GtkBindingSet * binding_set,guint keyval,guint modmask,GtkMovementStep step,gint count)773 xfdesktop_icon_view_add_move_binding(GtkBindingSet *binding_set,
774                                      guint keyval,
775                                      guint modmask,
776                                      GtkMovementStep step,
777                                      gint count)
778 {
779     gtk_binding_entry_add_signal(binding_set, keyval, modmask,
780                                  I_("move-cursor"), 2,
781                                  G_TYPE_ENUM, step,
782                                  G_TYPE_INT, count);
783 
784     gtk_binding_entry_add_signal(binding_set, keyval, GDK_SHIFT_MASK,
785                                  I_("move-cursor"), 2,
786                                  G_TYPE_ENUM, step,
787                                  G_TYPE_INT, count);
788 
789     if(modmask & GDK_CONTROL_MASK)
790         return;
791 
792     gtk_binding_entry_add_signal(binding_set, keyval,
793                                  GDK_CONTROL_MASK | GDK_SHIFT_MASK,
794                                  I_("move-cursor"), 2,
795                                  G_TYPE_ENUM, step,
796                                  G_TYPE_INT, count);
797 
798     gtk_binding_entry_add_signal(binding_set, keyval, GDK_CONTROL_MASK,
799                                  I_("move-cursor"), 2,
800                                  G_TYPE_ENUM, step,
801                                  G_TYPE_INT, count);
802 }
803 
804 static gboolean
xfdesktop_icon_view_get_single_click(XfdesktopIconView * icon_view)805 xfdesktop_icon_view_get_single_click(XfdesktopIconView *icon_view)
806 {
807     g_return_val_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view), FALSE);
808 
809     return icon_view->priv->single_click;
810 }
811 
812 static void
xfdesktop_icon_view_clear_drag_event(XfdesktopIconView * icon_view,GtkWidget * widget)813 xfdesktop_icon_view_clear_drag_event(XfdesktopIconView *icon_view, GtkWidget *widget)
814 {
815     DBG("unsetting stuff");
816     icon_view->priv->control_click = FALSE;
817     icon_view->priv->double_click = FALSE;
818     icon_view->priv->maybe_begin_drag = FALSE;
819     icon_view->priv->definitely_dragging = FALSE;
820     if(icon_view->priv->definitely_rubber_banding) {
821         /* Remove the rubber band selection box */
822         icon_view->priv->definitely_rubber_banding = FALSE;
823         gtk_widget_queue_draw_area(widget, icon_view->priv->band_rect.x,
824                                    icon_view->priv->band_rect.y,
825                                    icon_view->priv->band_rect.width,
826                                    icon_view->priv->band_rect.height);
827     }
828 }
829 
830 static gboolean
xfdesktop_icon_view_button_press(GtkWidget * widget,GdkEventButton * evt,gpointer user_data)831 xfdesktop_icon_view_button_press(GtkWidget *widget,
832                                  GdkEventButton *evt,
833                                  gpointer user_data)
834 {
835     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(user_data);
836     XfdesktopIcon *icon;
837 
838     DBG("entering");
839 
840     if(evt->type == GDK_BUTTON_PRESS) {
841         GList *icon_l;
842 
843         /* Clear drag event if ongoing */
844         if(evt->button == 2 || evt->button == 3)
845             xfdesktop_icon_view_clear_drag_event(icon_view, widget);
846 
847         /* Let xfce-desktop handle button 2 */
848         if(evt->button == 2) {
849             /* If we had the grab release it so the desktop gets the event */
850             if(gtk_widget_has_grab(widget))
851                 gtk_grab_remove(widget);
852 
853             return FALSE;
854         }
855 
856         /* Grab the focus, release on button release */
857         if(!gtk_widget_has_grab(widget))
858             gtk_grab_add(widget);
859 
860         icon_l = g_list_find_custom(icon_view->priv->icons, evt,
861                                     (GCompareFunc)xfdesktop_check_icon_clicked);
862         if(icon_l && (icon = icon_l->data)) {
863             if(xfdesktop_icon_view_is_icon_selected(icon_view, icon)) {
864                 /* clicked an already-selected icon */
865 
866                 if(evt->state & GDK_CONTROL_MASK)
867                     icon_view->priv->control_click = TRUE;
868 
869                 icon_view->priv->cursor = icon;
870             } else {
871                 /* clicked a non-selected icon */
872                 if(icon_view->priv->sel_mode != GTK_SELECTION_MULTIPLE
873                    || !(evt->state & GDK_CONTROL_MASK))
874                 {
875                     /* unselect all of the other icons if we haven't held
876                      * down the ctrl key.  we'll handle shift in the next block,
877                      * but for shift we do need to unselect everything */
878                     xfdesktop_icon_view_unselect_all(icon_view);
879 
880                     if(!(evt->state & GDK_SHIFT_MASK))
881                         icon_view->priv->first_clicked_item = NULL;
882                 }
883 
884                 icon_view->priv->cursor = icon;
885 
886                 if(!icon_view->priv->first_clicked_item)
887                     icon_view->priv->first_clicked_item = icon;
888 
889                 if(icon_view->priv->sel_mode == GTK_SELECTION_MULTIPLE
890                    && evt->state & GDK_SHIFT_MASK
891                    && icon_view->priv->first_clicked_item
892                    && icon_view->priv->first_clicked_item != icon)
893                 {
894                     xfdesktop_icon_view_select_between(icon_view,
895                                                        icon_view->priv->first_clicked_item,
896                                                        icon);
897                 } else
898                     xfdesktop_icon_view_select_item(icon_view, icon);
899             }
900 
901             if(evt->button == 1 || evt->button == 3) {
902                 /* we might be the start of a drag */
903                 DBG("setting stuff");
904                 icon_view->priv->maybe_begin_drag = TRUE;
905                 icon_view->priv->definitely_dragging = FALSE;
906                 icon_view->priv->definitely_rubber_banding = FALSE;
907                 icon_view->priv->press_start_x = evt->x;
908                 icon_view->priv->press_start_y = evt->y;
909             }
910 
911             return TRUE;
912         } else {
913             /* Button press wasn't over any icons */
914             /* unselect previously selected icons if we didn't click one */
915             if(icon_view->priv->sel_mode != GTK_SELECTION_MULTIPLE
916                || !(evt->state & GDK_CONTROL_MASK))
917             {
918                 xfdesktop_icon_view_unselect_all(icon_view);
919             }
920 
921             icon_view->priv->cursor = NULL;
922             icon_view->priv->first_clicked_item = NULL;
923 
924             if(icon_view->priv->allow_rubber_banding && evt->button == 1
925                && !(evt->state & GDK_SHIFT_MASK))
926             {
927                 icon_view->priv->maybe_begin_drag = TRUE;
928                 icon_view->priv->definitely_dragging = FALSE;
929                 icon_view->priv->press_start_x = evt->x;
930                 icon_view->priv->press_start_y = evt->y;
931             }
932 
933             /* Since we're not over any icons this won't be the start of a
934              * drag so we can pop up menu */
935             if(evt->button == 3 || (evt->button == 1 && (evt->state & GDK_SHIFT_MASK))) {
936                 xfce_desktop_popup_root_menu(XFCE_DESKTOP(widget), evt->button, evt->time);
937                 return TRUE;
938             }
939         }
940     } else if(evt->type == GDK_2BUTTON_PRESS) {
941         /* filter this event in single click mode */
942         if(xfdesktop_icon_view_get_single_click(icon_view)) {
943             icon_view->priv->double_click = TRUE;
944             xfdesktop_icon_view_unselect_all(icon_view);
945             return TRUE;
946         }
947 
948         /* be sure to cancel any pending drags that might have snuck through.
949          * this shouldn't happen, but it does sometimes (bug 3426).  */
950         icon_view->priv->maybe_begin_drag = FALSE;
951         icon_view->priv->definitely_dragging = FALSE;
952         icon_view->priv->definitely_rubber_banding = FALSE;
953 
954         if(evt->button == 1) {
955             GList *icon_l = g_list_find_custom(icon_view->priv->icons, evt,
956                                                (GCompareFunc)xfdesktop_check_icon_clicked);
957             if(icon_l && (icon = icon_l->data)) {
958                 icon_view->priv->cursor = icon;
959                 g_signal_emit(G_OBJECT(icon_view), __signals[SIG_ICON_ACTIVATED],
960                               0, NULL);
961                 xfdesktop_icon_activated(icon);
962                 xfdesktop_icon_view_unselect_all(icon_view);
963             }
964         }
965 
966         return TRUE;
967     }
968 
969     return FALSE;
970 }
971 
972 static gint
xfdesktop_icon_view_get_tooltip_size(XfdesktopIconView * icon_view)973 xfdesktop_icon_view_get_tooltip_size(XfdesktopIconView *icon_view)
974 {
975     g_return_val_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view), DEFAULT_TOOLTIP_SIZE);
976 
977     /* Check if we're showing tooltips at all */
978     if(!icon_view->priv->show_tooltips)
979         return 0;
980 
981     /* If the xfconf size is set and sane, use it */
982     if(icon_view->priv->tooltip_size_from_xfconf >= 0)
983         return icon_view->priv->tooltip_size_from_xfconf;
984 
985     /* if the style size is set and sane, use it */
986     if(icon_view->priv->tooltip_size_from_style >= 0)
987         return icon_view->priv->tooltip_size_from_style;
988 
989     /* Fall back */
990     return DEFAULT_TOOLTIP_SIZE;
991 }
992 
993 static gboolean
xfdesktop_icon_view_button_release(GtkWidget * widget,GdkEventButton * evt,gpointer user_data)994 xfdesktop_icon_view_button_release(GtkWidget *widget,
995                                    GdkEventButton *evt,
996                                    gpointer user_data)
997 {
998     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(user_data);
999     XfdesktopIcon *icon;
1000     GList *icon_l = NULL;
1001 
1002     DBG("entering btn=%d", evt->button);
1003 
1004     /* single-click */
1005     if(xfdesktop_icon_view_get_single_click(icon_view)
1006        && evt->button == 1
1007        && !(evt->state & GDK_SHIFT_MASK)
1008        && !(evt->state & GDK_CONTROL_MASK)
1009        && !icon_view->priv->definitely_dragging
1010        && !icon_view->priv->definitely_rubber_banding
1011        && !icon_view->priv->double_click) {
1012         /* Find out if we clicked on an icon */
1013         icon_l = g_list_find_custom(icon_view->priv->icons, evt,
1014                                     (GCompareFunc)xfdesktop_check_icon_clicked);
1015         if(icon_l && (icon = icon_l->data)) {
1016             /* We did, activate it */
1017             icon_view->priv->cursor = icon;
1018             g_signal_emit(G_OBJECT(icon_view), __signals[SIG_ICON_ACTIVATED],
1019                           0, NULL);
1020             xfdesktop_icon_activated(icon);
1021             xfdesktop_icon_view_unselect_all(icon_view);
1022         }
1023     }
1024 
1025     if((evt->button == 3 || (evt->button == 1 && (evt->state & GDK_SHIFT_MASK))) &&
1026        icon_view->priv->definitely_dragging == FALSE &&
1027        icon_view->priv->definitely_rubber_banding == FALSE &&
1028        icon_view->priv->maybe_begin_drag == TRUE)
1029     {
1030         /* If we're in single click mode we may already have the icon, don't
1031          * find it again. */
1032         if(icon_l == NULL) {
1033             icon_l = g_list_find_custom(icon_view->priv->icons, evt,
1034                                         (GCompareFunc)xfdesktop_check_icon_clicked);
1035         }
1036 
1037         /* If we clicked an icon then we didn't pop up the menu during the
1038          * button press in order to support right click DND, pop up the menu
1039          * now.
1040          * We pass 0 as the button because the docs say that you must use 0
1041          * for pop ups other than button press events. */
1042         if(icon_l && (icon = icon_l->data)) {
1043             xfce_desktop_popup_root_menu(XFCE_DESKTOP(widget), 0, evt->time);
1044         }
1045     }
1046 
1047     if(evt->button == 1 && evt->state & GDK_CONTROL_MASK
1048        && icon_view->priv->control_click)
1049     {
1050         icon_l = g_list_find_custom(icon_view->priv->icons, evt,
1051                                     (GCompareFunc)xfdesktop_check_icon_clicked);
1052         if(icon_l && (icon = icon_l->data)) {
1053             if(xfdesktop_icon_view_is_icon_selected(icon_view, icon)) {
1054                 /* clicked an already-selected icon */
1055 
1056                 /* unselect */
1057                 xfdesktop_icon_view_unselect_item(icon_view, icon);
1058             }
1059         }
1060     }
1061 
1062     if(evt->button == 1 || evt->button == 3 || evt->button == 0) {
1063         xfdesktop_icon_view_clear_drag_event(icon_view, widget);
1064     }
1065 
1066     gtk_grab_remove(widget);
1067 
1068     /* TRUE: stop other handlers from being invoked for the event. FALSE: propagate the event further. */
1069     /* On FALSE this method will be called twice in single-click-mode (possibly a gtk3 bug)            */
1070     return TRUE;
1071 }
1072 
1073 static gboolean
xfdesktop_icon_view_select_icon_from_list_by_key(XfdesktopIconView * icon_view,GdkEventKey * evt,GList * icon_list)1074 xfdesktop_icon_view_select_icon_from_list_by_key(XfdesktopIconView *icon_view,
1075                                                  GdkEventKey *evt,
1076                                                  GList *icon_list)
1077 {
1078     XfdesktopIcon *icon = NULL;
1079     const gchar *label;
1080     gunichar lchar, kchar;
1081     GList *l;
1082 
1083     /* Do it case-insensitive */
1084     kchar = g_unichar_tolower(gdk_keyval_to_unicode(evt->keyval));
1085     for(l = icon_list; l; l = l->next) {
1086         icon = (XfdesktopIcon *)l->data;
1087         label = xfdesktop_icon_peek_label(icon);
1088         if(label && g_utf8_validate(label, g_utf8_strlen(label, -1), NULL) == TRUE) {
1089             lchar = g_unichar_tolower(g_utf8_get_char(label));
1090             if(lchar == kchar) {
1091                 icon_view->priv->cursor = icon;
1092                 xfdesktop_icon_view_select_item(icon_view, icon);
1093                 return TRUE;
1094             }
1095         }
1096     }
1097 
1098     return FALSE;
1099 }
1100 
1101 static void
xfdesktop_icon_view_type_ahead_find_icon(XfdesktopIconView * icon_view,GdkEventKey * evt)1102 xfdesktop_icon_view_type_ahead_find_icon(XfdesktopIconView *icon_view,
1103                                          GdkEventKey *evt)
1104 {
1105     GList *icon_list_p_current_cursor;
1106     gboolean icon_selected = FALSE;
1107 
1108     xfdesktop_icon_view_unselect_all(icon_view);
1109 
1110     /* If we have a cursor, we try to select the next matching item after the cursor */
1111     if(icon_view->priv->cursor != NULL) {
1112     icon_list_p_current_cursor = g_list_find(icon_view->priv->icons, icon_view->priv->cursor);
1113     icon_selected = xfdesktop_icon_view_select_icon_from_list_by_key(icon_view, evt,
1114                                                                      g_list_next(icon_list_p_current_cursor));
1115     }
1116 
1117     /* still nothing is selected, select first icon from the beginning of the list */
1118     if(icon_selected == FALSE) {
1119         xfdesktop_icon_view_select_icon_from_list_by_key(icon_view,
1120                                                          evt,
1121                                                          icon_view->priv->icons);
1122     }
1123 }
1124 
1125 static gboolean
xfdesktop_icon_view_key_press(GtkWidget * widget,GdkEventKey * evt,gpointer user_data)1126 xfdesktop_icon_view_key_press(GtkWidget *widget,
1127                               GdkEventKey *evt,
1128                               gpointer user_data)
1129 {
1130     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(user_data);
1131     gboolean ret = FALSE;
1132 
1133     DBG("entering");
1134 
1135     /* since we're NO_WINDOW, events don't get delivered to us normally,
1136      * so we have to activate the bindings manually */
1137     ret = gtk_bindings_activate_event(G_OBJECT(icon_view), evt);
1138     if(ret == FALSE) {
1139         GdkModifierType ignore_modifiers = gtk_accelerator_get_default_mod_mask();
1140         if((evt->state & ignore_modifiers) == 0) {
1141             /* Binding not found and key press is not part of a combo.
1142              * Now inspect the pressed character. Let's try to find an
1143              * icon starting with this character and make the icon selected. */
1144             guint32 unicode = gdk_keyval_to_unicode(evt->keyval);
1145             if(unicode && g_unichar_isgraph(unicode) == TRUE)
1146                 xfdesktop_icon_view_type_ahead_find_icon(icon_view, evt);
1147         }
1148     }
1149 
1150     return ret;
1151 }
1152 
1153 static gboolean
xfdesktop_icon_view_focus_in(GtkWidget * widget,GdkEventFocus * evt,gpointer user_data)1154 xfdesktop_icon_view_focus_in(GtkWidget *widget,
1155                              GdkEventFocus *evt,
1156                              gpointer user_data)
1157 {
1158     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(user_data);
1159     GList *l;
1160 
1161     gtk_widget_grab_focus(GTK_WIDGET(icon_view));
1162     DBG("GOT FOCUS");
1163 
1164     for(l = icon_view->priv->selected_icons; l; l = l->next) {
1165         xfdesktop_icon_view_invalidate_icon(icon_view, l->data, FALSE);
1166     }
1167 
1168     return FALSE;
1169 }
1170 
1171 static gboolean
xfdesktop_icon_view_focus_out(GtkWidget * widget,GdkEventFocus * evt,gpointer user_data)1172 xfdesktop_icon_view_focus_out(GtkWidget *widget,
1173                               GdkEventFocus *evt,
1174                               gpointer user_data)
1175 {
1176     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(user_data);
1177     GList *l;
1178 
1179     DBG("LOST FOCUS");
1180 
1181     for(l = icon_view->priv->selected_icons; l; l = l->next) {
1182         xfdesktop_icon_view_invalidate_icon(icon_view, l->data, FALSE);
1183     }
1184 
1185     if(G_UNLIKELY(icon_view->priv->single_click)) {
1186         if(G_LIKELY(gtk_widget_get_window(GTK_WIDGET(icon_view->priv->parent_window)) != NULL)) {
1187             gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(icon_view->priv->parent_window)), NULL);
1188         }
1189     }
1190 
1191     return FALSE;
1192 }
1193 
1194 static gboolean
xfdesktop_icon_view_maybe_begin_drag(XfdesktopIconView * icon_view,GdkEventMotion * evt)1195 xfdesktop_icon_view_maybe_begin_drag(XfdesktopIconView *icon_view,
1196                                      GdkEventMotion *evt)
1197 {
1198     GdkDragAction actions;
1199 
1200     /* sanity check */
1201     g_return_val_if_fail(icon_view->priv->cursor, FALSE);
1202 
1203     if(!gtk_drag_check_threshold(GTK_WIDGET(icon_view),
1204                                  icon_view->priv->press_start_x,
1205                                  icon_view->priv->press_start_y,
1206                                  evt->x, evt->y))
1207     {
1208         return FALSE;
1209     }
1210 
1211     actions = GDK_ACTION_MOVE | (icon_view->priv->drag_source_set ?
1212                                  icon_view->priv->foreign_source_actions : 0);
1213 
1214     if(!(evt->state & GDK_BUTTON3_MASK)) {
1215         gtk_drag_begin_with_coordinates(GTK_WIDGET(icon_view),
1216                                         icon_view->priv->source_targets,
1217                                         actions,
1218                                         1,
1219                                         (GdkEvent *)evt,
1220                                         -1,
1221                                         -1);
1222     } else {
1223         gtk_drag_begin_with_coordinates(GTK_WIDGET(icon_view),
1224                                         icon_view->priv->source_targets,
1225                                         actions | GDK_ACTION_ASK,
1226                                         3,
1227                                         (GdkEvent *)evt,
1228                                         -1,
1229                                         -1);
1230     }
1231 
1232     DBG("DRAG BEGIN!");
1233 
1234     return TRUE;
1235 }
1236 
1237 static gboolean
xfdesktop_icon_view_show_tooltip(GtkWidget * widget,gint x,gint y,gboolean keyboard_tooltip,GtkTooltip * tooltip,gpointer user_data)1238 xfdesktop_icon_view_show_tooltip(GtkWidget *widget,
1239                                  gint x,
1240                                  gint y,
1241                                  gboolean keyboard_tooltip,
1242                                  GtkTooltip *tooltip,
1243                                  gpointer user_data)
1244 {
1245     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(widget);
1246     const gchar *tip_text;
1247     gchar *padded_tip_text = NULL;
1248     gint tooltip_size;
1249 
1250     if(!icon_view->priv->item_under_pointer
1251        || icon_view->priv->definitely_dragging)
1252     {
1253         return FALSE;
1254     }
1255 
1256     /* not showing tooltips */
1257     if(!icon_view->priv->show_tooltips)
1258         return FALSE;
1259 
1260     tooltip_size = xfdesktop_icon_view_get_tooltip_size(icon_view);
1261 
1262     tip_text = xfdesktop_icon_peek_tooltip(icon_view->priv->item_under_pointer);
1263     if(!tip_text)
1264         return FALSE;
1265 
1266     padded_tip_text = g_strdup_printf("%s\t", tip_text);
1267 
1268     if(tooltip_size > 0) {
1269         gtk_tooltip_set_icon(tooltip,
1270                 xfdesktop_icon_peek_tooltip_pixbuf(icon_view->priv->item_under_pointer,
1271                                                    tooltip_size * 1.5f,
1272                                                    tooltip_size));
1273     }
1274 
1275     gtk_tooltip_set_text(tooltip, padded_tip_text);
1276 
1277     g_free(padded_tip_text);
1278 
1279     return TRUE;
1280 }
1281 
1282 static gboolean
xfdesktop_icon_view_motion_notify(GtkWidget * widget,GdkEventMotion * evt,gpointer user_data)1283 xfdesktop_icon_view_motion_notify(GtkWidget *widget,
1284                                   GdkEventMotion *evt,
1285                                   gpointer user_data)
1286 {
1287     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(user_data);
1288     gboolean ret = FALSE;
1289 
1290     if(icon_view->priv->maybe_begin_drag
1291        && icon_view->priv->item_under_pointer
1292        && !icon_view->priv->definitely_dragging)
1293     {
1294         /* we might have the start of an icon click + drag here */
1295         icon_view->priv->definitely_dragging = xfdesktop_icon_view_maybe_begin_drag(icon_view,
1296                                                                                     evt);
1297         if(icon_view->priv->definitely_dragging) {
1298             icon_view->priv->maybe_begin_drag = FALSE;
1299             ret = TRUE;
1300         }
1301     } else if(icon_view->priv->maybe_begin_drag
1302               && ((!icon_view->priv->item_under_pointer
1303                    && !icon_view->priv->definitely_rubber_banding)
1304                   || icon_view->priv->definitely_rubber_banding))
1305     {
1306         GdkRectangle old_rect, *new_rect, intersect;
1307         cairo_region_t *region;
1308         GList *l;
1309 
1310         /* we're dragging with no icon under the cursor -> rubber band start
1311          * OR, we're already doin' the band -> update it */
1312 
1313         new_rect = &icon_view->priv->band_rect;
1314 
1315         if(!icon_view->priv->definitely_rubber_banding) {
1316             icon_view->priv->definitely_rubber_banding = TRUE;
1317             old_rect.x = icon_view->priv->press_start_x;
1318             old_rect.y = icon_view->priv->press_start_y;
1319             old_rect.width = old_rect.height = 1;
1320         } else
1321             memcpy(&old_rect, new_rect, sizeof(old_rect));
1322 
1323         new_rect->x = MIN(icon_view->priv->press_start_x, evt->x);
1324         new_rect->y = MIN(icon_view->priv->press_start_y, evt->y);
1325         new_rect->width = ABS(evt->x - icon_view->priv->press_start_x) + 1;
1326         new_rect->height = ABS(evt->y - icon_view->priv->press_start_y) + 1;
1327 
1328         region = cairo_region_create_rectangle(&old_rect);
1329         cairo_region_union_rectangle(region, new_rect);
1330 
1331         if(gdk_rectangle_intersect(&old_rect, new_rect, &intersect)
1332            && intersect.width > 2 && intersect.height > 2)
1333         {
1334             cairo_region_t *region_intersect;
1335 
1336             /* invalidate border too */
1337             intersect.x += 1;
1338             intersect.width -= 2;
1339             intersect.y += 1;
1340             intersect.height -= 2;
1341 
1342             region_intersect = cairo_region_create_rectangle(&intersect);
1343             cairo_region_subtract(region, region_intersect);
1344             cairo_region_destroy(region_intersect);
1345         }
1346 
1347         gdk_window_invalidate_region(gtk_widget_get_window(widget), region, TRUE);
1348         cairo_region_destroy(region);
1349 
1350         /* update list of selected icons */
1351 
1352         /* first pass: if the rubber band area got smaller at least in
1353          * one dimension, we can try first to just remove icons that
1354          * aren't in the band anymore */
1355         if(old_rect.width > new_rect->width
1356            || old_rect.height > new_rect->height)
1357         {
1358             l = icon_view->priv->selected_icons;
1359             while(l) {
1360                 GdkRectangle extents, dummy;
1361                 XfdesktopIcon *icon = l->data;
1362 
1363                 /* To be removed, it must intersect the old rectangle and
1364                  * not intersect the new one. This way CTRL + rubber band
1365                  * works properly (Bug 10275) */
1366                 if(xfdesktop_icon_get_extents(icon, NULL, NULL, &extents)
1367                    && gdk_rectangle_intersect(&extents, &old_rect, NULL)
1368                    && !gdk_rectangle_intersect(&extents, new_rect, &dummy))
1369                 {
1370                     /* remove the icon from the selected list */
1371                     l = l->next;
1372                     xfdesktop_icon_view_unselect_item(icon_view, icon);
1373                 } else
1374                     l = l->next;
1375             }
1376         }
1377 
1378         /* second pass: if at least one dimension got larger, unfortunately
1379          * we have to figure out what icons to add to the selected list */
1380         if(old_rect.width < new_rect->width
1381            || old_rect.height < new_rect->height)
1382         {
1383             for(l = icon_view->priv->icons; l; l = l->next) {
1384                 GdkRectangle extents, dummy;
1385                 XfdesktopIcon *icon = l->data;
1386 
1387                 if(xfdesktop_icon_get_extents(icon, NULL, NULL, &extents)
1388                    && gdk_rectangle_intersect(&extents, new_rect, &dummy)
1389                    && !xfdesktop_icon_view_is_icon_selected(icon_view, icon))
1390                 {
1391                     /* since _select_item() prepends to the list, we
1392                      * should be ok just calling this */
1393                     xfdesktop_icon_view_select_item(icon_view, icon);
1394                 }
1395             }
1396         }
1397     } else {
1398         XfdesktopIcon *icon;
1399         GdkRectangle extents;
1400 
1401         /* normal movement; highlight icons as they go under the pointer */
1402 
1403         if(icon_view->priv->item_under_pointer) {
1404             if(G_UNLIKELY(icon_view->priv->single_click)) {
1405                 GdkCursor *cursor = gdk_cursor_new_for_display(gtk_widget_get_display(widget), GDK_HAND2);
1406                 gdk_window_set_cursor(evt->window, cursor);
1407                 g_object_unref(cursor);
1408             }
1409             if(!xfdesktop_icon_get_extents(icon_view->priv->item_under_pointer,
1410                                            NULL, NULL, &extents)
1411                || !xfdesktop_rectangle_contains_point(&extents, evt->x, evt->y))
1412             {
1413                 icon = icon_view->priv->item_under_pointer;
1414                 icon_view->priv->item_under_pointer = NULL;
1415 
1416                 xfdesktop_icon_view_invalidate_icon_pixbuf(icon_view, icon);
1417             }
1418         } else {
1419             if(G_UNLIKELY(icon_view->priv->single_click)) {
1420                 gdk_window_set_cursor(evt->window, NULL);
1421             }
1422             icon = xfdesktop_icon_view_widget_coords_to_item(icon_view,
1423                                                              evt->x,
1424                                                              evt->y);
1425             if(icon && xfdesktop_icon_get_extents(icon, NULL, NULL, &extents)
1426                && xfdesktop_rectangle_contains_point(&extents, evt->x, evt->y))
1427             {
1428                 icon_view->priv->item_under_pointer = icon;
1429 
1430                 xfdesktop_icon_view_invalidate_icon_pixbuf(icon_view, icon);
1431             }
1432         }
1433     }
1434 
1435     gdk_event_request_motions(evt);
1436 
1437     return ret;
1438 }
1439 
1440 static gboolean
xfdesktop_icon_view_leave_notify(GtkWidget * widget,GdkEventCrossing * evt,gpointer user_data)1441 xfdesktop_icon_view_leave_notify(GtkWidget *widget,
1442                                  GdkEventCrossing *evt,
1443                                  gpointer user_data)
1444 {
1445     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(user_data);
1446 
1447     if(icon_view->priv->item_under_pointer) {
1448         XfdesktopIcon *icon = icon_view->priv->item_under_pointer;
1449         icon_view->priv->item_under_pointer = NULL;
1450 
1451         xfdesktop_icon_view_invalidate_icon(icon_view, icon, FALSE);
1452     }
1453 
1454     if(G_UNLIKELY(icon_view->priv->single_click)) {
1455         if(gtk_widget_get_realized(widget)) {
1456             gdk_window_set_cursor(gtk_widget_get_window(widget), NULL);
1457         }
1458     }
1459 
1460     return FALSE;
1461 }
1462 
1463 static void
xfdesktop_icon_view_drag_begin(GtkWidget * widget,GdkDragContext * context)1464 xfdesktop_icon_view_drag_begin(GtkWidget *widget,
1465                                GdkDragContext *context)
1466 {
1467     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(widget);
1468     XfdesktopIcon *icon;
1469     GdkRectangle extents;
1470 
1471     icon = icon_view->priv->cursor;
1472     g_return_if_fail(icon);
1473 
1474     if(xfdesktop_icon_get_extents(icon, NULL, NULL, &extents)) {
1475         GdkPixbuf *pix;
1476 
1477         pix = xfdesktop_icon_peek_pixbuf(icon, ICON_WIDTH, ICON_SIZE);
1478         if(pix)
1479             gtk_drag_set_icon_pixbuf(context, pix, 0, 0);
1480     }
1481 }
1482 
1483 static inline void
xfdesktop_xy_to_rowcol(XfdesktopIconView * icon_view,gint x,gint y,gint16 * row,gint16 * col)1484 xfdesktop_xy_to_rowcol(XfdesktopIconView *icon_view,
1485                        gint x,
1486                        gint y,
1487                        gint16 *row,
1488                        gint16 *col)
1489 {
1490     g_return_if_fail(row && col);
1491 
1492     *row = (y - icon_view->priv->yorigin - icon_view->priv->ymargin) / (CELL_SIZE + icon_view->priv->yspacing);
1493     *col = (x - icon_view->priv->xorigin - icon_view->priv->xmargin) / (CELL_SIZE + icon_view->priv->xspacing);
1494 }
1495 
1496 static inline void
xfdesktop_icon_view_clear_drag_highlight(XfdesktopIconView * icon_view)1497 xfdesktop_icon_view_clear_drag_highlight(XfdesktopIconView *icon_view)
1498 {
1499     XfdesktopIcon *icon;
1500 
1501     /* remove highlight from icon */
1502     if(icon_view->priv->item_under_pointer) {
1503         icon = icon_view->priv->item_under_pointer;
1504         icon_view->priv->item_under_pointer = NULL;
1505 
1506         xfdesktop_icon_view_invalidate_icon_pixbuf(icon_view, icon);
1507     }
1508 }
1509 
1510 static inline void
xfdesktop_icon_view_draw_drag_highlight(XfdesktopIconView * icon_view,guint16 row,guint16 col)1511 xfdesktop_icon_view_draw_drag_highlight(XfdesktopIconView *icon_view,
1512                                         guint16 row,
1513                                         guint16 col)
1514 {
1515     XfdesktopIcon *icon;
1516 
1517     icon = xfdesktop_icon_view_icon_in_cell(icon_view, row, col);
1518 
1519     if(!icon && icon_view->priv->item_under_pointer) {
1520         /* clear previous highlight */
1521         xfdesktop_icon_view_clear_drag_highlight(icon_view);
1522     }
1523 
1524     if(icon && icon_view->priv->item_under_pointer != icon) {
1525         if(icon_view->priv->item_under_pointer) {
1526             /* clear previous highlight */
1527             xfdesktop_icon_view_clear_drag_highlight(icon_view);
1528         }
1529 
1530         /* highlight icon */
1531         icon_view->priv->item_under_pointer = icon;
1532 
1533         xfdesktop_icon_view_invalidate_icon_pixbuf(icon_view, icon);
1534     }
1535 }
1536 
1537 static gboolean
xfdesktop_icon_view_drag_motion(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time_)1538 xfdesktop_icon_view_drag_motion(GtkWidget *widget,
1539                                 GdkDragContext *context,
1540                                 gint x,
1541                                 gint y,
1542                                 guint time_)
1543 {
1544     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(widget);
1545     GdkAtom target;
1546     gint16 hover_row = 0, hover_col = 0;
1547     XfdesktopIcon *icon_on_dest = NULL;
1548     GdkDragAction our_action = 0;
1549     gboolean is_local_drag;
1550 
1551     target = gtk_drag_dest_find_target(widget, context,
1552                                        icon_view->priv->native_targets);
1553     if(target == GDK_NONE) {
1554         target = gtk_drag_dest_find_target(widget, context,
1555                                            icon_view->priv->dest_targets);
1556         if(target == GDK_NONE)
1557             return FALSE;
1558     }
1559 
1560     /* can we drop here? */
1561     xfdesktop_xy_to_rowcol(icon_view, x, y, &hover_row, &hover_col);
1562     if(hover_row >= icon_view->priv->nrows || hover_col >= icon_view->priv->ncols)
1563         return FALSE;
1564     icon_on_dest = xfdesktop_icon_view_icon_in_cell(icon_view, hover_row,
1565                                                     hover_col);
1566     if(icon_on_dest) {
1567         if(!xfdesktop_icon_get_allowed_drop_actions(icon_on_dest, NULL))
1568             return FALSE;
1569     } else if(!xfdesktop_grid_is_free_position(icon_view, hover_row, hover_col))
1570         return FALSE;
1571 
1572     is_local_drag = (target == gdk_atom_intern("XFDESKTOP_ICON", FALSE));
1573 
1574     /* at this point there are four cases to account for:
1575      * 1.  local drag, empty space -> MOVE
1576      * 2.  local drag, icon is there -> depends on icon_on_dest
1577      * 3.  foreign drag, empty space -> depends on the source
1578      * 4.  foreign drag, icon is there -> depends on source and icon_on_dest
1579      */
1580 
1581     if(!icon_on_dest) {
1582         if(is_local_drag)  /* # 1 */
1583             our_action = GDK_ACTION_MOVE;
1584         else  /* #3 */
1585             our_action = gdk_drag_context_get_suggested_action(context);
1586     } else {
1587         /* start with all available actions (may be filtered by modifier keys) */
1588         GdkDragAction allowed_actions = gdk_drag_context_get_actions(context);
1589 
1590         if(is_local_drag) {  /* #2 */
1591             GList *l;
1592             gint16 sel_row, sel_col;
1593             gboolean action_ask = FALSE;
1594 
1595             /* check to make sure we aren't just hovering over ourself */
1596             for(l = icon_view->priv->selected_icons; l; l = l->next) {
1597                 XfdesktopIcon *sel_icon = l->data;
1598                 if(xfdesktop_icon_get_position(sel_icon, &sel_row, &sel_col)
1599                    && sel_row == hover_row && sel_col == hover_col)
1600                 {
1601                     xfdesktop_icon_view_clear_drag_highlight(icon_view);
1602                     return FALSE;
1603                 }
1604             }
1605 
1606             if(allowed_actions & GDK_ACTION_ASK)
1607                 action_ask = TRUE;
1608 
1609             allowed_actions &= xfdesktop_icon_get_allowed_drag_actions(icon_view->priv->cursor);
1610 
1611             /* for local drags, let the dest icon decide */
1612             allowed_actions &= xfdesktop_icon_get_allowed_drop_actions(icon_on_dest, &our_action);
1613 
1614             /* check if drag&drop menu should be triggered */
1615             if(action_ask) {
1616                 if(allowed_actions == (GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK)) {
1617                     allowed_actions |= GDK_ACTION_ASK;
1618                     our_action = GDK_ACTION_ASK;
1619                 }
1620             }
1621         } else {  /* #4 */
1622             allowed_actions &= xfdesktop_icon_get_allowed_drop_actions(icon_on_dest, NULL);
1623 
1624             /* for foreign drags, take the action suggested by the source */
1625             our_action = gdk_drag_context_get_suggested_action(context);
1626         }
1627 
1628         /* #2 or #4 */
1629 
1630         /* fallback actions if the suggested action is not allowed,
1631          * priority: move, copy, link */
1632         if(!(our_action & allowed_actions)) {
1633             if(allowed_actions & GDK_ACTION_MOVE)
1634                 our_action = GDK_ACTION_MOVE;
1635             else if(allowed_actions & GDK_ACTION_COPY)
1636                 our_action = GDK_ACTION_COPY;
1637             else if(allowed_actions & GDK_ACTION_LINK)
1638                 our_action = GDK_ACTION_LINK;
1639             else
1640                 our_action = 0;
1641         }
1642     }
1643 
1644     /* allow the drag dest to override the selected action based on the drag data */
1645     icon_view->priv->hover_row = hover_row;
1646     icon_view->priv->hover_col = hover_col;
1647     icon_view->priv->proposed_drop_action = our_action;
1648     icon_view->priv->dropped = FALSE;
1649     g_object_set_data(G_OBJECT(context), "--xfdesktop-icon-view-drop-icon",
1650                       icon_on_dest);
1651     gtk_drag_get_data(widget, context, target, time_);
1652 
1653     /* the actual call to gdk_drag_status() is deferred to
1654      * xfdesktop_icon_view_drag_data_received() */
1655 
1656     return TRUE;
1657 }
1658 
1659 static void
xfdesktop_icon_view_drag_leave(GtkWidget * widget,GdkDragContext * context,guint time_)1660 xfdesktop_icon_view_drag_leave(GtkWidget *widget,
1661                                GdkDragContext *context,
1662                                guint time_)
1663 {
1664     xfdesktop_icon_view_clear_drag_highlight(XFDESKTOP_ICON_VIEW(widget));
1665 }
1666 
1667 static void
xfdesktop_next_slot(XfdesktopIconView * icon_view,gint16 * col,gint16 * row,gint16 ncols,gint16 nrows)1668 xfdesktop_next_slot(XfdesktopIconView *icon_view,
1669                     gint16 *col,
1670                     gint16 *row,
1671                     gint16 ncols,
1672                     gint16 nrows)
1673 {
1674     gint scol = *col, srow = *row;
1675 
1676     if(icon_view->priv->gravity & GRAVITY_HORIZONTAL) {
1677         scol += (icon_view->priv->gravity & GRAVITY_RIGHT) ? -1 : 1;
1678         if(scol < 0) {
1679             scol = ncols - 1;
1680             srow += (icon_view->priv->gravity & GRAVITY_BOTTOM) ? -1 : 1;
1681         } else {
1682             if(scol >= ncols) {
1683                 scol = 0;
1684                 srow += (icon_view->priv->gravity & GRAVITY_BOTTOM) ? -1 : 1;
1685             }
1686         }
1687     } else {
1688         srow += (icon_view->priv->gravity & GRAVITY_BOTTOM) ? -1 : 1;
1689         if(srow < 0) {
1690             srow = nrows - 1;
1691             scol += (icon_view->priv->gravity & GRAVITY_RIGHT) ? -1 : 1;
1692         } else {
1693             if(srow >= nrows) {
1694                 srow = 0;
1695                 scol += (icon_view->priv->gravity & GRAVITY_RIGHT) ? -1 : 1;
1696             }
1697         }
1698     }
1699 
1700     *col = scol;
1701     *row = srow;
1702 }
1703 
1704 static gboolean
xfdesktop_icon_view_drag_drop(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time_)1705 xfdesktop_icon_view_drag_drop(GtkWidget *widget,
1706                               GdkDragContext *context,
1707                               gint x,
1708                               gint y,
1709                               guint time_)
1710 {
1711     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(widget);
1712     GdkAtom target;
1713     XfdesktopIcon *icon;
1714     gint16 old_row, old_col, row, col, offset_col, offset_row;
1715     GList *l;
1716     XfdesktopIcon *icon_on_dest = NULL;
1717 
1718     DBG("entering: (%d,%d)", x, y);
1719 
1720     DBG("unsetting stuff");
1721     icon_view->priv->control_click = FALSE;
1722     icon_view->priv->double_click = FALSE;
1723     icon_view->priv->maybe_begin_drag = FALSE;
1724     icon_view->priv->definitely_dragging = FALSE;
1725     icon_view->priv->dropped = TRUE;
1726 
1727     target = gtk_drag_dest_find_target(widget, context,
1728                                        icon_view->priv->native_targets);
1729     if(target == GDK_NONE) {
1730         target = gtk_drag_dest_find_target(widget, context,
1731                                            icon_view->priv->dest_targets);
1732         if(target == GDK_NONE)
1733             return FALSE;
1734     }
1735     XF_DEBUG("target=%ld (%s)", (glong)target, gdk_atom_name(target));
1736 
1737     xfdesktop_xy_to_rowcol(icon_view, x, y, &row, &col);
1738     icon_on_dest = xfdesktop_icon_view_icon_in_cell(icon_view, row, col);
1739 
1740     if(target == gdk_atom_intern("XFDESKTOP_ICON", FALSE)) {
1741         if(icon_on_dest) {
1742             GdkDragAction action;
1743             gboolean ret = FALSE;
1744 
1745             action = gdk_drag_context_get_selected_action(context);
1746 
1747 #ifdef ENABLE_FILE_ICONS
1748             if(action == GDK_ACTION_ASK) {
1749                 xfdesktop_dnd_menu(icon_view->priv->manager, icon_on_dest,
1750                                    context, &action, row, col, time_);
1751 
1752                 if(action == 0) {
1753                     gtk_drag_finish(context, FALSE, FALSE, time_);
1754                     return ret;
1755                 }
1756             }
1757 #endif
1758 
1759             for(l = icon_view->priv->selected_icons; l; l = l->next) {
1760                 if(xfdesktop_icon_do_drop_dest(icon_on_dest,
1761                                                XFDESKTOP_ICON(l->data),
1762                                                action))
1763                 {
1764                     ret = TRUE;
1765                 }
1766             }
1767 
1768             gtk_drag_finish(context, ret, FALSE, time_);
1769 
1770             return ret;
1771         }
1772 
1773         icon = icon_view->priv->cursor;
1774         g_return_val_if_fail(icon, FALSE);
1775 
1776         /* 1: Get amount of offset between the old slot and new slot
1777          *    of the icon that's being dragged.
1778          * 2: Remove all the icons that are going to be moved from
1779          *    the desktop. That's in case the icons being moved
1780          *    want to rearrange themselves there.
1781          * 3: We move all the icons using the offset. */
1782         if(xfdesktop_icon_get_position(icon, &old_row, &old_col)) {
1783             offset_col = old_col-col;
1784             offset_row = old_row-row;
1785         } else {
1786             offset_col = 0;
1787             offset_row = 0;
1788         }
1789 
1790         for(l = icon_view->priv->selected_icons; l; l = l->next) {
1791             /* clear out old position */
1792             xfdesktop_icon_view_invalidate_icon(icon_view, l->data, FALSE);
1793             if(xfdesktop_icon_get_position(l->data, &old_row, &old_col))
1794                 xfdesktop_grid_set_position_free(icon_view, old_row, old_col);
1795         }
1796 
1797         for(l = icon_view->priv->selected_icons; l; l = l->next) {
1798             /* use offset to figure out where to put the icon*/
1799             if(xfdesktop_icon_get_position(l->data, &old_row, &old_col)) {
1800                 col = (old_col-offset_col) % icon_view->priv->ncols;
1801                 row = (old_row-offset_row) % icon_view->priv->nrows;
1802                 /* wrap around the view */
1803                 while(col < 0)
1804                     col += icon_view->priv->ncols;
1805                 while(row < 0)
1806                     row += icon_view->priv->nrows;
1807             }
1808 
1809             /* Find the next available slot for an icon if offset slot is not available */
1810             while(!xfdesktop_grid_is_free_position(icon_view, row, col)) {
1811                 xfdesktop_next_slot(icon_view, &col, &row, icon_view->priv->ncols, icon_view->priv->nrows);
1812             }
1813 
1814             /* set new position */
1815             xfdesktop_icon_set_position(l->data, row, col);
1816             xfdesktop_grid_unset_position_free(icon_view, l->data);
1817 
1818             /* clear out old extents, if any */
1819             xfdesktop_icon_view_invalidate_icon(icon_view, l->data, TRUE);
1820         }
1821 
1822         XF_DEBUG("drag succeeded");
1823 
1824         gtk_drag_finish(context, TRUE, FALSE, time_);
1825     } else {
1826         g_object_set_data(G_OBJECT(context), "--xfdesktop-icon-view-drop-icon",
1827                           icon_on_dest);
1828         return xfdesktop_icon_view_manager_drag_drop(icon_view->priv->manager,
1829                                                      icon_on_dest,
1830                                                      context,
1831                                                      row, col, time_);
1832     }
1833 
1834     return TRUE;
1835 }
1836 
1837 static void
xfdesktop_icon_view_drag_data_get(GtkWidget * widget,GdkDragContext * context,GtkSelectionData * data,guint info,guint time_)1838 xfdesktop_icon_view_drag_data_get(GtkWidget *widget,
1839                                   GdkDragContext *context,
1840                                   GtkSelectionData *data,
1841                                   guint info,
1842                                   guint time_)
1843 {
1844     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(widget);
1845 
1846     DBG("entering");
1847 
1848     if(XFDESKTOP_IS_WINDOW_ICON_MANAGER(icon_view->priv->manager))
1849         return;
1850 
1851     /* Sometimes during a ctrl+drag this is NULL
1852      * but works when the file(s) are dropped */
1853     if(icon_view->priv->selected_icons == NULL)
1854         return;
1855 
1856     xfdesktop_icon_view_manager_drag_data_get(icon_view->priv->manager,
1857                                               icon_view->priv->selected_icons,
1858                                               context, data, info, time_);
1859 
1860     xfdesktop_icon_view_clear_drag_event(icon_view, widget);
1861 }
1862 
1863 static void
xfdesktop_icon_view_drag_data_received(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * data,guint info,guint time_)1864 xfdesktop_icon_view_drag_data_received(GtkWidget *widget,
1865                                        GdkDragContext *context,
1866                                        gint x,
1867                                        gint y,
1868                                        GtkSelectionData *data,
1869                                        guint info,
1870                                        guint time_)
1871 {
1872     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(widget);
1873     gint16 row, col;
1874     XfdesktopIcon *icon_on_dest;
1875 
1876     DBG("entering");
1877 
1878     icon_on_dest = g_object_get_data(G_OBJECT(context),
1879                                      "--xfdesktop-icon-view-drop-icon");
1880 
1881     if(icon_view->priv->dropped) {
1882         icon_view->priv->dropped = FALSE;
1883 
1884         xfdesktop_xy_to_rowcol(icon_view, x, y, &row, &col);
1885         if(row >= icon_view->priv->nrows || col >= icon_view->priv->ncols)
1886             return;
1887 
1888         xfdesktop_icon_view_manager_drag_data_received(icon_view->priv->manager,
1889                                                        icon_on_dest,
1890                                                        context, row, col, data,
1891                                                        info, time_);
1892     } else {
1893         /* FIXME: cannot use x and y here, for they don't seem to have any
1894          * meaningful value */
1895 
1896         GdkDragAction action = icon_view->priv->proposed_drop_action;
1897 
1898         if(!XFDESKTOP_IS_WINDOW_ICON_MANAGER(icon_view->priv->manager)) {
1899             action = xfdesktop_icon_view_manager_propose_drop_action(icon_view->priv->manager,
1900                                                                      icon_on_dest,
1901                                                                      action,
1902                                                                      context, data,
1903                                                                      info);
1904         }
1905 
1906         if(action == 0)
1907             xfdesktop_icon_view_clear_drag_highlight(icon_view);
1908         else
1909             xfdesktop_icon_view_draw_drag_highlight(icon_view,
1910                                                     icon_view->priv->hover_row,
1911                                                     icon_view->priv->hover_col);
1912 
1913         gdk_drag_status(context, action, time_);
1914     }
1915 }
1916 
1917 #ifdef ENABLE_FILE_ICONS
1918 static gint
xfdesktop_icon_view_compare_icons(gconstpointer * a,gconstpointer * b)1919 xfdesktop_icon_view_compare_icons(gconstpointer *a,
1920                                   gconstpointer *b)
1921 {
1922     XfdesktopIcon *a_icon, *b_icon;
1923     const gchar *a_str, *b_str;
1924 
1925     a_icon = XFDESKTOP_ICON(a);
1926     b_icon = XFDESKTOP_ICON(b);
1927 
1928     a_str = xfdesktop_icon_peek_label(a_icon);
1929     b_str = xfdesktop_icon_peek_label(b_icon);
1930 
1931     if(a_str == NULL)
1932         a_str = "";
1933     if(b_str == NULL)
1934         b_str = "";
1935 
1936     return g_utf8_collate(a_str, b_str);
1937 }
1938 #endif /* ENABLE_FILE_ICONS */
1939 
1940 #ifdef ENABLE_FILE_ICONS
1941 static void
xfdesktop_icon_view_append_icons(XfdesktopIconView * icon_view,GList * icon_list,gint16 * row,gint16 * col)1942 xfdesktop_icon_view_append_icons(XfdesktopIconView *icon_view,
1943                                  GList *icon_list,
1944                                  gint16 *row,
1945                                  gint16 *col)
1946 {
1947     GList *l = NULL;
1948     for(l = icon_list; l != NULL; l = g_list_next(l)) {
1949 
1950         /* Find the next available slot for an icon */
1951         do {
1952             xfdesktop_next_slot(icon_view, col, row, icon_view->priv->ncols, icon_view->priv->nrows);
1953         } while(!xfdesktop_grid_is_free_position(icon_view, *row, *col));
1954 
1955         /* set new position */
1956         xfdesktop_icon_set_position(l->data, *row, *col);
1957         xfdesktop_grid_unset_position_free(icon_view, l->data);
1958 
1959         xfdesktop_icon_view_invalidate_icon(icon_view, l->data, TRUE);
1960     }
1961 }
1962 #endif /* ENABLE_FILE_ICONS */
1963 
1964 void
xfdesktop_icon_view_sort_icons(XfdesktopIconView * icon_view)1965 xfdesktop_icon_view_sort_icons(XfdesktopIconView *icon_view)
1966 {
1967 #ifdef ENABLE_FILE_ICONS
1968     GList *l = NULL;
1969     guint i;
1970     GList *icons[4] = { NULL, NULL, NULL, NULL };
1971     gint16 row;
1972     gint16 col;
1973 
1974     for(l = icon_view->priv->icons; l; l = l->next) {
1975         /* clear out old position */
1976         xfdesktop_icon_view_invalidate_icon(icon_view, l->data, FALSE);
1977 
1978         /* Choose the correct list index */
1979         if(XFDESKTOP_IS_SPECIAL_FILE_ICON(l->data)) {
1980             i = 0;
1981         } else if(XFDESKTOP_IS_VOLUME_ICON(l->data)) {
1982             i = 1;
1983         } else if(XFDESKTOP_IS_FILE_ICON(l->data) &&
1984                   g_file_query_file_type(xfdesktop_file_icon_peek_file(l->data),
1985                                          G_FILE_QUERY_INFO_NONE,
1986                                          NULL) == G_FILE_TYPE_DIRECTORY)
1987         {
1988             i = 2;
1989         } else {
1990             i = 3;
1991         }
1992 
1993         /* Add the icon to the correct list */
1994         icons[i] = g_list_prepend(icons[i], l->data);
1995     }
1996 
1997     /* free all positions in the layout */
1998     for(col = 0; col < icon_view->priv->ncols; col++)
1999         for(row = 0; row < icon_view->priv->nrows; row++)
2000             icon_view->priv->grid_layout[col * icon_view->priv->nrows + row] = NULL;
2001 
2002     /* start at appropriate position */
2003     if(icon_view->priv->gravity & GRAVITY_HORIZONTAL) {
2004         row = -1;
2005         col = icon_view->priv->ncols - 1;
2006     } else {
2007         row = icon_view->priv->nrows - 1;
2008         col = -1;
2009     }
2010 
2011     if(icon_view->priv->gravity & GRAVITY_RIGHT)
2012         col = icon_view->priv->ncols - 1 - col;
2013     if(icon_view->priv->gravity & GRAVITY_BOTTOM)
2014         row = icon_view->priv->nrows - 1 - row;
2015 
2016     /* Append the icons: special, folder, then regular */
2017     for(i = 0; i < sizeof(icons) / sizeof(icons[0]); ++i) {
2018         l = g_list_sort(icons[i],
2019                         (GCompareFunc)xfdesktop_icon_view_compare_icons);
2020         xfdesktop_icon_view_append_icons(icon_view, l, &row, &col);
2021         g_list_free(l);
2022     }
2023 #endif
2024 }
2025 
2026 static void
xfdesktop_icon_view_icon_theme_changed(GtkIconTheme * icon_theme,gpointer user_data)2027 xfdesktop_icon_view_icon_theme_changed(GtkIconTheme *icon_theme,
2028                                        gpointer user_data)
2029 {
2030     gtk_widget_queue_draw(GTK_WIDGET(user_data));
2031 }
2032 
2033 static void
xfdesktop_icon_view_style_updated(GtkWidget * widget)2034 xfdesktop_icon_view_style_updated(GtkWidget *widget)
2035 {
2036     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(widget);
2037 
2038     DBG("entering");
2039 
2040     gtk_widget_style_get(widget,
2041                          "cell-spacing", &icon_view->priv->cell_spacing,
2042                          "cell-padding", &icon_view->priv->cell_padding,
2043                          "cell-text-width-proportion", &icon_view->priv->cell_text_width_proportion,
2044                          "ellipsize-icon-labels", &icon_view->priv->ellipsize_icon_labels,
2045                          "tooltip-size", &icon_view->priv->tooltip_size_from_style,
2046                          "label-radius", &icon_view->priv->label_radius,
2047                          NULL);
2048 
2049     XF_DEBUG("cell spacing is %d", icon_view->priv->cell_spacing);
2050     XF_DEBUG("cell padding is %d", icon_view->priv->cell_padding);
2051     XF_DEBUG("cell text width proportion is %f", icon_view->priv->cell_text_width_proportion);
2052     XF_DEBUG("ellipsize icon label is %s", icon_view->priv->ellipsize_icon_labels?"true":"false");
2053     XF_DEBUG("tooltip size is %d", icon_view->priv->tooltip_size_from_style);
2054     XF_DEBUG("label radius is %f", icon_view->priv->label_radius);
2055 
2056 
2057     GTK_WIDGET_CLASS(xfdesktop_icon_view_parent_class)->style_updated(widget);
2058 }
2059 
2060 static void
xfdesktop_icon_view_realize(GtkWidget * widget)2061 xfdesktop_icon_view_realize(GtkWidget *widget)
2062 {
2063     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(widget);
2064     PangoContext *pctx;
2065     GdkScreen *gscreen;
2066     GdkWindow *groot;
2067 
2068     icon_view->priv->parent_window = gtk_widget_get_toplevel(widget);
2069     g_return_if_fail(icon_view->priv->parent_window);
2070     gtk_widget_set_window(widget, gtk_widget_get_window(icon_view->priv->parent_window));
2071 
2072     /* we need this call here to initalize some members of icon_view->priv,
2073      * those depend on custom style properties */
2074     xfdesktop_icon_view_style_updated(widget);
2075 
2076     /* there's no reason to start up the manager before we're realized,
2077      * but we do NOT shut it down if we unrealize, since there may not be
2078      * a reason to do so.  shutdown occurs in finalize. */
2079     xfdesktop_icon_view_manager_init(icon_view->priv->manager, icon_view);
2080 
2081     gtk_widget_set_realized(widget, TRUE);
2082 
2083     gtk_window_set_accept_focus(GTK_WINDOW(icon_view->priv->parent_window),
2084                                 TRUE);
2085     gtk_window_set_focus_on_map(GTK_WINDOW(icon_view->priv->parent_window),
2086                                 FALSE);
2087 
2088     pctx = gtk_widget_get_pango_context(GTK_WIDGET(icon_view));
2089     icon_view->priv->playout = pango_layout_new(pctx);
2090 
2091     if(icon_view->priv->font_size > 0) {
2092         xfdesktop_icon_view_modify_font_size(icon_view,
2093                                              icon_view->priv->font_size);
2094     }
2095 
2096     xfdesktop_setup_grids(icon_view);
2097 
2098     /* unfortunately GTK_NO_WINDOW widgets don't receive events, with the
2099      * exception of draw events. */
2100     gtk_widget_add_events(icon_view->priv->parent_window,
2101                           GDK_POINTER_MOTION_HINT_MASK | GDK_KEY_PRESS_MASK
2102                           | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
2103                           | GDK_FOCUS_CHANGE_MASK | GDK_EXPOSURE_MASK
2104                           | GDK_LEAVE_NOTIFY_MASK);
2105     g_signal_connect(G_OBJECT(icon_view->priv->parent_window),
2106                      "motion-notify-event",
2107                      G_CALLBACK(xfdesktop_icon_view_motion_notify), icon_view);
2108     g_signal_connect(G_OBJECT(icon_view->priv->parent_window),
2109                      "leave-notify-event",
2110                      G_CALLBACK(xfdesktop_icon_view_leave_notify), icon_view);
2111     g_signal_connect(G_OBJECT(icon_view->priv->parent_window),
2112                      "key-press-event",
2113                      G_CALLBACK(xfdesktop_icon_view_key_press), icon_view);
2114     g_signal_connect(G_OBJECT(icon_view->priv->parent_window),
2115                      "button-press-event",
2116                      G_CALLBACK(xfdesktop_icon_view_button_press), icon_view);
2117     g_signal_connect(G_OBJECT(icon_view->priv->parent_window),
2118                      "button-release-event",
2119                      G_CALLBACK(xfdesktop_icon_view_button_release), icon_view);
2120     g_signal_connect(G_OBJECT(icon_view->priv->parent_window),
2121                      "focus-in-event",
2122                      G_CALLBACK(xfdesktop_icon_view_focus_in), icon_view);
2123     g_signal_connect(G_OBJECT(icon_view->priv->parent_window),
2124                      "focus-out-event",
2125                      G_CALLBACK(xfdesktop_icon_view_focus_out), icon_view);
2126 
2127     /* watch for _NET_WORKAREA changes */
2128     gscreen = gtk_widget_get_screen(widget);
2129     groot = gdk_screen_get_root_window(gscreen);
2130     gdk_window_set_events(groot, gdk_window_get_events(groot)
2131                                  | GDK_PROPERTY_CHANGE_MASK);
2132     gdk_window_add_filter(groot, xfdesktop_rootwin_watch_workarea, icon_view);
2133 
2134     g_signal_connect(G_OBJECT(gscreen), "monitors-changed",
2135                      G_CALLBACK(xfdesktop_monitors_changed_cb), icon_view);
2136     g_signal_connect(G_OBJECT(gscreen), "size-changed",
2137                      G_CALLBACK(xfdesktop_screen_size_changed_cb), icon_view);
2138 
2139     g_signal_connect_after(G_OBJECT(gtk_icon_theme_get_for_screen(gscreen)),
2140                            "changed",
2141                            G_CALLBACK(xfdesktop_icon_view_icon_theme_changed),
2142                            icon_view);
2143 
2144     xfdesktop_move_all_pending_icons_to_desktop(icon_view);
2145 }
2146 
2147 static void
xfdesktop_icon_view_unrealize(GtkWidget * widget)2148 xfdesktop_icon_view_unrealize(GtkWidget *widget)
2149 {
2150     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(widget);
2151     GdkScreen *gscreen;
2152     GdkWindow *groot;
2153 
2154     gtk_window_set_accept_focus(GTK_WINDOW(icon_view->priv->parent_window), FALSE);
2155 
2156     gscreen = gtk_widget_get_screen(widget);
2157     groot = gdk_screen_get_root_window(gscreen);
2158     gdk_window_remove_filter(groot, xfdesktop_rootwin_watch_workarea, icon_view);
2159 
2160     g_signal_handlers_disconnect_by_func(G_OBJECT(gtk_icon_theme_get_for_screen(gscreen)),
2161                      G_CALLBACK(xfdesktop_icon_view_icon_theme_changed),
2162                      icon_view);
2163 
2164     g_signal_handlers_disconnect_by_func(G_OBJECT(icon_view->priv->parent_window),
2165                      G_CALLBACK(xfdesktop_icon_view_motion_notify), icon_view);
2166     g_signal_handlers_disconnect_by_func(G_OBJECT(icon_view->priv->parent_window),
2167                      G_CALLBACK(xfdesktop_icon_view_leave_notify), icon_view);
2168     g_signal_handlers_disconnect_by_func(G_OBJECT(icon_view->priv->parent_window),
2169                      G_CALLBACK(xfdesktop_icon_view_key_press), icon_view);
2170     g_signal_handlers_disconnect_by_func(G_OBJECT(icon_view->priv->parent_window),
2171                      G_CALLBACK(xfdesktop_icon_view_button_press), icon_view);
2172     g_signal_handlers_disconnect_by_func(G_OBJECT(icon_view->priv->parent_window),
2173                      G_CALLBACK(xfdesktop_icon_view_button_release), icon_view);
2174     g_signal_handlers_disconnect_by_func(G_OBJECT(icon_view->priv->parent_window),
2175                      G_CALLBACK(xfdesktop_icon_view_focus_in), icon_view);
2176     g_signal_handlers_disconnect_by_func(G_OBJECT(icon_view->priv->parent_window),
2177                      G_CALLBACK(xfdesktop_icon_view_focus_out), icon_view);
2178 
2179     if(icon_view->priv->grid_resize_timeout) {
2180         g_source_remove(icon_view->priv->grid_resize_timeout);
2181         icon_view->priv->grid_resize_timeout = 0;
2182     }
2183 
2184     g_signal_handlers_disconnect_by_func(G_OBJECT(gscreen),
2185                                          G_CALLBACK(xfdesktop_screen_size_changed_cb),
2186                                          icon_view);
2187 
2188     /* FIXME: really clear these? */
2189     g_list_free(icon_view->priv->selected_icons);
2190     icon_view->priv->selected_icons = NULL;
2191 
2192     xfdesktop_move_all_icons_to_pending_icons_list(icon_view);
2193 
2194     g_free(icon_view->priv->grid_layout);
2195     icon_view->priv->grid_layout = NULL;
2196 
2197     g_object_unref(G_OBJECT(icon_view->priv->playout));
2198     icon_view->priv->playout = NULL;
2199 
2200     gtk_widget_set_window(widget, NULL);
2201     gtk_widget_set_realized(widget, FALSE);
2202 }
2203 
2204 static gboolean
xfdesktop_icon_view_draw(GtkWidget * widget,cairo_t * cr)2205 xfdesktop_icon_view_draw(GtkWidget *widget,
2206                          cairo_t *cr)
2207 {
2208     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(widget);
2209     cairo_rectangle_list_t *rects;
2210     cairo_rectangle_int_t temp;
2211     GdkRectangle clipbox;
2212     GtkStyleContext *context;
2213     gint i;
2214 
2215     /*DBG("entering");*/
2216 
2217     rects = cairo_copy_clip_rectangle_list(cr);
2218 
2219     if(rects->status != CAIRO_STATUS_SUCCESS) {
2220         cairo_rectangle_list_destroy (rects);
2221         return FALSE;
2222     }
2223 
2224     gdk_cairo_get_clip_rectangle(cr, &clipbox);
2225 
2226     xfdesktop_icon_view_repaint_icons(icon_view, &clipbox, cr);
2227 
2228     if(icon_view->priv->definitely_rubber_banding) {
2229         GdkRectangle intersect;
2230 
2231         context = gtk_widget_get_style_context(widget);
2232         gtk_style_context_save(context);
2233         gtk_style_context_add_class(context, GTK_STYLE_CLASS_RUBBERBAND);
2234 
2235         /* paint each rectangle in the expose region with the rubber
2236          * band color, semi-transparently */
2237         for(i = 0; i < rects->num_rectangles; ++i) {
2238             /* rects only contains cairo_rectangle_t's (with double values) which we
2239                cannot use in gdk_rectangle_intersect, so copy those values to temp.
2240                If there is a better way please update this part */
2241             temp.x = rects->rectangles[i].x;
2242             temp.y = rects->rectangles[i].y;
2243             temp.width = rects->rectangles[i].width;
2244             temp.height = rects->rectangles[i].height;
2245 
2246             if (!gdk_rectangle_intersect(&temp, &icon_view->priv->band_rect, &intersect))
2247             {
2248                 continue;
2249             }
2250 
2251             cairo_save(cr);
2252 
2253             /* paint the rubber band area */
2254             gdk_cairo_rectangle(cr, &intersect);
2255             cairo_clip_preserve(cr);
2256             gtk_render_background(context, cr,
2257                                   icon_view->priv->band_rect.x,
2258                                   icon_view->priv->band_rect.y,
2259                                   icon_view->priv->band_rect.width,
2260                                   icon_view->priv->band_rect.height);
2261             gtk_render_frame(context, cr,
2262                              icon_view->priv->band_rect.x,
2263                              icon_view->priv->band_rect.y,
2264                              icon_view->priv->band_rect.width,
2265                              icon_view->priv->band_rect.height);
2266 
2267             cairo_restore(cr);
2268         }
2269 
2270         gtk_style_context_remove_class(context, GTK_STYLE_CLASS_RUBBERBAND);
2271         gtk_style_context_restore(context);
2272     }
2273 
2274     cairo_rectangle_list_destroy(rects);
2275 
2276     return FALSE;
2277 }
2278 
2279 static void
xfdesktop_icon_view_real_select_all(XfdesktopIconView * icon_view)2280 xfdesktop_icon_view_real_select_all(XfdesktopIconView *icon_view)
2281 {
2282     DBG("entering");
2283 
2284     xfdesktop_icon_view_select_all(icon_view);
2285 }
2286 
2287 static void
xfdesktop_icon_view_real_unselect_all(XfdesktopIconView * icon_view)2288 xfdesktop_icon_view_real_unselect_all(XfdesktopIconView *icon_view)
2289 {
2290     DBG("entering");
2291 
2292     xfdesktop_icon_view_unselect_all(icon_view);
2293 }
2294 
2295 static void
xfdesktop_icon_view_real_select_cursor_item(XfdesktopIconView * icon_view)2296 xfdesktop_icon_view_real_select_cursor_item(XfdesktopIconView *icon_view)
2297 {
2298     DBG("entering");
2299 
2300     if(icon_view->priv->cursor)
2301         xfdesktop_icon_view_select_item(icon_view, icon_view->priv->cursor);
2302 }
2303 
2304 static void
xfdesktop_icon_view_real_toggle_cursor_item(XfdesktopIconView * icon_view)2305 xfdesktop_icon_view_real_toggle_cursor_item(XfdesktopIconView *icon_view)
2306 {
2307     DBG("entering");
2308 
2309     if(!icon_view->priv->cursor)
2310         return;
2311 
2312     if(g_list_find(icon_view->priv->selected_icons, icon_view->priv->cursor))
2313         xfdesktop_icon_view_unselect_item(icon_view, icon_view->priv->cursor);
2314     else
2315         xfdesktop_icon_view_select_item(icon_view, icon_view->priv->cursor);
2316 }
2317 
2318 static gboolean
xfdesktop_icon_view_real_activate_selected_items(XfdesktopIconView * icon_view)2319 xfdesktop_icon_view_real_activate_selected_items(XfdesktopIconView *icon_view)
2320 {
2321     DBG("entering");
2322 
2323     if(!icon_view->priv->selected_icons)
2324         return FALSE;
2325 
2326     g_signal_emit(G_OBJECT(icon_view), __signals[SIG_ICON_ACTIVATED], 0, NULL);
2327     g_list_foreach(icon_view->priv->selected_icons, (GFunc)xfdesktop_icon_activated, NULL);
2328 
2329     return TRUE;
2330 }
2331 
2332 static void
xfdesktop_icon_view_select_between(XfdesktopIconView * icon_view,XfdesktopIcon * start_icon,XfdesktopIcon * end_icon)2333 xfdesktop_icon_view_select_between(XfdesktopIconView *icon_view,
2334                                    XfdesktopIcon *start_icon,
2335                                    XfdesktopIcon *end_icon)
2336 {
2337     gint16 start_row, start_col, end_row, end_col;
2338     gint i, j;
2339     XfdesktopIcon *icon;
2340 
2341     if(xfdesktop_icon_get_position(start_icon, &start_row, &start_col)
2342        && xfdesktop_icon_get_position(end_icon, &end_row, &end_col))
2343     {
2344         if(start_row > end_row || (start_row == end_row && start_col > end_col)) {
2345             /* flip start and end */
2346             gint16 tmpr = start_row, tmpc = start_col;
2347 
2348             start_row = end_row;
2349             start_col = end_col;
2350             end_row = tmpr;
2351             end_col = tmpc;
2352         }
2353 
2354         for(i = start_row; i <= end_row; ++i) {
2355             for(j = (i == start_row ? start_col : 0);
2356                 (i == end_row ? j <= end_col : j < icon_view->priv->ncols);
2357                 ++j)
2358             {
2359                 icon = xfdesktop_icon_view_icon_in_cell(icon_view, i, j);
2360                 if(icon) {
2361                     xfdesktop_icon_view_select_item(icon_view, icon);
2362                 }
2363             }
2364         }
2365     }
2366 }
2367 
2368 static XfdesktopIcon *
xfdesktop_icon_view_find_first_icon(XfdesktopIconView * icon_view)2369 xfdesktop_icon_view_find_first_icon(XfdesktopIconView *icon_view)
2370 {
2371     gint i, j;
2372     XfdesktopIcon *icon = NULL;
2373 
2374     if(!icon_view->priv->icons)
2375         return NULL;
2376 
2377     for(i = 0; i < icon_view->priv->nrows && !icon; ++i) {
2378         for(j = 0; j < icon_view->priv->ncols; ++j) {
2379             icon = xfdesktop_icon_view_icon_in_cell(icon_view, i, j);
2380             if(icon)
2381                 break;
2382         }
2383     }
2384 
2385     return icon;
2386 }
2387 
2388 static XfdesktopIcon *
xfdesktop_icon_view_find_last_icon(XfdesktopIconView * icon_view)2389 xfdesktop_icon_view_find_last_icon(XfdesktopIconView *icon_view)
2390 {
2391     XfdesktopIcon *icon = NULL;
2392     gint i, j;
2393 
2394     if(!icon_view->priv->icons)
2395         return NULL;
2396 
2397     for(i = icon_view->priv->nrows - 1; i >= 0 && !icon; --i) {
2398         for(j = icon_view->priv->ncols - 1; j >= 0; --j) {
2399             icon = xfdesktop_icon_view_icon_in_cell(icon_view, i, j);
2400             if(icon)
2401                 break;
2402         }
2403     }
2404 
2405     return icon;
2406 }
2407 
2408 static void
xfdesktop_icon_view_move_cursor_left_right(XfdesktopIconView * icon_view,gint count,GdkModifierType modmask)2409 xfdesktop_icon_view_move_cursor_left_right(XfdesktopIconView *icon_view,
2410                                            gint count,
2411                                            GdkModifierType modmask)
2412 {
2413     gint16 row, col;
2414     gint i, j;
2415     guint left = (count < 0 ? -count : count);
2416     gint step = (count < 0 ? -1 : 1);
2417     XfdesktopIcon *icon = NULL;
2418 
2419     if(!icon_view->priv->cursor) {
2420         /* choose first or last item depending on left or right */
2421         if(count < 0)
2422             icon = xfdesktop_icon_view_find_last_icon(icon_view);
2423         else
2424             icon = xfdesktop_icon_view_find_first_icon(icon_view);
2425 
2426         if(icon) {
2427             if(!(modmask & GDK_CONTROL_MASK))
2428                 xfdesktop_icon_view_unselect_all(icon_view);
2429             icon_view->priv->cursor = icon;
2430             xfdesktop_icon_view_select_item(icon_view, icon);
2431         }
2432     } else {
2433         if(!xfdesktop_icon_get_position(icon_view->priv->cursor, &row, &col))
2434             return;
2435 
2436         if(!(modmask & (GDK_SHIFT_MASK|GDK_CONTROL_MASK)))
2437             xfdesktop_icon_view_unselect_all(icon_view);
2438 
2439         for(i = row;
2440             (count < 0 ? i >= 0 : i < icon_view->priv->nrows) && left > 0;
2441             i += step)
2442         {
2443             for(j = (i == row ? col + step : (count < 0) ? icon_view->priv->ncols - 1 : 0);
2444                 (count < 0 ? j >= 0 : j < icon_view->priv->ncols) && left > 0;
2445                 j += step)
2446             {
2447                 icon = xfdesktop_icon_view_icon_in_cell(icon_view, i, j);
2448                 if(icon) {
2449                     icon_view->priv->cursor = icon;
2450                     if((modmask & (GDK_SHIFT_MASK|GDK_CONTROL_MASK)) || left == 1)
2451                         xfdesktop_icon_view_select_item(icon_view, icon);
2452                     left--;
2453                 }
2454             }
2455         }
2456 
2457         if(!icon_view->priv->selected_icons) {
2458             if(count < 0)
2459                 icon = xfdesktop_icon_view_find_first_icon(icon_view);
2460             else
2461                 icon = xfdesktop_icon_view_find_last_icon(icon_view);
2462 
2463             if(icon) {
2464                 xfdesktop_icon_view_select_item(icon_view, icon);
2465                 icon_view->priv->cursor = icon;
2466             }
2467         }
2468     }
2469 }
2470 
2471 static void
xfdesktop_icon_view_move_cursor_up_down(XfdesktopIconView * icon_view,gint count,GdkModifierType modmask)2472 xfdesktop_icon_view_move_cursor_up_down(XfdesktopIconView *icon_view,
2473                                         gint count,
2474                                         GdkModifierType modmask)
2475 {
2476     gint16 row, col;
2477     gint i, j;
2478     guint left = (count < 0 ? -count : count);
2479     gint step = (count < 0 ? -1 : 1);
2480     XfdesktopIcon *icon = NULL;
2481 
2482     if(!icon_view->priv->cursor) {
2483         /* choose first or last item depending on up or down */
2484         if(count < 0)
2485             icon = xfdesktop_icon_view_find_last_icon(icon_view);
2486         else
2487             icon = xfdesktop_icon_view_find_first_icon(icon_view);
2488 
2489         if(icon) {
2490             if(!(modmask & GDK_CONTROL_MASK))
2491                 xfdesktop_icon_view_unselect_all(icon_view);
2492             icon_view->priv->cursor = icon;
2493             xfdesktop_icon_view_select_item(icon_view, icon);
2494         }
2495     } else {
2496         if(!xfdesktop_icon_get_position(icon_view->priv->cursor, &row, &col))
2497             return;
2498 
2499         if(!(modmask & (GDK_SHIFT_MASK|GDK_CONTROL_MASK)))
2500             xfdesktop_icon_view_unselect_all(icon_view);
2501 
2502         for(j = col;
2503             (count < 0 ? j >= 0 : j < icon_view->priv->ncols) && left > 0;
2504             j += step)
2505         {
2506         for(i = (j == col ? row + step : (count < 0) ? icon_view->priv->nrows - 1 : 0);
2507             (count < 0 ? i >= 0 : i < icon_view->priv->nrows) && left > 0;
2508             i += step)
2509         {
2510                 icon = xfdesktop_icon_view_icon_in_cell(icon_view, i, j);
2511                 if(icon) {
2512                     icon_view->priv->cursor = icon;
2513                     if((modmask & (GDK_SHIFT_MASK|GDK_CONTROL_MASK)) || left == 1)
2514                         xfdesktop_icon_view_select_item(icon_view, icon);
2515                     left--;
2516                 }
2517             }
2518         }
2519 
2520         if(!icon_view->priv->selected_icons) {
2521             if(count < 0)
2522                 icon = xfdesktop_icon_view_find_first_icon(icon_view);
2523             else
2524                 icon = xfdesktop_icon_view_find_last_icon(icon_view);
2525 
2526             if(icon) {
2527                 xfdesktop_icon_view_select_item(icon_view, icon);
2528                 icon_view->priv->cursor = icon;
2529             }
2530         }
2531     }
2532 }
2533 
2534 static void
xfdesktop_icon_view_move_cursor_begin_end(XfdesktopIconView * icon_view,gint count,GdkModifierType modmask)2535 xfdesktop_icon_view_move_cursor_begin_end(XfdesktopIconView *icon_view,
2536                                           gint count,
2537                                           GdkModifierType modmask)
2538 {
2539     XfdesktopIcon *icon = NULL, *old_cursor;
2540 
2541     if(count < 0)
2542         icon = xfdesktop_icon_view_find_first_icon(icon_view);
2543     else
2544         icon = xfdesktop_icon_view_find_last_icon(icon_view);
2545 
2546     if(!icon)
2547         return;
2548 
2549     old_cursor = icon_view->priv->cursor;
2550     icon_view->priv->cursor = icon;
2551 
2552     if(!old_cursor || !(modmask & (GDK_SHIFT_MASK|GDK_CONTROL_MASK))) {
2553         xfdesktop_icon_view_unselect_all(icon_view);
2554         xfdesktop_icon_view_select_item(icon_view, icon);
2555     } else if(old_cursor) {
2556         if(modmask & GDK_SHIFT_MASK) {
2557             /* select everything between the cursor and the old_cursor */
2558             xfdesktop_icon_view_select_between(icon_view, old_cursor, icon);
2559         } else if(modmask & GDK_CONTROL_MASK) {
2560             /* add the icon to the selection */
2561             xfdesktop_icon_view_select_item(icon_view, icon);
2562         }
2563 
2564     }
2565 }
2566 
2567 static gboolean
xfdesktop_icon_view_real_move_cursor(XfdesktopIconView * icon_view,GtkMovementStep step,gint count)2568 xfdesktop_icon_view_real_move_cursor(XfdesktopIconView *icon_view,
2569                                      GtkMovementStep step,
2570                                      gint count)
2571 {
2572     GdkModifierType modmask = 0;
2573 
2574     g_return_val_if_fail(step == GTK_MOVEMENT_VISUAL_POSITIONS
2575                          || step == GTK_MOVEMENT_DISPLAY_LINES
2576                          || step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
2577 
2578     if(count == 0)
2579         return FALSE;
2580 
2581     gtk_widget_grab_focus(GTK_WIDGET(icon_view));
2582     gtk_get_current_event_state(&modmask);
2583 
2584     switch(step) {
2585         case GTK_MOVEMENT_VISUAL_POSITIONS:
2586             xfdesktop_icon_view_move_cursor_left_right(icon_view, count, modmask);
2587             break;
2588 
2589         case GTK_MOVEMENT_DISPLAY_LINES:
2590             xfdesktop_icon_view_move_cursor_up_down(icon_view, count, modmask);
2591             break;
2592 
2593         case GTK_MOVEMENT_BUFFER_ENDS:
2594             xfdesktop_icon_view_move_cursor_begin_end(icon_view, count, modmask);
2595             break;
2596 
2597         default:
2598             g_assert_not_reached();
2599     }
2600 
2601     return TRUE;
2602 }
2603 
2604 
2605 static void
xfdesktop_monitors_changed_cb(GdkScreen * gscreen,gpointer user_data)2606 xfdesktop_monitors_changed_cb(GdkScreen *gscreen,
2607                               gpointer user_data)
2608 {
2609     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(user_data);
2610 
2611     /* Resize the grid to be sure we take into account monitor setup changes */
2612     xfdesktop_grid_do_resize(icon_view);
2613 }
2614 
2615 
2616 static void
xfdesktop_screen_size_changed_cb(GdkScreen * gscreen,gpointer user_data)2617 xfdesktop_screen_size_changed_cb(GdkScreen *gscreen,
2618                                  gpointer user_data)
2619 {
2620     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(user_data);
2621 
2622    /* this is kinda icky.  we want to use _NET_WORKAREA to reset the size of
2623      * the grid, but we can never be sure it'll actually change.  so let's
2624      * give it 7 seconds, and then fix it manually */
2625     if(icon_view->priv->grid_resize_timeout)
2626         g_source_remove(icon_view->priv->grid_resize_timeout);
2627     icon_view->priv->grid_resize_timeout = g_timeout_add(7000,
2628                                                          xfdesktop_grid_resize_timeout,
2629                                                          icon_view);
2630 }
2631 
2632 static void
xfdesktop_icon_view_repaint_icons(XfdesktopIconView * icon_view,GdkRectangle * area,cairo_t * cr)2633 xfdesktop_icon_view_repaint_icons(XfdesktopIconView *icon_view,
2634                                   GdkRectangle *area,
2635                                   cairo_t *cr)
2636 {
2637     GdkRectangle extents, dummy;
2638     GList *l;
2639     XfdesktopIcon *icon;
2640 
2641     /* fist paint non-selected items, then paint selected items */
2642     for(l = icon_view->priv->icons; l; l = l->next) {
2643         icon = (XfdesktopIcon *)l->data;
2644         if (xfdesktop_icon_view_is_icon_selected(icon_view, icon))
2645             continue;
2646 
2647         if(!xfdesktop_icon_get_extents(icon, NULL, NULL, &extents)
2648            || gdk_rectangle_intersect(area, &extents, &dummy))
2649         {
2650             xfdesktop_icon_view_paint_icon(icon_view, icon, area, cr);
2651         }
2652     }
2653 
2654     for(l = icon_view->priv->icons; l; l = l->next) {
2655         icon = (XfdesktopIcon *)l->data;
2656         if (!xfdesktop_icon_view_is_icon_selected(icon_view, icon))
2657             continue;
2658 
2659         if(!xfdesktop_icon_get_extents(icon, NULL, NULL, &extents)
2660            || gdk_rectangle_intersect(area, &extents, &dummy))
2661         {
2662             xfdesktop_icon_view_paint_icon(icon_view, icon, area, cr);
2663         }
2664     }
2665 }
2666 
2667 static inline gboolean
xfdesktop_rectangle_equal(GdkRectangle * rect1,GdkRectangle * rect2)2668 xfdesktop_rectangle_equal(GdkRectangle *rect1, GdkRectangle *rect2)
2669 {
2670     return (rect1->x == rect2->x && rect1->y == rect2->y
2671             && rect1->width == rect2->width && rect1->height == rect2->height);
2672 }
2673 
2674 static inline gboolean
xfdesktop_rectangle_is_bounded_by(GdkRectangle * rect,GdkRectangle * bounds)2675 xfdesktop_rectangle_is_bounded_by(GdkRectangle *rect,
2676                                   GdkRectangle *bounds)
2677 {
2678     GdkRectangle intersection;
2679 
2680     if(gdk_rectangle_intersect(rect, bounds, &intersection)) {
2681         if(xfdesktop_rectangle_equal(rect, &intersection))
2682             return TRUE;
2683     }
2684 
2685     return FALSE;
2686 }
2687 
2688 /* FIXME: add a cache for this so we don't have to compute this EVERY time */
2689 static void
xfdesktop_icon_view_setup_grids_xinerama(XfdesktopIconView * icon_view)2690 xfdesktop_icon_view_setup_grids_xinerama(XfdesktopIconView *icon_view)
2691 {
2692     GdkDisplay *display;
2693     GdkRectangle *monitor_geoms, cell_rect;
2694     gint nmonitors, i, row, col;
2695 
2696     DBG("entering");
2697 
2698     display = gtk_widget_get_display(GTK_WIDGET(icon_view));
2699     nmonitors = gdk_display_get_n_monitors(display);
2700 
2701     if(nmonitors == 1)  /* optimisation */
2702         return;
2703 
2704     monitor_geoms = g_new0(GdkRectangle, nmonitors);
2705 
2706     for(i = 0; i < nmonitors; ++i) {
2707         gdk_monitor_get_geometry(gdk_display_get_monitor(display, i), &monitor_geoms[i]);
2708     }
2709 
2710     /* cubic time; w00t! */
2711     cell_rect.width = cell_rect.height = CELL_SIZE;
2712     for(row = 0; row < icon_view->priv->nrows; ++row) {
2713         for(col = 0; col < icon_view->priv->ncols; ++col) {
2714             gboolean bounded = FALSE;
2715 
2716             cell_rect.x = icon_view->priv->xorigin + icon_view->priv->xmargin + col * CELL_SIZE + col * icon_view->priv->xspacing;
2717             cell_rect.y = icon_view->priv->yorigin + icon_view->priv->ymargin + row * CELL_SIZE + row * icon_view->priv->yspacing;
2718 
2719             for(i = 0; i < nmonitors; ++i) {
2720                 if(xfdesktop_rectangle_is_bounded_by(&cell_rect,
2721                                                      &monitor_geoms[i]))
2722                 {
2723                     bounded = TRUE;
2724                     break;
2725                 }
2726             }
2727 
2728             if(!bounded) {
2729                 xfdesktop_grid_unset_position_free_raw(icon_view, row, col,
2730                                                        (gpointer)0xdeadbeef);
2731             }
2732         }
2733     }
2734 
2735     g_free(monitor_geoms);
2736 
2737     DBG("exiting");
2738 }
2739 
2740 
2741 static void
xfdesktop_setup_grids(XfdesktopIconView * icon_view)2742 xfdesktop_setup_grids(XfdesktopIconView *icon_view)
2743 {
2744     gint xorigin = 0, yorigin = 0, xrest = 0, yrest = 0, width = 0, height = 0;
2745     gsize old_size, new_size;
2746     GdkScreen *screen;
2747     GdkDisplay *display;
2748     GdkMonitor *monitor;
2749     GdkRectangle rectangle;
2750 
2751     old_size = (guint)icon_view->priv->nrows * icon_view->priv->ncols
2752                * sizeof(XfdesktopIcon *);
2753 
2754     screen = gtk_widget_get_screen (GTK_WIDGET (icon_view));
2755     display = gdk_screen_get_display (screen);
2756     if (icon_view->priv->primary)
2757     {
2758         monitor = gdk_display_get_primary_monitor (display);
2759         gdk_monitor_get_workarea (monitor, &rectangle);
2760         width = rectangle.width;
2761         height = rectangle.height;
2762         xorigin = rectangle.x;
2763         yorigin = rectangle.y;
2764     }
2765     else if (!xfdesktop_get_workarea_single(icon_view, 0,
2766                                             &xorigin, &yorigin,
2767                                             &width, &height)) {
2768         monitor = gdk_display_get_monitor_at_window (display, gtk_widget_get_parent_window(GTK_WIDGET(icon_view)));
2769         xfdesktop_get_screen_dimensions (screen, &width, &height);
2770         xorigin = yorigin = 0;
2771     }
2772 
2773     icon_view->priv->xorigin = xorigin;
2774     icon_view->priv->yorigin = yorigin;
2775     icon_view->priv->width = width;
2776     icon_view->priv->height = height;
2777 
2778     icon_view->priv->nrows = MAX((icon_view->priv->height - MIN_MARGIN * 2) / CELL_SIZE, 0);
2779     icon_view->priv->ncols = MAX((icon_view->priv->width - MIN_MARGIN * 2) / CELL_SIZE, 0);
2780 
2781     xrest = icon_view->priv->width - icon_view->priv->ncols * CELL_SIZE;
2782     if (icon_view->priv->ncols > 1) {
2783         icon_view->priv->xspacing = (xrest - MIN_MARGIN * 2) / (icon_view->priv->ncols - 1);
2784     } else {
2785         /* Let's not try to divide by 0 */
2786         icon_view->priv->xspacing = 1;
2787     }
2788 
2789     icon_view->priv->xmargin = (xrest - (icon_view->priv->ncols - 1) * icon_view->priv->xspacing) / 2;
2790 
2791     yrest = icon_view->priv->height - icon_view->priv->nrows * CELL_SIZE;
2792     if (icon_view->priv->nrows > 1) {
2793         icon_view->priv->yspacing = (yrest - MIN_MARGIN * 2) / (icon_view->priv->nrows - 1);
2794     } else {
2795         /* Let's not try to divide by 0 */
2796         icon_view->priv->yspacing = 1;
2797     }
2798     icon_view->priv->ymargin = (yrest - (icon_view->priv->nrows - 1) * icon_view->priv->yspacing) / 2;
2799 
2800     new_size = (guint)icon_view->priv->nrows * icon_view->priv->ncols
2801                * sizeof(XfdesktopIcon *);
2802 
2803     if(old_size == new_size && icon_view->priv->grid_layout != NULL) {
2804         DBG("old_size == new_size exiting");
2805         return;
2806     }
2807 
2808     XF_DEBUG("CELL_SIZE=%0.3f, TEXT_WIDTH=%0.3f, ICON_SIZE=%u", CELL_SIZE, TEXT_WIDTH, ICON_SIZE);
2809     XF_DEBUG("grid size is %dx%d", icon_view->priv->nrows, icon_view->priv->ncols);
2810 
2811     if(icon_view->priv->grid_layout) {
2812         icon_view->priv->grid_layout = g_realloc(icon_view->priv->grid_layout,
2813                                                  new_size);
2814 
2815         if(new_size > old_size) {
2816             memset(((guint8 *)icon_view->priv->grid_layout) + old_size, 0,
2817                    new_size - old_size);
2818         }
2819     } else
2820         icon_view->priv->grid_layout = g_malloc0(new_size);
2821 
2822     XF_DEBUG("created grid_layout with %lu positions", (gulong)(new_size/sizeof(gpointer)));
2823     DUMP_GRID_LAYOUT(icon_view);
2824 
2825     xfdesktop_icon_view_setup_grids_xinerama(icon_view);
2826 }
2827 
2828 static GdkFilterReturn
xfdesktop_rootwin_watch_workarea(GdkXEvent * gxevent,GdkEvent * event,gpointer user_data)2829 xfdesktop_rootwin_watch_workarea(GdkXEvent *gxevent,
2830                                  GdkEvent *event,
2831                                  gpointer user_data)
2832 {
2833     XfdesktopIconView *icon_view = user_data;
2834     XPropertyEvent *xevt = (XPropertyEvent *)gxevent;
2835 
2836     if(xevt->type == PropertyNotify
2837        && XInternAtom(xevt->display, "_NET_WORKAREA", False) == xevt->atom)
2838     {
2839         XF_DEBUG("got _NET_WORKAREA change on rootwin!");
2840         if(icon_view->priv->grid_resize_timeout) {
2841             g_source_remove(icon_view->priv->grid_resize_timeout);
2842             icon_view->priv->grid_resize_timeout = 0;
2843         }
2844         xfdesktop_grid_do_resize(icon_view);
2845     }
2846 
2847     return GDK_FILTER_CONTINUE;
2848 }
2849 
2850 static void
xfdesktop_icon_view_invalidate_icon(XfdesktopIconView * icon_view,XfdesktopIcon * icon,gboolean recalc_extents)2851 xfdesktop_icon_view_invalidate_icon(XfdesktopIconView *icon_view,
2852                                     XfdesktopIcon *icon,
2853                                     gboolean recalc_extents)
2854 {
2855     GdkRectangle extents, box_extents;
2856     gboolean invalidated_something = FALSE;
2857 
2858     g_return_if_fail(icon);
2859 
2860     /*DBG("entering (recalc=%s)", recalc_extents?"true":"false");*/
2861 
2862     /* we always have to invalidate the old extents */
2863     if(xfdesktop_icon_get_extents(icon, NULL, NULL, &extents)) {
2864         if(gtk_widget_get_realized(GTK_WIDGET(icon_view))) {
2865             gtk_widget_queue_draw_area(GTK_WIDGET(icon_view), extents.x,
2866                                        extents.y, extents.width,
2867                                        extents.height);
2868         }
2869         invalidated_something = TRUE;
2870     } else
2871         recalc_extents = TRUE;
2872 
2873     if(recalc_extents) {
2874         GdkRectangle pixbuf_extents, text_extents, total_extents;
2875 
2876         if(!xfdesktop_icon_view_update_icon_extents(icon_view, icon,
2877                                                     &pixbuf_extents,
2878                                                     &text_extents,
2879                                                     &box_extents,
2880                                                     &total_extents))
2881         {
2882             g_warning("Trying to invalidate icon, but can't recalculate extents");
2883         } else if(gtk_widget_get_realized(GTK_WIDGET(icon_view))) {
2884             gtk_widget_queue_draw_area(GTK_WIDGET(icon_view),
2885                                        total_extents.x, total_extents.y,
2886                                        total_extents.width, total_extents.height);
2887             invalidated_something = TRUE;
2888         }
2889     }
2890 
2891     if(!invalidated_something) {
2892         DBG("Icon '%s' doesn't have extents: need to call paint some other way",
2893             xfdesktop_icon_peek_label(icon));
2894     }
2895 }
2896 
2897 static void
xfdesktop_icon_view_invalidate_icon_pixbuf(XfdesktopIconView * icon_view,XfdesktopIcon * icon)2898 xfdesktop_icon_view_invalidate_icon_pixbuf(XfdesktopIconView *icon_view,
2899                                            XfdesktopIcon *icon)
2900 {
2901     GdkPixbuf *pix;
2902 
2903     pix = xfdesktop_icon_peek_pixbuf(icon, ICON_WIDTH, ICON_SIZE);
2904     if(pix) {
2905         GdkRectangle rect = { 0, };
2906 
2907         rect.width = gdk_pixbuf_get_width(pix);
2908         rect.height = gdk_pixbuf_get_height(pix);
2909 
2910         if(!xfdesktop_icon_view_shift_area_to_cell(icon_view, icon, &rect))
2911             return;
2912 
2913         rect.x += CELL_PADDING + ((CELL_SIZE - 2 * CELL_PADDING) - rect.width) / 2;
2914         rect.y += CELL_PADDING + (ICON_SIZE - rect.height) / 2;;
2915 
2916         if(gtk_widget_get_realized(GTK_WIDGET(icon_view))) {
2917             gtk_widget_queue_draw_area(GTK_WIDGET(icon_view), rect.x, rect.y,
2918                                        rect.width, rect.height);
2919         }
2920     }
2921 }
2922 
2923 static gboolean
xfdesktop_icon_view_calculate_icon_pixbuf_area(XfdesktopIconView * icon_view,XfdesktopIcon * icon,GdkRectangle * pixbuf_area)2924 xfdesktop_icon_view_calculate_icon_pixbuf_area(XfdesktopIconView *icon_view,
2925                                                XfdesktopIcon *icon,
2926                                                GdkRectangle *pixbuf_area)
2927 {
2928     GdkPixbuf *pix;
2929 
2930     g_return_val_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view)
2931                          && XFDESKTOP_IS_ICON(icon)
2932                          && pixbuf_area, FALSE);
2933 
2934     pixbuf_area->x = 0;
2935     pixbuf_area->y = 0;
2936 
2937     pix = xfdesktop_icon_peek_pixbuf(icon, ICON_WIDTH, ICON_SIZE);
2938     if(G_LIKELY(pix)) {
2939         pixbuf_area->width = gdk_pixbuf_get_width(pix);
2940         pixbuf_area->height = gdk_pixbuf_get_height(pix);
2941     } else {
2942         /* presumably this should never happen, but... */
2943         pixbuf_area->width = ICON_SIZE;
2944         pixbuf_area->height = ICON_SIZE;
2945     }
2946 
2947     return TRUE;
2948 }
2949 
2950 static void
xfdesktop_icon_view_setup_pango_layout(XfdesktopIconView * icon_view,XfdesktopIcon * icon,PangoLayout * playout)2951 xfdesktop_icon_view_setup_pango_layout(XfdesktopIconView *icon_view,
2952                                        XfdesktopIcon *icon,
2953                                        PangoLayout *playout)
2954 {
2955 #if PANGO_VERSION_CHECK (1, 44, 0)
2956     PangoAttrList *attr_list;
2957     PangoAttribute *attr;
2958 #endif
2959     const gchar *label = xfdesktop_icon_peek_label(icon);
2960 
2961     g_return_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view)
2962                      && XFDESKTOP_IS_ICON(icon));
2963 
2964     pango_layout_set_ellipsize(playout, PANGO_ELLIPSIZE_NONE);
2965     pango_layout_set_wrap(playout, PANGO_WRAP_WORD_CHAR);
2966     pango_layout_set_width(playout, TEXT_WIDTH * PANGO_SCALE);
2967     if (icon_view->priv->center_text)
2968         pango_layout_set_alignment(playout, PANGO_ALIGN_CENTER);
2969     else
2970         pango_layout_set_alignment(playout, PANGO_ALIGN_LEFT);
2971     pango_layout_set_text(playout, label, -1);
2972 
2973     if(!xfdesktop_icon_view_is_icon_selected(icon_view, icon)
2974        && icon_view->priv->ellipsize_icon_labels) {
2975         /* constrain the text area */
2976         pango_layout_set_height(playout, TEXT_HEIGHT * PANGO_SCALE);
2977         pango_layout_set_ellipsize(playout, PANGO_ELLIPSIZE_END);
2978     }
2979 
2980 #if PANGO_VERSION_CHECK (1, 44, 0)
2981     /* Do not add hyphens on line breaks */
2982     attr_list = pango_attr_list_new ();
2983     attr = pango_attr_insert_hyphens_new (FALSE);
2984     attr->start_index = 0;
2985     attr->end_index = -1;
2986     pango_attr_list_insert (attr_list, attr);
2987     pango_layout_set_attributes (playout, attr_list);
2988     pango_attr_list_unref (attr_list);
2989 #endif
2990 }
2991 
2992 static gboolean
xfdesktop_icon_view_calculate_icon_text_area(XfdesktopIconView * icon_view,XfdesktopIcon * icon,GdkRectangle * text_area)2993 xfdesktop_icon_view_calculate_icon_text_area(XfdesktopIconView *icon_view,
2994                                              XfdesktopIcon *icon,
2995                                              GdkRectangle *text_area)
2996 {
2997     PangoLayout *playout;
2998     PangoRectangle prect;
2999 
3000     g_return_val_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view)
3001                          && XFDESKTOP_IS_ICON(icon)
3002                          && text_area, FALSE);
3003 
3004     playout = icon_view->priv->playout;
3005     xfdesktop_icon_view_setup_pango_layout(icon_view, icon, playout);
3006     pango_layout_get_pixel_extents(playout, NULL, &prect);
3007 
3008     text_area->x = prect.x;
3009     text_area->y = prect.y;
3010     text_area->width = prect.width + 2;
3011     text_area->height = prect.height + 2;
3012 
3013     return TRUE;
3014 }
3015 
3016 static gboolean
xfdesktop_icon_view_shift_area_to_cell(XfdesktopIconView * icon_view,XfdesktopIcon * icon,GdkRectangle * area)3017 xfdesktop_icon_view_shift_area_to_cell(XfdesktopIconView *icon_view,
3018                                        XfdesktopIcon *icon,
3019                                        GdkRectangle *area)
3020 {
3021     gint16 row, col;
3022 
3023     if(!xfdesktop_icon_get_position(icon, &row, &col)) {
3024         g_warning("trying to calculate without a position for icon '%s'",
3025                   xfdesktop_icon_peek_label(icon));
3026         return FALSE;
3027     }
3028 
3029     area->x = icon_view->priv->xorigin + icon_view->priv->xmargin + col * CELL_SIZE + col * icon_view->priv->xspacing;
3030     area->y = icon_view->priv->yorigin + icon_view->priv->ymargin + row * CELL_SIZE + row * icon_view->priv->yspacing;
3031 
3032     return TRUE;
3033 }
3034 
3035 static gboolean
xfdesktop_icon_view_update_icon_extents(XfdesktopIconView * icon_view,XfdesktopIcon * icon,GdkRectangle * pixbuf_extents,GdkRectangle * text_extents,GdkRectangle * box_extents,GdkRectangle * total_extents)3036 xfdesktop_icon_view_update_icon_extents(XfdesktopIconView *icon_view,
3037                                         XfdesktopIcon *icon,
3038                                         GdkRectangle *pixbuf_extents,
3039                                         GdkRectangle *text_extents,
3040                                         GdkRectangle *box_extents,
3041                                         GdkRectangle *total_extents)
3042 {
3043     gint rtl_offset;
3044 
3045     g_return_val_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view)
3046                          && XFDESKTOP_IS_ICON(icon)
3047                          && pixbuf_extents && text_extents
3048                          && box_extents && total_extents, FALSE);
3049 
3050     if(!xfdesktop_icon_view_calculate_icon_pixbuf_area(icon_view, icon,
3051                                                        pixbuf_extents)
3052        || !xfdesktop_icon_view_shift_area_to_cell(icon_view, icon,
3053                                                   pixbuf_extents))
3054     {
3055         return FALSE;
3056     }
3057     pixbuf_extents->x += CELL_PADDING + ((CELL_SIZE - CELL_PADDING * 2) - pixbuf_extents->width) / 2;
3058     pixbuf_extents->y += CELL_PADDING + (ICON_SIZE - pixbuf_extents->height) / 2;
3059 
3060     if(!xfdesktop_icon_view_calculate_icon_text_area(icon_view, icon, text_extents))
3061         return FALSE;
3062 
3063     /* text_extents->x right now includes the padding needed for rtl languages
3064      * to display properly if it's set */
3065     rtl_offset = text_extents->x;
3066 
3067     if(!xfdesktop_icon_view_shift_area_to_cell(icon_view, icon, text_extents))
3068         return FALSE;
3069 
3070     text_extents->x += (CELL_SIZE - text_extents->width) / 2 - rtl_offset;
3071     text_extents->y += ICON_SIZE + SPACING + LABEL_RADIUS + CELL_PADDING;
3072 
3073     *box_extents = *text_extents;
3074     box_extents->x -= LABEL_RADIUS - rtl_offset;
3075     box_extents->y -= LABEL_RADIUS;
3076     box_extents->width += LABEL_RADIUS * 2;
3077     box_extents->height += LABEL_RADIUS * 2;
3078 
3079     gdk_rectangle_union(pixbuf_extents, box_extents, total_extents);
3080 
3081     xfdesktop_icon_set_extents(icon, pixbuf_extents, text_extents, total_extents);
3082 
3083     return TRUE;
3084 }
3085 
3086 static void
xfdesktop_icon_view_draw_image(cairo_t * cr,GdkPixbuf * pix,GdkRectangle * rect)3087 xfdesktop_icon_view_draw_image(cairo_t *cr, GdkPixbuf *pix, GdkRectangle *rect)
3088 {
3089     cairo_save(cr);
3090 
3091     gdk_cairo_set_source_pixbuf(cr, pix, rect->x, rect->y);
3092     cairo_paint(cr);
3093 
3094     cairo_restore(cr);
3095 }
3096 
3097 static void
xfdesktop_icon_view_draw_text(GtkWidget * icon_view,cairo_t * cr,PangoLayout * playout,GdkRectangle * text_area,GdkRectangle * box_area,GtkStateFlags state)3098 xfdesktop_icon_view_draw_text(GtkWidget *icon_view, cairo_t *cr,
3099                               PangoLayout *playout, GdkRectangle *text_area,
3100                               GdkRectangle *box_area, GtkStateFlags state)
3101 {
3102     GtkStyleContext *context;
3103 
3104     cairo_save(cr);
3105 
3106     /*  Clip the cairo area */
3107     gdk_cairo_rectangle(cr, box_area);
3108     cairo_clip(cr);
3109 
3110     context = gtk_widget_get_style_context(icon_view);
3111     gtk_style_context_save(context);
3112     gtk_style_context_add_class(context, GTK_STYLE_CLASS_LABEL);
3113     gtk_style_context_set_state (context, state);
3114 
3115     gtk_render_background(context, cr, box_area->x, box_area->y, box_area->width, box_area->height);
3116     gtk_render_layout(context, cr, text_area->x, text_area->y, playout);
3117 
3118     gtk_style_context_remove_class(context, GTK_STYLE_CLASS_LABEL);
3119     gtk_style_context_restore(context);
3120     cairo_restore(cr);
3121 }
3122 
3123 static void
xfdesktop_icon_view_paint_icon(XfdesktopIconView * icon_view,XfdesktopIcon * icon,GdkRectangle * area,cairo_t * cr)3124 xfdesktop_icon_view_paint_icon(XfdesktopIconView *icon_view,
3125                                XfdesktopIcon *icon,
3126                                GdkRectangle *area,
3127                                cairo_t *cr)
3128 {
3129     GtkWidget *widget = GTK_WIDGET(icon_view);
3130     PangoLayout *playout;
3131     GdkRectangle pixbuf_extents, text_extents, box_extents, total_extents;
3132     GdkRectangle intersection;
3133     GtkStateFlags state;
3134 #ifdef G_ENABLE_DEBUG
3135     gint16 row, col;
3136 #endif
3137 
3138     DBG("entering, (%s)(area=%dx%d+%d+%d)", xfdesktop_icon_peek_label(icon),
3139           area->width, area->height, area->x, area->y);
3140 
3141     playout = icon_view->priv->playout;
3142 
3143     cr = cairo_reference(cr);
3144 
3145     if(!xfdesktop_icon_get_extents(icon, &pixbuf_extents,
3146                                    &text_extents, &total_extents))
3147     {
3148         g_warning("Can't get extents for icon '%s'", xfdesktop_icon_peek_label(icon));
3149     }
3150 
3151     if(!xfdesktop_icon_view_update_icon_extents(icon_view, icon,
3152                                                 &pixbuf_extents,
3153                                                 &text_extents,
3154                                                 &box_extents,
3155                                                 &total_extents))
3156     {
3157         g_warning("Can't update extents for icon '%s'",
3158                   xfdesktop_icon_peek_label(icon));
3159     }
3160 
3161     if(xfdesktop_icon_view_is_icon_selected(icon_view, icon)) {
3162         if(gtk_widget_has_focus(widget))
3163             state = GTK_STATE_FLAG_SELECTED;
3164         else
3165             state = GTK_STATE_FLAG_ACTIVE;
3166     } else
3167         state = GTK_STATE_FLAG_NORMAL;
3168 
3169     if(gdk_rectangle_intersect(area, &pixbuf_extents, &intersection)) {
3170         GdkPixbuf *pix = xfdesktop_icon_peek_pixbuf(icon, ICON_WIDTH, ICON_SIZE);
3171         GdkPixbuf *pix_free = NULL;
3172 
3173         if(state != GTK_STATE_FLAG_NORMAL) {
3174             GtkStyleContext *context;
3175             GdkRGBA rgba;
3176             GdkColor color;
3177 
3178             context = gtk_widget_get_style_context(widget);
3179             gtk_style_context_get_color(context, state, &rgba);
3180 
3181             color.red   = rgba.red   * G_MAXUINT16;
3182             color.green = rgba.green * G_MAXUINT16;
3183             color.blue  = rgba.blue  * G_MAXUINT16;
3184 
3185             pix_free = exo_gdk_pixbuf_colorize(pix, &color);
3186             pix = pix_free;
3187         }
3188 
3189         if(icon_view->priv->item_under_pointer == icon) {
3190             GdkPixbuf *tmp = exo_gdk_pixbuf_spotlight(pix);
3191             if(pix_free)
3192                 g_object_unref(G_OBJECT(pix_free));
3193             pix = tmp;
3194             pix_free = tmp;
3195         }
3196 
3197 #ifdef G_ENABLE_DEBUG
3198         if(!xfdesktop_icon_get_position(icon, &row, &col)) {
3199             g_warning("trying to calculate without a position for icon '%s'",
3200                       xfdesktop_icon_peek_label(icon));
3201         } else {
3202             DBG("painting pixbuf at %dx%d+%d+%d (row %d ,col %d)",
3203                   pixbuf_extents.width, pixbuf_extents.height,
3204                   pixbuf_extents.x, pixbuf_extents.y,
3205                   row, col);
3206         }
3207 #endif
3208 
3209         xfdesktop_icon_view_draw_image(cr, pix, &pixbuf_extents);
3210 
3211         if(pix_free)
3212             g_object_unref(G_OBJECT(pix_free));
3213     }
3214 
3215     /* Only redraw the text if the text area requires it. */
3216     if(gdk_rectangle_intersect(area, &box_extents, &intersection)
3217        && icon_view->priv->font_size > 0)
3218     {
3219         DBG("painting text at %dx%d+%d+%d",
3220               text_extents.width, text_extents.height,
3221               text_extents.x, text_extents.y);
3222 
3223         xfdesktop_icon_view_draw_text(GTK_WIDGET(icon_view), cr, playout,
3224                                       &text_extents, &box_extents,
3225                                       state);
3226     }
3227 
3228 
3229 #if 0 /*def DEBUG*/
3230     {
3231         GdkRectangle cell = { 0, };
3232         gint16 row, col;
3233 
3234         if(!xfdesktop_icon_get_position(icon, &row, &col))
3235             DBG("can't get icon position for '%s'", xfdesktop_icon_peek_label(icon));
3236         else
3237             DBG("for icon at (%hu,%hu) (%s)", row, col, xfdesktop_icon_peek_label(icon));
3238 
3239         cairo_set_line_width(cr, 1.0);
3240 
3241         cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 1.0);
3242         cairo_rectangle(cr, area->x, area->y, area->width, area->height);
3243         cairo_stroke(cr);
3244 
3245         cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 1.0);
3246         cairo_rectangle(cr, text_extents.x, text_extents.y,
3247                         text_extents.width, text_extents.height);
3248         cairo_stroke(cr);
3249 
3250         cairo_set_source_rgba(cr, 1.0, 1.0, 0.0, 1.0);
3251         cairo_rectangle(cr, total_extents.x, total_extents.y,
3252                         total_extents.width, total_extents.height);
3253         cairo_stroke(cr);
3254 
3255         /* this might not totally paint, but that's ok */
3256         cell.width = cell.height = CELL_SIZE;
3257         xfdesktop_icon_view_shift_area_to_cell(icon_view, icon, &cell);
3258 
3259         cairo_set_source_rgba(cr, 0.0, 0.0, 1.0, 1.0);
3260         cairo_rectangle(cr, cell.x, cell.y, cell.width, cell.height);
3261         cairo_stroke(cr);
3262 
3263 
3264         DBG("cell extents:       %dx%d+%d+%d", cell.width, cell.height, cell.x, cell.y);
3265         DBG("new pixbuf extents: %dx%d+%d+%d", pixbuf_extents.width, pixbuf_extents.height, pixbuf_extents.x, pixbuf_extents.y);
3266         DBG("new text extents:   %dx%d+%d+%d", text_extents.width, text_extents.height, text_extents.x, text_extents.y);
3267         DBG("new total extents:  %dx%d+%d+%d", total_extents.width, total_extents.height, total_extents.x, total_extents.y);
3268     }
3269 #endif
3270 
3271     cairo_destroy(cr);
3272 }
3273 
3274 static void
xfdesktop_move_all_icons_to_pending_icons_list(XfdesktopIconView * icon_view)3275 xfdesktop_move_all_icons_to_pending_icons_list(XfdesktopIconView *icon_view)
3276 {
3277     GList *l = NULL;
3278 
3279     /* move all icons into the pending_icons list and remove from the desktop */
3280     for(l = icon_view->priv->icons; l; l = l->next) {
3281         gint16 old_row, old_col;
3282 
3283         if(xfdesktop_icon_get_position(XFDESKTOP_ICON(l->data), &old_row, &old_col))
3284             xfdesktop_grid_set_position_free(icon_view, old_row, old_col);
3285 
3286         g_signal_handlers_disconnect_by_func(G_OBJECT(l->data),
3287                                              G_CALLBACK(xfdesktop_icon_view_icon_changed),
3288                                              icon_view);
3289     }
3290     icon_view->priv->pending_icons = g_list_concat(icon_view->priv->icons,
3291                                                    icon_view->priv->pending_icons);
3292     icon_view->priv->icons = NULL;
3293 
3294     memset(icon_view->priv->grid_layout, 0,
3295            (guint)icon_view->priv->nrows * icon_view->priv->ncols
3296            * sizeof(XfdesktopIcon *));
3297 
3298     xfdesktop_setup_grids(icon_view);
3299 }
3300 
3301 /* When changing resolutions this moves all the icons that are in the rc file
3302  * for the new resolution to the desktop and removes them from the pending
3303  * icons list */
3304 static void
xfdesktop_move_all_cached_icons_to_desktop(XfdesktopIconView * icon_view)3305 xfdesktop_move_all_cached_icons_to_desktop(XfdesktopIconView *icon_view)
3306 {
3307 #ifdef ENABLE_FILE_ICONS
3308     GList *l, *leftovers = NULL;
3309     XfdesktopFileIconManager *fmanager = NULL;
3310 
3311     DBG("entering");
3312 
3313     if(XFDESKTOP_IS_FILE_ICON_MANAGER(icon_view->priv->manager))
3314         fmanager = XFDESKTOP_FILE_ICON_MANAGER(icon_view->priv->manager);
3315 
3316     if(fmanager == NULL)
3317         return;
3318 
3319     xfdesktop_file_icon_save(fmanager);
3320 
3321     /* add all cached icons back */
3322     for(l = icon_view->priv->pending_icons; l; l = l->next) {
3323         gint16 row, col;
3324         XfdesktopIcon *icon = XFDESKTOP_ICON(l->data);
3325         gchar *identifier = xfdesktop_icon_get_identifier(icon);
3326 
3327         if(!XFDESKTOP_IS_FILE_ICON(icon))
3328             continue;
3329 
3330         /* Try to get the cached position for the new resolution */
3331         if(xfdesktop_file_icon_manager_get_cached_icon_position(
3332                                                             fmanager,
3333                                                             xfdesktop_icon_peek_label(icon),
3334                                                             identifier,
3335                                                             &row,
3336                                                             &col))
3337         {
3338             XF_DEBUG("icon %s setting position row%dxcol%d",
3339                      xfdesktop_icon_peek_label(icon), row, col);
3340 
3341             /* Make sure the slot is available */
3342             if(xfdesktop_grid_is_free_position(icon_view, row, col)) {
3343                 xfdesktop_icon_set_position(icon, row, col);
3344                 xfdesktop_icon_view_add_item_internal(icon_view, icon);
3345             } else {
3346                 leftovers = g_list_prepend(leftovers, icon);
3347             }
3348         } else {
3349             leftovers = g_list_prepend(leftovers, icon);
3350         }
3351 
3352         if(identifier)
3353             g_free(identifier);
3354     }
3355 
3356     g_list_free(icon_view->priv->pending_icons);
3357     icon_view->priv->pending_icons = g_list_reverse(leftovers);
3358 #endif
3359 }
3360 
3361 /* Takes any icons in the pending icons list that has their original slot open.
3362  * This way icons stay somewhat stable during minor resolution changes */
3363 static void
xfdesktop_move_all_previous_icons_to_desktop(XfdesktopIconView * icon_view)3364 xfdesktop_move_all_previous_icons_to_desktop(XfdesktopIconView *icon_view)
3365 {
3366     GList *l, *leftovers = NULL;
3367 
3368     DBG("entering");
3369 
3370     /* add all pending icons back if their space is still available */
3371     for(l = icon_view->priv->pending_icons; l; l = l->next) {
3372         gint16 row, col;
3373         XfdesktopIcon *icon = XFDESKTOP_ICON(l->data);
3374 
3375         if(!xfdesktop_icon_get_position(icon, &row, &col)) {
3376             g_warning("Trying to set previous position of an icon with no position");
3377         }
3378 
3379         if(xfdesktop_grid_is_free_position(icon_view, row, col)) {
3380             XF_DEBUG("adding icon %s position row %d x col %d",
3381                      xfdesktop_icon_peek_label(icon), row, col);
3382             xfdesktop_icon_view_add_item_internal(icon_view, icon);
3383         } else {
3384             leftovers = g_list_prepend(leftovers, icon);
3385         }
3386     }
3387 
3388     g_list_free(icon_view->priv->pending_icons);
3389     icon_view->priv->pending_icons = g_list_reverse(leftovers);
3390 }
3391 
3392 /* Takes any icons in the pending icons list and adds them where there is space */
3393 static void
xfdesktop_append_all_pending_icons(XfdesktopIconView * icon_view)3394 xfdesktop_append_all_pending_icons(XfdesktopIconView *icon_view)
3395 {
3396     GList *l, *leftovers = NULL;
3397 
3398     DBG("entering");
3399 
3400     /* add all pending icons back if space is available */
3401     for(l = icon_view->priv->pending_icons; l; l = l->next) {
3402         gint16 row, col;
3403         XfdesktopIcon *icon = XFDESKTOP_ICON(l->data);
3404 
3405         if(xfdesktop_grid_get_next_free_position(icon_view, &row, &col)) {
3406             xfdesktop_icon_set_position(icon, row, col);
3407             xfdesktop_icon_view_add_item_internal(icon_view, icon);
3408         } else {
3409             leftovers = g_list_prepend(leftovers, icon);
3410         }
3411     }
3412 
3413     g_list_free(icon_view->priv->pending_icons);
3414     icon_view->priv->pending_icons = g_list_reverse(leftovers);
3415 }
3416 
3417 static void
xfdesktop_move_all_pending_icons_to_desktop(XfdesktopIconView * icon_view)3418 xfdesktop_move_all_pending_icons_to_desktop(XfdesktopIconView *icon_view)
3419 {
3420     if(!XFDESKTOP_IS_ICON_VIEW(icon_view))
3421         return;
3422 
3423     if(icon_view->priv->grid_layout == NULL)
3424         return;
3425 
3426     xfdesktop_move_all_cached_icons_to_desktop(icon_view);
3427     xfdesktop_move_all_previous_icons_to_desktop(icon_view);
3428     xfdesktop_append_all_pending_icons(icon_view);
3429 }
3430 
3431 static void
xfdesktop_grid_do_resize(XfdesktopIconView * icon_view)3432 xfdesktop_grid_do_resize(XfdesktopIconView *icon_view)
3433 {
3434     gint xorigin = 0, yorigin = 0, width = 0, height = 0;
3435     gint16 new_rows, new_cols;
3436     gsize old_size, new_size;
3437     GdkScreen *screen;
3438 
3439     /* First check to see if the grid actually did change. This way
3440      * we don't remove all the icons just to put them back again */
3441     old_size = (guint)icon_view->priv->nrows * icon_view->priv->ncols
3442                * sizeof(XfdesktopIcon *);
3443 
3444     screen = gtk_widget_get_screen (GTK_WIDGET (icon_view));
3445 
3446     if (icon_view->priv->primary)
3447     {
3448         GdkDisplay *display;
3449         GdkMonitor *monitor;
3450         GdkRectangle rectangle;
3451 
3452         display = gdk_screen_get_display (screen);
3453         monitor = gdk_display_get_monitor_at_window (display, gtk_widget_get_parent_window(GTK_WIDGET(icon_view)));
3454         gdk_monitor_get_workarea (monitor, &rectangle);
3455         width = rectangle.width;
3456         height = rectangle.height;
3457     }
3458     else if(!xfdesktop_get_workarea_single(icon_view, 0,
3459                                            &xorigin, &yorigin,
3460                                            &width, &height))
3461     {
3462         xfdesktop_get_screen_dimensions (screen, &width, &height);
3463     }
3464 
3465     new_rows = (width - MIN_MARGIN * 2) / CELL_SIZE;
3466     new_cols = (height - MIN_MARGIN * 2) / CELL_SIZE;
3467 
3468     new_size = (guint)new_rows * new_cols * sizeof(XfdesktopIcon *);
3469 
3470     if(old_size != new_size) {
3471         DBG("old_size != new_size use cache icon list");
3472         #if 0 /*def DEBUG*/
3473             DUMP_GRID_LAYOUT(icon_view);
3474         #endif
3475 
3476         /* Grid size did change */
3477         xfdesktop_move_all_icons_to_pending_icons_list(icon_view);
3478         xfdesktop_move_all_pending_icons_to_desktop(icon_view);
3479 
3480         #if 0 /*def DEBUG*/
3481             DUMP_GRID_LAYOUT(icon_view);
3482         #endif
3483 
3484         /* Fire off an event to notify others of the change */
3485         g_signal_emit(G_OBJECT(icon_view), __signals[SIG_RESIZE_EVENT], 0, NULL);
3486     }
3487     else {
3488         DBG("old_size == new_size updating grid");
3489         xfdesktop_setup_grids (icon_view);
3490     }
3491 
3492     gtk_widget_queue_draw(GTK_WIDGET(icon_view));
3493 }
3494 
3495 static gboolean
xfdesktop_grid_resize_timeout(gpointer user_data)3496 xfdesktop_grid_resize_timeout(gpointer user_data)
3497 {
3498     XfdesktopIconView *icon_view = user_data;
3499 
3500     xfdesktop_grid_do_resize(icon_view);
3501 
3502     icon_view->priv->grid_resize_timeout = 0;
3503     return FALSE;
3504 }
3505 
3506 gboolean
xfdesktop_get_workarea_single(XfdesktopIconView * icon_view,guint ws_num,gint * xorigin,gint * yorigin,gint * width,gint * height)3507 xfdesktop_get_workarea_single(XfdesktopIconView *icon_view,
3508                               guint ws_num,
3509                               gint *xorigin,
3510                               gint *yorigin,
3511                               gint *width,
3512                               gint *height)
3513 {
3514     gboolean ret = FALSE;
3515     GdkScreen *gscreen;
3516     GdkDisplay *gdisplay;
3517     Display *dpy;
3518     Window root;
3519     Atom property, actual_type = None;
3520     gint actual_format = 0, first_id;
3521     gulong nitems = 0, bytes_after = 0, offset = 0, tmp_size = 0;
3522     unsigned char *data_p = NULL;
3523 
3524     g_return_val_if_fail(xorigin && yorigin
3525                          && width && height, FALSE);
3526 
3527     gscreen = gtk_widget_get_screen(GTK_WIDGET(icon_view));
3528     gdisplay = gdk_screen_get_display(gscreen);
3529     dpy = GDK_DISPLAY_XDISPLAY(gdisplay);
3530     root = GDK_WINDOW_XID(gdk_screen_get_root_window(gscreen));
3531     property = XInternAtom(dpy, "_NET_WORKAREA", False);
3532 
3533     first_id = ws_num * 4;
3534 
3535     gdk_x11_display_error_trap_push(gdisplay);
3536 
3537     do {
3538         if(Success == XGetWindowProperty(dpy, root, property, offset,
3539                                          G_MAXULONG, False, XA_CARDINAL,
3540                                          &actual_type, &actual_format, &nitems,
3541                                          &bytes_after, &data_p))
3542         {
3543             gint i;
3544             gulong *data;
3545 
3546             if(actual_format != 32 || actual_type != XA_CARDINAL) {
3547                 XFree(data_p);
3548                 break;
3549             }
3550 
3551             tmp_size = (actual_format / 8) * nitems;
3552             if(actual_format == 32) {
3553                 tmp_size *= sizeof(long)/4;
3554             }
3555 
3556             data = g_malloc(tmp_size);
3557             memcpy(data, data_p, tmp_size);
3558 
3559             i = offset / 32;  /* first element id in this batch */
3560 
3561             /* there's probably a better way to do this. */
3562             if(i + (glong)nitems >= first_id && first_id - (glong)offset >= 0)
3563                 *xorigin = data[first_id - offset] + MIN_MARGIN;
3564             if(i + (glong)nitems >= first_id + 1 && first_id - (glong)offset + 1 >= 0)
3565                 *yorigin = data[first_id - offset + 1] + MIN_MARGIN;
3566             if(i + (glong)nitems >= first_id + 2 && first_id - (glong)offset + 2 >= 0)
3567                 *width = data[first_id - offset + 2] - 2 * MIN_MARGIN;
3568             if(i + (glong)nitems >= first_id + 3 && first_id - (glong)offset + 3 >= 0) {
3569                 *height = data[first_id - offset + 3] - 2 * MIN_MARGIN;
3570                 ret = TRUE;
3571                 XFree(data_p);
3572                 g_free(data);
3573                 break;
3574             }
3575 
3576             offset += actual_format * nitems;
3577             XFree(data_p);
3578             g_free(data);
3579         } else
3580             break;
3581     } while(bytes_after > 0);
3582 
3583     gdk_x11_display_error_trap_pop_ignored(gdisplay);
3584 
3585     return ret;
3586 }
3587 
3588 static inline gboolean
xfdesktop_grid_is_free_position(XfdesktopIconView * icon_view,gint16 row,gint16 col)3589 xfdesktop_grid_is_free_position(XfdesktopIconView *icon_view,
3590                                 gint16 row,
3591                                 gint16 col)
3592 {
3593     if(icon_view->priv->grid_layout == NULL) {
3594         return FALSE;
3595     }
3596 
3597     if(row >= icon_view->priv->nrows || col >= icon_view->priv->ncols || row < 0 || col < 0)
3598     {
3599         return FALSE;
3600     }
3601 
3602     return !icon_view->priv->grid_layout[col * icon_view->priv->nrows + row];
3603 }
3604 
3605 
3606 static gboolean
xfdesktop_grid_get_next_free_position(XfdesktopIconView * icon_view,gint16 * row,gint16 * col)3607 xfdesktop_grid_get_next_free_position(XfdesktopIconView *icon_view,
3608                                       gint16 *row,
3609                                       gint16 *col)
3610 {
3611     gint16 i, j, c, r, idx;
3612 
3613     g_return_val_if_fail(row && col, FALSE);
3614 
3615     if(icon_view->priv->gravity & GRAVITY_HORIZONTAL) {
3616         for(j = 0; j < icon_view->priv->nrows; ++j) {
3617             r = (icon_view->priv->gravity & GRAVITY_BOTTOM) ?
3618                  icon_view->priv->nrows - 1 - j : j;
3619 
3620             for(i = 0; i < icon_view->priv->ncols; ++i) {
3621                 c = (icon_view->priv->gravity & GRAVITY_RIGHT) ?
3622                      icon_view->priv->ncols - 1 - i : i;
3623 
3624                 idx = c * icon_view->priv->nrows + r;
3625 
3626                 if(!icon_view->priv->grid_layout[idx]) {
3627                     *col = c;
3628                     *row = r;
3629                     return TRUE;
3630                 }
3631             }
3632         }
3633     } else {
3634         for(i = 0; i < icon_view->priv->ncols; ++i) {
3635             c = (icon_view->priv->gravity & GRAVITY_RIGHT) ?
3636                  icon_view->priv->ncols - 1 - i : i;
3637 
3638             for(j = 0; j < icon_view->priv->nrows; ++j) {
3639                 r = (icon_view->priv->gravity & GRAVITY_BOTTOM) ?
3640                     icon_view->priv->nrows - 1 - j : j;
3641 
3642                 idx = c * icon_view->priv->nrows + r;
3643 
3644                 if(!icon_view->priv->grid_layout[idx]) {
3645                     *col = c;
3646                     *row = r;
3647                     return TRUE;
3648                 }
3649             }
3650         }
3651     }
3652 
3653     return FALSE;
3654 }
3655 
3656 
3657 static inline void
xfdesktop_grid_set_position_free(XfdesktopIconView * icon_view,gint16 row,gint16 col)3658 xfdesktop_grid_set_position_free(XfdesktopIconView *icon_view,
3659                                  gint16 row,
3660                                  gint16 col)
3661 {
3662     g_return_if_fail(row < icon_view->priv->nrows
3663                      && col < icon_view->priv->ncols
3664                      && row >= 0 && col >= 0);
3665 
3666 #if 0 /*def DEBUG*/
3667     DUMP_GRID_LAYOUT(icon_view);
3668 #endif
3669 
3670     icon_view->priv->grid_layout[col * icon_view->priv->nrows + row] = NULL;
3671 
3672 #if 0 /*def DEBUG*/
3673     DUMP_GRID_LAYOUT(icon_view);
3674 #endif
3675 }
3676 
3677 static inline gboolean
xfdesktop_grid_unset_position_free_raw(XfdesktopIconView * icon_view,gint16 row,gint16 col,gpointer data)3678 xfdesktop_grid_unset_position_free_raw(XfdesktopIconView *icon_view,
3679                                        gint16 row,
3680                                        gint16 col,
3681                                        gpointer data)
3682 {
3683     gint idx;
3684 
3685     g_return_val_if_fail(row < icon_view->priv->nrows
3686                          && col < icon_view->priv->ncols
3687                          && row >= 0 && col >= 0, FALSE);
3688 
3689     idx = col * icon_view->priv->nrows + row;
3690     if(icon_view->priv->grid_layout[idx])
3691         return FALSE;
3692 
3693 #if 0 /*def DEBUG*/
3694     DUMP_GRID_LAYOUT(icon_view);
3695 #endif
3696 
3697     icon_view->priv->grid_layout[idx] = data;
3698 
3699 #if 0 /*def DEBUG*/
3700     DUMP_GRID_LAYOUT(icon_view);
3701 #endif
3702 
3703     return TRUE;
3704 }
3705 
3706 static inline gboolean
xfdesktop_grid_unset_position_free(XfdesktopIconView * icon_view,XfdesktopIcon * icon)3707 xfdesktop_grid_unset_position_free(XfdesktopIconView *icon_view,
3708                                    XfdesktopIcon *icon)
3709 {
3710     gint16 row, col;
3711 
3712     if(!xfdesktop_icon_get_position(icon, &row, &col)) {
3713         g_warning("Trying to set free position of an icon with no position");
3714         return FALSE;
3715     }
3716 
3717     return xfdesktop_grid_unset_position_free_raw(icon_view, row, col, icon);
3718 }
3719 
3720 static inline XfdesktopIcon *
xfdesktop_icon_view_icon_in_cell_raw(XfdesktopIconView * icon_view,gint idx)3721 xfdesktop_icon_view_icon_in_cell_raw(XfdesktopIconView *icon_view,
3722                                      gint idx)
3723 {
3724     XfdesktopIcon *icon = icon_view->priv->grid_layout[idx];
3725 
3726     if((gpointer)0xdeadbeef == icon)
3727         return NULL;
3728 
3729     return icon;
3730 }
3731 
3732 static inline XfdesktopIcon *
xfdesktop_icon_view_icon_in_cell(XfdesktopIconView * icon_view,gint16 row,gint16 col)3733 xfdesktop_icon_view_icon_in_cell(XfdesktopIconView *icon_view,
3734                                  gint16 row,
3735                                  gint16 col)
3736 {
3737     gint idx;
3738 
3739     g_return_val_if_fail(row < icon_view->priv->nrows
3740                          && col < icon_view->priv->ncols, NULL);
3741 
3742     idx = col * icon_view->priv->nrows + row;
3743 
3744     /* FIXME: that's why we can't drag icons to monitors on the left or above,
3745      * the array maps positions on the grid starting from the primary monitor. */
3746     if (idx < 0)
3747         return NULL;
3748 
3749     return xfdesktop_icon_view_icon_in_cell_raw(icon_view, idx);
3750 }
3751 
3752 static inline gboolean
xfdesktop_rectangle_contains_point(GdkRectangle * rect,gint x,gint y)3753 xfdesktop_rectangle_contains_point(GdkRectangle *rect, gint x, gint y)
3754 {
3755     if(x > rect->x + rect->width
3756             || x < rect->x
3757             || y > rect->y + rect->height
3758             || y < rect->y)
3759     {
3760         return FALSE;
3761     }
3762 
3763     return TRUE;
3764 }
3765 
3766 static gint
xfdesktop_check_icon_clicked(gconstpointer data,gconstpointer user_data)3767 xfdesktop_check_icon_clicked(gconstpointer data,
3768                              gconstpointer user_data)
3769 {
3770     XfdesktopIcon *icon = XFDESKTOP_ICON(data);
3771     GdkEventButton *evt = (GdkEventButton *)user_data;
3772     GdkRectangle extents;
3773 
3774     if(xfdesktop_icon_get_extents(icon, NULL, NULL, &extents)
3775        && xfdesktop_rectangle_contains_point(&extents, evt->x, evt->y))
3776     {
3777         return 0;
3778     } else
3779         return 1;
3780 }
3781 
3782 static void
xfdesktop_list_foreach_invalidate(gpointer data,gpointer user_data)3783 xfdesktop_list_foreach_invalidate(gpointer data,
3784                                   gpointer user_data)
3785 {
3786     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(user_data);
3787     XfdesktopIcon *icon = XFDESKTOP_ICON(data);
3788     xfdesktop_icon_view_invalidate_icon(icon_view, icon, TRUE);
3789 }
3790 
3791 static void
xfdesktop_icon_view_modify_font_size(XfdesktopIconView * icon_view,gdouble size)3792 xfdesktop_icon_view_modify_font_size(XfdesktopIconView *icon_view,
3793                                      gdouble size)
3794 {
3795     const PangoFontDescription *pfd;
3796     PangoFontDescription *pfd_new;
3797 
3798     pfd = pango_layout_get_font_description(icon_view->priv->playout);
3799     if(pfd)
3800         pfd_new = pango_font_description_copy(pfd);
3801     else
3802         pfd_new = pango_font_description_new();
3803 
3804     pango_font_description_set_size(pfd_new, (gint)(size * PANGO_SCALE));
3805 
3806     pango_layout_set_font_description(icon_view->priv->playout, pfd_new);
3807 
3808     pango_font_description_free(pfd_new);
3809 }
3810 
3811 static void
xfdesktop_icon_view_icon_changed(XfdesktopIcon * icon,gpointer user_data)3812 xfdesktop_icon_view_icon_changed(XfdesktopIcon *icon,
3813                                  gpointer user_data)
3814 {
3815     /* maybe can pass FALSE here */
3816     xfdesktop_icon_view_invalidate_icon(XFDESKTOP_ICON_VIEW(user_data),
3817                                         icon, TRUE);
3818 }
3819 
3820 static gboolean
xfdesktop_icon_view_is_icon_selected(XfdesktopIconView * icon_view,XfdesktopIcon * icon)3821 xfdesktop_icon_view_is_icon_selected(XfdesktopIconView *icon_view,
3822                                      XfdesktopIcon *icon)
3823 {
3824     return (g_list_find(icon_view->priv->selected_icons, icon)) == NULL ? FALSE : TRUE;
3825 }
3826 
3827 
3828 /* public api */
3829 
3830 
3831 GtkWidget *
xfdesktop_icon_view_new(XfdesktopIconViewManager * manager)3832 xfdesktop_icon_view_new(XfdesktopIconViewManager *manager)
3833 {
3834     XfdesktopIconView *icon_view;
3835 
3836     g_return_val_if_fail(XFDESKTOP_IS_ICON_VIEW_MANAGER(manager), NULL);
3837 
3838     icon_view = g_object_new(XFDESKTOP_TYPE_ICON_VIEW, NULL);
3839     icon_view->priv->manager = manager;
3840 
3841     icon_view->priv->channel = xfconf_channel_get(XFDESKTOP_CHANNEL);
3842 
3843     xfconf_g_property_bind(icon_view->priv->channel,
3844                            "/desktop-icons/single-click",
3845                            G_TYPE_BOOLEAN,
3846                            G_OBJECT(icon_view),
3847                            "single_click");
3848 
3849     xfconf_g_property_bind(icon_view->priv->channel,
3850                            "/desktop-icons/gravity",
3851                            G_TYPE_INT,
3852                            G_OBJECT(icon_view),
3853                            "gravity");
3854 
3855     xfconf_g_property_bind(icon_view->priv->channel,
3856                            "/desktop-icons/show-tooltips",
3857                            G_TYPE_BOOLEAN,
3858                            G_OBJECT(icon_view),
3859                            "show_tooltips");
3860 
3861     xfconf_g_property_bind(icon_view->priv->channel,
3862                            "/desktop-icons/tooltip-size",
3863                            G_TYPE_DOUBLE,
3864                            G_OBJECT(icon_view),
3865                            "tooltip_size");
3866 
3867     return GTK_WIDGET(icon_view);
3868 }
3869 
3870 static void
xfdesktop_icon_view_add_item_internal(XfdesktopIconView * icon_view,XfdesktopIcon * icon)3871 xfdesktop_icon_view_add_item_internal(XfdesktopIconView *icon_view,
3872                                       XfdesktopIcon *icon)
3873 {
3874     gint16 row, col;
3875     cairo_rectangle_int_t fake_area;
3876     GdkDrawingContext *gdc;
3877     cairo_region_t *region;
3878     cairo_t *cr;
3879     GdkWindow *gdkwindow;
3880 
3881     /* sanity check: at this point this should be taken care of */
3882     if(!xfdesktop_icon_get_position(icon, &row, &col)) {
3883         g_warning("Attempting to add item without a position");
3884         return;
3885     }
3886 
3887     xfdesktop_grid_unset_position_free(icon_view, icon);
3888 
3889     icon_view->priv->icons = g_list_prepend(icon_view->priv->icons, icon);
3890 
3891     g_signal_connect(G_OBJECT(icon), "pixbuf-changed",
3892                      G_CALLBACK(xfdesktop_icon_view_icon_changed),
3893                      icon_view);
3894     g_signal_connect(G_OBJECT(icon), "label-changed",
3895                      G_CALLBACK(xfdesktop_icon_view_icon_changed),
3896                      icon_view);
3897 
3898     gdkwindow = gtk_widget_get_window(GTK_WIDGET(icon_view));
3899 
3900     /* Calculate the region the icon will occupy */
3901     fake_area.x = icon_view->priv->xorigin + icon_view->priv->xmargin + col * CELL_SIZE + col * icon_view->priv->xspacing;
3902     fake_area.y = icon_view->priv->yorigin + icon_view->priv->ymargin + row * CELL_SIZE + row * icon_view->priv->yspacing;
3903     fake_area.width = fake_area.height = CELL_SIZE;
3904 
3905     /* Pack it into a cairo region to tell gdk that's where we will be painting */
3906     region = cairo_region_create_rectangle(&fake_area);
3907     gdc = gdk_window_begin_draw_frame(gdkwindow, region);
3908     cr = gdk_drawing_context_get_cairo_context(gdc);
3909 
3910     /* paint the icon */
3911     xfdesktop_icon_view_paint_icon(icon_view, icon, &fake_area, cr);
3912 
3913     /* we're done drawing */
3914     gdk_window_end_draw_frame(gdkwindow, gdc);
3915 
3916     cairo_region_destroy(region);
3917 }
3918 
3919 static gboolean
xfdesktop_icon_view_icon_find_position(XfdesktopIconView * icon_view,XfdesktopIcon * icon)3920 xfdesktop_icon_view_icon_find_position(XfdesktopIconView *icon_view,
3921                                        XfdesktopIcon *icon)
3922 {
3923     gint16 row, col;
3924 
3925     if (!xfdesktop_icon_get_position(icon, &row, &col)
3926         || !xfdesktop_grid_is_free_position(icon_view, row, col)
3927         || (((icon_view->priv->gravity & GRAVITY_BOTTOM) ||
3928              (icon_view->priv->gravity & GRAVITY_RIGHT)) && row == 0 && col == 0))
3929     {
3930         if (xfdesktop_grid_get_next_free_position(icon_view, &row, &col)) {
3931             XF_DEBUG("old position didn't exist or isn't free, got (%d,%d) instead",
3932                      row, col);
3933             xfdesktop_icon_set_position(icon, row, col);
3934         } else {
3935             XF_DEBUG("can't fit icon on screen");
3936             return FALSE;
3937         }
3938     }
3939 
3940     return TRUE;
3941 }
3942 
3943 void
xfdesktop_icon_view_add_item(XfdesktopIconView * icon_view,XfdesktopIcon * icon)3944 xfdesktop_icon_view_add_item(XfdesktopIconView *icon_view,
3945                              XfdesktopIcon *icon)
3946 {
3947     gint16 row, col;
3948 
3949     g_return_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view)
3950                      && XFDESKTOP_IS_ICON(icon));
3951 
3952     /* ensure the icon isn't already in an icon view */
3953     g_return_if_fail(!g_object_get_data(G_OBJECT(icon),
3954                                         "--xfdesktop-icon-view"));
3955 
3956     g_object_set_data(G_OBJECT(icon), "--xfdesktop-icon-view", icon_view);
3957     g_object_ref(G_OBJECT(icon));
3958 
3959     if(!gtk_widget_get_realized(GTK_WIDGET(icon_view))) {
3960         /* if we aren't realized, we don't know what our grid looks like, so
3961          * just hang onto the icon for later */
3962         if(xfdesktop_icon_get_position(icon, &row, &col)) {
3963             icon_view->priv->pending_icons = g_list_prepend(icon_view->priv->pending_icons,
3964                                                             icon);
3965         } else {
3966             icon_view->priv->pending_icons = g_list_append(icon_view->priv->pending_icons,
3967                                                            icon);
3968         }
3969     } else {
3970         if(xfdesktop_icon_view_icon_find_position(icon_view, icon))
3971             xfdesktop_icon_view_add_item_internal(icon_view, icon);
3972         else {
3973             icon_view->priv->pending_icons = g_list_append(icon_view->priv->pending_icons,
3974                                                            icon);
3975         }
3976     }
3977 }
3978 
3979 void
xfdesktop_icon_view_remove_item(XfdesktopIconView * icon_view,XfdesktopIcon * icon)3980 xfdesktop_icon_view_remove_item(XfdesktopIconView *icon_view,
3981                                 XfdesktopIcon *icon)
3982 {
3983     gint16 row, col;
3984     GList *l;
3985 
3986     g_return_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view)
3987                      && XFDESKTOP_IS_ICON(icon));
3988 
3989     l = g_list_find(icon_view->priv->icons, icon);
3990     if(l) {
3991         g_signal_handlers_disconnect_by_func(G_OBJECT(icon),
3992                                              G_CALLBACK(xfdesktop_icon_view_icon_changed),
3993                                              icon_view);
3994 
3995         if(xfdesktop_icon_get_position(icon, &row, &col)) {
3996             xfdesktop_icon_view_invalidate_icon(icon_view, icon, FALSE);
3997             xfdesktop_grid_set_position_free(icon_view, row, col);
3998         }
3999         icon_view->priv->icons = g_list_delete_link(icon_view->priv->icons, l);
4000         icon_view->priv->selected_icons = g_list_remove(icon_view->priv->selected_icons,
4001                                                         icon);
4002         if(icon_view->priv->cursor == icon) {
4003             icon_view->priv->cursor = NULL;
4004             if(icon_view->priv->selected_icons)
4005                 icon_view->priv->cursor = icon_view->priv->selected_icons->data;
4006         }
4007         if(icon_view->priv->first_clicked_item == icon)
4008             icon_view->priv->first_clicked_item = NULL;
4009         if(icon_view->priv->item_under_pointer == icon)
4010             icon_view->priv->item_under_pointer = NULL;
4011     } else if((l = g_list_find(icon_view->priv->pending_icons, icon))) {
4012         icon_view->priv->pending_icons = g_list_delete_link(icon_view->priv->pending_icons,
4013                                                             l);
4014     } else {
4015         g_warning("Attempt to remove icon %p from XfdesktopIconView %p, but it's not in there.",
4016                   icon, icon_view);
4017         return;
4018     }
4019 
4020     g_object_set_data(G_OBJECT(icon), "--xfdesktop-icon-view", NULL);
4021     g_object_unref(G_OBJECT(icon));
4022 
4023     if(icon_view->priv->pending_icons != NULL) {
4024         /* Move in any pending icons to the space available */
4025         xfdesktop_move_all_pending_icons_to_desktop(icon_view);
4026     }
4027 }
4028 
4029 void
xfdesktop_icon_view_remove_all(XfdesktopIconView * icon_view)4030 xfdesktop_icon_view_remove_all(XfdesktopIconView *icon_view)
4031 {
4032     GList *l;
4033     gint16 row, col;
4034 
4035     g_return_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view));
4036 
4037     if(icon_view->priv->pending_icons) {
4038         g_list_foreach(icon_view->priv->pending_icons, (GFunc)g_object_unref,
4039                        NULL);
4040         g_list_free(icon_view->priv->pending_icons);
4041         icon_view->priv->pending_icons = NULL;
4042     }
4043 
4044     for(l = icon_view->priv->icons; l; l = l->next) {
4045         XfdesktopIcon *icon = XFDESKTOP_ICON(l->data);
4046         if(xfdesktop_icon_get_position(icon, &row, &col)) {
4047             xfdesktop_icon_view_invalidate_icon(icon_view, icon, FALSE);
4048             xfdesktop_grid_set_position_free(icon_view, row, col);
4049         }
4050 
4051         g_signal_handlers_disconnect_by_func(G_OBJECT(l->data),
4052                                              G_CALLBACK(xfdesktop_icon_view_icon_changed),
4053                                              icon_view);
4054         g_object_set_data(G_OBJECT(l->data), "--xfdesktop-icon-view", NULL);
4055         g_object_unref(G_OBJECT(l->data));
4056     }
4057 
4058     if(G_LIKELY(icon_view->priv->icons)) {
4059         g_list_free(icon_view->priv->icons);
4060         icon_view->priv->icons = NULL;
4061     }
4062 
4063     if(icon_view->priv->selected_icons) {
4064         g_list_free(icon_view->priv->selected_icons);
4065         icon_view->priv->selected_icons = NULL;
4066     }
4067 
4068     icon_view->priv->item_under_pointer = NULL;
4069     icon_view->priv->cursor = NULL;
4070     icon_view->priv->first_clicked_item = NULL;
4071 }
4072 
4073 void
xfdesktop_icon_view_set_selection_mode(XfdesktopIconView * icon_view,GtkSelectionMode mode)4074 xfdesktop_icon_view_set_selection_mode(XfdesktopIconView *icon_view,
4075                                        GtkSelectionMode mode)
4076 {
4077     g_return_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view));
4078     g_return_if_fail(mode <= GTK_SELECTION_MULTIPLE);
4079 
4080     if(mode == icon_view->priv->sel_mode)
4081         return;
4082 
4083     icon_view->priv->sel_mode = mode;
4084 
4085     switch(mode) {
4086         case GTK_SELECTION_NONE:
4087             g_warning("GTK_SELECTION_NONE is not implemented for " \
4088                       "XfdesktopIconView.  Falling back to " \
4089                       "GTK_SELECTION_SINGLE.");
4090             icon_view->priv->sel_mode = GTK_SELECTION_SINGLE;
4091             /* fall through */
4092         case GTK_SELECTION_SINGLE:
4093             if(g_list_length(icon_view->priv->selected_icons) > 1) {
4094                 GList *l;
4095                 /* TODO: enable later and make sure it works */
4096                 /*gdk_window_freeze_updates(GTK_WIDGET(icon_view)->window);*/
4097                 for(l = icon_view->priv->selected_icons->next; l; l = l->next) {
4098                     xfdesktop_icon_view_unselect_item(icon_view,
4099                                                       XFDESKTOP_ICON(l->data));
4100                 }
4101                 /*gdk_window_thaw_updates(GTK_WIDGET(icon_view)->window);*/
4102             }
4103             icon_view->priv->allow_rubber_banding = FALSE;
4104             break;
4105 
4106         case GTK_SELECTION_BROWSE:
4107             g_warning("GTK_SELECTION_BROWSE is not implemented for " \
4108                   "XfdesktopIconView.  Falling back to " \
4109                   "GTK_SELECTION_MULTIPLE.");
4110             icon_view->priv->sel_mode = GTK_SELECTION_MULTIPLE;
4111             /* fall through */
4112         default:
4113             icon_view->priv->allow_rubber_banding = TRUE;
4114             break;
4115     }
4116 }
4117 
4118 GtkSelectionMode
xfdesktop_icon_view_get_selection_mode(XfdesktopIconView * icon_view)4119 xfdesktop_icon_view_get_selection_mode(XfdesktopIconView *icon_view)
4120 {
4121     g_return_val_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view),
4122                          GTK_SELECTION_NONE);
4123 
4124     return icon_view->priv->sel_mode;
4125 }
4126 
4127 void
xfdesktop_icon_view_enable_drag_source(XfdesktopIconView * icon_view,GdkModifierType start_button_mask,const GtkTargetEntry * targets,gint n_targets,GdkDragAction actions)4128 xfdesktop_icon_view_enable_drag_source(XfdesktopIconView *icon_view,
4129                                        GdkModifierType start_button_mask,
4130                                        const GtkTargetEntry *targets,
4131                                        gint n_targets,
4132                                        GdkDragAction actions)
4133 {
4134     g_return_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view));
4135 
4136     if(icon_view->priv->drag_source_set) {
4137         gtk_target_list_unref(icon_view->priv->source_targets);
4138         icon_view->priv->source_targets = gtk_target_list_new(icon_view_targets,
4139                                                               icon_view_n_targets);
4140     }
4141 
4142     icon_view->priv->foreign_source_actions = actions;
4143     icon_view->priv->foreign_source_mask = start_button_mask;
4144 
4145     gtk_target_list_add_table(icon_view->priv->source_targets, targets,
4146                               n_targets);
4147 
4148     gtk_drag_source_set(GTK_WIDGET(icon_view), start_button_mask, NULL, 0,
4149                         GDK_ACTION_MOVE | actions);
4150     gtk_drag_source_set_target_list(GTK_WIDGET(icon_view),
4151                                     icon_view->priv->source_targets);
4152 
4153     icon_view->priv->drag_source_set = TRUE;
4154 }
4155 
4156 void
xfdesktop_icon_view_enable_drag_dest(XfdesktopIconView * icon_view,const GtkTargetEntry * targets,gint n_targets,GdkDragAction actions)4157 xfdesktop_icon_view_enable_drag_dest(XfdesktopIconView *icon_view,
4158                                      const GtkTargetEntry *targets,
4159                                      gint n_targets,
4160                                      GdkDragAction actions)
4161 {
4162     g_return_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view));
4163 
4164     if(icon_view->priv->drag_dest_set) {
4165         gtk_target_list_unref(icon_view->priv->dest_targets);
4166         icon_view->priv->dest_targets = gtk_target_list_new(icon_view_targets,
4167                                                             icon_view_n_targets);
4168     }
4169 
4170     icon_view->priv->foreign_dest_actions = actions;
4171 
4172     gtk_target_list_add_table(icon_view->priv->dest_targets, targets,
4173                               n_targets);
4174 
4175     gtk_drag_dest_set(GTK_WIDGET(icon_view), 0, NULL, 0,
4176                       GDK_ACTION_MOVE | actions);
4177     gtk_drag_dest_set_target_list(GTK_WIDGET(icon_view),
4178                                   icon_view->priv->dest_targets);
4179 
4180     icon_view->priv->drag_dest_set = TRUE;
4181 }
4182 
4183 void
xfdesktop_icon_view_unset_drag_source(XfdesktopIconView * icon_view)4184 xfdesktop_icon_view_unset_drag_source(XfdesktopIconView *icon_view)
4185 {
4186     g_return_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view));
4187 
4188     if(!icon_view->priv->drag_source_set)
4189         return;
4190 
4191     if(icon_view->priv->source_targets)
4192         gtk_target_list_unref(icon_view->priv->source_targets);
4193 
4194     icon_view->priv->source_targets = gtk_target_list_new(icon_view_targets,
4195                                                               icon_view_n_targets);
4196 
4197     gtk_drag_source_set(GTK_WIDGET(icon_view), 0, NULL, 0, GDK_ACTION_MOVE);
4198     gtk_drag_source_set_target_list(GTK_WIDGET(icon_view),
4199                                     icon_view->priv->source_targets);
4200 
4201     icon_view->priv->drag_source_set = FALSE;
4202 }
4203 
4204 void
xfdesktop_icon_view_unset_drag_dest(XfdesktopIconView * icon_view)4205 xfdesktop_icon_view_unset_drag_dest(XfdesktopIconView *icon_view)
4206 {
4207     g_return_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view));
4208 
4209     if(!icon_view->priv->drag_dest_set)
4210         return;
4211 
4212     if(icon_view->priv->dest_targets)
4213         gtk_target_list_unref(icon_view->priv->dest_targets);
4214 
4215     icon_view->priv->dest_targets = gtk_target_list_new(icon_view_targets,
4216                                                         icon_view_n_targets);
4217 
4218     gtk_drag_dest_set(GTK_WIDGET(icon_view), 0, NULL, 0, GDK_ACTION_MOVE);
4219     gtk_drag_dest_set_target_list(GTK_WIDGET(icon_view),
4220                                   icon_view->priv->dest_targets);
4221 
4222     icon_view->priv->drag_dest_set = FALSE;
4223 }
4224 
4225 XfdesktopIcon *
xfdesktop_icon_view_widget_coords_to_item(XfdesktopIconView * icon_view,gint wx,gint wy)4226 xfdesktop_icon_view_widget_coords_to_item(XfdesktopIconView *icon_view,
4227                                           gint wx,
4228                                           gint wy)
4229 {
4230     gint16 row, col;
4231 
4232     xfdesktop_xy_to_rowcol(icon_view, wx, wy, &row, &col);
4233     if(row >= icon_view->priv->nrows || col >= icon_view->priv->ncols || row < 0 || col < 0)
4234     {
4235         return NULL;
4236     }
4237 
4238     return xfdesktop_icon_view_icon_in_cell(icon_view, row, col);
4239 }
4240 
4241 GList *
xfdesktop_icon_view_get_selected_items(XfdesktopIconView * icon_view)4242 xfdesktop_icon_view_get_selected_items(XfdesktopIconView *icon_view)
4243 {
4244     g_return_val_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view), NULL);
4245 
4246     return g_list_copy(icon_view->priv->selected_icons);
4247 }
4248 
4249 void
xfdesktop_icon_view_select_item(XfdesktopIconView * icon_view,XfdesktopIcon * icon)4250 xfdesktop_icon_view_select_item(XfdesktopIconView *icon_view,
4251                                 XfdesktopIcon *icon)
4252 {
4253     g_return_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view));
4254 
4255     if(xfdesktop_icon_view_is_icon_selected(icon_view, icon))
4256         return;
4257 
4258     if(icon_view->priv->sel_mode == GTK_SELECTION_SINGLE)
4259         xfdesktop_icon_view_unselect_all(icon_view);
4260 
4261     icon_view->priv->selected_icons = g_list_prepend(icon_view->priv->selected_icons,
4262                                                      icon);
4263     xfdesktop_icon_view_invalidate_icon(icon_view, icon, TRUE);
4264 
4265     g_signal_emit(G_OBJECT(icon_view),
4266                   __signals[SIG_ICON_SELECTION_CHANGED],
4267                   0, NULL);
4268     xfdesktop_icon_selected(icon);
4269 }
4270 
4271 void
xfdesktop_icon_view_select_all(XfdesktopIconView * icon_view)4272 xfdesktop_icon_view_select_all(XfdesktopIconView *icon_view)
4273 {
4274     GList *l;
4275 
4276     g_return_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view));
4277 
4278     if(!icon_view->priv->icons)
4279         return;
4280 
4281     if(icon_view->priv->selected_icons
4282        && g_list_length(icon_view->priv->icons)
4283           == g_list_length(icon_view->priv->selected_icons))
4284     {
4285         return;
4286     }
4287 
4288     /* simplify: just free the entire list and repopulate it */
4289     if(icon_view->priv->selected_icons) {
4290         g_list_free(icon_view->priv->selected_icons);
4291         icon_view->priv->selected_icons = NULL;
4292     }
4293 
4294     for(l = icon_view->priv->icons; l; l = l->next) {
4295         icon_view->priv->selected_icons = g_list_prepend(icon_view->priv->selected_icons, l->data);
4296         xfdesktop_icon_view_invalidate_icon(icon_view, l->data, TRUE);
4297         xfdesktop_icon_selected(l->data);
4298     }
4299 
4300     g_signal_emit(G_OBJECT(icon_view),
4301                   __signals[SIG_ICON_SELECTION_CHANGED],
4302                   0, NULL);
4303 }
4304 
4305 void
xfdesktop_icon_view_unselect_item(XfdesktopIconView * icon_view,XfdesktopIcon * icon)4306 xfdesktop_icon_view_unselect_item(XfdesktopIconView *icon_view,
4307                                   XfdesktopIcon *icon)
4308 {
4309     GList *l;
4310 
4311     g_return_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view)
4312                      && XFDESKTOP_IS_ICON(icon));
4313 
4314     l = g_list_find(icon_view->priv->selected_icons, icon);
4315     if(l) {
4316         icon_view->priv->selected_icons = g_list_delete_link(icon_view->priv->selected_icons,
4317                                                              l);
4318         xfdesktop_icon_view_invalidate_icon(icon_view, icon, TRUE);
4319         g_signal_emit(G_OBJECT(icon_view),
4320                       __signals[SIG_ICON_SELECTION_CHANGED],
4321                       0, NULL);
4322     }
4323 }
4324 
4325 void
xfdesktop_icon_view_unselect_all(XfdesktopIconView * icon_view)4326 xfdesktop_icon_view_unselect_all(XfdesktopIconView *icon_view)
4327 {
4328     g_return_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view));
4329 
4330     if(icon_view->priv->selected_icons) {
4331         GList *repaint_icons = icon_view->priv->selected_icons;
4332         icon_view->priv->selected_icons = NULL;
4333         g_list_foreach(repaint_icons, xfdesktop_list_foreach_invalidate,
4334                        icon_view);
4335         g_list_free(repaint_icons);
4336         g_signal_emit(G_OBJECT(icon_view),
4337                       __signals[SIG_ICON_SELECTION_CHANGED],
4338                       0, NULL);
4339     }
4340 }
4341 
4342 void
xfdesktop_icon_view_set_icon_size(XfdesktopIconView * icon_view,guint icon_size)4343 xfdesktop_icon_view_set_icon_size(XfdesktopIconView *icon_view,
4344                                   guint icon_size)
4345 {
4346     g_return_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view));
4347 
4348     /* Choose the correct icon based on it size */
4349     wnck_set_default_icon_size (icon_size);
4350 
4351     if(icon_size == icon_view->priv->icon_size)
4352         return;
4353 
4354     icon_view->priv->icon_size = icon_size;
4355 
4356     if(gtk_widget_get_realized(GTK_WIDGET(icon_view))) {
4357         xfdesktop_grid_do_resize(icon_view);
4358         gtk_widget_queue_draw(GTK_WIDGET(icon_view));
4359     }
4360 }
4361 
4362 guint
xfdesktop_icon_view_get_icon_size(XfdesktopIconView * icon_view)4363 xfdesktop_icon_view_get_icon_size(XfdesktopIconView *icon_view)
4364 {
4365     g_return_val_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view), 0);
4366     return icon_view->priv->icon_size;
4367 }
4368 
4369 void
xfdesktop_icon_view_set_primary(XfdesktopIconView * icon_view,gboolean primary)4370 xfdesktop_icon_view_set_primary(XfdesktopIconView *icon_view,
4371                                 gboolean primary)
4372 {
4373     g_return_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view));
4374 
4375     if(primary == icon_view->priv->primary)
4376         return;
4377 
4378     icon_view->priv->primary = primary;
4379 
4380     if(gtk_widget_get_realized(GTK_WIDGET(icon_view))) {
4381         xfdesktop_grid_do_resize(icon_view);
4382     }
4383 }
4384 
4385 void
xfdesktop_icon_view_set_font_size(XfdesktopIconView * icon_view,gdouble font_size_points)4386 xfdesktop_icon_view_set_font_size(XfdesktopIconView *icon_view,
4387                                   gdouble font_size_points)
4388 {
4389     g_return_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view));
4390 
4391     if(font_size_points == icon_view->priv->font_size)
4392         return;
4393 
4394     icon_view->priv->font_size = font_size_points;
4395 
4396     if(gtk_widget_get_realized(GTK_WIDGET(icon_view))) {
4397         xfdesktop_icon_view_modify_font_size(icon_view, font_size_points);
4398         xfdesktop_grid_do_resize(icon_view);
4399         gtk_widget_queue_draw(GTK_WIDGET(icon_view));
4400     }
4401 }
4402 
4403 gdouble
xfdesktop_icon_view_get_font_size(XfdesktopIconView * icon_view)4404 xfdesktop_icon_view_get_font_size(XfdesktopIconView *icon_view)
4405 {
4406     g_return_val_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view), 0.0);
4407     return icon_view->priv->font_size;
4408 }
4409 
4410 void
xfdesktop_icon_view_set_center_text(XfdesktopIconView * icon_view,gboolean center_text)4411 xfdesktop_icon_view_set_center_text (XfdesktopIconView *icon_view,
4412                                      gboolean center_text)
4413 {
4414     g_return_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view));
4415 
4416     if (center_text == icon_view->priv->center_text)
4417         return;
4418 
4419     icon_view->priv->center_text = center_text;
4420 
4421     if(gtk_widget_get_realized(GTK_WIDGET(icon_view))) {
4422         gtk_widget_queue_draw(GTK_WIDGET(icon_view));
4423     }
4424 }
4425 
4426 GtkWidget *
xfdesktop_icon_view_get_window_widget(XfdesktopIconView * icon_view)4427 xfdesktop_icon_view_get_window_widget(XfdesktopIconView *icon_view)
4428 {
4429     g_return_val_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view), NULL);
4430 
4431     return icon_view->priv->parent_window;
4432 }
4433 
4434 #if defined(DEBUG) && DEBUG > 0
4435 guint
_xfdesktop_icon_view_n_items(XfdesktopIconView * icon_view)4436 _xfdesktop_icon_view_n_items(XfdesktopIconView *icon_view)
4437 {
4438     return g_list_length(icon_view->priv->pending_icons) + g_list_length(icon_view->priv->icons);
4439 }
4440 #endif
4441