1
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
3
/* nautilus-icon-container.c - Icon container widget.
5
Copyright (C) 1999, 2000 Free Software Foundation
6
Copyright (C) 2000, 2001 Eazel, Inc.
7
Copyright (C) 2002, 2003 Red Hat, Inc.
9
The Gnome Library is free software; you can redistribute it and/or
10
modify it under the terms of the GNU Library General Public License as
11
published by the Free Software Foundation; either version 2 of the
12
License, or (at your option) any later version.
14
The Gnome Library is distributed in the hope that it will be useful,
15
but WITHOUT ANY WARRANTY; without even the implied warranty of
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
Library General Public License for more details.
19
You should have received a copy of the GNU Library General Public
20
License along with the Gnome Library; see the file COPYING.LIB. If not,
21
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22
Boston, MA 02111-1307, USA.
24
Authors: Ettore Perazzoli <ettore@gnu.org>,
25
Darin Adler <darin@bentspoon.com>
30
#include "nautilus-icon-container.h"
32
#include "nautilus-global-preferences.h"
33
#include "nautilus-icon-private.h"
34
#include "nautilus-lib-self-check-functions.h"
35
#include "nautilus-selection-canvas-item.h"
36
#include <atk/atkaction.h>
37
#include <eel/eel-accessibility.h>
38
#include <eel/eel-vfs-extensions.h>
39
#include <eel/eel-gtk-extensions.h>
40
#include <eel/eel-art-extensions.h>
41
#include <eel/eel-editable-label.h>
43
#include <gdk/gdkkeysyms.h>
46
#include <glib/gi18n.h>
50
#define DEBUG_FLAG NAUTILUS_DEBUG_ICON_CONTAINER
51
#include "nautilus-debug.h"
53
#define TAB_NAVIGATION_DISABLED
55
/* Interval for updating the rubberband selection, in milliseconds. */
56
#define RUBBERBAND_TIMEOUT_INTERVAL 10
58
/* Initial unpositioned icon value */
59
#define ICON_UNPOSITIONED_VALUE -1
61
/* Timeout for making the icon currently selected for keyboard operation visible.
62
* If this is 0, you can get into trouble with extra scrolling after holding
63
* down the arrow key for awhile when there are many items.
65
#define KEYBOARD_ICON_REVEAL_TIMEOUT 10
67
#define CONTEXT_MENU_TIMEOUT_INTERVAL 500
69
/* Maximum amount of milliseconds the mouse button is allowed to stay down
70
* and still be considered a click.
72
#define MAX_CLICK_TIME 1500
74
/* Button assignments. */
76
#define RUBBERBAND_BUTTON 1
77
#define MIDDLE_BUTTON 2
78
#define CONTEXTUAL_MENU_BUTTON 3
79
#define DRAG_MENU_BUTTON 2
81
/* Maximum size (pixels) allowed for icons at the standard zoom level. */
82
#define MINIMUM_IMAGE_SIZE 24
83
#define MAXIMUM_IMAGE_SIZE 96
85
#define ICON_PAD_LEFT 4
86
#define ICON_PAD_RIGHT 4
87
#define ICON_BASE_WIDTH 96
89
#define ICON_PAD_TOP 4
90
#define ICON_PAD_BOTTOM 4
92
#define CONTAINER_PAD_LEFT 4
93
#define CONTAINER_PAD_RIGHT 4
94
#define CONTAINER_PAD_TOP 4
95
#define CONTAINER_PAD_BOTTOM 4
97
#define STANDARD_ICON_GRID_WIDTH 155
99
#define TEXT_BESIDE_ICON_GRID_WIDTH 205
101
/* Desktop layout mode defines */
102
#define DESKTOP_PAD_HORIZONTAL 10
103
#define DESKTOP_PAD_VERTICAL 10
104
#define SNAP_SIZE_X 78
105
#define SNAP_SIZE_Y 20
107
#define MINIMUM_EMBEDDED_TEXT_RECT_WIDTH 20
108
#define MINIMUM_EMBEDDED_TEXT_RECT_HEIGHT 20
110
/* If icon size is bigger than this, request large embedded text.
111
* Its selected so that the non-large text should fit in "normal" icon sizes
113
#define ICON_SIZE_FOR_LARGE_EMBEDDED_TEXT 55
115
/* From nautilus-icon-canvas-item.c */
116
#define MAX_TEXT_WIDTH_BESIDE 90
118
#define SNAP_HORIZONTAL(func,x) ((func ((double)((x) - DESKTOP_PAD_HORIZONTAL) / SNAP_SIZE_X) * SNAP_SIZE_X) + DESKTOP_PAD_HORIZONTAL)
119
#define SNAP_VERTICAL(func, y) ((func ((double)((y) - DESKTOP_PAD_VERTICAL) / SNAP_SIZE_Y) * SNAP_SIZE_Y) + DESKTOP_PAD_VERTICAL)
121
#define SNAP_NEAREST_HORIZONTAL(x) SNAP_HORIZONTAL (eel_round, x)
122
#define SNAP_NEAREST_VERTICAL(y) SNAP_VERTICAL (eel_round, y)
124
#define SNAP_CEIL_HORIZONTAL(x) SNAP_HORIZONTAL (ceil, x)
125
#define SNAP_CEIL_VERTICAL(y) SNAP_VERTICAL (ceil, y)
127
/* Copied from NautilusIconContainer */
128
#define NAUTILUS_ICON_CONTAINER_SEARCH_DIALOG_TIMEOUT 5
130
/* Copied from NautilusFile */
131
#define UNDEFINED_TIME ((time_t) (-1))
141
char *action_descriptions[LAST_ACTION];
142
} NautilusIconContainerAccessiblePrivate;
144
static GType nautilus_icon_container_accessible_get_type (void);
146
static void preview_selected_items (NautilusIconContainer *container);
147
static void activate_selected_items (NautilusIconContainer *container);
148
static void activate_selected_items_alternate (NautilusIconContainer *container,
150
static void compute_stretch (StretchState *start,
151
StretchState *current);
152
static NautilusIcon *get_first_selected_icon (NautilusIconContainer *container);
153
static NautilusIcon *get_nth_selected_icon (NautilusIconContainer *container,
155
static gboolean has_multiple_selection (NautilusIconContainer *container);
156
static gboolean all_selected (NautilusIconContainer *container);
157
static gboolean has_selection (NautilusIconContainer *container);
158
static void icon_destroy (NautilusIconContainer *container,
160
static void end_renaming_mode (NautilusIconContainer *container,
162
static NautilusIcon *get_icon_being_renamed (NautilusIconContainer *container);
163
static void finish_adding_new_icons (NautilusIconContainer *container);
164
static inline void icon_get_bounding_box (NautilusIcon *icon,
169
NautilusIconCanvasItemBoundsUsage usage);
170
static gboolean is_renaming (NautilusIconContainer *container);
171
static gboolean is_renaming_pending (NautilusIconContainer *container);
172
static void process_pending_icon_to_rename (NautilusIconContainer *container);
173
static void nautilus_icon_container_stop_monitor_top_left (NautilusIconContainer *container,
174
NautilusIconData *data,
175
gconstpointer client);
176
static void nautilus_icon_container_start_monitor_top_left (NautilusIconContainer *container,
177
NautilusIconData *data,
178
gconstpointer client,
179
gboolean large_text);
180
static void handle_hadjustment_changed (GtkAdjustment *adjustment,
181
NautilusIconContainer *container);
182
static void handle_vadjustment_changed (GtkAdjustment *adjustment,
183
NautilusIconContainer *container);
184
static GList * nautilus_icon_container_get_selected_icons (NautilusIconContainer *container);
185
static void nautilus_icon_container_update_visible_icons (NautilusIconContainer *container);
186
static void reveal_icon (NautilusIconContainer *container,
189
static void nautilus_icon_container_set_rtl_positions (NautilusIconContainer *container);
190
static double get_mirror_x_position (NautilusIconContainer *container,
193
static void text_ellipsis_limit_changed_container_callback (gpointer callback_data);
195
static int compare_icons_horizontal (NautilusIconContainer *container,
196
NautilusIcon *icon_a,
197
NautilusIcon *icon_b);
199
static int compare_icons_vertical (NautilusIconContainer *container,
200
NautilusIcon *icon_a,
201
NautilusIcon *icon_b);
203
static void store_layout_timestamps_now (NautilusIconContainer *container);
204
static void remove_search_entry_timeout (NautilusIconContainer *container);
206
static gpointer accessible_parent_class;
208
static GQuark accessible_private_data_quark = 0;
210
static const char *nautilus_icon_container_accessible_action_names[] = {
216
static const char *nautilus_icon_container_accessible_action_descriptions[] = {
217
"Activate selected items",
218
"Popup context menu",
222
G_DEFINE_TYPE (NautilusIconContainer, nautilus_icon_container, EEL_TYPE_CANVAS);
224
/* The NautilusIconContainer signals. */
233
CONTEXT_CLICK_BACKGROUND,
234
CONTEXT_CLICK_SELECTION,
238
GET_ICON_DROP_TARGET_URI,
239
GET_STORED_ICON_POSITION,
240
ICON_POSITION_CHANGED,
241
GET_STORED_LAYOUT_TIMESTAMP,
242
STORE_LAYOUT_TIMESTAMP,
245
ICON_STRETCH_STARTED,
268
static guint signals[LAST_SIGNAL];
270
/* Functions dealing with NautilusIcons. */
273
icon_free (NautilusIcon *icon)
275
/* Destroy this canvas item; the parent will unref it. */
276
eel_canvas_item_destroy (EEL_CANVAS_ITEM (icon->item));
281
icon_is_positioned (const NautilusIcon *icon)
283
return icon->x != ICON_UNPOSITIONED_VALUE && icon->y != ICON_UNPOSITIONED_VALUE;
287
/* x, y are the top-left coordinates of the icon. */
289
icon_set_position (NautilusIcon *icon,
292
NautilusIconContainer *container;
293
double pixels_per_unit;
294
int container_left, container_top, container_right, container_bottom;
296
int container_x, container_y, container_width, container_height;
297
EelDRect icon_bounds;
298
int item_width, item_height;
299
int height_above, width_left;
300
int min_x, max_x, min_y, max_y;
302
if (icon->x == x && icon->y == y) {
306
container = NAUTILUS_ICON_CONTAINER (EEL_CANVAS_ITEM (icon->item)->canvas);
308
if (icon == get_icon_being_renamed (container)) {
309
end_renaming_mode (container, TRUE);
312
if (nautilus_icon_container_get_is_fixed_size (container)) {
313
/* FIXME: This should be:
315
container_x = GTK_WIDGET (container)->allocation.x;
316
container_y = GTK_WIDGET (container)->allocation.y;
317
container_width = GTK_WIDGET (container)->allocation.width;
318
container_height = GTK_WIDGET (container)->allocation.height;
320
But for some reason the widget allocation is sometimes not done
321
at startup, and the allocation is then only 45x60. which is
324
For now, we have a cheesy workaround:
328
container_width = gdk_screen_width () - container_x
329
- container->details->left_margin
330
- container->details->right_margin;
331
container_height = gdk_screen_height () - container_y
332
- container->details->top_margin
333
- container->details->bottom_margin;
334
pixels_per_unit = EEL_CANVAS (container)->pixels_per_unit;
335
/* Clip the position of the icon within our desktop bounds */
336
container_left = container_x / pixels_per_unit;
337
container_top = container_y / pixels_per_unit;
338
container_right = container_left + container_width / pixels_per_unit;
339
container_bottom = container_top + container_height / pixels_per_unit;
341
icon_get_bounding_box (icon, &x1, &y1, &x2, &y2,
342
BOUNDS_USAGE_FOR_ENTIRE_ITEM);
343
item_width = x2 - x1;
344
item_height = y2 - y1;
346
icon_bounds = nautilus_icon_canvas_item_get_icon_rectangle (icon->item);
348
/* determine icon rectangle relative to item rectangle */
349
height_above = icon_bounds.y0 - y1;
350
width_left = icon_bounds.x0 - x1;
352
min_x = container_left + DESKTOP_PAD_HORIZONTAL + width_left;
353
max_x = container_right - DESKTOP_PAD_HORIZONTAL - item_width + width_left;
354
x = CLAMP (x, min_x, max_x);
356
min_y = container_top + height_above + DESKTOP_PAD_VERTICAL;
357
max_y = container_bottom - DESKTOP_PAD_VERTICAL - item_height + height_above;
358
y = CLAMP (y, min_y, max_y);
361
if (icon->x == ICON_UNPOSITIONED_VALUE) {
364
if (icon->y == ICON_UNPOSITIONED_VALUE) {
368
eel_canvas_item_move (EEL_CANVAS_ITEM (icon->item),
377
icon_get_size (NautilusIconContainer *container,
382
*size = MAX (nautilus_get_icon_size_for_zoom_level (container->details->zoom_level)
383
* icon->scale, NAUTILUS_ICON_SIZE_SMALLEST);
387
/* The icon_set_size function is used by the stretching user
388
* interface, which currently stretches in a way that keeps the aspect
389
* ratio. Later we might have a stretching interface that stretches Y
390
* separate from X and we will change this around.
393
icon_set_size (NautilusIconContainer *container,
397
gboolean update_position)
402
icon_get_size (container, icon, &old_size);
403
if (icon_size == old_size) {
407
scale = (double) icon_size /
408
nautilus_get_icon_size_for_zoom_level
409
(container->details->zoom_level);
410
nautilus_icon_container_move_icon (container, icon,
413
snap, update_position);
417
icon_raise (NautilusIcon *icon)
419
EelCanvasItem *item, *band;
421
item = EEL_CANVAS_ITEM (icon->item);
422
band = NAUTILUS_ICON_CONTAINER (item->canvas)->details->rubberband_info.selection_rectangle;
424
eel_canvas_item_send_behind (item, band);
428
emit_stretch_started (NautilusIconContainer *container, NautilusIcon *icon)
430
g_signal_emit (container,
431
signals[ICON_STRETCH_STARTED], 0,
436
emit_stretch_ended (NautilusIconContainer *container, NautilusIcon *icon)
438
g_signal_emit (container,
439
signals[ICON_STRETCH_ENDED], 0,
444
icon_toggle_selected (NautilusIconContainer *container,
447
end_renaming_mode (container, TRUE);
449
icon->is_selected = !icon->is_selected;
450
eel_canvas_item_set (EEL_CANVAS_ITEM (icon->item),
451
"highlighted_for_selection", (gboolean) icon->is_selected,
454
/* If the icon is deselected, then get rid of the stretch handles.
455
* No harm in doing the same if the item is newly selected.
457
if (icon == container->details->stretch_icon) {
458
container->details->stretch_icon = NULL;
459
nautilus_icon_canvas_item_set_show_stretch_handles (icon->item, FALSE);
460
/* snap the icon if necessary */
461
if (container->details->keep_aligned) {
462
nautilus_icon_container_move_icon (container,
469
emit_stretch_ended (container, icon);
472
/* Raise each newly-selected icon to the front as it is selected. */
473
if (icon->is_selected) {
478
/* Select an icon. Return TRUE if selection has changed. */
480
icon_set_selected (NautilusIconContainer *container,
484
g_assert (select == FALSE || select == TRUE);
485
g_assert (icon->is_selected == FALSE || icon->is_selected == TRUE);
487
if (select == icon->is_selected) {
491
icon_toggle_selected (container, icon);
492
g_assert (select == icon->is_selected);
497
icon_get_bounding_box (NautilusIcon *icon,
498
int *x1_return, int *y1_return,
499
int *x2_return, int *y2_return,
500
NautilusIconCanvasItemBoundsUsage usage)
502
double x1, y1, x2, y2;
504
if (usage == BOUNDS_USAGE_FOR_DISPLAY) {
505
eel_canvas_item_get_bounds (EEL_CANVAS_ITEM (icon->item),
507
} else if (usage == BOUNDS_USAGE_FOR_LAYOUT) {
508
nautilus_icon_canvas_item_get_bounds_for_layout (icon->item,
510
} else if (usage == BOUNDS_USAGE_FOR_ENTIRE_ITEM) {
511
nautilus_icon_canvas_item_get_bounds_for_entire_item (icon->item,
514
g_assert_not_reached ();
517
if (x1_return != NULL) {
521
if (y1_return != NULL) {
525
if (x2_return != NULL) {
529
if (y2_return != NULL) {
534
/* Utility functions for NautilusIconContainer. */
537
nautilus_icon_container_scroll (NautilusIconContainer *container,
538
int delta_x, int delta_y)
540
GtkAdjustment *hadj, *vadj;
541
int old_h_value, old_v_value;
543
hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container));
544
vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container));
546
/* Store the old ajustment values so we can tell if we
547
* ended up actually scrolling. We may not have in a case
548
* where the resulting value got pinned to the adjustment
551
old_h_value = gtk_adjustment_get_value (hadj);
552
old_v_value = gtk_adjustment_get_value (vadj);
554
gtk_adjustment_set_value (hadj, gtk_adjustment_get_value (hadj) + delta_x);
555
gtk_adjustment_set_value (vadj, gtk_adjustment_get_value (vadj) + delta_y);
557
/* return TRUE if we did scroll */
558
return gtk_adjustment_get_value (hadj) != old_h_value || gtk_adjustment_get_value (vadj) != old_v_value;
562
pending_icon_to_reveal_destroy_callback (NautilusIconCanvasItem *item,
563
NautilusIconContainer *container)
565
g_assert (NAUTILUS_IS_ICON_CONTAINER (container));
566
g_assert (container->details->pending_icon_to_reveal != NULL);
567
g_assert (container->details->pending_icon_to_reveal->item == item);
569
container->details->pending_icon_to_reveal = NULL;
573
get_pending_icon_to_reveal (NautilusIconContainer *container)
575
return container->details->pending_icon_to_reveal;
579
set_pending_icon_to_reveal (NautilusIconContainer *container, NautilusIcon *icon)
581
NautilusIcon *old_icon;
583
old_icon = container->details->pending_icon_to_reveal;
585
if (icon == old_icon) {
589
if (old_icon != NULL) {
590
g_signal_handlers_disconnect_by_func
592
G_CALLBACK (pending_icon_to_reveal_destroy_callback),
597
g_signal_connect (icon->item, "destroy",
598
G_CALLBACK (pending_icon_to_reveal_destroy_callback),
602
container->details->pending_icon_to_reveal = icon;
606
item_get_canvas_bounds (EelCanvasItem *item,
612
eel_canvas_item_get_bounds (item,
617
eel_canvas_item_i2w (item->parent,
620
eel_canvas_item_i2w (item->parent,
624
world_rect.x0 -= ICON_PAD_LEFT + ICON_PAD_RIGHT;
625
world_rect.x1 += ICON_PAD_LEFT + ICON_PAD_RIGHT;
627
world_rect.y0 -= ICON_PAD_TOP + ICON_PAD_BOTTOM;
628
world_rect.y1 += ICON_PAD_TOP + ICON_PAD_BOTTOM;
631
eel_canvas_w2c (item->canvas,
636
eel_canvas_w2c (item->canvas,
644
icon_get_row_and_column_bounds (NautilusIconContainer *container,
650
NautilusIcon *one_icon;
653
item_get_canvas_bounds (EEL_CANVAS_ITEM (icon->item), bounds, safety_pad);
655
for (p = container->details->icons; p != NULL; p = p->next) {
658
if (icon == one_icon) {
662
if (compare_icons_horizontal (container, icon, one_icon) == 0) {
663
item_get_canvas_bounds (EEL_CANVAS_ITEM (one_icon->item), &one_bounds, safety_pad);
664
bounds->x0 = MIN (bounds->x0, one_bounds.x0);
665
bounds->x1 = MAX (bounds->x1, one_bounds.x1);
668
if (compare_icons_vertical (container, icon, one_icon) == 0) {
669
item_get_canvas_bounds (EEL_CANVAS_ITEM (one_icon->item), &one_bounds, safety_pad);
670
bounds->y0 = MIN (bounds->y0, one_bounds.y0);
671
bounds->y1 = MAX (bounds->y1, one_bounds.y1);
679
reveal_icon (NautilusIconContainer *container,
682
GtkAllocation allocation;
683
GtkAdjustment *hadj, *vadj;
686
if (!icon_is_positioned (icon)) {
687
set_pending_icon_to_reveal (container, icon);
691
set_pending_icon_to_reveal (container, NULL);
693
gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
695
hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container));
696
vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container));
698
if (nautilus_icon_container_is_auto_layout (container)) {
699
/* ensure that we reveal the entire row/column */
700
icon_get_row_and_column_bounds (container, icon, &bounds, TRUE);
702
item_get_canvas_bounds (EEL_CANVAS_ITEM (icon->item), &bounds, TRUE);
704
if (bounds.y0 < gtk_adjustment_get_value (vadj)) {
705
gtk_adjustment_set_value (vadj, bounds.y0);
706
} else if (bounds.y1 > gtk_adjustment_get_value (vadj) + allocation.height) {
707
gtk_adjustment_set_value
708
(vadj, bounds.y1 - allocation.height);
711
if (bounds.x0 < gtk_adjustment_get_value (hadj)) {
712
gtk_adjustment_set_value (hadj, bounds.x0);
713
} else if (bounds.x1 > gtk_adjustment_get_value (hadj) + allocation.width) {
714
gtk_adjustment_set_value
715
(hadj, bounds.x1 - allocation.width);
720
process_pending_icon_to_reveal (NautilusIconContainer *container)
722
NautilusIcon *pending_icon_to_reveal;
724
pending_icon_to_reveal = get_pending_icon_to_reveal (container);
726
if (pending_icon_to_reveal != NULL) {
727
reveal_icon (container, pending_icon_to_reveal);
732
keyboard_icon_reveal_timeout_callback (gpointer data)
734
NautilusIconContainer *container;
737
container = NAUTILUS_ICON_CONTAINER (data);
738
icon = container->details->keyboard_icon_to_reveal;
740
g_assert (icon != NULL);
742
/* Only reveal the icon if it's still the keyboard focus or if
743
* it's still selected. Someone originally thought we should
744
* cancel this reveal if the user manages to sneak a direct
745
* scroll in before the timeout fires, but we later realized
746
* this wouldn't actually be an improvement
747
* (see bugzilla.gnome.org 40612).
749
if (icon == container->details->keyboard_focus
750
|| icon->is_selected) {
751
reveal_icon (container, icon);
753
container->details->keyboard_icon_reveal_timer_id = 0;
759
unschedule_keyboard_icon_reveal (NautilusIconContainer *container)
761
NautilusIconContainerDetails *details;
763
details = container->details;
765
if (details->keyboard_icon_reveal_timer_id != 0) {
766
g_source_remove (details->keyboard_icon_reveal_timer_id);
771
schedule_keyboard_icon_reveal (NautilusIconContainer *container,
774
NautilusIconContainerDetails *details;
776
details = container->details;
778
unschedule_keyboard_icon_reveal (container);
780
details->keyboard_icon_to_reveal = icon;
781
details->keyboard_icon_reveal_timer_id
782
= g_timeout_add (KEYBOARD_ICON_REVEAL_TIMEOUT,
783
keyboard_icon_reveal_timeout_callback,
788
clear_keyboard_focus (NautilusIconContainer *container)
790
if (container->details->keyboard_focus != NULL) {
791
eel_canvas_item_set (EEL_CANVAS_ITEM (container->details->keyboard_focus->item),
792
"highlighted_as_keyboard_focus", 0,
796
container->details->keyboard_focus = NULL;
800
emit_atk_focus_tracker_notify (NautilusIcon *icon)
802
AtkObject *atk_object = atk_gobject_accessible_for_object (G_OBJECT (icon->item));
803
atk_focus_tracker_notify (atk_object);
806
/* Set @icon as the icon currently selected for keyboard operations. */
808
set_keyboard_focus (NautilusIconContainer *container,
811
g_assert (icon != NULL);
813
if (icon == container->details->keyboard_focus) {
817
clear_keyboard_focus (container);
819
container->details->keyboard_focus = icon;
821
eel_canvas_item_set (EEL_CANVAS_ITEM (container->details->keyboard_focus->item),
822
"highlighted_as_keyboard_focus", 1,
825
emit_atk_focus_tracker_notify (icon);
829
set_keyboard_rubberband_start (NautilusIconContainer *container,
832
container->details->keyboard_rubberband_start = icon;
836
clear_keyboard_rubberband_start (NautilusIconContainer *container)
838
container->details->keyboard_rubberband_start = NULL;
841
/* carbon-copy of eel_canvas_group_bounds(), but
842
* for NautilusIconContainerItems it returns the
843
* bounds for the “entire item”.
846
get_icon_bounds_for_canvas_bounds (EelCanvasGroup *group,
847
double *x1, double *y1,
848
double *x2, double *y2,
849
NautilusIconCanvasItemBoundsUsage usage)
851
EelCanvasItem *child;
853
double tx1, ty1, tx2, ty2;
854
double minx, miny, maxx, maxy;
857
/* Get the bounds of the first visible item */
859
child = NULL; /* Unnecessary but eliminates a warning. */
863
for (list = group->item_list; list; list = list->next) {
866
if (!NAUTILUS_IS_ICON_CANVAS_ITEM (child)) {
870
if (child->flags & EEL_CANVAS_ITEM_VISIBLE) {
872
if (!NAUTILUS_IS_ICON_CANVAS_ITEM (child) ||
873
usage == BOUNDS_USAGE_FOR_DISPLAY) {
874
eel_canvas_item_get_bounds (child, &minx, &miny, &maxx, &maxy);
875
} else if (usage == BOUNDS_USAGE_FOR_LAYOUT) {
876
nautilus_icon_canvas_item_get_bounds_for_layout (NAUTILUS_ICON_CANVAS_ITEM (child),
877
&minx, &miny, &maxx, &maxy);
878
} else if (usage == BOUNDS_USAGE_FOR_ENTIRE_ITEM) {
879
nautilus_icon_canvas_item_get_bounds_for_entire_item (NAUTILUS_ICON_CANVAS_ITEM (child),
880
&minx, &miny, &maxx, &maxy);
882
g_assert_not_reached ();
888
/* If there were no visible items, return an empty bounding box */
891
*x1 = *y1 = *x2 = *y2 = 0.0;
895
/* Now we can grow the bounds using the rest of the items */
899
for (; list; list = list->next) {
902
if (!NAUTILUS_IS_ICON_CANVAS_ITEM (child)) {
906
if (!(child->flags & EEL_CANVAS_ITEM_VISIBLE))
909
if (!NAUTILUS_IS_ICON_CANVAS_ITEM (child) ||
910
usage == BOUNDS_USAGE_FOR_DISPLAY) {
911
eel_canvas_item_get_bounds (child, &tx1, &ty1, &tx2, &ty2);
912
} else if (usage == BOUNDS_USAGE_FOR_LAYOUT) {
913
nautilus_icon_canvas_item_get_bounds_for_layout (NAUTILUS_ICON_CANVAS_ITEM (child),
914
&tx1, &ty1, &tx2, &ty2);
915
} else if (usage == BOUNDS_USAGE_FOR_ENTIRE_ITEM) {
916
nautilus_icon_canvas_item_get_bounds_for_entire_item (NAUTILUS_ICON_CANVAS_ITEM (child),
917
&tx1, &ty1, &tx2, &ty2);
919
g_assert_not_reached ();
935
/* Make the bounds be relative to our parent's coordinate system */
937
if (EEL_CANVAS_ITEM (group)->parent) {
962
get_all_icon_bounds (NautilusIconContainer *container,
963
double *x1, double *y1,
964
double *x2, double *y2,
965
NautilusIconCanvasItemBoundsUsage usage)
967
/* FIXME bugzilla.gnome.org 42477: Do we have to do something about the rubberband
968
* here? Any other non-icon items?
970
get_icon_bounds_for_canvas_bounds (EEL_CANVAS_GROUP (EEL_CANVAS (container)->root),
971
x1, y1, x2, y2, usage);
974
/* Don't preserve visible white space the next time the scroll region
975
* is recomputed when the container is not empty. */
977
nautilus_icon_container_reset_scroll_region (NautilusIconContainer *container)
979
container->details->reset_scroll_region_trigger = TRUE;
982
/* Set a new scroll region without eliminating any of the currently-visible area. */
984
canvas_set_scroll_region_include_visible_area (EelCanvas *canvas,
985
double x1, double y1,
986
double x2, double y2)
988
double old_x1, old_y1, old_x2, old_y2;
989
double old_scroll_x, old_scroll_y;
990
double height, width;
991
GtkAllocation allocation;
993
eel_canvas_get_scroll_region (canvas, &old_x1, &old_y1, &old_x2, &old_y2);
994
gtk_widget_get_allocation (GTK_WIDGET (canvas), &allocation);
996
width = (allocation.width) / canvas->pixels_per_unit;
997
height = (allocation.height) / canvas->pixels_per_unit;
999
old_scroll_x = gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas)));
1000
old_scroll_y = gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas)));
1002
x1 = MIN (x1, old_x1 + old_scroll_x);
1003
y1 = MIN (y1, old_y1 + old_scroll_y);
1004
x2 = MAX (x2, old_x1 + old_scroll_x + width);
1005
y2 = MAX (y2, old_y1 + old_scroll_y + height);
1007
eel_canvas_set_scroll_region
1008
(canvas, x1, y1, x2, y2);
1012
nautilus_icon_container_update_scroll_region (NautilusIconContainer *container)
1014
double x1, y1, x2, y2;
1015
double pixels_per_unit;
1016
GtkAdjustment *hadj, *vadj;
1017
float step_increment;
1018
gboolean reset_scroll_region;
1019
GtkAllocation allocation;
1021
pixels_per_unit = EEL_CANVAS (container)->pixels_per_unit;
1023
if (nautilus_icon_container_get_is_fixed_size (container)) {
1024
/* Set the scroll region to the size of the container allocation */
1025
gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
1026
eel_canvas_set_scroll_region
1027
(EEL_CANVAS (container),
1028
(double) - container->details->left_margin / pixels_per_unit,
1029
(double) - container->details->top_margin / pixels_per_unit,
1030
((double) (allocation.width - 1)
1031
- container->details->left_margin
1032
- container->details->right_margin)
1034
((double) (allocation.height - 1)
1035
- container->details->top_margin
1036
- container->details->bottom_margin)
1041
reset_scroll_region = container->details->reset_scroll_region_trigger
1042
|| nautilus_icon_container_is_empty (container)
1043
|| nautilus_icon_container_is_auto_layout (container);
1045
/* The trigger is only cleared when container is non-empty, so
1046
* callers can reliably reset the scroll region when an item
1047
* is added even if extraneous relayouts are called when the
1048
* window is still empty.
1050
if (!nautilus_icon_container_is_empty (container)) {
1051
container->details->reset_scroll_region_trigger = FALSE;
1054
get_all_icon_bounds (container, &x1, &y1, &x2, &y2, BOUNDS_USAGE_FOR_ENTIRE_ITEM);
1056
/* Add border at the "end"of the layout (i.e. after the icons), to
1057
* ensure we get some space when scrolled to the end.
1058
* For horizontal layouts, we add a bottom border.
1059
* Vertical layout is used by the compact view so the end
1060
* depends on the RTL setting.
1062
if (nautilus_icon_container_is_layout_vertical (container)) {
1063
if (nautilus_icon_container_is_layout_rtl (container)) {
1064
x1 -= ICON_PAD_LEFT + CONTAINER_PAD_LEFT;
1066
x2 += ICON_PAD_RIGHT + CONTAINER_PAD_RIGHT;
1069
y2 += ICON_PAD_BOTTOM + CONTAINER_PAD_BOTTOM;
1072
/* Auto-layout assumes a 0, 0 scroll origin and at least allocation->width.
1073
* Then we lay out to the right or to the left, so
1074
* x can be < 0 and > allocation */
1075
if (nautilus_icon_container_is_auto_layout (container)) {
1076
gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
1078
x2 = MAX (x2, allocation.width / pixels_per_unit);
1081
/* Otherwise we add the padding that is at the start of the
1083
if (nautilus_icon_container_is_layout_rtl (container)) {
1084
x2 += ICON_PAD_RIGHT + CONTAINER_PAD_RIGHT;
1086
x1 -= ICON_PAD_LEFT + CONTAINER_PAD_LEFT;
1088
y1 -= ICON_PAD_TOP + CONTAINER_PAD_TOP;
1097
if (reset_scroll_region) {
1098
eel_canvas_set_scroll_region
1099
(EEL_CANVAS (container),
1102
canvas_set_scroll_region_include_visible_area
1103
(EEL_CANVAS (container),
1107
hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container));
1108
vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container));
1110
/* Scroll by 1/4 icon each time you click. */
1111
step_increment = nautilus_get_icon_size_for_zoom_level
1112
(container->details->zoom_level) / 4;
1113
if (gtk_adjustment_get_step_increment (hadj) != step_increment) {
1114
gtk_adjustment_set_step_increment (hadj, step_increment);
1116
if (gtk_adjustment_get_step_increment (vadj) != step_increment) {
1117
gtk_adjustment_set_step_increment (vadj, step_increment);
1122
compare_icons (gconstpointer a, gconstpointer b, gpointer icon_container)
1124
NautilusIconContainerClass *klass;
1125
const NautilusIcon *icon_a, *icon_b;
1129
klass = NAUTILUS_ICON_CONTAINER_GET_CLASS (icon_container);
1131
return klass->compare_icons (icon_container, icon_a->data, icon_b->data);
1135
sort_icons (NautilusIconContainer *container,
1138
NautilusIconContainerClass *klass;
1140
klass = NAUTILUS_ICON_CONTAINER_GET_CLASS (container);
1141
g_assert (klass->compare_icons != NULL);
1143
*icons = g_list_sort_with_data (*icons, compare_icons, container);
1147
resort (NautilusIconContainer *container)
1149
sort_icons (container, &container->details->icons);
1154
get_grid_width (NautilusIconContainer *container)
1156
if (container->details->label_position == NAUTILUS_ICON_LABEL_POSITION_BESIDE) {
1157
return TEXT_BESIDE_ICON_GRID_WIDTH;
1159
return STANDARD_ICON_GRID_WIDTH;
1171
lay_down_one_line (NautilusIconContainer *container,
1177
gboolean whole_text)
1182
IconPositions *position;
1186
is_rtl = nautilus_icon_container_is_layout_rtl (container);
1188
/* Lay out the icons along the baseline. */
1191
for (p = line_start; p != line_end; p = p->next) {
1194
position = &g_array_index (positions, IconPositions, i++);
1196
if (container->details->label_position == NAUTILUS_ICON_LABEL_POSITION_BESIDE) {
1197
y_offset = (max_height - position->height) / 2;
1199
y_offset = position->y_offset;
1204
is_rtl ? get_mirror_x_position (container, icon, x + position->x_offset) : x + position->x_offset,
1206
nautilus_icon_canvas_item_set_entire_text (icon->item, whole_text);
1208
icon->saved_ltr_x = is_rtl ? get_mirror_x_position (container, icon, icon->x) : icon->x;
1210
x += position->width;
1215
lay_down_one_column (NautilusIconContainer *container,
1226
IconPositions *position;
1230
is_rtl = nautilus_icon_container_is_layout_rtl (container);
1232
/* Lay out the icons along the baseline. */
1235
for (p = line_start; p != line_end; p = p->next) {
1238
position = &g_array_index (positions, IconPositions, i++);
1242
is_rtl ? get_mirror_x_position (container, icon, x + position->x_offset) : x + position->x_offset,
1243
y + position->y_offset);
1245
icon->saved_ltr_x = is_rtl ? get_mirror_x_position (container, icon, icon->x) : icon->x;
1252
lay_down_icons_horizontal (NautilusIconContainer *container,
1256
GList *p, *line_start;
1258
double canvas_width, y;
1260
IconPositions *position;
1262
EelDRect icon_bounds;
1263
EelDRect text_bounds;
1264
double max_height_above, max_height_below;
1265
double height_above, height_below;
1268
double max_text_width, max_icon_width;
1271
GtkAllocation allocation;
1273
g_assert (NAUTILUS_IS_ICON_CONTAINER (container));
1275
if (icons == NULL) {
1279
positions = g_array_new (FALSE, FALSE, sizeof (IconPositions));
1280
gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
1282
/* Lay out icons a line at a time. */
1283
canvas_width = CANVAS_WIDTH(container, allocation);
1284
max_icon_width = max_text_width = 0.0;
1286
if (container->details->label_position == NAUTILUS_ICON_LABEL_POSITION_BESIDE) {
1287
/* Would it be worth caching these bounds for the next loop? */
1288
for (p = icons; p != NULL; p = p->next) {
1291
icon_bounds = nautilus_icon_canvas_item_get_icon_rectangle (icon->item);
1292
max_icon_width = MAX (max_icon_width, ceil (icon_bounds.x1 - icon_bounds.x0));
1294
text_bounds = nautilus_icon_canvas_item_get_text_rectangle (icon->item, TRUE);
1295
max_text_width = MAX (max_text_width, ceil (text_bounds.x1 - text_bounds.x0));
1298
grid_width = max_icon_width + max_text_width + ICON_PAD_LEFT + ICON_PAD_RIGHT;
1300
grid_width = STANDARD_ICON_GRID_WIDTH;
1303
line_width = container->details->label_position == NAUTILUS_ICON_LABEL_POSITION_BESIDE ? ICON_PAD_LEFT : 0;
1305
y = start_y + CONTAINER_PAD_TOP;
1308
max_height_above = 0;
1309
max_height_below = 0;
1310
for (p = icons; p != NULL; p = p->next) {
1313
/* Assume it's only one level hierarchy to avoid costly affine calculations */
1314
nautilus_icon_canvas_item_get_bounds_for_layout (icon->item,
1315
&bounds.x0, &bounds.y0,
1316
&bounds.x1, &bounds.y1);
1318
icon_bounds = nautilus_icon_canvas_item_get_icon_rectangle (icon->item);
1319
text_bounds = nautilus_icon_canvas_item_get_text_rectangle (icon->item, TRUE);
1321
icon_width = ceil ((bounds.x1 - bounds.x0)/grid_width) * grid_width;
1323
/* Calculate size above/below baseline */
1324
height_above = icon_bounds.y1 - bounds.y0;
1325
height_below = bounds.y1 - icon_bounds.y1;
1327
/* If this icon doesn't fit, it's time to lay out the line that's queued up. */
1328
if (line_start != p && line_width + icon_width >= canvas_width ) {
1329
if (container->details->label_position == NAUTILUS_ICON_LABEL_POSITION_BESIDE) {
1332
/* Advance to the baseline. */
1333
y += ICON_PAD_TOP + max_height_above;
1336
lay_down_one_line (container, line_start, p, y, max_height_above, positions, FALSE);
1338
if (container->details->label_position == NAUTILUS_ICON_LABEL_POSITION_BESIDE) {
1339
y += max_height_above + max_height_below + ICON_PAD_BOTTOM;
1341
/* Advance to next line. */
1342
y += max_height_below + ICON_PAD_BOTTOM;
1345
line_width = container->details->label_position == NAUTILUS_ICON_LABEL_POSITION_BESIDE ? ICON_PAD_LEFT : 0;
1349
max_height_above = height_above;
1350
max_height_below = height_below;
1352
if (height_above > max_height_above) {
1353
max_height_above = height_above;
1355
if (height_below > max_height_below) {
1356
max_height_below = height_below;
1360
g_array_set_size (positions, i + 1);
1361
position = &g_array_index (positions, IconPositions, i++);
1362
position->width = icon_width;
1363
position->height = icon_bounds.y1 - icon_bounds.y0;
1365
if (container->details->label_position == NAUTILUS_ICON_LABEL_POSITION_BESIDE) {
1366
position->x_offset = max_icon_width + ICON_PAD_LEFT + ICON_PAD_RIGHT - (icon_bounds.x1 - icon_bounds.x0);
1367
position->y_offset = 0;
1369
position->x_offset = (icon_width - (icon_bounds.x1 - icon_bounds.x0)) / 2;
1370
position->y_offset = icon_bounds.y0 - icon_bounds.y1;
1373
/* Add this icon. */
1374
line_width += icon_width;
1377
/* Lay down that last line of icons. */
1378
if (line_start != NULL) {
1379
if (container->details->label_position == NAUTILUS_ICON_LABEL_POSITION_BESIDE) {
1382
/* Advance to the baseline. */
1383
y += ICON_PAD_TOP + max_height_above;
1386
lay_down_one_line (container, line_start, NULL, y, max_height_above, positions, TRUE);
1388
/* Advance to next line. */
1389
y += max_height_below + ICON_PAD_BOTTOM;
1392
g_array_free (positions, TRUE);
1396
get_max_icon_dimensions (GList *icon_start,
1398
double *max_icon_width,
1399
double *max_icon_height,
1400
double *max_text_width,
1401
double *max_text_height,
1402
double *max_bounds_height)
1405
EelDRect icon_bounds;
1406
EelDRect text_bounds;
1410
*max_icon_width = *max_text_width = 0.0;
1411
*max_icon_height = *max_text_height = 0.0;
1412
*max_bounds_height = 0.0;
1414
/* Would it be worth caching these bounds for the next loop? */
1415
for (p = icon_start; p != icon_end; p = p->next) {
1418
icon_bounds = nautilus_icon_canvas_item_get_icon_rectangle (icon->item);
1419
*max_icon_width = MAX (*max_icon_width, ceil (icon_bounds.x1 - icon_bounds.x0));
1420
*max_icon_height = MAX (*max_icon_height, ceil (icon_bounds.y1 - icon_bounds.y0));
1422
text_bounds = nautilus_icon_canvas_item_get_text_rectangle (icon->item, TRUE);
1423
*max_text_width = MAX (*max_text_width, ceil (text_bounds.x1 - text_bounds.x0));
1424
*max_text_height = MAX (*max_text_height, ceil (text_bounds.y1 - text_bounds.y0));
1426
nautilus_icon_canvas_item_get_bounds_for_layout (icon->item,
1429
*max_bounds_height = MAX (*max_bounds_height, y2 - y1);
1433
/* column-wise layout. At the moment, this only works with label-beside-icon (used by "Compact View"). */
1435
lay_down_icons_vertical (NautilusIconContainer *container,
1439
GList *p, *line_start;
1441
double x, canvas_height;
1443
IconPositions *position;
1444
EelDRect icon_bounds;
1445
EelDRect text_bounds;
1446
GtkAllocation allocation;
1451
double max_height_with_borders;
1453
double max_width_in_column;
1455
double max_bounds_height;
1456
double max_bounds_height_with_borders;
1458
double max_text_width, max_icon_width;
1459
double max_text_height, max_icon_height;
1463
g_assert (NAUTILUS_IS_ICON_CONTAINER (container));
1464
g_assert (container->details->label_position == NAUTILUS_ICON_LABEL_POSITION_BESIDE);
1466
if (icons == NULL) {
1470
positions = g_array_new (FALSE, FALSE, sizeof (IconPositions));
1471
gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
1473
/* Lay out icons a column at a time. */
1474
canvas_height = CANVAS_HEIGHT(container, allocation);
1476
max_icon_width = max_text_width = 0.0;
1477
max_icon_height = max_text_height = 0.0;
1478
max_bounds_height = 0.0;
1480
get_max_icon_dimensions (icons, NULL,
1481
&max_icon_width, &max_icon_height,
1482
&max_text_width, &max_text_height,
1483
&max_bounds_height);
1485
max_width = max_icon_width + max_text_width;
1486
max_height = MAX (max_icon_height, max_text_height);
1487
max_height_with_borders = ICON_PAD_TOP + max_height;
1489
max_bounds_height_with_borders = ICON_PAD_TOP + max_bounds_height;
1491
line_height = ICON_PAD_TOP;
1496
max_width_in_column = 0.0;
1498
for (p = icons; p != NULL; p = p->next) {
1501
/* If this icon doesn't fit, it's time to lay out the column that's queued up. */
1503
/* We use the bounds height here, since for wrapping we also want to consider
1504
* overlapping emblems at the bottom. We may wrap a little bit too early since
1505
* the icon with the max. bounds height may actually not be in the last row, but
1506
* it is better than visual glitches
1508
if (line_start != p && line_height + (max_bounds_height_with_borders-1) >= canvas_height ) {
1511
/* correctly set (per-column) width */
1512
if (!container->details->all_columns_same_width) {
1513
for (i = 0; i < (int) positions->len; i++) {
1514
position = &g_array_index (positions, IconPositions, i);
1515
position->width = max_width_in_column;
1519
lay_down_one_column (container, line_start, p, x, CONTAINER_PAD_TOP, max_height_with_borders, positions);
1521
/* Advance to next column. */
1522
if (container->details->all_columns_same_width) {
1523
x += max_width + ICON_PAD_RIGHT;
1525
x += max_width_in_column + ICON_PAD_RIGHT;
1528
line_height = ICON_PAD_TOP;
1532
max_width_in_column = 0;
1535
icon_bounds = nautilus_icon_canvas_item_get_icon_rectangle (icon->item);
1536
text_bounds = nautilus_icon_canvas_item_get_text_rectangle (icon->item, TRUE);
1538
max_width_in_column = MAX (max_width_in_column,
1539
ceil (icon_bounds.x1 - icon_bounds.x0) +
1540
ceil (text_bounds.x1 - text_bounds.x0));
1542
g_array_set_size (positions, i + 1);
1543
position = &g_array_index (positions, IconPositions, i++);
1544
if (container->details->all_columns_same_width) {
1545
position->width = max_width;
1547
position->height = max_height;
1548
position->y_offset = ICON_PAD_TOP;
1549
position->x_offset = ICON_PAD_LEFT;
1551
position->x_offset += max_icon_width - ceil (icon_bounds.x1 - icon_bounds.x0);
1553
height = MAX (ceil (icon_bounds.y1 - icon_bounds.y0), ceil(text_bounds.y1 - text_bounds.y0));
1554
position->y_offset += (max_height - height) / 2;
1556
/* Add this icon. */
1557
line_height += max_height_with_borders;
1560
/* Lay down that last column of icons. */
1561
if (line_start != NULL) {
1563
lay_down_one_column (container, line_start, NULL, x, CONTAINER_PAD_TOP, max_height_with_borders, positions);
1566
g_array_free (positions, TRUE);
1570
snap_position (NautilusIconContainer *container,
1580
EelDRect icon_position;
1581
GtkAllocation allocation;
1583
icon_position = nautilus_icon_canvas_item_get_icon_rectangle (icon->item);
1584
icon_width = icon_position.x1 - icon_position.x0;
1585
icon_height = icon_position.y1 - icon_position.y0;
1587
gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
1588
total_width = CANVAS_WIDTH (container, allocation);
1589
total_height = CANVAS_HEIGHT (container, allocation);
1591
if (nautilus_icon_container_is_layout_rtl (container))
1592
*x = get_mirror_x_position (container, icon, *x);
1594
if (*x + icon_width / 2 < DESKTOP_PAD_HORIZONTAL + SNAP_SIZE_X) {
1595
*x = DESKTOP_PAD_HORIZONTAL + SNAP_SIZE_X - icon_width / 2;
1598
if (*x + icon_width / 2 > total_width - (DESKTOP_PAD_HORIZONTAL + SNAP_SIZE_X)) {
1599
*x = total_width - (DESKTOP_PAD_HORIZONTAL + SNAP_SIZE_X + (icon_width / 2));
1602
if (*y + icon_height < DESKTOP_PAD_VERTICAL + SNAP_SIZE_Y) {
1603
*y = DESKTOP_PAD_VERTICAL + SNAP_SIZE_Y - icon_height;
1606
if (*y + icon_height > total_height - (DESKTOP_PAD_VERTICAL + SNAP_SIZE_Y)) {
1607
*y = total_height - (DESKTOP_PAD_VERTICAL + SNAP_SIZE_Y + (icon_height / 2));
1610
center_x = *x + icon_width / 2;
1611
*x = SNAP_NEAREST_HORIZONTAL (center_x) - (icon_width / 2);
1612
if (nautilus_icon_container_is_layout_rtl (container)) {
1613
*x = get_mirror_x_position (container, icon, *x);
1617
/* Find the grid position vertically and place on the proper baseline */
1618
baseline_y = *y + icon_height;
1619
baseline_y = SNAP_NEAREST_VERTICAL (baseline_y);
1620
*y = baseline_y - icon_height;
1624
compare_icons_by_position (gconstpointer a, gconstpointer b)
1626
NautilusIcon *icon_a, *icon_b;
1631
icon_a = (NautilusIcon*)a;
1632
icon_b = (NautilusIcon*)b;
1634
icon_get_bounding_box (icon_a, &x1, &y1, &x2, &y2,
1635
BOUNDS_USAGE_FOR_DISPLAY);
1636
center_a = x1 + (x2 - x1) / 2;
1637
icon_get_bounding_box (icon_b, &x1, &y1, &x2, &y2,
1638
BOUNDS_USAGE_FOR_DISPLAY);
1639
center_b = x1 + (x2 - x1) / 2;
1641
return center_a == center_b ?
1642
icon_a->y - icon_b->y :
1643
center_a - center_b;
1646
static PlacementGrid *
1647
placement_grid_new (NautilusIconContainer *container, gboolean tight)
1649
PlacementGrid *grid;
1654
GtkAllocation allocation;
1656
/* Get container dimensions */
1657
gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
1658
width = CANVAS_WIDTH(container, allocation);
1659
height = CANVAS_HEIGHT(container, allocation);
1661
num_columns = width / SNAP_SIZE_X;
1662
num_rows = height / SNAP_SIZE_Y;
1664
if (num_columns == 0 || num_rows == 0) {
1668
grid = g_new0 (PlacementGrid, 1);
1669
grid->tight = tight;
1670
grid->num_columns = num_columns;
1671
grid->num_rows = num_rows;
1673
grid->grid_memory = g_new0 (int, (num_rows * num_columns));
1674
grid->icon_grid = g_new0 (int *, num_columns);
1676
for (i = 0; i < num_columns; i++) {
1677
grid->icon_grid[i] = grid->grid_memory + (i * num_rows);
1684
placement_grid_free (PlacementGrid *grid)
1686
g_free (grid->icon_grid);
1687
g_free (grid->grid_memory);
1692
placement_grid_position_is_free (PlacementGrid *grid, EelIRect pos)
1696
g_assert (pos.x0 >= 0 && pos.x0 < grid->num_columns);
1697
g_assert (pos.y0 >= 0 && pos.y0 < grid->num_rows);
1698
g_assert (pos.x1 >= 0 && pos.x1 < grid->num_columns);
1699
g_assert (pos.y1 >= 0 && pos.y1 < grid->num_rows);
1701
for (x = pos.x0; x <= pos.x1; x++) {
1702
for (y = pos.y0; y <= pos.y1; y++) {
1703
if (grid->icon_grid[x][y] != 0) {
1713
placement_grid_mark (PlacementGrid *grid, EelIRect pos)
1717
g_assert (pos.x0 >= 0 && pos.x0 < grid->num_columns);
1718
g_assert (pos.y0 >= 0 && pos.y0 < grid->num_rows);
1719
g_assert (pos.x1 >= 0 && pos.x1 < grid->num_columns);
1720
g_assert (pos.y1 >= 0 && pos.y1 < grid->num_rows);
1722
for (x = pos.x0; x <= pos.x1; x++) {
1723
for (y = pos.y0; y <= pos.y1; y++) {
1724
grid->icon_grid[x][y] = 1;
1730
canvas_position_to_grid_position (PlacementGrid *grid,
1731
EelIRect canvas_position,
1732
EelIRect *grid_position)
1734
/* The first causes minimal moving around during a snap, but
1735
* can end up with partially overlapping icons. The second one won't
1736
* allow any overlapping, but can cause more movement to happen
1739
grid_position->x0 = ceil ((double)(canvas_position.x0 - DESKTOP_PAD_HORIZONTAL) / SNAP_SIZE_X);
1740
grid_position->y0 = ceil ((double)(canvas_position.y0 - DESKTOP_PAD_VERTICAL) / SNAP_SIZE_Y);
1741
grid_position->x1 = floor ((double)(canvas_position.x1 - DESKTOP_PAD_HORIZONTAL) / SNAP_SIZE_X);
1742
grid_position->y1 = floor ((double)(canvas_position.y1 - DESKTOP_PAD_VERTICAL) / SNAP_SIZE_Y);
1744
grid_position->x0 = floor ((double)(canvas_position.x0 - DESKTOP_PAD_HORIZONTAL) / SNAP_SIZE_X);
1745
grid_position->y0 = floor ((double)(canvas_position.y0 - DESKTOP_PAD_VERTICAL) / SNAP_SIZE_Y);
1746
grid_position->x1 = floor ((double)(canvas_position.x1 - DESKTOP_PAD_HORIZONTAL) / SNAP_SIZE_X);
1747
grid_position->y1 = floor ((double)(canvas_position.y1 - DESKTOP_PAD_VERTICAL) / SNAP_SIZE_Y);
1750
grid_position->x0 = CLAMP (grid_position->x0, 0, grid->num_columns - 1);
1751
grid_position->y0 = CLAMP (grid_position->y0, 0, grid->num_rows - 1);
1752
grid_position->x1 = CLAMP (grid_position->x1, grid_position->x0, grid->num_columns - 1);
1753
grid_position->y1 = CLAMP (grid_position->y1, grid_position->y0, grid->num_rows - 1);
1757
placement_grid_mark_icon (PlacementGrid *grid, NautilusIcon *icon)
1762
icon_get_bounding_box (icon,
1763
&icon_pos.x0, &icon_pos.y0,
1764
&icon_pos.x1, &icon_pos.y1,
1765
BOUNDS_USAGE_FOR_LAYOUT);
1766
canvas_position_to_grid_position (grid,
1769
placement_grid_mark (grid, grid_pos);
1773
find_empty_location (NautilusIconContainer *container,
1774
PlacementGrid *grid,
1781
double icon_width, icon_height;
1784
int height_for_bound_check;
1785
EelIRect icon_position;
1786
EelDRect pixbuf_rect;
1788
GtkAllocation allocation;
1790
/* Get container dimensions */
1791
gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
1792
canvas_width = CANVAS_WIDTH(container, allocation);
1793
canvas_height = CANVAS_HEIGHT(container, allocation);
1795
icon_get_bounding_box (icon,
1796
&icon_position.x0, &icon_position.y0,
1797
&icon_position.x1, &icon_position.y1,
1798
BOUNDS_USAGE_FOR_LAYOUT);
1799
icon_width = icon_position.x1 - icon_position.x0;
1800
icon_height = icon_position.y1 - icon_position.y0;
1802
icon_get_bounding_box (icon,
1803
NULL, &icon_position.y0,
1804
NULL, &icon_position.y1,
1805
BOUNDS_USAGE_FOR_ENTIRE_ITEM);
1806
height_for_bound_check = icon_position.y1 - icon_position.y0;
1808
pixbuf_rect = nautilus_icon_canvas_item_get_icon_rectangle (icon->item);
1810
/* Start the icon on a grid location */
1811
snap_position (container, icon, &start_x, &start_y);
1813
icon_position.x0 = start_x;
1814
icon_position.y0 = start_y;
1815
icon_position.x1 = icon_position.x0 + icon_width;
1816
icon_position.y1 = icon_position.y0 + icon_height;
1819
EelIRect grid_position;
1820
gboolean need_new_column;
1824
canvas_position_to_grid_position (grid,
1828
need_new_column = icon_position.y0 + height_for_bound_check + DESKTOP_PAD_VERTICAL > canvas_height;
1830
if (need_new_column ||
1831
!placement_grid_position_is_free (grid, grid_position)) {
1832
icon_position.y0 += SNAP_SIZE_Y;
1833
icon_position.y1 = icon_position.y0 + icon_height;
1835
if (need_new_column) {
1836
/* Move to the next column */
1837
icon_position.y0 = DESKTOP_PAD_VERTICAL + SNAP_SIZE_Y - (pixbuf_rect.y1 - pixbuf_rect.y0);
1838
while (icon_position.y0 < DESKTOP_PAD_VERTICAL) {
1839
icon_position.y0 += SNAP_SIZE_Y;
1841
icon_position.y1 = icon_position.y0 + icon_height;
1843
icon_position.x0 += SNAP_SIZE_X;
1844
icon_position.x1 = icon_position.x0 + icon_width;
1849
} while (collision && (icon_position.x1 < canvas_width));
1851
*x = icon_position.x0;
1852
*y = icon_position.y0;
1856
align_icons (NautilusIconContainer *container)
1858
GList *unplaced_icons;
1860
PlacementGrid *grid;
1862
unplaced_icons = g_list_copy (container->details->icons);
1864
unplaced_icons = g_list_sort (unplaced_icons,
1865
compare_icons_by_position);
1867
if (nautilus_icon_container_is_layout_rtl (container)) {
1868
unplaced_icons = g_list_reverse (unplaced_icons);
1871
grid = placement_grid_new (container, TRUE);
1877
for (l = unplaced_icons; l != NULL; l = l->next) {
1882
x = icon->saved_ltr_x;
1884
find_empty_location (container, grid,
1885
icon, x, y, &x, &y);
1887
icon_set_position (icon, x, y);
1888
icon->saved_ltr_x = icon->x;
1889
placement_grid_mark_icon (grid, icon);
1892
g_list_free (unplaced_icons);
1894
placement_grid_free (grid);
1896
if (nautilus_icon_container_is_layout_rtl (container)) {
1897
nautilus_icon_container_set_rtl_positions (container);
1902
get_mirror_x_position (NautilusIconContainer *container, NautilusIcon *icon, double x)
1904
EelDRect icon_bounds;
1905
GtkAllocation allocation;
1907
gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
1908
icon_bounds = nautilus_icon_canvas_item_get_icon_rectangle (icon->item);
1910
return CANVAS_WIDTH(container, allocation) - x - (icon_bounds.x1 - icon_bounds.x0);
1914
nautilus_icon_container_set_rtl_positions (NautilusIconContainer *container)
1920
if (!container->details->icons) {
1924
for (l = container->details->icons; l != NULL; l = l->next) {
1926
x = get_mirror_x_position (container, icon, icon->saved_ltr_x);
1927
icon_set_position (icon, x, icon->y);
1932
lay_down_icons_vertical_desktop (NautilusIconContainer *container, GList *icons)
1934
GList *p, *placed_icons, *unplaced_icons;
1935
int total, new_length, placed;
1937
int height, max_width, column_width, icon_width, icon_height;
1938
int x, y, x1, x2, y1, y2;
1940
GtkAllocation allocation;
1942
/* Get container dimensions */
1943
gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
1944
height = CANVAS_HEIGHT(container, allocation);
1946
/* Determine which icons have and have not been placed */
1947
placed_icons = NULL;
1948
unplaced_icons = NULL;
1950
total = g_list_length (container->details->icons);
1951
new_length = g_list_length (icons);
1952
placed = total - new_length;
1954
PlacementGrid *grid;
1955
/* Add only placed icons in list */
1956
for (p = container->details->icons; p != NULL; p = p->next) {
1958
if (icon_is_positioned (icon)) {
1959
icon_set_position(icon, icon->saved_ltr_x, icon->y);
1960
placed_icons = g_list_prepend (placed_icons, icon);
1964
unplaced_icons = g_list_prepend (unplaced_icons, icon);
1967
placed_icons = g_list_reverse (placed_icons);
1968
unplaced_icons = g_list_reverse (unplaced_icons);
1970
grid = placement_grid_new (container, FALSE);
1973
for (p = placed_icons; p != NULL; p = p->next) {
1974
placement_grid_mark_icon
1975
(grid, (NautilusIcon*)p->data);
1978
/* Place unplaced icons in the best locations */
1979
for (p = unplaced_icons; p != NULL; p = p->next) {
1982
icon_rect = nautilus_icon_canvas_item_get_icon_rectangle (icon->item);
1984
/* Start the icon in the first column */
1985
x = DESKTOP_PAD_HORIZONTAL + (SNAP_SIZE_X / 2) - ((icon_rect.x1 - icon_rect.x0) / 2);
1986
y = DESKTOP_PAD_VERTICAL + SNAP_SIZE_Y - (icon_rect.y1 - icon_rect.y0);
1988
find_empty_location (container,
1994
icon_set_position (icon, x, y);
1995
icon->saved_ltr_x = x;
1996
placement_grid_mark_icon (grid, icon);
1999
placement_grid_free (grid);
2002
g_list_free (placed_icons);
2003
g_list_free (unplaced_icons);
2005
/* There are no placed icons. Just lay them down using our rules */
2006
x = DESKTOP_PAD_HORIZONTAL;
2008
while (icons != NULL) {
2011
int icon_height_for_bound_check;
2012
gboolean should_snap;
2014
should_snap = container->details->keep_aligned;
2016
y = DESKTOP_PAD_VERTICAL;
2020
/* Calculate max width for column */
2021
for (p = icons; p != NULL; p = p->next) {
2024
icon_get_bounding_box (icon, &x1, &y1, &x2, &y2,
2025
BOUNDS_USAGE_FOR_LAYOUT);
2026
icon_width = x2 - x1;
2027
icon_height = y2 - y1;
2029
icon_get_bounding_box (icon, NULL, &y1, NULL, &y2,
2030
BOUNDS_USAGE_FOR_ENTIRE_ITEM);
2031
icon_height_for_bound_check = y2 - y1;
2034
/* Snap the baseline to a grid position */
2035
icon_rect = nautilus_icon_canvas_item_get_icon_rectangle (icon->item);
2036
baseline = y + (icon_rect.y1 - icon_rect.y0);
2037
baseline = SNAP_CEIL_VERTICAL (baseline);
2038
y = baseline - (icon_rect.y1 - icon_rect.y0);
2041
/* Check and see if we need to move to a new column */
2042
if (y != DESKTOP_PAD_VERTICAL && y + icon_height_for_bound_check > height) {
2046
if (max_width < icon_width) {
2047
max_width = icon_width;
2050
y += icon_height + DESKTOP_PAD_VERTICAL;
2053
y = DESKTOP_PAD_VERTICAL;
2055
center_x = x + max_width / 2;
2056
column_width = max_width;
2058
/* Find the grid column to center on */
2059
center_x = SNAP_CEIL_HORIZONTAL (center_x);
2060
column_width = (center_x - x) + (max_width / 2);
2063
/* Lay out column */
2064
for (p = icons; p != NULL; p = p->next) {
2066
icon_get_bounding_box (icon, &x1, &y1, &x2, &y2,
2067
BOUNDS_USAGE_FOR_LAYOUT);
2068
icon_height = y2 - y1;
2070
icon_get_bounding_box (icon, NULL, &y1, NULL, &y2,
2071
BOUNDS_USAGE_FOR_ENTIRE_ITEM);
2072
icon_height_for_bound_check = y2 - y1;
2074
icon_rect = nautilus_icon_canvas_item_get_icon_rectangle (icon->item);
2077
baseline = y + (icon_rect.y1 - icon_rect.y0);
2078
baseline = SNAP_CEIL_VERTICAL (baseline);
2079
y = baseline - (icon_rect.y1 - icon_rect.y0);
2082
/* Check and see if we need to move to a new column */
2083
if (y != DESKTOP_PAD_VERTICAL && y > height - icon_height_for_bound_check &&
2084
/* Make sure we lay out at least one icon per column, to make progress */
2086
x += column_width + DESKTOP_PAD_HORIZONTAL;
2090
icon_set_position (icon,
2091
center_x - (icon_rect.x1 - icon_rect.x0) / 2,
2094
icon->saved_ltr_x = icon->x;
2095
y += icon_height + DESKTOP_PAD_VERTICAL;
2101
/* These modes are special. We freeze all of our positions
2102
* after we do the layout.
2104
/* FIXME bugzilla.gnome.org 42478:
2105
* This should not be tied to the direction of layout.
2106
* It should be a separate switch.
2108
nautilus_icon_container_freeze_icon_positions (container);
2113
lay_down_icons (NautilusIconContainer *container, GList *icons, double start_y)
2115
switch (container->details->layout_mode)
2117
case NAUTILUS_ICON_LAYOUT_L_R_T_B:
2118
case NAUTILUS_ICON_LAYOUT_R_L_T_B:
2119
lay_down_icons_horizontal (container, icons, start_y);
2122
case NAUTILUS_ICON_LAYOUT_T_B_L_R:
2123
case NAUTILUS_ICON_LAYOUT_T_B_R_L:
2124
if (nautilus_icon_container_get_is_desktop (container)) {
2125
lay_down_icons_vertical_desktop (container, icons);
2127
lay_down_icons_vertical (container, icons, start_y);
2132
g_assert_not_reached ();
2137
redo_layout_internal (NautilusIconContainer *container)
2139
finish_adding_new_icons (container);
2141
/* Don't do any re-laying-out during stretching. Later we
2142
* might add smart logic that does this and leaves room for
2143
* the stretched icon, but if we do it we want it to be fast
2144
* and only re-lay-out when it's really needed.
2146
if (container->details->auto_layout
2147
&& container->details->drag_state != DRAG_STATE_STRETCH) {
2148
if (container->details->needs_resort) {
2150
container->details->needs_resort = FALSE;
2152
lay_down_icons (container, container->details->icons, 0);
2155
if (nautilus_icon_container_is_layout_rtl (container)) {
2156
nautilus_icon_container_set_rtl_positions (container);
2159
nautilus_icon_container_update_scroll_region (container);
2161
process_pending_icon_to_reveal (container);
2162
process_pending_icon_to_rename (container);
2163
nautilus_icon_container_update_visible_icons (container);
2167
redo_layout_callback (gpointer callback_data)
2169
NautilusIconContainer *container;
2171
container = NAUTILUS_ICON_CONTAINER (callback_data);
2172
redo_layout_internal (container);
2173
container->details->idle_id = 0;
2179
unschedule_redo_layout (NautilusIconContainer *container)
2181
if (container->details->idle_id != 0) {
2182
g_source_remove (container->details->idle_id);
2183
container->details->idle_id = 0;
2188
schedule_redo_layout (NautilusIconContainer *container)
2190
if (container->details->idle_id == 0
2191
&& container->details->has_been_allocated) {
2192
container->details->idle_id = g_idle_add
2193
(redo_layout_callback, container);
2198
redo_layout (NautilusIconContainer *container)
2200
unschedule_redo_layout (container);
2201
redo_layout_internal (container);
2205
reload_icon_positions (NautilusIconContainer *container)
2207
GList *p, *no_position_icons;
2209
gboolean have_stored_position;
2210
NautilusIconPosition position;
2213
EelCanvasItem *item;
2215
g_assert (!container->details->auto_layout);
2219
no_position_icons = NULL;
2221
/* Place all the icons with positions. */
2223
for (p = container->details->icons; p != NULL; p = p->next) {
2226
have_stored_position = FALSE;
2227
g_signal_emit (container,
2228
signals[GET_STORED_ICON_POSITION], 0,
2231
&have_stored_position);
2232
if (have_stored_position) {
2233
icon_set_position (icon, position.x, position.y);
2234
item = EEL_CANVAS_ITEM (icon->item);
2235
nautilus_icon_canvas_item_get_bounds_for_layout (icon->item,
2240
eel_canvas_item_i2w (item->parent,
2243
eel_canvas_item_i2w (item->parent,
2246
if (bounds.y1 > bottom) {
2250
no_position_icons = g_list_prepend (no_position_icons, icon);
2253
no_position_icons = g_list_reverse (no_position_icons);
2255
/* Place all the other icons. */
2256
lay_down_icons (container, no_position_icons, bottom + ICON_PAD_BOTTOM);
2257
g_list_free (no_position_icons);
2260
/* Container-level icon handling functions. */
2263
button_event_modifies_selection (GdkEventButton *event)
2265
return (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) != 0;
2268
/* invalidate the cached label sizes for all the icons */
2270
invalidate_label_sizes (NautilusIconContainer *container)
2275
for (p = container->details->icons; p != NULL; p = p->next) {
2278
nautilus_icon_canvas_item_invalidate_label_size (icon->item);
2282
/* invalidate the entire labels (i.e. their attributes) for all the icons */
2284
invalidate_labels (NautilusIconContainer *container)
2289
for (p = container->details->icons; p != NULL; p = p->next) {
2292
nautilus_icon_canvas_item_invalidate_label (icon->item);
2297
select_range (NautilusIconContainer *container,
2298
NautilusIcon *icon1,
2299
NautilusIcon *icon2,
2300
gboolean unselect_outside_range)
2302
gboolean selection_changed;
2305
NautilusIcon *unmatched_icon;
2308
selection_changed = FALSE;
2310
unmatched_icon = NULL;
2312
for (p = container->details->icons; p != NULL; p = p->next) {
2315
if (unmatched_icon == NULL) {
2316
if (icon == icon1) {
2317
unmatched_icon = icon2;
2319
} else if (icon == icon2) {
2320
unmatched_icon = icon1;
2325
if (select || unselect_outside_range) {
2326
selection_changed |= icon_set_selected
2327
(container, icon, select);
2330
if (unmatched_icon != NULL && icon == unmatched_icon) {
2336
if (selection_changed && icon2 != NULL) {
2337
emit_atk_focus_tracker_notify (icon2);
2339
return selection_changed;
2344
select_one_unselect_others (NautilusIconContainer *container,
2345
NautilusIcon *icon_to_select)
2347
gboolean selection_changed;
2351
selection_changed = FALSE;
2353
for (p = container->details->icons; p != NULL; p = p->next) {
2356
selection_changed |= icon_set_selected
2357
(container, icon, icon == icon_to_select);
2360
if (selection_changed && icon_to_select != NULL) {
2361
emit_atk_focus_tracker_notify (icon_to_select);
2362
reveal_icon (container, icon_to_select);
2364
return selection_changed;
2368
unselect_all (NautilusIconContainer *container)
2370
return select_one_unselect_others (container, NULL);
2374
nautilus_icon_container_move_icon (NautilusIconContainer *container,
2380
gboolean update_position)
2382
NautilusIconContainerDetails *details;
2383
gboolean emit_signal;
2384
NautilusIconPosition position;
2386
details = container->details;
2388
emit_signal = FALSE;
2390
if (icon == get_icon_being_renamed (container)) {
2391
end_renaming_mode (container, TRUE);
2394
if (scale != icon->scale) {
2395
icon->scale = scale;
2396
nautilus_icon_container_update_icon (container, icon);
2397
if (update_position) {
2398
redo_layout (container);
2403
if (!details->auto_layout) {
2404
if (details->keep_aligned && snap) {
2405
snap_position (container, icon, &x, &y);
2408
if (x != icon->x || y != icon->y) {
2409
icon_set_position (icon, x, y);
2410
emit_signal = update_position;
2413
icon->saved_ltr_x = nautilus_icon_container_is_layout_rtl (container) ? get_mirror_x_position (container, icon, icon->x) : icon->x;
2417
position.x = icon->saved_ltr_x;
2418
position.y = icon->y;
2419
position.scale = scale;
2420
g_signal_emit (container,
2421
signals[ICON_POSITION_CHANGED], 0,
2422
icon->data, &position);
2429
/* FIXME bugzilla.gnome.org 42474:
2430
* Handling of the scroll region is inconsistent here. In
2431
* the scale-changing case, redo_layout is called, which updates the
2432
* scroll region appropriately. In other cases, it's up to the
2433
* caller to make sure the scroll region is updated. This could
2434
* lead to hard-to-track-down bugs.
2438
/* Implementation of rubberband selection. */
2440
rubberband_select (NautilusIconContainer *container,
2441
const EelDRect *previous_rect,
2442
const EelDRect *current_rect)
2445
gboolean selection_changed, is_in, canvas_rect_calculated;
2447
EelIRect canvas_rect;
2450
selection_changed = FALSE;
2451
canvas_rect_calculated = FALSE;
2453
for (p = container->details->icons; p != NULL; p = p->next) {
2456
if (!canvas_rect_calculated) {
2457
/* Only do this calculation once, since all the canvas items
2458
* we are interating are in the same coordinate space
2460
canvas = EEL_CANVAS_ITEM (icon->item)->canvas;
2461
eel_canvas_w2c (canvas,
2466
eel_canvas_w2c (canvas,
2471
canvas_rect_calculated = TRUE;
2474
is_in = nautilus_icon_canvas_item_hit_test_rectangle (icon->item, canvas_rect);
2476
selection_changed |= icon_set_selected
2478
is_in ^ icon->was_selected_before_rubberband);
2481
if (selection_changed) {
2482
g_signal_emit (container,
2483
signals[SELECTION_CHANGED], 0);
2488
rubberband_timeout_callback (gpointer data)
2490
NautilusIconContainer *container;
2492
NautilusIconRubberbandInfo *band_info;
2494
double x1, y1, x2, y2;
2495
double world_x, world_y;
2496
int x_scroll, y_scroll;
2498
gboolean adj_changed;
2499
GtkAllocation allocation;
2501
EelDRect selection_rect;
2503
widget = GTK_WIDGET (data);
2504
container = NAUTILUS_ICON_CONTAINER (data);
2505
band_info = &container->details->rubberband_info;
2507
g_assert (band_info->timer_id != 0);
2509
adj_changed = FALSE;
2510
gtk_widget_get_allocation (widget, &allocation);
2512
adj_x = gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container)));
2513
if (adj_x != band_info->last_adj_x) {
2514
band_info->last_adj_x = adj_x;
2518
adj_y = gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container)));
2519
if (adj_y != band_info->last_adj_y) {
2520
band_info->last_adj_y = adj_y;
2524
gtk_widget_get_pointer (widget, &x, &y);
2529
} else if (x >= allocation.width) {
2530
x_scroll = x - allocation.width + 1;
2531
x = allocation.width - 1;
2539
} else if (y >= allocation.height) {
2540
y_scroll = y - allocation.height + 1;
2541
y = allocation.height - 1;
2546
if (y_scroll == 0 && x_scroll == 0
2547
&& (int) band_info->prev_x == x && (int) band_info->prev_y == y && !adj_changed) {
2551
nautilus_icon_container_scroll (container, x_scroll, y_scroll);
2553
/* Remember to convert from widget to scrolled window coords */
2554
eel_canvas_window_to_world (EEL_CANVAS (container),
2555
x + gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container))),
2556
y + gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container))),
2557
&world_x, &world_y);
2559
if (world_x < band_info->start_x) {
2561
x2 = band_info->start_x;
2563
x1 = band_info->start_x;
2567
if (world_y < band_info->start_y) {
2569
y2 = band_info->start_y;
2571
y1 = band_info->start_y;
2575
/* Don't let the area of the selection rectangle be empty.
2576
* Aside from the fact that it would be funny when the rectangle disappears,
2577
* this also works around a crash in libart that happens sometimes when a
2578
* zero height rectangle is passed.
2580
x2 = MAX (x1 + 1, x2);
2581
y2 = MAX (y1 + 1, y2);
2584
(band_info->selection_rectangle,
2589
selection_rect.x0 = x1;
2590
selection_rect.y0 = y1;
2591
selection_rect.x1 = x2;
2592
selection_rect.y1 = y2;
2594
rubberband_select (container,
2595
&band_info->prev_rect,
2598
band_info->prev_x = x;
2599
band_info->prev_y = y;
2601
band_info->prev_rect = selection_rect;
2607
start_rubberbanding (NautilusIconContainer *container,
2608
GdkEventButton *event)
2610
AtkObject *accessible;
2611
NautilusIconContainerDetails *details;
2612
NautilusIconRubberbandInfo *band_info;
2613
GdkRGBA bg_color, border_color;
2616
GtkStyleContext *context;
2618
details = container->details;
2619
band_info = &details->rubberband_info;
2621
g_signal_emit (container,
2622
signals[BAND_SELECT_STARTED], 0);
2624
for (p = details->icons; p != NULL; p = p->next) {
2626
icon->was_selected_before_rubberband = icon->is_selected;
2629
eel_canvas_window_to_world
2630
(EEL_CANVAS (container), event->x, event->y,
2631
&band_info->start_x, &band_info->start_y);
2633
context = gtk_widget_get_style_context (GTK_WIDGET (container));
2634
gtk_style_context_save (context);
2635
gtk_style_context_add_class (context, GTK_STYLE_CLASS_RUBBERBAND);
2637
gtk_style_context_get_background_color (context, GTK_STATE_FLAG_NORMAL, &bg_color);
2638
gtk_style_context_get_border_color (context, GTK_STATE_FLAG_NORMAL, &border_color);
2640
gtk_style_context_restore (context);
2642
band_info->selection_rectangle = eel_canvas_item_new
2644
(EEL_CANVAS (container)),
2645
NAUTILUS_TYPE_SELECTION_CANVAS_ITEM,
2646
"x1", band_info->start_x,
2647
"y1", band_info->start_y,
2648
"x2", band_info->start_x,
2649
"y2", band_info->start_y,
2650
"fill_color_rgba", &bg_color,
2651
"outline_color_rgba", &border_color,
2655
accessible = atk_gobject_accessible_for_object
2656
(G_OBJECT (band_info->selection_rectangle));
2657
atk_object_set_name (accessible, "selection");
2658
atk_object_set_description (accessible, _("The selection rectangle"));
2660
band_info->prev_x = event->x - gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container)));
2661
band_info->prev_y = event->y - gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container)));
2663
band_info->active = TRUE;
2665
if (band_info->timer_id == 0) {
2666
band_info->timer_id = g_timeout_add
2667
(RUBBERBAND_TIMEOUT_INTERVAL,
2668
rubberband_timeout_callback,
2672
eel_canvas_item_grab (band_info->selection_rectangle,
2673
(GDK_POINTER_MOTION_MASK
2674
| GDK_BUTTON_RELEASE_MASK
2680
stop_rubberbanding (NautilusIconContainer *container,
2683
NautilusIconRubberbandInfo *band_info;
2686
band_info = &container->details->rubberband_info;
2688
g_assert (band_info->timer_id != 0);
2689
g_source_remove (band_info->timer_id);
2690
band_info->timer_id = 0;
2692
band_info->active = FALSE;
2694
/* Destroy this canvas item; the parent will unref it. */
2695
eel_canvas_item_ungrab (band_info->selection_rectangle, time);
2696
nautilus_selection_canvas_item_fade_out (NAUTILUS_SELECTION_CANVAS_ITEM (band_info->selection_rectangle), 150);
2697
band_info->selection_rectangle = NULL;
2699
/* if only one item has been selected, use it as range
2700
* selection base (cf. handle_icon_button_press) */
2701
icons = nautilus_icon_container_get_selected_icons (container);
2702
if (g_list_length (icons) == 1) {
2703
container->details->range_selection_base_icon = icons->data;
2705
g_list_free (icons);
2707
g_signal_emit (container,
2708
signals[BAND_SELECT_ENDED], 0);
2711
/* Keyboard navigation. */
2713
typedef gboolean (* IsBetterIconFunction) (NautilusIconContainer *container,
2714
NautilusIcon *start_icon,
2715
NautilusIcon *best_so_far,
2716
NautilusIcon *candidate,
2719
static NautilusIcon *
2720
find_best_icon (NautilusIconContainer *container,
2721
NautilusIcon *start_icon,
2722
IsBetterIconFunction function,
2726
NautilusIcon *best, *candidate;
2729
for (p = container->details->icons; p != NULL; p = p->next) {
2730
candidate = p->data;
2732
if (candidate != start_icon) {
2733
if ((* function) (container, start_icon, best, candidate, data)) {
2741
static NautilusIcon *
2742
find_best_selected_icon (NautilusIconContainer *container,
2743
NautilusIcon *start_icon,
2744
IsBetterIconFunction function,
2748
NautilusIcon *best, *candidate;
2751
for (p = container->details->icons; p != NULL; p = p->next) {
2752
candidate = p->data;
2754
if (candidate != start_icon && candidate->is_selected) {
2755
if ((* function) (container, start_icon, best, candidate, data)) {
2764
compare_icons_by_uri (NautilusIconContainer *container,
2765
NautilusIcon *icon_a,
2766
NautilusIcon *icon_b)
2768
char *uri_a, *uri_b;
2771
g_assert (NAUTILUS_IS_ICON_CONTAINER (container));
2772
g_assert (icon_a != NULL);
2773
g_assert (icon_b != NULL);
2774
g_assert (icon_a != icon_b);
2776
uri_a = nautilus_icon_container_get_icon_uri (container, icon_a);
2777
uri_b = nautilus_icon_container_get_icon_uri (container, icon_b);
2778
result = strcmp (uri_a, uri_b);
2779
g_assert (result != 0);
2787
get_cmp_point_x (NautilusIconContainer *container,
2790
if (container->details->label_position == NAUTILUS_ICON_LABEL_POSITION_BESIDE) {
2791
if (gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL) {
2792
return icon_rect.x0;
2794
return icon_rect.x1;
2797
return (icon_rect.x0 + icon_rect.x1) / 2;
2802
get_cmp_point_y (NautilusIconContainer *container,
2805
if (container->details->label_position == NAUTILUS_ICON_LABEL_POSITION_BESIDE) {
2806
return (icon_rect.y0 + icon_rect.y1)/2;
2808
return icon_rect.y1;
2814
compare_icons_horizontal (NautilusIconContainer *container,
2815
NautilusIcon *icon_a,
2816
NautilusIcon *icon_b)
2818
EelDRect world_rect;
2821
world_rect = nautilus_icon_canvas_item_get_icon_rectangle (icon_a->item);
2823
(EEL_CANVAS (container),
2824
get_cmp_point_x (container, world_rect),
2825
get_cmp_point_y (container, world_rect),
2828
world_rect = nautilus_icon_canvas_item_get_icon_rectangle (icon_b->item);
2830
(EEL_CANVAS (container),
2831
get_cmp_point_x (container, world_rect),
2832
get_cmp_point_y (container, world_rect),
2846
compare_icons_vertical (NautilusIconContainer *container,
2847
NautilusIcon *icon_a,
2848
NautilusIcon *icon_b)
2850
EelDRect world_rect;
2853
world_rect = nautilus_icon_canvas_item_get_icon_rectangle (icon_a->item);
2855
(EEL_CANVAS (container),
2856
get_cmp_point_x (container, world_rect),
2857
get_cmp_point_y (container, world_rect),
2860
world_rect = nautilus_icon_canvas_item_get_icon_rectangle (icon_b->item);
2862
(EEL_CANVAS (container),
2863
get_cmp_point_x (container, world_rect),
2864
get_cmp_point_y (container, world_rect),
2878
compare_icons_horizontal_first (NautilusIconContainer *container,
2879
NautilusIcon *icon_a,
2880
NautilusIcon *icon_b)
2882
EelDRect world_rect;
2885
world_rect = nautilus_icon_canvas_item_get_icon_rectangle (icon_a->item);
2887
(EEL_CANVAS (container),
2888
get_cmp_point_x (container, world_rect),
2889
get_cmp_point_y (container, world_rect),
2892
world_rect = nautilus_icon_canvas_item_get_icon_rectangle (icon_b->item);
2894
(EEL_CANVAS (container),
2895
get_cmp_point_x (container, world_rect),
2896
get_cmp_point_y (container, world_rect),
2912
return compare_icons_by_uri (container, icon_a, icon_b);
2916
compare_icons_vertical_first (NautilusIconContainer *container,
2917
NautilusIcon *icon_a,
2918
NautilusIcon *icon_b)
2920
EelDRect world_rect;
2923
world_rect = nautilus_icon_canvas_item_get_icon_rectangle (icon_a->item);
2925
(EEL_CANVAS (container),
2926
get_cmp_point_x (container, world_rect),
2927
get_cmp_point_y (container, world_rect),
2930
world_rect = nautilus_icon_canvas_item_get_icon_rectangle (icon_b->item);
2932
(EEL_CANVAS (container),
2933
get_cmp_point_x (container, world_rect),
2934
get_cmp_point_y (container, world_rect),
2950
return compare_icons_by_uri (container, icon_a, icon_b);
2954
leftmost_in_top_row (NautilusIconContainer *container,
2955
NautilusIcon *start_icon,
2956
NautilusIcon *best_so_far,
2957
NautilusIcon *candidate,
2960
if (best_so_far == NULL) {
2963
return compare_icons_vertical_first (container, best_so_far, candidate) > 0;
2967
rightmost_in_top_row (NautilusIconContainer *container,
2968
NautilusIcon *start_icon,
2969
NautilusIcon *best_so_far,
2970
NautilusIcon *candidate,
2973
if (best_so_far == NULL) {
2976
return compare_icons_vertical (container, best_so_far, candidate) > 0;
2977
return compare_icons_horizontal (container, best_so_far, candidate) < 0;
2981
rightmost_in_bottom_row (NautilusIconContainer *container,
2982
NautilusIcon *start_icon,
2983
NautilusIcon *best_so_far,
2984
NautilusIcon *candidate,
2987
if (best_so_far == NULL) {
2990
return compare_icons_vertical_first (container, best_so_far, candidate) < 0;
2994
compare_with_start_row (NautilusIconContainer *container,
2997
EelCanvasItem *item;
2999
item = EEL_CANVAS_ITEM (icon->item);
3001
if (container->details->arrow_key_start_y < item->y1) {
3004
if (container->details->arrow_key_start_y > item->y2) {
3011
compare_with_start_column (NautilusIconContainer *container,
3014
EelCanvasItem *item;
3016
item = EEL_CANVAS_ITEM (icon->item);
3018
if (container->details->arrow_key_start_x < item->x1) {
3021
if (container->details->arrow_key_start_x > item->x2) {
3028
same_row_right_side_leftmost (NautilusIconContainer *container,
3029
NautilusIcon *start_icon,
3030
NautilusIcon *best_so_far,
3031
NautilusIcon *candidate,
3034
/* Candidates not on the start row do not qualify. */
3035
if (compare_with_start_row (container, candidate) != 0) {
3039
/* Candidates that are farther right lose out. */
3040
if (best_so_far != NULL) {
3041
if (compare_icons_horizontal_first (container,
3048
/* Candidate to the left of the start do not qualify. */
3049
if (compare_icons_horizontal_first (container,
3059
same_row_left_side_rightmost (NautilusIconContainer *container,
3060
NautilusIcon *start_icon,
3061
NautilusIcon *best_so_far,
3062
NautilusIcon *candidate,
3065
/* Candidates not on the start row do not qualify. */
3066
if (compare_with_start_row (container, candidate) != 0) {
3070
/* Candidates that are farther left lose out. */
3071
if (best_so_far != NULL) {
3072
if (compare_icons_horizontal_first (container,
3079
/* Candidate to the right of the start do not qualify. */
3080
if (compare_icons_horizontal_first (container,
3090
next_row_leftmost (NautilusIconContainer *container,
3091
NautilusIcon *start_icon,
3092
NautilusIcon *best_so_far,
3093
NautilusIcon *candidate,
3096
/* sort out icons that are not below the current row */
3097
if (compare_with_start_row (container, candidate) >= 0) {
3101
if (best_so_far != NULL) {
3102
if (compare_icons_vertical_first (container,
3105
/* candidate is above best choice, but below the current row */
3109
if (compare_icons_horizontal_first (container,
3116
return best_so_far == NULL;
3120
next_row_rightmost (NautilusIconContainer *container,
3121
NautilusIcon *start_icon,
3122
NautilusIcon *best_so_far,
3123
NautilusIcon *candidate,
3126
/* sort out icons that are not below the current row */
3127
if (compare_with_start_row (container, candidate) >= 0) {
3131
if (best_so_far != NULL) {
3132
if (compare_icons_vertical_first (container,
3135
/* candidate is above best choice, but below the current row */
3139
if (compare_icons_horizontal_first (container,
3146
return best_so_far == NULL;
3150
next_column_bottommost (NautilusIconContainer *container,
3151
NautilusIcon *start_icon,
3152
NautilusIcon *best_so_far,
3153
NautilusIcon *candidate,
3156
/* sort out icons that are not on the right of the current column */
3157
if (compare_with_start_column (container, candidate) >= 0) {
3161
if (best_so_far != NULL) {
3162
if (compare_icons_horizontal_first (container,
3165
/* candidate is above best choice, but below the current row */
3169
if (compare_icons_vertical_first (container,
3176
return best_so_far == NULL;
3180
previous_row_rightmost (NautilusIconContainer *container,
3181
NautilusIcon *start_icon,
3182
NautilusIcon *best_so_far,
3183
NautilusIcon *candidate,
3186
/* sort out icons that are not above the current row */
3187
if (compare_with_start_row (container, candidate) <= 0) {
3191
if (best_so_far != NULL) {
3192
if (compare_icons_vertical_first (container,
3195
/* candidate is below the best choice, but above the current row */
3199
if (compare_icons_horizontal_first (container,
3206
return best_so_far == NULL;
3210
same_column_above_lowest (NautilusIconContainer *container,
3211
NautilusIcon *start_icon,
3212
NautilusIcon *best_so_far,
3213
NautilusIcon *candidate,
3216
/* Candidates not on the start column do not qualify. */
3217
if (compare_with_start_column (container, candidate) != 0) {
3221
/* Candidates that are higher lose out. */
3222
if (best_so_far != NULL) {
3223
if (compare_icons_vertical_first (container,
3230
/* Candidates below the start do not qualify. */
3231
if (compare_icons_vertical_first (container,
3241
same_column_below_highest (NautilusIconContainer *container,
3242
NautilusIcon *start_icon,
3243
NautilusIcon *best_so_far,
3244
NautilusIcon *candidate,
3247
/* Candidates not on the start column do not qualify. */
3248
if (compare_with_start_column (container, candidate) != 0) {
3252
/* Candidates that are lower lose out. */
3253
if (best_so_far != NULL) {
3254
if (compare_icons_vertical_first (container,
3261
/* Candidates above the start do not qualify. */
3262
if (compare_icons_vertical_first (container,
3272
previous_column_highest (NautilusIconContainer *container,
3273
NautilusIcon *start_icon,
3274
NautilusIcon *best_so_far,
3275
NautilusIcon *candidate,
3278
/* sort out icons that are not before the current column */
3279
if (compare_with_start_column (container, candidate) <= 0) {
3283
if (best_so_far != NULL) {
3284
if (compare_icons_horizontal (container,
3287
/* candidate is right of the best choice, but left of the current column */
3291
if (compare_icons_vertical (container,
3298
return best_so_far == NULL;
3303
next_column_highest (NautilusIconContainer *container,
3304
NautilusIcon *start_icon,
3305
NautilusIcon *best_so_far,
3306
NautilusIcon *candidate,
3309
/* sort out icons that are not after the current column */
3310
if (compare_with_start_column (container, candidate) >= 0) {
3314
if (best_so_far != NULL) {
3315
if (compare_icons_horizontal_first (container,
3318
/* candidate is left of the best choice, but right of the current column */
3322
if (compare_icons_vertical_first (container,
3329
return best_so_far == NULL;
3333
previous_column_lowest (NautilusIconContainer *container,
3334
NautilusIcon *start_icon,
3335
NautilusIcon *best_so_far,
3336
NautilusIcon *candidate,
3339
/* sort out icons that are not before the current column */
3340
if (compare_with_start_column (container, candidate) <= 0) {
3344
if (best_so_far != NULL) {
3345
if (compare_icons_horizontal_first (container,
3348
/* candidate is right of the best choice, but left of the current column */
3352
if (compare_icons_vertical_first (container,
3359
return best_so_far == NULL;
3363
last_column_lowest (NautilusIconContainer *container,
3364
NautilusIcon *start_icon,
3365
NautilusIcon *best_so_far,
3366
NautilusIcon *candidate,
3369
if (best_so_far == NULL) {
3372
return compare_icons_horizontal_first (container, best_so_far, candidate) < 0;
3376
closest_in_90_degrees (NautilusIconContainer *container,
3377
NautilusIcon *start_icon,
3378
NautilusIcon *best_so_far,
3379
NautilusIcon *candidate,
3382
EelDRect world_rect;
3389
world_rect = nautilus_icon_canvas_item_get_icon_rectangle (candidate->item);
3391
(EEL_CANVAS (container),
3392
get_cmp_point_x (container, world_rect),
3393
get_cmp_point_y (container, world_rect),
3397
dx = x - container->details->arrow_key_start_x;
3398
dy = y - container->details->arrow_key_start_y;
3400
switch (container->details->arrow_key_direction) {
3403
ABS(dx) > ABS(dy)) {
3409
ABS(dx) > ABS(dy)) {
3415
ABS(dy) > ABS(dx)) {
3421
ABS(dy) > ABS(dx)) {
3426
g_assert_not_reached();
3429
dist = dx*dx + dy*dy;
3432
if (best_so_far == NULL) {
3437
if (dist < *best_dist) {
3446
get_rubberband (NautilusIcon *icon1,
3447
NautilusIcon *icon2)
3453
eel_canvas_item_get_bounds (EEL_CANVAS_ITEM (icon1->item),
3454
&rect1.x0, &rect1.y0,
3455
&rect1.x1, &rect1.y1);
3456
eel_canvas_item_get_bounds (EEL_CANVAS_ITEM (icon2->item),
3457
&rect2.x0, &rect2.y0,
3458
&rect2.x1, &rect2.y1);
3460
eel_drect_union (&ret, &rect1, &rect2);
3466
keyboard_move_to (NautilusIconContainer *container,
3475
if (event != NULL &&
3476
(event->state & GDK_CONTROL_MASK) != 0 &&
3477
(event->state & GDK_SHIFT_MASK) == 0) {
3478
/* Move the keyboard focus. Use Control modifier
3479
* rather than Alt to avoid Sawfish conflict.
3481
set_keyboard_focus (container, icon);
3482
container->details->keyboard_rubberband_start = NULL;
3483
} else if (event != NULL &&
3484
((event->state & GDK_CONTROL_MASK) != 0 ||
3485
!container->details->auto_layout) &&
3486
(event->state & GDK_SHIFT_MASK) != 0) {
3487
/* Do rubberband selection */
3490
if (from && !container->details->keyboard_rubberband_start) {
3491
set_keyboard_rubberband_start (container, from);
3494
set_keyboard_focus (container, icon);
3496
if (icon && container->details->keyboard_rubberband_start) {
3497
rect = get_rubberband (container->details->keyboard_rubberband_start,
3499
rubberband_select (container, NULL, &rect);
3501
} else if (event != NULL &&
3502
(event->state & GDK_CONTROL_MASK) == 0 &&
3503
(event->state & GDK_SHIFT_MASK) != 0) {
3505
NautilusIcon *start_icon;
3507
start_icon = container->details->range_selection_base_icon;
3508
if (start_icon == NULL || !start_icon->is_selected) {
3510
container->details->range_selection_base_icon = icon;
3513
set_keyboard_focus (container, icon);
3515
if (select_range (container, start_icon, icon, TRUE)) {
3516
g_signal_emit (container,
3517
signals[SELECTION_CHANGED], 0);
3520
/* Select icons and get rid of the special keyboard focus. */
3521
clear_keyboard_focus (container);
3522
clear_keyboard_rubberband_start (container);
3524
container->details->range_selection_base_icon = icon;
3525
if (select_one_unselect_others (container, icon)) {
3526
g_signal_emit (container,
3527
signals[SELECTION_CHANGED], 0);
3530
schedule_keyboard_icon_reveal (container, icon);
3534
keyboard_home (NautilusIconContainer *container,
3540
/* Home selects the first icon.
3541
* Control-Home sets the keyboard focus to the first icon.
3544
from = find_best_selected_icon (container, NULL,
3545
rightmost_in_bottom_row,
3547
to = find_best_icon (container, NULL, leftmost_in_top_row, NULL);
3549
keyboard_move_to (container, to, from, event);
3553
keyboard_end (NautilusIconContainer *container,
3559
/* End selects the last icon.
3560
* Control-End sets the keyboard focus to the last icon.
3562
from = find_best_selected_icon (container, NULL,
3563
leftmost_in_top_row,
3565
to = find_best_icon (container, NULL,
3566
nautilus_icon_container_is_layout_vertical (container) ?
3567
last_column_lowest :
3568
rightmost_in_bottom_row,
3571
keyboard_move_to (container, to, from, event);
3575
record_arrow_key_start (NautilusIconContainer *container,
3577
GtkDirectionType direction)
3579
EelDRect world_rect;
3581
world_rect = nautilus_icon_canvas_item_get_icon_rectangle (icon->item);
3583
(EEL_CANVAS (container),
3584
get_cmp_point_x (container, world_rect),
3585
get_cmp_point_y (container, world_rect),
3586
&container->details->arrow_key_start_x,
3587
&container->details->arrow_key_start_y);
3588
container->details->arrow_key_direction = direction;
3592
keyboard_arrow_key (NautilusIconContainer *container,
3594
GtkDirectionType direction,
3595
IsBetterIconFunction better_start,
3596
IsBetterIconFunction empty_start,
3597
IsBetterIconFunction better_destination,
3598
IsBetterIconFunction better_destination_fallback_if_no_a11y,
3599
IsBetterIconFunction better_destination_fallback_fallback,
3600
IsBetterIconFunction better_destination_manual)
3606
/* Chose the icon to start with.
3607
* If we have a keyboard focus, start with it.
3608
* Otherwise, use the single selected icon.
3609
* If there's multiple selection, use the icon farthest toward the end.
3612
from = container->details->keyboard_focus;
3615
if (has_multiple_selection (container)) {
3616
if (all_selected (container)) {
3617
from = find_best_selected_icon
3621
from = find_best_selected_icon
3623
better_start, NULL);
3626
from = get_first_selected_icon (container);
3630
/* If there's no icon, select the icon farthest toward the end.
3631
* If there is an icon, select the next icon based on the arrow direction.
3634
to = from = find_best_icon
3638
record_arrow_key_start (container, from, direction);
3642
container->details->auto_layout ? better_destination : better_destination_manual,
3645
/* only wrap around to next/previous row/column if no a11y is used.
3646
* Visually impaired people may be easily confused by this.
3649
better_destination_fallback_if_no_a11y != NULL &&
3650
ATK_IS_NO_OP_OBJECT (gtk_widget_get_accessible (GTK_WIDGET (container)))) {
3653
better_destination_fallback_if_no_a11y,
3657
/* With a layout like
3660
* (horizontal layout)
3669
* * pressing down for any of 1,2,3 (horizontal layout)
3670
* * pressing right for any of 1,2,3 (vertical layout)
3675
container->details->auto_layout &&
3676
better_destination_fallback_fallback != NULL) {
3679
better_destination_fallback_fallback,
3689
keyboard_move_to (container, to, from, event);
3693
is_rectangle_selection_event (GdkEventKey *event)
3695
return (event->state & GDK_CONTROL_MASK) != 0 &&
3696
(event->state & GDK_SHIFT_MASK) != 0;
3700
keyboard_right (NautilusIconContainer *container,
3703
IsBetterIconFunction no_a11y;
3704
IsBetterIconFunction next_column_fallback;
3707
if (container->details->auto_layout &&
3708
!nautilus_icon_container_is_layout_vertical (container) &&
3709
!is_rectangle_selection_event (event)) {
3710
no_a11y = next_row_leftmost;
3713
next_column_fallback = NULL;
3714
if (nautilus_icon_container_is_layout_vertical (container) &&
3715
gtk_widget_get_direction (GTK_WIDGET (container)) != GTK_TEXT_DIR_RTL) {
3716
next_column_fallback = next_column_bottommost;
3719
/* Right selects the next icon in the same row.
3720
* Control-Right sets the keyboard focus to the next icon in the same row.
3722
keyboard_arrow_key (container,
3725
rightmost_in_bottom_row,
3726
nautilus_icon_container_is_layout_rtl (container) ?
3727
rightmost_in_top_row : leftmost_in_top_row,
3728
same_row_right_side_leftmost,
3730
next_column_fallback,
3731
closest_in_90_degrees);
3735
keyboard_left (NautilusIconContainer *container,
3738
IsBetterIconFunction no_a11y;
3739
IsBetterIconFunction previous_column_fallback;
3742
if (container->details->auto_layout &&
3743
!nautilus_icon_container_is_layout_vertical (container) &&
3744
!is_rectangle_selection_event (event)) {
3745
no_a11y = previous_row_rightmost;
3748
previous_column_fallback = NULL;
3749
if (nautilus_icon_container_is_layout_vertical (container) &&
3750
gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL) {
3751
previous_column_fallback = previous_column_lowest;
3754
/* Left selects the next icon in the same row.
3755
* Control-Left sets the keyboard focus to the next icon in the same row.
3757
keyboard_arrow_key (container,
3760
rightmost_in_bottom_row,
3761
nautilus_icon_container_is_layout_rtl (container) ?
3762
rightmost_in_top_row : leftmost_in_top_row,
3763
same_row_left_side_rightmost,
3765
previous_column_fallback,
3766
closest_in_90_degrees);
3770
keyboard_down (NautilusIconContainer *container,
3773
IsBetterIconFunction no_a11y;
3774
IsBetterIconFunction next_row_fallback;
3777
if (container->details->auto_layout &&
3778
nautilus_icon_container_is_layout_vertical (container) &&
3779
!is_rectangle_selection_event (event)) {
3780
if (gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL) {
3781
no_a11y = previous_column_highest;
3783
no_a11y = next_column_highest;
3787
next_row_fallback = NULL;
3788
if (!nautilus_icon_container_is_layout_vertical (container)) {
3789
if (gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL) {
3790
next_row_fallback = next_row_leftmost;
3792
next_row_fallback = next_row_rightmost;
3796
/* Down selects the next icon in the same column.
3797
* Control-Down sets the keyboard focus to the next icon in the same column.
3799
keyboard_arrow_key (container,
3802
rightmost_in_bottom_row,
3803
nautilus_icon_container_is_layout_rtl (container) ?
3804
rightmost_in_top_row : leftmost_in_top_row,
3805
same_column_below_highest,
3808
closest_in_90_degrees);
3812
keyboard_up (NautilusIconContainer *container,
3815
IsBetterIconFunction no_a11y;
3818
if (container->details->auto_layout &&
3819
nautilus_icon_container_is_layout_vertical (container) &&
3820
!is_rectangle_selection_event (event)) {
3821
if (gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL) {
3822
no_a11y = next_column_bottommost;
3824
no_a11y = previous_column_lowest;
3828
/* Up selects the next icon in the same column.
3829
* Control-Up sets the keyboard focus to the next icon in the same column.
3831
keyboard_arrow_key (container,
3834
rightmost_in_bottom_row,
3835
nautilus_icon_container_is_layout_rtl (container) ?
3836
rightmost_in_top_row : leftmost_in_top_row,
3837
same_column_above_lowest,
3840
closest_in_90_degrees);
3844
keyboard_space (NautilusIconContainer *container,
3849
if (!has_selection (container) &&
3850
container->details->keyboard_focus != NULL) {
3851
keyboard_move_to (container,
3852
container->details->keyboard_focus,
3854
} else if ((event->state & GDK_CONTROL_MASK) != 0 &&
3855
(event->state & GDK_SHIFT_MASK) == 0) {
3856
/* Control-space toggles the selection state of the current icon. */
3857
if (container->details->keyboard_focus != NULL) {
3858
icon_toggle_selected (container, container->details->keyboard_focus);
3859
g_signal_emit (container, signals[SELECTION_CHANGED], 0);
3860
if (container->details->keyboard_focus->is_selected) {
3861
container->details->range_selection_base_icon = container->details->keyboard_focus;
3864
icon = find_best_selected_icon (container,
3866
leftmost_in_top_row,
3869
icon = find_best_icon (container,
3871
leftmost_in_top_row,
3875
set_keyboard_focus (container, icon);
3878
} else if ((event->state & GDK_SHIFT_MASK) != 0) {
3879
activate_selected_items_alternate (container, NULL);
3881
preview_selected_items (container);
3885
/* look for the first icon that matches the longest part of a given
3890
int last_match_length;
3893
#ifndef TAB_NAVIGATION_DISABLED
3895
select_previous_or_next_icon (NautilusIconContainer *container,
3903
/* Chose the icon to start with.
3904
* If we have a keyboard focus, start with it.
3905
* Otherwise, use the single selected icon.
3907
icon = container->details->keyboard_focus;
3909
icon = get_first_selected_icon (container);
3913
/* must have at least @icon in the list */
3914
g_assert (container->details->icons != NULL);
3915
item = g_list_find (container->details->icons, icon);
3916
g_assert (item != NULL);
3918
item = next ? item->next : item->prev;
3920
item = next ? g_list_first (container->details->icons) : g_list_last (container->details->icons);
3923
} else if (container->details->icons != NULL) {
3924
/* no selection yet, pick the first or last item to select */
3925
item = next ? g_list_first (container->details->icons) : g_list_last (container->details->icons);
3928
icon = (item != NULL) ? item->data : NULL;
3931
keyboard_move_to (container, icon, NULL, event);
3937
destroy (GtkWidget *object)
3939
NautilusIconContainer *container;
3941
container = NAUTILUS_ICON_CONTAINER (object);
3943
nautilus_icon_container_clear (container);
3945
if (container->details->rubberband_info.timer_id != 0) {
3946
g_source_remove (container->details->rubberband_info.timer_id);
3947
container->details->rubberband_info.timer_id = 0;
3950
if (container->details->idle_id != 0) {
3951
g_source_remove (container->details->idle_id);
3952
container->details->idle_id = 0;
3955
if (container->details->stretch_idle_id != 0) {
3956
g_source_remove (container->details->stretch_idle_id);
3957
container->details->stretch_idle_id = 0;
3960
if (container->details->align_idle_id != 0) {
3961
g_source_remove (container->details->align_idle_id);
3962
container->details->align_idle_id = 0;
3965
if (container->details->selection_changed_id != 0) {
3966
g_source_remove (container->details->selection_changed_id);
3967
container->details->selection_changed_id = 0;
3970
if (container->details->size_allocation_count_id != 0) {
3971
g_source_remove (container->details->size_allocation_count_id);
3972
container->details->size_allocation_count_id = 0;
3975
/* destroy interactive search dialog */
3976
if (container->details->search_window) {
3977
gtk_widget_destroy (container->details->search_window);
3978
container->details->search_window = NULL;
3979
container->details->search_entry = NULL;
3982
remove_search_entry_timeout (container);
3984
GTK_WIDGET_CLASS (nautilus_icon_container_parent_class)->destroy (object);
3988
finalize (GObject *object)
3990
NautilusIconContainerDetails *details;
3992
details = NAUTILUS_ICON_CONTAINER (object)->details;
3994
g_signal_handlers_disconnect_by_func (nautilus_icon_view_preferences,
3995
text_ellipsis_limit_changed_container_callback,
3997
g_signal_handlers_disconnect_by_func (nautilus_desktop_preferences,
3998
text_ellipsis_limit_changed_container_callback,
4001
g_hash_table_destroy (details->icon_set);
4002
details->icon_set = NULL;
4004
g_free (details->font);
4006
if (details->a11y_item_action_queue != NULL) {
4007
while (!g_queue_is_empty (details->a11y_item_action_queue)) {
4008
g_free (g_queue_pop_head (details->a11y_item_action_queue));
4010
g_queue_free (details->a11y_item_action_queue);
4012
if (details->a11y_item_action_idle_handler != 0) {
4013
g_source_remove (details->a11y_item_action_idle_handler);
4018
G_OBJECT_CLASS (nautilus_icon_container_parent_class)->finalize (object);
4021
/* GtkWidget methods. */
4024
clear_size_allocation_count (gpointer data)
4026
NautilusIconContainer *container;
4028
container = NAUTILUS_ICON_CONTAINER (data);
4030
container->details->size_allocation_count_id = 0;
4031
container->details->size_allocation_count = 0;
4037
size_allocate (GtkWidget *widget,
4038
GtkAllocation *allocation)
4040
NautilusIconContainer *container;
4041
gboolean need_layout_redone;
4042
GtkAllocation wid_allocation;
4044
container = NAUTILUS_ICON_CONTAINER (widget);
4046
need_layout_redone = !container->details->has_been_allocated;
4047
gtk_widget_get_allocation (widget, &wid_allocation);
4049
if (allocation->width != wid_allocation.width) {
4050
need_layout_redone = TRUE;
4053
if (allocation->height != wid_allocation.height) {
4054
need_layout_redone = TRUE;
4057
/* Under some conditions we can end up in a loop when size allocating.
4058
* This happens when the icons don't fit without a scrollbar, but fits
4059
* when a scrollbar is added (bug #129963 for details).
4060
* We keep track of this looping by increasing a counter in size_allocate
4061
* and clearing it in a high-prio idle (the only way to detect the loop is
4063
* When we've done at more than two iterations (with/without scrollbar)
4064
* we terminate this looping by not redoing the layout when the width
4065
* is wider than the current one (i.e when removing the scrollbar).
4067
if (container->details->size_allocation_count_id == 0) {
4068
container->details->size_allocation_count_id =
4069
g_idle_add_full (G_PRIORITY_HIGH,
4070
clear_size_allocation_count,
4073
container->details->size_allocation_count++;
4074
if (container->details->size_allocation_count > 2 &&
4075
allocation->width >= wid_allocation.width) {
4076
need_layout_redone = FALSE;
4079
GTK_WIDGET_CLASS (nautilus_icon_container_parent_class)->size_allocate (widget, allocation);
4081
container->details->has_been_allocated = TRUE;
4083
if (need_layout_redone) {
4084
redo_layout (container);
4088
static GtkSizeRequestMode
4089
get_request_mode (GtkWidget *widget)
4091
/* Don't trade size at all, since we get whatever we get anyway. */
4092
return GTK_SIZE_REQUEST_CONSTANT_SIZE;
4095
/* We need to implement these since the GtkScrolledWindow uses them
4096
to guess whether to show scrollbars or not, and if we don't report
4097
anything it'll tend to get it wrong causing double calls
4098
to size_allocate (at different sizes) during its size allocation. */
4100
get_prefered_width (GtkWidget *widget,
4104
EelCanvasGroup *root;
4109
root = eel_canvas_root (EEL_CANVAS (widget));
4110
eel_canvas_item_get_bounds (EEL_CANVAS_ITEM (root),
4111
&x1, NULL, &x2, NULL);
4112
eel_canvas_w2c (EEL_CANVAS (widget), x1, 0, &cx1, NULL);
4113
eel_canvas_w2c (EEL_CANVAS (widget), x2, 0, &cx2, NULL);
4117
*natural_size = width;
4120
*minimum_size = width;
4125
get_prefered_height (GtkWidget *widget,
4129
EelCanvasGroup *root;
4134
root = eel_canvas_root (EEL_CANVAS (widget));
4135
eel_canvas_item_get_bounds (EEL_CANVAS_ITEM (root),
4136
NULL, &y1, NULL, &y2);
4137
eel_canvas_w2c (EEL_CANVAS (widget), 0, y1, NULL, &cy1);
4138
eel_canvas_w2c (EEL_CANVAS (widget), 0, y2, NULL, &cy2);
4142
*natural_size = height;
4145
*minimum_size = height;
4150
setup_background (NautilusIconContainer *container)
4154
GtkStyleContext *style;
4156
if (container->details->is_desktop) {
4160
style = gtk_widget_get_style_context (GTK_WIDGET (container));
4162
DEBUG ("Container %p: setting up background, is_active %d", container,
4163
container->details->active_background);
4165
window = gtk_layout_get_bin_window (GTK_LAYOUT (container));
4167
if (!container->details->active_background) {
4168
gtk_style_context_get_background_color (style, GTK_STATE_FLAG_NORMAL, &color);
4170
DEBUG ("Container %p, making color inactive", container);
4171
eel_make_color_inactive (&color);
4173
gtk_widget_override_background_color (GTK_WIDGET (container), GTK_STATE_FLAG_NORMAL,
4175
gtk_style_context_set_background (style, window);
4177
DEBUG ("Container %p, removing color override", container);
4178
gtk_widget_override_background_color (GTK_WIDGET (container), GTK_STATE_FLAG_NORMAL,
4180
gtk_style_context_set_background (style, window);
4185
realize (GtkWidget *widget)
4187
GtkAdjustment *vadj, *hadj;
4188
NautilusIconContainer *container;
4190
GTK_WIDGET_CLASS (nautilus_icon_container_parent_class)->realize (widget);
4192
container = NAUTILUS_ICON_CONTAINER (widget);
4194
/* Ensure that the desktop window is native so the background
4195
set on it is drawn by X. */
4196
if (container->details->is_desktop) {
4197
gdk_x11_window_get_xid (gtk_layout_get_bin_window (GTK_LAYOUT (widget)));
4201
nautilus_icon_dnd_init (container);
4203
setup_background (container);
4205
hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (widget));
4206
g_signal_connect (hadj, "value_changed",
4207
G_CALLBACK (handle_hadjustment_changed), widget);
4209
vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (widget));
4210
g_signal_connect (vadj, "value_changed",
4211
G_CALLBACK (handle_vadjustment_changed), widget);
4216
unrealize (GtkWidget *widget)
4218
NautilusIconContainer *container;
4220
container = NAUTILUS_ICON_CONTAINER (widget);
4222
nautilus_icon_dnd_fini (container);
4223
remove_search_entry_timeout (container);
4225
GTK_WIDGET_CLASS (nautilus_icon_container_parent_class)->unrealize (widget);
4229
style_updated (GtkWidget *widget)
4231
NautilusIconContainer *container;
4233
container = NAUTILUS_ICON_CONTAINER (widget);
4234
container->details->use_drop_shadows = container->details->drop_shadows_requested;
4236
/* Don't chain up to parent, if this is a desktop container,
4237
* because that resets the background of the window.
4239
if (!nautilus_icon_container_get_is_desktop (container)) {
4240
GTK_WIDGET_CLASS (nautilus_icon_container_parent_class)->style_updated (widget);
4243
if (gtk_widget_get_realized (widget)) {
4244
invalidate_labels (container);
4245
nautilus_icon_container_request_update_all (container);
4250
button_press_event (GtkWidget *widget,
4251
GdkEventButton *event)
4253
NautilusIconContainer *container;
4254
gboolean selection_changed;
4255
gboolean return_value;
4256
gboolean clicked_on_icon;
4258
container = NAUTILUS_ICON_CONTAINER (widget);
4259
container->details->button_down_time = event->time;
4261
/* Forget about the old keyboard selection now that we've started mousing. */
4262
clear_keyboard_focus (container);
4263
clear_keyboard_rubberband_start (container);
4265
if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS) {
4266
/* We use our own double-click detection. */
4270
/* Invoke the canvas event handler and see if an item picks up the event. */
4271
clicked_on_icon = GTK_WIDGET_CLASS (nautilus_icon_container_parent_class)->button_press_event (widget, event);
4273
/* Move focus to icon container, unless we're still renaming (to avoid exiting
4276
if (!gtk_widget_has_focus (widget) && !(is_renaming (container) || is_renaming_pending (container))) {
4277
gtk_widget_grab_focus (widget);
4280
if (clicked_on_icon) {
4284
if (event->button == DRAG_BUTTON &&
4285
event->type == GDK_BUTTON_PRESS) {
4286
/* Clear the last click icon for double click */
4287
container->details->double_click_icon[1] = container->details->double_click_icon[0];
4288
container->details->double_click_icon[0] = NULL;
4291
/* Button 1 does rubber banding. */
4292
if (event->button == RUBBERBAND_BUTTON) {
4293
if (! button_event_modifies_selection (event)) {
4294
selection_changed = unselect_all (container);
4295
if (selection_changed) {
4296
g_signal_emit (container,
4297
signals[SELECTION_CHANGED], 0);
4301
start_rubberbanding (container, event);
4305
/* Prevent multi-button weirdness such as bug 6181 */
4306
if (container->details->rubberband_info.active) {
4310
/* Button 2 may be passed to the window manager. */
4311
if (event->button == MIDDLE_BUTTON) {
4312
selection_changed = unselect_all (container);
4313
if (selection_changed) {
4314
g_signal_emit (container, signals[SELECTION_CHANGED], 0);
4316
g_signal_emit (widget, signals[MIDDLE_CLICK], 0, event);
4320
/* Button 3 does a contextual menu. */
4321
if (event->button == CONTEXTUAL_MENU_BUTTON) {
4322
end_renaming_mode (container, TRUE);
4323
selection_changed = unselect_all (container);
4324
if (selection_changed) {
4325
g_signal_emit (container, signals[SELECTION_CHANGED], 0);
4327
g_signal_emit (widget, signals[CONTEXT_CLICK_BACKGROUND], 0, event);
4331
/* Otherwise, we emit a button_press message. */
4332
g_signal_emit (widget,
4333
signals[BUTTON_PRESS], 0, event,
4335
return return_value;
4339
nautilus_icon_container_did_not_drag (NautilusIconContainer *container,
4340
GdkEventButton *event)
4342
NautilusIconContainerDetails *details;
4343
gboolean selection_changed;
4344
static gint64 last_click_time = 0;
4345
static gint click_count = 0;
4346
gint double_click_time;
4347
gint64 current_time;
4349
details = container->details;
4351
if (details->icon_selected_on_button_down &&
4352
((event->state & GDK_CONTROL_MASK) != 0 ||
4353
(event->state & GDK_SHIFT_MASK) == 0)) {
4354
if (button_event_modifies_selection (event)) {
4355
details->range_selection_base_icon = NULL;
4356
icon_toggle_selected (container, details->drag_icon);
4357
g_signal_emit (container,
4358
signals[SELECTION_CHANGED], 0);
4360
details->range_selection_base_icon = details->drag_icon;
4361
selection_changed = select_one_unselect_others
4362
(container, details->drag_icon);
4364
if (selection_changed) {
4365
g_signal_emit (container,
4366
signals[SELECTION_CHANGED], 0);
4371
if (details->drag_icon != NULL &&
4372
(details->single_click_mode ||
4373
event->button == MIDDLE_BUTTON)) {
4374
/* Determine click count */
4375
g_object_get (G_OBJECT (gtk_widget_get_settings (GTK_WIDGET (container))),
4376
"gtk-double-click-time", &double_click_time,
4378
current_time = eel_get_system_time ();
4379
if (current_time - last_click_time < double_click_time * 1000) {
4385
/* Stash time for next compare */
4386
last_click_time = current_time;
4388
/* If single-click mode, activate the selected icons, unless modifying
4389
* the selection or pressing for a very long time, or double clicking.
4393
if (click_count == 0 &&
4394
event->time - details->button_down_time < MAX_CLICK_TIME &&
4395
! button_event_modifies_selection (event)) {
4397
/* It's a tricky UI issue whether this should activate
4398
* just the clicked item (as if it were a link), or all
4399
* the selected items (as if you were issuing an "activate
4400
* selection" command). For now, we're trying the activate
4401
* entire selection version to see how it feels. Note that
4402
* NautilusList goes the other way because its "links" seem
4403
* much more link-like.
4405
if (event->button == MIDDLE_BUTTON) {
4406
activate_selected_items_alternate (container, NULL);
4408
activate_selected_items (container);
4415
clicked_within_double_click_interval (NautilusIconContainer *container)
4417
static gint64 last_click_time = 0;
4418
static gint click_count = 0;
4419
gint double_click_time;
4420
gint64 current_time;
4422
/* Determine click count */
4423
g_object_get (G_OBJECT (gtk_widget_get_settings (GTK_WIDGET (container))),
4424
"gtk-double-click-time", &double_click_time,
4426
current_time = eel_get_system_time ();
4427
if (current_time - last_click_time < double_click_time * 1000) {
4433
/* Stash time for next compare */
4434
last_click_time = current_time;
4436
/* Only allow double click */
4437
if (click_count == 1) {
4446
clear_drag_state (NautilusIconContainer *container)
4448
container->details->drag_icon = NULL;
4449
container->details->drag_state = DRAG_STATE_INITIAL;
4453
start_stretching (NautilusIconContainer *container)
4455
NautilusIconContainerDetails *details;
4457
EelDPoint world_point;
4458
GtkWidget *toplevel;
4459
GtkCornerType corner;
4462
details = container->details;
4463
icon = details->stretch_icon;
4465
/* Check if we hit the stretch handles. */
4466
world_point.x = details->drag_x;
4467
world_point.y = details->drag_y;
4468
if (!nautilus_icon_canvas_item_hit_test_stretch_handles (icon->item, world_point, &corner)) {
4473
case GTK_CORNER_TOP_LEFT:
4474
cursor = gdk_cursor_new (GDK_TOP_LEFT_CORNER);
4476
case GTK_CORNER_BOTTOM_LEFT:
4477
cursor = gdk_cursor_new (GDK_BOTTOM_LEFT_CORNER);
4479
case GTK_CORNER_TOP_RIGHT:
4480
cursor = gdk_cursor_new (GDK_TOP_RIGHT_CORNER);
4482
case GTK_CORNER_BOTTOM_RIGHT:
4483
cursor = gdk_cursor_new (GDK_BOTTOM_RIGHT_CORNER);
4489
/* Set up the dragging. */
4490
details->drag_state = DRAG_STATE_STRETCH;
4491
eel_canvas_w2c (EEL_CANVAS (container),
4494
&details->stretch_start.pointer_x,
4495
&details->stretch_start.pointer_y);
4496
eel_canvas_w2c (EEL_CANVAS (container),
4498
&details->stretch_start.icon_x,
4499
&details->stretch_start.icon_y);
4500
icon_get_size (container, icon,
4501
&details->stretch_start.icon_size);
4503
eel_canvas_item_grab (EEL_CANVAS_ITEM (icon->item),
4504
(GDK_POINTER_MOTION_MASK
4505
| GDK_BUTTON_RELEASE_MASK),
4509
g_object_unref (cursor);
4511
/* Ensure the window itself is focused.. */
4512
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4513
if (toplevel != NULL && gtk_widget_get_realized (toplevel)) {
4514
gdk_window_focus (gtk_widget_get_window (toplevel), GDK_CURRENT_TIME);
4521
update_stretch_at_idle (NautilusIconContainer *container)
4523
NautilusIconContainerDetails *details;
4525
double world_x, world_y;
4526
StretchState stretch_state;
4528
details = container->details;
4529
icon = details->stretch_icon;
4532
container->details->stretch_idle_id = 0;
4536
eel_canvas_w2c (EEL_CANVAS (container),
4537
details->world_x, details->world_y,
4538
&stretch_state.pointer_x, &stretch_state.pointer_y);
4540
compute_stretch (&details->stretch_start,
4543
eel_canvas_c2w (EEL_CANVAS (container),
4544
stretch_state.icon_x, stretch_state.icon_y,
4545
&world_x, &world_y);
4547
icon_set_position (icon, world_x, world_y);
4548
icon_set_size (container, icon, stretch_state.icon_size, FALSE, FALSE);
4550
container->details->stretch_idle_id = 0;
4556
continue_stretching (NautilusIconContainer *container,
4557
double world_x, double world_y)
4560
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
4562
container->details->world_x = world_x;
4563
container->details->world_y = world_y;
4565
if (container->details->stretch_idle_id == 0) {
4566
container->details->stretch_idle_id = g_idle_add ((GSourceFunc) update_stretch_at_idle, container);
4571
keyboard_stretching (NautilusIconContainer *container,
4577
icon = container->details->stretch_icon;
4579
if (icon == NULL || !icon->is_selected) {
4583
icon_get_size (container, icon, &size);
4585
switch (event->keyval) {
4588
case GDK_KEY_KP_Add:
4589
icon_set_size (container, icon, size + 5, FALSE, FALSE);
4592
case GDK_KEY_KP_Subtract:
4593
icon_set_size (container, icon, size - 5, FALSE, FALSE);
4597
nautilus_icon_container_move_icon (container, icon,
4608
ungrab_stretch_icon (NautilusIconContainer *container)
4610
eel_canvas_item_ungrab (EEL_CANVAS_ITEM (container->details->stretch_icon->item),
4615
end_stretching (NautilusIconContainer *container,
4616
double world_x, double world_y)
4618
NautilusIconPosition position;
4621
continue_stretching (container, world_x, world_y);
4622
ungrab_stretch_icon (container);
4624
/* now that we're done stretching, update the icon's position */
4626
icon = container->details->drag_icon;
4627
if (nautilus_icon_container_is_layout_rtl (container)) {
4628
position.x = icon->saved_ltr_x = get_mirror_x_position (container, icon, icon->x);
4630
position.x = icon->x;
4632
position.y = icon->y;
4633
position.scale = icon->scale;
4634
g_signal_emit (container,
4635
signals[ICON_POSITION_CHANGED], 0,
4636
icon->data, &position);
4638
clear_drag_state (container);
4639
redo_layout (container);
4643
undo_stretching (NautilusIconContainer *container)
4645
NautilusIcon *stretched_icon;
4647
stretched_icon = container->details->stretch_icon;
4649
if (stretched_icon == NULL) {
4653
if (container->details->drag_state == DRAG_STATE_STRETCH) {
4654
ungrab_stretch_icon (container);
4655
clear_drag_state (container);
4657
nautilus_icon_canvas_item_set_show_stretch_handles
4658
(stretched_icon->item, FALSE);
4660
icon_set_position (stretched_icon,
4661
container->details->stretch_initial_x,
4662
container->details->stretch_initial_y);
4663
icon_set_size (container,
4665
container->details->stretch_initial_size,
4669
container->details->stretch_icon = NULL;
4670
emit_stretch_ended (container, stretched_icon);
4671
redo_layout (container);
4677
button_release_event (GtkWidget *widget,
4678
GdkEventButton *event)
4680
NautilusIconContainer *container;
4681
NautilusIconContainerDetails *details;
4682
double world_x, world_y;
4684
container = NAUTILUS_ICON_CONTAINER (widget);
4685
details = container->details;
4687
if (event->button == RUBBERBAND_BUTTON && details->rubberband_info.active) {
4688
stop_rubberbanding (container, event->time);
4692
if (event->button == details->drag_button) {
4693
details->drag_button = 0;
4695
switch (details->drag_state) {
4696
case DRAG_STATE_MOVE_OR_COPY:
4697
if (!details->drag_started) {
4698
nautilus_icon_container_did_not_drag (container, event);
4700
nautilus_icon_dnd_end_drag (container);
4701
DEBUG ("Ending drag from icon container");
4704
case DRAG_STATE_STRETCH:
4705
eel_canvas_window_to_world
4706
(EEL_CANVAS (container), event->x, event->y, &world_x, &world_y);
4707
end_stretching (container, world_x, world_y);
4713
clear_drag_state (container);
4717
return GTK_WIDGET_CLASS (nautilus_icon_container_parent_class)->button_release_event (widget, event);
4721
motion_notify_event (GtkWidget *widget,
4722
GdkEventMotion *event)
4724
NautilusIconContainer *container;
4725
NautilusIconContainerDetails *details;
4726
double world_x, world_y;
4727
int canvas_x, canvas_y;
4728
GdkDragAction actions;
4730
container = NAUTILUS_ICON_CONTAINER (widget);
4731
details = container->details;
4733
if (details->drag_button != 0) {
4734
switch (details->drag_state) {
4735
case DRAG_STATE_MOVE_OR_COPY:
4736
if (details->drag_started) {
4740
eel_canvas_window_to_world
4741
(EEL_CANVAS (container), event->x, event->y, &world_x, &world_y);
4743
if (gtk_drag_check_threshold (widget,
4748
details->drag_started = TRUE;
4749
details->drag_state = DRAG_STATE_MOVE_OR_COPY;
4751
end_renaming_mode (container, TRUE);
4753
eel_canvas_w2c (EEL_CANVAS (container),
4759
actions = GDK_ACTION_COPY
4763
if (container->details->drag_allow_moves) {
4764
actions |= GDK_ACTION_MOVE;
4767
nautilus_icon_dnd_begin_drag (container,
4769
details->drag_button,
4773
DEBUG ("Beginning drag from icon container");
4776
case DRAG_STATE_STRETCH:
4777
eel_canvas_window_to_world
4778
(EEL_CANVAS (container), event->x, event->y, &world_x, &world_y);
4779
continue_stretching (container, world_x, world_y);
4786
return GTK_WIDGET_CLASS (nautilus_icon_container_parent_class)->motion_notify_event (widget, event);
4790
nautilus_icon_container_search_position_func (NautilusIconContainer *container,
4791
GtkWidget *search_dialog)
4794
gint cont_x, cont_y;
4795
gint cont_width, cont_height;
4796
GdkWindow *cont_window;
4798
GtkRequisition requisition;
4800
GdkRectangle monitor;
4803
cont_window = gtk_widget_get_window (GTK_WIDGET (container));
4804
screen = gdk_window_get_screen (cont_window);
4806
monitor_num = gdk_screen_get_monitor_at_window (screen, cont_window);
4807
gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
4809
gtk_widget_realize (search_dialog);
4811
gdk_window_get_origin (cont_window, &cont_x, &cont_y);
4812
cont_width = gdk_window_get_width (cont_window);
4813
cont_height = gdk_window_get_height (cont_window);
4815
gtk_widget_get_preferred_size (search_dialog, &requisition, NULL);
4817
if (cont_x + cont_width > gdk_screen_get_width (screen)) {
4818
x = gdk_screen_get_width (screen) - requisition.width;
4819
} else if (cont_x + cont_width - requisition.width < 0) {
4822
x = cont_x + cont_width - requisition.width;
4825
if (cont_y + cont_height + requisition.height > gdk_screen_get_height (screen)) {
4826
y = gdk_screen_get_height (screen) - requisition.height;
4827
} else if (cont_y + cont_height < 0) { /* isn't really possible ... */
4830
y = cont_y + cont_height;
4833
gdk_window_move (gtk_widget_get_window (search_dialog), x, y);
4836
/* Cut and paste from gtkwindow.c */
4838
send_focus_change (GtkWidget *widget, gboolean in)
4842
fevent = gdk_event_new (GDK_FOCUS_CHANGE);
4844
g_object_ref (widget);
4845
((GdkEventFocus *) fevent)->in = in;
4847
gtk_widget_send_focus_change (widget, fevent);
4849
fevent->focus_change.type = GDK_FOCUS_CHANGE;
4850
fevent->focus_change.window = g_object_ref (gtk_widget_get_window (widget));
4851
fevent->focus_change.in = in;
4853
gtk_widget_event (widget, fevent);
4855
g_object_notify (G_OBJECT (widget), "has-focus");
4857
g_object_unref (widget);
4858
gdk_event_free (fevent);
4862
nautilus_icon_container_search_dialog_hide (GtkWidget *search_dialog,
4863
NautilusIconContainer *container)
4865
if (container->details->search_entry_changed_id) {
4866
g_signal_handler_disconnect (container->details->search_entry,
4867
container->details->search_entry_changed_id);
4868
container->details->search_entry_changed_id = 0;
4871
remove_search_entry_timeout (container);
4873
/* send focus-in event */
4874
send_focus_change (GTK_WIDGET (container->details->search_entry), FALSE);
4875
gtk_widget_hide (search_dialog);
4876
gtk_entry_set_text (GTK_ENTRY (container->details->search_entry), "");
4880
nautilus_icon_container_search_entry_flush_timeout (gpointer data)
4882
NautilusIconContainer *container = data;
4884
container->details->typeselect_flush_timeout = 0;
4885
nautilus_icon_container_search_dialog_hide (container->details->search_window, container);
4891
add_search_entry_timeout (NautilusIconContainer *container)
4893
container->details->typeselect_flush_timeout =
4894
g_timeout_add_seconds (NAUTILUS_ICON_CONTAINER_SEARCH_DIALOG_TIMEOUT,
4895
nautilus_icon_container_search_entry_flush_timeout,
4900
remove_search_entry_timeout (NautilusIconContainer *container)
4902
if (container->details->typeselect_flush_timeout) {
4903
g_source_remove (container->details->typeselect_flush_timeout);
4904
container->details->typeselect_flush_timeout = 0;
4909
reset_search_entry_timeout (NautilusIconContainer *container)
4911
remove_search_entry_timeout (container);
4912
add_search_entry_timeout (container);
4915
/* Because we're visible but offscreen, we just set a flag in the preedit
4919
nautilus_icon_container_search_preedit_changed (GtkEntry *entry,
4921
NautilusIconContainer *container)
4923
container->details->imcontext_changed = 1;
4924
reset_search_entry_timeout (container);
4928
nautilus_icon_container_search_activate (GtkEntry *entry,
4929
NautilusIconContainer *container)
4931
nautilus_icon_container_search_dialog_hide (container->details->search_window,
4934
activate_selected_items (container);
4938
nautilus_icon_container_search_delete_event (GtkWidget *widget,
4940
NautilusIconContainer *container)
4942
nautilus_icon_container_search_dialog_hide (widget, container);
4948
nautilus_icon_container_search_button_press_event (GtkWidget *widget,
4949
GdkEventButton *event,
4950
NautilusIconContainer *container)
4952
nautilus_icon_container_search_dialog_hide (widget, container);
4954
if (event->window == gtk_layout_get_bin_window (GTK_LAYOUT (container))) {
4955
button_press_event (GTK_WIDGET (container), event);
4962
nautilus_icon_container_search_entry_button_press_event (GtkWidget *widget,
4963
GdkEventButton *event,
4964
NautilusIconContainer *container)
4966
reset_search_entry_timeout (container);
4972
nautilus_icon_container_search_populate_popup (GtkEntry *entry,
4974
NautilusIconContainer *container)
4976
remove_search_entry_timeout (container);
4977
g_signal_connect_swapped (menu, "hide",
4978
G_CALLBACK (add_search_entry_timeout), container);
4982
nautilus_icon_container_get_icon_text (NautilusIconContainer *container,
4983
NautilusIconData *data,
4984
char **editable_text,
4985
char **additional_text,
4986
gboolean include_invisible)
4988
NautilusIconContainerClass *klass;
4990
klass = NAUTILUS_ICON_CONTAINER_GET_CLASS (container);
4991
g_assert (klass->get_icon_text != NULL);
4993
klass->get_icon_text (container, data, editable_text, additional_text, include_invisible);
4997
nautilus_icon_container_search_iter (NautilusIconContainer *container,
4998
const char *key, gint n)
5004
char *normalized_key, *case_normalized_key;
5005
char *normalized_name, *case_normalized_name;
5007
g_assert (key != NULL);
5010
normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
5011
if (!normalized_key) {
5014
case_normalized_key = g_utf8_casefold (normalized_key, -1);
5015
g_free (normalized_key);
5016
if (!case_normalized_key) {
5023
for (p = container->details->icons; p != NULL && count != n; p = p->next) {
5025
nautilus_icon_container_get_icon_text (container, icon->data, &name,
5028
/* This can happen if a key event is handled really early while
5029
* loading the icon container, before the items have all been
5036
normalized_name = g_utf8_normalize (name, -1, G_NORMALIZE_ALL);
5037
if (!normalized_name) {
5040
case_normalized_name = g_utf8_casefold (normalized_name, -1);
5041
g_free (normalized_name);
5042
if (!case_normalized_name) {
5046
if (strncmp (case_normalized_key, case_normalized_name,
5047
strlen (case_normalized_key)) == 0) {
5051
g_free (case_normalized_name);
5056
g_free (case_normalized_key);
5059
if (select_one_unselect_others (container, icon)) {
5060
g_signal_emit (container, signals[SELECTION_CHANGED], 0);
5062
schedule_keyboard_icon_reveal (container, icon);
5071
nautilus_icon_container_search_move (GtkWidget *window,
5072
NautilusIconContainer *container,
5079
text = gtk_entry_get_text (GTK_ENTRY (container->details->search_entry));
5081
g_assert (text != NULL);
5083
if (container->details->selected_iter == 0) {
5087
if (up && container->details->selected_iter == 1) {
5091
len = strlen (text);
5098
unselect_all (container);
5100
ret = nautilus_icon_container_search_iter (container, text,
5101
up?((container->details->selected_iter) - 1):((container->details->selected_iter + 1)));
5105
container->details->selected_iter += up?(-1):(1);
5107
/* return to old iter */
5108
nautilus_icon_container_search_iter (container, text,
5109
container->details->selected_iter);
5114
nautilus_icon_container_search_scroll_event (GtkWidget *widget,
5115
GdkEventScroll *event,
5116
NautilusIconContainer *container)
5118
gboolean retval = FALSE;
5120
if (event->direction == GDK_SCROLL_UP) {
5121
nautilus_icon_container_search_move (widget, container, TRUE);
5123
} else if (event->direction == GDK_SCROLL_DOWN) {
5124
nautilus_icon_container_search_move (widget, container, FALSE);
5128
reset_search_entry_timeout (container);
5134
nautilus_icon_container_search_key_press_event (GtkWidget *widget,
5136
NautilusIconContainer *container)
5138
gboolean retval = FALSE;
5140
g_assert (GTK_IS_WIDGET (widget));
5141
g_assert (NAUTILUS_IS_ICON_CONTAINER (container));
5143
/* close window and cancel the search */
5144
if (event->keyval == GDK_KEY_Escape || event->keyval == GDK_KEY_Tab) {
5145
nautilus_icon_container_search_dialog_hide (widget, container);
5149
/* close window and activate alternate */
5150
if (event->keyval == GDK_KEY_Return && event->state & GDK_SHIFT_MASK) {
5151
nautilus_icon_container_search_dialog_hide (widget,
5154
activate_selected_items_alternate (container, NULL);
5158
/* select previous matching iter */
5159
if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up) {
5160
nautilus_icon_container_search_move (widget, container, TRUE);
5164
if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == (GDK_CONTROL_MASK | GDK_SHIFT_MASK))
5165
&& (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G)) {
5166
nautilus_icon_container_search_move (widget, container, TRUE);
5170
/* select next matching iter */
5171
if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down) {
5172
nautilus_icon_container_search_move (widget, container, FALSE);
5176
if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == GDK_CONTROL_MASK)
5177
&& (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G)) {
5178
nautilus_icon_container_search_move (widget, container, FALSE);
5182
reset_search_entry_timeout (container);
5188
nautilus_icon_container_search_init (GtkWidget *entry,
5189
NautilusIconContainer *container)
5195
g_assert (GTK_IS_ENTRY (entry));
5196
g_assert (NAUTILUS_IS_ICON_CONTAINER (container));
5198
text = gtk_entry_get_text (GTK_ENTRY (entry));
5199
len = strlen (text);
5202
unselect_all (container);
5203
reset_search_entry_timeout (container);
5209
ret = nautilus_icon_container_search_iter (container, text, 1);
5212
container->details->selected_iter = 1;
5217
nautilus_icon_container_ensure_interactive_directory (NautilusIconContainer *container)
5219
GtkWidget *frame, *vbox;
5221
if (container->details->search_window != NULL) {
5225
container->details->search_window = gtk_window_new (GTK_WINDOW_POPUP);
5227
gtk_window_set_modal (GTK_WINDOW (container->details->search_window), TRUE);
5228
gtk_window_set_type_hint (GTK_WINDOW (container->details->search_window),
5229
GDK_WINDOW_TYPE_HINT_COMBO);
5231
g_signal_connect (container->details->search_window, "delete_event",
5232
G_CALLBACK (nautilus_icon_container_search_delete_event),
5234
g_signal_connect (container->details->search_window, "key_press_event",
5235
G_CALLBACK (nautilus_icon_container_search_key_press_event),
5237
g_signal_connect (container->details->search_window, "button_press_event",
5238
G_CALLBACK (nautilus_icon_container_search_button_press_event),
5240
g_signal_connect (container->details->search_window, "scroll_event",
5241
G_CALLBACK (nautilus_icon_container_search_scroll_event),
5244
frame = gtk_frame_new (NULL);
5245
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
5246
gtk_widget_show (frame);
5247
gtk_container_add (GTK_CONTAINER (container->details->search_window), frame);
5249
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
5250
gtk_widget_show (vbox);
5251
gtk_container_add (GTK_CONTAINER (frame), vbox);
5252
gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
5255
container->details->search_entry = gtk_entry_new ();
5256
gtk_widget_show (container->details->search_entry);
5257
g_signal_connect (container->details->search_entry, "populate-popup",
5258
G_CALLBACK (nautilus_icon_container_search_populate_popup),
5260
g_signal_connect (container->details->search_entry, "activate",
5261
G_CALLBACK (nautilus_icon_container_search_activate),
5263
g_signal_connect (container->details->search_entry, "preedit-changed",
5264
G_CALLBACK (nautilus_icon_container_search_preedit_changed),
5266
g_signal_connect (container->details->search_entry, "button-press-event",
5267
G_CALLBACK (nautilus_icon_container_search_entry_button_press_event),
5269
gtk_container_add (GTK_CONTAINER (vbox), container->details->search_entry);
5271
gtk_widget_realize (container->details->search_entry);
5274
/* Pops up the interactive search entry. If keybinding is TRUE then the user
5275
* started this by typing the start_interactive_search keybinding. Otherwise, it came from
5278
nautilus_icon_container_start_interactive_search (NautilusIconContainer *container)
5280
/* We only start interactive search if we have focus. If one of our
5281
* children have focus, we don't want to start the search.
5283
GtkWidgetClass *entry_parent_class;
5285
if (container->details->search_window != NULL &&
5286
gtk_widget_get_visible (container->details->search_window)) {
5290
if (!gtk_widget_has_focus (GTK_WIDGET (container))) {
5294
nautilus_icon_container_ensure_interactive_directory (container);
5297
nautilus_icon_container_search_position_func (container, container->details->search_window);
5298
gtk_widget_show (container->details->search_window);
5299
if (container->details->search_entry_changed_id == 0) {
5300
container->details->search_entry_changed_id =
5301
g_signal_connect (container->details->search_entry, "changed",
5302
G_CALLBACK (nautilus_icon_container_search_init),
5306
/* Grab focus will select all the text. We don't want that to happen, so we
5307
* call the parent instance and bypass the selection change. This is probably
5308
* really non-kosher. */
5309
entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (container->details->search_entry));
5310
(entry_parent_class->grab_focus) (container->details->search_entry);
5312
/* send focus-in event */
5313
send_focus_change (container->details->search_entry, TRUE);
5315
/* search first matching iter */
5316
nautilus_icon_container_search_init (container->details->search_entry, container);
5322
handle_popups (NautilusIconContainer *container,
5326
GdkEventButton button_event = { 0 };
5328
/* ensure we clear the drag state before showing the menu */
5329
clear_drag_state (container);
5331
g_signal_emit_by_name (container, signal, &button_event);
5337
key_press_event (GtkWidget *widget,
5340
NautilusIconContainer *container;
5343
container = NAUTILUS_ICON_CONTAINER (widget);
5346
if (is_renaming (container) || is_renaming_pending (container)) {
5347
switch (event->keyval) {
5348
case GDK_KEY_Return:
5349
case GDK_KEY_KP_Enter:
5350
end_renaming_mode (container, TRUE);
5353
case GDK_KEY_Escape:
5354
end_renaming_mode (container, FALSE);
5361
switch (event->keyval) {
5363
case GDK_KEY_KP_Home:
5364
keyboard_home (container, event);
5368
case GDK_KEY_KP_End:
5369
keyboard_end (container, event);
5373
case GDK_KEY_KP_Left:
5374
/* Don't eat Alt-Left, as that is used for history browsing */
5375
if ((event->state & GDK_MOD1_MASK) == 0) {
5376
keyboard_left (container, event);
5382
/* Don't eat Alt-Up, as that is used for alt-shift-Up */
5383
if ((event->state & GDK_MOD1_MASK) == 0) {
5384
keyboard_up (container, event);
5389
case GDK_KEY_KP_Right:
5390
/* Don't eat Alt-Right, as that is used for history browsing */
5391
if ((event->state & GDK_MOD1_MASK) == 0) {
5392
keyboard_right (container, event);
5397
case GDK_KEY_KP_Down:
5398
/* Don't eat Alt-Down, as that is used for Open */
5399
if ((event->state & GDK_MOD1_MASK) == 0) {
5400
keyboard_down (container, event);
5405
keyboard_space (container, event);
5408
#ifndef TAB_NAVIGATION_DISABLED
5410
case GDK_KEY_ISO_Left_Tab:
5411
select_previous_or_next_icon (container,
5412
(event->state & GDK_SHIFT_MASK) == 0, event);
5416
case GDK_KEY_Return:
5417
case GDK_KEY_KP_Enter:
5418
if ((event->state & GDK_SHIFT_MASK) != 0) {
5419
activate_selected_items_alternate (container, NULL);
5421
activate_selected_items (container);
5426
case GDK_KEY_Escape:
5427
handled = undo_stretching (container);
5432
case GDK_KEY_KP_Add:
5433
case GDK_KEY_KP_Subtract:
5436
if (event->state & GDK_CONTROL_MASK) {
5437
handled = keyboard_stretching (container, event);
5441
/* handle Ctrl+F10 because we want to display the
5442
* background popup even if something is selected.
5443
* The other cases are handled by popup_menu().
5445
if (event->state & GDK_CONTROL_MASK) {
5446
handled = handle_popups (container, event,
5447
"context_click_background");
5451
/* Eat Control + v to not enable type ahead */
5452
if ((event->state & GDK_CONTROL_MASK) != 0) {
5462
handled = GTK_WIDGET_CLASS (nautilus_icon_container_parent_class)->key_press_event (widget, event);
5465
/* We pass the event to the search_entry. If its text changes, then we
5466
* start the typeahead find capabilities.
5467
* Copied from NautilusIconContainer */
5469
event->keyval != GDK_KEY_slash /* don't steal slash key event, used for "go to" */ &&
5470
event->keyval != GDK_KEY_BackSpace &&
5471
event->keyval != GDK_KEY_Delete) {
5472
GdkEvent *new_event;
5475
const char *new_text;
5478
gboolean text_modified;
5479
gulong popup_menu_id;
5481
nautilus_icon_container_ensure_interactive_directory (container);
5483
/* Make a copy of the current text */
5484
old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (container->details->search_entry)));
5485
new_event = gdk_event_copy ((GdkEvent *) event);
5486
window = ((GdkEventKey *) new_event)->window;
5487
((GdkEventKey *) new_event)->window = gtk_widget_get_window (container->details->search_entry);
5488
gtk_widget_realize (container->details->search_window);
5490
popup_menu_id = g_signal_connect (container->details->search_entry,
5491
"popup_menu", G_CALLBACK (gtk_true), NULL);
5493
/* Move the entry off screen */
5494
screen = gtk_widget_get_screen (GTK_WIDGET (container));
5495
gtk_window_move (GTK_WINDOW (container->details->search_window),
5496
gdk_screen_get_width (screen) + 1,
5497
gdk_screen_get_height (screen) + 1);
5498
gtk_widget_show (container->details->search_window);
5500
/* Send the event to the window. If the preedit_changed signal is emitted
5501
* during this event, we will set priv->imcontext_changed */
5502
container->details->imcontext_changed = FALSE;
5503
retval = gtk_widget_event (container->details->search_entry, new_event);
5504
gtk_widget_hide (container->details->search_window);
5506
g_signal_handler_disconnect (container->details->search_entry,
5509
/* We check to make sure that the entry tried to handle the text, and that
5510
* the text has changed. */
5511
new_text = gtk_entry_get_text (GTK_ENTRY (container->details->search_entry));
5512
text_modified = strcmp (old_text, new_text) != 0;
5514
if (container->details->imcontext_changed || /* we're in a preedit */
5515
(retval && text_modified)) { /* ...or the text was modified */
5516
if (nautilus_icon_container_start_interactive_search (container)) {
5517
gtk_widget_grab_focus (GTK_WIDGET (container));
5520
gtk_entry_set_text (GTK_ENTRY (container->details->search_entry), "");
5525
((GdkEventKey *) new_event)->window = window;
5526
gdk_event_free (new_event);
5533
popup_menu (GtkWidget *widget)
5535
NautilusIconContainer *container;
5537
container = NAUTILUS_ICON_CONTAINER (widget);
5539
if (has_selection (container)) {
5540
handle_popups (container, NULL,
5541
"context_click_selection");
5543
handle_popups (container, NULL,
5544
"context_click_background");
5551
draw_canvas_background (EelCanvas *canvas,
5554
/* Don't chain up to the parent to avoid clearing and redrawing */
5559
get_accessible (GtkWidget *widget)
5561
AtkObject *accessible;
5563
if ((accessible = eel_accessibility_get_atk_object (widget))) {
5567
accessible = g_object_new
5568
(nautilus_icon_container_accessible_get_type (), NULL);
5570
return eel_accessibility_set_atk_object_return (widget, accessible);
5574
grab_notify_cb (GtkWidget *widget,
5575
gboolean was_grabbed)
5577
NautilusIconContainer *container;
5579
container = NAUTILUS_ICON_CONTAINER (widget);
5581
if (container->details->rubberband_info.active &&
5583
/* we got a (un)grab-notify during rubberband.
5584
* This happens when a new modal dialog shows
5585
* up (e.g. authentication or an error). Stop
5586
* the rubberbanding so that we can handle the
5588
stop_rubberbanding (container,
5594
text_ellipsis_limit_changed_container_callback (gpointer callback_data)
5596
NautilusIconContainer *container;
5598
container = NAUTILUS_ICON_CONTAINER (callback_data);
5599
invalidate_label_sizes (container);
5600
schedule_redo_layout (container);
5604
nautilus_icon_container_constructor (GType type,
5605
guint n_construct_params,
5606
GObjectConstructParam *construct_params)
5608
NautilusIconContainer *container;
5611
object = G_OBJECT_CLASS (nautilus_icon_container_parent_class)->constructor
5616
container = NAUTILUS_ICON_CONTAINER (object);
5617
if (nautilus_icon_container_get_is_desktop (container)) {
5618
g_signal_connect_swapped (nautilus_desktop_preferences,
5619
"changed::" NAUTILUS_PREFERENCES_DESKTOP_TEXT_ELLIPSIS_LIMIT,
5620
G_CALLBACK (text_ellipsis_limit_changed_container_callback),
5623
g_signal_connect_swapped (nautilus_icon_view_preferences,
5624
"changed::" NAUTILUS_PREFERENCES_ICON_VIEW_TEXT_ELLIPSIS_LIMIT,
5625
G_CALLBACK (text_ellipsis_limit_changed_container_callback),
5632
/* Initialization. */
5635
nautilus_icon_container_class_init (NautilusIconContainerClass *class)
5637
GtkWidgetClass *widget_class;
5638
EelCanvasClass *canvas_class;
5640
G_OBJECT_CLASS (class)->constructor = nautilus_icon_container_constructor;
5641
G_OBJECT_CLASS (class)->finalize = finalize;
5645
signals[SELECTION_CHANGED]
5646
= g_signal_new ("selection_changed",
5647
G_TYPE_FROM_CLASS (class),
5649
G_STRUCT_OFFSET (NautilusIconContainerClass,
5652
g_cclosure_marshal_VOID__VOID,
5654
signals[BUTTON_PRESS]
5655
= g_signal_new ("button_press",
5656
G_TYPE_FROM_CLASS (class),
5658
G_STRUCT_OFFSET (NautilusIconContainerClass,
5661
g_cclosure_marshal_generic,
5665
= g_signal_new ("activate",
5666
G_TYPE_FROM_CLASS (class),
5668
G_STRUCT_OFFSET (NautilusIconContainerClass,
5671
g_cclosure_marshal_VOID__POINTER,
5674
signals[ACTIVATE_ALTERNATE]
5675
= g_signal_new ("activate_alternate",
5676
G_TYPE_FROM_CLASS (class),
5678
G_STRUCT_OFFSET (NautilusIconContainerClass,
5679
activate_alternate),
5681
g_cclosure_marshal_VOID__POINTER,
5684
signals[ACTIVATE_PREVIEWER]
5685
= g_signal_new ("activate_previewer",
5686
G_TYPE_FROM_CLASS (class),
5688
G_STRUCT_OFFSET (NautilusIconContainerClass,
5689
activate_previewer),
5691
g_cclosure_marshal_generic,
5693
G_TYPE_POINTER, G_TYPE_POINTER);
5694
signals[CONTEXT_CLICK_SELECTION]
5695
= g_signal_new ("context_click_selection",
5696
G_TYPE_FROM_CLASS (class),
5698
G_STRUCT_OFFSET (NautilusIconContainerClass,
5699
context_click_selection),
5701
g_cclosure_marshal_VOID__POINTER,
5704
signals[CONTEXT_CLICK_BACKGROUND]
5705
= g_signal_new ("context_click_background",
5706
G_TYPE_FROM_CLASS (class),
5708
G_STRUCT_OFFSET (NautilusIconContainerClass,
5709
context_click_background),
5711
g_cclosure_marshal_VOID__POINTER,
5714
signals[MIDDLE_CLICK]
5715
= g_signal_new ("middle_click",
5716
G_TYPE_FROM_CLASS (class),
5718
G_STRUCT_OFFSET (NautilusIconContainerClass,
5721
g_cclosure_marshal_VOID__POINTER,
5724
signals[ICON_POSITION_CHANGED]
5725
= g_signal_new ("icon_position_changed",
5726
G_TYPE_FROM_CLASS (class),
5728
G_STRUCT_OFFSET (NautilusIconContainerClass,
5729
icon_position_changed),
5731
g_cclosure_marshal_generic,
5735
signals[ICON_STRETCH_STARTED]
5736
= g_signal_new ("icon_stretch_started",
5737
G_TYPE_FROM_CLASS (class),
5739
G_STRUCT_OFFSET (NautilusIconContainerClass,
5740
icon_stretch_started),
5742
g_cclosure_marshal_VOID__POINTER,
5745
signals[ICON_STRETCH_ENDED]
5746
= g_signal_new ("icon_stretch_ended",
5747
G_TYPE_FROM_CLASS (class),
5749
G_STRUCT_OFFSET (NautilusIconContainerClass,
5750
icon_stretch_ended),
5752
g_cclosure_marshal_VOID__POINTER,
5755
signals[ICON_RENAME_STARTED]
5756
= g_signal_new ("icon_rename_started",
5757
G_TYPE_FROM_CLASS (class),
5759
G_STRUCT_OFFSET (NautilusIconContainerClass,
5760
icon_rename_started),
5762
g_cclosure_marshal_VOID__POINTER,
5765
signals[ICON_RENAME_ENDED]
5766
= g_signal_new ("icon_rename_ended",
5767
G_TYPE_FROM_CLASS (class),
5769
G_STRUCT_OFFSET (NautilusIconContainerClass,
5772
g_cclosure_marshal_generic,
5776
signals[GET_ICON_URI]
5777
= g_signal_new ("get_icon_uri",
5778
G_TYPE_FROM_CLASS (class),
5780
G_STRUCT_OFFSET (NautilusIconContainerClass,
5783
g_cclosure_marshal_generic,
5786
signals[GET_ICON_DROP_TARGET_URI]
5787
= g_signal_new ("get_icon_drop_target_uri",
5788
G_TYPE_FROM_CLASS (class),
5790
G_STRUCT_OFFSET (NautilusIconContainerClass,
5791
get_icon_drop_target_uri),
5793
g_cclosure_marshal_generic,
5796
signals[MOVE_COPY_ITEMS]
5797
= g_signal_new ("move_copy_items",
5798
G_TYPE_FROM_CLASS (class),
5800
G_STRUCT_OFFSET (NautilusIconContainerClass,
5803
g_cclosure_marshal_generic,
5808
GDK_TYPE_DRAG_ACTION,
5811
signals[HANDLE_NETSCAPE_URL]
5812
= g_signal_new ("handle_netscape_url",
5813
G_TYPE_FROM_CLASS (class),
5815
G_STRUCT_OFFSET (NautilusIconContainerClass,
5816
handle_netscape_url),
5818
g_cclosure_marshal_generic,
5822
GDK_TYPE_DRAG_ACTION,
5825
signals[HANDLE_URI_LIST]
5826
= g_signal_new ("handle_uri_list",
5827
G_TYPE_FROM_CLASS (class),
5829
G_STRUCT_OFFSET (NautilusIconContainerClass,
5832
g_cclosure_marshal_generic,
5836
GDK_TYPE_DRAG_ACTION,
5839
signals[HANDLE_TEXT]
5840
= g_signal_new ("handle_text",
5841
G_TYPE_FROM_CLASS (class),
5843
G_STRUCT_OFFSET (NautilusIconContainerClass,
5846
g_cclosure_marshal_generic,
5850
GDK_TYPE_DRAG_ACTION,
5854
= g_signal_new ("handle_raw",
5855
G_TYPE_FROM_CLASS (class),
5857
G_STRUCT_OFFSET (NautilusIconContainerClass,
5860
g_cclosure_marshal_generic,
5866
GDK_TYPE_DRAG_ACTION,
5869
signals[GET_CONTAINER_URI]
5870
= g_signal_new ("get_container_uri",
5871
G_TYPE_FROM_CLASS (class),
5873
G_STRUCT_OFFSET (NautilusIconContainerClass,
5876
g_cclosure_marshal_generic,
5878
signals[CAN_ACCEPT_ITEM]
5879
= g_signal_new ("can_accept_item",
5880
G_TYPE_FROM_CLASS (class),
5882
G_STRUCT_OFFSET (NautilusIconContainerClass,
5885
g_cclosure_marshal_generic,
5889
signals[GET_STORED_ICON_POSITION]
5890
= g_signal_new ("get_stored_icon_position",
5891
G_TYPE_FROM_CLASS (class),
5893
G_STRUCT_OFFSET (NautilusIconContainerClass,
5894
get_stored_icon_position),
5896
g_cclosure_marshal_generic,
5900
signals[GET_STORED_LAYOUT_TIMESTAMP]
5901
= g_signal_new ("get_stored_layout_timestamp",
5902
G_TYPE_FROM_CLASS (class),
5904
G_STRUCT_OFFSET (NautilusIconContainerClass,
5905
get_stored_layout_timestamp),
5907
g_cclosure_marshal_generic,
5911
signals[STORE_LAYOUT_TIMESTAMP]
5912
= g_signal_new ("store_layout_timestamp",
5913
G_TYPE_FROM_CLASS (class),
5915
G_STRUCT_OFFSET (NautilusIconContainerClass,
5916
store_layout_timestamp),
5918
g_cclosure_marshal_generic,
5922
signals[LAYOUT_CHANGED]
5923
= g_signal_new ("layout_changed",
5924
G_TYPE_FROM_CLASS (class),
5926
G_STRUCT_OFFSET (NautilusIconContainerClass,
5929
g_cclosure_marshal_VOID__VOID,
5931
signals[BAND_SELECT_STARTED]
5932
= g_signal_new ("band_select_started",
5933
G_TYPE_FROM_CLASS (class),
5935
G_STRUCT_OFFSET (NautilusIconContainerClass,
5936
band_select_started),
5938
g_cclosure_marshal_VOID__VOID,
5940
signals[BAND_SELECT_ENDED]
5941
= g_signal_new ("band_select_ended",
5942
G_TYPE_FROM_CLASS (class),
5944
G_STRUCT_OFFSET (NautilusIconContainerClass,
5947
g_cclosure_marshal_VOID__VOID,
5950
= g_signal_new ("icon_added",
5951
G_TYPE_FROM_CLASS (class),
5953
G_STRUCT_OFFSET (NautilusIconContainerClass,
5956
g_cclosure_marshal_VOID__POINTER,
5957
G_TYPE_NONE, 1, G_TYPE_POINTER);
5958
signals[ICON_REMOVED]
5959
= g_signal_new ("icon_removed",
5960
G_TYPE_FROM_CLASS (class),
5962
G_STRUCT_OFFSET (NautilusIconContainerClass,
5965
g_cclosure_marshal_VOID__POINTER,
5966
G_TYPE_NONE, 1, G_TYPE_POINTER);
5969
= g_signal_new ("cleared",
5970
G_TYPE_FROM_CLASS (class),
5972
G_STRUCT_OFFSET (NautilusIconContainerClass,
5975
g_cclosure_marshal_VOID__VOID,
5978
/* GtkWidget class. */
5980
widget_class = GTK_WIDGET_CLASS (class);
5981
widget_class->destroy = destroy;
5982
widget_class->size_allocate = size_allocate;
5983
widget_class->get_request_mode = get_request_mode;
5984
widget_class->get_preferred_width = get_prefered_width;
5985
widget_class->get_preferred_height = get_prefered_height;
5986
widget_class->realize = realize;
5987
widget_class->unrealize = unrealize;
5988
widget_class->button_press_event = button_press_event;
5989
widget_class->button_release_event = button_release_event;
5990
widget_class->motion_notify_event = motion_notify_event;
5991
widget_class->key_press_event = key_press_event;
5992
widget_class->popup_menu = popup_menu;
5993
widget_class->get_accessible = get_accessible;
5994
widget_class->style_updated = style_updated;
5995
widget_class->grab_notify = grab_notify_cb;
5997
canvas_class = EEL_CANVAS_CLASS (class);
5998
canvas_class->draw_background = draw_canvas_background;
6000
gtk_widget_class_install_style_property (widget_class,
6001
g_param_spec_boolean ("activate_prelight_icon_label",
6002
"Activate Prelight Icon Label",
6003
"Whether icon labels should make use of its prelight color in prelight state",
6009
update_selected (NautilusIconContainer *container)
6014
for (node = container->details->icons; node != NULL; node = node->next) {
6016
if (icon->is_selected) {
6017
eel_canvas_item_request_update (EEL_CANVAS_ITEM (icon->item));
6023
handle_focus_in_event (GtkWidget *widget, GdkEventFocus *event, gpointer user_data)
6025
update_selected (NAUTILUS_ICON_CONTAINER (widget));
6031
handle_focus_out_event (GtkWidget *widget, GdkEventFocus *event, gpointer user_data)
6033
/* End renaming and commit change. */
6034
end_renaming_mode (NAUTILUS_ICON_CONTAINER (widget), TRUE);
6035
update_selected (NAUTILUS_ICON_CONTAINER (widget));
6041
static int text_ellipsis_limits[NAUTILUS_ZOOM_LEVEL_N_ENTRIES];
6042
static int desktop_text_ellipsis_limit;
6045
get_text_ellipsis_limit_for_zoom (char **strs,
6046
const char *zoom_level,
6058
if (zoom_level != NULL) {
6059
str = g_strdup_printf ("%s:%%d", zoom_level);
6061
str = g_strdup ("%d");
6065
for (p = strs; *p != NULL; p++) {
6066
if (sscanf (*p, str, limit)) {
6077
static const char * zoom_level_names[] = {
6088
text_ellipsis_limit_changed_callback (gpointer callback_data)
6094
pref = g_settings_get_strv (nautilus_icon_view_preferences,
6095
NAUTILUS_PREFERENCES_ICON_VIEW_TEXT_ELLIPSIS_LIMIT);
6098
get_text_ellipsis_limit_for_zoom (pref, NULL, &one_limit);
6099
for (i = 0; i < NAUTILUS_ZOOM_LEVEL_N_ENTRIES; i++) {
6100
text_ellipsis_limits[i] = one_limit;
6103
/* override for each zoom level */
6104
for (i = 0; i < G_N_ELEMENTS(zoom_level_names); i++) {
6105
if (get_text_ellipsis_limit_for_zoom (pref,
6106
zoom_level_names[i],
6108
text_ellipsis_limits[i] = one_limit;
6116
desktop_text_ellipsis_limit_changed_callback (gpointer callback_data)
6120
pref = g_settings_get_int (nautilus_desktop_preferences, NAUTILUS_PREFERENCES_DESKTOP_TEXT_ELLIPSIS_LIMIT);
6121
desktop_text_ellipsis_limit = pref;
6125
nautilus_icon_container_init (NautilusIconContainer *container)
6127
NautilusIconContainerDetails *details;
6128
static gboolean setup_prefs = FALSE;
6130
details = g_new0 (NautilusIconContainerDetails, 1);
6132
details->icon_set = g_hash_table_new (g_direct_hash, g_direct_equal);
6133
details->layout_timestamp = UNDEFINED_TIME;
6134
details->active_background = TRUE;
6135
details->zoom_level = NAUTILUS_ZOOM_LEVEL_STANDARD;
6137
details->font_size_table[NAUTILUS_ZOOM_LEVEL_SMALLEST] = -2 * PANGO_SCALE;
6138
details->font_size_table[NAUTILUS_ZOOM_LEVEL_SMALLER] = -2 * PANGO_SCALE;
6139
details->font_size_table[NAUTILUS_ZOOM_LEVEL_SMALL] = -0 * PANGO_SCALE;
6140
details->font_size_table[NAUTILUS_ZOOM_LEVEL_STANDARD] = 0 * PANGO_SCALE;
6141
details->font_size_table[NAUTILUS_ZOOM_LEVEL_LARGE] = 0 * PANGO_SCALE;
6142
details->font_size_table[NAUTILUS_ZOOM_LEVEL_LARGER] = 0 * PANGO_SCALE;
6143
details->font_size_table[NAUTILUS_ZOOM_LEVEL_LARGEST] = 0 * PANGO_SCALE;
6145
container->details = details;
6147
g_signal_connect (container, "focus-in-event",
6148
G_CALLBACK (handle_focus_in_event), NULL);
6149
g_signal_connect (container, "focus-out-event",
6150
G_CALLBACK (handle_focus_out_event), NULL);
6153
g_signal_connect_swapped (nautilus_icon_view_preferences,
6154
"changed::" NAUTILUS_PREFERENCES_ICON_VIEW_TEXT_ELLIPSIS_LIMIT,
6155
G_CALLBACK (text_ellipsis_limit_changed_callback),
6157
text_ellipsis_limit_changed_callback (NULL);
6159
g_signal_connect_swapped (nautilus_icon_view_preferences,
6160
"changed::" NAUTILUS_PREFERENCES_DESKTOP_TEXT_ELLIPSIS_LIMIT,
6161
G_CALLBACK (desktop_text_ellipsis_limit_changed_callback),
6163
desktop_text_ellipsis_limit_changed_callback (NULL);
6170
NautilusIconContainer *container;
6171
GdkEventButton *event;
6172
} ContextMenuParameters;
6175
handle_icon_double_click (NautilusIconContainer *container,
6177
GdkEventButton *event)
6179
NautilusIconContainerDetails *details;
6181
if (event->button != DRAG_BUTTON) {
6185
details = container->details;
6187
if (!details->single_click_mode &&
6188
clicked_within_double_click_interval (container) &&
6189
details->double_click_icon[0] == details->double_click_icon[1] &&
6190
details->double_click_button[0] == details->double_click_button[1]) {
6191
if (!button_event_modifies_selection (event)) {
6192
activate_selected_items (container);
6194
} else if ((event->state & GDK_CONTROL_MASK) == 0 &&
6195
(event->state & GDK_SHIFT_MASK) != 0) {
6196
activate_selected_items_alternate (container, icon);
6204
/* NautilusIcon event handling. */
6206
/* Conceptually, pressing button 1 together with CTRL or SHIFT toggles
6207
* selection of a single icon without affecting the other icons;
6208
* without CTRL or SHIFT, it selects a single icon and un-selects all
6209
* the other icons. But in this latter case, the de-selection should
6210
* only happen when the button is released if the icon is already
6211
* selected, because the user might select multiple icons and drag all
6212
* of them by doing a simple click-drag.
6216
handle_icon_button_press (NautilusIconContainer *container,
6218
GdkEventButton *event)
6220
NautilusIconContainerDetails *details;
6222
details = container->details;
6224
if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS) {
6228
if (event->button != DRAG_BUTTON
6229
&& event->button != CONTEXTUAL_MENU_BUTTON
6230
&& event->button != DRAG_MENU_BUTTON) {
6234
if ((event->button == DRAG_BUTTON) &&
6235
event->type == GDK_BUTTON_PRESS) {
6236
/* The next double click has to be on this icon */
6237
details->double_click_icon[1] = details->double_click_icon[0];
6238
details->double_click_icon[0] = icon;
6240
details->double_click_button[1] = details->double_click_button[0];
6241
details->double_click_button[0] = event->button;
6244
if (handle_icon_double_click (container, icon, event)) {
6245
/* Double clicking does not trigger a D&D action. */
6246
details->drag_button = 0;
6247
details->drag_icon = NULL;
6251
if (event->button == DRAG_BUTTON
6252
|| event->button == DRAG_MENU_BUTTON) {
6253
details->drag_button = event->button;
6254
details->drag_icon = icon;
6255
details->drag_x = event->x;
6256
details->drag_y = event->y;
6257
details->drag_state = DRAG_STATE_MOVE_OR_COPY;
6258
details->drag_started = FALSE;
6260
/* Check to see if this is a click on the stretch handles.
6261
* If so, it won't modify the selection.
6263
if (icon == container->details->stretch_icon) {
6264
if (start_stretching (container)) {
6270
/* Modify the selection as appropriate. Selection is modified
6271
* the same way for contextual menu as it would be without.
6273
details->icon_selected_on_button_down = icon->is_selected;
6275
if ((event->button == DRAG_BUTTON || event->button == MIDDLE_BUTTON) &&
6276
(event->state & GDK_SHIFT_MASK) != 0) {
6277
NautilusIcon *start_icon;
6279
start_icon = details->range_selection_base_icon;
6280
if (start_icon == NULL || !start_icon->is_selected) {
6282
details->range_selection_base_icon = icon;
6284
if (select_range (container, start_icon, icon,
6285
(event->state & GDK_CONTROL_MASK) == 0)) {
6286
g_signal_emit (container,
6287
signals[SELECTION_CHANGED], 0);
6289
} else if (!details->icon_selected_on_button_down) {
6290
details->range_selection_base_icon = icon;
6291
if (button_event_modifies_selection (event)) {
6292
icon_toggle_selected (container, icon);
6293
g_signal_emit (container,
6294
signals[SELECTION_CHANGED], 0);
6296
select_one_unselect_others (container, icon);
6297
g_signal_emit (container,
6298
signals[SELECTION_CHANGED], 0);
6302
if (event->button == CONTEXTUAL_MENU_BUTTON) {
6303
clear_drag_state (container);
6305
g_signal_emit (container,
6306
signals[CONTEXT_CLICK_SELECTION], 0,
6315
item_event_callback (EelCanvasItem *item,
6319
NautilusIconContainer *container;
6322
container = NAUTILUS_ICON_CONTAINER (data);
6324
icon = NAUTILUS_ICON_CANVAS_ITEM (item)->user_data;
6325
g_assert (icon != NULL);
6327
switch (event->type) {
6328
case GDK_BUTTON_PRESS:
6329
if (handle_icon_button_press (container, icon, &event->button)) {
6330
/* Stop the event from being passed along further. Returning
6331
* TRUE ain't enough.
6342
nautilus_icon_container_new (void)
6344
return gtk_widget_new (NAUTILUS_TYPE_ICON_CONTAINER, NULL);
6347
/* Clear all of the icons in the container. */
6349
nautilus_icon_container_clear (NautilusIconContainer *container)
6351
NautilusIconContainerDetails *details;
6355
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
6357
details = container->details;
6358
details->layout_timestamp = UNDEFINED_TIME;
6359
details->store_layout_timestamps_when_finishing_new_icons = FALSE;
6361
if (details->icons == NULL) {
6365
end_renaming_mode (container, TRUE);
6367
clear_keyboard_focus (container);
6368
clear_keyboard_rubberband_start (container);
6369
unschedule_keyboard_icon_reveal (container);
6370
set_pending_icon_to_reveal (container, NULL);
6371
details->stretch_icon = NULL;
6372
details->drop_target = NULL;
6374
for (p = details->icons; p != NULL; p = p->next) {
6376
if (icon->is_monitored) {
6377
nautilus_icon_container_stop_monitor_top_left (container,
6381
icon_free (p->data);
6383
g_list_free (details->icons);
6384
details->icons = NULL;
6385
g_list_free (details->new_icons);
6386
details->new_icons = NULL;
6388
g_hash_table_destroy (details->icon_set);
6389
details->icon_set = g_hash_table_new (g_direct_hash, g_direct_equal);
6391
nautilus_icon_container_update_scroll_region (container);
6395
nautilus_icon_container_is_empty (NautilusIconContainer *container)
6397
return container->details->icons == NULL;
6401
nautilus_icon_container_get_first_visible_icon (NautilusIconContainer *container)
6404
NautilusIcon *icon, *best_icon;
6406
double x1, y1, x2, y2;
6407
double *pos, best_pos;
6408
double hadj_v, vadj_v, h_page_size;
6409
gboolean better_icon;
6410
gboolean compare_lt;
6412
hadj_v = gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container)));
6413
vadj_v = gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container)));
6414
h_page_size = gtk_adjustment_get_page_size (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container)));
6416
if (nautilus_icon_container_is_layout_rtl (container)) {
6417
x = hadj_v + h_page_size - ICON_PAD_LEFT - 1;
6424
eel_canvas_c2w (EEL_CANVAS (container),
6428
l = container->details->icons;
6434
if (icon_is_positioned (icon)) {
6435
eel_canvas_item_get_bounds (EEL_CANVAS_ITEM (icon->item),
6436
&x1, &y1, &x2, &y2);
6439
if (nautilus_icon_container_is_layout_vertical (container)) {
6441
if (nautilus_icon_container_is_layout_rtl (container)) {
6443
better_icon = x1 < x + ICON_PAD_LEFT;
6445
better_icon = x2 > x + ICON_PAD_LEFT;
6449
better_icon = y2 > y + ICON_PAD_TOP;
6452
if (best_icon == NULL) {
6454
} else if (compare_lt) {
6455
better_icon = best_pos < *pos;
6457
better_icon = best_pos > *pos;
6470
return best_icon ? best_icon->data : NULL;
6473
/* puts the icon at the top of the screen */
6475
nautilus_icon_container_scroll_to_icon (NautilusIconContainer *container,
6476
NautilusIconData *data)
6480
GtkAdjustment *hadj, *vadj;
6482
GtkAllocation allocation;
6484
hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container));
6485
vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container));
6486
gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
6488
/* We need to force a relayout now if there are updates queued
6489
* since we need the final positions */
6490
nautilus_icon_container_layout_now (container);
6492
l = container->details->icons;
6496
if (icon->data == data &&
6497
icon_is_positioned (icon)) {
6499
if (nautilus_icon_container_is_auto_layout (container)) {
6500
/* ensure that we reveal the entire row/column */
6501
icon_get_row_and_column_bounds (container, icon, &bounds, TRUE);
6503
item_get_canvas_bounds (EEL_CANVAS_ITEM (icon->item), &bounds, TRUE);
6506
if (nautilus_icon_container_is_layout_vertical (container)) {
6507
if (nautilus_icon_container_is_layout_rtl (container)) {
6508
gtk_adjustment_set_value (hadj, bounds.x1 - allocation.width);
6510
gtk_adjustment_set_value (hadj, bounds.x0);
6513
gtk_adjustment_set_value (vadj, bounds.y0);
6521
/* Call a function for all the icons. */
6523
NautilusIconCallback callback;
6524
gpointer callback_data;
6528
call_icon_callback (gpointer data, gpointer callback_data)
6531
CallbackAndData *callback_and_data;
6534
callback_and_data = callback_data;
6535
(* callback_and_data->callback) (icon->data, callback_and_data->callback_data);
6539
nautilus_icon_container_for_each (NautilusIconContainer *container,
6540
NautilusIconCallback callback,
6541
gpointer callback_data)
6543
CallbackAndData callback_and_data;
6545
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
6547
callback_and_data.callback = callback;
6548
callback_and_data.callback_data = callback_data;
6550
g_list_foreach (container->details->icons,
6551
call_icon_callback, &callback_and_data);
6555
selection_changed_at_idle_callback (gpointer data)
6557
NautilusIconContainer *container;
6559
container = NAUTILUS_ICON_CONTAINER (data);
6561
g_signal_emit (container,
6562
signals[SELECTION_CHANGED], 0);
6564
container->details->selection_changed_id = 0;
6568
/* utility routine to remove a single icon from the container */
6571
icon_destroy (NautilusIconContainer *container,
6574
NautilusIconContainerDetails *details;
6575
gboolean was_selected;
6576
NautilusIcon *icon_to_focus;
6579
details = container->details;
6581
item = g_list_find (details->icons, icon);
6582
item = item->next ? item->next : item->prev;
6583
icon_to_focus = (item != NULL) ? item->data : NULL;
6585
details->icons = g_list_remove (details->icons, icon);
6586
details->new_icons = g_list_remove (details->new_icons, icon);
6587
g_hash_table_remove (details->icon_set, icon->data);
6589
was_selected = icon->is_selected;
6591
if (details->keyboard_focus == icon ||
6592
details->keyboard_focus == NULL) {
6593
if (icon_to_focus != NULL) {
6594
set_keyboard_focus (container, icon_to_focus);
6596
clear_keyboard_focus (container);
6600
if (details->keyboard_rubberband_start == icon) {
6601
clear_keyboard_rubberband_start (container);
6604
if (details->keyboard_icon_to_reveal == icon) {
6605
unschedule_keyboard_icon_reveal (container);
6607
if (details->drag_icon == icon) {
6608
clear_drag_state (container);
6610
if (details->drop_target == icon) {
6611
details->drop_target = NULL;
6613
if (details->range_selection_base_icon == icon) {
6614
details->range_selection_base_icon = NULL;
6616
if (details->pending_icon_to_reveal == icon) {
6617
set_pending_icon_to_reveal (container, NULL);
6619
if (details->stretch_icon == icon) {
6620
details->stretch_icon = NULL;
6623
if (icon->is_monitored) {
6624
nautilus_icon_container_stop_monitor_top_left (container,
6631
/* Coalesce multiple removals causing multiple selection_changed events */
6632
details->selection_changed_id = g_idle_add (selection_changed_at_idle_callback, container);
6636
/* activate any selected items in the container */
6638
activate_selected_items (NautilusIconContainer *container)
6642
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
6644
selection = nautilus_icon_container_get_selection (container);
6645
if (selection != NULL) {
6646
g_signal_emit (container,
6647
signals[ACTIVATE], 0,
6650
g_list_free (selection);
6654
preview_selected_items (NautilusIconContainer *container)
6660
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
6662
selection = nautilus_icon_container_get_selection (container);
6663
locations = nautilus_icon_container_get_selected_icon_locations (container);
6665
for (idx = 0; idx < locations->len; idx++) {
6666
GdkPoint *point = &(g_array_index (locations, GdkPoint, idx));
6667
gint scroll_x, scroll_y;
6669
eel_canvas_get_scroll_offsets (EEL_CANVAS (container),
6670
&scroll_x, &scroll_y);
6672
point->x -= scroll_x;
6673
point->y -= scroll_y;
6676
if (selection != NULL) {
6677
g_signal_emit (container,
6678
signals[ACTIVATE_PREVIEWER], 0,
6679
selection, locations);
6681
g_list_free (selection);
6685
activate_selected_items_alternate (NautilusIconContainer *container,
6690
g_assert (NAUTILUS_IS_ICON_CONTAINER (container));
6693
selection = g_list_prepend (NULL, icon->data);
6695
selection = nautilus_icon_container_get_selection (container);
6697
if (selection != NULL) {
6698
g_signal_emit (container,
6699
signals[ACTIVATE_ALTERNATE], 0,
6702
g_list_free (selection);
6705
static NautilusIcon *
6706
get_icon_being_renamed (NautilusIconContainer *container)
6708
NautilusIcon *rename_icon;
6710
if (!is_renaming (container)) {
6714
g_assert (!has_multiple_selection (container));
6716
rename_icon = get_first_selected_icon (container);
6717
g_assert (rename_icon != NULL);
6722
static NautilusIconInfo *
6723
nautilus_icon_container_get_icon_images (NautilusIconContainer *container,
6724
NautilusIconData *data,
6726
char **embedded_text,
6727
gboolean for_drag_accept,
6728
gboolean need_large_embeddded_text,
6729
gboolean *embedded_text_needs_loading,
6730
gboolean *has_open_window)
6732
NautilusIconContainerClass *klass;
6734
klass = NAUTILUS_ICON_CONTAINER_GET_CLASS (container);
6735
g_assert (klass->get_icon_images != NULL);
6737
return klass->get_icon_images (container, data, size, embedded_text, for_drag_accept, need_large_embeddded_text, embedded_text_needs_loading, has_open_window);
6741
nautilus_icon_container_freeze_updates (NautilusIconContainer *container)
6743
NautilusIconContainerClass *klass;
6745
klass = NAUTILUS_ICON_CONTAINER_GET_CLASS (container);
6746
g_assert (klass->freeze_updates != NULL);
6748
klass->freeze_updates (container);
6752
nautilus_icon_container_unfreeze_updates (NautilusIconContainer *container)
6754
NautilusIconContainerClass *klass;
6756
klass = NAUTILUS_ICON_CONTAINER_GET_CLASS (container);
6757
g_assert (klass->unfreeze_updates != NULL);
6759
klass->unfreeze_updates (container);
6763
nautilus_icon_container_start_monitor_top_left (NautilusIconContainer *container,
6764
NautilusIconData *data,
6765
gconstpointer client,
6766
gboolean large_text)
6768
NautilusIconContainerClass *klass;
6770
klass = NAUTILUS_ICON_CONTAINER_GET_CLASS (container);
6771
g_assert (klass->start_monitor_top_left != NULL);
6773
klass->start_monitor_top_left (container, data, client, large_text);
6777
nautilus_icon_container_stop_monitor_top_left (NautilusIconContainer *container,
6778
NautilusIconData *data,
6779
gconstpointer client)
6781
NautilusIconContainerClass *klass;
6783
klass = NAUTILUS_ICON_CONTAINER_GET_CLASS (container);
6784
g_return_if_fail (klass->stop_monitor_top_left != NULL);
6786
klass->stop_monitor_top_left (container, data, client);
6791
nautilus_icon_container_prioritize_thumbnailing (NautilusIconContainer *container,
6794
NautilusIconContainerClass *klass;
6796
klass = NAUTILUS_ICON_CONTAINER_GET_CLASS (container);
6797
g_assert (klass->prioritize_thumbnailing != NULL);
6799
klass->prioritize_thumbnailing (container, icon->data);
6803
nautilus_icon_container_update_visible_icons (NautilusIconContainer *container)
6805
GtkAdjustment *vadj, *hadj;
6806
double min_y, max_y;
6807
double min_x, max_x;
6808
double x0, y0, x1, y1;
6812
GtkAllocation allocation;
6814
hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container));
6815
vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container));
6816
gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
6818
min_x = gtk_adjustment_get_value (hadj);
6819
max_x = min_x + allocation.width;
6821
min_y = gtk_adjustment_get_value (vadj);
6822
max_y = min_y + allocation.height;
6824
eel_canvas_c2w (EEL_CANVAS (container),
6825
min_x, min_y, &min_x, &min_y);
6826
eel_canvas_c2w (EEL_CANVAS (container),
6827
max_x, max_y, &max_x, &max_y);
6829
/* Do the iteration in reverse to get the render-order from top to
6830
* bottom for the prioritized thumbnails.
6832
for (node = g_list_last (container->details->icons); node != NULL; node = node->prev) {
6835
if (icon_is_positioned (icon)) {
6836
eel_canvas_item_get_bounds (EEL_CANVAS_ITEM (icon->item),
6841
eel_canvas_item_i2w (EEL_CANVAS_ITEM (icon->item)->parent,
6844
eel_canvas_item_i2w (EEL_CANVAS_ITEM (icon->item)->parent,
6848
if (nautilus_icon_container_is_layout_vertical (container)) {
6849
visible = x1 >= min_x && x0 <= max_x;
6851
visible = y1 >= min_y && y0 <= max_y;
6855
nautilus_icon_canvas_item_set_is_visible (icon->item, TRUE);
6856
nautilus_icon_container_prioritize_thumbnailing (container,
6859
nautilus_icon_canvas_item_set_is_visible (icon->item, FALSE);
6866
handle_vadjustment_changed (GtkAdjustment *adjustment,
6867
NautilusIconContainer *container)
6869
if (!nautilus_icon_container_is_layout_vertical (container)) {
6870
nautilus_icon_container_update_visible_icons (container);
6875
handle_hadjustment_changed (GtkAdjustment *adjustment,
6876
NautilusIconContainer *container)
6878
if (nautilus_icon_container_is_layout_vertical (container)) {
6879
nautilus_icon_container_update_visible_icons (container);
6885
nautilus_icon_container_update_icon (NautilusIconContainer *container,
6888
NautilusIconContainerDetails *details;
6890
guint min_image_size, max_image_size;
6891
NautilusIconInfo *icon_info;
6892
GdkPoint *attach_points;
6893
int n_attach_points;
6894
gboolean has_embedded_text_rect;
6896
char *editable_text, *additional_text;
6897
char *embedded_text;
6898
GdkRectangle embedded_text_rect;
6899
gboolean large_embedded_text;
6900
gboolean embedded_text_needs_loading;
6901
gboolean has_open_window;
6907
details = container->details;
6909
/* compute the maximum size based on the scale factor */
6910
min_image_size = MINIMUM_IMAGE_SIZE * EEL_CANVAS (container)->pixels_per_unit;
6911
max_image_size = MAX (MAXIMUM_IMAGE_SIZE * EEL_CANVAS (container)->pixels_per_unit, NAUTILUS_ICON_MAXIMUM_SIZE);
6913
/* Get the appropriate images for the file. */
6914
if (container->details->forced_icon_size > 0) {
6915
icon_size = container->details->forced_icon_size;
6917
icon_get_size (container, icon, &icon_size);
6921
icon_size = MAX (icon_size, min_image_size);
6922
icon_size = MIN (icon_size, max_image_size);
6924
DEBUG ("Icon size, getting for size %d", icon_size);
6926
/* Get the icons. */
6927
embedded_text = NULL;
6928
large_embedded_text = icon_size > ICON_SIZE_FOR_LARGE_EMBEDDED_TEXT;
6929
icon_info = nautilus_icon_container_get_icon_images (container, icon->data, icon_size,
6931
icon == details->drop_target,
6932
large_embedded_text, &embedded_text_needs_loading,
6935
if (container->details->forced_icon_size > 0) {
6936
pixbuf = nautilus_icon_info_get_pixbuf_at_size (icon_info, icon_size);
6938
pixbuf = nautilus_icon_info_get_pixbuf (icon_info);
6941
nautilus_icon_info_get_attach_points (icon_info, &attach_points, &n_attach_points);
6942
has_embedded_text_rect = nautilus_icon_info_get_embedded_rect (icon_info,
6943
&embedded_text_rect);
6945
g_object_unref (icon_info);
6947
if (has_embedded_text_rect && embedded_text_needs_loading) {
6948
icon->is_monitored = TRUE;
6949
nautilus_icon_container_start_monitor_top_left (container, icon->data, icon, large_embedded_text);
6952
nautilus_icon_container_get_icon_text (container,
6958
/* If name of icon being renamed was changed from elsewhere, end renaming mode.
6959
* Alternatively, we could replace the characters in the editable text widget
6960
* with the new name, but that could cause timing problems if the user just
6961
* happened to be typing at that moment.
6963
if (icon == get_icon_being_renamed (container) &&
6964
g_strcmp0 (editable_text,
6965
nautilus_icon_canvas_item_get_editable_text (icon->item)) != 0) {
6966
end_renaming_mode (container, FALSE);
6969
eel_canvas_item_set (EEL_CANVAS_ITEM (icon->item),
6970
"editable_text", editable_text,
6971
"additional_text", additional_text,
6972
"highlighted_for_drop", icon == details->drop_target,
6975
nautilus_icon_canvas_item_set_image (icon->item, pixbuf);
6976
nautilus_icon_canvas_item_set_attach_points (icon->item, attach_points, n_attach_points);
6977
nautilus_icon_canvas_item_set_embedded_text_rect (icon->item, &embedded_text_rect);
6978
nautilus_icon_canvas_item_set_embedded_text (icon->item, embedded_text);
6980
/* Let the pixbufs go. */
6981
g_object_unref (pixbuf);
6983
g_free (editable_text);
6984
g_free (additional_text);
6988
assign_icon_position (NautilusIconContainer *container,
6991
gboolean have_stored_position;
6992
NautilusIconPosition position;
6994
/* Get the stored position. */
6995
have_stored_position = FALSE;
6996
position.scale = 1.0;
6997
g_signal_emit (container,
6998
signals[GET_STORED_ICON_POSITION], 0,
7001
&have_stored_position);
7002
icon->scale = position.scale;
7003
if (!container->details->auto_layout) {
7004
if (have_stored_position) {
7005
icon_set_position (icon, position.x, position.y);
7006
icon->saved_ltr_x = icon->x;
7015
finish_adding_icon (NautilusIconContainer *container,
7018
nautilus_icon_container_update_icon (container, icon);
7019
eel_canvas_item_show (EEL_CANVAS_ITEM (icon->item));
7021
g_signal_connect_object (icon->item, "event",
7022
G_CALLBACK (item_event_callback), container, 0);
7024
g_signal_emit (container, signals[ICON_ADDED], 0, icon->data);
7028
finish_adding_new_icons (NautilusIconContainer *container)
7030
GList *p, *new_icons, *no_position_icons, *semi_position_icons;
7034
new_icons = container->details->new_icons;
7035
container->details->new_icons = NULL;
7037
/* Position most icons (not unpositioned manual-layout icons). */
7038
new_icons = g_list_reverse (new_icons);
7039
no_position_icons = semi_position_icons = NULL;
7040
for (p = new_icons; p != NULL; p = p->next) {
7042
if (icon->has_lazy_position) {
7043
assign_icon_position (container, icon);
7044
semi_position_icons = g_list_prepend (semi_position_icons, icon);
7045
} else if (!assign_icon_position (container, icon)) {
7046
no_position_icons = g_list_prepend (no_position_icons, icon);
7049
finish_adding_icon (container, icon);
7051
g_list_free (new_icons);
7053
if (semi_position_icons != NULL) {
7054
PlacementGrid *grid;
7058
g_assert (!container->details->auto_layout);
7060
semi_position_icons = g_list_reverse (semi_position_icons);
7062
/* This is currently only used on the desktop.
7063
* Thus, we pass FALSE for tight, like lay_down_icons_tblr */
7064
grid = placement_grid_new (container, FALSE);
7066
for (p = container->details->icons; p != NULL; p = p->next) {
7069
if (icon_is_positioned (icon) && !icon->has_lazy_position) {
7070
placement_grid_mark_icon (grid, icon);
7076
for (p = semi_position_icons; p != NULL; p = p->next) {
7078
NautilusIconPosition position;
7085
find_empty_location (container, grid,
7086
icon, x, y, &x, &y);
7088
icon_set_position (icon, x, y);
7090
position.x = icon->x;
7091
position.y = icon->y;
7092
position.scale = icon->scale;
7093
placement_grid_mark_icon (grid, icon);
7094
g_signal_emit (container, signals[ICON_POSITION_CHANGED], 0,
7095
icon->data, &position);
7096
g_signal_emit (container, signals[STORE_LAYOUT_TIMESTAMP], 0,
7097
icon->data, &now, &dummy);
7099
/* ensure that next time we run this code, the formerly semi-positioned
7100
* icons are treated as being positioned. */
7101
icon->has_lazy_position = FALSE;
7104
placement_grid_free (grid);
7106
g_list_free (semi_position_icons);
7109
/* Position the unpositioned manual layout icons. */
7110
if (no_position_icons != NULL) {
7111
g_assert (!container->details->auto_layout);
7113
sort_icons (container, &no_position_icons);
7114
if (nautilus_icon_container_get_is_desktop (container)) {
7115
lay_down_icons (container, no_position_icons, CONTAINER_PAD_TOP);
7117
get_all_icon_bounds (container, NULL, NULL, NULL, &bottom, BOUNDS_USAGE_FOR_LAYOUT);
7118
lay_down_icons (container, no_position_icons, bottom + ICON_PAD_BOTTOM);
7120
g_list_free (no_position_icons);
7123
if (container->details->store_layout_timestamps_when_finishing_new_icons) {
7124
store_layout_timestamps_now (container);
7125
container->details->store_layout_timestamps_when_finishing_new_icons = FALSE;
7130
is_old_or_unknown_icon_data (NautilusIconContainer *container,
7131
NautilusIconData *data)
7136
if (container->details->layout_timestamp == UNDEFINED_TIME) {
7141
g_signal_emit (container,
7142
signals[GET_STORED_LAYOUT_TIMESTAMP], 0,
7143
data, ×tamp, &success);
7144
return (!success || timestamp < container->details->layout_timestamp);
7148
* nautilus_icon_container_add:
7149
* @container: A NautilusIconContainer
7152
* Add icon to represent @data to container.
7153
* Returns FALSE if there was already such an icon.
7156
nautilus_icon_container_add (NautilusIconContainer *container,
7157
NautilusIconData *data)
7159
NautilusIconContainerDetails *details;
7161
EelCanvasItem *band, *item;
7163
g_return_val_if_fail (NAUTILUS_IS_ICON_CONTAINER (container), FALSE);
7164
g_return_val_if_fail (data != NULL, FALSE);
7166
details = container->details;
7168
if (g_hash_table_lookup (details->icon_set, data) != NULL) {
7172
/* Create the new icon, including the canvas item. */
7173
icon = g_new0 (NautilusIcon, 1);
7175
icon->x = ICON_UNPOSITIONED_VALUE;
7176
icon->y = ICON_UNPOSITIONED_VALUE;
7178
/* Whether the saved icon position should only be used
7179
* if the previous icon position is free. If the position
7180
* is occupied, another position near the last one will
7182
icon->has_lazy_position = is_old_or_unknown_icon_data (container, data);
7184
icon->item = NAUTILUS_ICON_CANVAS_ITEM
7185
(eel_canvas_item_new (EEL_CANVAS_GROUP (EEL_CANVAS (container)->root),
7186
nautilus_icon_canvas_item_get_type (),
7189
icon->item->user_data = icon;
7191
/* Make sure the icon is under the selection_rectangle */
7192
item = EEL_CANVAS_ITEM (icon->item);
7193
band = NAUTILUS_ICON_CONTAINER (item->canvas)->details->rubberband_info.selection_rectangle;
7195
eel_canvas_item_send_behind (item, band);
7198
/* Put it on both lists. */
7199
details->icons = g_list_prepend (details->icons, icon);
7200
details->new_icons = g_list_prepend (details->new_icons, icon);
7202
g_hash_table_insert (details->icon_set, data, icon);
7204
details->needs_resort = TRUE;
7206
/* Run an idle function to add the icons. */
7207
schedule_redo_layout (container);
7213
nautilus_icon_container_layout_now (NautilusIconContainer *container)
7215
if (container->details->idle_id != 0) {
7216
unschedule_redo_layout (container);
7217
redo_layout_internal (container);
7220
/* Also need to make sure we're properly resized, for instance
7221
* newly added files may trigger a change in the size allocation and
7222
* thus toggle scrollbars on */
7223
gtk_container_check_resize (GTK_CONTAINER (gtk_widget_get_parent (GTK_WIDGET (container))));
7227
* nautilus_icon_container_remove:
7228
* @container: A NautilusIconContainer.
7231
* Remove the icon with this data.
7234
nautilus_icon_container_remove (NautilusIconContainer *container,
7235
NautilusIconData *data)
7239
g_return_val_if_fail (NAUTILUS_IS_ICON_CONTAINER (container), FALSE);
7240
g_return_val_if_fail (data != NULL, FALSE);
7242
end_renaming_mode (container, FALSE);
7244
icon = g_hash_table_lookup (container->details->icon_set, data);
7250
icon_destroy (container, icon);
7251
schedule_redo_layout (container);
7253
g_signal_emit (container, signals[ICON_REMOVED], 0, icon);
7259
* nautilus_icon_container_request_update:
7260
* @container: A NautilusIconContainer.
7263
* Update the icon with this data.
7266
nautilus_icon_container_request_update (NautilusIconContainer *container,
7267
NautilusIconData *data)
7271
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
7272
g_return_if_fail (data != NULL);
7274
icon = g_hash_table_lookup (container->details->icon_set, data);
7277
nautilus_icon_container_update_icon (container, icon);
7278
container->details->needs_resort = TRUE;
7279
schedule_redo_layout (container);
7286
nautilus_icon_container_get_zoom_level (NautilusIconContainer *container)
7288
return container->details->zoom_level;
7292
nautilus_icon_container_set_zoom_level (NautilusIconContainer *container, int new_level)
7294
NautilusIconContainerDetails *details;
7296
double pixels_per_unit;
7298
details = container->details;
7300
end_renaming_mode (container, TRUE);
7302
pinned_level = new_level;
7303
if (pinned_level < NAUTILUS_ZOOM_LEVEL_SMALLEST) {
7304
pinned_level = NAUTILUS_ZOOM_LEVEL_SMALLEST;
7305
} else if (pinned_level > NAUTILUS_ZOOM_LEVEL_LARGEST) {
7306
pinned_level = NAUTILUS_ZOOM_LEVEL_LARGEST;
7309
if (pinned_level == details->zoom_level) {
7313
details->zoom_level = pinned_level;
7315
pixels_per_unit = (double) nautilus_get_icon_size_for_zoom_level (pinned_level)
7316
/ NAUTILUS_ICON_SIZE_STANDARD;
7317
eel_canvas_set_pixels_per_unit (EEL_CANVAS (container), pixels_per_unit);
7319
invalidate_labels (container);
7320
nautilus_icon_container_request_update_all (container);
7324
* nautilus_icon_container_request_update_all:
7325
* For each icon, synchronizes the displayed information (image, text) with the
7326
* information from the model.
7328
* @container: An icon container.
7331
nautilus_icon_container_request_update_all (NautilusIconContainer *container)
7336
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
7338
for (node = container->details->icons; node != NULL; node = node->next) {
7340
nautilus_icon_container_update_icon (container, icon);
7343
container->details->needs_resort = TRUE;
7344
redo_layout (container);
7348
* nautilus_icon_container_reveal:
7349
* Change scroll position as necessary to reveal the specified item.
7352
nautilus_icon_container_reveal (NautilusIconContainer *container, NautilusIconData *data)
7356
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
7357
g_return_if_fail (data != NULL);
7359
icon = g_hash_table_lookup (container->details->icon_set, data);
7362
reveal_icon (container, icon);
7367
* nautilus_icon_container_get_selection:
7368
* @container: An icon container.
7370
* Get a list of the icons currently selected in @container.
7372
* Return value: A GList of the programmer-specified data associated to each
7373
* selected icon, or NULL if no icon is selected. The caller is expected to
7374
* free the list when it is not needed anymore.
7377
nautilus_icon_container_get_selection (NautilusIconContainer *container)
7381
g_return_val_if_fail (NAUTILUS_IS_ICON_CONTAINER (container), NULL);
7384
for (p = container->details->icons; p != NULL; p = p->next) {
7388
if (icon->is_selected) {
7389
list = g_list_prepend (list, icon->data);
7393
return g_list_reverse (list);
7397
nautilus_icon_container_get_selected_icons (NautilusIconContainer *container)
7401
g_return_val_if_fail (NAUTILUS_IS_ICON_CONTAINER (container), NULL);
7404
for (p = container->details->icons; p != NULL; p = p->next) {
7408
if (icon->is_selected) {
7409
list = g_list_prepend (list, icon);
7413
return g_list_reverse (list);
7417
* nautilus_icon_container_invert_selection:
7418
* @container: An icon container.
7420
* Inverts the selection in @container.
7424
nautilus_icon_container_invert_selection (NautilusIconContainer *container)
7428
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
7430
for (p = container->details->icons; p != NULL; p = p->next) {
7434
icon_toggle_selected (container, icon);
7437
g_signal_emit (container, signals[SELECTION_CHANGED], 0);
7441
/* Returns an array of GdkPoints of locations of the icons. */
7443
nautilus_icon_container_get_icon_locations (NautilusIconContainer *container,
7450
result = g_array_new (FALSE, TRUE, sizeof (GdkPoint));
7451
result = g_array_set_size (result, g_list_length (icons));
7453
for (index = 0, node = icons; node != NULL; index++, node = node->next) {
7454
g_array_index (result, GdkPoint, index).x =
7455
((NautilusIcon *)node->data)->x;
7456
g_array_index (result, GdkPoint, index).y =
7457
((NautilusIcon *)node->data)->y;
7464
* nautilus_icon_container_get_selected_icon_locations:
7465
* @container: An icon container widget.
7467
* Returns an array of GdkPoints of locations of the selected icons.
7470
nautilus_icon_container_get_selected_icon_locations (NautilusIconContainer *container)
7475
g_return_val_if_fail (NAUTILUS_IS_ICON_CONTAINER (container), NULL);
7477
icons = nautilus_icon_container_get_selected_icons (container);
7478
result = nautilus_icon_container_get_icon_locations (container, icons);
7479
g_list_free (icons);
7485
* nautilus_icon_container_select_all:
7486
* @container: An icon container widget.
7488
* Select all the icons in @container at once.
7491
nautilus_icon_container_select_all (NautilusIconContainer *container)
7493
gboolean selection_changed;
7497
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
7499
selection_changed = FALSE;
7501
for (p = container->details->icons; p != NULL; p = p->next) {
7504
selection_changed |= icon_set_selected (container, icon, TRUE);
7507
if (selection_changed) {
7508
g_signal_emit (container,
7509
signals[SELECTION_CHANGED], 0);
7514
* nautilus_icon_container_set_selection:
7515
* @container: An icon container widget.
7516
* @selection: A list of NautilusIconData *.
7518
* Set the selection to exactly the icons in @container which have
7519
* programmer data matching one of the items in @selection.
7522
nautilus_icon_container_set_selection (NautilusIconContainer *container,
7525
gboolean selection_changed;
7530
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
7532
selection_changed = FALSE;
7534
hash = g_hash_table_new (NULL, NULL);
7535
for (p = selection; p != NULL; p = p->next) {
7536
g_hash_table_insert (hash, p->data, p->data);
7538
for (p = container->details->icons; p != NULL; p = p->next) {
7541
selection_changed |= icon_set_selected
7543
g_hash_table_lookup (hash, icon->data) != NULL);
7545
g_hash_table_destroy (hash);
7547
if (selection_changed) {
7548
g_signal_emit (container,
7549
signals[SELECTION_CHANGED], 0);
7554
* nautilus_icon_container_select_list_unselect_others.
7555
* @container: An icon container widget.
7556
* @selection: A list of NautilusIcon *.
7558
* Set the selection to exactly the icons in @selection.
7561
nautilus_icon_container_select_list_unselect_others (NautilusIconContainer *container,
7564
gboolean selection_changed;
7569
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
7571
selection_changed = FALSE;
7573
hash = g_hash_table_new (NULL, NULL);
7574
for (p = selection; p != NULL; p = p->next) {
7575
g_hash_table_insert (hash, p->data, p->data);
7577
for (p = container->details->icons; p != NULL; p = p->next) {
7580
selection_changed |= icon_set_selected
7582
g_hash_table_lookup (hash, icon) != NULL);
7584
g_hash_table_destroy (hash);
7586
if (selection_changed) {
7587
g_signal_emit (container,
7588
signals[SELECTION_CHANGED], 0);
7593
* nautilus_icon_container_unselect_all:
7594
* @container: An icon container widget.
7596
* Deselect all the icons in @container.
7599
nautilus_icon_container_unselect_all (NautilusIconContainer *container)
7601
if (unselect_all (container)) {
7602
g_signal_emit (container,
7603
signals[SELECTION_CHANGED], 0);
7608
* nautilus_icon_container_get_icon_by_uri:
7609
* @container: An icon container widget.
7610
* @uri: The uri of an icon to find.
7612
* Locate an icon, given the URI. The URI must match exactly.
7613
* Later we may have to have some way of figuring out if the
7614
* URI specifies the same object that does not require an exact match.
7617
nautilus_icon_container_get_icon_by_uri (NautilusIconContainer *container,
7620
NautilusIconContainerDetails *details;
7623
/* Eventually, we must avoid searching the entire icon list,
7624
but it's OK for now.
7625
A hash table mapping uri to icon is one possibility.
7628
details = container->details;
7630
for (p = details->icons; p != NULL; p = p->next) {
7637
icon_uri = nautilus_icon_container_get_icon_uri
7639
is_match = strcmp (uri, icon_uri) == 0;
7650
static NautilusIcon *
7651
get_nth_selected_icon (NautilusIconContainer *container, int index)
7655
int selection_count;
7657
g_assert (index > 0);
7659
/* Find the nth selected icon. */
7660
selection_count = 0;
7661
for (p = container->details->icons; p != NULL; p = p->next) {
7663
if (icon->is_selected) {
7664
if (++selection_count == index) {
7672
static NautilusIcon *
7673
get_first_selected_icon (NautilusIconContainer *container)
7675
return get_nth_selected_icon (container, 1);
7679
has_multiple_selection (NautilusIconContainer *container)
7681
return get_nth_selected_icon (container, 2) != NULL;
7685
all_selected (NautilusIconContainer *container)
7690
for (p = container->details->icons; p != NULL; p = p->next) {
7692
if (!icon->is_selected) {
7700
has_selection (NautilusIconContainer *container)
7702
return get_nth_selected_icon (container, 1) != NULL;
7706
* nautilus_icon_container_show_stretch_handles:
7707
* @container: An icon container widget.
7709
* Makes stretch handles visible on the first selected icon.
7712
nautilus_icon_container_show_stretch_handles (NautilusIconContainer *container)
7714
NautilusIconContainerDetails *details;
7718
icon = get_first_selected_icon (container);
7723
/* Check if it already has stretch handles. */
7724
details = container->details;
7725
if (details->stretch_icon == icon) {
7729
/* Get rid of the existing stretch handles and put them on the new icon. */
7730
if (details->stretch_icon != NULL) {
7731
nautilus_icon_canvas_item_set_show_stretch_handles
7732
(details->stretch_icon->item, FALSE);
7733
ungrab_stretch_icon (container);
7734
emit_stretch_ended (container, details->stretch_icon);
7736
nautilus_icon_canvas_item_set_show_stretch_handles (icon->item, TRUE);
7737
details->stretch_icon = icon;
7739
icon_get_size (container, icon, &initial_size);
7741
/* only need to keep size in one dimension, since they are constrained to be the same */
7742
container->details->stretch_initial_x = icon->x;
7743
container->details->stretch_initial_y = icon->y;
7744
container->details->stretch_initial_size = initial_size;
7746
emit_stretch_started (container, icon);
7750
* nautilus_icon_container_has_stretch_handles
7751
* @container: An icon container widget.
7753
* Returns true if the first selected item has stretch handles.
7756
nautilus_icon_container_has_stretch_handles (NautilusIconContainer *container)
7760
icon = get_first_selected_icon (container);
7765
return icon == container->details->stretch_icon;
7769
* nautilus_icon_container_is_stretched
7770
* @container: An icon container widget.
7772
* Returns true if the any selected item is stretched to a size other than 1.0.
7775
nautilus_icon_container_is_stretched (NautilusIconContainer *container)
7780
for (p = container->details->icons; p != NULL; p = p->next) {
7782
if (icon->is_selected && icon->scale != 1.0) {
7790
* nautilus_icon_container_unstretch
7791
* @container: An icon container widget.
7793
* Gets rid of any icon stretching.
7796
nautilus_icon_container_unstretch (NautilusIconContainer *container)
7801
for (p = container->details->icons; p != NULL; p = p->next) {
7803
if (icon->is_selected) {
7804
nautilus_icon_container_move_icon (container, icon,
7813
compute_stretch (StretchState *start,
7814
StretchState *current)
7816
gboolean right, bottom;
7817
int x_stretch, y_stretch;
7819
/* FIXME bugzilla.gnome.org 45390: This doesn't correspond to
7820
* the way the handles are drawn.
7822
/* Figure out which handle we are dragging. */
7823
right = start->pointer_x > start->icon_x + (int) start->icon_size / 2;
7824
bottom = start->pointer_y > start->icon_y + (int) start->icon_size / 2;
7826
/* Figure out how big we should stretch. */
7827
x_stretch = start->pointer_x - current->pointer_x;
7828
y_stretch = start->pointer_y - current->pointer_y;
7830
x_stretch = - x_stretch;
7833
y_stretch = - y_stretch;
7835
current->icon_size = MAX ((int) start->icon_size + MIN (x_stretch, y_stretch),
7836
(int) NAUTILUS_ICON_SIZE_SMALLEST);
7838
/* Figure out where the corner of the icon should be. */
7839
current->icon_x = start->icon_x;
7841
current->icon_x += start->icon_size - current->icon_size;
7843
current->icon_y = start->icon_y;
7845
current->icon_y += start->icon_size - current->icon_size;
7850
nautilus_icon_container_get_icon_uri (NautilusIconContainer *container,
7856
g_signal_emit (container,
7857
signals[GET_ICON_URI], 0,
7864
nautilus_icon_container_get_icon_drop_target_uri (NautilusIconContainer *container,
7870
g_signal_emit (container,
7871
signals[GET_ICON_DROP_TARGET_URI], 0,
7877
/* Call to reset the scroll region only if the container is not empty,
7878
* to avoid having the flag linger until the next file is added.
7881
reset_scroll_region_if_not_empty (NautilusIconContainer *container)
7883
if (!nautilus_icon_container_is_empty (container)) {
7884
nautilus_icon_container_reset_scroll_region (container);
7888
/* Switch from automatic layout to manual or vice versa.
7889
* If we switch to manual layout, we restore the icon positions from the
7890
* last manual layout.
7893
nautilus_icon_container_set_auto_layout (NautilusIconContainer *container,
7894
gboolean auto_layout)
7896
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
7897
g_return_if_fail (auto_layout == FALSE || auto_layout == TRUE);
7899
if (container->details->auto_layout == auto_layout) {
7903
reset_scroll_region_if_not_empty (container);
7904
container->details->auto_layout = auto_layout;
7907
reload_icon_positions (container);
7908
nautilus_icon_container_freeze_icon_positions (container);
7911
container->details->needs_resort = TRUE;
7912
redo_layout (container);
7914
g_signal_emit (container, signals[LAYOUT_CHANGED], 0);
7918
nautilus_icon_container_is_keep_aligned (NautilusIconContainer *container)
7920
return container->details->keep_aligned;
7924
align_icons_callback (gpointer callback_data)
7926
NautilusIconContainer *container;
7928
container = NAUTILUS_ICON_CONTAINER (callback_data);
7929
align_icons (container);
7930
container->details->align_idle_id = 0;
7936
unschedule_align_icons (NautilusIconContainer *container)
7938
if (container->details->align_idle_id != 0) {
7939
g_source_remove (container->details->align_idle_id);
7940
container->details->align_idle_id = 0;
7945
schedule_align_icons (NautilusIconContainer *container)
7947
if (container->details->align_idle_id == 0
7948
&& container->details->has_been_allocated) {
7949
container->details->align_idle_id = g_idle_add
7950
(align_icons_callback, container);
7955
nautilus_icon_container_set_keep_aligned (NautilusIconContainer *container,
7956
gboolean keep_aligned)
7958
if (container->details->keep_aligned != keep_aligned) {
7959
container->details->keep_aligned = keep_aligned;
7961
if (keep_aligned && !container->details->auto_layout) {
7962
schedule_align_icons (container);
7964
unschedule_align_icons (container);
7970
nautilus_icon_container_set_layout_mode (NautilusIconContainer *container,
7971
NautilusIconLayoutMode mode)
7973
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
7975
container->details->layout_mode = mode;
7976
invalidate_labels (container);
7978
container->details->needs_resort = TRUE;
7979
redo_layout (container);
7981
g_signal_emit (container, signals[LAYOUT_CHANGED], 0);
7985
nautilus_icon_container_set_label_position (NautilusIconContainer *container,
7986
NautilusIconLabelPosition position)
7988
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
7990
if (container->details->label_position != position) {
7991
container->details->label_position = position;
7993
invalidate_labels (container);
7994
nautilus_icon_container_request_update_all (container);
7996
schedule_redo_layout (container);
8000
/* Switch from automatic to manual layout, freezing all the icons in their
8001
* current positions instead of restoring icon positions from the last manual
8002
* layout as set_auto_layout does.
8005
nautilus_icon_container_freeze_icon_positions (NautilusIconContainer *container)
8010
NautilusIconPosition position;
8012
changed = container->details->auto_layout;
8013
container->details->auto_layout = FALSE;
8015
for (p = container->details->icons; p != NULL; p = p->next) {
8018
position.x = icon->saved_ltr_x;
8019
position.y = icon->y;
8020
position.scale = icon->scale;
8021
g_signal_emit (container, signals[ICON_POSITION_CHANGED], 0,
8022
icon->data, &position);
8026
g_signal_emit (container, signals[LAYOUT_CHANGED], 0);
8030
/* Re-sort, switching to automatic layout if it was in manual layout. */
8032
nautilus_icon_container_sort (NautilusIconContainer *container)
8036
changed = !container->details->auto_layout;
8037
container->details->auto_layout = TRUE;
8039
reset_scroll_region_if_not_empty (container);
8040
container->details->needs_resort = TRUE;
8041
redo_layout (container);
8044
g_signal_emit (container, signals[LAYOUT_CHANGED], 0);
8049
nautilus_icon_container_is_auto_layout (NautilusIconContainer *container)
8051
g_return_val_if_fail (NAUTILUS_IS_ICON_CONTAINER (container), FALSE);
8053
return container->details->auto_layout;
8057
pending_icon_to_rename_destroy_callback (NautilusIconCanvasItem *item, NautilusIconContainer *container)
8059
g_assert (container->details->pending_icon_to_rename != NULL);
8060
g_assert (container->details->pending_icon_to_rename->item == item);
8061
container->details->pending_icon_to_rename = NULL;
8064
static NautilusIcon*
8065
get_pending_icon_to_rename (NautilusIconContainer *container)
8067
return container->details->pending_icon_to_rename;
8071
set_pending_icon_to_rename (NautilusIconContainer *container, NautilusIcon *icon)
8073
NautilusIcon *old_icon;
8075
old_icon = container->details->pending_icon_to_rename;
8077
if (icon == old_icon) {
8081
if (old_icon != NULL) {
8082
g_signal_handlers_disconnect_by_func
8084
G_CALLBACK (pending_icon_to_rename_destroy_callback),
8089
g_signal_connect (icon->item, "destroy",
8090
G_CALLBACK (pending_icon_to_rename_destroy_callback), container);
8093
container->details->pending_icon_to_rename = icon;
8097
process_pending_icon_to_rename (NautilusIconContainer *container)
8099
NautilusIcon *pending_icon_to_rename;
8101
pending_icon_to_rename = get_pending_icon_to_rename (container);
8103
if (pending_icon_to_rename != NULL) {
8104
if (pending_icon_to_rename->is_selected && !has_multiple_selection (container)) {
8105
nautilus_icon_container_start_renaming_selected_item (container, FALSE);
8107
set_pending_icon_to_rename (container, NULL);
8113
is_renaming_pending (NautilusIconContainer *container)
8115
return get_pending_icon_to_rename (container) != NULL;
8119
is_renaming (NautilusIconContainer *container)
8121
return container->details->renaming;
8125
* nautilus_icon_container_start_renaming_selected_item
8126
* @container: An icon container widget.
8127
* @select_all: Whether the whole file should initially be selected, or
8128
* only its basename (i.e. everything except its extension).
8130
* Displays the edit name widget on the first selected icon
8133
nautilus_icon_container_start_renaming_selected_item (NautilusIconContainer *container,
8134
gboolean select_all)
8136
NautilusIconContainerDetails *details;
8140
PangoContext *context;
8141
PangoFontDescription *desc;
8142
const char *editable_text;
8144
int start_offset, end_offset;
8146
/* Check if it already in renaming mode, if so - select all */
8147
details = container->details;
8148
if (details->renaming) {
8149
eel_editable_label_select_region (EEL_EDITABLE_LABEL (details->rename_widget),
8155
/* Find selected icon */
8156
icon = get_first_selected_icon (container);
8161
g_assert (!has_multiple_selection (container));
8164
if (!icon_is_positioned (icon)) {
8165
set_pending_icon_to_rename (container, icon);
8169
set_pending_icon_to_rename (container, NULL);
8171
/* Make a copy of the original editable text for a later compare */
8172
editable_text = nautilus_icon_canvas_item_get_editable_text (icon->item);
8174
/* This could conceivably be NULL if a rename was triggered really early. */
8175
if (editable_text == NULL) {
8179
details->original_text = g_strdup (editable_text);
8181
/* Freeze updates so files added while renaming don't cause rename to loose focus, bug #318373 */
8182
nautilus_icon_container_freeze_updates (container);
8184
/* Create text renaming widget, if it hasn't been created already.
8185
* We deal with the broken icon text item widget by keeping it around
8186
* so its contents can still be cut and pasted as part of the clipboard
8188
if (details->rename_widget == NULL) {
8189
details->rename_widget = eel_editable_label_new ("Test text");
8190
eel_editable_label_set_line_wrap (EEL_EDITABLE_LABEL (details->rename_widget), TRUE);
8191
eel_editable_label_set_line_wrap_mode (EEL_EDITABLE_LABEL (details->rename_widget), PANGO_WRAP_WORD_CHAR);
8192
eel_editable_label_set_draw_outline (EEL_EDITABLE_LABEL (details->rename_widget), TRUE);
8194
if (details->label_position != NAUTILUS_ICON_LABEL_POSITION_BESIDE) {
8195
eel_editable_label_set_justify (EEL_EDITABLE_LABEL (details->rename_widget), GTK_JUSTIFY_CENTER);
8198
gtk_misc_set_padding (GTK_MISC (details->rename_widget), 1, 1);
8199
gtk_layout_put (GTK_LAYOUT (container),
8200
details->rename_widget, 0, 0);
8203
/* Set the right font */
8204
if (details->font) {
8205
desc = pango_font_description_from_string (details->font);
8207
context = gtk_widget_get_pango_context (GTK_WIDGET (container));
8208
desc = pango_font_description_copy (pango_context_get_font_description (context));
8209
pango_font_description_set_size (desc,
8210
pango_font_description_get_size (desc) +
8211
container->details->font_size_table [container->details->zoom_level]);
8213
eel_editable_label_set_font_description (EEL_EDITABLE_LABEL (details->rename_widget),
8215
pango_font_description_free (desc);
8217
icon_rect = nautilus_icon_canvas_item_get_icon_rectangle (icon->item);
8218
text_rect = nautilus_icon_canvas_item_get_text_rectangle (icon->item, TRUE);
8220
if (nautilus_icon_container_is_layout_vertical (container) &&
8221
container->details->label_position == NAUTILUS_ICON_LABEL_POSITION_BESIDE) {
8222
/* for one-line editables, the width changes dynamically */
8225
width = nautilus_icon_canvas_item_get_max_text_width (icon->item);
8228
if (details->label_position == NAUTILUS_ICON_LABEL_POSITION_BESIDE) {
8229
eel_canvas_w2c (EEL_CANVAS_ITEM (icon->item)->canvas,
8234
eel_canvas_w2c (EEL_CANVAS_ITEM (icon->item)->canvas,
8235
(icon_rect.x0 + icon_rect.x1) / 2,
8238
x = x - width / 2 - 1;
8241
gtk_layout_move (GTK_LAYOUT (container),
8242
details->rename_widget,
8245
gtk_widget_set_size_request (details->rename_widget,
8247
eel_editable_label_set_text (EEL_EDITABLE_LABEL (details->rename_widget),
8253
eel_filename_get_rename_region (editable_text, &start_offset, &end_offset);
8256
gtk_widget_show (details->rename_widget);
8257
gtk_widget_grab_focus (details->rename_widget);
8259
eel_editable_label_select_region (EEL_EDITABLE_LABEL (details->rename_widget),
8263
g_signal_emit (container,
8264
signals[ICON_RENAME_STARTED], 0,
8265
GTK_EDITABLE (details->rename_widget));
8267
nautilus_icon_container_update_icon (container, icon);
8269
/* We are in renaming mode */
8270
details->renaming = TRUE;
8271
nautilus_icon_canvas_item_set_renaming (icon->item, TRUE);
8275
end_renaming_mode (NautilusIconContainer *container, gboolean commit)
8278
const char *changed_text = NULL;
8280
set_pending_icon_to_rename (container, NULL);
8282
icon = get_icon_being_renamed (container);
8287
/* We are not in renaming mode */
8288
container->details->renaming = FALSE;
8289
nautilus_icon_canvas_item_set_renaming (icon->item, FALSE);
8291
nautilus_icon_container_unfreeze_updates (container);
8294
set_pending_icon_to_reveal (container, icon);
8297
gtk_widget_grab_focus (GTK_WIDGET (container));
8300
/* Verify that text has been modified before signalling change. */
8301
changed_text = eel_editable_label_get_text (EEL_EDITABLE_LABEL (container->details->rename_widget));
8302
if (strcmp (container->details->original_text, changed_text) == 0) {
8303
changed_text = NULL;
8307
g_signal_emit (container,
8308
signals[ICON_RENAME_ENDED], 0,
8312
gtk_widget_hide (container->details->rename_widget);
8313
g_free (container->details->original_text);
8317
nautilus_icon_container_has_stored_icon_positions (NautilusIconContainer *container)
8321
gboolean have_stored_position;
8322
NautilusIconPosition position;
8324
for (p = container->details->icons; p != NULL; p = p->next) {
8327
have_stored_position = FALSE;
8328
g_signal_emit (container,
8329
signals[GET_STORED_ICON_POSITION], 0,
8332
&have_stored_position);
8333
if (have_stored_position) {
8341
nautilus_icon_container_set_single_click_mode (NautilusIconContainer *container,
8342
gboolean single_click_mode)
8344
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
8346
container->details->single_click_mode = single_click_mode;
8349
/* Return if the icon container is a fixed size */
8351
nautilus_icon_container_get_is_fixed_size (NautilusIconContainer *container)
8353
g_return_val_if_fail (NAUTILUS_IS_ICON_CONTAINER (container), FALSE);
8355
return container->details->is_fixed_size;
8358
/* Set the icon container to be a fixed size */
8360
nautilus_icon_container_set_is_fixed_size (NautilusIconContainer *container,
8361
gboolean is_fixed_size)
8363
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
8365
container->details->is_fixed_size = is_fixed_size;
8369
nautilus_icon_container_get_is_desktop (NautilusIconContainer *container)
8371
g_return_val_if_fail (NAUTILUS_IS_ICON_CONTAINER (container), FALSE);
8373
return container->details->is_desktop;
8377
nautilus_icon_container_set_is_desktop (NautilusIconContainer *container,
8378
gboolean is_desktop)
8380
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
8382
container->details->is_desktop = is_desktop;
8385
GtkStyleContext *context;
8387
context = gtk_widget_get_style_context (GTK_WIDGET (container));
8388
gtk_style_context_add_class (context, "nautilus-desktop");
8393
nautilus_icon_container_set_margins (NautilusIconContainer *container,
8399
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
8401
container->details->left_margin = left_margin;
8402
container->details->right_margin = right_margin;
8403
container->details->top_margin = top_margin;
8404
container->details->bottom_margin = bottom_margin;
8406
/* redo layout of icons as the margins have changed */
8407
schedule_redo_layout (container);
8411
nautilus_icon_container_set_use_drop_shadows (NautilusIconContainer *container,
8412
gboolean use_drop_shadows)
8414
if (container->details->drop_shadows_requested == use_drop_shadows) {
8418
container->details->drop_shadows_requested = use_drop_shadows;
8419
container->details->use_drop_shadows = use_drop_shadows;
8420
gtk_widget_queue_draw (GTK_WIDGET (container));
8423
/* handle theme changes */
8426
nautilus_icon_container_set_font (NautilusIconContainer *container,
8429
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
8431
if (g_strcmp0 (container->details->font, font) == 0) {
8435
g_free (container->details->font);
8436
container->details->font = g_strdup (font);
8438
invalidate_labels (container);
8439
nautilus_icon_container_request_update_all (container);
8440
gtk_widget_queue_draw (GTK_WIDGET (container));
8444
nautilus_icon_container_set_font_size_table (NautilusIconContainer *container,
8445
const int font_size_table[NAUTILUS_ZOOM_LEVEL_LARGEST + 1])
8450
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
8451
g_return_if_fail (font_size_table != NULL);
8453
old_font_size = container->details->font_size_table[container->details->zoom_level];
8455
for (i = 0; i <= NAUTILUS_ZOOM_LEVEL_LARGEST; i++) {
8456
if (container->details->font_size_table[i] != font_size_table[i]) {
8457
container->details->font_size_table[i] = font_size_table[i];
8461
if (old_font_size != container->details->font_size_table[container->details->zoom_level]) {
8462
invalidate_labels (container);
8463
nautilus_icon_container_request_update_all (container);
8468
* nautilus_icon_container_get_icon_description
8469
* @container: An icon container widget.
8472
* Gets the description for the icon. This function may return NULL.
8475
nautilus_icon_container_get_icon_description (NautilusIconContainer *container,
8476
NautilusIconData *data)
8478
NautilusIconContainerClass *klass;
8480
klass = NAUTILUS_ICON_CONTAINER_GET_CLASS (container);
8482
if (klass->get_icon_description) {
8483
return klass->get_icon_description (container, data);
8490
nautilus_icon_container_get_allow_moves (NautilusIconContainer *container)
8492
g_return_val_if_fail (NAUTILUS_IS_ICON_CONTAINER (container), FALSE);
8494
return container->details->drag_allow_moves;
8498
nautilus_icon_container_set_allow_moves (NautilusIconContainer *container,
8499
gboolean allow_moves)
8501
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
8503
container->details->drag_allow_moves = allow_moves;
8507
nautilus_icon_container_set_forced_icon_size (NautilusIconContainer *container,
8508
int forced_icon_size)
8510
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
8512
if (forced_icon_size != container->details->forced_icon_size) {
8513
container->details->forced_icon_size = forced_icon_size;
8515
invalidate_label_sizes (container);
8516
nautilus_icon_container_request_update_all (container);
8521
nautilus_icon_container_set_all_columns_same_width (NautilusIconContainer *container,
8522
gboolean all_columns_same_width)
8524
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
8526
if (all_columns_same_width != container->details->all_columns_same_width) {
8527
container->details->all_columns_same_width = all_columns_same_width;
8529
invalidate_labels (container);
8530
nautilus_icon_container_request_update_all (container);
8535
* nautilus_icon_container_set_highlighted_for_clipboard
8536
* @container: An icon container widget.
8537
* @data: Icon Data associated with all icons that should be highlighted.
8538
* Others will be unhighlighted.
8541
nautilus_icon_container_set_highlighted_for_clipboard (NautilusIconContainer *container,
8542
GList *clipboard_icon_data)
8546
gboolean highlighted_for_clipboard;
8548
g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
8550
for (l = container->details->icons; l != NULL; l = l->next) {
8552
highlighted_for_clipboard = (g_list_find (clipboard_icon_data, icon->data) != NULL);
8554
eel_canvas_item_set (EEL_CANVAS_ITEM (icon->item),
8555
"highlighted-for-clipboard", highlighted_for_clipboard,
8562
nautilus_icon_container_set_active (NautilusIconContainer *container,
8565
container->details->active_background = active;
8567
if (gtk_widget_get_realized (GTK_WIDGET (container))) {
8568
setup_background (container);
8572
/* NautilusIconContainerAccessible */
8574
static NautilusIconContainerAccessiblePrivate *
8575
accessible_get_priv (AtkObject *accessible)
8577
NautilusIconContainerAccessiblePrivate *priv;
8579
priv = g_object_get_qdata (G_OBJECT (accessible),
8580
accessible_private_data_quark);
8585
/* AtkAction interface */
8588
nautilus_icon_container_accessible_do_action (AtkAction *accessible, int i)
8591
NautilusIconContainer *container;
8594
g_return_val_if_fail (i < LAST_ACTION, FALSE);
8596
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8601
container = NAUTILUS_ICON_CONTAINER (widget);
8603
case ACTION_ACTIVATE :
8604
selection = nautilus_icon_container_get_selection (container);
8607
g_signal_emit_by_name (container, "activate", selection);
8608
g_list_free (selection);
8612
handle_popups (container, NULL,"context_click_background");
8615
g_warning ("Invalid action passed to NautilusIconContainerAccessible::do_action");
8622
nautilus_icon_container_accessible_get_n_actions (AtkAction *accessible)
8628
nautilus_icon_container_accessible_action_get_description (AtkAction *accessible,
8631
NautilusIconContainerAccessiblePrivate *priv;
8633
g_assert (i < LAST_ACTION);
8635
priv = accessible_get_priv (ATK_OBJECT (accessible));
8637
if (priv->action_descriptions[i]) {
8638
return priv->action_descriptions[i];
8640
return nautilus_icon_container_accessible_action_descriptions[i];
8645
nautilus_icon_container_accessible_action_get_name (AtkAction *accessible, int i)
8647
g_assert (i < LAST_ACTION);
8649
return nautilus_icon_container_accessible_action_names[i];
8653
nautilus_icon_container_accessible_action_get_keybinding (AtkAction *accessible,
8656
g_assert (i < LAST_ACTION);
8662
nautilus_icon_container_accessible_action_set_description (AtkAction *accessible,
8664
const char *description)
8666
NautilusIconContainerAccessiblePrivate *priv;
8668
g_assert (i < LAST_ACTION);
8670
priv = accessible_get_priv (ATK_OBJECT (accessible));
8672
if (priv->action_descriptions[i]) {
8673
g_free (priv->action_descriptions[i]);
8675
priv->action_descriptions[i] = g_strdup (description);
8681
nautilus_icon_container_accessible_action_interface_init (AtkActionIface *iface)
8683
iface->do_action = nautilus_icon_container_accessible_do_action;
8684
iface->get_n_actions = nautilus_icon_container_accessible_get_n_actions;
8685
iface->get_description = nautilus_icon_container_accessible_action_get_description;
8686
iface->get_name = nautilus_icon_container_accessible_action_get_name;
8687
iface->get_keybinding = nautilus_icon_container_accessible_action_get_keybinding;
8688
iface->set_description = nautilus_icon_container_accessible_action_set_description;
8691
/* AtkSelection interface */
8694
nautilus_icon_container_accessible_update_selection (AtkObject *accessible)
8696
NautilusIconContainer *container;
8697
NautilusIconContainerAccessiblePrivate *priv;
8701
container = NAUTILUS_ICON_CONTAINER (gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)));
8703
priv = accessible_get_priv (accessible);
8705
if (priv->selection) {
8706
g_list_free (priv->selection);
8707
priv->selection = NULL;
8710
for (l = container->details->icons; l != NULL; l = l->next) {
8712
if (icon->is_selected) {
8713
priv->selection = g_list_prepend (priv->selection,
8718
priv->selection = g_list_reverse (priv->selection);
8722
nautilus_icon_container_accessible_selection_changed_cb (NautilusIconContainer *container,
8725
g_signal_emit_by_name (data, "selection_changed");
8729
nautilus_icon_container_accessible_icon_added_cb (NautilusIconContainer *container,
8730
NautilusIconData *icon_data,
8734
AtkObject *atk_parent;
8735
AtkObject *atk_child;
8738
icon = g_hash_table_lookup (container->details->icon_set, icon_data);
8740
atk_parent = ATK_OBJECT (data);
8741
atk_child = atk_gobject_accessible_for_object
8742
(G_OBJECT (icon->item));
8743
index = g_list_index (container->details->icons, icon);
8745
g_signal_emit_by_name (atk_parent, "children_changed::add",
8746
index, atk_child, NULL);
8751
nautilus_icon_container_accessible_icon_removed_cb (NautilusIconContainer *container,
8752
NautilusIconData *icon_data,
8756
AtkObject *atk_parent;
8757
AtkObject *atk_child;
8760
icon = g_hash_table_lookup (container->details->icon_set, icon_data);
8762
atk_parent = ATK_OBJECT (data);
8763
atk_child = atk_gobject_accessible_for_object
8764
(G_OBJECT (icon->item));
8765
index = g_list_index (container->details->icons, icon);
8767
g_signal_emit_by_name (atk_parent, "children_changed::remove",
8768
index, atk_child, NULL);
8773
nautilus_icon_container_accessible_cleared_cb (NautilusIconContainer *container,
8776
g_signal_emit_by_name (data, "children_changed", 0, NULL, NULL);
8781
nautilus_icon_container_accessible_add_selection (AtkSelection *accessible,
8785
NautilusIconContainer *container;
8790
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8795
container = NAUTILUS_ICON_CONTAINER (widget);
8797
l = g_list_nth (container->details->icons, i);
8801
selection = nautilus_icon_container_get_selection (container);
8802
selection = g_list_prepend (selection,
8804
nautilus_icon_container_set_selection (container, selection);
8806
g_list_free (selection);
8814
nautilus_icon_container_accessible_clear_selection (AtkSelection *accessible)
8817
NautilusIconContainer *container;
8819
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8824
container = NAUTILUS_ICON_CONTAINER (widget);
8826
nautilus_icon_container_unselect_all (container);
8832
nautilus_icon_container_accessible_ref_selection (AtkSelection *accessible,
8835
AtkObject *atk_object;
8836
NautilusIconContainerAccessiblePrivate *priv;
8840
nautilus_icon_container_accessible_update_selection (ATK_OBJECT (accessible));
8841
priv = accessible_get_priv (ATK_OBJECT (accessible));
8843
item = (g_list_nth (priv->selection, i));
8847
atk_object = atk_gobject_accessible_for_object (G_OBJECT (icon->item));
8849
g_object_ref (atk_object);
8859
nautilus_icon_container_accessible_get_selection_count (AtkSelection *accessible)
8862
NautilusIconContainerAccessiblePrivate *priv;
8864
nautilus_icon_container_accessible_update_selection (ATK_OBJECT (accessible));
8865
priv = accessible_get_priv (ATK_OBJECT (accessible));
8867
count = g_list_length (priv->selection);
8873
nautilus_icon_container_accessible_is_child_selected (AtkSelection *accessible,
8876
NautilusIconContainer *container;
8881
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8886
container = NAUTILUS_ICON_CONTAINER (widget);
8888
l = g_list_nth (container->details->icons, i);
8891
return icon->is_selected;
8897
nautilus_icon_container_accessible_remove_selection (AtkSelection *accessible,
8900
NautilusIconContainer *container;
8901
NautilusIconContainerAccessiblePrivate *priv;
8907
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8912
nautilus_icon_container_accessible_update_selection (ATK_OBJECT (accessible));
8913
priv = accessible_get_priv (ATK_OBJECT (accessible));
8915
container = NAUTILUS_ICON_CONTAINER (widget);
8917
l = g_list_nth (priv->selection, i);
8921
selection = nautilus_icon_container_get_selection (container);
8922
selection = g_list_remove (selection, icon->data);
8923
nautilus_icon_container_set_selection (container, selection);
8925
g_list_free (selection);
8933
nautilus_icon_container_accessible_select_all_selection (AtkSelection *accessible)
8935
NautilusIconContainer *container;
8938
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8943
container = NAUTILUS_ICON_CONTAINER (widget);
8945
nautilus_icon_container_select_all (container);
8951
nautilus_icon_container_widget_to_file_operation_position (NautilusIconContainer *container,
8956
g_return_if_fail (position != NULL);
8961
eel_canvas_window_to_world (EEL_CANVAS (container), x, y, &x, &y);
8963
position->x = (int) x;
8964
position->y = (int) y;
8966
/* ensure that we end up in the middle of the icon */
8967
position->x -= nautilus_get_icon_size_for_zoom_level (container->details->zoom_level) / 2;
8968
position->y -= nautilus_get_icon_size_for_zoom_level (container->details->zoom_level) / 2;
8972
nautilus_icon_container_accessible_selection_interface_init (AtkSelectionIface *iface)
8974
iface->add_selection = nautilus_icon_container_accessible_add_selection;
8975
iface->clear_selection = nautilus_icon_container_accessible_clear_selection;
8976
iface->ref_selection = nautilus_icon_container_accessible_ref_selection;
8977
iface->get_selection_count = nautilus_icon_container_accessible_get_selection_count;
8978
iface->is_child_selected = nautilus_icon_container_accessible_is_child_selected;
8979
iface->remove_selection = nautilus_icon_container_accessible_remove_selection;
8980
iface->select_all_selection = nautilus_icon_container_accessible_select_all_selection;
8985
nautilus_icon_container_accessible_get_n_children (AtkObject *accessible)
8987
NautilusIconContainer *container;
8991
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8996
container = NAUTILUS_ICON_CONTAINER (widget);
8998
i = g_hash_table_size (container->details->icon_set);
8999
if (container->details->rename_widget) {
9006
nautilus_icon_container_accessible_ref_child (AtkObject *accessible, int i)
9008
AtkObject *atk_object;
9009
NautilusIconContainer *container;
9014
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
9019
container = NAUTILUS_ICON_CONTAINER (widget);
9021
item = (g_list_nth (container->details->icons, i));
9026
atk_object = atk_gobject_accessible_for_object (G_OBJECT (icon->item));
9027
g_object_ref (atk_object);
9031
if (i == g_list_length (container->details->icons)) {
9032
if (container->details->rename_widget) {
9033
atk_object = gtk_widget_get_accessible (container->details->rename_widget);
9034
g_object_ref (atk_object);
9044
nautilus_icon_container_accessible_initialize (AtkObject *accessible,
9047
NautilusIconContainer *container;
9048
NautilusIconContainerAccessiblePrivate *priv;
9050
if (ATK_OBJECT_CLASS (accessible_parent_class)->initialize) {
9051
ATK_OBJECT_CLASS (accessible_parent_class)->initialize (accessible, data);
9054
priv = g_new0 (NautilusIconContainerAccessiblePrivate, 1);
9055
g_object_set_qdata (G_OBJECT (accessible),
9056
accessible_private_data_quark,
9059
if (GTK_IS_ACCESSIBLE (accessible)) {
9060
nautilus_icon_container_accessible_update_selection
9061
(ATK_OBJECT (accessible));
9063
container = NAUTILUS_ICON_CONTAINER (gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)));
9064
g_signal_connect (G_OBJECT (container), "selection_changed",
9065
G_CALLBACK (nautilus_icon_container_accessible_selection_changed_cb),
9067
g_signal_connect (G_OBJECT (container), "icon_added",
9068
G_CALLBACK (nautilus_icon_container_accessible_icon_added_cb),
9070
g_signal_connect (G_OBJECT (container), "icon_removed",
9071
G_CALLBACK (nautilus_icon_container_accessible_icon_removed_cb),
9073
g_signal_connect (G_OBJECT (container), "cleared",
9074
G_CALLBACK (nautilus_icon_container_accessible_cleared_cb),
9080
nautilus_icon_container_accessible_finalize (GObject *object)
9082
NautilusIconContainerAccessiblePrivate *priv;
9085
priv = accessible_get_priv (ATK_OBJECT (object));
9086
if (priv->selection) {
9087
g_list_free (priv->selection);
9090
for (i = 0; i < LAST_ACTION; i++) {
9091
if (priv->action_descriptions[i]) {
9092
g_free (priv->action_descriptions[i]);
9098
G_OBJECT_CLASS (accessible_parent_class)->finalize (object);
9102
nautilus_icon_container_accessible_class_init (AtkObjectClass *klass)
9104
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
9106
accessible_parent_class = g_type_class_peek_parent (klass);
9108
gobject_class->finalize = nautilus_icon_container_accessible_finalize;
9110
klass->get_n_children = nautilus_icon_container_accessible_get_n_children;
9111
klass->ref_child = nautilus_icon_container_accessible_ref_child;
9112
klass->initialize = nautilus_icon_container_accessible_initialize;
9114
accessible_private_data_quark = g_quark_from_static_string ("icon-container-accessible-private-data");
9118
nautilus_icon_container_accessible_get_type (void)
9120
static GType type = 0;
9123
static GInterfaceInfo atk_action_info = {
9124
(GInterfaceInitFunc) nautilus_icon_container_accessible_action_interface_init,
9125
(GInterfaceFinalizeFunc) NULL,
9129
static GInterfaceInfo atk_selection_info = {
9130
(GInterfaceInitFunc) nautilus_icon_container_accessible_selection_interface_init,
9131
(GInterfaceFinalizeFunc) NULL,
9135
type = eel_accessibility_create_derived_type
9136
("NautilusIconContainerAccessible",
9138
nautilus_icon_container_accessible_class_init);
9140
g_type_add_interface_static (type, ATK_TYPE_ACTION,
9142
g_type_add_interface_static (type, ATK_TYPE_SELECTION,
9143
&atk_selection_info);
9149
#if ! defined (NAUTILUS_OMIT_SELF_CHECK)
9152
check_compute_stretch (int icon_x, int icon_y, int icon_size,
9153
int start_pointer_x, int start_pointer_y,
9154
int end_pointer_x, int end_pointer_y)
9156
StretchState start, current;
9158
start.icon_x = icon_x;
9159
start.icon_y = icon_y;
9160
start.icon_size = icon_size;
9161
start.pointer_x = start_pointer_x;
9162
start.pointer_y = start_pointer_y;
9163
current.pointer_x = end_pointer_x;
9164
current.pointer_y = end_pointer_y;
9166
compute_stretch (&start, ¤t);
9168
return g_strdup_printf ("%d,%d:%d",
9175
nautilus_self_check_icon_container (void)
9177
EEL_CHECK_STRING_RESULT (check_compute_stretch (0, 0, 16, 0, 0, 0, 0), "0,0:16");
9178
EEL_CHECK_STRING_RESULT (check_compute_stretch (0, 0, 16, 16, 16, 17, 17), "0,0:17");
9179
EEL_CHECK_STRING_RESULT (check_compute_stretch (0, 0, 16, 16, 16, 17, 16), "0,0:16");
9180
EEL_CHECK_STRING_RESULT (check_compute_stretch (100, 100, 64, 105, 105, 40, 40), "35,35:129");
9184
nautilus_icon_container_is_layout_rtl (NautilusIconContainer *container)
9186
g_return_val_if_fail (NAUTILUS_IS_ICON_CONTAINER (container), 0);
9188
return container->details->layout_mode == NAUTILUS_ICON_LAYOUT_T_B_R_L ||
9189
container->details->layout_mode == NAUTILUS_ICON_LAYOUT_R_L_T_B;
9193
nautilus_icon_container_is_layout_vertical (NautilusIconContainer *container)
9195
g_return_val_if_fail (NAUTILUS_IS_ICON_CONTAINER (container), FALSE);
9197
return (container->details->layout_mode == NAUTILUS_ICON_LAYOUT_T_B_L_R ||
9198
container->details->layout_mode == NAUTILUS_ICON_LAYOUT_T_B_R_L);
9202
nautilus_icon_container_get_max_layout_lines_for_pango (NautilusIconContainer *container)
9206
if (nautilus_icon_container_get_is_desktop (container)) {
9207
limit = desktop_text_ellipsis_limit;
9209
limit = text_ellipsis_limits[container->details->zoom_level];
9220
nautilus_icon_container_get_max_layout_lines (NautilusIconContainer *container)
9224
if (nautilus_icon_container_get_is_desktop (container)) {
9225
limit = desktop_text_ellipsis_limit;
9227
limit = text_ellipsis_limits[container->details->zoom_level];
9238
nautilus_icon_container_begin_loading (NautilusIconContainer *container)
9242
if (nautilus_icon_container_get_store_layout_timestamps (container)) {
9243
container->details->layout_timestamp = UNDEFINED_TIME;
9244
g_signal_emit (container,
9245
signals[GET_STORED_LAYOUT_TIMESTAMP], 0,
9246
NULL, &container->details->layout_timestamp, &dummy);
9251
store_layout_timestamps_now (NautilusIconContainer *container)
9257
container->details->layout_timestamp = time (NULL);
9258
g_signal_emit (container,
9259
signals[STORE_LAYOUT_TIMESTAMP], 0,
9260
NULL, &container->details->layout_timestamp, &dummy);
9262
for (p = container->details->icons; p != NULL; p = p->next) {
9265
g_signal_emit (container,
9266
signals[STORE_LAYOUT_TIMESTAMP], 0,
9267
icon->data, &container->details->layout_timestamp, &dummy);
9273
nautilus_icon_container_end_loading (NautilusIconContainer *container,
9274
gboolean all_icons_added)
9276
if (all_icons_added &&
9277
nautilus_icon_container_get_store_layout_timestamps (container)) {
9278
if (container->details->new_icons == NULL) {
9279
store_layout_timestamps_now (container);
9281
container->details->store_layout_timestamps_when_finishing_new_icons = TRUE;
9287
nautilus_icon_container_get_store_layout_timestamps (NautilusIconContainer *container)
9289
return container->details->store_layout_timestamps;
9294
nautilus_icon_container_set_store_layout_timestamps (NautilusIconContainer *container,
9295
gboolean store_layout_timestamps)
9297
container->details->store_layout_timestamps = store_layout_timestamps;
9301
#endif /* ! NAUTILUS_OMIT_SELF_CHECK */