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